# Exact content and choreography contract

## Design API

Import `buildBookContent` and the `BookDesign` type from
`adapters/typography.ts`. This is the retained factory with the single r02
lower-corner repair described in `REVISION.md`, not a generic reimplementation.

| Field | Accepted values | Default |
| --- | --- | --- |
| `family` | required `rounded-book` or `field-notebook` | none |
| `turningLeafWidth` | finite number, inclusive 0.94–1.06 | 1 |
| `pageCurvature` | finite number, inclusive 0.85–1.15 | 1 |
| `ink` | opaque `#RRGGBB`, each channel 0–64 inclusive | `#080808` |
| `paper` | opaque `#ffffff` only; case normalized | `#ffffff` |

No other properties are accepted. No arbitrary logos, raw paths, media slots,
text, alpha colors, background colors, camera controls, aspect ratios, durations,
page counts or retiming controls are supported by this API. Numeric strings,
NaN and infinities fail. Width changes moving leaves relative to fixed rear and
outer leaves; curvature changes cover bow and leaf curves. Neither changes the
frame on which a leaf crosses or the order of filled surfaces.

The two delivered design files are exactly `{"family":"rounded-book"}` and
`{"family":"field-notebook"}`. They regenerate the delivered r02 Content objects
exactly; the adaptation remains byte-identical to r01. The colored README example is only
an illustration of a supported future substitution, not a delivered third render.

## Generated Content is not the authoring API

The factory returns 113 string fields: `paper`, `ink`, and 111 SVG `path` slots.
Slot names are `leafPoseNNLayerK`, with two-digit local frame `NN` and zero-based
back-to-front layer order `K`. The exact names/types are also retained in
`examples/study-outline-page-turn/input.ts` and the recipe's `fields` object.

| Local frames (inclusive) | Orders present | Path slots |
| --- | --- | --- |
| 0–10 | 0, 1 | 22 |
| 11–14 | 0, 1, 2 | 12 |
| 15–22 | 0, 1, 2, 3 | 32 |
| 23–37 | 0, 1, 2 | 45 |
| Total | 38 one-frame states | 111 |

The shared validator also enforces the complete exact field set and bounded
SVG path syntax. That low-level syntax check alone is not permission to supply
arbitrary pose geometry; the public render/preparation commands always invoke
the bounded original factory or verify its exact preserved example output.

## Locked visual mechanism

- Canvas 1920×1080, 30/1 CFR, local frames 0–37, exclusive end 38.
- Each local frame selects one distinct group, with a 320×320 SVG viewport.
  The group's top-left placement varies per frame. No crossfade, interpolation,
  spring, optical flow or rotational substitute connects the stored poses.
- Closed cover: frames 0–5; backmost fill is ink and front fill is opaque white.
  Outline widths are 20, 19.4, 18.8, 18.2, 17.6, 17 pixels.
- Frames 6–37 use opaque white leaf fills and 17-pixel ink strokes. All SVG
  strokes use their retained defaults: miter joins, butt caps, nonzero fill.
- First separating page: frame 6; near-edge-on at 10; left opening at 11.
  A four-surface state begins at 15. Additional contour crossings occupy 16–22.
  Three surfaces remain from 23, settling into the recognizable open-book state.
- Local 31–37 are not an invented freeze: x positions are 862, 863, 865, 868,
  873, 881, 902 pixels. Keep the final rightward movement and then cut. No blank
  outro or automatic ending hold is added.

`assets/VARIANT/controls.json` stores every exact path, fill, stroke,
viewport, placement and order; `frame-controls.csv` and `path-controls.csv` are
the corresponding flat controls for the Resolve guide. A layer order is not a
persistent physical page identity: the pose topology changes at 11, 15 and 23.

## Interpretation limits

These are original reconstruction controls, not recovered OpenAI authoring
parameters. Source observations, retained source PTS and proposed Resolve
workflows are separately labeled. The bounded default join change does not
establish source fidelity or resolve the unmodified early-cover differences.
