# 09-collage — REPORT

**拼贴日报 / THE COLLAGE DAILY** · 1920×1080 · 30 fps · 10.000 s · H.264 + AAC
`out/09-collage/video.mp4`

---

## 1. Concept

A Victorian gentleman has been cut out of his own photograph with scissors, pasted
onto a sheet of newsprint, and given one line of editorial copy. His skull is a
hinged lid: when it swings open, the inside of his head turns out to be deep space,
and everything he has been thinking about — flowers, swallows, a ringed planet, a
rocket, an idea — tumbles out onto the page and gets pasted down around him.

**The mind is a collage: you cut things out of the world, and you glue them together
yourself.**

## 2. Beat sheet

The cue sheet is the single source of truth for both picture and sound; the block
below is mirrored verbatim at the top of `parts/film.mjs` and `audio.py`.

| t (s) | picture | sound |
|---|---|---|
| −0.06 | masthead band slaps on, top-left | paper slap |
| 0.00 | torn red banner rips across the foot of the page | paper rip + whoosh |
| 0.40 | portrait cutout falls in from above, squash-and-stretch on landing | heavy slap + thud |
| 0.56 | halftone plate "rolls" down the sheet | roller hiss |
| 0.98 | scissors snip along the left edge of the cutout | snip snip snip |
| 1.16 | issue badge (第 9 号) stamps on, top-right | stamp + slap |
| 1.30 | three strips of tape pressed over the cutout | soft tack |
| 1.44 | editorial column types on: 本期内含 / 花 · 鸟 · 行星 · 火箭 | type ticks |
| 1.72 | the pasted mouth strip starts flapping, 6 fps | lip flops, 6 fps |
| 2.34 | marker arrow + scribble drawn across the spread | marker squeak |
| 2.68 | **ANTICIPATION** — the lid presses shut, the page holds its breath | riser |
| 3.02 | **LID POPS OPEN**, the cavity fills with space, light spills onto the page | comic pop + impact |
| 3.30 / 3.54 | flower out / bird out | pop / wing whir |
| 3.78 / 4.02 | ringed planet out / manicule hand slaps the head | boom tick / slap |
| 4.26 / 4.50 | second flower / second bird | pop / wing whir |
| 4.74 / 5.02 | rocket emerges / rocket launches off the top-right | riser / whoosh |
| 5.30 | brain-spark pulses above the open skull | shimmer |
| 6.02 | red diagonal banner slams across the foot | impact + band |
| 6.16 | 脑洞大开 — four characters cut in on a 2-frame stagger | four pops |
| 6.56 | THE MIND IS A COLLAGE, wiped in from the left | type |
| 7.02 | the editorial clears; the head drifts to centre | riser hit |
| 7.30 | **page-flip** — a whole new torn sheet sweeps the old page away | big rip + whoosh |
| 8.16 | end card lands; masthead rides the landing | heavy slap + type |
| 8.20 | a small bird drifts in from the right | quiet wing whir |
| 8.42 | the talking-head badge bopping in the lower right | small pop |
| 8.56 | Latin kicker breathes its tracking open | type ticks |
| 8.62 | 脑洞大开 — four cuts, staggered | four pops |
| 8.86 | red slash drawn under the title | down whoosh |
| 8.98 | tagline: 脑子是个剪纸盒子。 | soft type |
| 9.12 | credit strip: 导演 / 动效 / 声音 拼贴日报编辑部 | type ticks |
| 10.00 | hold — living micro-motion to the last frame | bed |

## 3. Signature features — how each one is built

