Skip to content

A lit backdrop is a distinct test configuration, not a variant

bg_bright > 0 is its own coverage axis, and until Plan 0051 nothing in the suite tested it deliberately. Nearly every golden baseline and scene fixture runs bg_bright = 0 — the right call for a baseline, since on black every lit pixel provably came from the scene rather than from the backdrop. It is also a structural blind spot: on a black backdrop, correctly compositing over the backdrop and wrongly covering it are the same picture. A stage or a scene that mishandles alpha costs nothing there and punches a hole in the frame the moment a preset turns bg_bright up — which is exactly what the shipped library does.

That blind spot has now produced four defects, all after ADR-0055 moved the backdrop out of the post chain and made every stage’s alpha load-bearing: the fold fading to black (Plan 0045 Phase 2b), the bloom recombine driving alpha past 1 and subtracting the backdrop (Phase 4b), and both draw seams emitting a constant alpha 1 over their whole quad (Plan 0051 / ADR-0056). Each was fixed with a guard of the same shape, and the guards are per-seam rather than global because nothing structurally forces a shader’s colour and alpha to stay in step.

Two golden baselines are lit, and they are the exception that proves the rule — both EXTRA_FIXTURES entries rather than rostered ones, so the per-system roster is still uniformly dark and the sentence above still describes what a drift baseline is for. Each exists because the backdrop pass is lazy: it does not build its gradient pipeline at all below a visible backdrop, so no dark baseline anywhere in the suite executes a line of it.

  • core/tests/fixtures/backdrop_ramp.toml (Plan 0080, ADR-0094) runs bg_bright = 0.6 — the directional ramp.
  • core/tests/fixtures/backdrop_band.toml (Plan 0081, ADR-0095) runs bg_bright = 0.5 and all seven band params off their defaults — the curved band, over a lit ramp so the baseline pins the two added rather than the band alone. It is not redundant with the one above: the band is an untaken select branch at bg_band_amount = 0, so backdrop_ramp — the suite’s only other lit baseline — executes none of it, and bg_band_curve off 0 is the only thing in the crate’s baselines that reads the along-band axis at all.

Both were adapter-compared before blessing (WARP against hardware, means recorded in each fixture’s header), because each plan grew this pass’s uniform and therefore moved its min_binding_size — a Plan 0053 fix against a measured WARP mis-render, so a divergence there is a finding rather than something to bless.

The fixtures below exist purely for this axis, and they are additive test surface rather than re-parameterized existing files, for the reason above:

  • core/tests/fixtures/swarm_lit_backdrop.toml — a sparse frozen swarm over a lit, un-vignetted backdrop. It guards the sprite pipeline, whose radial falloff over a square quad left four hard-edged black corners (~21 % of every sprite).
  • core/tests/fixtures/emitter_lit_backdrop.toml — a sparse emitter shower over the same lit backdrop, guarding the third draw seam (Plan 0052). It is the one fixture of the three that cannot be frozen: an emitter whose objects do not move has no picture at all, because its source line sits below the frame. That costs nothing — the three captures vary only bg_bright and size, and neither touches spawning or the path, so the object positions are identical across all three. Demonstrated in both directions: reverting its fragment shader to a constant alpha gives worst |L - B| 0.3345 with 13 330 of 136 617 compared channels violating, against 0.0002 and zero violations as shipped.
  • core/tests/fixtures/lines_lit_backdrop.toml — a sparse frozen rose at thickness = 9, guarding the shared line renderer and therefore all four line scenes at once. The fat stroke is load-bearing: the line falloff is one-dimensional, so its dark region is a rim whose width scales with thickness, and at shipped widths (2–3) that rim is close to a hairline a capture cannot discriminate. Narrowing it leaves the test green and blind. Its softness = "1.0" is pinned for the same reason and is deliberately not the shipped default (Plan 0114): since ADR-0124 the profile is authorable and the library default is 0.25, where a plateau reaches coverage 1 over a region — which is exactly what the fourth capture below reads as the defect. Normalising that line to the default retires the wide arm while leaving it green. The test asserts the pin.

All three bind a post stage (trails), and that is not decoration either: with an empty chain the scene draws straight onto the backdrop and its additive colour cannot remove light, so the defect is unrepresentable and the guard would prove nothing. All three tests read those preconditions back out of the fixture before they touch the GPU, and report the pixel counts either side of the property.

They live in core/src/render/, not in core/tests/, for the same reason the bloom guard does: capture::read_back_linear is pub(crate), and the assertion has to be made upstream of the tonemap where it is exact (see the previous section’s second bullet for why a display-byte version cannot be written). Follow that precedent for a fourth draw seam, if one is ever added.

The fourth capture, at zero emitted light — do not “simplify” it away

The swarm and line guards take a fourth capture (Plan 0053 Phase 4), and it is not a variant of the other three. It renders the same scene over the same backdrop with the stroke or sprite emitting no lightglow = 0 for the lines, brightness = 0 for the swarm — so src.rgb is zero everywhere and the composite reduces to exactly bg * (1 - a). The frame becomes a direct readout of alpha, which is the quantity these guards are actually about and the one the lit capture can only reach indirectly.

It exists because the line guard’s exact arm was nearly vacuous (design-backlog 0041). The line falloff is one-dimensional and — at the softness = 1.0 this fixture pins — quadratic. Since Plan 0114 that is a property of the fixture rather than of the renderer: the shipped default is 0.25, a solid core with a one-pixel edge, and every number in this section was measured at 1.0 and stays valid because the fixture holds it there. So the region where the falloff is identically zero is the outermost sub-pixel sliver of the quad: reverting the shader moved that arm on 15 channels, about five pixels, and no choice of samples / scale / thickness widens it. The fourth capture changes the property instead of the fixture. A pixel is fully extinguished exactly where a = 1, which pre-fix is the whole quad footprint and post-fix is the centreline:

guardfixed shaderpre-fix shaderthe exact arm, pre-fix
lines, glow = 0779 of 28 173 (2.77 %)28 178 (100.02 %)15 channels
swarm, brightness = 01 of 12 880 (0.01 %)16 052 (124.63 %)9 594 channels

Both arms stay, and neither replaces the other: the exact one says the backdrop arrives intact where nothing was drawn, the wide one says alpha is coverage. Both were confirmed in the reverted direction, and the wide arm’s count is measured before either assertion so a failing run prints both rather than short-circuiting on the first — the comparison between the two regions is the evidence, and hiding it would retire the improvement while keeping the code.

A ratio above 100 % is expected rather than a bug: the footprint is counted from where the scene put colour, and the regions that draw no colour but still cover a pixel — a sprite quad’s corners, an anti-aliased stroke edge — belong to the quad without registering as drawn. On the swarm that over-count is the defect’s signature.

One existing baseline was positioned to see this and did not. composite_kaleido.toml is a line scene over a lit vignette — the exception to the bg_bright = 0 rule above — and it moved when Plan 0051 landed, at mean 0.0009 against a 0.02 tolerance, with only the outlier gate firing. A mean-drift gate cannot see a hairline. That is the argument for asserting the property directly rather than trusting a baseline to notice.

RLX_BLESS=1 is not scoped to the scene you changed — it rewrites every baseline the run touches. git status after blessing and git checkout the baselines your change had no business moving; committing an incidental re-bless silently retires the drift guard for that scene. (Learned the hard way in Plan 0027, where an over-broad bless moved fragment_field and swarm.)

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