@motionscript/browser 0.1.0-alpha.0 → 0.1.0-alpha.10
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/CHANGELOG.md +187 -0
- package/NOTICE +49 -0
- package/README.md +96 -24
- package/dist/asset-bytes.d.ts +14 -5
- package/dist/asset-bytes.d.ts.map +1 -1
- package/dist/asset-bytes.js +23 -5
- package/dist/asset-bytes.js.map +1 -1
- package/dist/audio/bus-graph.d.ts +12 -3
- package/dist/audio/bus-graph.d.ts.map +1 -1
- package/dist/audio/bus-graph.js +35 -31
- package/dist/audio/bus-graph.js.map +1 -1
- package/dist/audio/effect-graph.d.ts +62 -0
- package/dist/audio/effect-graph.d.ts.map +1 -0
- package/dist/audio/effect-graph.js +234 -0
- package/dist/audio/effect-graph.js.map +1 -0
- package/dist/audio/index.d.ts.map +1 -1
- package/dist/audio/index.js +2 -3
- package/dist/audio/index.js.map +1 -1
- package/dist/audio/loop-region.d.ts +31 -0
- package/dist/audio/loop-region.d.ts.map +1 -0
- package/dist/audio/loop-region.js +43 -0
- package/dist/audio/loop-region.js.map +1 -0
- package/dist/audio/mixer.d.ts +4 -4
- package/dist/audio/mixer.d.ts.map +1 -1
- package/dist/audio/mixer.js +43 -44
- package/dist/audio/mixer.js.map +1 -1
- package/dist/audio/player.d.ts +15 -9
- package/dist/audio/player.d.ts.map +1 -1
- package/dist/audio/player.js +60 -69
- package/dist/audio/player.js.map +1 -1
- package/dist/browser/THIRD_PARTY_LICENSES.txt +784 -0
- package/dist/browser/audio.js +1 -1
- package/dist/browser/chunks/chunk-F3AZKPHU.js +2 -0
- package/dist/browser/chunks/chunk-F3AZKPHU.js.map +7 -0
- package/dist/browser/chunks/chunk-KLXMRKTL.js +2 -0
- package/dist/browser/chunks/chunk-L5UFQACH.js +163 -0
- package/dist/browser/chunks/chunk-L5UFQACH.js.map +7 -0
- package/dist/browser/chunks/mediabunny-mp3-encoder-ZCIHVVTJ.js +14 -0
- package/dist/browser/chunks/mediabunny-mp3-encoder-ZCIHVVTJ.js.map +7 -0
- package/dist/browser/index.js +52 -1490
- package/dist/browser/index.js.map +4 -4
- package/dist/browser/manifest.json +21 -4
- package/dist/browser/ms_renderer_bg.wasm +0 -0
- package/dist/concat.d.ts +33 -7
- package/dist/concat.d.ts.map +1 -1
- package/dist/concat.js +117 -72
- package/dist/concat.js.map +1 -1
- package/dist/deliver.d.ts +10 -0
- package/dist/deliver.d.ts.map +1 -0
- package/dist/deliver.js +22 -0
- package/dist/deliver.js.map +1 -0
- package/dist/dynamic-nodes.d.ts.map +1 -1
- package/dist/dynamic-nodes.js +9 -12
- package/dist/dynamic-nodes.js.map +1 -1
- package/dist/engine.d.ts +43 -15
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +58 -36
- package/dist/engine.js.map +1 -1
- package/dist/export-audio.d.ts +36 -0
- package/dist/export-audio.d.ts.map +1 -0
- package/dist/export-audio.js +56 -0
- package/dist/export-audio.js.map +1 -0
- package/dist/exporter.d.ts +134 -15
- package/dist/exporter.d.ts.map +1 -1
- package/dist/exporter.js +135 -90
- package/dist/exporter.js.map +1 -1
- package/dist/formats.d.ts +36 -0
- package/dist/formats.d.ts.map +1 -0
- package/dist/formats.js +83 -0
- package/dist/formats.js.map +1 -0
- package/dist/frame-loop.d.ts +190 -0
- package/dist/frame-loop.d.ts.map +1 -0
- package/dist/frame-loop.js +304 -0
- package/dist/frame-loop.js.map +1 -0
- package/dist/index.d.ts +12 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -47
- package/dist/index.js.map +1 -1
- package/dist/mix-timeline-audio.d.ts +7 -7
- package/dist/mix-timeline-audio.d.ts.map +1 -1
- package/dist/mix-timeline-audio.js +11 -14
- package/dist/mix-timeline-audio.js.map +1 -1
- package/dist/parallel/export-parallel.d.ts +32 -0
- package/dist/parallel/export-parallel.d.ts.map +1 -0
- package/dist/parallel/export-parallel.js +114 -0
- package/dist/parallel/export-parallel.js.map +1 -0
- package/dist/parallel/governor.d.ts +57 -0
- package/dist/parallel/governor.d.ts.map +1 -0
- package/dist/parallel/governor.js +79 -0
- package/dist/parallel/governor.js.map +1 -0
- package/dist/parallel/lane.d.ts +45 -0
- package/dist/parallel/lane.d.ts.map +1 -0
- package/dist/parallel/lane.js +2 -0
- package/dist/parallel/lane.js.map +1 -0
- package/dist/parallel/lanes.d.ts +20 -0
- package/dist/parallel/lanes.d.ts.map +1 -0
- package/dist/parallel/lanes.js +152 -0
- package/dist/parallel/lanes.js.map +1 -0
- package/dist/parallel/plan.d.ts +23 -0
- package/dist/parallel/plan.d.ts.map +1 -0
- package/dist/parallel/plan.js +30 -0
- package/dist/parallel/plan.js.map +1 -0
- package/dist/parallel/run-lanes.d.ts +38 -0
- package/dist/parallel/run-lanes.d.ts.map +1 -0
- package/dist/parallel/run-lanes.js +164 -0
- package/dist/parallel/run-lanes.js.map +1 -0
- package/dist/parallel/session.d.ts +9 -0
- package/dist/parallel/session.d.ts.map +1 -0
- package/dist/parallel/session.js +79 -0
- package/dist/parallel/session.js.map +1 -0
- package/dist/renderer.d.ts +22 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +23 -0
- package/dist/renderer.js.map +1 -0
- package/dist/screenshot.d.ts +6 -6
- package/dist/screenshot.d.ts.map +1 -1
- package/dist/screenshot.js +4 -5
- package/dist/screenshot.js.map +1 -1
- package/dist/still.d.ts +32 -24
- package/dist/still.d.ts.map +1 -1
- package/dist/still.js +54 -54
- package/dist/still.js.map +1 -1
- package/dist/ticker.d.ts +41 -9
- package/dist/ticker.d.ts.map +1 -1
- package/dist/ticker.js +113 -41
- package/dist/ticker.js.map +1 -1
- package/package.json +11 -10
- package/dist/audio/filter-graph.d.ts +0 -58
- package/dist/audio/filter-graph.d.ts.map +0 -1
- package/dist/audio/filter-graph.js +0 -235
- package/dist/audio/filter-graph.js.map +0 -1
- package/dist/browser/chunks/GLTFLoader-PGXD4V5B.js +0 -2
- package/dist/browser/chunks/GLTFLoader-PGXD4V5B.js.map +0 -7
- package/dist/browser/chunks/SkeletonUtils-XYDMTGTM.js +0 -2
- package/dist/browser/chunks/chunk-CTLBXZSU.js +0 -4119
- package/dist/browser/chunks/chunk-CTLBXZSU.js.map +0 -7
- package/dist/browser/chunks/chunk-FQ32PDIU.js +0 -2
- package/dist/browser/chunks/chunk-FQ32PDIU.js.map +0 -7
- package/dist/browser/chunks/chunk-FY3BTKY4.js +0 -2
- package/dist/browser/chunks/chunk-FY3BTKY4.js.map +0 -7
- package/dist/browser/chunks/chunk-NSFLRI4P.js +0 -2
- package/dist/browser/chunks/chunk-NSFLRI4P.js.map +0 -7
- package/dist/browser/chunks/three.module-Z4EOVUWF.js +0 -2
- package/dist/browser/chunks/three.module-Z4EOVUWF.js.map +0 -7
- package/dist/decode/image-levels.d.ts +0 -137
- package/dist/decode/image-levels.d.ts.map +0 -1
- package/dist/decode/image-levels.js +0 -477
- package/dist/decode/image-levels.js.map +0 -1
- package/dist/decode/levels.d.ts +0 -37
- package/dist/decode/levels.d.ts.map +0 -1
- package/dist/decode/levels.js +0 -68
- package/dist/decode/levels.js.map +0 -1
- package/dist/decode/video-levels.d.ts +0 -37
- package/dist/decode/video-levels.d.ts.map +0 -1
- package/dist/decode/video-levels.js +0 -95
- package/dist/decode/video-levels.js.map +0 -1
- package/dist/getter.d.ts +0 -10
- package/dist/getter.d.ts.map +0 -1
- package/dist/getter.js +0 -38
- package/dist/getter.js.map +0 -1
- package/dist/measure-context.d.ts +0 -12
- package/dist/measure-context.d.ts.map +0 -1
- package/dist/measure-context.js +0 -12
- package/dist/measure-context.js.map +0 -1
- package/dist/output.d.ts +0 -7
- package/dist/output.d.ts.map +0 -1
- package/dist/output.js +0 -6
- package/dist/output.js.map +0 -1
- package/dist/render-context.d.ts +0 -30
- package/dist/render-context.d.ts.map +0 -1
- package/dist/render-context.js +0 -55
- package/dist/render-context.js.map +0 -1
- package/dist/storage-adapter.d.ts +0 -367
- package/dist/storage-adapter.d.ts.map +0 -1
- package/dist/storage-adapter.js +0 -1278
- package/dist/storage-adapter.js.map +0 -1
- package/dist/three/renderer.d.ts +0 -48
- package/dist/three/renderer.d.ts.map +0 -1
- package/dist/three/renderer.js +0 -177
- package/dist/three/renderer.js.map +0 -1
- /package/dist/browser/chunks/{SkeletonUtils-XYDMTGTM.js.map → chunk-KLXMRKTL.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,192 @@
|
|
|
1
1
|
# @motionscript/browser
|
|
2
2
|
|
|
3
|
+
## 0.1.0-alpha.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [d2241c3]
|
|
8
|
+
- Updated dependencies [2026625]
|
|
9
|
+
- @motionscript/renderer@0.1.0-alpha.10
|
|
10
|
+
|
|
11
|
+
## 0.1.0-alpha.9
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- @motionscript/renderer@0.1.0-alpha.9
|
|
16
|
+
|
|
17
|
+
## 0.1.0-alpha.8
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- @motionscript/renderer@0.1.0-alpha.8
|
|
22
|
+
|
|
23
|
+
## 0.1.0-alpha.7
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- @motionscript/skia-render@0.1.0-alpha.7
|
|
28
|
+
|
|
29
|
+
## 0.1.0-alpha.6
|
|
30
|
+
|
|
31
|
+
### Minor Changes
|
|
32
|
+
|
|
33
|
+
- aa75a19: A source-string node default-exports a component, and is written with calls.
|
|
34
|
+
|
|
35
|
+
- `Registry.addNodeFromSource`, `engine.registerNode(source)` and a string in `nodes` (browser and headless) take a script whose default export is a component (`export default component2d({ key: "…", … })`), not a class decorated with `@node(...)`.
|
|
36
|
+
- `DynamicNodeConfig.jsxRuntime` is gone, and browser's default compiler reads TypeScript without JSX or decorators: a script with JSX fails to compile, and one that requires `@motionscript/sdk/jsx-runtime` fails to link. The CDN build no longer imports `@motionscript/core/jsx/jsx-runtime`, so an import map need not name it.
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- @motionscript/skia-render@0.1.0-alpha.6
|
|
41
|
+
|
|
42
|
+
## 0.1.0-alpha.5
|
|
43
|
+
|
|
44
|
+
### Patch Changes
|
|
45
|
+
|
|
46
|
+
- da6f97a: An export's audio mix asks the host's byte source before the network.
|
|
47
|
+
|
|
48
|
+
`mixAudio`, and so `exportVideo` and `mixTimelineAudio`, fetched every audio source from the network, while previews, stills and the rest of an export read bytes through `setAssetByteSource` first. A host holding a recording locally (one not yet uploaded, or with no network) exported silence or failed where the preview played. The source is now asked with the address the catalog resolves, as `WebStorageAdapter` does, and a `null` falls through to `fetch` as before.
|
|
49
|
+
|
|
50
|
+
- The headless engine can export a video across several pages at once, and an export can render a range of frames.
|
|
51
|
+
|
|
52
|
+
- `@motionscript/headless`: `renderVideo({ concurrency })` cuts the timeline into that many contiguous runs of frames, renders and encodes each in a page of its own (one Chromium, one bundle), and joins them with `concatVideoSegments` without re-encoding. Every segment gets the same codec, bitrate and hardware acceleration and begins on a key frame; the audio is mixed once over the whole timeline with `mixTimelineAudio`. The default of 1 exports in one page as before. The added pages stay open for the next export. Segments that still cannot be joined fall back to a one-page export, with the reason on stderr.
|
|
53
|
+
- `@motionscript/headless`: `renderVideo` also takes `supersample`, `codec`, `bitrate`, `hardwareAcceleration` and `includeAudio`, which reach the browser exporter, and `parseConcurrency` is exported beside the other option parsers. The page bridge has `countFrames()` and `concatSegments()`, and a bundle without them is `BRIDGE_INCOMPATIBLE`.
|
|
54
|
+
- `@motionscript/headless`: `renderVideo` sends the document into the page as its JSON text (a caller may pass the text itself), because Playwright carries a 5000-node object in about 1.4 s and its text in about 0.2 s. The page exports through `exportVideo` without opening a session, whose controller discovered every track on frame 0 only for the exporter to discover them again.
|
|
55
|
+
- `@motionscript/core`: `ExportVideoRequest` (so `session.export`) takes `frames: { start, end }`, a `FrameRange` with `end` excluded.
|
|
56
|
+
- `@motionscript/skia-render` and `@motionscript/browser`: `renderTimeline` and `exportVideo` take `frames` too. A range renders those frames alone, timestamped from 0, discovers only the tracks they touch, and is always silent: it is one segment of a split export. A range that is empty or leaves the timeline throws a `RangeError` before anything is encoded.
|
|
57
|
+
|
|
58
|
+
- da6f97a: Every package ships a `NOTICE`, and a browser build lists what it bundles.
|
|
59
|
+
|
|
60
|
+
- Each tarball carries the repository `NOTICE`: the copyright line and the MIT attributions for the noise functions in `skia-render`'s fractal-noise fill (David Hoskins' "Hash without Sine", Inigo Quilez's 2D simplex noise).
|
|
61
|
+
- `@motionscript/canvaskit` ships `THIRD_PARTY_NOTICES.txt` with the licences of the libraries compiled into the binary: FreeType, HarfBuzz, ICU 74, zlib, libpng, Brotli, WOFF2, Emscripten and musl.
|
|
62
|
+
- `dist/browser/manifest.json` gains `thirdParty`, the packages the browser build bundled (`name`, `version`, `license`), and their licence and NOTICE files are written to `dist/browser/THIRD_PARTY_LICENSES.txt`. `@motionscript/browser` bundles mediabunny (MPL-2.0, unmodified; source at https://github.com/Vanilagy/mediabunny), esbuild-wasm and three; `@motionscript/math` bundles MathJax.
|
|
63
|
+
|
|
64
|
+
- Updated dependencies
|
|
65
|
+
- Updated dependencies [da6f97a]
|
|
66
|
+
- Updated dependencies [1778355]
|
|
67
|
+
- Updated dependencies
|
|
68
|
+
- @motionscript/skia-render@0.1.0-alpha.5
|
|
69
|
+
|
|
70
|
+
## 0.1.0-alpha.4
|
|
71
|
+
|
|
72
|
+
### Minor Changes
|
|
73
|
+
|
|
74
|
+
- 158723b: **Breaking:** the engine no longer has a "scene" in its document API. Its unit is a clip document on a project track, so the names that said "scene" now say what the thing is. This is a clean break: there are no aliases and no deprecated re-exports, so update the names below.
|
|
75
|
+
|
|
76
|
+
| Before | After |
|
|
77
|
+
| -------------------------------------------------------- | ---------------------------- |
|
|
78
|
+
| `SceneDocument` (`StillDocument \| CompositionDocument`) | `VisualDocument` |
|
|
79
|
+
| `SceneTimeline` | `ClipTimeline` |
|
|
80
|
+
| `SceneEffect` (the union of effects a node can carry) | `NodeEffect` |
|
|
81
|
+
| `integrateSpeedToSceneTime` | `integrateSpeedToClipTime` |
|
|
82
|
+
| `sourceTimeAtSceneElapsed` | `sourceTimeAtClipElapsed` |
|
|
83
|
+
| `Sound.sceneDurationFor` | `Sound.clipDurationFor` |
|
|
84
|
+
| `AudioSink.syncTo(sceneTime)` (parameter name) | `AudioSink.syncTo(clipTime)` |
|
|
85
|
+
|
|
86
|
+
`ClipDocument` is now `VisualDocument | AudioDocument`, as before. The document types, the 3D `Scene3D` and its `scene3d` settings are unchanged: that is a 3D scene, not this.
|
|
87
|
+
|
|
88
|
+
Two messages changed with the names: `assertValidDocument` now throws `Invalid clip document:` (was `Invalid scene document:`), and the JSX runtime's error for a value that is not a node class reads `JSX element must be a Node class`.
|
|
89
|
+
|
|
90
|
+
The built-in `Canvas2D`, `Provider` and `ThemeProvider` moved from `nodes/scene/` to `nodes/root/` inside core. That directory was never an export path, so no import from the package changes.
|
|
91
|
+
|
|
92
|
+
- 8e9afad: One frame/time conversion and one `FrameSpec`, and fixes to browser playback and export.
|
|
93
|
+
|
|
94
|
+
- Core exports `clipFrameToTime`, `clipTimeToFrame`, `frameSpecAtTime`, `FrameSpec` and `DEFAULT_OUTPUT`. The conversion is tolerant of float error: a time within a few ulps of a whole frame is that frame. The playback controller, `Session.seek`, track placement and the evaluator all use it. Before, `currentFrame` read one frame early for 2 to 6 percent of frames (frame 123 at 60 fps), so a document swap after `seek(123)` repainted frame 122, and `trackFrameCount` gained a frame when a length on a boundary landed an ulp high (4.15 s at 60 fps counted 250, not 249).
|
|
95
|
+
- `FrameSpec` is declared once, in core, and re-exported by `@motionscript/browser` and `@motionscript/headless`; the browser's `DEFAULT_OUTPUT` and the React hook's fallback are core's defaults. The React playhead reads the frame the clock reports through the same conversion.
|
|
96
|
+
- `WebTicker` no longer stalls a looping host: the end of a run is read again after listeners and tick callbacks have run, a final tick always fires, and a finished run pauses itself. `play` is synchronous, as `Ticker.play` is typed, so a `pause` or `seek` in the same turn works; a rejected `AudioContext.resume()` pauses and logs.
|
|
97
|
+
- A supersampled export draws into a canvas that is a whole multiple of the output, so an odd-sized viewport is no longer stretched by about 1 percent.
|
|
98
|
+
- `StillRenderer.toBytes`, `toBlob` and `toDataURL` throw before any frame has been drawn onto the surface, instead of encoding blank pixels.
|
|
99
|
+
|
|
100
|
+
### Patch Changes
|
|
101
|
+
|
|
102
|
+
- 997dd9e: A `Video` whose file holds no audio track is a silent video, not a failed load.
|
|
103
|
+
|
|
104
|
+
- A `Video` declares its own sound for the same `src` as its picture. For a file with no audio track (a screen recording, say) the decode fails, and the asset manager reported `audio "…" could not be loaded: Unable to decode audio data`, which a host shows as its preview having stopped, and `mixAudio` rejected, which fails an export.
|
|
105
|
+
- `AudioClip` and `AudioRequest` take `optional`, and `Video` declares its clips so. A source only optional requests want is silence when it cannot be fetched or decoded: the manager says nothing and `mixAudio` leaves those requests out and renders the rest.
|
|
106
|
+
- A `sound` that names such a file is still a failure, reported once and rejecting the mix, because there the sound is the whole of what was asked for. That includes a request that starts wanting a source that had already failed quietly.
|
|
107
|
+
- A source that failed quietly is kept across a document swap instead of being fetched whole again on every edit; one that was reported is still tried afresh.
|
|
108
|
+
- `optional` is not part of a request's id.
|
|
109
|
+
|
|
110
|
+
- ada534c: Fixes across 3D, audio, asset loading, the session and the JSX runtime.
|
|
111
|
+
|
|
112
|
+
- A string shader or post-effect uniform is a texture only when it looks like an asset path. A colour uniform such as `uTint: 'tomato'` made declaring the scene's assets throw `Image asset not found`.
|
|
113
|
+
- `lookAt`, a camera's `target` and a light's `target` tween with `to()`. They had no tween, so a `to` moved the other props and left these where they started. An unset `target` tweens from the origin; an unset `lookAt` holds until the end, since "do not aim" has no midpoint.
|
|
114
|
+
- A `Canvas3D` with no 3D children records an empty scene instead of a default camera and rig, so a viewport holding only 2D children skips the 3D pass and no longer creates a WebGL context.
|
|
115
|
+
- A looping `Sound` repeats its trimmed region. `AudioRequest` carries the loop's `trimEnd`, a loop with a `trimEnd` and no cut runs open instead of playing once, and the live device and the offline mix set `loopStart` and `loopEnd` to the region (a seek into the middle of a loop is folded into it too), so the trim no longer wraps the whole buffer.
|
|
116
|
+
- An audio curve's ease is part of its key. Every engine easing is an anonymous closure, so editing only an ease left the request unchanged and the device kept playing the old sound. Easings record a description, and the same ease built twice keys the same.
|
|
117
|
+
- A failed audio fetch is caught, reported once, and not started again on every sync, instead of being an unhandled rejection. A layout-gated loader is no longer disposed and loaded again when the frame leaves its window.
|
|
118
|
+
- `AssetNotLoadedError` names `assets.video(...)` for a video, `assets.loader(...)` for a loader and `declareAudio()` for audio.
|
|
119
|
+
- `Engine.setManifest` reaches a live session's controller: a font or image added after open is known to clips already built, and tracks that failed for want of it are built again. `session.replace` keeps the `fps` and `viewport` the session was opened with instead of throwing on the document it is already playing.
|
|
120
|
+
- The JSX automatic runtime keeps `key`: `<Rect key="card" />` lowers to `jsx(Rect, {}, "card")`, and `jsx` now takes the third argument.
|
|
121
|
+
|
|
122
|
+
- 55a3b69: A still, a screenshot or an export refuses a font family the manifest does not describe.
|
|
123
|
+
|
|
124
|
+
- A text node naming a family with no manifest entry was shaped against the fallback face, with a console warning, and the frame was returned as if it were the document's. Described later, the same document draws differently, so a frame stored or encoded in the meantime was the wrong one. `StorageAdapter` now throws `AssetNotLoadedError` (`assetType: "font"`, `src` the family) for it when its `DecodePolicy` is `"exact"`, which every still, screenshot and export sets while it draws. Nothing is remembered of the refusal, so a renderer handed a manifest that describes the family loads it on the next render.
|
|
125
|
+
- A preview is unchanged: an undescribed family draws in the fallback face, with the warning, until a manifest describes it. The warning is no longer printed for a still or an export, which now fail instead.
|
|
126
|
+
- A text node that names no family at all is refused by `requireFontFamily`, as before.
|
|
127
|
+
- `renderImage` and `renderVideo` in `@motionscript/headless` reject with the page's error for such a document, where they used to return a frame with no text in it.
|
|
128
|
+
|
|
129
|
+
- Updated dependencies [cd1c774]
|
|
130
|
+
- Updated dependencies [fb0ac65]
|
|
131
|
+
- Updated dependencies [217ae88]
|
|
132
|
+
- Updated dependencies [cd420db]
|
|
133
|
+
- Updated dependencies [848c40c]
|
|
134
|
+
- Updated dependencies [7f8b4d0]
|
|
135
|
+
- @motionscript/skia-render@0.1.0-alpha.4
|
|
136
|
+
|
|
137
|
+
## 0.1.0-alpha.3
|
|
138
|
+
|
|
139
|
+
### Patch Changes
|
|
140
|
+
|
|
141
|
+
- 1f00320: 3D renders its settings from the first frame, and installs itself without relying on module side effects.
|
|
142
|
+
|
|
143
|
+
- The first 3D frame of a session, and the first after an `antialias` change, drew without the scene's tone mapping, shadows or `studio` environment, because they were written before the renderer existed. The renderer is now made before a scene syncs, so the same scene gives the same pixels on every frame. `Canvas3DRendererHost` gains `prepare(three, { antialias })`, which the backend calls first, and a scene's settings go to the host its backend was built with rather than whichever one is registered.
|
|
144
|
+
- After an `antialias` change, a `studio` environment kept a texture from the replaced renderer and metal drew dark on every later frame. The environment is now generated per renderer.
|
|
145
|
+
- `@motionscript/browser` registered 3D when its root module was evaluated, while declaring `sideEffects: false`. A bundler honouring the flag, such as rolldown under Vite 8, could drop both calls, and `Canvas3D` then drew its 2D parts only, with no error. Every `WebRenderContext` now installs the WebGL renderer and core's three loader when it is built, so each engine session, still renderer and export carries 3D with it, and importing the package registers nothing.
|
|
146
|
+
|
|
147
|
+
- 47b6b7d: A curve on an `AudioBus` animates, over the bus's own span.
|
|
148
|
+
|
|
149
|
+
- A curve in a bus's `filters` was resolved against a length of 0, so it held its first value: `AudioFilters.gain(fadeOut(1))` never faded, and a fade or `ramp` up from 0 silenced everything on the bus. It now runs over the bus's presence span, from its row's `startAt` to its `endAt`, or to its clip's end when nothing removes it, the way a sound's curve runs over the sound's. Every clip on the bus hears the same fade, wherever its own span falls.
|
|
150
|
+
- A curve-valued bus `volume` was read as 1. It is now scheduled like a curve in `filters`.
|
|
151
|
+
- A bus chain was built once per bus id and kept, so a later change to the bus's level, mute or filters was not heard for the life of the device, and the offline mix played every clip through whichever version of a bus it met first. A chain is now reused only for a bus that sounds the same, and the live device builds its bus chains again after each pause, so a curve lines up with wherever playback resumes.
|
|
152
|
+
- The live device restarted a curve segment from its first value when it began playing partway through that segment. It now picks the segment up where it has got to, as the offline mix does.
|
|
153
|
+
- `AudioBusStop` carries the bus's span as `startAt` and `endAt`, in the same seconds as the request that carries it, and `busStopKey` keys a stop by everything that changes its sound. `busPathOf` and `busPathTo` take the declaring `AudioScope` as a second argument, and `AudioBusGraph.inputFor` takes the time its start time falls at, in the stops' seconds, as a third.
|
|
154
|
+
|
|
155
|
+
- e2ce45c: A node compiled from source can use JSX and name its own variables freely.
|
|
156
|
+
|
|
157
|
+
- The default compiler for a source-string node emitted classic `React.createElement` calls, so a script with JSX registered and then threw `React is not defined` the first time its constructor ran. It now compiles JSX with the automatic runtime and `@motionscript/sdk` as the import source, which links to `DynamicNodeConfig.jsxRuntime`. A script needs no pragma, and a `@jsxRuntime` or `@jsxImportSource` pragma in it still takes precedence.
|
|
158
|
+
- A top-level `const`, `let` or `class` named like one of the globals a script is denied (`const frames = 30`, `let history = []`, `class Request {}`) failed with `SyntaxError: Identifier '…' has already been declared`. The script now runs in a scope of its own inside the one that denies those names, so its declaration shadows the denied global. Names it does not declare still read as `undefined`.
|
|
159
|
+
|
|
160
|
+
- 42e9217: A failed asset fetch fails instead of loading empty bytes. `WebStorageAdapter` read a response's body whatever its status, so a 404 for a font file reached the font manager, which registered nothing, and the family still counted as loaded: its text drew nothing, on every frame, and nothing reported it. A missing image or audio file failed later, in a decoder, with a message that never named the address. A response that is not OK now rejects the load with `Fetching "<url>" failed: HTTP <status>`, which reaches the host the way any failed load does: a seek, a still or an export rejects, and a prefetch logs it. Nothing is cached, so the next load tries again.
|
|
161
|
+
|
|
162
|
+
- A font family registers once every one of its files has arrived, so a family missing a weight is not registered half-way and a retry does not register the rest a second time.
|
|
163
|
+
- `mixAudio`, which mixes every export's soundtrack, checks the status the same way.
|
|
164
|
+
- A render through `@motionscript/headless` of a document whose font is missing from `assetsDir` now fails naming the file, instead of drawing its text empty.
|
|
165
|
+
|
|
166
|
+
- 1c48469: Stills and exports render the frame, theme and scale they were asked for.
|
|
167
|
+
|
|
168
|
+
- Overlapping `session.image()` calls each return their own frame. They shared one renderer, so every image held the last frame drawn; the engine's exporter now queues them.
|
|
169
|
+
- `exportVideo` applies the document's `theme`, and takes a `theme` option for a document that carries none, as `exportScreenshot` and `StillRenderer` do. A themed document exported on its own drew its tokens black, or in whatever theme was last set globally. `renderTimeline` and `drawFrameAt` take the same `theme` and apply it themselves.
|
|
170
|
+
- `RenderStillOptions.scale`, and so `session.image({ scale })`, applies to that call only. It used to become the renderer's scale, so the next call without one drew at it too.
|
|
171
|
+
- An export rejects with `NothingToDrawError` at the first frame whose every track failed to build, the same error a still of that frame throws. It used to encode a black video and log nothing. The error is exported from both packages and carries the `frame` and each track's failure. A track that built is drawable even when one of its nodes failed to declare its assets or audio; a still used to refuse it.
|
|
172
|
+
|
|
173
|
+
- Updated dependencies [1f00320]
|
|
174
|
+
- Updated dependencies [979a467]
|
|
175
|
+
- Updated dependencies [1c48469]
|
|
176
|
+
- @motionscript/skia-render@0.1.0-alpha.3
|
|
177
|
+
|
|
178
|
+
## 0.1.0-alpha.2
|
|
179
|
+
|
|
180
|
+
### Patch Changes
|
|
181
|
+
|
|
182
|
+
- @motionscript/skia-render@0.1.0-alpha.2
|
|
183
|
+
|
|
184
|
+
## 0.1.0-alpha.1
|
|
185
|
+
|
|
186
|
+
### Patch Changes
|
|
187
|
+
|
|
188
|
+
- @motionscript/skia-render@0.1.0-alpha.1
|
|
189
|
+
|
|
3
190
|
## 0.1.0-alpha.0
|
|
4
191
|
|
|
5
192
|
Initial release.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Motionscript
|
|
2
|
+
Copyright 2026 Motionscript LLC
|
|
3
|
+
|
|
4
|
+
This product includes the third-party code below, each part under the MIT
|
|
5
|
+
License reproduced at the end of this file.
|
|
6
|
+
|
|
7
|
+
- packages/renderer/crates/renderer/src/shaders/prim.wgsl (`fn_hash2`):
|
|
8
|
+
"Hash without Sine" by David Hoskins (https://www.shadertoy.com/view/4djSRW).
|
|
9
|
+
Copyright (c) 2014 David Hoskins.
|
|
10
|
+
|
|
11
|
+
- packages/renderer/crates/renderer/src/shaders/prim.wgsl (`simplex_noise`): "Noise - simplex - 2D" by Inigo Quilez
|
|
12
|
+
(https://www.shadertoy.com/view/Msf3WH). Copyright (c) 2013 Inigo Quilez.
|
|
13
|
+
|
|
14
|
+
- packages/renderer/crates/render3d (in @motionscript/renderer's WebAssembly):
|
|
15
|
+
its shaders (src/shaders/mesh.wgsl) port three.js r185's mesh programs and
|
|
16
|
+
src/geometry.rs its primitive generators (https://threejs.org).
|
|
17
|
+
Copyright (c) 2010-2026 three.js authors.
|
|
18
|
+
|
|
19
|
+
@motionscript/renderer's WebAssembly (dist/ms_renderer_bg.wasm) compiles in
|
|
20
|
+
Rust crates under MIT, Apache-2.0, Zlib and Unicode-3.0 terms (wgpu, naga,
|
|
21
|
+
harfrust, read-fonts, kurbo, wasm-bindgen and others); their notices are in
|
|
22
|
+
packages/renderer/THIRD_PARTY_NOTICES.txt.
|
|
23
|
+
|
|
24
|
+
MP3 export loads @mediabunny/mp3-encoder (MPL-2.0), a WebAssembly build of
|
|
25
|
+
the LAME MP3 encoder (LGPL, https://lame.sourceforge.io), on first use.
|
|
26
|
+
|
|
27
|
+
The browser builds under dist/browser/ bundle each package's npm dependencies;
|
|
28
|
+
dist/browser/THIRD_PARTY_LICENSES.txt in each package lists them with their
|
|
29
|
+
licences.
|
|
30
|
+
|
|
31
|
+
MIT License
|
|
32
|
+
|
|
33
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
34
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
35
|
+
in the Software without restriction, including without limitation the rights
|
|
36
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
37
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
38
|
+
furnished to do so, subject to the following conditions:
|
|
39
|
+
|
|
40
|
+
The above copyright notice and this permission notice shall be included in all
|
|
41
|
+
copies or substantial portions of the Software.
|
|
42
|
+
|
|
43
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
44
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
45
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
46
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
47
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
48
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
49
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,58 +1,119 @@
|
|
|
1
1
|
# @motionscript/browser
|
|
2
2
|
|
|
3
|
-
The browser
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
The browser platform for [Motion Script](https://motionscript.dev): it draws
|
|
4
|
+
every frame with WebGPU through [`@motionscript/renderer`](https://github.com/motionscript-dev/motionscript/tree/main/packages/renderer), which it
|
|
5
|
+
builds in. It implements the
|
|
6
|
+
`platform`/`render` abstractions from [`@motionscript/core`](https://github.com/motionscript-dev/motionscript/tree/main/packages/core) so
|
|
6
7
|
documents can be drawn to a canvas, played back with synchronized audio, and
|
|
7
8
|
exported to video all in the browser.
|
|
8
9
|
|
|
10
|
+
How a frame is drawn (shapes, fills, strokes, effects, text, 3D) lives in the
|
|
11
|
+
renderer (Rust/wgpu compiled to WebAssembly). This package supplies the browser's
|
|
12
|
+
half: the export frame loop, encoding, Web Audio, the clock and the entry points.
|
|
13
|
+
A browser without WebGPU cannot draw: every entry that draws rejects with
|
|
14
|
+
`WebGpuUnavailableError` (check `isWgpuSupported()` first to say so up front).
|
|
15
|
+
|
|
9
16
|
## What's in here
|
|
10
17
|
|
|
11
18
|
- **Engine**: `createBrowserEngine` wires every platform seam below into a
|
|
12
19
|
`@motionscript/core` `Engine`. Await it once at app start and share it.
|
|
13
|
-
- **Render context**: `WebRenderContext` draws the `@motionscript/core` scene
|
|
14
|
-
graph (shapes, fills, strokes, effects, text, video, masks) onto a CanvasKit
|
|
15
|
-
surface.
|
|
16
20
|
- **Exporter**: `exportVideo` renders a document offline and muxes video and
|
|
17
|
-
audio into an MP4
|
|
21
|
+
audio into an MP4 (H.264 + AAC, the default) or a WebM (VP9 + Opus) using
|
|
22
|
+
[mediabunny](https://github.com/Vanilagy/mediabunny). `exportAudio` writes the
|
|
23
|
+
timeline's mixed audio alone as WAV (the default), MP3 or M4A without rendering
|
|
24
|
+
a frame, and throws `NoAudioError` when nothing plays. `EXPORT_FORMATS` gives
|
|
25
|
+
each format's kind, extension and MIME type. MP3 loads a WASM build of LAME on
|
|
26
|
+
first use, in a worker started from a `blob:` URL, so a host's CSP needs
|
|
27
|
+
`worker-src blob:` for it.
|
|
18
28
|
- **Stills**: `StillRenderer` (from `createStillRenderer`) is a long-lived
|
|
19
29
|
renderer that repaints single frames into a canvas the host owns, for
|
|
20
30
|
thumbnails and previews; `exportScreenshot` is the one-shot wrapper over it.
|
|
21
|
-
- **Concat**: `concatVideoSegments` joins separately encoded MP4
|
|
22
|
-
without re-encoding, so an export can be split across workers.
|
|
31
|
+
- **Concat**: `concatVideoSegments` joins separately encoded MP4 (or WebM)
|
|
32
|
+
segments into one file of the same container without re-encoding, so an export can be split across workers. A segment is
|
|
33
|
+
`exportVideo({ frames: { start, end } })` (or `session.export({ frames })`):
|
|
34
|
+
that range alone, timestamped from 0 and silent.
|
|
23
35
|
`mixTimelineAudio` mixes the whole timeline's audio once for the joined file.
|
|
24
36
|
Every segment must share one encoder configuration; a mismatch throws
|
|
25
37
|
`ConcatMismatchError`.
|
|
26
|
-
- **
|
|
27
|
-
`
|
|
28
|
-
|
|
38
|
+
- **Parallel export**: `exportVideoParallel` takes `exportVideo`'s parameters
|
|
39
|
+
plus `lanes`, the renderers to spread the frames over: `localLane()` for
|
|
40
|
+
this page, and `messagePortLane(port)` for another realm (a second window or
|
|
41
|
+
process) that answers with `serveExportLane(port, resolve)`. It cuts the
|
|
42
|
+
timeline into key-frame-aligned frame ranges of the whole project, starts on
|
|
43
|
+
the first lane alone and admits the next only while that raises throughput
|
|
44
|
+
(every lane's encoder shares the browser's one GPU process, so light scenes
|
|
45
|
+
gain nothing from a second lane), mixes the audio once while the frames
|
|
46
|
+
render, joins each range as soon as the ones before it are done (into
|
|
47
|
+
`stream` when given) and reports progress by frames drawn.
|
|
48
|
+
`createSegmentJoiner` is the incremental join underneath.
|
|
29
49
|
- **Audio**: `WebAudioPlayer` drives playback through the Web Audio API;
|
|
30
50
|
`mixAudio` and `encodeWav` (also on the `@motionscript/browser/audio`
|
|
31
|
-
subpath, which skips
|
|
32
|
-
- **
|
|
33
|
-
|
|
51
|
+
subpath, which skips the renderer) mix down offline.
|
|
52
|
+
- **Assets**: `setAssetByteSource` lets a host answer for an asset's bytes (a file
|
|
53
|
+
the user just chose, say) before the renderer's storage goes to the network; it
|
|
54
|
+
applies to previews, exports and stills alike. `loadAssetBytes` reads through it.
|
|
55
|
+
- **Source-string nodes**: `createBrowserEngine({ nodes })` also accepts TS source
|
|
56
|
+
strings (array form only), each default-exporting a component (`component2d({ key })`),
|
|
57
|
+
compiled with `esbuild-wasm` on first use. A script is written with calls: JSX
|
|
58
|
+
neither compiles nor links. `dynamicNodes` overrides the SDK, extra importable
|
|
59
|
+
`modules` or the compiler, each field defaulting on its own.
|
|
34
60
|
- **Clock**: `WebTicker` synchronizes scene playback to `requestAnimationFrame` while calculating dt from audio context to ensure audio and animation line up.
|
|
35
|
-
- **
|
|
36
|
-
|
|
61
|
+
- **Renderer**: `isWgpuSupported`, `onWgpuEvent` (device loss and recovery), and
|
|
62
|
+
the WGSL shader tools `ShaderPreview`, `validateShader` and `WGSL_PRELUDE`, from
|
|
63
|
+
`@motionscript/renderer`.
|
|
37
64
|
|
|
38
65
|
## Usage
|
|
39
66
|
|
|
40
67
|
```bash
|
|
41
|
-
npm install @motionscript/browser @motionscript/core
|
|
68
|
+
npm install @motionscript/browser @motionscript/core
|
|
42
69
|
```
|
|
43
70
|
|
|
44
71
|
```ts
|
|
45
72
|
import { createBrowserEngine } from '@motionscript/browser';
|
|
46
73
|
|
|
47
|
-
const engine = await createBrowserEngine({
|
|
74
|
+
const engine = await createBrowserEngine({ nodes: [MyNode] });
|
|
48
75
|
const session = engine.open({ document, target: canvasEl });
|
|
49
76
|
session.playback!.play();
|
|
50
77
|
|
|
51
78
|
const mp4 = await session.export();
|
|
52
79
|
```
|
|
53
80
|
|
|
54
|
-
|
|
55
|
-
its URL as `
|
|
81
|
+
The renderer's `ms_renderer_bg.wasm` resolves beside its module, which a bundler
|
|
82
|
+
handles; elsewhere serve it and pass its URL as `rendererWasmUrl` (every entry
|
|
83
|
+
that draws takes it). `session.export()` resolves to the MP4 bytes unless
|
|
84
|
+
`encode: { download: true }` asks for a browser download; `encode: { format }`
|
|
85
|
+
picks another format (`'webm'`, or `'wav'`, `'mp3'` or `'m4a'` for audio alone).
|
|
86
|
+
|
|
87
|
+
## Render issues and GPU faults
|
|
88
|
+
|
|
89
|
+
What the renderer drew but not as the document says (a feature it lacks, a shader
|
|
90
|
+
that does not compile, a lost GPU device) is a typed `RenderIssue`: a session
|
|
91
|
+
lists it in `buildErrors`, and `exportVideo`, `exportVideoParallel`,
|
|
92
|
+
`session.export()`, `session.image()` and `StillRenderer.render` hand it to
|
|
93
|
+
`onIssue`. A lost device or a crashed backend fails those instead with a
|
|
94
|
+
`RenderBackendError` (from `@motionscript/core`; `retryable` when the backend
|
|
95
|
+
recovered on a new device).
|
|
96
|
+
|
|
97
|
+
A shader stored in the retired SkSL language (`language: "sksl"`, from documents
|
|
98
|
+
written before WGSL was the only one) draws nothing and is reported as a `shader`
|
|
99
|
+
issue asking for a WGSL port.
|
|
100
|
+
|
|
101
|
+
## CDN build
|
|
102
|
+
|
|
103
|
+
`pnpm build` ends by writing `dist/browser/` (generated, never edited): one minified
|
|
104
|
+
ES module per `exports` entry (`index.js`, `audio.js`), shared and lazy chunks, `esbuild.wasm`, `ms_renderer_bg.wasm`, and a
|
|
105
|
+
`manifest.json` mapping each export and binary asset to a package-relative path.
|
|
106
|
+
The renderer is bundled in; the peers stay imports, so a host's import map names each
|
|
107
|
+
of these bare specifiers once, to one copy:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
@motionscript/core
|
|
111
|
+
@motionscript/core/sdk
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Against a CDN module URL the default `ms_renderer_bg.wasm` and `esbuild.wasm` URLs do
|
|
115
|
+
not resolve, so a host passes `rendererWasmUrl` and, if it compiles source-string nodes,
|
|
116
|
+
`compilerWasmUrl`. Both binaries are listed in the packages' manifests.
|
|
56
117
|
|
|
57
118
|
See the [docs](https://motionscript.dev/docs) for the full feature set and API
|
|
58
119
|
reference.
|
|
@@ -62,8 +123,19 @@ reference.
|
|
|
62
123
|
From the monorepo root:
|
|
63
124
|
|
|
64
125
|
```bash
|
|
65
|
-
pnpm --filter @motionscript/browser build
|
|
66
|
-
pnpm --filter @motionscript/browser test
|
|
126
|
+
pnpm --filter @motionscript/browser build # eslint, tsc, tsc-alias, then the CDN build
|
|
127
|
+
pnpm --filter @motionscript/browser test # vitest: real Chromium, plus a Node project
|
|
67
128
|
```
|
|
68
129
|
|
|
69
|
-
|
|
130
|
+
The tests run in Chromium on SwiftShader's WebGPU adapter through
|
|
131
|
+
`@vitest/browser-playwright` (headed with `HEADED=1`, which Linux needs, under
|
|
132
|
+
`xvfb-run`: a headless page there reads a WebGPU canvas back empty), so install it
|
|
133
|
+
once with `pnpm --filter @motionscript/browser exec playwright install --with-deps chromium`.
|
|
134
|
+
They import the **built** `dist/` of core and the renderer: run `pnpm build:lib` (Rust
|
|
135
|
+
needed) first on a fresh checkout. Files named `*.node.test.ts` run in Node and ask what a consumer's bundler
|
|
136
|
+
keeps of this package (`tree-shaking`, `cdn-build`). Suites that need an H.264 or AAC
|
|
137
|
+
encoder skip on a Chromium without one; `REQUIRE_ENCODERS=1` makes them fail instead.
|
|
138
|
+
|
|
139
|
+
See [CLAUDE.md](https://github.com/motionscript-dev/motionscript/blob/main/packages/browser/CLAUDE.md) for the traps when editing here,
|
|
140
|
+
[ARCHITECTURE.md](https://github.com/motionscript-dev/motionscript/blob/main/ARCHITECTURE.md) for the layering and
|
|
141
|
+
[CONTRIBUTING.md](https://github.com/motionscript-dev/motionscript/blob/main/CONTRIBUTING.md) for the workflow.
|
package/dist/asset-bytes.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Where a source URL's bytes
|
|
2
|
+
* Where a source URL's bytes come from: a host's local store, then the network.
|
|
3
|
+
* The renderer's storage adapter reads every asset through it (`loadBytes`).
|
|
3
4
|
*
|
|
4
5
|
* ## Why the web adapter needs this at all
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
+
* The storage adapter addresses every asset by URL and fetches it. That is
|
|
7
8
|
* right for an asset that lives somewhere, and wrong for one whose bytes the
|
|
8
9
|
* host already has in hand — a file the user has just chosen, a render a local
|
|
9
10
|
* model has just produced, a picture whose upload has not finished or cannot
|
|
@@ -16,9 +17,9 @@
|
|
|
16
17
|
*
|
|
17
18
|
* ## Why it is module-level
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* The storage adapter is constructed at several sites *inside* this package —
|
|
21
|
+
* sessions, the exporter, the audio mixer and the still renderer — none of
|
|
22
|
+
* which a host can reach. A constructor argument would
|
|
22
23
|
* therefore cover the preview and leave export and stills on the network,
|
|
23
24
|
* which is the worst of both: the picture a user sees would come from local
|
|
24
25
|
* bytes and the one they render would not.
|
|
@@ -47,4 +48,12 @@ export declare function setAssetByteSource(next: AssetByteSource | null): void;
|
|
|
47
48
|
* is what it would have done had the source never been installed.
|
|
48
49
|
*/
|
|
49
50
|
export declare function localAssetBytes(src: string): Promise<Blob | null>;
|
|
51
|
+
/**
|
|
52
|
+
* The network's bytes for `url`. A response that is not OK is a failed load,
|
|
53
|
+
* never bytes: a 404 page handed to the font manager marked a family loaded
|
|
54
|
+
* with no face in it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function fetchAssetBytes(url: string): Promise<Blob>;
|
|
57
|
+
/** The bytes for `src`: the host's local store first, then the network. */
|
|
58
|
+
export declare function loadAssetBytes(src: string): Promise<Blob>;
|
|
50
59
|
//# sourceMappingURL=asset-bytes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset-bytes.d.ts","sourceRoot":"","sources":["../src/asset-bytes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"asset-bytes.d.ts","sourceRoot":"","sources":["../src/asset-bytes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,oEAAoE;AACpE,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;AAIpE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAErE;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAOvE;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhE;AAED,2EAA2E;AAC3E,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/D"}
|
package/dist/asset-bytes.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Where a source URL's bytes
|
|
2
|
+
* Where a source URL's bytes come from: a host's local store, then the network.
|
|
3
|
+
* The renderer's storage adapter reads every asset through it (`loadBytes`).
|
|
3
4
|
*
|
|
4
5
|
* ## Why the web adapter needs this at all
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
+
* The storage adapter addresses every asset by URL and fetches it. That is
|
|
7
8
|
* right for an asset that lives somewhere, and wrong for one whose bytes the
|
|
8
9
|
* host already has in hand — a file the user has just chosen, a render a local
|
|
9
10
|
* model has just produced, a picture whose upload has not finished or cannot
|
|
@@ -16,9 +17,9 @@
|
|
|
16
17
|
*
|
|
17
18
|
* ## Why it is module-level
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* The storage adapter is constructed at several sites *inside* this package —
|
|
21
|
+
* sessions, the exporter, the audio mixer and the still renderer — none of
|
|
22
|
+
* which a host can reach. A constructor argument would
|
|
22
23
|
* therefore cover the preview and leave export and stills on the network,
|
|
23
24
|
* which is the worst of both: the picture a user sees would come from local
|
|
24
25
|
* bytes and the one they render would not.
|
|
@@ -57,4 +58,21 @@ export async function localAssetBytes(src) {
|
|
|
57
58
|
return null;
|
|
58
59
|
}
|
|
59
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* The network's bytes for `url`. A response that is not OK is a failed load,
|
|
63
|
+
* never bytes: a 404 page handed to the font manager marked a family loaded
|
|
64
|
+
* with no face in it.
|
|
65
|
+
*/
|
|
66
|
+
export async function fetchAssetBytes(url) {
|
|
67
|
+
const response = await fetch(url);
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
const status = response.statusText ? `${response.status} ${response.statusText}` : `${response.status}`;
|
|
70
|
+
throw new Error(`Fetching "${url}" failed: HTTP ${status}`);
|
|
71
|
+
}
|
|
72
|
+
return response.blob();
|
|
73
|
+
}
|
|
74
|
+
/** The bytes for `src`: the host's local store first, then the network. */
|
|
75
|
+
export async function loadAssetBytes(src) {
|
|
76
|
+
return (await localAssetBytes(src)) ?? fetchAssetBytes(src);
|
|
77
|
+
}
|
|
60
78
|
//# sourceMappingURL=asset-bytes.js.map
|
package/dist/asset-bytes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset-bytes.js","sourceRoot":"","sources":["../src/asset-bytes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"asset-bytes.js","sourceRoot":"","sources":["../src/asset-bytes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,IAAI,MAAM,GAA2B,IAAI,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAA4B;IAC3D,MAAM,GAAG,IAAI,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW;IAC7C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC;QACD,OAAO,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW;IAC7C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxG,MAAM,IAAI,KAAK,CAAC,aAAa,GAAG,kBAAkB,MAAM,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED,2EAA2E;AAC3E,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAW;IAC5C,OAAO,CAAC,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;AAChE,CAAC","sourcesContent":["/**\n * Where a source URL's bytes come from: a host's local store, then the network.\n * The renderer's storage adapter reads every asset through it (`loadBytes`).\n *\n * ## Why the web adapter needs this at all\n *\n * The storage adapter addresses every asset by URL and fetches it. That is\n * right for an asset that lives somewhere, and wrong for one whose bytes the\n * host already has in hand — a file the user has just chosen, a render a local\n * model has just produced, a picture whose upload has not finished or cannot\n * start because there is no network. In all three the adapter downloads bytes\n * that never needed to travel.\n *\n * `NodeStorageAdapter` has had the answer since it was written: an injected\n * `AssetLoader`, with an `inline` map consulted ahead of the disk. This is the\n * same seam for the browser.\n *\n * ## Why it is module-level\n *\n * The storage adapter is constructed at several sites *inside* this package —\n * sessions, the exporter, the audio mixer and the still renderer — none of\n * which a host can reach. A constructor argument would\n * therefore cover the preview and leave export and stills on the network,\n * which is the worst of both: the picture a user sees would come from local\n * bytes and the one they render would not.\n *\n * So this is an *injection point*, not a cache. The adapter still owns every\n * decode, every cache, every size ceiling and every eviction rule; all this\n * changes is where the compressed bytes came from. A source that answers `null`\n * — which is what an unregistered URL, an evicted entry or a host with no local\n * store does — leaves the adapter exactly as it was.\n */\n\n/** Local bytes for a source URL, or `null` to go to the network. */\nexport type AssetByteSource = (src: string) => Promise<Blob | null>;\n\nlet source: AssetByteSource | null = null;\n\n/**\n * Installs the byte source for this browsing context, or clears it with `null`.\n *\n * Called once per window that renders. Later calls replace the previous source\n * rather than stacking, because two sources disagreeing about one URL has no\n * sensible answer.\n */\nexport function setAssetByteSource(next: AssetByteSource | null): void {\n source = next;\n}\n\n/**\n * The bytes for `src`, or `null`.\n *\n * Swallows a throwing source on purpose. A host's local store failing is a\n * cache miss, not a render failure — the caller falls through to `fetch`, which\n * is what it would have done had the source never been installed.\n */\nexport async function localAssetBytes(src: string): Promise<Blob | null> {\n if (!source) return null;\n try {\n return await source(src);\n } catch {\n return null;\n }\n}\n\n/**\n * The network's bytes for `url`. A response that is not OK is a failed load,\n * never bytes: a 404 page handed to the font manager marked a family loaded\n * with no face in it.\n */\nexport async function fetchAssetBytes(url: string): Promise<Blob> {\n const response = await fetch(url);\n if (!response.ok) {\n const status = response.statusText ? `${response.status} ${response.statusText}` : `${response.status}`;\n throw new Error(`Fetching \"${url}\" failed: HTTP ${status}`);\n }\n return response.blob();\n}\n\n/** The bytes for `src`: the host's local store first, then the network. */\nexport async function loadAssetBytes(src: string): Promise<Blob> {\n return (await localAssetBytes(src)) ?? fetchAssetBytes(src);\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AudioBusStop } from "@motionscript/core";
|
|
2
2
|
/**
|
|
3
3
|
* The live chains for one audio context's buses.
|
|
4
4
|
*
|
|
@@ -23,9 +23,13 @@ export declare class AudioBusGraph {
|
|
|
23
23
|
* each stop after it is that bus's own parent. An empty or absent chain
|
|
24
24
|
* returns the destination, which is what every clip did before buses
|
|
25
25
|
* existed.
|
|
26
|
+
*
|
|
27
|
+
* `startTime` is the context time a new chain's schedule starts from, and
|
|
28
|
+
* `clipTime` the same instant in the stops' own seconds. A curve on a stop
|
|
29
|
+
* runs over its `startAt`–`endAt`, so the two are what place it.
|
|
26
30
|
*/
|
|
27
|
-
inputFor(bus: readonly AudioBusStop[] | undefined, startTime: number): AudioNode;
|
|
28
|
-
/** Disconnect every live bus node. Safe to call more than once. */
|
|
31
|
+
inputFor(bus: readonly AudioBusStop[] | undefined, startTime: number, clipTime: number): AudioNode;
|
|
32
|
+
/** Disconnect every live bus node, so the next {@link inputFor} builds afresh. Safe to call more than once. */
|
|
29
33
|
dispose(): void;
|
|
30
34
|
private readonly inputs;
|
|
31
35
|
private readonly nodes;
|
|
@@ -37,6 +41,11 @@ export declare class AudioBusGraph {
|
|
|
37
41
|
* Recursive rather than iterative because a bus's *output* has to exist
|
|
38
42
|
* before its own nodes can connect to it, and the outermost bus is the last
|
|
39
43
|
* entry.
|
|
44
|
+
*
|
|
45
|
+
* Reused by everything that changes what it sounds like, down to the master,
|
|
46
|
+
* not by id alone: a bus edited under a playing device, or one id on two
|
|
47
|
+
* tracks, is a different chain, and one built for the first would play the
|
|
48
|
+
* second through stale levels and a curve anchored to the wrong span.
|
|
40
49
|
*/
|
|
41
50
|
private chainFrom;
|
|
42
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bus-graph.d.ts","sourceRoot":"","sources":["../../src/audio/bus-graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"bus-graph.d.ts","sourceRoot":"","sources":["../../src/audio/bus-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,YAAY,EAAoB,MAAM,oBAAoB,CAAC;AAGrF;;;;;;;;GAQG;AACH,qBAAa,aAAa;IAElB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,WAAW;gBAFX,GAAG,EAAE,gBAAgB;IACtC,+EAA+E;IAC9D,WAAW,EAAE,SAAS;IAG3C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,GAAG,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS;IAKlG,+GAA+G;IAC/G,OAAO,IAAI,IAAI;IAYf,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwB;IAEpD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,SAAS;CAuCpB"}
|