[claude] Phase 1: Core Foundation — scene, ticker, theme, state (#410) #463
35
app.js
35
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.');
|
||||
|
||||
12
modules/core/scene.js
Normal file
12
modules/core/scene.js
Normal file
@@ -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';
|
||||
@@ -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',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user