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 (

Game HUD — Live Concept (3D)

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 */}
{/* 3D Canvas */}
{/* HUD overlay */}
{/* TOP BAR */}
{ e.currentTarget.style.color = 'var(--fg-bright)'; e.currentTarget.style.borderColor = 'var(--accent)'; }} onMouseLeave={(e) => { e.currentTarget.style.color = 'var(--fg-dim)'; e.currentTarget.style.borderColor = 'var(--border)'; }} title="Back to Game Docs" > DOCS
{system.name} {system.security.toFixed(1)}
Ship {ship.name}
₢125,000
TQ Online 14:23 UTC
3D
{/* MIDDLE */}
{/* LEFT — Ship Panel */}
Ship Status
{[ { label: 'SH', value: ship.shields, color: '#22d3ee' }, { label: 'AR', value: ship.armor, color: '#f0a030' }, { label: 'HU', value: ship.hull, color: '#22c55e' }, { label: 'CA', value: ship.capacitor, color: '#a78bfa' }, ].map(bar => (
{bar.label}
30 ? 'linear-gradient(90deg, #6366f1, #a78bfa)' : 'linear-gradient(90deg, #dc2626, #ef4444)') : `linear-gradient(90deg, ${bar.color}88, ${bar.color})`, borderRadius: 'var(--radius-pill)' }} />
{bar.label === 'CA' ? Math.round(bar.value) : bar.value}%
))}
{/* Speed */}
0 ? 'var(--fg-bright)' : 'var(--muted)', letterSpacing: '-0.02em' }}> {ship.speed}m/s
{/* RIGHT — Overview */}
Overview {filteredEntities.length} items
{['all', 'hostile', 'asteroid', 'friendly'].map(f => ( ))}
{filteredEntities.map(ent => { const col = ent.type === 'hostile' ? '#ef4444' : ent.type === 'asteroid' ? '#a78bfa' : ent.type === 'station' ? '#22d3ee' : ent.type === 'gate' ? '#5a6b82' : '#22c55e'; return (
{ent.name} {ent.dist}
); })}
{/* BOTTOM BAR */}
{/* Modules */}
Modules {activeModules} active
{['high', 'med', 'low'].map(slotType => (
{slotType.toUpperCase()} {modules.filter(m => m.slot === slotType).map(mod => (
toggleModule(mod.id)} title={`${mod.name} (${mod.active ? 'Active' : 'Inactive'})`}> {mod.name.length > 14 ? mod.name.slice(0, 12) + '…' : mod.name}
))}
))}
{/* Target */}
Target
{target.name}
{target.type} · LOCKED
{[ { label: 'SH', value: target.shields, color: '#22d3ee' }, { label: 'AR', value: target.armor, color: '#f0a030' }, { label: 'HU', value: target.hull, color: '#22c55e' }, ].map(bar => (
{bar.label}
{bar.value}%
))}
{target.distance.toLocaleString()} km ₢{target.bounty.toLocaleString()}
{/* Cargo */}
Cargo
{cargo.used}/{cargo.total} m³ {Math.round(cargo.used / cargo.total * 100)}%
{cargo.items.map((item, i) => (
{item.name} ×{item.qty}
))}
{/* Chat */}
{['local', 'corp', 'trade'].map(tab => ( ))}
{chatState.messages.map((msg, i) => (
{msg.sender} {msg.body} {msg.time}
))}
{/* Architecture notes */}
HUD

HUD Panel Architecture — 3D

3D Viewport

  • Three.js WebGL replaces 2D Canvas — proper 3D ship meshes, asteroids, stations, star fields
  • Depth and lighting — ships and asteroids are lit by ambient + directional lights
  • Particle star field — 4000 point-based stars with subtle rotation for depth
  • Engine glows — point lights on each ship with pulsing intensity
  • Lock brackets — 3D wireframe targeting indicator that rotates around the target

HUD Overlay Pattern

  • CSS overlay — HUD panels are positioned absolutely over the 3D canvas
  • Glass morphism — backdrop-filter blur + semi-transparent backgrounds
  • Pointer events — HUD panels capture clicks, center viewport passes through
  • Performance — Three.js renderer is separate from React DOM updates
Rendering upgrade: The space viewport now uses Three.js with WebGL. Ships are 3D meshes with lighting, asteroids use icosahedron geometry with vertex perturbation, and the star field is a 4000-particle Points system. The HUD overlay panels remain identical React components.
); } window.GDD.GameHudDemo = GameHudDemo;