@vibeo/cli 0.3.4 → 0.3.5
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/commands/install-skills.d.ts.map +1 -1
- package/dist/commands/install-skills.js +13 -76
- package/dist/commands/install-skills.js.map +1 -1
- package/package.json +2 -1
- package/skills/vibeo-audio/SKILL.md +283 -0
- package/skills/vibeo-core/SKILL.md +380 -0
- package/skills/vibeo-effects/SKILL.md +432 -0
- package/skills/vibeo-extras/SKILL.md +457 -0
- package/skills/vibeo-rendering/SKILL.md +364 -0
- package/src/commands/install-skills.ts +16 -75
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# Vibeo Rendering (`@vibeo/renderer` + `@vibeo/cli`)
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`@vibeo/renderer` provides the headless rendering pipeline: bundling a Vibeo project, launching Playwright browser instances, capturing frames, and stitching them into video via FFmpeg. `@vibeo/cli` wraps this in a CLI.
|
|
6
|
+
|
|
7
|
+
**When to use**: When you need to render a composition to a video file, preview it, or list available compositions.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## CLI Commands
|
|
12
|
+
|
|
13
|
+
### `vibeo render`
|
|
14
|
+
|
|
15
|
+
Render a composition to a video file.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bunx vibeo render --entry src/index.tsx --composition MyComp --output out.mp4
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Required flags**:
|
|
22
|
+
| Flag | Description |
|
|
23
|
+
|------|-------------|
|
|
24
|
+
| `--entry <path>` | Path to the root file with compositions |
|
|
25
|
+
| `--composition <id>` | Composition ID to render |
|
|
26
|
+
|
|
27
|
+
**Optional flags**:
|
|
28
|
+
| Flag | Default | Description |
|
|
29
|
+
|------|---------|-------------|
|
|
30
|
+
| `--output <path>` | `out/<compositionId>.<ext>` | Output file path |
|
|
31
|
+
| `--fps <number>` | Composition fps | Override frames per second |
|
|
32
|
+
| `--frames <range>` | Full duration | Frame range, e.g. `"0-100"` |
|
|
33
|
+
| `--codec <codec>` | `h264` | `h264 \| h265 \| vp9 \| prores` |
|
|
34
|
+
| `--concurrency <n>` | `CPU cores / 2` | Parallel browser tabs |
|
|
35
|
+
| `--image-format <fmt>` | `png` | `png \| jpeg` |
|
|
36
|
+
| `--quality <n>` | `80` | JPEG quality / CRF value (0-100) |
|
|
37
|
+
|
|
38
|
+
### `vibeo preview`
|
|
39
|
+
|
|
40
|
+
Start a dev server with live preview in the browser.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
bunx vibeo preview --entry src/index.tsx --port 3000
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Required flags**:
|
|
47
|
+
| Flag | Description |
|
|
48
|
+
|------|-------------|
|
|
49
|
+
| `--entry <path>` | Path to the root file with compositions |
|
|
50
|
+
|
|
51
|
+
**Optional flags**:
|
|
52
|
+
| Flag | Default | Description |
|
|
53
|
+
|------|---------|-------------|
|
|
54
|
+
| `--port <number>` | `3000` | Port for the dev server |
|
|
55
|
+
| `--help`, `-h` | — | Show help |
|
|
56
|
+
|
|
57
|
+
### `vibeo list`
|
|
58
|
+
|
|
59
|
+
List all registered compositions in the project. Bundles the entry, launches a headless browser, and prints a table of composition IDs with their dimensions, FPS, and duration.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
bunx vibeo list --entry src/index.tsx
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Required flags**:
|
|
66
|
+
| Flag | Description |
|
|
67
|
+
|------|-------------|
|
|
68
|
+
| `--entry <path>` | Path to the root file with compositions |
|
|
69
|
+
|
|
70
|
+
**Optional flags**:
|
|
71
|
+
| Flag | Description |
|
|
72
|
+
|------|-------------|
|
|
73
|
+
| `--help`, `-h` | Show help |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Programmatic Rendering API
|
|
78
|
+
|
|
79
|
+
### `renderComposition(config, compositionInfo): Promise<string>`
|
|
80
|
+
|
|
81
|
+
Full render orchestration: bundle → capture frames → stitch video. Returns the path to the final output file.
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { renderComposition } from "@vibeo/renderer";
|
|
85
|
+
|
|
86
|
+
const outputPath = await renderComposition(
|
|
87
|
+
{
|
|
88
|
+
entry: "src/index.tsx",
|
|
89
|
+
compositionId: "MyComp",
|
|
90
|
+
outputPath: "out/video.mp4",
|
|
91
|
+
codec: "h264",
|
|
92
|
+
imageFormat: "png",
|
|
93
|
+
quality: 80,
|
|
94
|
+
fps: null, // use composition fps
|
|
95
|
+
frameRange: null, // render all frames
|
|
96
|
+
concurrency: 4,
|
|
97
|
+
pixelFormat: "yuv420p",
|
|
98
|
+
onProgress: (p) => console.log(`${(p.percent * 100).toFixed(1)}%`),
|
|
99
|
+
},
|
|
100
|
+
{ width: 1920, height: 1080, fps: 30, durationInFrames: 300 },
|
|
101
|
+
);
|
|
102
|
+
console.log(`Rendered to ${outputPath}`);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### `RenderConfig`
|
|
106
|
+
|
|
107
|
+
| Field | Type | Description |
|
|
108
|
+
|-------|------|-------------|
|
|
109
|
+
| `entry` | `string` | Path to the entry file |
|
|
110
|
+
| `compositionId` | `string` | Composition ID |
|
|
111
|
+
| `outputPath` | `string` | Output video path |
|
|
112
|
+
| `codec` | `Codec` | Video codec |
|
|
113
|
+
| `imageFormat` | `ImageFormat` | `"png" \| "jpeg"` |
|
|
114
|
+
| `quality` | `number` | 0-100 quality/CRF |
|
|
115
|
+
| `fps` | `number \| null` | FPS override |
|
|
116
|
+
| `frameRange` | `FrameRange \| null` | `[start, end]` or null for all |
|
|
117
|
+
| `concurrency` | `number` | Parallel browser tabs |
|
|
118
|
+
| `pixelFormat` | `string` | FFmpeg pixel format |
|
|
119
|
+
| `onProgress?` | `(progress: RenderProgress) => void` | Progress callback |
|
|
120
|
+
|
|
121
|
+
### `RenderProgress`
|
|
122
|
+
|
|
123
|
+
| Field | Type | Description |
|
|
124
|
+
|-------|------|-------------|
|
|
125
|
+
| `framesRendered` | `number` | Frames completed |
|
|
126
|
+
| `totalFrames` | `number` | Total frames |
|
|
127
|
+
| `percent` | `number` | 0-1 fraction |
|
|
128
|
+
| `etaMs` | `number \| null` | Estimated time remaining (ms) |
|
|
129
|
+
|
|
130
|
+
### Browser Lifecycle
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { launchBrowser, closeBrowser, createPage } from "@vibeo/renderer";
|
|
134
|
+
|
|
135
|
+
const browser = await launchBrowser();
|
|
136
|
+
const page = await createPage(browser, 1920, 1080); // browser, width, height
|
|
137
|
+
// ... render frames ...
|
|
138
|
+
await closeBrowser(); // closes the singleton browser, no argument needed
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Bundler
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
import { bundle } from "@vibeo/renderer";
|
|
145
|
+
|
|
146
|
+
const result: BundleResult = await bundle(entryPath);
|
|
147
|
+
// result.outDir — bundled output directory
|
|
148
|
+
// result.url — URL to access bundled app
|
|
149
|
+
// result.cleanup() — stop server and remove temp files
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Frame Operations
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { seekToFrame, loadBundle, captureFrame } from "@vibeo/renderer";
|
|
156
|
+
|
|
157
|
+
await loadBundle(page, bundleUrl);
|
|
158
|
+
await seekToFrame(page, 42, "MyComp");
|
|
159
|
+
const filePath = await captureFrame(page, outputDir, frameNumber, {
|
|
160
|
+
imageFormat: "png",
|
|
161
|
+
quality: 80, // optional, for jpeg
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Frame Range Utilities
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import { parseFrameRange, getRealFrameRange, validateFrameRange } from "@vibeo/renderer";
|
|
169
|
+
|
|
170
|
+
const range = parseFrameRange("0-100", 300); // parseFrameRange(input, durationInFrames) → [0, 100]
|
|
171
|
+
const real = getRealFrameRange(300, range); // getRealFrameRange(durationInFrames, frameRange) → [0, 100]
|
|
172
|
+
const fullRange = getRealFrameRange(300, null); // → [0, 299]
|
|
173
|
+
validateFrameRange([0, 100], 300); // throws on invalid
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### FFmpeg Stitching
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import { stitchFrames, getContainerExt, stitchAudio } from "@vibeo/renderer";
|
|
180
|
+
|
|
181
|
+
await stitchFrames({
|
|
182
|
+
framesDir: "/tmp/frames",
|
|
183
|
+
outputPath: "out.mp4",
|
|
184
|
+
fps: 30,
|
|
185
|
+
codec: "h264",
|
|
186
|
+
imageFormat: "png",
|
|
187
|
+
pixelFormat: "yuv420p",
|
|
188
|
+
quality: 80,
|
|
189
|
+
width: 1920,
|
|
190
|
+
height: 1080,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const ext = getContainerExt("vp9"); // "webm"
|
|
194
|
+
|
|
195
|
+
await stitchAudio({
|
|
196
|
+
videoPath: "out.mp4",
|
|
197
|
+
audioPaths: ["/tmp/audio.wav"],
|
|
198
|
+
outputPath: "final.mp4",
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Parallel Rendering
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
import { parallelRender } from "@vibeo/renderer";
|
|
206
|
+
|
|
207
|
+
await parallelRender({
|
|
208
|
+
browser, // Playwright Browser instance
|
|
209
|
+
bundleUrl, // URL from bundle()
|
|
210
|
+
compositionId: "MyComp",
|
|
211
|
+
frameRange: [0, 299], // [start, end] inclusive
|
|
212
|
+
outputDir: "/tmp/frames",
|
|
213
|
+
width: 1920,
|
|
214
|
+
height: 1080,
|
|
215
|
+
concurrency: 8,
|
|
216
|
+
imageFormat: "png",
|
|
217
|
+
quality: 80, // optional
|
|
218
|
+
onProgress: (p) => {}, // optional RenderProgress callback
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Codec Options
|
|
225
|
+
|
|
226
|
+
| Codec | Container | Use Case |
|
|
227
|
+
|-------|-----------|----------|
|
|
228
|
+
| `h264` | `.mp4` | General purpose, best compatibility |
|
|
229
|
+
| `h265` | `.mp4` | Better compression, less compatible |
|
|
230
|
+
| `vp9` | `.webm` | Web delivery, open format |
|
|
231
|
+
| `prores` | `.mov` | Professional editing, lossless quality |
|
|
232
|
+
|
|
233
|
+
### When to use each
|
|
234
|
+
|
|
235
|
+
- **`h264`**: Default. Works everywhere. Good quality/size trade-off.
|
|
236
|
+
- **`h265`**: 30-50% smaller files than h264 at same quality. Use when file size matters and playback devices support it.
|
|
237
|
+
- **`vp9`**: Best for web embedding. Royalty-free.
|
|
238
|
+
- **`prores`**: Editing workflows (Premiere, DaVinci). Large files but no quality loss.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Output Format Options
|
|
243
|
+
|
|
244
|
+
- **`png` frames**: Lossless intermediate frames. Larger but no quality loss during capture.
|
|
245
|
+
- **`jpeg` frames**: Lossy but much smaller intermediate files. Use `--quality` to control (80 is good default).
|
|
246
|
+
- **`pixelFormat: "yuv420p"`**: Standard for h264/h265. Use `"yuv444p"` for maximum color fidelity with prores.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Parallel Rendering Config
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
# Use 8 parallel browser tabs
|
|
254
|
+
bunx vibeo render --entry src/index.tsx --composition MyComp --concurrency 8
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The frame range is split evenly across tabs. Default concurrency is `CPU cores / 2`.
|
|
258
|
+
|
|
259
|
+
For a 300-frame video with `--concurrency 4`:
|
|
260
|
+
- Tab 1: frames 0-74
|
|
261
|
+
- Tab 2: frames 75-149
|
|
262
|
+
- Tab 3: frames 150-224
|
|
263
|
+
- Tab 4: frames 225-299
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Types
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
import type {
|
|
271
|
+
RenderConfig,
|
|
272
|
+
RenderProgress,
|
|
273
|
+
Codec,
|
|
274
|
+
ImageFormat,
|
|
275
|
+
FrameRange,
|
|
276
|
+
StitchOptions,
|
|
277
|
+
AudioMuxOptions,
|
|
278
|
+
BundleResult,
|
|
279
|
+
} from "@vibeo/renderer";
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Gotchas and Tips
|
|
285
|
+
|
|
286
|
+
1. **FFmpeg must be installed** and available on `PATH` for stitching to work.
|
|
287
|
+
|
|
288
|
+
2. **Playwright is required** — the renderer uses it for headless browser rendering. Install with `bunx playwright install chromium`.
|
|
289
|
+
|
|
290
|
+
3. **Frame capture is the bottleneck** — increase `--concurrency` on machines with many cores to speed up rendering.
|
|
291
|
+
|
|
292
|
+
4. **`--frames` range is inclusive** — `--frames=0-100` renders 101 frames.
|
|
293
|
+
|
|
294
|
+
5. **Output directory is created automatically** — you don't need to `mkdir` before rendering.
|
|
295
|
+
|
|
296
|
+
6. **`pixelFormat: "yuv420p"`** is required for most players to handle h264/h265 correctly.
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## LLM & Agent Integration
|
|
302
|
+
|
|
303
|
+
Vibeo's CLI is built with [incur](https://github.com/wevm/incur), making it natively discoverable by AI agents and LLMs.
|
|
304
|
+
|
|
305
|
+
### Discovering the API
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
# Get a compact summary of all CLI commands (ideal for LLM system prompts)
|
|
309
|
+
bunx @vibeo/cli --llms
|
|
310
|
+
|
|
311
|
+
# Get the full manifest with schemas, examples, and argument details
|
|
312
|
+
bunx @vibeo/cli --llms-full
|
|
313
|
+
|
|
314
|
+
# Get JSON Schema for a specific command (useful for structured tool calls)
|
|
315
|
+
bunx @vibeo/cli render --schema
|
|
316
|
+
bunx @vibeo/cli create --schema
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Using as an MCP Server
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
# Start Vibeo as an MCP (Model Context Protocol) server
|
|
323
|
+
bunx @vibeo/cli --mcp
|
|
324
|
+
|
|
325
|
+
# Register as a persistent MCP server for your agent
|
|
326
|
+
bunx @vibeo/cli mcp add
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
This lets LLMs call `create`, `render`, `preview`, and `list` as structured tool calls through the MCP protocol.
|
|
330
|
+
|
|
331
|
+
### Generating Skill Files
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
# Sync skill files to your agent's skill directory
|
|
335
|
+
bunx @vibeo/cli skills add
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
This generates markdown skill files that agents like Claude Code can discover and use to write Vibeo code without reading source.
|
|
339
|
+
|
|
340
|
+
### Agent-Friendly Output
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
# Output as JSON for programmatic consumption
|
|
344
|
+
bunx @vibeo/cli list --entry src/index.tsx --format json
|
|
345
|
+
|
|
346
|
+
# Output as YAML
|
|
347
|
+
bunx @vibeo/cli list --entry src/index.tsx --format yaml
|
|
348
|
+
|
|
349
|
+
# Filter output to specific keys
|
|
350
|
+
bunx @vibeo/cli list --entry src/index.tsx --filter-output compositions[0].id
|
|
351
|
+
|
|
352
|
+
# Count tokens in output (useful for context window planning)
|
|
353
|
+
bunx @vibeo/cli render --schema --token-count
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### How LLMs Should Use Vibeo
|
|
357
|
+
|
|
358
|
+
1. **Discover commands**: Run `bunx @vibeo/cli --llms` to get the command manifest
|
|
359
|
+
2. **Create a project**: `bunx @vibeo/cli create my-video --template basic`
|
|
360
|
+
3. **Edit `src/index.tsx`**: Write React components using `@vibeo/core` hooks and components
|
|
361
|
+
4. **Preview**: `bunx @vibeo/cli preview --entry src/index.tsx`
|
|
362
|
+
5. **Render**: `bunx @vibeo/cli render --entry src/index.tsx --composition MyComp`
|
|
363
|
+
|
|
364
|
+
All commands accept `--format json` for structured output that LLMs can parse reliably.
|
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
import { resolve, join, dirname } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
2
3
|
import { mkdir, writeFile, readFile } from "node:fs/promises";
|
|
3
4
|
import { existsSync } from "node:fs";
|
|
4
5
|
import { homedir } from "node:os";
|
|
5
6
|
|
|
6
7
|
// ---------------------------------------------------------------------------
|
|
7
|
-
//
|
|
8
|
+
// Skill loader — resolves from the CLI package's own skills/ directory
|
|
8
9
|
// ---------------------------------------------------------------------------
|
|
9
10
|
|
|
11
|
+
const SKILL_NAMES = ["vibeo-core", "vibeo-audio", "vibeo-effects", "vibeo-extras", "vibeo-rendering"];
|
|
12
|
+
|
|
10
13
|
async function loadSkills(): Promise<Record<string, string>> {
|
|
11
|
-
//
|
|
14
|
+
// Resolve from this file's location — skills/ is shipped alongside dist/ in the npm package
|
|
15
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
16
|
+
const thisDir = dirname(thisFile);
|
|
17
|
+
|
|
18
|
+
// From dist/commands/install-skills.js → ../../skills
|
|
19
|
+
// From src/commands/install-skills.ts → ../../skills
|
|
12
20
|
const candidates = [
|
|
13
|
-
join(
|
|
14
|
-
join(
|
|
21
|
+
join(thisDir, "..", "..", "skills"), // from dist/commands/ or src/commands/
|
|
22
|
+
join(thisDir, "..", "..", "..", "skills"), // from deeper nesting
|
|
23
|
+
join(process.cwd(), "skills"), // from project root
|
|
15
24
|
];
|
|
16
25
|
|
|
17
26
|
for (const dir of candidates) {
|
|
18
|
-
const names = ["vibeo-core", "vibeo-audio", "vibeo-effects", "vibeo-extras", "vibeo-rendering"];
|
|
19
27
|
const skills: Record<string, string> = {};
|
|
20
28
|
let found = true;
|
|
21
29
|
|
|
22
|
-
for (const name of
|
|
30
|
+
for (const name of SKILL_NAMES) {
|
|
23
31
|
const path = join(dir, name, "SKILL.md");
|
|
24
32
|
if (existsSync(path)) {
|
|
25
33
|
skills[name] = await readFile(path, "utf-8");
|
|
@@ -32,78 +40,11 @@ async function loadSkills(): Promise<Record<string, string>> {
|
|
|
32
40
|
if (found) return skills;
|
|
33
41
|
}
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
vibeo: getEmbeddedSkill(),
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function getEmbeddedSkill(): string {
|
|
42
|
-
return `# Vibeo — React Video Framework
|
|
43
|
-
|
|
44
|
-
Vibeo is a React-based programmatic video framework. Write video compositions as React components, preview in the browser, and render to video with FFmpeg.
|
|
45
|
-
|
|
46
|
-
## Quick Reference
|
|
47
|
-
|
|
48
|
-
\`\`\`bash
|
|
49
|
-
# Get full CLI docs
|
|
50
|
-
bunx @vibeo/cli --llms-full
|
|
51
|
-
|
|
52
|
-
# Create a project
|
|
53
|
-
bunx @vibeo/cli create my-video --template basic
|
|
54
|
-
|
|
55
|
-
# Preview
|
|
56
|
-
bunx @vibeo/cli preview --entry src/index.tsx
|
|
57
|
-
|
|
58
|
-
# Render
|
|
59
|
-
bunx @vibeo/cli render --entry src/index.tsx --composition MyComp
|
|
60
|
-
|
|
61
|
-
# List compositions
|
|
62
|
-
bunx @vibeo/cli list --entry src/index.tsx
|
|
63
|
-
\`\`\`
|
|
64
|
-
|
|
65
|
-
## Packages
|
|
66
|
-
|
|
67
|
-
- \`@vibeo/core\` — Composition, Sequence, Loop, useCurrentFrame, useVideoConfig, interpolate, easing
|
|
68
|
-
- \`@vibeo/audio\` — Audio/Video components, 48kHz sync, volume curves, audio mixing
|
|
69
|
-
- \`@vibeo/effects\` — useKeyframes, useSpring, Transition (fade/wipe/slide/dissolve), useAudioData
|
|
70
|
-
- \`@vibeo/extras\` — Subtitle (SRT/VTT), AudioWaveform, AudioSpectrogram, SceneGraph, AudioMix
|
|
71
|
-
- \`@vibeo/player\` — Interactive Player component with controls
|
|
72
|
-
- \`@vibeo/renderer\` — Headless rendering via Playwright + FFmpeg
|
|
73
|
-
- \`@vibeo/cli\` — CLI with incur (supports --llms, --mcp, --schema)
|
|
74
|
-
|
|
75
|
-
## Core Pattern
|
|
76
|
-
|
|
77
|
-
\`\`\`tsx
|
|
78
|
-
import { Composition, Sequence, VibeoRoot, useCurrentFrame, useVideoConfig, interpolate } from "@vibeo/core";
|
|
79
|
-
|
|
80
|
-
function MyScene() {
|
|
81
|
-
const frame = useCurrentFrame();
|
|
82
|
-
const { width, height, fps } = useVideoConfig();
|
|
83
|
-
const opacity = interpolate(frame, [0, 30], [0, 1], { extrapolateRight: "clamp" });
|
|
84
|
-
return <div style={{ width, height, opacity }}>Hello</div>;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export function Root() {
|
|
88
|
-
return (
|
|
89
|
-
<VibeoRoot>
|
|
90
|
-
<Composition id="MyComp" component={MyScene} width={1920} height={1080} fps={30} durationInFrames={150} />
|
|
91
|
-
</VibeoRoot>
|
|
43
|
+
throw new Error(
|
|
44
|
+
"Could not find skill files. Make sure the @vibeo/cli package is installed correctly.",
|
|
92
45
|
);
|
|
93
46
|
}
|
|
94
|
-
\`\`\`
|
|
95
|
-
|
|
96
|
-
## Key Math
|
|
97
47
|
|
|
98
|
-
- Frame to time: \`time = frame / fps\`
|
|
99
|
-
- Samples per frame (audio): \`(48000 * 2) / fps\`
|
|
100
|
-
- Media time with playback rate: uses interpolation with rate scaling
|
|
101
|
-
- Sequence relative frame: \`absoluteFrame - (cumulatedFrom + relativeFrom)\`
|
|
102
|
-
- Loop iteration: \`floor(currentFrame / durationInFrames)\`
|
|
103
|
-
|
|
104
|
-
For full API details, run \`bunx @vibeo/cli --llms-full\` or \`bunx @vibeo/cli <command> --schema\`.
|
|
105
|
-
`;
|
|
106
|
-
}
|
|
107
48
|
|
|
108
49
|
// ---------------------------------------------------------------------------
|
|
109
50
|
// LLM tool targets
|