**Photo cutout with a white scissor keyline.** The Victorian portrait is a MET
daguerreotype converted at load time into two duotone halftone sprites (6 px and
3 px cells) and composited with a multiplied fine pass. The cutout is a closed
silhouette assembled from three polygons (head, neck, bust) unioned through
`traceUnion()`, which walks each ring, inserts the intersections, and re-samples
everything through a Catmull-Rom spline so the edge reads as a hand-drawn contour.
The keyline is the classic trick: stroke the union path with a wide CREAM line and
fill it CREAM, then draw the ink line, then `clip()` to the same path and drop the
photo in — so only the *outside* half of the cream stroke survives as the pasted
paper edge. The ink line is deliberately drawn **before** the plate, otherwise the
seams where head/neck/bust overlap print as internal lines.

**Halftone screens.** `halftoneSprite()` re-samples the photo per cell, remaps the
plate's narrow tonal range with explicit levels (`lo`/`hi`/`gamma`) and draws a dot
whose radius is `pow(1-lum, dot)`, with a little seeded jitter so the dots look
pressed rather than computed. `colorHalftone()` does the same for the nebula,
sampling r/g/b per cell and boosting them onto a near-black ground; the head cavity
and every planet are cut from that one plate, so the space inside the skull and the
space around the ringed planet are literally the same photograph.

**Newsprint paper.** `buildGround()` bakes one 1920×1080 sheet at load: a coarse
value-noise mottle, 2600 drawn pulp fibres, dark flecks, two tea stains, a faint
tiling print dot screen, a vertical fold crease, and edge darkening. It is blitted
as a single image every frame, so all of that texture costs one `drawImage`.

**Surreal, mis-scaled assembly.** Nothing on the page agrees about scale: a
manicule hand the size of the man's torso, a planet half the width of his head, a
flower with petals longer than his neck, a rocket that fits on his cheek. Placement
is grid-driven but the grid is deliberately violated by the props.

**Held, stepped motion.** Bodies move on a 12 fps grid and the mouth on a 6 fps
grid (`step12`, `step6`), and every pasted piece gets a small re-rolled position
jitter at 1/12 s (`makeJitter`) so the whole page boils the way real cut-out
animation does. Between the steps the only motion is the breathing, the drift and
the grain — the film never moves smoothly in the places where it should be still.

**The head that opens.** The silhouette is split by the hinge line into `cap` and
`headLower`; the cap rotates about the hinge's right end while the camera-space
`clip()` keeps the cavity floor in place. Inside the cavity: the colour-halftone
space plate drifting, a darkened rim, an amber inner glow, and a screen-space
additive light spill so the open skull actually lights the page around it.

## 4. Technical route

* Headless Chrome driven over CDP; the page exposes `window.__ready` and
  `window.renderAt(t)`; the harness screenshots all 300 frames and wraps them with
  ffmpeg. Audio is built first (`audio.py`, pure Python synthesis), normalised to
  −14 LUFS, and muxed as 48 kHz stereo AAC.
* Everything is Canvas 2D, drawn procedurally. No framework, no shader, no
  vendored library, no runtime network access — the only external files are the two
  public-domain photographs (see `CREDITS.md`), fetched once and stored in `parts/`.
* **Determinism:** every frame is a pure function of `t`. All randomness is
  `mulberry32(seed)` or seeded value noise; `Math.random`, `Date.now`, CSS
  transitions and `requestAnimationFrame` animation are never used. Re-rendering the
  same time twice gives byte-identical pixels.
* **Bitrate-aware finish:** `finish()` drifts the film grain at ~3 px/s instead of
  re-seeding it per frame. Consecutive frames stay near-identical to the codec, so
  the grain costs almost nothing in bitrate while still killing the flat-digital
  look. Measured result: 13.5 Mbps, comfortably inside the 8–25 Mbps window, with
  no texture removed.

## 5. Checked numbers

