cueframe 0.1.0 → 0.2.0

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.
@@ -0,0 +1,248 @@
1
+ ---
2
+ name: cueframe-brand-demo
3
+ description: Use when turning a local app into a brand-consistent product demo with CueFrame — extract the brand straight from the repo (colors/fonts/logo/motion), capture a Playwright walkthrough of the running app, and author a branded, auto-zoomed demo whose intro/outro/logo/colors/fonts/motion are frozen by CueFrame's engine — e.g. "make an on-brand demo of my app", "record my localhost and produce a branded launch video". This is the end-to-end brand pipeline over the CueFrame curated tools.
4
+ ---
5
+
6
+ # CueFrame — Brand demo recipe
7
+
8
+ A **use-case recipe** that runs end-to-end from inside the user's own project
9
+ folder. You (Claude) already see their code and their running app — that's the
10
+ unfair advantage. This skill turns that context into a brand-consistent product
11
+ video: pull the brand from the repo, capture the app, and author a demo whose
12
+ **brand identity is enforced by the engine**, not re-typed per clip.
13
+
14
+ Two things make this different from `cueframe-product-video`:
15
+
16
+ 1. **The brand is real engine state.** A `brandKit` (created with
17
+ `create_brand_kit`) carries colors / fonts / spacing / sizing / motion / logo
18
+ / intro / outro / watermark. A composition references it by `brandKitId`;
19
+ **render freezes it** — intro/outro bumpers are auto-prepended/appended, and
20
+ every overlay that binds a `$brand:` token resolves against the kit. Edit the
21
+ kit, re-render, the whole video re-themes. You don't hand-paint brand colors
22
+ onto each clip.
23
+ 2. **Drive CueFrame directly — Vaaya-free.** Brand consistency is a first-class
24
+ CueFrame capability now. Don't reach for an external generator to "make it
25
+ look branded"; author the intent against the brand kit and let render
26
+ materialize it.
27
+
28
+ Drive the primitives with the `cueframe-cli` skill and converge with
29
+ `cueframe-compose-loop`; this tells you *what brand-demo to author*.
30
+
31
+ ## The pipeline
32
+
33
+ ```
34
+ extract brand (repo + live UI) → create_brand_kit
35
+ → capture (Kishu: Playwright walkthrough of localhost → MP4) → import_media
36
+ → get_media_context (faces + transcript)
37
+ → apply_composition (edit plan + brand template, refs brandKitId + $brand:)
38
+ → compose { fromComposition:true } → wait_job kind:compose
39
+ → create_render → wait_job kind:render → branded MP4
40
+ ```
41
+
42
+ ## 1. Extract the brand → `create_brand_kit`
43
+
44
+ You are running in the user's project. Read the brand out of the codebase
45
+ instead of asking for it:
46
+
47
+ - **Colors** — `tailwind.config.*` `theme.extend.colors`, CSS custom properties
48
+ (`:root { --primary … }`), a `design.md` / tokens file, or the rendered UI.
49
+ - **Fonts** — `@font-face` / `next/font` / `<link>` declarations, the Tailwind
50
+ `fontFamily` map, and which family is headings vs body.
51
+ - **Logo** — `public/`/`assets/` SVG/PNG; host it at a public https URL (or
52
+ `import_media` it and use the resulting URL) so render can fetch it.
53
+ - **Spacing / sizing / radius** — the Tailwind scale, `--radius`, base font sizes.
54
+ - **Voice** — README / landing copy → a one-paragraph `voiceGuidelines`.
55
+
56
+ Synthesize and call `create_brand_kit`. The accepted shape (Phase 1 — the kit now
57
+ carries full brand identity, not just colors/fonts):
58
+
59
+ ```jsonc
60
+ {
61
+ "kitId": "acme", // caller-chosen stable id (re-POST upserts in place)
62
+ "name": "Acme",
63
+ "tagline": "Ship faster",
64
+ "colors": { // REQUIRED — all five
65
+ "primary": "#4F46E5", "secondary": "#0EA5E9", "accent": "#22C55E",
66
+ "background": "#0B0B0F", "text": "#FAFAFA"
67
+ },
68
+ "headingFont": { "fontFamily": "Geist", "fontWeight": 700 },
69
+ "bodyFont": { "fontFamily": "Inter", "fontWeight": 400 },
70
+ "voiceGuidelines": "Confident, plain-spoken, no hype.",
71
+ "motion": { "duration": 0.4, "easing": "ease-out", "entrance": "stagger-up", "staggerMs": 60 },
72
+ "logo": { "src": "https://…/logo.svg", "placement": "br", "sizePct": 8 },
73
+ "intro": { "kind": "card", "title": "Acme", "subtitle": "Ship faster", "durationMs": 1500 },
74
+ "outro": { "kind": "card", "title": "acme.dev", "durationMs": 2000 },
75
+ "watermark": { "src": "https://…/mark.svg", "opacity": 0.6, "placement": "br" },
76
+ "spacing": { "base": 16, "lg": 32, "sm": 8 },
77
+ "sizing": { "fontSizeHeading": 64, "fontSizeBody": 28, "borderRadius": 12 }
78
+ }
79
+ ```
80
+
81
+ `colors{primary,secondary,accent,background,text}`, `headingFont`, `bodyFont`,
82
+ `name`, `kitId` are required; everything else is optional. The response returns the
83
+ kit `id` — that's the `brandKitId` you'll reference. **Show the founder the
84
+ synthesized kit and let them override** before composing; the kit is the brand
85
+ contract for every clip.
86
+
87
+ ## 2. Capture → one clean MP4
88
+
89
+ Record a walkthrough of the **running local app** with Kishu: a headed Playwright
90
+ script drives `localhost`, native screen-record captures it, and you get one
91
+ CFR / faststart MP4 plus the cursor/click events (timed viewport coordinates —
92
+ the focus points the auto-zoom follows; see `cueframe-product-video` §1–2). Use
93
+ your codebase knowledge to script the walkthrough: open the real flows that
94
+ matter, click the features worth showing, pause on results.
95
+
96
+ Get the recording into CueFrame with `import_media` (public https URL) — it's
97
+ async; poll `list_media` for `processingStatus:"ready"` (or register
98
+ `create_webhook` on `media.completed`). Keep the click points; you'll map them onto
99
+ the rendered duration for the zoom.
100
+
101
+ ## 3. Context → `get_media_context`
102
+
103
+ `get_media_context` returns **faces** (subject roster + `speakingShare`, for any
104
+ talking-head/presenter beat) and the **transcript** (per-word `start`/`end` for
105
+ caption timing). Combine it with what you already know from the code — you can
106
+ script and interpret the demo better than transcript-alone, because you know what
107
+ each screen *is*.
108
+
109
+ ## 4. Author the seed composition → `apply_composition`
110
+
111
+ Author the edit plan **and** the brand template in one composition, then reference
112
+ the kit by `brandKitId`. Two layers:
113
+
114
+ **a. The edit plan** (same craft as `cueframe-product-video`): the screen
115
+ recording on a video track carrying `reframe` punch-ins from the click points
116
+ (`autoZoom` output — `frame-center` in the gaps, `point` over each click),
117
+ optional speed, and transcript-timed `captions`.
118
+
119
+ **b. The brand template** — overlays that bind `$brand:` tokens so they resolve
120
+ against the kit at render:
121
+
122
+ | Goal | how |
123
+ |---|---|
124
+ | intro / outro card | **automatic** — the kit's `intro`/`outro` are prepended/appended at render. Don't author bumper clips. |
125
+ | logo bug | **automatic** — the kit's `logo` is painted as a corner mark at render (placement/size from the kit; it lifts above the caption band). Don't author a logo overlay. |
126
+ | lower-third / title | `lower-third` or `heroText` overlay, colors/fonts bound to `$brand:` tokens |
127
+ | captions | top-level `captions` — themed by the kit's `captionProfile` + `syncCaptions` (don't bind `$brand:` in `captions.style`; captions resolve through the profile, not token refs) |
128
+ | motion identity | overlays inherit `$brand:motion.*`; the kit's entrance/timing drive the feel |
129
+
130
+ The `$brand:` vocabulary (the frozen token paths render resolves) — bind these,
131
+ never hardcode brand hexes/fonts:
132
+
133
+ - **colors** — `$brand:colors.{background,surface,card,text,textMuted,textOnMedia,border,accent,accentMuted,textOnAccent,textOnSurface}`.
134
+ Text **over footage** → `$brand:colors.textOnMedia` (the legible-over-video slot).
135
+ - **fonts** — `$brand:fonts.heading.family`, `$brand:fonts.body.family`, `$brand:fonts.caption.family`.
136
+ - **motion** — `$brand:motion.{duration,easing,entrance,staggerMs,exitMs}`.
137
+ - **spacing / sizing** — `$brand:spacing.{base,lg,sm}`, `$brand:sizing.{fontSizeHeading,fontSizeBody,fontSizeLabel,borderRadius}`.
138
+
139
+ An unset brand-driven slot on a text overlay auto-binds to its token (you don't
140
+ have to spell out every one); spell out the ones you care about. A `$brand:` ref
141
+ that doesn't resolve is **loud** in render logs and a contrast-critical text color
142
+ falls to a legible neutral — it never silently ships an off-brand frame.
143
+
144
+ Set `brandKitId` at the top of the composition. `apply_composition` with
145
+ `dry_run:true` validates the batch without persisting — validate before you
146
+ compose.
147
+
148
+ ### Worked example — branded seed composition (16:9)
149
+
150
+ `brandKitId` ties the kit in; the intro/outro/logo come from the kit
151
+ automatically (NOT authored here); the `lower-third` binds `$brand:` tokens and
152
+ the `captions` are themed by the kit's `captionProfile`. Swap `<…>` for real ids;
153
+ durations are illustrative — match your source.
154
+
155
+ ```json
156
+ {
157
+ "v": 1,
158
+ "format": { "aspectRatio": "16:9", "fps": 30 },
159
+ "brandKitId": "<brandKitId>",
160
+ "tracks": [
161
+ {
162
+ "id": "v-screen", "kind": "video", "contents": [
163
+ {
164
+ "id": "rec", "startTime": 0, "duration": 12,
165
+ "source": {
166
+ "kind": "media", "mediaId": "<screenMediaId>",
167
+ "reframe": { "segments": [
168
+ { "startSec": 0, "endSec": 2, "focus": { "mode": "frame-center" }, "zoom": 1 },
169
+ { "startSec": 2, "endSec": 5, "focus": { "mode": "point", "x": 0.28, "y": 0.42 }, "zoom": 0.6, "ease": { "in": 0.4, "out": 0.4 } },
170
+ { "startSec": 5, "endSec": 7, "focus": { "mode": "frame-center" }, "zoom": 1, "ease": { "in": 0.4, "out": 0.4 } },
171
+ { "startSec": 7, "endSec": 10, "focus": { "mode": "point", "x": 0.72, "y": 0.66 }, "zoom": 0.55, "ease": { "in": 0.4, "out": 0.4 } },
172
+ { "startSec": 10, "endSec": 12, "focus": { "mode": "frame-center" }, "zoom": 1, "ease": { "in": 0.4, "out": 0.4 } }
173
+ ] }
174
+ }
175
+ }
176
+ ]
177
+ },
178
+ {
179
+ "id": "ov", "kind": "overlay", "contents": [
180
+ {
181
+ "id": "title", "startTime": 1, "duration": 3.5,
182
+ "source": {
183
+ "kind": "overlay", "primitiveId": "lower-third",
184
+ "params": {
185
+ "text": "One-command deploys", "subtitle": "Acme", "variant": "modern",
186
+ "tokens": {
187
+ "textColor": "$brand:colors.textOnMedia",
188
+ "accentColor": "$brand:colors.accent",
189
+ "fontFamily": "$brand:fonts.heading.family"
190
+ }
191
+ }
192
+ }
193
+ }
194
+ ]
195
+ }
196
+ ],
197
+ "captions": {
198
+ "segments": [
199
+ { "words": [
200
+ { "text": "Ship", "startMs": 0, "endMs": 360 },
201
+ { "text": "in", "startMs": 360, "endMs": 520 },
202
+ { "text": "one", "startMs": 520, "endMs": 760, "emphasis": true },
203
+ { "text": "command", "startMs": 760, "endMs": 1300 }
204
+ ] }
205
+ ]
206
+ }
207
+ }
208
+ ```
209
+
210
+ ## 5. Refine + judge → `compose { fromComposition: true }`
211
+
212
+ Hand the seed to the Director: `compose` with `{ fromComposition: true }`
213
+ authors an ensemble of candidates from your seed, runs the **server-side judge —
214
+ including the brand axis** (on-brand color/type/voice cohesion), and saves the
215
+ winner. Returns a `composeJobId`; `wait_job` `kind:"compose"` (or a webhook on
216
+ `compose.completed`). The result carries the winner's composite score — verification
217
+ is built in. Pass your brief as `editorialIntent` so editorial is graded against
218
+ what you meant. (To self-drive the loop instead, see `cueframe-compose-loop`.)
219
+
220
+ ## 6. Render → branded MP4
221
+
222
+ `create_render` → `wait_job` `kind:"render"` (or a webhook on `render.completed`)
223
+ for the download URL. The output is brand-frozen: the kit's **intro/outro** bumper
224
+ the video, the **logo** bug sits in its corner, **motion** drives the overlay
225
+ entrances, and every `$brand:` color/font is resolved. Verify the output (sample
226
+ frames) before declaring done.
227
+
228
+ ## Notes / honesty
229
+
230
+ - **The brand kit is the source of truth — edit it, re-render, re-theme.** Brand
231
+ values are resolved at render from the `brandKitId`-referenced kit, so a
232
+ `create_brand_kit` upsert (same `kitId`) re-themes every existing composition
233
+ that points at it. Don't bake brand hexes/fonts into clips.
234
+ - **Intro / outro / logo are NOT clips you author** — they live on the kit and
235
+ the engine places them at render (intro prepended, outro appended, logo painted
236
+ as a corner mark). A srcless/absent bumper or logo reserves/draws nothing (soft)
237
+ — it's just skipped, never an error.
238
+ - **`watermark` is accepted by `create_brand_kit` and persisted, but render does
239
+ NOT yet auto-composite the kit's watermark asset** (the only watermark painted
240
+ today is CueFrame's product mark). Set it for forward-compat, but don't promise
241
+ the founder a custom watermark in the output yet.
242
+ - **Drive CueFrame directly.** This whole recipe is Vaaya-free: the brand, the
243
+ capture, the compose, the render are all CueFrame. Reach for an external
244
+ generator only for footage CueFrame genuinely can't produce — not to "make it
245
+ look branded," which is the engine's job now.
246
+ - This recipe lives in a skill on purpose: the engine stays use-case-free; the
247
+ product opinions (what to extract, which overlays, how to brand) live here and
248
+ ship via `cueframe install`.
@@ -27,7 +27,7 @@ clip suggestion required.
27
27
 
