motionrender 0.2.0 → 0.2.2
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.
- package/dist/cli.js +2634 -528
- package/dist/index.js +46 -1
- package/dist/player.js +13 -13
- package/dist/react.js +704 -9
- package/dist/types/packages/ai/src/agent.d.ts +57 -0
- package/dist/types/packages/ai/src/brand-scraper.d.ts +35 -0
- package/dist/types/packages/ai/src/captions.d.ts +11 -0
- package/dist/types/packages/ai/src/compose.d.ts +2 -0
- package/dist/types/packages/ai/src/edit.d.ts +69 -0
- package/dist/types/packages/ai/src/index.d.ts +8 -1
- package/dist/types/packages/ai/src/plan.d.ts +42 -0
- package/dist/types/packages/ai/src/prompt.d.ts +18 -0
- package/dist/types/packages/ai/src/providers.d.ts +35 -2
- package/dist/types/packages/ai/src/registry.d.ts +81 -0
- package/dist/types/packages/ai/src/retime.d.ts +7 -0
- package/dist/types/packages/ai/src/shorts.d.ts +75 -0
- package/dist/types/packages/cli/src/agent-cli.d.ts +15 -0
- package/dist/types/packages/cli/src/ai-studio-page.d.ts +1 -1
- package/dist/types/packages/cli/src/ai.d.ts +1 -1
- package/dist/types/packages/cli/src/build.d.ts +2 -0
- package/dist/types/packages/cli/src/templates.d.ts +13 -4
- package/dist/types/packages/contracts/src/index.d.ts +12 -12
- package/dist/types/packages/core/src/review.d.ts +24 -0
- package/dist/types/packages/ffmpeg/src/index.d.ts +1 -0
- package/dist/types/packages/jobs/src/queue.d.ts +2 -2
- package/dist/types/packages/jobs/src/redis.d.ts +2 -2
- package/dist/types/packages/react/src/components.d.ts +166 -0
- package/dist/types/packages/react/src/index.d.ts +54 -2
- package/dist/types/packages/react/src/springs.d.ts +25 -0
- package/dist/types/packages/schema/src/captions.d.ts +2 -0
- package/dist/types/packages/schema/src/index.d.ts +66 -66
- package/dist/types/scripts/eval-briefs.d.ts +67 -0
- package/package.json +1 -1
- package/skills/ove/SKILL.md +40 -2
- package/skills/ove-agent/SKILL.md +144 -0
- package/skills/ove-code-video/SKILL.md +17 -9
- package/skills/ove-motion-graphics/SKILL.md +113 -0
- package/skills/ove-react-video/SKILL.md +212 -0
- package/skills/ove-remotion/SKILL.md +122 -0
- package/studio/assets/index-DmZj9wTZ.css +1 -0
- package/studio/assets/index-n3DJI_GV.js +10 -0
- package/studio/index.html +2 -2
- package/templates/case-study/composition.json +25 -10
- package/templates/event-invite/composition.json +12 -2
- package/templates/explainer-square/composition.json +1 -1
- package/templates/keynote-wide/composition.json +2 -2
- package/templates/kinetic-reel/composition.json +73 -0
- package/templates/kinetic-reel/composition.schema.json +9295 -0
- package/templates/kinetic-reel/template.json +17 -0
- package/templates/kinetic-reel/video.bundle.js +72 -0
- package/templates/kinetic-reel/video.tsx +283 -0
- package/templates/product-card/composition.json +7 -2
- package/templates/product-wide/composition.json +1 -1
- package/templates/quote-card/composition.json +6 -1
- package/templates/saas-launch/composition.json +70 -0
- package/templates/saas-launch/composition.schema.json +9295 -0
- package/templates/saas-launch/template.json +16 -0
- package/templates/saas-launch/video.bundle.js +72 -0
- package/templates/saas-launch/video.tsx +217 -0
- package/templates/sale-promo/composition.json +16 -1
- package/templates/showcase-tall/composition.json +4 -4
- package/templates/slideshow/composition.json +1 -1
- package/templates/social-reel/composition.json +19 -4
- package/templates/story-tall/composition.json +1 -1
- package/studio/assets/index-CzOvWv9w.css +0 -1
- package/studio/assets/index-J_fvKgng.js +0 -11
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { AiProvider } from './providers.js';
|
|
2
|
+
export type VideoFormat = 'reel' | 'landscape';
|
|
3
|
+
export type BrandColor = {
|
|
4
|
+
primary: string;
|
|
5
|
+
secondary?: string;
|
|
6
|
+
accent?: string;
|
|
7
|
+
background?: string;
|
|
8
|
+
text?: string;
|
|
9
|
+
};
|
|
10
|
+
export type BrandFont = {
|
|
11
|
+
heading?: string;
|
|
12
|
+
body?: string;
|
|
13
|
+
};
|
|
14
|
+
export type BrandPack = {
|
|
15
|
+
colors?: BrandColor;
|
|
16
|
+
fonts?: BrandFont;
|
|
17
|
+
logo?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
style?: string;
|
|
20
|
+
};
|
|
21
|
+
export type AgentOptions = {
|
|
22
|
+
brief?: string;
|
|
23
|
+
url?: string;
|
|
24
|
+
dir?: string;
|
|
25
|
+
format?: VideoFormat;
|
|
26
|
+
durationSeconds?: number;
|
|
27
|
+
fps?: number;
|
|
28
|
+
render?: boolean;
|
|
29
|
+
outputMp4?: string;
|
|
30
|
+
onProgress?: (message: string) => void;
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
brand?: BrandPack;
|
|
33
|
+
visualCheck?: (videoPath: string, compositionPath: string) => Promise<{
|
|
34
|
+
passed: boolean;
|
|
35
|
+
report: string;
|
|
36
|
+
sheet?: Buffer;
|
|
37
|
+
}>;
|
|
38
|
+
};
|
|
39
|
+
export type AgentResult = {
|
|
40
|
+
dir: string;
|
|
41
|
+
videoPath: string;
|
|
42
|
+
compositionPath: string;
|
|
43
|
+
bundlePath: string;
|
|
44
|
+
mp4Path?: string;
|
|
45
|
+
previewPath?: string;
|
|
46
|
+
attempts: number;
|
|
47
|
+
code: string;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Returns true when the brief hints at a vertical reel format.
|
|
51
|
+
* Checks for social/vertical keywords case-insensitively.
|
|
52
|
+
*/
|
|
53
|
+
export declare function detectReelFormat(brief: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Autonomous Video Agent that plans, codes, builds, and self-corrects React videos.
|
|
56
|
+
*/
|
|
57
|
+
export declare function runVideoAgent(provider: AiProvider, options: AgentOptions, buildHelper?: (source: string, output: string) => Promise<void>): Promise<AgentResult>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { BrandPack } from './agent.js';
|
|
2
|
+
import type { AiProvider } from './providers.js';
|
|
3
|
+
export type ScrapedWebsite = {
|
|
4
|
+
url: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
siteName?: string;
|
|
8
|
+
logo?: string;
|
|
9
|
+
themeColor?: string;
|
|
10
|
+
colors: string[];
|
|
11
|
+
headings: string[];
|
|
12
|
+
paragraphs: string[];
|
|
13
|
+
suggestedBrief?: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Normalizes a URL so that 'linear.app' becomes 'https://linear.app'.
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeUrl(input: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Fast, lightweight regex-based HTML metadata & brand asset extractor.
|
|
21
|
+
* Doesn't require heavy DOM dependencies; works seamlessly in Node 20+.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseWebsiteHtml(html: string, baseUrl: string): ScrapedWebsite;
|
|
24
|
+
/**
|
|
25
|
+
* Fetches the website HTML and extracts brand assets, colors, and value proposition.
|
|
26
|
+
*/
|
|
27
|
+
export declare function scrapeWebsiteBrand(urlInput: string, timeoutMs?: number): Promise<ScrapedWebsite>;
|
|
28
|
+
/**
|
|
29
|
+
* Distills raw scraped website metadata into a structured BrandPack using the AI provider,
|
|
30
|
+
* with a deterministic fallback if the AI request fails or provider is absent.
|
|
31
|
+
*/
|
|
32
|
+
export declare function distillBrandPack(scraped: ScrapedWebsite, provider?: AiProvider): Promise<{
|
|
33
|
+
brand: BrandPack;
|
|
34
|
+
suggestedBrief: string;
|
|
35
|
+
}>;
|
|
@@ -6,6 +6,8 @@ export type ComposeOptions = PromptOptions & {
|
|
|
6
6
|
maxAttempts?: number;
|
|
7
7
|
/** Run `ove review`-style checks between attempts and feed design errors back. Slow; off by default. */
|
|
8
8
|
review?: boolean;
|
|
9
|
+
/** Plan beats and look first (Claude-style motion graphics), then write the composition. */
|
|
10
|
+
plan?: boolean;
|
|
9
11
|
baseDir?: string;
|
|
10
12
|
signal?: AbortSignal;
|
|
11
13
|
onProgress?: (message: string) => void;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Composition } from '../../core/src/index.js';
|
|
2
|
+
import type { AiProvider, Transcript, TranscriptWord } from './providers.js';
|
|
3
|
+
export type CutSegment = {
|
|
4
|
+
from: number;
|
|
5
|
+
to: number;
|
|
6
|
+
};
|
|
7
|
+
export type CutPlan = {
|
|
8
|
+
/** The kept stretches of the source, in seconds, in order. */
|
|
9
|
+
segments: CutSegment[];
|
|
10
|
+
/** The kept words with their times remapped onto the edited timeline (what the captions show). */
|
|
11
|
+
words: TranscriptWord[];
|
|
12
|
+
/** Seconds removed between the first and last kept word. */
|
|
13
|
+
cut: number;
|
|
14
|
+
/** Filler and repeated words cut (um, uh, "the the"). */
|
|
15
|
+
fillers: number;
|
|
16
|
+
};
|
|
17
|
+
export type PlanCutsOptions = {
|
|
18
|
+
/** A pause longer than this, in seconds, is cut (default 0.5). */
|
|
19
|
+
maxSilence?: number;
|
|
20
|
+
/** Keep filler words in the video instead of cutting them. */
|
|
21
|
+
keepFillers?: boolean;
|
|
22
|
+
/** Breathing room kept before the first and after the last word, in seconds (default 0.3). */
|
|
23
|
+
padding?: number;
|
|
24
|
+
};
|
|
25
|
+
/** Turns word timings into a cut list: speech runs join across pauses up to maxSilence, longer pauses become cuts. */
|
|
26
|
+
export declare function planCuts(transcript: Transcript, options?: PlanCutsOptions): CutPlan;
|
|
27
|
+
export type EditCompositionOptions = {
|
|
28
|
+
fps: number;
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
/** The clip, as an asset id or a path relative to the composition. */
|
|
32
|
+
src: string;
|
|
33
|
+
plan: CutPlan;
|
|
34
|
+
/** Composition-relative path to a captions file (word timings); left out, the reel has no captions. */
|
|
35
|
+
captionsSrc?: string;
|
|
36
|
+
};
|
|
37
|
+
/** Builds the edited composition: one video layer per kept stretch (hard jump cuts between them), captions over all of it. */
|
|
38
|
+
export declare function editComposition(options: EditCompositionOptions): Composition;
|
|
39
|
+
export type EditOptions = {
|
|
40
|
+
/** Path to the raw clip (any file FFmpeg reads). */
|
|
41
|
+
clip: string;
|
|
42
|
+
/** Project directory to write: composition.json, composition.schema.json, assets/. */
|
|
43
|
+
outDir: string;
|
|
44
|
+
width?: number;
|
|
45
|
+
height?: number;
|
|
46
|
+
fps?: number;
|
|
47
|
+
maxSilence?: number;
|
|
48
|
+
keepFillers?: boolean;
|
|
49
|
+
padding?: number;
|
|
50
|
+
captions?: boolean;
|
|
51
|
+
language?: string;
|
|
52
|
+
/** Write into a directory that already has files. */
|
|
53
|
+
force?: boolean;
|
|
54
|
+
signal?: AbortSignal;
|
|
55
|
+
onProgress?: (message: string) => void;
|
|
56
|
+
};
|
|
57
|
+
export type EditResult = {
|
|
58
|
+
dir: string;
|
|
59
|
+
composition: string;
|
|
60
|
+
captions?: string;
|
|
61
|
+
durationSeconds: number;
|
|
62
|
+
sourceSeconds: number;
|
|
63
|
+
segments: number;
|
|
64
|
+
cut: number;
|
|
65
|
+
fillers: number;
|
|
66
|
+
words: number;
|
|
67
|
+
};
|
|
68
|
+
/** Transcribes a raw clip, cuts its fillers and silences, and writes the edited reel as a project. */
|
|
69
|
+
export declare function editVideo(provider: AiProvider, options: EditOptions): Promise<EditResult>;
|
|
@@ -6,8 +6,15 @@ export * from './template.js';
|
|
|
6
6
|
export { applyFixes, isFixReply, type Fix } from './patch.js';
|
|
7
7
|
export * from './narrate.js';
|
|
8
8
|
export * from './voiceover.js';
|
|
9
|
+
export * from './edit.js';
|
|
10
|
+
export * from './shorts.js';
|
|
11
|
+
export * from './retime.js';
|
|
9
12
|
export * from './image.js';
|
|
10
13
|
export * from './batch.js';
|
|
11
14
|
export * from './project.js';
|
|
15
|
+
export * from './agent.js';
|
|
16
|
+
export * from './brand-scraper.js';
|
|
17
|
+
export * from './registry.js';
|
|
18
|
+
export * from './plan.js';
|
|
12
19
|
export { extractJson, sanitizeCompositionJson } from './json.js';
|
|
13
|
-
export { systemPrompt, userPrompt, refineUserPrompt, refineOutlinePrompt, compositionOutline, refineOutlineChars, ratioName, type PromptOptions } from './prompt.js';
|
|
20
|
+
export { systemPrompt, userPrompt, planSystemPrompt, planUserPrompt, isMotionPlan, refineUserPrompt, refineOutlinePrompt, compositionOutline, refineOutlineChars, ratioName, type PromptOptions, type MotionPlan, type MotionBeat } from './prompt.js';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { AiProvider } from './providers.js';
|
|
2
|
+
import type { MotionBeat } from './prompt.js';
|
|
3
|
+
import { type GenerationPath, type Registry } from './registry.js';
|
|
4
|
+
export type BuildPlan = {
|
|
5
|
+
path: GenerationPath;
|
|
6
|
+
template?: string;
|
|
7
|
+
theme?: string;
|
|
8
|
+
idea?: string;
|
|
9
|
+
beats: MotionBeat[];
|
|
10
|
+
reasons: string[];
|
|
11
|
+
};
|
|
12
|
+
export type PlanOptions = {
|
|
13
|
+
brief: string;
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
fps: number;
|
|
17
|
+
durationSeconds: number;
|
|
18
|
+
kind?: string;
|
|
19
|
+
registry: Registry;
|
|
20
|
+
/** Which routes the caller will actually act on (default: all; react additionally needs allowReact). */
|
|
21
|
+
paths?: GenerationPath[];
|
|
22
|
+
/** Full JSON compositions and React code can use sounds and clips; templates cannot. */
|
|
23
|
+
assets?: {
|
|
24
|
+
id: string;
|
|
25
|
+
type: string;
|
|
26
|
+
src: string;
|
|
27
|
+
}[];
|
|
28
|
+
allowReact?: boolean;
|
|
29
|
+
maxAttempts?: number;
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
onProgress?: (message: string) => void;
|
|
32
|
+
};
|
|
33
|
+
/** Parses and validates one reply against the registry. Returns the plan, or the problems to send back to the model. */
|
|
34
|
+
export declare function readBuildPlan(reply: unknown, options: PlanOptions): {
|
|
35
|
+
plan?: BuildPlan;
|
|
36
|
+
problems: string[];
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Plans the video. Returns a validated plan, or undefined when the planner cannot be trusted (no reply within the attempt
|
|
40
|
+
* budget or non-plan-shaped output), so callers fall back to the routing that always worked.
|
|
41
|
+
*/
|
|
42
|
+
export declare function planBuild(provider: AiProvider, options: PlanOptions): Promise<BuildPlan | undefined>;
|
|
@@ -17,8 +17,26 @@ export type PromptOptions = {
|
|
|
17
17
|
}[];
|
|
18
18
|
includeSchema?: boolean;
|
|
19
19
|
narration?: boolean;
|
|
20
|
+
/** Beats and look from the planning pass; the composition must follow them. */
|
|
21
|
+
motionPlan?: MotionPlan;
|
|
20
22
|
};
|
|
23
|
+
export type MotionBeat = {
|
|
24
|
+
name: string;
|
|
25
|
+
takeaway?: string;
|
|
26
|
+
onScreen?: string;
|
|
27
|
+
seconds?: number;
|
|
28
|
+
motion?: string;
|
|
29
|
+
};
|
|
30
|
+
export type MotionPlan = {
|
|
31
|
+
idea?: string;
|
|
32
|
+
look?: Record<string, string>;
|
|
33
|
+
beats: MotionBeat[];
|
|
34
|
+
transition?: string;
|
|
35
|
+
};
|
|
36
|
+
export declare function isMotionPlan(raw: unknown): raw is MotionPlan;
|
|
21
37
|
export declare function systemPrompt(options?: Partial<PromptOptions>): string;
|
|
38
|
+
export declare function planSystemPrompt(): string;
|
|
39
|
+
export declare function planUserPrompt(brief: string, options: PromptOptions): string;
|
|
22
40
|
export declare function userPrompt(brief: string, options: PromptOptions): string;
|
|
23
41
|
export declare function refineUserPrompt(composition: any, instruction: string): string;
|
|
24
42
|
/** Compositions longer than this many characters are shown to the model as an outline, not in full (about 4000 tokens). */
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
export type ChatRole = 'system' | 'user' | 'assistant';
|
|
2
2
|
export type ChatMessage = {
|
|
3
3
|
role: ChatRole;
|
|
4
|
-
content: string;
|
|
4
|
+
content: string | any[];
|
|
5
5
|
};
|
|
6
|
+
export type ChatTask = 'compose' | 'template' | 'heal' | 'brand' | 'batch' | 'vision' | 'fast';
|
|
6
7
|
export type ChatOptions = {
|
|
7
8
|
json?: boolean;
|
|
8
9
|
temperature?: number;
|
|
9
10
|
maxTokens?: number;
|
|
10
11
|
signal?: AbortSignal;
|
|
12
|
+
task?: ChatTask;
|
|
13
|
+
model?: string;
|
|
11
14
|
};
|
|
12
15
|
export type ImageOptions = {
|
|
13
16
|
size?: string;
|
|
@@ -53,7 +56,7 @@ export type AiProvider = {
|
|
|
53
56
|
signal?: AbortSignal;
|
|
54
57
|
}): Promise<Transcript>;
|
|
55
58
|
};
|
|
56
|
-
export type ProviderId = 'groq' | 'mock';
|
|
59
|
+
export type ProviderId = 'anthropic' | 'claude' | 'groq' | 'nvidia' | 'nim' | 'freellmapi' | 'openai' | 'mock';
|
|
57
60
|
export type ProviderConfig = {
|
|
58
61
|
provider?: string;
|
|
59
62
|
model?: string;
|
|
@@ -98,6 +101,36 @@ export declare class GroqProvider implements AiProvider {
|
|
|
98
101
|
signal?: AbortSignal;
|
|
99
102
|
}): Promise<Transcript>;
|
|
100
103
|
}
|
|
104
|
+
export declare class AnthropicProvider implements AiProvider {
|
|
105
|
+
id: string;
|
|
106
|
+
model: string;
|
|
107
|
+
baseUrl: string;
|
|
108
|
+
apiKey: string;
|
|
109
|
+
constructor(config?: ProviderConfig);
|
|
110
|
+
chat(messages: ChatMessage[], options?: ChatOptions): Promise<string>;
|
|
111
|
+
}
|
|
112
|
+
export declare class NvidiaProvider implements AiProvider {
|
|
113
|
+
id: string;
|
|
114
|
+
model: string;
|
|
115
|
+
baseUrl: string;
|
|
116
|
+
apiKey: string;
|
|
117
|
+
constructor(config?: ProviderConfig);
|
|
118
|
+
private headers;
|
|
119
|
+
chat(messages: ChatMessage[], options?: ChatOptions): Promise<string>;
|
|
120
|
+
}
|
|
121
|
+
export declare const TASK_MODEL_PREFERENCES: Record<ChatTask, string[]>;
|
|
122
|
+
export declare function getAvailableFreeLlmModels(baseUrl: string, headers: Record<string, string>, signal?: AbortSignal): Promise<Set<string>>;
|
|
123
|
+
export declare function inferChatTask(messages: ChatMessage[], options?: ChatOptions): ChatTask;
|
|
124
|
+
export declare class FreeLlmApiProvider implements AiProvider {
|
|
125
|
+
id: string;
|
|
126
|
+
model: string;
|
|
127
|
+
baseUrl: string;
|
|
128
|
+
apiKey: string;
|
|
129
|
+
constructor(config?: ProviderConfig);
|
|
130
|
+
private headers;
|
|
131
|
+
resolveModel(task: ChatTask, explicitModel?: string, signal?: AbortSignal): Promise<string>;
|
|
132
|
+
chat(messages: ChatMessage[], options?: ChatOptions): Promise<string>;
|
|
133
|
+
}
|
|
101
134
|
export declare class MockProvider implements AiProvider {
|
|
102
135
|
id: string;
|
|
103
136
|
model: string;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export type GenerationPath = 'template' | 'json' | 'react';
|
|
2
|
+
export type CapabilityKind = 'template' | 'theme' | 'block' | 'component' | 'effect' | 'sound';
|
|
3
|
+
export type Param = {
|
|
4
|
+
name: string;
|
|
5
|
+
type: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
};
|
|
8
|
+
export type Capability = {
|
|
9
|
+
id: string;
|
|
10
|
+
kind: CapabilityKind;
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
/** Which generation paths can use this capability. */
|
|
14
|
+
paths: GenerationPath[];
|
|
15
|
+
version: string;
|
|
16
|
+
/** What the user (or the model filling a template) must supply. */
|
|
17
|
+
params: Param[];
|
|
18
|
+
/** Compatibility text, such as an aspect ratio, the wanted length, or "takes a theme". */
|
|
19
|
+
fit?: string;
|
|
20
|
+
example?: string;
|
|
21
|
+
width?: number;
|
|
22
|
+
height?: number;
|
|
23
|
+
durationSeconds?: number;
|
|
24
|
+
takesTheme?: boolean;
|
|
25
|
+
};
|
|
26
|
+
export type Registry = {
|
|
27
|
+
version: string;
|
|
28
|
+
capabilities: Capability[];
|
|
29
|
+
select(kind: CapabilityKind): Capability[];
|
|
30
|
+
find(kind: CapabilityKind, id: string): Capability | undefined;
|
|
31
|
+
counts(): Record<CapabilityKind, number>;
|
|
32
|
+
};
|
|
33
|
+
/** Entries the calling package knows: its own template, theme and block catalogues. Metadata only; no source JSON. */
|
|
34
|
+
export type TemplateEntry = {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
description: string;
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
durationSeconds: number;
|
|
41
|
+
themed?: boolean;
|
|
42
|
+
variables: {
|
|
43
|
+
name: string;
|
|
44
|
+
type: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
}[];
|
|
47
|
+
};
|
|
48
|
+
export type ThemeEntry = {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
description: string;
|
|
52
|
+
};
|
|
53
|
+
export type BlockEntry = {
|
|
54
|
+
id: string;
|
|
55
|
+
name: string;
|
|
56
|
+
description: string;
|
|
57
|
+
category: string;
|
|
58
|
+
kind: 'scene' | 'overlay';
|
|
59
|
+
durationFrames: number;
|
|
60
|
+
};
|
|
61
|
+
export type RegistryInput = {
|
|
62
|
+
templates?: TemplateEntry[];
|
|
63
|
+
themes?: ThemeEntry[];
|
|
64
|
+
blocks?: BlockEntry[];
|
|
65
|
+
};
|
|
66
|
+
export declare const registryVersion = "1";
|
|
67
|
+
export declare function buildRegistry(input?: RegistryInput): Registry;
|
|
68
|
+
/** The same aspect ratio, within 2%: a 1080x1080 template fits a 1078x1085 canvas. */
|
|
69
|
+
export declare function sameShape(a: {
|
|
70
|
+
width?: number;
|
|
71
|
+
height?: number;
|
|
72
|
+
}, b: {
|
|
73
|
+
width: number;
|
|
74
|
+
height: number;
|
|
75
|
+
}): boolean;
|
|
76
|
+
/** The registry as compact text for the planner prompt, grouped by kind. */
|
|
77
|
+
export declare function describeCapabilities(registry: Registry, fit: {
|
|
78
|
+
width: number;
|
|
79
|
+
height: number;
|
|
80
|
+
allowReact?: boolean;
|
|
81
|
+
}): string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Composition } from '../../core/src/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Stretches or trims a composition to the requested length in seconds. Scenes keep their relative lengths and
|
|
4
|
+
* everything inside them scales by the same factor; the composition is returned unchanged when it already has
|
|
5
|
+
* the requested length.
|
|
6
|
+
*/
|
|
7
|
+
export declare function retimeComposition(composition: Composition, targetSeconds: number): Composition;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { AiProvider, Transcript, TranscriptWord } from './providers.js';
|
|
2
|
+
import { type CutPlan } from './edit.js';
|
|
3
|
+
export type ShortCandidate = {
|
|
4
|
+
/** Seconds into the source where the short starts and ends. */
|
|
5
|
+
from: number;
|
|
6
|
+
to: number;
|
|
7
|
+
/** The rubric total; see planShorts for the parts. */
|
|
8
|
+
score: number;
|
|
9
|
+
breakdown: {
|
|
10
|
+
endsClean: number;
|
|
11
|
+
hook: number;
|
|
12
|
+
density: number;
|
|
13
|
+
lengthFit: number;
|
|
14
|
+
};
|
|
15
|
+
/** The words in the short, in source time. */
|
|
16
|
+
words: TranscriptWord[];
|
|
17
|
+
/** The words as one line — the first sentence is the hook a viewer sees first. */
|
|
18
|
+
text: string;
|
|
19
|
+
};
|
|
20
|
+
export type PlanShortsOptions = {
|
|
21
|
+
/** How many shorts to pick (default 3). */
|
|
22
|
+
count?: number;
|
|
23
|
+
/** Shortest candidate, in seconds (default 15). */
|
|
24
|
+
minSeconds?: number;
|
|
25
|
+
/** Longest candidate, in seconds (default 60). */
|
|
26
|
+
maxSeconds?: number;
|
|
27
|
+
/** A pause longer than this, in seconds, ends a sentence even without punctuation (default 0.8). */
|
|
28
|
+
maxSilence?: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Scores windows of whole sentences as candidate shorts. Every candidate starts at a sentence boundary (a cut
|
|
32
|
+
* there never looks accidental); the rubric rewards a clean ending (2), a hook in the first sentence (2), dense
|
|
33
|
+
* speech (0–1), and a length near the 25–45 s sweet spot (0–1). The best `count` non-overlapping windows win.
|
|
34
|
+
*/
|
|
35
|
+
export declare function planShorts(transcript: Transcript, options?: PlanShortsOptions): ShortCandidate[];
|
|
36
|
+
/** The cut plan for one candidate: tightened like `ove ai edit`, or one continuous stretch with `cut: false`. */
|
|
37
|
+
export declare function shortsCandidatePlan(candidate: ShortCandidate, cut: boolean, maxSilence: number, keepFillers: boolean): CutPlan;
|
|
38
|
+
export type ShortsOptions = {
|
|
39
|
+
/** Path to the long recording (any file FFmpeg reads). */
|
|
40
|
+
clip: string;
|
|
41
|
+
/** Directory to write the projects into: `<outDir>/short-01/`, `<outDir>/short-02/`, … */
|
|
42
|
+
outDir: string;
|
|
43
|
+
count?: number;
|
|
44
|
+
minSeconds?: number;
|
|
45
|
+
maxSeconds?: number;
|
|
46
|
+
width?: number;
|
|
47
|
+
height?: number;
|
|
48
|
+
fps?: number;
|
|
49
|
+
/** Tighten silences and fillers inside each short (default true); false keeps each short one continuous stretch. */
|
|
50
|
+
cut?: boolean;
|
|
51
|
+
maxSilence?: number;
|
|
52
|
+
keepFillers?: boolean;
|
|
53
|
+
captions?: boolean;
|
|
54
|
+
language?: string;
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
onProgress?: (message: string) => void;
|
|
57
|
+
};
|
|
58
|
+
export type ShortResult = {
|
|
59
|
+
dir: string;
|
|
60
|
+
composition: string;
|
|
61
|
+
index: number;
|
|
62
|
+
from: number;
|
|
63
|
+
to: number;
|
|
64
|
+
score: number;
|
|
65
|
+
text: string;
|
|
66
|
+
durationSeconds: number;
|
|
67
|
+
words: number;
|
|
68
|
+
};
|
|
69
|
+
export type ShortsResult = {
|
|
70
|
+
dir: string;
|
|
71
|
+
sourceSeconds: number;
|
|
72
|
+
shorts: ShortResult[];
|
|
73
|
+
};
|
|
74
|
+
/** Transcribes a long recording once and writes the best `count` shorts as projects. */
|
|
75
|
+
export declare function shortsFrom(provider: AiProvider, options: ShortsOptions): Promise<ShortsResult>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type VideoFormat } from '../../ai/src/agent.js';
|
|
2
|
+
/** The agent's settings parsed from the checked arguments index.ts passes ([command, ...args]). */
|
|
3
|
+
export declare function agentArgs(argv: string[]): {
|
|
4
|
+
brief: string | undefined;
|
|
5
|
+
dir: string | undefined;
|
|
6
|
+
url: string | undefined;
|
|
7
|
+
format: VideoFormat;
|
|
8
|
+
durationSeconds: number;
|
|
9
|
+
fps: number;
|
|
10
|
+
shouldRender: boolean;
|
|
11
|
+
noPlan: boolean;
|
|
12
|
+
providerName: string | undefined;
|
|
13
|
+
model: string | undefined;
|
|
14
|
+
};
|
|
15
|
+
export declare function runAgentCli(argv: string[]): Promise<number>;
|