| check | value | target |
|---|---|---|
| duration / frames | 10.000 s / 300 | 10.000 s, 300 |
| resolution / fps | 1920×1080 @ 30 | same |
| video codec / pix fmt | h264 / yuv420p | H.264 |
| audio | AAC stereo 48 kHz, 192.9 kbps | stereo AAC 48 kHz |
| file size / bitrate | 16.8 MB / **13.5 Mbps** | 8–25 Mbps |
| integrated loudness | **−13.7 LUFS** | −14 LUFS |
| loudness range | 1.3 LU | — |
| true peak | **−1.4 dBTP** | ≤ −1 dBTP |
| black frames | 0 | 0 |
| frozen frames | 1 | — |
| frame luma range | 162.05 – 212.29 | no crushed/blank frames |
| console errors / 404s | **0** | 0 |
| page-side cost per frame | mean **39.3 ms**, median 36.9 ms, p90 53 ms, max 229.5 ms (forced-flush timing at 1920×1080) | ≤ ~250 ms |
| rhythm | **no dead spans**; min inter-frame Δ 0.057 | no dead spans |

`node harness/render.mjs demos/09-collage` prints no `PROBLEMS` line, and
`node harness/rhythm.mjs out/09-collage/video.mp4 0.5` reports *no dead spans* and
no stuck frame. The busiest window is the page-flip (7.5–8.0 s, 18.6 % of pixels
moving per frame); the calmest are the pre-pop anticipation (2.0–3.0 s, ~0.9–1.2 %)
and the final hold (9.5–10 s, 0.67 %) — both deliberately quiet, both still alive.

## 6. Top three weaknesses

1. **The anticipation window (2.0–3.0 s) is the thinnest stretch of the film.**
   Between the editorial typing on and the lid popping open, the only motion is the
   6 fps mouth flop, the head breathing and the grain. It is intentional — the film
   needs a held breath before the pop — but it is the part where a viewer's eye has
   the least to do.
2. **The prop beats fire on take-off, not on landing.** Each pasted piece starts
   moving on its cue and lands 0.4–0.6 s later, so the sound you hear at, say, 3.78 s
   is the planet *leaving* the skull rather than the *slap* of it hitting the page.
   It reads as cause-and-effect if you follow it, but frame-accurate sync would put
   the impact sound on the landing.
3. **The mouth is a rectangular strip, not a jaw.** The mouth is a horizontal band
   cut between two lines (366 and 404 in image space) so that the silhouette can
   never tear while it flaps. It reads correctly at speed, but on a held close-up the
   cut is visibly a straight-edged rectangle rather than a chin-shaped cutout. The
   halftone portrait is also the one photographic element on the page and its tonal
   range is narrow next to the flat vector props.

Two smaller ones, for honesty: the score is four identical boom-bap bars with no
musical development across the ten seconds, and the page-flip sheet only reveals its
cargo (bird, scribble, burst, the red banner) in the middle of the sweep, so its
first few frames are a fairly plain shape of paper.

## 7. Self-assessment

| dimension | score | why |
|---|---|---|
| style fidelity | 9.0 | every signature of cut-out collage is present and load-bearing: white keylines, halftone plates, newsprint ground, mis-scaled assembly, stepped 12/6 fps motion, a hinged skull |
| concept | 9.0 | one clear idea ("a mind is a collage") carried by an invented masthead, in idiomatic Chinese, with a payoff in the end card |
| motion craft | 8.5 | staged arrivals with anticipation → travel → overshoot, 2–4 frame stagger, ~10 % squash on landing, one subject moving at a time; a couple of the floaty props are less precisely staged than the head |
| design & typography | 9.0 | a real magazine grid — masthead, badge, column, captioned photo inset, rules, credit strip — with correct Chinese punctuation and no tofu |
| finish | 9.0 | torn edges, tape, contact shadows, paper mottle, fold crease, regrained vignette; nothing reads as a default |
| sound & sync | 8.0 | one cue sheet genuinely drives both halves, and every picture beat has a sound; loses points for the 0.5 s take-off/landing offset and a four-bar loop with no development |
| technical | 9.5 | deterministic to the pixel, zero console errors, zero black frames, 13.5 Mbps, −13.7 LUFS / −1.4 dBTP, ~39 ms of real render per frame |
