cueframe 0.4.2 → 0.4.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 (32) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +42 -2
  3. package/dist/analyze-NKSULY3V.js +2 -0
  4. package/dist/chunk-CTELK3ZK.js +12 -0
  5. package/dist/chunk-MCQRX24V.js +2 -0
  6. package/dist/cueframe.js +109 -40
  7. package/{skills → dist/skills}/add-music-bed/SKILL.md +6 -16
  8. package/{skills → dist/skills}/brand-reel/SKILL.md +6 -16
  9. package/{skills → dist/skills}/clip-a-talking-head/SKILL.md +15 -19
  10. package/{skills → dist/skills}/composing-video/SKILL.md +21 -9
  11. package/{skills → dist/skills}/cueframe-brand-demo/SKILL.md +5 -0
  12. package/{skills → dist/skills}/cueframe-cli/SKILL.md +8 -2
  13. package/dist/skills/cueframe-component-authoring/SKILL.md +167 -0
  14. package/{skills → dist/skills}/cueframe-compose-loop/SKILL.md +38 -30
  15. package/dist/skills/cueframe-compose-loop/references/preview-workflow.md +37 -0
  16. package/dist/skills/cueframe-connect/SKILL.md +25 -0
  17. package/{skills → dist/skills}/cueframe-product-video/SKILL.md +11 -0
  18. package/dist/skills/cueframe-scene-shot/SKILL.md +66 -0
  19. package/{skills → dist/skills}/cueframe-storyboard/SKILL.md +6 -1
  20. package/{skills → dist/skills}/every-format-from-one-edit/SKILL.md +5 -16
  21. package/{skills → dist/skills}/extracting-brand-kits/SKILL.md +6 -3
  22. package/{skills → dist/skills}/launch-video/SKILL.md +5 -16
  23. package/{skills → dist/skills}/make-a-social-reel/SKILL.md +5 -15
  24. package/{skills → dist/skills}/rebrand-a-video/SKILL.md +5 -16
  25. package/{skills → dist/skills}/video-craft-standards/SKILL.md +10 -3
  26. package/dist/supportedAgents.js +1 -1
  27. package/package.json +17 -15
  28. package/dist/analyze-6QSD7KHH.js +0 -2
  29. package/dist/chunk-3QSA3EBY.js +0 -2
  30. package/dist/chunk-7TCLKYUZ.js +0 -12
  31. package/skills/_connect.md +0 -29
  32. package/skills/cueframe-component-authoring/SKILL.md +0 -68
@@ -20,22 +20,8 @@ cuts moved onto its beat grid. Attribution included, levels disciplined, one re-
20
20
  ## Before you start
21
21
 
22
22
  Listen first — identify what audio the composition already has before proposing anything. When
23
- the first tool call approaches and CueFrame isn't connected:
24
-
25
- <!-- cueframe:connect -->
26
- - **Claude Code:** offer to run
27
- `claude mcp add --transport http cueframe https://api.cueframe.ai/v1/mcp` — a browser
28
- opens and the user clicks **Allow**. No API key.
29
- - **Claude.ai / Claude Desktop:** Settings → Connectors → add a custom connector with
30
- `https://api.cueframe.ai/v1/mcp`.
31
- - **Other agents (Cursor, Codex, VS Code, Windsurf, Zed, Gemini CLI, Copilot CLI, …):**
32
- run `npx -y cueframe install` — it detects what is on the machine and wires each one.
33
- - **ChatGPT:** the CLI cannot wire it (there is no local config to write) — add
34
- `https://api.cueframe.ai/v1/mcp` as a custom connector instead.
35
- - **No account at all (pay-per-call):** connect
36
- `https://api.cueframe.ai/v1/mcp/x402` — no sign-up, no API key; priced calls
37
- settle per-call in USDC over x402 from the agent's wallet.
38
- <!-- /cueframe:connect -->
23
+ the first tool call approaches and CueFrame isn't connected, load **`cueframe-connect`** and
24
+ follow it once.
39
25
 
40
26
  Then back to the soundtrack — this is usually a one-sitting job.
41
27
 
@@ -51,6 +37,10 @@ Then back to the soundtrack — this is usually a one-sitting job.
51
37
 
52
38
  ## Workflow
53
39
 
40
+ Use `cueframe-compose-loop`'s [preview workflow](../cueframe-compose-loop/references/preview-workflow.md).
41
+ Listen to a scoped `preview_clip` across speech, ducking, fades, and beat changes before final
42
+ delivery; stills and a visual judge cannot establish the mix. Recheck visuals where cuts moved.
43
+
54
44
  1. **Read the composition and its speech.** `list_compositions` / the composition body for
55
45
  what's on the timeline; `get_media_context` for transcripts. Speech present → the voice is
56
46
  the rhythm authority and the bed serves it. No speech → the bed IS the rhythm authority and
@@ -12,22 +12,8 @@ beat, tagline lockup — where every graphic could belong to this brand and no o
12
12
  ## Before you start
13
13
 
14
14
  Talk brand first — palette, type, the one line they'd put on a poster — before any setup. When
15
- the first tool call approaches and CueFrame isn't connected:
16
-
17
- <!-- cueframe:connect -->
18
- - **Claude Code:** offer to run
19
- `claude mcp add --transport http cueframe https://api.cueframe.ai/v1/mcp` — a browser
20
- opens and the user clicks **Allow**. No API key.
21
- - **Claude.ai / Claude Desktop:** Settings → Connectors → add a custom connector with
22
- `https://api.cueframe.ai/v1/mcp`.
23
- - **Other agents (Cursor, Codex, VS Code, Windsurf, Zed, Gemini CLI, Copilot CLI, …):**
24
- run `npx -y cueframe install` — it detects what is on the machine and wires each one.
25
- - **ChatGPT:** the CLI cannot wire it (there is no local config to write) — add
26
- `https://api.cueframe.ai/v1/mcp` as a custom connector instead.
27
- - **No account at all (pay-per-call):** connect
28
- `https://api.cueframe.ai/v1/mcp/x402` — no sign-up, no API key; priced calls
29
- settle per-call in USDC over x402 from the agent's wallet.
30
- <!-- /cueframe:connect -->
15
+ the first tool call approaches and CueFrame isn't connected, load **`cueframe-connect`** and
16
+ follow it once.
31
17
 
