From eeeed16a9b232de2a2eb5ebbd0e8ab60c816abb7 Mon Sep 17 00:00:00 2001 From: Google AI Agent Date: Mon, 30 Mar 2026 16:07:20 +0000 Subject: [PATCH] chore: update app.js from workspace --- app.js | 796 +-------------------------------------------------------- 1 file changed, 6 insertions(+), 790 deletions(-) diff --git a/app.js b/app.js index 4147640..5a2bcaa 100644 --- a/app.js +++ b/app.js @@ -35,7 +35,6 @@ let activePortal = null; // Portal currently in proximity let activeVisionPoint = null; // Vision point currently in proximity let portalOverlayActive = false; let visionOverlayActive = false; -let atlasOverlayActive = false; let thoughtStreamMesh; let harnessPulseMesh; let powerMeterBars = []; @@ -76,569 +75,6 @@ const orbitState = { let flyY = 2; // ═══ INIT ═══ - -// ═══ SOVEREIGN SYMBOLIC ENGINE (GOFAI) ═══ -class SymbolicEngine { - constructor() { - this.facts = new Map(); - this.factIndices = new Map(); - this.factMask = 0n; - this.rules = []; - this.reasoningLog = []; - } - - addFact(key, value) { - this.facts.set(key, value); - if (!this.factIndices.has(key)) { - this.factIndices.set(key, BigInt(this.factIndices.size)); - } - const bitIndex = this.factIndices.get(key); - if (value) { - this.factMask |= (1n << bitIndex); - } else { - this.factMask &= ~(1n << bitIndex); - } - } - - addRule(condition, action, description) { - this.rules.push({ condition, action, description }); - } - - reason() { - this.rules.forEach(rule => { - if (rule.condition(this.facts)) { - const result = rule.action(this.facts); - if (result) { - this.logReasoning(rule.description, result); - } - } - }); - } - - logReasoning(ruleDesc, outcome) { - const entry = { timestamp: Date.now(), rule: ruleDesc, outcome: outcome }; - this.reasoningLog.unshift(entry); - if (this.reasoningLog.length > 5) this.reasoningLog.pop(); - - const container = document.getElementById('symbolic-log-content'); - if (container) { - const logDiv = document.createElement('div'); - logDiv.className = 'symbolic-log-entry'; - logDiv.innerHTML = `[RULE] ${ruleDesc}→ ${outcome}`; - container.prepend(logDiv); - if (container.children.length > 5) container.lastElementChild.remove(); - } - } -} - -class AgentFSM { - constructor(agentId, initialState) { - this.agentId = agentId; - this.state = initialState; - this.transitions = {}; - } - - addTransition(fromState, toState, condition) { - if (!this.transitions[fromState]) this.transitions[fromState] = []; - this.transitions[fromState].push({ toState, condition }); - } - - update(facts) { - const possibleTransitions = this.transitions[this.state] || []; - for (const transition of possibleTransitions) { - if (transition.condition(facts)) { - console.log(`[FSM] Agent ${this.agentId} transitioning: ${this.state} -> ${transition.toState}`); - this.state = transition.toState; - return true; - } - } - return false; - } -} - -class KnowledgeGraph { - constructor() { - this.nodes = new Map(); - this.edges = []; - } - - addNode(id, type, metadata = {}) { - this.nodes.set(id, { id, type, ...metadata }); - } - - addEdge(from, to, relation) { - this.edges.push({ from, to, relation }); - } - - query(from, relation) { - return this.edges - .filter(e => e.from === from && e.relation === relation) - .map(e => this.nodes.get(e.to)); - } -} - -class Blackboard { - constructor() { - this.data = {}; - this.subscribers = []; - } - - write(key, value, source) { - const oldValue = this.data[key]; - this.data[key] = value; - this.notify(key, value, oldValue, source); - } - - read(key) { return this.data[key]; } - - subscribe(callback) { this.subscribers.push(callback); } - - notify(key, value, oldValue, source) { - this.subscribers.forEach(sub => sub(key, value, oldValue, source)); - const container = document.getElementById('blackboard-log-content'); - if (container) { - const entry = document.createElement('div'); - entry.className = 'blackboard-entry'; - entry.innerHTML = `[${source}] ${key}: ${JSON.stringify(value)}`; - container.prepend(entry); - if (container.children.length > 8) container.lastElementChild.remove(); - } - } -} - -class SymbolicPlanner { - constructor() { - this.actions = []; - this.currentPlan = []; - } - - addAction(name, preconditions, effects) { - this.actions.push({ name, preconditions, effects }); - } - - heuristic(state, goal) { - let h = 0; - for (let key in goal) { - if (state[key] !== goal[key]) { - h += Math.abs((state[key] || 0) - (goal[key] || 0)); - } - } - return h; - } - - findPlan(initialState, goalState) { - let openSet = [{ state: initialState, plan: [], g: 0, h: this.heuristic(initialState, goalState) }]; - let visited = new Map(); - visited.set(JSON.stringify(initialState), 0); - - while (openSet.length > 0) { - openSet.sort((a, b) => (a.g + a.h) - (b.g + b.h)); - let { state, plan, g } = openSet.shift(); - - if (this.isGoalReached(state, goalState)) return plan; - - for (let action of this.actions) { - if (this.arePreconditionsMet(state, action.preconditions)) { - let nextState = { ...state, ...action.effects }; - let stateStr = JSON.stringify(nextState); - let nextG = g + 1; - - if (!visited.has(stateStr) || nextG < visited.get(stateStr)) { - visited.set(stateStr, nextG); - openSet.push({ - state: nextState, - plan: [...plan, action.name], - g: nextG, - h: this.heuristic(nextState, goalState) - }); - } - } - } - } - return null; - } - - isGoalReached(state, goal) { - for (let key in goal) { - if (state[key] !== goal[key]) return false; - } - return true; - } - - arePreconditionsMet(state, preconditions) { - for (let key in preconditions) { - if (state[key] < preconditions[key]) return false; - } - return true; - } - - logPlan(plan) { - this.currentPlan = plan; - const container = document.getElementById('planner-log-content'); - if (container) { - container.innerHTML = ''; - if (!plan || plan.length === 0) { - container.innerHTML = '
NO ACTIVE PLAN
'; - return; - } - plan.forEach((step, i) => { - const div = document.createElement('div'); - div.className = 'planner-step'; - div.innerHTML = `${i+1}. ${step}`; - container.appendChild(div); - }); - } - } -} - -class HTNPlanner { - constructor() { - this.methods = {}; - this.primitiveTasks = {}; - } - - addMethod(taskName, preconditions, subtasks) { - if (!this.methods[taskName]) this.methods[taskName] = []; - this.methods[taskName].push({ preconditions, subtasks }); - } - - addPrimitiveTask(taskName, preconditions, effects) { - this.primitiveTasks[taskName] = { preconditions, effects }; - } - - findPlan(initialState, tasks) { - return this.decompose(initialState, tasks, []); - } - - decompose(state, tasks, plan) { - if (tasks.length === 0) return plan; - const [task, ...remainingTasks] = tasks; - if (this.primitiveTasks[task]) { - const { preconditions, effects } = this.primitiveTasks[task]; - if (this.arePreconditionsMet(state, preconditions)) { - const nextState = { ...state, ...effects }; - return this.decompose(nextState, remainingTasks, [...plan, task]); - } - return null; - } - const methods = this.methods[task] || []; - for (const method of methods) { - if (this.arePreconditionsMet(state, method.preconditions)) { - const result = this.decompose(state, [...method.subtasks, ...remainingTasks], plan); - if (result) return result; - } - } - return null; - } - - arePreconditionsMet(state, preconditions) { - for (const key in preconditions) { - if (state[key] < (preconditions[key] || 0)) return false; - } - return true; - } -} - -class CaseBasedReasoner { - constructor() { - this.caseLibrary = []; - } - - addCase(situation, action, outcome) { - this.caseLibrary.push({ situation, action, outcome, timestamp: Date.now() }); - } - - findSimilarCase(currentSituation) { - let bestMatch = null; - let maxSimilarity = -1; - this.caseLibrary.forEach(c => { - let similarity = this.calculateSimilarity(currentSituation, c.situation); - if (similarity > maxSimilarity) { - maxSimilarity = similarity; - bestMatch = c; - } - }); - return maxSimilarity > 0.7 ? bestMatch : null; - } - - calculateSimilarity(s1, s2) { - let score = 0, total = 0; - for (let key in s1) { - if (s2[key] !== undefined) { - score += 1 - Math.abs(s1[key] - s2[key]); - total += 1; - } - } - return total > 0 ? score / total : 0; - } - - logCase(c) { - const container = document.getElementById('cbr-log-content'); - if (container) { - const div = document.createElement('div'); - div.className = 'cbr-entry'; - div.innerHTML = ` -
SIMILAR CASE FOUND (${(this.calculateSimilarity(symbolicEngine.facts, c.situation) * 100).toFixed(0)}%)
-
SUGGESTED: ${c.action}
-
PREVIOUS OUTCOME: ${c.outcome}
- `; - container.prepend(div); - if (container.children.length > 3) container.lastElementChild.remove(); - } - } -} - -class NeuroSymbolicBridge { - constructor(symbolicEngine, blackboard) { - this.engine = symbolicEngine; - this.blackboard = blackboard; - this.perceptionLog = []; - } - - perceive(rawState) { - const concepts = []; - if (rawState.stability < 0.4 && rawState.energy > 60) concepts.push('UNSTABLE_OSCILLATION'); - if (rawState.energy < 30 && rawState.activePortals > 2) concepts.push('CRITICAL_DRAIN_PATTERN'); - concepts.forEach(concept => { - this.engine.addFact(concept, true); - this.logPerception(concept); - }); - return concepts; - } - - logPerception(concept) { - const container = document.getElementById('neuro-bridge-log-content'); - if (container) { - const div = document.createElement('div'); - div.className = 'neuro-bridge-entry'; - div.innerHTML = `🧠 ${concept}`; - container.prepend(div); - if (container.children.length > 5) container.lastElementChild.remove(); - } - } -} - -class MetaReasoningLayer { - constructor(planner, blackboard) { - this.planner = planner; - this.blackboard = blackboard; - this.reasoningCache = new Map(); - this.performanceMetrics = { totalReasoningTime: 0, calls: 0 }; - } - - getCachedPlan(stateKey) { - const cached = this.reasoningCache.get(stateKey); - if (cached && (Date.now() - cached.timestamp < 10000)) return cached.plan; - return null; - } - - cachePlan(stateKey, plan) { - this.reasoningCache.set(stateKey, { plan, timestamp: Date.now() }); - } - - reflect() { - const avgTime = this.performanceMetrics.totalReasoningTime / (this.performanceMetrics.calls || 1); - const container = document.getElementById('meta-log-content'); - if (container) { - container.innerHTML = ` -
CACHE SIZE: ${this.reasoningCache.size}
-
AVG LATENCY: ${avgTime.toFixed(2)}ms
-
STATUS: ${avgTime > 50 ? 'OPTIMIZING' : 'NOMINAL'}
- `; - } - } - - track(startTime) { - const duration = performance.now() - startTime; - this.performanceMetrics.totalReasoningTime += duration; - this.performanceMetrics.calls++; - } -} - -// ═══ ADAPTIVE CALIBRATOR (LOCAL EFFICIENCY) ═══ -class AdaptiveCalibrator { - constructor(modelId, initialParams) { - this.model = modelId; - this.weights = { - 'input_tokens': 0.0, - 'complexity_score': 0.0, - 'task_type_indicator': 0.0, - 'bias': initialParams.base_rate || 0.0 - }; - this.learningRate = 0.01; - this.history = []; - } - - predict(features) { - let prediction = this.weights['bias']; - for (let feature in features) { - if (this.weights[feature] !== undefined) { - prediction += this.weights[feature] * features[feature]; - } - } - return Math.max(0, prediction); - } - - update(features, actualCost) { - const predicted = this.predict(features); - const error = actualCost - predicted; - for (let feature in features) { - if (this.weights[feature] !== undefined) { - this.weights[feature] += this.learningRate * error * features[feature]; - } - } - this.history.push({ predicted, actual: actualCost, timestamp: Date.now() }); - - const container = document.getElementById('calibrator-log-content'); - if (container) { - const div = document.createElement('div'); - div.className = 'calibrator-entry'; - div.innerHTML = `CALIBRATED: ${predicted.toFixed(4)} ERR: ${error.toFixed(4)}`; - container.prepend(div); - if (container.children.length > 5) container.lastElementChild.remove(); - } - } -} - - -// ═══ NOSTR AGENT REGISTRATION ═══ -class NostrAgent { - constructor(pubkey) { - this.pubkey = pubkey; - this.relays = ['wss://relay.damus.io', 'wss://nos.lol']; - } - - async announce(metadata) { - console.log(`[NOSTR] Announcing agent ${this.pubkey}...`); - const event = { - kind: 0, - pubkey: this.pubkey, - created_at: Math.floor(Date.now() / 1000), - tags: [], - content: JSON.stringify(metadata), - id: 'mock_id', - sig: 'mock_sig' - }; - - this.relays.forEach(url => { - console.log(`[NOSTR] Publishing to ${url}: `, event); - }); - - const container = document.getElementById('nostr-log-content'); - if (container) { - const div = document.createElement('div'); - div.className = 'nostr-entry'; - div.innerHTML = `[${this.pubkey.substring(0,8)}...] ANNOUNCED`; - container.prepend(div); - } - } -} - -// ═══ L402 CLIENT LOGIC ═══ -class L402Client { - async fetchWithL402(url) { - console.log(`[L402] Fetching ${url}...`); - const response = await fetch(url); - - if (response.status === 402) { - const authHeader = response.headers.get('WWW-Authenticate'); - console.log(`[L402] Challenge received: ${authHeader}`); - - const container = document.getElementById('l402-log-content'); - if (container) { - const div = document.createElement('div'); - div.className = 'l402-entry'; - div.innerHTML = `CHALLENGE Payment Required`; - container.prepend(div); - } - return { status: 402, challenge: authHeader }; - } - - return response.json(); - } -} - -let nostrAgent, l402Client; - - -// ═══ PARALLEL SYMBOLIC EXECUTION (PSE) ═══ -class PSELayer { - constructor() { - this.worker = new Worker('gofai_worker.js'); - this.worker.onmessage = (e) => this.handleWorkerMessage(e); - this.pendingRequests = new Map(); - } - - handleWorkerMessage(e) { - const { type, results, plan } = e.data; - if (type === 'REASON_RESULT') { - results.forEach(res => symbolicEngine.logReasoning(res.rule, res.outcome)); - } else if (type === 'PLAN_RESULT') { - symbolicPlanner.logPlan(plan); - } - } - - offloadReasoning(facts, rules) { - this.worker.postMessage({ type: 'REASON', data: { facts, rules } }); - } - - offloadPlanning(initialState, goalState, actions) { - this.worker.postMessage({ type: 'PLAN', data: { initialState, goalState, actions } }); - } -} - -let pseLayer; - -let metaLayer, neuroBridge, cbr, symbolicPlanner, knowledgeGraph, blackboard, symbolicEngine, calibrator; -let agentFSMs = {}; - -function setupGOFAI() { - knowledgeGraph = new KnowledgeGraph(); - blackboard = new Blackboard(); - symbolicEngine = new SymbolicEngine(); - symbolicPlanner = new SymbolicPlanner(); - cbr = new CaseBasedReasoner(); - neuroBridge = new NeuroSymbolicBridge(symbolicEngine, blackboard); - metaLayer = new MetaReasoningLayer(symbolicPlanner, blackboard); - nostrAgent = new NostrAgent("npub1..."); - l402Client = new L402Client(); - nostrAgent.announce({ name: "Timmy Nexus Agent", capabilities: ["GOFAI", "L402"] }); - pseLayer = new PSELayer(); - calibrator = new AdaptiveCalibrator('nexus-v1', { base_rate: 0.05 }); - - // Setup initial facts - symbolicEngine.addFact('energy', 100); - symbolicEngine.addFact('stability', 1.0); - - // Setup FSM - agentFSMs['timmy'] = new AgentFSM('timmy', 'IDLE'); - agentFSMs['timmy'].addTransition('IDLE', 'ANALYZING', (facts) => facts.get('activePortals') > 0); - - // Setup Planner - symbolicPlanner.addAction('Stabilize Matrix', { energy: 50 }, { stability: 1.0 }); -} - -function updateGOFAI(delta, elapsed) { - const startTime = performance.now(); - - // Simulate perception - neuroBridge.perceive({ stability: 0.3, energy: 80, activePortals: 1 }); - - // Run reasoning - if (Math.floor(elapsed * 2) > Math.floor((elapsed - delta) * 2)) { - symbolicEngine.reason(); - pseLayer.offloadReasoning(Array.from(symbolicEngine.facts.entries()), symbolicEngine.rules.map(r => ({ description: r.description }))); - document.getElementById("pse-task-count").innerText = parseInt(document.getElementById("pse-task-count").innerText) + 1; - metaLayer.reflect(); - - // Simulate calibration update - calibrator.update({ input_tokens: 100, complexity_score: 0.5 }, 0.06); - if (Math.random() > 0.95) l402Client.fetchWithL402("http://localhost:8080/api/cost-estimate"); - } - - metaLayer.track(startTime); -} - async function init() { clock = new THREE.Clock(); playerPos = new THREE.Vector3(0, 2, 12); @@ -658,7 +94,6 @@ async function init() { scene = new THREE.Scene(); scene.fog = new THREE.FogExp2(0x050510, 0.012); - setupGOFAI(); camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.copy(playerPos); @@ -1512,91 +947,14 @@ function createPortal(config) { scene.add(group); - const portalObj = { + return { config, group, ring, swirl, pSystem, - light, - customElements: {} + light }; - - // ═══ DISTINCT VISUAL IDENTITIES ═══ - if (config.id === 'archive') { - // Floating Data Cubes - const cubes = []; - for (let i = 0; i < 6; i++) { - const cubeGeo = new THREE.BoxGeometry(0.4, 0.4, 0.4); - const cubeMat = new THREE.MeshStandardMaterial({ - color: portalColor, - emissive: portalColor, - emissiveIntensity: 1.5, - transparent: true, - opacity: 0.8 - }); - const cube = new THREE.Mesh(cubeGeo, cubeMat); - group.add(cube); - cubes.push(cube); - } - portalObj.customElements.cubes = cubes; - } else if (config.id === 'chapel') { - // Glowing Core + Halo - const coreGeo = new THREE.SphereGeometry(1.2, 32, 32); - const coreMat = new THREE.MeshPhysicalMaterial({ - color: 0xffffff, - emissive: portalColor, - emissiveIntensity: 2, - transparent: true, - opacity: 0.4, - transmission: 0.9, - thickness: 2 - }); - const core = new THREE.Mesh(coreGeo, coreMat); - core.position.y = 3.5; - group.add(core); - portalObj.customElements.core = core; - - const haloGeo = new THREE.TorusGeometry(3.5, 0.05, 16, 100); - const haloMat = new THREE.MeshBasicMaterial({ color: portalColor, transparent: true, opacity: 0.3 }); - const halo = new THREE.Mesh(haloGeo, haloMat); - halo.position.y = 3.5; - group.add(halo); - portalObj.customElements.halo = halo; - } else if (config.id === 'courtyard') { - // Double Rotating Rings - const outerRingGeo = new THREE.TorusGeometry(4.2, 0.1, 16, 80); - const outerRingMat = new THREE.MeshStandardMaterial({ - color: portalColor, - emissive: portalColor, - emissiveIntensity: 0.8, - transparent: true, - opacity: 0.5 - }); - const outerRing = new THREE.Mesh(outerRingGeo, outerRingMat); - outerRing.position.y = 3.5; - group.add(outerRing); - portalObj.customElements.outerRing = outerRing; - } else if (config.id === 'gate') { - // Spiky Monoliths - const spikes = []; - for (let i = 0; i < 8; i++) { - const spikeGeo = new THREE.ConeGeometry(0.2, 1.5, 4); - const spikeMat = new THREE.MeshStandardMaterial({ color: 0x111111, emissive: portalColor, emissiveIntensity: 0.5 }); - const spike = new THREE.Mesh(spikeGeo, spikeMat); - const angle = (i / 8) * Math.PI * 2; - spike.position.set(Math.cos(angle) * 3.5, 3.5 + Math.sin(angle) * 3.5, 0); - spike.rotation.z = angle + Math.PI / 2; - group.add(spike); - spikes.push(spike); - } - portalObj.customElements.spikes = spikes; - - // Darker Swirl - swirl.material.uniforms.uColor.value = new THREE.Color(0x220000); - } - - return portalObj; } // ═══ PARTICLES ═══ @@ -1800,14 +1158,10 @@ function setupControls() { input.focus(); } } - if (e.key.toLowerCase() === 'm' && document.activeElement !== document.getElementById('chat-input')) { - openPortalAtlas(); - } if (e.key === 'Escape') { document.getElementById('chat-input').blur(); if (portalOverlayActive) closePortalOverlay(); if (visionOverlayActive) closeVisionOverlay(); - if (atlasOverlayActive) closePortalAtlas(); } if (e.key.toLowerCase() === 'v' && document.activeElement !== document.getElementById('chat-input')) { cycleNavMode(); @@ -1876,44 +1230,18 @@ function setupControls() { chatOpen = !chatOpen; document.getElementById('chat-panel').classList.toggle('collapsed', !chatOpen); }); - document.getElementById('chat-send').addEventListener('click', () => sendChatMessage()); - - // Chat quick actions - document.getElementById('chat-quick-actions').addEventListener('click', (e) => { - const btn = e.target.closest('.quick-action-btn'); - if (!btn) return; - - const action = btn.dataset.action; - - switch(action) { - case 'status': - sendChatMessage("Timmy, what is the current system status?"); - break; - case 'agents': - sendChatMessage("Timmy, check on all active agents."); - break; - case 'portals': - openPortalAtlas(); - break; - case 'help': - sendChatMessage("Timmy, I need assistance with Nexus navigation."); - break; - } - }); + document.getElementById('chat-send').addEventListener('click', sendChatMessage); document.getElementById('portal-close-btn').addEventListener('click', closePortalOverlay); document.getElementById('vision-close-btn').addEventListener('click', closeVisionOverlay); - - document.getElementById('atlas-toggle-btn').addEventListener('click', openPortalAtlas); - document.getElementById('atlas-close-btn').addEventListener('click', closePortalAtlas); } -function sendChatMessage(overrideText = null) { +function sendChatMessage() { const input = document.getElementById('chat-input'); - const text = overrideText || input.value.trim(); + const text = input.value.trim(); if (!text) return; addChatMessage('user', text); - if (!overrideText) input.value = ''; + input.value = ''; setTimeout(() => { const responses = [ 'Processing your request through the harness...', @@ -2192,86 +1520,6 @@ function closeVisionOverlay() { document.getElementById('vision-overlay').style.display = 'none'; } -// ═══ PORTAL ATLAS ═══ -function openPortalAtlas() { - atlasOverlayActive = true; - document.getElementById('atlas-overlay').style.display = 'flex'; - populateAtlas(); -} - -function closePortalAtlas() { - atlasOverlayActive = false; - document.getElementById('atlas-overlay').style.display = 'none'; -} - -function populateAtlas() { - const grid = document.getElementById('atlas-grid'); - grid.innerHTML = ''; - - let onlineCount = 0; - let standbyCount = 0; - - portals.forEach(portal => { - const config = portal.config; - if (config.status === 'online') onlineCount++; - if (config.status === 'standby') standbyCount++; - - const card = document.createElement('div'); - card.className = 'atlas-card'; - card.style.setProperty('--portal-color', config.color); - - const statusClass = `status-${config.status || 'online'}`; - - card.innerHTML = ` -
-
${config.name}
-
${config.status || 'ONLINE'}
-
-
${config.description}
- - `; - - card.addEventListener('click', () => { - focusPortal(portal); - closePortalAtlas(); - }); - - grid.appendChild(card); - }); - - document.getElementById('atlas-online-count').textContent = onlineCount; - document.getElementById('atlas-standby-count').textContent = standbyCount; - - // Update Bannerlord HUD status - const bannerlord = portals.find(p => p.config.id === 'bannerlord'); - if (bannerlord) { - const statusEl = document.getElementById('bannerlord-status'); - statusEl.className = 'hud-status-item ' + (bannerlord.config.status || 'offline'); - } -} - -function focusPortal(portal) { - // Teleport player to a position in front of the portal - const offset = new THREE.Vector3(0, 0, 6).applyEuler(new THREE.Euler(0, portal.config.rotation?.y || 0, 0)); - playerPos.copy(portal.group.position).add(offset); - playerPos.y = 2; // Keep at eye level - - // Rotate player to face the portal - playerRot.y = (portal.config.rotation?.y || 0) + Math.PI; - playerRot.x = 0; - - addChatMessage('system', `Navigation focus: ${portal.config.name}`); - - // If in orbit mode, reset target - if (NAV_MODES[navModeIdx] === 'orbit') { - orbitState.target.copy(portal.group.position); - orbitState.target.y = 3.5; - } -} - // ═══ GAME LOOP ═══ let lastThoughtTime = 0; let pulseTimer = 0; @@ -2387,38 +1635,6 @@ function gameLoop() { } // Pulse light portal.light.intensity = 1.5 + Math.sin(elapsed * 2) * 0.5; - - // Custom animations for distinct identities - if (portal.config.id === 'archive' && portal.customElements.cubes) { - portal.customElements.cubes.forEach((cube, i) => { - cube.rotation.x += delta * (0.5 + i * 0.1); - cube.rotation.y += delta * (0.3 + i * 0.1); - const orbitSpeed = 0.5 + i * 0.2; - const orbitRadius = 4 + Math.sin(elapsed * 0.5 + i) * 0.5; - cube.position.x = Math.cos(elapsed * orbitSpeed + i) * orbitRadius; - cube.position.z = Math.sin(elapsed * orbitSpeed + i) * orbitRadius; - cube.position.y = 3.5 + Math.sin(elapsed * 1.2 + i) * 1.5; - }); - } - - if (portal.config.id === 'chapel' && portal.customElements.halo) { - portal.customElements.halo.rotation.z -= delta * 0.2; - portal.customElements.halo.scale.setScalar(1 + Math.sin(elapsed * 0.8) * 0.05); - portal.customElements.core.material.emissiveIntensity = 2 + Math.sin(elapsed * 3) * 1; - } - - if (portal.config.id === 'courtyard' && portal.customElements.outerRing) { - portal.customElements.outerRing.rotation.z -= delta * 0.5; - portal.customElements.outerRing.rotation.y = Math.cos(elapsed * 0.4) * 0.2; - } - - if (portal.config.id === 'gate' && portal.customElements.spikes) { - portal.customElements.spikes.forEach((spike, i) => { - const s = 1 + Math.sin(elapsed * 2 + i) * 0.2; - spike.scale.set(s, s, s); - }); - } - // Animate particles const positions = portal.pSystem.geometry.attributes.position.array; for (let i = 0; i < positions.length / 3; i++) {