@vibeframe/cli 0.113.26 → 0.113.27

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 (28) hide show
  1. package/dist/commands/_shared/build-plan.d.ts +7 -0
  2. package/dist/commands/_shared/compose-beat-prompt.d.ts +47 -0
  3. package/dist/commands/_shared/compose-prompts.d.ts +8 -10
  4. package/dist/commands/_shared/install-skill.d.ts +67 -90
  5. package/dist/commands/_shared/scene-build-mode.d.ts +15 -0
  6. package/dist/commands/_shared/scene-build.d.ts +2 -8
  7. package/dist/commands/_shared/scene-lint.d.ts +23 -0
  8. package/dist/commands/_shared/scene-render.d.ts +12 -3
  9. package/dist/commands/_shared/walkthroughs/walkthroughs.d.ts +1 -1
  10. package/dist/index.js +2196 -3687
  11. package/dist/tools/manifest/agent-only.d.ts +2 -2
  12. package/dist/tools/manifest/audio.d.ts +2 -2
  13. package/dist/tools/manifest/edit.d.ts +12 -12
  14. package/dist/tools/manifest/export.d.ts +2 -2
  15. package/dist/tools/manifest/generate.d.ts +6 -6
  16. package/dist/tools/manifest/index.js +1663 -3236
  17. package/dist/tools/manifest/inspect.d.ts +8 -8
  18. package/dist/tools/manifest/remix.d.ts +10 -10
  19. package/dist/tools/manifest/scene.d.ts +20 -23
  20. package/dist/tools/manifest/storyboard.d.ts +2 -2
  21. package/dist/utils/exec-safe.d.ts +1 -0
  22. package/dist/utils/stdout-guard.d.ts +22 -0
  23. package/package.json +4 -4
  24. package/dist/commands/_shared/compose-scenes-skills.d.ts +0 -334
  25. package/dist/commands/_shared/hf-skill-bundle/bundle-content.d.ts +0 -16
  26. package/dist/commands/_shared/hf-skill-bundle/bundle.d.ts +0 -63
  27. package/dist/commands/_shared/hf-skill-bundle/bundle.test.d.ts +0 -1
  28. /package/dist/{commands/_shared/compose-scenes-skills.test.d.ts → utils/stdout-guard.test.d.ts} +0 -0