32
18
  Then pick the brand conversation back up where it paused — connection is the smallest step in
33
19
  this job.
@@ -43,6 +29,10 @@ this job.
43
29
 
44
30
  ## Workflow
45
31
 
32
+ Use `cueframe-compose-loop`'s [preview workflow](../cueframe-compose-loop/references/preview-workflow.md)
33
+ for stills and motion windows. For a small revision, preserve the approved arc and inspect the
34
+ affected behavior and regressions; reserve full-film judging and export for the relevant review/delivery.
35
+
46
36
 
47
37
  0. **Find the claim (before anything else).** Interrogate the brand/material
48
38
  for its tension — what it believes that its category doesn't — and write
@@ -12,22 +12,8 @@ dead air, and caption every word from the real transcript.
12
12
  ## Before you start
13
13
 
14
14
  Get the source URL and what "best moment" means to the user before any setup ceremony. When the
15
- first tool call is close and CueFrame isn't connected:
16
-
17
- <!-- cueframe:connect -->
18
- - **Claude Code:** offer to run
19
- `claude mcp add --transport http cueframe https://api.cueframe.ai/v1/mcp` — a browser
20
- opens and the user clicks **Allow**. No API key.
21
- - **Claude.ai / Claude Desktop:** Settings → Connectors → add a custom connector with
22
- `https://api.cueframe.ai/v1/mcp`.
23
- - **Other agents (Cursor, Codex, VS Code, Windsurf, Zed, Gemini CLI, Copilot CLI, …):**
24
- run `npx -y cueframe install` — it detects what is on the machine and wires each one.
25
- - **ChatGPT:** the CLI cannot wire it (there is no local config to write) — add
26
- `https://api.cueframe.ai/v1/mcp` as a custom connector instead.
27
- - **No account at all (pay-per-call):** connect
28
- `https://api.cueframe.ai/v1/mcp/x402` — no sign-up, no API key; priced calls
29
- settle per-call in USDC over x402 from the agent's wallet.
30
- <!-- /cueframe:connect -->
15
+ first tool call is close and CueFrame isn't connected, load **`cueframe-connect`** and follow it
16
+ once.
31
17
 
32
18
  Then straight back to hunting the moment — setup is a footnote, not a phase.
33
19
 
@@ -43,6 +29,10 @@ Then straight back to hunting the moment — setup is a footnote, not a phase.
43
29
 
44
30
  ## Workflow
45
31
 
32
+ Use `cueframe-compose-loop`'s [preview workflow](../cueframe-compose-loop/references/preview-workflow.md).
33
+ Watch/listen across changed cuts and caption/subject motion with `preview_clip`. For a small
34
+ correction, retain the approved edit and check relevant regressions without automatically exporting.
35
+
46
36
  1. **Import and read.** `import_media` the recording, wait for ready, then `get_media_context`
47
37
  — the transcript with word timings and the face roster (with `faceId`s and speaking share)
48
38
  are your whole map. For an assisted hunt, `suggest_briefs` proposes clip candidates from the
@@ -63,13 +53,19 @@ Then straight back to hunting the moment — setup is a footnote, not a phase.
63
53
  6. **Captions from the real transcript.** `captions.fromTranscript` with the mediaId and the
64
54
  clip's window; style via `setCaptionStyle` — plated, high-contrast, never over the mouth or
65
55
  eyes. Where the footage allows, put the emphasized keyword BEHIND the speaker as an overlay
66
- clip at `zPlane:"behind-subject"` (the caption layer itself carries no zPlane) — the
67
- signature depth move.
56
+ clip at `zPlane:"behind-subject"` — the focused signature depth move. If the user explicitly
57
+ wants every running caption behind the speaker, set the caption layer's own
58
+ `zPlane:"behind-subject"`; that choice resolves cutouts across every captioned source window.
68
59
  7. **Decide the audio — required.** Speech is the spine here, but decide the rest: a subtle bed
69
60
  from `search_resources` honoring the brand kit's `musicMood`, ducked under the voice — or
70
61
  intentional speech-only, recorded with its reason in the delivery note. Either is fine;
71
62
  defaulted silence is not.
72
- 8. **Preview, judge, render once per clip.** `preview_frame` at t=0 and each cut; describe each
63
+ 8. **Prepare the subject evidence.** If `get_media_context.faces.status` is `not_detected`, call
64
+ `prepare_media` with `kind:"subjectTrack"` and the clip's exact SOURCE trim window; if the
65
+ edit has `zPlane:"behind-subject"`, prepare `kind:"matte"` for that same window. Poll
66
+ `get_media_facts` with kind + startSec + endSec until `exact.state:"ready"`. A flattened
67
+ depth title or ignored speaker crop is not preview evidence.
68
+ 9. **Preview, judge, render once per clip.** `preview_frame` at t=0 and each cut; describe each
73
69
  still (is the framed person the one talking? is the top of the head in frame?).
74
70
  `score_composition` with the clip's claim as `editorialIntent`; fix worst-first to ≥ 7.5,
75
71
  then `create_render` → `wait_job (kind:"render")`.
@@ -5,6 +5,12 @@ description: Use when an agent is asked to make ANY video with CueFrame — a pr
5
5
 
6
6
  # Composing Video: craft for CueFrame
7
7
 
8
+ For preview selection and small revisions, use `cueframe-compose-loop`'s
9
+ [preview workflow](../cueframe-compose-loop/references/preview-workflow.md). Retain the approved
10
+ brief/rubric for a local correction; check the affected behavior and relevant regressions instead
11
+ of restarting the new-film method below. A diagnostic or preview-only request does not require
12
+ a final export or a whole-film judge pass. Explicit user scope takes precedence over craft defaults.
13
+
8
14
  > **The bar:** the `video-craft-standards` skill (GET /v1/skills/video-craft-standards) defines DONE for every artifact class — per-class MUST checklists and kill criteria. Read it before composing and score against it before rendering. When this skill and that document disagree, the standards win.
9
15
 
10
16
  ## The one idea
@@ -31,6 +37,7 @@ This skill is the **craft / quality layer** for an agent driving CueFrame over t
31
37
  - **`cueframe-product-video`** — the click-points → reframe-segment **auto-zoom tiling** + picture-in-picture recipe for screen demos.
32
38
  - **`cueframe-brand-demo`** — brand-token vocabulary + auto intro/outro/logo for branded launches.
