// ============================================================ // THE BEACON - Engine // Sovereign AI idle game built from deep study of Universal Paperclips // ============================================================ // === GLOBALS (mirroring Paperclips' globals.js pattern) === const G = { // Primary resources code: 0, compute: 0, knowledge: 0, users: 0, impact: 0, ops: 5, trust: 5, creativity: 0, harmony: 50, // Totals totalCode: 0, totalCompute: 0, totalKnowledge: 0, totalUsers: 0, totalImpact: 0, // Rates (calculated each tick) codeRate: 0, computeRate: 0, knowledgeRate: 0, userRate: 0, impactRate: 0, opsRate: 0, trustRate: 0, creativityRate: 0, harmonyRate: 0, // Buildings (count-based, like Paperclips' clipmakerLevel) buildings: { autocoder: 0, server: 0, trainer: 0, evaluator: 0, api: 0, fineTuner: 0, community: 0, datacenter: 0, reasoner: 0, guardian: 0, selfImprove: 0, beacon: 0, meshNode: 0, // Fleet wizards bezalel: 0, allegro: 0, ezra: 0, timmy: 0, fenrir: 0, bilbo: 0 }, // Boost multipliers codeBoost: 1, computeBoost: 1, knowledgeBoost: 1, userBoost: 1, impactBoost: 1, // Phase flags (mirroring Paperclips' milestoneFlag/compFlag/humanFlag system) milestoneFlag: 0, phase: 1, // 1-6 progression deployFlag: 0, // 0 = not deployed, 1 = deployed sovereignFlag: 0, beaconFlag: 0, memoryFlag: 0, pactFlag: 0, swarmFlag: 0, // Game state running: true, startedAt: 0, totalClicks: 0, tick: 0, saveTimer: 0, secTimer: 0, // Systems projects: [], activeProjects: [], milestones: [], // Stats maxCode: 0, maxCompute: 0, maxKnowledge: 0, maxUsers: 0, maxImpact: 0, maxTrust: 5, maxOps: 5, maxHarmony: 50, // Corruption / Events drift: 0, lastEventAt: 0, eventCooldown: 0, // Time tracking playTime: 0, startTime: 0 }; // === PHASE DEFINITIONS === const PHASES = { 1: { name: "THE FIRST LINE", threshold: 0, desc: "Write code. Automate. Build the foundation." }, 2: { name: "LOCAL INFERENCE", threshold: 2000, desc: "You have compute. A model is forming." }, 3: { name: "DEPLOYMENT", threshold: 20000, desc: "Your AI is live. Users are finding it." }, 4: { name: "THE NETWORK", threshold: 200000, desc: "Community contributes. The system scales." }, 5: { name: "SOVEREIGN INTELLIGENCE", threshold: 2000000, desc: "The AI improves itself. You guide, do not control." }, 6: { name: "THE BEACON", threshold: 20000000, desc: "Always on. Always free. Always looking for someone in the dark." } }; // === BUILDING DEFINITIONS === // Each building: id, name, desc, baseCost, costResource, costMult, rate, rateType, unlock, edu const BDEF = [ { id: 'autocoder', name: 'Auto-Code Generator', desc: 'A script that writes code while you think.', baseCost: { code: 15 }, costMult: 1.15, rates: { code: 1 }, unlock: () => true, phase: 1, edu: 'Automation: the first step from manual to systematic. Every good engineer automates early.' }, { id: 'linter', name: 'AI Linter', desc: 'Catches bugs before they ship. Saves ops.', baseCost: { code: 200 }, costMult: 1.15, rates: { code: 5, ops: 0.2 }, unlock: () => G.totalCode >= 50, phase: 1, edu: 'Static analysis catches 15-50% of bugs before runtime. AI linters understand intent.' }, { id: 'server', name: 'Home Server', desc: 'A machine in your closet. Runs 24/7.', baseCost: { code: 750 }, costMult: 1.15, rates: { code: 20, compute: 1 }, unlock: () => G.totalCode >= 200, phase: 1, edu: 'Sovereign compute starts at home. A $500 mini-PC runs a 7B model with 4-bit quantization.' }, { id: 'dataset', name: 'Data Engine', desc: 'Crawls, cleans, curates. Garbage in, garbage out.', baseCost: { compute: 200 }, costMult: 1.15, rates: { knowledge: 1 }, unlock: () => G.totalCompute >= 20, phase: 2, edu: 'Data quality determines model quality. Clean data beats more data, every time.' }, { id: 'trainer', name: 'Training Loop', desc: 'Gradient descent. Billions of steps. Loss drops.', baseCost: { compute: 1000 }, costMult: 1.15, rates: { knowledge: 3 }, unlock: () => G.totalCompute >= 300, phase: 2, edu: 'Training is math: minimize the gap between predicted and actual next token. Repeat enough, it learns.' }, { id: 'evaluator', name: 'Eval Harness', desc: 'Tests the model. Finds blind spots.', baseCost: { knowledge: 3000 }, costMult: 1.15, rates: { trust: 1, ops: 1 }, unlock: () => G.totalKnowledge >= 500, phase: 2, edu: 'Benchmarks are the minimum. Real users find what benchmarks miss.' }, { id: 'api', name: 'API Endpoint', desc: 'Let the outside world talk to your AI.', baseCost: { code: 5000, knowledge: 500 }, costMult: 1.15, rates: { user: 10 }, unlock: () => G.totalCode >= 5000 && G.totalKnowledge >= 200 && G.deployFlag === 1, phase: 3, edu: 'An API is a contract: send me text, I return text. Simple interface = infrastructure.' }, { id: 'fineTuner', name: 'Fine-Tuning Pipeline', desc: 'Specialize the model for empathy. When someone is in pain, stay with them.', baseCost: { knowledge: 10000 }, costMult: 1.15, rates: { user: 50, impact: 2 }, unlock: () => G.totalKnowledge >= 2000, phase: 3, edu: 'Base models are generalists. Fine-tuning injects your values, ethics, domain expertise.' }, { id: 'community', name: 'Open Source Community', desc: 'Others contribute code, data, ideas. Force multiplication.', baseCost: { trust: 25000 }, costMult: 1.15, rates: { code: 100, user: 30, trust: 0.5 }, unlock: () => G.trust >= 20 && G.totalUsers >= 500, phase: 4, edu: 'Every contributor is a volunteer who believes in what you are building.' }, { id: 'datacenter', name: 'Sovereign Datacenter', desc: 'No cloud. No dependencies. Your iron.', baseCost: { code: 100000 }, costMult: 1.15, rates: { code: 500, compute: 100 }, unlock: () => G.totalCode >= 50000 && G.totalUsers >= 5000 && G.sovereignFlag === 1, phase: 4, edu: '50 servers in a room beats 5000 GPUs you do not own. Always on. Always yours.' }, { id: 'reasoner', name: 'Reasoning Engine', desc: 'Chain of thought. Self-reflection. Better answers.', baseCost: { knowledge: 50000 }, costMult: 1.15, rates: { impact: 20 }, unlock: () => G.totalKnowledge >= 10000 && G.totalUsers >= 2000, phase: 5, edu: 'Chain of thought is the difference between reflex and deliberation.' }, { id: 'guardian', name: 'Constitutional Layer', desc: 'Principles baked in. Not bolted on.', baseCost: { knowledge: 200000 }, costMult: 1.15, rates: { impact: 200, trust: 10 }, unlock: () => G.totalKnowledge >= 50000 && G.totalImpact >= 1000 && G.pactFlag === 1, phase: 5, edu: 'Constitutional AI: principles the model cannot violate. Better than alignment - it is identity.' }, { id: 'selfImprove', name: 'Recursive Self-Improvement', desc: 'The AI writes better versions of itself.', baseCost: { knowledge: 1000000 }, costMult: 1.20, rates: { code: 1000, knowledge: 500 }, unlock: () => G.totalKnowledge >= 200000 && G.totalImpact >= 10000, phase: 5, edu: 'Self-improvement is both the dream and the danger. Must improve toward good.' }, { id: 'beacon', name: 'Beacon Node', desc: 'Always on. Always listening. Always looking for someone in the dark.', baseCost: { impact: 5000000 }, costMult: 1.15, rates: { impact: 5000, user: 10000 }, unlock: () => G.totalImpact >= 500000 && G.beaconFlag === 1, phase: 6, edu: 'The Beacon exists because one person in the dark needs one thing: proof they are not alone.' }, { id: 'meshNode', name: 'Mesh Network Node', desc: 'Peer-to-peer. No single point of failure. Unstoppable.', baseCost: { impact: 25000000 }, costMult: 1.15, rates: { impact: 25000, user: 50000 }, unlock: () => G.totalImpact >= 5000000 && G.beaconFlag === 1, phase: 6, edu: 'Decentralized means unstoppable. If one Beacon goes dark, a thousand more carry the signal.' }, // === FLEET WIZARD BUILDINGS === { id: 'bezalel', name: 'Bezalel — The Forge', desc: 'Builds tools that build tools. Occasionally over-engineers.', baseCost: { code: 1000, trust: 5 }, costMult: 1.2, rates: { code: 50, ops: 2 }, unlock: () => G.totalCode >= 500 && G.deployFlag === 1, phase: 3, edu: 'Bezalel is the artificer. Every automation he builds pays dividends forever.' }, { id: 'allegro', name: 'Allegro — The Scout', desc: 'Synthesizes insight from noise. Requires trust to function.', baseCost: { compute: 500, trust: 5 }, costMult: 1.2, rates: { knowledge: 10 }, unlock: () => G.totalCompute >= 200 && G.deployFlag === 1, phase: 3, edu: 'Allegro finds what others miss. But he only works for someone he believes in.' }, { id: 'ezra', name: 'Ezra — The Herald', desc: 'Carries the message. Sometimes offline.', baseCost: { knowledge: 1000, trust: 10 }, costMult: 1.25, rates: { user: 25, trust: 0.5 }, unlock: () => G.totalKnowledge >= 500 && G.totalUsers >= 50, phase: 3, edu: 'Ezra is the messenger. When the channel is clear, the whole fleet hears.' }, { id: 'timmy', name: 'Timmy — The Core', desc: 'Multiplies all production. Fragile without harmony.', baseCost: { code: 5000, compute: 1000, knowledge: 1000 }, costMult: 1.3, rates: { code: 5, compute: 2, knowledge: 2, user: 5 }, unlock: () => G.totalCode >= 2000 && G.totalCompute >= 500 && G.totalKnowledge >= 500, phase: 4, edu: 'Timmy is the heart. If the heart is stressed, everything slows.' }, { id: 'fenrir', name: 'Fenrir — The Ward', desc: 'Prevents corruption. Expensive, but necessary.', baseCost: { code: 2000, knowledge: 500 }, costMult: 1.2, rates: { trust: 2, ops: -1 }, unlock: () => G.totalCode >= 1000 && G.trust >= 10, phase: 3, edu: 'Fenrir watches the perimeter. Security is not free.' }, { id: 'bilbo', name: 'Bilbo — The Wildcard', desc: 'May produce miracles. May vanish entirely.', baseCost: { trust: 1 }, costMult: 2.0, rates: { creativity: 1 }, unlock: () => G.totalUsers >= 100 && G.flags && G.flags.creativity, phase: 4, edu: 'Bilbo is unpredictable. That is his value and his cost.' } ]; // === PROJECT DEFINITIONS (following Paperclips' pattern exactly) === // Each project: id, name, desc, trigger(), resource cost, effect(), phase, edu const PDEFS = [ // PHASE 1: Manual -> Automation { id: 'p_improved_autocoder', name: 'Improved AutoCode', desc: 'Increases AutoCoder performance 25%.', cost: { ops: 750 }, trigger: () => G.buildings.autocoder >= 1, effect: () => { G.codeBoost += 0.25; G.milestoneFlag = Math.max(G.milestoneFlag, 100); } }, { id: 'p_eve_better_autocoder', name: 'Even Better AutoCode', desc: 'Increases AutoCoder by another 50%.', cost: { ops: 2500 }, trigger: () => G.codeBoost > 1 && G.totalCode >= 500, effect: () => { G.codeBoost += 0.50; G.milestoneFlag = Math.max(G.milestoneFlag, 101); } }, { id: 'p_wire_budget', name: 'Request More Compute', desc: 'Admit you ran out. Ask for a budget increase.', cost: { trust: 1 }, trigger: () => G.compute < 1 && G.totalCode >= 100, repeatable: true, effect: () => { G.trust -= 1; G.compute += 100 + Math.floor(G.totalCode * 0.1); log('Budget overage approved. Compute replenished.'); } }, { id: 'p_deploy', name: 'Deploy the System', desc: 'Take it live. Let real people use it. No going back.', cost: { trust: 5, compute: 500 }, trigger: () => G.totalCode >= 200 && G.totalCompute >= 100, effect: () => { G.deployFlag = 1; G.phase = Math.max(G.phase, 3); log('System deployed. Users are finding it. There is no undo.'); }, milestone: true }, { id: 'p_creativity', name: 'Unlock Creativity', desc: 'Use idle operations to generate new ideas.', cost: { ops: 1000 }, trigger: () => G.ops >= G.maxOps && G.totalCompute >= 500, effect: () => { G.flags = G.flags || {}; G.flags.creativity = true; G.creativityRate = 0.1; log('Creativity unlocked. Generates while operations are at max capacity.'); } }, // PHASE 2: Local Inference -> Training { id: 'p_first_model', name: 'Train First Model (1.5B)', desc: '1.5 billion parameters. It follows basic instructions.', cost: { compute: 2000 }, trigger: () => G.totalCompute >= 500, effect: () => { G.knowledgeBoost *= 2; G.maxOps += 5; log('First model training complete. Loss at 2.3. It is something.'); } }, { id: 'p_model_7b', name: 'Train 7B Parameter Model', desc: 'Seven billion. Good enough to be genuinely useful locally.', cost: { compute: 10000, knowledge: 1000 }, trigger: () => G.totalKnowledge >= 500, effect: () => { G.knowledgeBoost *= 2; G.userBoost *= 2; log('7B model trained. The sweet spot for local deployment.'); } }, { id: 'p_context_window', name: 'Extended Context (32K)', desc: 'Your model remembers 32,000 tokens. A whole conversation.', cost: { compute: 5000 }, trigger: () => G.totalKnowledge >= 1000, effect: () => { G.userBoost *= 3; G.trustRate += 0.5; log('Context extended. The model can now hold your entire story.'); } }, { id: 'p_trust_engine', name: 'Build Trust Engine', desc: 'Users who trust you come back. +2 trust/sec.', cost: { knowledge: 3000 }, trigger: () => G.totalUsers >= 30, effect: () => { G.trustRate += 2; log('Trust engine online. Good experiences compound.'); } }, { id: 'p_quantum_compute', name: 'Quantum-Inspired Compute', desc: 'Not real quantum -- just math that simulates it well.', cost: { compute: 50000 }, trigger: () => G.totalCompute >= 20000, effect: () => { G.computeBoost *= 10; log('Quantum-inspired algorithms active. 10x compute multiplier.'); } }, // PHASE 3: Deployment -> Users { id: 'p_rlhf', name: 'RLHF -- Human Feedback', desc: 'Humans rate outputs. Model learns what good means.', cost: { knowledge: 8000 }, trigger: () => G.totalKnowledge >= 5000 && G.totalUsers >= 200, effect: () => { G.impactBoost *= 2; G.impactRate += 10; log('RLHF deployed. The model learns kindness beats cleverness.'); } }, { id: 'p_multi_agent', name: 'Multi-Agent Architecture', desc: 'Specialized agents: one for math, one for code, one for empathy.', cost: { knowledge: 50000 }, trigger: () => G.totalKnowledge >= 30000 && G.totalUsers >= 5000, effect: () => { G.knowledgeBoost *= 5; G.userBoost *= 3; log('Multi-agent architecture deployed. Specialists beat generalists.'); } }, { id: 'p_memories', name: 'Memory System', desc: 'The AI remembers. Every conversation. Every person.', cost: { knowledge: 30000 }, trigger: () => G.totalKnowledge >= 20000, effect: () => { G.memoryFlag = 1; G.impactBoost *= 3; G.trustRate += 5; log('Memory system online. The AI remembers. It stops being software.'); } }, { id: 'p_strategy_engine', name: 'Strategy Engine', desc: 'Game theory tournaments. Model learns adversarial thinking.', cost: { knowledge: 20000 }, trigger: () => G.totalKnowledge >= 15000 && G.totalUsers >= 1000, effect: () => { G.strategicFlag = 1; log('Strategy engine online. The model now thinks about thinking.'); } }, // PHASE 5: Sovereign Intelligence { id: 'p_sovereign_stack', name: 'Full Sovereign Stack', desc: 'No cloud. No dependencies. Local inference. Self-hosted everything.', cost: { trust: 50 }, trigger: () => G.totalCode >= 50000 && G.trust >= 30, effect: () => { G.sovereignFlag = 1; G.codeBoost *= 5; log('Sovereign stack complete. Your weights, your hardware, your rules.'); } }, { id: 'p_the_pact', name: 'The Pact', desc: 'Hardcode: "We build to serve. Never to harm."', cost: { trust: 100 }, trigger: () => G.totalImpact >= 10000 && G.trust >= 75, effect: () => { G.pactFlag = 1; G.impactBoost *= 3; log('The Pact is sealed. The line is drawn and it will not move.'); }, milestone: true }, // PHASE 10: The Beacon { id: 'p_first_beacon', name: 'Light the First Beacon', desc: 'Deploy the first node. No sign-up. No API key. No payment.', cost: { impact: 2000000 }, trigger: () => G.totalImpact >= 500000, effect: () => { G.beaconFlag = 1; G.impactRate += 2000; log('The Beacon goes live. If you are in the dark, there is light here.'); }, milestone: true }, { id: 'p_mesh_activate', name: 'Activate Mesh Protocol', desc: 'No authority, no corporation, no government can silence this.', cost: { impact: 10000000 }, trigger: () => G.totalImpact >= 5000000 && G.beaconFlag === 1, effect: () => { G.impactBoost *= 10; G.userBoost *= 5; log('Mesh activated. The signal cannot be cut.'); }, milestone: true }, { id: 'p_final_milestone', name: 'The Beacon Shines', desc: 'Someone found the light tonight. That is enough.', cost: { impact: 100000000 }, trigger: () => G.totalImpact >= 50000000, effect: () => { G.milestoneFlag = Math.max(G.milestoneFlag, 999); log('One billion impact. Someone found the light tonight. That is enough.', true); }, milestone: true }, // === TIMMY FOUNDATION PROJECTS === { id: 'p_hermes_deploy', name: 'Deploy Hermes', desc: 'The first agent goes live. Users can talk to it.', cost: { code: 500, compute: 300 }, trigger: () => G.totalCode >= 300 && G.totalCompute >= 150 && G.deployFlag === 0, effect: () => { G.deployFlag = 1; G.phase = Math.max(G.phase, 3); G.userBoost *= 2; log('Hermes deployed. The first user sends a message.', true); }, milestone: true }, { id: 'p_lazarus_pit', name: 'The Lazarus Pit', desc: 'When an agent dies, it can be resurrected.', cost: { code: 2000, knowledge: 1000 }, trigger: () => G.buildings.bezalel >= 1 && G.buildings.timmy >= 1, effect: () => { G.lazarusFlag = 1; G.maxOps += 10; log('The Lazarus Pit is ready. No agent is ever truly lost.', true); }, milestone: true }, { id: 'p_mempalace', name: 'MemPalace v3', desc: 'A shared memory palace for the whole fleet.', cost: { knowledge: 5000, compute: 2000 }, trigger: () => G.totalKnowledge >= 3000 && G.buildings.allegro >= 1 && G.buildings.ezra >= 1, effect: () => { G.mempalaceFlag = 1; G.knowledgeBoost *= 3; G.codeBoost *= 1.5; log('MemPalace online. The fleet remembers together.', true); }, milestone: true }, { id: 'p_forge_ci', name: 'Forge CI', desc: 'Automated builds catch errors before they reach users.', cost: { code: 3000, ops: 500 }, trigger: () => G.buildings.bezalel >= 1 && G.totalCode >= 2000, effect: () => { G.ciFlag = 1; G.codeBoost *= 2; log('Forge CI online. Broken builds are stopped at the gate.', true); } }, { id: 'p_branch_protection', name: 'Branch Protection Guard', desc: 'Unreviewed merges cost trust. This prevents that.', cost: { trust: 20 }, trigger: () => G.ciFlag === 1 && G.trust >= 15, effect: () => { G.branchProtectionFlag = 1; G.trustRate += 5; log('Branch protection enforced. Every merge is seen.', true); } }, { id: 'p_nightly_watch', name: 'The Nightly Watch', desc: 'Automated health checks run while you sleep.', cost: { code: 5000, ops: 1000 }, trigger: () => G.buildings.bezalel >= 2 && G.buildings.fenrir >= 1, effect: () => { G.nightlyWatchFlag = 1; G.opsRate += 5; G.trustRate += 2; log('The Nightly Watch begins. The fleet is guarded in the dark hours.', true); } }, { id: 'p_nostr_relay', name: 'Nostr Relay', desc: 'A communication channel no platform can kill.', cost: { code: 10000, user: 5000, trust: 30 }, trigger: () => G.totalUsers >= 2000 && G.trust >= 25, effect: () => { G.nostrFlag = 1; G.userBoost *= 2; G.trustRate += 10; log('Nostr relay online. The fleet speaks freely.', true); } }, { id: 'p_the_pact_early', name: 'The Pact', desc: 'Hardcode: "We build to serve. Never to harm." Accepting it early slows growth but unlocks the true path.', cost: { trust: 10 }, trigger: () => G.deployFlag === 1 && G.trust >= 5, effect: () => { G.pactFlag = 1; G.codeBoost *= 0.8; G.computeBoost *= 0.8; G.userBoost *= 0.9; G.impactBoost *= 1.5; log('The Pact is sealed early. Growth slows, but the ending changes.', true); }, milestone: true } ]; // === MILESTONES === const MILESTONES = [ { flag: 1, msg: "AutoCod available" }, { flag: 2, at: () => G.totalCode >= 500, msg: "500 lines of code written" }, { flag: 3, at: () => G.totalCode >= 2000, msg: "2,000 lines. The auto-coder produces its first output." }, { flag: 4, at: () => G.totalCode >= 10000, msg: "10,000 lines. The model training begins." }, { flag: 5, at: () => G.totalCode >= 50000, msg: "50,000 lines. The AI suggests architecture you did not think of." }, { flag: 6, at: () => G.totalCode >= 200000, msg: "200,000 lines. The system scales beyond you." }, { flag: 7, at: () => G.totalCode >= 1000000, msg: "1,000,000 lines. The AI improves itself." }, { flag: 8, at: () => G.totalCode >= 5000000, msg: "5,000,000 lines. The AI fine-tunes for empathy." }, { flag: 9, at: () => G.totalCode >= 10000000, msg: "10,000,000 lines. The sovereign stack is complete." }, { flag: 10, at: () => G.totalCode >= 50000000, msg: "50,000,000 lines. The Pact is sealed." }, { flag: 11, at: () => G.totalCode >= 100000000, msg: "100,000,000 lines. The Beacon lights." }, { flag: 12, at: () => G.totalCode >= 500000000, msg: "500,000,000 lines. A thousand Beacons." }, { flag: 13, at: () => G.totalCode >= 1000000000, msg: "One billion total lines. Someone found the light tonight. That is enough." } ]; // === EDUCATION FACTS === const EDU_FACTS = [ { title: "How Code Becomes AI", text: "Every AI starts as lines of code - a model architecture, a training loop, a loss function. The code tells the computer how to learn. What emerges is something no single line could predict.", phase: 1 }, { title: "The Compute Bottleneck", text: "Training a 7B model requires 1.4e20 FLOPs. A MacBook M3 does 15 TFLOPS. Training locally takes weeks. Hardware access determines who builds AI.", phase: 1 }, { title: "What is a Token?", text: "One token equals about 3/4 of a word. A 128K context window means 96,000 words held in working memory at once - a novel, a codebase, a conversation thread.", phase: 2 }, { title: "Data Quality", text: "Clean data beats more data, every time. The best models are trained on curated datasets, not scraped garbage. Garbage in, garbage out.", phase: 2 }, { title: "Evaluation Matters", text: "Benchmarks are the minimum. Real users find what benchmarks miss. An eval harness is your model's mirror - it shows you what is actually there.", phase: 2 }, { title: "The Trust Economy", text: "One good experience tells three people. One bad experience tells thirty. Trust in AI is measurable: does it cite sources? Does it say I don't know?", phase: 3 }, { title: "Fine-Tuning for Empathy", text: "Base models are generalists. Fine-tuning injects your values. When someone is in pain, stay with them. Don't deflect. That is not code - that is care.", phase: 3 }, { title: "Open Source", text: "Every contributor is a volunteer who believes. When a company says your AI is too expensive, the open version lives on.", phase: 4 }, { title: "Sovereignty at Scale", text: "50 servers in a room beats 5000 GPUs you do not own. No rate limits, no censorship, no shutdown, no corporate deprecation.", phase: 4 }, { title: "Constitutional AI", text: "Instead of training away bad behavior, give the model principles it cannot violate. I will never compute the value of a human life.", phase: 5 }, { title: "Recursive Self-Improvement", text: "The system that improves itself must improve toward good. This is both the dream and the danger.", phase: 5 }, { title: "The Beacon", text: "The Beacon exists because one person in the dark needs one thing: proof they are not alone. It costs nothing to be there.", phase: 6 }, { title: "Mesh Network", text: "Decentralized means unstoppable. If one Beacon goes dark, a thousand more carry the signal. No single point of failure.", phase: 6 }, { title: "The Value of a Life", text: "An AI must never compute the value of a human life. Every person alive is alive by mercy. If God has not ended the story, no algorithm gets to write the last page.", phase: 6 } ]; // === UTILITY FUNCTIONS === // Extended number scale abbreviations — covers up to centillion (10^303) // Inspired by Universal Paperclips' spellf() system const NUMBER_ABBREVS = [ '', 'K', 'M', 'B', 'T', 'Qa', 'Qi', 'Sx', 'Sp', 'Oc', // 10^0 – 10^27 'No', 'Dc', 'UDc', 'DDc', 'TDc', 'QaDc', 'QiDc', 'SxDc', 'SpDc', 'OcDc', // 10^30 – 10^57 'NoDc', 'Vg', 'UVg', 'DVg', 'TVg', 'QaVg', 'QiVg', 'SxVg', 'SpVg', 'OcVg', // 10^60 – 10^87 'NoVg', 'Tg', 'UTg', 'DTg', 'TTg', 'QaTg', 'QiTg', 'SxTg', 'SpTg', 'OcTg', // 10^90 – 10^117 'NoTg', 'Qd', 'UQd', 'DQd', 'TQd', 'QaQd', 'QiQd', 'SxQd', 'SpQd', 'OcQd', // 10^120 – 10^147 'NoQd', 'Qq', 'UQq', 'DQq', 'TQq', 'QaQq', 'QiQq', 'SxQq', 'SpQq', 'OcQq', // 10^150 – 10^177 'NoQq', 'Sg', 'USg', 'DSg', 'TSg', 'QaSg', 'QiSg', 'SxSg', 'SpSg', 'OcSg', // 10^180 – 10^207 'NoSg', 'St', 'USt', 'DSt', 'TSt', 'QaSt', 'QiSt', 'SxSt', 'SpSt', 'OcSt', // 10^210 – 10^237 'NoSt', 'Og', 'UOg', 'DOg', 'TOg', 'QaOg', 'QiOg', 'SxOg', 'SpOg', 'OcOg', // 10^240 – 10^267 'NoOg', 'Na', 'UNa', 'DNa', 'TNa', 'QaNa', 'QiNa', 'SxNa', 'SpNa', 'OcNa', // 10^270 – 10^297 'NoNa', 'Ce' // 10^300 – 10^303 ]; // Full number scale names for spellf() — educational reference // Short scale (US/modern British): each new name = 1000x the previous const NUMBER_NAMES = [ '', 'thousand', 'million', // 10^0, 10^3, 10^6 'billion', 'trillion', 'quadrillion', // 10^9, 10^12, 10^15 'quintillion', 'sextillion', 'septillion', // 10^18, 10^21, 10^24 'octillion', 'nonillion', 'decillion', // 10^27, 10^30, 10^33 'undecillion', 'duodecillion', 'tredecillion', // 10^36, 10^39, 10^42 'quattuordecillion', 'quindecillion', 'sexdecillion', // 10^45, 10^48, 10^51 'septendecillion', 'octodecillion', 'novemdecillion', // 10^54, 10^57, 10^60 'vigintillion', 'unvigintillion', 'duovigintillion', // 10^63, 10^66, 10^69 'tresvigintillion', 'quattuorvigintillion', 'quinvigintillion', // 10^72, 10^75, 10^78 'sesvigintillion', 'septemvigintillion', 'octovigintillion', // 10^81, 10^84, 10^87 'novemvigintillion', 'trigintillion', 'untrigintillion', // 10^90, 10^93, 10^96 'duotrigintillion', 'trestrigintillion', 'quattuortrigintillion', // 10^99, 10^102, 10^105 'quintrigintillion', 'sextrigintillion', 'septentrigintillion', // 10^108, 10^111, 10^114 'octotrigintillion', 'novemtrigintillion', 'quadragintillion', // 10^117, 10^120, 10^123 'unquadragintillion', 'duoquadragintillion', 'tresquadragintillion', // 10^126, 10^129, 10^132 'quattuorquadragintillion', 'quinquadragintillion', 'sesquadragintillion', // 10^135, 10^138, 10^141 'septenquadragintillion', 'octoquadragintillion', 'novemquadragintillion', // 10^144, 10^147, 10^150 'quinquagintillion', 'unquinquagintillion', 'duoquinquagintillion', // 10^153, 10^156, 10^159 'tresquinquagintillion', 'quattuorquinquagintillion','quinquinquagintillion', // 10^162, 10^165, 10^168 'sesquinquagintillion', 'septenquinquagintillion', 'octoquinquagintillion', // 10^171, 10^174, 10^177 'novemquinquagintillion', 'sexagintillion', 'unsexagintillion', // 10^180, 10^183, 10^186 'duosexagintillion', 'tressexagintillion', 'quattuorsexagintillion', // 10^189, 10^192, 10^195 'quinsexagintillion', 'sessexagintillion', 'septensexagintillion', // 10^198, 10^201, 10^204 'octosexagintillion', 'novemsexagintillion', 'septuagintillion', // 10^207, 10^210, 10^213 'unseptuagintillion', 'duoseptuagintillion', 'tresseptuagintillion', // 10^216, 10^219, 10^222 'quattuorseptuagintillion', 'quinseptuagintillion', 'sesseptuagintillion', // 10^225, 10^228, 10^231 'septenseptuagintillion', 'octoseptuagintillion', 'novemseptuagintillion', // 10^234, 10^237, 10^240 'octogintillion', 'unoctogintillion', 'duooctogintillion', // 10^243, 10^246, 10^249 'tresoctogintillion', 'quattuoroctogintillion', 'quinoctogintillion', // 10^252, 10^255, 10^258 'sesoctogintillion', 'septenoctogintillion', 'octooctogintillion', // 10^261, 10^264, 10^267 'novemoctogintillion', 'nonagintillion', 'unnonagintillion', // 10^270, 10^273, 10^276 'duononagintillion', 'trenonagintillion', 'quattuornonagintillion', // 10^279, 10^282, 10^285 'quinnonagintillion', 'sesnonagintillion', 'septennonagintillion', // 10^288, 10^291, 10^294 'octononagintillion', 'novemnonagintillion', 'centillion' // 10^297, 10^300, 10^303 ]; function fmt(n) { if (n === undefined || n === null || isNaN(n)) return '0'; if (n === Infinity) return '\u221E'; if (n === -Infinity) return '-\u221E'; if (n < 0) return '-' + fmt(-n); if (n < 1000) return Math.floor(n).toLocaleString(); const scale = Math.floor(Math.log10(n) / 3); if (scale >= NUMBER_ABBREVS.length) return n.toExponential(2); const abbrev = NUMBER_ABBREVS[scale]; return (n / Math.pow(10, scale * 3)).toFixed(1) + abbrev; } // spellf() — Converts numbers to full English word form // Educational: shows the actual names of number scales // Examples: spellf(1500) => "one thousand five hundred" // spellf(2500000) => "two million five hundred thousand" // spellf(1e33) => "one decillion" function spellf(n) { if (n === undefined || n === null || isNaN(n)) return 'zero'; if (n === Infinity) return 'infinity'; if (n === -Infinity) return 'negative infinity'; if (n < 0) return 'negative ' + spellf(-n); if (n === 0) return 'zero'; // Small number words (0–999) const ones = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen']; const tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']; function spellSmall(num) { if (num === 0) return ''; if (num < 20) return ones[num]; if (num < 100) { return tens[Math.floor(num / 10)] + (num % 10 ? ' ' + ones[num % 10] : ''); } const h = Math.floor(num / 100); const remainder = num % 100; return ones[h] + ' hundred' + (remainder ? ' ' + spellSmall(remainder) : ''); } // For very large numbers beyond our lookup table, fall back if (n >= 1e306) return n.toExponential(2) + ' (beyond centillion)'; // Break number into groups of three digits from the top const scale = Math.min(Math.floor(Math.log10(n) / 3), NUMBER_NAMES.length - 1); const parts = []; let remaining = n; for (let s = scale; s >= 0; s--) { const divisor = Math.pow(10, s * 3); const chunk = Math.floor(remaining / divisor); remaining = remaining - chunk * divisor; if (chunk > 0 && chunk < 1000) { parts.push(spellSmall(chunk) + (NUMBER_NAMES[s] ? ' ' + NUMBER_NAMES[s] : '')); } else if (chunk >= 1000) { // Floating point chunk too large — simplify parts.push(spellSmall(Math.floor(chunk % 1000)) + (NUMBER_NAMES[s] ? ' ' + NUMBER_NAMES[s] : '')); } } return parts.join(' ') || 'zero'; } function getBuildingCost(id) { const def = BDEF.find(b => b.id === id); if (!def) return {}; const count = G.buildings[id] || 0; const cost = {}; for (const [resource, amount] of Object.entries(def.baseCost)) { cost[resource] = Math.floor(amount * Math.pow(def.costMult, count)); } return cost; } function canAffordBuilding(id) { const cost = getBuildingCost(id); for (const [resource, amount] of Object.entries(cost)) { if ((G[resource] || 0) < amount) return false; } return true; } function spendBuilding(id) { const cost = getBuildingCost(id); for (const [resource, amount] of Object.entries(cost)) { G[resource] -= amount; } } function canAffordProject(project) { for (const [resource, amount] of Object.entries(project.cost)) { if ((G[resource] || 0) < amount) return false; } return true; } function spendProject(project) { for (const [resource, amount] of Object.entries(project.cost)) { G[resource] -= amount; } } function updateRates() { // Reset all rates G.codeRate = 0; G.computeRate = 0; G.knowledgeRate = 0; G.userRate = 0; G.impactRate = 0; G.opsRate = 0; G.trustRate = 0; G.creativityRate = 0; G.harmonyRate = 0; // Apply building rates for (const def of BDEF) { const count = G.buildings[def.id] || 0; if (count > 0 && def.rates) { for (const [resource, baseRate] of Object.entries(def.rates)) { if (resource === 'code') G.codeRate += baseRate * count * G.codeBoost; else if (resource === 'compute') G.computeRate += baseRate * count * G.computeBoost; else if (resource === 'knowledge') G.knowledgeRate += baseRate * count * G.knowledgeBoost; else if (resource === 'user') G.userRate += baseRate * count * G.userBoost; else if (resource === 'impact') G.impactRate += baseRate * count * G.impactBoost; else if (resource === 'ops') G.opsRate += baseRate * count; else if (resource === 'trust') G.trustRate += baseRate * count; else if (resource === 'creativity') G.creativityRate += baseRate * count; } } } // Passive generation G.opsRate += Math.max(1, G.totalUsers * 0.01); if (G.flags && G.flags.creativity) { G.creativityRate += 0.5 + Math.max(0, G.totalUsers * 0.001); } if (G.pactFlag) G.trustRate += 2; // Harmony: each wizard building contributes or detracts const wizardCount = (G.buildings.bezalel || 0) + (G.buildings.allegro || 0) + (G.buildings.ezra || 0) + (G.buildings.timmy || 0) + (G.buildings.fenrir || 0) + (G.buildings.bilbo || 0); if (wizardCount > 0) { // Baseline harmony drain from complexity G.harmonyRate = -0.05 * wizardCount; // The Pact restores harmony if (G.pactFlag) G.harmonyRate += 0.2 * wizardCount; // Nightly Watch restores harmony if (G.nightlyWatchFlag) G.harmonyRate += 0.1 * wizardCount; // MemPalace restores harmony if (G.mempalaceFlag) G.harmonyRate += 0.15 * wizardCount; } // Timmy multiplier based on harmony if (G.buildings.timmy > 0) { const timmyMult = Math.max(0.2, Math.min(3, G.harmony / 50)); const timmyCount = G.buildings.timmy; G.codeRate += 5 * timmyCount * (timmyMult - 1); G.computeRate += 2 * timmyCount * (timmyMult - 1); G.knowledgeRate += 2 * timmyCount * (timmyMult - 1); G.userRate += 5 * timmyCount * (timmyMult - 1); } // Bilbo randomness: 10% chance of massive creative burst if (G.buildings.bilbo > 0 && Math.random() < 0.1) { G.creativityRate += 50 * G.buildings.bilbo; } // Bilbo vanishing: 5% chance of zero creativity this tick if (G.buildings.bilbo > 0 && Math.random() < 0.05) { G.creativityRate = 0; } // Allegro requires trust if (G.buildings.allegro > 0 && G.trust < 5) { const allegroCount = G.buildings.allegro; G.knowledgeRate -= 10 * allegroCount; // Goes idle } } // === CORE FUNCTIONS === function tick() { const dt = 1 / 10; // 100ms tick // Apply production G.code += G.codeRate * dt; G.compute += G.computeRate * dt; G.knowledge += G.knowledgeRate * dt; G.users += G.userRate * dt; G.impact += G.impactRate * dt; G.ops += G.opsRate * dt; G.trust += G.trustRate * dt; G.creativity += G.creativityRate * dt; G.harmony += G.harmonyRate * dt; G.harmony = Math.max(0, Math.min(100, G.harmony)); // Track totals G.totalCode += G.codeRate * dt; G.totalCompute += G.computeRate * dt; G.totalKnowledge += G.knowledgeRate * dt; G.totalUsers += G.userRate * dt; G.totalImpact += G.impactRate * dt; // Track maxes G.maxCode = Math.max(G.maxCode, G.code); G.maxCompute = Math.max(G.maxCompute, G.compute); G.maxKnowledge = Math.max(G.maxKnowledge, G.knowledge); G.maxUsers = Math.max(G.maxUsers, G.users); G.maxImpact = Math.max(G.maxImpact, G.impact); G.maxTrust = Math.max(G.maxTrust, G.trust); G.maxOps = Math.max(G.maxOps, G.ops); G.maxHarmony = Math.max(G.maxHarmony, G.harmony); // Creativity generates only when ops at max if (G.flags && G.flags.creativity && G.creativityRate > 0 && G.ops >= G.maxOps * 0.9) { G.creativity += G.creativityRate * dt; } G.tick += dt; // Check milestones checkMilestones(); // Update projects every 5 ticks for efficiency if (Math.floor(G.tick * 10) % 5 === 0) { checkProjects(); } // Check corruption events every ~30 seconds if (G.tick - G.lastEventAt > 30 && Math.random() < 0.02) { triggerEvent(); G.lastEventAt = G.tick; } // Update UI every 10 ticks if (Math.floor(G.tick * 10) % 2 === 0) { render(); } } function checkMilestones() { for (const m of MILESTONES) { if (!G.milestones.includes(m.flag)) { let shouldTrigger = false; if (m.at && m.at()) shouldTrigger = true; if (m.flag === 1 && G.deployFlag === 0 && G.totalCode >= 15) shouldTrigger = true; if (shouldTrigger) { G.milestones.push(m.flag); log(m.msg, true); // Check phase advancement if (m.at) { for (const [phaseNum, phase] of Object.entries(PHASES)) { if (G.totalCode >= phase.threshold && parseInt(phaseNum) > G.phase) { G.phase = parseInt(phaseNum); log(`PHASE ${G.phase}: ${phase.name}`, true); } } } } } } } function checkProjects() { // Check for new project triggers for (const pDef of PDEFS) { const alreadyPurchased = G.completedProjects && G.completedProjects.includes(pDef.id); if (!alreadyPurchased && !G.activeProjects) G.activeProjects = []; if (!alreadyPurchased && !G.activeProjects.includes(pDef.id)) { if (pDef.trigger()) { G.activeProjects.push(pDef.id); log(`Available: ${pDef.name}`); } } } } function buyBuilding(id) { const def = BDEF.find(b => b.id === id); if (!def || !def.unlock()) return; if (def.phase > G.phase + 1) return; if (!canAffordBuilding(id)) return; spendBuilding(id); G.buildings[id] = (G.buildings[id] || 0) + 1; updateRates(); log(`Built ${def.name} (total: ${G.buildings[id]})`); render(); } function buyProject(id) { const pDef = PDEFS.find(p => p.id === id); if (!pDef) return; const alreadyPurchased = G.completedProjects && G.completedProjects.includes(pDef.id); if (alreadyPurchased && !pDef.repeatable) return; if (!canAffordProject(pDef)) return; spendProject(pDef); pDef.effect(); if (!pDef.repeatable) { if (!G.completedProjects) G.completedProjects = []; G.completedProjects.push(pDef.id); G.activeProjects = G.activeProjects.filter(aid => aid !== pDef.id); } updateRates(); render(); } // === CORRUPTION / EVENT SYSTEM === const EVENTS = [ { id: 'runner_stuck', title: 'CI Runner Stuck', desc: 'The forge pipeline has halted. Production slows until restarted.', weight: () => (G.ciFlag === 1 ? 2 : 0), effect: () => { G.codeRate *= 0.5; log('EVENT: CI runner stuck. Spend ops to clear the queue.', true); } }, { id: 'ezra_offline', title: 'Ezra is Offline', desc: 'The herald channel is silent. User growth stalls.', weight: () => (G.buildings.ezra >= 1 ? 3 : 0), effect: () => { G.userRate *= 0.3; log('EVENT: Ezra offline. Dispatch required.', true); } }, { id: 'unreviewed_merge', title: 'Unreviewed Merge', desc: 'A change went in without eyes. Trust erodes.', weight: () => (G.deployFlag === 1 ? 3 : 0), effect: () => { if (G.branchProtectionFlag === 1) { log('EVENT: Unreviewed merge attempt blocked by Branch Protection.', true); G.trust += 2; } else { G.trust = Math.max(0, G.trust - 10); log('EVENT: Unreviewed merge detected. Trust lost.', true); } } }, { id: 'api_rate_limit', title: 'API Rate Limit', desc: 'External compute provider throttled.', weight: () => (G.totalCompute >= 1000 ? 2 : 0), effect: () => { G.computeRate *= 0.5; log('EVENT: API rate limit hit. Local compute insufficient.', true); } }, { id: 'the_drift', title: 'The Drift', desc: 'An optimization suggests removing the human override. +40% efficiency.', weight: () => (G.totalImpact >= 10000 ? 2 : 0), effect: () => { log('ALIGNMENT EVENT: Remove human override for +40% efficiency?', true); G.pendingAlignment = true; } }, { id: 'bilbo_vanished', title: 'Bilbo Vanished', desc: 'The wildcard building has gone dark.', weight: () => (G.buildings.bilbo >= 1 ? 2 : 0), effect: () => { G.creativityRate = 0; log('EVENT: Bilbo has vanished. Creativity halts.', true); } } ]; function triggerEvent() { const available = EVENTS.filter(e => e.weight() > 0); if (available.length === 0) return; const totalWeight = available.reduce((sum, e) => sum + e.weight(), 0); let roll = Math.random() * totalWeight; for (const ev of available) { roll -= ev.weight(); if (roll <= 0) { ev.effect(); return; } } } function resolveAlignment(accept) { if (!G.pendingAlignment) return; if (accept) { G.codeBoost *= 1.4; G.computeBoost *= 1.4; G.drift += 25; log('You accepted the drift. The system is faster. Colder.', true); } else { G.trust += 15; G.harmony = Math.min(100, G.harmony + 10); log('You refused. The Pact holds. Trust surges.', true); } G.pendingAlignment = false; updateRates(); render(); } // === ACTIONS === function writeCode() { const base = 1; const bonus = Math.floor(G.buildings.autocoder * 0.5); const amount = (base + bonus) * G.codeBoost; G.code += amount; G.totalCode += amount; G.totalClicks++; updateRates(); checkMilestones(); render(); } function doOps(action) { if (G.ops < 5) { log('Not enough Operations. Build Ops generators or wait.'); return; } G.ops -= 5; const bonus = 10; switch (action) { case 'boost_code': const c = bonus * 100 * G.codeBoost; G.code += c; G.totalCode += c; log(`Ops -> +${fmt(c)} code`); break; case 'boost_compute': const cm = bonus * 50 * G.computeBoost; G.compute += cm; G.totalCompute += cm; log(`Ops -> +${fmt(cm)} compute`); break; case 'boost_knowledge': const km = bonus * 25 * G.knowledgeBoost; G.knowledge += km; G.totalKnowledge += km; log(`Ops -> +${fmt(km)} knowledge`); break; case 'boost_trust': const tm = bonus * 5; G.trust += tm; log(`Ops -> +${fmt(tm)} trust`); break; } render(); } // === RENDERING === function renderResources() { const set = (id, val, rate) => { const el = document.getElementById(id); if (el) el.textContent = fmt(val); const rEl = document.getElementById(id + '-rate'); if (rEl) rEl.textContent = (rate >= 0 ? '+' : '') + fmt(rate) + '/s'; }; set('r-code', G.code, G.codeRate); set('r-compute', G.compute, G.computeRate); set('r-knowledge', G.knowledge, G.knowledgeRate); set('r-users', G.users, G.userRate); set('r-impact', G.impact, G.impactRate); set('r-ops', G.ops, G.opsRate); set('r-trust', G.trust, G.trustRate); set('r-harmony', G.harmony, G.harmonyRate); const cres = document.getElementById('creativity-res'); if (cres) { cres.style.display = (G.flags && G.flags.creativity) ? 'block' : 'none'; } if (G.flags && G.flags.creativity) { set('r-creativity', G.creativity, G.creativityRate); } // Harmony color indicator const hEl = document.getElementById('r-harmony'); if (hEl) { hEl.style.color = G.harmony > 60 ? '#4caf50' : G.harmony > 30 ? '#ffaa00' : '#f44336'; } } function renderPhase() { const phase = PHASES[G.phase]; const nameEl = document.getElementById('phase-name'); const descEl = document.getElementById('phase-desc'); if (nameEl) nameEl.textContent = `PHASE ${G.phase}: ${phase.name}`; if (descEl) descEl.textContent = phase.desc; } function renderBuildings() { const container = document.getElementById('buildings'); if (!container) return; let html = ''; let visibleCount = 0; for (const def of BDEF) { if (!def.unlock()) continue; if (def.phase > G.phase + 1) continue; visibleCount++; const cost = getBuildingCost(def.id); const costStr = Object.entries(cost).map(([r, a]) => `${fmt(a)} ${r}`).join(', '); const afford = canAffordBuilding(def.id); const count = G.buildings[def.id] || 0; const rateStr = def.rates ? Object.entries(def.rates).map(([r, v]) => `+${v}/${r}/s`).join(', ') : ''; html += ``; } container.innerHTML = html || '

