# Review a draft, preserve the cut, then begin dispatch

Manual Resolve/Fusion construction for one editable Remotion study and two
fictional content variants. No native Resolve execution, importable .drp,
moving-source review or source-quality approval is claimed.

## Clock and observed contract

Use a 1920×1080 timeline at 24000/1001 fps, a 190-frame composition, and no
audio. Local frame 0 maps to retained source frame 4272; local189 is4461.
The half-open source extent is [4272,4462). Set the timeline rate before
adding media; do not substitute integer24, add ending frames or optical flow.
`source-timing.json` binds all190 actual integer PTS at time base1/24000,
1001ticks per frame. This is not equivalence to an absent historical master.

The observed sequence is: an artifact-local request becomes a pending rewrite;
the rewrite is accepted separately; the film cuts to a different recipient
and a lower draft position; the camera pushes toward Send; Sending remains
unfinished at the end. The cause of the recipient change is not visible.
Do not turn it into a manual edit or imply successful mail delivery.

## Editable inputs

Choose `inputs/default.json` or `inputs/adaptation.json`. `theme` is meadow
or harbor. String keys are `workspaceTitle`, `recipientBefore`,
`recipientAfter`, `subject`, `greeting`, `request`, `before`, `listLead`,
`closing`, and `signature`. `after` has exactly two lines, `bullets` three,
and `sourceLabels` two. The two recipients must differ; the before and after
paragraphs must also differ. Only trimmed printable ASCII without markup is
accepted. Unknown or missing keys fail instead of falling back silently.

All text uses bundled licensed Geist. The main copy is18px/weight400 with27px
line spacing; subject and window title use weight500. Character caps and
actual loaded-font width budgets are in `src/model.ts` under `limits` and
`TEXT`. The request has a510px budget and55-character cap. Subject, greeting,
paragraphs and closing have960px budgets. Bullets have930px; recipients900px;
window title700px; source labels335px. The browser rejects overwide text.
Do not shrink or wrap to force a pass. Calibrate Resolve Text+ metrics against
the raster, rather than equating its normalized size to CSS pixels.

`scripts/build-art.py` regenerates two original desktop fields and two vector
presenter illustrations. `docs/asset-construction.json` records their nested
SVG primitives. Rebuild or import those permitted vector layers using a
locally verified workflow. No source footage, screenshots, people or branding
are renderer inputs. UI controls, typography and pointer stay live layers.

## Fusion layer map

Coordinates are pixels measured from the top-left before the camera. Use a
full-raster transparent canvas for each group so pivots remain stable.
For a rectangle at(x,y) with size(w,h), normalized Center is
((x+w/2)/1920, 1-(y+h/2)/1080); width and height divide by1920 and1080.
The current `draftY` is added to every child of Draft, including its toolbar,
recipient, paragraph, review controls and signature. Sources and the global
composer do not inherit it. Do not animate recipient text between its slots.

| Group/layer | Top-left and size | Construction |
| --- | --- | --- |
| Desktop |0,0;1920×1080|Original gradient/path SVG, outside Camera.|
| Window |60,34;1800×1008|Paper panel,21px corners,62px titlebar and live icons.|
| Draft |218,130+draftY;1040×676|White card,23px corners, thin border.|
| Inline request |Draft+(27,25);560×30|Pencil, request text, submit arrow or spinner.|
| Recipient |Draft+(26,83);960×27|Held before/after recipient strings.|
| Send |Draft+(912,20);104×44|Blue rounded control; neutral Sending at178.|
| Subject |Draft+(26,145);960×27|18px/500 text.|
| Greeting |Draft+(26,198);960×27|18px text; small caret only81–157.|
| Paragraph |Draft+(26,250);960×54|Before line through80; after lines from81.|
| Review controls |Draft+(444,138);166×34|Reject/Accept, only81–146.|
| List lead |Draft+(26,333)|One line.|
| Three bullets |Draft+(37,378)|35px baseline spacing.|
| Closing/signature |Draft+(26,510)/(26,562)|Closing, then Best and signature.|
| Global composer |218,896;1040×125|Independent fixed field; never the local request.|
| Sources |1430,114;390×305|Independent card with two fictional source labels.|
| Inset |1512,104;286×366|Original vector illustration; separate opacity.|
| Pointer |pointerX,pointerY;25×32|Original vector path in `Scene.tsx`.|

Merge Window, Draft, global composer, Sources, Inset and Pointer into Camera.
Scale around the raster top-left, then translate by cameraX/cameraY. For a
pixel point, output=(cameraX+cameraScale*x,cameraY+cameraScale*y). In Fusion,
set a top-left pivot with the correct Y-axis convention and validate three
corners before animation. Do not apply camera twice to child layers.

## Frame controls and switches

Regenerate `docs/controls.csv` with
`node --experimental-strip-types scripts/controls.mjs`. It has one row per
native frame; key each named value at that frame and use linear interpolation
between consecutive rows. Boolean/string switches must hold, not crossfade.
This CSV is a construction reference, not a claim that Resolve imports it.

| Local frame | Required visible state |
| ---: | --- |
|0–2|Empty artifact-local request; original paragraph; Send remains available.|
|3–58|Authored typing schedule within the observed bracket; complete by58.|
|62→63|Submit arrow changes to processing indicator.|
|60–78|Independent inset fade; fully absent at78.|
|80→81|Before paragraph becomes two blue proposal lines; Reject/Accept appear.|
|146→147|Review controls disappear; same revised text becomes neutral.|
|157→158|Recipient changes discretely; draftY jumps0→38; greeting caret clears.|
|161→162|Camera first departs wide view, after the documented recipient cut.|
|174|Camera reaches1.8 scale, x−970, y−30; holds through189.|
|177→178|Send changes to neutral Sending with rotating spinner.|
|178–189|Exactly12 unfinished Sending positions. No success screen.|

Type the request using the integer prefix returned by `requestAt`; it has an
authored first nonempty frame3, not a recovered event timestamp. For each
distinct prefix use a held Text+ string and visibility interval if the local
Text+ text-keyframing workflow is not verified. Processing spinner rotation
is frame*22degrees; Sending spinner frame*24degrees. Card geometry, pointer
paths, type metrics, fade and camera curves are authored approximations.
The native gates and the recipient discontinuity are source observations.

## Verification before export

Check both contents at0,62/63,80/81,146/147,157/158,161/162 and177/178/189.
The revised paragraph must be byte-identical through pending, accepted and
post-cut states. Acceptance is not dispatch. The same subject, bullet list
and signature persist around the cut; the recipient deliberately does not.
Preserve cropping during the late push and do not stretch Sending to make it
easier to read. Export a silent190-frame H.264 MP4 at1920×1080 and24000/1001.
Check encoded PTS, frame count, content width and state changes afterward.
This guide still needs application-level validation in Resolve.
