@openvidstudio/mcp-server 1.3.1 → 1.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/canvasExplainer.d.ts +198 -0
- package/dist/canvasExplainer.js +661 -0
- package/dist/canvasValidate.d.ts +76 -0
- package/dist/canvasValidate.js +263 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +2 -0
- package/dist/install.d.ts +63 -0
- package/dist/install.js +225 -0
- package/dist/lessonArc.d.ts +68 -0
- package/dist/lessonArc.js +188 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/stdio.js +12 -4
- package/dist/tools/checkScript.d.ts +31 -1
- package/dist/tools/checkScript.js +183 -6
- package/dist/tools/fitBeats.d.ts +69 -0
- package/dist/tools/fitBeats.js +229 -0
- package/dist/tools/generateNarration.d.ts +19 -0
- package/dist/tools/generateNarration.js +48 -5
- package/dist/tools/index.js +6 -0
- package/dist/tools/initProject.js +6 -1
- package/dist/tools/preflight.js +20 -1
- package/dist/tools/renderCanvasExplainer.d.ts +2 -0
- package/dist/tools/renderCanvasExplainer.js +56 -0
- package/dist/tools/renderVideo.d.ts +3 -0
- package/dist/tools/renderVideo.js +13 -4
- package/dist/tools/validateBeats.d.ts +2 -0
- package/dist/tools/validateBeats.js +5 -5
- package/dist/tools/validateCanvasExplainer.d.ts +2 -0
- package/dist/tools/validateCanvasExplainer.js +35 -0
- package/dist/tools/validateScenes.d.ts +6 -0
- package/dist/tools/validateScenes.js +27 -6
- package/dist/tools/validateScenesRender.d.ts +8 -0
- package/dist/tools/validateScenesRender.js +31 -0
- package/dist/tools/writeDescription.d.ts +6 -0
- package/dist/tools/writeDescription.js +64 -2
- package/docs/API.md +291 -0
- package/docs/NARRATION.md +12 -5
- package/docs/PIPELINE.md +46 -0
- package/docs/SCRIPT.md +63 -3
- package/docs/SUPERNOVA.md +53 -15
- package/docs/TOOLS.md +4 -1
- package/package.json +4 -4
- package/templates/default/openvidstudio-core/package.json +9 -9
- package/templates/default/openvidstudio-stem/package.json +5 -5
- package/templates/default/openvidstudio-stem/src/ComplexityCurve.tsx +108 -0
- package/templates/default/openvidstudio-stem/src/Derivation.tsx +334 -0
- package/templates/default/openvidstudio-stem/src/Equation.tsx +3 -3
- package/templates/default/openvidstudio-stem/src/GraphViz.tsx +249 -0
- package/templates/default/openvidstudio-stem/src/LessonCaptions.tsx +135 -0
- package/templates/default/openvidstudio-stem/src/MatrixGrid.tsx +187 -0
- package/templates/default/openvidstudio-stem/src/Orbit.tsx +241 -0
- package/templates/default/openvidstudio-stem/src/TreeViz.tsx +241 -0
- package/templates/default/openvidstudio-stem/src/VectorField.tsx +231 -0
- package/templates/default/openvidstudio-stem/src/Wave.tsx +234 -0
- package/templates/default/openvidstudio-stem/src/index.ts +21 -0
- package/templates/default/package.json +10 -10
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import type { Browser, Page } from "playwright";
|
|
2
|
+
import type { SceneFinding } from "./tools/validateScenes";
|
|
3
|
+
/**
|
|
4
|
+
* Turns a canvas explainer into a video. A canvas explainer is one self-contained HTML file with a canvas
|
|
5
|
+
* and three promises: `window.seek(t)` draws the frame at time `t` (seconds) as a pure function of `t`,
|
|
6
|
+
* `window.DURATION` is its length in seconds, and `window.scoreSound(kit)` is its Web Audio score, rendered
|
|
7
|
+
* offline through `window.SOUND.renderOffline(scoreSound, seconds, sampleRate, { voiceover })`.
|
|
8
|
+
*
|
|
9
|
+
* The renderer loads the file in headless Chromium, walks the frames, pipes the canvas PNGs into ffmpeg,
|
|
10
|
+
* renders the score, optionally mixes the narration clips of a project over it, and muxes the two. It can run
|
|
11
|
+
* from the MCP tool (tools/renderCanvasExplainer.ts) or standalone:
|
|
12
|
+
*
|
|
13
|
+
* node dist/canvasExplainer.js --html explainer.html --out out.mp4 [--width 1280 --height 720 --fps 30 --video name]
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEFAULT_CANVAS_WIDTH = 1280;
|
|
16
|
+
export declare const DEFAULT_CANVAS_HEIGHT = 720;
|
|
17
|
+
export declare const DEFAULT_CANVAS_FPS = 30;
|
|
18
|
+
export declare const AUDIO_SAMPLE_RATE = 48000;
|
|
19
|
+
/** How far the score sits under a narration clip while it plays, in dB. At least 6 is promised. */
|
|
20
|
+
export declare const DEFAULT_DUCK_DB = 9;
|
|
21
|
+
/** Seconds a caption stays after its last word is said, if the next one has not started. */
|
|
22
|
+
export declare const CAPTION_HOLD_SECONDS = 0.3;
|
|
23
|
+
/** One beat as the explainer sees it in `window.BEATS`: seconds, and the line spoken in it. */
|
|
24
|
+
export interface CanvasBeat {
|
|
25
|
+
id: string;
|
|
26
|
+
start: number;
|
|
27
|
+
end: number;
|
|
28
|
+
text: string;
|
|
29
|
+
}
|
|
30
|
+
export interface CanvasAudioOptions {
|
|
31
|
+
/** Drop beds and music and lower effects in the sound kit. Default: on when a project's beats are used with narration. */
|
|
32
|
+
voiceover?: boolean;
|
|
33
|
+
sampleRate?: number;
|
|
34
|
+
/** dB the score ducks under a narration clip. Default 9. */
|
|
35
|
+
duckDb?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface CanvasExplainerInput {
|
|
38
|
+
projectRoot?: string;
|
|
39
|
+
/** The explainer, absolute or relative to the project root. */
|
|
40
|
+
htmlPath: string;
|
|
41
|
+
/** The mp4 to write, relative to the project root (or absolute). */
|
|
42
|
+
outPath: string;
|
|
43
|
+
width?: number;
|
|
44
|
+
height?: number;
|
|
45
|
+
fps?: number;
|
|
46
|
+
/** false for a silent video, or the sound options. */
|
|
47
|
+
audio?: false | CanvasAudioOptions;
|
|
48
|
+
/** A video of the project: its beats.json becomes `window.BEATS`, and its narration clips are mixed in. */
|
|
49
|
+
videoName?: string;
|
|
50
|
+
/** Burn the beats' text in as captions. Default true when there is narration. */
|
|
51
|
+
captions?: boolean;
|
|
52
|
+
/** Run validate_canvas_explainer first and refuse to render on an error. Default true. */
|
|
53
|
+
validate?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface CanvasRenderProgress {
|
|
56
|
+
framesRendered: number;
|
|
57
|
+
totalFrames: number;
|
|
58
|
+
}
|
|
59
|
+
export interface CanvasExplainerResult {
|
|
60
|
+
success: true;
|
|
61
|
+
outPath: string;
|
|
62
|
+
width: number;
|
|
63
|
+
height: number;
|
|
64
|
+
fps: number;
|
|
65
|
+
durationSeconds: number;
|
|
66
|
+
frames: number;
|
|
67
|
+
/** SHA-256 of the PNG the page produced for the first, middle and last frame: the purity promise, as numbers. */
|
|
68
|
+
frameHashes: {
|
|
69
|
+
first: string;
|
|
70
|
+
middle: string;
|
|
71
|
+
last: string;
|
|
72
|
+
};
|
|
73
|
+
audio: {
|
|
74
|
+
included: boolean;
|
|
75
|
+
sampleRate: number | null;
|
|
76
|
+
voiceover: boolean;
|
|
77
|
+
/** The narration clips mixed in, with the sample the voice starts at. */
|
|
78
|
+
voiceClips: {
|
|
79
|
+
beatId: string;
|
|
80
|
+
startSeconds: number;
|
|
81
|
+
startSample: number;
|
|
82
|
+
durationSeconds: number;
|
|
83
|
+
}[];
|
|
84
|
+
duckDb: number | null;
|
|
85
|
+
};
|
|
86
|
+
captions: {
|
|
87
|
+
burned: boolean;
|
|
88
|
+
chunks: number;
|
|
89
|
+
};
|
|
90
|
+
warnings: string[];
|
|
91
|
+
/** The pre-flight's findings (warnings and notes; an error would have stopped the render). */
|
|
92
|
+
findings: SceneFinding[];
|
|
93
|
+
}
|
|
94
|
+
/** The caption chunks of a project, with the seconds each one is on screen. */
|
|
95
|
+
export interface CaptionChunk {
|
|
96
|
+
beatId: string;
|
|
97
|
+
from: number;
|
|
98
|
+
to: number;
|
|
99
|
+
text: string;
|
|
100
|
+
}
|
|
101
|
+
export interface CanvasProject {
|
|
102
|
+
beats: CanvasBeat[];
|
|
103
|
+
/** "none" for a silent lesson: no clips, no captions. */
|
|
104
|
+
narration: "voice" | "none";
|
|
105
|
+
clips: {
|
|
106
|
+
beatId: string;
|
|
107
|
+
start: number;
|
|
108
|
+
file: string;
|
|
109
|
+
}[];
|
|
110
|
+
chunks: CaptionChunk[];
|
|
111
|
+
}
|
|
112
|
+
/** Sentence-end and comma rules of LessonCaptions (packages/stem), so a canvas lesson captions the same way. */
|
|
113
|
+
export declare function captionChunks(words: string[], maxWords?: number): [number, number][];
|
|
114
|
+
/** Pure: the caption chunks of one beat, timed from word times when they are known and evenly by length when not. */
|
|
115
|
+
export declare function chunksForBeat(beat: CanvasBeat, spokenSeconds: number, words?: {
|
|
116
|
+
startMs: number;
|
|
117
|
+
endMs: number;
|
|
118
|
+
}[]): CaptionChunk[];
|
|
119
|
+
/** Reads a project's beats.json into what a canvas explainer needs. */
|
|
120
|
+
export declare function readCanvasProject(projectRoot: string, videoName: string): CanvasProject;
|
|
121
|
+
/** Runs before the explainer's own scripts: the size, the beats, the captions helper. */
|
|
122
|
+
export declare function bootScript(cfg: {
|
|
123
|
+
width: number;
|
|
124
|
+
height: number;
|
|
125
|
+
fps: number;
|
|
126
|
+
voiceover: boolean;
|
|
127
|
+
beats: CanvasBeat[] | null;
|
|
128
|
+
chunks: CaptionChunk[];
|
|
129
|
+
probes: boolean;
|
|
130
|
+
}): string;
|
|
131
|
+
export interface OpenedExplainer {
|
|
132
|
+
page: Page;
|
|
133
|
+
durationSeconds: number;
|
|
134
|
+
width: number;
|
|
135
|
+
height: number;
|
|
136
|
+
/** Set when the canvas was not the size asked for and was resized. */
|
|
137
|
+
resized: boolean;
|
|
138
|
+
/** The DURATION the file itself declared, before a beats file's last end replaced it. */
|
|
139
|
+
ownDuration: number;
|
|
140
|
+
errors: string[];
|
|
141
|
+
}
|
|
142
|
+
/** Loads the file and checks it keeps its three promises. */
|
|
143
|
+
export declare function openExplainer(browser: Browser, htmlPath: string, cfg: {
|
|
144
|
+
width: number;
|
|
145
|
+
height: number;
|
|
146
|
+
fps: number;
|
|
147
|
+
voiceover: boolean;
|
|
148
|
+
project: CanvasProject | null;
|
|
149
|
+
probes: boolean;
|
|
150
|
+
requireScore: boolean;
|
|
151
|
+
}): Promise<OpenedExplainer>;
|
|
152
|
+
/** Seeks to `t` and returns the canvas as PNG bytes. An explainer that did not draw captions gets them from the renderer. */
|
|
153
|
+
export declare function captureFrame(page: Page, t: number): Promise<Buffer>;
|
|
154
|
+
export interface PcmAudio {
|
|
155
|
+
sampleRate: number;
|
|
156
|
+
channels: number;
|
|
157
|
+
/** Interleaved. */
|
|
158
|
+
data: Float32Array;
|
|
159
|
+
}
|
|
160
|
+
/** Renders the explainer's score through its sound kit. */
|
|
161
|
+
export declare function renderScore(page: Page, durationSeconds: number, sampleRate: number, voiceover: boolean): Promise<PcmAudio>;
|
|
162
|
+
/** Pure: `audio` as stereo, so mixing and writing deal with one shape. */
|
|
163
|
+
export declare function toStereo(audio: PcmAudio): PcmAudio;
|
|
164
|
+
export interface MixResult {
|
|
165
|
+
audio: PcmAudio;
|
|
166
|
+
clips: {
|
|
167
|
+
beatId: string;
|
|
168
|
+
startSeconds: number;
|
|
169
|
+
startSample: number;
|
|
170
|
+
durationSeconds: number;
|
|
171
|
+
}[];
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Mixes narration clips over a score. Each clip starts at its beat's start (to the sample), and the score is
|
|
175
|
+
* ducked by `duckDb` while any clip plays: eased down over 40 ms and back up over 250 ms, so it does not pump.
|
|
176
|
+
*/
|
|
177
|
+
export declare function mixVoice(score: PcmAudio, clips: {
|
|
178
|
+
beatId: string;
|
|
179
|
+
start: number;
|
|
180
|
+
file: string;
|
|
181
|
+
}[], duckDb: number): MixResult;
|
|
182
|
+
/** A 32-bit float WAV, which ffmpeg reads directly. */
|
|
183
|
+
export declare function wavBytes(audio: PcmAudio): Buffer;
|
|
184
|
+
/** The warnings that need only the source. */
|
|
185
|
+
export declare function sourceWarnings(html: string, file: string): string[];
|
|
186
|
+
interface Resolved {
|
|
187
|
+
projectRoot: string;
|
|
188
|
+
htmlPath: string;
|
|
189
|
+
outPath: string;
|
|
190
|
+
width: number;
|
|
191
|
+
height: number;
|
|
192
|
+
fps: number;
|
|
193
|
+
}
|
|
194
|
+
export declare function resolveCanvasInput(input: CanvasExplainerInput): Resolved;
|
|
195
|
+
export declare function runCanvasExplainer(input: CanvasExplainerInput, opts?: {
|
|
196
|
+
onProgress?: (p: CanvasRenderProgress) => void;
|
|
197
|
+
}): Promise<CanvasExplainerResult>;
|
|
198
|
+
export {};
|