spine-html 0.5.0 → 0.5.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/dist/DomTexture.d.ts +26 -3
- package/dist/DomTexture.d.ts.map +1 -1
- package/dist/DomTexture.js +164 -61
- package/dist/DomTexture.js.map +1 -1
- package/package.json +1 -1
- package/dist/main.d.ts +0 -2
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js +0 -243
- package/dist/main.js.map +0 -1
package/dist/DomTexture.d.ts
CHANGED
|
@@ -30,14 +30,37 @@ export interface RegionImage {
|
|
|
30
30
|
* rendering is pure DOM (one <img> per slot, one CSS matrix write per frame).
|
|
31
31
|
*
|
|
32
32
|
* A region that covers its whole page unrotated skips the cut and reuses the
|
|
33
|
-
* page image URL — see the pass-through
|
|
33
|
+
* page image URL — see the pass-through in cutRegion.
|
|
34
|
+
*
|
|
35
|
+
* **The cuts run concurrently.** PNG encoding is asynchronous and the browser
|
|
36
|
+
* does it off the main thread, so the encodes are started together and awaited
|
|
37
|
+
* together instead of one `toBlob` per iteration: awaited in series a load
|
|
38
|
+
* costs the *sum* of every encode, which a throttled document turns into one
|
|
39
|
+
* full throttle period per region (measured: a single 8×8 `toBlob` took 7.5 s
|
|
40
|
+
* to call back in a hidden desktop Chromium pane). How many run at once is
|
|
41
|
+
* bounded by CUT_BACKING_BUDGET_PX above, not by an option.
|
|
42
|
+
*
|
|
43
|
+
* Concurrency changes nothing a caller can observe:
|
|
44
|
+
*
|
|
45
|
+
* - **Order.** The returned map is keyed in `atlas.regions` order whatever
|
|
46
|
+
* order the blobs arrive in — the map is built after the cuts settle, from
|
|
47
|
+
* the region list, not from the arrivals.
|
|
48
|
+
* - **Duplicate names.** The last region of a given name in atlas order wins,
|
|
49
|
+
* and the shadowed URL is revoked (and dropped from the ledger) rather than
|
|
50
|
+
* stranded.
|
|
51
|
+
* - **Failure.** Every URL this call minted is revoked before the error
|
|
52
|
+
* propagates, *including cuts that were still in flight when the first
|
|
53
|
+
* failure happened* — their blobs arrive later, and a load that walked away
|
|
54
|
+
* from them would mint owned URLs nobody could ever revoke. So a failure
|
|
55
|
+
* stops new cuts from starting but still waits for the started ones, and the
|
|
56
|
+
* error it raises is the one from the earliest region in atlas order (what
|
|
57
|
+
* the serial loop used to throw). Nothing here rejects unobserved.
|
|
34
58
|
*
|
|
35
59
|
* The blob URLs stay alive until revokeRegions() frees them — a document-wide
|
|
36
60
|
* allocation the GC cannot reclaim on its own. Callers that load and unload
|
|
37
61
|
* skeletons repeatedly (cutscenes, level transitions) must pair every
|
|
38
62
|
* unpackRegions() with a revokeRegions(); a caller that loads once for the
|
|
39
|
-
* page lifetime can ignore it.
|
|
40
|
-
* everything it already minted is revoked before the error propagates.
|
|
63
|
+
* page lifetime can ignore it.
|
|
41
64
|
*/
|
|
42
65
|
export declare function unpackRegions(atlas: TextureAtlas, pageImages: Map<string, HTMLImageElement>): Promise<Map<string, RegionImage>>;
|
|
43
66
|
/**
|
package/dist/DomTexture.d.ts.map
CHANGED
|
@@ -1 +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;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;CAChB;
|
|
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;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;CAChB;AAsGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;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,CA0EnC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,IAAI,CAEpE"}
|
package/dist/DomTexture.js
CHANGED
|
@@ -24,6 +24,81 @@ function revokeOwned(url) {
|
|
|
24
24
|
return;
|
|
25
25
|
URL.revokeObjectURL(url);
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Backing pixels the cuts still waiting for their PNG encode may hold at once.
|
|
29
|
+
*
|
|
30
|
+
* A started cut keeps its canvas alive until `toBlob` calls back, so starting
|
|
31
|
+
* every region at once peaks at Σ(region area) of canvas backing — on top of
|
|
32
|
+
* the decoded pages, which stay resident throughout. Measured by counting the
|
|
33
|
+
* simultaneously-alive cut canvases and their backing at `toBlob` (chromium):
|
|
34
|
+
* the demo's 40-region 1024×256 atlas peaks at all 40 cuts and 194,742 px
|
|
35
|
+
* (0.19 Mpx ≈ 0.74 MiB), which is nothing; a synthetic 256-region atlas on
|
|
36
|
+
* four 2048×2048 pages peaks at 16.78 Mpx ≈ 64 MiB, which doubles that
|
|
37
|
+
* atlas's resident cost for the length of the load.
|
|
38
|
+
*
|
|
39
|
+
* So the cuts are started against a budget rather than all at once. 4 Mpx is
|
|
40
|
+
* one 2048×2048 page's worth (≈ 16 MiB at 4 bytes/px): small atlases still run
|
|
41
|
+
* every region concurrently (spineboy: all 40, budget never engaged), and the
|
|
42
|
+
* synthetic one runs 64 cuts at a time — 4 waves instead of 256 serial
|
|
43
|
+
* encodes, for a quarter of the peak. A single region bigger than the budget
|
|
44
|
+
* is started anyway when nothing else is in flight, so the budget can never
|
|
45
|
+
* starve a cut.
|
|
46
|
+
*/
|
|
47
|
+
const CUT_BACKING_BUDGET_PX = 4 * 1024 * 1024;
|
|
48
|
+
/**
|
|
49
|
+
* One region's bitmap: the whole-page pass-through, or a cut canvas encoded to
|
|
50
|
+
* a blob URL this module then owns.
|
|
51
|
+
*
|
|
52
|
+
* Everything before the `toBlob` await runs synchronously, so calling this is
|
|
53
|
+
* what "starts" a cut: the canvas is painted and the encode is handed to the
|
|
54
|
+
* browser before control comes back.
|
|
55
|
+
*/
|
|
56
|
+
async function cutRegion(region, pageImages) {
|
|
57
|
+
const image = pageImages.get(region.page.name);
|
|
58
|
+
if (!image)
|
|
59
|
+
throw new Error(`Missing page image: ${region.page.name}`);
|
|
60
|
+
const w = region.width;
|
|
61
|
+
const h = region.height;
|
|
62
|
+
// Whole-page pass-through: an unrotated region covering its entire page
|
|
63
|
+
// would be cut into a pixel-for-pixel copy of the page image, so reuse
|
|
64
|
+
// the page URL instead — no canvas, no PNG re-encode, no second decoded
|
|
65
|
+
// copy in memory, and nothing to revoke afterwards. Atlases written as
|
|
66
|
+
// one part per page (the loose-part-PNG workflow, where every part is
|
|
67
|
+
// declared its own page) hit this for every single region.
|
|
68
|
+
//
|
|
69
|
+
// The test is against the image, not the atlas `size:` line: a page
|
|
70
|
+
// declared at the wrong size still goes through the cut, since the cut
|
|
71
|
+
// is what the region's coordinates actually describe.
|
|
72
|
+
if (region.degrees === 0 &&
|
|
73
|
+
region.x === 0 &&
|
|
74
|
+
region.y === 0 &&
|
|
75
|
+
w === image.naturalWidth &&
|
|
76
|
+
h === image.naturalHeight) {
|
|
77
|
+
return { url: image.src, width: w, height: h };
|
|
78
|
+
}
|
|
79
|
+
const canvas = document.createElement('canvas');
|
|
80
|
+
canvas.width = w;
|
|
81
|
+
canvas.height = h;
|
|
82
|
+
const ctx = canvas.getContext('2d');
|
|
83
|
+
if (!ctx)
|
|
84
|
+
throw new Error('2d context unavailable');
|
|
85
|
+
if (region.degrees === 90) {
|
|
86
|
+
// The region is packed rotated: it occupies an h×w rect in the page.
|
|
87
|
+
// Rotate it back so the bitmap is in artwork orientation.
|
|
88
|
+
ctx.translate(0, h);
|
|
89
|
+
ctx.rotate(-Math.PI / 2);
|
|
90
|
+
ctx.drawImage(image, region.x, region.y, h, w, 0, 0, h, w);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
ctx.drawImage(image, region.x, region.y, w, h, 0, 0, w, h);
|
|
94
|
+
}
|
|
95
|
+
const blob = await new Promise((resolve, reject) => {
|
|
96
|
+
canvas.toBlob((b) => (b ? resolve(b) : reject(new Error('toBlob failed'))), 'image/png');
|
|
97
|
+
});
|
|
98
|
+
const url = URL.createObjectURL(blob);
|
|
99
|
+
ownedUrls.add(url);
|
|
100
|
+
return { url, width: w, height: h };
|
|
101
|
+
}
|
|
27
102
|
/**
|
|
28
103
|
* Cuts every atlas region out of the page image into its own bitmap once at
|
|
29
104
|
* load time, restoring 90° packing rotation, so the per-frame path never
|
|
@@ -33,78 +108,106 @@ function revokeOwned(url) {
|
|
|
33
108
|
* rendering is pure DOM (one <img> per slot, one CSS matrix write per frame).
|
|
34
109
|
*
|
|
35
110
|
* A region that covers its whole page unrotated skips the cut and reuses the
|
|
36
|
-
* page image URL — see the pass-through
|
|
111
|
+
* page image URL — see the pass-through in cutRegion.
|
|
112
|
+
*
|
|
113
|
+
* **The cuts run concurrently.** PNG encoding is asynchronous and the browser
|
|
114
|
+
* does it off the main thread, so the encodes are started together and awaited
|
|
115
|
+
* together instead of one `toBlob` per iteration: awaited in series a load
|
|
116
|
+
* costs the *sum* of every encode, which a throttled document turns into one
|
|
117
|
+
* full throttle period per region (measured: a single 8×8 `toBlob` took 7.5 s
|
|
118
|
+
* to call back in a hidden desktop Chromium pane). How many run at once is
|
|
119
|
+
* bounded by CUT_BACKING_BUDGET_PX above, not by an option.
|
|
120
|
+
*
|
|
121
|
+
* Concurrency changes nothing a caller can observe:
|
|
122
|
+
*
|
|
123
|
+
* - **Order.** The returned map is keyed in `atlas.regions` order whatever
|
|
124
|
+
* order the blobs arrive in — the map is built after the cuts settle, from
|
|
125
|
+
* the region list, not from the arrivals.
|
|
126
|
+
* - **Duplicate names.** The last region of a given name in atlas order wins,
|
|
127
|
+
* and the shadowed URL is revoked (and dropped from the ledger) rather than
|
|
128
|
+
* stranded.
|
|
129
|
+
* - **Failure.** Every URL this call minted is revoked before the error
|
|
130
|
+
* propagates, *including cuts that were still in flight when the first
|
|
131
|
+
* failure happened* — their blobs arrive later, and a load that walked away
|
|
132
|
+
* from them would mint owned URLs nobody could ever revoke. So a failure
|
|
133
|
+
* stops new cuts from starting but still waits for the started ones, and the
|
|
134
|
+
* error it raises is the one from the earliest region in atlas order (what
|
|
135
|
+
* the serial loop used to throw). Nothing here rejects unobserved.
|
|
37
136
|
*
|
|
38
137
|
* The blob URLs stay alive until revokeRegions() frees them — a document-wide
|
|
39
138
|
* allocation the GC cannot reclaim on its own. Callers that load and unload
|
|
40
139
|
* skeletons repeatedly (cutscenes, level transitions) must pair every
|
|
41
140
|
* unpackRegions() with a revokeRegions(); a caller that loads once for the
|
|
42
|
-
* page lifetime can ignore it.
|
|
43
|
-
* everything it already minted is revoked before the error propagates.
|
|
141
|
+
* page lifetime can ignore it.
|
|
44
142
|
*/
|
|
45
143
|
export async function unpackRegions(atlas, pageImages) {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
h === image.naturalHeight) {
|
|
78
|
-
put(atlasRegion.name, { url: image.src, width: w, height: h });
|
|
79
|
-
continue;
|
|
144
|
+
const regions = atlas.regions;
|
|
145
|
+
const cuts = new Array(regions.length);
|
|
146
|
+
// The earliest-in-atlas-order failure is the one that propagates, so that a
|
|
147
|
+
// broken atlas reports the same region whichever encode happens to land
|
|
148
|
+
// first.
|
|
149
|
+
let failedIndex = -1;
|
|
150
|
+
let failure;
|
|
151
|
+
let inFlight = [];
|
|
152
|
+
let inFlightPixels = 0;
|
|
153
|
+
for (let index = 0; index < regions.length && failedIndex === -1; index++) {
|
|
154
|
+
const region = regions[index];
|
|
155
|
+
if (!region)
|
|
156
|
+
continue;
|
|
157
|
+
// A pass-through allocates no canvas, but it also resolves without waiting
|
|
158
|
+
// for anything, so charging it the region's area costs at most one drain.
|
|
159
|
+
const pixels = region.width * region.height;
|
|
160
|
+
while (inFlight.length > 0 && inFlightPixels + pixels > CUT_BACKING_BUDGET_PX) {
|
|
161
|
+
await Promise.race(inFlight.map((job) => job.promise));
|
|
162
|
+
inFlight = inFlight.filter((job) => !job.done);
|
|
163
|
+
if (failedIndex !== -1)
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
if (failedIndex !== -1)
|
|
167
|
+
break;
|
|
168
|
+
inFlightPixels += pixels;
|
|
169
|
+
const job = { done: false, promise: Promise.resolve() };
|
|
170
|
+
// Jobs settle, they never reject: the failure is recorded here so that
|
|
171
|
+
// nothing is left for an unhandled-rejection handler to find.
|
|
172
|
+
job.promise = (async () => {
|
|
173
|
+
try {
|
|
174
|
+
cuts[index] = await cutRegion(region, pageImages);
|
|
80
175
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
throw new Error('2d context unavailable');
|
|
87
|
-
if (region.degrees === 90) {
|
|
88
|
-
// The region is packed rotated: it occupies an h×w rect in the page.
|
|
89
|
-
// Rotate it back so the bitmap is in artwork orientation.
|
|
90
|
-
ctx.translate(0, h);
|
|
91
|
-
ctx.rotate(-Math.PI / 2);
|
|
92
|
-
ctx.drawImage(image, atlasRegion.x, atlasRegion.y, h, w, 0, 0, h, w);
|
|
176
|
+
catch (error) {
|
|
177
|
+
if (failedIndex === -1 || index < failedIndex) {
|
|
178
|
+
failedIndex = index;
|
|
179
|
+
failure = error;
|
|
180
|
+
}
|
|
93
181
|
}
|
|
94
|
-
|
|
95
|
-
|
|
182
|
+
finally {
|
|
183
|
+
inFlightPixels -= pixels;
|
|
184
|
+
job.done = true;
|
|
96
185
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
186
|
+
})();
|
|
187
|
+
inFlight.push(job);
|
|
188
|
+
}
|
|
189
|
+
// Every cut this call started is settled after this, so the cleanup below
|
|
190
|
+
// reaches the blobs that arrived after the first failure too.
|
|
191
|
+
await Promise.all(inFlight.map((job) => job.promise));
|
|
192
|
+
if (failedIndex !== -1) {
|
|
193
|
+
for (const cut of cuts)
|
|
194
|
+
if (cut)
|
|
195
|
+
revokeOwned(cut.url);
|
|
196
|
+
throw failure;
|
|
104
197
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
198
|
+
const result = new Map();
|
|
199
|
+
for (let index = 0; index < regions.length; index++) {
|
|
200
|
+
const region = regions[index];
|
|
201
|
+
const cut = cuts[index];
|
|
202
|
+
if (!region || !cut)
|
|
203
|
+
continue;
|
|
204
|
+
// Duplicate region names would otherwise strand the shadowed URL in the
|
|
205
|
+
// ledger with nothing left pointing at it. Map.set keeps the key where it
|
|
206
|
+
// first appeared, so atlas order survives the overwrite.
|
|
207
|
+
const shadowed = result.get(region.name);
|
|
208
|
+
if (shadowed)
|
|
209
|
+
revokeOwned(shadowed.url);
|
|
210
|
+
result.set(region.name, cut);
|
|
108
211
|
}
|
|
109
212
|
return result;
|
|
110
213
|
}
|
package/dist/DomTexture.js.map
CHANGED
|
@@ -1 +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;AAeD;;;;;;;GAOG;AACH,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;AAEpC,yEAAyE;AACzE,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC;QAAE,OAAO;IACnC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;AAC3B,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"DomTexture.js","sourceRoot":"","sources":["../src/DomTexture.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spine-html",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
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
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/dist/main.d.ts
DELETED
package/dist/main.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
|
package/dist/main.js
DELETED
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import { AnimationState, AnimationStateData, AtlasAttachmentLoader, Physics, Skeleton, SkeletonJson, TextureAtlas, } from '@esotericsoftware/spine-core';
|
|
2
|
-
import { DomTexture, unpackRegions } from './DomTexture.js';
|
|
3
|
-
import { SpineHtmlRenderer } from './SpineHtmlRenderer.js';
|
|
4
|
-
const ASSET_BASE = '/spineboy';
|
|
5
|
-
const SKELETONS = {
|
|
6
|
-
pro: 'spineboy-pro.json', // meshes (deform tier → per-part canvases)
|
|
7
|
-
ess: 'spineboy-ess.json', // region attachments only (rigid tier → pure DOM)
|
|
8
|
-
};
|
|
9
|
-
const STAGE_SCALE = 0.4;
|
|
10
|
-
// Debug knobs: ?skel=pro|ess &anim=walk &count=10 pick the scene;
|
|
11
|
-
// ?expand=0 shows the mesh cracks; ?tint=ff8080 tints the whole skeleton;
|
|
12
|
-
// ?dpr=2 overrides the mesh-canvas backing ratio; ?timescale=0 freezes the
|
|
13
|
-
// animation (isolates the dirty-skip path: every mesh should report reused);
|
|
14
|
-
// ?backend=webgl rasterizes meshes through the shared WebGL blitter;
|
|
15
|
-
// ?time=1.2 seeks every instance to the same pose (deterministic screenshots).
|
|
16
|
-
const params = new URLSearchParams(location.search);
|
|
17
|
-
function parseTint() {
|
|
18
|
-
const hex = params.get('tint');
|
|
19
|
-
if (!hex || !/^[0-9a-fA-F]{6}$/.test(hex))
|
|
20
|
-
return null;
|
|
21
|
-
return {
|
|
22
|
-
r: parseInt(hex.slice(0, 2), 16) / 255,
|
|
23
|
-
g: parseInt(hex.slice(2, 4), 16) / 255,
|
|
24
|
-
b: parseInt(hex.slice(4, 6), 16) / 255,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
async function loadImage(url) {
|
|
28
|
-
return new Promise((resolve, reject) => {
|
|
29
|
-
const img = new Image();
|
|
30
|
-
img.onload = () => resolve(img);
|
|
31
|
-
img.onerror = () => reject(new Error(`Failed to load ${url}`));
|
|
32
|
-
img.src = url;
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
async function load() {
|
|
36
|
-
const [atlasText, proText, essText] = await Promise.all([
|
|
37
|
-
fetch(`${ASSET_BASE}/spineboy.atlas`).then((r) => r.text()),
|
|
38
|
-
fetch(`${ASSET_BASE}/${SKELETONS.pro}`).then((r) => r.text()),
|
|
39
|
-
fetch(`${ASSET_BASE}/${SKELETONS.ess}`).then((r) => r.text()),
|
|
40
|
-
]);
|
|
41
|
-
const atlas = new TextureAtlas(atlasText);
|
|
42
|
-
const pageImages = new Map();
|
|
43
|
-
for (const page of atlas.pages) {
|
|
44
|
-
const image = await loadImage(`${ASSET_BASE}/${page.name}`);
|
|
45
|
-
page.setTexture(new DomTexture(image));
|
|
46
|
-
pageImages.set(page.name, image);
|
|
47
|
-
}
|
|
48
|
-
const regionImages = await unpackRegions(atlas, pageImages);
|
|
49
|
-
const loader = new AtlasAttachmentLoader(atlas);
|
|
50
|
-
return {
|
|
51
|
-
data: {
|
|
52
|
-
pro: new SkeletonJson(loader).readSkeletonData(proText),
|
|
53
|
-
ess: new SkeletonJson(loader).readSkeletonData(essText),
|
|
54
|
-
},
|
|
55
|
-
regionImages,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
function main(data, regionImages) {
|
|
59
|
-
const stage = document.getElementById('stage');
|
|
60
|
-
const skelSelect = document.getElementById('skel');
|
|
61
|
-
const animSelect = document.getElementById('anim');
|
|
62
|
-
const countInput = document.getElementById('count');
|
|
63
|
-
const backendSelect = document.getElementById('backend');
|
|
64
|
-
const stats = document.getElementById('stats');
|
|
65
|
-
backendSelect.value = params.get('backend') === 'webgl' ? 'webgl' : 'canvas2d';
|
|
66
|
-
const skelParam = params.get('skel');
|
|
67
|
-
let variant = skelParam === 'ess' ? 'ess' : 'pro';
|
|
68
|
-
skelSelect.value = variant;
|
|
69
|
-
let stateData = new AnimationStateData(data[variant]);
|
|
70
|
-
let instances = [];
|
|
71
|
-
const tint = parseTint();
|
|
72
|
-
function fillAnimations() {
|
|
73
|
-
animSelect.innerHTML = '';
|
|
74
|
-
for (const anim of data[variant].animations) {
|
|
75
|
-
const option = document.createElement('option');
|
|
76
|
-
option.value = anim.name;
|
|
77
|
-
option.textContent = anim.name;
|
|
78
|
-
animSelect.appendChild(option);
|
|
79
|
-
}
|
|
80
|
-
const names = data[variant].animations.map((a) => a.name);
|
|
81
|
-
animSelect.value = names.includes('walk') ? 'walk' : names[0];
|
|
82
|
-
}
|
|
83
|
-
function rebuild(count) {
|
|
84
|
-
for (const inst of instances) {
|
|
85
|
-
inst.renderer.dispose();
|
|
86
|
-
inst.container.remove();
|
|
87
|
-
}
|
|
88
|
-
instances = [];
|
|
89
|
-
for (let i = 0; i < count; i++) {
|
|
90
|
-
const container = document.createElement('div');
|
|
91
|
-
container.className = 'skeleton-root';
|
|
92
|
-
// Spread instances horizontally; each root is the skeleton origin
|
|
93
|
-
// (feet), so park it near the stage bottom.
|
|
94
|
-
const x = count === 1 ? 50 : 10 + (80 * i) / (count - 1);
|
|
95
|
-
container.style.left = `${x}%`;
|
|
96
|
-
container.style.transform = `scale(${STAGE_SCALE})`;
|
|
97
|
-
stage.appendChild(container);
|
|
98
|
-
const skeleton = new Skeleton(data[variant]);
|
|
99
|
-
if (tint)
|
|
100
|
-
skeleton.color.set(tint.r, tint.g, tint.b, 1);
|
|
101
|
-
const state = new AnimationState(stateData);
|
|
102
|
-
state.setAnimation(0, animSelect.value, true);
|
|
103
|
-
// Desync walk cycles so N instances don't look like one stamped sprite —
|
|
104
|
-
// unless ?time seeks them all to one pose (for deterministic captures).
|
|
105
|
-
const timeParam = params.get('time');
|
|
106
|
-
state.update(timeParam !== null ? Number(timeParam) || 0 : (i * 0.37) % 2);
|
|
107
|
-
const timescaleParam = params.get('timescale');
|
|
108
|
-
if (timescaleParam !== null)
|
|
109
|
-
state.timeScale = Number(timescaleParam) || 0;
|
|
110
|
-
const renderer = new SpineHtmlRenderer(container, regionImages);
|
|
111
|
-
renderer.meshBackend = backendSelect.value;
|
|
112
|
-
const expandParam = params.get('expand');
|
|
113
|
-
if (expandParam !== null)
|
|
114
|
-
renderer.triangleExpand = Number(expandParam) || 0;
|
|
115
|
-
// Mesh canvases raster at the effective on-screen resolution: device
|
|
116
|
-
// pixels × the stage downscale (a plain devicePixelRatio would
|
|
117
|
-
// oversample by 1/STAGE_SCALE).
|
|
118
|
-
const dprParam = params.get('dpr');
|
|
119
|
-
renderer.pixelRatio =
|
|
120
|
-
dprParam !== null ? Number(dprParam) || 1 : (window.devicePixelRatio || 1) * STAGE_SCALE;
|
|
121
|
-
instances.push({ skeleton, state, renderer, container });
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
skelSelect.addEventListener('change', () => {
|
|
125
|
-
variant = skelSelect.value;
|
|
126
|
-
stateData = new AnimationStateData(data[variant]);
|
|
127
|
-
stateData.defaultMix = 0.2;
|
|
128
|
-
fillAnimations();
|
|
129
|
-
rebuild(instances.length || 1);
|
|
130
|
-
});
|
|
131
|
-
animSelect.addEventListener('change', () => {
|
|
132
|
-
for (const inst of instances)
|
|
133
|
-
inst.state.setAnimation(0, animSelect.value, true);
|
|
134
|
-
});
|
|
135
|
-
countInput.addEventListener('change', () => {
|
|
136
|
-
const count = Math.min(50, Math.max(1, Number(countInput.value) || 1));
|
|
137
|
-
countInput.value = String(count);
|
|
138
|
-
rebuild(count);
|
|
139
|
-
});
|
|
140
|
-
backendSelect.addEventListener('change', () => {
|
|
141
|
-
// Live switch: the backend signature re-dirties every mesh on its own.
|
|
142
|
-
for (const inst of instances)
|
|
143
|
-
inst.renderer.meshBackend = backendSelect.value;
|
|
144
|
-
});
|
|
145
|
-
stateData.defaultMix = 0.2;
|
|
146
|
-
fillAnimations();
|
|
147
|
-
const animParam = params.get('anim');
|
|
148
|
-
if (animParam && data[variant].animations.some((a) => a.name === animParam)) {
|
|
149
|
-
animSelect.value = animParam;
|
|
150
|
-
}
|
|
151
|
-
const initialCount = Math.min(50, Math.max(1, Number(params.get('count')) || 1));
|
|
152
|
-
countInput.value = String(initialCount);
|
|
153
|
-
rebuild(initialCount);
|
|
154
|
-
// Click the stats line to copy it (hand-selecting it mid-animation is fiddly).
|
|
155
|
-
stats.title = 'click to copy';
|
|
156
|
-
stats.addEventListener('click', async () => {
|
|
157
|
-
try {
|
|
158
|
-
await navigator.clipboard.writeText(stats.textContent ?? '');
|
|
159
|
-
stats.style.color = '#ffd166';
|
|
160
|
-
setTimeout(() => (stats.style.color = ''), 300);
|
|
161
|
-
}
|
|
162
|
-
catch {
|
|
163
|
-
// Clipboard unavailable (non-secure context) — selecting stays possible.
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
// --- frame loop with split timings (skeleton math vs DOM writes) ---
|
|
167
|
-
let last = performance.now();
|
|
168
|
-
let updateMs = 0;
|
|
169
|
-
let renderMs = 0;
|
|
170
|
-
let frames = 0;
|
|
171
|
-
let statsAt = last;
|
|
172
|
-
function frame(now) {
|
|
173
|
-
const delta = Math.min((now - last) / 1000, 1 / 15);
|
|
174
|
-
last = now;
|
|
175
|
-
const t0 = performance.now();
|
|
176
|
-
for (const inst of instances) {
|
|
177
|
-
inst.state.update(delta);
|
|
178
|
-
inst.state.apply(inst.skeleton);
|
|
179
|
-
inst.skeleton.update(delta);
|
|
180
|
-
inst.skeleton.updateWorldTransform(Physics.update);
|
|
181
|
-
}
|
|
182
|
-
const t1 = performance.now();
|
|
183
|
-
for (const inst of instances)
|
|
184
|
-
inst.renderer.render(inst.skeleton);
|
|
185
|
-
const t2 = performance.now();
|
|
186
|
-
updateMs += t1 - t0;
|
|
187
|
-
renderMs += t2 - t1;
|
|
188
|
-
frames++;
|
|
189
|
-
if (now - statsAt >= 500 && frames > 0) {
|
|
190
|
-
let meshes = 0;
|
|
191
|
-
let reused = 0;
|
|
192
|
-
let reallocs = 0;
|
|
193
|
-
let triangles = 0;
|
|
194
|
-
let clips = 0;
|
|
195
|
-
let backing = 0;
|
|
196
|
-
for (const inst of instances) {
|
|
197
|
-
meshes += inst.renderer.meshCount;
|
|
198
|
-
reused += inst.renderer.meshReuseCount;
|
|
199
|
-
reallocs += inst.renderer.canvasReallocCount;
|
|
200
|
-
triangles += inst.renderer.triangleCount;
|
|
201
|
-
clips += inst.renderer.clipSkipCount;
|
|
202
|
-
backing += inst.renderer.meshBackingPixels;
|
|
203
|
-
}
|
|
204
|
-
const reallocNote = reallocs ? ` / ${reallocs} realloc'd` : '';
|
|
205
|
-
// Allocated mesh-canvas pixels: what an oversampling stage (a scaled
|
|
206
|
-
// root whose scale is not folded into pixelRatio) shows first.
|
|
207
|
-
const backingNote = backing ? ` · backing ${(backing / 1e6).toFixed(1)} Mpx` : '';
|
|
208
|
-
const meshNote = meshes + reused
|
|
209
|
-
? ` · mesh canvases ${meshes} drawn (${triangles} tris) / ${reused} reused${reallocNote}${backingNote}`
|
|
210
|
-
: '';
|
|
211
|
-
const first = instances[0]?.renderer;
|
|
212
|
-
// Surface the backend that actually ran, so a perf reading proves its path.
|
|
213
|
-
const backendNote = first && first.meshBackend === 'webgl'
|
|
214
|
-
? first.meshBackendActive === 'webgl'
|
|
215
|
-
? ' · webgl'
|
|
216
|
-
: ' · webgl unavailable → canvas2d'
|
|
217
|
-
: '';
|
|
218
|
-
const clipNote = clips ? ` · ${clips} clips skipped` : '';
|
|
219
|
-
// Real fps from rAF cadence: catches bottlenecks that live outside the
|
|
220
|
-
// frame callback (compositing, page throttling) which the ms split
|
|
221
|
-
// cannot see.
|
|
222
|
-
const fps = (frames * 1000) / (now - statsAt);
|
|
223
|
-
stats.textContent =
|
|
224
|
-
`${instances.length} skeleton(s) · ${fps.toFixed(0)} fps · ` +
|
|
225
|
-
`skeleton ${(updateMs / frames).toFixed(2)}ms · ` +
|
|
226
|
-
`render ${(renderMs / frames).toFixed(2)}ms / frame${meshNote}${backendNote}${clipNote}`;
|
|
227
|
-
updateMs = renderMs = 0;
|
|
228
|
-
frames = 0;
|
|
229
|
-
statsAt = now;
|
|
230
|
-
}
|
|
231
|
-
requestAnimationFrame(frame);
|
|
232
|
-
}
|
|
233
|
-
requestAnimationFrame(frame);
|
|
234
|
-
}
|
|
235
|
-
load()
|
|
236
|
-
.then(({ data, regionImages }) => main(data, regionImages))
|
|
237
|
-
.catch((err) => {
|
|
238
|
-
const stats = document.getElementById('stats');
|
|
239
|
-
if (stats)
|
|
240
|
-
stats.textContent = `Load failed: ${err.message} — did you run bun run fetch-assets?`;
|
|
241
|
-
console.error(err);
|
|
242
|
-
});
|
|
243
|
-
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,OAAO,EACP,QAAQ,EAER,YAAY,EACZ,YAAY,GACb,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,UAAU,EAAoB,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAAoB,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE7E,MAAM,UAAU,GAAG,WAAW,CAAC;AAC/B,MAAM,SAAS,GAAG;IAChB,GAAG,EAAE,mBAAmB,EAAE,2CAA2C;IACrE,GAAG,EAAE,mBAAmB,EAAE,kDAAkD;CACpE,CAAC;AAEX,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB,kEAAkE;AAClE,0EAA0E;AAC1E,2EAA2E;AAC3E,6EAA6E;AAC7E,qEAAqE;AACrE,+EAA+E;AAC/E,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAEpD,SAAS,SAAS;IAChB,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,OAAO;QACL,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG;QACtC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG;QACtC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG;KACvC,CAAC;AACJ,CAAC;AASD,KAAK,UAAU,SAAS,CAAC,GAAW;IAClC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAChC,GAAG,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,kBAAkB,GAAG,EAAE,CAAC,CAAC,CAAC;QAC/D,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,IAAI;IAIjB,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACtD,KAAK,CAAC,GAAG,UAAU,iBAAiB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3D,KAAK,CAAC,GAAG,UAAU,IAAI,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7D,KAAK,CAAC,GAAG,UAAU,IAAI,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;KAC9D,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,IAAI,GAAG,EAA4B,CAAC;IACvD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,GAAG,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;QACvC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,IAAI,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAChD,OAAO;QACL,IAAI,EAAE;YACJ,GAAG,EAAE,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC;YACvD,GAAG,EAAE,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC;SACxD;QACD,YAAY;KACb,CAAC;AACJ,CAAC;AAED,SAAS,IAAI,CACX,IAA2C,EAC3C,YAAsC;IAEtC,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAmB,CAAC;IACjE,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAsB,CAAC;IACxE,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAsB,CAAC;IACxE,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAqB,CAAC;IACxE,MAAM,aAAa,GAAG,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAsB,CAAC;IAC9E,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAmB,CAAC;IACjE,aAAa,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IAE/E,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,OAAO,GAAoB,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IACnE,UAAU,CAAC,KAAK,GAAG,OAAO,CAAC;IAC3B,IAAI,SAAS,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACtD,IAAI,SAAS,GAAe,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC;IAEzB,SAAS,cAAc;QACrB,UAAU,CAAC,SAAS,GAAG,EAAE,CAAC;QAC1B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAChD,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC;YACzB,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC;YAC/B,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1D,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,SAAS,OAAO,CAAC,KAAa;QAC5B,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;QAC1B,CAAC;QACD,SAAS,GAAG,EAAE,CAAC;QACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAChD,SAAS,CAAC,SAAS,GAAG,eAAe,CAAC;YACtC,kEAAkE;YAClE,4CAA4C;YAC5C,MAAM,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YACzD,SAAS,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC;YAC/B,SAAS,CAAC,KAAK,CAAC,SAAS,GAAG,SAAS,WAAW,GAAG,CAAC;YACpD,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YAE7B,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YAC7C,IAAI,IAAI;gBAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACxD,MAAM,KAAK,GAAG,IAAI,cAAc,CAAC,SAAS,CAAC,CAAC;YAC5C,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAC9C,yEAAyE;YACzE,wEAAwE;YACxE,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACrC,KAAK,CAAC,MAAM,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3E,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC/C,IAAI,cAAc,KAAK,IAAI;gBAAE,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YAE3E,MAAM,QAAQ,GAAG,IAAI,iBAAiB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;YAChE,QAAQ,CAAC,WAAW,GAAG,aAAa,CAAC,KAAoB,CAAC;YAC1D,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,WAAW,KAAK,IAAI;gBAAE,QAAQ,CAAC,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YAC7E,qEAAqE;YACrE,+DAA+D;YAC/D,gCAAgC;YAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACnC,QAAQ,CAAC,UAAU;gBACjB,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC,GAAG,WAAW,CAAC;YAC3F,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE;QACzC,OAAO,GAAG,UAAU,CAAC,KAAwB,CAAC;QAC9C,SAAS,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QAClD,SAAS,CAAC,UAAU,GAAG,GAAG,CAAC;QAC3B,cAAc,EAAE,CAAC;QACjB,OAAO,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IACH,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE;QACzC,KAAK,MAAM,IAAI,IAAI,SAAS;YAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IACH,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACvE,UAAU,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;IACH,aAAa,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE;QAC5C,uEAAuE;QACvE,KAAK,MAAM,IAAI,IAAI,SAAS;YAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG,aAAa,CAAC,KAAoB,CAAC;IAC/F,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,UAAU,GAAG,GAAG,CAAC;IAC3B,cAAc,EAAE,CAAC;IACjB,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;QAC5E,UAAU,CAAC,KAAK,GAAG,SAAS,CAAC;IAC/B,CAAC;IACD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjF,UAAU,CAAC,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACxC,OAAO,CAAC,YAAY,CAAC,CAAC;IAEtB,+EAA+E;IAC/E,KAAK,CAAC,KAAK,GAAG,eAAe,CAAC;IAC9B,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;QACzC,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;YAC7D,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC;YAC9B,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;QAC3E,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,sEAAsE;IACtE,IAAI,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,OAAO,GAAG,IAAI,CAAC;IAEnB,SAAS,KAAK,CAAC,GAAW;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QACpD,IAAI,GAAG,GAAG,CAAC;QAEX,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAChC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5B,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrD,CAAC;QACD,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,SAAS;YAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClE,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAE7B,QAAQ,IAAI,EAAE,GAAG,EAAE,CAAC;QACpB,QAAQ,IAAI,EAAE,GAAG,EAAE,CAAC;QACpB,MAAM,EAAE,CAAC;QAET,IAAI,GAAG,GAAG,OAAO,IAAI,GAAG,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YACvC,IAAI,MAAM,GAAG,CAAC,CAAC;YACf,IAAI,MAAM,GAAG,CAAC,CAAC;YACf,IAAI,QAAQ,GAAG,CAAC,CAAC;YACjB,IAAI,SAAS,GAAG,CAAC,CAAC;YAClB,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;gBAC7B,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAClC,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;gBACvC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC;gBAC7C,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;gBACzC,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;gBACrC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAC7C,CAAC;YACD,MAAM,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,QAAQ,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/D,qEAAqE;YACrE,+DAA+D;YAC/D,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YAClF,MAAM,QAAQ,GACZ,MAAM,GAAG,MAAM;gBACb,CAAC,CAAC,oBAAoB,MAAM,WAAW,SAAS,YAAY,MAAM,UAAU,WAAW,GAAG,WAAW,EAAE;gBACvG,CAAC,CAAC,EAAE,CAAC;YACT,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;YACrC,4EAA4E;YAC5E,MAAM,WAAW,GACf,KAAK,IAAI,KAAK,CAAC,WAAW,KAAK,OAAO;gBACpC,CAAC,CAAC,KAAK,CAAC,iBAAiB,KAAK,OAAO;oBACnC,CAAC,CAAC,UAAU;oBACZ,CAAC,CAAC,iCAAiC;gBACrC,CAAC,CAAC,EAAE,CAAC;YACT,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,KAAK,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,uEAAuE;YACvE,mEAAmE;YACnE,cAAc;YACd,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC;YAC9C,KAAK,CAAC,WAAW;gBACf,GAAG,SAAS,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;oBAC5D,YAAY,CAAC,QAAQ,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;oBACjD,UAAU,CAAC,QAAQ,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,QAAQ,GAAG,WAAW,GAAG,QAAQ,EAAE,CAAC;YAC3F,QAAQ,GAAG,QAAQ,GAAG,CAAC,CAAC;YACxB,MAAM,GAAG,CAAC,CAAC;YACX,OAAO,GAAG,GAAG,CAAC;QAChB,CAAC;QAED,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,qBAAqB,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,IAAI,EAAE;KACH,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;KAC1D,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACb,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAC/C,IAAI,KAAK;QAAE,KAAK,CAAC,WAAW,GAAG,gBAAgB,GAAG,CAAC,OAAO,sCAAsC,CAAC;IACjG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC,CAAC,CAAC"}
|