textmode.export.js 1.8.0 → 1.9.0-beta.1

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.
Files changed (38) hide show
  1. package/README.md +7 -2
  2. package/dist/textmode.export.esm.js +1 -1
  3. package/dist/textmode.export.umd.js +1 -1
  4. package/dist/types/exporters/base/FileHandler.d.ts +1 -14
  5. package/dist/types/exporters/base/FilenamePolicy.d.ts +6 -0
  6. package/dist/types/exporters/base/FramePreparation.d.ts +7 -0
  7. package/dist/types/exporters/base/frame-sequence/ExclusiveCaptureGate.d.ts +7 -0
  8. package/dist/types/exporters/base/frame-sequence/FrameSchedule.d.ts +8 -0
  9. package/dist/types/exporters/{video/VideoFrameDriver.d.ts → base/frame-sequence/FrameSequenceDriver.d.ts} +5 -11
  10. package/dist/types/exporters/base/frame-sequence/errors.d.ts +12 -0
  11. package/dist/types/exporters/base/frame-sequence/index.d.ts +5 -0
  12. package/dist/types/exporters/base/frame-sequence/types.d.ts +20 -0
  13. package/dist/types/exporters/base/frame-sequence/withAbortableTimeout.d.ts +1 -0
  14. package/dist/types/exporters/base/index.d.ts +3 -0
  15. package/dist/types/exporters/gif/GIFExporter.d.ts +1 -1
  16. package/dist/types/exporters/gif/index.d.ts +0 -1
  17. package/dist/types/exporters/gif/types.d.ts +6 -12
  18. package/dist/types/exporters/json/JSONExporter.d.ts +2 -2
  19. package/dist/types/exporters/video/VideoEncodingPolicy.d.ts +2 -19
  20. package/dist/types/exporters/video/VideoExporter.d.ts +4 -6
  21. package/dist/types/exporters/video/VideoRecorder.d.ts +2 -1
  22. package/dist/types/exporters/video/errors.d.ts +1 -0
  23. package/dist/types/exporters/video/index.d.ts +1 -1
  24. package/dist/types/exporters/video/types.d.ts +104 -107
  25. package/dist/types/exporters/zip/FrameSerializerRegistry.d.ts +4 -0
  26. package/dist/types/exporters/zip/ZIPArchiveWriter.d.ts +21 -0
  27. package/dist/types/exporters/zip/ZIPExporter.d.ts +32 -0
  28. package/dist/types/exporters/zip/ZIPManifest.d.ts +12 -0
  29. package/dist/types/exporters/zip/errors.d.ts +14 -0
  30. package/dist/types/exporters/zip/index.d.ts +3 -0
  31. package/dist/types/exporters/zip/types.d.ts +177 -0
  32. package/dist/types/index.d.ts +34 -6
  33. package/dist/types/overlay/blades/VideoBlade.d.ts +3 -6
  34. package/dist/types/overlay/types.d.ts +2 -4
  35. package/dist/types/runtime/TextmodeExportController.d.ts +3 -0
  36. package/dist/types/types.d.ts +72 -11
  37. package/package.json +6 -3
  38. package/dist/types/exporters/gif/GIFRecorder.d.ts +0 -23
@@ -1,45 +1,83 @@
1
- import type { PrepareExportFrame } from '../base';
1
+ import type { FrameSequenceDriverLike, FrameSequenceRenderOptions, PrepareExportFrame } from '../base';
2
2
  /**
3
- * Lifecycle state reported while a video export is being prepared, recorded, encoded, or completed.
3
+ * High-level lifecycle state reported while a video export is captured, encoded, or completed.
4
4
  *
5
- * @category Animation export
5
+ * @category Video export
6
6
  *
7
7
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoRecordingState | VideoRecordingState API reference}
8
8
  */
9
9
  export type VideoRecordingState = 'idle' | 'recording' | 'encoding' | 'completed' | 'error';
10
10
  /**
11
- * More granular phase information for progress UIs that need to distinguish setup, rendering, and finalization.
11
+ * Detailed phase information for progress UIs that distinguish capability probing, frame capture, and output.
12
12
  *
13
- * `rendering` is retained for 1.5.x compatibility. Current deterministic video capture emits `capturing`.
13
+ * Current exports emit `probing`, `capturing`, and either `writing` for streamed file-system output or `finalizing`
14
+ * for buffered output. `rendering`, `encoding`, and `draining` remain available for compatibility with older progress
15
+ * producers.
14
16
  *
15
- * @category Animation export
17
+ * @category Video export
16
18
  *
17
19
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportPhase | VideoExportPhase API reference}
18
20
  */
