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.
108 lines
3.1 KiB
JavaScript
108 lines
3.1 KiB
JavaScript
// === DEBUG MODE + WEBSOCKET + SESSION EXPORT ===
|
|
import * as THREE from 'three';
|
|
import { scene } from './scene-setup.js';
|
|
import { S } from './state.js';
|
|
|
|
// === DEBUG MODE ===
|
|
export function initDebug() {
|
|
document.getElementById('debug-toggle').addEventListener('click', () => {
|
|
S.debugMode = !S.debugMode;
|
|
document.getElementById('debug-toggle').style.backgroundColor = S.debugMode
|
|
? 'var(--color-text-muted)'
|
|
: 'var(--color-secondary)';
|
|
console.log(`Debug mode ${S.debugMode ? 'enabled' : 'disabled'}`);
|
|
|
|
if (S.debugMode) {
|
|
document.querySelectorAll('.collision-box').forEach((el) => el.style.outline = '2px solid red');
|
|
document.querySelectorAll('.light-source').forEach((el) => el.style.outline = '2px dashed yellow');
|
|
} else {
|
|
document.querySelectorAll('.collision-box, .light-source').forEach((el) => {
|
|
el.style.outline = 'none';
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
const DEBUG_MODE = false;
|
|
|
|
export function debugVisualize(sceneRef) {
|
|
if (!DEBUG_MODE) return;
|
|
sceneRef.traverse((object) => {
|
|
if (object.userData && object.userData.isCollidable) {
|
|
object.material = new THREE.MeshBasicMaterial({ color: 0xff00ff, wireframe: true });
|
|
}
|
|
});
|
|
sceneRef.traverse((object) => {
|
|
if (object instanceof THREE.Light) {
|
|
const helper = new THREE.LightHelper(object, 1, 0xffff00);
|
|
sceneRef.add(helper);
|
|
}
|
|
});
|
|
}
|
|
|
|
// === WEBSOCKET CLIENT ===
|
|
import { wsClient } from '../ws-client.js';
|
|
|
|
export { wsClient };
|
|
|
|
export function initWebSocket() {
|
|
wsClient.connect();
|
|
|
|
window.addEventListener('player-joined', (event) => {
|
|
console.log('Player joined:', event.detail);
|
|
});
|
|
|
|
window.addEventListener('player-left', (event) => {
|
|
console.log('Player left:', event.detail);
|
|
});
|
|
}
|
|
|
|
// === SESSION EXPORT ===
|
|
export const sessionLog = [];
|
|
const sessionStart = Date.now();
|
|
|
|
export function logMessage(speaker, text) {
|
|
sessionLog.push({ ts: Date.now(), speaker, text });
|
|
}
|
|
|
|
export function exportSessionAsMarkdown() {
|
|
const startStr = new Date(sessionStart).toISOString().replace('T', ' ').slice(0, 19) + ' UTC';
|
|
const lines = [
|
|
'# Nexus Session Export',
|
|
'',
|
|
`**Session started:** ${startStr}`,
|
|
`**Messages:** ${sessionLog.length}`,
|
|
'',
|
|
'---',
|
|
'',
|
|
];
|
|
|
|
for (const entry of sessionLog) {
|
|
const timeStr = new Date(entry.ts).toISOString().replace('T', ' ').slice(0, 19) + ' UTC';
|
|
lines.push(`### ${entry.speaker} — ${timeStr}`);
|
|
lines.push('');
|
|
lines.push(entry.text);
|
|
lines.push('');
|
|
}
|
|
|
|
if (sessionLog.length === 0) {
|
|
lines.push('*No messages recorded this session.*');
|
|
lines.push('');
|
|
}
|
|
|
|
const blob = new Blob([lines.join('\n')], { type: 'text/markdown' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = `nexus-session-${new Date(sessionStart).toISOString().slice(0, 10)}.md`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
export function initSessionExport() {
|
|
const exportBtn = document.getElementById('export-session');
|
|
if (exportBtn) {
|
|
exportBtn.addEventListener('click', exportSessionAsMarkdown);
|
|
}
|
|
}
|