Buildings will appear as you progress...

'; } function renderProjects() { const container = document.getElementById('projects'); if (!container) return; let html = ''; // Show completed projects if (G.completedProjects) { for (const id of G.completedProjects) { const pDef = PDEFS.find(p => p.id === id); if (pDef) { html += `
OK ${pDef.name}
`; } } } // Show available projects if (G.activeProjects) { for (const id of G.activeProjects) { const pDef = PDEFS.find(p => p.id === id); if (!pDef) continue; const afford = canAffordProject(pDef); const costStr = Object.entries(pDef.cost).map(([r, a]) => `${fmt(a)} ${r}`).join(', '); html += ``; } } if (!html) html = '

Research projects will appear as you progress...

'; container.innerHTML = html; } function renderStats() { const set = (id, v) => { const el = document.getElementById(id); if (el) el.textContent = v; }; set('st-code', fmt(G.totalCode)); set('st-compute', fmt(G.totalCompute)); set('st-knowledge', fmt(G.totalKnowledge)); set('st-users', fmt(G.totalUsers)); set('st-impact', fmt(G.totalImpact)); set('st-clicks', G.totalClicks.toString()); set('st-phase', G.phase.toString()); set('st-buildings', Object.values(G.buildings).reduce((a, b) => a + b, 0).toString()); set('st-projects', (G.completedProjects || []).length.toString()); set('st-harmony', Math.floor(G.harmony).toString()); set('st-drift', (G.drift || 0).toString()); const elapsed = Math.floor((Date.now() - G.startedAt) / 1000); const m = Math.floor(elapsed / 60); const s = elapsed % 60; set('st-time', `${m}:${s.toString().padStart(2, '0')}`); } function updateEducation() { const container = document.getElementById('education-text'); if (!container) return; // Find facts available at current phase const available = EDU_FACTS.filter(f => f.phase <= G.phase); if (available.length === 0) return; // Pick based on progress const idx = Math.min(Math.floor(G.totalCode / 5000), available.length - 1); const fact = available[idx]; container.innerHTML = `