19
21
  export type VideoExportPhase = 'probing' | 'rendering' | 'capturing' | 'encoding' | 'draining' | 'writing' | 'finalizing';
20
22
  export type VideoCodec = 'vp8' | 'vp9' | 'avc' | (string & {});
21
23
  /**
22
- * Subjective bitrate preset used when an exact bits-per-second value is not supplied.
24
+ * Qualitative video quality level matching Mediabunny's five native levels.
23
25
  *
24
- * Higher presets request higher constant perceptual quality from Mediabunny. The `ultra` preset requests quantizer
25
- * zero with a frame-rate-aware bitrate fallback and should be described as near-lossless, never mathematically
26
- * lossless. For exact bitrate control, pass a numeric `bitrate` value in bits per second instead.
26
+ * Higher levels generally preserve more detail and produce larger, content-dependent files. Mediabunny may use
27
+ * quantizer-based encoding or a codec-adjusted bitrate, depending on codec and browser support.
27
28
  *
28
- * @category Animation export
29
+ * @category Video export
29
30
  *
30
- * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoBitratePreset | VideoBitratePreset API reference}
31
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoQualityLevel | VideoQualityLevel API reference}
31
32
  */
32
- export type VideoBitratePreset = 'low' | 'medium' | 'high' | 'ultra';
33
+ export type VideoQualityLevel = 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
33
34
  /**
34
- * Hint for the encoder's content-aware rate control.
35
+ * Video compression policy passed to Mediabunny.
35
36
  *
36
- * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoContentHint | VideoContentHint API reference}
37
+ * Use a named {@link VideoQualityLevel} for content-dependent qualitative encoding. Use the object form to request a
38
+ * positive target bitrate in bits per second and, optionally, constant or variable allocation. When `bitrateMode` is
39
+ * omitted, Mediabunny defaults bitrate-based encoding to `'variable'`. A target bitrate guides the encoder but does
40
+ * not guarantee an exact final file size.
41
+ *
42
+ * @example Named qualitative quality
43
+ * ```ts
44
+ * await t.saveVideo({ quality: 'very-high' });
45
+ * ```
46
+ *
47
+ * @example Target bitrate with constant allocation
48
+ * ```ts
49
+ * await t.saveVideo({ quality: { bitrate: 8_000_000, bitrateMode: 'constant' } });
50
+ * ```
51
+ *
52
+ * @category Video export
53
+ *
54
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoQuality | VideoQuality API reference}
37
55
  */
38
- export type VideoContentHint = '' | 'motion' | 'detail' | 'text';
56
+ export type VideoQuality = VideoQualityLevel | {
57
+ bitrate: number;
58
+ bitrateMode?: VideoBitrateMode;
59
+ };
39
60
  /**
40
- * Video container format written by `saveVideo`.
61
+ * Destination policy used by `saveVideo()`.
62
+ *
63
+ * - `'download'` is the default. The complete video is buffered in memory before a browser download begins.
64
+ * - `'file-system'` opens the browser's save picker and streams encoded chunks directly to the selected file. It
65
+ * requires the File System Access API and rejects with `VIDEO_EXPORT_UNSUPPORTED` when that API is unavailable.
66
+ *
67
+ * This setting does not affect `toVideoBlob()`, which always returns an in-memory `Blob`.
41
68
  *
42
- * @category Animation export
69
+ * @category Video export
70
+ *
71
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoSaveDestination | VideoSaveDestination API reference}
72
+ */
73
+ export type VideoSaveDestination = 'download' | 'file-system';
74
+ /**
75
+ * Video container format produced by `saveVideo()` and `toVideoBlob()`.
76
+ *
77
+ * MP4 uses AVC/H.264 and requires even coded dimensions. WebM selects VP9 when available and falls back to VP8; it
78
+ * is the only format that can be requested with transparency.
79
+ *
80
+ * @category Video export
43
81
  *
44
82
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportFormat | VideoExportFormat API reference}
45
83
  */
