@openvidstudio/mcp-server 0.1.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/beats.d.ts +47 -0
- package/dist/beats.js +9 -0
- package/dist/capture.d.ts +116 -0
- package/dist/capture.js +148 -0
- package/dist/config.d.ts +58 -0
- package/dist/config.js +130 -0
- package/dist/paths.d.ts +20 -0
- package/dist/paths.js +57 -0
- package/dist/scenes/pngSize.d.ts +11 -0
- package/dist/scenes/pngSize.js +75 -0
- package/dist/scenes/templates.d.ts +42 -0
- package/dist/scenes/templates.js +468 -0
- package/dist/server.d.ts +16 -0
- package/dist/server.js +37 -0
- package/dist/stdio.d.ts +2 -0
- package/dist/stdio.js +33 -0
- package/dist/tools/captureScreenRecording.d.ts +28 -0
- package/dist/tools/captureScreenRecording.js +181 -0
- package/dist/tools/captureScreenshot.d.ts +34 -0
- package/dist/tools/captureScreenshot.js +148 -0
- package/dist/tools/contactSheet.d.ts +36 -0
- package/dist/tools/contactSheet.js +116 -0
- package/dist/tools/generateNarration.d.ts +54 -0
- package/dist/tools/generateNarration.js +185 -0
- package/dist/tools/importHiggsfieldClip.d.ts +41 -0
- package/dist/tools/importHiggsfieldClip.js +108 -0
- package/dist/tools/index.d.ts +13 -0
- package/dist/tools/index.js +47 -0
- package/dist/tools/initProject.d.ts +37 -0
- package/dist/tools/initProject.js +166 -0
- package/dist/tools/mcp.d.ts +33 -0
- package/dist/tools/mcp.js +36 -0
- package/dist/tools/planBeats.d.ts +40 -0
- package/dist/tools/planBeats.js +143 -0
- package/dist/tools/preflight.d.ts +30 -0
- package/dist/tools/preflight.js +170 -0
- package/dist/tools/qcExtractFrames.d.ts +25 -0
- package/dist/tools/qcExtractFrames.js +129 -0
- package/dist/tools/renderVideo.d.ts +43 -0
- package/dist/tools/renderVideo.js +120 -0
- package/dist/tools/scaffoldScene.d.ts +23 -0
- package/dist/tools/scaffoldScene.js +147 -0
- package/dist/tools/stitchComposition.d.ts +24 -0
- package/dist/tools/stitchComposition.js +230 -0
- package/dist/tools/validateBeats.d.ts +14 -0
- package/dist/tools/validateBeats.js +164 -0
- package/dist/tools/validateScenes.d.ts +31 -0
- package/dist/tools/validateScenes.js +191 -0
- package/dist/tools/writeBeatsFile.d.ts +20 -0
- package/dist/tools/writeBeatsFile.js +81 -0
- package/dist/util.d.ts +43 -0
- package/dist/util.js +163 -0
- package/docs/API.md +344 -0
- package/docs/CAPTURE.md +106 -0
- package/docs/HIGGSFIELD.md +118 -0
- package/docs/NARRATION.md +111 -0
- package/docs/OVERVIEW.md +112 -0
- package/docs/PIPELINE.md +173 -0
- package/docs/PLANNING.md +206 -0
- package/docs/SCRIPT.md +50 -0
- package/docs/STYLE.md +88 -0
- package/package.json +54 -0
- package/templates/default/CLAUDE.md +63 -0
- package/templates/default/openvidstudio-core/package.json +51 -0
- package/templates/default/openvidstudio-core/scripts/gen-sfx.sh +74 -0
- package/templates/default/openvidstudio-core/src/ChecklistPanel.tsx +97 -0
- package/templates/default/openvidstudio-core/src/CinematicScene.tsx +53 -0
- package/templates/default/openvidstudio-core/src/CodePanel.tsx +122 -0
- package/templates/default/openvidstudio-core/src/CursorActor.tsx +90 -0
- package/templates/default/openvidstudio-core/src/DeviceFrame.tsx +74 -0
- package/templates/default/openvidstudio-core/src/KineticText.tsx +142 -0
- package/templates/default/openvidstudio-core/src/RepoCta.tsx +128 -0
- package/templates/default/openvidstudio-core/src/TerminalReplay.tsx +263 -0
- package/templates/default/openvidstudio-core/src/camera.tsx +141 -0
- package/templates/default/openvidstudio-core/src/index.ts +60 -0
- package/templates/default/openvidstudio-core/src/look.tsx +90 -0
- package/templates/default/openvidstudio-core/src/motion.ts +50 -0
- package/templates/default/openvidstudio-core/src/sfx.tsx +106 -0
- package/templates/default/openvidstudio-core/src/tokens.ts +41 -0
- package/templates/default/package.json +31 -0
- package/templates/default/public/sfx/bell.wav +0 -0
- package/templates/default/public/sfx/blip.wav +0 -0
- package/templates/default/public/sfx/click.wav +0 -0
- package/templates/default/public/sfx/key_a.wav +0 -0
- package/templates/default/public/sfx/key_b.wav +0 -0
- package/templates/default/public/sfx/key_c.wav +0 -0
- package/templates/default/public/sfx/key_enter.wav +0 -0
- package/templates/default/public/sfx/music-bed.mp3 +0 -0
- package/templates/default/public/sfx/success.wav +0 -0
- package/templates/default/public/sfx/whoosh.wav +0 -0
- package/templates/default/remotion.config.ts +13 -0
- package/templates/default/src/Root.tsx +9 -0
- package/templates/default/src/index.ts +4 -0
- package/templates/default/tsconfig.json +16 -0
package/docs/PLANNING.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# PLANNING.md: guided intake to beats.json
|
|
2
|
+
|
|
3
|
+
This is step 0 of building any video with openvidstudio. Read this before
|
|
4
|
+
touching `beats.json`. It defines: the intake question set, how to handle
|
|
5
|
+
free-form pasted material instead, the per-feature capture-method decision
|
|
6
|
+
tree, the full `captureMethod` field spec, and the mandatory approval gate
|
|
7
|
+
before anything gets written to disk.
|
|
8
|
+
|
|
9
|
+
## 1. Fixed intake question set
|
|
10
|
+
|
|
11
|
+
Ask the dev, in order, before drafting anything:
|
|
12
|
+
|
|
13
|
+
1. **Product name and one-liner.** What is it, in one sentence?
|
|
14
|
+
2. **3-6 features to demo.** The specific things the video should show,
|
|
15
|
+
not a full feature list; pick the ones that carry the pitch.
|
|
16
|
+
3. **Target video length.** Total seconds (or a range); this bounds the
|
|
17
|
+
beat arc chosen in `PIPELINE.md` (Simple demo vs. Packed-hook,
|
|
18
|
+
multi-feature).
|
|
19
|
+
4. **Higgsfield access: yes or no.** Determines whether `higgsfield` is an
|
|
20
|
+
available `captureMethod` for this video at all. If no, every "not
|
|
21
|
+
product UI" beat either gets dropped or reworked as `dom-demo`.
|
|
22
|
+
5. **Brand info.** Colors, fonts, logo, if the project has its own and
|
|
23
|
+
wants it over openvidstudio's default palette/type (`STYLE.md`).
|
|
24
|
+
6. **Existing assets to reference.** Screenshots, recordings, a deployed
|
|
25
|
+
URL, a design file; anything that saves a capture step later.
|
|
26
|
+
|
|
27
|
+
## 2. Free-form pasted material
|
|
28
|
+
|
|
29
|
+
If the dev instead pastes a README, a feature list, a Slack thread, or
|
|
30
|
+
similar material, don't force the fixed question set on top of it. Read
|
|
31
|
+
the paste and extract the same six things from it instead:
|
|
32
|
+
|
|
33
|
+
- Product name/one-liner: usually the README's title plus its first
|
|
34
|
+
paragraph.
|
|
35
|
+
- Feature candidates: bullet lists, headers, or a "Features" section map
|
|
36
|
+
directly to feature candidates; pick 3-6 that carry the pitch, same as
|
|
37
|
+
question 2 above.
|
|
38
|
+
- Target length: often absent from a paste; ask this one directly if it's
|
|
39
|
+
missing, don't guess it.
|
|
40
|
+
- Higgsfield access: always ask directly; a paste never answers this.
|
|
41
|
+
- Brand info: look for a design-tokens file, a Tailwind config, a
|
|
42
|
+
`theme.ts`, or explicit brand colors mentioned in the paste; ask only
|
|
43
|
+
for what's genuinely missing.
|
|
44
|
+
- Existing assets: URLs, screenshot paths, or asset folders mentioned in
|
|
45
|
+
the paste count directly.
|
|
46
|
+
|
|
47
|
+
Only ask the dev to fill in whatever the paste didn't already answer. The
|
|
48
|
+
goal is one pass of the fixed question set's information, not necessarily
|
|
49
|
+
one pass of its literal questions.
|
|
50
|
+
|
|
51
|
+
## 3. Per-feature capture-method decision tree
|
|
52
|
+
|
|
53
|
+
Run this once per feature/claim the video will make. It's meant to be
|
|
54
|
+
followed mechanically, not judged holistically.
|
|
55
|
+
|
|
56
|
+
1. Does this claim describe real, working functionality in a running
|
|
57
|
+
instance of the product right now (not "will do," not roadmap, not
|
|
58
|
+
something a real screenshot would contradict)?
|
|
59
|
+
- No: go to step 4 (`dom-demo`).
|
|
60
|
+
- Yes: go to step 2.
|
|
61
|
+
2. Is the important part of this feature a single held state (one screen,
|
|
62
|
+
one panel, nothing essential changes while the viewer watches), or does
|
|
63
|
+
understanding it require seeing something change over time (typing,
|
|
64
|
+
dragging, a live update, an animation intrinsic to the feature)?
|
|
65
|
+
- Single held state: `captureMethod: "screenshot"`. Capture per
|
|
66
|
+
`CAPTURE.md`.
|
|
67
|
+
- Needs visible change over time: go to step 3.
|
|
68
|
+
3. Can that change be captured by actually interacting with the real,
|
|
69
|
+
running product on screen, within v1's fixed full-viewport scope (no
|
|
70
|
+
post-hoc DOM-rect cropping of a moving recording, see `PIPELINE.md`)?
|
|
71
|
+
- Yes: `captureMethod: "recording"`. Capture per `CAPTURE.md`'s
|
|
72
|
+
recording section.
|
|
73
|
+
- No, the motion needed isn't something the product's own UI can
|
|
74
|
+
produce at all (an atmosphere shot, a desk/hands shot, an abstract
|
|
75
|
+
visual metaphor with no real UI in it): go to step 4, but check
|
|
76
|
+
Higgsfield access from intake question 4 first. If access is "no,"
|
|
77
|
+
this beat either gets dropped or reworked as a still `dom-demo`
|
|
78
|
+
instead of the motion originally wanted.
|
|
79
|
+
4. `dom-demo`: build a hand-coded panel using the project's real design
|
|
80
|
+
tokens/copy (question 5's brand info, or `STYLE.md`'s defaults if none
|
|
81
|
+
was given). Reuse real copy, real claim IDs, or real UI conventions
|
|
82
|
+
from an actual screenshot elsewhere in the same video where possible,
|
|
83
|
+
so it reads as a continuation, not an invention. Where a real adjacent
|
|
84
|
+
screenshot genuinely backs part of the claim, use the real capture for
|
|
85
|
+
that part and confine the constructed part to just the aspirational
|
|
86
|
+
connection. Never build a `dom-demo` that contradicts a real,
|
|
87
|
+
capturable page's own on-screen copy: if a real page says the opposite
|
|
88
|
+
of the claim, that's a sign the claim needs rewriting, not a signal to
|
|
89
|
+
avoid screenshotting that page.
|
|
90
|
+
- If step 3 routed here because Higgsfield access is "yes" and the
|
|
91
|
+
beat genuinely isn't product UI (atmosphere/b-roll), use
|
|
92
|
+
`captureMethod: "higgsfield"` instead; see `HIGGSFIELD.md`.
|
|
93
|
+
|
|
94
|
+
## 4. The captureMethod field spec
|
|
95
|
+
|
|
96
|
+
Every beat's `visual` block carries a `captureMethod` field:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
"captureMethod": "screenshot" | "recording" | "dom-demo" | "higgsfield"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Method-specific fields:
|
|
103
|
+
|
|
104
|
+
| Method | Extra fields | Notes |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `screenshot` | `url`, `interactions` | `interactions` is an ordered array of steps (click/fill/select/hover/scroll/wait, the exact set `capture_screenshot`/`capture_screen_recording` replay) to reach the exact state the beat needs |
|
|
107
|
+
| `recording` | `url`, `interactions` | same shape as `screenshot`; the interactions happen while recording, not before |
|
|
108
|
+
| `dom-demo` | none | the beat's visual is authored directly in its scene file, no capture step |
|
|
109
|
+
| `higgsfield` | `higgsfieldPrompt` | the AI-generation prompt for the b-roll clip; must not request on-screen product text or real UI |
|
|
110
|
+
|
|
111
|
+
See section 6 below for a concrete `beats.json` fragment with one full,
|
|
112
|
+
working example of each of these four shapes.
|
|
113
|
+
|
|
114
|
+
## 5. The mandatory approval gate
|
|
115
|
+
|
|
116
|
+
Once every beat has a decided `captureMethod` and the full `beats.json` is
|
|
117
|
+
drafted: show the dev the full file, not a summary, and get explicit
|
|
118
|
+
approval before persisting it. This applies even to a small, obviously
|
|
119
|
+
fine-looking draft.
|
|
120
|
+
|
|
121
|
+
The `write_beats_file` MCP tool will refuse to write anything
|
|
122
|
+
`validate_beats` hasn't passed, but that's schema/structural
|
|
123
|
+
validation, not dev approval. The human-approval step itself is a protocol
|
|
124
|
+
rule for the calling agent, not something any tool enforces. Skipping it
|
|
125
|
+
because the tool would technically allow the write is a protocol
|
|
126
|
+
violation.
|
|
127
|
+
|
|
128
|
+
## 6. Worked example (fictional product, anonymized)
|
|
129
|
+
|
|
130
|
+
**Product:** "Loomcard," a spaced-repetition flashcard app for technical
|
|
131
|
+
interview prep.
|
|
132
|
+
|
|
133
|
+
**Intake answers (abbreviated):**
|
|
134
|
+
- One-liner: "Loomcard turns your notes into spaced-repetition flashcards
|
|
135
|
+
and schedules review so you actually remember them."
|
|
136
|
+
- Features to demo: card review flow, confidence-based scheduling that
|
|
137
|
+
adjusts in real time, CSV/Anki import (not wired up yet, a roadmap
|
|
138
|
+
item).
|
|
139
|
+
- Higgsfield access: yes.
|
|
140
|
+
|
|
141
|
+
**Resulting beats.json fragment** (hook / demo / differentiator / cta, one
|
|
142
|
+
of each `captureMethod` so the shapes above are all represented):
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"fps": 30,
|
|
147
|
+
"title": "Loomcard",
|
|
148
|
+
"beats": [
|
|
149
|
+
{
|
|
150
|
+
"id": "hook",
|
|
151
|
+
"start": 0,
|
|
152
|
+
"duration": 180,
|
|
153
|
+
"vo": "Loomcard turns your notes into spaced-repetition flashcards, and schedules review so you actually remember them.",
|
|
154
|
+
"visual": {
|
|
155
|
+
"captureMethod": "higgsfield",
|
|
156
|
+
"higgsfieldPrompt": "slow push-in on a warm desk scene, hands resting near a closed notebook, soft morning light, no screens or readable text in frame, cinematic shallow depth of field"
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"id": "demo-review",
|
|
161
|
+
"start": 180,
|
|
162
|
+
"duration": 120,
|
|
163
|
+
"vo": "Flip a card, and Loomcard scores your confidence on the spot.",
|
|
164
|
+
"visual": {
|
|
165
|
+
"captureMethod": "screenshot",
|
|
166
|
+
"url": "https://app.loomcard.example/review",
|
|
167
|
+
"interactions": [
|
|
168
|
+
{ "type": "click", "selector": "[data-testid=flip-card]" },
|
|
169
|
+
{ "type": "click", "selector": "[data-testid=confidence-4]" }
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"id": "demo-schedule",
|
|
175
|
+
"start": 300,
|
|
176
|
+
"duration": 240,
|
|
177
|
+
"vo": "That confidence score adjusts your next review date live, so easy cards fade back and hard ones come around sooner.",
|
|
178
|
+
"visual": {
|
|
179
|
+
"captureMethod": "recording",
|
|
180
|
+
"url": "https://app.loomcard.example/review",
|
|
181
|
+
"interactions": [
|
|
182
|
+
{ "type": "click", "selector": "[data-testid=confidence-1]" },
|
|
183
|
+
{ "type": "wait", "ms": 600 }
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"id": "cta",
|
|
189
|
+
"start": 540,
|
|
190
|
+
"duration": 180,
|
|
191
|
+
"vo": "Loomcard is free and open source. Star it, try it, or send a pull request.",
|
|
192
|
+
"visual": {
|
|
193
|
+
"captureMethod": "dom-demo"
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Note the `demo-schedule` beat: the CSV/Anki import feature from intake was
|
|
201
|
+
dropped, not shown, because it isn't wired up yet and no real capture or
|
|
202
|
+
honest `dom-demo` was worth building for a roadmap item this early in the
|
|
203
|
+
pitch. A beat that claimed it anyway would have failed the
|
|
204
|
+
claim-obligates-visual rule (`SCRIPT.md`). The `cta` beat uses `dom-demo`
|
|
205
|
+
because `RepoCta` is a hand-authored scene built from real repo data, not
|
|
206
|
+
a captured screenshot of anything.
|
package/docs/SCRIPT.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# SCRIPT.md: VO pacing and writing rules
|
|
2
|
+
|
|
3
|
+
VO for every video should sound like the same person wrote it: direct,
|
|
4
|
+
confident about what's actually shown, never claiming more than the visual
|
|
5
|
+
backs up.
|
|
6
|
+
|
|
7
|
+
## Pace
|
|
8
|
+
|
|
9
|
+
Target **~2.3-2.9 words/sec**. This is edge-tts's natural reading pace at
|
|
10
|
+
default settings, the actual ratio observed across this pipeline's
|
|
11
|
+
production use, not a theoretical number. If you're writing VO for a beat
|
|
12
|
+
of known duration, word-count budget equals `duration_seconds * pace`;
|
|
13
|
+
stay inside that range rather than writing to a "feels about right" length
|
|
14
|
+
and hoping it fits.
|
|
15
|
+
|
|
16
|
+
## Duration formula
|
|
17
|
+
|
|
18
|
+
When a beat's duration is being derived from its VO (rather than the other
|
|
19
|
+
way around):
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
duration = (VO word count / pace) + pad
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Use a pad of **0.3-0.6s**. The pad exists so the visual doesn't cut the
|
|
26
|
+
instant speech ends: a beat that ends exactly when the last word does
|
|
27
|
+
reads as clipped, and a small buffer lets the shot breathe for a moment
|
|
28
|
+
before the cut.
|
|
29
|
+
|
|
30
|
+
## The claim-obligates-visual rule
|
|
31
|
+
|
|
32
|
+
If a beat's VO asserts the product does something, the visual must back it
|
|
33
|
+
up: either a real capture (`screenshot`/`recording`) of the product
|
|
34
|
+
actually doing it, or an explicitly labeled `dom-demo` mockup built for a
|
|
35
|
+
feature that isn't wired up yet. Never let VO overclaim past what's on
|
|
36
|
+
screen. If the visual can't back a sentence, rewrite the sentence, don't
|
|
37
|
+
leave it in and hope no one checks.
|
|
38
|
+
|
|
39
|
+
This is the same rule `PIPELINE.md` states for beat authoring generally;
|
|
40
|
+
here it's specifically about VO, because VO is usually written first and
|
|
41
|
+
is where an overclaim first gets introduced. Use `PLANNING.md`'s
|
|
42
|
+
per-feature capture-method decision tree to decide, for each claim,
|
|
43
|
+
whether it needs a real capture or an honest `dom-demo`. Don't write a
|
|
44
|
+
claim the decision tree can't resolve to something real or
|
|
45
|
+
explicitly-labeled-constructed.
|
|
46
|
+
|
|
47
|
+
## No em dashes
|
|
48
|
+
|
|
49
|
+
No em dashes in any VO line, ever, same writing rule as every other doc in
|
|
50
|
+
this pipeline. Use commas, periods, or a rewritten sentence instead.
|
package/docs/STYLE.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# STYLE.md: Art Direction Bible
|
|
2
|
+
|
|
3
|
+
Binding rules for every video built with openvidstudio. If a scene violates
|
|
4
|
+
a rule here, it fails QC.
|
|
5
|
+
|
|
6
|
+
## What good cinematography for this pipeline looks like (decoded)
|
|
7
|
+
|
|
8
|
+
1. **Camera lives INSIDE the UI.** Never show a flat full-screen
|
|
9
|
+
screenshot. The camera is always zoomed into a region (120-250% scale),
|
|
10
|
+
slightly tilted (1-4 degrees rotateZ, 2-8 degrees rotateX/Y
|
|
11
|
+
perspective), and moving (push-in, drift, pan). UI is rendered oversized
|
|
12
|
+
on a stage; the camera crops into it.
|
|
13
|
+
2. **Shallow depth of field.** One focal plane per shot. Everything else
|
|
14
|
+
(background layers, edge regions, sidebars) carries gaussian blur.
|
|
15
|
+
Focus can rack between layers mid-shot.
|
|
16
|
+
3. **Low-key lighting.** Dark scenes: deep vignette, soft glow accents on
|
|
17
|
+
the key element (accent-colored text-shadow/box-shadow). Light scenes:
|
|
18
|
+
soft large-radius drop shadows, floating cards, generous negative
|
|
19
|
+
space.
|
|
20
|
+
4. **Cursor is an actor.** Oversized cursor, eased movement (never
|
|
21
|
+
linear), click = ripple ring + glow pulse on the target. Buttons
|
|
22
|
+
visibly react.
|
|
23
|
+
5. **The montage shot.** Isometric-tilted grid of floating UI windows,
|
|
24
|
+
depth-stacked, edges blurred, slow drift. Used for hooks/outros.
|
|
25
|
+
6. **Warm/cool contrast.** Cool UI (blues, slate) against warm accent
|
|
26
|
+
lighting or warm desk tones.
|
|
27
|
+
7. **Motion never stops.** Every shot has at least a subtle push-in (2-5%
|
|
28
|
+
scale over the shot). Static frame = dead frame = QC fail.
|
|
29
|
+
|
|
30
|
+
## Hard rules
|
|
31
|
+
|
|
32
|
+
- NO linear easing. Ever. Use `@openvidstudio/core`'s `E.*` presets
|
|
33
|
+
(cinematic bezier / springs).
|
|
34
|
+
- Every scene wrapped in `CinematicScene` (grain + vignette + grade always
|
|
35
|
+
on).
|
|
36
|
+
- **On-screen text and UI is real by provenance, not by medium.** The
|
|
37
|
+
earlier version of this rule was "all text is DOM text," reasoned from
|
|
38
|
+
medium: anything not literally re-rendered as DOM inside the composition
|
|
39
|
+
wasn't trusted. That rule was a refinement waiting to happen: a genuine
|
|
40
|
+
screen recording of the real, running product isn't AI-hallucinated,
|
|
41
|
+
it's ground truth exactly like a screenshot is, so a medium-based rule
|
|
42
|
+
would have wrongly forbidden a legitimate capture method. The restated
|
|
43
|
+
rule: real product UI/text, whether DOM-rendered, screenshotted, or
|
|
44
|
+
screen-recorded, is always allowed on screen, because it's ground truth
|
|
45
|
+
by provenance. Screenshots may only appear inside `BrowserFrame`;
|
|
46
|
+
recordings composite as an `OffthreadVideo` inside a `Layer`, the same
|
|
47
|
+
camera-keyframe pattern. Both are captured per `CAPTURE.md`'s protocol
|
|
48
|
+
(a plain "set DPR to 2x" isn't enough on its own; the Playwright profile
|
|
49
|
+
can carry a per-origin zoom desync that silently shrinks/misframes an
|
|
50
|
+
uncompensated capture, and `CAPTURE.md`'s viewport-compensation plus
|
|
51
|
+
DOM-rect-crop steps are the actual fix). AI-generated clips (Higgsfield
|
|
52
|
+
or any future model) never carry on-screen product text or real UI:
|
|
53
|
+
b-roll/atmosphere only, see `HIGGSFIELD.md`.
|
|
54
|
+
- One focal point per shot. If two things matter, that's two shots.
|
|
55
|
+
- Text enters via mask reveal / clip-path wipe / per-word stagger, never
|
|
56
|
+
plain opacity fade.
|
|
57
|
+
- Cut rhythm: shots 1.5-5s. Hold longer only when content itself animates
|
|
58
|
+
(typing, install cascade).
|
|
59
|
+
- Terminal is always `TerminalReplay` (DOM), never screen-recorded HTML.
|
|
60
|
+
- SFX on every interaction: keystrokes (low volume 0.12-0.2), UI blips on
|
|
61
|
+
reveals, whoosh on camera moves/cuts, click ring + click sound together.
|
|
62
|
+
- Shot list per video lives in the video's own brief; camera keyframes
|
|
63
|
+
reference it.
|
|
64
|
+
|
|
65
|
+
## Palette + type (defaults; per-video themes may override)
|
|
66
|
+
|
|
67
|
+
- Stage/dark bg: #0B0E14 to #11151F radial. Panel: #151A24. Border:
|
|
68
|
+
#232B3A.
|
|
69
|
+
- Text: #E6EAF2 primary, #8A94A6 secondary.
|
|
70
|
+
- Accent: #4E9EFF (cool blue) + #9D6BFF (violet), glow accents. Success:
|
|
71
|
+
#3ECF8E. Warn: #F5A623.
|
|
72
|
+
- Light scenes: bg #F4F6F9, cards #FFFFFF, shadow rgba(15,23,42,0.12)
|
|
73
|
+
large radius.
|
|
74
|
+
- Fonts: Inter (UI), JetBrains Mono (terminal/code) via
|
|
75
|
+
`@remotion/google-fonts`.
|
|
76
|
+
- Grain: 4-6% opacity, animated (re-seeded translate per frame). Vignette:
|
|
77
|
+
25-40% edge darkening.
|
|
78
|
+
|
|
79
|
+
## Deferred (do not attempt in pure Remotion)
|
|
80
|
+
|
|
81
|
+
- Live-action beats (desk/keyboard shots, ambient texture): text-free, so
|
|
82
|
+
these are the Higgsfield/AI-footage slot; see `HIGGSFIELD.md`. Still skip
|
|
83
|
+
by default: design scenes so they aren't needed unless a brief
|
|
84
|
+
specifically calls for a live-action beat, and never let an AI-generated
|
|
85
|
+
clip carry on-screen product text or real UI.
|
|
86
|
+
- Music beds (added with VO in post, or looped under a baked-in VO mix,
|
|
87
|
+
see `SCRIPT.md`). Chromatic aberration + real bloom passes (perf;
|
|
88
|
+
revisit).
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openvidstudio/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server exposing openvidstudio's mechanical pipeline tools: project scaffolding, beats validation, scene stubs, composition stitching, render, QC frame extraction, and zoom-compensated screenshot/screen-recording capture.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"bin": {
|
|
8
|
+
"openvidstudio-mcp": "dist/stdio.js"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/server.js",
|
|
11
|
+
"types": "./dist/server.d.ts",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"templates",
|
|
15
|
+
"docs"
|
|
16
|
+
],
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
19
|
+
"playwright": "^1.48.0",
|
|
20
|
+
"sharp": "^0.33.5",
|
|
21
|
+
"zod": "^4.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^22.10.5",
|
|
25
|
+
"typescript": "5.9.3"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "node scripts/copy-template.mjs && node scripts/copy-docs.mjs && tsc",
|
|
29
|
+
"prepublishOnly": "npm run build",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"test": "node scripts/manual-test.mjs"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/AnayDhawan/openvidstudio.git",
|
|
39
|
+
"directory": "packages/mcp-server"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/AnayDhawan/openvidstudio#readme",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/AnayDhawan/openvidstudio/issues"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"mcp",
|
|
47
|
+
"model-context-protocol",
|
|
48
|
+
"remotion",
|
|
49
|
+
"playwright",
|
|
50
|
+
"video",
|
|
51
|
+
"demo-video",
|
|
52
|
+
"claude"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# CLAUDE.md: this project's video pipeline
|
|
2
|
+
|
|
3
|
+
This project was scaffolded with openvidstudio: a Remotion + Playwright
|
|
4
|
+
video-generation add-on driven via MCP tools. If you're an AI coding agent
|
|
5
|
+
about to build a video for this project, read `PLANNING.md` first. That's
|
|
6
|
+
step 0, before you touch `beats.json` or write a single scene.
|
|
7
|
+
|
|
8
|
+
## Docs
|
|
9
|
+
|
|
10
|
+
`init_project` copies these into this project's own `docs/` directory
|
|
11
|
+
when it scaffolds the project shell (it never overwrites a file you've
|
|
12
|
+
already edited, so a second `init_project` call for a second video won't
|
|
13
|
+
clobber local edits here). If a doc listed below is missing, re-run
|
|
14
|
+
`init_project` rather than guessing where it lives.
|
|
15
|
+
|
|
16
|
+
- `./docs/PLANNING.md`: start here. Guided intake to beats.json protocol,
|
|
17
|
+
capture-method decision tree, the mandatory approval gate.
|
|
18
|
+
- `./docs/PIPELINE.md`: beats.json, scenes, composition, QC loop.
|
|
19
|
+
- `./docs/STYLE.md`: binding art-direction rules.
|
|
20
|
+
- `./docs/CAPTURE.md`: real-screenshot protocol.
|
|
21
|
+
- `./docs/SCRIPT.md`: VO pacing and writing rules.
|
|
22
|
+
- `./docs/OVERVIEW.md`: conceptual overview; read this if you're unsure
|
|
23
|
+
why any of the rules below exist.
|
|
24
|
+
- `./docs/HIGGSFIELD.md`: AI b-roll tier protocol.
|
|
25
|
+
- `./docs/API.md`: every prop of every `@openvidstudio/core` component. Read
|
|
26
|
+
this instead of opening the library source.
|
|
27
|
+
- `./docs/NARRATION.md`: voice, music and sound effects, and why generated
|
|
28
|
+
voiceover usually sounds synthetic.
|
|
29
|
+
|
|
30
|
+
## Rules a scene-writing agent must never violate
|
|
31
|
+
|
|
32
|
+
These are QC-fail rules, not defaults, pulled from `STYLE.md` and
|
|
33
|
+
`PIPELINE.md` and restated here because they're the ones most likely to get
|
|
34
|
+
silently broken while writing a scene:
|
|
35
|
+
|
|
36
|
+
- **No linear easing, ever.** Use the eased/spring presets
|
|
37
|
+
`@openvidstudio/core` exports from its motion helpers. A static,
|
|
38
|
+
non-eased move fails QC.
|
|
39
|
+
- **Every scene wrapped in `CinematicScene`.** No screen ever renders
|
|
40
|
+
outside it (grain, vignette, and grade are always on).
|
|
41
|
+
- **Motion never stops.** Every shot needs at least a subtle push-in. A
|
|
42
|
+
frozen frame is a QC fail.
|
|
43
|
+
- **No em dashes**, on screen or in VO, anywhere.
|
|
44
|
+
|
|
45
|
+
## Before you hand-write a scene
|
|
46
|
+
|
|
47
|
+
`scaffold_scene` emits a scene that renders, using that beat's own copy and
|
|
48
|
+
duration. Start from it and edit the content rather than composing a scene
|
|
49
|
+
from primitives: it already has correct camera keyframes, a safe content
|
|
50
|
+
width, and the right shape for the beat's capture method.
|
|
51
|
+
|
|
52
|
+
Then run `validate_scenes`. The commonest mistake in this pipeline is
|
|
53
|
+
invisible: content laid out at full stage width gets cropped once the camera
|
|
54
|
+
pushes in, and the render does not warn.
|
|
55
|
+
|
|
56
|
+
## Components
|
|
57
|
+
|
|
58
|
+
Reach for `@openvidstudio/core`'s components before building anything new:
|
|
59
|
+
`CinematicScene`, `CameraRig`/`Layer`, `BrowserFrame`, `TerminalReplay`,
|
|
60
|
+
`CodePanel`, `ChecklistPanel`, `CursorActor`, `RepoCta`,
|
|
61
|
+
`TitleSlam`/`Caption`. Only build a new component when a beat truly needs
|
|
62
|
+
one, then keep it generic: it's a candidate for `@openvidstudio/core`
|
|
63
|
+
itself, not just this project.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openvidstudio/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Camera rig, motion, SFX, look pass, and scene components shared by every openvidstudio video project.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"main": "src/index.ts",
|
|
8
|
+
"types": "src/index.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"src",
|
|
11
|
+
"scripts",
|
|
12
|
+
"public"
|
|
13
|
+
],
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@remotion/google-fonts": "^4.0.490"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"react": "19.2.3",
|
|
19
|
+
"react-dom": "19.2.3",
|
|
20
|
+
"remotion": "4.0.490"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/react": "19.2.7",
|
|
24
|
+
"react": "19.2.3",
|
|
25
|
+
"react-dom": "19.2.3",
|
|
26
|
+
"remotion": "4.0.490",
|
|
27
|
+
"typescript": "5.9.3"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"typecheck": "tsc --noEmit"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/AnayDhawan/openvidstudio.git",
|
|
38
|
+
"directory": "packages/core"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/AnayDhawan/openvidstudio#readme",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/AnayDhawan/openvidstudio/issues"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"remotion",
|
|
46
|
+
"video",
|
|
47
|
+
"demo-video",
|
|
48
|
+
"screencast",
|
|
49
|
+
"mcp"
|
|
50
|
+
]
|
|
51
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Generate synthesized UI SFX into public/sfx/ (no licensing, fully reproducible).
|
|
3
|
+
# Swap any file for a real recorded pack later, sfx.tsx API stays identical.
|
|
4
|
+
set -e
|
|
5
|
+
cd "$(dirname "$0")/.."
|
|
6
|
+
mkdir -p public/sfx
|
|
7
|
+
|
|
8
|
+
# Mechanical key thocks: filtered brown-noise bursts, 3 pitch variations
|
|
9
|
+
ffmpeg -v error -y -f lavfi -i "anoisesrc=d=0.06:c=brown:a=0.9" \
|
|
10
|
+
-af "highpass=f=180,lowpass=f=2400,afade=t=in:d=0.004,afade=t=out:st=0.025:d=0.035,volume=3.2" \
|
|
11
|
+
public/sfx/key_a.wav
|
|
12
|
+
ffmpeg -v error -y -f lavfi -i "anoisesrc=d=0.055:c=brown:a=0.9:seed=7" \
|
|
13
|
+
-af "highpass=f=200,lowpass=f=1900,afade=t=in:d=0.004,afade=t=out:st=0.022:d=0.033,volume=3.4" \
|
|
14
|
+
public/sfx/key_b.wav
|
|
15
|
+
ffmpeg -v error -y -f lavfi -i "anoisesrc=d=0.065:c=brown:a=0.9:seed=23" \
|
|
16
|
+
-af "highpass=f=160,lowpass=f=2900,afade=t=in:d=0.004,afade=t=out:st=0.028:d=0.037,volume=3.0" \
|
|
17
|
+
public/sfx/key_c.wav
|
|
18
|
+
|
|
19
|
+
# Click: sharp short tick
|
|
20
|
+
ffmpeg -v error -y -f lavfi -i "anoisesrc=d=0.03:c=white:a=0.8" \
|
|
21
|
+
-af "highpass=f=1400,lowpass=f=6500,afade=t=in:d=0.002,afade=t=out:st=0.01:d=0.02,volume=2.2" \
|
|
22
|
+
public/sfx/click.wav
|
|
23
|
+
|
|
24
|
+
# Whoosh: bandpassed pink noise swell
|
|
25
|
+
ffmpeg -v error -y -f lavfi -i "anoisesrc=d=0.55:c=pink:a=0.8" \
|
|
26
|
+
-af "bandpass=f=650:w=500,afade=t=in:d=0.18,afade=t=out:st=0.25:d=0.3,volume=2.6" \
|
|
27
|
+
public/sfx/whoosh.wav
|
|
28
|
+
|
|
29
|
+
# Blip: soft sine tick for UI reveals
|
|
30
|
+
ffmpeg -v error -y -f lavfi -i "sine=frequency=740:duration=0.07" \
|
|
31
|
+
-af "afade=t=in:d=0.008,afade=t=out:st=0.03:d=0.04,volume=0.9" \
|
|
32
|
+
public/sfx/blip.wav
|
|
33
|
+
|
|
34
|
+
# Success: rising two-tone
|
|
35
|
+
ffmpeg -v error -y \
|
|
36
|
+
-f lavfi -i "sine=frequency=660:duration=0.09" \
|
|
37
|
+
-f lavfi -i "sine=frequency=990:duration=0.14" \
|
|
38
|
+
-filter_complex "[0]afade=t=out:st=0.05:d=0.04[a];[1]afade=t=in:d=0.01,afade=t=out:st=0.08:d=0.06[b];[a][b]concat=n=2:v=0:a=1,volume=0.9" \
|
|
39
|
+
public/sfx/success.wav
|
|
40
|
+
|
|
41
|
+
echo "SFX generated:"
|
|
42
|
+
ls public/sfx/
|
|
43
|
+
|
|
44
|
+
# Bell: struck metallic tone, harmonic stack with a long decay
|
|
45
|
+
ffmpeg -v error -y \
|
|
46
|
+
-f lavfi -i "sine=frequency=1568:duration=1.6" \
|
|
47
|
+
-f lavfi -i "sine=frequency=2350:duration=1.6" \
|
|
48
|
+
-f lavfi -i "sine=frequency=3136:duration=1.6" \
|
|
49
|
+
-filter_complex "[0]volume=1.0[a];[1]volume=0.45[b];[2]volume=0.22[c];[a][b][c]amix=inputs=3:normalize=0,afade=t=in:d=0.004,afade=t=out:st=0.12:d=1.45,volume=1.2" \
|
|
50
|
+
public/sfx/bell.wav
|
|
51
|
+
|
|
52
|
+
# Enter key: deeper, heavier thock than a letter key
|
|
53
|
+
ffmpeg -v error -y -f lavfi -i "anoisesrc=d=0.085:c=brown:a=0.95:seed=41" \
|
|
54
|
+
-af "highpass=f=110,lowpass=f=1500,afade=t=in:d=0.004,afade=t=out:st=0.03:d=0.05,volume=3.6" \
|
|
55
|
+
public/sfx/key_enter.wav
|
|
56
|
+
|
|
57
|
+
# Music bed: slow ambient pad, two detuned sines under a filtered noise wash.
|
|
58
|
+
# Synthesized rather than licensed, so a generated video carries no third-party
|
|
59
|
+
# audio rights. 60s, loop it for longer videos.
|
|
60
|
+
ffmpeg -v error -y \
|
|
61
|
+
-f lavfi -i "sine=frequency=110:duration=60" \
|
|
62
|
+
-f lavfi -i "sine=frequency=164.81:duration=60" \
|
|
63
|
+
-f lavfi -i "sine=frequency=220.5:duration=60" \
|
|
64
|
+
-f lavfi -i "anoisesrc=d=60:c=pink:a=0.06" \
|
|
65
|
+
-filter_complex "\
|
|
66
|
+
[0]volume=0.34,tremolo=f=0.11:d=0.30[p1];\
|
|
67
|
+
[1]volume=0.20,tremolo=f=0.13:d=0.26[p2];\
|
|
68
|
+
[2]volume=0.13,tremolo=f=0.17:d=0.35[p3];\
|
|
69
|
+
[3]lowpass=f=900,volume=0.5[air];\
|
|
70
|
+
[p1][p2][p3][air]amix=inputs=4:normalize=0,\
|
|
71
|
+
lowpass=f=2600,afade=t=in:d=3,afade=t=out:st=56:d=4,volume=0.5" \
|
|
72
|
+
-c:a libmp3lame -q:a 5 public/sfx/music-bed.mp3
|
|
73
|
+
|
|
74
|
+
echo "generated: $(ls public/sfx | wc -l) files in public/sfx/"
|