@lalalic/markcut 2.2.9 → 2.3.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/package.json
CHANGED
package/skills/markcut/SKILL.md
CHANGED
|
@@ -23,11 +23,6 @@ see [docs/markdown-descriptive.md](docs/markdown-descriptive.md) for full detail
|
|
|
23
23
|
### Video Variants
|
|
24
24
|
- define variants for different video configurations, such as different languages, aspects, platforms
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
### Templates
|
|
28
|
-
- Templates in ``docs/templates/`` provide ready-to-use video structures for `orchestrator` agents, use them as starting point to create your own videos.
|
|
29
|
-
|
|
30
|
-
|
|
31
26
|
### Viral Story requires
|
|
32
27
|
- **Hooks** : why should the viewer watch this?
|
|
33
28
|
- **Conflict** : what challenges or obstacles do the characters face?
|
|
@@ -36,11 +31,22 @@ see [docs/markdown-descriptive.md](docs/markdown-descriptive.md) for full detail
|
|
|
36
31
|
- **Call to action** : what should the viewer do next?
|
|
37
32
|
- **Open ending** : does the story leave room for interpretation or continuation?
|
|
38
33
|
|
|
34
|
+
### TTS, TTI, TTV, STT media generation
|
|
35
|
+
markcut implements a **media generation pipeline** to generate TTS, TTI, TTV, STT media automatically.
|
|
36
|
+
- `npx @lalalic/markcut --show-clis` to see the default CLIs for TTS, TTI, TTV, STT media generation.
|
|
37
|
+
- `orchestrator` agent DONT generate media directly
|
|
38
|
+
|
|
39
39
|
## 3. CLI
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
npx @lalalic/markcut <command> [options]
|
|
43
43
|
npx @lalalic/markcut --help # get overall information
|
|
44
|
+
npx @lalalic/markcut --show-clis # get command specific information
|
|
45
|
+
npx @lalalic/markcut preview <file> # assemble and preview the video with a local server, and chat to edit the video and auto refresh
|
|
46
|
+
npx @lalalic/markcut render <file> # render the video to mp4
|
|
47
|
+
npx @lalalic/markcut vision <folder> # vision understanding medias in folder
|
|
48
|
+
npx @lalalic/markcut vision <folder> --label # full pipeline vision understanding medias in folder, and provide ui to label the medias with text, time ranges
|
|
49
|
+
|
|
44
50
|
```
|
|
45
51
|
|
|
46
52
|
---
|
|
@@ -60,8 +66,6 @@ some common issues (photo or video can't be displayed, audio missing), take belo
|
|
|
60
66
|
| Topic | File |
|
|
61
67
|
|-------|------|
|
|
62
68
|
| Markdown descriptive format (primary authoring format) | [docs/markdown-descriptive.md](docs/markdown-descriptive.md) |
|
|
63
|
-
| Label system (browse, label, export labels.json) | [docs/label-mode.md](docs/label-mode.md) |
|
|
64
|
-
| Player servers (label + edit mode) | [docs/edit-mode.md](docs/edit-mode.md) |
|
|
65
69
|
|
|
66
70
|
|
|
67
71
|
## common used components
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
# Watch Mode
|
|
2
|
-
|
|
3
|
-
> `preview <file.md> --edit` — live editing loop with AI-assisted JSON editing.
|
|
4
|
-
|
|
5
|
-
Edit mode gives you a browser player that **automatically reloads** when the source file changes, plus an **edit input** that calls an AI coding agent (pi) to make changes on your behalf.
|
|
6
|
-
|
|
7
|
-
Generated artifacts (TTS audio, compiled includes, component bundles) are
|
|
8
|
-
stored under `.markcut/` next to the source file — see [SKILL.md](../SKILL.md) for the full layout.
|
|
9
|
-
|
|
10
|
-
## Quickstart
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
cd remotion-engine
|
|
14
|
-
npm run preview -- sample-visual.json --edit
|
|
15
|
-
# → Browser opens, terminal blocks until you close it
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Architecture
|
|
19
|
-
|
|
20
|
-
```
|
|
21
|
-
┌─────────────┐ HTTP ┌──────────────────┐ spawn ┌──────────┐
|
|
22
|
-
│ Browser │◄──────────────►│ player/server │◄────────────►│ pi CLI │
|
|
23
|
-
│ (Chrome) │ SSE │ .mjs (Node) │ one-shot │ (agent) │
|
|
24
|
-
└──────┬──────┘ └────────┬─────────┘ └──────────┘
|
|
25
|
-
│ │
|
|
26
|
-
│ POST /api/edit │ fs.watchFile
|
|
27
|
-
│ {text: "make text bigger"} │ (poll every 500ms)
|
|
28
|
-
│ │
|
|
29
|
-
│ GET /api/video-data ▼
|
|
30
|
-
│ ← stream tree JSON ┌──────────────┐
|
|
31
|
-
│ │ stream tree │
|
|
32
|
-
│ EventSource │ .json (file) │
|
|
33
|
-
│ /api/events └──────────────┘
|
|
34
|
-
│ ← {type:"reload"} ▲
|
|
35
|
-
│ │
|
|
36
|
-
│ window.dispatchEvent │ pi edits
|
|
37
|
-
│ ("refresh-player") │ this file
|
|
38
|
-
│ │
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## File: `src/player/server.mjs`
|
|
42
|
-
|
|
43
|
-
### Server startup (`cli.mjs` → `server.mjs`)
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
node src/render/cli.mjs preview file.json --edit --port 3031
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
1. `cli.mjs` spawns `server.mjs` with `--edit` flag
|
|
50
|
-
2. `server.mjs` parses `file.json` to build a recursive tree description
|
|
51
|
-
3. Starts `fs.watchFile(file.json, {interval:500})` — polls every 500ms for changes
|
|
52
|
-
4. Starts HTTP server on specified port
|
|
53
|
-
5. Auto-opens browser via `open http://localhost:PORT`
|
|
54
|
-
|
|
55
|
-
### Page served
|
|
56
|
-
|
|
57
|
-
The HTML page loads two scripts:
|
|
58
|
-
|
|
59
|
-
| Script | Source | Role |
|
|
60
|
-
|--------|--------|------|
|
|
61
|
-
| `player.js` | Bundled esbuild output from `src/player/browser.tsx` | Renders the stream tree using `@remotion/player` with `MarkCut` |
|
|
62
|
-
| Inline script | Generated by `getHtml()` in `server.mjs` | Watch-mode UI controls (close button, edit input, SSE) |
|
|
63
|
-
|
|
64
|
-
### Edit flow
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
Browser Server pi CLI
|
|
68
|
-
│ │ │
|
|
69
|
-
│── POST /api/edit ────────────► │ │
|
|
70
|
-
│ {text: "make text bigger"} │ │
|
|
71
|
-
│ │── spawn("pi", ["-p", prompt])│
|
|
72
|
-
│ │ prompt includes: │
|
|
73
|
-
│ │ • full tree description │
|
|
74
|
-
│ │ (recursive, any depth) │
|
|
75
|
-
│ │ • edit history │
|
|
76
|
-
│ │ • knowledge (all stream │
|
|
77
|
-
│ │ types, components, │
|
|
78
|
-
│ │ schema, styling guide) │
|
|
79
|
-
│ │ • edit request │
|
|
80
|
-
│ │ │
|
|
81
|
-
│ │ pi can edit ANY field on │
|
|
82
|
-
│ │ ANY node in the tree │
|
|
83
|
-
│ │ ├── edits file.json
|
|
84
|
-
│ │ └── exits
|
|
85
|
-
│ │◄── exit code 0 │
|
|
86
|
-
│◄── {done:true, output:"..."} ──┤ │
|
|
87
|
-
│ │ │
|
|
88
|
-
│ suppressReload = true │ │
|
|
89
|
-
│ header shows "Changed text..." │ │
|
|
90
|
-
│ │ │
|
|
91
|
-
│ (fs.watchFile fires SSE │ │
|
|
92
|
-
│ but suppressReload=true │ │
|
|
93
|
-
│ so it's ignored) │ │
|
|
94
|
-
│ │ │
|
|
95
|
-
│ after 4s: │ │
|
|
96
|
-
│ dispatchEvent("refresh-player")│ │
|
|
97
|
-
│ → player re-fetches /api/data │ │
|
|
98
|
-
│ → re-renders with new JSON │ │
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### Key design decisions
|
|
102
|
-
|
|
103
|
-
**Why in-place refresh instead of `location.reload()`?**
|
|
104
|
-
- Timeline playback continues uninterrupted
|
|
105
|
-
- Status text persists until next edit
|
|
106
|
-
- No page flash
|
|
107
|
-
|
|
108
|
-
**Why `suppressReload`?**
|
|
109
|
-
- SSE fires ~500ms after pi edits the file
|
|
110
|
-
- API response arrives at the same time
|
|
111
|
-
- `suppressReload` flag ignores the SSE event during edit
|
|
112
|
-
- The client reloads itself after showing the summary
|
|
113
|
-
|
|
114
|
-
## File: `src/player/browser.tsx`
|
|
115
|
-
|
|
116
|
-
The bundled player app:
|
|
117
|
-
|
|
118
|
-
1. Fetches `/api/video-data` on mount
|
|
119
|
-
2. Renders the stream tree using `@remotion/player` with `MarkCut`
|
|
120
|
-
3. Listens for `"refresh-player"` custom DOM event
|
|
121
|
-
4. On refresh event: re-fetches data, re-renders in-place
|
|
122
|
-
|
|
123
|
-
## File: `src/render/cli.mjs`
|
|
124
|
-
|
|
125
|
-
The CLI routes `--edit` flag to the player server:
|
|
126
|
-
|
|
127
|
-
```javascript
|
|
128
|
-
if (args.edit) {
|
|
129
|
-
const serverArgs = ["src/player/server.mjs", file, "--edit", `--port=${port}`];
|
|
130
|
-
const child = spawn("node", serverArgs, { cwd: ROOT, stdio: "inherit" });
|
|
131
|
-
// ...blocks until server exits...
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## API Endpoints
|
|
136
|
-
|
|
137
|
-
| Endpoint | Method | Description |
|
|
138
|
-
|----------|--------|-------------|
|
|
139
|
-
| `/api/video-data` | GET | Returns the raw stream tree JSON file |
|
|
140
|
-
| `/api/scenes` | GET | Returns parsed scenes array with timing |
|
|
141
|
-
| `/api/video-info` | GET | Returns scenes + totalDuration + mode flags |
|
|
142
|
-
| `/api/edit` | POST | Accepts `{text}` → spawns pi to edit the JSON → file watcher triggers → SSE reload |
|
|
143
|
-
| `/api/shutdown` | POST | Kills the server process, unblocking the agent |
|
|
144
|
-
| `/api/events` | GET | SSE stream — sends `{type:"reload"}` when file changes |
|
|
145
|
-
| `/api/labels` | GET/POST | (label mode only) Save/load scene labels |
|
|
146
|
-
|
|
147
|
-
## The pi prompt
|
|
148
|
-
|
|
149
|
-
Each edit call sends a structured prompt with a **recursive tree description** instead of a flat scene list:
|
|
150
|
-
|
|
151
|
-
```
|
|
152
|
-
You are editing sample-visual.json, a Remotion stream tree JSON.
|
|
153
|
-
|
|
154
|
-
The stream tree (indentation shows nesting; timing in seconds):
|
|
155
|
-
root "root" (1080×1920, 30fps, series, transition:fade)
|
|
156
|
-
folder "scene-1" (parallel)
|
|
157
|
-
component GradientBackground {type:"radial",animated:true,noise:true} [05s, bg]
|
|
158
|
-
component AnimatedHeadline {"text":"Hello Remotion",...} [0.54.5s]
|
|
159
|
-
folder "scene-2" (parallel)
|
|
160
|
-
component GradientBackground {type:"linear",animated:true} [05s, bg]
|
|
161
|
-
subtitle "This text is styled with CSS" fontSize:52 [0.54.5s]
|
|
162
|
-
...
|
|
163
|
-
|
|
164
|
-
Previous edits:
|
|
165
|
-
1. make scene 1 headline text orange
|
|
166
|
-
|
|
167
|
-
Edit request: make scene 1 headline text bigger
|
|
168
|
-
|
|
169
|
-
--- Knowledge ---
|
|
170
|
-
You can edit ANY field on ANY node in the JSON...
|
|
171
|
-
Stream types: root, folder, video, audio, image, subtitle, component, effect, rhythm, map
|
|
172
|
-
...
|
|
173
|
-
IMPORTANT: Read the full existing JSON file before editing. Only edit the JSON file. You can change, add, or remove any field on any node. Output ONLY a one-line summary of what specific change you made.
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
The tree description walks the JSON recursively, showing:
|
|
177
|
-
- **Nesting depth** via indentation
|
|
178
|
-
- **Type** and **id/name** of each node
|
|
179
|
-
- **Key fields** (dimensions, fps, theme, series/parallel, transitions)
|
|
180
|
-
- **Timing** from leaf span (`[start→end]`)
|
|
181
|
-
- **isBackground** flag (`[bg]`)
|
|
182
|
-
- **Component props** and node-specific fields (fontSize, fit, style, volume, etc.)
|
|
183
|
-
|
|
184
|
-
This means pi can edit **any aspect of the JSON** ÔÇö not just scene props. Nested folders, effects, rhythms, maps, actions, styles, themes, global stylesheets, audio config ÔÇö everything is visible and editable.
|
|
185
|
-
|
|
186
|
-
## Session context
|
|
187
|
-
|
|
188
|
-
The server maintains `editHistory[]` — every edit is appended. On each call, previous edits are included so pi knows what was done before:
|
|
189
|
-
|
|
190
|
-
```
|
|
191
|
-
Previous edits:
|
|
192
|
-
1. make scene 1 headline text orange
|
|
193
|
-
2. change background from radial to linear gradient
|
|
194
|
-
3. add 3D angle to device mockup in scene 4
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
This gives pi enough context to make coherent changes across multiple edit rounds.
|
|
198
|
-
|
|
199
|
-
## Close / tab-close
|
|
200
|
-
|
|
201
|
-
| Action | What happens |
|
|
202
|
-
|--------|-------------|
|
|
203
|
-
| Click **✕** | `sendBeacon("/api/shutdown")` → server exits → agent unblocks |
|
|
204
|
-
| Close **tab** | SSE connection drops → 3s grace → server exits |
|
|
205
|
-
| Close **browser** | Same as tab close |
|
|
206
|
-
|
|
207
|
-
## Label mode (`--label`)
|
|
208
|
-
|
|
209
|
-
`preview <file.json> --label` starts the same player but with a **label input** instead of the edit input. Labels are saved to `labels.json` next to the source file. No AI editing, no file watching.
|
|
210
|
-
|
|
211
|
-
## Build
|
|
212
|
-
|
|
213
|
-
The browser bundle is built with esbuild:
|
|
214
|
-
|
|
215
|
-
```bash
|
|
216
|
-
bash scripts/build-player.sh
|
|
217
|
-
# → src/player/bundle/player.js
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
The bundle includes React, @remotion/player, MarkCut, all 13 built-in components, themes, templates, and the duration utility. It is served as a static file by the player server.
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# Label System
|
|
2
|
-
|
|
3
|
-
Interactive media labeling before understanding clips in json stream tree.
|
|
4
|
-
The stream tree follow rules, see [docs/json-descriptive.md](docs/json-descriptive.md) for full details .
|
|
5
|
-
|
|
6
|
-
## Overview
|
|
7
|
-
|
|
8
|
-
The label player lets you load a stream tree, browse its clips, and attach descriptive labels to each clip's media.
|
|
9
|
-
The output is an updated `labels.json` file with `description` fields populated.
|
|
10
|
-
|
|
11
|
-
## Usage
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
# Label from a stream tree JSON or labels.json
|
|
15
|
-
npx markcut preview labels.json --label
|
|
16
|
-
|
|
17
|
-
# Specify port
|
|
18
|
-
npx markcut preview labels.json --label --port 3031
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### Labels Persistence
|
|
22
|
-
The stream tree follow rules, see [docs/json-descriptive.md](docs/json-descriptive.md) for full details .
|
|
23
|
-
Labels are saved to the source file.
|
|
24
|
-
|
|
25
|
-
```json
|
|
26
|
-
{
|
|
27
|
-
"root": {
|
|
28
|
-
"id": "root",
|
|
29
|
-
"type": "root",
|
|
30
|
-
"children": [
|
|
31
|
-
{
|
|
32
|
-
"id": "scene-1",
|
|
33
|
-
"type": "folder",
|
|
34
|
-
"children": [
|
|
35
|
-
{
|
|
36
|
-
"id": "scene-1-media",
|
|
37
|
-
"type": "image",
|
|
38
|
-
"src": "/media/photo.jpg",
|
|
39
|
-
"start": 0, "end": 5,
|
|
40
|
-
"description": "Best group shot from the campfire"
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"id": "scene-2",
|
|
46
|
-
"type": "folder",
|
|
47
|
-
"children": [
|
|
48
|
-
{
|
|
49
|
-
"id": "scene-2-media",
|
|
50
|
-
"type": "video",
|
|
51
|
-
"src": "/media/clip.mp4",
|
|
52
|
-
"start": 0, "end": 5,
|
|
53
|
-
"description": "Sunset timelapse — use for intro"
|
|
54
|
-
}
|
|
55
|
-
]
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
The `description` field on each media leaf node holds the label text.
|
|
63
|
-
|
|
64
|
-
## Workflow
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
Stream tree JSON (labels.json)
|
|
68
|
-
│
|
|
69
|
-
▼
|
|
70
|
-
─── preview --label ───→ Browse & label clips
|
|
71
|
-
│ │
|
|
72
|
-
│ ▼
|
|
73
|
-
│ Updated labels.json
|
|
74
|
-
│ │
|
|
75
|
-
▼ ▼
|
|
76
|
-
Use in Storyboard ──────→ Assemble → Render
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
1. **Prepare** a stream tree JSON with scenes
|
|
80
|
-
2. **Label** with `preview --label` to add descriptions to each scene
|
|
81
|
-
3. **Export** labels are saved alongside the source file
|
|
82
|
-
4. **Use** the labeled scenes in your storyboard or assembly workflow
|
|
83
|
-
|
|
84
|
-
## API Endpoints
|
|
85
|
-
|
|
86
|
-
| Endpoint | Method | Description |
|
|
87
|
-
|----------|--------|-------------|
|
|
88
|
-
| `/api/video-data` | GET | Returns the raw stream tree JSON |
|
|
89
|
-
| `/api/video-info` | GET | Returns scenes array with timing + totalDuration |
|
|
90
|
-
| `/api/labels` | GET | Returns the current stream tree with descriptions |
|
|
91
|
-
| `/api/labels` | POST | Saves updated descriptions ({descriptions: {index: "text"}}) |
|
|
92
|
-
| `/api/shutdown` | POST | Kills the server |
|
|
93
|
-
| `/api/events` | GET | SSE events (reload on file change) |
|
|
94
|
-
|
|
95
|
-
## Implementation
|
|
96
|
-
|
|
97
|
-
Source: `src/player/server.mjs` (unified server, use `--label` flag)
|
|
98
|
-
UI controls: `src/player/components/LabelControls.tsx` (React component)
|
|
99
|
-
|
|
100
|
-
- Built on Node.js `http` module (no Express dependency)
|
|
101
|
-
- Serves bundled `player.js` (esbuild output from `src/player/browser.tsx`)
|
|
102
|
-
- Labels saved atomically to disk on each POST
|
|
103
|
-
- Supports stream tree JSON, descriptive JSON, and markdown input
|
|
104
|
-
- React components in `src/player/components/` replace the old HTML-based `ui/` directory
|
|
105
|
-
|
|
106
|
-
## Reference
|
|
107
|
-
|
|
108
|
-
| Topic | Link |
|
|
109
|
-
|-------|------|
|
|
110
|
-
| Storyboard (video planning) | [storyboard.md](storyboard.md) |
|
|
111
|
-
| Stream tree types | `SKILL.md` |
|
|
112
|
-
| Dynamic components | [dynamic-components.md](dynamic-components.md) |
|