From e4ee25295c7071a07b292e570eaae2f7e04a22c6 Mon Sep 17 00:00:00 2001 From: Ellie <6687206+wizzeh@users.noreply.github.com> Date: Mon, 15 Jun 2026 21:22:41 -0700 Subject: [PATCH] observer effect content --- .gitignore | 1 + flake.nix | 1 + services/observer-effect.nix | 86 ++ services/observer-effect/README.md | 66 ++ services/observer-effect/devserver.mjs | 67 ++ services/observer-effect/relay/.gitignore | 1 + services/observer-effect/relay/Cargo.lock | 772 ++++++++++++++++++ services/observer-effect/relay/Cargo.toml | 15 + services/observer-effect/relay/src/main.rs | 251 ++++++ services/observer-effect/site/clock.css | 438 ++++++++++ services/observer-effect/site/clock.html | 46 ++ services/observer-effect/site/clock.js | 215 +++++ services/observer-effect/site/common.js | 134 +++ services/observer-effect/site/control.css | 260 ++++++ services/observer-effect/site/control.html | 101 +++ services/observer-effect/site/control.js | 120 +++ .../observer-effect/site/sfx/communion.mp3 | Bin 0 -> 107458 bytes services/observer-effect/site/sfx/generate.sh | 65 ++ services/observer-effect/site/sfx/pulse.mp3 | Bin 0 -> 25120 bytes services/observer-effect/site/sfx/relay.wav | Bin 0 -> 8016 bytes services/observer-effect/site/sfx/whisper.mp3 | Bin 0 -> 27628 bytes services/observer-effect/site/sound.js | 326 ++++++++ services/secrets/observer_vps.yaml | 17 + 23 files changed, 2982 insertions(+) create mode 100644 services/observer-effect.nix create mode 100644 services/observer-effect/README.md create mode 100644 services/observer-effect/devserver.mjs create mode 100644 services/observer-effect/relay/.gitignore create mode 100644 services/observer-effect/relay/Cargo.lock create mode 100644 services/observer-effect/relay/Cargo.toml create mode 100644 services/observer-effect/relay/src/main.rs create mode 100644 services/observer-effect/site/clock.css create mode 100644 services/observer-effect/site/clock.html create mode 100644 services/observer-effect/site/clock.js create mode 100644 services/observer-effect/site/common.js create mode 100644 services/observer-effect/site/control.css create mode 100644 services/observer-effect/site/control.html create mode 100644 services/observer-effect/site/control.js create mode 100644 services/observer-effect/site/sfx/communion.mp3 create mode 100755 services/observer-effect/site/sfx/generate.sh create mode 100644 services/observer-effect/site/sfx/pulse.mp3 create mode 100644 services/observer-effect/site/sfx/relay.wav create mode 100644 services/observer-effect/site/sfx/whisper.mp3 create mode 100644 services/observer-effect/site/sound.js create mode 100644 services/secrets/observer_vps.yaml diff --git a/.gitignore b/.gitignore index 77f12ae..5d612f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ docs/ +games/ diff --git a/flake.nix b/flake.nix index 0f1e00c..35566b8 100644 --- a/flake.nix +++ b/flake.nix @@ -105,6 +105,7 @@ ./hosts/vps/disko-config.nix ./services/nginx.nix ./services/blog.nix + ./services/observer-effect.nix ./services/phanpy.nix ./services/coturn.nix ./services/livekit.nix diff --git a/services/observer-effect.nix b/services/observer-effect.nix new file mode 100644 index 0000000..a92f931 --- /dev/null +++ b/services/observer-effect.nix @@ -0,0 +1,86 @@ +{ config, pkgs, ... }: + +let + # Tiny Rust WebSocket relay. cargoLock.lockFile pins deps from the committed + # Cargo.lock, so there's no vendor hash to chase on dependency bumps. + relay = pkgs.rustPlatform.buildRustPackage { + pname = "observer-relay"; + version = "0.1.0"; + src = ./observer-effect/relay; + cargoLock.lockFile = ./observer-effect/relay/Cargo.lock; + }; + + # The two static pages (player chronometer + Handler panel) and their assets. + site = pkgs.copyPathToStore ./observer-effect/site; + + domain = "observer.ellie.town"; + port = 8770; +in +{ + # Shared control key. Decrypts to a file the relay reads at startup, so it + # never lands in /nix/store. + sops.secrets."observer/token" = { + sopsFile = ./secrets/observer_vps.yaml; + owner = "observer"; + group = "observer"; + mode = "0400"; + }; + + users.users.observer = { + isSystemUser = true; + group = "observer"; + }; + users.groups.observer = { }; + + systemd.services.observer-relay = { + description = "Observer Effect doomsday-clock relay"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + environment = { + OBSERVER_ADDR = "127.0.0.1:${toString port}"; + OBSERVER_TOKEN_FILE = config.sops.secrets."observer/token".path; + }; + + serviceConfig = { + ExecStart = "${relay}/bin/observer-relay"; + User = "observer"; + Group = "observer"; + Restart = "on-failure"; + RestartSec = "5s"; + + # Hardening — it only needs a loopback socket and to read one secret. + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + NoNewPrivileges = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + RestrictSUIDSGID = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + SystemCallFilter = [ "@system-service" ]; + }; + }; + + services.nginx.virtualHosts.${domain} = { + enableACME = true; + forceSSL = true; + root = site; + + locations."/" = { + index = "clock.html"; + }; + + # Tidy URL for the Handler's panel. + locations."= /control".return = "302 /control.html"; + + # Relay socket: upgrade to WebSocket and hand off to the local service. + locations."/ws" = { + proxyPass = "http://127.0.0.1:${toString port}"; + proxyWebsockets = true; + }; + }; +} diff --git a/services/observer-effect/README.md b/services/observer-effect/README.md new file mode 100644 index 0000000..bc6ea4a --- /dev/null +++ b/services/observer-effect/README.md @@ -0,0 +1,66 @@ +# 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?:///ws`, so behind nginx everything is same-origin. diff --git a/services/observer-effect/devserver.mjs b/services/observer-effect/devserver.mjs new file mode 100644 index 0000000..934db8b --- /dev/null +++ b/services/observer-effect/devserver.mjs @@ -0,0 +1,67 @@ +/* Local dev server: serves ./site and proxies /ws to the relay, so the pages + run same-origin exactly like they do behind nginx in production. + + Usage: + OBSERVER_TOKEN=test cargo run # in relay/, terminal 1 + node devserver.mjs # terminal 2 -> http://localhost:8080 + Env: PORT (default 8080), RELAY (default 127.0.0.1:8770). */ + +import { createServer } from "node:http"; +import { connect } from "node:net"; +import { readFile } from "node:fs/promises"; +import { extname, join, normalize } from "node:path"; +import { fileURLToPath } from "node:url"; + +const PORT = Number(process.env.PORT || 8080); +const [RELAY_HOST, RELAY_PORT] = (process.env.RELAY || "127.0.0.1:8770").split(":"); +const SITE = join(fileURLToPath(new URL(".", import.meta.url)), "site"); + +const MIME = { + ".html": "text/html; charset=utf-8", + ".css": "text/css; charset=utf-8", + ".js": "text/javascript; charset=utf-8", + ".mp3": "audio/mpeg", + ".wav": "audio/wav", +}; + +const server = createServer(async (req, res) => { + let path = decodeURIComponent(req.url.split("?")[0]); + if (path === "/") path = "/clock.html"; + if (path === "/control") path = "/control.html"; + + // keep it inside SITE + const file = join(SITE, normalize(path)); + if (!file.startsWith(SITE)) { + res.writeHead(403).end("forbidden"); + return; + } + try { + const body = await readFile(file); + res.writeHead(200, { "content-type": MIME[extname(file)] || "application/octet-stream" }); + res.end(body); + } catch { + res.writeHead(404).end("not found"); + } +}); + +// Proxy the WebSocket upgrade straight through to the relay. +server.on("upgrade", (req, socket, head) => { + const upstream = connect(Number(RELAY_PORT), RELAY_HOST, () => { + const lines = [`${req.method} ${req.url} HTTP/1.1`]; + for (let i = 0; i < req.rawHeaders.length; i += 2) { + lines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`); + } + upstream.write(lines.join("\r\n") + "\r\n\r\n"); + if (head && head.length) upstream.write(head); + socket.pipe(upstream); + upstream.pipe(socket); + }); + const bail = () => socket.destroy(); + upstream.on("error", bail); + socket.on("error", () => upstream.destroy()); +}); + +server.listen(PORT, () => { + console.log(`observer-effect dev server: http://localhost:${PORT}/ (control: /control)`); + console.log(`proxying /ws -> ${RELAY_HOST}:${RELAY_PORT}`); +}); diff --git a/services/observer-effect/relay/.gitignore b/services/observer-effect/relay/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/services/observer-effect/relay/.gitignore @@ -0,0 +1 @@ +/target diff --git a/services/observer-effect/relay/Cargo.lock b/services/observer-effect/relay/Cargo.lock new file mode 100644 index 0000000..9425f2a --- /dev/null +++ b/services/observer-effect/relay/Cargo.lock @@ -0,0 +1,772 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core", + "base64", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "data-encoding" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "http" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "bytes", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "log" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mio" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "observer-relay" +version = "0.1.0" +dependencies = [ + "axum", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "socket2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio" +version = "1.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "zerocopy" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/services/observer-effect/relay/Cargo.toml b/services/observer-effect/relay/Cargo.toml new file mode 100644 index 0000000..c01a268 --- /dev/null +++ b/services/observer-effect/relay/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "observer-relay" +version = "0.1.0" +edition = "2021" +description = "Tiny WebSocket relay that syncs the Observer Effect doomsday clock from the Handler's control panel to every player's screen." + +[dependencies] +axum = { version = "0.7", features = ["ws"] } +tokio = { version = "1", features = ["rt-multi-thread", "macros", "net", "signal"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +[profile.release] +lto = true +strip = true diff --git a/services/observer-effect/relay/src/main.rs b/services/observer-effect/relay/src/main.rs new file mode 100644 index 0000000..6fc7768 --- /dev/null +++ b/services/observer-effect/relay/src/main.rs @@ -0,0 +1,251 @@ +//! Observer Effect — doomsday clock relay. +//! +//! A single authoritative clock lives here. The Handler's control panel sends +//! commands (authenticated with a shared token); every connected screen — the +//! Handler's and every player's — receives the resulting state and reacts. +//! +//! The clock is deterministic: we broadcast a snapshot (in-world seconds + a +//! server timestamp + running/rate) and let each browser free-run from it, so +//! the wire stays quiet between the Handler's deliberate actions. + +use std::{ + net::SocketAddr, + sync::{Arc, Mutex}, + time::{SystemTime, UNIX_EPOCH}, +}; + +use axum::{ + extract::{ + ws::{Message, WebSocket}, + State, WebSocketUpgrade, + }, + response::IntoResponse, + routing::get, + Router, +}; +use serde::Deserialize; +use serde_json::{json, Value}; +use tokio::sync::broadcast; + +/// In-world second-of-day at which Azathoth achieves communion (22:03:37). +const COMMUNION: f64 = 79_417.0; + +/// Where each iteration's reality "resets" to, in second-of-day. Iteration 1 +/// starts when the Agents reach the Array (17:00); later iterations wake nearer +/// the end, as the loop tightens toward the singularity. +fn reset_point(iteration: u64) -> f64 { + match iteration { + 1 => 61_200.0, // 17:00:00 — arrival + 2 => 67_576.0, // 18:46:16 — Takagawa awakens + 3 => 75_470.0, // 20:57:50 — Klinger's rampage + _ => COMMUNION, // 4 — singularity + } +} + +fn now_ms() -> u128 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis() +} + +/// The persistent clock. `inworld`/`updated_ms` form an anchor: while running, +/// the live time is `inworld + (now - updated_ms) * rate`. +#[derive(Clone)] +struct Clock { + iteration: u64, + running: bool, + rate: f64, + inworld: f64, + updated_ms: u128, +} + +impl Clock { + fn current(&self, now: u128) -> f64 { + if self.running { + let elapsed = (now.saturating_sub(self.updated_ms)) as f64 / 1000.0; + self.inworld + elapsed * self.rate + } else { + self.inworld + } + } + + /// Fold elapsed time into the anchor so we can mutate from a clean baseline. + fn settle(&mut self, now: u128) { + self.inworld = self.current(now); + self.updated_ms = now; + } + + fn snapshot(&self, now: u128) -> String { + json!({ + "type": "state", + "iteration": self.iteration, + "running": self.running, + "rate": self.rate, + "inworld": self.current(now), + "communion": COMMUNION, + "serverMs": now, + }) + .to_string() + } +} + +struct App { + token: String, + clock: Mutex, + tx: broadcast::Sender, +} + +#[derive(Deserialize)] +struct Command { + token: Option, + cmd: String, + #[serde(default)] + rate: Option, + #[serde(default)] + inworld: Option, + #[serde(default)] + n: Option, + #[serde(default)] + text: Option, +} + +#[tokio::main] +async fn main() { + let token = std::env::var("OBSERVER_TOKEN") + .or_else(|_| { + std::env::var("OBSERVER_TOKEN_FILE") + .and_then(|p| std::fs::read_to_string(p).map_err(|_| std::env::VarError::NotPresent)) + }) + .map(|s| s.trim().to_string()) + .unwrap_or_else(|_| { + eprintln!("warning: no OBSERVER_TOKEN(_FILE) set; control is locked out"); + String::new() + }); + + let addr: SocketAddr = std::env::var("OBSERVER_ADDR") + .unwrap_or_else(|_| "127.0.0.1:8770".to_string()) + .parse() + .expect("OBSERVER_ADDR must be host:port"); + + let (tx, _rx) = broadcast::channel(64); + let app = Arc::new(App { + token, + clock: Mutex::new(Clock { + iteration: 1, + running: false, + rate: 1.0, + inworld: reset_point(1), + updated_ms: now_ms(), + }), + tx, + }); + + let router = Router::new() + .route("/ws", get(ws_handler)) + .route("/healthz", get(|| async { "ok" })) + .with_state(app); + + let listener = tokio::net::TcpListener::bind(addr).await.expect("bind"); + eprintln!("observer-relay listening on {addr}"); + axum::serve(listener, router) + .with_graceful_shutdown(async { + let _ = tokio::signal::ctrl_c().await; + }) + .await + .expect("serve"); +} + +async fn ws_handler(ws: WebSocketUpgrade, State(app): State>) -> impl IntoResponse { + ws.on_upgrade(move |socket| handle_socket(socket, app)) +} + +async fn handle_socket(mut socket: WebSocket, app: Arc) { + // Greet the newcomer with the world as it stands right now. + let hello = app.clock.lock().unwrap().snapshot(now_ms()); + if socket.send(Message::Text(hello)).await.is_err() { + return; + } + + let mut rx = app.tx.subscribe(); + + loop { + tokio::select! { + // Fan broadcasts out to this client. + msg = rx.recv() => match msg { + Ok(text) => { + if socket.send(Message::Text(text)).await.is_err() { + break; + } + } + Err(broadcast::error::RecvError::Lagged(_)) => continue, + Err(broadcast::error::RecvError::Closed) => break, + }, + // Read commands from this client (only the Handler's pass auth). + incoming = socket.recv() => match incoming { + Some(Ok(Message::Text(text))) => handle_command(&app, &text), + Some(Ok(Message::Close(_))) | None => break, + Some(Ok(_)) => {} // ping/pong/binary — ignore + Some(Err(_)) => break, + }, + } + } +} + +fn handle_command(app: &App, text: &str) { + let cmd: Command = match serde_json::from_str(text) { + Ok(c) => c, + Err(_) => return, + }; + + // Constant-ish check; empty server token rejects everyone. + if app.token.is_empty() || cmd.token.as_deref() != Some(app.token.as_str()) { + return; + } + + let now = now_ms(); + + // Transient effects don't touch the clock — just relay them. + match cmd.cmd.as_str() { + "pulse" => return broadcast_fx(app, json!({ "type": "fx", "fx": "pulse" })), + "communion" => return broadcast_fx(app, json!({ "type": "fx", "fx": "communion" })), + "msg" => { + return broadcast_fx(app, json!({ "type": "fx", "fx": "msg", "text": cmd.text })) + } + _ => {} + } + + let snapshot = { + let mut clock = app.clock.lock().unwrap(); + clock.settle(now); + match cmd.cmd.as_str() { + "play" => clock.running = true, + "pause" => clock.running = false, + "rate" => { + if let Some(r) = cmd.rate { + clock.rate = r.clamp(0.0, 3600.0); + } + } + "set" => { + if let Some(s) = cmd.inworld { + clock.inworld = s.clamp(0.0, 86_400.0); + } + } + "iteration" => { + if let Some(n) = cmd.n { + clock.iteration = n.clamp(1, 4); + clock.inworld = reset_point(clock.iteration); + clock.running = false; + } + } + _ => return, + } + clock.snapshot(now) + }; + + let _ = app.tx.send(snapshot); +} + +fn broadcast_fx(app: &App, value: Value) { + let _ = app.tx.send(value.to_string()); +} diff --git a/services/observer-effect/site/clock.css b/services/observer-effect/site/clock.css new file mode 100644 index 0000000..f831817 --- /dev/null +++ b/services/observer-effect/site/clock.css @@ -0,0 +1,438 @@ +/* Olympian Holobeam Array — Master Chronometer. + Atomic-age console: brushed steel, nixie tubes, warning lamps. 1964. */ + +:root { + --bg: #0a0b0c; + --steel-hi: #4c5054; + --steel: #2c2f32; + --steel-lo: #16181a; + --engrave: #0c0d0e; + --label: #c9cdd1; + --nixie: #ff7a1e; + --nixie-core: #ffe2bc; + --nixie-glow: #ff6a00; + --amber: #ffb347; + --red: #ff3b30; + --green: #46e06a; +} + +* { + box-sizing: border-box; +} + +html, +body { + height: 100%; + margin: 0; +} + +body.screen { + display: grid; + place-items: center; + min-height: 100%; + padding: clamp(0.5rem, 3vw, 3rem); + background: + radial-gradient(120% 120% at 50% 30%, #15171a 0%, var(--bg) 70%); + color: var(--label); + font-family: "Helvetica Neue", Arial, system-ui, sans-serif; + overflow: hidden; +} + +/* --- the console body ----------------------------------------------------- */ +.console { + width: min(92vw, 880px); +} + +.bezel { + position: relative; + padding: clamp(1rem, 3.5vw, 2.4rem); + border-radius: 14px; + background: + repeating-linear-gradient( + 90deg, + rgba(255, 255, 255, 0.035) 0 1px, + transparent 1px 3px + ), + linear-gradient(180deg, var(--steel-hi) -20%, var(--steel) 45%, var(--steel-lo)); + border: 2px solid #0d0e0f; + box-shadow: + inset 0 2px 0 rgba(255, 255, 255, 0.12), + inset 0 -3px 8px rgba(0, 0, 0, 0.6), + 0 22px 60px rgba(0, 0, 0, 0.7); +} + +/* corner screws */ +.bezel::before { + content: ""; + position: absolute; + inset: 10px; + border-radius: 8px; + pointer-events: none; + background: + radial-gradient(circle at 0 0, #555 1.5px, #1a1a1a 3px, transparent 4px) 6px 6px / 100% 100% no-repeat, + radial-gradient(circle at 100% 0, #555 1.5px, #1a1a1a 3px, transparent 4px) -6px 6px / 100% 100% no-repeat, + radial-gradient(circle at 0 100%, #555 1.5px, #1a1a1a 3px, transparent 4px) 6px -6px / 100% 100% no-repeat, + radial-gradient(circle at 100% 100%, #555 1.5px, #1a1a1a 3px, transparent 4px) -6px -6px / 100% 100% no-repeat; +} + +/* --- engraved plates ------------------------------------------------------ */ +.plate { + display: flex; + align-items: center; + justify-content: space-between; + font-weight: 700; + letter-spacing: 0.18em; + font-size: clamp(0.6rem, 1.6vw, 0.9rem); + color: var(--label); + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.8), 0 -1px 0 rgba(255, 255, 255, 0.06); +} +.stencil { + font-weight: 800; +} +.subplate { + margin: 0.35rem 0 1.1rem; + text-align: center; + letter-spacing: 0.3em; + font-size: clamp(0.5rem, 1.3vw, 0.72rem); + color: #8b9094; + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.8); +} +.plate--bottom { + margin-top: 1.2rem; + justify-content: center; + letter-spacing: 0.22em; + font-size: clamp(0.45rem, 1.2vw, 0.66rem); + color: #7d8286; +} +.rec { + display: inline-flex; + align-items: center; + gap: 0.4em; + color: #9aa0a4; +} + +/* --- nixie readout -------------------------------------------------------- */ +.readout { + display: flex; + align-items: stretch; + justify-content: center; + gap: clamp(0.15rem, 0.8vw, 0.5rem); + padding: clamp(0.6rem, 2vw, 1.2rem) clamp(0.4rem, 2vw, 1rem); + border-radius: 10px; + background: + radial-gradient(120% 160% at 50% 0%, #141312 0%, #070605 100%); + border: 1px solid #000; + box-shadow: inset 0 6px 18px rgba(0, 0, 0, 0.9), inset 0 -1px 0 rgba(255, 255, 255, 0.04); +} + +.tube { + position: relative; + display: grid; + place-items: center; + width: clamp(2.6rem, 9vw, 5.2rem); + padding: clamp(0.3rem, 1.5vw, 0.9rem) 0; + border-radius: 40% 40% 38% 38% / 14% 14% 12% 12%; + background: + linear-gradient(180deg, rgba(80, 70, 55, 0.16), rgba(20, 16, 10, 0.05) 30%, rgba(0, 0, 0, 0.25)); + box-shadow: + inset 0 2px 6px rgba(255, 200, 140, 0.06), + inset 0 -8px 14px rgba(0, 0, 0, 0.6); +} +/* curvature vignette behind the digit */ +.tube::before { + content: ""; + position: absolute; + inset: 0; + z-index: 0; + border-radius: inherit; + pointer-events: none; + background: radial-gradient(120% 130% at 50% 45%, transparent 52%, rgba(0, 0, 0, 0.45) 100%); +} +/* curved-glass glare in front (offset to a corner so it doesn't wash the digit) */ +.tube::after { + content: ""; + position: absolute; + inset: 0; + z-index: 3; + border-radius: inherit; + pointer-events: none; + background: + radial-gradient(55% 32% at 32% 15%, rgba(255, 255, 255, 0.28), rgba(255, 255, 255, 0.06) 45%, transparent 70%), + radial-gradient(38% 22% at 72% 82%, rgba(255, 255, 255, 0.06), transparent 60%); +} + +.digit { + position: relative; + z-index: 2; + font-size: clamp(2.4rem, 9vw, 5.4rem); + font-weight: 400; + line-height: 1; + transform: scaleY(1.18); + color: var(--nixie-core); + text-shadow: + 0 0 4px var(--nixie), + 0 0 14px var(--nixie-glow), + 0 0 34px var(--nixie-glow), + 0 0 60px rgba(255, 90, 0, 0.55); + /* per-tube flicker via vars, so the communion rupture can fully override it */ + animation: tube-flicker var(--flick-dur, 6s) var(--flick-delay, 0s) infinite steps(40); +} + +/* afterglow: the outgoing numeral lingers and fades (neon de-ionization) */ +.ghost { + position: absolute; + inset: 0; + z-index: 1; + display: grid; + place-items: center; + opacity: 0; + font-size: clamp(2.4rem, 9vw, 5.4rem); + font-weight: 400; + line-height: 1; + transform: scaleY(1.18); + color: var(--nixie-core); + text-shadow: 0 0 4px var(--nixie), 0 0 16px var(--nixie-glow); + pointer-events: none; +} +@keyframes tube-flicker { + 0%, 97%, 100% { opacity: 1; } + 98% { opacity: 0.86; } + 99% { opacity: 0.95; } +} + +.colon { + display: flex; + flex-direction: column; + justify-content: center; + gap: clamp(0.5rem, 2vw, 1.2rem); + padding: 0 clamp(0.05rem, 0.5vw, 0.3rem); +} +.colon i { + width: clamp(0.3rem, 1vw, 0.6rem); + height: clamp(0.3rem, 1vw, 0.6rem); + border-radius: 50%; + background: var(--nixie-core); + box-shadow: 0 0 6px var(--nixie), 0 0 16px var(--nixie-glow); +} + +.srtime { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip: rect(0 0 0 0); +} + +/* --- lamps ---------------------------------------------------------------- */ +.lamps { + margin-top: 1.3rem; + display: flex; + align-items: center; + justify-content: center; + gap: clamp(1rem, 5vw, 3rem); +} +.lampcell { + display: flex; + align-items: center; + gap: 0.5em; + letter-spacing: 0.16em; + font-size: clamp(0.55rem, 1.4vw, 0.78rem); + color: #8b9094; +} +.lamp { + width: 0.85em; + height: 0.85em; + border-radius: 50%; + background: #2a2a2a; + box-shadow: inset 0 0 3px #000, 0 1px 0 rgba(255, 255, 255, 0.08); + transition: background 0.08s, box-shadow 0.08s; +} +.lamp--rec { + width: 0.7em; + height: 0.7em; +} +.lamp--on { + background: var(--green); + box-shadow: 0 0 8px var(--green), 0 0 16px rgba(70, 224, 106, 0.6); +} +/* REC indicator: steady recording lamp (flavor). */ +.lamp--rec { + background: var(--red); + box-shadow: 0 0 5px var(--red); +} + +/* --- pulse shudder --------------------------------------------------------- */ +body.pulsing #cellPulse .lamp { + background: var(--amber); + box-shadow: 0 0 10px var(--amber), 0 0 24px rgba(255, 179, 71, 0.8); +} +body.pulsing .bezel { + animation: shudder 0.45s ease-out; +} +body.pulsing .digit { + text-shadow: + 0 0 6px var(--nixie-core), + 0 0 20px var(--nixie), + 0 0 50px var(--nixie-glow), + 0 0 90px rgba(255, 120, 0, 0.8); +} +@keyframes shudder { + 0%, 100% { transform: translate(0, 0); } + 20% { transform: translate(-3px, 1px); } + 40% { transform: translate(3px, -2px); } + 60% { transform: translate(-2px, -1px); } + 80% { transform: translate(2px, 1px); } +} + +/* --- dread wash (driven by --tension, 0..1) -------------------------------- */ +.screen::before { + content: ""; + position: fixed; + inset: 0; + pointer-events: none; + background: radial-gradient(120% 120% at 50% 50%, transparent 38%, rgba(120, 0, 0, 0.6) 100%); + opacity: calc(var(--tension, 0) * 0.95); + z-index: 5; +} +/* once the menace is high, the wash starts to crawl */ +body.agitated::before { + animation: wash-flicker 0.4s infinite; +} +@keyframes wash-flicker { + 0%, 100% { opacity: calc(var(--tension, 0) * 0.95); } + 50% { opacity: calc(var(--tension, 0) * 0.7); } +} + +/* --- communion: Azathoth breaks through ------------------------------------ */ +/* A ~6s sequence over three layers: the void (roiling black), the flash (the + blue-white detonation), plus a console quake and digit rupture. */ +.void { + position: fixed; + inset: 0; + z-index: 21; + pointer-events: none; + opacity: 0; + background: #000; +} +.flash { + position: fixed; + inset: 0; + z-index: 22; + pointer-events: none; + opacity: 0; + mix-blend-mode: screen; + background: radial-gradient(circle at 50% 45%, #fff 0%, #dce9ff 12%, #6fb0ff 34%, #163a8f 68%, transparent 100%); +} + +body.communion .console { animation: quake 2.3s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; } +body.communion .void { animation: thevoid 6s ease-out forwards; } +body.communion .flash { animation: detonate 6s ease-out forwards; } +body.communion .digit { animation: digit-rupture 6s steps(60) forwards; } +body.communion .lamp { animation: panic-lamp 0.18s steps(1) 12; } + +@keyframes quake { + 0%, 100% { transform: translate(0, 0) rotate(0deg); } + 5% { transform: translate(-14px, 8px) rotate(-0.6deg); } + 10% { transform: translate(13px, -10px) rotate(0.5deg); } + 15% { transform: translate(-16px, -6px) rotate(0.4deg); } + 21% { transform: translate(15px, 11px) rotate(-0.5deg); } + 27% { transform: translate(-19px, 7px) rotate(0.7deg); } + 33% { transform: translate(18px, -9px) rotate(-0.6deg); } + 41% { transform: translate(-11px, 7px) rotate(0.3deg); } + 52% { transform: translate(8px, -5px) rotate(-0.2deg); } + 64% { transform: translate(-5px, 3px); } + 78% { transform: translate(3px, -2px); } +} +@keyframes detonate { + 0% { opacity: 0; } + 18% { opacity: 0.12; } + 22% { opacity: 0; } + 26% { opacity: 1; } + 30% { opacity: 0.7; } + 34% { opacity: 1; } + 44% { opacity: 0.2; } + 60% { opacity: 0.06; } + 78%, 100% { opacity: 0; } +} +@keyframes thevoid { + 0%, 30% { opacity: 0; } + 45% { opacity: 1; } + 86% { opacity: 1; } + 100% { opacity: 0; } +} +@keyframes digit-rupture { + 0% { color: var(--nixie-core); text-shadow: 0 0 4px var(--nixie), 0 0 14px var(--nixie-glow); } + 10% { color: #fff; text-shadow: -3px 0 #ff003c, 3px 0 #00e5ff, 0 0 18px #fff; } + 20% { text-shadow: 4px 0 #ff003c, -4px 0 #00e5ff, 0 0 22px #fff; } + 26% { color: #eaf3ff; text-shadow: -6px 0 #ff003c, 6px 0 #00e5ff, 0 0 30px #fff; } + 34% { opacity: 0.2; } + 40% { opacity: 1; color: #b9c6ff; text-shadow: -5px 0 #ff003c, 5px 0 #00e5ff; } + 55% { opacity: 0.5; text-shadow: -3px 0 #6a00ff, 3px 0 #00d0ff; } + 70% { opacity: 0.12; } + 82% { opacity: 0.04; } + 100% { opacity: 1; color: var(--nixie-core); text-shadow: 0 0 4px var(--nixie), 0 0 14px var(--nixie-glow); } +} +@keyframes panic-lamp { + 0% { background: var(--red); box-shadow: 0 0 10px var(--red); } + 50% { background: #1a0000; box-shadow: inset 0 0 3px #000; } +} + +/* --- message overlay ------------------------------------------------------- */ +.message { + position: fixed; + inset: 0; + z-index: 30; + display: grid; + place-items: center; + padding: 2rem; + text-align: center; + font-weight: 800; + letter-spacing: 0.22em; + font-size: clamp(1.6rem, 7vw, 4.5rem); + color: #fff; + text-shadow: 0 0 12px #6fb0ff, 0 0 40px #2a6bff; + background: rgba(0, 0, 0, 0.35); + opacity: 0; + visibility: hidden; + transition: opacity 0.4s, visibility 0.4s; +} +.message.show { + opacity: 1; + visibility: visible; +} + +/* --- offline -------------------------------------------------------------- */ +body.offline .bezel { + filter: saturate(0.5) brightness(0.85); +} + +/* --- sound button --------------------------------------------------------- */ +.sound { + position: fixed; + right: 0.8rem; + bottom: 0.8rem; + z-index: 40; + padding: 0.4rem 0.8rem; + font: inherit; + font-size: 0.7rem; + letter-spacing: 0.14em; + color: #9aa0a4; + background: #1b1d1f; + border: 1px solid #000; + border-radius: 6px; + cursor: pointer; +} +.sound.on { + color: var(--green); + cursor: default; +} + +@media (prefers-reduced-motion: reduce) { + .digit, + body.agitated::before, + body.communion .console, + body.communion .digit, + body.communion .lamp { + animation: none !important; + } +} diff --git a/services/observer-effect/site/clock.html b/services/observer-effect/site/clock.html new file mode 100644 index 0000000..2c4ab8d --- /dev/null +++ b/services/observer-effect/site/clock.html @@ -0,0 +1,46 @@ + + + + + + + Warner Center Radio Array — Master Chronometer + + + +
+
+
+ WARNER CENTER RADIO ARRAY + REC +
+
MASTER CHRONOMETER
+ + +

