diff --git a/app.js b/app.js index d4d82d7..e59fa5a 100644 --- a/app.js +++ b/app.js @@ -1,9 +1,12 @@ // === THE NEXUS — Main Entry Point === +// Thin orchestrator: imports core modules, wires updates, starts the ticker. import * as THREE from 'three'; -import { S, Broadcaster } from './modules/state.js'; -import { NEXUS } from './modules/constants.js'; -import { scene, camera, renderer, composer } from './modules/scene-setup.js'; -import { clock, warpPass } from './modules/warp.js'; +import { scene, composer } from './modules/core/scene.js'; +import { subscribe, start } from './modules/core/ticker.js'; +import { NEXUS } from './modules/core/theme.js'; // eslint-disable-line no-unused-vars +import { state } from './modules/core/state.js'; // eslint-disable-line no-unused-vars +import { S } from './modules/state.js'; +import { warpPass } from './modules/warp.js'; import { nostr } from './modules/nostr.js'; import { createNostrPanelTexture } from './modules/nostr-panel.js'; @@ -17,13 +20,9 @@ nostrPanel.position.set(-6, 3.5, -7.5); nostrPanel.rotation.y = 0.4; scene.add(nostrPanel); -// === MAIN ANIMATION LOOP === -function animate() { - requestAnimationFrame(animate); - const delta = clock.getDelta(); - const elapsed = clock.elapsedTime; - - // Update Nostr UI periodically or on event +// === MAIN UPDATE — subscribed to the single RAF loop in ticker.js === +subscribe((elapsed, delta) => { + // Update Nostr UI periodically if (Math.random() > 0.95) { updateNostrUI(); nostrTexture.needsUpdate = true; @@ -35,8 +34,14 @@ function animate() { if (S.energyBeamPulse < 0) S.energyBeamPulse = 0; } - composer.render(); -} + // Warp pass time uniform + if (S.isWarping) { + warpPass.uniforms['time'].value = elapsed; + } -animate(); -console.log('Nexus Sovereign Node: NOSTR CONNECTED.'); + composer.render(); +}); + +// === START THE SINGLE RAF LOOP === +start(); +console.log('Nexus Sovereign Node: ONLINE.'); diff --git a/modules/core/scene.js b/modules/core/scene.js new file mode 100644 index 0000000..7e70d93 --- /dev/null +++ b/modules/core/scene.js @@ -0,0 +1,12 @@ +// modules/core/scene.js — Canonical scene exports +// Provides THREE.Scene, camera, renderer, OrbitControls, and resize handler +// for use by app.js and any module that needs scene primitives. +// +// Implementation detail: the actual objects live in ../scene-setup.js and +// ../controls.js until those modules are absorbed here in a later phase. + +export { scene, camera, renderer, raycaster, forwardVector, + ambientLight, overheadLight, + stars, starMaterial, constellationLines, + STAR_BASE_OPACITY, STAR_PEAK_OPACITY, STAR_PULSE_DECAY } from '../scene-setup.js'; +export { orbitControls, composer, bokehPass, exitZoom, WARP_DURATION } from '../controls.js'; diff --git a/modules/core/theme.js b/modules/core/theme.js index d8e1c5e..3dcdd0b 100644 --- a/modules/core/theme.js +++ b/modules/core/theme.js @@ -1,17 +1,78 @@ +// modules/core/theme.js — NEXUS visual constants +// Single source of truth for all colors, fonts, line weights, glow params. +// No module may use inline hex codes or hardcoded font strings. + +/** NEXUS — the canonical theme object used by all visual modules */ +export const NEXUS = { + /** Numeric hex colors for THREE.js materials */ + colors: { + bg: 0x000008, + starCore: 0xffffff, + starDim: 0x8899cc, + constellationLine: 0x334488, + constellationFade: 0x112244, + accent: 0x4488ff, + }, + + /** All canvas/CSS/string visual constants */ + theme: { + // Accent (hex number + CSS string pair) + accent: 0x4488ff, + accentStr: '#4488ff', + + // Panel surfaces + panelBg: '#0a1428', + panelText: '#4af0c0', + panelDim: '#7b9bbf', + panelVeryDim: '#3a5070', + panelBorderFaint: '#1a3050', + + // Agent status colors (CSS strings for canvas) + agentWorking: '#4af0c0', + agentIdle: '#7b5cff', + agentDormant: '#2a4060', + agentDormantHex: 0x2a4060, + agentDead: '#3a2040', + + // Sovereignty meter + sovereignHigh: '#4af0c0', + sovereignHighHex: 0x4af0c0, + sovereignMid: '#ffd700', + sovereignMidHex: 0xffd700, + sovereignLow: '#ff4444', + sovereignLowHex: 0xff4444, + + // Holographic earth + earthOcean: '#0a2040', + earthLand: '#1a4020', + earthAtm: '#204070', + earthGlow: '#4488ff', + + // LoRA panel + loraActive: '#4af0c0', + loraInactive: '#3a5070', + loraAccent: '#7b5cff', + + // Typography + fontMono: 'monospace', + }, +}; + +/** THEME — glass / text presets (kept for SovOS.js and other legacy consumers) */ export const THEME = { glass: { - color: 0x112244, - opacity: 0.35, - roughness: 0.05, - metalness: 0.1, + color: 0x112244, + opacity: 0.35, + roughness: 0.05, + metalness: 0.1, transmission: 0.95, - thickness: 0.8, - ior: 1.5 + thickness: 0.8, + ior: 1.5, }, text: { - primary: '#4af0c0', + primary: '#4af0c0', secondary: '#7b5cff', - white: '#ffffff', - dim: '#a0b8d0' - } + white: '#ffffff', + dim: '#a0b8d0', + }, }; diff --git a/modules/core/ticker.js b/modules/core/ticker.js index 333e2c3..ed4ae95 100644 --- a/modules/core/ticker.js +++ b/modules/core/ticker.js @@ -1,10 +1,31 @@ -export class Ticker { - constructor() { - this.callbacks = []; - } - subscribe(fn) { this.callbacks.push(fn); } - tick(delta, elapsed) { - this.callbacks.forEach(fn => fn(delta, elapsed)); - } +// modules/core/ticker.js — Global Animation Clock +// Single requestAnimationFrame loop. No module may call RAF directly. +// All modules subscribe their update(elapsed, delta) function here. +import * as THREE from 'three'; + +const _clock = new THREE.Clock(); +const _subs = []; + +/** Register an update function: fn(elapsed, delta) */ +export function subscribe(fn) { + if (!_subs.includes(fn)) _subs.push(fn); +} + +/** Remove a previously registered update function */ +export function unsubscribe(fn) { + const i = _subs.indexOf(fn); + if (i !== -1) _subs.splice(i, 1); +} + +function _tick() { + requestAnimationFrame(_tick); + const delta = _clock.getDelta(); + const elapsed = _clock.getElapsedTime(); + for (const fn of _subs) fn(elapsed, delta); +} + +/** Start the single RAF loop. Call once from app.js. */ +export function start() { + _clock.start(); + _tick(); } -export const globalTicker = new Ticker();