@clipkit/runtime 1.0.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 +54 -0
- package/README.md +98 -0
- package/dist/animation/easings.d.ts +9 -0
- package/dist/animation/easings.d.ts.map +1 -0
- package/dist/animation/easings.js +230 -0
- package/dist/animation/easings.js.map +1 -0
- package/dist/animation/expr.d.ts +44 -0
- package/dist/animation/expr.d.ts.map +1 -0
- package/dist/animation/expr.js +236 -0
- package/dist/animation/expr.js.map +1 -0
- package/dist/animation/keyframes.d.ts +23 -0
- package/dist/animation/keyframes.d.ts.map +1 -0
- package/dist/animation/keyframes.js +117 -0
- package/dist/animation/keyframes.js.map +1 -0
- package/dist/animation/motion-path.d.ts +18 -0
- package/dist/animation/motion-path.d.ts.map +1 -0
- package/dist/animation/motion-path.js +269 -0
- package/dist/animation/motion-path.js.map +1 -0
- package/dist/animation/noise1d.d.ts +5 -0
- package/dist/animation/noise1d.d.ts.map +1 -0
- package/dist/animation/noise1d.js +27 -0
- package/dist/animation/noise1d.js.map +1 -0
- package/dist/animation/presets.d.ts +60 -0
- package/dist/animation/presets.d.ts.map +1 -0
- package/dist/animation/presets.js +221 -0
- package/dist/animation/presets.js.map +1 -0
- package/dist/assets/cache.d.ts +18 -0
- package/dist/assets/cache.d.ts.map +1 -0
- package/dist/assets/cache.js +56 -0
- package/dist/assets/cache.js.map +1 -0
- package/dist/assets/fonts.d.ts +20 -0
- package/dist/assets/fonts.d.ts.map +1 -0
- package/dist/assets/fonts.js +127 -0
- package/dist/assets/fonts.js.map +1 -0
- package/dist/assets/loader.d.ts +18 -0
- package/dist/assets/loader.d.ts.map +1 -0
- package/dist/assets/loader.js +87 -0
- package/dist/assets/loader.js.map +1 -0
- package/dist/assets/lut.d.ts +5 -0
- package/dist/assets/lut.d.ts.map +1 -0
- package/dist/assets/lut.js +77 -0
- package/dist/assets/lut.js.map +1 -0
- package/dist/assets/media-time.d.ts +31 -0
- package/dist/assets/media-time.d.ts.map +1 -0
- package/dist/assets/media-time.js +65 -0
- package/dist/assets/media-time.js.map +1 -0
- package/dist/assets/mp4-frame-source.d.ts +44 -0
- package/dist/assets/mp4-frame-source.d.ts.map +1 -0
- package/dist/assets/mp4-frame-source.js +387 -0
- package/dist/assets/mp4-frame-source.js.map +1 -0
- package/dist/audio/encoder.d.ts +31 -0
- package/dist/audio/encoder.d.ts.map +1 -0
- package/dist/audio/encoder.js +96 -0
- package/dist/audio/encoder.js.map +1 -0
- package/dist/audio/fades.d.ts +16 -0
- package/dist/audio/fades.d.ts.map +1 -0
- package/dist/audio/fades.js +43 -0
- package/dist/audio/fades.js.map +1 -0
- package/dist/audio/limiter.d.ts +8 -0
- package/dist/audio/limiter.d.ts.map +1 -0
- package/dist/audio/limiter.js +39 -0
- package/dist/audio/limiter.js.map +1 -0
- package/dist/audio/loader.d.ts +6 -0
- package/dist/audio/loader.d.ts.map +1 -0
- package/dist/audio/loader.js +42 -0
- package/dist/audio/loader.js.map +1 -0
- package/dist/audio/mixer.d.ts +17 -0
- package/dist/audio/mixer.d.ts.map +1 -0
- package/dist/audio/mixer.js +204 -0
- package/dist/audio/mixer.js.map +1 -0
- package/dist/audio/varispeed.d.ts +24 -0
- package/dist/audio/varispeed.d.ts.map +1 -0
- package/dist/audio/varispeed.js +114 -0
- package/dist/audio/varispeed.js.map +1 -0
- package/dist/audio/wav.d.ts +6 -0
- package/dist/audio/wav.d.ts.map +1 -0
- package/dist/audio/wav.js +62 -0
- package/dist/audio/wav.js.map +1 -0
- package/dist/backend/backend.d.ts +579 -0
- package/dist/backend/backend.d.ts.map +1 -0
- package/dist/backend/backend.js +17 -0
- package/dist/backend/backend.js.map +1 -0
- package/dist/backend/webgl-backend.d.ts +97 -0
- package/dist/backend/webgl-backend.d.ts.map +1 -0
- package/dist/backend/webgl-backend.js +2142 -0
- package/dist/backend/webgl-backend.js.map +1 -0
- package/dist/backend/webgpu-backend.d.ts +121 -0
- package/dist/backend/webgpu-backend.d.ts.map +1 -0
- package/dist/backend/webgpu-backend.js +2481 -0
- package/dist/backend/webgpu-backend.js.map +1 -0
- package/dist/compositor/bitfont.d.ts +8 -0
- package/dist/compositor/bitfont.d.ts.map +1 -0
- package/dist/compositor/bitfont.js +52 -0
- package/dist/compositor/bitfont.js.map +1 -0
- package/dist/compositor/camera.d.ts +5 -0
- package/dist/compositor/camera.d.ts.map +1 -0
- package/dist/compositor/camera.js +114 -0
- package/dist/compositor/camera.js.map +1 -0
- package/dist/compositor/color.d.ts +26 -0
- package/dist/compositor/color.d.ts.map +1 -0
- package/dist/compositor/color.js +189 -0
- package/dist/compositor/color.js.map +1 -0
- package/dist/compositor/element-renderers/caption.d.ts +4 -0
- package/dist/compositor/element-renderers/caption.d.ts.map +1 -0
- package/dist/compositor/element-renderers/caption.js +376 -0
- package/dist/compositor/element-renderers/caption.js.map +1 -0
- package/dist/compositor/element-renderers/group.d.ts +12 -0
- package/dist/compositor/element-renderers/group.d.ts.map +1 -0
- package/dist/compositor/element-renderers/group.js +259 -0
- package/dist/compositor/element-renderers/group.js.map +1 -0
- package/dist/compositor/element-renderers/image.d.ts +4 -0
- package/dist/compositor/element-renderers/image.d.ts.map +1 -0
- package/dist/compositor/element-renderers/image.js +97 -0
- package/dist/compositor/element-renderers/image.js.map +1 -0
- package/dist/compositor/element-renderers/lit.d.ts +6 -0
- package/dist/compositor/element-renderers/lit.d.ts.map +1 -0
- package/dist/compositor/element-renderers/lit.js +82 -0
- package/dist/compositor/element-renderers/lit.js.map +1 -0
- package/dist/compositor/element-renderers/particles.d.ts +4 -0
- package/dist/compositor/element-renderers/particles.d.ts.map +1 -0
- package/dist/compositor/element-renderers/particles.js +212 -0
- package/dist/compositor/element-renderers/particles.js.map +1 -0
- package/dist/compositor/element-renderers/shape.d.ts +4 -0
- package/dist/compositor/element-renderers/shape.d.ts.map +1 -0
- package/dist/compositor/element-renderers/shape.js +171 -0
- package/dist/compositor/element-renderers/shape.js.map +1 -0
- package/dist/compositor/element-renderers/svg.d.ts +4 -0
- package/dist/compositor/element-renderers/svg.d.ts.map +1 -0
- package/dist/compositor/element-renderers/svg.js +210 -0
- package/dist/compositor/element-renderers/svg.js.map +1 -0
- package/dist/compositor/element-renderers/text.d.ts +25 -0
- package/dist/compositor/element-renderers/text.d.ts.map +1 -0
- package/dist/compositor/element-renderers/text.js +1358 -0
- package/dist/compositor/element-renderers/text.js.map +1 -0
- package/dist/compositor/element-renderers/video.d.ts +12 -0
- package/dist/compositor/element-renderers/video.d.ts.map +1 -0
- package/dist/compositor/element-renderers/video.js +109 -0
- package/dist/compositor/element-renderers/video.js.map +1 -0
- package/dist/compositor/fit.d.ts +18 -0
- package/dist/compositor/fit.d.ts.map +1 -0
- package/dist/compositor/fit.js +106 -0
- package/dist/compositor/fit.js.map +1 -0
- package/dist/compositor/lighting.d.ts +63 -0
- package/dist/compositor/lighting.d.ts.map +1 -0
- package/dist/compositor/lighting.js +141 -0
- package/dist/compositor/lighting.js.map +1 -0
- package/dist/compositor/mat4.d.ts +88 -0
- package/dist/compositor/mat4.d.ts.map +1 -0
- package/dist/compositor/mat4.js +245 -0
- package/dist/compositor/mat4.js.map +1 -0
- package/dist/compositor/project.d.ts +24 -0
- package/dist/compositor/project.d.ts.map +1 -0
- package/dist/compositor/project.js +105 -0
- package/dist/compositor/project.js.map +1 -0
- package/dist/compositor/render-context.d.ts +194 -0
- package/dist/compositor/render-context.d.ts.map +1 -0
- package/dist/compositor/render-context.js +10 -0
- package/dist/compositor/render-context.js.map +1 -0
- package/dist/compositor/resolve.d.ts +80 -0
- package/dist/compositor/resolve.d.ts.map +1 -0
- package/dist/compositor/resolve.js +276 -0
- package/dist/compositor/resolve.js.map +1 -0
- package/dist/compositor/scene.d.ts +10 -0
- package/dist/compositor/scene.d.ts.map +1 -0
- package/dist/compositor/scene.js +658 -0
- package/dist/compositor/scene.js.map +1 -0
- package/dist/compositor/transform.d.ts +73 -0
- package/dist/compositor/transform.d.ts.map +1 -0
- package/dist/compositor/transform.js +229 -0
- package/dist/compositor/transform.js.map +1 -0
- package/dist/compositor/unit.d.ts +27 -0
- package/dist/compositor/unit.d.ts.map +1 -0
- package/dist/compositor/unit.js +74 -0
- package/dist/compositor/unit.js.map +1 -0
- package/dist/encoder/exporter.d.ts +95 -0
- package/dist/encoder/exporter.d.ts.map +1 -0
- package/dist/encoder/exporter.js +341 -0
- package/dist/encoder/exporter.js.map +1 -0
- package/dist/encoder/index.d.ts +3 -0
- package/dist/encoder/index.d.ts.map +1 -0
- package/dist/encoder/index.js +2 -0
- package/dist/encoder/index.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +32 -0
- package/dist/logger.js.map +1 -0
- package/dist/runtime.d.ts +216 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1012 -0
- package/dist/runtime.js.map +1 -0
- package/dist/svg/morph.d.ts +6 -0
- package/dist/svg/morph.d.ts.map +1 -0
- package/dist/svg/morph.js +62 -0
- package/dist/svg/morph.js.map +1 -0
- package/dist/svg/svg-renderer.d.ts +18 -0
- package/dist/svg/svg-renderer.d.ts.map +1 -0
- package/dist/svg/svg-renderer.js +142 -0
- package/dist/svg/svg-renderer.js.map +1 -0
- package/dist/text/caption-chunk.d.ts +17 -0
- package/dist/text/caption-chunk.d.ts.map +1 -0
- package/dist/text/caption-chunk.js +76 -0
- package/dist/text/caption-chunk.js.map +1 -0
- package/dist/text/font-atlas.d.ts +63 -0
- package/dist/text/font-atlas.d.ts.map +1 -0
- package/dist/text/font-atlas.js +225 -0
- package/dist/text/font-atlas.js.map +1 -0
- package/dist/text/measure.d.ts +38 -0
- package/dist/text/measure.d.ts.map +1 -0
- package/dist/text/measure.js +164 -0
- package/dist/text/measure.js.map +1 -0
- package/dist/text/text-animation.d.ts +52 -0
- package/dist/text/text-animation.d.ts.map +1 -0
- package/dist/text/text-animation.js +133 -0
- package/dist/text/text-animation.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare class AssetCache<T> {
|
|
2
|
+
private store;
|
|
3
|
+
private inFlight;
|
|
4
|
+
/**
|
|
5
|
+
* Get an asset, loading it if not cached. Concurrent calls for the same
|
|
6
|
+
* key share a single in-flight Promise.
|
|
7
|
+
*/
|
|
8
|
+
getOrLoad(key: string, load: () => Promise<T>): Promise<T>;
|
|
9
|
+
has(key: string): boolean;
|
|
10
|
+
get(key: string): T | undefined;
|
|
11
|
+
/** Set a value synchronously (for assets that are generated, not loaded). */
|
|
12
|
+
set(key: string, value: T): void;
|
|
13
|
+
delete(key: string): T | undefined;
|
|
14
|
+
clear(): void;
|
|
15
|
+
get size(): number;
|
|
16
|
+
entries(): IterableIterator<[string, T]>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/assets/cache.ts"],"names":[],"mappings":"AAGA,qBAAa,UAAU,CAAC,CAAC;IACvB,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,QAAQ,CAAiC;IAEjD;;;OAGG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAoBhE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAI/B,6EAA6E;IAC7E,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAIhC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAMlC,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;CAGzC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Keyed asset cache. Simple wrapper around a Map so consumers don't have
|
|
2
|
+
// to deal with the get-or-load pattern themselves.
|
|
3
|
+
export class AssetCache {
|
|
4
|
+
store = new Map();
|
|
5
|
+
inFlight = new Map();
|
|
6
|
+
/**
|
|
7
|
+
* Get an asset, loading it if not cached. Concurrent calls for the same
|
|
8
|
+
* key share a single in-flight Promise.
|
|
9
|
+
*/
|
|
10
|
+
async getOrLoad(key, load) {
|
|
11
|
+
const cached = this.store.get(key);
|
|
12
|
+
if (cached !== undefined)
|
|
13
|
+
return cached;
|
|
14
|
+
const pending = this.inFlight.get(key);
|
|
15
|
+
if (pending)
|
|
16
|
+
return pending;
|
|
17
|
+
const promise = load()
|
|
18
|
+
.then((value) => {
|
|
19
|
+
this.store.set(key, value);
|
|
20
|
+
this.inFlight.delete(key);
|
|
21
|
+
return value;
|
|
22
|
+
})
|
|
23
|
+
.catch((err) => {
|
|
24
|
+
this.inFlight.delete(key);
|
|
25
|
+
throw err;
|
|
26
|
+
});
|
|
27
|
+
this.inFlight.set(key, promise);
|
|
28
|
+
return promise;
|
|
29
|
+
}
|
|
30
|
+
has(key) {
|
|
31
|
+
return this.store.has(key);
|
|
32
|
+
}
|
|
33
|
+
get(key) {
|
|
34
|
+
return this.store.get(key);
|
|
35
|
+
}
|
|
36
|
+
/** Set a value synchronously (for assets that are generated, not loaded). */
|
|
37
|
+
set(key, value) {
|
|
38
|
+
this.store.set(key, value);
|
|
39
|
+
}
|
|
40
|
+
delete(key) {
|
|
41
|
+
const v = this.store.get(key);
|
|
42
|
+
this.store.delete(key);
|
|
43
|
+
return v;
|
|
44
|
+
}
|
|
45
|
+
clear() {
|
|
46
|
+
this.store.clear();
|
|
47
|
+
this.inFlight.clear();
|
|
48
|
+
}
|
|
49
|
+
get size() {
|
|
50
|
+
return this.store.size;
|
|
51
|
+
}
|
|
52
|
+
entries() {
|
|
53
|
+
return this.store.entries();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/assets/cache.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,mDAAmD;AAEnD,MAAM,OAAO,UAAU;IACb,KAAK,GAAG,IAAI,GAAG,EAAa,CAAC;IAC7B,QAAQ,GAAG,IAAI,GAAG,EAAsB,CAAC;IAEjD;;;OAGG;IACH,KAAK,CAAC,SAAS,CAAC,GAAW,EAAE,IAAsB;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAE5B,MAAM,OAAO,GAAG,IAAI,EAAE;aACnB,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;YACd,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC1B,OAAO,KAAK,CAAC;QACf,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACb,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC1B,MAAM,GAAG,CAAC;QACZ,CAAC,CAAC,CAAC;QACL,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAChC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,6EAA6E;IAC7E,GAAG,CAAC,GAAW,EAAE,KAAQ;QACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;IAC9B,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FontFace as ProtocolFontFace } from '@clipkit/protocol';
|
|
2
|
+
/**
|
|
3
|
+
* Ensure a font face is loaded so the canvas-text rasterizer can use it.
|
|
4
|
+
* Generic CSS families (sans-serif, monospace, etc.) skip the load — the
|
|
5
|
+
* browser always has them available.
|
|
6
|
+
*
|
|
7
|
+
* Quietly succeeds when the FontFace API is unavailable (non-browser
|
|
8
|
+
* environments). Logs a warning and resolves when the font fails to load
|
|
9
|
+
* — text will fall back to the browser's default font, visibly wrong
|
|
10
|
+
* but at least not blank.
|
|
11
|
+
*/
|
|
12
|
+
export declare function loadFont(family: string, weight?: string | number, style?: 'normal' | 'italic'): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Wait for ALL currently-pending fonts in the document to finish loading.
|
|
15
|
+
* Call this once after the page has declared its @font-face rules but
|
|
16
|
+
* before generating font atlases.
|
|
17
|
+
*/
|
|
18
|
+
export declare function fontsReady(): Promise<void>;
|
|
19
|
+
export declare function registerSourceFonts(fonts: ProtocolFontFace[]): Promise<void>;
|
|
20
|
+
//# sourceMappingURL=fonts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../../src/assets/fonts.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAgCtE;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAM,GAAG,MAAiB,EAClC,KAAK,GAAE,QAAQ,GAAG,QAAmB,GACpC,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED;;;;GAIG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAIhD;AAWD,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsClF"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Font loading. The previous runtime silently rendered with a fallback
|
|
2
|
+
// font when the requested family wasn't loaded, which caused empty-looking
|
|
3
|
+
// or wrong-looking text. We make font loading explicit here: callers
|
|
4
|
+
// request a font, and the promise resolves when the font is available
|
|
5
|
+
// (or rejects loudly if not).
|
|
6
|
+
import { getLogger } from '../logger.js';
|
|
7
|
+
/**
|
|
8
|
+
* Get the current global FontFaceSet — `document.fonts` on the main
|
|
9
|
+
* thread, `self.fonts` inside a (Dedicated/Shared) Worker. The playback
|
|
10
|
+
* pipeline runs ClipkitRuntime inside a worker via OffscreenCanvas, so
|
|
11
|
+
* skipping when only `document` is checked would silently disable
|
|
12
|
+
* font handling for live playback.
|
|
13
|
+
*/
|
|
14
|
+
function getFontFaceSet() {
|
|
15
|
+
if (typeof document !== 'undefined' && document.fonts)
|
|
16
|
+
return document.fonts;
|
|
17
|
+
if (typeof self !== 'undefined') {
|
|
18
|
+
const s = self;
|
|
19
|
+
if (s.fonts)
|
|
20
|
+
return s.fonts;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const KNOWN_GENERIC_FAMILIES = new Set([
|
|
25
|
+
'serif',
|
|
26
|
+
'sans-serif',
|
|
27
|
+
'monospace',
|
|
28
|
+
'cursive',
|
|
29
|
+
'fantasy',
|
|
30
|
+
'system-ui',
|
|
31
|
+
'ui-serif',
|
|
32
|
+
'ui-sans-serif',
|
|
33
|
+
'ui-monospace',
|
|
34
|
+
'ui-rounded',
|
|
35
|
+
]);
|
|
36
|
+
/**
|
|
37
|
+
* Ensure a font face is loaded so the canvas-text rasterizer can use it.
|
|
38
|
+
* Generic CSS families (sans-serif, monospace, etc.) skip the load — the
|
|
39
|
+
* browser always has them available.
|
|
40
|
+
*
|
|
41
|
+
* Quietly succeeds when the FontFace API is unavailable (non-browser
|
|
42
|
+
* environments). Logs a warning and resolves when the font fails to load
|
|
43
|
+
* — text will fall back to the browser's default font, visibly wrong
|
|
44
|
+
* but at least not blank.
|
|
45
|
+
*/
|
|
46
|
+
export async function loadFont(family, weight = 'normal', style = 'normal') {
|
|
47
|
+
const fontSet = getFontFaceSet();
|
|
48
|
+
if (!fontSet)
|
|
49
|
+
return;
|
|
50
|
+
// font_family is often a full CSS stack ("Geist, ui-sans-serif, sans-serif").
|
|
51
|
+
// Resolve the first CONCRETE family: quoting the whole stack as one name never
|
|
52
|
+
// matches (it only warns), and a leading generic means the browser already has
|
|
53
|
+
// it — nothing to load.
|
|
54
|
+
const target = family
|
|
55
|
+
.split(',')
|
|
56
|
+
.map((s) => s.trim().replace(/^["']|["']$/g, ''))
|
|
57
|
+
.find((f) => f && !KNOWN_GENERIC_FAMILIES.has(f.toLowerCase()));
|
|
58
|
+
if (!target)
|
|
59
|
+
return;
|
|
60
|
+
const spec = `${style} ${weight} 16px "${target}"`;
|
|
61
|
+
try {
|
|
62
|
+
const faces = await fontSet.load(spec);
|
|
63
|
+
if (faces.length === 0) {
|
|
64
|
+
getLogger().warn(`Font "${target}" (${weight} ${style}) was requested but no matching FontFace was found. ` +
|
|
65
|
+
`Declare it in the Source's fonts[] (family + src), or add the @font-face to the page. ` +
|
|
66
|
+
`Text will render with the browser default.`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
getLogger().warn(`Loading font "${target}" failed:`, err instanceof Error ? err.message : String(err));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Wait for ALL currently-pending fonts in the document to finish loading.
|
|
75
|
+
* Call this once after the page has declared its @font-face rules but
|
|
76
|
+
* before generating font atlases.
|
|
77
|
+
*/
|
|
78
|
+
export async function fontsReady() {
|
|
79
|
+
const fontSet = getFontFaceSet();
|
|
80
|
+
if (!fontSet)
|
|
81
|
+
return;
|
|
82
|
+
await fontSet.ready;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Register Source-declared @font-face entries into the host document so
|
|
86
|
+
* the canvas-text path renders with the exact font the snapshot saw.
|
|
87
|
+
*
|
|
88
|
+
* Idempotent per (family, weight, style, src) tuple: a face already added
|
|
89
|
+
* by an earlier preload() (or by the host page) is skipped — the
|
|
90
|
+
* FontFaceSet doesn't dedupe these for us.
|
|
91
|
+
*/
|
|
92
|
+
const registeredFontKeys = new Set();
|
|
93
|
+
export async function registerSourceFonts(fonts) {
|
|
94
|
+
const fontSet = getFontFaceSet();
|
|
95
|
+
if (!fontSet)
|
|
96
|
+
return;
|
|
97
|
+
if (typeof FontFace === 'undefined')
|
|
98
|
+
return;
|
|
99
|
+
const loads = [];
|
|
100
|
+
for (const f of fonts) {
|
|
101
|
+
const weight = f.weight === undefined ? 'normal' : String(f.weight);
|
|
102
|
+
const style = f.style ?? 'normal';
|
|
103
|
+
const key = `${f.family}|${weight}|${style}|${f.src}`;
|
|
104
|
+
if (registeredFontKeys.has(key))
|
|
105
|
+
continue;
|
|
106
|
+
registeredFontKeys.add(key);
|
|
107
|
+
try {
|
|
108
|
+
const face = new FontFace(f.family, `url(${f.src})`, {
|
|
109
|
+
weight,
|
|
110
|
+
style,
|
|
111
|
+
// Subsetted webfonts ship one file per script with identical
|
|
112
|
+
// family/weight/style; without the range every subset matches
|
|
113
|
+
// every codepoint and the winner may lack the needed glyphs.
|
|
114
|
+
...(f.unicode_range ? { unicodeRange: f.unicode_range } : {}),
|
|
115
|
+
});
|
|
116
|
+
fontSet.add(face);
|
|
117
|
+
loads.push(face.load().catch((err) => {
|
|
118
|
+
getLogger().warn(`Failed to load Source font "${f.family}" (${weight} ${style}) from ${f.src}:`, err instanceof Error ? err.message : String(err));
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
getLogger().warn(`Failed to register Source font "${f.family}" (${weight} ${style}):`, err instanceof Error ? err.message : String(err));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
await Promise.all(loads);
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=fonts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.js","sourceRoot":"","sources":["../../src/assets/fonts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load an image URL and decode it into an ImageBitmap. ImageBitmaps are
|
|
3
|
+
* preferred over HTMLImageElement here because they can be uploaded to
|
|
4
|
+
* GPU textures without re-decoding.
|
|
5
|
+
*/
|
|
6
|
+
export declare function loadImage(url: string): Promise<ImageBitmap>;
|
|
7
|
+
/**
|
|
8
|
+
* Load a video URL into an HTMLVideoElement. Resolves once the video has
|
|
9
|
+
* enough data to seek and sample frames (`loadeddata`). Caller can then
|
|
10
|
+
* `video.currentTime = t` and read frames.
|
|
11
|
+
*/
|
|
12
|
+
export declare function loadVideo(url: string): Promise<HTMLVideoElement>;
|
|
13
|
+
/**
|
|
14
|
+
* Seek a video to the given time and resolve once the new frame is ready
|
|
15
|
+
* to be sampled. Necessary for deterministic frame-by-frame export.
|
|
16
|
+
*/
|
|
17
|
+
export declare function seekVideo(video: HTMLVideoElement, time: number): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/assets/loader.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAwBjE;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA0BtE;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc9E"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// URL → asset loaders.
|
|
2
|
+
//
|
|
3
|
+
// All functions throw on failure; callers can wrap in try/catch or let the
|
|
4
|
+
// error propagate through the scene's preload step. The runtime's public
|
|
5
|
+
// API has a single preload() boundary; once that resolves, render() can
|
|
6
|
+
// be called synchronously without worrying about async loads.
|
|
7
|
+
/**
|
|
8
|
+
* Load an image URL and decode it into an ImageBitmap. ImageBitmaps are
|
|
9
|
+
* preferred over HTMLImageElement here because they can be uploaded to
|
|
10
|
+
* GPU textures without re-decoding.
|
|
11
|
+
*/
|
|
12
|
+
export async function loadImage(url) {
|
|
13
|
+
// 10s fetch timeout. Without this a single stalled CDN (hotlink-
|
|
14
|
+
// protected images on URL-snapshotted pages especially) hangs the
|
|
15
|
+
// entire Promise.all in runtime.preload() and the worker never
|
|
16
|
+
// resolves "ready".
|
|
17
|
+
const ac = new AbortController();
|
|
18
|
+
const timer = setTimeout(() => ac.abort(), 10000);
|
|
19
|
+
let response;
|
|
20
|
+
try {
|
|
21
|
+
response = await fetch(url, { mode: 'cors', signal: ac.signal });
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
clearTimeout(timer);
|
|
25
|
+
}
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
throw new Error(`Failed to fetch image ${url}: HTTP ${response.status}`);
|
|
28
|
+
}
|
|
29
|
+
const blob = await response.blob();
|
|
30
|
+
// imageOrientation: 'from-image' respects EXIF orientation; colorSpaceConversion: 'none'
|
|
31
|
+
// skips browser color-space tweaks that can shift colors slightly.
|
|
32
|
+
return createImageBitmap(blob, {
|
|
33
|
+
imageOrientation: 'from-image',
|
|
34
|
+
premultiplyAlpha: 'none', // we premultiply on the GPU during upload
|
|
35
|
+
colorSpaceConversion: 'none',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Load a video URL into an HTMLVideoElement. Resolves once the video has
|
|
40
|
+
* enough data to seek and sample frames (`loadeddata`). Caller can then
|
|
41
|
+
* `video.currentTime = t` and read frames.
|
|
42
|
+
*/
|
|
43
|
+
export async function loadVideo(url) {
|
|
44
|
+
const video = document.createElement('video');
|
|
45
|
+
video.crossOrigin = 'anonymous';
|
|
46
|
+
video.muted = true; // required for autoplay-on-seek in some browsers
|
|
47
|
+
video.playsInline = true;
|
|
48
|
+
video.preload = 'auto';
|
|
49
|
+
video.src = url;
|
|
50
|
+
await new Promise((resolve, reject) => {
|
|
51
|
+
const onLoaded = () => {
|
|
52
|
+
cleanup();
|
|
53
|
+
resolve();
|
|
54
|
+
};
|
|
55
|
+
const onError = () => {
|
|
56
|
+
cleanup();
|
|
57
|
+
reject(new Error(`Failed to load video ${url}`));
|
|
58
|
+
};
|
|
59
|
+
const cleanup = () => {
|
|
60
|
+
video.removeEventListener('loadeddata', onLoaded);
|
|
61
|
+
video.removeEventListener('error', onError);
|
|
62
|
+
};
|
|
63
|
+
video.addEventListener('loadeddata', onLoaded);
|
|
64
|
+
video.addEventListener('error', onError);
|
|
65
|
+
});
|
|
66
|
+
return video;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Seek a video to the given time and resolve once the new frame is ready
|
|
70
|
+
* to be sampled. Necessary for deterministic frame-by-frame export.
|
|
71
|
+
*/
|
|
72
|
+
export function seekVideo(video, time) {
|
|
73
|
+
return new Promise((resolve) => {
|
|
74
|
+
const target = Math.max(0, Math.min(video.duration || Number.POSITIVE_INFINITY, time));
|
|
75
|
+
if (Math.abs(video.currentTime - target) < 1e-4) {
|
|
76
|
+
resolve();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const onSeeked = () => {
|
|
80
|
+
video.removeEventListener('seeked', onSeeked);
|
|
81
|
+
resolve();
|
|
82
|
+
};
|
|
83
|
+
video.addEventListener('seeked', onSeeked);
|
|
84
|
+
video.currentTime = target;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/assets/loader.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,EAAE;AACF,2EAA2E;AAC3E,yEAAyE;AACzE,wEAAwE;AACxE,8DAA8D;AAE9D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,iEAAiE;IACjE,kEAAkE;IAClE,+DAA+D;IAC/D,oBAAoB;IACpB,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;IAClD,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;IACnE,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,yFAAyF;IACzF,mEAAmE;IACnE,OAAO,iBAAiB,CAAC,IAAI,EAAE;QAC7B,gBAAgB,EAAE,YAAY;QAC9B,gBAAgB,EAAE,MAAM,EAAE,0CAA0C;QACpE,oBAAoB,EAAE,MAAM;KAC7B,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;IAChC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,iDAAiD;IACrE,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC;IAEhB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,QAAQ,GAAG,GAAG,EAAE;YACpB,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,IAAI,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC,CAAC;QACnD,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,KAAK,CAAC,mBAAmB,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;YAClD,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9C,CAAC,CAAC;QACF,KAAK,CAAC,gBAAgB,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QAC/C,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,KAAuB,EAAE,IAAY;IAC7D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC,CAAC;QACvF,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;YAChD,OAAO,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QACD,MAAM,QAAQ,GAAG,GAAG,EAAE;YACpB,KAAK,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC9C,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC3C,KAAK,CAAC,WAAW,GAAG,MAAM,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lut.d.ts","sourceRoot":"","sources":["../../src/assets/lut.ts"],"names":[],"mappings":"AAWA,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA0D1F"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// .cube 3D LUT loader (§4.7 `lut`) — fetch + parse + pack the lattice
|
|
2
|
+
// into an N²×N RGBA bitmap: N slices laid along x (slice index = blue
|
|
3
|
+
// level), u = red, v = green within a slice. The stylize shader does
|
|
4
|
+
// manual trilinear sampling over this atlas (two bilinear taps mixed
|
|
5
|
+
// across the blue axis), so the texture must use linear filtering —
|
|
6
|
+
// the backend's default.
|
|
7
|
+
//
|
|
8
|
+
// v1 scope: LUT_3D_SIZE only (1D LUTs rejected), default 0..1 domain.
|
|
9
|
+
// Values are clamped to [0, 1] and quantized to 8-bit, matching the
|
|
10
|
+
// pipeline's working precision.
|
|
11
|
+
export async function loadCube(url) {
|
|
12
|
+
// 10s fetch timeout (mirrors loadImage) so a dead LUT URL can't dangle.
|
|
13
|
+
const ac = new AbortController();
|
|
14
|
+
const timer = setTimeout(() => ac.abort(), 10000);
|
|
15
|
+
let res;
|
|
16
|
+
try {
|
|
17
|
+
res = await fetch(url, { signal: ac.signal });
|
|
18
|
+
}
|
|
19
|
+
finally {
|
|
20
|
+
clearTimeout(timer);
|
|
21
|
+
}
|
|
22
|
+
if (!res.ok)
|
|
23
|
+
throw new Error(`fetch failed: ${res.status}`);
|
|
24
|
+
const text = await res.text();
|
|
25
|
+
let n = 0;
|
|
26
|
+
const values = [];
|
|
27
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
28
|
+
const line = rawLine.trim();
|
|
29
|
+
if (!line || line.startsWith('#'))
|
|
30
|
+
continue;
|
|
31
|
+
const up = line.toUpperCase();
|
|
32
|
+
if (up.startsWith('TITLE'))
|
|
33
|
+
continue;
|
|
34
|
+
if (up.startsWith('DOMAIN_MIN') || up.startsWith('DOMAIN_MAX')) {
|
|
35
|
+
const expect = up.startsWith('DOMAIN_MIN') ? 0 : 1;
|
|
36
|
+
const nums = line.split(/\s+/).slice(1).map(Number);
|
|
37
|
+
if (nums.some((v) => v !== expect))
|
|
38
|
+
throw new Error('non-default DOMAIN not supported');
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (up.startsWith('LUT_1D_SIZE'))
|
|
42
|
+
throw new Error('1D LUTs not supported');
|
|
43
|
+
if (up.startsWith('LUT_3D_SIZE')) {
|
|
44
|
+
n = parseInt(line.split(/\s+/)[1] ?? '0', 10);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const parts = line.split(/\s+/);
|
|
48
|
+
if (parts.length >= 3) {
|
|
49
|
+
const r = Number(parts[0]);
|
|
50
|
+
const g = Number(parts[1]);
|
|
51
|
+
const b = Number(parts[2]);
|
|
52
|
+
if (Number.isFinite(r) && Number.isFinite(g) && Number.isFinite(b))
|
|
53
|
+
values.push(r, g, b);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (!Number.isInteger(n) || n < 2 || n > 256)
|
|
57
|
+
throw new Error('missing or invalid LUT_3D_SIZE');
|
|
58
|
+
if (values.length < n * n * n * 3)
|
|
59
|
+
throw new Error('truncated LUT data');
|
|
60
|
+
// .cube data order: red fastest, then green, then blue.
|
|
61
|
+
const data = new Uint8ClampedArray(n * n * n * 4);
|
|
62
|
+
let i = 0;
|
|
63
|
+
for (let b = 0; b < n; b++) {
|
|
64
|
+
for (let g = 0; g < n; g++) {
|
|
65
|
+
for (let r = 0; r < n; r++) {
|
|
66
|
+
const o = (g * n * n + (b * n + r)) * 4;
|
|
67
|
+
data[o] = Math.round(Math.min(1, Math.max(0, values[i++])) * 255);
|
|
68
|
+
data[o + 1] = Math.round(Math.min(1, Math.max(0, values[i++])) * 255);
|
|
69
|
+
data[o + 2] = Math.round(Math.min(1, Math.max(0, values[i++])) * 255);
|
|
70
|
+
data[o + 3] = 255;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const bitmap = await createImageBitmap(new ImageData(data, n * n, n));
|
|
75
|
+
return { bitmap, size: n };
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=lut.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lut.js","sourceRoot":"","sources":["../../src/assets/lut.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Keyframe } from '@clipkit/protocol';
|
|
2
|
+
export interface MediaTiming {
|
|
3
|
+
/** Composition time the element becomes active, seconds. */
|
|
4
|
+
elementStart: number;
|
|
5
|
+
/** trim_start, seconds into the media. */
|
|
6
|
+
trimStart: number;
|
|
7
|
+
/** trim_duration, seconds of media after trimStart. null = to media end. */
|
|
8
|
+
trimDuration: number | null;
|
|
9
|
+
/** playback_rate. 1 = realtime. */
|
|
10
|
+
rate: number;
|
|
11
|
+
loop: boolean;
|
|
12
|
+
/** time_remap keyframes (element-local time → media seconds), or null. */
|
|
13
|
+
timeRemap?: Keyframe[] | null;
|
|
14
|
+
}
|
|
15
|
+
/** The playable media window [start, start+length] after trims. */
|
|
16
|
+
export declare function trimWindow(timing: Pick<MediaTiming, 'trimStart' | 'trimDuration'>, mediaDuration: number): {
|
|
17
|
+
start: number;
|
|
18
|
+
length: number;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Media time for a composition time. Returns a value inside the trim
|
|
22
|
+
* window (wrapping when looping, clamping otherwise).
|
|
23
|
+
*/
|
|
24
|
+
export declare function mapToMediaTime(compositionTime: number, timing: MediaTiming, mediaDuration: number): number;
|
|
25
|
+
/** Coerce a schema time_remap value (keyframe array or absent). */
|
|
26
|
+
export declare function timeRemapOf(value: unknown): Keyframe[] | null;
|
|
27
|
+
/** Coerce a schema playback_rate value (static number only). */
|
|
28
|
+
export declare function rateOf(value: unknown): number;
|
|
29
|
+
/** Coerce a schema trim_duration value. */
|
|
30
|
+
export declare function trimDurationOf(value: unknown): number | null;
|
|
31
|
+
//# sourceMappingURL=media-time.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-time.d.ts","sourceRoot":"","sources":["../../src/assets/media-time.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlD,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,0EAA0E;IAC1E,SAAS,CAAC,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;CAC/B;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CACxB,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,cAAc,CAAC,EACvD,aAAa,EAAE,MAAM,GACpB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAQnC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,WAAW,EACnB,aAAa,EAAE,MAAM,GACpB,MAAM,CAYR;AAED,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,EAAE,GAAG,IAAI,CAE7D;AAED,gEAAgE;AAChE,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAG7C;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAG5D"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Composition-time → media-time mapping for video (and video-audio)
|
|
2
|
+
// elements. ONE implementation shared by:
|
|
3
|
+
// - runtime.prepareVideoFrames (WebCodecs decode path)
|
|
4
|
+
// - runtime.renderAsync (element-backed export seeks)
|
|
5
|
+
// - the playback engine's fallback <video> pump
|
|
6
|
+
// - the audio scheduler / offline mixer (video audio tracks)
|
|
7
|
+
//
|
|
8
|
+
// Semantics:
|
|
9
|
+
// - `trim_start` offsets into the media.
|
|
10
|
+
// - `trim_duration` caps the playable media window (clamped to what
|
|
11
|
+
// the media actually has after trim_start).
|
|
12
|
+
// - `playback_rate` multiplies media consumption per timeline second.
|
|
13
|
+
// Static number only — keyframed rates would make this an integral.
|
|
14
|
+
// - `loop` wraps WITHIN the trim window; otherwise the last frame
|
|
15
|
+
// holds (clamp just inside the window's end).
|
|
16
|
+
// - `time_remap` (§5.3.2), when present, REPLACES all of the above:
|
|
17
|
+
// the keyframe curve maps element-local time directly to media
|
|
18
|
+
// time (clamped to the media), making speed ramps, freeze frames,
|
|
19
|
+
// and reverse playback plain data.
|
|
20
|
+
import { interpolateKeyframes } from '../animation/keyframes.js';
|
|
21
|
+
/** The playable media window [start, start+length] after trims. */
|
|
22
|
+
export function trimWindow(timing, mediaDuration) {
|
|
23
|
+
const start = Math.max(0, timing.trimStart);
|
|
24
|
+
const available = Math.max(0, mediaDuration - start);
|
|
25
|
+
const length = timing.trimDuration != null
|
|
26
|
+
? Math.max(0, Math.min(timing.trimDuration, available))
|
|
27
|
+
: available;
|
|
28
|
+
return { start, length };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Media time for a composition time. Returns a value inside the trim
|
|
32
|
+
* window (wrapping when looping, clamping otherwise).
|
|
33
|
+
*/
|
|
34
|
+
export function mapToMediaTime(compositionTime, timing, mediaDuration) {
|
|
35
|
+
// time_remap replaces the trim/rate/loop mapping entirely (§5.3.2).
|
|
36
|
+
if (timing.timeRemap && timing.timeRemap.length > 0) {
|
|
37
|
+
const local = Math.max(0, compositionTime - timing.elementStart);
|
|
38
|
+
const t = interpolateKeyframes(timing.timeRemap, local);
|
|
39
|
+
return Math.max(0, Math.min(t, Math.max(0, mediaDuration - 1e-4)));
|
|
40
|
+
}
|
|
41
|
+
const { start, length } = trimWindow(timing, mediaDuration);
|
|
42
|
+
if (length <= 0)
|
|
43
|
+
return start;
|
|
44
|
+
const consumed = Math.max(0, compositionTime - timing.elementStart) * timing.rate;
|
|
45
|
+
if (timing.loop)
|
|
46
|
+
return start + (consumed % length);
|
|
47
|
+
return start + Math.min(consumed, length - 1e-4);
|
|
48
|
+
}
|
|
49
|
+
/** Coerce a schema time_remap value (keyframe array or absent). */
|
|
50
|
+
export function timeRemapOf(value) {
|
|
51
|
+
return Array.isArray(value) && value.length > 0 ? value : null;
|
|
52
|
+
}
|
|
53
|
+
/** Coerce a schema playback_rate value (static number only). */
|
|
54
|
+
export function rateOf(value) {
|
|
55
|
+
if (typeof value === 'number' && Number.isFinite(value) && value > 0)
|
|
56
|
+
return value;
|
|
57
|
+
return 1;
|
|
58
|
+
}
|
|
59
|
+
/** Coerce a schema trim_duration value. */
|
|
60
|
+
export function trimDurationOf(value) {
|
|
61
|
+
if (typeof value === 'number' && Number.isFinite(value) && value >= 0)
|
|
62
|
+
return value;
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=media-time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-time.js","sourceRoot":"","sources":["../../src/assets/media-time.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare class Mp4FrameSource {
|
|
2
|
+
#private;
|
|
3
|
+
readonly width: number;
|
|
4
|
+
readonly height: number;
|
|
5
|
+
/** Media duration in seconds. */
|
|
6
|
+
readonly duration: number;
|
|
7
|
+
/** Samples in decode order, with composition times. */
|
|
8
|
+
private samples;
|
|
9
|
+
/** Indices of keyframes within `samples`, ascending. */
|
|
10
|
+
private keyIndices;
|
|
11
|
+
/** Decoder-output timestamp → sample index (composition order lookup). */
|
|
12
|
+
private tsToIndex;
|
|
13
|
+
private config;
|
|
14
|
+
private decoder;
|
|
15
|
+
/** Next sample index (decode order) to feed the decoder. */
|
|
16
|
+
private nextFeedIndex;
|
|
17
|
+
/** True after an end-of-stream flush — next decode needs a reset. */
|
|
18
|
+
private flushed;
|
|
19
|
+
/** Decoded frames, keyed by sample index. Evicted + closed as the window moves. */
|
|
20
|
+
private cache;
|
|
21
|
+
/** Cache window [lo, hi] — outputs outside it are closed on arrival. */
|
|
22
|
+
private windowLo;
|
|
23
|
+
private windowHi;
|
|
24
|
+
/** Previous request's target — direction detection for the window shape. */
|
|
25
|
+
private lastTarget;
|
|
26
|
+
/** Pending getFrame waiters, keyed by sample index. */
|
|
27
|
+
private waiters;
|
|
28
|
+
/** Serializes getFrame calls. */
|
|
29
|
+
private opChain;
|
|
30
|
+
private disposed;
|
|
31
|
+
static isSupported(): boolean;
|
|
32
|
+
private constructor();
|
|
33
|
+
/** Fetch + demux + verify the codec is decodable. Throws on any failure. */
|
|
34
|
+
static load(url: string): Promise<Mp4FrameSource>;
|
|
35
|
+
/**
|
|
36
|
+
* The decoded frame covering media time `t` (seconds). The RETURNED
|
|
37
|
+
* FRAME IS OWNED BY THE SOURCE — upload it, don't close it; it's
|
|
38
|
+
* closed when the cache window moves past it. Returns null after
|
|
39
|
+
* dispose or on decode failure.
|
|
40
|
+
*/
|
|
41
|
+
getFrame(t: number): Promise<VideoFrame | null>;
|
|
42
|
+
dispose(): void;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=mp4-frame-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mp4-frame-source.d.ts","sourceRoot":"","sources":["../../src/assets/mp4-frame-source.ts"],"names":[],"mappings":"AA0DA,qBAAa,cAAc;;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,uDAAuD;IACvD,OAAO,CAAC,OAAO,CAAc;IAC7B,wDAAwD;IACxD,OAAO,CAAC,UAAU,CAAW;IAC7B,0EAA0E;IAC1E,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,MAAM,CAAqB;IAEnC,OAAO,CAAC,OAAO,CAA6B;IAC5C,4DAA4D;IAC5D,OAAO,CAAC,aAAa,CAA4B;IACjD,qEAAqE;IACrE,OAAO,CAAC,OAAO,CAAS;IACxB,mFAAmF;IACnF,OAAO,CAAC,KAAK,CAAiC;IAC9C,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAA4B;IAC5C,4EAA4E;IAC5E,OAAO,CAAC,UAAU,CAAM;IACxB,uDAAuD;IACvD,OAAO,CAAC,OAAO,CAA4D;IAC3E,iCAAiC;IACjC,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,QAAQ,CAAS;IAEzB,MAAM,CAAC,WAAW,IAAI,OAAO;IAI7B,OAAO;IAwBP,4EAA4E;WAC/D,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAoFvD;;;;;OAKG;IACH,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAkL/C,OAAO,IAAI,IAAI;CAShB"}
|