66 lines
2.7 KiB
Markdown
66 lines
2.7 KiB
Markdown
# Observer Effect — doomsday clock
|
||
|
||
A period-styled (1964) clock for running Delta Green: *Observer Effect* online.
|
||
|
||
- **Player screen** — `observer.ellie.town/` (`clock.html`): an Olympian Holobeam
|
||
Array master chronometer. Nixie tubes counting toward 22:03:37, warning lamps
|
||
that flash on each pulse, a red wash and dissonant flutes/drums as communion
|
||
nears. Read-only; safe to share with the players.
|
||
- **Handler panel** — `observer.ellie.town/control` (`control.html`): run/hold,
|
||
scrub the clock, jump to any scenario beat, set the iteration (which resets
|
||
reality to its wake point), and fire pulse / communion / text effects on the
|
||
players' screen.
|
||
|
||
## How it syncs
|
||
|
||
A tiny Rust WebSocket relay (`relay/`) holds the one authoritative clock. The
|
||
panel sends authenticated commands; every connected screen gets the new state
|
||
and free-runs the digits locally between actions. Late joiners get the current
|
||
state immediately. Served behind nginx with TLS; the relay only listens on
|
||
loopback.
|
||
|
||
## Deploy
|
||
|
||
1. DNS: point `observer.ellie.town` at the VPS (A/AAAA). ACME does the cert.
|
||
2. It's already wired into `flake.nix` (vps modules) as
|
||
`./services/observer-effect.nix`. Rebuild the VPS:
|
||
`nixos-rebuild switch --flake .#vps` (however you normally deploy).
|
||
|
||
## The control key
|
||
|
||
Commands are authenticated with a shared token in `services/secrets/observer_vps.yaml`
|
||
(sops). Enter it once in the panel's **CONTROL KEY** field (saved in that
|
||
browser). Rotate any time with `sops services/secrets/observer_vps.yaml` then
|
||
rebuild.
|
||
|
||
## Running a session
|
||
|
||
The clock starts paused at iteration I, 17:00:00 (the Agents' arrival). Drive it
|
||
by hand to match table pacing — **JUMP TO BEAT** for the scripted moments, or
|
||
**RATE ×N** + **RUN** to let it tick. Fire **PULSE** on the live shudders and
|
||
**COMMUNION** at 22:03:37; then hit **ITERATION II/III/IV** to reset reality
|
||
nearer the end as the loop tightens. **SHOW** broadcasts a line of text over the
|
||
players' screen (e.g. *"I see the throne of God."*).
|
||
|
||
## Sound effects
|
||
|
||
The player screen's pulse / communion / broadcast-text sounds are pre-rendered
|
||
mp3s in `site/sfx/`, synthesized from pure ffmpeg `lavfi` filtergraphs (no
|
||
samples). Regenerate with:
|
||
|
||
```sh
|
||
cd site/sfx && nix-shell -p ffmpeg --run ./generate.sh
|
||
```
|
||
|
||
If a file fails to load the screen falls back to an equivalent WebAudio synth.
|
||
The ambient dread drone is always synth (it's driven by the tension level).
|
||
|
||
## Local dev (no Nix)
|
||
|
||
```sh
|
||
cd relay
|
||
OBSERVER_TOKEN=test cargo run # relay on 127.0.0.1:8770
|
||
# serve ./site on :8080 and proxy /ws -> 127.0.0.1:8770, or just open
|
||
# site/clock.html and append ?, then point common.js' WS at ws://localhost:8770/ws
|
||
```
|
||
The pages connect to `wss?://<host>/ws`, so behind nginx everything is same-origin.
|