spine-html 0.4.0 → 0.5.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/NOTICE.md +4 -3
- package/README.md +141 -3
- package/dist/MeshGlBlitter.d.ts +43 -1
- package/dist/MeshGlBlitter.d.ts.map +1 -1
- package/dist/MeshGlBlitter.js +85 -8
- package/dist/MeshGlBlitter.js.map +1 -1
- package/dist/SpineHtmlRenderer.d.ts +129 -7
- package/dist/SpineHtmlRenderer.d.ts.map +1 -1
- package/dist/SpineHtmlRenderer.js +281 -32
- package/dist/SpineHtmlRenderer.js.map +1 -1
- package/dist/binary.d.ts +48 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +29 -0
- package/dist/binary.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/loadAtlasAssets.d.ts +73 -0
- package/dist/loadAtlasAssets.d.ts.map +1 -0
- package/dist/loadAtlasAssets.js +75 -0
- package/dist/loadAtlasAssets.js.map +1 -0
- package/dist/loadSkeletonAssets.d.ts +41 -22
- package/dist/loadSkeletonAssets.d.ts.map +1 -1
- package/dist/loadSkeletonAssets.js +48 -49
- package/dist/loadSkeletonAssets.js.map +1 -1
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +243 -0
- package/dist/main.js.map +1 -0
- package/package.json +5 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAoB,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAoB,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAoB,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAEL,eAAe,GAEhB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,kBAAkB,EAElB,gBAAgB,GAGjB,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { TextureAtlas } from '@esotericsoftware/spine-core';
|
|
2
|
+
import { type RegionImage } from './DomTexture.js';
|
|
3
|
+
/**
|
|
4
|
+
* Optional convenience loader, atlas half: fetch an atlas export, attach the
|
|
5
|
+
* page images, unpack the regions — once, for however many skeletons share it.
|
|
6
|
+
*
|
|
7
|
+
* It is deliberately the *only* thing this module does, and it deliberately
|
|
8
|
+
* knows nothing about skeleton exports: it must not drag a skeleton reader
|
|
9
|
+
* (SkeletonJson or SkeletonBinary) into the bundle of a consumer that only
|
|
10
|
+
* wanted the atlas. Reading a skeleton against these assets is
|
|
11
|
+
* `loadSkeletonJson` in loadSkeletonAssets.ts or `loadSkeletonBinary` in
|
|
12
|
+
* binary.ts, both of which sit on this seam.
|
|
13
|
+
*
|
|
14
|
+
* Nothing on the renderer's path imports this file, so a bundler drops it when
|
|
15
|
+
* it is unused.
|
|
16
|
+
*/
|
|
17
|
+
export interface LoadAtlasAssetsOptions {
|
|
18
|
+
/** URL of the atlas (.atlas) export. */
|
|
19
|
+
atlasUrl: string;
|
|
20
|
+
/**
|
|
21
|
+
* Maps an atlas page name to the URL its image lives at. Defaults to
|
|
22
|
+
* resolving the page name against the atlas URL's directory, which is what
|
|
23
|
+
* a Spine editor export next to its atlas needs.
|
|
24
|
+
*/
|
|
25
|
+
resolvePage?: (pageName: string, atlasUrl: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* crossOrigin attribute for the page images. Needed when the images come
|
|
28
|
+
* from another origin: the region cut reads them into a canvas, and a
|
|
29
|
+
* tainted canvas cannot be exported (SecurityError from toBlob).
|
|
30
|
+
*/
|
|
31
|
+
crossOrigin?: string;
|
|
32
|
+
/** fetch implementation, for custom headers or a test double. */
|
|
33
|
+
fetch?: typeof globalThis.fetch;
|
|
34
|
+
}
|
|
35
|
+
export interface AtlasAssets {
|
|
36
|
+
/** The parsed atlas, page textures attached. */
|
|
37
|
+
atlas: TextureAtlas;
|
|
38
|
+
/** Unpacked per-region bitmaps, ready for `new SpineHtmlRenderer(root, …)`. */
|
|
39
|
+
regionImages: Map<string, RegionImage>;
|
|
40
|
+
/**
|
|
41
|
+
* Frees the blob URLs this load created (see revokeRegions). Idempotent.
|
|
42
|
+
* Call it after the renderers using these images are disposed — a live
|
|
43
|
+
* <img> would be left pointing at a dead URL.
|
|
44
|
+
*/
|
|
45
|
+
dispose(): void;
|
|
46
|
+
}
|
|
47
|
+
/** @internal Shared with loadSkeletonAssets.ts; not part of the package API. */
|
|
48
|
+
export declare function fetchText(fetchImpl: typeof globalThis.fetch, url: string): Promise<string>;
|
|
49
|
+
/**
|
|
50
|
+
* @internal Shared with binary.ts; not part of the package API. Same HTTP
|
|
51
|
+
* failure message as fetchText, so both skeleton readers reject alike.
|
|
52
|
+
*/
|
|
53
|
+
export declare function fetchBytes(fetchImpl: typeof globalThis.fetch, url: string): Promise<Uint8Array>;
|
|
54
|
+
/**
|
|
55
|
+
* Loads an atlas and its regions once, to be shared by several skeletons.
|
|
56
|
+
*
|
|
57
|
+
* ```ts
|
|
58
|
+
* const shared = await loadAtlasAssets({ atlasUrl: '/spineboy/spineboy.atlas' });
|
|
59
|
+
* const [ess, pro] = await Promise.all([
|
|
60
|
+
* loadSkeletonJson(shared, '/spineboy/spineboy-ess.json'),
|
|
61
|
+
* loadSkeletonJson(shared, '/spineboy/spineboy-pro.json'),
|
|
62
|
+
* ]);
|
|
63
|
+
* // …later, after every renderer using them is disposed: shared.dispose();
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* The caller owns the result: reading a skeleton against it never disposes it,
|
|
67
|
+
* and one `regionImages` map is meant to be handed to several renderers.
|
|
68
|
+
*
|
|
69
|
+
* Page images load in parallel. If anything fails part-way, no blob URL is
|
|
70
|
+
* left behind.
|
|
71
|
+
*/
|
|
72
|
+
export declare function loadAtlasAssets(options: LoadAtlasAssetsOptions): Promise<AtlasAssets>;
|
|
73
|
+
//# sourceMappingURL=loadAtlasAssets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadAtlasAssets.d.ts","sourceRoot":"","sources":["../src/loadAtlasAssets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAc,KAAK,WAAW,EAAgC,MAAM,iBAAiB,CAAC;AAE7F;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,sBAAsB;IACrC,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7D;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,KAAK,EAAE,YAAY,CAAC;IACpB,+EAA+E;IAC/E,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACvC;;;;OAIG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAMD,gFAAgF;AAChF,wBAAsB,SAAS,CAAC,SAAS,EAAE,OAAO,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIhG;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,SAAS,EAAE,OAAO,UAAU,CAAC,KAAK,EAClC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,CAAC,CAIrB;AAYD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CA2B3F"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { TextureAtlas } from '@esotericsoftware/spine-core';
|
|
2
|
+
import { DomTexture, revokeRegions, unpackRegions } from './DomTexture.js';
|
|
3
|
+
function resolveAgainstAtlas(pageName, atlasUrl) {
|
|
4
|
+
return new URL(pageName, new URL(atlasUrl, document.baseURI)).href;
|
|
5
|
+
}
|
|
6
|
+
/** @internal Shared with loadSkeletonAssets.ts; not part of the package API. */
|
|
7
|
+
export async function fetchText(fetchImpl, url) {
|
|
8
|
+
const response = await fetchImpl(url);
|
|
9
|
+
if (!response.ok)
|
|
10
|
+
throw new Error(`Failed to fetch ${url}: ${response.status}`);
|
|
11
|
+
return response.text();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* @internal Shared with binary.ts; not part of the package API. Same HTTP
|
|
15
|
+
* failure message as fetchText, so both skeleton readers reject alike.
|
|
16
|
+
*/
|
|
17
|
+
export async function fetchBytes(fetchImpl, url) {
|
|
18
|
+
const response = await fetchImpl(url);
|
|
19
|
+
if (!response.ok)
|
|
20
|
+
throw new Error(`Failed to fetch ${url}: ${response.status}`);
|
|
21
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
22
|
+
}
|
|
23
|
+
function loadImage(url, crossOrigin) {
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
const image = new Image();
|
|
26
|
+
if (crossOrigin !== undefined)
|
|
27
|
+
image.crossOrigin = crossOrigin;
|
|
28
|
+
image.onload = () => resolve(image);
|
|
29
|
+
image.onerror = () => reject(new Error(`Failed to load atlas page image: ${url}`));
|
|
30
|
+
image.src = url;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Loads an atlas and its regions once, to be shared by several skeletons.
|
|
35
|
+
*
|
|
36
|
+
* ```ts
|
|
37
|
+
* const shared = await loadAtlasAssets({ atlasUrl: '/spineboy/spineboy.atlas' });
|
|
38
|
+
* const [ess, pro] = await Promise.all([
|
|
39
|
+
* loadSkeletonJson(shared, '/spineboy/spineboy-ess.json'),
|
|
40
|
+
* loadSkeletonJson(shared, '/spineboy/spineboy-pro.json'),
|
|
41
|
+
* ]);
|
|
42
|
+
* // …later, after every renderer using them is disposed: shared.dispose();
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* The caller owns the result: reading a skeleton against it never disposes it,
|
|
46
|
+
* and one `regionImages` map is meant to be handed to several renderers.
|
|
47
|
+
*
|
|
48
|
+
* Page images load in parallel. If anything fails part-way, no blob URL is
|
|
49
|
+
* left behind.
|
|
50
|
+
*/
|
|
51
|
+
export async function loadAtlasAssets(options) {
|
|
52
|
+
const { atlasUrl, crossOrigin } = options;
|
|
53
|
+
const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
54
|
+
const resolvePage = options.resolvePage ?? resolveAgainstAtlas;
|
|
55
|
+
const atlas = new TextureAtlas(await fetchText(fetchImpl, atlasUrl));
|
|
56
|
+
const pageImages = new Map();
|
|
57
|
+
await Promise.all(atlas.pages.map(async (page) => {
|
|
58
|
+
const image = await loadImage(resolvePage(page.name, atlasUrl), crossOrigin);
|
|
59
|
+
page.setTexture(new DomTexture(image));
|
|
60
|
+
pageImages.set(page.name, image);
|
|
61
|
+
}));
|
|
62
|
+
const regionImages = await unpackRegions(atlas, pageImages);
|
|
63
|
+
let disposed = false;
|
|
64
|
+
return {
|
|
65
|
+
atlas,
|
|
66
|
+
regionImages,
|
|
67
|
+
dispose() {
|
|
68
|
+
if (disposed)
|
|
69
|
+
return;
|
|
70
|
+
disposed = true;
|
|
71
|
+
revokeRegions(regionImages);
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=loadAtlasAssets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadAtlasAssets.js","sourceRoot":"","sources":["../src/loadAtlasAssets.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type SkeletonData, TextureAtlas } from '@esotericsoftware/spine-core';
|
|
2
|
-
import {
|
|
2
|
+
import type { RegionImage } from './DomTexture.js';
|
|
3
|
+
import { type LoadAtlasAssetsOptions } from './loadAtlasAssets.js';
|
|
3
4
|
/**
|
|
4
5
|
* Optional convenience loader: fetch a skeleton export and its atlas, attach
|
|
5
6
|
* the page images, unpack the regions.
|
|
@@ -8,30 +9,24 @@ import { type RegionImage } from './DomTexture';
|
|
|
8
9
|
* deliberately the *only* thing this module does — it owns no frame loop, no
|
|
9
10
|
* AnimationState, no layout, and it is not on the renderer's path, so the
|
|
10
11
|
* low-level route (TextureAtlas + DomTexture + unpackRegions by hand) stays
|
|
11
|
-
* the way to do anything this does not cover:
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* the way to do anything this does not cover: images that come from somewhere
|
|
13
|
+
* other than a URL, an atlas that is not fetched at all. Binary (.skel) exports
|
|
14
|
+
* are read by `loadSkeletonBinary`, from the separate `spine-html/binary` entry,
|
|
15
|
+
* on the same seam. Sharing one atlas across several
|
|
16
|
+
* skeletons has its own seam: `loadAtlasAssets` (loadAtlasAssets.ts) plus one
|
|
17
|
+
* `loadSkeletonJson` per skeleton, which is what this function is built on.
|
|
18
|
+
* Nothing else in the package imports this file, so a bundler drops it when it
|
|
19
|
+
* is unused.
|
|
15
20
|
*/
|
|
16
|
-
export interface LoadSkeletonAssetsOptions {
|
|
17
|
-
/** URL of the atlas (.atlas) export. */
|
|
18
|
-
atlasUrl: string;
|
|
21
|
+
export interface LoadSkeletonAssetsOptions extends LoadAtlasAssetsOptions {
|
|
19
22
|
/** URL of the skeleton JSON (.json) export. */
|
|
20
23
|
skeletonUrl: string;
|
|
21
|
-
/**
|
|
22
|
-
* Maps an atlas page name to the URL its image lives at. Defaults to
|
|
23
|
-
* resolving the page name against the atlas URL's directory, which is what
|
|
24
|
-
* a Spine editor export next to its atlas needs.
|
|
25
|
-
*/
|
|
26
|
-
resolvePage?: (pageName: string, atlasUrl: string) => string;
|
|
27
24
|
/** SkeletonJson.scale — scales the skeleton as it is read. */
|
|
28
25
|
scale?: number;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
*/
|
|
34
|
-
crossOrigin?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface LoadSkeletonJsonOptions {
|
|
28
|
+
/** SkeletonJson.scale — scales the skeleton as it is read. */
|
|
29
|
+
scale?: number;
|
|
35
30
|
/** fetch implementation, for custom headers or a test double. */
|
|
36
31
|
fetch?: typeof globalThis.fetch;
|
|
37
32
|
}
|
|
@@ -49,6 +44,26 @@ export interface SkeletonAssets {
|
|
|
49
44
|
*/
|
|
50
45
|
dispose(): void;
|
|
51
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Reads one skeleton JSON export against already-loaded atlas assets — the
|
|
49
|
+
* second step of the shared-atlas path.
|
|
50
|
+
*
|
|
51
|
+
* ```ts
|
|
52
|
+
* const shared = await loadAtlasAssets({ atlasUrl: '/spineboy/spineboy.atlas' });
|
|
53
|
+
* const [ess, pro] = await Promise.all([
|
|
54
|
+
* loadSkeletonJson(shared, '/spineboy/spineboy-ess.json'),
|
|
55
|
+
* loadSkeletonJson(shared, '/spineboy/spineboy-pro.json'),
|
|
56
|
+
* ]);
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* `assets` needs nothing but a parsed atlas with its page textures attached,
|
|
60
|
+
* so a caller on the low-level path can pass its own `{ atlas }`. Ownership
|
|
61
|
+
* stays with the caller: this never disposes `assets`, whether it succeeds or
|
|
62
|
+
* throws, because the same assets normally back several skeletons.
|
|
63
|
+
*/
|
|
64
|
+
export declare function loadSkeletonJson(assets: {
|
|
65
|
+
atlas: TextureAtlas;
|
|
66
|
+
}, skeletonUrl: string, options?: LoadSkeletonJsonOptions): Promise<SkeletonData>;
|
|
52
67
|
/**
|
|
53
68
|
* Loads everything the renderer needs from two URLs.
|
|
54
69
|
*
|
|
@@ -62,8 +77,12 @@ export interface SkeletonAssets {
|
|
|
62
77
|
* // …later: renderer.dispose(); assets.dispose();
|
|
63
78
|
* ```
|
|
64
79
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
80
|
+
* One atlas, one skeleton. Several skeletons sharing one atlas is the two-step
|
|
81
|
+
* path instead (`loadAtlasAssets` + `loadSkeletonJson`), which this is built
|
|
82
|
+
* on — calling this once per skeleton would refetch and re-unpack the atlas.
|
|
83
|
+
*
|
|
84
|
+
* Page images load in parallel, and the skeleton export downloads alongside
|
|
85
|
+
* the atlas half. If anything fails part-way, no blob URL is left behind.
|
|
67
86
|
*/
|
|
68
87
|
export declare function loadSkeletonAssets(options: LoadSkeletonAssetsOptions): Promise<SkeletonAssets>;
|
|
69
88
|
//# sourceMappingURL=loadSkeletonAssets.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadSkeletonAssets.d.ts","sourceRoot":"","sources":["../src/loadSkeletonAssets.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EAEjB,YAAY,EACb,MAAM,8BAA8B,CAAC;AACtC,OAAO,
|
|
1
|
+
{"version":3,"file":"loadSkeletonAssets.d.ts","sourceRoot":"","sources":["../src/loadSkeletonAssets.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EAEjB,YAAY,EACb,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAa,KAAK,sBAAsB,EAAmB,MAAM,sBAAsB,CAAC;AAE/F;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,yBAA0B,SAAQ,sBAAsB;IACvE,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACtC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,IAAI,EAAE,YAAY,CAAC;IACnB,+EAA+E;IAC/E,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACvC,gDAAgD;IAChD,KAAK,EAAE,YAAY,CAAC;IACpB;;;;OAIG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAQD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE;IAAE,KAAK,EAAE,YAAY,CAAA;CAAE,EAC/B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,YAAY,CAAC,CAIvB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,cAAc,CAAC,CA6BzB"}
|
|
@@ -1,23 +1,32 @@
|
|
|
1
|
-
import { AtlasAttachmentLoader, SkeletonJson,
|
|
2
|
-
import {
|
|
3
|
-
function
|
|
4
|
-
|
|
1
|
+
import { AtlasAttachmentLoader, SkeletonJson, } from '@esotericsoftware/spine-core';
|
|
2
|
+
import { fetchText, loadAtlasAssets } from './loadAtlasAssets.js';
|
|
3
|
+
function readSkeletonData(atlas, text, scale) {
|
|
4
|
+
const json = new SkeletonJson(new AtlasAttachmentLoader(atlas));
|
|
5
|
+
if (scale !== undefined)
|
|
6
|
+
json.scale = scale;
|
|
7
|
+
return json.readSkeletonData(text);
|
|
5
8
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Reads one skeleton JSON export against already-loaded atlas assets — the
|
|
11
|
+
* second step of the shared-atlas path.
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* const shared = await loadAtlasAssets({ atlasUrl: '/spineboy/spineboy.atlas' });
|
|
15
|
+
* const [ess, pro] = await Promise.all([
|
|
16
|
+
* loadSkeletonJson(shared, '/spineboy/spineboy-ess.json'),
|
|
17
|
+
* loadSkeletonJson(shared, '/spineboy/spineboy-pro.json'),
|
|
18
|
+
* ]);
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* `assets` needs nothing but a parsed atlas with its page textures attached,
|
|
22
|
+
* so a caller on the low-level path can pass its own `{ atlas }`. Ownership
|
|
23
|
+
* stays with the caller: this never disposes `assets`, whether it succeeds or
|
|
24
|
+
* throws, because the same assets normally back several skeletons.
|
|
25
|
+
*/
|
|
26
|
+
export async function loadSkeletonJson(assets, skeletonUrl, options = {}) {
|
|
27
|
+
const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
28
|
+
const text = await fetchText(fetchImpl, skeletonUrl);
|
|
29
|
+
return readSkeletonData(assets.atlas, text, options.scale);
|
|
21
30
|
}
|
|
22
31
|
/**
|
|
23
32
|
* Loads everything the renderer needs from two URLs.
|
|
@@ -32,48 +41,38 @@ function loadImage(url, crossOrigin) {
|
|
|
32
41
|
* // …later: renderer.dispose(); assets.dispose();
|
|
33
42
|
* ```
|
|
34
43
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
44
|
+
* One atlas, one skeleton. Several skeletons sharing one atlas is the two-step
|
|
45
|
+
* path instead (`loadAtlasAssets` + `loadSkeletonJson`), which this is built
|
|
46
|
+
* on — calling this once per skeleton would refetch and re-unpack the atlas.
|
|
47
|
+
*
|
|
48
|
+
* Page images load in parallel, and the skeleton export downloads alongside
|
|
49
|
+
* the atlas half. If anything fails part-way, no blob URL is left behind.
|
|
37
50
|
*/
|
|
38
51
|
export async function loadSkeletonAssets(options) {
|
|
39
|
-
const { atlasUrl, skeletonUrl, crossOrigin, scale } = options;
|
|
40
52
|
const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
await Promise.all(atlas.pages.map(async (page) => {
|
|
49
|
-
const image = await loadImage(resolvePage(page.name, atlasUrl), crossOrigin);
|
|
50
|
-
page.setTexture(new DomTexture(image));
|
|
51
|
-
pageImages.set(page.name, image);
|
|
52
|
-
}));
|
|
53
|
-
const regionImages = await unpackRegions(atlas, pageImages);
|
|
53
|
+
// Started before the atlas half is awaited, so the two downloads overlap.
|
|
54
|
+
const skeletonText = fetchText(fetchImpl, options.skeletonUrl);
|
|
55
|
+
// The atlas half can throw first and leave this rejection unobserved until
|
|
56
|
+
// the catch below, which is an unhandled rejection in between. A no-op
|
|
57
|
+
// handler marks it observed; the value/error is still read from the promise.
|
|
58
|
+
skeletonText.catch(() => { });
|
|
59
|
+
const assets = await loadAtlasAssets(options);
|
|
54
60
|
let data;
|
|
55
61
|
try {
|
|
56
|
-
|
|
57
|
-
if (scale !== undefined)
|
|
58
|
-
json.scale = scale;
|
|
59
|
-
data = json.readSkeletonData(skeletonText);
|
|
62
|
+
data = readSkeletonData(assets.atlas, await skeletonText, options.scale);
|
|
60
63
|
}
|
|
61
64
|
catch (error) {
|
|
62
|
-
//
|
|
63
|
-
// the
|
|
64
|
-
|
|
65
|
+
// The regions exist by now, so the skeleton half is the one step that
|
|
66
|
+
// could strand them — whether the fetch failed or the read did.
|
|
67
|
+
assets.dispose();
|
|
65
68
|
throw error;
|
|
66
69
|
}
|
|
67
|
-
let disposed = false;
|
|
68
70
|
return {
|
|
69
|
-
atlas,
|
|
71
|
+
atlas: assets.atlas,
|
|
70
72
|
data,
|
|
71
|
-
regionImages,
|
|
73
|
+
regionImages: assets.regionImages,
|
|
72
74
|
dispose() {
|
|
73
|
-
|
|
74
|
-
return;
|
|
75
|
-
disposed = true;
|
|
76
|
-
revokeRegions(regionImages);
|
|
75
|
+
assets.dispose();
|
|
77
76
|
},
|
|
78
77
|
};
|
|
79
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadSkeletonAssets.js","sourceRoot":"","sources":["../src/loadSkeletonAssets.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EAErB,YAAY,
|
|
1
|
+
{"version":3,"file":"loadSkeletonAssets.js","sourceRoot":"","sources":["../src/loadSkeletonAssets.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EAErB,YAAY,GAEb,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,SAAS,EAA+B,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAiD/F,SAAS,gBAAgB,CAAC,KAAmB,EAAE,IAAY,EAAE,KAAc;IACzE,MAAM,IAAI,GAAG,IAAI,YAAY,CAAC,IAAI,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC;IAChE,IAAI,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAC5C,OAAO,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAA+B,EAC/B,WAAmB,EACnB,UAAmC,EAAE;IAErC,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACrE,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACrD,OAAO,gBAAgB,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAkC;IAElC,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAErE,0EAA0E;IAC1E,MAAM,YAAY,GAAG,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/D,2EAA2E;IAC3E,uEAAuE;IACvE,6EAA6E;IAC7E,YAAY,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAE7B,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,IAAkB,CAAC;IACvB,IAAI,CAAC;QACH,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,sEAAsE;QACtE,gEAAgE;QAChE,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,KAAK,CAAC;IACd,CAAC;IAED,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,IAAI;QACJ,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,OAAO;YACL,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
|