17:00:00 local time

+ +
+
+ ARRAY +
+
+ SIGNAL +
+
+ +
+ PROPERTY OF THE U.S. DEPARTMENT OF ENERGY · MCMLXIV · AUTHORIZED PERSONNEL ONLY +
+
+
+ + + + + + + + + + + diff --git a/services/observer-effect/site/clock.js b/services/observer-effect/site/clock.js new file mode 100644 index 0000000..384cac8 --- /dev/null +++ b/services/observer-effect/site/clock.js @@ -0,0 +1,215 @@ +/* Player screen. Read-only and deliberately ignorant of the scenario's + structure — no countdown, no iteration counter, nothing the in-world DOE + inspectors couldn't see. It shows the Array's current time and reacts to + whatever the Handler chooses to push: signal pulses, the catastrophe, text. + Dread builds from the pulses the Handler fires, not from any visible clock. */ +(function () { + "use strict"; + + const $ = (id) => document.getElementById(id); + const body = document.body; + const reduceMotion = + window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; + + // Build six nixie tubes as HH MM SS with two colons; keep digit + ghost refs. + const tubeWrap = $("tubes"); + const digits = []; + const ghosts = []; + "HH:MM:SS".split("").forEach((ch) => { + if (ch === ":") { + const c = document.createElement("span"); + c.className = "colon"; + c.innerHTML = ""; + tubeWrap.appendChild(c); + } else { + const tube = document.createElement("span"); + tube.className = "tube"; + // afterglow layer: holds the outgoing numeral as it de-ionizes + const g = document.createElement("span"); + g.className = "ghost"; + const d = document.createElement("span"); + d.className = "digit"; + d.textContent = "0"; + // each tube flickers on its own rhythm (via CSS vars, so the communion + // rupture animation can still fully override the flicker) + d.style.setProperty("--flick-dur", (5 + Math.random() * 4).toFixed(2) + "s"); + d.style.setProperty("--flick-delay", (-Math.random() * 6).toFixed(2) + "s"); + tube.appendChild(g); + tube.appendChild(d); + tubeWrap.appendChild(tube); + digits.push(d); + ghosts.push(g); + } + }); + + function renderDigits(str) { + const order = [0, 1, 3, 4, 6, 7]; // skip the colon positions + const glitching = body.classList.contains("communion"); + order.forEach((pos, i) => { + const ch = str[pos]; + if (digits[i].textContent !== ch) { + // leave a fading ghost of the outgoing numeral (neon persistence) + if (!glitching && !reduceMotion) { + ghosts[i].textContent = digits[i].textContent; + ghosts[i].animate([{ opacity: 0.7 }, { opacity: 0 }], { + duration: 160, + easing: "ease-out", + }); + } + digits[i].textContent = ch; + } + }); + } + + // cathode-poisoning exercise: a rapid slot-machine cycle through 0-9, + // staggered per tube, run only while the clock sits idle + function renderSpin(now) { + for (let i = 0; i < digits.length; i++) { + digits[i].textContent = ((Math.floor(now / 45) + i * 2) % 10).toString(); + } + } + + // --- dread / tension ------------------------------------------------------- + // 0..1, nudged up by each pulse and decaying slowly. Drives the red wash and + // the audio drone, so the Handler paces the menace by firing pulses. + let tension = 0; + function bumpTension(amount) { + tension = Math.min(1, tension + amount); + } + + // --- effects --------------------------------------------------------------- + let pulseTimer = null; + function flashPulse() { + body.classList.add("pulsing"); + clearTimeout(pulseTimer); + pulseTimer = setTimeout(() => body.classList.remove("pulsing"), 750); + bumpTension(0.2); + if (window.OESound) OESound.pulse(); + } + + let communionTimer = null; + let scrambleUntil = 0; + function communionSeq() { + body.classList.remove("communion"); + void body.offsetWidth; // restart the whole sequence + body.classList.add("communion"); + if (window.OESound && OESound.cancelTicks) OESound.cancelTicks(); + tension = 1; + scrambleUntil = performance.now() + 2300; // digits possessed through the blast + clearTimeout(communionTimer); + communionTimer = setTimeout(() => body.classList.remove("communion"), 6200); + if (window.OESound) OESound.communion(); + } + function renderScramble() { + for (const d of digits) d.textContent = ((Math.random() * 10) | 0).toString(); + } + + const msgEl = $("message"); + function showMessage(text) { + msgEl.textContent = text; + msgEl.classList.add("show"); + } + function hideMessage() { + msgEl.classList.remove("show"); + } + + // --- model + connection ---------------------------------------------------- + const model = OE.ClockModel(); + let nextTickTime = null; // next scheduled relay click, in AudioContext time + + const conn = OE.connect(OE.defaultWsUrl(), { + onstatus(s) { + $("lampLink").classList.toggle("lamp--on", s === "open"); + body.classList.toggle("offline", s !== "open"); + }, + onstate(state) { + model.apply(state); + // drop queued clicks and realign — so pausing stops ticks promptly and a + // jump/rate change re-aligns instead of replaying a backlog + if (window.OESound && OESound.cancelTicks) OESound.cancelTicks(); + nextTickTime = null; + }, + onfx(fx) { + if (fx.fx === "pulse") flashPulse(); + else if (fx.fx === "communion") communionSeq(); + else if (fx.fx === "msg") { + if (fx.text) { + showMessage(fx.text); + if (window.OESound && OESound.enabled()) OESound.message(); + } else hideMessage(); + } + }, + }); + window.addEventListener("beforeunload", () => conn.close()); + + // --- tick scheduler -------------------------------------------------------- + // Schedule relay clicks ahead of time on the AudioContext clock, so they keep + // ticking precisely even when the tab is backgrounded (requestAnimationFrame + // is paused there, but Web Audio scheduling is not). Each click is aligned to + // the in-world second boundary — i.e. the digit changeover. + const TICK_LOOKAHEAD = 2.5; // seconds of clicks kept queued + function scheduleTicks() { + if (!window.OESound || !OESound.enabled()) return (nextTickTime = null); + const m = model.now(); + if (!m.running || body.classList.contains("communion")) return (nextTickTime = null); + const aNow = OESound.now(); + const rate = m.rate || 1; + if (nextTickTime === null) { + const nextSec = Math.floor(m.inworld) + 1; + nextTickTime = aNow + (nextSec - m.inworld) / rate; + } + const stepGap = Math.max(1 / rate, 0.07); // never buzz at high rates + while (nextTickTime < aNow + TICK_LOOKAHEAD) { + if (nextTickTime > aNow) OESound.step(nextTickTime); + nextTickTime += stepGap; + } + } + setInterval(scheduleTicks, 250); + + // --- render loop ----------------------------------------------------------- + let last = performance.now(); + let spinUntil = 0; + const SPIN_IDLE = 90000; // exercise the tubes after this long sitting idle + let nextSpinAt = performance.now() + SPIN_IDLE; + function frame(now) { + const dt = (now - last) / 1000; + last = now; + + const s = model.now(); + + // cathode-poisoning spin, but only while the clock sits idle (paused) + if (s.running || body.classList.contains("communion") || reduceMotion) { + nextSpinAt = now + SPIN_IDLE; + } else if (now >= nextSpinAt && now >= spinUntil) { + spinUntil = now + 1600; + nextSpinAt = now + SPIN_IDLE; + } + + if (now < scrambleUntil) renderScramble(); + else if (now < spinUntil) renderSpin(now); + else renderDigits(OE.clock(s.inworld)); + $("srtime").textContent = OE.clock(s.inworld); + + // (relay ticks are scheduled on the audio clock above, not here) + + // decay tension and reflect it on the console — quick enough that the + // drone and red wash settle within several seconds, not minutes + tension = Math.max(0, tension - dt * 0.12); + body.style.setProperty("--tension", tension.toFixed(3)); + body.classList.toggle("agitated", tension > 0.6); + if (window.OESound && OESound.enabled()) OESound.setDread(tension); + + requestAnimationFrame(frame); + } + requestAnimationFrame(frame); + + // --- sound toggle ---------------------------------------------------------- + const soundBtn = $("soundBtn"); + soundBtn.addEventListener("click", () => { + if (OESound.enable()) { + soundBtn.textContent = "◉ SOUND ON"; + soundBtn.classList.add("on"); + soundBtn.disabled = true; + } + }); +})(); diff --git a/services/observer-effect/site/common.js b/services/observer-effect/site/common.js new file mode 100644 index 0000000..0e40fa9 --- /dev/null +++ b/services/observer-effect/site/common.js @@ -0,0 +1,134 @@ +/* Observer Effect — shared clock logic for the player screen and the Handler's + panel. Classic script (no modules) so the pages also open straight from disk + for a quick look. Everything hangs off the global `OE`. */ +(function () { + "use strict"; + + // In-world second-of-day for the moment Azathoth achieves communion. + const COMMUNION = 79417; // 22:03:37 + + // The scenario's beats, in second-of-day. `pulse: true` marks the live + // on-site shudders the player screen reacts to; the rest are scene markers + // and useful jump targets for the Handler. + const EVENTS = [ + { t: 36000, label: "Array activated", time: "10:00:00" }, + { t: 55735, label: "Power surge", time: "15:28:55" }, + { t: 59682, label: "Phantom signal", time: "16:34:42" }, + { t: 61200, label: "Agents arrive", time: "17:00:00" }, + { t: 63629, label: "Pulse", time: "17:40:29", pulse: true }, + { t: 67576, label: "Takagawa awakens", time: "18:46:16", pulse: true }, + { t: 71523, label: "Klinger appears", time: "19:52:03", pulse: true }, + { t: 75470, label: "Klinger's rampage", time: "20:57:50", pulse: true }, + { t: COMMUNION, label: "COMMUNION", time: "22:03:37", communion: true }, + ]; + + const RESET_POINTS = { 1: 61200, 2: 67576, 3: 75470, 4: COMMUNION }; + const ROMAN = { 1: "I", 2: "II", 3: "III", 4: "IV" }; + + function pad(n) { + return String(Math.floor(n)).padStart(2, "0"); + } + + // second-of-day (may exceed a day or go negative) -> "HH:MM:SS", clamped 0..24h. + function clock(sec) { + let s = Math.max(0, Math.min(86399, Math.floor(sec))); + return pad(s / 3600) + ":" + pad((s % 3600) / 60) + ":" + pad(s % 60); + } + + // A signed duration in seconds -> "H:MM:SS". + function duration(sec) { + const neg = sec < 0; + let s = Math.abs(Math.floor(sec)); + const h = Math.floor(s / 3600); + return (neg ? "-" : "") + h + ":" + pad((s % 3600) / 60) + ":" + pad(s % 60); + } + + /* Holds the latest authoritative snapshot and free-runs from it locally, so + the digits keep ticking between the Handler's actions. */ + function ClockModel() { + let base = RESET_POINTS[1]; + let baseAt = performance.now(); + let running = false; + let rate = 1; + let iteration = 1; + + return { + apply(state) { + base = state.inworld; + baseAt = performance.now(); + running = state.running; + rate = state.rate; + iteration = state.iteration; + }, + now() { + const live = running + ? base + ((performance.now() - baseAt) / 1000) * rate + : base; + return { + inworld: live, + remaining: COMMUNION - live, + running, + rate, + iteration, + }; + }, + }; + } + + /* Auto-reconnecting WebSocket. `onstate`/`onfx` get parsed messages; + `onstatus` gets "open"/"closed" for the link lamp. */ + function connect(url, handlers) { + let ws; + let closed = false; + + function open() { + ws = new WebSocket(url); + ws.onopen = () => handlers.onstatus && handlers.onstatus("open"); + ws.onclose = () => { + handlers.onstatus && handlers.onstatus("closed"); + if (!closed) setTimeout(open, 1000); + }; + ws.onerror = () => ws.close(); + ws.onmessage = (e) => { + let m; + try { + m = JSON.parse(e.data); + } catch (_) { + return; + } + if (m.type === "state") handlers.onstate && handlers.onstate(m); + else if (m.type === "fx") handlers.onfx && handlers.onfx(m); + }; + } + open(); + + return { + send(obj) { + if (ws && ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify(obj)); + }, + close() { + closed = true; + if (ws) ws.close(); + }, + }; + } + + // Default WS endpoint: same host, /ws, matching page's TLS. + function defaultWsUrl() { + const proto = location.protocol === "https:" ? "wss:" : "ws:"; + return proto + "//" + location.host + "/ws"; + } + + window.OE = { + COMMUNION, + EVENTS, + RESET_POINTS, + ROMAN, + clock, + duration, + pad, + ClockModel, + connect, + defaultWsUrl, + }; +})(); diff --git a/services/observer-effect/site/control.css b/services/observer-effect/site/control.css new file mode 100644 index 0000000..3af6bc0 --- /dev/null +++ b/services/observer-effect/site/control.css @@ -0,0 +1,260 @@ +/* Array Control — the Handler's cockpit. Same steel as the chronometer, + but laid out as a dense bank of switches and push-buttons. */ + +:root { + --bg: #0a0b0c; + --steel-hi: #4c5054; + --steel: #2c2f32; + --steel-lo: #16181a; + --label: #c9cdd1; + --amber: #ffb347; + --red: #ff3b30; + --green: #46e06a; +} + +* { + box-sizing: border-box; +} +html, +body { + margin: 0; +} + +body.panel { + min-height: 100vh; + padding: clamp(0.6rem, 2.5vw, 2rem); + background: radial-gradient(120% 120% at 50% 0%, #15171a, var(--bg) 70%); + color: var(--label); + font-family: "Helvetica Neue", Arial, system-ui, sans-serif; + -webkit-text-size-adjust: 100%; +} + +.rig { + width: min(96vw, 760px); + margin: 0 auto; + display: flex; + flex-direction: column; + gap: 0.9rem; +} + +/* engraved header */ +.plate { + display: flex; + align-items: center; + justify-content: space-between; + font-weight: 800; + letter-spacing: 0.16em; + font-size: clamp(0.7rem, 2vw, 0.95rem); + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.8); +} +.link { + display: inline-flex; + align-items: center; + gap: 0.4em; + color: #9aa0a4; + font-size: 0.78rem; +} +.lamp { + width: 0.8em; + height: 0.8em; + border-radius: 50%; + background: #2a2a2a; + box-shadow: inset 0 0 3px #000; + transition: background 0.1s; +} +.lamp--on { + background: var(--green); + box-shadow: 0 0 8px var(--green); +} + +/* --- mirror --------------------------------------------------------------- */ +.mirror { + padding: clamp(0.7rem, 2.5vw, 1.2rem); + border-radius: 12px; + background: radial-gradient(120% 160% at 50% 0%, #141312, #070605); + border: 1px solid #000; + box-shadow: inset 0 5px 16px rgba(0, 0, 0, 0.9); +} +.mirror-time { + display: flex; + align-items: baseline; + justify-content: center; + gap: 1rem; +} +.big { + font-variant-numeric: tabular-nums; + font-size: clamp(2.4rem, 12vw, 4.5rem); + font-weight: 400; + letter-spacing: 0.04em; + color: #ffe2bc; + text-shadow: 0 0 6px #ff7a1e, 0 0 22px #ff6a00, 0 0 50px rgba(255, 90, 0, 0.5); +} +.run { + letter-spacing: 0.2em; + font-size: 0.75rem; + color: #7d8286; +} +.run.live { + color: var(--green); + text-shadow: 0 0 8px rgba(70, 224, 106, 0.6); +} +.mirror-meta { + margin-top: 0.6rem; + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.6rem 1.4rem; + font-size: clamp(0.6rem, 1.6vw, 0.8rem); + letter-spacing: 0.12em; + color: #8b9094; +} +.mirror-meta b { + color: var(--amber); +} + +/* --- banks ---------------------------------------------------------------- */ +.bank { + padding: 0.8rem clamp(0.7rem, 2.5vw, 1.1rem) 1rem; + border-radius: 12px; + background: linear-gradient(180deg, var(--steel-hi) -40%, var(--steel) 50%, var(--steel-lo)); + border: 1px solid #0d0e0f; + box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.1), inset 0 -3px 8px rgba(0, 0, 0, 0.5); +} +.bank-label, +.sub { + display: block; + letter-spacing: 0.18em; + font-size: 0.62rem; + font-weight: 700; + color: #8b9094; + margin-bottom: 0.6rem; + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.7); +} +.sub { + display: inline; + margin: 0 0.4rem 0 0; + align-self: center; +} +.row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.5rem; +} +.row + .row { + margin-top: 0.6rem; +} + +/* --- buttons -------------------------------------------------------------- */ +.btn { + font: inherit; + font-weight: 700; + letter-spacing: 0.08em; + font-size: 0.8rem; + color: #e7eaed; + padding: 0.55rem 0.9rem; + border-radius: 7px; + border: 1px solid #000; + background: linear-gradient(180deg, #3c4044, #23262a); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 2px 4px rgba(0, 0, 0, 0.5); + cursor: pointer; + transition: transform 0.05s, filter 0.1s; +} +.btn:hover { + filter: brightness(1.15); +} +.btn:active { + transform: translateY(1px); + box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.6); +} +.btn--wide { + flex: 1; +} +.btn.active { + color: #0a0b0c; + background: linear-gradient(180deg, #ffd98a, var(--amber)); + box-shadow: 0 0 10px rgba(255, 179, 71, 0.6); +} +.btn--amber { + color: #2a1c00; + background: linear-gradient(180deg, #ffd98a, var(--amber)); +} +.btn--red { + color: #fff; + background: linear-gradient(180deg, #ff6a60, var(--red)); +} +.btn--big { + flex: 1; + font-size: 1rem; + padding: 0.9rem; + letter-spacing: 0.16em; +} + +.grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); + gap: 0.5rem; + margin-bottom: 0.7rem; +} +.jump { + display: flex; + flex-direction: column; + gap: 0.15rem; + align-items: flex-start; + text-align: left; + padding: 0.5rem 0.7rem; +} +.jump b { + font-variant-numeric: tabular-nums; + font-size: 0.9rem; +} +.jump span { + font-weight: 400; + font-size: 0.62rem; + letter-spacing: 0.06em; + color: #aeb3b7; +} +.jump.btn--amber span, +.jump.btn--red span { + color: rgba(0, 0, 0, 0.65); +} + +.iters .iter { + flex: 1; + min-width: 90px; +} + +/* --- inputs --------------------------------------------------------------- */ +input { + font: inherit; + font-size: 0.85rem; + color: #e7eaed; + background: #101214; + border: 1px solid #000; + border-radius: 6px; + padding: 0.5rem 0.6rem; + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.6); +} +input:focus { + outline: 1px solid var(--amber); +} +#token, +#msg { + flex: 1; + min-width: 8rem; +} +.hint { + font-size: 0.7rem; + color: var(--amber); + letter-spacing: 0.08em; +} + +.foot { + text-align: center; + font-size: 0.72rem; + letter-spacing: 0.1em; + color: #7d8286; +} +.foot a { + color: var(--amber); +} diff --git a/services/observer-effect/site/control.html b/services/observer-effect/site/control.html new file mode 100644 index 0000000..e312a02 --- /dev/null +++ b/services/observer-effect/site/control.html @@ -0,0 +1,101 @@ + + + + + + + Array Control + + + +
+
+ ARRAY CONTROL · HANDLER ONLY + LINK +
+ + +
+
+ 17:00:00 + PAUSED +
+
+ COMMUNION IN —:—:— + ITERATION I + NEXT +
+
+ + +
+ +
+ + + +
+
+ + +
+ TRANSPORT +
+ + +
+
+ RATE + + + + + +
+
+ + +
+ JUMP TO BEAT +
+
+ SET + + +
+
+ + +
+ ITERATION — resets reality to its wake point +
+ + + + +
+
+ + +
+ EFFECTS — fire on the players' screen +
+ + +
+
+ + + +
+
+ + +
+ + + + + diff --git a/services/observer-effect/site/control.js b/services/observer-effect/site/control.js new file mode 100644 index 0000000..58ddede --- /dev/null +++ b/services/observer-effect/site/control.js @@ -0,0 +1,120 @@ +/* Handler's control panel. Sends authenticated commands to the relay and + mirrors the live clock so the Handler sees exactly what the players see. */ +(function () { + "use strict"; + + const $ = (id) => document.getElementById(id); + + // --- control key (persisted locally) -------------------------------------- + const tokenInput = $("token"); + tokenInput.value = localStorage.getItem("oe-token") || ""; + function saveToken() { + localStorage.setItem("oe-token", tokenInput.value.trim()); + flashHint("key set"); + } + $("saveToken").addEventListener("click", saveToken); + tokenInput.addEventListener("keydown", (e) => { + if (e.key === "Enter") saveToken(); + }); + let hintTimer = null; + function flashHint(text) { + const el = $("tokenHint"); + el.textContent = text; + clearTimeout(hintTimer); + hintTimer = setTimeout(() => (el.textContent = ""), 1500); + } + + // --- connection ----------------------------------------------------------- + const model = OE.ClockModel(); + const conn = OE.connect(OE.defaultWsUrl(), { + onstatus(s) { + $("lampLink").classList.toggle("lamp--on", s === "open"); + }, + onstate(state) { + model.apply(state); + syncRateButtons(state.rate); + }, + }); + window.addEventListener("beforeunload", () => conn.close()); + + function send(obj) { + const token = (localStorage.getItem("oe-token") || "").trim(); + if (!token) { + flashHint("no control key set"); + tokenInput.focus(); + return; + } + conn.send(Object.assign({ token }, obj)); + } + + // --- wire fixed-command buttons (play/pause/pulse/communion) --------------- + document.querySelectorAll("[data-cmd]").forEach((btn) => { + btn.addEventListener("click", () => send({ cmd: btn.dataset.cmd })); + }); + + // --- rate ----------------------------------------------------------------- + document.querySelectorAll(".rate").forEach((btn) => { + btn.addEventListener("click", () => send({ cmd: "rate", rate: Number(btn.dataset.rate) })); + }); + function syncRateButtons(rate) { + document.querySelectorAll(".rate").forEach((b) => { + b.classList.toggle("active", Number(b.dataset.rate) === rate); + }); + } + + // --- iterations ----------------------------------------------------------- + document.querySelectorAll(".iter").forEach((btn) => { + btn.addEventListener("click", () => send({ cmd: "iteration", n: Number(btn.dataset.iter) })); + }); + + // --- timeline jumps ------------------------------------------------------- + const jumps = $("jumps"); + OE.EVENTS.forEach((ev) => { + const b = document.createElement("button"); + b.type = "button"; + b.className = "btn jump" + (ev.communion ? " btn--red" : ev.pulse ? " btn--amber" : ""); + b.innerHTML = "" + ev.time + "" + ev.label + ""; + b.addEventListener("click", () => send({ cmd: "set", inworld: ev.t })); + jumps.appendChild(b); + }); + + // manual time -> seconds-of-day + $("manualJump").addEventListener("click", () => { + const parts = $("manualTime").value.split(":").map(Number); + if (parts.length >= 2 && parts.every((n) => !Number.isNaN(n))) { + const sec = (parts[0] || 0) * 3600 + (parts[1] || 0) * 60 + (parts[2] || 0); + send({ cmd: "set", inworld: sec }); + } + }); + + // --- broadcast message ---------------------------------------------------- + $("sendMsg").addEventListener("click", () => { + const text = $("msg").value.trim(); + if (text) send({ cmd: "msg", text }); + }); + $("clearMsg").addEventListener("click", () => send({ cmd: "msg", text: null })); + $("msg").addEventListener("keydown", (e) => { + if (e.key === "Enter") $("sendMsg").click(); + }); + + // player-screen link points at clock.html next to this page + $("clockLink").href = new URL("clock.html", location.href).href; + + // --- mirror loop ---------------------------------------------------------- + function nextBeat(inworld) { + const upcoming = OE.EVENTS.filter((e) => e.t > inworld + 0.5); + return upcoming.length ? upcoming[0] : null; + } + function frame() { + const s = model.now(); + $("mClock").textContent = OE.clock(s.inworld); + $("mIter").textContent = OE.ROMAN[s.iteration] || s.iteration; + $("mCountdown").textContent = s.remaining <= 0 ? "00:00:00" : OE.duration(s.remaining); + $("mRun").textContent = s.running ? "RUNNING" : "PAUSED"; + $("mRun").classList.toggle("live", s.running); + const nb = nextBeat(s.inworld); + $("mNext").textContent = nb ? nb.time + " " + nb.label : "—"; + requestAnimationFrame(frame); + } + requestAnimationFrame(frame); +})(); diff --git a/services/observer-effect/site/sfx/communion.mp3 b/services/observer-effect/site/sfx/communion.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..6ff07866649df957bdabe7ebdbdf44f29e1e1e33 GIT binary patch literal 107458 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 z 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 a%{%{Bd$;oajN0~W(*W!YLFrEp3 sub-bass impact -> screaming +# flutes over a beating void drone ------------------------------------- +ROAR='(1-exp(-2.5*t))*exp(-0.28*t)*0.28*(sin(2*PI*(60*t-2.5*t*t))+0.5*sin(4*PI*(60*t-2.5*t*t))+0.33*sin(6*PI*(60*t-2.5*t*t)))' +IMPACT='(1/(1+exp(-30*(t-1.6))))*exp(-3.2*(t-1.6))*0.95*sin(2*PI*(80*(t-1.6)-35*(t-1.6)*(t-1.6)))' +FLUTES='(1/(1+exp(-30*(t-1.7))))*exp(-0.9*(t-1.7))*0.07*(sin(2*PI*1700*t)+sin(2*PI*2050*t)+sin(2*PI*2390*t)+sin(2*PI*2900*t)+sin(2*PI*3550*t))*(1+0.4*sin(2*PI*5*t))' +DRONE='(1/(1+exp(-25*(t-1.7))))*exp(-0.5*(t-1.7))*0.22*(sin(2*PI*40*t)+sin(2*PI*40.5*t))' +TONAL="${ROAR} + ${IMPACT} + ${FLUTES} + ${DRONE}" +SWELL="volume=volume='0.4*(1-exp(-2.2*t))*(1/(1+exp(8*(t-1.95))))*(0.6+0.4*sin(2*PI*0.9*t))':eval=frame" +ffmpeg -y -hide_banner -loglevel error \ + -f lavfi -i "aevalsrc=${TONAL}:s=${SR}:d=6.5" \ + -f lavfi -i "anoisesrc=color=white:amplitude=0.6:r=${SR}:d=6.5" \ + -filter_complex "[1:a]highpass=f=3000,${SWELL}[n];[0:a][n]amix=inputs=2:normalize=0,aecho=0.8:0.85:55|150:0.35|0.2,alimiter=limit=0.96,aresample=44100[out]" \ + -map "[out]" "${MP3[@]}" communion.mp3 + +# --- whisper: a brief eerie transmission for broadcast text ------------------ +WHISP='(1-exp(-8*t))*exp(-2*t)*0.12*(sin(2*PI*620*t)+sin(2*PI*623*t))' +WHISP+=' + exp(-3*t)*0.04*sin(2*PI*(2200*t-300*t*t))' +WHISP+=' + 0.03*exp(-1.5*t)*sin(2*PI*1240*t)*(1+0.6*sin(2*PI*11*t))' +ffmpeg -y -hide_banner -loglevel error \ + -f lavfi -i "aevalsrc=${WHISP}:s=${SR}:d=1.6" \ + -f lavfi -i "anoisesrc=color=white:amplitude=0.25:r=${SR}:d=1.6" \ + -filter_complex "[1:a]bandpass=f=1500:width_type=h:w=900,volume=volume='0.18*exp(-2.5*t)*(0.5+0.5*sin(2*PI*13*t))':eval=frame[n];[0:a][n]amix=inputs=2:normalize=0,volume=12dB,aecho=0.8:0.6:70:0.3,alimiter=limit=0.9,aresample=44100[out]" \ + -map "[out]" "${MP3[@]}" whisper.mp3 + +# --- relay: a dry electromechanical seconds step (armature snap + body) ------- +# The seconds advance is a stepping relay, not a pendulum: a sharp broadband +# snap with a faint low "thunk" and almost no tonal tail. +RELAY='exp(-120*t)*0.3*sin(2*PI*430*t) + exp(-220*t)*0.32*sin(2*PI*1700*t)' +ffmpeg -y -hide_banner -loglevel error \ + -f lavfi -i "aevalsrc=${RELAY}:s=${SR}:d=0.09" \ + -f lavfi -i "anoisesrc=color=white:amplitude=0.6:r=${SR}:d=0.09" \ + -filter_complex "[1:a]bandpass=f=2400:width_type=h:w=2400,volume=volume='0.6*exp(-230*t)':eval=frame[n];[0:a][n]amix=inputs=2:normalize=0,alimiter=limit=0.95,aresample=44100[out]" \ + -map "[out]" "${WAV[@]}" relay.wav + +echo "generated:" +for f in pulse.mp3 communion.mp3 whisper.mp3 relay.wav; do + printf ' %-14s %s\n' "$f" "$(du -h "$f" | cut -f1)" +done diff --git a/services/observer-effect/site/sfx/pulse.mp3 b/services/observer-effect/site/sfx/pulse.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..202c98216decf0f231361b4cc334ee141dd5ddbc GIT binary patch literal 25120 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 BAPoQj literal 0 HcmV?d00001 diff --git a/services/observer-effect/site/sfx/relay.wav b/services/observer-effect/site/sfx/relay.wav new file mode 100644 index 0000000000000000000000000000000000000000..a9b3fca29b2607ad9cf1fb804b5b0fa63470e618 GIT binary patch literal 8016 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 literal 0 HcmV?d00001 diff --git a/services/observer-effect/site/sfx/whisper.mp3 b/services/observer-effect/site/sfx/whisper.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..46ed91912ef26c738530a2ae7678108fd2a4fa65 GIT binary patch literal 27628 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 literal 0 HcmV?d00001 diff --git a/services/observer-effect/site/sound.js b/services/observer-effect/site/sound.js new file mode 100644 index 0000000..aee0ada --- /dev/null +++ b/services/observer-effect/site/sound.js @@ -0,0 +1,326 @@ +/* Optional soundscape for the player screen — the "flutes and drums" the + scenario keeps describing. Silent until the player clicks to enable it + (browsers block audio without a gesture). All synthesized; no asset files. */ +(function () { + "use strict"; + + let ctx = null; + let master = null; + let droneGain = null; + + // Pre-rendered ffmpeg SFX (see sfx/generate.sh). Decoded into buffers on + // enable; if a file fails to load we fall back to the synth below. + const FILES = { + pulse: "sfx/pulse.mp3", + communion: "sfx/communion.mp3", + whisper: "sfx/whisper.mp3", + relay: "sfx/relay.wav", + }; + const buffers = {}; + + function loadBuffers() { + for (const [name, url] of Object.entries(FILES)) { + fetch(new URL(url, location.href)) + .then((r) => (r.ok ? r.arrayBuffer() : Promise.reject())) + .then((data) => ctx.decodeAudioData(data)) + .then((buf) => (buffers[name] = buf)) + .catch(() => {}); + } + } + + function play(name) { + const buf = buffers[name]; + if (!buf || !ctx) return false; + const src = ctx.createBufferSource(); + src.buffer = buf; + src.connect(master); + src.start(); + return true; + } + + function enable() { + if (ctx) return true; + const AC = window.AudioContext || window.webkitAudioContext; + if (!AC) return false; + ctx = new AC(); + master = ctx.createGain(); + master.gain.value = 0.8; + master.connect(ctx.destination); + + // A near-subaudible drone that swells as communion nears (see setDread). + droneGain = ctx.createGain(); + droneGain.gain.value = 0; + droneGain.connect(master); + const drone = ctx.createOscillator(); + drone.type = "sine"; + drone.frequency.value = 33; + const drone2 = ctx.createOscillator(); + drone2.type = "sine"; + drone2.frequency.value = 33.4; // beat against the first for unease + drone.connect(droneGain); + drone2.connect(droneGain); + drone.start(); + drone2.start(); + + // Mains hum: this is a high-voltage 1964 nixie device, so it's never truly + // silent. A 60 Hz transformer hum with harmonics plus a faint HV whine, + // synthesized live so it loops seamlessly. Constant while sound is on. + const humGain = ctx.createGain(); + humGain.gain.value = 0.07; + humGain.connect(master); + const humLfo = ctx.createOscillator(); // slow amplitude waver + humLfo.frequency.value = 0.5; + const humLfoGain = ctx.createGain(); + humLfoGain.gain.value = 0.012; + humLfo.connect(humLfoGain).connect(humGain.gain); + humLfo.start(); + const humLp = ctx.createBiquadFilter(); + humLp.type = "lowpass"; + humLp.frequency.value = 500; + humLp.connect(humGain); + [[60, 0.5], [120, 0.32], [180, 0.12]].forEach(([f, g]) => { + const o = ctx.createOscillator(); + o.type = "sine"; + o.frequency.value = f; + const og = ctx.createGain(); + og.gain.value = g; + o.connect(og).connect(humLp); + o.start(); + }); + const whine = ctx.createOscillator(); // high-voltage supply whine + whine.type = "sine"; + whine.frequency.value = 15000; + const whineGain = ctx.createGain(); + whineGain.gain.value = 0.015; + whine.connect(whineGain).connect(humGain); + whine.start(); + + loadBuffers(); + return true; + } + + function enabled() { + return !!ctx; + } + + // Low drum thump + a thin flute whistle: one "pulse" of Azathoth's court. + function synthPulse() { + if (!ctx) return; + const t = ctx.currentTime; + + const drum = ctx.createOscillator(); + const dg = ctx.createGain(); + drum.type = "sine"; + drum.frequency.setValueAtTime(64, t); + drum.frequency.exponentialRampToValueAtTime(34, t + 0.5); + dg.gain.setValueAtTime(0.0001, t); + dg.gain.exponentialRampToValueAtTime(0.9, t + 0.02); + dg.gain.exponentialRampToValueAtTime(0.0001, t + 0.7); + drum.connect(dg).connect(master); + drum.start(t); + drum.stop(t + 0.75); + + const flute = ctx.createOscillator(); + const fg = ctx.createGain(); + flute.type = "triangle"; + flute.frequency.setValueAtTime(1900, t); + flute.frequency.exponentialRampToValueAtTime(3300, t + 0.6); + fg.gain.setValueAtTime(0.0001, t); + fg.gain.exponentialRampToValueAtTime(0.12, t + 0.05); + fg.gain.exponentialRampToValueAtTime(0.0001, t + 0.65); + flute.connect(fg).connect(master); + flute.start(t); + flute.stop(t + 0.7); + } + + function noise(dur) { + const len = Math.floor(ctx.sampleRate * dur); + const buf = ctx.createBuffer(1, len, ctx.sampleRate); + const data = buf.getChannelData(0); + for (let i = 0; i < len; i++) data[i] = Math.random() * 2 - 1; + return buf; + } + + // The full extrusion: a rising roar and noise swell that detonate into a + // sub-bass impact, then a cluster of screaming flutes over a void drone. + // Timed so the impact lands with the visual blast (~1.6s in). + function synthCommunion() { + if (!ctx) return; + const t = ctx.currentTime; + const blast = t + 1.6; + + // rising roar into the blast + const roar = ctx.createOscillator(); + const rg = ctx.createGain(); + roar.type = "sawtooth"; + roar.frequency.setValueAtTime(26, t); + roar.frequency.exponentialRampToValueAtTime(64, blast); + roar.frequency.exponentialRampToValueAtTime(30, blast + 2.6); + rg.gain.setValueAtTime(0.0001, t); + rg.gain.exponentialRampToValueAtTime(0.5, blast); + rg.gain.exponentialRampToValueAtTime(0.0001, blast + 3.2); + roar.connect(rg).connect(master); + roar.start(t); + roar.stop(blast + 3.4); + + // reverse-cymbal noise swell sucking up into the blast + const sw = ctx.createBufferSource(); + sw.buffer = noise(2); + const swf = ctx.createBiquadFilter(); + swf.type = "highpass"; + swf.frequency.setValueAtTime(200, t); + swf.frequency.exponentialRampToValueAtTime(9000, blast); + const swg = ctx.createGain(); + swg.gain.setValueAtTime(0.0001, t); + swg.gain.exponentialRampToValueAtTime(0.22, blast); + swg.gain.exponentialRampToValueAtTime(0.0001, blast + 0.4); + sw.connect(swf).connect(swg).connect(master); + sw.start(t); + sw.stop(blast + 0.5); + + // THE IMPACT: a plunging sub-bass body + a broadband burst + const imp = ctx.createOscillator(); + const ig = ctx.createGain(); + imp.type = "sine"; + imp.frequency.setValueAtTime(82, blast); + imp.frequency.exponentialRampToValueAtTime(18, blast + 0.8); + ig.gain.setValueAtTime(0.0001, blast); + ig.gain.exponentialRampToValueAtTime(0.95, blast + 0.03); + ig.gain.exponentialRampToValueAtTime(0.0001, blast + 1.4); + imp.connect(ig).connect(master); + imp.start(blast); + imp.stop(blast + 1.5); + + const burst = ctx.createBufferSource(); + burst.buffer = noise(1); + const bf = ctx.createBiquadFilter(); + bf.type = "bandpass"; + bf.frequency.value = 1100; + bf.Q.value = 0.4; + const bg = ctx.createGain(); + bg.gain.setValueAtTime(0.55, blast); + bg.gain.exponentialRampToValueAtTime(0.0001, blast + 0.6); + burst.connect(bf).connect(bg).connect(master); + burst.start(blast); + burst.stop(blast + 0.7); + + // screaming flute cluster after the rupture + [1700, 2050, 2390, 2900, 3550, 4200].forEach((f, i) => { + const o = ctx.createOscillator(); + const g = ctx.createGain(); + o.type = "triangle"; + o.frequency.setValueAtTime(f, blast); + o.frequency.linearRampToValueAtTime(f * 1.22, blast + 2.6); + g.gain.setValueAtTime(0.0001, blast + i * 0.06); + g.gain.exponentialRampToValueAtTime(0.06, blast + 0.3 + i * 0.06); + g.gain.exponentialRampToValueAtTime(0.0001, blast + 3); + o.connect(g).connect(master); + o.start(blast + i * 0.06); + o.stop(blast + 3.2); + }); + + // void drone tail (two detuned sines, beating) + const vg = ctx.createGain(); + vg.gain.setValueAtTime(0.0001, blast + 0.2); + vg.gain.exponentialRampToValueAtTime(0.3, blast + 1); + vg.gain.exponentialRampToValueAtTime(0.0001, blast + 4); + vg.connect(master); + [40, 40.5].forEach((f) => { + const o = ctx.createOscillator(); + o.type = "sine"; + o.frequency.value = f; + o.connect(vg); + o.start(blast); + o.stop(blast + 4.2); + }); + } + + // level 0..1 — swells the drone with tension, but cuts cleanly to silence + // once tension is spent so the deep pulse doesn't hang around. + function setDread(level) { + if (!ctx || !droneGain) return; + const clamped = Math.max(0, Math.min(1, level)); + const now = ctx.currentTime; + if (clamped <= 0.08) { + droneGain.gain.cancelScheduledValues(now); + droneGain.gain.setTargetAtTime(0, now, 0.3); + return; + } + droneGain.gain.setTargetAtTime(clamped * 0.22, now, 1.5); + } + + // File first, synth as fallback. + function pulse() { + if (!play("pulse")) synthPulse(); + } + function communion() { + if (!play("communion")) synthCommunion(); + } + function message() { + play("whisper"); + } + + // Per-second stepping relay — consistent level, no variation. Optionally + // scheduled at a future AudioContext time (`when`) so ticks keep firing while + // the tab is backgrounded. Pending clicks are tracked so they can be canceled. + let pendingTicks = []; + function step(when) { + if (!ctx) return; + const at = when || ctx.currentTime; + const g = ctx.createGain(); + g.gain.value = 0.4; + g.connect(master); + let node; + if (buffers.relay) { + node = ctx.createBufferSource(); + node.buffer = buffers.relay; + node.connect(g); + node.start(at); + } else { + node = ctx.createOscillator(); + node.type = "square"; + node.frequency.value = 1800; + const e = ctx.createGain(); + e.gain.setValueAtTime(0.0001, at); + e.gain.exponentialRampToValueAtTime(0.4, at + 0.002); + e.gain.exponentialRampToValueAtTime(0.0001, at + 0.03); + node.connect(e).connect(g); + node.start(at); + node.stop(at + 0.04); + } + pendingTicks.push({ node, at }); + if (pendingTicks.length > 64) { + pendingTicks = pendingTicks.filter((p) => p.at > ctx.currentTime - 1); + } + } + + // Stop any clicks scheduled for the future (e.g. on pause or a clock jump). + function cancelTicks() { + if (!ctx) return; + const t = ctx.currentTime; + for (const p of pendingTicks) { + if (p.at > t) { + try { + p.node.stop(t); + } catch (_) {} + } + } + pendingTicks = pendingTicks.filter((p) => p.at > t); + } + + function audioNow() { + return ctx ? ctx.currentTime : 0; + } + + window.OESound = { + enable, + enabled, + pulse, + communion, + message, + step, + cancelTicks, + now: audioNow, + setDread, + }; +})(); diff --git a/services/secrets/observer_vps.yaml b/services/secrets/observer_vps.yaml new file mode 100644 index 0000000..2c2ab9f --- /dev/null +++ b/services/secrets/observer_vps.yaml @@ -0,0 +1,17 @@ +observer: + token: ENC[AES256_GCM,data:0qpwXX4QtrQFkmCZJ1RnvIbI+1DN+lB9OAIvvLvh694=,iv:3T5KFJxrzYkOr+LwNmk+FeKoySub+BJ5brf4kJvfxAE=,tag:6gVWgBPD5KYMVYzhkN7Nyg==,type:str] +sops: + age: + - recipient: age1856wmagg3dz4j07alwqnn6d75655t6wcs8glklyjyezhu5p875fq9sez4p + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIU3NCcHZvRFlvRmcvc1Yz + cDB6NUo2MkRsTVh5ekZic01oM0xQTXJFKzNRCjRsZFRRQnIrTjNzcFM0RzVFbVhV + NDBjVzhuTTVVOFp1dVJJL1hObDNVaHMKLS0tIDZxWFNtSWFxQ1hyV2tLTHNFZzJ5 + YmRBT3d2d05XdURiMkU4dm5lc1h0MFkK0HyRftTHpoDCk0qxDydBc1cCORf4p7Ev + Cyqy+YKJXXI5HGlBG+pxVbpVPgKebY8WNt2891i/v9vgQkN1owk0iA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-06-15T06:20:11Z" + mac: ENC[AES256_GCM,data:uXv9/78DBOZxIS8nj+UK8OZzvRUCq1tmMSNV+WVZGUnEYcmYzQFT4ZAR2ojvk5uTjn1DQg9lppNH3WFEQc3LOuxFmbOBLWFIqsRHFfaek7xVbcWPibe9SGJ7opqbRWCTpC/yEC2Uf8/Zcjp5tkqI7+3FUunK0R1mYo2KBNxe+68=,iv:2T9PGvfB07+V5pCIq/InQpXNtVGwutA5HwfJ4L03Ymc=,tag:+Sm77auYcLyHYFIXDpBagQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.12.1