# Title chunks → glyph bursts — Resolve construction, r03

**Existing example, 33 frames at 30000/1001. Native Resolve verified: 0.**
The browser-preparation fault is repaired. This is not a source-quality win,
new mechanism, moving review, native export or final presentation approval.
This public-facing directory is a **separate path/configuration adaptation**
made after the single-executable private repair passed. It is not published.
Private operational scripts/logs are not part of this directory.

**r03 changes only the standalone verifier's manifest checks and adds regression
tests.** The four actual CLI cases reuse the frozen r02 preparation and its 29
unchanged PNGs. No browser preparation or movie rendering was repeated. Width
measurements and source observations below are inherited from r02, not new r03
visual review. The existing 40MB preparation cap is also unchanged.

## Original assets and exact existing Remotion subset

- [Original white-field SVG](assets/paper.svg), [original prefix authoring HTML](assets/plate.html),
  [frame/layer recipe](recipe.json), [PNG preparer](prepare.py), [cut-list code](model.py).
  Only paper is supplied as SVG. No outlined-glyph SVG or native SVG import is
  implied; the text remains editable original copy plus HTML/CSS.
- The runnable Remotion subset is **both**
  [core-publication-v08.zip](https://openai-film-fieldnotes-100.pages.dev/videos/editing/benchmark/library/downloads/core-publication-v08.zip)
  **and** [title-chunk-to-glyph/addon-001.zip](https://openai-film-fieldnotes-100.pages.dev/videos/editing/benchmark/library/downloads/assets/title-chunk-to-glyph/addon-001.zip).
  The addon alone is not the runtime. Its recipe member matches the
  [accepted Remotion recipe](https://openai-film-fieldnotes-100.pages.dev/videos/editing/benchmark/library/project/recipes/title-chunk-to-glyph.json)
  byte-for-byte.
- [Original](https://openai-film-fieldnotes-100.pages.dev/videos/editing/benchmark/library/renders/title-chunk-to-glyph/native-v1/original.mp4)
  and [Adaptation](https://openai-film-fieldnotes-100.pages.dev/videos/editing/benchmark/library/renders/title-chunk-to-glyph/native-v1/adaptation.mp4)
  are the existing Remotion movies: each1920×1080, 33 frames, silent. Original
  means original sample content, not the OpenAI movie.
- [Official-source excerpt](https://openai-film-fieldnotes-100.pages.dev/videos/editing/benchmark/library/evidence/title-chunk-to-glyph/native-v1/source.mp4):
  retained960×540 H.264, 33 frames at native cadence, silent. It is research
  evidence, not a production asset. Native cadence is not native source resolution.
- [Artifact bindings](artifact-bindings.json), [accepted input bindings](accepted-stage-binding.json),
  [verification evidence](evidence.json) and [package checksums](SHA256SUMS)
  are actual files in this directory, not filesystem URLs into a builder's machine.

Remote paths were checked against the retained accepted stage, **not fetched
from the public deployment in this task**. There is no bundled font, browser,
source movie, dependency tree or full site. Generated PNG names in the binding
are relative to a generated plate directory, not promised public download URLs.
The source film is *Interrupting and Adding Details in GPT-5.4 Thinking*,
retained metadata March5,2026; metadata was not refreshed.

## The one-variable repair

The actual preparation and original strict verifier were rerun, not replaced
with the critic's in-memory diagnostic:

| Executable; both version152.0.7977.42 | Maximum XOR / ink union, all66 frames | Strict `<3%` |
| --- | ---: | --- |
| Chrome Headless Shell | 3.7272773563% | Fail |
| Full Chrome application binary, launched headless | 0.1213257597% | Pass |

Fresh Headless Shell output reproduced all29 old PNGs byte-for-byte. The only
visual variable changed between those runs was the browser executable. The
recipe, font, HTML/SVG, text, origins, opacity, transforms, timing and verifier
were unchanged; loaded text advances matched. Worker isolation and executable
identity recording were established before the A/B. All13 existing tests pass.

Use the tested full Chrome binary, SHA-256
`9a1fec86405041cdf16c9977d022130c4caf96da6d1a9a20b1767b4ae370e8f6`.
The failed Headless Shell hash is
`7e0227229e5d5d6050a743ec8c2954b2e7b90e84d73c6796ab6ae61a0dde9bce`.
A version string alone is insufficient. The public preparer requires an explicit
binary and rejects another hash; no PATH search, wrapper substitution or fallback.
It retains the existing `--font-render-hinting=none` argument.

This isolates a browser/render-path discrepancy, not a CSS-origin mismatch.
No coordinate nudge, font adjustment or threshold relaxation was used. The
browser internals responsible for different edge pixels were not traced. The
historical movie manifests redact their executable path, so the repair does
not identify that historical binary. A passing diagnostic is not pixel identity,
a codec-only residual explanation, source fidelity or native Resolve validation.

## Standalone manifest validation in r03

The earlier verifier accepted three contradictory manifests despite correct
PNGs: the known failing browser record, a zeroed font hash, and a 29-row inventory
containing a duplicate paper entry and one missing text-plate path. All three
actual CLI reproducers exited 0 before this fix and now exit 1 before decoding.
The valid control still checks all 29 PNGs and 66 render frames at the unchanged
maximum **0.1213257597%**, strictly below 3%.

The verifier now compares the declared browser name/hash/version and version
string with the full Chrome reference binding. It compares the declared font
hash with the actual project font after the existing stage-binding checks.
Before opening any PNG, it requires the exact unique path set derived from the
recipe: one paper image and 14 prefixes per variant. Duplicate, missing and
unexpected inventory paths are rejected, then every expected file's bytes are
hash-checked. Inventory ordering is not significant.

These are consistency checks against trusted local bindings, **not signed
provenance or proof that a manifest's claimed browser actually ran**. The
verifier does not launch a browser, authenticate historical execution, validate
every descriptive manifest field, attest dependency trees, OCR the titles or
render in Resolve. The retained independent r02 replay supplies the preparation
evidence; r03 adds no source, moving-review or native-quality credit.

[Regression tests](test_verifier.py) retain the three counterexamples and valid
control; [evidence](evidence.json) binds their before/after results. Actual fixture
files and command logs remain private and are not in the code/SVG handoff.

## Construct the two lines, not a typewriter

Use **one independent full-raster transparent PNG for each visible prefix**:
four upper states and ten lower states per variant. The text is laid out afresh
for each prefix with the existing recipe's CSS/font settings, not sliced from
a completed sentence. This preserves partial-word shaping without revealing a
sliver of a following glyph. These PNGs are individual editable-build layer
states, not an animated movie or a flattened two-line slide.

`assets/plate.html` is the original text-layer authoring code;
`assets/paper.svg` is the original white field. `prepare.py` reads the existing
licensed font without copying it, checks loaded-font widths, and prepares PNGs.
It renders each original prefix alone over white, then extracts straight alpha
as `255−gray` with black RGB. Exact recomposition onto white is checked. This is
an original-content layer preparation, never a trace of a reference frame.
**Resolve receives PNG stills, not the HTML or SVG.** The PNG preparation was
executed in Chromium; Resolve import was not. No native Text+ size/tracking or
variable-weight equivalence is implied.

Build **two separate 33-frame timelines**, one per variant:

1. Set 1920×1080, square pixels, progressive, **29.97 = 30000/1001** playback.
   Use non-drop-frame labels and start `01:00:00:00`. This guide's timecode
   arithmetic has 30 frame **labels** per second, not 30 frames per real second.
   Set the rate before adding media; do not conform this study into a 30 fps edit.
2. Import `paper.png` and only that variant's 14 prefix PNGs as **individual
   stills**, not a numbered image sequence. Use the Media Storage option
   **Show Individual Frames** if Resolve groups them. Retain the full 1920×1080
   transparent canvas; do not trim each PNG to its ink bounds.
3. Put paper on **V1 `[0,33)`**, upper states on **V2**, lower states on **V3**,
   using the tables below. Empty V2 at frame0 and empty V3 through frame12 are
   deliberate track gaps above paper. From each line's first arrival onward,
   its clips touch with neither overlap nor gap.
4. For every prefix still: Clip Attributes → **Alpha Mode: Straight**; Edit
   Inspector Transform **Position 0,0; Anchor 0,0; linked Zoom 1; Rotation 0**;
   Crop **0 on all edges**; Composite **Normal / Opacity 100%**. The origin is
   already inside the full-frame PNG. Entering `288,423` or `530,540` again in
   Inspector Position would double the translation. Verify alpha over white
   in the installed app; these are requested settings, not tested app behavior.
5. Use ordinary **butted cuts** between stills. No crossfades, keyframes,
   animated masks, Write On, uniform typewriter, caret, optical flow, blur,
   centering, zoom or automatic wrapping. A prefix's transparency is its
   per-state visibility mask; no rectangle sweeps across live text.

There is no continuous curve to configure. Temporal interpolation is a discrete
state replacement on the first included frame. Earlier prefixes do not fade
out before the replacement; both layers retain their respective origins.

### Upper line: V2

All intervals are **inclusive In, exclusive Out**. “Last” is the frame to use
when an app command asks for an inclusive Out. Cut durations are in **frames**.

| Asset | `[In,Out)` | Last | Duration | Original visible prefix | Adaptation visible prefix |
| --- | --- | --- | --- | --- | --- |
| `headline-c12.png` | `[1,4)` | 3 | 3 | Articulating | Recollecting |
| `headline-c18.png` | `[4,7)` | 6 | 3 | Articulating the s | Recollecting the l |
| `headline-c23.png` | `[7,10)` | 9 | 3 | Articulating the subtle | Recollecting the little |
| `headline-c31.png` | `[10,33)` | 32 | 23 | Articulating the subtle details | Recollecting the little stories |

This is a whole leading word, then a multiword chunk ending **inside** word3,
then completion of word3, then a whole trailing word. It is not four whole-word
onsets and not one character per frame. Frame4 must include the final `s`/`l`.

### Indented lower line: V3

| Asset | `[In,Out)` | Last | Duration | Original visible prefix | Adaptation visible prefix |
| --- | --- | --- | --- | --- | --- |
| `detail-c02.png` | `[13,17)` | 16 | 4 | in | at |
| `detail-c04.png` | `[17,18)` | 17 | 1 | in P | at P |
| `detail-c06.png` | `[18,19)` | 18 | 1 | in Pro | at Pro |
| `detail-c09.png` | `[19,20)` | 19 | 1 | in Projec | at Projec |
| `detail-c10.png` | `[20,21)` | 20 | 1 | in Project | at Project |
| `detail-c13.png` | `[21,22)` | 21 | 1 | in Project Ti | at Project Br |
| `detail-c15.png` | `[22,23)` | 22 | 1 | in Project Time | at Project Brie |
| `detail-c16.png` | `[23,24)` | 23 | 1 | in Project Timel | at Project Brief |
| `detail-c18.png` | `[24,25)` | 24 | 1 | in Project Timelin | at Project Briefin |
| `detail-c19.png` | `[25,33)` | 32 | 8 | in Project Timeline | at Project Briefing |

Counts include spaces. The lower lead lasts **four** frames; then increments
are 2/2/3/1/3/2/1/2/1 characters, not equal bursts. All completed upper text
stays visible during the lower build. Both complete lines hold on `[25,33)`;
do not append a reading hold and call that another example.

`recipe.json` has every one of the 33 frame states plus each layer's clip
interval, prefix count and asset. `model.py --variant original` (or `adaptation`)
prints the exact cut list with durations, timeline In, last included timecode
and visible text. **That CSV is a control reference, not a Resolve import file.**

### Clock check

Frame `n` occupies `[n*1001/30000,(n+1)*1001/30000)` seconds relative to this
study's start. Source index = local index here. The 33-frame duration is exactly
`33033/30000 = 1.1011` seconds. Final displayed frame32 starts at
`32032/30000 = 1.067733…` seconds; frame33 is a boundary, not an image.

- Frame0: `01:00:00:00`, paper only.
- Frame13: `01:00:00:13`, lower two-character lead first present.
- Frame25: `01:00:00:25`, both lines first complete.
- Frame32: **`01:00:01:02`**, final included image.
- Exclusive boundary33: **`01:00:01:03`**, do not render this frame.

The inherited master ledger records millisecond-rounded PTS: frame32 `1.068000`
and boundary33 `1.101000`. Those are not exact CFR calculations or newly probed
master timestamps. `evidence.json` separately records actual excerpt/render
PTS; it does not overwrite the inherited ledger with the CFR clock.

## Geometry: measurements versus fits

| Quantity | Value | Evidence category |
| --- | --- | --- |
| Final upper ink bounds | `[294,444,1635,538)` | Inherited threshold-96 measurement at source frame32, on declared 1920×1080 master raster |
| Final lower ink bounds | `[536,561,1388,655)` | Same inherited measurement; exclusive right/bottom, not a text box |
| Upper CSS box | x288, y423, width1380, height118 | Existing Remotion authoring fit |
| Lower CSS box | x530, y540, width890, height118 | Existing Remotion authoring fit |
| Indent / vertical separation | 242 px / 117 px | Fixed differences between those fitted origins; neither origin is a measured source baseline |
| Type | Geist 98 px, weight650, tracking−1.5 px, line-height1.17 | Existing substitute-font fit; line box114.66 px |
| Paper / ink | `#ffffff` / `#000000` | Authoring values; source colors were visual estimates |
| Easing | None | Discrete source arrivals; no recovered easing function or fitted smooth curve |

The preserved recipe calls the 117 px separation a baseline separation. The
portable control here is **CSS top-origin separation**: same font and line box
give the same baseline offset on both lines. No absolute native Text+ baseline
has been measured. Do not substitute ink-bound left/top for the CSS origin.

Fresh decoded source bounds in `evidence.json` are measured on the actual
**960×540 excerpt**, without upscaling. They must not be compared numerically to
the inherited 1920×1080 master bounds as if they shared a raster. The excerpt's
crop origin and full-master framing were not independently re-established.

Original completed advance widths measured here are **1369.2878 / 851.5215 px**;
Adaptation widths are **1328.6669 / 833.6855 px** (upper/lower). These are loaded-font
advances, not source ink measurements. Final visual centers and glyph forms
differ with the original content. There is no recentering to conceal that.
Threshold-mask comparisons to existing Remotion outputs test raster preparation,
not source typeface fidelity or Resolve rasterization.

## Replace original content without replacing the mechanism

Create a new JSON using `apply_patch` in a separate working input directory, containing
**only** `headline` and `detail`. Preserve the existing examples.

- `headline`: exactly four ASCII words, lengths **12/3/6/7**, single spaces;
  first word initial-capitalized, remaining letters lowercase. Exactly31
  characters. Loaded Geist advance must be **1300–1380 px**.
- `detail`: exactly three ASCII words, lengths **2/7/8**, single spaces;
  first word lowercase, other two initial-capitalized. Exactly19 characters.
  Loaded advance must be **800–890 px**.
- No extra field, punctuation, emoji, combining marks, multilingual shaping,
  line break, trailing whitespace or font substitution. Structural validity
  is necessary but not sufficient: width is measured with the loaded bound font.
- Width formula matches the existing renderer: Canvas `measureText` at
  Geist98/650, plus `(length−1)*−1.5`. Do not use the PNG ink rectangle as that
  metric. Wide and narrow structurally valid negative examples are rejected
  by the executed browser preflight.
- Regenerate **all14** prefix PNGs for the new content, not only completed
  lines. Keep the schedule, origins and canvas. If copy fails, reject that
  substitution; do not silently shrink, stretch, re-space, wrap, recenter or
  redistribute the arrivals. Different copy structure requires a separately
  reviewed adaptation, not this content-only route.

The sample Project Timeline/Project Briefing labels are fictional editorial
titles, not claims about Poe or demonstrated product capabilities. No OpenAI
source wording, image, brand or product data enters the prepared prefix assets.

### Font and asset rights

The font is the existing `project/public/fonts/Geist.ttf`, SHA256
`73894e0448cae90a92b6c2f8732b7bb9acb7b94c418bff559dad4a18e1de9659`.
The core carries `project/public/fonts/OFL.txt`: **SIL Open Font License1.1**,
copyright2024 The Geist Project Authors. This task does not bundle another font
copy or license. Keep that existing notice/license with any font redistribution;
do not describe Geist as the source film's unidentified font or as our font.
The HTML/white-field SVG and sample text are original authoring inputs. The
official excerpt and source sheets remain research references, not deliverable
production assets or permission to use the source's branding.

## Portable preparation and verification

Use existing Python with Pillow/Playwright, FFmpeg/FFprobe, `flock`, the tested
full Chrome binary and an authorized storage guard. No dependency or browser is
installed/copied by these scripts. This is **path-portable Linux tooling**, not
tested platform/browser independence or a Resolve plugin.

Configure these existing paths in the invoking environment:

- `FIELDNOTES_RUN_ROOT`: the run named by your storage guard's authorization.
- `FIELDNOTES_WORKER_ROOT`: your existing assigned directory directly under that
  run's `workers/`. PNG output must be a new child directory of this worker.
- `FIELDNOTES_STORAGE_GUARD`: your existing guard script; its returned `runRoot`
  must match the configured run. The requested worker is the configured basename.
- `PYTHON`: an existing Python executable with the stated modules.
- `CHROME_BINARY`: the explicit full Chrome executable with the bound hash.
- `PROJECT`: the read-only selected core+addon `project/` directory.
- `STAGE`: for all-media verification only, a root containing the21 accepted
  files at their public-relative paths in `accepted-stage-binding.json`.

The preparer needs only seven selected project files (font, license, recipe,
two inputs, two implementation files), not a full site. The all-media verifier
needs the21 named files, not unlisted site files. Reuse a retained stage or a
selected-file layout; do not copy a full-site/dependency tree. If the installed
browser requires non-system libraries, explicitly configure `LD_LIBRARY_PATH`
in the environment. The script inherits it without copying libraries.

From this directory, after the assigned worker exists:

```bash
set -euo pipefail
export PYTHONDONTWRITEBYTECODE=1
export TMPDIR="$FIELDNOTES_RUN_ROOT/tmp"
OUT="$FIELDNOTES_WORKER_ROOT/new-full-chrome-plates"
MANIFEST="$FIELDNOTES_WORKER_ROOT/new-full-chrome-preparation.json"
test ! -e "$OUT"
test ! -e "$MANIFEST"

"$PYTHON" "$FIELDNOTES_STORAGE_GUARD" --incoming-bytes 40000000 \
  --worker "$(basename "$FIELDNOTES_WORKER_ROOT")"
"$PYTHON" binding.py --project "$PROJECT"
"$PYTHON" test_recipe.py -v
"$PYTHON" prepare.py --project "$PROJECT" --browser "$CHROME_BINARY" \
  --out "$OUT" > "$MANIFEST"
"$PYTHON" verify.py --stage "$STAGE" --plates "$OUT" --preparation "$MANIFEST"
"$PYTHON" test_verifier.py --stage "$STAGE" --plates "$OUT" --preparation "$MANIFEST" -v
"$PYTHON" model.py --variant original
"$PYTHON" model.py --variant adaptation
```

Use unused output and manifest names. Run the block in Bash; strict mode stops
the chain on a failed guard, binding check, test, preparation or verification.
The preparer checks the40MB budget before
writing, creates29 PNGs and prints its manifest to stdout. It never writes back
to this public source directory or the input project. `output_directory: "."`
means the explicitly supplied plate directory, not the manifest's directory.
The manifest binds actual executable hash/version, code/font hashes, original
contents, loaded advances and every PNG. Absolute input/output paths are not
stored in it. Operational stdout/stderr and generated images stay in the worker,
separate from public deliverables. Save those logs only in your assigned lane.

The public adapter keeps the original mask/PTS/state calculations and strict
`<0.03` gate; its verifier accepts an explicit manifest path instead of a fixed
kit-relative manifest. Even raw FFmpeg decode uses the configured run's
`encoder.lock`; no movie is encoded. Failures exit nonzero. The public CLI is
replayed separately against actual PNGs in r02; r03 reruns only verification
against those frozen PNGs. It does not replace the controlled browser A/B.

To check an existing frozen preparation without generating new PNGs, configure
`PLATES` as its read-only PNG directory and `MANIFEST` as its existing preparation
JSON, then run the following instead of the preparation block. Neither input
must be inside the worker; both remain read-only. Keep the run/worker/guard
environment configured as above; dependencies resolve from the existing Python
environment, without dependency copies or symlinks.

```bash
set -euo pipefail
export PYTHONDONTWRITEBYTECODE=1
export TMPDIR="$FIELDNOTES_RUN_ROOT/tmp"
"$PYTHON" "$FIELDNOTES_STORAGE_GUARD" --incoming-bytes 40000000 \
  --worker "$(basename "$FIELDNOTES_WORKER_ROOT")"
"$PYTHON" verify.py --stage "$STAGE" --plates "$PLATES" --preparation "$MANIFEST"
"$PYTHON" test_verifier.py --stage "$STAGE" --plates "$PLATES" --preparation "$MANIFEST" -v
```

For replacement content, add `--content "$CONTENT"` with a new output/manifest
name and regenerate all14 prefixes. The all-media verifier above is specifically
for the supplied pair, not semantic approval of new titles. Different content
needs its own layout, artifact and moving-review checks; do not compare it to
old sample PNG hashes as if it were the same content.

The existing Remotion direct-content API remains:

```bash
set -euo pipefail
flock "$FIELDNOTES_RUN_ROOT/encoder.lock" npm run render -- --recipe title-chunk-to-glyph \
  --content examples/title-chunk-to-glyph/YOUR-CONTENT.json --out out/YOUR-CONTENT.mp4
flock "$FIELDNOTES_RUN_ROOT/encoder.lock" npm run verify -- --out out/YOUR-CONTENT.mp4
```

Run those only in a separately writable selected project, with the existing
supported runtime, unused output names and required encoder lock in a bounded
run. They were not run against the read-only stage here. Retain the new movie's
own manifest; the supplied pair is not evidence of a new content rendering.

## Remaining native and source limits

**Native Resolve renders:0. Moving review in this repair:none.** The99-frame
decode and66-frame binary-mask comparisons are technical/static evidence, not
continuous-motion or source-quality approval. The3% gate is a chosen mechanical
ceiling, not an official standard. No `.drp`, `.dra`, Fusion setup or native
SVG import was created or implied.

In the actual installed Resolve, build both timelines and record its version,
alpha/color settings and output. Inspect all33 states, including previous/current
frames at1/4/7/10/13/17/18/19/20/21/22/23/24/25, the lower13–16 lead and full25–32
hold. Check full-raster registration, Straight Alpha and halos. Do not conceal
an import/raster/color problem with a position or type adjustment.

Export1920×1080, 30000/1001, exactly33 frames and no audio to a new file. Inclusive
export Out is `01:00:01:02`, not boundary33. Reprobe/decode all output frames, then
review motion at1× against the source separately. A completed export alone is
not source-quality approval. Confirm proposed controls against the installed
manual; no installed Resolve version was tested here.

The [older title-cut guide](https://openai-film-fieldnotes-100.pages.dev/videos/resolve/recipes/title-cut/index.html)
omits this word/chunk/glyph build. Do not borrow its30fps hold or centered
completed-title treatment. Original glyph shapes, source ink heights and final
centers remain different with Geist and original copy. Full-master framing,
crop origin and the later frame79 demo cut were not re-established. No new
source download, demo, crop, sound, title hold or final all-hands production
was added. OBS cue, playback offset and ending buffer remain unset until the
actual talking-head recording and consolidated storyboard review exist.
