@open-take/compositor 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/LICENSE +21 -0
- package/dist/chunk-Cl8Af3a2.js +11 -0
- package/dist/index.d.ts +482 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +973 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
- package/src/ffmpeg.ts +60 -0
- package/src/index.ts +21 -0
- package/src/math.ts +459 -0
- package/src/plan.ts +157 -0
- package/src/presets.ts +147 -0
- package/src/render.ts +237 -0
- package/src/scene/project.ts +19 -0
- package/src/scene/scene.tsx +231 -0
- package/src/types.ts +349 -0
- package/src/validate.ts +245 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pascal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import { __export } from "./chunk-Cl8Af3a2.js";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
type Pt = {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
};
|
|
8
|
+
type BBox = {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
w: number;
|
|
12
|
+
h: number;
|
|
13
|
+
};
|
|
14
|
+
/** Editorial zoom intent for an action (set by the planner/agent). */
|
|
15
|
+
type ZoomIntent = "auto" | "never" | "always";
|
|
16
|
+
/** Fields common to every captured action. `x,y` is the anchor / start
|
|
17
|
+
* point (cursor target), viewport CSS px. */
|
|
18
|
+
type CaptureEventBase = {
|
|
19
|
+
/** anchor point (click target / field / drag start), viewport CSS px */
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
/** element bounding box, viewport CSS px — the ground-truth edge */
|
|
23
|
+
box?: BBox;
|
|
24
|
+
/** ms from recording start (when the cursor arrives / action begins) */
|
|
25
|
+
tMs: number;
|
|
26
|
+
/** selector / note, kept for editability */
|
|
27
|
+
sel?: string;
|
|
28
|
+
note?: string;
|
|
29
|
+
/** selective-zoom intent from the plan (default auto = heuristic) */
|
|
30
|
+
zoom?: ZoomIntent;
|
|
31
|
+
};
|
|
32
|
+
/** A click (or a type's focus-click): an instantaneous action at a point. */
|
|
33
|
+
type CaptureClick = CaptureEventBase & {
|
|
34
|
+
kind?: "click";
|
|
35
|
+
};
|
|
36
|
+
/** Typing into a focused field: the cursor parks and the zoom holds for
|
|
37
|
+
* `durationMs` while the text appears in the recording. */
|
|
38
|
+
type CaptureType = CaptureEventBase & {
|
|
39
|
+
kind: "type";
|
|
40
|
+
/** what was typed (editability) */
|
|
41
|
+
text: string;
|
|
42
|
+
/** ms the typing occupies on screen (ground-truth wall time) */
|
|
43
|
+
durationMs: number;
|
|
44
|
+
};
|
|
45
|
+
/** A drag: a path from the anchor (`x,y`) to `to`, optionally via `path`,
|
|
46
|
+
* with the button held for `durationMs`. */
|
|
47
|
+
type CaptureDrag = CaptureEventBase & {
|
|
48
|
+
kind: "drag";
|
|
49
|
+
/** drag end point, viewport CSS px */
|
|
50
|
+
to: {
|
|
51
|
+
x: number;
|
|
52
|
+
y: number;
|
|
53
|
+
};
|
|
54
|
+
/** full polyline incl. ends, viewport CSS px (freehand strokes) */
|
|
55
|
+
path?: {
|
|
56
|
+
x: number;
|
|
57
|
+
y: number;
|
|
58
|
+
}[];
|
|
59
|
+
/** ms the drag occupies on screen (ground-truth wall time) */
|
|
60
|
+
durationMs: number;
|
|
61
|
+
/** how the stroke was paced and BAKED into the ink: "smooth" (accel-in /
|
|
62
|
+
* decel-out — a natural hand-draw) or "linear" (constant speed). The
|
|
63
|
+
* compositor cursor must replay the SAME easing to stay locked to the ink.
|
|
64
|
+
* Absent ⇒ linear (legacy captures). */
|
|
65
|
+
ease?: "linear" | "smooth";
|
|
66
|
+
};
|
|
67
|
+
/** A scroll: the content pans for `durationMs`. The cursor holds (no travel),
|
|
68
|
+
* full-view (no zoom). `dy` is the signed pixels scrolled (editability). */
|
|
69
|
+
type CaptureScroll = CaptureEventBase & {
|
|
70
|
+
kind: "scroll";
|
|
71
|
+
/** signed pixels scrolled (positive = down) */
|
|
72
|
+
dy: number;
|
|
73
|
+
/** ms the scroll occupies on screen (ground-truth wall time) */
|
|
74
|
+
durationMs: number;
|
|
75
|
+
};
|
|
76
|
+
/** A hover: the cursor travels to `x,y` and dwells for `durationMs` so a
|
|
77
|
+
* tooltip / menu / hover-state reveals. Like a click that doesn't click. */
|
|
78
|
+
type CaptureHover = CaptureEventBase & {
|
|
79
|
+
kind: "hover";
|
|
80
|
+
/** ms the dwell occupies on screen (ground-truth wall time) */
|
|
81
|
+
durationMs: number;
|
|
82
|
+
};
|
|
83
|
+
/** A key press / shortcut: keyboard-driven, so the cursor holds (no travel).
|
|
84
|
+
* Holds for `durationMs` while the effect plays out; if a reveal element was
|
|
85
|
+
* located, `box` carries its bbox so the zoom can frame it. */
|
|
86
|
+
type CapturePress = CaptureEventBase & {
|
|
87
|
+
kind: "press";
|
|
88
|
+
/** the chord pressed, e.g. "Enter" / "Meta+k" (editability) */
|
|
89
|
+
keys: string;
|
|
90
|
+
/** ms the hold occupies on screen (ground-truth wall time) */
|
|
91
|
+
durationMs: number;
|
|
92
|
+
};
|
|
93
|
+
type CaptureEvent = CaptureClick | CaptureType | CaptureDrag | CaptureScroll | CaptureHover | CapturePress;
|
|
94
|
+
type CaptureLog = {
|
|
95
|
+
video: {
|
|
96
|
+
width: number;
|
|
97
|
+
height: number;
|
|
98
|
+
fps?: number | string;
|
|
99
|
+
durationS?: number;
|
|
100
|
+
};
|
|
101
|
+
viewport: {
|
|
102
|
+
w: number;
|
|
103
|
+
h: number;
|
|
104
|
+
};
|
|
105
|
+
start?: {
|
|
106
|
+
x: number;
|
|
107
|
+
y: number;
|
|
108
|
+
};
|
|
109
|
+
/** the ordered ground-truth actions (click / type / drag) */
|
|
110
|
+
events: CaptureEvent[];
|
|
111
|
+
tEndMs?: number;
|
|
112
|
+
};
|
|
113
|
+
type ZoomDecision = {
|
|
114
|
+
/** selective: not every action zooms. Edit this to tune/remove. */
|
|
115
|
+
enabled: boolean;
|
|
116
|
+
/** absolute stage scale to reach (bbox-fit, capped) */
|
|
117
|
+
scale: number;
|
|
118
|
+
/** video-px point to frame (bbox center), pre-clamp */
|
|
119
|
+
center: Pt;
|
|
120
|
+
/** when the zoom-in begins (ms) */
|
|
121
|
+
inAtMs: number;
|
|
122
|
+
/** Optional "glide": a slow camera drift WHILE the zoom is held, as a velocity
|
|
123
|
+
* in video-px per second {x,y}. The held centre pans from `center` by
|
|
124
|
+
* `glide · holdSeconds` across the hold window (then the next beat ramps from
|
|
125
|
+
* there / it zooms out from there). Adds life vs a dead-static hold (Screen
|
|
126
|
+
* Studio's glide). Absent/0 ⇒ a still hold. Clamped to the video at read time,
|
|
127
|
+
* so a drift just stops at the edge. Keep it gentle (tens of px/s). */
|
|
128
|
+
glide?: Pt;
|
|
129
|
+
/** why this decision (for the human/agent reading the composition) */
|
|
130
|
+
reason: string;
|
|
131
|
+
};
|
|
132
|
+
type CompEvent = {
|
|
133
|
+
kind: "click" | "type" | "drag" | "scroll" | "hover" | "press";
|
|
134
|
+
tMs: number;
|
|
135
|
+
/** anchor point (click / focus / drag start / hover) in video-px. For a
|
|
136
|
+
* scroll/press the cursor does not move; this is its resting point. */
|
|
137
|
+
point: Pt;
|
|
138
|
+
/** element bbox in video-px (if known) */
|
|
139
|
+
bbox?: BBox;
|
|
140
|
+
label?: string;
|
|
141
|
+
zoom: ZoomDecision;
|
|
142
|
+
/** how long the action plays out after `tMs` (type/drag/scroll/hover/press);
|
|
143
|
+
* 0 for a click. The cursor parks and the zoom holds for this long. */
|
|
144
|
+
durationMs?: number;
|
|
145
|
+
/** typed text (kind=type), for editability */
|
|
146
|
+
text?: string;
|
|
147
|
+
/** chord pressed (kind=press), for editability */
|
|
148
|
+
keys?: string;
|
|
149
|
+
/** drag end point, video-px (kind=drag) */
|
|
150
|
+
to?: Pt;
|
|
151
|
+
/** drag polyline incl. ends, video-px (kind=drag) — the cursor path */
|
|
152
|
+
path?: Pt[];
|
|
153
|
+
/** drag stroke easing baked into the ink (kind=drag): "smooth" or "linear".
|
|
154
|
+
* The cursor replays it so it stays locked to the ink. Absent ⇒ linear. */
|
|
155
|
+
ease?: "linear" | "smooth";
|
|
156
|
+
};
|
|
157
|
+
type FramingConfig = {
|
|
158
|
+
/** video occupies this fraction of the frame at rest (inset for the backdrop) */
|
|
159
|
+
insetFrac: number;
|
|
160
|
+
cornerRadius: number;
|
|
161
|
+
shadow: {
|
|
162
|
+
color: string;
|
|
163
|
+
blur: number;
|
|
164
|
+
offset: Pt;
|
|
165
|
+
};
|
|
166
|
+
/** backdrop behind the framed video. `type` defaults to "gradient" (from→to);
|
|
167
|
+
* "solid" fills `from` only. `angle` (deg, CSS-like: 0 = upward) rotates the
|
|
168
|
+
* gradient; absent ⇒ the legacy top-left→bottom-right diagonal (pixel-identical). */
|
|
169
|
+
background: {
|
|
170
|
+
from: string;
|
|
171
|
+
to: string;
|
|
172
|
+
type?: "gradient" | "solid";
|
|
173
|
+
angle?: number;
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
type CursorConfig = {
|
|
177
|
+
/** Fallback travel duration (ms) when `travelWidthsPerSec` is unset/0. A FIXED
|
|
178
|
+
* duration makes cursor speed scale with distance (short=slow, long=fast),
|
|
179
|
+
* which reads inconsistent; prefer the distance-aware speed below. */
|
|
180
|
+
travelMs: number;
|
|
181
|
+
/** Distance-aware travel speed, as a fraction of the source video WIDTH per
|
|
182
|
+
* second (resolution-independent). A travel leg's duration is
|
|
183
|
+
* `clamp(distance / (widthsPerSec·videoWidth), travelMinMs, travelMaxMs)`, so
|
|
184
|
+
* the cursor holds a roughly CONSTANT on-screen speed regardless of distance —
|
|
185
|
+
* the premium-recorder feel (measured ~0.30 widths/s on the reference). Set 0
|
|
186
|
+
* to fall back to the fixed `travelMs`. */
|
|
187
|
+
travelWidthsPerSec: number;
|
|
188
|
+
/** Floor for a distance-aware travel (ms) so short hops aren't an instant snap. */
|
|
189
|
+
travelMinMs: number;
|
|
190
|
+
/** Ceiling for a distance-aware travel (ms) so a full-width jump stays a glide,
|
|
191
|
+
* not a multi-second crawl. */
|
|
192
|
+
travelMaxMs: number;
|
|
193
|
+
scale: number;
|
|
194
|
+
arcFrac: number;
|
|
195
|
+
arcMax: number;
|
|
196
|
+
rippleMs: number;
|
|
197
|
+
/** ms to hold a zoom after the action settles, before zooming back out */
|
|
198
|
+
holdMs: number;
|
|
199
|
+
/** ms for the zoom-OUT ramp (back to rest) */
|
|
200
|
+
zoomOutMs: number;
|
|
201
|
+
/** ms for the zoom-IN ramp (into a target). Decoupled from travelMs so the
|
|
202
|
+
* zoom can be slower/gentler than the cursor (a cinematic ~1s zoom). */
|
|
203
|
+
zoomInMs: number;
|
|
204
|
+
/** Easing for the zoom/pan stage ramps (scale + center together), as
|
|
205
|
+
* cubic-bezier control points. Absent ⇒ symmetric smootherstep — whose broad
|
|
206
|
+
* near-constant-velocity middle reads a bit linear, esp. on the zoom-OUT
|
|
207
|
+
* settle. A decel-biased curve gives a softer landing into rest. */
|
|
208
|
+
zoomEase?: [number, number, number, number];
|
|
209
|
+
/** Spring easing for the zoom/pan stage ramps, as a `bounce` amount ∈ [0,~0.6):
|
|
210
|
+
* 0 = critically damped (a soft physical ease-out), higher = more overshoot/
|
|
211
|
+
* snap (the "silky" settle a premium screen-recorder has; ~0.06 for zoom). When
|
|
212
|
+
* set, this WINS over `zoomEase` (see math.ts stageEasing). Absent ⇒ use
|
|
213
|
+
* `zoomEase`/smootherstep. The segment duration stays zoomInMs/zoomOutMs;
|
|
214
|
+
* bounce only shapes the curve. NB: large bounce can undershoot rest on the
|
|
215
|
+
* zoom-OUT (momentary backdrop dead-space) — keep it small for zoom. */
|
|
216
|
+
zoomSpring?: number;
|
|
217
|
+
/** ms to delay the synthetic cursor along a DRAG stroke, compensating for the
|
|
218
|
+
* capture pipeline latency: the captured ink appears ~this long after the pen
|
|
219
|
+
* actually moved, so without the delay the (exact-time) cursor leads the ink.
|
|
220
|
+
* Tune so the cursor tip sits on the ink front mid-stroke. */
|
|
221
|
+
dragLagMs: number;
|
|
222
|
+
/** easing for a travel move, as cubic-bezier control points [x1,y1,x2,y2].
|
|
223
|
+
* Default is a symmetric ease-in-out — measured from a reference recording, whose
|
|
224
|
+
* cursor accelerates and decelerates evenly (a slow start, fast middle, soft
|
|
225
|
+
* landing). Drag strokes ignore this (they ease the stroke in lockstep with
|
|
226
|
+
* the captured ink — see math.ts). */
|
|
227
|
+
travelEase: [number, number, number, number];
|
|
228
|
+
};
|
|
229
|
+
/** Camera motion blur (temporal supersampling — what a real shutter does). The
|
|
230
|
+
* renderer samples the composition camera at `samples` sub-times within each
|
|
231
|
+
* output frame and averages them, so a fast zoom/pan/cursor smears in the
|
|
232
|
+
* motion direction (a camera/shutter motion blur). It smears the
|
|
233
|
+
* backdrop-reveal on a zoom-OUT into a soft gradient instead of a hard
|
|
234
|
+
* single-frame pop. The captured video's frames repeat across sub-samples, so
|
|
235
|
+
* the recording's own content is NOT blurred — only the camera move + cursor. */
|
|
236
|
+
type MotionBlurConfig = {
|
|
237
|
+
/** sub-frames sampled per output frame. 1 ⇒ OFF (no supersampling, no cost). */
|
|
238
|
+
samples: number;
|
|
239
|
+
/** fraction of the frame interval the shutter is open (0..1). Blur strength;
|
|
240
|
+
* 0 ⇒ OFF. ~0.5 = a 180° shutter, 1 = 360°. */
|
|
241
|
+
shutter: number;
|
|
242
|
+
};
|
|
243
|
+
/** One caption window on a review copy: the pill reads `text` from `fromMs`
|
|
244
|
+
* (inclusive) to `toMs` (exclusive) on the composition timeline. */
|
|
245
|
+
type ReviewBadge = {
|
|
246
|
+
fromMs: number;
|
|
247
|
+
toMs: number;
|
|
248
|
+
text: string;
|
|
249
|
+
};
|
|
250
|
+
/** Render-time decoration for review copies and A/B variant reels: burned-in
|
|
251
|
+
* beat badges, a REVIEW watermark, and a per-variant corner label. Drawn by the
|
|
252
|
+
* scene in SCREEN space (fixed, outside the composition camera) so the text is
|
|
253
|
+
* legible at any zoom. This is a render input only — it is never written into
|
|
254
|
+
* the editable `*.composition.json` artifact (render strips it) and the
|
|
255
|
+
* validator ignores it. Text renders in the headless Chrome, so any script
|
|
256
|
+
* (incl. CJK) works without ffmpeg font filters. */
|
|
257
|
+
type ReviewDecor = {
|
|
258
|
+
/** top-right watermark, e.g. "REVIEW" — marks a copy as not-for-posting */
|
|
259
|
+
watermark?: string;
|
|
260
|
+
/** bottom-left caption pill, swapping per timeline window */
|
|
261
|
+
badges?: ReviewBadge[];
|
|
262
|
+
/** constant bottom-left variant label for A/B reels, e.g. "B · tight ×1.8" */
|
|
263
|
+
label?: string;
|
|
264
|
+
};
|
|
265
|
+
type TakeComposition = {
|
|
266
|
+
output: {
|
|
267
|
+
width: number;
|
|
268
|
+
height: number;
|
|
269
|
+
fps: number;
|
|
270
|
+
};
|
|
271
|
+
source: {
|
|
272
|
+
videoUrl: string;
|
|
273
|
+
videoWidth: number;
|
|
274
|
+
videoHeight: number;
|
|
275
|
+
viewport: {
|
|
276
|
+
w: number;
|
|
277
|
+
h: number;
|
|
278
|
+
};
|
|
279
|
+
};
|
|
280
|
+
framing: FramingConfig;
|
|
281
|
+
cursor: CursorConfig;
|
|
282
|
+
/** camera motion blur; absent ⇒ off (renders exactly as before). */
|
|
283
|
+
motionBlur?: MotionBlurConfig;
|
|
284
|
+
/** cursor start, video-px */
|
|
285
|
+
start: Pt;
|
|
286
|
+
events: CompEvent[];
|
|
287
|
+
durationMs: number;
|
|
288
|
+
/** render-time review decoration (badges/watermark/label); never persisted */
|
|
289
|
+
review?: ReviewDecor;
|
|
290
|
+
};
|
|
291
|
+
/** True when motion blur is configured to actually do something (so the OFF
|
|
292
|
+
* path stays byte-identical to the pre-motion-blur renderer). */
|
|
293
|
+
declare function motionBlurActive(mb: MotionBlurConfig | undefined): mb is MotionBlurConfig;
|
|
294
|
+
declare const DEFAULT_FRAMING: FramingConfig;
|
|
295
|
+
declare const DEFAULT_MOTION_BLUR: MotionBlurConfig;
|
|
296
|
+
declare const DEFAULT_CURSOR: CursorConfig; //#endregion
|
|
297
|
+
//#region src/presets.d.ts
|
|
298
|
+
|
|
299
|
+
//# sourceMappingURL=types.d.ts.map
|
|
300
|
+
declare const ZOOM_LEVELS: {
|
|
301
|
+
readonly light: 1.25;
|
|
302
|
+
readonly medium: 1.5;
|
|
303
|
+
readonly tight: 1.8;
|
|
304
|
+
readonly close: 2.2;
|
|
305
|
+
};
|
|
306
|
+
type ZoomLevelName = keyof typeof ZOOM_LEVELS;
|
|
307
|
+
/** Name a scale if it sits within tolerance of a preset; else null (custom). */
|
|
308
|
+
declare function zoomLevelName(scale: number, tol?: number): ZoomLevelName | null;
|
|
309
|
+
type MotionPreset = Pick<CursorConfig, "travelWidthsPerSec" | "holdMs" | "zoomInMs" | "zoomOutMs">;
|
|
310
|
+
declare const MOTION: Record<"calm" | "natural" | "brisk", MotionPreset>;
|
|
311
|
+
type MotionName = keyof typeof MOTION;
|
|
312
|
+
declare function motionName(cursor: CursorConfig): MotionName | null;
|
|
313
|
+
type LookPreset = Pick<FramingConfig, "background" | "cornerRadius" | "shadow">;
|
|
314
|
+
declare const LOOKS: Record<string, LookPreset>;
|
|
315
|
+
type LookName = keyof typeof LOOKS;
|
|
316
|
+
declare function lookName(framing: FramingConfig): string | null;
|
|
317
|
+
declare const FINISH: Record<"smooth" | "crisp" | "heavy", MotionBlurConfig | undefined>;
|
|
318
|
+
type FinishName = keyof typeof FINISH;
|
|
319
|
+
declare function finishName(mb: MotionBlurConfig | undefined): FinishName | null;
|
|
320
|
+
|
|
321
|
+
//#endregion
|
|
322
|
+
//#region src/ffmpeg.d.ts
|
|
323
|
+
//# sourceMappingURL=presets.d.ts.map
|
|
324
|
+
declare function resolveFfmpeg(): Promise<string>;
|
|
325
|
+
declare function resolveFfprobe(): Promise<string>;
|
|
326
|
+
|
|
327
|
+
//#endregion
|
|
328
|
+
//#region src/plan.d.ts
|
|
329
|
+
//# sourceMappingURL=ffmpeg.d.ts.map
|
|
330
|
+
type PlanOpts = {
|
|
331
|
+
output?: {
|
|
332
|
+
width?: number;
|
|
333
|
+
height?: number;
|
|
334
|
+
fps?: number;
|
|
335
|
+
};
|
|
336
|
+
framing?: Partial<FramingConfig>;
|
|
337
|
+
cursor?: Partial<CursorConfig>;
|
|
338
|
+
/** element should fill this fraction of the frame when zoomed (default 0.55) */
|
|
339
|
+
fillFrac?: number;
|
|
340
|
+
/** hard cap on zoom (default 1.5 — a gentle workhorse; lower than
|
|
341
|
+
* the old 2.0 reads more premium. Small targets still zoom, just not as hard;
|
|
342
|
+
* raise per-beat in the composition when a tiny element needs it.) */
|
|
343
|
+
maxScale?: number;
|
|
344
|
+
/** require fit-scale to exceed rest*this to bother zooming (default 1.3) */
|
|
345
|
+
zoomRatio?: number;
|
|
346
|
+
/** never zoom the first (orienting) action by default (Finding 1) */
|
|
347
|
+
zoomFirst?: boolean;
|
|
348
|
+
};
|
|
349
|
+
declare function planComposition(log: CaptureLog, opts?: PlanOpts): TakeComposition;
|
|
350
|
+
|
|
351
|
+
//#endregion
|
|
352
|
+
//#region src/render.d.ts
|
|
353
|
+
//# sourceMappingURL=plan.d.ts.map
|
|
354
|
+
type RenderTakeOpts = {
|
|
355
|
+
/** input capture video (webm or mp4) */
|
|
356
|
+
videoPath: string;
|
|
357
|
+
/** output polished mp4 path */
|
|
358
|
+
outPath: string;
|
|
359
|
+
/** provide a capture log (auto-planned) ... */
|
|
360
|
+
log?: CaptureLog;
|
|
361
|
+
/** ... or a ready-made composition (editable artifact) */
|
|
362
|
+
composition?: TakeComposition;
|
|
363
|
+
planOpts?: PlanOpts;
|
|
364
|
+
logProgress?: boolean;
|
|
365
|
+
/** Chrome binary for the headless render. Pass the same Chrome-for-Testing
|
|
366
|
+
* the capture path uses so a single browser serves both stages (no second
|
|
367
|
+
* download). revideo forwards this to puppeteer.launch's executablePath;
|
|
368
|
+
* if unset, revideo's bundled puppeteer resolves its own. */
|
|
369
|
+
chromePath?: string;
|
|
370
|
+
/** the capture log, for cross-checking that an edited composition didn't
|
|
371
|
+
* drift an action's capture-locked tMs (see validateComposition). Optional —
|
|
372
|
+
* the structural checks run regardless. */
|
|
373
|
+
captureLog?: CaptureLog;
|
|
374
|
+
/** skip the pre-render structural validation. Default false — we validate and
|
|
375
|
+
* refuse to render an errored composition (a render is expensive; catch a bad
|
|
376
|
+
* hand-edit in milliseconds instead). */
|
|
377
|
+
skipValidate?: boolean;
|
|
378
|
+
/** progress callback (0..1) forwarded from revideo's renderer. */
|
|
379
|
+
onProgress?: (progress: number) => void;
|
|
380
|
+
/** render only this window of the composition timeline, in SECONDS — the
|
|
381
|
+
* windowed-render path behind A/B variant reels (a 4s window instead of the
|
|
382
|
+
* whole take). With motion blur OFF, frames are identical to the same span
|
|
383
|
+
* of a full render (the timeline is deterministic). With blur active the
|
|
384
|
+
* content matches but not bit-exactly: the tmix shutter windows are phased
|
|
385
|
+
* from the CLIP start, and the first frame's trailing window is truncated.
|
|
386
|
+
* Forwarded to revideo's projectSettings.range. */
|
|
387
|
+
rangeSec?: [number, number];
|
|
388
|
+
/** write the editable `<out>.composition.json` sibling (default true). Review
|
|
389
|
+
* copies and A/B reels are disposable — they skip the sibling. */
|
|
390
|
+
writeCompositionSibling?: boolean;
|
|
391
|
+
};
|
|
392
|
+
declare function renderTake(opts: RenderTakeOpts): Promise<{
|
|
393
|
+
mp4Path: string;
|
|
394
|
+
compositionPath: string;
|
|
395
|
+
}>;
|
|
396
|
+
|
|
397
|
+
//#endregion
|
|
398
|
+
//#region src/validate.d.ts
|
|
399
|
+
//# sourceMappingURL=render.d.ts.map
|
|
400
|
+
type CompositionIssue = {
|
|
401
|
+
severity: "error" | "warn";
|
|
402
|
+
/** dotted/indexed field path, e.g. "events[3].zoom.scale" */
|
|
403
|
+
path: string;
|
|
404
|
+
message: string;
|
|
405
|
+
/** a concrete suggested correction the agent can apply */
|
|
406
|
+
fix?: string;
|
|
407
|
+
};
|
|
408
|
+
type ValidateOpts = {
|
|
409
|
+
/** soft ceiling on zoom scale — above it the pixels visibly soften (warn).
|
|
410
|
+
* Default 2.5 (the planner caps auto-zoom at 1.5; manual edits get headroom). */
|
|
411
|
+
maxScale?: number;
|
|
412
|
+
/** the ground-truth capture log. When given, action `tMs` is checked against
|
|
413
|
+
* it (capture-lock). Omit to skip that check. */
|
|
414
|
+
captureLog?: CaptureLog;
|
|
415
|
+
};
|
|
416
|
+
declare function validateComposition(comp: TakeComposition, opts?: ValidateOpts): CompositionIssue[];
|
|
417
|
+
/** Format issues for a human/agent log. Errors first. */
|
|
418
|
+
declare function formatIssues(issues: CompositionIssue[]): string;
|
|
419
|
+
|
|
420
|
+
//#endregion
|
|
421
|
+
//#region src/math.d.ts
|
|
422
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
423
|
+
declare namespace math_d_exports {
|
|
424
|
+
export { StageKeyframes, bboxFitScale, buildLegs, buildStageKeyframes, clampCenter, cubicBezier, cursorPos, gradientEndpoints, isDragging, keyvalN, keyvalP, panEasing, restStageScale, smoother, springEase, stageEasing };
|
|
425
|
+
}
|
|
426
|
+
declare function smoother(t: number): number;
|
|
427
|
+
declare function cubicBezier(x1: number, y1: number, x2: number, y2: number): (x: number) => number;
|
|
428
|
+
declare function springEase(bounce: number): (p: number) => number;
|
|
429
|
+
declare function stageEasing(cursor: TakeComposition["cursor"]): (u: number) => number;
|
|
430
|
+
declare function panEasing(cursor: TakeComposition["cursor"]): (u: number) => number;
|
|
431
|
+
declare function gradientEndpoints(angleDeg: number | undefined, oW: number, oH: number): {
|
|
432
|
+
x0: number;
|
|
433
|
+
y0: number;
|
|
434
|
+
x1: number;
|
|
435
|
+
y1: number;
|
|
436
|
+
};
|
|
437
|
+
type KF<T> = [number, T];
|
|
438
|
+
declare function keyvalN(t: number, kfs: KF<number>[], ease?: (u: number) => number, easeDown?: (u: number) => number): number;
|
|
439
|
+
declare function keyvalP(t: number, kfs: KF<Pt>[], ease?: (u: number) => number): Pt;
|
|
440
|
+
/**
|
|
441
|
+
* Scale (absolute, video-px → output-px) that fits `bbox` into `fillFrac`
|
|
442
|
+
* of the output frame, capped at `maxScale` and floored at `restScale`.
|
|
443
|
+
* Wide/long elements naturally get a gentler scale because the limiting
|
|
444
|
+
* dimension dominates min().
|
|
445
|
+
*/
|
|
446
|
+
declare function bboxFitScale(bbox: BBox, outW: number, outH: number, fillFrac: number, maxScale: number, restScale: number): number;
|
|
447
|
+
/** Stage scale at rest: video inset into the frame (leaves backdrop margin). */
|
|
448
|
+
declare function restStageScale(videoW: number, videoH: number, outW: number, outH: number, insetFrac: number): number;
|
|
449
|
+
/**
|
|
450
|
+
* Clamp a desired video-px center so the scaled video still covers the output
|
|
451
|
+
* frame (the viewport crop stays inside the source video) when zoomed in. When
|
|
452
|
+
* the content does not cover an axis (zoomed out / inset), centre that axis.
|
|
453
|
+
*
|
|
454
|
+
* In the composition-camera model the whole composition
|
|
455
|
+
* (backdrop + inset screen) is zoomed by one camera; this keeps the camera crop
|
|
456
|
+
* within the screen so a zoom fills the frame (no backdrop margin) without ever
|
|
457
|
+
* panning past the recording's edge.
|
|
458
|
+
*/
|
|
459
|
+
declare function clampCenter(center: Pt, scale: number, videoW: number, videoH: number, outW: number, outH: number): Pt;
|
|
460
|
+
type StageKeyframes = {
|
|
461
|
+
z: KF<number>[];
|
|
462
|
+
c: KF<Pt>[];
|
|
463
|
+
T: number;
|
|
464
|
+
};
|
|
465
|
+
declare function buildStageKeyframes(comp: TakeComposition): StageKeyframes;
|
|
466
|
+
type Leg = {
|
|
467
|
+
t0: number;
|
|
468
|
+
t1: number;
|
|
469
|
+
a: Pt;
|
|
470
|
+
b: Pt;
|
|
471
|
+
drag?: boolean;
|
|
472
|
+
path?: Pt[];
|
|
473
|
+
ease?: "linear" | "smooth";
|
|
474
|
+
};
|
|
475
|
+
declare function buildLegs(comp: TakeComposition): Leg[];
|
|
476
|
+
declare function cursorPos(t: number, legs: Leg[], comp: TakeComposition): Pt;
|
|
477
|
+
/** True while a drag is mid-stroke (button held) — for the pressed cursor. */
|
|
478
|
+
declare function isDragging(t: number, legs: Leg[]): boolean;
|
|
479
|
+
|
|
480
|
+
//#endregion
|
|
481
|
+
export { BBox, CaptureClick, CaptureDrag, CaptureEvent, CaptureEventBase, CaptureHover, CaptureLog, CapturePress, CaptureScroll, CaptureType, CompEvent, CompositionIssue, CursorConfig, DEFAULT_CURSOR, DEFAULT_FRAMING, DEFAULT_MOTION_BLUR, FINISH, FinishName, FramingConfig, LOOKS, LookName, LookPreset, MOTION, MotionBlurConfig, MotionName, MotionPreset, PlanOpts, Pt, RenderTakeOpts, ReviewBadge, ReviewDecor, TakeComposition, ValidateOpts, ZOOM_LEVELS, ZoomDecision, ZoomIntent, ZoomLevelName, finishName, formatIssues, lookName, math_d_exports as math, motionBlurActive, motionName, planComposition, renderTake, resolveFfmpeg, resolveFfprobe, validateComposition, zoomLevelName };
|
|
482
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/presets.ts","../src/ffmpeg.ts","../src/plan.ts","../src/render.ts","../src/validate.ts","../src/math.ts"],"sourcesContent":null,"mappings":"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"}
|