cueframe 0.11.0 → 0.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +8 -0
  2. package/dist/analyze-I7B5SFLM.js +2 -0
  3. package/dist/{chunk-M3NS5UR2.js → chunk-HB4NDWMH.js} +7 -7
  4. package/dist/cueframe.js +46 -46
  5. package/dist/skills/add-music-bed/SKILL.md +5 -23
  6. package/dist/skills/brand-reel/SKILL.md +5 -28
  7. package/dist/skills/clip-a-talking-head/SKILL.md +2 -20
  8. package/dist/skills/composing-video/SKILL.md +36 -432
  9. package/dist/skills/composing-video/references/acceptance-template.md +21 -0
  10. package/dist/skills/composing-video/references/audio-design.md +125 -0
  11. package/dist/skills/composing-video/references/card-and-motion-runtime.md +49 -0
  12. package/dist/skills/composing-video/references/craft-principles.md +25 -0
  13. package/dist/skills/composing-video/references/film-planning.md +37 -0
  14. package/dist/skills/composing-video/references/format-decisions.md +17 -0
  15. package/dist/skills/composing-video/references/format-playbooks.md +96 -0
  16. package/dist/skills/composing-video/references/motion-design.md +25 -0
  17. package/dist/skills/composing-video/references/project-policy.md +18 -0
  18. package/dist/skills/composing-video/references/sfx-pack.md +69 -0
  19. package/dist/skills/composing-video/references/sound-and-timing.md +15 -0
  20. package/dist/skills/composing-video/references/tool-map.md +43 -0
  21. package/dist/skills/cueframe-brand-demo/SKILL.md +1 -7
  22. package/dist/skills/cueframe-cli/SKILL.md +9 -7
  23. package/dist/skills/cueframe-component-authoring/SKILL.md +20 -169
  24. package/dist/skills/cueframe-component-authoring/references/authoring-paths.md +72 -0
  25. package/dist/skills/cueframe-component-authoring/references/forking-and-layout.md +35 -0
  26. package/dist/skills/cueframe-component-authoring/references/native-component-workflows.md +98 -0
  27. package/dist/skills/cueframe-component-authoring/references/native-source-contract.md +54 -0
  28. package/dist/skills/cueframe-component-authoring/references/parented-device-card.json +13 -0
  29. package/dist/skills/cueframe-component-authoring/references/parented-motion.md +25 -0
  30. package/dist/skills/cueframe-component-authoring/references/retired-projects.md +26 -0
  31. package/dist/skills/cueframe-compose-loop/SKILL.md +14 -115
  32. package/dist/skills/cueframe-compose-loop/references/convergence-loop.md +128 -0
  33. package/dist/skills/cueframe-compose-loop/references/preview-workflow.md +6 -2
  34. package/dist/skills/cueframe-connect/SKILL.md +1 -7
  35. package/dist/skills/cueframe-connect/references/tools.md +6 -5
  36. package/dist/skills/cueframe-product-video/SKILL.md +1 -7
  37. package/dist/skills/cueframe-reference-video/SKILL.md +30 -0
  38. package/dist/skills/cueframe-reference-video/references/measurement-and-comparison.md +45 -0
  39. package/dist/skills/cueframe-reference-video/scripts/motion-grid.sh +116 -0
  40. package/dist/skills/cueframe-scene-shot/SKILL.md +2 -8
  41. package/dist/skills/cueframe-storyboard/SKILL.md +1 -7
  42. package/dist/skills/every-format-from-one-edit/SKILL.md +3 -19
  43. package/dist/skills/extracting-brand-kits/SKILL.md +1 -7
  44. package/dist/skills/launch-video/SKILL.md +6 -26
  45. package/dist/skills/make-a-social-reel/SKILL.md +7 -26
  46. package/dist/skills/rebrand-a-video/SKILL.md +2 -19
  47. package/dist/skills/video-craft-standards/SKILL.md +20 -103
  48. package/dist/skills/video-craft-standards/references/format-standards.md +118 -0
  49. package/package.json +4 -4
  50. package/dist/analyze-5KCAIZI6.js +0 -2
@@ -5,13 +5,7 @@ description: Use when editing, clipping, or rendering video via the CueFrame CLI
5
5
 
6
6
  # CueFrame CLI
7
7
 
8
- ## Scope and capability policy
9
-
10
- User intent and acceptance criteria override this recipe's aesthetic defaults. Silent, typography-only, uncaptioned and slow work are valid; no universal narration, footage, CTA, beat count or score target. Contracts, factual fidelity, media bindings and current source revisions remain mandatory.
11
-
12
- Read available tools and current project; preserve the chosen local/hosted lane. Supported local work needs no hosted registration. Do not silently install, authenticate, switch projects or upload local content. Before metered hosted work, check `get_account`, entitlements, balance and quotes. Desktop setup: https://docs.cueframe.ai.
13
-
14
- For scoped revisions, preserve unrelated timing, media, audio and shared brand-kit state. Edit affected content; inspect relevant frames, continuous motion and affected audio. No restarted intake, new approval pause, paid judge or final export by default. Judge only when useful; scores never override acceptance failures. Stop/report after two no-improvement passes. See [preview workflow](../cueframe-compose-loop/references/preview-workflow.md).
8
+ Use the [project and capability policy](../composing-video/references/project-policy.md) for scope, current state and metered work.
15
9
 
16
10
  ## MCP is the primary surface — read this before using the CLI
17
11
 
@@ -65,6 +59,14 @@ Validate first, then use `preview_card` / `preview_component` for isolated graph
65
59
  MCP tools or the CLI's `api` escape hatch with the live request contract. Full `render` is for
66
60
  delivery, not checking each edit. CLI validation does not replace visual evidence.
67
61
 
