A base first, refinements after.
Every stage rebuilt in this tab, and checked.
A clip arrives as separate objects. Each group of four frames has a coarse base; each
frame then has a layer 1, and each group a layer 2. Every layer is its own
WAI1 envelope that names, by content hash, the base it refines and the
producer of the stage it expects each frame to be at. A sink applies a layer only to a frame
that is exactly there, holds it for a frame that is not there yet, and refuses it with a reason
from a closed list otherwise.
This page runs the reference implementation's sink, compiled to WebAssembly. It fetches each object as binary bytes, offers it to the sink, and checks every stage the sink reaches against the stage hash the native reference wrote for the same frame and producer.
Shown at 8 frames per second, enlarged three times without smoothing; the source runs at 25.
Each frame's stage
The number in each corner is the frame's stage: 0 for its base, 1 and 2 for its layers. A ✓ means the stage hash equals the native reference's; frozen marks a frame a conflict stopped. Select a frame to show it in the player.
Quality and bytes per stage
| Stage | Objects delivered | Bytes | Bytes so far | Frames seen at this stage | PSNR over those frames | Rebuild time in this tab |
|---|---|---|---|---|---|---|
| 0 · bases | — | — | — | — | — | — |
| 1 · layer 1 | — | — | — | — | — | — |
| 2 · layer 2 | — | — | — | — | — | — |
| The clip now | — | — | — | — | — |
PSNR = 10·log10(255²·N / SSE), where SSE is the exact integer sum of squared differences between the rebuilt frames and the source frames over all N samples of the frames counted (128 × 128 × 3 per frame), summed by the WebAssembly sink itself. A frame is counted at a stage when the page sees it there; a layer the sink applies as its base arrives is never seen at the stages below it. Rebuild time is the wall-clock time of the sink's calls for that stage's objects. Bytes are the objects as delivered.
The objects
Each object is a binary WAI1 envelope: 12 bytes of framing, the manifest and the payload.
The split, a layer's residual step q, and the declared cost (the output bytes, symbols and
working bytes a decode will need) are read from the envelope when it arrives. The sink compares a
layer's declared cost with its limit, and the page a base's, before anything is decoded or
allocated. Nothing on the wire is JSON or base64.
| Object | Layer | Bytes | Framing · manifest · payload | q | Declared cost: output B · symbols · working B | Identity (content hash, SHA-256) | Outcome | Deliver |
|---|
What the sink reported
What a layer names
Each layer carries refines: the base it refines, its layer
number, the span of frames it covers, and prev, the producer it expects
each of those frames to have. A frame's producer is the content hash of the envelope that made its
current stage: its base at stage 0. A layer 1 here covers one frame and names its base; a layer 2
covers four frames and names, as runs, the four layer-1 objects it was coded against.
Held, applied, refused
A layer whose base the sink has not decoded is held for that base. A frame one stage short of a
layer holds it until its own predecessor applies, then takes it; past the hold bound it is
discarded for that frame (layer-gap), and the frame keeps what it had. Two different
layers for the same frame, layer and producer conflict: the sink refuses the second
(layer-conflict) and freezes the frame at its stage, so no later layer moves it.
Why every stage has one hash
The base is wai.video.int_motion, an integer decode, and each layer is a
WIR1 residual: an integer prediction from the stage below, plus the residual times
its step, clamped. Every stage is therefore the same bytes on every conforming sink, its tier is
decode-equivalence, and its SHA-256 can be compared with the native reference's. A tier the
sink cannot state gets no hash.
The reference, and the code
The objects were written, and the reference stage hashes produced, with the wai stage
command-line tool. The sink in this tab is the same Rust, wai::staged::StageSink,
compiled to WebAssembly; a conformance script replays the standard's staged-delivery corpus
through the WebAssembly build. The extension is
staged delivery; the code is Apache-2.0 in the
open-standards repository.
The source and how the objects were made
Frames 1 to 12 of the sequence “Sunflower” (1920 × 1080, 25 frames per second) from the Xiph.org test media collection (derf), whose notes state Restrictions of use: No restrictions and Copyright: No Copyright. A 384 × 384 window is converted from BT.709 YCbCr in integer arithmetic and averaged in 3 × 3 blocks to 128 × 128. The page fetches these source frames as raw RGB bytes to measure PSNR.
The commands
python3 extract_source.py Sunflower_1920x1080_25-1fps_500f.yuv source.rgb
# per group g of four frames (gop.rgb), and per frame f (frame.rgb):
wai stage base --frames gop.rgb --dims 4,128,128 --q 32 -o g/base.wai
wai stage refine --base g/base.wai --span f:1 --target frame.rgb --q 8 -o g/L1_ff.wai
wai stage refine --base g/base.wai --on g/L1_f0.wai … --on g/L1_f3.wai \
--target gop.rgb --q 2 -o g/L2.wai
# the conflicting layer: frame 2 again, at another step
wai stage refine --base g0/base.wai --span 1:1 --target frame.rgb --q 12 -o g0/L1_f1_alt.wai
# the native reference
wai stage apply --json g0/base.wai g1/base.wai g2/base.wai g*/L1_f?.wai g*/L2.wai The full script, make.sh, and the extraction script sit beside the objects, under /models/staged/v1/, with a README and the SHA-256 of every file.
Runs the reference implementation compiled to WebAssembly. In the standard: the staged-delivery extension, its refinement capabilities and the sink. Building: the WebAssembly binding this page loads. Measured in this browser on this content; not a general result.