codeboard-studio 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE +23 -0
- package/README.md +54 -0
- package/dist/src/animation/camera-plane.d.ts +8 -0
- package/dist/src/animation/camera-plane.d.ts.map +1 -0
- package/dist/src/animation/camera-plane.js +16 -0
- package/dist/src/animation/camera-plane.js.map +1 -0
- package/dist/src/animation/drawing-neighbors.d.ts +4 -0
- package/dist/src/animation/drawing-neighbors.d.ts.map +1 -0
- package/dist/src/animation/drawing-neighbors.js +38 -0
- package/dist/src/animation/drawing-neighbors.js.map +1 -0
- package/dist/src/animation/evaluate.d.ts +17 -0
- package/dist/src/animation/evaluate.d.ts.map +1 -0
- package/dist/src/animation/evaluate.js +70 -0
- package/dist/src/animation/evaluate.js.map +1 -0
- package/dist/src/animation/frame.d.ts +8 -0
- package/dist/src/animation/frame.d.ts.map +1 -0
- package/dist/src/animation/frame.js +16 -0
- package/dist/src/animation/frame.js.map +1 -0
- package/dist/src/animation/ik.d.ts +26 -0
- package/dist/src/animation/ik.d.ts.map +1 -0
- package/dist/src/animation/ik.js +47 -0
- package/dist/src/animation/ik.js.map +1 -0
- package/dist/src/animation/retime.d.ts +4 -0
- package/dist/src/animation/retime.d.ts.map +1 -0
- package/dist/src/animation/retime.js +116 -0
- package/dist/src/animation/retime.js.map +1 -0
- package/dist/src/audio/wav.d.ts +11 -0
- package/dist/src/audio/wav.d.ts.map +1 -0
- package/dist/src/audio/wav.js +58 -0
- package/dist/src/audio/wav.js.map +1 -0
- package/dist/src/authoring-runner.d.ts +2 -0
- package/dist/src/authoring-runner.d.ts.map +1 -0
- package/dist/src/authoring-runner.js +24 -0
- package/dist/src/authoring-runner.js.map +1 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +127 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/core/coordinates.d.ts +16 -0
- package/dist/src/core/coordinates.d.ts.map +1 -0
- package/dist/src/core/coordinates.js +48 -0
- package/dist/src/core/coordinates.js.map +1 -0
- package/dist/src/core/handles.d.ts +93 -0
- package/dist/src/core/handles.d.ts.map +1 -0
- package/dist/src/core/handles.js +190 -0
- package/dist/src/core/handles.js.map +1 -0
- package/dist/src/core/history.d.ts +14 -0
- package/dist/src/core/history.d.ts.map +1 -0
- package/dist/src/core/history.js +80 -0
- package/dist/src/core/history.js.map +1 -0
- package/dist/src/core/inspection.d.ts +51 -0
- package/dist/src/core/inspection.d.ts.map +1 -0
- package/dist/src/core/inspection.js +72 -0
- package/dist/src/core/inspection.js.map +1 -0
- package/dist/src/core/production.d.ts +208 -0
- package/dist/src/core/production.d.ts.map +1 -0
- package/dist/src/core/production.js +894 -0
- package/dist/src/core/production.js.map +1 -0
- package/dist/src/core/project.d.ts +146 -0
- package/dist/src/core/project.d.ts.map +1 -0
- package/dist/src/core/project.js +700 -0
- package/dist/src/core/project.js.map +1 -0
- package/dist/src/drawing/brush-authoring.d.ts +6 -0
- package/dist/src/drawing/brush-authoring.d.ts.map +1 -0
- package/dist/src/drawing/brush-authoring.js +12 -0
- package/dist/src/drawing/brush-authoring.js.map +1 -0
- package/dist/src/drawing/brushes.d.ts +157 -0
- package/dist/src/drawing/brushes.d.ts.map +1 -0
- package/dist/src/drawing/brushes.js +50 -0
- package/dist/src/drawing/brushes.js.map +1 -0
- package/dist/src/drawing/color.d.ts +5 -0
- package/dist/src/drawing/color.d.ts.map +1 -0
- package/dist/src/drawing/color.js +63 -0
- package/dist/src/drawing/color.js.map +1 -0
- package/dist/src/drawing/curves.d.ts +27 -0
- package/dist/src/drawing/curves.d.ts.map +1 -0
- package/dist/src/drawing/curves.js +170 -0
- package/dist/src/drawing/curves.js.map +1 -0
- package/dist/src/drawing/math.d.ts +10 -0
- package/dist/src/drawing/math.d.ts.map +1 -0
- package/dist/src/drawing/math.js +40 -0
- package/dist/src/drawing/math.js.map +1 -0
- package/dist/src/drawing/path-geometry.d.ts +18 -0
- package/dist/src/drawing/path-geometry.d.ts.map +1 -0
- package/dist/src/drawing/path-geometry.js +115 -0
- package/dist/src/drawing/path-geometry.js.map +1 -0
- package/dist/src/drawing/path-sampling.d.ts +10 -0
- package/dist/src/drawing/path-sampling.d.ts.map +1 -0
- package/dist/src/drawing/path-sampling.js +64 -0
- package/dist/src/drawing/path-sampling.js.map +1 -0
- package/dist/src/drawing/path.d.ts +4 -0
- package/dist/src/drawing/path.d.ts.map +1 -0
- package/dist/src/drawing/path.js +27 -0
- package/dist/src/drawing/path.js.map +1 -0
- package/dist/src/drawing/pen-input.d.ts +5 -0
- package/dist/src/drawing/pen-input.d.ts.map +1 -0
- package/dist/src/drawing/pen-input.js +30 -0
- package/dist/src/drawing/pen-input.js.map +1 -0
- package/dist/src/drawing/pixel-selection.d.ts +23 -0
- package/dist/src/drawing/pixel-selection.d.ts.map +1 -0
- package/dist/src/drawing/pixel-selection.js +142 -0
- package/dist/src/drawing/pixel-selection.js.map +1 -0
- package/dist/src/drawing/pixels.d.ts +22 -0
- package/dist/src/drawing/pixels.d.ts.map +1 -0
- package/dist/src/drawing/pixels.js +79 -0
- package/dist/src/drawing/pixels.js.map +1 -0
- package/dist/src/drawing/resource-binary.d.ts +23 -0
- package/dist/src/drawing/resource-binary.d.ts.map +1 -0
- package/dist/src/drawing/resource-binary.js +135 -0
- package/dist/src/drawing/resource-binary.js.map +1 -0
- package/dist/src/drawing/resources.d.ts +51 -0
- package/dist/src/drawing/resources.d.ts.map +1 -0
- package/dist/src/drawing/resources.js +239 -0
- package/dist/src/drawing/resources.js.map +1 -0
- package/dist/src/drawing/stroke-outline.d.ts +5 -0
- package/dist/src/drawing/stroke-outline.d.ts.map +1 -0
- package/dist/src/drawing/stroke-outline.js +53 -0
- package/dist/src/drawing/stroke-outline.js.map +1 -0
- package/dist/src/drawing/swatch.d.ts +6 -0
- package/dist/src/drawing/swatch.d.ts.map +1 -0
- package/dist/src/drawing/swatch.js +15 -0
- package/dist/src/drawing/swatch.js.map +1 -0
- package/dist/src/export/animatic-export.d.ts +11 -0
- package/dist/src/export/animatic-export.d.ts.map +1 -0
- package/dist/src/export/animatic-export.js +52 -0
- package/dist/src/export/animatic-export.js.map +1 -0
- package/dist/src/export/movie-export.d.ts +16 -0
- package/dist/src/export/movie-export.d.ts.map +1 -0
- package/dist/src/export/movie-export.js +108 -0
- package/dist/src/export/movie-export.js.map +1 -0
- package/dist/src/export/sheet-layout.d.ts +27 -0
- package/dist/src/export/sheet-layout.d.ts.map +1 -0
- package/dist/src/export/sheet-layout.js +72 -0
- package/dist/src/export/sheet-layout.js.map +1 -0
- package/dist/src/export/storyboard-export.d.ts +8 -0
- package/dist/src/export/storyboard-export.d.ts.map +1 -0
- package/dist/src/export/storyboard-export.js +76 -0
- package/dist/src/export/storyboard-export.js.map +1 -0
- package/dist/src/index.d.ts +36 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +27 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/model/query.d.ts +6 -0
- package/dist/src/model/query.d.ts.map +1 -0
- package/dist/src/model/query.js +7 -0
- package/dist/src/model/query.js.map +1 -0
- package/dist/src/model/schema.d.ts +754 -0
- package/dist/src/model/schema.d.ts.map +1 -0
- package/dist/src/model/schema.js +205 -0
- package/dist/src/model/schema.js.map +1 -0
- package/dist/src/model/types.d.ts +537 -0
- package/dist/src/model/types.d.ts.map +1 -0
- package/dist/src/model/types.js +8 -0
- package/dist/src/model/types.js.map +1 -0
- package/dist/src/model/validate.d.ts +12 -0
- package/dist/src/model/validate.d.ts.map +1 -0
- package/dist/src/model/validate.js +183 -0
- package/dist/src/model/validate.js.map +1 -0
- package/dist/src/preview/server.d.ts +6 -0
- package/dist/src/preview/server.d.ts.map +1 -0
- package/dist/src/preview/server.js +71 -0
- package/dist/src/preview/server.js.map +1 -0
- package/dist/src/render/annotations.d.ts +4 -0
- package/dist/src/render/annotations.d.ts.map +1 -0
- package/dist/src/render/annotations.js +27 -0
- package/dist/src/render/annotations.js.map +1 -0
- package/dist/src/render/brush-engine.d.ts +14 -0
- package/dist/src/render/brush-engine.d.ts.map +1 -0
- package/dist/src/render/brush-engine.js +230 -0
- package/dist/src/render/brush-engine.js.map +1 -0
- package/dist/src/render/layer-compositor.d.ts +33 -0
- package/dist/src/render/layer-compositor.d.ts.map +1 -0
- package/dist/src/render/layer-compositor.js +296 -0
- package/dist/src/render/layer-compositor.js.map +1 -0
- package/dist/src/render/panel-renderer.d.ts +33 -0
- package/dist/src/render/panel-renderer.d.ts.map +1 -0
- package/dist/src/render/panel-renderer.js +118 -0
- package/dist/src/render/panel-renderer.js.map +1 -0
- package/dist/src/render/png.d.ts +4 -0
- package/dist/src/render/png.d.ts.map +1 -0
- package/dist/src/render/png.js +10 -0
- package/dist/src/render/png.js.map +1 -0
- package/dist/src/render/review.d.ts +42 -0
- package/dist/src/render/review.d.ts.map +1 -0
- package/dist/src/render/review.js +192 -0
- package/dist/src/render/review.js.map +1 -0
- package/dist/src/render/vector-renderer.d.ts +5 -0
- package/dist/src/render/vector-renderer.d.ts.map +1 -0
- package/dist/src/render/vector-renderer.js +98 -0
- package/dist/src/render/vector-renderer.js.map +1 -0
- package/dist/src/starter.d.ts +2 -0
- package/dist/src/starter.d.ts.map +1 -0
- package/dist/src/starter.js +23 -0
- package/dist/src/starter.js.map +1 -0
- package/dist/src/storage/codec.d.ts +20 -0
- package/dist/src/storage/codec.d.ts.map +1 -0
- package/dist/src/storage/codec.js +203 -0
- package/dist/src/storage/codec.js.map +1 -0
- package/dist/src/storage/store.d.ts +89 -0
- package/dist/src/storage/store.d.ts.map +1 -0
- package/dist/src/storage/store.js +392 -0
- package/dist/src/storage/store.js.map +1 -0
- package/dist/src/updates.d.ts +10 -0
- package/dist/src/updates.d.ts.map +1 -0
- package/dist/src/updates.js +134 -0
- package/dist/src/updates.js.map +1 -0
- package/package.json +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nonomnonom and Codeboard contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Codeboard — MIT-licensed implementation.
|
|
2
|
+
|
|
3
|
+
Runtime dependencies:
|
|
4
|
+
- skia-canvas: MIT
|
|
5
|
+
- sharp: Apache-2.0 (bundled libvips and codecs carry their own notices)
|
|
6
|
+
- commander: MIT
|
|
7
|
+
- zod: MIT
|
|
8
|
+
- fflate: MIT
|
|
9
|
+
- fast-xml-parser: MIT
|
|
10
|
+
- SQLite through Node.js: SQLite is public domain; see Node distribution notices.
|
|
11
|
+
|
|
12
|
+
Skia uses a BSD-style license and bundled third-party notices. Consult installed
|
|
13
|
+
dependency distributions and https://skia.org/docs/user/license/.
|
|
14
|
+
FFmpeg is external and is not bundled; the installed FFmpeg build determines
|
|
15
|
+
its applicable LGPL/GPL notices and codecs.
|
|
16
|
+
|
|
17
|
+
Original example artwork, synthesized audio, and torn-feather bitmap tip are
|
|
18
|
+
dedicated to the public domain under CC0-1.0. Example source code is MIT.
|
|
19
|
+
https://creativecommons.org/publicdomain/zero/1.0/
|
|
20
|
+
|
|
21
|
+
No Toon Boom assets, Photoshop brushes, GIMP brushes, or Krita resources are
|
|
22
|
+
included in the npm distribution. Third-party files under ignored tmp/ were
|
|
23
|
+
used only for import evaluation; their redistribution rights are not assumed.
|
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Codeboard
|
|
2
|
+
|
|
3
|
+
**Draw with code. Keep the artwork editable. Render the film.**
|
|
4
|
+
|
|
5
|
+
Codeboard is a JavaScript/TypeScript toolkit for drawing, storyboards, and 2D animation. Your coding agent creates the artwork, renders it for review, and makes targeted revisions through code.
|
|
6
|
+
|
|
7
|
+
The [agent skills](docs/agent-plugin.md) guide drawing, brushes, storyboards, animation, camera, audio, revision, review, and debugging. Install the plugin in Codex or Claude Code, or copy the complete skill folders into another compatible Agent Skills host. The source and bundled offline reference live under `plugin/`.
|
|
8
|
+
|
|
9
|
+
[Website](https://codeboard.nonom.xyz) · [Documentation](https://codeboard.nonom.xyz/docs/) · [Examples](https://codeboard.nonom.xyz/examples/) · [GitHub Releases](https://github.com/nonomnonom/codeboard/releases/latest)
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
macOS or Linux:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
curl -fsSL https://codeboard.nonom.xyz/install.sh | sh
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Windows, in 64-bit PowerShell:
|
|
20
|
+
|
|
21
|
+
```powershell
|
|
22
|
+
& ([scriptblock]::Create((Invoke-RestMethod https://codeboard.nonom.xyz/install.ps1)))
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The installer downloads a GitHub release, verifies its checksum, and sets up the `codeboard` command. Node is included; no npm account is required. [Supported systems and installation options](docs/install.md).
|
|
26
|
+
|
|
27
|
+
## Draw something
|
|
28
|
+
|
|
29
|
+
Open a new terminal in your working folder:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
codeboard init
|
|
33
|
+
codeboard run scene.mjs
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Open `output/first.png` to see the stroke. `output/first.cboard` keeps the editable project. Change the script and run it again, or [reopen and revise the saved artwork](docs/projects.md).
|
|
37
|
+
|
|
38
|
+
## Create and revise
|
|
39
|
+
|
|
40
|
+
- [Draw](docs/drawing.md) with pressure-sensitive paint, vector contours, and pixel surfaces.
|
|
41
|
+
- [Make brushes](docs/brushes.md) using your own tips or supported external resources.
|
|
42
|
+
- [Animate](docs/animation.md) with drawing substitutions, holds, keyframes, and camera motion.
|
|
43
|
+
- [Review](docs/review.md) exact frames, detail crops, sheets, and layer-specific onion skins.
|
|
44
|
+
- [Export](docs/export.md) PNGs, storyboard PDFs, and movies with audio. MP4 export requires FFmpeg.
|
|
45
|
+
|
|
46
|
+
[](https://codeboard.nonom.xyz/docs/code-board-demo/)
|
|
47
|
+
|
|
48
|
+
**The Codeboard demo** follows Clawd through a walk, pause, hop and landing. [Run the example](docs/code-board-demo.md), inspect its onion skins, and revise a drawing hold. Download either the eight-second study or the complete 48-second demo, then run it with the installed `codeboard` CLI. Both use the public API; no engine build is needed. See [all runnable examples](examples/README.md).
|
|
49
|
+
|
|
50
|
+
## Contribute
|
|
51
|
+
|
|
52
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for building from source and running tests. Report reproducible problems through [GitHub Issues](https://github.com/nonomnonom/codeboard/issues), and security vulnerabilities through [SECURITY.md](SECURITY.md).
|
|
53
|
+
|
|
54
|
+
Code: [MIT](LICENSE). The Last Light and Lengkap original artwork and audio: CC0-1.0. The Clawd demo does not assert ownership of third-party character branding. Dependencies and imported resources have their own licenses; see [NOTICE](NOTICE).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { EvaluatedCamera } from './evaluate.js';
|
|
2
|
+
export declare function cameraPlane(camera: EvaluatedCamera, depth: number, width: number, height: number): {
|
|
3
|
+
zoom: number;
|
|
4
|
+
panX: number;
|
|
5
|
+
panY: number;
|
|
6
|
+
matrix: import("../index.ts").AffineMatrix;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=camera-plane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"camera-plane.d.ts","sourceRoot":"","sources":["../../../src/animation/camera-plane.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAGnD,wBAAgB,WAAW,CAAC,MAAM,EAAC,eAAe,EAAC,KAAK,EAAC,MAAM,EAAC,KAAK,EAAC,MAAM,EAAC,MAAM,EAAC,MAAM;;;;;EAWzF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { matrixFromTransform, multiplyMatrices } from '../drawing/math.js';
|
|
2
|
+
export function cameraPlane(camera, depth, width, height) {
|
|
3
|
+
if (![camera.x, camera.y, camera.zoom, camera.rotation, depth, width, height].every(Number.isFinite) || camera.zoom <= 0 || depth <= 0)
|
|
4
|
+
throw new Error('Camera plane requires finite camera values and positive zoom/depth');
|
|
5
|
+
const zoom = Math.pow(camera.zoom, 1 / depth), panX = camera.x / depth, panY = camera.y / depth;
|
|
6
|
+
if (!Number.isFinite(zoom) || zoom <= 0 || !Number.isFinite(1 / zoom) || !Number.isFinite(panX) || !Number.isFinite(panY))
|
|
7
|
+
throw new Error('Camera/depth combination exceeds the supported numerical range; increase depth or reduce camera zoom/pan');
|
|
8
|
+
try {
|
|
9
|
+
const matrix = multiplyMatrices(matrixFromTransform({ x: width / 2, y: height / 2, rotation: -camera.rotation, scaleX: zoom, scaleY: zoom }), matrixFromTransform({ x: -width / 2 - panX, y: -height / 2 - panY }));
|
|
10
|
+
return { zoom, panX, panY, matrix };
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new Error('Camera plane transform exceeds the supported numerical range; increase depth or reduce camera zoom/pan');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=camera-plane.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"camera-plane.js","sourceRoot":"","sources":["../../../src/animation/camera-plane.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,mBAAmB,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAExE,MAAM,UAAU,WAAW,CAAC,MAAsB,EAAC,KAAY,EAAC,KAAY,EAAC,MAAa;IACzF,IAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAC,MAAM,CAAC,CAAC,EAAC,MAAM,CAAC,IAAI,EAAC,MAAM,CAAC,QAAQ,EAAC,KAAK,EAAC,KAAK,EAAC,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAE,MAAM,CAAC,IAAI,IAAE,CAAC,IAAE,KAAK,IAAE,CAAC;QAAC,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;IAC9M,MAAM,IAAI,GAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAC,CAAC,GAAC,KAAK,CAAC,EAAC,IAAI,GAAC,MAAM,CAAC,CAAC,GAAC,KAAK,EAAC,IAAI,GAAC,MAAM,CAAC,CAAC,GAAC,KAAK,CAAC;IACjF,IAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAE,IAAI,IAAE,CAAC,IAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAC,IAAI,CAAC,IAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAC,MAAM,IAAI,KAAK,CAAC,0GAA0G,CAAC,CAAC;IACzO,IAAG,CAAC;QACH,MAAM,MAAM,GAAC,gBAAgB,CAC5B,mBAAmB,CAAC,EAAC,CAAC,EAAC,KAAK,GAAC,CAAC,EAAC,CAAC,EAAC,MAAM,GAAC,CAAC,EAAC,QAAQ,EAAC,CAAC,MAAM,CAAC,QAAQ,EAAC,MAAM,EAAC,IAAI,EAAC,MAAM,EAAC,IAAI,EAAC,CAAC,EAC7F,mBAAmB,CAAC,EAAC,CAAC,EAAC,CAAC,KAAK,GAAC,CAAC,GAAC,IAAI,EAAC,CAAC,EAAC,CAAC,MAAM,GAAC,CAAC,GAAC,IAAI,EAAC,CAAC,CACvD,CAAC;QACF,OAAO,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,MAAM,EAAC,CAAC;IAChC,CAAC;IAAA,MAAK,CAAC;QAAA,MAAM,IAAI,KAAK,CAAC,wGAAwG,CAAC,CAAC;IAAA,CAAC;AACnI,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DrawingExposure, DrawingNeighbors } from '../model/types.js';
|
|
2
|
+
/** Inspect held drawings, clipped to the owning panel; no artwork is loaded or cloned. */
|
|
3
|
+
export declare function drawingNeighbors(keys: readonly DrawingExposure[], frame: number, start: number, end: number, skipBlank: boolean): DrawingNeighbors;
|
|
4
|
+
//# sourceMappingURL=drawing-neighbors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drawing-neighbors.d.ts","sourceRoot":"","sources":["../../../src/animation/drawing-neighbors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,eAAe,EAAiB,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AAIxF,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAAC,IAAI,EAAC,SAAS,eAAe,EAAE,EAAC,KAAK,EAAC,MAAM,EAAC,KAAK,EAAC,MAAM,EAAC,GAAG,EAAC,MAAM,EAAC,SAAS,EAAC,OAAO,GAAE,gBAAgB,CAuBxI"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { assertRenderFrame } from './frame.js';
|
|
2
|
+
import { evaluateDrawing } from './evaluate.js';
|
|
3
|
+
/** Inspect held drawings, clipped to the owning panel; no artwork is loaded or cloned. */
|
|
4
|
+
export function drawingNeighbors(keys, frame, start, end, skipBlank) {
|
|
5
|
+
assertRenderFrame(frame);
|
|
6
|
+
if (frame < start || frame >= end)
|
|
7
|
+
throw new Error(`Frame ${frame} is outside the drawing's panel interval [${start}, ${end})`);
|
|
8
|
+
if (typeof skipBlank !== 'boolean')
|
|
9
|
+
throw new Error('skipBlank must be boolean');
|
|
10
|
+
let previous = null, current = null, next = null;
|
|
11
|
+
let runStart = start;
|
|
12
|
+
let drawingId = evaluateDrawing(keys, start) ?? null;
|
|
13
|
+
const visit = (endFrame) => {
|
|
14
|
+
const interval = { startFrame: runStart, endFrame, drawingId };
|
|
15
|
+
if (frame >= runStart && frame < endFrame)
|
|
16
|
+
current = interval;
|
|
17
|
+
else if (!skipBlank || drawingId !== null) {
|
|
18
|
+
if (endFrame <= frame)
|
|
19
|
+
previous = interval;
|
|
20
|
+
else if (runStart > frame && next === null)
|
|
21
|
+
next = interval;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
for (const key of keys) {
|
|
25
|
+
if (key.frame <= start)
|
|
26
|
+
continue;
|
|
27
|
+
if (key.frame >= end)
|
|
28
|
+
break;
|
|
29
|
+
if (key.drawingId === drawingId)
|
|
30
|
+
continue;
|
|
31
|
+
visit(key.frame);
|
|
32
|
+
runStart = key.frame;
|
|
33
|
+
drawingId = key.drawingId;
|
|
34
|
+
}
|
|
35
|
+
visit(end);
|
|
36
|
+
return { current: current, previous, next };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=drawing-neighbors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drawing-neighbors.js","sourceRoot":"","sources":["../../../src/animation/drawing-neighbors.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,iBAAiB,EAAC,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAE9C,0FAA0F;AAC1F,MAAM,UAAU,gBAAgB,CAAC,IAA+B,EAAC,KAAY,EAAC,KAAY,EAAC,GAAU,EAAC,SAAiB;IACtH,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACzB,IAAG,KAAK,GAAC,KAAK,IAAE,KAAK,IAAE,GAAG;QAAC,MAAM,IAAI,KAAK,CAAC,SAAS,KAAK,6CAA6C,KAAK,KAAK,GAAG,GAAG,CAAC,CAAC;IACxH,IAAG,OAAO,SAAS,KAAG,SAAS;QAAC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC7E,IAAI,QAAQ,GAAsB,IAAI,EAAC,OAAO,GAAsB,IAAI,EAAC,IAAI,GAAsB,IAAI,CAAC;IACxG,IAAI,QAAQ,GAAC,KAAK,CAAC;IACnB,IAAI,SAAS,GAAa,eAAe,CAAC,IAAI,EAAC,KAAK,CAAC,IAAE,IAAI,CAAC;IAC5D,MAAM,KAAK,GAAC,CAAC,QAAe,EAAC,EAAE;QAC9B,MAAM,QAAQ,GAAC,EAAC,UAAU,EAAC,QAAQ,EAAC,QAAQ,EAAC,SAAS,EAAC,CAAC;QACxD,IAAG,KAAK,IAAE,QAAQ,IAAE,KAAK,GAAC,QAAQ;YAAC,OAAO,GAAC,QAAQ,CAAC;aAC/C,IAAG,CAAC,SAAS,IAAE,SAAS,KAAG,IAAI,EAAC,CAAC;YACrC,IAAG,QAAQ,IAAE,KAAK;gBAAC,QAAQ,GAAC,QAAQ,CAAC;iBAChC,IAAG,QAAQ,GAAC,KAAK,IAAE,IAAI,KAAG,IAAI;gBAAC,IAAI,GAAC,QAAQ,CAAC;QACnD,CAAC;IACF,CAAC,CAAC;IACF,KAAI,MAAM,GAAG,IAAI,IAAI,EAAC,CAAC;QACtB,IAAG,GAAG,CAAC,KAAK,IAAE,KAAK;YAAC,SAAS;QAC7B,IAAG,GAAG,CAAC,KAAK,IAAE,GAAG;YAAC,MAAM;QACxB,IAAG,GAAG,CAAC,SAAS,KAAG,SAAS;YAAC,SAAS;QACtC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAAA,QAAQ,GAAC,GAAG,CAAC,KAAK,CAAC;QAAA,SAAS,GAAC,GAAG,CAAC,SAAS,CAAC;IAC7D,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,CAAC;IACX,OAAO,EAAC,OAAO,EAAC,OAAQ,EAAC,QAAQ,EAAC,IAAI,EAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CameraKeyframe, Layer, Transform, DrawingExposure } from "../model/types.js";
|
|
2
|
+
/** Undefined is an ordinary group; null is a blank exposure. Keys are sorted on authoring. */
|
|
3
|
+
export declare function evaluateDrawing(sequence: readonly DrawingExposure[] | undefined, frame: number): string | null | undefined;
|
|
4
|
+
export interface EvaluatedLayerState {
|
|
5
|
+
transform: Transform;
|
|
6
|
+
opacity: number;
|
|
7
|
+
depth: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function evaluateLayer(layer: Layer, frame: number): EvaluatedLayerState;
|
|
10
|
+
export interface EvaluatedCamera {
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
zoom: number;
|
|
14
|
+
rotation: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function evaluateCamera(keyframes: readonly CameraKeyframe[], frame: number): EvaluatedCamera;
|
|
17
|
+
//# sourceMappingURL=evaluate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../../src/animation/evaluate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,EAAuC,MAAM,mBAAmB,CAAC;AAIhI,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,QAAQ,EAAC,SAAS,eAAe,EAAE,GAAC,SAAS,EAAC,KAAK,EAAC,MAAM,GAAE,MAAM,GAAC,IAAI,GAAC,SAAS,CAKhH;AA8BD,MAAM,WAAW,mBAAmB;IAAG,SAAS,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAC,MAAM,CAAA;CAAE;AAE5F,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,mBAAmB,CAY9E;AAED,MAAM,WAAW,eAAe;IAAG,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AAEzF,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,CAGnG"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const mix = (a, b, t) => a + (b - a) * t;
|
|
2
|
+
/** Undefined is an ordinary group; null is a blank exposure. Keys are sorted on authoring. */
|
|
3
|
+
export function evaluateDrawing(sequence, frame) {
|
|
4
|
+
if (sequence === undefined)
|
|
5
|
+
return undefined;
|
|
6
|
+
let low = 0, high = sequence.length;
|
|
7
|
+
while (low < high) {
|
|
8
|
+
const middle = (low + high) >>> 1;
|
|
9
|
+
if (sequence[middle].frame <= frame)
|
|
10
|
+
low = middle + 1;
|
|
11
|
+
else
|
|
12
|
+
high = middle;
|
|
13
|
+
}
|
|
14
|
+
return low ? sequence[low - 1].drawingId : null;
|
|
15
|
+
}
|
|
16
|
+
function ease(t, easing) {
|
|
17
|
+
if (easing === "hold")
|
|
18
|
+
return 0;
|
|
19
|
+
if (easing === "linear")
|
|
20
|
+
return t;
|
|
21
|
+
if (easing === "ease-in-out")
|
|
22
|
+
return t * t * (3 - 2 * t);
|
|
23
|
+
if (t <= 0)
|
|
24
|
+
return 0;
|
|
25
|
+
if (t >= 1)
|
|
26
|
+
return 1;
|
|
27
|
+
const cubic = (u, a, b) => 3 * (1 - u) * (1 - u) * u * a + 3 * (1 - u) * u * u * b + u * u * u;
|
|
28
|
+
// Time is the curve's x coordinate, not its parameter. Bisection also handles flat tangents.
|
|
29
|
+
let low = 0, high = 1;
|
|
30
|
+
for (let i = 0; i < 52; i++) {
|
|
31
|
+
const u = (low + high) / 2;
|
|
32
|
+
if (cubic(u, easing.x1, easing.x2) < t)
|
|
33
|
+
low = u;
|
|
34
|
+
else
|
|
35
|
+
high = u;
|
|
36
|
+
}
|
|
37
|
+
return cubic((low + high) / 2, easing.y1, easing.y2);
|
|
38
|
+
}
|
|
39
|
+
function propertyValue(keys, frame, value, easing, fallback) {
|
|
40
|
+
let before, after;
|
|
41
|
+
for (const key of keys) {
|
|
42
|
+
if (value(key) === undefined)
|
|
43
|
+
continue;
|
|
44
|
+
if (key.frame <= frame && (!before || key.frame > before.frame))
|
|
45
|
+
before = key;
|
|
46
|
+
if (key.frame >= frame && (!after || key.frame < after.frame))
|
|
47
|
+
after = key;
|
|
48
|
+
}
|
|
49
|
+
const a = before ?? after, b = after ?? before;
|
|
50
|
+
if (!a || !b)
|
|
51
|
+
return fallback;
|
|
52
|
+
if (a.frame === b.frame)
|
|
53
|
+
return value(a);
|
|
54
|
+
return mix(value(a), value(b), ease((frame - a.frame) / (b.frame - a.frame), easing(a)));
|
|
55
|
+
}
|
|
56
|
+
export function evaluateLayer(layer, frame) {
|
|
57
|
+
const property = (channel) => propertyValue(layer.keyframes, frame, key => channel === "opacity" || channel === "depth" ? key[channel] : key.transform[channel], key => key.channelEasing?.[channel] ?? key.easing, channel === "opacity" || channel === "depth" ? layer[channel] : layer.transform[channel]);
|
|
58
|
+
return {
|
|
59
|
+
transform: {
|
|
60
|
+
x: property("x"), y: property("y"), scaleX: property("scaleX"), scaleY: property("scaleY"), rotation: property("rotation"),
|
|
61
|
+
},
|
|
62
|
+
opacity: property("opacity"),
|
|
63
|
+
depth: property("depth"),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export function evaluateCamera(keyframes, frame) {
|
|
67
|
+
const property = (channel) => propertyValue(keyframes, frame, key => key[channel], key => key.channelEasing?.[channel] ?? key.easing, channel === "zoom" ? 1 : 0);
|
|
68
|
+
return { x: property("x"), y: property("y"), zoom: property("zoom"), rotation: property("rotation") };
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=evaluate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../../src/animation/evaluate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Panel } from "../model/types.js";
|
|
2
|
+
export declare function assertRenderFrame(frame: number): void;
|
|
3
|
+
export declare function selectFramePanels<T extends Pick<Panel, "startFrame" | "durationFrames" | "transition">>(source: readonly T[], frame: number): {
|
|
4
|
+
panel: T;
|
|
5
|
+
incoming: T | undefined;
|
|
6
|
+
progress: number;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=frame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../../src/animation/frame.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAE7C,wBAAgB,iBAAiB,CAAC,KAAK,EAAC,MAAM,GAAE,IAAI,CAEnD;AAED,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,IAAI,CAAC,KAAK,EAAC,YAAY,GAAC,gBAAgB,GAAC,YAAY,CAAC,EAAE,MAAM,EAAC,SAAS,CAAC,EAAE,EAAC,KAAK,EAAC,MAAM;;;;EASnI"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function assertRenderFrame(frame) {
|
|
2
|
+
if (!Number.isSafeInteger(frame) || frame < 0)
|
|
3
|
+
throw new Error("Render frame must be a nonnegative safe integer");
|
|
4
|
+
}
|
|
5
|
+
export function selectFramePanels(source, frame) {
|
|
6
|
+
assertRenderFrame(frame);
|
|
7
|
+
const panels = [...source].sort((a, b) => a.startFrame - b.startFrame);
|
|
8
|
+
const index = panels.findIndex(panel => frame >= panel.startFrame && frame < panel.startFrame + panel.durationFrames);
|
|
9
|
+
const panel = panels[index];
|
|
10
|
+
if (!panel)
|
|
11
|
+
throw new Error(`No panel is exposed at frame ${frame}`);
|
|
12
|
+
const transitionStart = panel.startFrame + panel.durationFrames - panel.transition.durationFrames;
|
|
13
|
+
const incoming = panel.transition.type !== "cut" && panel.transition.durationFrames > 0 && frame >= transitionStart ? panels[index + 1] : undefined;
|
|
14
|
+
return { panel, incoming, progress: incoming ? (frame - transitionStart + 1) / panel.transition.durationFrames : 0 };
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame.js","sourceRoot":"","sources":["../../../src/animation/frame.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAAC,KAAY;IAC5C,IAAG,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAE,KAAK,GAAC,CAAC;QAAC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;AAC9G,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAmE,MAAmB,EAAC,KAAY;IAClI,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACzB,MAAM,MAAM,GAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,EAAE,CAAA,CAAC,CAAC,UAAU,GAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAChE,MAAM,KAAK,GAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAA,EAAE,CAAA,KAAK,IAAE,KAAK,CAAC,UAAU,IAAE,KAAK,GAAC,KAAK,CAAC,UAAU,GAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAC1G,MAAM,KAAK,GAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1B,IAAG,CAAC,KAAK;QAAC,MAAM,IAAI,KAAK,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;IACnE,MAAM,eAAe,GAAC,KAAK,CAAC,UAAU,GAAC,KAAK,CAAC,cAAc,GAAC,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC;IAC5F,MAAM,QAAQ,GAAC,KAAK,CAAC,UAAU,CAAC,IAAI,KAAG,KAAK,IAAE,KAAK,CAAC,UAAU,CAAC,cAAc,GAAC,CAAC,IAAE,KAAK,IAAE,eAAe,CAAA,CAAC,CAAA,MAAM,CAAC,KAAK,GAAC,CAAC,CAAC,CAAA,CAAC,CAAA,SAAS,CAAC;IAClI,OAAO,EAAC,KAAK,EAAC,QAAQ,EAAC,QAAQ,EAAC,QAAQ,CAAA,CAAC,CAAA,CAAC,KAAK,GAAC,eAAe,GAAC,CAAC,CAAC,GAAC,KAAK,CAAC,UAAU,CAAC,cAAc,CAAA,CAAC,CAAA,CAAC,EAAC,CAAC;AACxG,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { GroupLayer, Layer, TwoBoneRig } from '../model/types.js';
|
|
2
|
+
/** Check only rigs whose joints are affected, without copying artwork payloads. */
|
|
3
|
+
export declare function validateRigLayerChange(layers: readonly Layer[], proposed: Layer): void;
|
|
4
|
+
export interface TwoBoneSolution {
|
|
5
|
+
rootRotation: number;
|
|
6
|
+
elbowRotation: number;
|
|
7
|
+
elbow: {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
};
|
|
11
|
+
end: {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
};
|
|
15
|
+
reachable: boolean;
|
|
16
|
+
error: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function solveTwoBoneIK(origin: {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
}, target: {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
}, upperLength: number, lowerLength: number, bend?: 1 | -1): TwoBoneSolution;
|
|
25
|
+
export declare function validateTwoBoneRig(root: GroupLayer, rig: TwoBoneRig): GroupLayer;
|
|
26
|
+
//# sourceMappingURL=ik.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ik.d.ts","sourceRoot":"","sources":["../../../src/animation/ik.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAEnE,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,MAAM,EAAC,SAAS,KAAK,EAAE,EAAC,QAAQ,EAAC,KAAK,GAAE,IAAI,CASlF;AAED,MAAM,WAAW,eAAe;IAC/B,YAAY,EAAC,MAAM,CAAC;IAAC,aAAa,EAAC,MAAM,CAAC;IAC1C,KAAK,EAAC;QAAC,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAA;KAAC,CAAC;IAAC,GAAG,EAAC;QAAC,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAA;KAAC,CAAC;IAAC,SAAS,EAAC,OAAO,CAAC;IAAC,KAAK,EAAC,MAAM,CAAC;CACpF;AACD,wBAAgB,cAAc,CAAC,MAAM,EAAC;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,EAAC,MAAM,EAAC;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,EAAC,WAAW,EAAC,MAAM,EAAC,WAAW,EAAC,MAAM,EAAC,IAAI,GAAC,CAAC,GAAC,CAAC,CAAG,GAAE,eAAe,CActJ;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAC,UAAU,EAAC,GAAG,EAAC,UAAU,GAAE,UAAU,CAU5E"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Check only rigs whose joints are affected, without copying artwork payloads. */
|
|
2
|
+
export function validateRigLayerChange(layers, proposed) {
|
|
3
|
+
for (const layer of layers) {
|
|
4
|
+
if (layer.kind !== 'group')
|
|
5
|
+
continue;
|
|
6
|
+
const root = layer.id === proposed.id ? proposed : layer;
|
|
7
|
+
if (root.kind === 'group' && root.twoBoneRig && (root.id === proposed.id || root.twoBoneRig.elbowId === proposed.id)) {
|
|
8
|
+
validateTwoBoneRig({ ...root, children: root.children.map(child => child.id === proposed.id ? proposed : child) }, root.twoBoneRig);
|
|
9
|
+
}
|
|
10
|
+
validateRigLayerChange(layer.children, proposed);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function solveTwoBoneIK(origin, target, upperLength, lowerLength, bend = 1) {
|
|
14
|
+
if (![origin.x, origin.y, target.x, target.y, upperLength, lowerLength].every(Number.isFinite) || upperLength <= 0 || lowerLength <= 0 || (bend !== 1 && bend !== -1))
|
|
15
|
+
throw new Error('IK requires finite coordinates, positive lengths and bend +1 or -1');
|
|
16
|
+
const scale = Math.max(upperLength, lowerLength), minimum = Math.abs(upperLength - lowerLength), maximum = upperLength + lowerLength;
|
|
17
|
+
if (!Number.isFinite(maximum) || Math.min(upperLength, lowerLength) / scale < Number.EPSILON)
|
|
18
|
+
throw new Error('IK lengths exceed the supported numerical range');
|
|
19
|
+
const dx = target.x - origin.x, dy = target.y - origin.y, distance = Math.hypot(dx, dy);
|
|
20
|
+
if (!Number.isFinite(distance))
|
|
21
|
+
throw new Error('IK target offset exceeds the supported numerical range');
|
|
22
|
+
const reach = Math.max(minimum, Math.min(maximum, distance)), a = upperLength / scale, b = lowerLength / scale, d = reach / scale;
|
|
23
|
+
const elbowRotation = bend * Math.acos(Math.max(-1, Math.min(1, (d * d - a * a - b * b) / (2 * a * b))));
|
|
24
|
+
const direction = distance === 0 ? 0 : Math.atan2(dy, dx);
|
|
25
|
+
const rootRotation = reach === 0 ? direction : direction - Math.atan2(b * Math.sin(elbowRotation), a + b * Math.cos(elbowRotation));
|
|
26
|
+
const elbow = { x: origin.x + upperLength * Math.cos(rootRotation), y: origin.y + upperLength * Math.sin(rootRotation) };
|
|
27
|
+
const end = { x: elbow.x + lowerLength * Math.cos(rootRotation + elbowRotation), y: elbow.y + lowerLength * Math.sin(rootRotation + elbowRotation) };
|
|
28
|
+
if (![elbow.x, elbow.y, end.x, end.y].every(Number.isFinite))
|
|
29
|
+
throw new Error('IK result exceeds the supported numerical range');
|
|
30
|
+
return { rootRotation, elbowRotation, elbow, end, reachable: distance >= minimum && distance <= maximum, error: Math.hypot(end.x - target.x, end.y - target.y) };
|
|
31
|
+
}
|
|
32
|
+
export function validateTwoBoneRig(root, rig) {
|
|
33
|
+
solveTwoBoneIK({ x: 0, y: 0 }, { x: 0, y: 0 }, rig.upperLength, rig.lowerLength);
|
|
34
|
+
const elbow = root.children.find(child => child.id === rig.elbowId);
|
|
35
|
+
if (elbow?.kind !== 'group')
|
|
36
|
+
throw new Error(`Rig elbow must be an immediate child group: ${rig.elbowId}`);
|
|
37
|
+
if (root.drawingSequence !== undefined)
|
|
38
|
+
throw new Error('A two-bone rig root cannot select drawing alternatives');
|
|
39
|
+
for (const joint of [root, elbow]) {
|
|
40
|
+
if (joint.transform.scaleX !== 1 || joint.transform.scaleY !== 1 || joint.pivot?.x || joint.pivot?.y || joint.keyframes.some(key => key.transform.scaleX !== undefined || key.transform.scaleY !== undefined))
|
|
41
|
+
throw new Error('Two-bone joints require unit scale and origin pivots; scale an ancestor instead');
|
|
42
|
+
}
|
|
43
|
+
if (elbow.transform.x !== rig.upperLength || elbow.transform.y !== 0 || elbow.keyframes.some(key => key.transform.x !== undefined || key.transform.y !== undefined))
|
|
44
|
+
throw new Error('Rig elbow must stay at (upperLength, 0) in root coordinates');
|
|
45
|
+
return elbow;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=ik.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ik.js","sourceRoot":"","sources":["../../../src/animation/ik.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { StoryboardDocument } from "../model/types.js";
|
|
2
|
+
/** Frame positions are global; stroke point.time remains pen-input milliseconds. */
|
|
3
|
+
export declare function retimePanel(document: StoryboardDocument, panelId: string, duration: number): string[];
|
|
4
|
+
//# sourceMappingURL=retime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retime.d.ts","sourceRoot":"","sources":["../../../src/animation/retime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEnE,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAkFrG"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/** Frame positions are global; stroke point.time remains pen-input milliseconds. */
|
|
2
|
+
export function retimePanel(document, panelId, duration) {
|
|
3
|
+
const panel = document.panels.find(p => p.id === panelId);
|
|
4
|
+
if (!panel)
|
|
5
|
+
throw new Error(`Panel not found: ${panelId}`);
|
|
6
|
+
if (!Number.isSafeInteger(duration) || duration < 1)
|
|
7
|
+
throw new Error("Panel duration must be a positive safe integer frame count");
|
|
8
|
+
const oldDuration = panel.durationFrames;
|
|
9
|
+
const end = panel.startFrame + oldDuration;
|
|
10
|
+
const delta = duration - oldDuration;
|
|
11
|
+
if (!delta)
|
|
12
|
+
return [];
|
|
13
|
+
if (panel.transition.durationFrames >= duration)
|
|
14
|
+
throw new Error("Shortened panel would truncate its transition; revise the transition first");
|
|
15
|
+
const affected = new Set([panelId]);
|
|
16
|
+
const updates = [];
|
|
17
|
+
const safe = (frame) => {
|
|
18
|
+
if (!Number.isSafeInteger(frame) || frame < 0)
|
|
19
|
+
throw new Error("Retiming exceeds the safe integer frame range");
|
|
20
|
+
return frame;
|
|
21
|
+
};
|
|
22
|
+
for (const p of document.panels)
|
|
23
|
+
safe(p.id === panelId ? p.startFrame + duration : p.startFrame >= end ? safe(p.startFrame + delta) + p.durationFrames : p.startFrame + p.durationFrames);
|
|
24
|
+
const map = (frame) => {
|
|
25
|
+
if (frame < panel.startFrame)
|
|
26
|
+
return frame;
|
|
27
|
+
if (frame >= end)
|
|
28
|
+
return safe(frame + delta);
|
|
29
|
+
if (oldDuration === 1)
|
|
30
|
+
return panel.startFrame;
|
|
31
|
+
// Round the rational position without losing frame precision in the product.
|
|
32
|
+
const numerator = BigInt(frame - panel.startFrame) * BigInt(duration - 1), denominator = BigInt(oldDuration - 1);
|
|
33
|
+
return safe(panel.startFrame + Number((2n * numerator + denominator) / (2n * denominator)));
|
|
34
|
+
};
|
|
35
|
+
const keys = (entries) => {
|
|
36
|
+
const positions = new Set();
|
|
37
|
+
for (const key of entries) {
|
|
38
|
+
const frame = map(key.frame);
|
|
39
|
+
if (positions.has(frame))
|
|
40
|
+
throw new Error(`Retiming collapses keyframes at frame ${frame}; remove or move a keyframe first`);
|
|
41
|
+
positions.add(frame);
|
|
42
|
+
if (frame !== key.frame)
|
|
43
|
+
affected.add(key.id);
|
|
44
|
+
updates.push(() => { key.frame = frame; });
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const visit = (layers) => {
|
|
48
|
+
for (const layer of layers) {
|
|
49
|
+
keys(layer.keyframes);
|
|
50
|
+
if (layer.exposure) {
|
|
51
|
+
const exposure = layer.exposure, startFrame = map(exposure.startFrame), endFrame = map(exposure.endFrame);
|
|
52
|
+
if (endFrame <= startFrame)
|
|
53
|
+
throw new Error(`Retiming collapses drawing exposure ${layer.id}`);
|
|
54
|
+
updates.push(() => { exposure.startFrame = startFrame; exposure.endFrame = endFrame; });
|
|
55
|
+
}
|
|
56
|
+
if (layer.kind === "group") {
|
|
57
|
+
if (layer.drawingSequence) {
|
|
58
|
+
const positions = new Set();
|
|
59
|
+
for (const key of layer.drawingSequence) {
|
|
60
|
+
const frame = map(key.frame);
|
|
61
|
+
if (positions.has(frame))
|
|
62
|
+
throw new Error(`Retiming collapses drawing exposures in ${layer.id}; revise the drawing sequence first`);
|
|
63
|
+
positions.add(frame);
|
|
64
|
+
if (frame !== key.frame)
|
|
65
|
+
affected.add(layer.id);
|
|
66
|
+
updates.push(() => { key.frame = frame; });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
visit(layer.children);
|
|
70
|
+
}
|
|
71
|
+
else
|
|
72
|
+
for (const e of layer.elements)
|
|
73
|
+
if (e.kind === "raster-stroke" && e.reveal) {
|
|
74
|
+
const startFrame = map(e.reveal.startFrame), endFrame = map(e.reveal.endFrame);
|
|
75
|
+
if (endFrame <= startFrame)
|
|
76
|
+
throw new Error(`Retiming collapses stroke reveal ${e.id}`);
|
|
77
|
+
updates.push(() => { e.reveal = { startFrame, endFrame }; });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
for (const p of document.panels) {
|
|
82
|
+
if (p.startFrame >= end) {
|
|
83
|
+
const startFrame = map(p.startFrame);
|
|
84
|
+
updates.push(() => { p.startFrame = startFrame; });
|
|
85
|
+
affected.add(p.id);
|
|
86
|
+
}
|
|
87
|
+
visit(p.layers);
|
|
88
|
+
}
|
|
89
|
+
for (const shot of document.shots)
|
|
90
|
+
keys(shot.cameraKeyframes);
|
|
91
|
+
for (const track of document.audioTracks)
|
|
92
|
+
for (const clip of track.clips) {
|
|
93
|
+
// Sound is never time-stretched: later cues ripple, crossing ambience keeps its source duration.
|
|
94
|
+
if (clip.startFrame >= end) {
|
|
95
|
+
if (track.locked)
|
|
96
|
+
throw new Error(`Retiming would move a clip on locked audio track ${track.id}`);
|
|
97
|
+
const startFrame = map(clip.startFrame);
|
|
98
|
+
safe(startFrame + clip.durationFrames);
|
|
99
|
+
updates.push(() => { clip.startFrame = startFrame; });
|
|
100
|
+
affected.add(clip.id);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (const comment of document.comments)
|
|
104
|
+
if (comment.anchor.frame !== undefined) {
|
|
105
|
+
const frame = map(comment.anchor.frame);
|
|
106
|
+
updates.push(() => { comment.anchor.frame = frame; });
|
|
107
|
+
}
|
|
108
|
+
for (const update of updates)
|
|
109
|
+
update();
|
|
110
|
+
panel.durationFrames = duration;
|
|
111
|
+
for (const p of document.panels)
|
|
112
|
+
if (affected.has(p.id))
|
|
113
|
+
p.revision++;
|
|
114
|
+
return [...affected];
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=retime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retime.js","sourceRoot":"","sources":["../../../src/animation/retime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ToneOptions {
|
|
2
|
+
frequency?: number;
|
|
3
|
+
durationSeconds?: number;
|
|
4
|
+
sampleRate?: number;
|
|
5
|
+
volume?: number;
|
|
6
|
+
attackSeconds?: number;
|
|
7
|
+
releaseSeconds?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function encodeWav(channels: Float32Array[], sampleRate?: number): Buffer;
|
|
10
|
+
export declare function createToneWav(options?: ToneOptions): Buffer;
|
|
11
|
+
//# sourceMappingURL=wav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wav.d.ts","sourceRoot":"","sources":["../../../src/audio/wav.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,UAAU,SAAM,GAAE,MAAM,CAY3E;AAED,wBAAgB,aAAa,CAAC,OAAO,GAAE,WAAgB,GAAG,MAAM,CA4B/D"}
|