@@ -52,23 +90,13 @@ export type VideoExportFormat = 'webm' | 'mp4';
52
90
  * - `'constant'`: asks the encoder to keep the bitrate steadier throughout the export. This can make file size
53
91
  * more predictable, but may waste bits on simple frames or reduce detail on complex frames.
54
92
  *
55
- * @category Animation export
93
+ * If omitted for an explicit target bitrate, Mediabunny uses `'variable'`.
94
+ *
95
+ * @category Video export
56
96
  *
57
97
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoBitrateMode | VideoBitrateMode API reference}
58
98
  */
59
99
  export type VideoBitrateMode = 'variable' | 'constant';
60
- /**
61
- * Encoder scheduling mode.
62
- *
63
- * - `'quality'`: prioritizes complete, stable export output. Mediabunny notes that this mode prevents dropped frames.
64
- * - `'realtime'`: prioritizes low-latency encoding. It is intended for live streams and may drop frames when overloaded,
65
- * so it is usually not recommended for frame-perfect exports.
66
- *
67
- * @category Animation export
68
- *
69
- * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoLatencyMode | VideoLatencyMode API reference}
70
- */
71
- export type VideoLatencyMode = 'quality' | 'realtime';
72
100
  /**
73
101
  * WebCodecs hardware acceleration preference.
74
102
  *
@@ -78,34 +106,34 @@ export type VideoLatencyMode = 'quality' | 'realtime';
78
106
  * availability and output characteristics vary by device.
79
107
  * - `'prefer-software'`: prefer CPU encoding, often more consistent across machines, but usually slower.
80
108
  *
81
- * @category Animation export
109
+ * @category Video export
82
110
  *
83
111
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoHardwareAcceleration | VideoHardwareAcceleration API reference}
84
112
  */
85
113
  export type VideoHardwareAcceleration = 'no-preference' | 'prefer-hardware' | 'prefer-software';
86
- export type VideoExportErrorCode = 'VIDEO_EXPORT_UNSUPPORTED' | 'VIDEO_CODEC_UNSUPPORTED' | 'VIDEO_EXPORT_ABORTED' | 'VIDEO_EXPORT_TIMEOUT' | 'VIDEO_EXPORT_FAILED' | 'VIDEO_TRANSPARENCY_UNSUPPORTED' | 'VIDEO_DIMENSIONS_UNSUPPORTED' | 'VIDEO_OUTPUT_TOO_LARGE';
114
+ export type VideoExportErrorCode = 'VIDEO_EXPORT_UNSUPPORTED' | 'VIDEO_CODEC_UNSUPPORTED' | 'VIDEO_EXPORT_ABORTED' | 'VIDEO_EXPORT_TIMEOUT' | 'VIDEO_EXPORT_FAILED' | 'VIDEO_TRANSPARENCY_UNSUPPORTED' | 'VIDEO_DIMENSIONS_UNSUPPORTED';
87
115
  /**
88
- * Progress information emitted during the video export process.
116
+ * Progress information emitted while a deterministic video is probed, captured, and written.
89
117
  *
90
- * @category Animation export
118
+ * @category Video export
91
119
  *
92
120
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportProgress | VideoExportProgress API reference}
93
121
  */
