Skip to content

Checklist

  • Low-end / older Windows iGPU box (§9), 1080p. Run the current release standalone, let it reach steady state, capture diagnostics.log. Report (a) fps holds ≥ 60 @ 1080p, and (b) steady-state working set + private commit. (This is Plan 0012 Phase 3, extracted; it also satisfies the identical Plan 0003 Phase 3 iGPU-60-fps carry-forward — same measurement.)

  • Second GPU vendor — Intel iGPU, if a box is available, 1080p. Same capture. The point is the footprint spread vs the AMD dev box — confirms whether the ~350 MB ceiling is AMD-specific.

  • The dual-live dissolve budget, on the low-end box. Plan 0023 made every preset switch a ~1 s dissolve, and its governor re-renders the outgoing preset live as well whenever the two presets hold independent GPU state and the smoothed frame time is under DUAL_LIVE_BUDGET_MS (core/src/render/mod.rs, currently 18.0 — the code calls it “the number to calibrate on a low-end rig”, and no capture can speak to it because a headless run collects no frame times and so never upgrades). Two things to report, both with the overlay on (F3) so the p99 is visible: (a) press Space repeatedly between light presets — does the frame time hold ≥ 60 fps through the dissolves, or does the governor’s threshold need to come down; (b) the heavy pair — dissolve an attractor preset into a reaction-diffusion one and back. That pair is the freeze fallback’s reason for existing; on this box it should either stay frozen (fine) or, if it upgrades, still hold the floor. (Plan 0023 Phase 4’s done-when and its budget-tuning risk, extracted at that plan’s close.)

  • The layered heavy pair (Plan 0076), on the low-end box, 1080p. A preset may now compose a second scene ([layer], ADR-0090), and Floor renders both layers by design — a two-layer world must not lose half its content on weak hardware. The deliberately heavy pairing is an attractor main with a reaction-diffusion layer, at both joins (under, and over with a blend — the over join adds a surface-sized Rgba16Float offscreen pair and one blend pass). With the overlay on (F3), load such a preset — the Plan 0076 close notes carry probe TOMLs, or write one from presets/README.md — and report (a) whether fps holds ≥ 60 at 1080p for each join and (b) the p99 against the attractor preset alone. (Plan 0076 Phase 4’s measured numbers are dev-box hardware figures, not iGPU evidence; this line is where that evidence comes from. If it fails, the response is authoring guidance — heavy-plus-heavy pairings are an authoring responsibility per ADR-0090 — not a tier change.)

  • Trails at native resolution, on the low-end box, 1080p. Plan 0033 made the two post stages size their internal grid from the render target instead of a fixed 1280x720 (ADR-0034). With trails active that is now a full-resolution Rgba16Float ping-pong read and write every frame where it used to be a 720p one — roughly 2.25x the feedback bandwidth at 1080p. Plan 0045 raised it again: the accumulation was always float, but the stage’s composited output and the fold’s source were the surface format and are now Rgba16Float too (ADR-0046), so every hand-off between stages moved from 4 to 8 bytes a texel. Composite bandwidth roughly doubled on top of the 2.25x. NFR §1’s ≥ 60 fps @ 1080p floor is exactly the claim at risk, and no headless capture can speak to it: WARP timings say nothing about an iGPU’s memory bandwidth. Load rose_trails — it binds trails around 0.78 and is the shipped preset that exercises this path (fragment_kaleido covers the fold). Let it settle with the overlay on (F3), and report (a) whether fps holds ≥ 60 and (b) the p99 against the same preset with trails = 0. (Plan 0033’s stated main exposure, widened by Plan 0045. If it fails, lower TierConfig::FLOOR.post_cap in core/src/render/tier.rs — the constant moved there in Plan 0044 — and do not re-fix the grids.)

  • Working-set delta from the post stages, including mid-dissolve. Re-stated for the float composite (Plan 0045). These numbers moved twice: Plan 0033 grew the composite from ~22 MB per chain to ~50 MB at the cap by sizing the grids from the target, and Plan 0045 took that to ~66 MB by moving every intermediate to Rgba16Float (8 bytes a texel, not 4). A dual-live dissolve holds two chains, so the transient peak is ~133 MB, and the worst case — dual-live, every stage on including bloom, ink on — is ~246 MB against NFR §12’s ~350 MB soft ceiling, which is mostly driver floor already. There is also a genuinely new surface-sized float buffer that exists on every frame regardless of preset: the tonemap’s input, 16.6 MB at 1080p. The full before/after table is in Non-functional requirements §12. Those figures are arithmetic from the texture descriptors, not a measurement. On the low-end box, report the steady-state working set with a trails preset active, and again while holding down preset switches so a dissolve is live, against the same numbers with trails = 0. Read rss_bytes, not gpu_bytes — the latter is a swapchain-only approximation (ADR-0008) that does not count the post stages’ offscreens, so it reads identically either way. Measured on the dev box after Plan 0033 landed: gpu_bytes unchanged at 16,588,800 (= 1920x1080 x 4 B x 2 — the swapchain exactly), and rss_bytes up only ~3 MB, because that box renders on a discrete GPU where the textures sit in VRAM and never enter the working set. That is exactly why this item needs the iGPU, where GPU memory is system memory — and why the doubled float footprint is unmeasured rather than known-harmless. (Plan 0033 Risks: “memory is a projection, not a measurement”. Same mitigation as above — the cap is one constant.)

  • Bloom on the low-end box, 1080p. Plan 0045 Phase 4 added a bright-pass, a blur pyramid and a recombine as a third PostStage. It is off by default (bloom_amount = 0 skips the stage entirely — no offscreens, no pyramid, no pipelines), so an ordinary run on most of the library measures none of it. Load star_lantern — it is the shipped preset built for this stage and binds all three params (bloom_amount around 0.95 rising on onset, bloom_threshold = 1.0, bloom_radius around 2.15), so no scratch RLX_PRESET_DIR is needed any more. When active the stage costs 4N passes at TierConfig::bloom_levels (Floor = 4, Rich = 6) plus its own grid-sized bloom-src offscreen and the pyramid — 16.6 + ~11 ≈ 28 MB at the floor cap (NFR §12). Report (a) whether fps holds ≥ 60 @ 1080p with bloom active on top of trails + the fold, and (b) the p99 against the same preset with bloom_amount = 0. If it misses, the lever is TierConfig::FLOOR.bloom_levels — a capacity, not a look, so it is a smaller decision than the other levers on this page, but the halo does visibly shorten. (Plan 0045 Phase 6 measured the Rich side on the dev box’s discrete GPU. Bloom is not what is expensive there: star_lantern runs 164 fps, p99 8.2 ms windowed — comfortably inside a 60 Hz frame — against attractor_clifford’s p99 19.9 ms and attractor_leviathan’s 19.0 ms on the same run, neither of which binds bloom at all. (Both attractor figures predate ADR-0140 and were taken at a flat 150 000 samples; see the Rich calibration item below.) So the cost that puts the heaviest shipped preset past a 60 Hz frame at Rich is the float composite plus the attractor, not this stage. Still owed on this page: the same star_lantern run at native fullscreen, the Floor-pinned sanity pass, and all of the low-end-box side.)

  • The reaction-diffusion present’s reconstruction cost, on the low-end box, 1080p. Plan 0033 replaced the RD present’s field sampling with a Catmull-Rom reconstruction to get the coral look. The present pass now calls sample_v five times per fragment, each at nine bilinear taps — roughly 45 texture fetches per fragment, over the whole screen, every frame. It shipped unmeasured on hardware: the WARP figure first reported was retracted as run-to-run noise (the same suite timed 193.6 / 224.2 / 105.2 s across three runs), and a software rasterizer says nothing about an iGPU’s texture-unit throughput anyway. Load reaction_reef (or any reaction_* preset), let it settle with the overlay on (F3), and report (a) whether fps holds ≥ 60 @ 1080p and (b) the p99. If it fails, that is a user call, not an automatic revert. The reconstruction is one function in the RD present shader and reverting it is cheap, but it costs the coral look outright — so route a failure to architect with the number, and let the look/perf tradeoff be decided rather than assumed. (Plan 0033 shipped this and never measured it; extracted at Plan 0035’s Phase 4.)

  • The swarm’s depth axis, on the low-end box, 1080p. Plan 0043 Phase 3 added per-particle depth math and a fourth vertex attribute inside a loop that runs 10 000 times per frame. Measured on the dev box over 5000 frames at 1920x1080: 1.03–1.09 ms/frame before, 1.56–1.58 ms after — about +0.5 ms. That is not fill rate (pinning the sprite scale flat still measures 1.60), so it is the depth math plus the wider instance, and it will not shrink on a slower box. Phase 3’s done-when named NFR §1/§9’s ≥ 60 fps @ 1080p floor as the acceptance criterion and that floor was never measured — it is defined on this box. Load swarm_dense.toml (the highest visible density of the three survivors, and the one whose field_freq ~5.2 keeps the most particles resolving separately), let it settle with the overlay on (F3), and report (a) whether fps holds ≥ 60 and (b) the p99. If it fails, the lever is TierConfig::FLOOR.swarm_particles (core/src/render/tier.rs — the constant moved there in Plan 0044) — and per Plan 0043’s own risk bullet that is a look decision that routes back to architect, not a constant to quietly lower. (Plan 0043 Phase 3’s done-when, extracted at that plan’s close.)

  • Frame-time p99 with the debug overlay on, any box. Plan 0030 put the three post stages behind a PostStage trait, so a rendered frame now costs ~4 vtable calls plus ~4 TextureView Arc bumps it did not before. Expected to be unmeasurable against a render pass, but it was never measured — the check needs a live window, so it could not run at that plan’s close. Run the standalone with the overlay on, let it settle, and report whether p99 moved. (Plan 0030’s dynamic-dispatch risk bullet, extracted.)

  • The display-write dither, on a second display and on the low-end box, 1080p fullscreen. Plan 0082 made the tonemap add ±1 encoded LSB of triangular noise before the 8-bit write (ADR-0096) — always on, no param, so every frame the engine draws carries it. Two things were settled on one machine and one panel and neither generalizes for free. (a) Does the grain read? The dither is a fixed pattern by design (that is what keeps every byte-equality test working), and a fixed pattern on a long-held still frame can resolve as texture. The 2026-08-12 verdict was “looks fine” on the dev box’s own display; a 6-bit + FRC panel, which runs its own temporal dither over ours, is the case that verdict cannot speak to. Load the reference frame (RLX_PRESET_DIR=core/tests/fixtures/scratch-0082 …, the run line is in that directory’s README), go fullscreen, and hold it. If the grain reads as texture the answer is ADR-0096 Alternative F — an animated dither, one term — and it is an architect call, not a constant to lower. (b) Does it cost anything? The pass gained three pow calls per pixel (one per channel, in srgb_slope) on a fullscreen draw. Expected to be unmeasurable, never measured on weak hardware. Overlay on (F3), report the p99. (Plan 0082 Phase 5 was a human verdict on one display; extracted at that plan’s close.)

  • A live audio input, unplugged and plugged back in — with a removable interface attached. Plan 0130 made the capture stream restartable and gave a dead input a recovery path (ADR-0142): the capture thread stores one flag when AUDCLNT_E_DEVICE_INVALIDATED comes back from a packet call, and the shell reopens the mode’s default endpoint up to INPUT_RECOVERY_ATTEMPTS times before writing a lost … verdict. None of that has ever run against a real device loss — the plan’s Phase 5 ran with no removable interface on the box, so the whole path is pinned only by unit tests over a synthesized flag. With music playing into an interface (the Line (ZOOM AMS-22 Audio) endpoint the plan was designed against, or any USB interface), select it from the S menu’s Input device row and then pull the cable. Report (a) whether the picture recovers to the default endpoint within a few frames and what F3’s audio line then reads; (b) whether re-plugging leaves it unrecovered — it should, and confirming that is the check, because hot-plug is ADR-0142 Alternative D and deliberately unbuilt; and (c) that config.toml’s [input] device still names the interface you chose, since a recovery deliberately does not persist its fallback. (Plan 0130 Phase 5 bullet 3, extracted at that plan’s close.)

    **The open question this answers is not "does the recovery work" but "does it fire at all".**
    The plan's own risk register names the case that would defeat every line of it: a real unplug
    whose packet loop simply returns zero frames forever, which is indistinguishable from silence
    and never sets the flag. If that is what happens, the honest fix is a silence-duration
    heuristic and that is a worse mechanism worth its own ADR — not a quiet addition. Report which
    of the two you saw.
    **Plan 0135 Phase 5 joined this item at that plan's close (2026-08-30), for the same reason:
    no removable interface on the box.** It adds three questions and **changes what is under
    test** — the policy is now the repaired one, so run this against a build at v0.95.0 or later:
    the settle window is `INPUT_RECOVERY_SETTLE_SECS = 0.36` rather than 60 frames, and an
    operator-initiated swap resets the incident instead of inheriting a spent latch. Report
    **(d)** whether `CoCreateInstance` ever returns `REGDB_E_CLASSNOTREG` during a *real* loss, as
    opposed to the menu-speed churn where it was seen once; **(e)** how many of the three attempts
    a real unplug consumes; and **(f)** whether the verdict that lands names the right cause —
    `lost …` for a gone endpoint, not a COM failure wearing the same string. **(d) is the one
    that matters most**: design-backlog 0154 names three candidate fixes and says explicitly that
    choosing between them wants this evidence, so a run answering it is what unblocks that ADR.
    **A run that reproduces nothing is a result worth recording** — one activation in 22 is a
    single sample, not a rate. _(Plan 0135 Phase 5, carried at that plan's close.)_
  • A 96 kHz interface, if one is to hand. Both analysis windows are sized in samples (WINDOW_SIZE, LOW_WINDOW_SIZE in core/src/dsp/mod.rs), so a 96 kHz stream loses roughly a third of the band axis to one-bin resolution. This is the stated trigger of design-backlog 0032“worth taking the day someone runs the standalone on a 96 kHz interface and says the sub-bass reads mushy” — and Plan 0130 is what turned hitting it from a config edit into a keypress. Set the interface to 96 kHz, swap to it from the S menu, and report whether the low end reads mushy against the same music at 48 kHz. A finding here is a backlog update on 0032, not a fix: sizing the windows in seconds re-opens ADR-0049 and is ADR territory by that entry’s own argument. (Plan 0130 Phase 5 bullet 4, extracted at that plan’s close.)

  • The live video-out’s size ceiling (Plan 0115 Phase 6, item 2 — the one item that phase did not answer). ritmolux --stream is proved steady at 1280x720 at 60 fps: 108,000 frames in 1800.00 s wall against 1799.99 s scene, +2.0 MB resident, per-stage 3.67-7.82 ms render+readback against 0.27-0.58 ms Spout send, on the RTX 3080. The largest size and rate that hold was deferred for time and is still unmeasured, which matters because ADR-0125 states its bandwidth figures (8.29 MB/frame, ~498 MB/s) at 1920x1080 and nothing has confirmed that size end to end — the receiving install is TouchDesigner Non-Commercial, which caps the TOP at 1280x1280. So this item needs either a commercial TouchDesigner licence or a different Spout receiver. Run --stream --size WxH --fps N --frames N upward from 1280x720, read the per-stage cost line, and report the largest that holds and which GPU rendered it — the mode prints both resolved adapters at startup, and a frame-rate figure that does not name its adapter is worthless on a two-adapter box (ADR-0071, ADR-0146). Trap: a Spout receiver that loses its sender keeps presenting the last texture it received, so a still-looking picture is not evidence of a live one. Judge from motion in the frames, not from the fact that something is on screen. (Plan 0115 Phase 6 item 2, extracted at that plan’s close.)

  • The operator console on two displays (Plan 0131 Phase 6). C opens a second window on another display carrying the modals, the transport strip and a live preview of the output. Two things here are structurally invisible to CI and nothing else will answer them. (a) What the second swapchain costs the show. Record the output’s frame time console-closed and console-open, on two displays of different refresh rates, with the console on the slower one. Report it as a measurement naming the machine, both refresh rates, the GPU and which present mode the console negotiated — it is written to diagnostics.log on open as a #-prefixed note (ADR-0071). Same-refresh displays cannot answer this: that is exactly the configuration where the two pacing sources agree. “It costs the output frames” is a valid outcome and routes back to architect rather than being tuned away. (b) The dual-GPU path. On a hybrid laptop, say whether the console surface configured on the renderer’s adapter or fell to the no-preview path — the degrade exists, is logged, and has never been exercised; nothing on a single-GPU box can reach it. If no such machine is available, say so: an untested path honestly named beats a guess. Also report a legibility judgement at desk distance — the rows, the transport labels and the preview at the size the console actually opens. (Plan 0131 Phase 6, extracted at that plan’s close.)

    > **PART-RUN 2026-08-30 on one display; the rest is DEFERRED to ~2026-09-06, when a second
    > monitor is available.** What ran: two 95 s release runs differing only by `--console`.
    > **The console cost the output about half its frame rate — 61.7 fps against 33.1 fps,
    > `frame_ms_p99_steady` 18.6 ms against 47.3 ms**, with the console's present mode confirmed
    > as `Mailbox`. That is a finding for `architect`, not something to tune here. It was measured
    > **on the integrated GPU** (see below) and with **both surfaces on one display**, which is
    > exactly the configuration this entry says cannot separate the two pacing sources — so the
    > cross-refresh run is still owed and now matters more. Resident set: flat closed, +1.2 MB
    > across 90 s open.
    >
    > **Still owed, all of it needing the second monitor:** the two-display cross-refresh
    > measurement with the console on the slower panel; the cadence verdict that rides on it; and
    > the **dual-GPU degrade path**, which this hybrid box still cannot reach because one display
    > puts both windows on one adapter. Also owed and needing nobody: a legibility judgement at
    > desk distance.
    >
    > **A second finding came out of it and is not about the console at all.** The windowed app
    > renders on `AMD Radeon(TM) Graphics (Dx12, IntegratedGpu)` on this machine, which also has
    > an RTX 3080 — `request_adapter` with a default power preference hands a hybrid laptop the
    > power-saving GPU. Every windowed frame-time figure quoted on this machine before
    > 2026-08-30 is therefore an iGPU figure. The startup note that says which adapter is running
    > is what makes any of these numbers attributable.
    >
    > **`--gpu` now reaches the window** (ADR-0155), and `ritmolux --gpu 1` has been observed putting
    > this box's window on `NVIDIA GeForce RTX 3080 Laptop GPU (Dx12, DiscreteGpu)` with the
    > startup line reading `(pinned by --gpu)`. What that unblocks and nobody has yet done: **re-take
    > the windowed frame-time figures on the discrete adapter and compare them against the iGPU
    > ones already recorded.** Unflagged behaviour is unchanged by design, so the existing numbers
    > remain valid for the default and the comparison is a new row rather than a correction.

Built from a8ce055 at version 0.115.0. This site tracks main and is not versioned per release.