Composition showcase — every hard 2D/3D overlap, on one page

Fourteen numbered cases covering every way flat 2D and woven 3D can land on top of each other in an ordinary web page: translucent chrome, frosted glass, opaque plates, modals, nested scrollers, sticky tiles, tile-on-tile, and a mixed producer load. Two jobs in one page — a demo of what draw-order occlusion buys an author, and a standing hardware regression surface.

The second job constrains the first: nothing here is tuned to look good. Cases that glitch today are built anyway and marked red on-page. A case softened until it passes is not a regression test. Zero exclusion-era API is used — no exclude(), no addGlobalOverlay(), no data-inline3d-overlay: every 2D element below is an ordinary DOM sibling painted after the canvas, and the page opens exactly one createInline3D() session with autoChrome:false.

Reading order: straight through, 01–15. The full-tile frost pair (02, 03) spent a while in a red-bannered tail at the end, because browser#120 made them open the page with a screenful of frosted black; that shipped in 0.1.16, so they are back in place with their frost armed on load. Cases that were broken keep a short note saying what the failure looked like — that is the shape a regression would take, and it is the reason to keep judging them rather than to skip them.

Version floor: judged against 0.1.19 or newer. Cases 02, 03, 07 and 12 all assert behaviour that landed between 0.1.15 and 0.1.16, and 15 asserts a fix newer still — on an older browser they fail for a reason that is not a regression.

Detecting DisplayXR Browser…
01

Translucent bar over a woven tile

must pass

expected: the bar reads as crisp translucent 2D and the woven 3D shows through it at its designed opacity. No raw side-by-side anywhere, and no weave bleeding into the bar's text. This is the shipped page-header case, shrunk onto one tile.

translucent bar · rgba(16,17,22,.72) · 3D shows through
02

Frosted glass fully covering a tile strip

must pass

expected, armed (as shipped): the frost reads crisp, with flat (mono, un-woven) tile content behind it — the D′ contract, where a backdrop filter is a function of what is behind it. Flat means the tile’s own content in 2D, not empty: what the glass blurs is a mono draw of the tile, made at the canvas quad’s own place in the page raster. The control tile above the strip stays 3D.

expected, disarmed: the panel is plain translucent 2D and all three tiles under it weave normally, exactly like case 01.