62
+ To compare a certified reference frame with an existing saved preview, use `compare`:
63
+
64
+ ```bash
65
+ npx -y cueframe@0.11 compare <projectId> --reference-media <mediaId> --reference-representation <identity> --reference-frame 117 --candidate-job <jobId> --candidate-artifact <artifactId> --out ./comparison --json
66
+ ```
67
+
68
+ The command calls the shared comparison operation; it does not rerender the composition. `--views overlay,difference` selects diagnostics and `--crop x,y,width,height` uses one common-coordinate crop. NDJSON contains source identities and image receipts, never base64 payloads. `--out` saves verified PNGs; without it, image receipts explicitly say `metadata_only`. Inspect those images and relevant motion before judging the film.
69
+
68
70
  ```bash
69
71
  # 0. Always use --json for agent-driven runs (NDJSON to stdout, no spinners).
70
72
  # Commands run against production; auth is stored in ~/.cueframe/auth.json.
@@ -1,187 +1,38 @@
1
1
  ---
2
2
  name: cueframe-component-authoring
3
- description: Use when authoring, forking, or customizing a CueFrame motion-graphics component/primitive/graphic — e.g. "customize the parallax look", "make my own animated lower-third", "fork a CueFrame template and edit it", "author a custom graphic and render it". Covers cloud MCP, local desktop, and CLI project paths using complete versioned source snapshots. Use BEFORE hand-writing a component from scratch — forking a built-in is usually the faster start.
3
+ description: "Use when authoring, forking or customizing CueFrame HTML cards, motion-graphics primitives or reusable native components, including a fork of an exact catalog source. Covers cloud MCP, local desktop and CLI project paths using complete versioned source snapshots. For scene-shot devices and cameras use cueframe-scene-shot. Triggers on \"customize the parallax look\", \"make my own animated lower-third\", \"fork a CueFrame template and edit it\", \"author a custom graphic and render it\". Use before hand-writing a component from scratch: forking a built-in is usually the faster start."
4
4
  ---
5
5
 
6
- # CueFrame component authoring (fork / customize / own)
6
+ # CueFrame graphic authoring
7
7
 
8
- ## Scope and capability policy
8
+ Use the [project and capability policy](../composing-video/references/project-policy.md). Preserve the current project and source identities; make the intended visual behavior inspectable and editable.
9
9
 
10
- User intent and acceptance criteria override this recipe's aesthetic defaults. Silent, typography-only, uncaptioned and slow work are valid; no universal narration, footage, CTA, beat count or score target. Contracts, factual fidelity, media bindings and current source revisions remain mandatory.
10
+ ## Choose the representation
11
11
 
12
- Read available tools and current project; preserve the chosen local/hosted lane. Supported local work needs no hosted registration. Do not silently install, authenticate, switch projects or upload local content. Before metered hosted work, check `get_account`, entitlements, balance and quotes. Desktop setup: https://docs.cueframe.ai.
12
+ - **HTML card:** authored typography, UI, diagrams and 2D motion with deterministic CSS. It can depict perspective, but does not provide the scene renderer's physical camera, lighting or occlusion.
13
+ - **Whole-clip keyframes:** position, scale, rotation and opacity when the entire card or layer moves together. Read the current `clip.setKeyframes` schema; times are relative to the clip.
14
+ - **Scene shot:** supported groups, devices, pages, world text, surfaces and cameras. Use `cueframe-scene-shot` and its current schema; author JSON, not the generated wrapper.
15
+ - **Native component:** reusable version-4 media-tile scenes with declared inputs, assets and deterministic rendering. Discover a near-fit definition before writing one. Read the [native source contract](references/native-source-contract.md), then the applicable [MCP, CLI or desktop workflow](references/native-component-workflows.md). This is not an arbitrary browser application runtime.
13
16
 
14
- For scoped revisions, preserve unrelated timing, media, audio and shared brand-kit state. Edit affected content; inspect relevant frames, continuous motion and affected audio. No restarted intake, new approval pause, paid judge or final export by default. Judge only when useful; scores never override acceptance failures. Stop/report after two no-improvement passes. See [preview workflow](../cueframe-compose-loop/references/preview-workflow.md).
17
+ A definition, preset and recipe are different catalog items. Preserve the selected item's exact scoped identity. A builtin source read needs `componentId`, `sourceVersionId` and `builtinCollection`; unavailable pins do not authorize a different source. Keep the complete template, manifest and definition when forking.
15
18
 
16
- Use `cueframe-compose-loop`'s [preview workflow](../cueframe-compose-loop/references/preview-workflow.md)
17
- to select hosted or local evidence and separate iteration from final delivery.
19
+ ## Cards: geometry, clock and controls
18
20
 
19
- CueFrame ships built-in motion-graphics definitions (titles, lower-thirds, captions,
20
- effects, transitions and layouts). Discover the current catalog; fork an exact definition, customize it,
21
- and render it on CueFrame — or author a brand-new component. This is shadcn-for-video: own the
22
- component code; CueFrame is the reliable engine that renders it.
21
+ A card source is `{kind:"card", html, tokens}`. Each token key `x` becomes the CSS property `--cf-x`; read `var(--cf-x)`. Keys have no leading dashes. Missing variables silently invalidate CSS, so inspect returned warnings and actual output. Use literal or supported whole-string brand references and do not overwrite reserved motion variables.
23
22
 
24
- **Before you hand-write 3D:** a device mockup or a screenshot floating in a lit 3D scene is a
25
- **scene shot** — validated JSON with `scene.add` / `scene.update`, not a component you author.
26
- See the `cueframe-scene-shot` skill and `cueframe://scene-shot`. Author a component here when
27
- you need behaviour the scene contract does not express.
23
+ The host injects a clip-local clock each frame: `--cf-frame`, `--cf-t` (seconds), `--cf-fps`, `--cf-duration` (frames), `--cf-progress`, `--cf-ease`, `--cf-enter` and `--cf-exit`. CSS animations, transitions and timers are not the render clock. The built-in entrance/exit ramps span up to 18 frames; use explicit event times when the brief needs other choreography.
28
24
 
29
- **Source format matters:**
30
- - New and changed components are native (source version 4): `{version:4, componentId, template,
31
- manifest, definition}`. `template` is one HyperFrames sub-composition whose script ends in one
32
- `__cfScene.mount(...)`; the manifest is `{version:4, runtime:'hyperframes', hfContract:1,
33
- kind:'scene', assets, graphics, alphaPolicy}`. The definition declares input schema, defaults,
34
- timing, brand/media bindings and capabilities. The server instructions' Component Contract has
35
- the full rules. Version-3 TSX sources are retired and refused as `component_source_retired`.
36
- - Neither renderer runs authored source in the editor process. Local and hosted execution
37
- use isolated render processes and exact immutable source revisions.
25
+ Use flex/grid for text and UI reflow, and coordinate-based nested transforms for spatial animation. Parent mounted contents to their object: a moving phone should carry its bezel, screen mask and controls. Use a separate local transform only when that part really moves relative to the object. The [parented motion recipe](references/parented-motion.md) includes a complete editable card with a shared pose and named pointer-contact/response times.
38
26
 
39
- ## Path A — MCP agent (no filesystem; source lives server-side)
27
+ Expose likely revisions as meaningful inputs rather than unrelated constants. A card's text token used by CSS `content` needs a quoted CSS string. Preserve the current token values when changing its HTML. The native component definition declares defaults and input controls; its placement binds media in `execution.assets`, separately from `params`.
40
28
 
41
- Use the live tool schema for request envelopes; hosted write fields are normally under `body`.
29
+ ## Iterate on the saved result
42
30
 
