open-standards/wai/extensions/linear-film.md
Transaction Science 161d147767
Some checks failed
wai-quantum WebGPU member / member · discrete GPU, Vulkan (jetson-hub) (pull_request) Successful in 9m59s
spec citations resolve / Code cites no section its SPEC lacks (pull_request) Successful in 4s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m12s
standards workspaces build + test / eoc-rs (pull_request) Successful in 2m15s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m48s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m10s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m13s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m35s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m14s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m35s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no comparison (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no company or product (pull_request) Has been cancelled
no-vanity-metrics / No new orphan source files (pull_request) Has been cancelled
standards workspaces build + test / jouleclaw-rs (pull_request) Has been cancelled
standards workspaces build + test / aac-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-code-rs (pull_request) Has been cancelled
standards workspaces build + test / joulecontract-rs (pull_request) Has been cancelled
standards workspaces build + test / jouledesk-rs (pull_request) Has been cancelled
standards workspaces build + test / map-rs (pull_request) Has been cancelled
standards workspaces build + test / mesh-rs (pull_request) Has been cancelled
standards workspaces build + test / openpay (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
tests in CI / every test file is run by a job or listed with its reason (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
WAI HTTP delivery / WAI HTTP · does this change touch it (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Has been cancelled
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Has been cancelled
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Has been cancelled
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Has been cancelled
wai-pack / wai-pack · does this change touch it (pull_request) Has been cancelled
wai-pack / wai-pack · linux (pull_request) Has been cancelled
wai-pack / wai-pack · linux-arm64 (pull_request) Has been cancelled
wai-pack / wai-pack · macos (pull_request) Has been cancelled
wai-pack / wai-pack · independent verifier (Python) (pull_request) Has been cancelled
wai-pack / wai-pack · the floor through a media prober (pull_request) Has been cancelled
wai-pack / wai-pack · dependency licences (pull_request) Has been cancelled
wai-quantum WebGPU member / shader checks · browser build · wasip2 inertness · MSRV (pull_request) Has been cancelled
wai-quantum WebGPU member / member · software Vulkan (linux) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · Metal (macos) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · browser WebGPU (macos) (pull_request) Has been cancelled
WAI section references / cited sections exist (pull_request) Has been cancelled
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Has been cancelled
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Has been cancelled
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Has been cancelled
workflow hygiene / every workflow supersedes its own queue (pull_request) Has been cancelled
lockfiles / every Cargo.lock is current (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (pull_request) Has been cancelled
standards workspaces build + test / smart-byte-rs (pull_request) Has been cancelled
wai: reader limits for the extension formats' durations
A score, haptic signal, audio scene, splat4d clip or film declares its length in its
contract, and rendering allocates in proportion: a score's mixdown allocated `duration`
samples outright, a haptic channel `duration` × 2 bytes, a scene's stereo mix 20 bytes a
sample, and the splat4d and film receipts a hash a frame. Nothing bounded the
declaration, so a few bytes could ask a renderer for more memory than any machine has.
SECURITY.md recorded it as a gap when the fuzzing PR found the reader-side reservations.

Each extension's contract section (score, haptics, spatial-audio, volumetric,
linear-film and its reel) now has a reader limit shared with SPEC §2, through a new
always-on module `wai::limits`:
- score and haptics: `duration × channels` at most 2^27 samples;
- audio scene: `duration` at most 2^26, so the stereo floor is at most 2^27 samples;
- splat4d `n_frames`, film `frames`, a reel's shots together: at most 2^20 frames.
A reader may refuse past them (`duration_too_long`) when it reads the contract, before
anything is rendered; a conforming encoder writes none.

The film schedule's tick, `start_tick + f × ticks_per_frame`, wrapped in release builds
and panicked in debug ones. A reader must now refuse a schedule whose last tick passes
2^64 - 1 (a film's, and each shot's of a reel); `Film::frame_tick` saturates and
`Reel::frame_tick` uses checked arithmetic.

tests/extension_duration_limits.rs rewrites a committed vector of each format to declare
exactly its limit (it reads) and one past it (refused by name), and checks the film
schedule ending at 2^64 - 1 (reads) and past it (refused). Falsified: with the readers
as they were, all three tests fail. The world, audio, haptic, splat4d, score and film
corpora verify unchanged; the 275 lib tests with the container features pass. CI runs
the test beside container_reservations on every leg.

SECURITY.md drops the gap and keeps the one this exposes: replaying a world to a far
tick costs time in proportion (memory is bounded, time is not).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 11:07:16 -04:00

196 lines
9.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WAI Extension: Linear Film
> Status: Draft. "A film is a sealed, camera-on-rails world." Ship a
> feature not as pixels but as the **world** that generates it (a sealed
> `wai.world.replay`) plus a **camera track** and a **frame schedule**;
> the sink renders the frames itself, at its own resolution, frame rate,
> and quality. Conformance is **film-equivalence**. Reference impl: the
> `film` feature of `wai-rs`; corpus: `film-conformance/`.
Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
## 1. Scope and model
A `wai.film.linear` object is a **linear (non-interactive) film** composed
of three parts:
1. an embedded **sealed `wai.world.replay`** — the world that produces the
imagery, carried verbatim (kilobytes of signed CausalOps + a seal);
2. a **camera track** — a keyframed camera pose (position, orientation,
field of view) over the world's tick timeline; and
3. a **frame schedule** — which world tick each frame samples.
The sink renders the frames. The wire carries the *instructions* that
generate the film (the world + the camera), not the rendered result —
lever 3 (instructions-at-the-sink) applied to the largest
captured-as-pixels category there is. A two-hour feature generated from a
world is the world's op log plus a camera spline, together with the assets the
world references (meshes, splats, textures, audio), which travel as their own
content-addressed capabilities and can be large; the pixels are reconstituted at
the sink's native resolution and frame rate. A film captured from a camera has no
world to replay and is not this capability.
In scope: the container, the camera-track model, the frame schedule, the
deterministic **film-equivalence** conformance criterion, and the receipt
profile.
Out of scope: a transport; the **render** — projection, rasterization,
shading, lighting, the actual pixels — which is the sink's, exactly as the
worlds renderer and the audio-scene HRTF are; encoding a *captured* film
(live-action photography is irreducible samples — that is `wai.video.*`,
not this). This extension carries and verifies a film that is *generated*
from a world, it does not fit a world to existing footage.
Relationship to the core spec: it **composes** the interactive-worlds
extension. The embedded world's **replay-equivalence** (every sink agrees
on the state hash at every tick) is reused unchanged; the camera track
runs in the same `wai.det.fixed64` floor as every other cargo class.
`media` takes the informational value `"video"`; `wai.film.linear` is
authoritative.
## 2. Container (`WFLM`)
```
"WFLM" | u16 n_sections | section table (u8 kind, u32 off, u32 len) | sections
```
| kind | section | required |
|---|---|---|
| `0x01` | contract (canonical JSON) | REQUIRED |
| `0x02` | embedded sealed world (a `WWLD` container, verbatim) | REQUIRED |
| `0x03` | camera track | REQUIRED |
### 2.1 Contract
```json
{ "frames": 9, "numeric": "wai.det.fixed64",
"start_tick": 0, "ticks_per_frame": 5 }
```
`frames` ≥ 1 and `ticks_per_frame` ≥ 1. Frame `f` samples the world at
tick `start_tick + f * ticks_per_frame`. The map is exact and
resolution-free: a sink that wants smoother motion renders *between* these
sampled states, but the verified quantity is the schedule above. `fps` is
**not** in the contract — it is playback speed (presentation), not part of
the film's identity.
**Reader limit.** A reader MUST NOT refuse a film for its length while `frames` is at
most 1 048 576 (2²⁰, the video limit of SPEC §2), and MAY refuse one past it
(`duration_too_long`), when it reads the contract, before it renders anything. It MUST
refuse a contract whose last tick, `start_tick + (frames − 1) × ticks_per_frame`, is
past 2⁶⁴ − 1: that schedule names no tick. A conforming encoder writes neither.
### 2.2 Embedded world
The exact bytes of a sealed `wai.world.replay` (`WWLD`) container. The film
is content-addressed over these bytes; the world's own seal and
replay-equivalence are inherited unchanged.
### 2.3 Camera track
`n_keys u32`, then per key `tick u64 | pos[3] | rot[4] | fov`, the 8
attributes as `i64` Fx in that field order (72 bytes/key). Keys MUST be
strictly ascending by `tick`; the track MUST carry at least one key. `rot`
is a quaternion `(x, y, z, w)`.
## 3. Reconstruct contract
For each frame `f` at tick `t = start_tick + f * ticks_per_frame`:
1. **World state** — the embedded world's state hash at tick `t`, the same
replay-equivalent hash a full replay computes at `t` (the sink samples
the timeline at frame ticks; `t` MUST be ≤ the world's sealed final
tick).
2. **Camera pose** — each of the 8 camera attributes is the `Fx` linear
interpolation of the track's keys at `t`; before the first / after the
last key the endpoint holds. The floor stays trig-free — the quaternion
interpolates component-wise (the sink renormalizes for rendering, which
is presentation, exactly as in the splat/skeletal tracks).
## 4. Conformance — film-equivalence
> Given the same `wai.film.linear`, a conforming sink MUST compute the
> identical per-frame identity for every frame, hence the identical
> BLAKE3 — on every machine, no tolerance parameter.
```
frame_hash = BLAKE3("wai:film-frame\x01" || frame_le
|| world_state_hash(frame_tick) || camera_pose)
film_hash = BLAKE3("wai:film\x01" || contract_bytes || world_bytes || camera)
```
`camera_pose` is the canonical `pos[3] | rot[4] | fov` (raw `Fx` bits,
little-endian). `frame_hash` is the per-frame reconstruction block;
`film_hash` is the frame-independent identity binding the exact inputs. A
sink MUST first validate the embedded world as a conformant sealed replay
(its seal verifies and the log re-derives the sealed final hash).
## 5. Fidelity and size (honest)
`wai.film.linear` is tiered **Lossless**: film-equivalence reproduces the
per-frame `(world state, camera pose)` identity exactly, the simulation
analog of lossless, like the world it is built on. The **size** win is
real and large — a generated film travels as its world + camera (kilobytes
in the conformance corpus) instead of an encoded pixel stream — but it
applies **only to films that are generated from a world** (animation, CGI,
motion graphics, a sealed simulation). It makes **no** claim about
live-action capture, which is irreducible samples and belongs to
`wai.video.*`. The honest scope: this is the medium-shift lever for the
synthesizable slice of "video," not a video codec.
## 6. Receipt (JWP profile)
`film_hash` is the identity; the group's objects are the per-frame
reconstruction blocks (`frame_hash` per frame), Merkle-bound; one Ed25519
signature (verified as SPEC §7 *Signatures* requires) over film_hash + root + `work` (= frames) + carried
`joules_micro` (the native `wai_meter` supplies a **measured** value);
`parent_receipt_hash` chains — the worlds / volumetric receipt shape
reused. The figure's acquisition class rides beside it as an optional signed label
([energy-measurement](energy-measurement.md) §2.8): absent, the receipt keeps
its legacy bytes and the figure is unlabelled; present, it is inside the
signature. The reference meter labels every figure it measures
`OnChipCounter`, with its declared uncertainty. A reel's receipt is the same profile.
## 7. Reel — a film with cuts (`wai.film.reel`)
A [`wai.film.linear`](#) is a single continuous camera move. A **reel** is the
editor's layer over it: one embedded sealed world, and a sequence of **shots**
played back to back — each shot its own camera track + frame schedule. Cutting
from a wide to a close-up, or showing one beat from two angles, is the essence
of film grammar; a reel carries it as a few extra kilobytes of camera keys,
the world (the cargo) shared across every shot.
Container `WREL`: `0x01` contract (canonical JSON, `{ "numeric", "shots" }`),
`0x02` embedded sealed world (`WWLD`), `0x03` shots — `n_shots u32`, then per
shot `frames u64 | start_tick u64 | ticks_per_frame u64 | camera track`. Each
shot's keys MUST be strictly ascending by tick; a shot's local frame `j`
samples world tick `start_tick + j * ticks_per_frame`. The frame limit of §2.1 holds
for the sum of the shots' frames, and each shot's last tick is held as a film's is.
Conformance is **reel-equivalence**, film-equivalence extended over cuts: the
global frame `f` belongs to a shot, samples the world at that shot's tick, is
framed by that shot's camera, and its identity is
```
frame_hash = BLAKE3("wai:reel-frame\x01" || frame_le
|| world_state_hash(tick) || camera_pose)
reel_hash = BLAKE3("wai:reel\x01" || contract || world_bytes || shots)
```
Shots MAY revisit earlier world ticks (a cut back to a moment from a new
angle), so the world is sampled at the **sorted, de-duplicated** union of every
shot's frame ticks — the convergence guarantee still holds, because the world's
replay-equivalence is order-independent. The receipt is the same JWP profile
(per-frame Merkle leaves, identity = `reel_hash`); the meter reports measured
joules for the whole reel.
## Appendix
Film-equivalence is the composition the taxonomy promised: a film is a
sealed world (replay-equivalence, already a corpus) read through a camera
track (the `wai.det.fixed64` floor, the same one behind every cargo
class). The world engine gained one general primitive for it — a sampler
that reads the state hash at an arbitrary frame cadence, independent of the
world's internal checkpoint cadence — and the film is a thin, exact layer
on top. One floor, one more cargo class; the representation is the cheapest
possible (the generating world), and the *reconstruction* of every frame is
exact and auditable — the honest thing the standard adds to "video."