Was broken, now fixed — which is exactly why it is still here. Until the mono-under-frost draw landed (browser#120, shipped 0.1.16) this strip went to a blurred veil over black: inside a frost rect the frame held neither the tile’s canvas (suppressed once the tile joins) nor the woven draw-back (D′ clips the weave out of every frost rect), so the blur had nothing to sample. A return of that black veil is the regression this case catches — hence the frost is now armed on load rather than opt-in.

panel disarmed · plain translucent 2D
three tiles weaving underneath
backdrop-filter: blur(14px)
fully covering three tiles

toggles backdrop-filter on the panel live · scripted: __showcase.frost('02', true)

03

Frost straddling a tile edge

must pass

expected, armed (as shipped): a clean boundary down the panel’s left border — frosted-flat inside, woven 3D outside, on the same tile, with no shimmer or seam-crawl while scrolling. Inside the frost the tile reads as its own content in mono, not as a dark patch: that is the same mono-under-frost draw case 02 checks, here judged against a live 3D half of the very same tile, which is the strictest place to see it.

expected, disarmed: a translucent panel overhanging the tile’s right half; the whole tile weaves, and the panel’s left border is just a 2D edge.

panel disarmed →
translucent 2D, tile woven throughout
frost boundary →
flat inside, woven outside

toggles backdrop-filter on the panel live · scripted: __showcase.frost('03', true)

04

Opaque plate over a tile — persistent and on hover

must pass

expected: both plates render as fully opaque 2D over live 3D. The hover plate appears and disappears with no flash of raw side-by-side and leaves no hole behind it when it goes.

persistent plate
opaque 2D
hover plate

Hover the tile to raise the second plate.

05

Page-DOM modal and scrim over a tile

must pass

expected: the scrim dims the tile as translucent 2D while the tile keeps weaving under it; the card is crisp. Dismissing restores the tile immediately — no stale dark rectangle. This is a page-DOM occluder, not a browser popup.

 scripted: __showcase.modal(true)

06

Programmatic plate thrash (~10 Hz)

must pass

expected: start the thrash, then scroll this section through the viewport. Every plate appears and vanishes cleanly — no stuck hole, no tile dropping to raw side-by-side, no plate woven into the tile content.

THRASH

 ~10 Hz display toggle · scripted: __showcase.thrash(true)

07

Partial visibility at every viewport edge

must pass

expected: walk the tile through 10 / 30 / 50 / 70 / 90 % visibility at the top and bottom edges (vertical leg), then at the left and right edges (horizontal leg). At every mark the visible part must weave correctly — no raw side-by-side, no stretch, no eye swap. A tile whose id-join works should weave at any nonzero visibility.

This is browser#117’s acceptance surface, and since that landed (0.1.15) the bar is two-sided: at every mark the visible part either weaves correctly or does not weave at all — a tile whose canvas the compositor could not join is now withheld from the weave and drawn by the page like any 2D element. What must never appear is a third outcome: raw side-by-side, or page chrome coming back interlaced. Before 0.1.15 anything under roughly 70 % showed raw side-by-side. The page’s sticky header is frosted so the top-edge leg runs under a bar that reaches the compositor through its own render pass — judge this case with header: frosted on, and flip it to solid only to attribute a failure. The ruler ticks sit in the gutters, never on the tile: a hairline painted over the tile would add a 2D-over-3D composition on top of the thing being measured.

snap top edge bottom edge
SCROLL ↓
▲ top edge
▼ bottom edge
SCROLL ↓

Horizontal leg. Parking a tile off the left or right viewport edge needs horizontal scroll, so this leg is a full-bleed overflow-x:auto strip whose own edges are the viewport edges. It therefore also carries a little of case 08's nested-scroll flavour — attribute a failure here accordingly.

snap left edge right edge
08

Tile inside a nested overflow:auto panel

must pass

expected: the weave rect tracks the inner scroll, not the page. The tile clips exactly at the panel's edges, never paints outside them, and never ghosts at a stale position after the inner scroll stops.

↓ scroll INSIDE this panel ↓
↑ independent of the page scroll ↑
09

Sticky tile, content scrolling behind and over it

must pass

expected: the pinned tile weaves at its pinned position the whole way. Cards at z-index:1 pass behind it (hidden); cards at z-index:20 pass over it as crisp 2D. Draw order decides — not who is 3D.

z-index: 1 — this card passes BEHIND the pinned tile and must disappear under it.
z-index: 20 — this card passes OVER the pinned tile and must stay crisp 2D.
z-index: 1 — behind again. No half-states, no card fragment surviving on top.
z-index: 20 — over again. Text must never pick up the lens interleave.
10

Browser zoom sweep, 67 % → 150 %

manual gesture

expected: press Ctrl + +/ by hand across the range. The weave rect stays registered with the CSS box, stereo stays square (no squeeze), and the bar and badge stay on their pixels at every step.

Browser zoom is a user gesture — nothing here can drive it, so this section is an ordinary composed fixture (tile + translucent bar + frosted badge) that you zoom manually.

zoom me · the bar must stay on these pixels
frost
11

Edge-adjacent tile pair, no gap

must pass

expected: both tiles weave, the shared border is a clean line, and neither tile bleeds a column of the other's eye across it. Heights are matched exactly and both boxes are square, so neither is squeezed. Corner radius is 0 on this whole page precisely so this seam can be judged.

12

Partially overlapping tile pair

must pass

expected: topmost wins, and both tiles stay 3D. Where the upper tile covers the lower one the upper tile’s content is what weaves; everywhere the lower tile is still visible it keeps weaving its own — including the parts beside and below the overlap, not just a full-width band. No eye swap on either tile, no garble in the overlap, and the non-overlapping regions of both must be correct 3D.

Tile-over-tile is defined now: the compositor subtracts the upper tile’s rect from the lower one by paint order (browser#131, shipped 0.1.16) and then re-packs what the lower tile still owns piece by piece (#143), which is what keeps a corner occluder from flattening the whole tile. This case was the forcing function for that definition and now guards it.

13

The sandwich: 3D → 2D → 3D

must pass

expected: strict draw order through three layers — tile A woven at the bottom, the 2D card crisp over it, tile B woven over the card. No layer swallows the one above it.

z-index: 2 — a plain 2D card. It must be crisp over tile A, and tile B must be woven over it.
14

Mixed producers under load

must pass

expected: a live three.js scene, a side-by-side video and two still photos weave simultaneously in one viewport — all 3D, none falling back to mono or raw side-by-side, video playback smooth. This is the producer-weight mix that has historically pushed a session into its degraded path.

addScene() — a live three.js turntable, rendered twice per frame into the two eye viewports.

addImage() — a still side-by-side photo.

addImage() — a second still, so the mix is not two producers.

addVideo() — a VP9/WebM side-by-side clip (640×360 per eye).

15

Opaque sticky bar with a tile scrolled under it

must pass

expected: press park under the bar. The tile scrolls up until nothing of it clears the bar, and at that moment the bar must stay crisp, ordinary 2D — especially its small text. Scroll back and the tile resumes weaving immediately. What must never happen is the bar’s own glyphs coming back interlaced.

Not a bigger case 04, and deliberately not a plate. A static opaque plate over a tile does not reproduce this — measured on hardware, the canvas layer keeps drawing. It takes a bar that is both sticky and truly opaque, with the tile scrolled until nothing of it is left showing: only then does the compositor drop the fully occluded canvas layer from the drawn layer list, so it emits no quad at all, nothing resolves, and — on a page where no other tile resolved either — the weave fell through to snapshotting the page and weaving the bar’s own pixels (browser#167, reported as the words in a shop’s sticky header interlacing as a product stage scrolled up under it). Alpha exactly 1 is the trigger: this page’s own header: solid is rgba(16,17,22,.94) and does not occlude, which is why nothing here reached the state before. And the scroll is the PAGE’s, not a nested panel’s — a tile in an overflow:auto container loses its join to #164 (see case 08) long before it is covered, which would fail this case for an unrelated reason.

switches the page header to opaque (alpha 1 — the trigger) and scrolls until the tile is entirely behind it · scripted: __showcase.park15()