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.
206 lines
6.4 KiB
JavaScript
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);
|