All five agents died mid-flight (three on session limits, two on 529s), but their worktrees held real work — 17 files. Salvaged everything, wrote the missing pieces, and finished the integration by hand. PROFILES + RANK User gains display_name, bio, gender, avatar_form, avatar_hue and profile_public — all nullable, so every existing row including the guest `wanderer-` accounts stays valid with no backfill. The avatar is procedural (a GhostForm plus a hue, drawn by the same GhostGlyph that renders entities): no uploads means no moderation surface, no EXIF and no blob storage, and an `avatar_url` still slots in later without changing anything. rank.py converts encounters, essence and favor into one "standing" currency and maps it onto six one-word titles. An encounter is worth ten points to ten essence's one, because contact is what the app is about — a seeker who only buys unlocks climbs very slowly. Negative essence and favor floor at zero rather than subtracting, so a bad judgment can never demote you: rank is a record of what you have done. Level 1 costs exactly one encounter, so a new hunter sees the bar move after their first séance. Privacy invariants, verified live rather than assumed: - `email` is returned by GET /api/profile/me and by nothing else. Confirmed against the running server: zero occurrences in both public payloads. - A hidden profile 404s rather than 403s — confirming the account exists would leak exactly what hiding it was meant to prevent. WHISPERS BETWEEN HUNTERS Plain text, no attachments, no editing. Guests can RECEIVE but not send: that gives registering a felt purpose beyond keeping a codex, and closes the obvious spam vector since guest accounts are free and automatic. Verified live: alice→bob delivers, a guest send returns 403, and a third party's conversation list comes back empty — no cross-user leak. Message bodies are rendered as text nodes, never as HTML, and wrap with overflow-wrap:anywhere so a long unbroken string can't blow out the layout. THE ENCOUNTER RECORD The Codex already knew all of this — Entity.discovered_by has always been recorded and every contact was already an entity_sightings row. Nobody ever showed it. Now an entity page names its summoner and lists every hunter who has met it. Hunters who opted out of a public profile are still COUNTED but not linkable: an anonymous contact is still a contact, so a spirit's history stays honest without exposing anyone. Live on production data: Mabel Crump, discovered by Charly, 1 encounter; Charly ranks channeler (level 2) from 5 real sightings — all computed from data that was already sitting there. 385 frontend tests pass; i18n parity holds across both languages. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
736 lines
28 KiB
JSON
736 lines
28 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",
|
||
"inventory": "inventory",
|
||
"devices": "devices",
|
||
"seance": "séance",
|
||
"enter": "enter",
|
||
"logout": "depart",
|
||
"log": "log",
|
||
"hunters": "hunters"
|
||
},
|
||
"log": {
|
||
"title": "GHOST LOG",
|
||
"subtitle": "every séance leaves a page behind",
|
||
"back": "return to the séance",
|
||
"loading": "leafing back through the log…",
|
||
"error": "the log will not open — the veil resists tonight",
|
||
"empty": "no séances yet — the log waits",
|
||
"noEntity": "no one answered",
|
||
"filterLabel": "filter by channel",
|
||
"filterAll": "all channels",
|
||
"showMore_one": "+{{count}} more echo",
|
||
"showMore_other": "+{{count}} more echoes",
|
||
"showLess": "show less",
|
||
"counts": {
|
||
"question_one": "{{count}} question",
|
||
"question_other": "{{count}} questions",
|
||
"anomaly_one": "{{count}} anomaly",
|
||
"anomaly_other": "{{count}} anomalies",
|
||
"utterance_one": "{{count}} utterance",
|
||
"utterance_other": "{{count}} utterances"
|
||
},
|
||
"time": {
|
||
"moments": "moments past",
|
||
"minutes_one": "a minute past",
|
||
"minutes_other": "{{count}} minutes past",
|
||
"hours_one": "an hour past",
|
||
"hours_other": "{{count}} hours past",
|
||
"days_one": "a day past",
|
||
"days_other": "{{count}} days past"
|
||
}
|
||
},
|
||
"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",
|
||
"guest": "slip through as a wanderer"
|
||
},
|
||
"seance": {
|
||
"modes": {
|
||
"wire": "Wire Ghost",
|
||
"evp": "EVP",
|
||
"radio": "Spirit Radio",
|
||
"ouija": "Ouija",
|
||
"emf": "FIELD",
|
||
"camera": "LENS"
|
||
},
|
||
"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"
|
||
},
|
||
"hints": {
|
||
"wire": "the wire whispers on its own when you listen passively",
|
||
"evp": "the veil listens through your microphone — grant it your ear",
|
||
"radio": "a tuner in the hand hears further than the wire",
|
||
"ouija": "ask below, or let the board drift",
|
||
"emf": "hold still; the field remembers movement",
|
||
"camera": "a lens shows the dead your room — they will name what they see, and mistake it for something they lost."
|
||
},
|
||
"conditions": {
|
||
"title": "VEIL CONDITIONS",
|
||
"lit": "{{percent}}% lit",
|
||
"veil": {
|
||
"thin": "the veil runs thin tonight",
|
||
"veiled": "the veil hangs, neither open nor shut",
|
||
"heavy": "the veil lies heavy"
|
||
},
|
||
"fieldQuiet": "field: quiet",
|
||
"fieldStorm": "geomagnetic storm",
|
||
"moon": {
|
||
"new_moon": "new moon",
|
||
"waxing_crescent": "waxing crescent",
|
||
"first_quarter": "first quarter",
|
||
"waxing_gibbous": "waxing gibbous",
|
||
"full_moon": "full moon",
|
||
"waning_gibbous": "waning gibbous",
|
||
"last_quarter": "last quarter",
|
||
"waning_crescent": "waning crescent"
|
||
}
|
||
},
|
||
"evp": {
|
||
"start": "open the microphone",
|
||
"stop": "close the microphone",
|
||
"listening": "listening to the voice band…",
|
||
"floor": "room floor",
|
||
"band": "voice band 300–3400 Hz",
|
||
"scopeLabel": "live audio spectrum from the microphone",
|
||
"fail": {
|
||
"deniedTitle": "the microphone stays shut",
|
||
"denied": "This vessel refused the microphone. Grant audio permission in your browser's site settings to practice EVP — or turn to the ouija board or the Wire Ghost instead; the board needs no ear, and the wire only the network you already fear.",
|
||
"insecureTitle": "unconsecrated ground",
|
||
"insecure": "The dead only speak through a secured channel. Open this site by its https address — or over localhost — and the microphone will answer. Until then, the ouija board and the Wire Ghost need no ear at all.",
|
||
"absentTitle": "no ear to listen with",
|
||
"absent": "This vessel has no microphone the veil can find. Attach one and try again — or turn to the ouija board or the Wire Ghost, which hear by other means.",
|
||
"busyTitle": "the ear is already spoken for",
|
||
"busy": "Another rite already holds the microphone. Close whatever else is listening — a call, a recorder, another tab — then open it here again."
|
||
}
|
||
},
|
||
"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 still answer — EVP hears through the microphone you already carry, and the wire needs nothing at all.",
|
||
"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",
|
||
"scopeLabel": "live radio spectrum from the receiver"
|
||
},
|
||
"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.",
|
||
"trueField": "magnetic field"
|
||
},
|
||
"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"
|
||
}
|
||
},
|
||
"ritual": {
|
||
"title": "focus the channel",
|
||
"none": "no presence to focus on",
|
||
"noneHint": "summon a spirit before attempting the rite",
|
||
"begin": "begin the rite",
|
||
"retry": "attempt again",
|
||
"hold": "hold to focus",
|
||
"awaiting": "awaiting the veil's answer…",
|
||
"successTitle": "the channel holds — the truth surfaces",
|
||
"failureTitle": "the channel collapses",
|
||
"failureHint": "the truth stays hidden — the rite may be tried again",
|
||
"traits": {
|
||
"alignment": "alignment",
|
||
"power": "power",
|
||
"volatility": "volatility",
|
||
"deceptiveness": "deceptiveness"
|
||
},
|
||
"steps": {
|
||
"align": {
|
||
"command": "> aligning the wire…",
|
||
"locked": "> wire aligned ✓"
|
||
},
|
||
"breath": {
|
||
"command": "> steadying the breath…",
|
||
"locked": "> breath steadied ✓"
|
||
},
|
||
"trace": {
|
||
"command": "> tracing the sigil…",
|
||
"locked": "> sigil traced ✓"
|
||
},
|
||
"lock": {
|
||
"command": "> locking the channel…",
|
||
"locked": "> channel locked ✓"
|
||
}
|
||
}
|
||
},
|
||
"judgment": {
|
||
"title": "render judgment",
|
||
"none": "no presence to judge",
|
||
"noneHint": "summon a spirit first",
|
||
"trust": "trust",
|
||
"banish": "banish",
|
||
"crossOver": "cross over",
|
||
"test": "test",
|
||
"pending": "awaiting the verdict…",
|
||
"favor": "favor",
|
||
"essence": "essence",
|
||
"reward": {
|
||
"title": "the bond holds",
|
||
"body": "the spirit answers your trust in kind."
|
||
},
|
||
"escalation": {
|
||
"title": "a reckoning",
|
||
"body": "wrongly trusted, it turns — the haunting sharpens."
|
||
},
|
||
"withdrawal": {
|
||
"title": "it recoils",
|
||
"body": "banished in error, the presence withdraws, wounded."
|
||
},
|
||
"crossedOver": {
|
||
"title": "at peace",
|
||
"body": "the spirit lets go, and the line falls quiet."
|
||
},
|
||
"resisted": {
|
||
"title": "it will not go",
|
||
"body": "a demon does not cross over — it claws back to stay."
|
||
},
|
||
"neutral": {
|
||
"title": "no verdict rendered",
|
||
"body": "a diagnostic pulse only — nothing risked, nothing gained."
|
||
}
|
||
},
|
||
"whisper": {
|
||
"title": "THE VESSEL WHISPERS",
|
||
"online": "the vessel is awake",
|
||
"offline": "the vessel sleeps",
|
||
"waiting": "no whisper yet…",
|
||
"coldSpot": "❄ a cold spot gathers around the vessel",
|
||
"pressureAnomaly": "◎ the air presses close — the atmosphere shifts"
|
||
},
|
||
"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"
|
||
}
|
||
},
|
||
"wanderer": {
|
||
"note": "your contacts fade with the mist —",
|
||
"claim": "claim a name to keep your codex",
|
||
"dismiss": "let the mist take it"
|
||
},
|
||
"camera": {
|
||
"previewLabel": "live view from your camera",
|
||
"privacy": "nothing leaves this page until you let it look — then one still frame is shown to the presence, and kept by no one.",
|
||
"open": "open the lens",
|
||
"opening": "opening the lens…",
|
||
"close": "close the lens",
|
||
"flip": "turn the lens",
|
||
"look": "let it look",
|
||
"needEntity": "summon a presence first — there is no one here to look.",
|
||
"fail": {
|
||
"deniedTitle": "the lens stays covered",
|
||
"denied": "This vessel refused the camera. Grant camera permission in your browser's site settings, then open the lens again.",
|
||
"insecureTitle": "unconsecrated ground",
|
||
"insecure": "The dead will not look through an unsecured lens. Open this site by its https address — or over localhost — and try again.",
|
||
"absentTitle": "no lens to look through",
|
||
"absent": "This vessel has no camera the veil can find. Attach one, or turn to another channel.",
|
||
"busyTitle": "the lens is already in use",
|
||
"busy": "Another rite already holds the camera. Close whatever else is watching, then open the lens again.",
|
||
"unknownTitle": "the lens will not open",
|
||
"unknown": "Something refused the camera and would not say what. Try again, or turn to another channel."
|
||
}
|
||
}
|
||
},
|
||
"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."
|
||
},
|
||
"inventory": {
|
||
"back": "← back to the séance",
|
||
"pageTitle": "THE SHELF",
|
||
"pageSubtitle": "what the veil has left you, and what it will still trade for",
|
||
"title": "inventory",
|
||
"essenceLabel": "essence",
|
||
"unlocksTitle": "unlocks",
|
||
"noUnlocks": "nothing unlocked yet",
|
||
"ownedTag": "[OWNED]",
|
||
"lockedTag": "[LOCKED]",
|
||
"priceValue": "{{price}} essence",
|
||
"priceUnknown": "price unknown",
|
||
"priceEstimate": "(est.)",
|
||
"buy": "buy",
|
||
"buying": "buying…",
|
||
"buyInsufficient": "not enough essence",
|
||
"buyError": "the purchase failed",
|
||
"itemsTitle": "items",
|
||
"itemsLoading": "reading the shelf…",
|
||
"itemsEmpty": "nothing collected yet",
|
||
"sigil": {
|
||
"title": "sigil designer",
|
||
"canvasLabel": "circle of anchor points",
|
||
"slotLabel": "anchor point {{slot}}",
|
||
"coordLabel": "coords",
|
||
"hoverHint": "hover an anchor point",
|
||
"pointsLabel": "points",
|
||
"lastLabel": "last",
|
||
"runeLabel": "rune",
|
||
"nameLabel": "name",
|
||
"namePlaceholder": "untitled sigil",
|
||
"save": "inscribe sigil",
|
||
"saving": "inscribing…",
|
||
"saved": "the sigil is bound",
|
||
"error": "the sigil would not hold"
|
||
}
|
||
},
|
||
"devices": {
|
||
"back": "← the threshold",
|
||
"title": "DEVICE BAY",
|
||
"subtitle": "pair hardware to your account and watch its telemetry live",
|
||
"pair": {
|
||
"title": "PAIR A NEW DEVICE",
|
||
"nameLabel": "device name",
|
||
"namePlaceholder": "e.g. attic-node-01",
|
||
"submit": "pair device",
|
||
"pending": "pairing…",
|
||
"nameRequired": "name the device before pairing",
|
||
"error": "the pairing handshake failed — try again"
|
||
},
|
||
"token": {
|
||
"warning": "copy this now — it cannot be shown again. losing it means re-pairing the device.",
|
||
"copy": "copy",
|
||
"copied": "copied",
|
||
"confirm": "I've saved it — hide token"
|
||
},
|
||
"dashboard": {
|
||
"title": "LIVE FEED",
|
||
"empty": "no devices paired yet — pair one above to see it here",
|
||
"lastSeen": "last seen",
|
||
"lastSeenNever": "never",
|
||
"noReadings": "awaiting first reading…",
|
||
"connection": {
|
||
"connecting": "reaching the feed…",
|
||
"open": "feed live",
|
||
"unstable": "feed unstable…",
|
||
"closed": "feed offline"
|
||
},
|
||
"coldSpot": {
|
||
"callout": "COLD SPOT — {{deviation}} {{unit}} below baseline"
|
||
},
|
||
"pressureAnomaly": {
|
||
"callout": "PRESSURE ANOMALY — {{magnitude}} {{unit}} swing, atmosphere shifting"
|
||
},
|
||
"disturbance": {
|
||
"title": "ATMOSPHERIC DISTURBANCE",
|
||
"ariaLabel": "atmospheric disturbance index"
|
||
}
|
||
}
|
||
},
|
||
"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"
|
||
},
|
||
"profile": {
|
||
"back": "← the table",
|
||
"title": "YOUR SIGIL",
|
||
"subtitle": "how the veil will remember you",
|
||
"loading": "reading your sigil…",
|
||
"loadError": "your sigil will not resolve — the glass is clouded",
|
||
"save": "seal it",
|
||
"saving": "sealing…",
|
||
"saved": "sealed — the veil has taken it",
|
||
"saveError": "the veil refused the change",
|
||
"viewPublic": "see what others see",
|
||
"rankLine": "{{title}} · rank {{level}}",
|
||
"titles": {
|
||
"curious": "curious",
|
||
"sensitive": "sensitive",
|
||
"channeler": "channeler",
|
||
"medium": "medium",
|
||
"adept": "adept",
|
||
"oracle": "oracle"
|
||
},
|
||
"wanderer": {
|
||
"body": "you drift here without a name. wanderers may look, but the veil forgets them at dawn — claim a name and your sigil will hold.",
|
||
"claim": "claim a name"
|
||
},
|
||
"avatar": {
|
||
"heading": "your shape",
|
||
"note": "no likeness is taken. your sigil is drawn from a form and a colour, the same way the dead are drawn.",
|
||
"formLabel": "choose a form",
|
||
"hueLabel": "colour · {{hue}}°"
|
||
},
|
||
"identity": {
|
||
"heading": "your name",
|
||
"nameLabel": "name others will read",
|
||
"nameHint": "leave it blank and the veil will use your true name",
|
||
"nameTooLong": "no more than {{max}} characters",
|
||
"bioLabel": "a few words on yourself",
|
||
"bioCount": "{{remaining}} of {{max}} left",
|
||
"bioTooLong": "no more than {{max}} characters"
|
||
},
|
||
"gender": {
|
||
"label": "how you are addressed",
|
||
"male": "he",
|
||
"female": "she",
|
||
"unspecified": "unspoken"
|
||
},
|
||
"veil": {
|
||
"heading": "the veil over you",
|
||
"public": "visible to other seekers",
|
||
"private": "veiled",
|
||
"publicNote": "your sigil, rank and recent contacts can be read by anyone who knows your name.",
|
||
"privateNote": "no one will find you on the roll. your séances continue unchanged."
|
||
},
|
||
"email": {
|
||
"label": "a way back (optional)",
|
||
"note": "for recovering your account only. never shown on your page, never given to another seeker, never used to reach you otherwise.",
|
||
"invalid": "that address will not carry a message"
|
||
}
|
||
},
|
||
"hunters": {
|
||
"back": "← the table",
|
||
"backToRoster": "← the roll",
|
||
"title": "THE ROLL",
|
||
"subtitle": "every seeker who left their name on the veil",
|
||
"loading": "calling the roll…",
|
||
"empty": "no one has left a name yet",
|
||
"card": {
|
||
"encounters_one": "{{count}} spirit reached",
|
||
"encounters_other": "{{count}} spirits reached"
|
||
},
|
||
"profile": {
|
||
"loading": "tracing their sigil…",
|
||
"veiledTitle": "no trace of them",
|
||
"veiledBody": "the veil holds no record of “{{username}}”. either the name was never claimed, or they have drawn the veil over themselves.",
|
||
"progressLabel": "progress toward the next rank",
|
||
"progressNext_one": "{{count}} more spirit to rise",
|
||
"progressNext_other": "{{count}} more spirits to rise",
|
||
"progressMax": "as far as the veil goes",
|
||
"encounters": "spirits reached",
|
||
"joined": "first crossed",
|
||
"recentTitle": "recently reached",
|
||
"recentEmpty": "they have reached no one yet",
|
||
"sendMessage": "send word"
|
||
}
|
||
},
|
||
"messages": {
|
||
"title": "whispers between hunters",
|
||
"findHunters": "find hunters",
|
||
"emptyInbox": "no one has whispered to you yet. find a hunter whose codex you admire, and say something.",
|
||
"emptyThread": "nothing has passed between you yet.",
|
||
"needAccount": "whispers need a name. a wanderer's voice does not carry.",
|
||
"claimName": "claim a name",
|
||
"backToInbox": "back to the whispers",
|
||
"noSuchHunter": "no such hunter walks here.",
|
||
"placeholder": "speak, and it will carry…",
|
||
"send": "send",
|
||
"sending": "sending…",
|
||
"sendFailed": "the whisper did not carry. try again.",
|
||
"guestBlocked": "a wanderer cannot be heard. claim a name and your whispers will carry.",
|
||
"youPrefix": "you: ",
|
||
"unread": "unread whispers",
|
||
"time": {
|
||
"now": "just now",
|
||
"minutes_one": "{{count}} minute past",
|
||
"minutes_other": "{{count}} minutes past",
|
||
"hours_one": "{{count}} hour past",
|
||
"hours_other": "{{count}} hours past",
|
||
"days_one": "{{count}} day past",
|
||
"days_other": "{{count}} days past"
|
||
}
|
||
}
|
||
}
|