28
28
  ```bash
29
29
  # 0. Always use --json for agent-driven runs (NDJSON to stdout, no spinners).
30
- # This build connects to a fixed environment — no target flag needed.
30
+ # Commands run against production; auth is stored in ~/.cueframe/auth.json.
31
31
 
32
32
  # 1. Register media (one or many — mixed video / image / audio).
33
33
  cueframe upload "/path/to/source.mp4" --json # → mediaItemId (process_complete)
@@ -145,6 +145,36 @@ composition from a suggestion instead of you hand-writing it.
145
145
 
146
146
  Pipe `--json` output through `jq -c 'select(.event=="…")'` to grab specific lifecycle events.
147
147
 
148
+ ## Component authoring — fork a built-in primitive or scaffold your own
149
+
150
+ Own the motion-graphics components you render (shadcn-style): fork a built-in CueFrame
151
+ primitive as editable source, customize it, and render it on CueFrame — or scaffold a blank
152
+ one. The source lives in your repo under version control; CueFrame bakes it to a transparent
153
+ video and composites it (the shared renderer never runs your code).
154
+
155
+ ```bash
156
+ # 1. Scaffold a workspace (writes cueframe.json + cueframe/components/). Idempotent.
157
+ cueframe init --json
158
+
159
+ # 2a. FORK a built-in primitive into cueframe/components/<id>/ as owned, editable source.
160
+ # Discover ids from the catalog: cueframe api GET /v1/components (87 primitives).
161
+ cueframe eject cinematic-title --json
162
+
163
+ # 2b. …or scaffold a blank custom component.
164
+ cueframe new component my-badge --json
165
+
166
+ # 3. Edit cueframe/components/<id>/ — it's standard Remotion. The component is mounted
167
+ # ({ durationInFrames, params }) at render; params are your composition's clip params.
168
+
169
+ # 4. Publish to CueFrame so it can render (uploads index.tsx as the component's tsxSource).
170
+ cueframe push cinematic-title --json # one component
171
+ cueframe sync --json # every component in the workspace
172
+
173
+ # 5. Reference the component id in your composition (as an alpha-layer clip), then render
174
+ # with the same verb. Preview a single component first via the MCP preview_component loop.
175
+ cueframe render <projectId> -o ./out.mp4 --json
176
+ ```
177
+
148
178
  ## Quick reference
149
179
 
150
180
  | Need to… | Command |
@@ -162,12 +192,12 @@ Pipe `--json` output through `jq -c 'select(.event=="…")'` to grab specific li
162
192
  | Anything not wrapped | `cueframe api GET /v1/... -i` (escape hatch, like `gh api`) |
163
193
  | Validate a composition without mutating | `cueframe composition validate -b @plan.json` |
164
194
 
165
- ## Targets and auth
195
+ ## Auth
166
196
 
167
- **This build connects to a fixed CueFrame environment.** The `-t` / `--target`, `--url`, and `CUEFRAME_API_URL` inputs are accepted but **ignored** — there is no environment to select. Authenticate once:
197
+ Commands run against production. Authenticate once:
168
198
 
169
- - `cueframe auth <cf_test_… key>` — save a static API key (CI / headless).
170
199
  - `cueframe login` — OAuth device flow (laptops).
200
+ - `cueframe auth <cf_live_… key>` — save a static API key (CI / headless).
171
201
 
172
202
  Creds are stored in `~/.cueframe/auth.json`; the key can also come from the `CUEFRAME_API_KEY` env var.
173
203
 
@@ -186,15 +216,16 @@ Errors come as `{"event":"error", "phase":"<step>", "message":"...", "code":"...
186
216
  | Mistake | Reality |
187
217
  |---|---|
188
218
  | Reaching for `curl …/v1/...` because the CLI didn't have a command | Use `cueframe api METHOD /v1/...` — same auth, same JSON pipeline. |
189
- | Passing `-t` / `--url` to switch environment | No-op. The target is fixed for this release; those inputs are ignored. |
190
219
  | Polling for render completion with a sleep loop | `cueframe render` already SSE-watches and exits when done. Use `render watch <id>` to reattach. |
191
220
  | Skipping `--json` and trying to parse human output | Human output is for humans. Agents always use `--json`. |
192
221
  | Hand-editing the composition without an ETag | `composition put` GETs the ETag for you; `from-suggestion` rebuilds from a clip. Don't hand-craft unless you have to. |
193
222
  | Calling `cueframe render <projectId> <suggestionId>` (old two-positional shape) | `render` takes ONLY a projectId; commander rejects the extra arg. It renders the SAVED composition — author it first via `composition put` (hand-author) or `project create --from-suggestion <sug>` (clip-finder on-ramp). |
194
223
  | Assuming `render` needs a clip suggestion / that captions only come from a suggestion | No — `render` renders the saved composition directly; a suggestion is optional. Captions come from `composition.captions` (author them in the `put` JSON). The clip-suggestion on-ramp just fills those captions for you by slicing the transcript at author time. |
195
224
 
196
- ## When NOT to use this skill
225
+ ## When this skill applies (routing)
226
+
227
+ Route on **intent, not operation**. This is the path whenever the task is *creating a video* — captioning, reframing or keeping a subject framed, finding the best moment, composing or branding clips, rendering to a target aspect/format. A mechanical verb ("trim", "concat") *inside* a creative goal ("…into a captioned 9:16 short") is still this skill — CueFrame does the trim too. If a task is part mechanical and part creative, it's this skill. When unsure whether a video task needs CueFrame, it does — author it here; validate cost-free with `--dry-run` first.
228
+
229
+ Drop to raw `ffmpeg` only for a **single mechanical operation with zero creative or perceptual intent** — losslessly concatenating two finished files, transcoding a codec, extracting an audio track. That one carve-out aside, reach for `cueframe`.
197
230
 
198
- - Pure local video manipulation (concatenate, trim, transcode) where AI clip selection adds no value → use `ffmpeg` directly.
199
- - Inspecting internal backend state → that has its own operator tooling, not this CLI.
200
- - Building the CLI itself (changes to the CLI source) → that's CLI development, not CLI usage.
231
+ Not this skill at all: inspecting internal backend state (that has its own operator tooling); changing the CLI's own source (that's CLI development, not usage).
@@ -0,0 +1,67 @@
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 both the MCP agent path (get_component_source → create_component) and the CLI repo path (cueframe eject/new → push). 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
+ CueFrame ships 87 built-in motion-graphics **primitives** (titles, lower-thirds, captions,
9
+ effects, transitions, scenes). You can **fork any of them as editable source**, customize it,
10
+ and render it on CueFrame — or author a brand-new component. This is shadcn-for-video: own the
11
+ component code; CueFrame is the reliable engine that renders it.
12
+
13
+ **The two facts that shape everything:**
14
+ - A component is mounted **`({ durationInFrames, params }) => JSX`** at render — `params` is the
15
+ single props bag (your composition clip's params). A forked primitive is auto-wrapped in this
16
+ adapter; a from-scratch component must default-export this shape.
17
+ - The shared renderer **never runs your code**: a component is baked to a transparent (alpha)
18
+ video in an isolated box first, then composited as trusted pixels. So owning/editing source is
19
+ safe, and rendering stays on CueFrame.
20
+
21
+ ## Path A — MCP agent (no filesystem; source lives server-side)
22
+
23
+ Single self-contained module per component (`create_component` takes one `tsxSource`).
24
+
25
+ 1. **Fork a built-in:** `get_component_source(componentId: "cinematic-title")` → returns the
26
+ primitive's editable single-module `tsxSource` (the named component + the adapter). Discover
27
+ ids from the catalog (`/v1/components`). *(Or author from scratch — skip to step 2.)*
28
+ 2. **Author/own it:** edit the `tsxSource`, then `create_component({ componentId, tsxSource, … })`
29
+ to store your customized copy (origin `server-native`; if forked, `ejectedFrom` is stamped).
30
+ 3. **Iterate (author→preview→fix):** `preview_component({ componentId, params })` (sessionless — a cold first call returns 409 box_warming; retry in a few seconds)
31
+ renders ONE still. A 422 `component_does_not_compile` returns the compiler error — read it, fix
32
+ via `update_component` (same id, in place), preview again.
33
+ 4. **Render:** add it to a composition as an `alpha-layer` clip (`apply_composition`), then
34
+ `create_render` → `wait_job kind:"render"` for the MP4.
35
+
36
+ ## Path B — CLI / coding agent (repo-owned source under git)
37
+
38
+ Source lives in `cueframe/components/<id>/` (the `cueframe.json` workspace); edit locally as
39
+ standard Remotion, push to render.
40
+
41
+ ```bash
42
+ cueframe init --json # scaffold cueframe.json + cueframe/components/
43
+ cueframe eject cinematic-title --json # fork a built-in primitive as owned source
44
+ # or: cueframe new component my-badge --json # scaffold a blank one
45
+ # …edit cueframe/components/<id>/ in your editor (standard Remotion)…
46
+ cueframe push cinematic-title --json # upload index.tsx as the component tsxSource
47
+ # or: cueframe sync --json # push every component in the workspace
48
+ # reference the component id in your composition, then render:
49
+ cueframe render <projectId> -o ./out.mp4 --json
50
+ ```
51
+
52
+ The CLI writes a 3-file layout (`index.tsx` = renderable module + adapter; `_config.ts` + `config.ts`
53
+ = local workspace metadata). `push` sends `index.tsx` as the single `tsxSource` — the same shape the
54
+ MCP path stores. To preview before a full render, push it and use the MCP `preview_component` loop.
55
+
56
+ ## Choosing what to fork
57
+ The catalog (`/v1/components`) gives each primitive's `description` / `useWhen` / `tags` / `mood` /
58
+ `tier` / `useCase` / `examples` (example params) + `propSchema` + its source via `get_component_source`.
59
+ Read the spec + the code to pick a starting point. (Rendered preview thumbnails are a separate
60
+ follow-up — today you choose from prose + params + source, or compose+`preview_frame` to see it.)
61
+
62
+ ## Don't
63
+ - Don't expect a forked primitive to use rich named props — it's adapted to `({durationInFrames,
64
+ params})`; read `params` inside.
65
+ - Don't hand-roll a graphic from zero when a built-in is close — fork it (`get_component_source` /
66
+ `cueframe eject`) and edit.
67
+ - Don't `create_component` a fresh id each fix iteration — `update_component` (same id) is the loop.
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: cueframe-storyboard
3
+ description: Use BEFORE composing when starting a NEW video from scratch and you need to plan its structure — turning a rough ask ("make a launch video", "30s promo", "an explainer for our API") into a concrete beat flow. Owns the intake + storyboard step: interview the user for the brief, resolve the format from the platform, and lay out the hook→body→cta beats that drive the compose workflow. Triggers on "plan a video", "storyboard", "structure this video", "outline the video", "where do I start", or any new-video ask that has no structure yet. Hand off to composing-video for per-beat craft.
4
+ ---
5
+
6
+ # CueFrame Storyboard: brief → flow
7
+
8
+ ## The one idea
9
+
10
+ **You are the planner.** You have the user, the whole conversation, the brand, and the judgment — you are
11
+ the smartest thing in this loop. CueFrame is the hands. This skill is the **intake + structure** step:
12
+ turn intent into a concrete **beat flow** *before* you seed a composition, so the curated workflow (media →
13
+ components → seed) executes a plan instead of a guess. Craft — grounded-vs-slop, the verify loop — belongs
14
+ to the sibling **composing-video** skill; this skill gets you a flow, then hands off to it.
15
+
16
+ Do not offload the *thinking* to CueFrame. There is no server that plans the video for you, and you would
17
+ not want one — it would be a blind model with none of your context. Plan here, in the open, with the user.
18
+
19
+ ## 1. Interview for the brief — ask only what you can't infer
20
+
21
+ Fill the brief from the conversation first; ask the user **only for the 1–2 things you genuinely cannot
22
+ infer**, and STATE what you assume for the rest. Never wall them with a form.
23
+
24
+ - **Goal / intent** *(required)* — what is this video FOR? launch, promo, explainer, demo, teaser, recap.
25
+ - **Platform** *(sets the format)* — reels / tiktok / shorts → **9:16, ~20s** · youtube → **16:9, ~45s** ·
26
+ linkedin / x → **1:1, ~20s** · web → **16:9, ~30s**. (Or an explicit aspect ratio + duration.)
27
+ - **Audience**, **tone** (punchy / premium-calm / playful / authoritative), **CTA**, **must-includes**
28
+ (a number, a name, a screen), **references** (a style to echo), **brand kit**.
29
+
30
+ If the ask is "make a launch video for our API," you already have goal + a hint of audience — ask "Reels,
31
+ YouTube, or your site?" and infer the rest: *"I'll assume a developer audience and a punchy tone — say if
32
+ you'd rather it feel calm/premium."* One or two questions, not seven.
33
+
34
+ ## 2. Structure the flow — the storyboard
35
+
36
+ Lay the duration into **beats** using the fixed editorial vocabulary
37
+ **hook → context → body → proof → cta → outro** (use what the piece needs — most short-form is
38
+ hook → body → cta). For each beat decide:
39
+
40
+ - a one-line **intent** (what this beat does for the viewer),
41
+ - a **duration** (they sum to the target; the hook earns attention in ~3s),
42
+ - a **media need** — real footage is the strongest grounding and CueFrame's home turf, so reach for it
43
+ first; otherwise `generate` a *purposeful* clip (a diagram of the real mechanism, the real UI) or `find`
44
+ stock. Animated text over a gradient is not grounding — it's the slop default,
45
+ - an optional **graphic** (a lower-third, title, CTA card),
46
+ - a **caption** and/or a **VO/script** line.
47
+
48
+ **Ground it, don't invent it.** Pick every graphic/scene from `list_catalog` (filter by `useCase`/`tier`)
49
+ — never hardcode hex or positions or name a component that doesn't exist. Theme from the brand kit. If
50
+ you're planning over real footage, read `get_media_context` (detected faces + transcript) so beat timing,
51
+ crops, and captions land on what's actually there.
52
+
53
+ ## 3. Show the flow, then persist it as a Brief
54
+
55
+ Show the user the beat list **first** — a five-line outline. It is cheap to change here and expensive to
56
+ change after a render, so this is where you converge on structure. On their go, **persist the plan with
57
+ `create_brief`** — the beats/goal/format/gates you just elicited map 1:1 onto its fields, and the plan stops
58
+ being chat-ephemeral (it survives the session, carries a cost quote, and is honored field-by-field):
59
+
60
+ 1. `import_media` / `generate_media` for each beat's media need,
61
+ 2. `create_brief` — goal, audience, platform/format, durationSec, tone, cta, locale, and the beats
62
+ (each with its editorial intent and, when you're cutting real footage, MOMENT PINNING
63
+ `source: {mediaId, startSec, endSec}` from the transcript — honored to-the-frame or refused).
64
+ Relay the response's **quote** (compose + estimated render) BEFORE composing.
65
+ 3. `compose { briefId }` — the Director authors FROM your brief; every field is honored or the
66
+ compose is refused loudly naming the field. Gates: put `holdAt: ["layout"]` in the brief's `gates` when
67
+ the user wants to approve the storyboard mid-flight; `autoApprove: true` for hands-off.
68
+ 4. `score_composition` / `consult` to fix the weakest beat,
69
+ 5. `create_render` for the MP4.
70
+
71
+ **Two graphic media — pick per beat, and review accordingly:** a `card` (verbatim HTML in
72
+ `seededGraphics`) is a STATIC graphic — cheap, approve it from a still; a **component**
73
+ (`create_component`, `useCurrentFrame`) is MOTION — a still is one frame, so preview it before trusting it.
74
+ Seeded graphics you author into the brief are carried VERBATIM as locked clips — the Director never
75
+ re-authors them; `exclusions` bans graphic kinds you never want it to author.
76
+
77
+ Then load **composing-video** and apply its craft to make each beat good.
78
+
79
+ ## Related skills & positioning
80
+
81
+ This skill owns **structure/intake**; its siblings own execution and craft — defer to them:
82
+
83
+ - **composing-video** — the craft/quality layer (grounded specificity vs. slop, the vision → rubric →
84
+ verify loop). Load it *after* you have a flow; it makes each beat good.
85
+ - **cueframe-compose-loop** — the author → render → verify → fix convergence loop + the ship bar.
86
+ - **cueframe-product-video** — click-points → auto-zoom tiling + PiP for screen demos.
87
+ - **cueframe-brand-demo** — brand-token vocabulary + auto intro/outro/logo for branded launches.
88
+ - **cueframe-component-authoring** — fork → preview → push for a custom graphic a beat needs.
89
+ - **cueframe-cli** — the `cueframe` binary + wire mechanics.
90
+
91
+ ## The boundary
92
+
93
+ You own the **vision** (the one idea and the flow for *this* video) and **data correctness** (a wrong
94
+ number you supply is rendered faithfully — the mistake is yours). CueFrame owns being faithful, legible,
95
+ and giving you real footage + real components to plan against. Reason from this; skip the whole flow only
96
+ for a re-render of an approved composition or a single trivial one-off.
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{A as a}from"./chunk-KEYFXLX4.js";export{a as analyzeCommand};