Files
the-nexus/modules/dual-brain.js
Alexander Whitestone cbfacdfe19
Some checks failed
Deploy Nexus / deploy (push) Failing after 3s
Staging Smoke Test / smoke-test (push) Successful in 1s
refactor: split app.js (5416 lines) into 21 modules — hard cap 1000 lines/file
app.js: 5416 → 528 lines (entry point, animation loop, event wiring)
modules/state.js: shared mutable state object
modules/constants.js: color palette
modules/matrix-rain.js: matrix rain canvas effect
modules/scene-setup.js: scene, camera, renderer, lighting, stars
modules/platform.js: glass platform, perlin noise, floating island, clouds
modules/heatmap.js: commit heatmap
modules/sigil.js: Timmy sigil
modules/controls.js: mouse, overview, zoom, photo mode
modules/effects.js: energy beam, sovereignty meter, rune ring
modules/earth.js: holographic earth
modules/warp.js: warp tunnel, crystals, lightning
modules/dual-brain.js: dual-brain holographic panel
modules/audio.js: Web Audio, spatial, portal hums
modules/debug.js: debug mode, websocket, session export
modules/celebrations.js: easter egg, shockwave, fireworks
modules/portals.js: portal loading
modules/bookshelves.js: floating bookshelves, spine textures
modules/oath.js: The Oath interactive SOUL.md
modules/panels.js: agent status board, LoRA panel
modules/weather.js: weather system, portal health
modules/extras.js: gravity zones, speech, timelapse, bitcoin

Largest file: 528 lines (app.js). No file exceeds 1000.
All files pass node --check. No refactoring — mechanical split only.
2026-03-24 15:12:22 -04:00

206 lines
6.4 KiB
JavaScript

