spine-html 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE.md +19 -0
- package/README.md +124 -0
- package/dist/DomTexture.d.ts +29 -0
- package/dist/DomTexture.d.ts.map +1 -0
- package/dist/DomTexture.js +52 -0
- package/dist/DomTexture.js.map +1 -0
- package/dist/SpineHtmlRenderer.d.ts +67 -0
- package/dist/SpineHtmlRenderer.d.ts.map +1 -0
- package/dist/SpineHtmlRenderer.js +306 -0
- package/dist/SpineHtmlRenderer.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 firejune (Joon Kyoung)
|
|
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.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
## Spine Runtimes
|
|
4
|
+
|
|
5
|
+
This project depends on `@esotericsoftware/spine-core`, part of the
|
|
6
|
+
[Spine Runtimes](https://github.com/EsotericSoftware/spine-runtimes),
|
|
7
|
+
Copyright (c) 2013-2025 Esoteric Software LLC, licensed under the
|
|
8
|
+
[Spine Runtimes License Agreement](https://esotericsoftware.com/spine-runtimes-license).
|
|
9
|
+
|
|
10
|
+
Key obligation that propagates to users of this project: integration of the Spine
|
|
11
|
+
Runtimes into software (including via this renderer) is permitted **provided that each
|
|
12
|
+
user of the resulting product obtains their own Spine Editor license**, and any
|
|
13
|
+
redistribution includes the Spine Runtimes license and copyright notice.
|
|
14
|
+
|
|
15
|
+
## Example assets
|
|
16
|
+
|
|
17
|
+
The spineboy skeleton, atlas, and images used by the demo are owned by Esoteric
|
|
18
|
+
Software. They are **not redistributed** in this repository; `scripts/fetch-assets.sh`
|
|
19
|
+
downloads them from the official spine-runtimes repository for local evaluation.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# spine-html
|
|
2
|
+
|
|
3
|
+
Render [Spine](https://esotericsoftware.com/) skeletal animations as **plain DOM** — one
|
|
4
|
+
absolutely-positioned `<img>` per slot, posed with a single CSS `matrix()` write per frame.
|
|
5
|
+
No canvas, no WebGL for the rigid tier.
|
|
6
|
+
|
|
7
|
+
## Why
|
|
8
|
+
|
|
9
|
+
Every Spine web runtime rasterizes into a canvas. But `spine-core` is fully
|
|
10
|
+
renderer-independent: it computes bone world transforms — and even deformed mesh
|
|
11
|
+
vertices — on the CPU. For **region attachments** (the rigid parts of a skeleton), a bone
|
|
12
|
+
transform is a plain affine map, and CSS `transform: matrix()` expresses that *exactly*.
|
|
13
|
+
So the rigid tier of a Spine skeleton can live in the DOM, composited by the browser,
|
|
14
|
+
inspectable in devtools, styled with CSS.
|
|
15
|
+
|
|
16
|
+
The idea has been floated on the official forum three times since 2014 and was never
|
|
17
|
+
built — the blockers named were meshes, clipping, and DOM update overhead. This project
|
|
18
|
+
is the experiment: how far does the DOM actually go, and how cheap is it?
|
|
19
|
+
|
|
20
|
+
Measured so far (PoC, Chromium on Apple silicon):
|
|
21
|
+
|
|
22
|
+
- Rigid only (spineboy-ess): 10 skeletons / 180 slot images at **~0.03 ms skeleton math
|
|
23
|
+
+ ~0.22 ms DOM writes per frame** — about 1.5% of a 60 fps frame budget.
|
|
24
|
+
- With meshes (spineboy-pro): 1 skeleton = **~0.05 ms + ~0.5 ms render** (8 mesh
|
|
25
|
+
canvases, 323 triangles); 10 running skeletons = **~4.4 ms/frame** total.
|
|
26
|
+
|
|
27
|
+
## Status
|
|
28
|
+
|
|
29
|
+
**Proof of concept.**
|
|
30
|
+
|
|
31
|
+
- ✅ Region attachments (rigid parts): exact affine mapping, draw-order via `z-index`,
|
|
32
|
+
attachment swaps, alpha
|
|
33
|
+
- ✅ Atlas unpacking at load time (90°-packed regions restored), so the rigid per-frame
|
|
34
|
+
path never touches a canvas
|
|
35
|
+
- ✅ Mesh attachments (deform tier): small per-part canvases sized to the mesh's world
|
|
36
|
+
bounds, interleaved with the rigid `<img>` slots in one stacking context — the DOM
|
|
37
|
+
handles the bones, a rasterizer handles the warps
|
|
38
|
+
- ✅ Blend modes via `mix-blend-mode` (additive = `plus-lighter`)
|
|
39
|
+
- ✅ Crack-free mesh seams on clip-antialiasing browsers (Safari): each triangle's
|
|
40
|
+
clip polygon is expanded 0.5px from its centroid so neighbours overlap — the
|
|
41
|
+
texture is continuous across shared edges, so the overlap is invisible
|
|
42
|
+
(`?expand=0` shows the cracks for comparison)
|
|
43
|
+
- ⬜ Clipping — deliberately unsupported (counted and skipped); layered transparent
|
|
44
|
+
parts + `overflow: hidden` cover the practical cases
|
|
45
|
+
- ⬜ RGB tinting (alpha works); DPR-aware mesh canvas backing store
|
|
46
|
+
- ⬜ WebKit mesh-canvas cost: Safari rasterizes the per-triangle path noticeably
|
|
47
|
+
slower than Chromium (measured ~7.6ms vs ~0.5ms per frame headless) — dirty-check
|
|
48
|
+
skipping and/or an optional WebGL blit backend are the candidates
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm i spine-html @esotericsoftware/spine-core
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { TextureAtlas, AtlasAttachmentLoader, SkeletonJson, Skeleton,
|
|
58
|
+
AnimationState, AnimationStateData, Physics } from '@esotericsoftware/spine-core';
|
|
59
|
+
import { SpineHtmlRenderer, DomTexture, unpackRegions } from 'spine-html';
|
|
60
|
+
|
|
61
|
+
// Load: parse the atlas, attach page images, unpack per-region bitmaps once.
|
|
62
|
+
const atlas = new TextureAtlas(atlasText);
|
|
63
|
+
const pageImages = new Map<string, HTMLImageElement>();
|
|
64
|
+
for (const page of atlas.pages) {
|
|
65
|
+
const image = await loadImage(page.name); // your loader
|
|
66
|
+
page.setTexture(new DomTexture(image));
|
|
67
|
+
pageImages.set(page.name, image);
|
|
68
|
+
}
|
|
69
|
+
const regionImages = await unpackRegions(atlas, pageImages);
|
|
70
|
+
const data = new SkeletonJson(new AtlasAttachmentLoader(atlas)).readSkeletonData(jsonText);
|
|
71
|
+
|
|
72
|
+
// A positioned element becomes the skeleton origin (Spine is Y-up: the
|
|
73
|
+
// skeleton grows upward from it).
|
|
74
|
+
const skeleton = new Skeleton(data);
|
|
75
|
+
const state = new AnimationState(new AnimationStateData(data));
|
|
76
|
+
state.setAnimation(0, 'walk', true);
|
|
77
|
+
const renderer = new SpineHtmlRenderer(rootElement, regionImages);
|
|
78
|
+
|
|
79
|
+
function frame(delta: number) {
|
|
80
|
+
state.update(delta);
|
|
81
|
+
state.apply(skeleton);
|
|
82
|
+
skeleton.update(delta);
|
|
83
|
+
skeleton.updateWorldTransform(Physics.update);
|
|
84
|
+
renderer.render(skeleton);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`spine-html` is a third-party renderer and is not affiliated with or endorsed by
|
|
89
|
+
Esoteric Software.
|
|
90
|
+
|
|
91
|
+
## Demo (this repository)
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
bun install
|
|
95
|
+
bun run dev
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The official spineboy example assets are downloaded automatically on first `dev`/`build`
|
|
99
|
+
(they are owned by Esoteric Software and not redistributed in this repository — see
|
|
100
|
+
[NOTICE.md](NOTICE.md)); `bun run fetch-assets` runs the same idempotent step manually.
|
|
101
|
+
|
|
102
|
+
## How it works
|
|
103
|
+
|
|
104
|
+
1. `@esotericsoftware/spine-core` loads the skeleton and drives `AnimationState`,
|
|
105
|
+
constraints, and physics — all CPU-side, renderer-agnostic.
|
|
106
|
+
2. At load time each atlas region is cut into its own bitmap (rotation restored), one
|
|
107
|
+
blob URL per region.
|
|
108
|
+
3. Per frame, for each slot in draw order: `computeWorldVertices` yields the region's
|
|
109
|
+
four corners in world space (order **BL, UL, UR, BR** — note the comments inside
|
|
110
|
+
`computeWorldVertices` are stale). Flip Y (Spine is Y-up), derive the affine from
|
|
111
|
+
three corners, write one `matrix()` string. That's the whole render path.
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
The code in this repository is MIT licensed.
|
|
116
|
+
|
|
117
|
+
It depends on the [Spine Runtimes](https://github.com/EsotericSoftware/spine-runtimes)
|
|
118
|
+
(`@esotericsoftware/spine-core`), which are licensed under the
|
|
119
|
+
[Spine Runtimes License](https://esotericsoftware.com/spine-runtimes-license):
|
|
120
|
+
**integrating the Spine Runtimes — including through this project — requires each user
|
|
121
|
+
to have their own valid Spine Editor license.** See [NOTICE.md](NOTICE.md).
|
|
122
|
+
|
|
123
|
+
Example assets (spineboy) are owned by Esoteric Software and are fetched from the
|
|
124
|
+
official repository at setup time, not redistributed here.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Texture, TextureAtlas, type TextureFilter, type TextureWrap } from '@esotericsoftware/spine-core';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal Texture implementation for the DOM renderer. spine-core only needs
|
|
4
|
+
* it as a handle attached to atlas pages; filtering/wrapping are GPU concepts
|
|
5
|
+
* with no DOM equivalent, so they are no-ops.
|
|
6
|
+
*/
|
|
7
|
+
export declare class DomTexture extends Texture {
|
|
8
|
+
setFilters(_minFilter: TextureFilter, _magFilter: TextureFilter): void;
|
|
9
|
+
setWraps(_uWrap: TextureWrap, _vWrap: TextureWrap): void;
|
|
10
|
+
dispose(): void;
|
|
11
|
+
}
|
|
12
|
+
export interface RegionImage {
|
|
13
|
+
/** Blob URL of the unpacked (rotation-restored) region pixels. */
|
|
14
|
+
url: string;
|
|
15
|
+
/** Unpacked width in atlas pixels. */
|
|
16
|
+
width: number;
|
|
17
|
+
/** Unpacked height in atlas pixels. */
|
|
18
|
+
height: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Cuts every atlas region out of the page image into its own bitmap once at
|
|
22
|
+
* load time, restoring 90° packing rotation, so the per-frame path never
|
|
23
|
+
* touches a canvas. Returns blob URLs keyed by region name.
|
|
24
|
+
*
|
|
25
|
+
* This is a loading-pipeline step, not a rendering step: after this runs,
|
|
26
|
+
* rendering is pure DOM (one <img> per slot, one CSS matrix write per frame).
|
|
27
|
+
*/
|
|
28
|
+
export declare function unpackRegions(atlas: TextureAtlas, pageImages: Map<string, HTMLImageElement>): Promise<Map<string, RegionImage>>;
|
|
29
|
+
//# sourceMappingURL=DomTexture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DomTexture.d.ts","sourceRoot":"","sources":["../src/DomTexture.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,YAAY,EAEZ,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAEtC;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,OAAO;IACrC,UAAU,CAAC,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,GAAG,IAAI;IACtE,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IACxD,OAAO,IAAI,IAAI;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,YAAY,EACnB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,GACxC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAiCnC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Texture, } from '@esotericsoftware/spine-core';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal Texture implementation for the DOM renderer. spine-core only needs
|
|
4
|
+
* it as a handle attached to atlas pages; filtering/wrapping are GPU concepts
|
|
5
|
+
* with no DOM equivalent, so they are no-ops.
|
|
6
|
+
*/
|
|
7
|
+
export class DomTexture extends Texture {
|
|
8
|
+
setFilters(_minFilter, _magFilter) { }
|
|
9
|
+
setWraps(_uWrap, _vWrap) { }
|
|
10
|
+
dispose() { }
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Cuts every atlas region out of the page image into its own bitmap once at
|
|
14
|
+
* load time, restoring 90° packing rotation, so the per-frame path never
|
|
15
|
+
* touches a canvas. Returns blob URLs keyed by region name.
|
|
16
|
+
*
|
|
17
|
+
* This is a loading-pipeline step, not a rendering step: after this runs,
|
|
18
|
+
* rendering is pure DOM (one <img> per slot, one CSS matrix write per frame).
|
|
19
|
+
*/
|
|
20
|
+
export async function unpackRegions(atlas, pageImages) {
|
|
21
|
+
const result = new Map();
|
|
22
|
+
for (const region of atlas.regions) {
|
|
23
|
+
const atlasRegion = region;
|
|
24
|
+
const image = pageImages.get(atlasRegion.page.name);
|
|
25
|
+
if (!image)
|
|
26
|
+
throw new Error(`Missing page image: ${atlasRegion.page.name}`);
|
|
27
|
+
const w = region.width;
|
|
28
|
+
const h = region.height;
|
|
29
|
+
const canvas = document.createElement('canvas');
|
|
30
|
+
canvas.width = w;
|
|
31
|
+
canvas.height = h;
|
|
32
|
+
const ctx = canvas.getContext('2d');
|
|
33
|
+
if (!ctx)
|
|
34
|
+
throw new Error('2d context unavailable');
|
|
35
|
+
if (region.degrees === 90) {
|
|
36
|
+
// The region is packed rotated: it occupies an h×w rect in the page.
|
|
37
|
+
// Rotate it back so the bitmap is in artwork orientation.
|
|
38
|
+
ctx.translate(0, h);
|
|
39
|
+
ctx.rotate(-Math.PI / 2);
|
|
40
|
+
ctx.drawImage(image, atlasRegion.x, atlasRegion.y, h, w, 0, 0, h, w);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
ctx.drawImage(image, atlasRegion.x, atlasRegion.y, w, h, 0, 0, w, h);
|
|
44
|
+
}
|
|
45
|
+
const blob = await new Promise((resolve, reject) => {
|
|
46
|
+
canvas.toBlob((b) => (b ? resolve(b) : reject(new Error('toBlob failed'))), 'image/png');
|
|
47
|
+
});
|
|
48
|
+
result.set(atlasRegion.name, { url: URL.createObjectURL(blob), width: w, height: h });
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=DomTexture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DomTexture.js","sourceRoot":"","sources":["../src/DomTexture.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,GAKR,MAAM,8BAA8B,CAAC;AAEtC;;;;GAIG;AACH,MAAM,OAAO,UAAW,SAAQ,OAAO;IACrC,UAAU,CAAC,UAAyB,EAAE,UAAyB,IAAS,CAAC;IACzE,QAAQ,CAAC,MAAmB,EAAE,MAAmB,IAAS,CAAC;IAC3D,OAAO,KAAU,CAAC;CACnB;AAWD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAmB,EACnB,UAAyC;IAEzC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;IAE9C,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QACnC,MAAM,WAAW,GAAG,MAA4B,CAAC;QACjD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAE5E,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC;QACvB,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;QACxB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;QACjB,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAClB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAEpD,IAAI,MAAM,CAAC,OAAO,KAAK,EAAE,EAAE,CAAC;YAC1B,qEAAqE;YACrE,0DAA0D;YAC1D,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpB,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACzB,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACvE,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACvD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QAC3F,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type Skeleton } from '@esotericsoftware/spine-core';
|
|
2
|
+
import type { RegionImage } from './DomTexture';
|
|
3
|
+
/**
|
|
4
|
+
* Renders a spine-core Skeleton as DOM, split by slot type:
|
|
5
|
+
*
|
|
6
|
+
* - Region attachments (rigid parts) become one absolutely-positioned <img>
|
|
7
|
+
* posed with a single CSS matrix() write per frame — exact, since bone
|
|
8
|
+
* transforms are affine.
|
|
9
|
+
* - Mesh attachments (deform parts) each get a small per-part <canvas> sized
|
|
10
|
+
* to the mesh's world bounding box, redrawn per frame with the standard
|
|
11
|
+
* per-triangle clip+transform+drawImage mapping.
|
|
12
|
+
*
|
|
13
|
+
* Both element kinds share one stacking context, so draw order interleaves
|
|
14
|
+
* freely via z-index (rear hair canvas < torso img < front hair canvas).
|
|
15
|
+
* Clipping attachments are deliberately unsupported (transparent layered
|
|
16
|
+
* parts make them unnecessary); they are counted in clipSkipCount.
|
|
17
|
+
*
|
|
18
|
+
* Coordinate mapping: Spine is Y-up, CSS is Y-down — world Y is negated.
|
|
19
|
+
* spine-core computes everything (bones, constraints, physics, deformed
|
|
20
|
+
* vertices) on the CPU; this class only draws.
|
|
21
|
+
*/
|
|
22
|
+
export declare class SpineHtmlRenderer {
|
|
23
|
+
private readonly root;
|
|
24
|
+
private readonly regionImages;
|
|
25
|
+
/** Clipping attachments encountered (visible but unsupported). */
|
|
26
|
+
clipSkipCount: number;
|
|
27
|
+
/** Mesh canvases drawn last frame. */
|
|
28
|
+
meshCount: number;
|
|
29
|
+
/** Triangles rasterized last frame. */
|
|
30
|
+
triangleCount: number;
|
|
31
|
+
/**
|
|
32
|
+
* How far (px) each triangle's clip polygon is expanded from its centroid.
|
|
33
|
+
* Closes antialiased-clip cracks between adjacent triangles (Safari);
|
|
34
|
+
* set to 0 to see them.
|
|
35
|
+
*/
|
|
36
|
+
triangleExpand: number;
|
|
37
|
+
private readonly views;
|
|
38
|
+
private meshVertices;
|
|
39
|
+
/**
|
|
40
|
+
* @param root Positioned element (e.g. position:absolute) that becomes the
|
|
41
|
+
* skeleton origin. The renderer only appends slot elements to it — layout
|
|
42
|
+
* and scaling of the root belong to the caller.
|
|
43
|
+
* @param regionImages Unpacked per-region bitmaps (for the rigid tier).
|
|
44
|
+
*/
|
|
45
|
+
constructor(root: HTMLElement, regionImages: Map<string, RegionImage>);
|
|
46
|
+
render(skeleton: Skeleton): void;
|
|
47
|
+
dispose(): void;
|
|
48
|
+
private renderRegion;
|
|
49
|
+
private renderMesh;
|
|
50
|
+
/**
|
|
51
|
+
* Standard canvas triangle texture mapping (same math as the official
|
|
52
|
+
* spine-canvas renderer): derive the affine that sends the triangle's
|
|
53
|
+
* texture-space corners to its screen-space corners, clip, draw the page.
|
|
54
|
+
*
|
|
55
|
+
* The clip polygon is expanded outward from the centroid by a fraction of
|
|
56
|
+
* a pixel. Browsers that antialias clip paths (Safari) otherwise leave
|
|
57
|
+
* hairline cracks between adjacent triangles; the expanded clips overlap
|
|
58
|
+
* into the neighbouring triangle, and since the texture is continuous
|
|
59
|
+
* across the shared edge the overlap draws the same pixels — cracks close
|
|
60
|
+
* with no visible cost. The texture-mapping affine itself stays exact.
|
|
61
|
+
*/
|
|
62
|
+
private drawTriangle;
|
|
63
|
+
private applyCommon;
|
|
64
|
+
private view;
|
|
65
|
+
private hide;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=SpineHtmlRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpineHtmlRenderer.d.ts","sourceRoot":"","sources":["../src/SpineHtmlRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,QAAQ,EAId,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAqChD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,iBAAiB;IAwB1B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAxB/B,kEAAkE;IAClE,aAAa,SAAK;IAClB,sCAAsC;IACtC,SAAS,SAAK;IACd,uCAAuC;IACvC,aAAa,SAAK;IAClB;;;;OAIG;IACH,cAAc,SAAO;IAErB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IACnD,OAAO,CAAC,YAAY,CAAyB;IAE7C;;;;;OAKG;gBAEgB,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC;IAGzD,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IA2BhC,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,YAAY;IA8CpB,OAAO,CAAC,UAAU;IAiFlB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,YAAY;IAwCpB,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,IAAI;IAiCZ,OAAO,CAAC,IAAI;CAOb"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { BlendMode, ClippingAttachment, MeshAttachment, RegionAttachment, } from '@esotericsoftware/spine-core';
|
|
2
|
+
const regionVertices = new Float32Array(8);
|
|
3
|
+
/** Push a point away from (cx, cy) by `amount` pixels. */
|
|
4
|
+
function expandPoint(x, y, cx, cy, amount) {
|
|
5
|
+
const dx = x - cx;
|
|
6
|
+
const dy = y - cy;
|
|
7
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
8
|
+
if (len < 1e-6)
|
|
9
|
+
return [x, y];
|
|
10
|
+
const s = amount / len;
|
|
11
|
+
return [x + dx * s, y + dy * s];
|
|
12
|
+
}
|
|
13
|
+
const BLEND_CSS = {
|
|
14
|
+
[BlendMode.Normal]: '',
|
|
15
|
+
[BlendMode.Additive]: 'plus-lighter',
|
|
16
|
+
[BlendMode.Multiply]: 'multiply',
|
|
17
|
+
[BlendMode.Screen]: 'screen',
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Renders a spine-core Skeleton as DOM, split by slot type:
|
|
21
|
+
*
|
|
22
|
+
* - Region attachments (rigid parts) become one absolutely-positioned <img>
|
|
23
|
+
* posed with a single CSS matrix() write per frame — exact, since bone
|
|
24
|
+
* transforms are affine.
|
|
25
|
+
* - Mesh attachments (deform parts) each get a small per-part <canvas> sized
|
|
26
|
+
* to the mesh's world bounding box, redrawn per frame with the standard
|
|
27
|
+
* per-triangle clip+transform+drawImage mapping.
|
|
28
|
+
*
|
|
29
|
+
* Both element kinds share one stacking context, so draw order interleaves
|
|
30
|
+
* freely via z-index (rear hair canvas < torso img < front hair canvas).
|
|
31
|
+
* Clipping attachments are deliberately unsupported (transparent layered
|
|
32
|
+
* parts make them unnecessary); they are counted in clipSkipCount.
|
|
33
|
+
*
|
|
34
|
+
* Coordinate mapping: Spine is Y-up, CSS is Y-down — world Y is negated.
|
|
35
|
+
* spine-core computes everything (bones, constraints, physics, deformed
|
|
36
|
+
* vertices) on the CPU; this class only draws.
|
|
37
|
+
*/
|
|
38
|
+
export class SpineHtmlRenderer {
|
|
39
|
+
root;
|
|
40
|
+
regionImages;
|
|
41
|
+
/** Clipping attachments encountered (visible but unsupported). */
|
|
42
|
+
clipSkipCount = 0;
|
|
43
|
+
/** Mesh canvases drawn last frame. */
|
|
44
|
+
meshCount = 0;
|
|
45
|
+
/** Triangles rasterized last frame. */
|
|
46
|
+
triangleCount = 0;
|
|
47
|
+
/**
|
|
48
|
+
* How far (px) each triangle's clip polygon is expanded from its centroid.
|
|
49
|
+
* Closes antialiased-clip cracks between adjacent triangles (Safari);
|
|
50
|
+
* set to 0 to see them.
|
|
51
|
+
*/
|
|
52
|
+
triangleExpand = 0.5;
|
|
53
|
+
views = new Map();
|
|
54
|
+
meshVertices = new Float32Array(256);
|
|
55
|
+
/**
|
|
56
|
+
* @param root Positioned element (e.g. position:absolute) that becomes the
|
|
57
|
+
* skeleton origin. The renderer only appends slot elements to it — layout
|
|
58
|
+
* and scaling of the root belong to the caller.
|
|
59
|
+
* @param regionImages Unpacked per-region bitmaps (for the rigid tier).
|
|
60
|
+
*/
|
|
61
|
+
constructor(root, regionImages) {
|
|
62
|
+
this.root = root;
|
|
63
|
+
this.regionImages = regionImages;
|
|
64
|
+
}
|
|
65
|
+
render(skeleton) {
|
|
66
|
+
this.clipSkipCount = 0;
|
|
67
|
+
this.meshCount = 0;
|
|
68
|
+
this.triangleCount = 0;
|
|
69
|
+
const drawOrder = skeleton.drawOrder.appliedPose;
|
|
70
|
+
const skeletonAlpha = skeleton.color.a;
|
|
71
|
+
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
|
72
|
+
const slot = drawOrder[i];
|
|
73
|
+
const pose = slot.appliedPose;
|
|
74
|
+
const attachment = pose.attachment;
|
|
75
|
+
if (!slot.bone.active) {
|
|
76
|
+
this.hide(slot);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (attachment instanceof RegionAttachment) {
|
|
80
|
+
this.renderRegion(slot, pose, attachment, i, skeletonAlpha);
|
|
81
|
+
}
|
|
82
|
+
else if (attachment instanceof MeshAttachment) {
|
|
83
|
+
this.renderMesh(skeleton, slot, pose, attachment, i, skeletonAlpha);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
if (attachment instanceof ClippingAttachment)
|
|
87
|
+
this.clipSkipCount++;
|
|
88
|
+
this.hide(slot);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
dispose() {
|
|
93
|
+
for (const view of this.views.values())
|
|
94
|
+
view.el.remove();
|
|
95
|
+
this.views.clear();
|
|
96
|
+
}
|
|
97
|
+
// --- rigid tier -----------------------------------------------------------
|
|
98
|
+
renderRegion(slot, pose, attachment, zIndex, skeletonAlpha) {
|
|
99
|
+
const sequence = attachment.sequence;
|
|
100
|
+
const region = sequence.regions[sequence.resolveIndex(pose)];
|
|
101
|
+
const regionImage = region && this.regionImages.get(region.name);
|
|
102
|
+
if (!regionImage) {
|
|
103
|
+
this.hide(slot);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const view = this.view(slot, 'image');
|
|
107
|
+
const img = view.el;
|
|
108
|
+
if (view.regionName !== region.name) {
|
|
109
|
+
view.regionName = region.name;
|
|
110
|
+
img.src = regionImage.url;
|
|
111
|
+
img.width = regionImage.width;
|
|
112
|
+
img.height = regionImage.height;
|
|
113
|
+
}
|
|
114
|
+
attachment.computeWorldVertices(slot, attachment.getOffsets(pose), regionVertices, 0, 2);
|
|
115
|
+
// Corner order from spine-core is BL, UL, UR, BR — derived from
|
|
116
|
+
// computeUVs, whose per-vertex UVs are (u,v2), (u,v), (u2,v), (u2,v2).
|
|
117
|
+
// (The br/bl/ul/ur comments inside computeWorldVertices are stale.)
|
|
118
|
+
// Flip Y for CSS (Spine is Y-up).
|
|
119
|
+
const blx = regionVertices[0], bly = -regionVertices[1];
|
|
120
|
+
const ulx = regionVertices[2], uly = -regionVertices[3];
|
|
121
|
+
const urx = regionVertices[4], ury = -regionVertices[5];
|
|
122
|
+
const w = regionImage.width;
|
|
123
|
+
const h = regionImage.height;
|
|
124
|
+
const a = (urx - ulx) / w;
|
|
125
|
+
const b = (ury - uly) / w;
|
|
126
|
+
const c = (blx - ulx) / h;
|
|
127
|
+
const d = (bly - uly) / h;
|
|
128
|
+
img.style.transform = `matrix(${a},${b},${c},${d},${ulx},${uly})`;
|
|
129
|
+
this.applyCommon(view, slot, zIndex, skeletonAlpha * pose.color.a * attachment.color.a);
|
|
130
|
+
}
|
|
131
|
+
// --- deform tier ----------------------------------------------------------
|
|
132
|
+
renderMesh(skeleton, slot, pose, attachment, zIndex, skeletonAlpha) {
|
|
133
|
+
const sequence = attachment.sequence;
|
|
134
|
+
const sequenceIndex = sequence.resolveIndex(pose);
|
|
135
|
+
const region = sequence.regions[sequenceIndex];
|
|
136
|
+
const page = region?.texture?.getImage();
|
|
137
|
+
if (!page) {
|
|
138
|
+
this.hide(slot);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const count = attachment.worldVerticesLength;
|
|
142
|
+
if (this.meshVertices.length < count)
|
|
143
|
+
this.meshVertices = new Float32Array(count);
|
|
144
|
+
const vertices = this.meshVertices;
|
|
145
|
+
attachment.computeWorldVertices(skeleton, slot, 0, count, vertices, 0, 2);
|
|
146
|
+
// World bounds (in CSS coords: Y negated).
|
|
147
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
148
|
+
for (let v = 0; v < count; v += 2) {
|
|
149
|
+
const x = vertices[v];
|
|
150
|
+
const y = -vertices[v + 1];
|
|
151
|
+
vertices[v + 1] = y;
|
|
152
|
+
if (x < minX)
|
|
153
|
+
minX = x;
|
|
154
|
+
if (x > maxX)
|
|
155
|
+
maxX = x;
|
|
156
|
+
if (y < minY)
|
|
157
|
+
minY = y;
|
|
158
|
+
if (y > maxY)
|
|
159
|
+
maxY = y;
|
|
160
|
+
}
|
|
161
|
+
const pad = 1;
|
|
162
|
+
minX = Math.floor(minX) - pad;
|
|
163
|
+
minY = Math.floor(minY) - pad;
|
|
164
|
+
const w = Math.ceil(maxX) + pad - minX;
|
|
165
|
+
const h = Math.ceil(maxY) + pad - minY;
|
|
166
|
+
if (w <= 0 || h <= 0) {
|
|
167
|
+
this.hide(slot);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const view = this.view(slot, 'canvas');
|
|
171
|
+
const canvas = view.el;
|
|
172
|
+
// NOTE: 1x backing store for the PoC; the example atlas is 0.5-scale
|
|
173
|
+
// anyway. DPR-aware backing is a follow-up.
|
|
174
|
+
if (view.canvasW !== w || view.canvasH !== h) {
|
|
175
|
+
view.canvasW = w;
|
|
176
|
+
view.canvasH = h;
|
|
177
|
+
canvas.width = w;
|
|
178
|
+
canvas.height = h;
|
|
179
|
+
}
|
|
180
|
+
canvas.style.transform = `translate(${minX}px,${minY}px)`;
|
|
181
|
+
const ctx = canvas.getContext('2d');
|
|
182
|
+
if (!ctx)
|
|
183
|
+
return;
|
|
184
|
+
ctx.clearRect(0, 0, w, h);
|
|
185
|
+
const uvs = sequence.getUVs(sequenceIndex);
|
|
186
|
+
const triangles = attachment.triangles;
|
|
187
|
+
const uw = page.width - 1;
|
|
188
|
+
const uh = page.height - 1;
|
|
189
|
+
for (let t = 0; t < triangles.length; t += 3) {
|
|
190
|
+
const i0 = triangles[t] * 2;
|
|
191
|
+
const i1 = triangles[t + 1] * 2;
|
|
192
|
+
const i2 = triangles[t + 2] * 2;
|
|
193
|
+
this.drawTriangle(ctx, page, vertices[i0] - minX, vertices[i0 + 1] - minY, uvs[i0] * uw, uvs[i0 + 1] * uh, vertices[i1] - minX, vertices[i1 + 1] - minY, uvs[i1] * uw, uvs[i1 + 1] * uh, vertices[i2] - minX, vertices[i2 + 1] - minY, uvs[i2] * uw, uvs[i2 + 1] * uh);
|
|
194
|
+
}
|
|
195
|
+
this.meshCount++;
|
|
196
|
+
this.triangleCount += triangles.length / 3;
|
|
197
|
+
this.applyCommon(view, slot, zIndex, skeletonAlpha * pose.color.a * attachment.color.a);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Standard canvas triangle texture mapping (same math as the official
|
|
201
|
+
* spine-canvas renderer): derive the affine that sends the triangle's
|
|
202
|
+
* texture-space corners to its screen-space corners, clip, draw the page.
|
|
203
|
+
*
|
|
204
|
+
* The clip polygon is expanded outward from the centroid by a fraction of
|
|
205
|
+
* a pixel. Browsers that antialias clip paths (Safari) otherwise leave
|
|
206
|
+
* hairline cracks between adjacent triangles; the expanded clips overlap
|
|
207
|
+
* into the neighbouring triangle, and since the texture is continuous
|
|
208
|
+
* across the shared edge the overlap draws the same pixels — cracks close
|
|
209
|
+
* with no visible cost. The texture-mapping affine itself stays exact.
|
|
210
|
+
*/
|
|
211
|
+
drawTriangle(ctx, img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) {
|
|
212
|
+
const cx = (x0 + x1 + x2) / 3;
|
|
213
|
+
const cy = (y0 + y1 + y2) / 3;
|
|
214
|
+
const expand = this.triangleExpand;
|
|
215
|
+
ctx.beginPath();
|
|
216
|
+
ctx.moveTo(...expandPoint(x0, y0, cx, cy, expand));
|
|
217
|
+
ctx.lineTo(...expandPoint(x1, y1, cx, cy, expand));
|
|
218
|
+
ctx.lineTo(...expandPoint(x2, y2, cx, cy, expand));
|
|
219
|
+
ctx.closePath();
|
|
220
|
+
x1 -= x0;
|
|
221
|
+
y1 -= y0;
|
|
222
|
+
x2 -= x0;
|
|
223
|
+
y2 -= y0;
|
|
224
|
+
u1 -= u0;
|
|
225
|
+
v1 -= v0;
|
|
226
|
+
u2 -= u0;
|
|
227
|
+
v2 -= v0;
|
|
228
|
+
let det = u1 * v2 - u2 * v1;
|
|
229
|
+
if (det === 0)
|
|
230
|
+
return;
|
|
231
|
+
det = 1 / det;
|
|
232
|
+
const a = (v2 * x1 - v1 * x2) * det;
|
|
233
|
+
const b = (v2 * y1 - v1 * y2) * det;
|
|
234
|
+
const c = (u1 * x2 - u2 * x1) * det;
|
|
235
|
+
const d = (u1 * y2 - u2 * y1) * det;
|
|
236
|
+
const e = x0 - a * u0 - c * v0;
|
|
237
|
+
const f = y0 - b * u0 - d * v0;
|
|
238
|
+
ctx.save();
|
|
239
|
+
ctx.transform(a, b, c, d, e, f);
|
|
240
|
+
ctx.clip();
|
|
241
|
+
ctx.drawImage(img, 0, 0);
|
|
242
|
+
ctx.restore();
|
|
243
|
+
}
|
|
244
|
+
// --- shared plumbing -------------------------------------------------------
|
|
245
|
+
applyCommon(view, slot, zIndex, alpha) {
|
|
246
|
+
if (view.zIndex !== zIndex) {
|
|
247
|
+
view.zIndex = zIndex;
|
|
248
|
+
view.el.style.zIndex = String(zIndex);
|
|
249
|
+
}
|
|
250
|
+
// Alpha only; RGB tinting has no cheap DOM equivalent (out of scope).
|
|
251
|
+
if (view.opacity !== alpha) {
|
|
252
|
+
view.opacity = alpha;
|
|
253
|
+
view.el.style.opacity = alpha === 1 ? '' : String(alpha);
|
|
254
|
+
}
|
|
255
|
+
const blendMode = slot.data.blendMode;
|
|
256
|
+
if (view.blendMode !== blendMode) {
|
|
257
|
+
view.blendMode = blendMode;
|
|
258
|
+
view.el.style.mixBlendMode = BLEND_CSS[blendMode];
|
|
259
|
+
}
|
|
260
|
+
if (!view.visible) {
|
|
261
|
+
view.visible = true;
|
|
262
|
+
view.el.style.display = '';
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
view(slot, kind) {
|
|
266
|
+
let view = this.views.get(slot);
|
|
267
|
+
if (view && view.kind !== kind) {
|
|
268
|
+
view.el.remove();
|
|
269
|
+
view = undefined;
|
|
270
|
+
}
|
|
271
|
+
if (!view) {
|
|
272
|
+
const el = kind === 'image' ? document.createElement('img') : document.createElement('canvas');
|
|
273
|
+
if (el instanceof HTMLImageElement)
|
|
274
|
+
el.draggable = false;
|
|
275
|
+
el.style.position = 'absolute';
|
|
276
|
+
el.style.left = '0';
|
|
277
|
+
el.style.top = '0';
|
|
278
|
+
el.style.transformOrigin = '0 0';
|
|
279
|
+
el.style.pointerEvents = 'none';
|
|
280
|
+
el.style.userSelect = 'none';
|
|
281
|
+
el.style.display = 'none';
|
|
282
|
+
view = {
|
|
283
|
+
kind,
|
|
284
|
+
el,
|
|
285
|
+
regionName: '',
|
|
286
|
+
visible: false,
|
|
287
|
+
zIndex: -1,
|
|
288
|
+
opacity: 1,
|
|
289
|
+
blendMode: BlendMode.Normal,
|
|
290
|
+
canvasW: 0,
|
|
291
|
+
canvasH: 0,
|
|
292
|
+
};
|
|
293
|
+
this.views.set(slot, view);
|
|
294
|
+
this.root.appendChild(el);
|
|
295
|
+
}
|
|
296
|
+
return view;
|
|
297
|
+
}
|
|
298
|
+
hide(slot) {
|
|
299
|
+
const view = this.views.get(slot);
|
|
300
|
+
if (view && view.visible) {
|
|
301
|
+
view.visible = false;
|
|
302
|
+
view.el.style.display = 'none';
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=SpineHtmlRenderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpineHtmlRenderer.js","sourceRoot":"","sources":["../src/SpineHtmlRenderer.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAoB,MAAM,cAAc,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "spine-html",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Render Spine skeletal animations as plain DOM — rigid slots as <img> posed by CSS matrix, deform meshes on small per-part canvases, interleaved in one stacking context.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "firejune",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/firejune/spine-html.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/firejune/spine-html#readme",
|
|
13
|
+
"bugs": "https://github.com/firejune/spine-html/issues",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"spine",
|
|
16
|
+
"spine2d",
|
|
17
|
+
"skeletal-animation",
|
|
18
|
+
"mesh-deformation",
|
|
19
|
+
"dom",
|
|
20
|
+
"css-transform",
|
|
21
|
+
"renderer",
|
|
22
|
+
"2d",
|
|
23
|
+
"animation",
|
|
24
|
+
"character-animation"
|
|
25
|
+
],
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"NOTICE.md"
|
|
37
|
+
],
|
|
38
|
+
"sideEffects": false,
|
|
39
|
+
"scripts": {
|
|
40
|
+
"predev": "bash scripts/fetch-assets.sh",
|
|
41
|
+
"dev": "vite",
|
|
42
|
+
"prebuild": "bash scripts/fetch-assets.sh",
|
|
43
|
+
"build": "tsc --noEmit && vite build",
|
|
44
|
+
"build:lib": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
45
|
+
"prepublishOnly": "npm run build:lib",
|
|
46
|
+
"preview": "vite preview",
|
|
47
|
+
"fetch-assets": "bash scripts/fetch-assets.sh"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@esotericsoftware/spine-core": "^4.3.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@esotericsoftware/spine-core": "^4.3.13",
|
|
54
|
+
"typescript": "^5.6.0",
|
|
55
|
+
"vite": "^6.0.0"
|
|
56
|
+
}
|
|
57
|
+
}
|