43
- 1. **Discover and read a built-in:** call `list_catalog` with
44
- `projection: "component-library", origin: "builtin", libraryKind: "definition"`.
45
- Select the intended card and preserve its complete scoped source reference. Call
46
- `get_component_source` with that reference's `componentId`, `sourceVersionId`,
47
- `builtinCollection` (its scope collection).
48
- ID-only builtin reads are unsupported. An unavailable exact pin is a refusal; never
49
- retry another scope or an unpinned head.
50
- 2. **Author/own it:** edit the complete native `sourceSnapshot`; use your chosen owned ID
51
- consistently in its `componentId` and the request. Send it as `body.source` to
52
- `create_component`, with required metadata. Preserve its definition, capability
53
- declarations, manifest and source format. For an existing component, keep its ID and
54
- use `update_component` with the complete source. Do not send an old pin as the identity
55
- of changed source: saving produces a new immutable source version.
56
- 3. **Iterate (author→preview→fix):** `preview_component({ componentId, params })` queues a durable
57
- preview and returns a `jobId`; call `wait_job(kind:"preview")`. The typed terminal result is a
58
- verified artifact produced by the same bundle contract used by final render. A failed
59
- `component_does_not_compile` job carries the compiler error — read it, fix via `update_component`
60
- (same id, in place), and preview again.
61
- **Repin only the requested scope:** for all matching placements in one composition, use
62
- `update_component({ componentId, body: { source: editedSnapshot, projectId, compositionId? } })`
63
- with the observed revision and dependency guards. A placed clip
64
- renders the exact version it pins; only the composition you name moves to the new version in the
65
- same write (`repinned` says what moved). Without `projectId` your clips keep rendering the old
66
- version, and `placementsPinnedToPrevious` counts them. For a single placement, update the
67
- source without `projectId`, then change only that clip to the returned exact source pin
68
- using the observed concurrency guards.
69
- Set preview duration deliberately: `durationInFrames` is not a trim window and can retime
70
- duration-dependent motion. Preserve production timing; inspect the live tool's request shape.
71
- 4. **Check integration:** add it as a `{kind:'component', componentId, props:{},
72
- execution:{version:4,componentId,sourceVersionId,params,seed,assets}, placement:{version:3,kind:'clip'}}` clip
73
- (`apply_composition`), then inspect saved-composition stills or a scoped `preview_clip` for
74
- placement and motion. Use `create_render` → `wait_job kind:"render"` when delivering a
75
- finished MP4, not per tweak.
31
+ Keep the same owned component ID while updating its complete source. Saving creates a new immutable source version; existing placements keep their old pins unless explicitly repinned in the intended composition. An isolated preview is not a saved timeline edit. The workflow reference explains scoped repinning and local preview commits.
76
32
 
77
- ## Path B — CLI / coding agent (customer-owned source under git)
33
+ Use [cueframe-compose-loop](../cueframe-compose-loop/SKILL.md) for isolated, integrated and final evidence. Preserve production duration when previewing duration-dependent motion. Check the relationship that could fail, including screen corners, overlap, pointer contact and the complete ending, rather than only a pleasing middle still. For `needsUpgrade`, use [retired-source recovery](references/retired-projects.md) and replace only the reported clips.
78
34
 
79
- Source lives in `cueframe/components/<id>/` (the `cueframe.json` workspace); edit the native
80
- template locally, push to render.
35
+ ## Detailed guidance
81
36
 