// === DUAL-BRAIN HOLOGRAPHIC PANEL ===
import * as THREE from 'three';
import { NEXUS } from './constants.js';
import { scene } from './scene-setup.js';
const DUAL_BRAIN_ORIGIN = new THREE.Vector3(10, 3, -8);
export const dualBrainGroup = new THREE.Group();
dualBrainGroup.position.copy(DUAL_BRAIN_ORIGIN);
dualBrainGroup.lookAt(0, 3, 0);
scene.add(dualBrainGroup);
function createDualBrainTexture() {
const W = 512, H = 512;
const canvas = document.createElement('canvas');
canvas.width = W;
canvas.height = H;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(0, 6, 20, 0.90)';
ctx.fillRect(0, 0, W, H);
ctx.strokeStyle = '#4488ff';
ctx.lineWidth = 2;
ctx.strokeRect(1, 1, W - 2, H - 2);
ctx.strokeStyle = '#223366';
ctx.lineWidth = 1;
ctx.strokeRect(5, 5, W - 10, H - 10);
ctx.font = 'bold 22px "Courier New", monospace';
ctx.fillStyle = '#88ccff';
ctx.textAlign = 'center';
ctx.fillText('\u25C8 DUAL-BRAIN STATUS', W / 2, 40);
ctx.strokeStyle = '#1a3a6a';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(20, 52);
ctx.lineTo(W - 20, 52);
ctx.stroke();
ctx.font = '11px "Courier New", monospace';
ctx.fillStyle = '#556688';
ctx.textAlign = 'left';
ctx.fillText('BRAIN GAP SCORECARD', 20, 74);
const categories = [
{ name: 'Triage' },
{ name: 'Tool Use' },
{ name: 'Code Gen' },
{ name: 'Planning' },
{ name: 'Communication' },
{ name: 'Reasoning' },
];
const barX = 20;
const barW = W - 130;
const barH = 20;
let y = 90;
for (const cat of categories) {
ctx.font = '13px "Courier New", monospace';
ctx.fillStyle = '#445566';
ctx.textAlign = 'left';
ctx.fillText(cat.name, barX, y + 14);
ctx.font = 'bold 13px "Courier New", monospace';
ctx.fillStyle = '#334466';
ctx.textAlign = 'right';
ctx.fillText('\u2014', W - 20, y + 14);
y += 22;
ctx.fillStyle = 'rgba(255, 255, 255, 0.06)';
ctx.fillRect(barX, y, barW, barH);
y += barH + 12;
}
ctx.strokeStyle = '#1a3a6a';
ctx.beginPath();
ctx.moveTo(20, y + 4);
ctx.lineTo(W - 20, y + 4);
ctx.stroke();
y += 22;
ctx.font = 'bold 18px "Courier New", monospace';
ctx.fillStyle = '#334466';
ctx.textAlign = 'center';
ctx.fillText('AWAITING DEPLOYMENT', W / 2, y + 10);
ctx.font = '11px "Courier New", monospace';
ctx.fillStyle = '#223344';
ctx.fillText('Dual-brain system not yet connected', W / 2, y + 32);
y += 52;
ctx.beginPath();
ctx.arc(W / 2 - 60, y + 8, 6, 0, Math.PI * 2);
ctx.fillStyle = '#334466';
ctx.fill();
ctx.font = '11px "Courier New", monospace';
ctx.fillStyle = '#334466';
ctx.textAlign = 'left';
ctx.fillText('CLOUD', W / 2 - 48, y + 12);
ctx.beginPath();
ctx.arc(W / 2 + 30, y + 8, 6, 0, Math.PI * 2);
ctx.fillStyle = '#334466';
ctx.fill();
ctx.fillStyle = '#334466';
ctx.fillText('LOCAL', W / 2 + 42, y + 12);
return new THREE.CanvasTexture(canvas);
}
const dualBrainTexture = createDualBrainTexture();
const dualBrainMaterial = new THREE.SpriteMaterial({
map: dualBrainTexture, transparent: true, opacity: 0.92, depthWrite: false,
});
export const dualBrainSprite = new THREE.Sprite(dualBrainMaterial);
dualBrainSprite.scale.set(5.0, 5.0, 1);
dualBrainSprite.position.set(0, 0, 0);
dualBrainSprite.userData = {
baseY: 0, floatPhase: 0, floatSpeed: 0.22, zoomLabel: 'Dual-Brain Status',
};
dualBrainGroup.add(dualBrainSprite);
export const dualBrainLight = new THREE.PointLight(0x4488ff, 0.6, 10);
dualBrainLight.position.set(0, 0.5, 1);
dualBrainGroup.add(dualBrainLight);
// Brain Orbs
const CLOUD_ORB_COLOR = 0x334466;
const cloudOrbGeo = new THREE.SphereGeometry(0.35, 32, 32);
export const cloudOrbMat = new THREE.MeshStandardMaterial({
color: CLOUD_ORB_COLOR,
emissive: new THREE.Color(CLOUD_ORB_COLOR),
emissiveIntensity: 0.1, metalness: 0.3, roughness: 0.2,
transparent: true, opacity: 0.85,
});
export const cloudOrb = new THREE.Mesh(cloudOrbGeo, cloudOrbMat);
cloudOrb.position.set(-2.0, 3.0, 0);
cloudOrb.userData.zoomLabel = 'Cloud Brain';
dualBrainGroup.add(cloudOrb);
export const cloudOrbLight = new THREE.PointLight(CLOUD_ORB_COLOR, 0.15, 5);
cloudOrbLight.position.copy(cloudOrb.position);
dualBrainGroup.add(cloudOrbLight);
const LOCAL_ORB_COLOR = 0x334466;
const localOrbGeo = new THREE.SphereGeometry(0.35, 32, 32);
export const localOrbMat = new THREE.MeshStandardMaterial({
color: LOCAL_ORB_COLOR,
emissive: new THREE.Color(LOCAL_ORB_COLOR),
emissiveIntensity: 0.1, metalness: 0.3, roughness: 0.2,
transparent: true, opacity: 0.85,
});
export const localOrb = new THREE.Mesh(localOrbGeo, localOrbMat);
localOrb.position.set(2.0, 3.0, 0);
localOrb.userData.zoomLabel = 'Local Brain';
dualBrainGroup.add(localOrb);
export const localOrbLight = new THREE.PointLight(LOCAL_ORB_COLOR, 0.15, 5);
localOrbLight.position.copy(localOrb.position);
dualBrainGroup.add(localOrbLight);
// Brain Pulse Particle Stream
export const BRAIN_PARTICLE_COUNT = 0;
const brainParticlePositions = new Float32Array(BRAIN_PARTICLE_COUNT * 3);
export const brainParticlePhases = new Float32Array(BRAIN_PARTICLE_COUNT);
export const brainParticleSpeeds = new Float32Array(BRAIN_PARTICLE_COUNT);
for (let i = 0; i < BRAIN_PARTICLE_COUNT; i++) {
brainParticlePhases[i] = Math.random();
brainParticleSpeeds[i] = 0.15 + Math.random() * 0.2;
brainParticlePositions[i * 3] = 0;
brainParticlePositions[i * 3 + 1] = 0;
brainParticlePositions[i * 3 + 2] = 0;
}
export const brainParticleGeo = new THREE.BufferGeometry();
brainParticleGeo.setAttribute('position', new THREE.BufferAttribute(brainParticlePositions, 3));
export const brainParticleMat = new THREE.PointsMaterial({
color: 0x44ddff, size: 0.08, sizeAttenuation: true,
transparent: true, opacity: 0.8, depthWrite: false,
});
const brainParticles = new THREE.Points(brainParticleGeo, brainParticleMat);
dualBrainGroup.add(brainParticles);
// Scanning line overlay
const _scanCanvas = document.createElement('canvas');
_scanCanvas.width = 512;
_scanCanvas.height = 512;
export const _scanCtx = _scanCanvas.getContext('2d');
export const dualBrainScanTexture = new THREE.CanvasTexture(_scanCanvas);
const dualBrainScanMat = new THREE.SpriteMaterial({
map: dualBrainScanTexture, transparent: true, opacity: 0.18, depthWrite: false,
});
export const dualBrainScanSprite = new THREE.Sprite(dualBrainScanMat);
dualBrainScanSprite.scale.set(5.0, 5.0, 1);
dualBrainScanSprite.position.set(0, 0, 0.01);
dualBrainGroup.add(dualBrainScanSprite);