33
39
  - **`cueframe-component-authoring`** — the full fork → preview → push loop for custom components.
40
+ - **`cueframe-scene-shot`** — the 3D product shot authored as JSON (a tilted page screenshot, a lit laptop/phone showing a real app screenshot, camera move, focus). Reach for it *before* hand-writing a WebGL component for a device mockup.
34
41
 
35
42
  Loading this skill and a sibling together: this one governs *what makes the video good*; the sibling governs *how that mechanic works*.
36
43
 
@@ -95,17 +102,19 @@ Do not fake the missing footage, and do not dress up generic filler as grounding
95
102
  ### 4 — Author against `get_media_context`
96
103
  When you have imported media, pull the detected **faces** (subject boxes per frame, with `faceId`s) and **transcript** before composing. Align reframe/punch-in to the faces, caption words to the transcript timing, and cut points to the speech. Discover primitives with `list_catalog` before hand-placing hex and coordinates — a built-in almost always exists.
97
104
 
105
+ If `faces.status` is `not_detected` and the edit uses `active-speaker`/`face` framing, call `prepare_media` with `kind:"subjectTrack"` and the clip's exact SOURCE trim window, then poll `get_media_facts` with that same kind/window until `exact.state:"ready"`. Do the same with `kind:"matte"` before sighting a `zPlane:"behind-subject"` graphic. `preview_frame` and `score_composition` fail loud when required perception is unresolved; never treat a flattened title or a static wide crop as acceptable preview evidence.
106
+
98
107
  ### 5 — Iterate on REAL PIXELS (and prove you looked)
99
- `preview_frame` PNG stills at your rubric's named timestamps — **always including t=0 and hook-end** — and **look at them**. (Sessionless; if a cold first call returns 409 box_warming, retry in a few seconds.)
108
+ `preview_frame` PNG stills at your rubric's named timestamps — **always including t=0 and hook-end** — and **look at them**. It queues durable capture and returns a `jobId`; call `wait_job(kind:"preview_frame")` until the evidence is terminal.
100
109
 
101
110
  For every still, before you score it, write one literal line of what is visible: *Is there a grounded subject (real footage, real UI/data, or a purposeful content-specific graphic)? Real UI, or a styled div? Is the background mostly empty decoration? Is the text legible over what's behind it? Does any on-screen number match its written source?* If you can't describe the pixels, you did not look — render again. Score only from these descriptions, never from what you intended to author. Grade the first frame hardest: if t=0 is a bare gradient with the product name, K1 trips and you're done.
102
111
 
103
112
  `validate_composition` only checks shape (membership, params, track-family, reframe coverage) — a pass there means nothing about quality. Judge the pixels, not the JSON.
104
113
 
105
114
  ### 6 — Get an independent second opinion, then stop
106
- You grading your own render is the weak link. Call `score_composition` (sessionless — the warm box is a server detail) with your VISION line as `editorialIntent` and brand facts as `brandContext`. It renders and grades **four fixed server-side criteria** — editorial, spatial, brand, caption (0–10 each) — plus a weighted composite and a worst-first critique, **on frames it samples itself.** Your `editorialIntent` steers *what "good" means for this video*; it does **not** replace the criteria, and you cannot feed it your own rubric or pick its frames — that un-gameable sampling *is* the independence. Treat a low score on a frame you didn't choose as ground truth, not noise.
115
+ You grading your own render is the weak link. Call `score_composition` with your VISION line as `editorialIntent` and brand facts as `brandContext`, then call `wait_job(kind:"verify")`. It renders and grades **four fixed server-side criteria** — editorial, spatial, brand, caption (0–10 each) — plus a weighted composite and a worst-first critique, **on frames it samples itself.** Your `editorialIntent` steers *what "good" means for this video*; it does **not** replace the criteria, and you cannot feed it your own rubric or pick its frames — that un-gameable sampling *is* the independence. Treat a low score on a frame you didn't choose as ground truth, not noise.
107
116
 
108
- Fix the worst thing via `apply_composition`, re-render the affected frames, re-score. **Budget 3–5 verify passes** (two no-improvement passes = diminishing returns — `cueframe-compose-loop` owns the full convergence loop). Ship only when your own rubric passes with zero kill criteria tripped AND the `score_composition` composite ≥ 7.5 — not when you get bored. (No session to close — the warm box is a server detail that reaps itself.)
117
+ Fix the worst thing via `apply_composition`, preview the affected frames and motion, and re-score when useful. For a whole-film review, budget up to 3–5 verify passes; two no-improvement passes are a reason to stop spending and report remaining gaps (`cueframe-compose-loop` owns the convergence loop). The rubric's acceptance criteria still apply; a score around 7.5 is guidance, not permission to ship a known mismatch. Hosted preview and scoring are stateless durable jobs; there is no hosted session to close.
109
118
 
110
119
  ---
111
120
 
@@ -159,10 +168,10 @@ Chromium captures; the clock never advances). Use these instead:
159
168
  2. **`transitionIn` on any overlay clip** — `{ transitionIn: { type: "fade", duration: 0.4 } }`
160
169
  now applies to overlay-family clips (cards, components, primitives), not just video.
161
170
  Use it for entrances; author exits in-card via `--cf-exit`.
162
- 3. **`applyMotionPreset` op** — shell a static card into a live motion component in one op:
171
+ 3. **`applyMotionPreset` op** — shell a static card into a frame-driven component in one op:
163
172
  `{ type: "applyMotionPreset", clipId, preset }` (unknown presets are rejected with the
164
173
  full preset list). The layout stays verbatim; the preset adds entrance/idle/exit
165
- choreography. The result is a live component you can `get_component_source` and refine.
174
+ choreography. The result is a component you can `get_component_source` and refine.
166
175
 
167
176
  ---
168
177
 
@@ -494,10 +503,10 @@ Each playbook is a **floor**, not a template — reason above it. Every beat map
494
503
  | Craft goal | Do this in CueFrame |
495
504
  |---|---|
496
505
  | Bring in the real thing | `import_media` — requires `url` (public https) + `filename` + `contentType` (from the fixed enum: `video/mp4`, `video/quicktime`, `image/png`, `audio/mpeg`, …). Poll `list_media` or `create_webhook` on `media.completed` (status inside: complete|failed). |
