feat: legibility — conditions, hints, kinder errors (Workstream B)

GET /api/conditions surfaces what the backend already computes: moon
phase, veil thinness, geomagnetic state — junk lon degrades to moon-only
instead of a 422, missing NOAA data means fewer lines, never an error.
VeilConditions renders it in the séance side column, polling every 10 min.

ModeHint: one in-fiction line per mode after 15s of an unused sensor,
dismissed forever via localStorage. Error copy in evp/radio now
detect-and-redirects (mic denied -> 'the board needs no ear'; no WebUSB
-> try EVP) instead of dead-ending.

No geolocation prompt from the conditions strip — asking for location
from a passive readout would be hostile; ?lon= stays supported for
callers that have it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

# Conflicts:
#	frontend/src/pages/SeancePage.tsx
This commit is contained in:
Indiana
2026-07-28 19:19:44 +00:00
13 changed files with 579 additions and 4 deletions

View File

@@ -155,12 +155,40 @@
"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"
},
"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…",
"deniedTitle": "el micrófono sigue cerrado",
"denied": "Este recipiente rechazó el micrófono. Concede el permiso de audio en tu navegador para practicar EVP — o deja que el Fantasma del Cable escuche en tu lugar; no necesita más que la red que ya temes.",
"denied": "Este recipiente rechazó el micrófono. Concede el permiso de audio en los ajustes del sitio de tu navegador para practicar EVP — 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.",
"floor": "suelo de la sala",
"band": "banda de voz 300–3400 Hz",
"scopeLabel": "espectro de audio en vivo desde el micrófono"
@@ -169,7 +197,7 @@
"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 no — el cable y el micrófono aún responden.",
"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.",