@vibeo/cli 0.3.4 → 0.4.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.
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +1 -0
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/editor.d.ts +2 -0
- package/dist/commands/editor.d.ts.map +1 -0
- package/dist/commands/editor.js +18 -0
- package/dist/commands/editor.js.map +1 -0
- 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/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/skills/vibeo-audio/SKILL.md +283 -0
- package/skills/vibeo-core/SKILL.md +442 -0
- package/skills/vibeo-editor/SKILL.md +348 -0
- package/skills/vibeo-effects/SKILL.md +580 -0
- package/skills/vibeo-extras/SKILL.md +457 -0
- package/skills/vibeo-rendering/SKILL.md +367 -0
- package/skills/vibeo-tiktok/SKILL.md +319 -0
- package/src/commands/create.ts +1 -0
- package/src/commands/editor.ts +23 -0
- package/src/commands/install-skills.ts +16 -75
- package/src/index.ts +15 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# Vibeo Editor (`@vibeo/editor`)
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`@vibeo/editor` is a visual video editing studio for Vibeo. It provides a dark-themed, multi-track timeline editor with canvas preview, property editing, drag-and-drop clip manipulation, audio waveforms, subtitle editing, and export controls.
|
|
6
|
+
|
|
7
|
+
**When to use**: When you need a visual editing interface for Vibeo compositions, or when building a custom video editor UI on top of Vibeo.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### CLI (recommended)
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Open the editor for a Vibeo project
|
|
17
|
+
bunx @vibeo/cli editor --entry src/index.tsx
|
|
18
|
+
|
|
19
|
+
# With custom port
|
|
20
|
+
bunx @vibeo/cli editor --entry src/index.tsx --port 8080
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
In a scaffolded project (`bunx @vibeo/cli create my-video`), just run:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun run editor
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Programmatic
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { Editor } from "@vibeo/editor";
|
|
33
|
+
|
|
34
|
+
const compositions = [
|
|
35
|
+
{
|
|
36
|
+
id: "MyComp",
|
|
37
|
+
name: "My Composition",
|
|
38
|
+
component: MyVideoComponent,
|
|
39
|
+
width: 1920,
|
|
40
|
+
height: 1080,
|
|
41
|
+
fps: 30,
|
|
42
|
+
durationInFrames: 300,
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
function App() {
|
|
47
|
+
return <Editor compositions={compositions} />;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## API Reference
|
|
54
|
+
|
|
55
|
+
### `Editor`
|
|
56
|
+
|
|
57
|
+
The root editor component. Renders the full editor UI.
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
<Editor compositions={compositions} />
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Props:**
|
|
64
|
+
- `compositions` — Array of composition entries:
|
|
65
|
+
- `id: string` — unique composition identifier
|
|
66
|
+
- `name: string` — display name
|
|
67
|
+
- `component: React.ComponentType` — the React component to render
|
|
68
|
+
- `width: number` — composition width in pixels
|
|
69
|
+
- `height: number` — composition height in pixels
|
|
70
|
+
- `fps: number` — frames per second
|
|
71
|
+
- `durationInFrames: number` — total duration in frames
|
|
72
|
+
|
|
73
|
+
### `EditorProvider`
|
|
74
|
+
|
|
75
|
+
Context provider wrapping the editor state. Use if you need to embed editor components individually.
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import { EditorProvider } from "@vibeo/editor";
|
|
79
|
+
|
|
80
|
+
<EditorProvider>
|
|
81
|
+
{/* editor components */}
|
|
82
|
+
</EditorProvider>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Editor Layout
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
91
|
+
│ Toolbar: [⟲ Undo] [⟳ Redo] CompositionName 100% │
|
|
92
|
+
├──────────┬─────────────────────────────────┬────────────────┤
|
|
93
|
+
│ SCENES │ │ PROPERTIES │
|
|
94
|
+
│ & TRACKS │ Canvas Preview │ Canvas: W × H │
|
|
95
|
+
│ │ (live composition with │ Duration: N │
|
|
96
|
+
│ 🎬 Scene1│ checkerboard background) │ FPS: 30 │
|
|
97
|
+
│ 🎵 Audio │ │ │
|
|
98
|
+
│ 📝 Subs │ │ EXPORT │
|
|
99
|
+
│ │ │ Codec: H.264 │
|
|
100
|
+
│ [+Add] ├──── |◀ ▶ ▶| 00:00 / 03:33 1x ──│ [Render video] │
|
|
101
|
+
├──────────┴─────────────────────────────────┴────────────────┤
|
|
102
|
+
│ Timeline: ruler with time markers [- zoom +] │
|
|
103
|
+
│ Track 1: [████ Scene A ████][████ Scene B ████] │
|
|
104
|
+
│ Track 2: [████████ Audio Track ████████] │
|
|
105
|
+
│ Track 3: [Sub1] [Sub2] [Sub3] │
|
|
106
|
+
│ ▲ playhead cursor (draggable) │
|
|
107
|
+
└─────────────────────────────────────────────────────────────┘
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Panels
|
|
111
|
+
|
|
112
|
+
| Panel | Location | Purpose |
|
|
113
|
+
|-------|----------|---------|
|
|
114
|
+
| Toolbar | Top | Undo/redo, composition name, zoom % |
|
|
115
|
+
| Scene List | Left sidebar | Track list with visibility/mute toggles, "+ Add Track" |
|
|
116
|
+
| Canvas | Center top | Live preview of active composition |
|
|
117
|
+
| Playback Controls | Center middle | Play/pause, frame step, timecode, rate, loop |
|
|
118
|
+
| Timeline | Center bottom | Multi-track clip editor with ruler and playhead |
|
|
119
|
+
| Properties | Right sidebar | Editable props for selected clip, composition info, export |
|
|
120
|
+
|
|
121
|
+
All panels are resizable via drag handles between them.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## State Management
|
|
126
|
+
|
|
127
|
+
The editor uses `useReducer` with an immutable state model and undo/redo history.
|
|
128
|
+
|
|
129
|
+
### EditorState
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
interface EditorState {
|
|
133
|
+
tracks: Track[];
|
|
134
|
+
selectedTrackId: string | null;
|
|
135
|
+
selectedClipId: string | null;
|
|
136
|
+
playing: boolean;
|
|
137
|
+
frame: number;
|
|
138
|
+
fps: number;
|
|
139
|
+
durationInFrames: number;
|
|
140
|
+
compositionWidth: number;
|
|
141
|
+
compositionHeight: number;
|
|
142
|
+
playbackRate: number;
|
|
143
|
+
zoom: number;
|
|
144
|
+
scrollX: number;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Track & Clip Types
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
type TrackType = "scene" | "audio" | "subtitle";
|
|
152
|
+
|
|
153
|
+
interface Track {
|
|
154
|
+
id: string;
|
|
155
|
+
name: string;
|
|
156
|
+
type: TrackType;
|
|
157
|
+
clips: Clip[];
|
|
158
|
+
visible: boolean;
|
|
159
|
+
muted: boolean;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
interface Clip {
|
|
163
|
+
id: string;
|
|
164
|
+
trackId: string;
|
|
165
|
+
name: string;
|
|
166
|
+
from: number; // start frame
|
|
167
|
+
durationInFrames: number;
|
|
168
|
+
type: TrackType;
|
|
169
|
+
data: any; // type-specific data
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Actions
|
|
174
|
+
|
|
175
|
+
| Action | Description |
|
|
176
|
+
|--------|-------------|
|
|
177
|
+
| `ADD_TRACK` | Add a new track (scene/audio/subtitle) |
|
|
178
|
+
| `REMOVE_TRACK` | Remove a track and all its clips |
|
|
179
|
+
| `ADD_CLIP` | Add a clip to a track |
|
|
180
|
+
| `REMOVE_CLIP` | Remove a clip |
|
|
181
|
+
| `MOVE_CLIP` | Change a clip's `from` position |
|
|
182
|
+
| `RESIZE_CLIP` | Change a clip's `from` and/or `durationInFrames` |
|
|
183
|
+
| `SELECT_CLIP` | Select a clip (highlights in timeline, shows in properties) |
|
|
184
|
+
| `SET_FRAME` | Set the current playhead frame |
|
|
185
|
+
| `SET_PLAYING` | Toggle playback |
|
|
186
|
+
| `SET_ZOOM` | Set timeline zoom level |
|
|
187
|
+
| `UNDO` | Undo last action |
|
|
188
|
+
| `REDO` | Redo undone action |
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Timeline
|
|
193
|
+
|
|
194
|
+
### Clip Colors
|
|
195
|
+
|
|
196
|
+
| Type | Color | Hex |
|
|
197
|
+
|------|-------|-----|
|
|
198
|
+
| Scene | Purple | `#8b5cf6` |
|
|
199
|
+
| Audio | Green | `#22c55e` |
|
|
200
|
+
| Subtitle | Yellow | `#eab308` |
|
|
201
|
+
|
|
202
|
+
### Timeline Math
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
pixelsPerFrame = basePixelsPerFrame * zoom (base = 2)
|
|
206
|
+
clipLeft = clip.from * pixelsPerFrame
|
|
207
|
+
clipWidth = clip.durationInFrames * pixelsPerFrame
|
|
208
|
+
cursorLeft = currentFrame * pixelsPerFrame
|
|
209
|
+
totalWidth = durationInFrames * pixelsPerFrame
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Drag-and-Drop
|
|
213
|
+
|
|
214
|
+
- **Move clip**: drag the clip body to change its `from` position
|
|
215
|
+
- **Resize clip**: drag left/right edges to trim `from`/`durationInFrames`
|
|
216
|
+
- **Minimum**: 1 frame
|
|
217
|
+
- **Snap**: rounds to nearest integer frame
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Keyboard Shortcuts
|
|
222
|
+
|
|
223
|
+
| Key | Action |
|
|
224
|
+
|-----|--------|
|
|
225
|
+
| Space | Play / Pause |
|
|
226
|
+
| ArrowLeft | Previous frame |
|
|
227
|
+
| ArrowRight | Next frame |
|
|
228
|
+
| Shift+ArrowLeft | -10 frames |
|
|
229
|
+
| Shift+ArrowRight | +10 frames |
|
|
230
|
+
| Cmd/Ctrl+Z | Undo |
|
|
231
|
+
| Cmd/Ctrl+Shift+Z | Redo |
|
|
232
|
+
| Delete / Backspace | Remove selected clip |
|
|
233
|
+
| Escape | Deselect |
|
|
234
|
+
| ? | Show keyboard shortcuts |
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Dark Theme
|
|
239
|
+
|
|
240
|
+
All colors are defined in `@vibeo/editor/theme/colors`:
|
|
241
|
+
|
|
242
|
+
| Token | Value | Usage |
|
|
243
|
+
|-------|-------|-------|
|
|
244
|
+
| `bg` | `#0d1117` | Darkest background |
|
|
245
|
+
| `surface` | `#161b22` | Panel backgrounds |
|
|
246
|
+
| `surfaceHover` | `#1c2333` | Hover states |
|
|
247
|
+
| `border` | `#30363d` | Borders |
|
|
248
|
+
| `text` | `#e6edf3` | Primary text |
|
|
249
|
+
| `textMuted` | `#7d8590` | Secondary text |
|
|
250
|
+
| `accent` | `#58a6ff` | Playhead, selection, focus rings |
|
|
251
|
+
| `scene` | `#8b5cf6` | Scene clip color |
|
|
252
|
+
| `audio` | `#22c55e` | Audio clip color |
|
|
253
|
+
| `subtitle` | `#eab308` | Subtitle clip color |
|
|
254
|
+
| `danger` | `#f85149` | Delete, errors |
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Common Patterns
|
|
259
|
+
|
|
260
|
+
### Adding a scene track with a clip
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
dispatch({ type: "ADD_TRACK", payload: { id: "track-1", name: "Main Scene", type: "scene" } });
|
|
264
|
+
dispatch({
|
|
265
|
+
type: "ADD_CLIP",
|
|
266
|
+
payload: {
|
|
267
|
+
id: "clip-1",
|
|
268
|
+
trackId: "track-1",
|
|
269
|
+
name: "Intro",
|
|
270
|
+
from: 0,
|
|
271
|
+
durationInFrames: 90,
|
|
272
|
+
type: "scene",
|
|
273
|
+
data: { component: IntroScene },
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Adding an audio track
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
dispatch({ type: "ADD_TRACK", payload: { id: "track-2", name: "Background Music", type: "audio" } });
|
|
282
|
+
dispatch({
|
|
283
|
+
type: "ADD_CLIP",
|
|
284
|
+
payload: {
|
|
285
|
+
id: "clip-2",
|
|
286
|
+
trackId: "track-2",
|
|
287
|
+
name: "Music",
|
|
288
|
+
from: 0,
|
|
289
|
+
durationInFrames: 300,
|
|
290
|
+
type: "audio",
|
|
291
|
+
data: { src: "/music.mp3", volume: 0.8 },
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Adding subtitle cues
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
dispatch({ type: "ADD_TRACK", payload: { id: "track-3", name: "Subtitles", type: "subtitle" } });
|
|
300
|
+
dispatch({
|
|
301
|
+
type: "ADD_CLIP",
|
|
302
|
+
payload: {
|
|
303
|
+
id: "sub-1",
|
|
304
|
+
trackId: "track-3",
|
|
305
|
+
name: "Welcome",
|
|
306
|
+
from: 15,
|
|
307
|
+
durationInFrames: 75,
|
|
308
|
+
type: "subtitle",
|
|
309
|
+
data: { text: "Welcome to the demo", fontSize: 36, color: "white", position: "bottom" },
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Gotchas
|
|
317
|
+
|
|
318
|
+
1. **Editor creates its own providers** — it wraps content in `VibeoRoot`, `TimelineProvider`, etc. Don't nest it inside another `VibeoRoot` manually.
|
|
319
|
+
|
|
320
|
+
2. **Compositions must export a `Root` function** — the CLI editor command imports `{ Root }` from your entry file to register compositions.
|
|
321
|
+
|
|
322
|
+
3. **The editor renders the Player internally** — it uses `@vibeo/player` to show the canvas preview. Frame sync is handled automatically.
|
|
323
|
+
|
|
324
|
+
4. **Undo/redo is state-level** — every dispatched action pushes to the history stack. `UNDO`/`REDO` actions navigate the stack.
|
|
325
|
+
|
|
326
|
+
5. **Timeline zoom range** — 0.1x to 10x. Default is 1x where `pixelsPerFrame = 2`.
|
|
327
|
+
|
|
328
|
+
6. **Audio waveform** — rendered as canvas bars inside audio clips. If audio analysis isn't available, shows flat placeholder bars.
|
|
329
|
+
|
|
330
|
+
7. **Subtitle inline editing** — double-click a subtitle cue in the timeline to edit text inline. Press Escape or click outside to save.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## LLM & Agent Integration
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
# Get CLI docs including editor command
|
|
338
|
+
bunx @vibeo/cli --llms
|
|
339
|
+
|
|
340
|
+
# Get editor command schema
|
|
341
|
+
bunx @vibeo/cli editor --schema
|
|
342
|
+
|
|
343
|
+
# Install skills for all LLM tools
|
|
344
|
+
bunx @vibeo/cli install-skills
|
|
345
|
+
|
|
346
|
+
# Run as MCP server (includes editor command)
|
|
347
|
+
bunx @vibeo/cli --mcp
|
|
348
|
+
```
|