497
- | Know where subject + speech are | `get_media_context` → face boxes per frame (with `faceId`) + transcript |
506
+ | Know where subject + speech are | `get_media_context` → face boxes per frame (with `faceId`) + transcript. If faces are not detected, `prepare_media(kind:"subjectTrack", intent:{startSec,endSec})` → poll `get_media_facts` for the same SOURCE window until ready. |
498
507
  | Keep the speaker framed / punch-in | `setCropIntents` op (the PREFERRED authoring path) or inline `reframe.segments` on a `clip.add` source. Each segment needs `startSec`/`endSec`/`focus`/`zoom`; **segments must TILE the clip** (an uncovered span → `reframe_coverage_gap` at validate). `focus.mode`: `frame-center` \| `point{x,y}` \| `face{faceId, shotScale?: close\|standard\|wide}` \| `all-faces` \| `active-speaker`. `zoom<1` punches in, `=1` full frame, `>1` rejected (min 0.1). Times in **seconds**. |
499
- | Captions that track real speech | `composition.captions.segments[].words[]` = `{text, startMs, endMs, emphasis?, annotate?: circle\|underline}` — word times in **milliseconds**. Author the words directly with the `setCaptions` op (segments wholesale — how a generated-VO film gets its word-synced spine without a source transcript); style via `setCaptionStyle`: `position` (top\|center\|bottom), `entrance` (fade\|word-pop\|stagger-up), `emphasisPlate` + plate colors for legibility. **Captions have NO `zPlane`.** |
500
- | Text behind the speaker's head | An `overlay` clip (a title/label primitive) with `zPlane:"behind-subject"` — NOT the caption layer. Render bakes the person matte + handles occlusion. |
508
+ | Captions that track real speech | `composition.captions.segments[].words[]` = `{text, startMs, endMs, emphasis?, annotate?: circle\|underline}` — word times in **milliseconds**. Author the words directly with the `setCaptions` op (segments wholesale — how a generated-VO film gets its word-synced spine without a source transcript); style via `setCaptionStyle`: `position` (top\|center\|bottom), `entrance` (fade\|word-pop\|stagger-up), `emphasisPlate` + plate colors for legibility. Captions default to front; set top-level `composition.captions.zPlane:"behind-subject"` only when the user wants the whole caption layer behind the speaker. It resolves person cutouts for every overlapping source window and degrades visibly to front where the legibility gate refuses the effect. |
509
+ | Text behind the speaker's head | An `overlay` clip (a title/label primitive) with `zPlane:"behind-subject"`. This is the focused hero treatment; caption-layer depth is a separate whole-layer choice. Before preview/judgment, `prepare_media(kind:"matte", intent:{startSec,endSec})` for the overlapping clip's SOURCE trim and poll `get_media_facts` until ready. Render also resolves the person cutout on miss. |
501
510
  | Name someone / label a step | `lower-third` scene from `list_catalog` |
502
511
  | Title / closing wordmark | `cinematic-title` scene (closing, not opening) |
503
512
  | Grade the look | `color-grade` scene/effect |
@@ -506,11 +515,14 @@ Each playbook is a **floor**, not a template — reason above it. Every beat map
506
515
  | Auto-reframe to another aspect | `derive_composition` (content-aware 9:16 / 1:1 / 4:5 from a 16:9 master) |
507
516
  | Discover what to build with | `list_catalog` — over MCP it takes **NO input params**, so the FULL live catalog + your installed components returns, and you filter the RESULT **client-side** by `category`/`kind`/`tier`/`useCase`/`mood`/`intent`. Each entry carries `placement` (how to author it), `tier`/`useCase`, and `fixedCopy` (baked text no param changes). Read `cueframe://component/{id}` for the full **prop schema**. |
508
517
  | Own / fork a custom graphic | `get_component_source` / `create_component` (self-contained tsxSource) / `update_component` — **see `cueframe-component-authoring`** for the full fork→preview→push loop |
518
+ | Several cells that share space and must reflow together (feature grid, rail + fluid content, cast + type) | An authored component on `FlexLayout` from `@cueframe/animate` — tracks are **weights** (`{ weight: 0, basis: px }` = content-sized, pushes neighbours), `tracksEnd` animates the reflow per frame, `fits` per cell (`stretch`/`contain`/`cover`/`position`/`scale`/`matte`). Static PiP / split is clip `region` + `fit` instead. Never CSS-scale the layout. **See `cueframe-component-authoring`** |
509
519
  | Seed + edit the timeline | `apply_composition` (atomic batch ops; `dry_run:true` to check, `if_match` for OCC) — this is where clips, reframe, captions, and format are authored |
510
520
  | Set the brand | `create_brand_kit` (402-gated) → set `brandKitId` on the **project** (`create_project` / `update_project`). It lives on the project, NOT on a composition op — trying to set it elsewhere is silently dropped. |
511
521
  | Shape-check (NOT quality) | `validate_composition` → `{ valid, errors[] }` (`unknown_primitive`, `invalid_primitive_params`, `clip_source_track_mismatch`, `reframe_coverage_gap`, …); does **not** check trim bounds or image-on-video-track (those fail at save/render) |
512
522
  | Look at real pixels | `preview_frame` at timestamps → PNG stills → LOOK |
