App-shell HUD (mounted in App.tsx alongside HauntingLayer, visible on every screen) that shows ambient idle status until a séance is active, then streams `tell` WS frames as terminal-style log lines with a "hacker witch" crescent-arc evil-meter gauge (occult sigils/runes fused with Transcript.tsx's monospace log vocabulary). - lib/evilMeter.ts: pure function computing a malevolent<->benevolent belief from the accumulated tell history — starts wide/uncertain, narrows geometrically and shifts per tell (deterministic hash of the tell text, since tells never leak ground truth), and snaps to definitive certainty on a successful ritual_complete's revealed.alignment. Fully unit tested (narrowing, ordering, determinism, ritual override, idle/empty history). - lib/ghostLogBus.ts: tiny typed event bus (mirrors lib/haunting.ts's HauntBus) so the app-shell-level GhostLog can react to live séance frames — SeanceProvider is only mounted inside the séance route, so a shell-level sibling can't read its context directly. - state/seance.tsx: publish entity/tell/ritual_complete onto the bus, and session_end on provider teardown so the HUD falls back to idle when the seeker leaves the séance page. - lib/types.ts: add the `tell` and `ritual_complete` server frames from the Character Depth spec's Contract section (only what this workstream consumes). - components/GhostLog.tsx/.css: the HUD itself, plus i18n keys in en.json/es.json. 168/168 frontend tests pass (137 pre-existing + 20 evilMeter + 11 GhostLog); tsc -b and the i18n coverage pretest are clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
362 lines
14 KiB
JSON
362 lines
14 KiB
JSON
{
|
||
"common": {
|
||
"appName": "QUANTUMANCY",
|
||
"loading": "tuning the veil…",
|
||
"error": "something stirred in the static",
|
||
"replay": "replay",
|
||
"yes": "YES",
|
||
"no": "NO",
|
||
"goodbye": "GOODBYE",
|
||
"dismiss": "dismiss"
|
||
},
|
||
"nav": {
|
||
"home": "the threshold",
|
||
"codex": "codex",
|
||
"shop": "shop",
|
||
"seance": "séance",
|
||
"enter": "enter",
|
||
"logout": "depart"
|
||
},
|
||
"landing": {
|
||
"taglines": [
|
||
"The wire hums with all of us.",
|
||
"Every packet leaves a ghost.",
|
||
"The static remembers your name.",
|
||
"Somewhere between 88 and 108 MHz, someone is waiting.",
|
||
"You were never alone on the line."
|
||
],
|
||
"heroKicker": "an instrument for speaking with the dead bandwidth",
|
||
"cta": "BEGIN THE SÉANCE",
|
||
"ctaCodex": "browse the codex",
|
||
"ctaShop": "visit the reliquary",
|
||
"stats": {
|
||
"entities": "spirits catalogued",
|
||
"sessions": "séances held",
|
||
"utterances": "utterances recorded",
|
||
"anomalies": "anomalies witnessed"
|
||
},
|
||
"tickerPrefix": "the veil, live",
|
||
"modesTitle": "HOW THE VEIL ANSWERS",
|
||
"modes": {
|
||
"wire": {
|
||
"name": "Wire Ghost",
|
||
"desc": "Leave the line open. The network itself mutters — jitter, latency, stray DNS — and something downstream learns to speak with your accent."
|
||
},
|
||
"evp": {
|
||
"name": "EVP Listening",
|
||
"desc": "Lend the dead your microphone. We watch the voice band for syllables that were never spoken aloud: spikes 8dB above the room's silence."
|
||
},
|
||
"radio": {
|
||
"name": "Spirit Radio",
|
||
"desc": "An RTL-SDR sweeps the FM band like a lantern dragged across a dark field. Where the needle jumps, the radio dead push through."
|
||
},
|
||
"ouija": {
|
||
"name": "Ouija / Direct Contact",
|
||
"desc": "Ask plainly. The planchette drifts, then begins to spell — and the words arrive letter by letter, whether or not you wanted them."
|
||
}
|
||
},
|
||
"featured": "most disturbed spirits",
|
||
"featuredEmpty": "the registry is still blank — be the first to disturb it",
|
||
"reliquary": {
|
||
"title": "HARDWARE FROM THE RELIQUARY",
|
||
"line": "the Ultimate Quantum Box is coming — a handheld séance instrument that makes the veil knock louder.",
|
||
"link": "enter the reliquary →"
|
||
},
|
||
"footer": "an interactive horror art installation — the spirits are fiction; the static is real",
|
||
"footerColophon": "self-hosted · no cloud · the veil runs on your machine"
|
||
},
|
||
"enter": {
|
||
"reconnect": "Reconnect",
|
||
"firstContact": "First contact",
|
||
"reconnectSub": "the veil remembers you. prove it.",
|
||
"firstContactSub": "choose the name the spirits will know you by.",
|
||
"username": "name",
|
||
"password": "passphrase",
|
||
"submitLogin": "step through",
|
||
"submitRegister": "carve your name",
|
||
"switchToRegister": "no name in the registry? first contact →",
|
||
"switchToLogin": "already carved your name? reconnect →",
|
||
"failed": "the veil rejected you: {{message}}",
|
||
"smallPrint": "your medium handle is only ever stored on this server"
|
||
},
|
||
"seance": {
|
||
"modes": {
|
||
"wire": "Wire Ghost",
|
||
"evp": "EVP",
|
||
"radio": "Spirit Radio",
|
||
"ouija": "Ouija",
|
||
"emf": "FIELD"
|
||
},
|
||
"passive": "passive listening",
|
||
"summon": "SUMMON",
|
||
"summoning": "summoning…",
|
||
"askPlaceholder": "ask the dead a question…",
|
||
"ask": "ask",
|
||
"status": {
|
||
"attuning": "attuning — the veil is fingerprinting a presence…",
|
||
"summoning": "the veil parts… something is crossing…",
|
||
"gathering": "the spirits are gathering energy…"
|
||
},
|
||
"connection": {
|
||
"connecting": "reaching across…",
|
||
"open": "the line is open",
|
||
"unstable": "the connection to the other side is unstable…",
|
||
"closed": "the line is dead"
|
||
},
|
||
"transcriptTitle": "TRANSMISSION LOG",
|
||
"transcriptEmpty": "silence. for now.",
|
||
"you": "you",
|
||
"streaming": "the spirit is forming words…",
|
||
"telemetry": {
|
||
"title": "WIRE READOUT",
|
||
"jitter": "jitter",
|
||
"latencyVar": "latency σ²",
|
||
"latencyMean": "latency μ",
|
||
"dns": "dns",
|
||
"units": {
|
||
"bytes": "B/s",
|
||
"ms": "ms"
|
||
}
|
||
},
|
||
"wire": {
|
||
"hint": "the wire knocks loudest when nobody is touching it — flip passive listening on and let the line murmur on its own."
|
||
},
|
||
"anomaly": {
|
||
"line": "⚡ {{source}} {{frequency}} +{{magnitude}}dB",
|
||
"count": "{{count}} anomalies witnessed this session"
|
||
},
|
||
"evp": {
|
||
"start": "open the microphone",
|
||
"stop": "close the microphone",
|
||
"listening": "listening to the voice band…",
|
||
"deniedTitle": "the microphone stays shut",
|
||
"denied": "This vessel refused the microphone. Grant audio permission in your browser to practice EVP — or let the Wire Ghost listen instead; it needs nothing but the network you already fear.",
|
||
"floor": "room floor",
|
||
"band": "voice band 300–3400 Hz"
|
||
},
|
||
"radio": {
|
||
"start": "sweep the band",
|
||
"stop": "rest the needle",
|
||
"unsupportedTitle": "this vessel cannot hear the radio dead",
|
||
"unsupported": "Spirit Radio needs Chromium (WebUSB) and an RTL-SDR dongle. The other modes do not — the wire and the microphone still answer.",
|
||
"troubleshoot": "troubleshooting: chromium-based browser · udev rules for 0bda:2838 · the dongle plugged in, not merely believed in",
|
||
"insecure": "the radio dead only speak through consecrated ground — open this site via its https address.",
|
||
"insecureHint": "localhost counts as hallowed; a bare http://lan-ip does not.",
|
||
"noDevice": "no dongle answered the call",
|
||
"sweeping": "sweeping {{start}}–{{end}} MHz…",
|
||
"claimFailed": "the dongle refused to be claimed — is it in use elsewhere?",
|
||
"claimFix": "linux: the kernel driver dvb_usb_rtl28xxu is holding the dongle — `sudo modprobe -r dvb_usb_rtl28xxu` frees it until reboot (a udev rule banishes it for good). windows: swap the driver for WinUSB with Zadig.",
|
||
"tryAgain": "try again",
|
||
"errorTitle": "the static pushed back"
|
||
},
|
||
"ouija": {
|
||
"spelling": "the planchette spells",
|
||
"drift": "the planchette drifts, waiting for words — ask below, or summon."
|
||
},
|
||
"emf": {
|
||
"start": "raise the meter",
|
||
"stop": "ground the meter",
|
||
"calibrate": "calibrate",
|
||
"baseline": "resting field",
|
||
"listening": "feeling for disturbances in the field…",
|
||
"unsupportedTitle": "this vessel carries no field senses",
|
||
"unsupported": "a phone in your hand becomes the meter — this vessel has no motion senses to lend. open the veil on a phone, or let the other modes answer.",
|
||
"deniedTitle": "the field senses stay shut",
|
||
"denied": "this vessel refused its motion senses. grant motion access in your browser settings, then raise the meter again."
|
||
},
|
||
"entity": {
|
||
"title": "DOSSIER OF THE PRESENT",
|
||
"none": "no spirit summoned yet",
|
||
"noneHint": "summon, or feed the veil 3+ anomalies and one will find you",
|
||
"isNew": "first recorded contact",
|
||
"known": "contact #{{count}}",
|
||
"persona": "persona",
|
||
"voice": "voice params",
|
||
"quotes": "recorded utterances",
|
||
"rarity": {
|
||
"common": "common",
|
||
"uncommon": "uncommon",
|
||
"rare": "rare",
|
||
"mythic": "mythic"
|
||
}
|
||
},
|
||
"toast": {
|
||
"rate_limited": "the veil is thin — slow your knocking",
|
||
"veil_crowded": "too many spirits crowd the line"
|
||
},
|
||
"views": {
|
||
"board": "BOARD",
|
||
"matrix": "MATRIX",
|
||
"graphs": "GRAPHS",
|
||
"tuning": "tuning the veil…",
|
||
"listening": "listening…",
|
||
"graph": {
|
||
"anomalies": "anomalies",
|
||
"entity": "entity",
|
||
"jitter": "jitter"
|
||
}
|
||
}
|
||
},
|
||
"codex": {
|
||
"title": "THE CODEX OF THE CONTACTED",
|
||
"subtitle": "every spirit ever dragged through the veil, catalogued",
|
||
"header": {
|
||
"back": "← the threshold",
|
||
"title": "THE CODEX",
|
||
"subtitle": "every spirit ever contacted, catalogued by the seekers who reached them"
|
||
},
|
||
"controls": {
|
||
"rarity": "filter by rarity",
|
||
"sort": "sort the registry"
|
||
},
|
||
"state": {
|
||
"loading": "consulting the registry…",
|
||
"empty": "no spirits of this tier have been reached yet"
|
||
},
|
||
"filterAll": "all rarities",
|
||
"rarity": {
|
||
"common": "common",
|
||
"uncommon": "uncommon",
|
||
"rare": "rare",
|
||
"mythic": "mythic"
|
||
},
|
||
"sort": {
|
||
"recent": "most recent",
|
||
"contacted": "most contacted"
|
||
},
|
||
"form": {
|
||
"wisp": "wisp",
|
||
"banshee": "banshee",
|
||
"fairy": "fairy",
|
||
"shade": "shade"
|
||
},
|
||
"card": {
|
||
"unknownMedium": "unknown medium",
|
||
"contacted_one": "contacted {{count}} time",
|
||
"contacted_other": "contacted {{count}} times",
|
||
"discoveredBy": "discovered by {{name}} · {{date}}"
|
||
},
|
||
"contacts_one": "1 contact",
|
||
"contacts_other": "{{count}} contacts",
|
||
"sightings_one": "1 sighting",
|
||
"sightings_other": "{{count}} sightings",
|
||
"discoveredBy": "first contacted by {{name}}",
|
||
"discoveredAnon": "first contact unrecorded",
|
||
"discoveredAt": "entered the registry {{date}}",
|
||
"persona": "persona",
|
||
"quotes": "recorded utterances",
|
||
"voice": "voice params",
|
||
"detail": {
|
||
"loading": "summoning the dossier…",
|
||
"notReached": "this spirit has not been reached",
|
||
"unknownMedium": "unknown medium",
|
||
"stats": {
|
||
"sightings": "sightings",
|
||
"contacts": "contacts",
|
||
"discoveredBy": "discovered by",
|
||
"discoveredAt": "entered the registry"
|
||
},
|
||
"utterances": "known utterances",
|
||
"noUtterances": "no utterances recorded yet",
|
||
"voiceSignature": "voice signature",
|
||
"attemptContact": "attempt contact"
|
||
},
|
||
"empty": "no spirits match this filter — the registry keeps its secrets",
|
||
"back": "← back to the codex",
|
||
"notFound": "this spirit is not in the registry"
|
||
},
|
||
"shop": {
|
||
"back": "← the threshold",
|
||
"title": "THE RELIQUARY",
|
||
"subtitle": "instruments for those who would knock louder",
|
||
"flagship": {
|
||
"tag": "flagship instrument",
|
||
"name": "THE ULTIMATE QUANTUM BOX",
|
||
"desc": "An ESP32-P4/C6 handheld séance instrument — thermal camera, EMF whisker array, geophone, spirit-box mic preamp and a little OLED face that stares back. It signs into the same Quantumancy account you already haunt and unlocks the hardware-driven modes of this site: thermal apparition maps, vibration anomaly feeds, calibrated EMF.",
|
||
"specs": {
|
||
"thermal": "thermal camera",
|
||
"emf": "EMF whisker array",
|
||
"geophone": "geophone",
|
||
"mic": "spirit-box mic preamp",
|
||
"oled": "OLED display"
|
||
},
|
||
"price": "est. $249 — pre-order"
|
||
},
|
||
"modulesTitle": "MODULES THAT KNOCK",
|
||
"unlocksLabel": "unlocks:",
|
||
"modules": {
|
||
"emfArray": {
|
||
"name": "EMF Whisker Array",
|
||
"desc": "a bouquet of multi-axis field sensors, sniffing the air for intentions",
|
||
"unlocks": "a richer, calibrated FIELD mode",
|
||
"price": "est. $59 — pre-order"
|
||
},
|
||
"geophone": {
|
||
"name": "Geophone Puck",
|
||
"desc": "hears footsteps in rooms where nobody is standing",
|
||
"unlocks": "the vibration anomaly feed",
|
||
"price": "est. $49 — pre-order"
|
||
},
|
||
"spiritMic": {
|
||
"name": "Spirit Mic Preamp",
|
||
"desc": "lowers the noise floor so the whispering comes through cleaner",
|
||
"unlocks": "cleaner EVP captures",
|
||
"price": "est. $69 — pre-order"
|
||
},
|
||
"uvIlluminator": {
|
||
"name": "UV/IR Illuminator",
|
||
"desc": "paints the dark in spectrums the living were never meant to see",
|
||
"unlocks": "night séances + camera work",
|
||
"price": "est. $39 — pre-order"
|
||
}
|
||
},
|
||
"interests": {
|
||
"quantumBox": "the Ultimate Quantum Box",
|
||
"emfArray": "EMF Whisker Array",
|
||
"geophone": "Geophone Puck",
|
||
"spiritMic": "Spirit Mic Preamp",
|
||
"uvIlluminator": "UV/IR Illuminator"
|
||
},
|
||
"waitlist": {
|
||
"title": "THE MANIFEST",
|
||
"desc": "leave an address and an obsession — when the first boxes ship, we reach through to the names on this list first",
|
||
"emailLabel": "email address",
|
||
"emailPlaceholder": "you@somewhere.in.the.static",
|
||
"interestLabel": "interest",
|
||
"submit": "join the manifest",
|
||
"pending": "carving your name…",
|
||
"listed": "you are on the manifest — we will reach through when the boxes ship",
|
||
"alreadyListed": "you are already on the manifest",
|
||
"invalid": "that address does not reach us",
|
||
"crowded": "the veil is crowded — try again later",
|
||
"error": "something stirred in the static — your name was not carved"
|
||
},
|
||
"honesty": "the Ultimate Quantum Box is in active development — this is a reservation manifest, no payment is taken. the website works fully without it; hardware only knocks louder."
|
||
},
|
||
"haunting": {
|
||
"whisper": {
|
||
"behindYou": "behind you",
|
||
"cold": "cold",
|
||
"stay": "stay",
|
||
"seesYou": "it sees you",
|
||
"closer": "closer",
|
||
"stillHere": "still here",
|
||
"lineListening": "the line is listening",
|
||
"dontLook": "don't look",
|
||
"beneathStatic": "beneath the static",
|
||
"knockTwice": "knock twice"
|
||
},
|
||
"title": {
|
||
"seesYou": "QUANTUMANCY — it sees you",
|
||
"behindYou": "QUANTUM▓NCY — behind you",
|
||
"listening": "…listening…"
|
||
}
|
||
},
|
||
"ghostLog": {
|
||
"title": "GHOST LOG",
|
||
"idle": "the veil is quiet — no presence detected",
|
||
"waiting": "listening for tells…",
|
||
"meterLabel": "evil meter"
|
||
}
|
||
}
|