diff --git a/app.js b/app.js index 60689a0..2176054 100644 --- a/app.js +++ b/app.js @@ -115,6 +115,9 @@ function init() { setTimeout(() => { document.getElementById('loading-screen').remove(); }, 900); }, 600); + // Tower Log + initTowerLog(); + // Start loop requestAnimationFrame(gameLoop); } @@ -872,6 +875,124 @@ function addChatMessage(type, text) { container.scrollTop = container.scrollHeight; } +// ═══ TOWER LOG ═══ +const TOWER_LOG = { + maxEntries: 60, + open: true, + seedEvents: [ + { type: 'system', msg: 'Tower Log initialized — monitoring all systems' }, + { type: 'commit', msg: '⎇ feat: add procedural nebula skybox shader' }, + { type: 'commit', msg: '⎇ fix: portal torus rotation clamping' }, + { type: 'agent', msg: '🤖 Kimi completed: nexus-v1 layout pass' }, + { type: 'training', msg: '⚙ Training cycle #14892 completed — loss 0.0031' }, + { type: 'merge', msg: '⬡ PR #47 merged: batcave terminal panels' }, + { type: 'visitor', msg: '👁 Visitor arrived: Alexander Whitestone' }, + { type: 'commit', msg: '⎇ chore: update README with architecture notes' }, + { type: 'agent', msg: '🤖 Claude Code completed: floor grid optimization' }, + { type: 'commit', msg: '⎇ feat: ambient crystal formations' }, + { type: 'training', msg: '⚙ Thought cycle #14893 — priority rebalance' }, + { type: 'merge', msg: '⬡ PR #48 merged: post-processing bloom pass' }, + ], + liveTemplates: { + commit: [ + '⎇ fix: resolve shader uniform timing drift', + '⎇ feat: add runestone float animation', + '⎇ refactor: extract portal swirl to helper', + '⎇ chore: bump three.js to 0.183', + '⎇ feat: dust particle emitter tuning', + '⎇ fix: memory leak in canvas texture disposal', + '⎇ feat: nexus core emissive pulse', + ], + merge: [ + '⬡ PR #49 merged: harness agent loop v2', + '⬡ PR #50 merged: world navigation scaffolding', + '⬡ PR #51 merged: WebSocket chat integration', + '⬡ PR #52 merged: tower log narrative feed', + ], + agent: [ + '🤖 Hermes: routed 7 new tasks to queue', + '🤖 Kimi completed: issue triage pass #204', + '🤖 Claude Code: opened PR for #11 tower log', + '🤖 Gemini: woke from standby — code review cycle', + '🤖 Perplexity: world snapshot saved', + ], + visitor: [ + '👁 Visitor arrived: Alexander Whitestone', + '👁 Visitor arrived: anonymous scout', + '👁 Observer detected in sector 7', + ], + training: [ + '⚙ Training cycle complete — model saved', + '⚙ Thought stream checkpoint written', + '⚙ Memory consolidation pass finished', + '⚙ Attention layer tuning: Δ0.0004', + ], + }, +}; + +function towerLogTimestamp() { + const d = new Date(); + return d.toTimeString().slice(0, 8); +} + +function addTowerEntry(type, msg) { + const container = document.getElementById('tower-log-entries'); + if (!container) return; + + const entry = document.createElement('div'); + entry.className = `tower-log-entry type-${type}`; + entry.innerHTML = + `${towerLogTimestamp()}` + + `${msg}`; + + // Prepend so newest is at top (column-reverse layout handles visual order) + container.appendChild(entry); + + // Trim old entries + while (container.children.length > TOWER_LOG.maxEntries) { + container.removeChild(container.firstChild); + } +} + +function initTowerLog() { + // Seed with historical events (oldest first) + TOWER_LOG.seedEvents.forEach(e => addTowerEntry(e.type, e.msg)); + + // Toggle collapse + document.getElementById('tower-log-toggle')?.addEventListener('click', () => { + TOWER_LOG.open = !TOWER_LOG.open; + document.getElementById('tower-log').classList.toggle('collapsed', !TOWER_LOG.open); + }); + + // Schedule live events + scheduleLiveEvents(); +} + +function scheduleLiveEvents() { + const types = Object.keys(TOWER_LOG.liveTemplates); + // Weights: commits most frequent, visitors rare + const weighted = [ + ...Array(5).fill('commit'), + ...Array(2).fill('agent'), + ...Array(2).fill('training'), + ...Array(1).fill('merge'), + ...Array(1).fill('visitor'), + ]; + + function fireNext() { + const type = weighted[Math.floor(Math.random() * weighted.length)]; + const msgs = TOWER_LOG.liveTemplates[type]; + const msg = msgs[Math.floor(Math.random() * msgs.length)]; + addTowerEntry(type, msg); + // Next event in 8–25 seconds + const delay = 8000 + Math.random() * 17000; + setTimeout(fireNext, delay); + } + + // First live event after 5–10s + setTimeout(fireNext, 5000 + Math.random() * 5000); +} + // ═══ GAME LOOP ═══ function gameLoop() { requestAnimationFrame(gameLoop); diff --git a/index.html b/index.html index 3a2c6ea..7b6bd99 100644 --- a/index.html +++ b/index.html @@ -95,6 +95,16 @@ + +