# Load-bearing comments Code carries none. Anything non-obvious is explained here instead. ## `apps/web/src/gpu.ts` (PROJECTOR) Uniforms never ride the frame JSON: `shade` carries only the program (plus `route`/`mesh` for the mesh path) and the vector comes from wasm as a Float32Array, the same route `geometry()` takes. The rAF loop tweens shader uniforms between the last two kernel keyframes, lagging one beat behind so interpolation is exact - no prediction, no correction pops. The `TWEENS` table classifies uniform indices per program: `linear` lerps, `angle` lerps by shortest path around TAU, `viewport` lerps centers linearly and spans in log space (fractal zoom compounds multiplicatively, so a linear span lerp would stutter). `leaps` snaps instead of tweening when a keyframe jumps (span ratio over 8x or the center leaving the old view) - that is a `begin()` reset, not motion. Tween duration is the observed keyframe gap clamped to 125-500ms, so a lagging kernel stretches gracefully. Reduced motion clears every tween and the kernel's honest 8/s stepping shows. Untabled programs (textured shaders) never tween. The `mesh` program is a second draw path: vertex buffers instead of a fullscreen triangle, its own depth texture per canvas, and geometry fetched from wasm only when `shade.mesh` (the signature) changes, since the buffer itself never rides the per-frame uniforms. Alpha (uniform 19) picks opaque (one pass, depth write) or glass (two passes, back then front by `facing`, depth test only) - there is no per-triangle sort on the GPU, so glass correctness relies on the shapes being convex. ## `apps/web/src/journal.ts` (RUNS) Only beat-flagged calls merge, and only verbs in `RUNS`; the caps mirror each verb's kernel clamp (64 for the physics sims, 1024 elsewhere), so a merged row always replays whole. Merging rewrites the tail row's `{n}` and `now` in place and persists, so a crash loses at most one beat. Any other verb lands after the run row, preserving order and outcome. The tick verbs (clock, font, memory, timer) take no `n` and stay unmerged. ## `pkgs/mrlyrs/mrlyos/src/kernel/os.rs` (RING) The display ring merges a call into the tail entry when the verb matches and both args are the n-shape ({} or {n}), so a beat run reads as one "verb n" row in the log app. Display only - the replay journal has its own merge rule in apps/web/src/journal.ts, which must stay outcome-exact. ## `pkgs/mrlyrs/mrlyos/src/kernel/app.rs` (CAPTURE) In gpu render mode mandelbrot/julia skip the CPU raster and emit an empty `frame` (real width/height, no rows) - the shell reads only `shade` then. solids/three instead raster a small real 96 frame in gpu mode (the `detail` setting sizes the cpu mode), so replay stays whole. `sys.shot` goes through `App::capture()`, which these apps override to raster at `detail` on demand, so shots stay bit-identical in both modes. ## `pkgs/mrlyrs/mrlyui/src/shaders/mesh.wgsl` (MESH) The vertex stages are float ports of `Camera::matrix()`/`view()` and `beam()` from camera.rs, which stays the tested spec - its LUT-quantized i64 angles cannot serve smooth steer, so the shader takes radians and rebuilds the matrix per vertex. Geometry rides one packed Float32Array: `[tri floats, line floats, tris..., lines...]`; a tri vertex is pos3+normal3, a line vertex pos3+spin flag+rgba, flag 1 spins with the model, 0 is world furniture (axes, grid). The shade's `mesh` signature names the buffer; gpu.ts refetches geometry only when it changes. ## `apps/web/src/render/nodes.ts` (CANVAS) `Canvas` patches skip on a committed signature (the `Cells` pattern) built from render mode, darkmode, the pulled uniform vector, palette and rows; theme's accent case clears it because the alpha fill path reads the CSS color. `strip` playback paints intermediate frames across one 125ms beat window on rAF; reduced motion paints only the final frame. ## `pkgs/mrlyrs/mrlymath/src/physics/waves.rs` The `step` leapfrog update is `n = 2c - p + c2*lap - damp*(c-p)`, with neighbor values zeroed across reflective walls and walls themselves held at 0. Sources inject additively through a baked Gaussian stamp, suppressed inside walls, at amplitude `amp * envelope[age] * SINE[phase]`. The whole step path is `+ - * /` only, no libm, to stay parity-clean with the GPU shader. Everything that survives a save is integer: `WavesConfig` is milli, source `x`/`y` are milli grid units, `phase` is step-milli on the 256-step wheel (`WHEEL` = 256000 per turn) and `age` is a tick count. Only the field itself, recomputed every step and never saved, stays f32. ## `pkgs/mrlyrs/mrlymath/src/physics/lasers.rs` Ray directions are step-milli positions on the baked `trig::SINE` ring (`WHEEL` = 256000 per turn), not radians. `dir`, `omega_idx` and `spread_idx` all carry that unit, so the step/trace path never calls `cos`/`sin`; the app's spread and spin tables are baked step-milli constants rather than radians converted at runtime. Emitter `x`/`y` are milli grid units and only ray marching, which ends in pixels, drops to f32. ## `pkgs/mrlyrs/mrlymusic/src/theory.rs` `MILLIHERTZ` bakes all 128 midi notes as integer millihertz, equal temperament from A4 = 440000, so `freq` is a table lookup and cue payloads carry exact integers with no float in the construction path. Cue `gain` is centi percent. The ear boundary is the only place that divides: synthesis in `render.rs` and WebAudio in `apps/web/src/shell/effects.ts`. ## `pkgs/mrlyrs/mrlymath/src/physics/rng.rs` `Rng` is a hand-rolled SplitMix64, not the `rand` crate, so the exact bit sequence is fixed in source and reproduces identically across every backend that mirrors this module (needed for `examples/physics_parity.rs`). ## `pkgs/mrlyrs/mrlymath/src/physics/waves_luts.rs` Generated by `data/physics/gen_waves.py`. Do not hand-edit; regenerate with the script if the envelope/stamp formulas change. ## `apps/web/src/render/wallpaper.ts` The pattern tile is a data-URI SVG on `body`'s `background-image`, so the glass `backdrop-filter` blurs it for free (body paints behind everything - no extra DOM, no z-index). Data-URI SVGs cannot load webfonts, so the tile is emoji-only (system font; the `emoji` and mrly-font settings cannot reach it) and geometry derives from `seed` via a Park-Miller LCG (`seed + 1` because the multiplier needs a nonzero state). The accent tint is read with `getComputedStyle`, which substitutes the `var()` chain to a real hex - a literal color is required inside the SVG. ## `apps/web/styles/boxes.css` (GLASS) Glass selectors are wrapped in `:where()` to pin specificity at one class: they must beat the base `.mrly-box`/`.border-box` rules (same specificity, later in the sheet) yet lose to the two-class hover/active inversions and `.cell-box > .mrly-box`. The reduced-transparency block restores solid values and must stay below the glass rules for the same reason. Cards paint through the `--tint` var (set inline by `patch`/`repaint`), never inline `background-color`, or glass could not translate the tint to `color-mix`. ## `pkgs/mrlyrs/mrlyos/build.rs` MRLY_VERSION hashes every .rs under `pkgs/mrlyrs/` (the `..` walk), not just mrlyos: the web app invalidates persisted journals on version change, so the stamp must move when any crate's behavior can. With MRLY_RELEASE set the hash is dropped for a stable version string. ## `pkgs/mrlyrs/mrlycore/src/codec.rs` (EGRESS) The png encoder is egress only - the world stores Grids (`Image` facts), never png bytes. The zlib stream uses deflate's fixed Huffman table (BTYPE 01) over a greedy hash-chain LZ77 matcher: window 32768, chain capped at 128, first full-length match wins. Fixed beats stored by ~100x on our flat-color faces and even beats the old png crate, because runs of identical pixels collapse into short match symbols; dynamic Huffman (BTYPE 10, per-image code tables) would shave maybe another third off at 3x the code and is not worth owning until a real consumer feels the bytes. The tests carry a tiny fixed-only inflater so round-trips stay proven without any dependency; Python's zlib and macOS sips validated the streams independently when the encoder landed. The `huffman` writer reverses bit order because deflate packs Huffman codes MSB-first into an LSB-first stream - the one genuinely confusing rule in RFC 1951. ## `pkgs/mrlyrs/mrlycore/src/chacha.rs` (STREAM) A from-scratch port of the exact stream `rand_chacha` 0.3 + `rand` 0.8 produced, so every seeded replay recorded before the port stays bit-identical forever. That contract explains everything odd in the file: `from_u64` is rand_core's PCG32 seed expansion; the 64-word buffer with counters advancing four blocks per refill mirrors BlockRng, including `next_u64`'s three-way branch at the buffer edge; `word_pos`/`set_word_pos` reproduce ChaCha8Rng's 68-bit word addressing for `Rng::pos`/`seek`. The samplers are rand 0.8 verbatim: widening-multiply rejection with the shifted-zone approximation for single draws, the exact-modulus zone for `sample_rejection`, the `f32` cost model picking floyd/inplace/rejection in `sample_indices`, and the u32 fast path in `shuffle`. None of it may be "improved" - any deviation changes streams and breaks replay. The pinned tests in the file were generated from the real crates before they were removed; golden app fixtures pin the same contract end to end. `state.rs` seeds its unseeded default from `RandomState` (the one entropy source std offers everywhere, wasm included); every product path seeds explicitly, so that default is only a fallback. ## `testkit` features (mrlycore, mrlyos) `mrlyos::kernel::testkit` and `mrlycore::state::guard` are gated `any(test, feature = "testkit")` because cfg(test) items are invisible across crate boundaries: downstream crates enable the feature in their dev-dependencies to reach them from tests. ## `pkgs/mrlyrs/mrlyos/src/kernel/goose.rs` (GOOSE) Verb args are type hints, not legal moves, so the goose synthesizes: enums split on `|`, `int a..b` is inclusive, bare ints roll 0..15 (except `seed` keys, which roll wide), `square` builds chess notation, strings draw from a small word list. A verb is playable when a dry run against a cloned rng fills every hint - the clone keeps the real stream unmoved, so filtering never disturbs determinism. `*.reset` is excluded from the pool: games drop their play verbs when over, so an empty pool IS game over and triggers the reset directly; PATIENCE consecutive all-miss steps (chess-like odds) do the same. ## `apps/web/src/shell/mount.ts` (ATTRACT) Games and puzzles idle under a live goose (`lure`/`shoo`/`wake`): the wasm Handle caches one Goose per seed, so a 250 ms interval replaying `goose(seed)` continues one playthrough, and each visit reseeds from the clock. `wake` resets before forwarding the waking input, so the first keypress both starts and plays. Beats never wake; `calm` skips the interval but keeps the start affordance. ## `apps/git/public/style.css` (HERO) The home hero replays the MRLYPROD merge from `apps/jsx/src/lib/frames.ts` in pure CSS: letters snap in left to right (opacity keyframes 0.2% apart make the fade binary), hold, then collapse pairwise inward over 72%-92% in four 5% sub-phases, one 6-unit jump per phase, mirroring the frames.ts phase walk. Each letter's final offset is 22-(1+i*6), so the eight letters stack on one 5x5 cell whose union is the X glyph - `cargo test -p mrlyssg mrlyprod_union_is_x` proves it. The final translate sits on `92%, 100%`: drop the 100% and the browser synthesizes it from the base value 0, sliding every letter home. The 87% keyframe switches to `steps(3, end)` so the last 3-unit phase still jumps exactly one unit per step. ## `utils/brand.py` (MANIFEST) `MANIFEST` is the only declaration of what lands in each app's `public/`. Shared bytes (the text faces, the emoji shards, MrlyFont, the licenses) go to `data/cdn/` under content-hashed names and are served from cdn.mrly.net; site-specific bytes (favicon, mark, pngs, the per-site icon subset) stay local, because each site subsets a different set of Material Symbols. `fnv` must stay bit-identical to `pkgs/mrlyssg/src/dist.rs`, so a name hashed here and a name hashed by the git projection agree. The icon subset url differs by site on purpose: git's sheet is served raw so it takes `/fonts/site.woff2`, while web's is bundled by bun, which cannot resolve a root-absolute url and needs `./fonts/icons.woff2`.