94
122
  export type VideoExportProgress = {
95
123
  /**
96
- * Current state of the recording process.
124
+ * Current high-level export state.
97
125
  *
98
126
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportProgress#state | VideoExportProgress.state API reference}
99
127
  */
100
128
  state: VideoRecordingState;
101
129
  /**
102
- * Current export phase for newer progress UIs.
130
+ * Current detailed phase. See {@link VideoExportPhase} for current and compatibility-only values.
103
131
  *
104
132
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportProgress#phase | VideoExportProgress.phase API reference}
105
133
  */
106
134
  phase?: VideoExportPhase;
107
135
  /**
108
- * Number of frames that have been recorded so far.
136
+ * Number of frames captured so far.
109
137
  *
110
138
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportProgress#frameindex | VideoExportProgress.frameIndex API reference}
111
139
  */
@@ -123,7 +151,9 @@ export type VideoExportProgress = {
123
151
  */
124
152
  totalFrames?: number;
125
153
  /**
126
- * Export completion ratio between `0` and `1`.
154
+ * Normalized frame-capture completion ratio between `0` and `1`.
155
+ *
156
+ * Final writing or muxing may still be in progress when this value reaches `1`.
127
157
  *
128
158
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportProgress#progress | VideoExportProgress.progress API reference}
129
159
  */
@@ -135,22 +165,34 @@ export type VideoExportProgress = {
135
165
  */
136
166
  message?: string;
137
167
  /**
138
- * The rate-control path selected by the browser, when known.
168
+ * Effective codec family selected after capability probing (`avc`, `vp9`, or `vp8`).
169
+ *
170
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportProgress#codec | VideoExportProgress.codec API reference}
171
+ */
172
+ codec?: VideoCodec;
173
+ /**
174
+ * Effective coded width in pixels.
175
+ *
176
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportProgress#codedwidth | VideoExportProgress.codedWidth API reference}
177
+ */
178
+ codedWidth?: number;
179
+ /**
180
+ * Effective coded height in pixels.
139
181
  *
140
- * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportProgress#ratecontrol | VideoExportProgress.rateControl API reference}
182
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportProgress#codedheight | VideoExportProgress.codedHeight API reference}
141
183
  */
142
- rateControl?: 'quantizer' | 'bitrate-fallback' | 'bitrate';
184
+ codedHeight?: number;
143
185
  /**
144
- * Conservative output-size estimate in bytes, when available.
186
+ * Exact output frame rate passed to the muxer.
145
187
  *
146
- * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportProgress#estimatedbytes | VideoExportProgress.estimatedBytes API reference}
188
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportProgress#framerate | VideoExportProgress.frameRate API reference}
147
189
  */
148
- estimatedBytes?: number;
190
+ frameRate?: number;
149
191
  };
150
192
  /**
151
- * Options for exporting the textmode content to video format.
193
+ * Options for capturing deterministic textmode frames as MP4 or WebM video.
152
194
  *
153
- * @category Animation export
195
+ * @category Video export
154
196
  *
155
197
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportOptions | VideoExportOptions API reference}
156
198
  */
@@ -180,39 +222,23 @@ export type VideoExportOptions = {
180
222
  */
181
223
  frameRate?: number;
182
224
  /**
183
- * Target bitrate in bits per second or a quality preset. Defaults to `'medium'`.
225
+ * Video quality policy. Defaults to `'medium'`.
184
226
  *
185
- * String values request constant-quality encoding through Mediabunny. `low`, `medium`, and `high` map to the
186
- * upstream `medium`, `high`, and `very-high` quality levels; `ultra` requests quantizer zero and may create very
187
- * large files. Numeric values remain exact bits-per-second targets and are wrapped in Mediabunny `Quality`.
227
+ * Named levels map one-to-one to Mediabunny's qualitative levels and produce content-dependent file sizes. Use the
228
+ * object form to request a positive target bitrate in bits per second and an optional bitrate mode.
188
229
  *
189
- * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportOptions#bitrate | VideoExportOptions.bitrate API reference}
230
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportOptions#quality | VideoExportOptions.quality API reference}
190
231
  */
191
- bitrate?: number | VideoBitratePreset;
232
+ quality?: VideoQuality;
192
233
  /**
193
- * Bitrate allocation mode for numeric bitrates and quality fallback paths. Defaults to `'variable'`.
194
- *
195
- * Use `'variable'` for most exports so simple frames can compress efficiently and complex frames can receive more
196
- * bits. Use `'constant'` only when a steadier data rate is more important than compression efficiency.
234
+ * Save destination used by `saveVideo()`. Defaults to `'download'`.
197
235
  *
198
- * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportOptions#bitratemode | VideoExportOptions.bitrateMode API reference}
199
- */
200
- bitrateMode?: VideoBitrateMode;
201
- /**
202
- * Content hint passed to the native video encoder. Defaults to `'text'`.
236
+ * `'file-system'` opens a save picker and streams directly to the selected file when the File System Access API is
237
+ * available. `toVideoBlob()` always returns an in-memory blob and does not use this setting.
203
238
  *
204
- * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportOptions#contenthint | VideoExportOptions.contentHint API reference}
239
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportOptions#destination | VideoExportOptions.destination API reference}
205
240
  */
206
- contentHint?: VideoContentHint;
207
- /**
208
- * Encoder latency mode. Defaults to `'quality'`.
209
- *
210
- * Use `'quality'` for deterministic exports; it prioritizes completed output and avoids dropped frames. Use
211
- * `'realtime'` only for low-latency use cases where dropped frames are acceptable.
212
- *
213
- * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportOptions#latencymode | VideoExportOptions.latencyMode API reference}
214
- */
215
- latencyMode?: VideoLatencyMode;
241
+ destination?: VideoSaveDestination;
216
242
  /**
217
243
  * WebCodecs hardware acceleration hint. Defaults to `'no-preference'`.
218
244
  *
@@ -251,7 +277,7 @@ export type VideoExportOptions = {
251
277
  */
252
278
  prepareFrame?: PrepareExportFrame;
253
279
  /**
254
- * When true, attempts to preserve alpha data in WebM recordings. MP4 exports reject this option.
280
+ * When `true`, attempts to preserve alpha data in WebM recordings. MP4 exports reject this option.
255
281
  *
256
282
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportOptions#transparent | VideoExportOptions.transparent API reference}
257
283
  */
@@ -268,22 +294,13 @@ export type VideoExportOptions = {
268
294
  * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportOptions#debuglogging | VideoExportOptions.debugLogging API reference}
269
295
  */
270
296
  debugLogging?: boolean;
271
- /**
272
- * Allows `toVideoBlob()` to retain its in-memory contract above the safe 100 MB default.
273
- *
274
- * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/VideoExportOptions#allowlargeinmemory | VideoExportOptions.allowLargeInMemory API reference}
275
- */
276
- allowLargeInMemory?: boolean;
277
297
  };
278
298
  export interface VideoGenerationOptions {
279
299
  filename?: string;
280
300
  format: VideoExportFormat;
281
301
  frameRate: number;
282
302
  frameCount: number;
283
- bitrate: number | VideoBitratePreset;
284
- bitrateMode: VideoBitrateMode;
285
- contentHint?: VideoContentHint;
286
- latencyMode: VideoLatencyMode;
303
+ quality: VideoQuality;
287
304
  hardwareAcceleration: VideoHardwareAcceleration;
288
305
  keyFrameInterval: number;
289
306
  pixelDensity: number;
@@ -291,7 +308,6 @@ export interface VideoGenerationOptions {
291
308
  height: number;
292
309
  transparent: boolean;
293
310
  debugLogging: boolean;
294
- allowLargeInMemory?: boolean;
295
311
  signal?: AbortSignal;
296
312
  prepareFrame?: PrepareExportFrame;
297
313
  }
@@ -300,14 +316,7 @@ export interface VideoEncodingPlan {
300
316
  extension: '.webm' | '.mp4';
301
317
  mimeType: string;
302
318
  codec: VideoCodec;
303
- bitrate: number;
304
- bitrateMode: VideoBitrateMode;
305
- qualityPreset: VideoBitratePreset | null;
306
- rateControlIntent: 'bitrate' | 'constant-quality' | 'ultra';
307
- qualityLevel?: 'medium' | 'high' | 'very-high';
308
- contentHint: VideoContentHint;
309
- estimatedBytes: number;
310
- latencyMode: VideoLatencyMode;
319
+ quality: VideoQuality;
311
320
  hardwareAcceleration: VideoHardwareAcceleration;
312
321
  keyFrameInterval: number;
313
322
  frameRate: number;
@@ -316,17 +325,5 @@ export interface VideoEncodingPlan {
316
325
  height: number;
317
326
  transparent: boolean;
318
327
  }
319
- export interface VideoRenderFrameOptions {
320
- frameCount: number;
321
- frameRate: number;
322
- signal?: AbortSignal;
323
- prepareFrame?: PrepareExportFrame;
324
- onFrame(frame: {
325
- frameIndex: number;
326
- canvas: HTMLCanvasElement;
327
- }): Promise<void> | void;
328
- }
329
- export interface VideoFrameDriverLike {
330
- readonly canvas: HTMLCanvasElement;
331
- $render(options: VideoRenderFrameOptions): Promise<void>;
332
- }
328
+ export type VideoRenderFrameOptions = FrameSequenceRenderOptions;
329
+ export type VideoFrameDriverLike = FrameSequenceDriverLike;
@@ -0,0 +1,4 @@
1
+ import type { Textmodifier } from 'textmode.js';
2
+ import type { ZIPFrameFormat, ZIPFrameSerializer } from './types';
3
+ /** Resolves the thin adapter for one supported ZIP frame format. */
4
+ export declare function createZIPFrameSerializerRegistry(textmodifier: Textmodifier): Record<ZIPFrameFormat, ZIPFrameSerializer>;
@@ -0,0 +1,21 @@
1
+ import type { ZIPEntryCompression } from './types';
2
+ /** Streaming ZIP wrapper that retains only compressed archive output chunks. */
3
+ export declare class ZIPArchiveWriter {
4
+ private readonly _archive;
5
+ private readonly _chunks;
6
+ private readonly _entryNames;
7
+ private readonly _modifiedAt;
8
+ private readonly _maxArchiveBytes;
9
+ private _state;
10
+ private _archiveBytes;
11
+ private _failure;
12
+ private _resolveFinal?;
13
+ private _rejectFinal?;
14
+ constructor(modifiedAt: Date, maxArchiveBytes?: number);
15
+ $addEntry(path: string, data: Uint8Array, compression: ZIPEntryCompression): Promise<void>;
16
+ $finalize(): Promise<Blob>;
17
+ $abort(reason?: unknown): void;
18
+ private _assertOpen;
19
+ private _validateEntryPath;
20
+ private _fail;
21
+ }
@@ -0,0 +1,32 @@
1
+ import type { Textmodifier } from 'textmode.js';
2
+ import { type FrameSequenceDriverLike, type PostDrawSubscription } from '../base';
3
+ import type { ZIPExportOptions, ZIPFrameFormat, ZIPFrameSerializer } from './types';
4
+ interface ZIPExporterDependencies {
5
+ createDriver?: () => FrameSequenceDriverLike;
6
+ createWriter?: (createdAt: Date) => ZIPArchiveWriterLike;
7
+ resolveSerializer?: (format: ZIPFrameFormat) => ZIPFrameSerializer;
8
+ now?: () => Date;
9
+ }
10
+ interface ZIPArchiveWriterLike {
11
+ $addEntry(path: string, data: Uint8Array, compression: 'store' | 'deflate'): Promise<void>;
12
+ $finalize(): Promise<Blob>;
13
+ $abort(reason?: unknown): void;
14
+ }
15
+ /** Captures deterministic frames and archives them in capture order. */
16
+ export declare class ZIPExporter {
17
+ private readonly _textmodifier;
18
+ private readonly _registerPostDrawHook;
19
+ private readonly _dependencies;
20
+ constructor(_textmodifier: Textmodifier, _registerPostDrawHook: PostDrawSubscription, dependencies?: ZIPExporterDependencies);
21
+ $saveZIP(options: ZIPExportOptions): Promise<void>;
22
+ /** Generates a deterministic ZIP archive without initiating a download. */
23
+ $generateZIPBlob(options: ZIPExportOptions): Promise<Blob>;
24
+ private _export;
25
+ private _executeExport;
26
+ private _validateAndNormalize;
27
+ private _emitProgress;
28
+ private _progressFrameCount;
29
+ private _throwIfAborted;
30
+ private _yieldToBrowser;
31
+ }
32
+ export {};
@@ -0,0 +1,12 @@
1
+ import type { ZIPFrameFormat, ZIPFrameSequenceManifest } from './types';
2
+ export declare function createZIPFramePath(rootStem: string, frameIndex: number, extension: string): string;
3
+ export declare function createZIPManifest(options: {
4
+ createdAt: Date;
5
+ format: ZIPFrameFormat;
6
+ frameCount: number;
7
+ frameRate: number;
8
+ width: number;
9
+ height: number;
10
+ extension: string;
11
+ }): ZIPFrameSequenceManifest;
12
+ export declare function encodeZIPManifest(manifest: ZIPFrameSequenceManifest): Uint8Array;
@@ -0,0 +1,14 @@
1
+ import type { ZIPExportErrorCode } from './types';
2
+ /**
3
+ * Error raised by ZIP frame-sequence validation, capture, or archive creation.
4
+ *
5
+ * @category ZIP frame-sequence export
6
+ * @see {@link https://code.textmode.art/api/textmode.export.js/classes/ZIPExportError | ZIPExportError API reference}
7
+ */
8
+ export declare class ZIPExportError extends Error {
9
+ readonly code: ZIPExportErrorCode;
10
+ readonly cause?: unknown;
11
+ constructor(code: ZIPExportErrorCode, message: string, cause?: unknown);
12
+ }
13
+ export declare function createZIPAbortError(cause?: unknown): ZIPExportError;
14
+ export declare function normalizeZIPExportError(error: unknown): ZIPExportError;
@@ -0,0 +1,3 @@
1
+ export { ZIPExporter } from './ZIPExporter';
2
+ export { ZIPExportError } from './errors';
3
+ export type { ZIPCaptureOptions, ZIPExportErrorCode, ZIPExportOptions, ZIPExportProgress, ZIPExportState, ZIPFrameFormat, ZIPFrameOptionsMap, } from './types';
@@ -0,0 +1,177 @@
1
+ import type { PrepareExportFrame } from '../base';
2
+ import type { ImageExportOptions } from '../image';
3
+ import type { JSONExportOptions } from '../json';
4
+ import type { SVGExportOptions } from '../svg';
5
+ import type { TXTExportOptions } from '../txt';
6
+ /**
7
+ * File format used for every frame in a ZIP frame-sequence export.
8
+ *
9
+ * @category ZIP frame-sequence export
10
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/ZIPFrameFormat | ZIPFrameFormat API reference}
11
+ */
12
+ export type ZIPFrameFormat = 'png' | 'jpg' | 'webp' | 'svg' | 'json' | 'txt';
13
+ /**
14
+ * Lifecycle state reported by a ZIP frame-sequence export.
15
+ *
16
+ * @category ZIP frame-sequence export
17
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/ZIPExportState | ZIPExportState API reference}
18
+ */
19
+ export type ZIPExportState = 'capturing' | 'finalizing' | 'completed' | 'error';
20
+ /**
21
+ * Machine-readable ZIP export failure category.
22
+ *
23
+ * @category ZIP frame-sequence export
24
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/ZIPExportErrorCode | ZIPExportErrorCode API reference}
25
+ */
26
+ export type ZIPExportErrorCode = 'ZIP_EXPORT_INVALID_OPTIONS' | 'ZIP_EXPORT_ENCODING_UNSUPPORTED' | 'ZIP_EXPORT_TOO_LARGE' | 'ZIP_EXPORT_ABORTED' | 'ZIP_EXPORT_TIMEOUT' | 'ZIP_EXPORT_BUSY' | 'ZIP_EXPORT_DISPOSED' | 'ZIP_EXPORT_FAILED';
27
+ /**
28
+ * Progress information emitted while ZIP frames are captured and archived.
29
+ *
30
+ * @category ZIP frame-sequence export
31
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPExportProgress | ZIPExportProgress API reference}
32
+ */
33
+ export interface ZIPExportProgress {
34
+ /**
35
+ * Current ZIP export state.
36
+ *
37
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPExportProgress#state | ZIPExportProgress.state API reference}
38
+ */
39
+ state: ZIPExportState;
40
+ /**
41
+ * Number of completed frame entries.
42
+ *
43
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPExportProgress#frameindex | ZIPExportProgress.frameIndex API reference}
44
+ */
45
+ frameIndex: number;
46
+ /**
47
+ * Total number of frame entries planned for the archive.
48
+ *
49
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPExportProgress#totalframes | ZIPExportProgress.totalFrames API reference}
50
+ */
51
+ totalFrames: number;
52
+ /**
53
+ * Normalized completed-frame ratio from `0` through `1`.
54
+ *
55
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPExportProgress#progress | ZIPExportProgress.progress API reference}
56
+ */
57
+ progress: number;
58
+ /**
59
+ * Optional failure message for an `error` event.
60
+ *
61
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPExportProgress#message | ZIPExportProgress.message API reference}
62
+ */
63
+ message?: string;
64
+ }
65
+ /**
66
+ * Options shared by all ZIP frame formats.
67
+ *
68
+ * @category ZIP frame-sequence export
69
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPCaptureOptions | ZIPCaptureOptions API reference}
70
+ */
71
+ export interface ZIPCaptureOptions {
72
+ /**
73
+ * Target archive filename, with or without `.zip`.
74
+ *
75
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPCaptureOptions#filename | ZIPCaptureOptions.filename API reference}
76
+ */
77
+ filename?: string;
78
+ /**
79
+ * Number of frames to capture. Defaults to `300`.
80
+ *
81
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPCaptureOptions#framecount | ZIPCaptureOptions.frameCount API reference}
82
+ */
83
+ frameCount?: number;
84
+ /**
85
+ * Deterministic sampling rate. Defaults to `60`.
86
+ *
87
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPCaptureOptions#framerate | ZIPCaptureOptions.frameRate API reference}
88
+ */
89
+ frameRate?: number;
90
+ /**
91
+ * Prepares external state before each deterministic redraw.
92
+ *
93
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPCaptureOptions#prepareframe | ZIPCaptureOptions.prepareFrame API reference}
94
+ */
95
+ prepareFrame?: PrepareExportFrame;
96
+ /**
97
+ * Cancels capture, serialization, or archive finalization.
98
+ *
99
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPCaptureOptions#signal | ZIPCaptureOptions.signal API reference}
100
+ */
101
+ signal?: AbortSignal;
102
+ /**
103
+ * Receives capture and archive lifecycle updates.
104
+ *
105
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPCaptureOptions#onprogress | ZIPCaptureOptions.onProgress API reference}
106
+ */
107
+ onProgress?: (progress: ZIPExportProgress) => void;
108
+ }
109
+ /**
110
+ * Format-specific options forwarded to each existing still exporter.
111
+ *
112
+ * @category ZIP frame-sequence export
113
+ * @see {@link https://code.textmode.art/api/textmode.export.js/interfaces/ZIPFrameOptionsMap | ZIPFrameOptionsMap API reference}
114
+ */
115
+ export interface ZIPFrameOptionsMap {
116
+ png: Omit<ImageExportOptions, 'filename' | 'format'>;
117
+ jpg: Omit<ImageExportOptions, 'filename' | 'format'>;
118
+ webp: Omit<ImageExportOptions, 'filename' | 'format'>;
119
+ svg: Omit<SVGExportOptions, 'filename'>;
120
+ json: Omit<JSONExportOptions, 'filename'>;
121
+ txt: Omit<TXTExportOptions, 'filename'>;
122
+ }
123
+ /**
124
+ * Discriminated options for a deterministic ZIP frame-sequence export.
125
+ *
126
+ * @category ZIP frame-sequence export
127
+ * @see {@link https://code.textmode.art/api/textmode.export.js/type-aliases/ZIPExportOptions | ZIPExportOptions API reference}
128
+ */
129
+ export type ZIPExportOptions = {
130
+ [F in ZIPFrameFormat]: ZIPCaptureOptions & {
131
+ format: F;
132
+ frameOptions?: ZIPFrameOptionsMap[F];
133
+ };
134
+ }[ZIPFrameFormat];
135
+ export interface ZIPGenerationOptions {
136
+ format: ZIPFrameFormat;
137
+ filename?: string;
138
+ frameCount: number;
139
+ frameRate: number;
140
+ frameOptions: unknown;
141
+ prepareFrame?: PrepareExportFrame;
142
+ signal?: AbortSignal;
143
+ onProgress?: (progress: ZIPExportProgress) => void;
144
+ }
145
+ export type ZIPEntryCompression = 'store' | 'deflate';
146
+ export interface ZIPFrameSerializer {
147
+ readonly extension: `.${ZIPFrameFormat}`;
148
+ readonly compression: ZIPEntryCompression;
149
+ getDimensions(context: {
150
+ canvas: HTMLCanvasElement;
151
+ frameOptions: unknown;
152
+ }): {
153
+ width: number;
154
+ height: number;
155
+ };
156
+ serialize(context: {
157
+ canvas: HTMLCanvasElement;
158
+ frameOptions: unknown;
159
+ createdAt: Date;
160
+ }): Promise<Uint8Array>;
161
+ }
162
+ export interface ZIPFrameSequenceManifest {
163
+ schema: 'textmode.frame-sequence';
164
+ schemaVersion: '1.0.0';
165
+ generator: {
166
+ name: 'textmode.export.js';
167
+ version: string;
168
+ };
169
+ createdAt: string;
170
+ format: ZIPFrameFormat;
171
+ frameCount: number;
172
+ frameRate: number;
173
+ width: number;
174
+ height: number;
175
+ indexBase: 1;
176
+ filePattern: string;
177
+ }