diff --git a/app.js b/app.js
index 3abfd71..0a757f9 100644
--- a/app.js
+++ b/app.js
@@ -76,6 +76,473 @@ 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();
+ }
+ }
+}
+
+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);
+ 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();
+ metaLayer.reflect();
+
+ // Simulate calibration update
+ calibrator.update({ input_tokens: 100, complexity_score: 0.5 }, 0.06);
+ }
+
+ metaLayer.track(startTime);
+}
+
async function init() {
clock = new THREE.Clock();
playerPos = new THREE.Vector3(0, 2, 12);
@@ -95,6 +562,7 @@ 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);
diff --git a/index.html b/index.html
index 39eb7d1..5ea207e 100644
--- a/index.html
+++ b/index.html
@@ -65,6 +65,38 @@
+
+
+
diff --git a/style.css b/style.css
index 2ad3a5f..5594850 100644
--- a/style.css
+++ b/style.css
@@ -977,3 +977,68 @@ canvas#nexus-canvas {
font-size: var(--text-xl);
}
}
+
+/* === GOFAI HUD STYLING === */
+.gofai-hud {
+ position: fixed;
+ left: 20px;
+ top: 80px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ pointer-events: none;
+ z-index: 100;
+}
+
+.hud-panel {
+ width: 280px;
+ background: rgba(5, 5, 16, 0.8);
+ border: 1px solid rgba(74, 240, 192, 0.2);
+ border-left: 3px solid #4af0c0;
+ padding: 8px;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 11px;
+ color: #e0f0ff;
+ pointer-events: auto;
+}
+
+.panel-header {
+ font-size: 10px;
+ font-weight: 700;
+ color: #4af0c0;
+ margin-bottom: 6px;
+ letter-spacing: 1px;
+ border-bottom: 1px solid rgba(74, 240, 192, 0.1);
+ padding-bottom: 2px;
+}
+
+.panel-content {
+ max-height: 120px;
+ overflow-y: auto;
+}
+
+.symbolic-log-entry { margin-bottom: 4px; border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 2px; }
+.symbolic-rule { color: #7b5cff; display: block; }
+.symbolic-outcome { color: #4af0c0; font-weight: 600; }
+
+.blackboard-entry { font-size: 10px; margin-bottom: 2px; }
+.bb-source { color: #ffd700; opacity: 0.7; }
+.bb-key { color: #7b5cff; }
+.bb-value { color: #fff; }
+
+.planner-step { color: #4af0c0; margin-bottom: 2px; }
+.step-num { opacity: 0.5; }
+
+.cbr-match { color: #ffd700; font-weight: 700; margin-bottom: 2px; }
+.cbr-action { color: #4af0c0; }
+
+.neuro-bridge-entry { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
+.neuro-icon { font-size: 14px; }
+.neuro-concept { color: #7b5cff; font-weight: 600; }
+
+.meta-stat { margin-bottom: 2px; display: flex; justify-content: space-between; }
+
+.calibrator-entry { font-size: 10px; display: flex; gap: 8px; }
+.cal-label { color: #ffd700; }
+.cal-val { color: #4af0c0; }
+.cal-err { color: #ff4466; opacity: 0.8; }