82
- ```bash
83
- npx -y cueframe@0.11 init --json # scaffold cueframe.json + cueframe/components/
84
- npx -y cueframe@0.11 new component my-badge --category ui-blocks --json # scaffold a component in the workspace
85
- # New scaffolds contain template.html and definition.json (native source, version 4).
86
- # …edit cueframe/components/<id>/template.html and definition.json in your editor…
87
- npx -y cueframe@0.11 push my-badge --json # send the native source; the server admits it
88
- # or: npx -y cueframe@0.11 sync --json # push every component in the workspace
89
- # reference the component id in your composition, then render:
90
- npx -y cueframe@0.11 render <projectId> -o ./out.mp4 --json
91
- ```
92
-
93
- The CLI writes `template.html` and `definition.json` (input schema, defaults, timing and
94
- capabilities). `cueframe.json` → `components.<id>` holds the version-4 `manifest` and the catalog
95
- `name` and `category`, which `push` requires; it refuses a component missing either.
96
- `push`/`sync` send these as one native `source`, checked against the contract's source schema;
97
- the server's admission (template lint, determinism, declarations) refuses with a named rule.
98
- For a builtin fork, copy **all three parts** from the selected `sourceSnapshot`: template,
99
- definition and manifest. A workspace component that still has a version-3 `index.tsx` is
100
- refused as `component_source_retired` before any API call; author it again as a native template. To preview before
101
- a full render, push it and use the appropriate component preview loop.
102
-
103
- ## Path C — Director editing a local desktop project (project-embedded source)
104
-
105
- When `get_context` reports the project lane as local, motion does not need an account or an org
106
- component. Components here are native (source version 4) too:
107
- - **New component:** open a draft with `open_component_preview`, passing `template`,
108
- `component_manifest` (`{version:4, runtime:'hyperframes', hfContract:1, kind:'scene', assets,
109
- graphics, alphaPolicy}`) and `component_definition`.
110
- - **Existing component:** pass `component_id` instead, to start from the clip's pinned version or
111
- the library version.
112
-
113
- The draft is admitted in full: template lint, determinism and the variable declaration.
114
- `data-composition-variables` must equal the definition's projection (its scalar inputSchema
115
- properties, then the manifest's slots).
116
-
117
- Edit the draft with `update_component_preview` (exact-text `{oldText, newText, replaceAll?}`
118
- edits). Check exact frames with `render_component_preview_frame`, and inspect playback for motion.
119
- `commit_component_preview` publishes the checked source to the library and pins the clip, and
120
- returns the project's new ETag. `read_component` and `edit_component` read and edit the library
121
- directly. Close the preview when finished.
122
-
123
- Media slots are image or video, declared in `component_manifest.assets` and bound to project
124
- media ids in `component_assets`. The template passes them to `MediaTileScene` as
125
- `streams: { hero: { asset: assets.hero } }`. Declare `alphaPolicy` explicitly:
126
- `requires-transparency` for overlays, `allows-opaque` for full-frame plates.
127
-
128
- Every frame must be a pure function of `render.frame`, params and `render.seed`. Timers, `Date`,
129
- network, imports, other globals and CSS animation are refused at admission. The timeline and final
130
- export render the exact committed version. Use `create_component` only for a reusable org-catalog
131
- component on a reachable cloud lane.
132
-
133
- ## Upgrading an old project
134
-
135
- `get_composition` returns `needsUpgrade` only when clips from before the native cutover remain:
136
- `[{clipId, kind, componentId?, sourceVersionId?, primitiveId?, successorComponentId?,
137
- successorSourceVersionId?}]`. Saves and renders refuse those clips. A retired component is
138
- refused with `component_source_retired`, and a retired
139
- primitive with `render_unknown_primitive`. Upgrade only the listed clips. Keep every other clip,
140
- timing, track and brand-kit binding as it is.
141
-
142
- - **Any entry with a `successorSourceVersionId`:** call `repin_component` with its clip ids. It
143
- moves them to the native successor and keeps their saved inputs.
144
- - **`v3-component` with no successor** (a custom pre-cutover component): read its source, params,
145
- timing and placement, and author a native replacement with `create_component` as a version-4
146
- template following the server instructions' Component Contract.
147
- - **`unpinned-component`:** the clip carries a `retired` record (what was stored before the cutover), with its
148
- props preserved. Re-author it from those props the same way.
149
- - **`retired-primitive`:** rebuild what `primitiveId` drew from the clip's params, as a card or
150
- a native component.
151
-
152
- For each replacement, use `apply_composition` to replace only that clip at the same start,
153
- duration, track and placement, pinned to the new exact `sourceVersionId`. Map the old params
154
- onto the new inputs; do not invent new content. Verify each clip with `preview_frame` at a time
155
- inside its window and confirm `needsUpgrade` is gone. Only then render (`create_render`).
156
-
157
- ## Choosing what to fork
158
- Use the `component-library` projection to choose a definition, inspect its input schema and
159
- capabilities, then fetch its exact scoped source as described in Path A. Presets and recipes
160
- are different card kinds: follow their exact definition/document references rather than treating
161
- those IDs as source IDs. Inspect appropriate previews before judging visual behavior.
162
-
163
- ## Layout inside a component — CSS flex/grid
164
-
165
- When several cells must share space (a feature grid, a fixed rail beside fluid content, a cast of
166
- objects next to type), lay them out with CSS flex or grid in the HTML, not hand-placed pixels.
167
- Use the template of a native component, or a `card`:
168
-
169
- ```html
170
- <div style="display:grid; grid-template-columns: 520px 1fr 3fr; gap:16px; width:100%; height:100%">
171
- <div class="rail"></div><div class="type"></div><div class="art"></div>
172
- </div>
173
- ```
174
-
175
- - Fixed tracks (`520px`) hold content-sized cells. Fractions (`1fr`, `3fr`) share what is left.
176
- - Animate a reflow from the frame, never from time: in a card, drive `grid-template-columns`
177
- or `flex-basis` from `var(--cf-progress)` (or `--cf-enter`/`--cf-exit`); in a native template,
178
- derive it from `render.frame`.
179
- - Size the container to its region instead of CSS-`scale()`-ing the layout, which resamples.
180
- Use `object-fit` for media in a cell.
181
-
182
- ## Don't
183
- - Don't expect a forked primitive to use rich named props — read `params` inside and use the explicit
184
- `assets` and `render` bags for media and frame state.
185
- - When a built-in fits the request, fork its exact snapshot using Path A. Never discard its
186
- definition by copying only its template; preserve the definition and manifest too.
187
- - Don't `create_component` a fresh id each fix iteration — `update_component` (same id) is the loop.
37
+ - [Authoring paths](references/authoring-paths.md): the MCP path step by step, when no filesystem is available.
38
+ - [Forking and layout](references/forking-and-layout.md): what to fork, flex and grid inside a component, and what to avoid.
@@ -0,0 +1,72 @@
1
+ # Authoring paths
2
+
3
+ Defaults, examples and detail for this topic. The [skill](../SKILL.md) and the [project and capability policy](../../composing-video/references/project-policy.md) take precedence where they differ, and the current tool schemas are authoritative.
4
+
5
+ ## Scope and capability policy
6
+
7
+ User intent and acceptance criteria override this recipe's aesthetic defaults. Silent, typography-only, uncaptioned and slow work are valid; no universal narration, footage, CTA, beat count or score target. Contracts, factual fidelity, media bindings and current source revisions remain mandatory.
8
+
9
+ Read available tools and current project; preserve the chosen local/hosted lane. Supported local work needs no hosted registration. Do not silently install, authenticate, switch projects or upload local content. Before metered hosted work, check `get_account`, entitlements, balance and quotes. Desktop setup: https://docs.cueframe.ai.
10
+
11
+ For scoped revisions, preserve unrelated timing, media, audio and shared brand-kit state. Edit affected content; inspect relevant frames, continuous motion and affected audio. No restarted intake, new approval pause, paid judge or final export by default. Judge only when useful; scores never override acceptance failures. Stop/report after two no-improvement passes. See [preview workflow](../../cueframe-compose-loop/references/preview-workflow.md).
12
+
13
+ Use `cueframe-compose-loop`'s [preview workflow](../../cueframe-compose-loop/references/preview-workflow.md)
14
+ to select hosted or local evidence and separate iteration from final delivery.
15
+
16
+ CueFrame ships built-in motion-graphics definitions (titles, lower-thirds, captions,
17
+ effects, transitions and layouts). Discover the current catalog; fork an exact definition, customize it,
18
+ and render it on CueFrame — or author a brand-new component. This is shadcn-for-video: own the
19
+ component code; CueFrame is the reliable engine that renders it.
20
+
21
+ **Before you hand-write 3D:** a device mockup or a screenshot floating in a lit 3D scene is a
22
+ **scene shot** — validated JSON with `scene.add` / `scene.update`, not a component you author.
23
+ See the `cueframe-scene-shot` skill and `cueframe://scene-shot`. Author a component here when
24
+ you need behaviour the scene contract does not express.
25
+
26
+ **Source format matters:**
27
+ - New and changed components are native (source version 4): `{version:4, componentId, template,
28
+ manifest, definition}`. `template` is one HyperFrames sub-composition whose script ends in one
29
+ `__cfScene.mount(...)`; the manifest is `{version:4, runtime:'hyperframes', hfContract:1,
30
+ kind:'scene', assets, graphics, alphaPolicy}`. The definition declares input schema, defaults,
31
+ timing, brand/media bindings and capabilities. The server instructions' Component Contract has
32
+ the full rules. Version-3 TSX sources are retired and refused as `component_source_retired`.
33
+ - Neither renderer runs authored source in the editor process. Local and hosted execution
34
+ use isolated render processes and exact immutable source revisions.
35
+
36
+ ## Path A — MCP agent (no filesystem; source lives server-side)
37
+
38
+ Use the live tool schema for request envelopes; hosted write fields are normally under `body`.
39
+
40
+ 1. **Discover and read a built-in:** call `list_catalog` with
41
+ `projection: "component-library", origin: "builtin", libraryKind: "definition"`.
42
+ Select the intended card and preserve its complete scoped source reference. Call
43
+ `get_component_source` with that reference's `componentId`, `sourceVersionId`,
44
+ `builtinCollection` (its scope collection).
45
+ ID-only builtin reads are unsupported. An unavailable exact pin is a refusal; never
46
+ retry another scope or an unpinned head.
47
+ 2. **Author/own it:** edit the complete native `sourceSnapshot`; use your chosen owned ID
48
+ consistently in its `componentId` and the request. Send it as `body.source` to
49
+ `create_component`, with required metadata. Preserve its definition, capability
50
+ declarations, manifest and source format. For an existing component, keep its ID and
51
+ use `update_component` with the complete source. Do not send an old pin as the identity
52
+ of changed source: saving produces a new immutable source version.
53
+ 3. **Iterate (author→preview→fix):** `preview_component({ componentId, params })` queues a durable
54
+ preview and returns a `jobId`; call `wait_job(kind:"preview")`. The typed terminal result is a
55
+ verified artifact produced by the same bundle contract used by final render. A failed
56
+ `component_does_not_compile` job carries the compiler error — read it, fix via `update_component`
57
+ (same id, in place), and preview again.
58
+ **Repin only the requested scope:** for all matching placements in one composition, use
59
+ `update_component({ componentId, body: { source: editedSnapshot, projectId, compositionId? } })`
60
+ with the observed revision and dependency guards. A placed clip
61
+ renders the exact version it pins; only the composition you name moves to the new version in the
62
+ same write (`repinned` says what moved). Without `projectId` your clips keep rendering the old
63
+ version, and `placementsPinnedToPrevious` counts them. For a single placement, update the
64
+ source without `projectId`, then change only that clip to the returned exact source pin
65
+ using the observed concurrency guards.
66
+ Set preview duration deliberately: `durationInFrames` is not a trim window and can retime
67
+ duration-dependent motion. Preserve production timing; inspect the live tool's request shape.
68
+ 4. **Check integration:** add it as a `{kind:'component', componentId, props:{},
69
+ execution:{version:4,componentId,sourceVersionId,params,seed,assets}, placement:{version:3,kind:'clip'}}` clip
70
+ (`apply_composition`), then inspect saved-composition stills or a scoped `preview_clip` for
71
+ placement and motion. Use `create_render` → `wait_job kind:"render"` when delivering a
72
+ finished MP4, not per tweak.
@@ -0,0 +1,35 @@
1
+ # Forking and layout
2
+
3
+ Defaults, examples and detail for this topic. The [skill](../SKILL.md) and the [project and capability policy](../../composing-video/references/project-policy.md) take precedence where they differ, and the current tool schemas are authoritative.
4
+
5
+ ## Choosing what to fork
6
+ Use the `component-library` projection to choose a definition, inspect its input schema and
7
+ capabilities, then fetch its exact scoped source as described in Path A. Presets and recipes
8
+ are different card kinds: follow their exact definition/document references rather than treating
9
+ those IDs as source IDs. Inspect appropriate previews before judging visual behavior.
10
+
11
+ ## Layout inside a component — CSS flex/grid
12
+
13
+ When several cells must share space (a feature grid, a fixed rail beside fluid content, a cast of
14
+ objects next to type), lay them out with CSS flex or grid in the HTML, not hand-placed pixels.
15
+ Use the template of a native component, or a `card`:
16
+
17
+ ```html
18
+ <div style="display:grid; grid-template-columns: 520px 1fr 3fr; gap:16px; width:100%; height:100%">
19
+ <div class="rail"></div><div class="type"></div><div class="art"></div>
20
+ </div>
21
+ ```
22
+
23
+ - Fixed tracks (`520px`) hold content-sized cells. Fractions (`1fr`, `3fr`) share what is left.
24
+ - Animate a reflow from the frame, never from time: in a card, drive `grid-template-columns`
25
+ or `flex-basis` from `var(--cf-progress)` (or `--cf-enter`/`--cf-exit`); in a native template,
26
+ derive it from `render.frame`.
27
+ - Size the container to its region instead of CSS-`scale()`-ing the layout, which resamples.
28
+ Use `object-fit` for media in a cell.
29
+
30
+ ## Don't
31
+ - Don't expect a forked primitive to use rich named props — read `params` inside and use the explicit
32
+ `assets` and `render` bags for media and frame state.
33
+ - When a built-in fits the request, fork its exact snapshot using Path A. Never discard its
34
+ definition by copying only its template; preserve the definition and manifest too.
35
+ - Don't `create_component` a fresh id each fix iteration — `update_component` (same id) is the loop.
@@ -0,0 +1,98 @@
1
+ # Native component workflows
2
+
3
+ Choose the path exposed by the current host. Request schemas and the Component Contract own exact fields; these examples explain source and placement identity.
4
+
5
+ ## Path A — MCP agent (no filesystem; source lives server-side)
6
+
7
+ Use the live tool schema for request envelopes; hosted write fields are normally under `body`. When `get_composition` advertises `clipIds` and `response`, use selected clip IDs with `response:"full"` to retrieve the complete sources you need without pulling every large HTML body. Treat a projection as a partial read, never a replacement composition. Compact apply receipts retain the saved revision and warnings; reread relevant state before a dependent edit. Desktop surfaces may expose different fields.
8
+
9
+ 1. **Discover and read a built-in:** call `list_catalog` with
10
+ `projection: "component-library", origin: "builtin", libraryKind: "definition"`.
11
+ Select the intended card and preserve its complete scoped source reference. Call
12
+ `get_component_source` with that reference's `componentId`, `sourceVersionId`,
13
+ `builtinCollection` (its scope collection).
14
+ ID-only builtin reads are unsupported. An unavailable exact pin is a refusal; never
15
+ retry another scope or an unpinned head.
16
+ 2. **Author/own it:** edit the complete native `sourceSnapshot`; use your chosen owned ID
17
+ consistently in its `componentId` and the request. Send it as `body.source` to
18
+ `create_component`, with required metadata. Preserve its definition, capability
19
+ declarations, manifest and source format. For an existing component, keep its ID and
20
+ use `update_component` with the complete source. Do not send an old pin as the identity
21
+ of changed source: saving produces a new immutable source version.
22
+ 3. **Iterate (author→preview→fix):** `preview_component({ componentId, params })` queues a durable
23
+ preview and returns a `jobId`; call `wait_job(kind:"preview")`. The typed terminal result is a
24
+ verified artifact produced by the same bundle contract used by final render. A failed
25
+ `component_does_not_compile` job carries the compiler error — read it, fix via `update_component`
26
+ (same id, in place), and preview again.
27
+ **Adopt the source in the requested scope:** publication leaves existing placements pinned
28
+ to their previous versions; `placementsPinnedToPrevious` reports those uses. Source publication
29
+ plus placement adoption is not an atomic source-write operation. Read the current composition
30
+ and `describe_composition_ops`, then use the admitted `component.repin-v3` operation with complete
31
+ before/after execution references and the observed exact composition revision. Its historical
32
+ name also covers supported version-4 execution references. Preserve unrelated placements and
33
+ parameters. An unavailable placement capability is a refusal, not permission to bypass source
34
+ admission or substitute an unpinned head. Reinspect the adopted source in the saved timeline.
35
+ Set preview duration deliberately: `durationInFrames` is not a trim window and can retime
36
+ duration-dependent motion. Preserve production timing; inspect the live tool's request shape.
37
+ 4. **Check integration:** add it as a `{kind:'component', componentId, props:{},
38
+ execution:{version:4,componentId,sourceVersionId,params,seed,assets}, placement:{version:3,kind:'clip'}}` clip
39
+ (`apply_composition`), then inspect saved-composition stills or a scoped `preview_clip` for
40
+ placement and motion. Use `create_render` → `wait_job kind:"render"` when delivering a
41
+ finished MP4, not per tweak.
42
+
43
+ ## Path B — CLI / coding agent (customer-owned source under git)
44
+
45
+ Source lives in `cueframe/components/<id>/` (the `cueframe.json` workspace); edit the native
46
+ template locally, push to render.
47
+
48
+ ```bash
49
+ npx -y cueframe@0.11 init --json # scaffold cueframe.json + cueframe/components/
50
+ npx -y cueframe@0.11 new component my-badge --category ui-blocks --json # scaffold a component in the workspace
51
+ # New scaffolds contain template.html and definition.json (native source, version 4).
52
+ # …edit cueframe/components/<id>/template.html and definition.json in your editor…
53
+ npx -y cueframe@0.11 push my-badge --json # send the native source; the server admits it
54
+ # or: npx -y cueframe@0.11 sync --json # push every component in the workspace
55
+ # reference the component id in your composition, then render:
56
+ npx -y cueframe@0.11 render <projectId> -o ./out.mp4 --json
57
+ ```
58
+
59
+ The CLI writes `template.html` and `definition.json` (input schema, defaults, timing and
60
+ capabilities). `cueframe.json` → `components.<id>` holds the version-4 `manifest` and the catalog
61
+ `name` and `category`, which `push` requires; it refuses a component missing either.
62
+ `push`/`sync` send these as one native `source`, checked against the contract's source schema;
63
+ the server's admission (template lint, determinism, declarations) refuses with a named rule.
64
+ For a builtin fork, copy **all three parts** from the selected `sourceSnapshot`: template,
65
+ definition and manifest. A workspace component that still has a version-3 `index.tsx` is
66
+ refused as `component_source_retired` before any API call; author it again as a native template. To preview before
67
+ a full render, push it and use the appropriate component preview loop.
68
+
69
+ ## Path C — Director editing a local desktop project (project-embedded source)
70
+
71
+ When `get_context` reports the project lane as local, motion does not need an account or an org
72
+ component. Components here are native (source version 4) too:
73
+ - **New component:** open a draft with `open_component_preview`, passing `template`,
74
+ `component_manifest` (`{version:4, runtime:'hyperframes', hfContract:1, kind:'scene', assets,
75
+ graphics, alphaPolicy}`) and `component_definition`.
76
+ - **Existing component:** pass `component_id` instead, to start from the clip's pinned version or
77
+ the library version.
78
+
79
+ The draft is admitted in full: template lint, determinism and the variable declaration.
80
+ `data-composition-variables` must equal the definition's projection (its scalar inputSchema
81
+ properties, then the manifest's slots).
82
+
83
+ Edit the draft with `update_component_preview` (exact-text `{oldText, newText, replaceAll?}`
84
+ edits). Check exact frames with `render_component_preview_frame`, and inspect playback for motion.
85
+ `commit_component_preview` publishes the checked source to the library and pins the clip, and
86
+ returns the project's new ETag. `read_component` and `edit_component` read and edit the library
87
+ directly. Close the preview when finished.
88
+
89
+ Media slots are image or video, declared in `component_manifest.assets` and bound to project
90
+ media ids in `component_assets`. The template passes them to `MediaTileScene` as
91
+ `streams: { hero: { asset: assets.hero } }`. Declare `alphaPolicy` explicitly:
92
+ `requires-transparency` for overlays, `allows-opaque` for full-frame plates.
93
+
94
+ Every frame must be a pure function of `render.frame`, params and `render.seed`. Timers, `Date`,
95
+ network, imports, other globals and CSS animation are refused at admission. The timeline and final
96
+ export render the exact committed version. Use `create_component` only for a reusable org-catalog
97
+ component on a reachable cloud lane.
98
+
@@ -0,0 +1,54 @@
1
+ # Native version-4 source contract
2
+
3
+ Read this when authoring or changing a custom native component. Scene-shot JSON is a different contract served by `cueframe://scene-shot` or desktop `get_scene_contract`; it does not describe a custom component source. Live schemas and named admission errors govern supported fields.
4
+
5
+ Create and update components with a complete `source` object: `{version:4, componentId, template, manifest, definition}`. TSX (version 3) sources are retired: writing one is refused as `component_source_retired`. The definition declares input schema, defaults, timing, brand/media bindings and placement capabilities. The manifest is `{version:4, runtime:'hyperframes', hfContract:1, kind:'scene', assets, graphics, alphaPolicy}`: `assets` declares the media slots (only `image` and `video` slots), `graphics.api` is `webgl2` (or `webgl`), and `alphaPolicy` is `requires-transparency` or `allows-opaque`.
6
+
7
+ The `template` is one sub-composition. Every source is admitted before it is stored or rendered, and a refusal names the broken rule:
8
+ - `<template>` holds one root `<div id="root" data-composition-id="<componentId>" data-width="1920" data-height="1080" data-no-timeline data-composition-variables='…'>` containing one empty `<div data-cf-scene></div>` (and any static DOM of your own beside it), and one classic inline `<script>`.
9
+ - The script finds its root with `document.getElementById('root')`. The runtime scopes that lookup to each placed instance; a global `[data-composition-id]` selector is refused, because a component placed twice would find no root.
10
+ - `data-composition-variables` is the definition's projection: each scalar `inputSchema` property in schema order, then each manifest slot. `number`/`integer` → `{"id","type":"number","label","default","min","max"}` (min/max from minimum/maximum, omitted when absent); a property with `enum` → `{"type":"enum","default":"<as string>","options":[{"value","label"}]}`; `boolean` → `"boolean"`; a string whose `pattern` admits exactly `#RRGGBB` → `"color"`; any other string → `"string"`; an image slot → `{"id","type":"image","label":"<id>","default":""}`; a video slot → the same with `"type":"string"`. `label` is the property's `title`, else its id; `default` is `definition.defaults[id]`, else the schema default. Any difference is refused as `component_api_mismatch`.
11
+ - The script ends with exactly one `__cfScene.mount({ root: document.getElementById('root'), component: Name, variables: __hyperframes.getVariables() })`. `Name({ params, assets, render, durationInFrames })` returns `h(MediaTileScene, { streams, tiles, camera, fog, background })`, taken from `const { h, MediaTileScene, three } = __cfScene`: a description, not React. `render` is `{ frame, fps, width, height, seed }`. `params` holds only the keys the placement's `execution.params` sets, so read every param with its default as a fallback.
12
+ - Pass a declared slot as `streams: { hero: { asset: assets.hero } }` and place it with `tiles: [{ stream: 'hero', x, y, width, height }]` (pixels; x/y are the tile centre's offset from the frame centre, y down). Tiles also take `z`, `rotation`, `rotationX`, `rotationY` (degrees), `opacity`, `crop` and `renderOrder`; the camera takes `x`, `y`, `z`, `zoom` and `perspective`. Video streams take `trimBeforeFrames`, `trimAfterFrames`, `playbackRate` and `loop`. Audio belongs on composition audio tracks.
13
+ - The template lays out at its declared `data-width` × `data-height`, and the host scales that whole box to the rendered size: DOM beside the scene keeps its place and proportion at every size. The scene draws at the rendered size (`render.width` × `render.height`). A component without media passes `streams: {}` and no tiles; its scene presents its `background`.
14
+ - Every frame is a pure function of `render.frame`, `params` and `render.seed`. The script reads only its own declarations, `__cfScene`, `__hyperframes`, `document` and JavaScript built-ins such as `Math` and `JSON`. Timers, `Date`, `requestAnimationFrame`, `fetch`, `eval`, imports, `window` and other globals are refused (`component_v4_nondeterministic`, `component_import_denied`). The template has no `<img>`, `<video>`, `<link>` or `<iframe>`, no external or `data:` URL, and no CSS `transition`, `animation` or `@keyframes`. The template linter runs in sub-composition mode, and its errors refuse the source (`component_v4_lint_failed`).
15
+
16
+ Example: one image swinging flat over the clip. Its definition and manifest:
17
+
18
+ ```json
19
+ {
20
+ "definition": {
21
+ "inputSchema": { "type": "object", "additionalProperties": false, "properties": {
22
+ "background": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$", "default": "#101014" },
23
+ "tilt": { "type": "number", "minimum": 0, "maximum": 60, "default": 35 }
24
+ } },
25
+ "defaults": {}, "brandBindings": [], "timing": { "defaultDuration": { "frames": 90, "fps": 30 } }, "capabilities": [{ "kind": "clip" }]
26
+ },
27
+ "manifest": { "version": 4, "runtime": "hyperframes", "hfContract": 1, "kind": "scene",
28
+ "assets": { "hero": { "kind": "image", "required": true } },
29
+ "graphics": { "api": "webgl2", "required": true, "accelerationPreference": "hardware-preferred" }, "alphaPolicy": "allows-opaque" }
30
+ }
31
+ ```
32
+
33
+ Its template, with `componentId` `swing-hero`:
34
+
35
+ ```html
36
+ <template><div id="root" data-composition-id="swing-hero" data-width="1920" data-height="1080" data-no-timeline data-composition-variables='[{"id":"background","type":"color","label":"background","default":"#101014"},{"id":"tilt","type":"number","label":"tilt","default":35,"min":0,"max":60},{"id":"hero","type":"image","label":"hero","default":""}]'><div data-cf-scene></div></div><script>
37
+ const { h, MediaTileScene } = __cfScene;
38
+ function SwingHero({ params, assets, render, durationInFrames }) {
39
+ const t = Math.min(1, render.frame / Math.max(1, durationInFrames - 1));
40
+ const ease = 1 - Math.pow(1 - t, 3);
41
+ const tilt = Number.isFinite(params.tilt) ? params.tilt : 35;
42
+ return h(MediaTileScene, {
43
+ streams: { hero: { asset: assets.hero } },
44
+ tiles: [{ stream: 'hero', x: 0, y: 0, width: 1280, height: 720, rotationY: tilt * (1 - ease) }],
45
+ camera: { x: 0, y: 0, z: 0, zoom: 1, perspective: 1200 },
46
+ background: params.background ?? '#101014',
47
+ });
48
+ }
49
+ __cfScene.mount({ root: document.getElementById('root'), component: SwingHero, variables: __hyperframes.getVariables() });
50
+ </script></template>
51
+ ```
52
+
53
+ Place a component as a `{kind:'component', componentId, props:{}, execution:{version:4, componentId, sourceVersionId, params, seed, assets:{hero:'<mediaId>'}}, placement:{version:3, kind:'clip'}}` clip. Bind each slot to a project media id in `execution.assets`; a slot never travels in `params`.
54
+
@@ -0,0 +1,13 @@
1
+ {
2
+ "kind": "card",
3
+ "html": "<style>\n.cf-mounted-demo{position:relative;width:100%;height:100%;overflow:hidden;background:#e9edf5;font-family:Arial,sans-serif;color:#162033;--settle:clamp(0,calc(var(--cf-t)/var(--cf-settleSec)),1);--pose:calc(1 - (1 - var(--settle))*(1 - var(--settle))*(1 - var(--settle)));--approach:clamp(0,calc((var(--cf-t) - var(--cf-contactSec) + var(--cf-approachSec))/var(--cf-approachSec)),1);--response:clamp(0,calc((var(--cf-t) - var(--cf-contactSec))/var(--cf-responseSec)),1)}\n.cf-mounted-demo .stage{position:absolute;left:50%;top:50%;width:380px;height:720px;transform:translate(-50%,-50%);perspective:1400px}\n.cf-mounted-demo .phone{position:absolute;inset:0;border:10px solid #172032;border-radius:52px;background:#172032;box-sizing:border-box;box-shadow:18px 30px 45px #15263a30;transform:translateY(calc((1 - var(--pose))*120px)) rotateY(calc((1 - var(--pose))*var(--cf-tiltDeg)*1deg)) rotateZ(calc((1 - var(--pose))*-5deg))}\n.cf-mounted-demo .screen{position:absolute;inset:0;border-radius:40px;overflow:hidden;background:#fbfcff}\n.cf-mounted-demo .top{position:absolute;left:28px;right:28px;top:38px;font-size:24px;font-weight:700}\n.cf-mounted-demo .card{position:absolute;left:28px;right:28px;top:110px;height:182px;border-radius:18px;background:var(--cf-accent);color:white;box-shadow:0 9px 18px #16203328}\n.cf-mounted-demo .card:before{content:\"NORTH\";position:absolute;left:22px;top:24px;font-size:21px;font-weight:700;letter-spacing:3px}\n.cf-mounted-demo .holder:after{content:var(--cf-holder)}\n.cf-mounted-demo .holder{position:absolute;left:22px;bottom:24px;font-size:18px;letter-spacing:2px}\n.cf-mounted-demo .label{position:absolute;top:330px;left:28px;font-size:20px}\n.cf-mounted-demo .control{position:absolute;left:100px;top:400px;width:160px;height:70px;border:2px solid #b5bfd1;border-radius:18px;box-sizing:border-box;background:#eef2f9;display:grid;place-items:center;font-size:22px;font-weight:700}\n.cf-mounted-demo .frozen{position:absolute;inset:0;border-radius:16px;background:var(--cf-accent);color:white;display:grid;place-items:center;opacity:var(--response)}\n.cf-mounted-demo .pointer{position:absolute;left:180px;top:435px;width:36px;height:48px;background:#162033;clip-path:polygon(0 0,100% 65%,58% 68%,43% 100%);filter:drop-shadow(1px 3px 2px #15263a99);transform:translate(calc((1 - var(--approach))*95px),calc((1 - var(--approach))*80px));transform-origin:0 0}\n.cf-mounted-demo .status{position:absolute;left:28px;right:28px;top:530px;font-size:20px;line-height:1.4;opacity:var(--response)}\n</style><div class=\"cf-mounted-demo\"><div class=\"stage\"><div class=\"phone\"><div class=\"screen\"><div class=\"top\">Your card</div><div class=\"card\"><div class=\"holder\"></div></div><div class=\"label\">Card controls</div><div class=\"control\">Freeze<div class=\"frozen\">Frozen</div></div><div class=\"pointer\"></div><div class=\"status\">Payments are paused.<br>Your card is still here.</div></div></div></div></div>",
4
+ "tokens": {
5
+ "accent": "#4265d5",
6
+ "holder": "\"MAYA\"",
7
+ "settleSec": "1.0",
8
+ "tiltDeg": "28",
9
+ "contactSec": "2.0",
10
+ "approachSec": "0.65",
11
+ "responseSec": "0.2"
12
+ }
13
+ }
@@ -0,0 +1,25 @@
1
+ # Parented motion with an editable event clock
2
+
3
+ Use this example to keep mounted UI on one projected plane and make a cursor action retimeable. It is original CueFrame sample artwork under this repository's Apache-2.0 license, with no external assets. It is not a Cardly reproduction or a real app capture. For physical lighting, depth intersections or a moving 3D camera, use the scene-shot contract instead.
4
+
5
+ [Complete card source](parented-device-card.json) is a `kind:"card"` source object. Put it on an overlay clip at full-frame 1920×1080, 30 fps, duration 4 seconds; use the live `clip.add` schema for the surrounding operation. It includes an opaque full-duration background, so it is a complete scene plate. When using it over other content, remove that background intentionally rather than hoping it is transparent.
6
+
7
+ The `.phone` applies the pose once. Its `.screen` clips the card, text, control and pointer as mounted children. Their coordinates stay in phone space. No child independently counter-rotates to approximate the parent's pose. The pointer's top-left tip arrives at the control center `(180,435)` in screen coordinates.
8
+
9
+ The host supplies `--cf-t` in clip-local seconds. Tokens `settleSec`, `contactSec`, `approachSec` and `responseSec` determine arrival, pointer contact and response; the status and control use the same response phase. The sample keeps its readable state after settling and after contact. Changing `contactSec` shifts the approach and response together. Positive travel/response durations are required by its CSS divisions; keep contact after the approach and allow a readable hold before the clip ends.
10
+
11
+ `holder` is a CSS string token, so its value includes quote characters. Preserve it when editing the pose or timing. `accent` and `tiltDeg` control visible style and geometry. They are ordinary card tokens; built-in clock keys are not authored tokens.
12
+
13
+ For the initial proof, inspect the pose in travel, the settled plane, the frame before contact, the contact frame, the response and the last frame. Also inspect a motion preview across arrival and contact. After changing `contactSec`, check that the cursor and response move together, the holder remains, and the full scene still covers its duration. These are tests of this recipe's mechanism; use the reference's actual landmarks for a real film.
14
+
15
+ This CSS uses a fixed design-space phone inside a full-size card. Recompose for a different aspect/size instead of assuming this sample is responsive. Static layout fidelity, sampled motion and actual playback are distinct evidence. The validation record belongs with the produced preview artifact, not inside this reusable skill.
16
+
17
+ ## Fit and reuse the same object
18
+
19
+ For a reference-led device, compare the outer silhouette, screen corners and inset, then the mounted card and its typography. A correct bounding width can still hide the wrong perspective. Parenting keeps transforms together, but a child rendered on a different apparent plane can still contradict the device. Inspect a moving pose as well as the settled one before reusing the object across scenes.
20
+
21
+ Use a small set of editable properties for likely corrections: screen inset, card size, text scale, internal gap, pose and event times. A CSS font-size is not a measurement of visible cap height or text width. Calibrate those relationships from the rendered glyphs and preserve intentional copy adaptations. Do not turn every measured pixel into a global design token.
22
+
23
+ Publish a reusable native source once, then pass its exact version and relevant parameters to coauthors. Editing its source creates a new version; placed clips remain pinned to the old version. Explicitly adopt the fitted version in the intended placements through the available admitted composition operation, and inspect those uses. Source publication and placement adoption are separate operations; an isolated preview alone does not prove the timeline changed.
24
+
25
+ When several authors work on one project, existing clip guards cover the whole clip and its structural dependencies, not independent CSS fields. A shared source adoption or dependent timing revision needs current composition state. If another author or the user changed the target, reread and reconcile the intended edit; preserve their copy, timing and unrelated placements rather than replacing a stale document with a fresh token.
@@ -0,0 +1,26 @@
1
+ # Retired project sources
2
+
3
+ ## Upgrading an old project
4
+
5
+ `get_composition` returns `needsUpgrade` only when clips from before the native cutover remain:
6
+ `[{clipId, kind, componentId?, sourceVersionId?, primitiveId?, successorComponentId?,
7
+ successorSourceVersionId?}]`. Saves and renders refuse those clips. A retired component is
8
+ refused with `component_source_retired`, and a retired
9
+ primitive with `render_unknown_primitive`. Upgrade only the listed clips. Keep every other clip,
10
+ timing, track and brand-kit binding as it is.
11
+
12
+ - **Any entry with a `successorSourceVersionId`:** call `repin_component` with its clip ids. It
13
+ moves them to the native successor and keeps their saved inputs.
14
+ - **`v3-component` with no successor** (a custom pre-cutover component): read its source, params,
15
+ timing and placement, and author a native replacement with `create_component` as a version-4
16
+ template following the server instructions' Component Contract.
17
+ - **`unpinned-component`:** the clip carries a `retired` record (what was stored before the cutover), with its
18
+ props preserved. Re-author it from those props the same way.
19
+ - **`retired-primitive`:** rebuild what `primitiveId` drew from the clip's params, as a card or
20
+ a native component.
21
+
22
+ For each replacement, use `apply_composition` to replace only that clip at the same start,
23
+ duration, track and placement, pinned to the new exact `sourceVersionId`. Map the old params
24
+ onto the new inputs; do not invent new content. Verify each clip with `preview_frame` at a time
25
+ inside its window and confirm `needsUpgrade` is gone. Only then render (`create_render`).
26
+