@bendyline/squisq-video-react 2.1.0 → 2.2.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/NOTICE.md +23 -33
- package/dist/chunk-KQG6DZ7G.js +549 -0
- package/dist/chunk-VI5AIVOQ.js +1951 -0
- package/dist/chunk-VILZP3GL.js +856 -0
- package/dist/chunk-YZN7D4IC.js +300 -0
- package/dist/components/index.d.ts +90 -0
- package/dist/components/index.js +11 -0
- package/dist/encoder/index.d.ts +95 -0
- package/dist/encoder/index.js +13 -0
- package/dist/hooks/index.d.ts +32 -0
- package/dist/hooks/index.js +10 -0
- package/dist/index.d.ts +8 -315
- package/dist/index.js +12 -1664
- package/dist/useVideoExport-NtqZVgaz.d.ts +115 -0
- package/dist/workers/encode.worker.js +1 -1
- package/package.json +22 -7
- package/dist/chunk-2PGWBGAT.js +0 -46
package/dist/index.d.ts
CHANGED
|
@@ -1,316 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export { VideoExportButton, VideoExportButtonProps, VideoExportModal, VideoExportModalProps, VideoExportPalette } from './components/index.js';
|
|
2
|
+
export { V as VideoAudioPolicy, a as VideoExportConfig, b as VideoExportResult, c as VideoExportState, d as VideoOutputFormat, u as useVideoExport } from './useVideoExport-NtqZVgaz.js';
|
|
3
|
+
export { FrameCaptureHandle, useFrameCapture } from './hooks/index.js';
|
|
4
|
+
export { EncoderConfig, MainThreadEncoder, createEncoder, supportsWebCodecs, supportsWebCodecsAac, supportsWebCodecsH264 } from './encoder/index.js';
|
|
5
5
|
export { FfmpegWasmLoadConfig } from '@bendyline/squisq-video';
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*
|
|
11
|
-
* Coordinates frame capture (hidden iframe + html2canvas) with
|
|
12
|
-
* main-thread WebCodecs encoding via mp4-muxer. Manages the full
|
|
13
|
-
* lifecycle: prepare → capture + encode → download.
|
|
14
|
-
*
|
|
15
|
-
* Encoding runs on the main thread because frame capture via html2canvas
|
|
16
|
-
* (~100-200ms per frame) is the bottleneck, not encoding (~1ms per frame
|
|
17
|
-
* with hardware-accelerated WebCodecs). Worker offloading would add
|
|
18
|
-
* complexity with minimal benefit.
|
|
19
|
-
*
|
|
20
|
-
* Usage:
|
|
21
|
-
* const { state, progress, phase, startExport, cancel, downloadUrl } = useVideoExport();
|
|
22
|
-
* <button onClick={() => startExport(doc, options)}>Export</button>
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
type VideoExportState = 'idle' | 'preparing' | 'capturing' | 'encoding' | 'complete' | 'error';
|
|
26
|
-
/** Browser export container format. */
|
|
27
|
-
type VideoOutputFormat = 'mp4' | 'gif';
|
|
28
|
-
type VideoAudioPolicy = 'require' | 'best-effort' | 'omit';
|
|
29
|
-
interface VideoExportConfig {
|
|
30
|
-
/** Output container (default: 'mp4') */
|
|
31
|
-
outputFormat?: VideoOutputFormat;
|
|
32
|
-
/**
|
|
33
|
-
* How authored MP4 audio is handled. `require` (default) fails before
|
|
34
|
-
* capture when audio cannot be loaded/decoded and fails the export if later
|
|
35
|
-
* encoding or muxing fails. `best-effort` explicitly permits video-only
|
|
36
|
-
* degradation; `omit` intentionally skips audio.
|
|
37
|
-
*/
|
|
38
|
-
audioPolicy?: VideoAudioPolicy;
|
|
39
|
-
/** Render authored animations and slide transitions (default: true for MP4, false for GIF). */
|
|
40
|
-
animationsEnabled?: boolean;
|
|
41
|
-
/** Encoding quality preset (default: 'normal') */
|
|
42
|
-
quality?: VideoQuality;
|
|
43
|
-
/** Frames per second (default: 30) */
|
|
44
|
-
fps?: number;
|
|
45
|
-
/** Viewport orientation (default: 'landscape') */
|
|
46
|
-
orientation?: VideoOrientation;
|
|
47
|
-
/** Explicit output width. GIF defaults to 960 landscape / 540 portrait. */
|
|
48
|
-
width?: number;
|
|
49
|
-
/** Explicit output height. GIF defaults to 540 landscape / 960 portrait. */
|
|
50
|
-
height?: number;
|
|
51
|
-
/**
|
|
52
|
-
* Map of relative image paths to binary data.
|
|
53
|
-
* Used to embed images into the render HTML.
|
|
54
|
-
*/
|
|
55
|
-
images?: Map<string, ArrayBuffer>;
|
|
56
|
-
/**
|
|
57
|
-
* Map of audio segment names to binary data.
|
|
58
|
-
* Used to embed audio into the render HTML.
|
|
59
|
-
*/
|
|
60
|
-
audio?: Map<string, ArrayBuffer>;
|
|
61
|
-
/** MediaProvider to resolve media URLs (alternative to passing images directly) */
|
|
62
|
-
mediaProvider?: MediaProvider;
|
|
63
|
-
/** Policy and byte/time limits for MediaProvider URLs. */
|
|
64
|
-
resourcePolicy?: ResourcePolicy;
|
|
65
|
-
/** Caption mode for the exported video (default: 'off') */
|
|
66
|
-
captionMode?: CaptionMode;
|
|
67
|
-
/** Player IIFE bundle (unused in browser export, kept for CLI/Playwright path) */
|
|
68
|
-
playerScript?: string;
|
|
69
|
-
/** Optional self-hosted ffmpeg.wasm core URLs for fallback/offline/CSP use. */
|
|
70
|
-
ffmpegWasm?: FfmpegWasmLoadConfig;
|
|
71
|
-
}
|
|
72
|
-
interface VideoExportResult {
|
|
73
|
-
/** Current export state */
|
|
74
|
-
state: VideoExportState;
|
|
75
|
-
/** 0–100 progress percentage */
|
|
76
|
-
progress: number;
|
|
77
|
-
/** Human-readable description of the current phase */
|
|
78
|
-
phase: string;
|
|
79
|
-
/** Video duration detected from the doc (seconds) */
|
|
80
|
-
duration: number;
|
|
81
|
-
/** Effective output format for the current or most recent export. */
|
|
82
|
-
outputFormat: VideoOutputFormat;
|
|
83
|
-
/** Encoder backend ('webcodecs' when WebCodecs H.264 active, 'ffmpeg-wasm' when worker fallback active, null when idle) */
|
|
84
|
-
backend: 'webcodecs' | 'ffmpeg-wasm' | null;
|
|
85
|
-
/** Blob download URL (populated when state === 'complete') */
|
|
86
|
-
downloadUrl: string | null;
|
|
87
|
-
/** File size in bytes (populated when state === 'complete') */
|
|
88
|
-
fileSize: number;
|
|
89
|
-
/**
|
|
90
|
-
* Whether an audio track was muxed into the exported MP4 (populated when
|
|
91
|
-
* state === 'complete'). False when the doc had no audio or when audio was
|
|
92
|
-
* skipped/degraded — see {@link audioSkippedReason}.
|
|
93
|
-
*/
|
|
94
|
-
audioIncluded: boolean;
|
|
95
|
-
/**
|
|
96
|
-
* Why audio is absent, when `audioIncluded` is false. `null` means the doc
|
|
97
|
-
* simply had no audio (not a failure); a non-null string explains a genuine
|
|
98
|
-
* capability shortfall or runtime failure. Audio problems never fail the
|
|
99
|
-
* export — the video always completes.
|
|
100
|
-
*/
|
|
101
|
-
audioSkippedReason: string | null;
|
|
102
|
-
/** Error message (populated when state === 'error') */
|
|
103
|
-
error: string | null;
|
|
104
|
-
/** Seconds elapsed since export started */
|
|
105
|
-
elapsed: number;
|
|
106
|
-
/** Estimated seconds remaining (0 when idle or complete) */
|
|
107
|
-
estimatedRemaining: number;
|
|
108
|
-
/** Start a new export */
|
|
109
|
-
startExport: (doc: Doc, config: VideoExportConfig) => Promise<void>;
|
|
110
|
-
/** Cancel an in-progress export */
|
|
111
|
-
cancel: () => void;
|
|
112
|
-
/** Reset state back to idle (e.g., after complete or error) */
|
|
113
|
-
reset: () => void;
|
|
114
|
-
}
|
|
115
|
-
declare function useVideoExport(): VideoExportResult;
|
|
116
|
-
|
|
117
|
-
interface VideoExportModalProps {
|
|
118
|
-
/** The document to export */
|
|
119
|
-
doc: Doc;
|
|
120
|
-
/**
|
|
121
|
-
* Player IIFE bundle source. Unused by the browser export path (frames
|
|
122
|
-
* are captured from a live in-page DocPlayer); only forwarded for
|
|
123
|
-
* CLI/Playwright-style pipelines that render standalone HTML.
|
|
124
|
-
*/
|
|
125
|
-
playerScript?: string;
|
|
126
|
-
/** Optional media provider for resolving images/audio */
|
|
127
|
-
mediaProvider?: MediaProvider;
|
|
128
|
-
/** Pre-collected images map (alternative to mediaProvider) */
|
|
129
|
-
images?: Map<string, ArrayBuffer>;
|
|
130
|
-
/** Pre-collected audio map */
|
|
131
|
-
audio?: Map<string, ArrayBuffer>;
|
|
132
|
-
/**
|
|
133
|
-
* Seeds the modal's initial format, motion, quality, FPS, orientation, and
|
|
134
|
-
* caption selections. It is merged (as a base) into the config passed to the
|
|
135
|
-
* export hook, so a host can share one config shape with `useVideoExport`.
|
|
136
|
-
* The individual `images`/`audio`/`mediaProvider`/`playerScript` props still
|
|
137
|
-
* take precedence over any matching key here.
|
|
138
|
-
*/
|
|
139
|
-
defaultConfig?: Partial<VideoExportConfig>;
|
|
140
|
-
/** Visual color scheme for the portaled dialog. Defaults to light. */
|
|
141
|
-
colorScheme?: 'light' | 'dark';
|
|
142
|
-
/** Optional host overrides for dialog surfaces, controls, status, and accent colors. */
|
|
143
|
-
uiPalette?: Partial<VideoExportPalette>;
|
|
144
|
-
/** Called when the modal should close */
|
|
145
|
-
onClose: () => void;
|
|
146
|
-
}
|
|
147
|
-
interface VideoExportPalette {
|
|
148
|
-
overlay: string;
|
|
149
|
-
surface: string;
|
|
150
|
-
control: string;
|
|
151
|
-
border: string;
|
|
152
|
-
text: string;
|
|
153
|
-
heading: string;
|
|
154
|
-
label: string;
|
|
155
|
-
muted: string;
|
|
156
|
-
secondary: string;
|
|
157
|
-
primary: string;
|
|
158
|
-
primaryBorder: string;
|
|
159
|
-
primaryText: string;
|
|
160
|
-
success: string;
|
|
161
|
-
danger: string;
|
|
162
|
-
}
|
|
163
|
-
declare function VideoExportModal({ doc, playerScript, mediaProvider, images, audio, defaultConfig, colorScheme, uiPalette, onClose, }: VideoExportModalProps): react_jsx_runtime.JSX.Element;
|
|
164
|
-
|
|
165
|
-
interface VideoExportButtonProps {
|
|
166
|
-
/** The document to export */
|
|
167
|
-
doc: Doc;
|
|
168
|
-
/**
|
|
169
|
-
* Player IIFE bundle source. Unused by the browser export path (frames
|
|
170
|
-
* are captured from a live in-page DocPlayer); only forwarded for
|
|
171
|
-
* CLI/Playwright-style pipelines that render standalone HTML.
|
|
172
|
-
*/
|
|
173
|
-
playerScript?: string;
|
|
174
|
-
/** Optional media provider for resolving images/audio */
|
|
175
|
-
mediaProvider?: MediaProvider;
|
|
176
|
-
/** Pre-collected images map */
|
|
177
|
-
images?: Map<string, ArrayBuffer>;
|
|
178
|
-
/** Pre-collected audio map */
|
|
179
|
-
audio?: Map<string, ArrayBuffer>;
|
|
180
|
-
/**
|
|
181
|
-
* Seeds the modal's initial output format and export settings and is merged
|
|
182
|
-
* as a base into the config passed to the export hook. Forwarded to
|
|
183
|
-
* {@link VideoExportModal}.
|
|
184
|
-
*/
|
|
185
|
-
defaultConfig?: Partial<VideoExportConfig>;
|
|
186
|
-
/** Visual color scheme forwarded to the portaled modal. Defaults to light. */
|
|
187
|
-
colorScheme?: 'light' | 'dark';
|
|
188
|
-
/** Optional host palette overrides forwarded to the portaled modal. */
|
|
189
|
-
uiPalette?: Partial<VideoExportPalette>;
|
|
190
|
-
/** Button label (defaults to "Export Video", or "Export GIF" for a GIF default config) */
|
|
191
|
-
label?: string;
|
|
192
|
-
/** Additional inline styles for the button */
|
|
193
|
-
style?: React.CSSProperties;
|
|
194
|
-
/** Whether the button is disabled */
|
|
195
|
-
disabled?: boolean;
|
|
196
|
-
}
|
|
197
|
-
declare function VideoExportButton({ doc, playerScript, mediaProvider, images, audio, defaultConfig, colorScheme, uiPalette, label, style, disabled, }: VideoExportButtonProps): react_jsx_runtime.JSX.Element;
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* useFrameCapture — Hidden div + html2canvas frame capture.
|
|
201
|
-
*
|
|
202
|
-
* Mounts a DocPlayer in renderMode inside a hidden div (same document),
|
|
203
|
-
* then captures individual frames by seeking the player and rendering
|
|
204
|
-
* the DOM to a canvas via html2canvas.
|
|
205
|
-
*
|
|
206
|
-
* Uses React directly — no script injection, no iframes, no eval.
|
|
207
|
-
*
|
|
208
|
-
* Returns an ImageBitmap for each frame (transferable to a Worker).
|
|
209
|
-
*/
|
|
210
|
-
|
|
211
|
-
interface FrameCaptureHandle {
|
|
212
|
-
/** Initialize the hidden player. Returns the video duration in seconds. */
|
|
213
|
-
init: (doc: Doc, renderOptions: Omit<RenderHtmlOptions, 'playerScript'>, captionMode?: CaptionMode) => Promise<number>;
|
|
214
|
-
/** Capture a single frame at the given time (seconds). Returns an ImageBitmap. */
|
|
215
|
-
captureFrame: (time: number) => Promise<ImageBitmap>;
|
|
216
|
-
/** Clean up resources. */
|
|
217
|
-
destroy: () => void;
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Hook that manages a hidden div for frame capture.
|
|
221
|
-
*/
|
|
222
|
-
declare function useFrameCapture(): FrameCaptureHandle;
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Main-thread WebCodecs encoder.
|
|
226
|
-
*
|
|
227
|
-
* Encodes video frames to MP4 using the WebCodecs API and mp4-muxer,
|
|
228
|
-
* running directly on the main thread. This is simpler and avoids
|
|
229
|
-
* worker module-resolution issues with bundlers. Since frame capture
|
|
230
|
-
* via html2canvas (~100-200ms per frame) is the bottleneck — not
|
|
231
|
-
* encoding (~1ms per frame with hardware-accelerated WebCodecs) —
|
|
232
|
-
* worker offloading provides minimal benefit.
|
|
233
|
-
*
|
|
234
|
-
* Requirements: Chrome 94+ / Edge 94+ (WebCodecs support).
|
|
235
|
-
*/
|
|
236
|
-
interface EncoderConfig {
|
|
237
|
-
width: number;
|
|
238
|
-
height: number;
|
|
239
|
-
fps: number;
|
|
240
|
-
quality: 'draft' | 'normal' | 'high';
|
|
241
|
-
/**
|
|
242
|
-
* Total frames the caller intends to submit, when known. Unused by the
|
|
243
|
-
* main-thread encoder (the caller owns the progress bar) but forwarded by
|
|
244
|
-
* {@link createWorkerEncoder} so the worker can report real progress instead
|
|
245
|
-
* of guessing from the frames it happens to have seen.
|
|
246
|
-
*/
|
|
247
|
-
totalFrames?: number;
|
|
248
|
-
/**
|
|
249
|
-
* When present, the underlying muxer is configured with an AAC audio track
|
|
250
|
-
* and {@link MainThreadEncoder.addAudioChunk} becomes usable. Absent → the
|
|
251
|
-
* encoder produces a video-only MP4 exactly as before.
|
|
252
|
-
*/
|
|
253
|
-
audio?: {
|
|
254
|
-
numberOfChannels: number;
|
|
255
|
-
sampleRate: number;
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
interface MainThreadEncoder {
|
|
259
|
-
/** Encode a single frame. The bitmap is closed after encoding. */
|
|
260
|
-
encodeFrame(bitmap: ImageBitmap, frameIndex: number): Promise<void>;
|
|
261
|
-
/**
|
|
262
|
-
* Hand an encoded audio chunk (from a WebCodecs `AudioEncoder`) to the muxer.
|
|
263
|
-
* Only valid when the encoder was created with an `audio` config; otherwise a
|
|
264
|
-
* no-op. Must be called before {@link finalize}.
|
|
265
|
-
*/
|
|
266
|
-
addAudioChunk?(chunk: EncodedAudioChunk, meta?: EncodedAudioChunkMetadata): void;
|
|
267
|
-
/** Flush pending frames and finalize the MP4. Returns the MP4 ArrayBuffer. */
|
|
268
|
-
finalize(): Promise<ArrayBuffer>;
|
|
269
|
-
/** Close the encoder without producing output (e.g., on cancel). */
|
|
270
|
-
close(): void;
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Check whether the browser supports WebCodecs video encoding.
|
|
274
|
-
*/
|
|
275
|
-
declare function supportsWebCodecs(): boolean;
|
|
276
|
-
/**
|
|
277
|
-
* Probe whether the WebCodecs encoder actually supports the H.264 profile
|
|
278
|
-
* we use. The `VideoEncoder` global can exist while the specific codec is
|
|
279
|
-
* unavailable — this is the case on Linux Chromium, which ships without
|
|
280
|
-
* the proprietary H.264 encoder.
|
|
281
|
-
*/
|
|
282
|
-
declare function supportsWebCodecsH264(config: EncoderConfig): Promise<boolean>;
|
|
283
|
-
/**
|
|
284
|
-
* Create a main-thread WebCodecs encoder.
|
|
285
|
-
*
|
|
286
|
-
* Throws if WebCodecs is not available.
|
|
287
|
-
*/
|
|
288
|
-
declare function createEncoder(config: EncoderConfig): MainThreadEncoder;
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* audioTrack — In-browser audio rendering + AAC encoding for MP4 export.
|
|
292
|
-
*
|
|
293
|
-
* Replaces the CLI's ffmpeg `adelay`/`atrim`/`amix` graph with browser-native
|
|
294
|
-
* primitives:
|
|
295
|
-
*
|
|
296
|
-
* - {@link supportsWebCodecsAac} probes whether the browser can encode AAC
|
|
297
|
-
* (WebCodecs `AudioEncoder`).
|
|
298
|
-
* - {@link renderAudioTimeline} mixes an {@link AudioTimelineClip} list into a
|
|
299
|
-
* single `AudioBuffer` using an `OfflineAudioContext` (decode → schedule →
|
|
300
|
-
* render).
|
|
301
|
-
* - {@link encodeAacTrack} feeds that buffer through a WebCodecs
|
|
302
|
-
* `AudioEncoder` and hands the chunks to an mp4-muxer audio track (tier 1).
|
|
303
|
-
* - {@link audioBufferToWav} + {@link muxAudioWithFfmpegWasm} cover the
|
|
304
|
-
* ffmpeg.wasm fallback (tier 2).
|
|
305
|
-
* - {@link selectAudioTier} is the pure capability→tier decision shared with
|
|
306
|
-
* `useVideoExport` (and unit-tested at the module boundary).
|
|
307
|
-
*/
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Whether the browser can encode AAC (`mp4a.40.2`) via WebCodecs.
|
|
311
|
-
* Returns false when `AudioEncoder` is undefined (e.g. Node/jsdom, Safari,
|
|
312
|
-
* older Chromium) or the config is unsupported.
|
|
313
|
-
*/
|
|
314
|
-
declare function supportsWebCodecsAac(sampleRate?: number, channels?: number): Promise<boolean>;
|
|
315
|
-
|
|
316
|
-
export { type EncoderConfig, type FrameCaptureHandle, type MainThreadEncoder, type VideoAudioPolicy, VideoExportButton, type VideoExportButtonProps, type VideoExportConfig, VideoExportModal, type VideoExportModalProps, type VideoExportPalette, type VideoExportResult, type VideoExportState, type VideoOutputFormat, createEncoder, supportsWebCodecs, supportsWebCodecsAac, supportsWebCodecsH264, useFrameCapture, useVideoExport };
|
|
6
|
+
import 'react/jsx-runtime';
|
|
7
|
+
import '@bendyline/squisq/schemas';
|
|
8
|
+
import '@bendyline/squisq/markdown';
|
|
9
|
+
import '@bendyline/squisq-react';
|