diff --git a/app.js b/app.js index 551008c..58b4431 100644 --- a/app.js +++ b/app.js @@ -332,173 +332,71 @@ function createFloor() { const ringMat = new THREE.MeshBasicMaterial({ color: NEXUS.colors.primary, transparent: true, - opacity: 0.15, + opacity: 0.4, side: THREE.DoubleSide, }); const ring = new THREE.Mesh(ringGeo, ringMat); - ring.rotation.x = -Math.PI / 2; + ring.rotation.x = Math.PI / 2; ring.position.y = 0.05; scene.add(ring); - - // Inner ring - const innerRingGeo = new THREE.RingGeometry(14.5, 15, 32); - const innerRingMat = new THREE.MeshBasicMaterial({ - color: NEXUS.colors.secondary, - transparent: true, - opacity: 0.08, - side: THREE.DoubleSide, - }); - const innerRing = new THREE.Mesh(innerRingGeo, innerRingMat); - innerRing.rotation.x = -Math.PI / 2; - innerRing.position.y = 0.03; - scene.add(innerRing); } // ═══ BATCAVE TERMINAL ═══ function createBatcaveTerminal() { - const termGroup = new THREE.Group(); - termGroup.position.set(0, 0, -8); + const terminalGroup = new THREE.Group(); + terminalGroup.position.set(0, 0, -8); - // Main large screen - createHoloPanel(termGroup, { - x: 0, y: 4, z: 0, w: 8, h: 5, - title: '◈ NEXUS COMMAND', - lines: [ - '┌─────────────────────────────────┐', - '│ SYSTEM STATUS NOMINAL │', - '│ HERMES HARNESS ACTIVE │', - '│ AGENT LOOPS 3/3 RUN │', - '│ MEMORY BANKS 2.4 GB │', - '│ THOUGHT CYCLES 14,892 │', - '├─────────────────────────────────┤', - '│ ACTIVE PROCESSES │', - '│ ▸ triage-daemon ● RUNNING │', - '│ ▸ code-review-loop ● RUNNING │', - '│ ▸ world-builder ○ STANDBY │', - '│ ▸ matrix-renderer ● RUNNING │', - '└─────────────────────────────────┘', - ], - color: NEXUS.colors.primary, + const panelData = [ + { title: 'NEXUS COMMAND', color: NEXUS.colors.primary, rot: -0.4, x: -6, y: 3, lines: ['> STATUS: NOMINAL', '> UPTIME: 142.4h', '> HARNESS: STABLE', '> MODE: SOVEREIGN'] }, + { title: 'DEV QUEUE', color: NEXUS.colors.gold, rot: -0.2, x: -3, y: 3, lines: ['> ISSUE #4: CORE', '> ISSUE #5: PORTAL', '> ISSUE #6: TERMINAL', '> ISSUE #7: TIMMY'] }, + { title: 'METRICS', color: NEXUS.colors.secondary, rot: 0, x: 0, y: 3, lines: ['> CPU: 12% [||....]', '> MEM: 4.2GB', '> COMMITS: 842', '> ACTIVE LOOPS: 5'] }, + { title: 'THOUGHTS', color: NEXUS.colors.primary, rot: 0.2, x: 3, y: 3, lines: ['> ANALYZING WORLD...', '> SYNCING MEMORY...', '> WAITING FOR INPUT', '> SOUL ON BITCOIN'] }, + { title: 'AGENT STATUS', color: NEXUS.colors.gold, rot: 0.4, x: 6, y: 3, lines: ['> TIMMY: ● RUNNING', '> KIMI: ○ STANDBY', '> CLAUDE: ● ACTIVE', '> PERPLEXITY: ○'] }, + ]; + + panelData.forEach(data => { + createTerminalPanel(terminalGroup, data.x, data.y, data.rot, data.title, data.color, data.lines); }); - // Left panel — Dev Items - createHoloPanel(termGroup, { - x: -6, y: 3.5, z: 1, w: 4, h: 4, rotY: 0.3, - title: '⚡ DEV QUEUE', - lines: [ - '#1090 Nexus v1 Build', - '#1079 Code Hygiene Epic', - '#1080 Showcase Epic', - '#864 PR Pending Merge', - '#1076 Deep Triage Gov.', - '', - 'Open Issues: 293', - 'Closed Today: 19', - ], - color: NEXUS.colors.secondary, - }); - - // Right panel — Metrics - createHoloPanel(termGroup, { - x: 6, y: 3.5, z: 1, w: 4, h: 4, rotY: -0.3, - title: '📊 METRICS', - lines: [ - 'Uptime: 23d 14h 22m', - 'Commits: 1,847', - 'Agents: 5 active', - 'Worlds: 1 (Nexus)', - 'Portals: 1 staging', - '', - 'CPU: ████████░░ 78%', - 'MEM: ██████░░░░ 62%', - ], - color: 0x44aaff, - }); - - // Far left — Thought Stream - createHoloPanel(termGroup, { - x: -10, y: 2.5, z: 3, w: 3.5, h: 3, rotY: 0.5, - title: '💭 THOUGHTS', - lines: [ - 'Considering portal arch.', - 'Morrowind integration is', - 'next priority after the', - 'Nexus shell is stable.', - '', - 'The harness is the core', - 'product. Focus there.', - ], - color: NEXUS.colors.gold, - }); - - // Far right — Agents - createHoloPanel(termGroup, { - x: 10, y: 2.5, z: 3, w: 3.5, h: 3, rotY: -0.5, - title: '🤖 AGENTS', - lines: [ - 'Claude Code ● ACTIVE', - 'Kimi ● ACTIVE', - 'Gemini ○ STANDBY', - 'Hermes ● ACTIVE', - 'Perplexity ● ACTIVE', - ], - color: 0xff8844, - }); - - scene.add(termGroup); + scene.add(terminalGroup); } -function createHoloPanel(parent, opts) { - const { x, y, z, w, h, title, lines, color, rotY } = opts; +function createTerminalPanel(parent, x, y, rot, title, color, lines) { + const w = 2.8, h = 3.5; const group = new THREE.Group(); - group.position.set(x, y, z); - if (rotY) group.rotation.y = rotY; + group.position.set(x, y, 0); + group.rotation.y = rot; - // Background panel - const panelGeo = new THREE.PlaneGeometry(w, h); - const panelMat = new THREE.MeshBasicMaterial({ - color: 0x000815, - transparent: true, - opacity: 0.7, - side: THREE.DoubleSide, - }); - const panel = new THREE.Mesh(panelGeo, panelMat); - group.add(panel); - - // Border frame - const borderGeo = new THREE.EdgesGeometry(panelGeo); - const borderMat = new THREE.LineBasicMaterial({ - color: color, + // Panel background (glassy) + const bgGeo = new THREE.PlaneGeometry(w, h); + const bgMat = new THREE.MeshPhysicalMaterial({ + color: NEXUS.colors.panelBg, transparent: true, opacity: 0.6, + roughness: 0.1, + metalness: 0.5, + side: THREE.DoubleSide, }); - const border = new THREE.LineSegments(borderGeo, borderMat); + const bg = new THREE.Mesh(bgGeo, bgMat); + group.add(bg); + + // Border + const borderMat = new THREE.MeshBasicMaterial({ color: color, transparent: true, opacity: 0.3, side: THREE.DoubleSide }); + const border = new THREE.Mesh(new THREE.PlaneGeometry(w + 0.05, h + 0.05), borderMat); + border.position.z = -0.01; group.add(border); - // Text content via CanvasTexture + // Canvas for text const textCanvas = document.createElement('canvas'); + textCanvas.width = 512; + textCanvas.height = 640; const ctx = textCanvas.getContext('2d'); - const res = 512; - textCanvas.width = res * (w / h); - textCanvas.height = res; - ctx.fillStyle = 'transparent'; - ctx.clearRect(0, 0, textCanvas.width, textCanvas.height); - - // Title - const cHex = '#' + new THREE.Color(color).getHexString(); - ctx.font = 'bold 28px "JetBrains Mono", monospace'; - ctx.fillStyle = cHex; - ctx.fillText(title, 20, 40); - - // Separator - ctx.strokeStyle = cHex; - ctx.globalAlpha = 0.3; - ctx.beginPath(); - ctx.moveTo(20, 52); - ctx.lineTo(textCanvas.width - 20, 52); - ctx.stroke(); - ctx.globalAlpha = 1; + // Header + ctx.fillStyle = '#' + new THREE.Color(color).getHexString(); + ctx.font = 'bold 32px "Orbitron", sans-serif'; + ctx.fillText(title, 20, 45); + ctx.fillRect(20, 55, 472, 2); // Lines ctx.font = '20px "JetBrains Mono", monospace'; @@ -510,7 +408,7 @@ function createHoloPanel(parent, opts) { else if (line.includes('○ STANDBY')) fillColor = '#5a6a8a'; else if (line.includes('NOMINAL')) fillColor = '#4af0c0'; ctx.fillStyle = fillColor; - ctx.fillText(line, 20, 80 + i * 30); + ctx.fillText(line, 20, 100 + i * 40); }); const textTexture = new THREE.CanvasTexture(textCanvas); @@ -797,8 +695,6 @@ function createAmbientStructures() { color: NEXUS.colors.primary, emissive: NEXUS.colors.primary, emissiveIntensity: 0.5, - roughness: 0.3, - metalness: 0.7, }); const stone = new THREE.Mesh(geo, mat); stone.position.set(Math.cos(angle) * r, 5 + Math.sin(i * 1.3) * 1.5, Math.sin(angle) * r);