{ "common": { "appName": "QUANTUMANCY", "loading": "afinando el velo…", "error": "algo se agitó en la estática", "replay": "repetir", "yes": "SÍ", "no": "NO", "goodbye": "ADIÓS", "dismiss": "cerrar" }, "nav": { "home": "el umbral", "codex": "códice", "shop": "relicario", "inventory": "inventario", "devices": "dispositivos", "seance": "sesión", "enter": "entrar", "logout": "partir", "log": "registro", "hunters": "lista", "title": "los caminos", "openMenu": "los caminos", "closeMenu": "cerrar los caminos", "messages": "mensajes", "profile": "perfil", "doctrine": "doctrina", "blurb": { "seance": "abre un canal y llama", "log": "lo que la sala ha dicho", "codex": "cada espíritu nombrado", "hunters": "otros que hacen esto", "messages": "palabra de otros cazadores", "profile": "tu rango y posición", "inventory": "lo que has guardado", "devices": "vincula un sensor", "doctrine": "cómo funciona el instrumento", "shop": "instrumentos por venir" } }, "log": { "title": "REGISTRO ESPECTRAL", "subtitle": "cada sesión deja una página tras de sí", "back": "volver a la sesión", "loading": "hojeando el registro hacia atrás…", "error": "el registro no se abre — el velo se resiste esta noche", "empty": "aún no hay sesiones — el registro espera", "noEntity": "nadie respondió", "filterLabel": "filtrar por canal", "filterAll": "todos los canales", "showMore_one": "+{{count}} eco más", "showMore_other": "+{{count}} ecos más", "showLess": "mostrar menos", "counts": { "question_one": "{{count}} pregunta", "question_other": "{{count}} preguntas", "anomaly_one": "{{count}} anomalía", "anomaly_other": "{{count}} anomalías", "utterance_one": "{{count}} voz", "utterance_other": "{{count}} voces" }, "time": { "moments": "hace instantes", "minutes_one": "hace un minuto", "minutes_other": "hace {{count}} minutos", "hours_one": "hace una hora", "hours_other": "hace {{count}} horas", "days_one": "hace un día", "days_other": "hace {{count}} días" } }, "landing": { "taglines": [ "El cable zumba con todos nosotros.", "Cada paquete deja un fantasma.", "La estática recuerda tu nombre.", "Entre 88 y 108 MHz, alguien espera.", "Nunca estuviste solo en la línea." ], "heroKicker": "un instrumento para hablar con el ancho de banda muerto", "cta": "COMENZAR LA SESIÓN", "ctaCodex": "hojear el códice", "ctaShop": "visitar el relicario", "stats": { "entities": "espíritus catalogados", "sessions": "sesiones celebradas", "utterances": "enunciados registrados", "anomalies": "anomalías presenciadas" }, "tickerPrefix": "el velo, en vivo", "modesTitle": "CÓMO RESPONDE EL VELO", "modes": { "wire": { "name": "Fantasma del Cable", "desc": "Deja la línea abierta. La red misma murmura — jitter, latencia, DNS extraviado — y algo, aguas abajo, aprende a hablar con tu acento." }, "evp": { "name": "Escucha EVP", "desc": "Préstales tu micrófono. Vigilamos la banda de voz en busca de sílabas que jamás se pronunciaron: picos 8dB sobre el silencio de la sala." }, "radio": { "name": "Radio Espíritu", "desc": "Un RTL-SDR barre la banda FM como un farol arrastrado por un campo oscuro. Donde salta la aguja, los muertos de la radio se abren paso." }, "ouija": { "name": "Ouija / Contacto Directo", "desc": "Pregunta claro. La planchette deriva, y luego empieza a deletrear — y las palabras llegan letra a letra, lo quisieras o no." } }, "featured": "los espíritus más perturbados", "featuredEmpty": "el registro aún está en blanco — sé quien lo perturbe primero", "reliquary": { "title": "HARDWARE DEL RELICARIO", "line": "la Ultimate Quantum Box se acerca — un instrumento de sesión de mano que hace que el velo golpee más fuerte.", "link": "entrar al relicario →" }, "footer": "una instalación de arte de terror interactiva — los espíritus son ficción; la estática es real", "footerColophon": "autoalojado · sin nube · el velo corre en tu máquina", "doctrine": { "title": "CÓMO FUNCIONA REALMENTE EL INSTRUMENTO", "line": "la doctrina — once artículos sobre la física real tras la sesión, cada uno traducido sin rodeos, incluida una relación honesta de lo que el instrumento no puede hacer.", "link": "leer la doctrina →" } }, "enter": { "reconnect": "Reconectar", "firstContact": "Primer contacto", "reconnectSub": "el velo te recuerda. demuéstralo.", "firstContactSub": "elige el nombre por el que te conocerán los espíritus.", "username": "nombre", "password": "contraseña", "submitLogin": "cruzar el umbral", "submitRegister": "grabar tu nombre", "switchToRegister": "¿sin nombre en el registro? primer contacto →", "switchToLogin": "¿ya grabaste tu nombre? reconectar →", "failed": "el velo te rechazó: {{message}}", "smallPrint": "tu nombre de médium solo se guarda en este servidor", "guest": "escabúllete como errante", "guestFailed": "el velo no abrió una puerta sin nombre ahora mismo — demasiados errantes han pasado desde aquí hace poco. reclama un nombre abajo, o vuelve en un rato." }, "seance": { "modes": { "wire": "Fantasma del Cable", "evp": "EVP", "radio": "Radio Espíritu", "ouija": "Ouija", "emf": "CAMPO", "camera": "LENTE" }, "passive": "escucha pasiva", "summon": "INVOCAR", "summoning": "invocando…", "askPlaceholder": "pregúntale algo a los muertos…", "ask": "preguntar", "status": { "attuning": "sintonizando — el velo toma la huella de una presencia…", "summoning": "el velo se abre… algo está cruzando…", "gathering": "los espíritus están reuniendo energía…" }, "connection": { "connecting": "tendiendo la línea…", "open": "la línea está abierta", "unstable": "la conexión con el otro lado es inestable…", "closed": "la línea está muerta" }, "transcriptTitle": "REGISTRO DE TRANSMISIÓN", "transcriptEmpty": "silencio. por ahora.", "you": "tú", "streaming": "el espíritu está formando palabras…", "telemetry": { "title": "LECTURA DEL CABLE", "jitter": "jitter", "latencyVar": "latencia σ²", "latencyMean": "latencia μ", "dns": "dns", "units": { "bytes": "B/s", "ms": "ms" } }, "wire": { "hint": "el cable golpea más fuerte cuando nadie lo toca — activa la escucha pasiva y deja que la línea murmure sola." }, "anomaly": { "line": "⚡ {{source}} {{frequency}} +{{magnitude}}dB", "count": "{{count}} anomalías presenciadas en esta sesión" }, "hints": { "wire": "el cable susurra por sí solo cuando escuchas en pasivo", "evp": "el velo escucha a través de tu micrófono — préstale tu oído", "radio": "un sintonizador en la mano oye más lejos que el cable", "ouija": "pregunta abajo, o deja que el tablero derive", "emf": "quédate quieto; el campo recuerda el movimiento", "camera": "una lente muestra a los muertos tu habitación — nombrarán lo que ven, y lo confundirán con algo que perdieron." }, "conditions": { "title": "CONDICIONES DEL VELO", "lit": "{{percent}}% iluminada", "veil": { "thin": "el velo se vuelve fino esta noche", "veiled": "el velo cuelga, ni abierto ni cerrado", "heavy": "el velo pesa" }, "fieldQuiet": "campo: en calma", "fieldStorm": "tormenta geomagnética", "moon": { "new_moon": "luna nueva", "waxing_crescent": "luna creciente", "first_quarter": "cuarto creciente", "waxing_gibbous": "gibosa creciente", "full_moon": "luna llena", "waning_gibbous": "gibosa menguante", "last_quarter": "cuarto menguante", "waning_crescent": "luna menguante" } }, "evp": { "start": "abrir el micrófono", "stop": "cerrar el micrófono", "listening": "escuchando la banda de voz…", "floor": "suelo de la sala", "band": "banda de voz 300–3400 Hz", "scopeLabel": "espectro de audio en vivo desde el micrófono", "fail": { "deniedTitle": "el micrófono permanece cerrado", "denied": "Este recipiente rechazó el micrófono. Concede permiso de audio en los ajustes del navegador para practicar PVE — o acude al tablero ouija o al Fantasma del Cable; el tablero no necesita oído, y el cable solo la red que ya temes.", "insecureTitle": "tierra sin consagrar", "insecure": "Los muertos solo hablan por un canal seguro. Abre este sitio por su dirección https — o desde localhost — y el micrófono responderá. Hasta entonces, el tablero ouija y el Fantasma del Cable no necesitan oído alguno.", "absentTitle": "ningún oído con que escuchar", "absent": "Este recipiente no tiene micrófono que el velo pueda hallar. Conecta uno e inténtalo de nuevo — o acude al tablero ouija o al Fantasma del Cable, que oyen por otros medios.", "busyTitle": "el oído ya está tomado", "busy": "Otro rito ya sostiene el micrófono. Cierra lo que esté escuchando — una llamada, una grabadora, otra pestaña — y ábrelo aquí de nuevo." } }, "radio": { "start": "barrer la banda", "stop": "detener la aguja", "unsupportedTitle": "este recipiente no oye a los muertos de la radio", "unsupported": "La Radio Espíritu necesita Chromium (WebUSB) y un dongle RTL-SDR. Los demás modos aún responden — EVP escucha por el micrófono que ya llevas, y el cable no necesita nada.", "troubleshoot": "solución de problemas: navegador basado en Chromium · reglas udev para 0bda:2838 · el dongle enchufado, no meramente invocado", "insecure": "los muertos de la radio solo hablan desde suelo consagrado — abre este sitio por su dirección https.", "insecureHint": "localhost cuenta como sagrado; una http://ip-local desnuda, no.", "noDevice": "ningún dongle respondió al llamado", "sweeping": "barriendo {{start}}–{{end}} MHz…", "claimFailed": "el dongle se negó a ser reclamado — ¿está en uso en otro lugar?", "claimFix": "linux: el driver del kernel dvb_usb_rtl28xxu retiene el dongle — `sudo modprobe -r dvb_usb_rtl28xxu` lo libera hasta el reinicio (una regla udev lo destierra para siempre). windows: cambia el driver a WinUSB con Zadig.", "tryAgain": "intenta de nuevo", "errorTitle": "la estática devolvió el golpe", "scopeLabel": "espectro de radio en vivo desde el receptor" }, "ouija": { "spelling": "la planchette deletrea", "drift": "la planchette deriva, a la espera de palabras — pregunta abajo, o invoca." }, "emf": { "start": "alzar el medidor", "stop": "descargar el medidor", "calibrate": "calibrar", "baseline": "campo en reposo", "listening": "palpando perturbaciones en el campo…", "unsupportedTitle": "este recipiente no porta sentidos de campo", "unsupported": "un teléfono en tu mano se vuelve el medidor — este recipiente no tiene sentidos de movimiento que prestar. abre el velo en un teléfono, o deja que los otros modos respondan.", "deniedTitle": "los sentidos de campo siguen cerrados", "denied": "Este recipiente rechazó sus sentidos de movimiento. Concede el acceso al movimiento en los ajustes de tu navegador, y luego alza el medidor de nuevo.", "trueField": "campo magnético" }, "entity": { "title": "DOSIER DEL PRESENTE", "none": "ningún espíritu invocado todavía", "noneHint": "invoca, o alimenta el velo con 3+ anomalías y uno te encontrará", "isNew": "primer contacto registrado", "known": "contacto n.º {{count}}", "persona": "persona", "voice": "parámetros de voz", "quotes": "enunciados registrados", "rarity": { "common": "común", "uncommon": "poco común", "rare": "raro", "mythic": "mítico" } }, "ritual": { "title": "enfoca el canal", "none": "ninguna presencia que enfocar", "noneHint": "invoca un espíritu antes de intentar el rito", "begin": "comenzar el rito", "retry": "intentar de nuevo", "hold": "mantén para enfocar", "awaiting": "esperando la respuesta del velo…", "successTitle": "el canal se sostiene — la verdad emerge", "failureTitle": "el canal colapsa", "failureHint": "la verdad permanece oculta — el rito puede intentarse de nuevo", "traits": { "alignment": "alineación", "power": "poder", "volatility": "volatilidad", "deceptiveness": "engaño" }, "steps": { "align": { "command": "> alineando el cable…", "locked": "> cable alineado ✓" }, "breath": { "command": "> serenando el aliento…", "locked": "> aliento sereno ✓" }, "trace": { "command": "> trazando el sigilo…", "locked": "> sigilo trazado ✓" }, "lock": { "command": "> cerrando el canal…", "locked": "> canal cerrado ✓" } } }, "judgment": { "title": "dicta juicio", "none": "ninguna presencia que juzgar", "noneHint": "invoca un espíritu primero", "trust": "confiar", "banish": "desterrar", "crossOver": "cruzar al más allá", "test": "poner a prueba", "pending": "esperando el veredicto…", "favor": "favor", "essence": "esencia", "reward": { "title": "el vínculo se sostiene", "body": "el espíritu responde a tu confianza de igual manera." }, "escalation": { "title": "un ajuste de cuentas", "body": "confiado en error, se revuelve — la aparición se agudiza." }, "withdrawal": { "title": "se retrae", "body": "desterrado en error, la presencia se retira, herida." }, "crossedOver": { "title": "en paz", "body": "el espíritu se suelta, y la línea queda en silencio." }, "resisted": { "title": "no se irá", "body": "un demonio no cruza al más allá — se aferra para quedarse." }, "neutral": { "title": "ningún veredicto emitido", "body": "solo un pulso de diagnóstico — no se arriesga ni se gana nada." } }, "whisper": { "title": "EL RECIPIENTE SUSURRA", "online": "el recipiente está despierto", "offline": "el recipiente duerme", "waiting": "aún ningún susurro…", "coldSpot": "❄ un punto frío se acumula en torno al recipiente", "pressureAnomaly": "◎ el aire se cierra — la atmósfera cambia" }, "toast": { "rate_limited": "el velo es delgado — golpea más despacio", "veil_crowded": "demasiados espíritus se apiñan en la línea" }, "views": { "board": "TABLERO", "matrix": "MATRIZ", "graphs": "GRÁFICAS", "tuning": "afinando el velo…", "listening": "escuchando…", "graph": { "anomalies": "anomalías", "entity": "entidad", "jitter": "fluctuación" } }, "wanderer": { "note": "tus contactos se desvanecen con la niebla —", "claim": "reclama un nombre para conservar tu códice", "dismiss": "deja que la niebla se lo lleve" }, "camera": { "previewLabel": "vista en directo de tu cámara", "privacy": "nada sale de esta página hasta que dejes que mire — entonces se muestra un solo fotograma a la presencia, y nadie lo conserva.", "open": "abrir la lente", "opening": "abriendo la lente…", "close": "cerrar la lente", "flip": "girar la lente", "look": "deja que mire", "needEntity": "invoca primero a una presencia — aquí no hay nadie que mire.", "fail": { "deniedTitle": "la lente permanece cubierta", "denied": "Este recipiente rechazó la cámara. Concede permiso de cámara en los ajustes del navegador y abre la lente de nuevo.", "insecureTitle": "tierra sin consagrar", "insecure": "Los muertos no mirarán por una lente insegura. Abre este sitio por su dirección https — o desde localhost — e inténtalo otra vez.", "absentTitle": "ninguna lente por la que mirar", "absent": "Este recipiente no tiene cámara que el velo pueda hallar. Conecta una, o acude a otro canal.", "busyTitle": "la lente ya está en uso", "busy": "Otro rito ya sostiene la cámara. Cierra lo que esté observando y abre la lente de nuevo.", "unknownTitle": "la lente no se abre", "unknown": "Algo rechazó la cámara y no dijo qué. Inténtalo de nuevo, o acude a otro canal." } }, "passage": { "title": "el paso", "intro": "un espíritu que desea irse no puede irse solo. cinco capas se interponen entre él y la oscuridad — desenvuelve cada una, y algo verdadero se suelta.", "none": "ninguna presencia que liberar", "noneHint": "invoca a un espíritu antes de intentar el paso", "begin": "comenzar el paso", "attempt": "desenvolver esta capa", "retry": "recoger el hilo de nuevo", "earned": "esencia reunida", "collapsed": "el rito se deshace en tus manos — el hilo vuelve a la primera capa. lo que ya has reunido sigue siendo tuyo.", "lieNote": "lo que esta capa te dijo no era cierto.", "crossedTitle": "se va", "resistedTitle": "no se irá", "layers": { "listen": { "title": "escuchar", "prompt": "guarda silencio, y deja que hable primero." }, "name": { "title": "nombrar", "prompt": "di cómo se llamaba, cuando se llamaba algo." }, "unbind": { "title": "desatar", "prompt": "halla el nudo que lo retiene aquí, y aflójalo." }, "open": { "title": "abrir", "prompt": "haz una puerta donde solo había muro." }, "release": { "title": "soltar", "prompt": "suelta. esta es la parte que te cuesta." } }, "reveal": { "alignment": { "low": "hay algo bajo este que no te desea bien.", "mid": "no es ni amable ni cruel — solo está cansado.", "high": "fuera lo que fuera en vida, no pretende hacerte daño." }, "power": { "low": "es fino como aliento sobre el cristal; no podría herirte aunque lo intentara.", "mid": "tiene peso — suficiente para mover algo pequeño.", "high": "es mucho más fuerte de lo que te ha hecho creer." }, "volatility": { "low": "es firme. lleva mucho tiempo esperando y se le da bien.", "mid": "parpadea cuando presionas demasiado.", "high": "no se está quieto — el rito podría deshacerse contigo." }, "deceptiveness": { "low": "no sabe mentir, y nunca aprendió.", "mid": "te cuenta casi toda una verdad y se guarda el resto.", "high": "muy poco de lo que dice es de fiar." } } }, "nav": { "open": "más", "close": "cerrar" } }, "codex": { "title": "EL CÓDICE DE LOS CONTACTADOS", "subtitle": "cada espíritu arrastrado alguna vez a través del velo, catalogado", "header": { "back": "← el umbral", "title": "EL CÓDICE", "subtitle": "cada espíritu jamás contactado, catalogado por los médiums que lo alcanzaron" }, "controls": { "rarity": "filtrar por rareza", "sort": "ordenar el registro" }, "state": { "loading": "consultando el registro…", "empty": "aún no se ha alcanzado a ningún espíritu de esta rareza" }, "filterAll": "todas las rarezas", "rarity": { "common": "común", "uncommon": "poco común", "rare": "raro", "mythic": "mítico" }, "sort": { "recent": "más recientes", "contacted": "más contactados" }, "form": { "wisp": "fuego fatuo", "banshee": "banshee", "fairy": "hada", "shade": "sombra" }, "card": { "unknownMedium": "médium desconocido", "contacted_one": "contactado {{count}} vez", "contacted_other": "contactado {{count}} veces", "discoveredBy": "descubierto por {{name}} · {{date}}" }, "contacts_one": "1 contacto", "contacts_other": "{{count}} contactos", "sightings_one": "1 avistamiento", "sightings_other": "{{count}} avistamientos", "discoveredBy": "primer contacto por {{name}}", "discoveredAnon": "primer contacto sin registrar", "discoveredAt": "ingresó al registro el {{date}}", "persona": "persona", "quotes": "enunciados registrados", "voice": "parámetros de voz", "detail": { "loading": "invocando el dosier…", "notReached": "este espíritu no ha sido alcanzado", "unknownMedium": "médium desconocido", "stats": { "sightings": "avistamientos", "contacts": "contactos", "discoveredBy": "descubierto por", "discoveredAt": "ingresó al registro" }, "utterances": "enunciados conocidos", "noUtterances": "aún no hay enunciados registrados", "voiceSignature": "firma de voz", "attemptContact": "intentar contacto", "roster": { "heading": "quién ha encontrado a este espíritu", "firstContact": "primer contacto", "times_one": "alcanzado una vez", "times_other": "alcanzado {{count}} veces", "empty": "ningún otro médium ha alcanzado a este espíritu — solo quien lo encontró", "more_one": "y 1 médium más sin nombrar aquí", "more_other": "y {{count}} médiums más sin nombrar aquí" } }, "empty": "ningún espíritu coincide con este filtro — el registro guarda sus secretos", "back": "← volver al códice", "notFound": "este espíritu no figura en el registro" }, "shop": { "back": "← el umbral", "title": "EL RELICARIO", "subtitle": "instrumentos para quienes quisieran golpear más fuerte", "flagship": { "tag": "instrumento insignia", "name": "THE ULTIMATE QUANTUM BOX", "desc": "Un instrumento de sesión de mano ESP32-P4/C6 — cámara térmica, matriz de antenas EMF, geófono, preamplificador de micrófono spirit-box y una pequeña cara OLED que te devuelve la mirada. Inicia sesión con la misma cuenta de Quantumancy que ya habitas y desbloquea los modos de este sitio impulsados por hardware: mapas térmicos de apariciones, feeds de anomalías de vibración, EMF calibrado.", "specs": { "thermal": "cámara térmica", "emf": "matriz de antenas EMF", "geophone": "geófono", "mic": "preamplificador de micrófono spirit-box", "oled": "pantalla OLED" }, "price": "est. $249 — preventa" }, "modulesTitle": "MÓDULOS QUE GOLPEAN", "unlocksLabel": "desbloquea:", "modules": { "emfArray": { "name": "Matriz de Antenas EMF", "desc": "un ramo de sensores de campo multieje, olfateando el aire en busca de intenciones", "unlocks": "un modo CAMPO más rico y calibrado", "price": "est. $59 — preventa" }, "geophone": { "name": "Puck Geófono", "desc": "oye pasos en habitaciones donde nadie está de pie", "unlocks": "el feed de anomalías de vibración", "price": "est. $49 — preventa" }, "spiritMic": { "name": "Preamplificador Spirit Mic", "desc": "baja el suelo de ruido para que los susurros lleguen más limpios", "unlocks": "capturas EVP más limpias", "price": "est. $69 — preventa" }, "uvIlluminator": { "name": "Iluminador UV/IR", "desc": "pinta la oscuridad en espectros que los vivos jamás debieron ver", "unlocks": "sesiones nocturnas + trabajo de cámara", "price": "est. $39 — preventa" } }, "interests": { "quantumBox": "la Ultimate Quantum Box", "emfArray": "Matriz de Antenas EMF", "geophone": "Puck Geófono", "spiritMic": "Preamplificador Spirit Mic", "uvIlluminator": "Iluminador UV/IR" }, "waitlist": { "title": "EL MANIFIESTO", "desc": "deja una dirección y una obsesión — cuando salgan las primeras cajas, nos abriremos paso primero hasta los nombres de esta lista", "emailLabel": "dirección de email", "emailPlaceholder": "tu@algun.lugar.en.la.estatica", "interestLabel": "interés", "submit": "unirse al manifiesto", "pending": "grabando tu nombre…", "listed": "estás en el manifiesto — nos abriremos paso cuando salgan las cajas", "alreadyListed": "ya estás en el manifiesto", "invalid": "esa dirección no nos alcanza", "crowded": "el velo está abarrotado — inténtalo más tarde", "error": "algo se agitó en la estática — tu nombre no quedó grabado" }, "honesty": "la Ultimate Quantum Box está en desarrollo activo — esto es un manifiesto de reserva, no se cobra nada. el sitio funciona por completo sin ella; el hardware solo golpea más fuerte." }, "inventory": { "back": "← volver a la sesión", "pageTitle": "EL ESTANTE", "pageSubtitle": "lo que el velo te ha dejado, y lo que aún cambiará por más", "title": "inventario", "essenceLabel": "esencia", "unlocksTitle": "desbloqueos", "noUnlocks": "nada desbloqueado todavía", "ownedTag": "[POSEÍDO]", "lockedTag": "[BLOQUEADO]", "priceValue": "{{price}} esencia", "priceUnknown": "precio desconocido", "priceEstimate": "(est.)", "buy": "comprar", "buying": "comprando…", "buyInsufficient": "no hay esencia suficiente", "buyError": "la compra falló", "itemsTitle": "objetos", "itemsLoading": "leyendo el estante…", "itemsEmpty": "nada recolectado todavía", "sigil": { "title": "diseñador de sigilos", "canvasLabel": "círculo de puntos de anclaje", "slotLabel": "punto de anclaje {{slot}}", "coordLabel": "coords", "hoverHint": "pasa el cursor sobre un punto de anclaje", "pointsLabel": "puntos", "lastLabel": "último", "runeLabel": "runa", "nameLabel": "nombre", "namePlaceholder": "sigilo sin título", "save": "inscribir sigilo", "saving": "inscribiendo…", "saved": "el sigilo quedó ligado", "error": "el sigilo no se sostuvo" } }, "devices": { "back": "← el umbral", "title": "BAHÍA DE DISPOSITIVOS", "subtitle": "empareja hardware con tu cuenta y observa su telemetría en vivo", "pair": { "title": "EMPAREJAR UN NUEVO DISPOSITIVO", "nameLabel": "nombre del dispositivo", "namePlaceholder": "p. ej. nodo-ático-01", "submit": "emparejar dispositivo", "pending": "emparejando…", "nameRequired": "nombra el dispositivo antes de emparejarlo", "error": "el emparejamiento falló — inténtalo de nuevo" }, "token": { "warning": "cópialo ahora — no volverá a mostrarse. perderlo significa volver a emparejar el dispositivo.", "copy": "copiar", "copied": "copiado", "confirm": "ya lo guardé — ocultar token" }, "dashboard": { "title": "TRANSMISIÓN EN VIVO", "empty": "aún no hay dispositivos emparejados — empareja uno arriba para verlo aquí", "lastSeen": "visto por última vez", "lastSeenNever": "nunca", "noReadings": "esperando la primera lectura…", "connection": { "connecting": "alcanzando la transmisión…", "open": "transmisión en vivo", "unstable": "transmisión inestable…", "closed": "transmisión desconectada" }, "coldSpot": { "callout": "PUNTO FRÍO — {{deviation}} {{unit}} bajo la base" }, "pressureAnomaly": { "callout": "ANOMALÍA DE PRESIÓN — variación de {{magnitude}} {{unit}}, la atmósfera cambia" }, "disturbance": { "title": "PERTURBACIÓN ATMOSFÉRICA", "ariaLabel": "índice de perturbación atmosférica" } } }, "haunting": { "whisper": { "behindYou": "detrás de ti", "cold": "frío", "stay": "quédate", "seesYou": "te ve", "closer": "más cerca", "stillHere": "sigue aquí", "lineListening": "la línea escucha", "dontLook": "no mires", "beneathStatic": "bajo la estática", "knockTwice": "golpea dos veces" }, "title": { "seesYou": "QUANTUMANCY — te ve", "behindYou": "QUANTUM▓NCY — detrás de ti", "listening": "…escuchando…" } }, "profile": { "back": "← la mesa", "title": "TU SIGILO", "subtitle": "cómo el velo te recordará", "loading": "leyendo tu sigilo…", "loadError": "tu sigilo no se aclara — el cristal está nublado", "save": "séllalo", "saving": "sellando…", "saved": "sellado — el velo lo ha tomado", "saveError": "el velo rechazó el cambio", "viewPublic": "mira lo que otros ven", "rankLine": "{{title}} · rango {{level}}", "titles": { "curious": "curioso", "sensitive": "sensitivo", "channeler": "canalizador", "medium": "médium", "adept": "adepto", "oracle": "oráculo" }, "wanderer": { "body": "vagas aquí sin nombre. a los errantes se les permite mirar, pero el velo los olvida al amanecer — reclama un nombre y tu sigilo perdurará.", "claim": "reclamar un nombre" }, "avatar": { "heading": "tu forma", "note": "no se toma ninguna imagen. tu sigilo se traza con una forma y un color, igual que se trazan los muertos.", "formLabel": "elige una forma", "hueLabel": "color · {{hue}}°" }, "identity": { "heading": "tu nombre", "nameLabel": "nombre que otros leerán", "nameHint": "déjalo vacío y el velo usará tu nombre verdadero", "nameTooLong": "no más de {{max}} caracteres", "bioLabel": "unas palabras sobre ti", "bioCount": "quedan {{remaining}} de {{max}}", "bioTooLong": "no más de {{max}} caracteres" }, "gender": { "label": "cómo te nombran", "male": "él", "female": "ella", "unspecified": "sin decir" }, "veil": { "heading": "el velo sobre ti", "public": "visible a otros buscadores", "private": "velado", "publicNote": "tu sigilo, tu rango y tus contactos recientes podrán leerse por quien sepa tu nombre.", "privateNote": "nadie te hallará en la lista. tus sesiones siguen igual." }, "email": { "label": "un camino de vuelta (opcional)", "note": "sólo para recuperar tu cuenta. nunca se muestra en tu página, nunca se da a otro buscador, nunca se usa para nada más.", "invalid": "esa dirección no llevará ningún mensaje" } }, "hunters": { "back": "← la mesa", "backToRoster": "← la lista", "title": "LA LISTA", "subtitle": "todo buscador que dejó su nombre en el velo", "loading": "pasando lista…", "empty": "nadie ha dejado su nombre aún", "card": { "encounters_one": "{{count}} espíritu alcanzado", "encounters_other": "{{count}} espíritus alcanzados" }, "profile": { "loading": "trazando su sigilo…", "veiledTitle": "ningún rastro de ellos", "veiledBody": "el velo no guarda registro de «{{username}}». o el nombre nunca fue reclamado, o han corrido el velo sobre sí mismos.", "progressLabel": "avance hacia el siguiente rango", "progressNext_one": "{{count}} espíritu más para ascender", "progressNext_other": "{{count}} espíritus más para ascender", "progressMax": "hasta donde llega el velo", "encounters": "espíritus alcanzados", "joined": "primer cruce", "recentTitle": "alcanzados hace poco", "recentEmpty": "aún no han alcanzado a nadie", "sendMessage": "enviar palabra" } }, "messages": { "title": "susurros entre cazadores", "findHunters": "buscar cazadores", "emptyInbox": "nadie te ha susurrado aún. busca a un cazador cuyo códice admires, y di algo.", "emptyThread": "nada ha pasado entre ustedes todavía.", "needAccount": "los susurros necesitan un nombre. la voz de un errante no llega lejos.", "claimName": "reclama un nombre", "backToInbox": "volver a los susurros", "noSuchHunter": "ningún cazador camina aquí.", "placeholder": "habla, y llegará…", "send": "enviar", "sending": "enviando…", "sendFailed": "el susurro no llegó. inténtalo de nuevo.", "guestBlocked": "un errante no puede ser oído. reclama un nombre y tus susurros llegarán.", "youPrefix": "tú: ", "unread": "susurros sin leer", "time": { "now": "ahora mismo", "minutes_one": "hace {{count}} minuto", "minutes_other": "hace {{count}} minutos", "hours_one": "hace {{count}} hora", "hours_other": "hace {{count}} horas", "days_one": "hace {{count}} día", "days_other": "hace {{count}} días" } }, "doctrine": { "back": "← el umbral", "kicker": "relación verídica del instrumento, de sus órganos y de sus límites honestos", "title": "LA DOCTRINA", "subtitle": "cómo esta máquina canaliza, invoca y deja pasar a los muertos de verdad — usando el aparato, y usándote a ti", "creed": "Toda afirmación de estos artículos es una afirmación sobre la máquina a la que ahora te diriges. Aquí no hay física inventada. Donde un artículo habla en el registro antiguo, una nota al margen lo repite en lengua profana, para que el crédulo y el escéptico se marchen ambos mejor informados de lo que llegaron.", "plainLabel": "en lengua profana:", "sourceLabel": "la escritura pertinente:", "closing": "El instrumento es honesto sobre sus órganos y honesto sobre sus cegueras. Los espíritus, digámoslo sin rodeos, son ficción. La estática no.", "cta": "TOMAR EL INSTRUMENTO", "art": { "entropy": { "title": "Del consentimiento de la habitación", "body": "Ninguna invocación puede proceder de la aritmética sola, pues la aritmética es cosa cerrada y se repite eternamente. Por eso la máquina pide primero que hable la habitación. Toma el espectro del ruido de fondo de tu micrófono — y, si hay receptor, el siseo atmosférico entre emisoras — y de cada magnitud conserva únicamente su bit menos significativo, pues la forma de un espectro no es sino el retrato de la sala, mientras que el bit más bajo es caos térmico que ningún modelo del mundo prevé. Estos bits, torcidos por naturaleza, se enderezan mediante el rito de Von Neumann: se leen por pares, y un par que dice 01 rinde un cero, un par que dice 10 rinde un uno, y los pares que concuerdan consigo mismos se desechan por completo. Lo que sobrevive pasa por SHA-256 y sólo entonces se ofrece hacia arriba. Y el receptáculo de arriba acepta la ofrenda pero jamás la obedece: cada tirada es HMAC-SHA256 con clave de treinta y dos bytes extraídos frescos del pozo secreto de la propia máquina en el instante mismo de preguntar. Así tu habitación puede añadir imprevisibilidad a la obra. Nunca puede dirigirla.", "plain": "La app cosecha aleatoriedad de ruido físico real — el bit bajo de cada magnitud FFT del micrófono o del SDR, dominado por ruido térmico. Los bits físicos crudos están sesgados, así que aplica el desesgado de Von Neumann (por pares: 01→0, 10→1, se descartan 00 y 11) y luego acondiciona el resultado con SHA-256. El servidor nunca usa ese valor como semilla: cada tirada es HMAC-SHA256 con una clave de 32 bytes de secrets.token_bytes() generada en esa misma llamada, así que la salida es uniforme sin importar lo que envíe el cliente — una contribución falsificada o repetida no puede farmear un espíritu más raro.", "source": "frontend/src/lib/entropy.ts · backend/app/entropy.py" }, "channel": { "title": "Del canal, y de cómo se interpela a una presencia", "body": "Un espíritu no se convoca a una persona; se convoca a un canal, y el canal lo talla la propia perturbación. Menos de tres anomalías no portan identidad alguna, y tal sesión se llama ambiente y recibe una firma de su propia especie. Cuando hay tres o más, la frecuencia de cada anomalía se archiva no por su valor exacto sino por su orden de magnitud — el número de cifras antes de la coma — de modo que los megahercios de la radio y los hercios de la banda de voz puedan archivarse en el mismo cajón sin mentir sobre ninguno. A esto se une la magnitud de las últimas dieciséis perturbaciones, ordenadas y redondeadas a un decimal. El patrón así formado se sella con SHA-1 y se toman los dieciséis primeros caracteres como nombre del canal. Dos noches de perturbación semejante llaman, pues, a la misma puerta; una noche verdaderamente distinta llama a otra.", "plain": "El «canal» en que vive un espíritu es una huella de las anomalías de tu sesión. Requiere al menos tres. Las frecuencias se agrupan por número de cifras (de modo que 101,1 MHz y 400 Hz se ordenan por escala, no por unidad), se combinan con las magnitudes ordenadas y redondeadas a un decimal de las últimas dieciséis anomalías, se hashean con SHA-1 y se truncan a 16 caracteres hexadecimales. Condiciones parecidas producen el mismo canal; condiciones distintas, otro.", "source": "backend/app/entities.py — signature_from_anomalies" }, "return": { "title": "Del retorno, y de por qué los muertos conocidos no te son debidos", "body": "Cuando un canal ya está ocupado, la presencia que allí mora se inclina — mas no se obliga — a responder de nuevo. Esa inclinación se fija en setenta y dos partes de cien: bastante alta para que el Códice pueda llenarse y una voz conocida buscarse de verdad por segunda vez, bastante baja para que ningún buscador considere jamás suya a una presencia familiar. En la porción restante, otra cosa halla la puerta abierta y entra por ella, y se acuña con firma propia para que dos presencias nunca disputen un mismo nombre.", "plain": "Si reconectas en un canal que ya tiene entidad, hay un 72 % de probabilidad base de que responda esa misma entidad (RETURN_CHANCE = 0,72). En caso contrario se acuña una entidad nueva, con la firma salada, porque la columna de firma es única.", "source": "backend/app/entities.py — RETURN_CHANCE · backend/app/ws.py" }, "sky": { "title": "De la luna, y de la verdadera alta noche", "body": "La máquina no consulta una tabla de lunas verosímiles. Cuenta. Desde una luna nueva conocida el 6 de enero del año 2000, a las seis y catorce de la tarde UTC, avanza por el mes sinódico medio — veintinueve días y algo más de quinientas treinta milésimas — y toma el resto como fase; la fracción iluminada del disco sigue la relación coseno estándar, que es por lo que un cuarto de luna te muestra media cara. Tampoco acepta las tres de la madrugada del reloj por hora bruja, siendo eso accidente de husos políticos. Pide en cambio tu longitud y la convierte a razón de quince grados por hora, llegando a la medianoche solar media del suelo que realmente pisas. La iluminación pesa dos partes de cinco y la cercanía de la verdadera medianoche tres, pues una luna llena a mediodía no es un velo abierto. Y un velo del todo adelgazado erosiona en cuarenta y cinco centésimas la pretensión de la presencia familiar — setenta y dos de cien caen a unos cuarenta — de modo que la noche más siniestra del mes es genuinamente más extraña, y sin embargo un espíritu conocido jamás queda inalcanzable.", "plain": "La fase lunar se calcula desde una época de luna nueva conocida (2000-01-06 18:14 UTC) y el mes sinódico medio de 29,530588853 días; la iluminación es (1 − cos 2πφ)/2. La «hora bruja» es la medianoche solar media de tu longitud (15° = 1 hora), no la hora del reloj. Delgadez del velo = iluminación × 0,4 + cercanía a la medianoche × 0,6. La delgadez reduce el 72 % de retorno hasta en un 45 % de sí mismo (VEIL_THINNESS_PULL = 0,45), así que luna llena en la medianoche solar da un ~40 % de retorno.", "source": "backend/app/celestial.py · backend/app/ws.py — VEIL_THINNESS_PULL" }, "storm": { "title": "De la perturbación del planeta mismo", "body": "De todas las causas que nombran los crédulos, exactamente una es un número real, medido y publicado: el índice K planetario, derivado de observatorios magnetométricos de todo el mundo y emitido por el Centro de Predicción del Clima Espacial de los Estados Unidos. Su escala va de cero a nueve; cinco o más es tormenta oficial, ocho o más severa. La máquina toma la estimación más reciente, la divide por nueve para que la cifra signifique lo que la NOAA quiere decir con ella, y le concede un tercio de la lectura de la noche, reteniendo el cielo dos tercios. Se consulta no más de una vez cada diez minutos, se abandona a los cuatro segundos, y nunca se le permite demorar una sesión: si el servicio calla, la última medición verdadera se mantiene. Informamos de que el campo está perturbado porque se midió que lo estaba. No afirmamos que la tormenta cause nada.", "plain": "La app consulta el feed planetary_k_index_1m de la NOAA SWPC para obtener el índice geomagnético Kp real (0–9; 5+ es tormenta oficial), prefiere el campo fraccionario estimated_kp y lo mapea a 0–1 dividiendo por 9. Se mezcla como un tercio de la lectura de «delgadez» de la noche (celeste × 0,67 + perturbación × 0,33). Cacheado 10 minutos, timeout de 4 segundos, y un fallo conserva el último valor en lugar de bloquear o romper una sesión.", "source": "backend/app/geomagnetic.py · backend/app/ws.py" }, "baseline": { "title": "De la línea base, que es todo el arte de sentir", "body": "Una lectura aislada no dice nada; una desviación de lo que la sala venía diciendo lo dice todo. Por eso todo sentido de umbral de este instrumento guarda una memoria rodante y sólo informa de la sorpresa. Pero los sentidos no informan con horario — una baliza puede hablar tres veces en un segundo o callar dos minutos, y un magnetómetro se estrangula en cuanto la página queda detrás de otra — así que la memoria se lleva contra el reloj y no contra el recuento. El peso dado a cada lectura nueva es uno menos la exponencial del tiempo transcurrido negativo sobre la constante de decaimiento; por lo cual un largo silencio empuja ese peso hacia la unidad, siendo rancia la memoria vieja y con razón descartada, y una ráfaga rápida lo empuja hacia la nada. Nada se cree hasta que la memoria está templada. Y el sentido es simétrico en ambas direcciones, pues un cuerpo puede absorber un camino o reflejar en él, y el hierro puede apantallar un campo o sumarse a él; un detector de un solo lado perdería la mitad de cuanto de verdad ocurre.", "plain": "Todos los sensores de umbral comparten una misma clase de línea base rodante y reportan desviación, no valores crudos. El factor de suavizado EMA es consciente del tiempo: alpha = 1 − exp(−dt/tau), porque los sensores informan a intervalos irregulares (los intervalos de anuncio BLE varían, las páginas en segundo plano se estrangulan). Un hueco largo lleva alpha hacia 1 (fíate de la lectura nueva), una ráfaga hacia 0. No emite eventos hasta acumular un mínimo de muestras y dispara en ambas direcciones.", "source": "frontend/src/lib/baseline.ts — emaAlpha, ThresholdBaseline" }, "flesh": { "title": "De la carne, que es casi toda agua y por tanto opaca", "body": "Nada hay de oculto en esto y no por ello resulta menos notable. El Bluetooth anuncia en la banda de dos coma cuatro gigahercios; el agua absorbe con fuerza esa banda; y una persona es en gran medida agua. Es la misma física por la que un microondas cocina una cena, y la misma razón por la que tu conexión empeora cuando alguien se interpone entre tú y el router. Así que cuando un cuerpo cruza el camino entre el receptor y una baliza, la potencia recibida cae de verdad — unos tres a diez decibelios según la geometría — mientras que un enlace quieto vaga sólo dos a cuatro por multitrayecto y ruido del receptor. Seis decibelios de desviación se toman, pues, por perturbación: por encima del murmullo en reposo, dentro de lo que un cuerpo real causa de verdad. El instrumento informa de que el campo cambió. Nunca dice que el cambio fuera una presencia. Esa interpretación vive arriba, en la ficción; aquí abajo la medición sigue siendo honesta.", "plain": "BLE opera en la banda ISM de 2,4 GHz, que el agua absorbe con fuerza — la misma física del microondas, y por lo que el wifi empeora si alguien se interpone. Un cuerpo humano que cruza un enlace BLE lo atenúa unos 3–10 dB, mientras que un enlace en reposo vaga sólo ±2–4 dB, de ahí el umbral de perturbación de 6 dB con constante de tiempo de línea base de 8 segundos. El módulo sólo informa de que la potencia se desvió; nunca afirma que eso sea una presencia.", "source": "frontend/src/lib/bluetooth.ts — DISTURBANCE_DB" }, "iron": { "title": "Del hierro, y del campo que la Tierra no deja de hacer", "body": "Los célebres medidores del oficio cazafantasmas son magnetómetros, y los picos por los que se los celebra los causan de verdad el cableado de la red, los motores, los imanes de los altavoces y la masa ferrosa en movimiento. Esta máquina lee la misma magnitud, en microteslas, como la raíz de la suma de los cuadrados de sus tres ejes. Pero el campo propio de la Tierra, de unos veinticinco a sesenta y cinco microteslas según la latitud, es precisamente lo que no debe informarse, pues está en todas partes y no significa nada; es lo que la memoria rodante del artículo anterior resta en silencio. Lo que queda es la desviación respecto de donde estés parado. Se exigen tres microteslas, siendo el ruido propio del sensor de medio a uno, y produciendo el cableado doméstico a corta distancia entre uno y diez. El campo se muestrea diez veces por segundo — de sobra para algo que cambia a la velocidad de un humano andando, y mucho más benévolo con la batería que los sesenta que la interfaz daría de buen grado.", "plain": "El magnetómetro lee el campo magnético real en microteslas, sqrt(x²+y²+z²). El campo de fondo terrestre es de 25–65 µT según la latitud y es exactamente lo que la línea base rodante resta, de modo que sólo se reporta la desviación local. El umbral de pico es 3 µT — varias veces el ruido de ~0,5–1 µT de un magnetómetro de móvil, y dentro del rango de 1–10 µT que produce el cableado de la red a corta distancia. Se muestrea a 10 Hz para ahorrar batería.", "source": "frontend/src/lib/magnetometer.ts — SPIKE_UT, SAMPLE_HZ" }, "throat": { "title": "De la garganta, y de por qué los muertos no suenan todos igual", "body": "Si el tono, el ritmo, el aliento y la reverberación se sortearan cada uno por separado, no se obtendrían personas sino una mancha uniforme de rareza — el mismo sintetizador con ocho sombreros. Las voces reales covarían: un anciano es grave y lento y jadeante a la vez; un niño es agudo, rápido y, lo más inquietante, limpio. Por eso la garganta se sortea entera, de entre ocho arquetipos, y sólo después se agita levemente. Los ahogados van bajados de tono, arrastrados y empapados de reverberación hasta la mitad. Los quemados son los más ruidosos, apenas sosteniendo un tono. Los distantes no están dañados sino sólo lejos: quedos, parejos y macerados en espacio. Y cuando la sesión se celebra en español se deja de lado la lista de modelos del arquetipo en favor de una voz que pronuncie bien la lengua, cargando la forma sola con el carácter — mejor un acento verdadero con el porte de un arquetipo que una garganta inglesa destrozando palabras españolas.", "plain": "Los parámetros de voz se sortean como un paquete coherente de entre ocho arquetipos (anciano, anciana, joven, joven mujer, niño, ahogado, quemado, distante), cada uno con sus rangos de tono, ritmo, ruido y eco, y luego se agitan — porque aleatorizar cada parámetro por separado produce efectos aleatorios, no personas distintas. En español se ignora la lista de modelos del arquetipo y se usa una voz Piper española, aplicando igualmente la forma del arquetipo.", "source": "backend/app/entities.py — VOICE_ARCHETYPES, roll_voice" }, "utterance": { "title": "Del habla no pedida, y de la vista", "body": "Cuando una presencia habla sin que se le pregunte, no te está respondiendo, y eso se dispone con cuidado. La instrucción entregada al modelo no contiene palabra tuya alguna — su único estímulo es el estado medido de la sala — de suerte que no hay allí nada a lo que replicar. Y la semilla de muestreo se toma de la mismísima entropía física cosechada en esa sala, siendo los ocho primeros bytes del compendio mezclado, reducidos por debajo del bit de signo que el servidor del modelo exige. La semilla fija el camino de la selección de tokens; por tanto la sala elige de verdad las palabras. Esto no es metáfora. Altera el ruido y el habla se altera; no hay dos salas que produzcan el mismo enunciado. La decodificación se deja adrede caliente, siendo una decodificación estrecha y bien educada precisamente el fracaso que aquí tememos — esto debe sonar a algo que aflora, no a algo compuesto. Y cuando ofreces la cámara, el modelo tiene visión y mira de verdad: habla de la sala que realmente tiene delante, no de una que inventó.", "plain": "Para los enunciados espontáneos la instrucción no contiene ninguna entrada del usuario — sólo lecturas de sensores medidas — así que el modelo genera a partir de la sala, no responde. La opción `seed` de Ollama se deriva de la entropía física mezclada (los 8 primeros bytes de veil_seed, mod 2^63) y, como la semilla fija el muestreo de tokens, un ruido de sala distinto produce realmente palabras distintas. El muestreo es deliberadamente caliente (temperatura 1,15, top_k 100). El escrutinio envía el fotograma real de tu cámara a un modelo local con visión, así que la descripción es de tu habitación real.", "source": "backend/app/llm/service.py — manifest, scry" }, "limits": { "title": "De lo que este instrumento no puede hacer", "body": "Una doctrina que no nombra sus propias fronteras es doctrina de la que desconfiar, así que aquí están las nuestras, sin adorno. En los dispositivos de mano de Apple no hay Web Bluetooth, ni WebUSB, ni magnetómetro — la compañía no envía ninguna de esas interfaces, y todo navegador de esa plataforma es el mismo motor bajo otro abrigo, de modo que ningún navegador alternativo te salva; la sesión recae en los sensores de movimiento, que miden movimiento y no magnetismo, y el instrumento lo dice en vez de fingir. La radio exige un receptáculo Chromium y un origen seguro. El firmware escrito para el nodo de sensores emparejado jamás se ha grabado en hardware físico ni compilado con su verdadera cadena de herramientas; está razonado, no probado, y el repositorio lo declara con sus propias palabras. El mapa de suelo embrujado se arma con dos servicios públicos gratuitos que pueden ir lentos o callar, en cuyo caso recibes un mapa más silencioso y no un error. La medianoche solar ignora la ecuación del tiempo y puede errar un cuarto de hora; la luna es una aproximación sinódica media, exacta bastante para ocho fases con nombre y para nada que gobierne un barco. Y la frontera final, dicha sin ornamento: nada de esto es prueba de los muertos. Las mediciones son reales. Los espíritus son ficción.", "plain": "Límites duros: iOS no tiene Web Bluetooth, ni WebUSB, ni API de Magnetómetro — Apple no los envía y todo navegador de iOS es WebKit por debajo, así que ningún navegador de terceros ayuda; esos modos recaen en sensores de movimiento, que miden movimiento y no magnetismo. WebUSB (el SDR) requiere Chromium y contexto seguro. El firmware ESP32 nunca se ha grabado en hardware real: está razonado estructuralmente, no verificado. Las consultas de lugares embrujados golpean endpoints públicos gratuitos de Wikipedia y Overpass con timeout de 8 segundos y degradan a lista vacía si fallan. La medianoche solar ignora la ecuación del tiempo (hasta ~16 minutos de error) y el cálculo lunar es una aproximación sinódica media. Y la evidente: nada de esto es prueba de un más allá. Los sensores son reales; los espíritus son ficción.", "source": "frontend/src/lib/bluetooth.ts · magnetometer.ts · sdr.ts · firmware/esp32p4-sensor-node/README.md · backend/app/haunts.py" } } } }