@@ -122,4 +122,11 @@ export interface CreateBuildPlanOptions {
122
122
  * (e.g. 7 beats quoted as ~$21 when the real cost is ~$0.35–1.40).
123
123
  */
124
124
  export declare function backdropCostUsd(quality: "standard" | "hd"): number;
125
+ /**
126
+ * Per-beat narration cost by resolved TTS provider. Kokoro runs locally and
127
+ * costs $0 — a flat per-narration charge here is what made zero-key builds
128
+ * report phantom spend. Shared by the dry-run estimate and the post-build
129
+ * actuals so the two can never disagree.
130
+ */
131
+ export declare function narrationCostUsd(provider: string | undefined): number;
125
132
  export declare function createBuildPlan(opts: CreateBuildPlanOptions): Promise<BuildPlanResult>;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @module _shared/compose-beat-prompt
3
+ *
4
+ * Per-beat authoring contract handed to the HOST agent. `getComposePrompts()`
5
+ * (and therefore `vibe scene compose-prompts` / `scene_compose_prompts`) uses
6
+ * this to describe exactly what one `compositions/scene-<id>.html` fragment
7
+ * must contain: the bare `<template>` shape, the paused GSAP timeline anchored
8
+ * to the full beat duration, full-window `.clip` rules, and which generated
9
+ * assets to reference.
10
+ *
11
+ * These rules were written against the Hyperframes sub-composition contract
12
+ * and every one of them encodes a render bug we hit: black holds from a short
13
+ * timeline, stacked text from non-zero `data-start` phase clips, shimmer from
14
+ * transforms on text ancestors.
15
+ */
16
+ import type { Beat } from "./storyboard-parse.js";
17
+ import type { SceneTranscriptWord } from "./scene-html-emit.js";
18
+ /** The slice of beat context the prompt builder needs. */
19
+ export interface ComposeBeatPromptContext {
20
+ beat: Beat;
21
+ storyboardGlobal: string;
22
+ retryFeedback?: string;
23
+ finalDurationSec?: number;
24
+ transcript?: SceneTranscriptWord[];
25
+ }
26
+ /**
27
+ * Word-level timing entries above this count are downgraded to coarse,
28
+ * phrase-level anchors in the prompt. A token-budget guard: a 60s narration
29
+ * can exceed 150 words, and inlining every `[start, "word"]` pair bloats the
30
+ * prompt (and the cache key) for little composer benefit past a point.
31
+ */
32
+ export declare const TRANSCRIPT_PROMPT_MAX_WORDS = 120;
33
+ /**
34
+ * Render narration word timings as a compact, deterministic prompt section.
35
+ * Token-budget guard (the `oversized` case is the reason this is a function,
36
+ * not an inline template):
37
+ * - no transcript → `""` (section omitted entirely; prompt unchanged).
38
+ * - ≤ {@link TRANSCRIPT_PROMPT_MAX_WORDS} → full word-level `[start, "word"]`
39
+ * table the composer can map 1:1 to GSAP reveals.
40
+ * - more → group into ~`MAX/2` phrase anchors (start time of each phrase),
41
+ * tagged "approximate" so the composer paces reveals across the beat
42
+ * rather than over-trusting per-word truth.
43
+ * Pure and stable for a given input → the compose cache stays consistent.
44
+ */
45
+ export declare function formatTranscriptSection(transcript: SceneTranscriptWord[] | undefined, maxWords?: number): string;
46
+ /** Build the user prompt — instructions + storyboard global + beat body. */
47
+ export declare function buildUserPrompt(ctx: ComposeBeatPromptContext): string;
@@ -13,7 +13,7 @@
13
13
  * "projectDir": "<abs>",
14
14
  * "designReference": "DESIGN.md",
15
15
  * "storyboardReference": "STORYBOARD.md",
16
- * "skillReference": "SKILL.md", // present after `scene install-skill`
16
+ * "skillReference": ".agents/skills/hyperframes/SKILL.md",
17
17
  * "compositionsDir": "compositions",
18
18
  * "beats": [
19
19
  * { "id": "hook", "outputPath": "compositions/scene-hook.html",
@@ -22,14 +22,14 @@
22
22
  * "instructions": [...]
23
23
  * }
24
24
  *
25
- * Pairs with H1 (`vibe scene install-skill`) — the host agent reads
26
- * `SKILL.md` for framework rules, `DESIGN.md` for visual identity, then
25
+ * Pairs with `vibe scene install-skill` — the host agent reads the
26
+ * Hyperframes rules, `DESIGN.md` for visual identity, then
27
27
  * writes each `compositions/scene-<id>.html`. After authoring, runs
28
- * `vibe scene lint --fix` to verify and `vibe render` to produce MP4.
28
+ * `vibe build <project> --stage sync` to assemble the root composition,
29
+ * `vibe scene lint <project> --fix` to verify, and `vibe render` for MP4.
29
30
  *
30
- * The internal-LLM path (`vibe scene build`, PR #176) still works — it's
31
- * the batch / non-agent fallback. H3 will add mode dispatch so a single
32
- * entry point picks between agentic and batch depending on context.
31
+ * This is the only model-authored compose path: the host agent writes each
32
+ * file. `--composer template` is the deterministic alternative.
33
33
  */
34
34
  export interface ComposePromptsBeat {
35
35
  /** Stable beat id from `parseStoryboard().deriveBeatId()`. */
@@ -54,7 +54,7 @@ export interface ComposePromptsBeat {
54
54
  /**
55
55
  * Pre-built user prompt — the same shape `composeBeatHtml` would send to
56
56
  * Claude / OpenAI / Gemini. The host agent consumes this directly so the
57
- * agentic and batch paths produce equivalent HTML.
57
+ * the host agent and the template composer produce equivalent structure.
58
58
  */
59
59
  userPrompt: string;
60
60
  /**
@@ -95,8 +95,6 @@ export interface ComposePromptsResult {
95
95
  beats: ComposePromptsBeat[];
96
96
  /** Step-by-step instructions for the host agent. */
97
97
  instructions: string[];
98
- /** Hyperframes bundle version — informational; ties cache keys back to the internal-LLM path. */
99
- bundleVersion: string;
100
98
  /** Non-fatal hints surfaced to the agent (e.g. missing SKILL.md). */
101
99
  warnings: string[];
102
100
  /** Set when {@link success} is false. */
@@ -1,117 +1,94 @@
1
1
  /**
2
2
  * @module _shared/install-skill
3
3
  *
4
- * Phase H1 — install the vendored Hyperframes skill bundle into a user's
5
- * scene project so that the host agent (Claude Code, Cursor, Codex, Aider,
6
- * etc.) can read the framework rules + house style directly. This is the
7
- * agentic-CLI-native pattern: the host agent is the sole LLM that reasons
8
- * about scene composition, and it does so with the skill files in its
9
- * context — VibeFrame's CLI is the deterministic toolbelt.
4
+ * Put the Hyperframes composition rules where the host agent will read them,
5
+ * by running upstream's own installer instead of shipping a copy.
10
6
  *
11
- * Layout written:
7
+ * VibeFrame used to vendor a snapshot of Hyperframes' skill markdown and write
8
+ * it into each project under hand-maintained per-host layouts (project-root
9
+ * `SKILL.md` + `references/`, `.claude/skills/hyperframes/`,
10
+ * `.cursor/rules/hyperframes.mdc`). That snapshot went stale - upstream has
11
+ * since restructured the skill into a router plus a `references/` tree and
12
+ * ships 31 skills, none of which a frozen copy can follow - and the two host
13
+ * layouts covered a fraction of what upstream's installer reaches.
12
14
  *
13
- * <project>/
14
- * SKILL.md # universal — all agents see this
15
- * references/
16
- * house-style.md
17
- * motion-principles.md
18
- * typography.md
19
- * transitions.md
20
- * .claude/skills/hyperframes/ # if hosts includes "claude-code"
21
- * SKILL.md (copy)
22
- * references/{house-style,...}.md
23
- * .cursor/rules/hyperframes.mdc # if hosts includes "cursor"
15
+ * npx skills add heygen-com/hyperframes -s hyperframes -y
24
16
  *
25
- * Codex + Aider are AGENTS.md-driven hosts; they discover the project-root
26
- * SKILL.md because AGENTS.md points at it in prose (the init-templates
27
- * AGENTS_MD "Composition rules" section, not an `@`-import).
17
+ * installs to `.agents/skills/hyperframes/`, serves ~19 agents universally
18
+ * (Amp, Antigravity, Cline, Codex, and more), symlinks the ones that want
19
+ * their own directory (Claude Code, Eve), and records the result in
20
+ * `skills-lock.json`. The generated `AGENTS.md` has pointed users at this
21
+ * command for a while; now the code agrees with the docs.
28
22
  *
29
- * The content is byte-identical to what `loadHyperframesSkillBundle()`
30
- * uses — same vendored files, same `BUNDLE_VERSION`. Build/render never read
31
- * these project files (they use the vendored bundle); they exist only so host
32
- * agents can read the rules and so users can edit them per project.
33
- *
34
- * Lean scaffolds: the automatic `vibe init` path passes `lean: true`, so when
35
- * the Hyperframes skill is already installed globally
36
- * (`hasGlobalHyperframesSkill()`) it skips the redundant copies — the
37
- * `.claude/skills/hyperframes/` copy always, and the root `SKILL.md` +
38
- * `references/` unless a root-reading host (codex/aider/gemini/opencode) needs
39
- * them. Explicit `vibe scene install-skill` omits `lean`, fully materializing
40
- * editable copies regardless (the "eject").
23
+ * Nothing in build or render reads these files. They exist so the host agent
24
+ * can read the rules while it authors scene HTML.
41
25
  */
42
- import type { AgentHostId } from "../../utils/agent-host-detect.js";
26
+ /** Upstream repository the `skills` CLI installs from. */
27
+ export declare const HYPERFRAMES_SKILL_PACKAGE = "heygen-com/hyperframes";
28
+ /** The command a user can run by hand to get the same result. */
29
+ export declare const HYPERFRAMES_SKILL_INSTALL_COMMAND = "npx skills add heygen-com/hyperframes";
30
+ /** Where upstream's installer puts the skill inside a project. */
31
+ export declare const PROJECT_SKILL_PATH: string;
43
32
  /**
44
33
  * True when the Hyperframes skill is installed at the user's global Claude
45
- * skills dir (`~/.claude/skills/hyperframes/`). When present, materializing the
46
- * skill into a project is redundant — the host agent already loads it globally —
47
- * so `vibe init` keeps the scaffold lean and skips the copies. Explicit
48
- * `vibe scene install-skill` ignores this (it's the opt-in "eject" path).
34
+ * skills dir (`~/.claude/skills/hyperframes/`). A host agent already loads it
35
+ * from there, so installing into the project is redundant.
49
36
  */
50
37
  export declare function hasGlobalHyperframesSkill(): boolean;
51
- /** Hosts the install-skill command knows file layouts for. */
52
- export type InstallSkillHost = "claude-code" | "cursor" | "all";
38
+ /** True when upstream's installer has already run in this project. */
39
+ export declare function hasProjectHyperframesSkill(projectDir: string): boolean;
40
+ /**
41
+ * Project-relative path to the composition rules a host agent should read, or
42
+ * `null` when neither the project nor the global install has them.
43
+ *
44
+ * The bare root `SKILL.md` is still honoured: projects scaffolded before the
45
+ * switch to upstream's installer have one, and it should keep working.
46
+ */
47
+ export declare function resolveSkillReference(projectDir: string): string | null;
48
+ /**
49
+ * True when the host agent can read the Hyperframes rules from anywhere -
50
+ * this project or the user's global skills dir. Callers that only need to
51
+ * decide whether to nag should use this rather than
52
+ * {@link resolveSkillReference}, which is about the in-project path and is
53
+ * null for a global-only install.
54
+ */
55
+ export declare function hyperframesSkillAvailable(projectDir: string): boolean;
56
+ export type InstallSkillStatus = "installed" | "already-installed" | "would-install" | "failed";
53
57
  export interface InstallSkillOptions {
54
- /** Project directory (must exist or be creatable). */
58
+ /** Project to install into. The installer runs with this as its cwd. */
55
59
  projectDir: string;
56
- /**
57
- * Hosts to install host-specific copies for. The universal `SKILL.md` +
58
- * `references/` directory at the project root are always written.
59
- * Pass `["all"]` to install every host-specific layout.
60
- */
61
- hosts: InstallSkillHost[];
62
- /** Overwrite existing files. Default false (skip-on-exist). */
60
+ /** Install at user level (`~/.claude/skills/...`) rather than per project. */
61
+ global?: boolean;
62
+ /** Reinstall even when the skill is already present. */
63
63
  force?: boolean;
64
- /** Don't write — just describe what would happen. */
64
+ /** Report the command without running it. */
65
65
  dryRun?: boolean;
66
66
  /**
67
- * Opt into redundancy gating: skip copies the globally-installed Hyperframes
68
- * skill already provides. The automatic `vibe init` path sets this so the
69
- * scaffold stays lean; the explicit `vibe scene install-skill` path leaves it
70
- * false to fully materialize editable copies (the "eject"). Default false.
71
- */
72
- lean?: boolean;
73
- /**
74
- * Caller signals a root-reading host (codex / aider / gemini / opencode) is
75
- * present, so the root `SKILL.md` + `references/` must be written even when
76
- * the global Claude skill exists. Default false. Only consulted when `lean`.
77
- */
78
- rootReaderHostPresent?: boolean;
79
- /**
80
- * Override the global-skill probe (testing seam). Defaults to
81
- * {@link hasGlobalHyperframesSkill}. Only consulted when `lean`.
67
+ * Override the global-skill probe. Testing seam - a developer machine that
68
+ * already has the skill would otherwise short-circuit every install.
82
69
  */
83
70
  hasGlobalSkill?: boolean;
84
71
  }
85
- export type InstallSkillFileStatus = "wrote" | "skipped-exists" | "would-write" | "would-skip-exists";
86
- export interface InstallSkillFileAction {
87
- path: string;
88
- status: InstallSkillFileStatus;
89
- bytes: number;
90
- }
91
72
  export interface InstallSkillResult {
92
73
  success: boolean;
93
- bundleVersion: string;
94
- files: InstallSkillFileAction[];
74
+ status: InstallSkillStatus;
75
+ /** The exact command run (or that would run). */
76
+ command: string;
77
+ /** Project-relative path to the installed rules, when they are present. */
78
+ skillPath: string | null;
79
+ /** Installer output, trimmed. Present on a real run. */
80
+ output?: string;
81
+ error?: string;
82
+ retryWith?: string[];
95
83
  }
84
+ /** Build the argv for upstream's installer. Pure - unit-testable. */
85
+ export declare function buildInstallSkillArgs(opts?: {
86
+ global?: boolean;
87
+ }): string[];
96
88
  /**
97
- * Map an `AgentHostId[]` to whether a root-reading host is present. Codex,
98
- * Aider, Gemini, and OpenCode read the project-root `SKILL.md` via AGENTS.md
99
- * prose — they have no global-skill mechanism, so the root files must be
100
- * written for them even when the global Claude skill exists.
101
- */
102
- export declare function deriveRootReaderPresent(detected: AgentHostId[]): boolean;
103
- /**
104
- * Install Hyperframes skill files at the project + host-specific paths.
89
+ * Run upstream's installer for the Hyperframes skill.
105
90
  *
106
- * Idempotent by default — existing files are skipped (logged as
107
- * `skipped-exists`). Pass `force: true` to overwrite. `dryRun: true`
108
- * reports the same actions but with `would-*` status and writes nothing.
91
+ * Skips when the skill is already available (globally or in the project)
92
+ * unless `force` is set, so calling it twice costs nothing.
109
93
  */
110
94
  export declare function installHyperframesSkill(opts: InstallSkillOptions): Promise<InstallSkillResult>;
111
- /**
112
- * Map an `AgentHostId[]` (from `detectedAgentHosts()`) to the
113
- * install-skill command's host vocabulary. Codex / Aider don't get
114
- * host-specific layouts — they read the universal `SKILL.md` via
115
- * AGENTS.md, so they're filtered out here.
116
- */
117
- export declare function deriveInstallHosts(detected: AgentHostId[]): InstallSkillHost[];
@@ -1,4 +1,19 @@
1
1
  export type SceneBuildMode = "agent" | "batch" | "auto";
2
+ /**
3
+ * Resolve which compose path a build takes.
4
+ *
5
+ * `agent` is the only LLM-authored path VibeFrame ships: the host's agent
6
+ * writes each `compositions/scene-<id>.html` and the CLI lints, syncs, and
7
+ * renders around it. `batch` now means one thing - the deterministic
8
+ * `--composer template` path, which authors HTML without any model.
9
+ *
10
+ * The mode used to also select a CLI-internal LLM composer that called
11
+ * Claude/OpenAI/Gemini directly. That path is gone: the host agent is the
12
+ * outer loop, and duplicating its job inside the CLI meant carrying a stale
13
+ * copy of upstream's authoring skill and demanding an extra API key.
14
+ * `VIBE_BUILD_MODE=batch` therefore no longer forces a model-authored build;
15
+ * without `--composer template` it resolves to `agent`.
16
+ */
2
17
  export declare function resolveSceneBuildMode(opts: {
3
18
  mode?: SceneBuildMode;
4
19
  }): "agent" | "batch";
@@ -19,7 +19,6 @@
19
19
  * already have one with sub-composition references.
20
20
  */
21
21
  import { type ImageOptions } from "@vibeframe/ai-providers";
22
- import { type ComposeEffort, type ComposeProgressEvent, type ComposeScenesActionResult } from "./compose-scenes-skills.js";
23
22
  import type { ComposerProvider } from "./composer-resolve.js";
24
23
  import { type ComposePromptsBeat } from "./compose-prompts.js";
25
24
  import { type SceneRenderResult } from "./scene-render.js";
@@ -155,7 +154,7 @@ export type SceneBuildProgressEvent = {
155
154
  type: "music-skipped";
156
155
  beatId: string;
157
156
  reason: string;
158
- } | ComposeProgressEvent | {
157
+ } | {
159
158
  type: "render-start";
160
159
  } | {
161
160
  type: "render-done";
@@ -240,8 +239,6 @@ export interface SceneBuildOptions {
240
239
  * Build mode dispatch. See {@link SceneBuildMode}. Default: `auto`.
241
240
  */
242
241
  mode?: SceneBuildMode;
243
- /** Compose effort tier — passed through to `compose-scenes-with-skills`. */
244
- effort?: ComposeEffort;
245
242
  /**
246
243
  * Composer LLM provider. Defaults to whatever `resolveComposer()` picks
247
244
  * based on env keys (claude > gemini > openai). Pass an explicit value
@@ -343,7 +340,6 @@ export interface SceneBuildResult {
343
340
  beats: BeatBuildOutcome[];
344
341
  /** MP4 path when `skipRender` is false and render succeeded. */
345
342
  outputPath?: string;
346
- composeData?: ComposeScenesActionResult["data"];
347
343
  renderResult?: SceneRenderResult;
348
344
  /**
349
345
  * Populated only in agent mode when {@link phase} === `"needs-author"`.
@@ -358,7 +354,6 @@ export interface SceneBuildResult {
358
354
  compositionsDir: string;
359
355
  instructions: string[];
360
356
  beats: ComposePromptsBeat[];
361
- bundleVersion: string;
362
357
  warnings: string[];
363
358
  };
364
359
  selectedStage?: BuildStage;
@@ -463,7 +458,6 @@ declare function toBuildReport(projectDir: string, result: SceneBuildResult): {
463
458
  path: string;
464
459
  exists: boolean;
465
460
  status: BuildReportCompositionStatus;
466
- cacheKey?: string;
467
461
  };
468
462
  narrationPath: string | undefined;
469
463
  narrationDurationSec: number | undefined;
@@ -505,4 +499,4 @@ declare function toBuildReport(projectDir: string, result: SceneBuildResult): {
505
499
  retryWith: string[];
506
500
  totalLatencyMs: number;
507
501
  };
508
- type BuildReportCompositionStatus = "generated" | "cached" | "exists" | "needs-author" | "skipped" | "failed";
502
+ type BuildReportCompositionStatus = "exists" | "needs-author" | "skipped" | "failed";
@@ -137,3 +137,26 @@ export declare function runProjectLint(opts: RunProjectLintOptions): Promise<Pro
137
137
  /** True if `root` exists and is a regular file. Used by callers that want to
138
138
  * pre-validate before invoking `runProjectLint`. */
139
139
  export declare function rootExists(projectDir: string, rootRel?: string): Promise<boolean>;
140
+ export interface BeatLintResult {
141
+ errorCount: number;
142
+ warningCount: number;
143
+ findings: LintFinding[];
144
+ }
145
+ /**
146
+ * Lint one beat's HTML in memory, with no temp project shell and no
147
+ * subprocess. Sub-composition false positives are filtered the same way
148
+ * `vibe scene lint` filters them, so an agent submitting a beat sees the
149
+ * findings it would see after the file landed in the project.
150
+ */
151
+ export declare function lintBeatHtml(html: string, beatId: string): Promise<BeatLintResult>;
152
+ /** Thrown when a submission carries no recoverable HTML. */
153
+ export declare class BeatHtmlError extends Error {
154
+ readonly code: "no-html-in-response";
155
+ constructor(code: "no-html-in-response", message: string);
156
+ }
157
+ /**
158
+ * Pull the HTML fragment out of an agent's reply. Prefers a fenced ```html
159
+ * block and accepts a bare fragment, since hosts often skip the fence when
160
+ * the whole reply is the document.
161
+ */
162
+ export declare function extractHtml(responseText: string): string;
@@ -12,7 +12,7 @@
12
12
  * tool and the C5 `--format scenes` pipeline can call it the same way. It
13
13
  * returns a structured result instead of throwing or exiting.
14
14
  */
15
- import { type RenderConfig } from "@hyperframes/producer";
15
+ import { type RenderConfigInput } from "@hyperframes/producer";
16
16
  import { type SceneAspect } from "./scene-project.js";
17
17
  export type RenderFps = 24 | 30 | 60;
18
18
  export type RenderQuality = "draft" | "standard" | "high";
@@ -105,8 +105,14 @@ export declare function defaultOutputPath(opts: {
105
105
  now?: Date;
106
106
  }): string;
107
107
  /**
108
- * Build the producer's `RenderConfig` from caller options. Pure — useful for
108
+ * Build the producer's render config from caller options. Pure - useful for
109
109
  * unit tests that want to assert defaults without touching Chrome.
110
+ *
111
+ * Returns `RenderConfigInput` (not `RenderConfig`) so `fps` stays an integer:
112
+ * the producer models fps as a rational `{num, den}` internally but accepts a
113
+ * plain number on the way in. The intersection pins `fps`/`format` to our
114
+ * narrower unions so callers keep arithmetic on fps and never see the
115
+ * producer-only formats (`gif`, `png-sequence`) VibeFrame does not expose.
110
116
  */
111
117
  export declare function buildRenderConfig(opts: {
112
118
  fps?: RenderFps;
@@ -114,7 +120,10 @@ export declare function buildRenderConfig(opts: {
114
120
  format?: RenderFormat;
115
121
  workers?: number;
116
122
  entryFile?: string;
117
- }): RenderConfig;
123
+ }): RenderConfigInput & {
124
+ fps: RenderFps;
125
+ format: RenderFormat;
126
+ };
118
127
  export declare function buildMediaOpenCommand(action: RenderOpenAction, filePath: string, platform?: NodeJS.Platform): MediaOpenCommand;
119
128
  /**
120
129
  * Render a scene project. Mirrors the contract of the existing Hyperframes
@@ -12,7 +12,7 @@
12
12
  * a terminal) gets the same step-by-step authoring guide that the
13
13
  * slash commands deliver in Claude Code. The content is vendored as
14
14
  * TS template-literal strings so the CLI binary ships with zero
15
- * filesystem dependencies — same approach as `hf-skill-bundle`.
15
+ * filesystem dependencies.
16
16
  *
17
17
  * Source of truth lives here. The Claude Code slash command files
18
18
  * under `.claude/skills/vibe-{scene,pipeline}/SKILL.md` mirror this