window.GDD = window.GDD || {}; const { useState, useEffect, useRef, useCallback } = React; const TH = window.GDD.THREE; /* ===== Game HUD Demo — 3D space viewport inside HUD overlay ===== */ function GameHudDemo() { const containerRef = useRef(null); const sceneRef = useRef(null); const animIdRef = useRef(null); const [modules, setModules] = useState([ { id: 'h1', name: '150mm Railgun', icon: '⊕', active: false, type: 'weapon', slot: 'high' }, { id: 'h2', name: 'Missile Launcher', icon: '⊕', active: false, type: 'weapon', slot: 'high' }, { id: 'h3', name: 'Mining Laser', icon: '⛏', active: false, type: 'mining', slot: 'high' }, { id: 'm1', name: 'Shield Booster', icon: '◎', active: false, type: 'shield', slot: 'med' }, { id: 'm2', name: 'Afterburner', icon: '»', active: false, type: 'propulsion', slot: 'med' }, { id: 'm3', name: 'Warp Scram', icon: '◎', active: false, type: 'ewar', slot: 'med' }, { id: 'l1', name: 'Armor Plate', icon: '◼', active: true, type: 'armor', slot: 'low' }, { id: 'l2', name: 'Damage Control', icon: '↯', active: true, type: 'damage_mod', slot: 'low' }, { id: 'l3', name: 'Cargo Expander', icon: '□', active: false, type: 'cargo', slot: 'low' }, ]); const [target] = useState({ name: 'Guristas Pirate', type: 'Frigate', locked: true, shields: 62, armor: 85, hull: 100, distance: 12400, bounty: 85000 }); const [cargo] = useState({ used: 340, total: 600, items: [{ name: 'Veldspar', qty: 120 }, { name: 'Scordite', qty: 80 }, { name: 'Pyroxeres', qty: 45 }, { name: 'Tritanium', qty: 200 }] }); const [chatState, setChatState] = useState({ activeTab: 'local', messages: [ { sender: 'CMDR Picard', body: ' Pirates in belt 3, be careful ', time: '14:23' }, { sender: 'MinerBob', body: ' Anyone selling compressed ore? ', time: '14:21' }, { sender: 'CMDR Worf', body: ' Target locked, engaging hostiles ', time: '14:19' }, { sender: '[SYSTEM]', body: ' Guristas fleet detected in nearby system ', time: '14:15' }, { sender: 'TraderAlice', body: ' Best buy orders at Jita IV — check market ', time: '14:12' }, ], }); const [ship, setShip] = useState({ shields: 100, armor: 92, hull: 100, capacitor: 78, speed: 0, maxSpeed: 420, name: 'USS ENTERPRISE', class: 'VENTURE-CLASS' }); const [entities] = useState([ { id: 'e1', name: 'Asteroid Belt', type: 'asteroid', dist: '12 km' }, { id: 'e2', name: 'Guristas Pirate', type: 'hostile', dist: '24 km' }, { id: 'e3', name: 'CMDR Riker', type: 'friendly', dist: '38 km' }, { id: 'e4', name: 'Jita IV Station', type: 'station', dist: '45 km' }, { id: 'e5', name: 'Veldspar Rock', type: 'asteroid', dist: '8 km' }, { id: 'e6', name: 'MinerBob', type: 'friendly', dist: '52 km' }, { id: 'e7', name: 'Jump Gate', type: 'gate', dist: '120 km' }, { id: 'e8', name: 'Scordite Deposit', type: 'asteroid', dist: '15 km' }, ]); const [overviewFilter, setOverviewFilter] = useState('all'); const [system] = useState({ name: 'Jita', security: 0.9 }); // Build 3D scene useEffect(() => { const container = containerRef.current; if (!container) return; const scene = new THREE.Scene(); const w = container.clientWidth; const h = container.clientHeight; const camera = new THREE.PerspectiveCamera(60, w / h, 0.1, 5000); camera.position.set(0, 8, 25); camera.lookAt(0, 0, -20); const renderer = TH.createRenderer(container, { clearColor: 0x040810 }); renderer.setSize(w, h); // Stars const stars = TH.createStarField(4000, 3000); scene.add(stars); // Nebulae TH.addNebula(scene, 0x22d3ee, [-30, 20, -100], 80); TH.addNebula(scene, 0xa78bfa, [50, -10, -80], 60); TH.addNebula(scene, 0xf0a030, [-60, 15, -120], 50); // Lighting TH.setupSpaceLighting(scene); // Player ship (small, at bottom center of view) const playerGroup = new THREE.Group(); const pMesh = TH.createShipMesh(0xc8d6e5, 0xf0a030, 0.5); pMesh.rotation.y = Math.PI / 2; playerGroup.add(pMesh); const pEngine = TH.createEngineGlow(0x22d3ee, 2, 8); pEngine.position.set(0, 0, 5); playerGroup.add(pEngine); const pShield = TH.createShield(2.5, 0x22d3ee, 0.05); playerGroup.add(pShield); playerGroup.position.set(0, -1, 15); scene.add(playerGroup); // Enemy ship (in the distance) const enemyGroup = new THREE.Group(); const eMesh = TH.createShipMesh(0x7f1d1d, 0xef4444, 0.4); eMesh.rotation.y = -Math.PI / 2; enemyGroup.add(eMesh); const eEngine = TH.createEngineGlow(0xef4444, 1.5, 6); eEngine.position.set(0, 0, -4); enemyGroup.add(eEngine); const lockBrackets = TH.createLockBrackets(2, 0xf0a030); enemyGroup.add(lockBrackets); const eLabel = TH.createLabel('GURISTAS PIRATE', '#ef4444', 12); eLabel.position.y = 4; enemyGroup.add(eLabel); enemyGroup.position.set(5, 1, -20); scene.add(enemyGroup); // Asteroids const asteroidPositions = [ { x: -25, y: -3, z: -15, size: 3 }, { x: -20, y: -2, z: -10, size: 2 }, { x: -30, y: -4, z: -20, size: 2.5 }, { x: 30, y: -3, z: -18, size: 2 }, { x: 35, y: -2, z: -12, size: 1.5 }, { x: -15, y: -5, z: -30, size: 3.5 }, { x: 20, y: -4, z: -35, size: 2 }, ]; asteroidPositions.forEach(ap => { const ast = TH.createAsteroid(ap.size); ast.position.set(ap.x, ap.y, ap.z); ast.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, 0); scene.add(ast); }); // Station (far right) const station = TH.createStation(3, 0x22d3ee); station.position.set(40, 2, -40); scene.add(station); const stnLabel = TH.createLabel('JITA IV STN', '#22d3ee', 12); stnLabel.position.set(40, 8, -40); scene.add(stnLabel); // Targeting line (dashed) const linePoints = [playerGroup.position, enemyGroup.position]; const lineGeo = new THREE.BufferGeometry().setFromPoints(linePoints); const lineMat = new THREE.LineDashedMaterial({ color: 0xf0a030, dashSize: 1, gapSize: 0.8, transparent: true, opacity: 0.2 }); const targetLine = new THREE.Line(lineGeo, lineMat); targetLine.computeLineDistances(); scene.add(targetLine); sceneRef.current = { scene, camera, renderer, stars, playerGroup, enemyGroup, pEngine, eEngine, lockBrackets, targetLine }; // Animation const clock = new THREE.Clock(); const animate = () => { animIdRef.current = requestAnimationFrame(animate); const t = clock.getElapsedTime(); // Star drift stars.rotation.y = t * 0.002; stars.rotation.x = t * 0.001; // Player ship idle bob playerGroup.position.y = -1 + Math.sin(t * 1.5) * 0.2; playerGroup.rotation.z = Math.sin(t * 0.3) * 0.02; // Enemy ship slight movement enemyGroup.position.x = 5 + Math.sin(t * 1.2) * 1; enemyGroup.position.y = 1 + Math.cos(t * 0.8) * 0.5; enemyGroup.rotation.z = Math.sin(t * 0.4) * 0.03; // Lock brackets rotate lockBrackets.rotation.y = t * 0.3; // Update target line const positions = targetLine.geometry.attributes.position; positions.setXYZ(0, playerGroup.position.x, playerGroup.position.y, playerGroup.position.z); positions.setXYZ(1, enemyGroup.position.x, enemyGroup.position.y, enemyGroup.position.z); positions.needsUpdate = true; targetLine.computeLineDistances(); // Engine glow pulse pEngine.intensity = 2 + Math.sin(t * 3) * 0.5; eEngine.intensity = 1 + Math.sin(t * 2.5) * 0.3; // Shield shimmer pShield.material.opacity = 0.04 + Math.sin(t * 2) * 0.02; renderer.render(scene, camera); }; animate(); const onResize = () => { const w2 = container.clientWidth; const h2 = container.clientHeight; renderer.setSize(w2, h2); camera.aspect = w2 / h2; camera.updateProjectionMatrix(); }; window.addEventListener('resize', onResize); return () => { if (animIdRef.current) cancelAnimationFrame(animIdRef.current); window.removeEventListener('resize', onResize); }; }, []); const toggleModule = useCallback((modId) => { setModules(prev => prev.map(m => m.id === modId ? { ...m, active: !m.active } : m)); }, []); // Simulate capacitor tick useEffect(() => { const interval = setInterval(() => { setShip(prev => { const activeCount = modules.filter(m => m.active).length; return { ...prev, capacitor: Math.max(0, Math.min(100, prev.capacitor - activeCount * 0.3 + 0.8)), speed: modules.find(m => m.id === 'm2' && m.active) ? 280 : 0 }; }); }, 1000); return () => clearInterval(interval); }, [modules]); const filteredEntities = overviewFilter === 'all' ? entities : entities.filter(e => e.type === overviewFilter); const activeModules = modules.filter(m => m.active).length; return (
The in-game HUD with a 3D WebGL space viewport. All panels overlay the Three.js scene — ship health, modules, overview, target info, cargo, and chat.
{/* Full HUD mockup */}