Files
the-nexus/modules/core/ticker.js
Alexander Whitestone f0fe9d76b6
All checks were successful
CI / validate (pull_request) Successful in 6s
CI / auto-merge (pull_request) Successful in 2s
feat: Phase 3 — extract panel modules from app.js (Refs #422)
Create 6 panel modules under modules/panels/ plus supporting core
infrastructure (state.js, theme.js, ticker.js). Each panel:
  - Exports init(scene, state, theme) and update(elapsed, delta)
  - Uses NEXUS.theme for all colors/fonts (no inline hex codes)
  - Reads from state.js (no direct API calls)
  - Subscribes to ticker for animation

Panel modules:
  panels/heatmap.js       — Commit heatmap floor overlay (DATA-TETHERED)
  panels/agent-board.js   — Agent status holographic board (REAL)
  panels/dual-brain.js    — Dual-brain panel (HONEST-OFFLINE)
  panels/lora-panel.js    — LoRA adapter panel (HONEST-OFFLINE)
  panels/sovereignty.js   — Sovereignty meter arc gauge (REAL manual)
  panels/earth.js         — Holographic Earth, activity-tethered (DATA-TETHERED)

Core infrastructure (consumed by panels):
  core/state.js   — shared reactive data bus
  core/theme.js   — NEXUS.theme design system
  core/ticker.js  — single RAF loop + subscribe/unsubscribe API

All files pass `node --check`. app.js unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 14:21:33 -04:00

47 lines
1.1 KiB
JavaScript

// modules/core/ticker.js — Global Animation Clock
// Single requestAnimationFrame loop. All modules subscribe here.
// No module may call requestAnimationFrame directly.
import * as THREE from 'three';
const _clock = new THREE.Clock();
const _subscribers = [];
let _running = false;
let _elapsed = 0;
/**
* Subscribe a callback to the animation loop.
* @param {(elapsed: number, delta: number) => void} fn
*/
export function subscribe(fn) {
_subscribers.push(fn);
}
/**
* Unsubscribe a callback from the animation loop.
* @param {(elapsed: number, delta: number) => void} fn
*/
export function unsubscribe(fn) {
const idx = _subscribers.indexOf(fn);
if (idx !== -1) _subscribers.splice(idx, 1);
}
/** Start the animation loop. Called once by app.js after all modules are init'd. */
export function start() {
if (_running) return;
_running = true;
_tick();
}
function _tick() {
if (!_running) return;
requestAnimationFrame(_tick);
const delta = _clock.getDelta();
_elapsed += delta;
for (const fn of _subscribers) fn(_elapsed, delta);
}
/** Current elapsed time in seconds (read-only). */
export function elapsed() { return _elapsed; }