513
- | Preview one graphic | `preview_component` (async motion clip: 202 + jobId → `wait_job(kind:"preview")`; compile errors land on the job's failed terminal with the author-fixable message) |
523
+ | Judge motion or audio timing | `preview_clip` for the affected `[fromSec, toSec)` window → `wait_job(kind:"render")` → watch/listen; use matching reference timestamps |
524
+ | Check an isolated card | `preview_card` with its HTML and tokens; no scratch composition needed |
525
+ | Preview one graphic | `preview_component` (202 + jobId → `wait_job(kind:"preview")`; returns the verified artifact from the same immutable bundle used by production; compile/runtime/capability errors land on the job's failed terminal with the author-fixable message) |
514
526
  | Independent grade (steered, un-gameable) | `score_composition` (sessionless; `editorialIntent`=your vision, `brandContext`=brand facts) → four fixed criteria + composite + worst-first critique, on frames it samples itself |
515
527
  | Director ensemble compose | `compose` — set EXACTLY ONE of `fromComposition:true` (author from the seeded composition) or `suggestionId` (clipping path) → `wait_job(kind:"compose")` |
516
528
  | Final MP4 | `create_render` → `wait_job(kind:"render")` or `create_webhook` on `render.completed`; `retry_render` (transient only) / `cancel_render` |
@@ -31,6 +31,11 @@ Two things make this different from `cueframe-product-video`:
31
31
  Drive the primitives with the `cueframe-cli` skill and converge with
32
32
  `cueframe-compose-loop`; this tells you *what brand-demo to author*.
33
33
 
34
+ Use the compose-loop [preview workflow](../cueframe-compose-loop/references/preview-workflow.md)
35
+ for iteration. Check brand/layout with stills and motion with `preview_clip`; a small revision
36
+ does not require rerunning the Director or exporting the whole film. The pipeline below is for
37
+ a new finished demo; choose the self-driven loop when the user has not asked for Director authoring.
38
+
34
39
  ## The pipeline
35
40
 
36
41
  ```
@@ -35,6 +35,12 @@ schema is the source of truth.
35
35
  The general path for any agent. Author the timeline yourself and render it — no
36
36
  clip suggestion required.
37
37
 
38
+ For iteration, use `cueframe-compose-loop`'s [preview workflow](../cueframe-compose-loop/references/preview-workflow.md).
39
+ Validate first, then use `preview_card` / `preview_component` for isolated graphics,
40
+ `preview_frame` for composition stills, or `preview_clip` for a motion window. Use the available
41
+ MCP tools or the CLI's `api` escape hatch with the live request contract. Full `render` is for
42
+ delivery, not checking each edit. CLI validation does not replace visual evidence.
43
+
38
44
  ```bash
39
45
  # 0. Always use --json for agent-driven runs (NDJSON to stdout, no spinners).
40
46
  # Commands run against production; auth is stored in ~/.cueframe/auth.json.
@@ -174,7 +180,7 @@ npx -y cueframe new component my-badge --json
174
180
  # cueframe/components/my-badge/index.tsx as your starting point.
175
181
 
176
182
  # 3. Edit cueframe/components/<id>/ — it's standard Remotion. The component is mounted
177
- # ({ durationInFrames, params }) at render; params are your composition's clip params.
183
+ # ({ durationInFrames, params, assets, render }) at render; declare its v2 manifest.
178
184
 
179
185
  # 4. Publish to CueFrame so it can render (uploads index.tsx as the component's tsxSource).
180
186
  npx -y cueframe push my-badge --json # one component
@@ -190,7 +196,7 @@ npx -y cueframe render <projectId> -o ./out.mp4 --json
190
196
  | Need to… | Command |
191
197
  |---|---|
192
198
  | See every command + flags | `npx -y cueframe describe --json` |
193
- | (Re)install/update this skill | `npx -y cueframe install` (→ `~/.claude/skills/cueframe-cli`) |
199
+ | Install/refresh managed skills | `npx -y cueframe install` (shared `~/.agents/skills` and Claude `~/.claude/skills`; locally changed or untracked packages are preserved and reported) |
194
200
  | List projects | `npx -y cueframe list -n 50` |
195
201
  | List your media | `npx -y cueframe clips` (no mediaId arg) |
196
202
  | Discover the live composition schema | `npx -y cueframe schema composition` |
@@ -0,0 +1,167 @@
1
+ ---
2
+ name: cueframe-component-authoring
3
+ description: Use when authoring, forking, or customizing a CueFrame motion-graphics component/primitive/graphic — e.g. "customize the cinematic-title primitive", "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 through the same component-v2 contract. Use BEFORE hand-writing a component from scratch — forking a built-in is usually the faster start.
4
+ ---
5
+
6
+ # CueFrame component authoring (fork / customize / own)
7
+
8
+ Use `cueframe-compose-loop`'s [preview workflow](../cueframe-compose-loop/references/preview-workflow.md)
9
+ to select hosted or local evidence and separate iteration from final delivery.
10
+
11
+ CueFrame ships 87 built-in motion-graphics **primitives** (titles, lower-thirds, captions,
12
+ effects, transitions, scenes). You can **fork any of them as editable source**, customize it,
13
+ and render it on CueFrame — or author a brand-new component. This is shadcn-for-video: own the
14
+ component code; CueFrame is the reliable engine that renders it.
15
+
16
+ **Before you hand-write 3D:** a device mockup or a screenshot floating in a lit 3D scene is a
17
+ **scene shot** — validated JSON with `scene.add` / `scene.update`, not a component you author.
18
+ See the `cueframe-scene-shot` skill and `cueframe://scene-shot`. Author a component here when
19
+ you need behaviour the scene contract does not express.
20
+
21
+ **The two facts that shape everything:**
22
+ - A component is mounted through contract v2 as
23
+ **`({ durationInFrames, params, assets, render }) => JSX`**. `render` contains frame, fps,
24
+ dimensions, deterministic seed, and color space. A from-scratch component must default-export
25
+ this shape; older components may ignore the added properties.
26
+ - Neither renderer runs authored component source in the editor process. Hosted org components are
27
+ baked in an isolated box. A local project compiles source in a separate headless-Chromium child
28
+ process, pins the immutable source version in the project, and uses that version for the editor and export.
29
+
30
+ ## Path A — MCP agent (no filesystem; source lives server-side)
31
+
32
+ Single self-contained module per component (`create_component` takes one `tsxSource`).
33
+
34
+ 1. **Fork a built-in:** `get_component_source(componentId: "cinematic-title")` → returns the
35
+ primitive's editable single-module `tsxSource` (the named component + the adapter). Discover
36
+ ids from the catalog (`/v1/components`). *(Or author from scratch — skip to step 2.)*
37
+ 2. **Author/own it:** edit the `tsxSource`, declare its v2 `manifest`, then call
38
+ `create_component({ componentId, tsxSource, manifest, … })` to store your customer-owned copy.
39
+ If forked, `ejectedFrom` is stamped.
40
+ 3. **Iterate (author→preview→fix):** `preview_component({ componentId, params })` queues a durable
41
+ preview and returns a `jobId`; call `wait_job(kind:"preview")`. The typed terminal result is a
42
+ verified artifact produced by the same bundle contract used by final render. A failed
43
+ `component_does_not_compile` job carries the compiler error — read it, fix via `update_component`
44
+ (same id, in place), and preview again.
45
+ Set preview duration deliberately: `durationInFrames` is not a trim window and can retime
46
+ duration-dependent motion. Preserve production timing; inspect the live tool's request shape.
47
+ 4. **Check integration:** add it as an `alpha-layer` clip (`apply_composition`), then inspect
48
+ saved-composition stills or a scoped `preview_clip` for placement and motion. Use
49
+ `create_render` → `wait_job kind:"render"` when delivering a finished MP4, not per tweak.
50
+
51
+ ## Path B — CLI / coding agent (customer-owned source under git)
52
+
53
+ Source lives in `cueframe/components/<id>/` (the `cueframe.json` workspace); edit locally as
54
+ standard Remotion, push to render.
55
+
56
+ ```bash
57
+ npx -y cueframe init --json # scaffold cueframe.json + cueframe/components/
58
+ npx -y cueframe new component my-badge --json # scaffold a component in the workspace
59
+ # to start from a built-in instead of a blank file: fetch its source with the
60
+ # `get_component_source` tool and paste it into cueframe/components/my-badge/index.tsx
61
+ # …edit cueframe/components/<id>/ in your editor (standard Remotion)…
62
+ npx -y cueframe push my-badge --json # upload index.tsx as the component tsxSource
63
+ # or: npx -y cueframe sync --json # push every component in the workspace
64
+ # reference the component id in your composition, then render:
65
+ npx -y cueframe render <projectId> -o ./out.mp4 --json
66
+ ```
67
+
68
+ The CLI writes a 3-file layout (`index.tsx` = renderable module + adapter; `_config.ts` + `config.ts`
69
+ = local workspace metadata). `push` sends `index.tsx` as the single `tsxSource` — the same shape the
70
+ MCP path stores. To preview before a full render, push it and use the MCP `preview_component` loop.
71
+
72
+ ## Path C — Director editing a local desktop project (project-embedded source)
73
+
74
+ When `get_context` reports the project lane as local, motion does not require an account or an org
75
+ component. When exposed, use `open_component_preview` to compile an isolated preview,
76
+ `update_component_preview` to replace its source, and `render_component_preview_frame` for exact
77
+ frame evidence. Inspect playback for motion; `commit_component_preview` commits the checked revision
78
+ with a fresh ETag. Close the preview when finished. This loop does not bake a timeline video and
79
+ does not imply HMR: source updates still compile.
80
+
81
+ If those tools are unavailable, add/update through `apply_composition` and inspect the local
82
+ timeline. An inline custom overlay has this shape:
83
+
84
+ ```json
85
+ {
86
+ "type": "clip.add",
87
+ "clip": {
88
+ "id": "local-motion",
89
+ "kind": "overlay",
90
+ "startTime": 0,
91
+ "duration": 3,
92
+ "source": {
93
+ "kind": "overlay",
94
+ "primitiveId": "custom",
95
+ "params": {
96
+ "jsxSource": "export default function Graphic({ durationInFrames, params, assets, render }) { ... }",
97
+ "componentManifest": { "version": 2, "assets": {}, "graphics": { "api": "canvas2d", "required": true, "accelerationPreference": "software-allowed" }, "alphaPolicy": "requires-transparency" },
98
+ "componentAssets": {}
99
+ }
100
+ }
101
+ },
102
+ "newTrack": true
103
+ }
104
+ ```
105
+
106
+ The desktop compiles the module in an isolated child process and persists its immutable source version.
107
+ The timeline and final export render that exact version; no preview media is baked. A compile failure
108
+ refuses the whole batch and leaves the composition untouched. Use `create_component` only for a reusable
109
+ org-catalog component on a reachable cloud lane.
110
+
111
+ For media-backed graphics, declare each slot in `componentManifest.assets`, bind the slot to a
112
+ project media id in `componentAssets`, and read its request-scoped handle from `assets`. The renderer
113
+ localizes and hashes the file before execution. Remote URLs, undeclared assets, arbitrary filesystem
114
+ paths, WebGL substitution, and static/card substitution are not fallback paths.
115
+
116
+ Declare `componentManifest.alphaPolicy` explicitly: `requires-transparency` for overlays and
117
+ `allows-opaque` for intentional full-frame plates. Both adapters verify the same field.
118
+
119
+ Normal static imports are supported only from the runtime allowlist: React, Remotion, Three.js
120
+ WebGPU/TSL, React Three Fiber/Drei, Remotion Three, and CueFrame animation helpers. Use ordinary hooks,
121
+ loops, refs, constructors, typed arrays, canvas, and WebGPU when needed. Drive visible animation from
122
+ `render.frame`/`render.fps` and seed variation from `render.seed`; ambient time/randomness is refused.
123
+
124
+ ## Choosing what to fork
125
+ The catalog (`/v1/components`) gives each primitive's `description` / `useWhen` / `tags` / `mood` /
126
+ `tier` / `useCase` / `examples` (example params) + `propSchema` + its source via `get_component_source`.
127
+ Read the spec + the code to pick a starting point. (Rendered preview thumbnails are a separate
128
+ follow-up — today you choose from prose + params + source, or compose+`preview_frame` to see it.)
129
+
130
+ ## Layout inside a component — `FlexLayout` / `solveFlex`
131
+ When a graphic has several cells that must share space — a feature grid, a fixed rail beside
132
+ fluid content, a cast of objects next to type — don't hand-place pixels. The layout helpers
133
+ are in `@cueframe/animate` (on the import allowlist):
134
+
135
+ ```tsx
136
+ import { FlexLayout } from '@cueframe/animate';
137
+ const R = params.region ?? { x: 0, y: 0, w: 1, h: 1 };
138
+ <FlexLayout
139
+ tracks={[{ weight: 0, basis: 520 }, 1, { weight: 3, split: [1, 1] }]}
140
+ tracksEnd={[{ weight: 0, basis: 520 }, 1, { weight: 1, split: [2, 1] }]}
141
+ fits={[{ mode: 'stretch' }, { mode: 'position' }, { mode: 'matte', aspect: 1 }, { mode: 'stretch' }]}
142
+ gap={16} width={R.w * width} height={R.h * height}>
143
+ <Rail /> <Type /> <Art /> <Block />
144
+ </FlexLayout>
145
+ ```
146
+
147
+ - Tracks are **weights, not pixels**; `{ weight: 0, basis: 520 }` is content-sized and pushes its
148
+ neighbours. Children fill the leaves depth-first (a `split` nests cells on the other axis).
149
+ - `tracksEnd` animates: weights ease across the clip and **every cell re-solves per frame**. A cell
150
+ present on only one side enters from / exits to zero. Layout is the motion — no keyframed positions.
151
+ - `fits`, one per leaf: `stretch | contain | cover | position | scale | matte`. `position` keeps type at
152
+ its natural size; `matte` clips a window instead of resizing the art.
153
+ - Inside a `params.region` container pass `width`/`height` = the region's pixel size so nested splits and
154
+ aspect fits solve against the region, not the frame. **Never CSS-`scale()` the layout** — it resamples;
155
+ size the container instead.
156
+ - 3D in the same rig: `solveFlex(tree, size, weights)` returns the boxes; `flexBoxToThree(box, size)`
157
+ centres a mesh under `<ThreeCanvas orthographic>` (frustum pinned 1:1 to pixels), so one canvas holds
158
+ every object exactly on its cell.
159
+ - Same inputs, same boxes everywhere: the solve is pure and yoga-backed; nothing is measured from the DOM.
160
+ Text is placed, not measured — declare sizes with `basis` when a cell must fit its content.
161
+
162
+ ## Don't
163
+ - Don't expect a forked primitive to use rich named props — read `params` inside and use the explicit
164
+ `assets` and `render` bags for media and frame state.
165
+ - Don't hand-roll a graphic from zero when a built-in is close — fork it (fetch the source with
166
+ `get_component_source`, paste it into a `npx -y cueframe new component` scaffold) and edit.
167
+ - Don't `create_component` a fresh id each fix iteration — `update_component` (same id) is the loop.
@@ -5,23 +5,27 @@ description: Use when an AI agent should DRIVE CueFrame to a high-quality clip i
5
5
 
6
6
  # CueFrame — Compose convergence loop
7
7
 
8
- > **LANE SCOPE:** this skill is written against the DESKTOP/REST compose-session surface. Over MCP those endpoints do not exist — use the `composing-video` skill (sessionless judge/preview) instead; this document is reference for the REST lane only.
9
-
10
-
11
8
  You are the director. CueFrame gives you hands (author), eyes (capture), and a
12
9
  judge (verify); you supply the taste and the iteration. The engine does NOT
13
10
  auto-compose for you here — you drive the loop and decide when it's done. Drive
14
11
  the primitives with the `cueframe-cli` skill; this tells you *how to converge*.
15
12
 
13
+ Before choosing a preview or export, read [preview-workflow.md](references/preview-workflow.md).
14
+ It owns hosted/local routing, bounded motion evidence, and the distinction between a small edit
15
+ and final delivery. For a minor revision, keep the approved brief and inspect the changed behavior
16
+ plus relevant regressions; do not restart the full planning/judging loop below.
17
+
16
18
  ## The loop
17
19
 
18
20
  ```
19
- get_context → author → capture (look) → verify (score)
20
- ↑ │
21
- └──── fix the WORST criterion ──┘ → stop → render
21
+ get_context → author → scoped preview (look) → judge if useful
22
+ ↑ │
23
+ └──────── fix the WORST criterion ──────┘ → stop → render
22
24
  ```
23
25
 
24
- Run it on a warm **session** (one boot, many fast renders), not one-shot renders.
26
+ Hosted preview and scoring are durable, stateless jobs. Keep their job IDs and
27
+ wait for each terminal result; there is no hosted render box to open, warm, or close.
28
+ Use the local live-preview tools when working in a desktop project that exposes them.
25
29
 
26
30
  ## 0. Context — always first
27
31
 
@@ -44,24 +48,23 @@ are `.strict()`: a typo'd key is rejected, not silently dropped, so read the
44
48
  error and fix the key. Reference faces from get_context in your reframe segments;
45
49
  time captions/overlays from the transcript word timings.
46
50
 
47
- ## 2. Open a session
48
-
49
- `POST /v1/projects/:id/compose-session` → `{ sessionId }`. Boots a warm render box
50
- (~60–120s the first time). Reuse it for every capture/verify in the loop; close
51
- it (`DELETE …/:sessionId`) when done — it also self-reaps at its TTL.
52
-
53
- ## 3. Capture — look at it
51
+ ## 2. Preview — look at it
54
52
 
55
- `POST /v1/projects/:id/compose-session/:sessionId/render` with `{ composition,
56
- timestamps }` → stills, each with a presigned `url` you can actually view. Look at
57
- the beats you're unsure about (a cut, an overlay entrance, the hook). Stills are
58
- real render output — what you see is what ships.
53
+ Use the curated `preview_frame` MCP tool, or
54
+ `POST /v1/projects/:id/preview-frame-jobs`, with the composition target and the
55
+ timestamps you need to inspect. The operation returns `{ jobId }` immediately.
56
+ Call `wait_job({ kind: "preview_frame", id: jobId })`, then view the image artifact
57
+ URLs in the successful result. Look at the beats you're unsure about: a cut, an
58
+ overlay entrance, or the hook. The stills are real render evidence, not continuous-motion proof.
59
+ Use `preview_clip` for the affected composition window to judge cuts, entrances, camera movement,
60
+ and audio timing; use `preview_component` or `preview_card` for isolated authoring checks.
59
61
 
60
- ## 4. Verify — score it
62
+ ## 3. Score it
61
63
 
62
- `POST /v1/projects/:id/compose-session/:sessionId/verify` with `{ composition,
63
- editorialIntent?, brandContext? }`. CueFrame's judge samples the meaningful beats,
64
- renders them, and returns:
64
+ Use `score_composition`, or `POST /v1/projects/:id/score-composition`, with the
65
+ composition target plus optional `editorialIntent` and `brandContext`. It returns
66
+ `{ jobId }`; call `wait_job({ kind: "verify", jobId })`. CueFrame's judge samples
67
+ the meaningful beats, renders them, and returns:
65
68
 
66
69
  ```
67
70
  { perCriterion: { editorial, spatial, brand, caption } each { score 0–10, critique },
@@ -83,18 +86,23 @@ You get **scores and the critique, never the rubric** — the taste is CueFrame'
83
86
  Pass `editorialIntent` (your brief/hook) so editorial is graded against what you
84
87
  meant.
85
88
 
86
- ## 5. Fix the worst — then re-verify
89
+ ## 4. Fix the worst — then re-score
87
90
 
88
91
  Read `critique` — it names the lowest criterion first and says why. Fix **that one
89
- thing** (re-author the relevant ops), then verify again. One criterion per pass:
92
+ thing** (re-author the relevant ops), then score again. One criterion per pass:
90
93
  chasing all four at once thrashes. Example: editorial 4 "two subjects off-center
91
- vs centered intent" → tighten the reframe onto face-0 → re-verify.
94
+ vs centered intent" → tighten the reframe onto face-0 → re-score. A layout critique
95
+ ("cramped", "unbalanced", "text crowds the art") on a component built with
96
+ `FlexLayout` is a `tracks` weight or `fits` change — re-author those and re-solve; never
97
+ nudge pixels (see `cueframe-component-authoring`).
92
98
 
93
- ## 6. Stop — then render
99
+ ## 5. Stop — then render
94
100
 
95
- Stop when **composite ≥ ~7.5** OR a pass doesn't improve the composite (two
96
- no-improvement passes = diminishing returns; ship the best so far). Then render
97
- the final: `createRender` (see `cueframe-cli`) → MP4.
101
+ For a whole-film review, use **composite ≥ ~7.5** as a guide alongside the brief's actual
102
+ acceptance criteria. Two no-improvement passes are a reason to stop spending and report what
103
+ remains, not to declare a rejected result approved. Render with `create_render` only when a
104
+ finished video is requested or the work reaches final delivery. A scoped revision can end with
105
+ verified preview evidence and an explicit note that no new final export was made.
98
106
 
99
107
  ## Notes
100
108
 
@@ -102,5 +110,5 @@ the final: `createRender` (see `cueframe-cli`) → MP4.
102
110
  infra (capture/render) + the judge. That's the point — you keep the orchestration.
103
111
  - **Don't re-derive the judge or beat sampling** — verify owns both. Your job is
104
112
  author → read scores → fix worst → repeat.
105
- - **Budget the loop:** 3–5 verify passes is plenty for most clips. If composite
113
+ - **Budget the loop:** 3–5 scoring passes is plenty for most clips. If composite
106
114
  won't climb, the limiter is usually the source or the intent, not more passes.
@@ -0,0 +1,37 @@
1
+ # Preview, iteration, and delivery
2
+
3
+ Choose the evidence for the current request. A small revision is not a new-film workflow. Preserve the approved brief, timeline, and unaffected source; inspect the affected behavior and relevant regressions. Export when the user requests a finished video or the work reaches final delivery, not after every preview or parameter edit.
4
+
5
+ ## Select the available lane
6
+
7
+ Read the current tool contracts and project context. Do not infer a hosted session from a local desktop tool, or require cloud registration for a local project.
8
+
9
+ | Need | Hosted evidence | Local desktop evidence, when exposed |
10
+ |---|---|---|
11
+ | Isolated HTML card layout | `preview_card` with the card's HTML and tokens | Inspect the card in the local project |
12
+ | Authored component layout or motion | `preview_component`, with explicit dimensions, FPS, params, assets, and appropriate duration | `open_component_preview` → `update_component_preview`; inspect playback and `render_component_preview_frame` at exact frames |
13
+ | Saved composition layout and overlap | `preview_frame`, batching the needed timestamps | The local composition preview/capture tools |
14
+ | Cuts, entrances, camera motion, or audio timing | `preview_clip` for the affected `[fromSec, toSec)` window, including its lead-in and settle | Play/seek the affected window; capture matching frames when needed |
15
+ | Finished deliverable | `create_render` and verify the resulting file | The project's export path and verification of its resulting file |
16
+
17
+ Hosted calls use `projectId` and the request shape declared by the live tool. `preview_component` returns a job ID: wait with `kind:"preview"`. `preview_frame` uses `kind:"preview_frame"`. `preview_clip` returns a render job: wait with `kind:"render"`, even though it is a preview. Reuse the returned job ID; do not submit duplicate jobs while waiting. Hosted evidence jobs do not require opening or warming a compose session.
18
+
19
+ The local component preview compiles replacement source revisions; it is not a promise of browser HMR or zero compilation work. `commit_component_preview` commits the inspected revision with a fresh project ETag. An isolated preview does not itself edit the saved timeline. Close the preview when finished if that tool is available.
20
+
21
+ ## Bound the work without changing the animation
22
+
23
+ - Use a component's existing params for supported changes; update its source in place only when necessary. Do not create a new component ID for each tweak.
24
+ - `durationInFrames` sets the component's render duration; it is **not a generic trim window**. Shortening it can retime animations normalized over duration. Preserve production timing. Use a documented component-specific offset only if it preserves that timing, or use the saved composition's `preview_clip` window. `startFrame` is not a universal preview API parameter.
25
+ - Preserve FPS when judging motion. Choose resolution for the question: a low-resolution motion preview may establish timing but not typography, glass edges, or final-resolution shader quality. Use appropriate stills for those details.
26
+ - Batch related still timestamps. Build contact sheets from returned images for inspection; a grid is a presentation of sampled frames, not proof of continuous motion. Watch the critical window as well. Listen when the change affects sound.
27
+ - Scope output and compute are different: a short composition preview can still trigger preparation or an alpha bake on a cache miss. Inspect progress/receipts before diagnosing cost. Do not promise instant previews, cross-job cache hits, or that every requested still requires a full bake.
28
+
29
+ ## Evidence and stopping
30
+
31
+ Keep component source revision/hash, params, asset bindings, dimensions, FPS, requested frames/window, and returned artifact/job identity together. For hosted composition parity, inspect `previewed.source`, composition ID, and ETag where provided. Source can change without changing the composition ETag. Unchanged pixels outside an edit's visible frame range do not by themselves prove a stale cache.
32
+
33
+ Compare affected frames and motion with the reference at matching timestamps. Keep isolated-component proof distinct from saved-composition proof and final-export proof. For a minor edit, stop once the requested behavior and relevant regressions are checked; report the preview and explicitly say if no new final export was made.
34
+
35
+ Use `score_composition` for broader editorial/brand review when useful and within budget. Do not require repeated whole-film judging to verify a known local correction. A judge score does not override a failed acceptance criterion or the user's visual feedback.
36
+
37
+ Check account balance and current quotes before metered hosted work. Record actual job charges separately for preview, judging, and final export; separate those from agent time/token cost and from infrastructure estimates. Compare workflows only after testing equivalent changes and evidence requirements. Existing previews should be exercised before proposing new infrastructure.