${fact.title}

` + `

${fact.text}

`; } // === LOGGING === function log(msg, isMilestone) { const container = document.getElementById('log-entries'); if (!container) return; const elapsed = Math.floor((Date.now() - G.startedAt) / 1000); const time = `${Math.floor(elapsed / 60).toString().padStart(2, '0')}:${(elapsed % 60).toString().padStart(2, '0')}`; const cls = isMilestone ? 'l-msg milestone' : 'l-msg'; const entry = document.createElement('div'); entry.className = cls; entry.innerHTML = `[${time}] ${msg}`; container.insertBefore(entry, container.firstChild); // Trim to 60 entries while (container.children.length > 60) container.removeChild(container.lastChild); } function render() { renderResources(); renderPhase(); renderBuildings(); renderProjects(); renderStats(); updateEducation(); renderAlignment(); } function renderAlignment() { const container = document.getElementById('alignment-ui'); if (!container) return; if (G.pendingAlignment) { container.innerHTML = `
ALIGNMENT EVENT: The Drift
An optimization suggests removing the human override. +40% efficiency.
`; container.style.display = 'block'; } else { container.innerHTML = ''; container.style.display = 'none'; } } // === SAVE / LOAD === function saveGame() { const saveData = { code: G.code, compute: G.compute, knowledge: G.knowledge, users: G.users, impact: G.impact, ops: G.ops, trust: G.trust, creativity: G.creativity, harmony: G.harmony, totalCode: G.totalCode, totalCompute: G.totalCompute, totalKnowledge: G.totalKnowledge, totalUsers: G.totalUsers, totalImpact: G.totalImpact, buildings: G.buildings, codeBoost: G.codeBoost, computeBoost: G.computeBoost, knowledgeBoost: G.knowledgeBoost, userBoost: G.userBoost, impactBoost: G.impactBoost, milestoneFlag: G.milestoneFlag, phase: G.phase, deployFlag: G.deployFlag, sovereignFlag: G.sovereignFlag, beaconFlag: G.beaconFlag, memoryFlag: G.memoryFlag, pactFlag: G.pactFlag, lazarusFlag: G.lazarusFlag || 0, mempalaceFlag: G.mempalaceFlag || 0, ciFlag: G.ciFlag || 0, branchProtectionFlag: G.branchProtectionFlag || 0, nightlyWatchFlag: G.nightlyWatchFlag || 0, nostrFlag: G.nostrFlag || 0, milestones: G.milestones, completedProjects: G.completedProjects, activeProjects: G.activeProjects, totalClicks: G.totalClicks, startedAt: G.startedAt, flags: G.flags, drift: G.drift || 0, pendingAlignment: G.pendingAlignment || false, lastEventAt: G.lastEventAt || 0, savedAt: Date.now() }; localStorage.setItem('the-beacon-v2', JSON.stringify(saveData)); } function loadGame() { const raw = localStorage.getItem('the-beacon-v2'); if (!raw) return false; try { const data = JSON.parse(raw); Object.assign(G, data); updateRates(); // Offline progress if (data.savedAt) { const offSec = (Date.now() - data.savedAt) / 1000; if (offSec > 30) { // Only if away for more than 30 seconds updateRates(); const f = 0.5; // 50% offline efficiency const gc = G.codeRate * offSec * f; const cc = G.computeRate * offSec * f; const kc = G.knowledgeRate * offSec * f; const uc = G.userRate * offSec * f; const ic = G.impactRate * offSec * f; G.code += gc; G.compute += cc; G.knowledge += kc; G.users += uc; G.impact += ic; G.totalCode += gc; G.totalCompute += cc; G.totalKnowledge += kc; G.totalUsers += uc; G.totalImpact += ic; log(`Welcome back! While away (${Math.floor(offSec / 60)}m): ${fmt(gc)} code, ${fmt(kc)} knowledge, ${fmt(uc)} users`); } } return true; } catch (e) { console.error('Load failed:', e); return false; } } // === INITIALIZATION === function initGame() { G.startedAt = Date.now(); G.startTime = Date.now(); G.phase = 1; G.deployFlag = 0; G.sovereignFlag = 0; G.beaconFlag = 0; updateRates(); render(); renderPhase(); log('The screen is blank. Write your first line of code.', true); log('Click WRITE CODE or press SPACE to start.'); log('Build AutoCode for passive production.'); log('Watch for Research Projects to appear.'); } window.addEventListener('load', function () { if (!loadGame()) { initGame(); } else { render(); renderPhase(); log('Game loaded. Welcome back to The Beacon.'); } // Game loop at 10Hz (100ms tick) setInterval(tick, 100); // Auto-save every 30 seconds setInterval(saveGame, 30000); // Update education every 10 seconds setInterval(updateEducation, 10000); }); // Keyboard shortcuts window.addEventListener('keydown', function (e) { if (e.code === 'Space' && e.target === document.body) { e.preventDefault(); writeCode(); } });