@codexo/exojs-aseprite 0.15.2 → 0.16.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/README.md +10 -24
- package/dist/esm/AsepriteData.d.ts +22 -6
- package/dist/esm/AsepriteData.d.ts.map +1 -0
- package/dist/esm/AsepriteData.js +4 -7
- package/dist/esm/AsepriteData.js.map +1 -1
- package/dist/esm/AsepriteSheet.d.ts +25 -11
- package/dist/esm/AsepriteSheet.d.ts.map +1 -0
- package/dist/esm/AsepriteSheet.js +212 -225
- package/dist/esm/AsepriteSheet.js.map +1 -1
- package/dist/esm/asepriteExtension.d.ts +5 -4
- package/dist/esm/asepriteExtension.d.ts.map +1 -0
- package/dist/esm/asepriteExtension.js +16 -16
- package/dist/esm/asepriteExtension.js.map +1 -1
- package/dist/esm/asepriteType.d.ts +28 -0
- package/dist/esm/asepriteType.d.ts.map +1 -0
- package/dist/esm/asepriteType.js +83 -0
- package/dist/esm/asepriteType.js.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +6 -5
- package/dist/esm/public.d.ts +3 -1
- package/dist/esm/public.d.ts.map +1 -0
- package/package.json +7 -14
- package/dist/esm/asepriteBinding.d.ts +0 -27
- package/dist/esm/asepriteBinding.js +0 -106
- package/dist/esm/asepriteBinding.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/register.d.ts +0 -1
- package/dist/esm/register.js +0 -15
- package/dist/esm/register.js.map +0 -1
|
@@ -1,232 +1,219 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { isAsepriteArrayData } from "./AsepriteData.js";
|
|
2
|
+
import { AnimatedSprite, Spritesheet } from "@codexo/exojs";
|
|
3
3
|
|
|
4
|
+
//#region src/AsepriteSheet.ts
|
|
4
5
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return Object.values(data.frames);
|
|
14
|
-
}
|
|
6
|
+
* Normalises an {@link AsepriteData} document into an ordered array of
|
|
7
|
+
* {@link AsepriteFrameData} entries regardless of whether the JSON was
|
|
8
|
+
* produced in array or hash mode.
|
|
9
|
+
*/
|
|
10
|
+
const normaliseFrames = (data) => {
|
|
11
|
+
if (isAsepriteArrayData(data)) return [...data.frames];
|
|
12
|
+
return Object.values(data.frames);
|
|
13
|
+
};
|
|
15
14
|
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
for (let i = from + 1; i < to; i++)
|
|
49
|
-
indices.push(i);
|
|
50
|
-
break;
|
|
51
|
-
case 'forward':
|
|
52
|
-
default:
|
|
53
|
-
for (let i = from; i <= to; i++)
|
|
54
|
-
indices.push(i);
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
return indices;
|
|
58
|
-
}
|
|
15
|
+
* Expands a frame tag's inclusive `[from, to]` range into the ordered
|
|
16
|
+
* sequence of frame indices it actually plays, according to its
|
|
17
|
+
* {@link AsepriteDirection}. Indices are not bounds-checked against the
|
|
18
|
+
* frame array here; callers filter out-of-range entries separately.
|
|
19
|
+
*
|
|
20
|
+
* - `forward`: `[from, from+1, ..., to]`.
|
|
21
|
+
* - `reverse`: `[to, to-1, ..., from]`.
|
|
22
|
+
* - `pingpong`: a forward pass followed by a backward pass that excludes
|
|
23
|
+
* both endpoints, e.g. `[0,1,2]` becomes `[0,1,2,1]`.
|
|
24
|
+
* - `pingpong_reverse`: the mirrored shape, starting from `to`.
|
|
25
|
+
* - A single-frame tag (`from === to`) always yields just that one frame.
|
|
26
|
+
*/
|
|
27
|
+
const expandFrameIndices = (tag) => {
|
|
28
|
+
const { from, to } = tag;
|
|
29
|
+
if (from === to) return [from];
|
|
30
|
+
const indices = [];
|
|
31
|
+
switch (tag.direction) {
|
|
32
|
+
case "reverse":
|
|
33
|
+
for (let i = to; i >= from; i--) indices.push(i);
|
|
34
|
+
break;
|
|
35
|
+
case "pingpong":
|
|
36
|
+
for (let i = from; i <= to; i++) indices.push(i);
|
|
37
|
+
for (let i = to - 1; i > from; i--) indices.push(i);
|
|
38
|
+
break;
|
|
39
|
+
case "pingpong_reverse":
|
|
40
|
+
for (let i = to; i >= from; i--) indices.push(i);
|
|
41
|
+
for (let i = from + 1; i < to; i++) indices.push(i);
|
|
42
|
+
break;
|
|
43
|
+
default: for (let i = from; i <= to; i++) indices.push(i);
|
|
44
|
+
}
|
|
45
|
+
return indices;
|
|
46
|
+
};
|
|
59
47
|
/**
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const totalMs = durations.reduce((sum, d) => sum + d, 0);
|
|
72
|
-
const avgMs = totalMs / durations.length;
|
|
73
|
-
return avgMs > 0 ? 1000 / avgMs : 12;
|
|
74
|
-
}
|
|
48
|
+
* Calculates the average frames-per-second for a sequence of frame indices,
|
|
49
|
+
* based on the per-frame `duration` field (milliseconds per frame) exported
|
|
50
|
+
* by Aseprite. Every occurrence of an index counts toward the average - for
|
|
51
|
+
* ping-pong sequences that means repeated (bounced) frames are weighted twice.
|
|
52
|
+
* Falls back to `12` fps when all durations are zero or the sequence is empty.
|
|
53
|
+
*/
|
|
54
|
+
const avgFps = (frames) => {
|
|
55
|
+
if (frames.length === 0) return 12;
|
|
56
|
+
const avgMs = frames.reduce((sum, { frameData }) => sum + frameData.duration, 0) / frames.length;
|
|
57
|
+
return avgMs > 0 ? 1e3 / avgMs : 12;
|
|
58
|
+
};
|
|
75
59
|
/**
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
60
|
+
* Resolves a tag's frame indices against the frame array, dropping any that
|
|
61
|
+
* fall outside it - Aseprite exports can reference frames a later edit removed.
|
|
62
|
+
*/
|
|
63
|
+
const resolveTaggedFrames = (frameArray, indices) => {
|
|
64
|
+
const resolved = [];
|
|
65
|
+
for (const index of indices) {
|
|
66
|
+
const frameData = frameArray[index];
|
|
67
|
+
if (frameData !== void 0) resolved.push({
|
|
68
|
+
index,
|
|
69
|
+
frameData
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return resolved;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Parsed representation of an Aseprite JSON sprite sheet export.
|
|
76
|
+
*
|
|
77
|
+
* `AsepriteSheet.parse(data, texture)` converts the raw JSON document into:
|
|
78
|
+
* - A {@link Spritesheet} whose frames correspond to the Aseprite frame array
|
|
79
|
+
* (keyed by zero-based index string: `"0"`, `"1"`, ...).
|
|
80
|
+
* - A `clips` map of {@link AnimatedSpriteClipDefinition} entries built from
|
|
81
|
+
* `meta.frameTags`, one per named tag.
|
|
82
|
+
* - The `slices` and `layers` metadata maps, carried through verbatim.
|
|
83
|
+
*
|
|
84
|
+
* Call {@link createAnimatedSprite} to obtain a ready-to-use
|
|
85
|
+
* {@link AnimatedSprite} with all clips pre-registered.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const sheet = await loader.load(Asset.type('asepriteSheet', 'hero.aseprite.json'));
|
|
90
|
+
* const sprite = sheet.createAnimatedSprite();
|
|
91
|
+
* sprite.play('run');
|
|
92
|
+
* scene.addChild(sprite);
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
var AsepriteSheet = class AsepriteSheet {
|
|
96
|
+
/** The underlying {@link Spritesheet} whose frames are keyed by index string. */
|
|
97
|
+
spritesheet;
|
|
98
|
+
/**
|
|
99
|
+
* Animation clips derived from the Aseprite `frameTags` metadata.
|
|
100
|
+
* Each clip's frames are live references into {@link spritesheet.frames};
|
|
101
|
+
* they are cloned automatically when passed to {@link AnimatedSprite.defineClip}.
|
|
102
|
+
*/
|
|
103
|
+
clips;
|
|
104
|
+
/**
|
|
105
|
+
* Named slices from the Aseprite `meta.slices` metadata, keyed by slice
|
|
106
|
+
* name. Slices describe editor-defined regions - hitboxes, nine-patch
|
|
107
|
+
* borders, UI anchor points - that aren't part of the frame/animation
|
|
108
|
+
* data itself. Each {@link AsepriteSlice} carries one {@link AsepriteSliceKey}
|
|
109
|
+
* per frame at which its bounds change; consumers resolve the applicable
|
|
110
|
+
* key for a given frame index themselves.
|
|
111
|
+
*/
|
|
112
|
+
slices;
|
|
113
|
+
/**
|
|
114
|
+
* Layers from the Aseprite `meta.layers` metadata, keyed by layer name and
|
|
115
|
+
* in export order (bottom-most first). Aseprite packs the sheet already
|
|
116
|
+
* composited, so these are descriptive rather than renderable: they tell a
|
|
117
|
+
* consumer which layers went into a frame and how - opacity, blend mode,
|
|
118
|
+
* editor user data - and {@link AsepriteLayer.group} names the enclosing
|
|
119
|
+
* group layer, so the flat map still encodes the layer tree.
|
|
120
|
+
*
|
|
121
|
+
* Empty when the export carries no `meta.layers` block. Layer names are
|
|
122
|
+
* unique within an Aseprite document, so keying by name loses nothing.
|
|
123
|
+
*/
|
|
124
|
+
layers;
|
|
125
|
+
/**
|
|
126
|
+
* @internal - use {@link AsepriteSheet.parse} to create instances.
|
|
127
|
+
* The public modifier is required for the Loader's `AssetConstructor` token
|
|
128
|
+
* contract; users should call `parse()` instead of constructing directly.
|
|
129
|
+
*/
|
|
130
|
+
constructor(spritesheet, clips, slices, layers = /* @__PURE__ */ new Map()) {
|
|
131
|
+
this.spritesheet = spritesheet;
|
|
132
|
+
this.clips = clips;
|
|
133
|
+
this.slices = slices;
|
|
134
|
+
this.layers = layers;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Parse a raw {@link AsepriteData} document and the already-loaded
|
|
138
|
+
* {@link Texture} into an {@link AsepriteSheet}.
|
|
139
|
+
*
|
|
140
|
+
* Supports both Aseprite array mode and hash mode. Frame indices from
|
|
141
|
+
* `frameTags` are resolved against the ordered frame array; out-of-range
|
|
142
|
+
* indices are silently skipped.
|
|
143
|
+
*
|
|
144
|
+
* A tag's `direction` determines the expanded frame sequence fed into the
|
|
145
|
+
* clip - `forward` and `reverse` play the `[from, to]` range in order or
|
|
146
|
+
* in reverse, while `pingpong`/`pingpong_reverse` append a backward pass
|
|
147
|
+
* (excluding both endpoints) so the bounce plays back correctly on the
|
|
148
|
+
* engine's forward-only {@link AnimatedSprite} playback. The tag's
|
|
149
|
+
* `repeat` field maps directly onto {@link AnimatedSpriteClipDefinition.repeat}:
|
|
150
|
+
* absent means the clip loops indefinitely (`repeat: -1`); a numeric
|
|
151
|
+
* string (`"1"`, `"2"`, ...) means it plays exactly that many full cycles
|
|
152
|
+
* before stopping.
|
|
153
|
+
*
|
|
154
|
+
* Each clip's `frameDurations` carries the real per-frame `duration` from
|
|
155
|
+
* the export (falling back to the tag's average when a frame's duration is
|
|
156
|
+
* non-positive), so uneven hold-frames survive into playback instead of
|
|
157
|
+
* being flattened to a uniform fps. `frameOffsets` carries each frame's
|
|
158
|
+
* `spriteSourceSize` `{x,y}` - its trimmed content's offset within the
|
|
159
|
+
* untrimmed canvas - whenever any frame in the tag is trimmed, so frames
|
|
160
|
+
* trimmed by different amounts stay anchored instead of jittering; it's
|
|
161
|
+
* omitted entirely for tags with no trimmed frames.
|
|
162
|
+
*/
|
|
163
|
+
static parse(data, texture) {
|
|
164
|
+
const frameArray = normaliseFrames(data);
|
|
165
|
+
const spritesheetFrames = {};
|
|
166
|
+
for (const [i, frameData] of frameArray.entries()) spritesheetFrames[String(i)] = { frame: frameData.frame };
|
|
167
|
+
const spritesheet = new Spritesheet(texture, { frames: spritesheetFrames });
|
|
168
|
+
const clips = /* @__PURE__ */ new Map();
|
|
169
|
+
const frameTags = data.meta.frameTags ?? [];
|
|
170
|
+
for (const tag of frameTags) {
|
|
171
|
+
const taggedFrames = resolveTaggedFrames(frameArray, expandFrameIndices(tag));
|
|
172
|
+
const frames = taggedFrames.map(({ index }) => spritesheet.getFrame(String(index)));
|
|
173
|
+
if (frames.length === 0) continue;
|
|
174
|
+
const repeat = tag.repeat !== void 0 ? Number(tag.repeat) : -1;
|
|
175
|
+
const fps = avgFps(taggedFrames);
|
|
176
|
+
const avgDurationFallback = 1e3 / fps;
|
|
177
|
+
const frameDurations = taggedFrames.map(({ frameData }) => frameData.duration > 0 ? frameData.duration : avgDurationFallback);
|
|
178
|
+
const frameOffsets = taggedFrames.some(({ frameData }) => frameData.trimmed) ? taggedFrames.map(({ frameData }) => {
|
|
179
|
+
const { x, y } = frameData.spriteSourceSize;
|
|
180
|
+
return {
|
|
181
|
+
x,
|
|
182
|
+
y
|
|
183
|
+
};
|
|
184
|
+
}) : void 0;
|
|
185
|
+
clips.set(tag.name, {
|
|
186
|
+
fps,
|
|
187
|
+
frames,
|
|
188
|
+
repeat,
|
|
189
|
+
frameDurations,
|
|
190
|
+
...frameOffsets ? { frameOffsets } : {}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const slices = /* @__PURE__ */ new Map();
|
|
194
|
+
for (const slice of data.meta.slices ?? []) slices.set(slice.name, slice);
|
|
195
|
+
const layers = /* @__PURE__ */ new Map();
|
|
196
|
+
for (const layer of data.meta.layers ?? []) layers.set(layer.name, layer);
|
|
197
|
+
return new AsepriteSheet(spritesheet, clips, slices, layers);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Create an {@link AnimatedSprite} with all frame-tag clips pre-defined.
|
|
201
|
+
*
|
|
202
|
+
* Each clip is registered via {@link AnimatedSprite.defineClip}, which
|
|
203
|
+
* clones the frame {@link Rectangle}s so the sprite owns its own copies.
|
|
204
|
+
* Call {@link AnimatedSprite.play} with a tag name to start playback.
|
|
205
|
+
*/
|
|
206
|
+
createAnimatedSprite() {
|
|
207
|
+
const sprite = new AnimatedSprite(this.spritesheet.texture);
|
|
208
|
+
for (const [name, clip] of this.clips) sprite.defineClip(name, clip);
|
|
209
|
+
return sprite;
|
|
210
|
+
}
|
|
211
|
+
/** Destroy the underlying {@link Spritesheet} and release its frame resources. */
|
|
212
|
+
destroy() {
|
|
213
|
+
this.spritesheet.destroy();
|
|
214
|
+
}
|
|
215
|
+
};
|
|
230
216
|
|
|
217
|
+
//#endregion
|
|
231
218
|
export { AsepriteSheet };
|
|
232
|
-
//# sourceMappingURL=AsepriteSheet.js.map
|
|
219
|
+
//# sourceMappingURL=AsepriteSheet.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AsepriteSheet.js","sources":["../../../src/AsepriteSheet.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AsepriteSheet.js","names":[],"sources":["../../src/AsepriteSheet.ts"],"sourcesContent":["import { AnimatedSprite, type AnimatedSpriteClipDefinition, Spritesheet, type Texture } from '@codexo/exojs';\n\nimport { type AsepriteData, type AsepriteFrameData, type AsepriteFrameTag, type AsepriteLayer, type AsepriteSlice, isAsepriteArrayData } from './AsepriteData';\n\n/**\n * Normalises an {@link AsepriteData} document into an ordered array of\n * {@link AsepriteFrameData} entries regardless of whether the JSON was\n * produced in array or hash mode.\n */\nconst normaliseFrames = (data: AsepriteData): AsepriteFrameData[] => {\n if (isAsepriteArrayData(data)) {\n return [...data.frames];\n }\n\n return Object.values(data.frames);\n};\n\n/**\n * Expands a frame tag's inclusive `[from, to]` range into the ordered\n * sequence of frame indices it actually plays, according to its\n * {@link AsepriteDirection}. Indices are not bounds-checked against the\n * frame array here; callers filter out-of-range entries separately.\n *\n * - `forward`: `[from, from+1, ..., to]`.\n * - `reverse`: `[to, to-1, ..., from]`.\n * - `pingpong`: a forward pass followed by a backward pass that excludes\n * both endpoints, e.g. `[0,1,2]` becomes `[0,1,2,1]`.\n * - `pingpong_reverse`: the mirrored shape, starting from `to`.\n * - A single-frame tag (`from === to`) always yields just that one frame.\n */\nconst expandFrameIndices = (tag: AsepriteFrameTag): number[] => {\n const { from, to } = tag;\n\n if (from === to) {\n return [from];\n }\n\n const indices: number[] = [];\n\n switch (tag.direction) {\n case 'reverse':\n for (let i = to; i >= from; i--) indices.push(i);\n break;\n\n case 'pingpong':\n for (let i = from; i <= to; i++) indices.push(i);\n for (let i = to - 1; i > from; i--) indices.push(i);\n break;\n\n case 'pingpong_reverse':\n for (let i = to; i >= from; i--) indices.push(i);\n for (let i = from + 1; i < to; i++) indices.push(i);\n break;\n\n case 'forward':\n default:\n for (let i = from; i <= to; i++) indices.push(i);\n break;\n }\n\n return indices;\n};\n\n/**\n * Calculates the average frames-per-second for a sequence of frame indices,\n * based on the per-frame `duration` field (milliseconds per frame) exported\n * by Aseprite. Every occurrence of an index counts toward the average - for\n * ping-pong sequences that means repeated (bounced) frames are weighted twice.\n * Falls back to `12` fps when all durations are zero or the sequence is empty.\n */\nconst avgFps = (frames: TaggedFrame[]): number => {\n if (frames.length === 0) {\n return 12;\n }\n\n const totalMs = frames.reduce((sum, { frameData }) => sum + frameData.duration, 0);\n const avgMs = totalMs / frames.length;\n\n return avgMs > 0 ? 1000 / avgMs : 12;\n};\n\n/**\n * A frame a tag actually resolved to, paired with the index it came from.\n * Resolving index and data together is what keeps every per-frame array below\n * (durations, offsets, spritesheet lookups) aligned without re-indexing.\n */\ninterface TaggedFrame {\n index: number;\n frameData: AsepriteFrameData;\n}\n\n/**\n * Resolves a tag's frame indices against the frame array, dropping any that\n * fall outside it - Aseprite exports can reference frames a later edit removed.\n */\nconst resolveTaggedFrames = (frameArray: AsepriteFrameData[], indices: number[]): TaggedFrame[] => {\n const resolved: TaggedFrame[] = [];\n\n for (const index of indices) {\n const frameData = frameArray[index];\n\n if (frameData !== undefined) {\n resolved.push({ index, frameData });\n }\n }\n\n return resolved;\n};\n\n/**\n * Parsed representation of an Aseprite JSON sprite sheet export.\n *\n * `AsepriteSheet.parse(data, texture)` converts the raw JSON document into:\n * - A {@link Spritesheet} whose frames correspond to the Aseprite frame array\n * (keyed by zero-based index string: `\"0\"`, `\"1\"`, ...).\n * - A `clips` map of {@link AnimatedSpriteClipDefinition} entries built from\n * `meta.frameTags`, one per named tag.\n * - The `slices` and `layers` metadata maps, carried through verbatim.\n *\n * Call {@link createAnimatedSprite} to obtain a ready-to-use\n * {@link AnimatedSprite} with all clips pre-registered.\n *\n * @example\n * ```ts\n * const sheet = await loader.load(Asset.type('asepriteSheet', 'hero.aseprite.json'));\n * const sprite = sheet.createAnimatedSprite();\n * sprite.play('run');\n * scene.addChild(sprite);\n * ```\n */\nexport class AsepriteSheet {\n /** The underlying {@link Spritesheet} whose frames are keyed by index string. */\n public readonly spritesheet: Spritesheet;\n\n /**\n * Animation clips derived from the Aseprite `frameTags` metadata.\n * Each clip's frames are live references into {@link spritesheet.frames};\n * they are cloned automatically when passed to {@link AnimatedSprite.defineClip}.\n */\n public readonly clips: ReadonlyMap<string, AnimatedSpriteClipDefinition>;\n\n /**\n * Named slices from the Aseprite `meta.slices` metadata, keyed by slice\n * name. Slices describe editor-defined regions - hitboxes, nine-patch\n * borders, UI anchor points - that aren't part of the frame/animation\n * data itself. Each {@link AsepriteSlice} carries one {@link AsepriteSliceKey}\n * per frame at which its bounds change; consumers resolve the applicable\n * key for a given frame index themselves.\n */\n public readonly slices: ReadonlyMap<string, AsepriteSlice>;\n\n /**\n * Layers from the Aseprite `meta.layers` metadata, keyed by layer name and\n * in export order (bottom-most first). Aseprite packs the sheet already\n * composited, so these are descriptive rather than renderable: they tell a\n * consumer which layers went into a frame and how - opacity, blend mode,\n * editor user data - and {@link AsepriteLayer.group} names the enclosing\n * group layer, so the flat map still encodes the layer tree.\n *\n * Empty when the export carries no `meta.layers` block. Layer names are\n * unique within an Aseprite document, so keying by name loses nothing.\n */\n public readonly layers: ReadonlyMap<string, AsepriteLayer>;\n\n /**\n * @internal - use {@link AsepriteSheet.parse} to create instances.\n * The public modifier is required for the Loader's `AssetConstructor` token\n * contract; users should call `parse()` instead of constructing directly.\n */\n public constructor(\n spritesheet: Spritesheet,\n clips: ReadonlyMap<string, AnimatedSpriteClipDefinition>,\n slices: ReadonlyMap<string, AsepriteSlice>,\n layers: ReadonlyMap<string, AsepriteLayer> = new Map(),\n ) {\n this.spritesheet = spritesheet;\n this.clips = clips;\n this.slices = slices;\n this.layers = layers;\n }\n\n /**\n * Parse a raw {@link AsepriteData} document and the already-loaded\n * {@link Texture} into an {@link AsepriteSheet}.\n *\n * Supports both Aseprite array mode and hash mode. Frame indices from\n * `frameTags` are resolved against the ordered frame array; out-of-range\n * indices are silently skipped.\n *\n * A tag's `direction` determines the expanded frame sequence fed into the\n * clip - `forward` and `reverse` play the `[from, to]` range in order or\n * in reverse, while `pingpong`/`pingpong_reverse` append a backward pass\n * (excluding both endpoints) so the bounce plays back correctly on the\n * engine's forward-only {@link AnimatedSprite} playback. The tag's\n * `repeat` field maps directly onto {@link AnimatedSpriteClipDefinition.repeat}:\n * absent means the clip loops indefinitely (`repeat: -1`); a numeric\n * string (`\"1\"`, `\"2\"`, ...) means it plays exactly that many full cycles\n * before stopping.\n *\n * Each clip's `frameDurations` carries the real per-frame `duration` from\n * the export (falling back to the tag's average when a frame's duration is\n * non-positive), so uneven hold-frames survive into playback instead of\n * being flattened to a uniform fps. `frameOffsets` carries each frame's\n * `spriteSourceSize` `{x,y}` - its trimmed content's offset within the\n * untrimmed canvas - whenever any frame in the tag is trimmed, so frames\n * trimmed by different amounts stay anchored instead of jittering; it's\n * omitted entirely for tags with no trimmed frames.\n */\n public static parse(data: AsepriteData, texture: Texture): AsepriteSheet {\n const frameArray = normaliseFrames(data);\n\n // Build SpritesheetData: frame names are zero-based index strings.\n const spritesheetFrames: Record<string, { frame: { x: number; y: number; w: number; h: number } }> = {};\n\n for (const [i, frameData] of frameArray.entries()) {\n spritesheetFrames[String(i)] = { frame: frameData.frame };\n }\n\n const spritesheet = new Spritesheet(texture, { frames: spritesheetFrames });\n\n // Build clips from frameTags, resolving frame indices into Rectangles.\n const clips = new Map<string, AnimatedSpriteClipDefinition>();\n const frameTags = data.meta.frameTags ?? [];\n\n for (const tag of frameTags) {\n // Out-of-range indices are silently skipped; `taggedFrames` parallels\n // `frames` exactly, so it's the basis for every other per-frame array\n // (durations, offsets) built below.\n const taggedFrames = resolveTaggedFrames(frameArray, expandFrameIndices(tag));\n const frames = taggedFrames.map(({ index }) => spritesheet.getFrame(String(index)));\n\n if (frames.length === 0) {\n continue;\n }\n\n // Aseprite's `tag.repeat` (a numeric string, `'1'` through any N) maps\n // directly onto the engine's `repeat` count. Absent means the tag\n // loops indefinitely, the engine's `-1` sentinel.\n const repeat = tag.repeat !== undefined ? Number(tag.repeat) : -1;\n const fps = avgFps(taggedFrames);\n\n // Per-frame hold duration (Aseprite \"duration\"), so uneven hold-frames\n // (e.g. a lingering idle frame) survive into playback instead of being\n // flattened to the tag's average fps. A non-positive duration (same\n // degenerate case `avgFps` guards against) falls back to the average.\n const avgDurationFallback = 1000 / fps;\n const frameDurations = taggedFrames.map(({ frameData }) => (frameData.duration > 0 ? frameData.duration : avgDurationFallback));\n\n // Per-frame trim offset (Aseprite \"spriteSourceSize\"), so frames trimmed\n // by different amounts stay anchored to the same point in the untrimmed\n // canvas instead of jittering frame to frame. Omitted entirely when no\n // frame in the tag is trimmed, to avoid noise on untrimmed sheets.\n const anyTrimmed = taggedFrames.some(({ frameData }) => frameData.trimmed);\n const frameOffsets = anyTrimmed\n ? taggedFrames.map(({ frameData }) => {\n const { x, y } = frameData.spriteSourceSize;\n\n return { x, y };\n })\n : undefined;\n\n clips.set(tag.name, {\n fps,\n frames,\n repeat,\n frameDurations,\n ...(frameOffsets ? { frameOffsets } : {}),\n });\n }\n\n // Build the slices map from meta.slices, keyed by slice name.\n const slices = new Map<string, AsepriteSlice>();\n\n for (const slice of data.meta.slices ?? []) {\n slices.set(slice.name, slice);\n }\n\n // Same for meta.layers - insertion order is the export order, so the map\n // doubles as the ordered layer list.\n const layers = new Map<string, AsepriteLayer>();\n\n for (const layer of data.meta.layers ?? []) {\n layers.set(layer.name, layer);\n }\n\n return new AsepriteSheet(spritesheet, clips, slices, layers);\n }\n\n /**\n * Create an {@link AnimatedSprite} with all frame-tag clips pre-defined.\n *\n * Each clip is registered via {@link AnimatedSprite.defineClip}, which\n * clones the frame {@link Rectangle}s so the sprite owns its own copies.\n * Call {@link AnimatedSprite.play} with a tag name to start playback.\n */\n public createAnimatedSprite(): AnimatedSprite {\n const sprite = new AnimatedSprite(this.spritesheet.texture);\n\n for (const [name, clip] of this.clips) {\n sprite.defineClip(name, clip);\n }\n\n return sprite;\n }\n\n /** Destroy the underlying {@link Spritesheet} and release its frame resources. */\n public destroy(): void {\n this.spritesheet.destroy();\n }\n}\n"],"mappings":"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"}
|
|
@@ -2,12 +2,13 @@ import type { Extension } from '@codexo/exojs/extensions';
|
|
|
2
2
|
/**
|
|
3
3
|
* Default immutable Aseprite extension descriptor.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* - {@link
|
|
5
|
+
* Installs one asset type:
|
|
6
|
+
* - {@link asepriteType} - `loader.load(asepriteType.asset('hero.aseprite.json'))`
|
|
7
7
|
* fetches the Aseprite JSON, resolves and loads the packed texture, and
|
|
8
8
|
* returns a fully-parsed {@link AsepriteSheet} with all frame-tag clips.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
* `
|
|
10
|
+
* Pass it to the application that should have it via
|
|
11
|
+
* `ApplicationOptions.extensions`.
|
|
12
12
|
*/
|
|
13
13
|
export declare const asepriteExtension: Extension;
|
|
14
|
+
//# sourceMappingURL=asepriteExtension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asepriteExtension.d.ts","sourceRoot":"","sources":["../../src/asepriteExtension.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAI1D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAG9B,CAAC"}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { asepriteType } from "./asepriteType.js";
|
|
2
2
|
|
|
3
|
+
//#region src/asepriteExtension.ts
|
|
3
4
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
* Default immutable Aseprite extension descriptor.
|
|
6
|
+
*
|
|
7
|
+
* Installs one asset type:
|
|
8
|
+
* - {@link asepriteType} - `loader.load(asepriteType.asset('hero.aseprite.json'))`
|
|
9
|
+
* fetches the Aseprite JSON, resolves and loads the packed texture, and
|
|
10
|
+
* returns a fully-parsed {@link AsepriteSheet} with all frame-tag clips.
|
|
11
|
+
*
|
|
12
|
+
* Pass it to the application that should have it via
|
|
13
|
+
* `ApplicationOptions.extensions`.
|
|
14
|
+
*/
|
|
14
15
|
const asepriteExtension = Object.freeze({
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// untyped Extension.assets contract here. Runtime behavior is unaffected.
|
|
18
|
-
assets: [asepriteBinding],
|
|
16
|
+
id: "@codexo/exojs-aseprite",
|
|
17
|
+
assets: [asepriteType]
|
|
19
18
|
});
|
|
20
19
|
|
|
20
|
+
//#endregion
|
|
21
21
|
export { asepriteExtension };
|
|
22
|
-
//# sourceMappingURL=asepriteExtension.js.map
|
|
22
|
+
//# sourceMappingURL=asepriteExtension.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asepriteExtension.js","sources":["
|
|
1
|
+
{"version":3,"file":"asepriteExtension.js","names":[],"sources":["../../src/asepriteExtension.ts"],"sourcesContent":["import type { Extension } from '@codexo/exojs/extensions';\n\nimport { asepriteType } from './asepriteType';\n\n/**\n * Default immutable Aseprite extension descriptor.\n *\n * Installs one asset type:\n * - {@link asepriteType} - `loader.load(asepriteType.asset('hero.aseprite.json'))`\n * fetches the Aseprite JSON, resolves and loads the packed texture, and\n * returns a fully-parsed {@link AsepriteSheet} with all frame-tag clips.\n *\n * Pass it to the application that should have it via\n * `ApplicationOptions.extensions`.\n */\nexport const asepriteExtension: Extension = Object.freeze({\n id: '@codexo/exojs-aseprite',\n assets: [asepriteType],\n});\n"],"mappings":";;;;;;;;;;;;;;AAeA,MAAa,oBAA+B,OAAO,OAAO;CACxD,IAAI;CACJ,QAAQ,CAAC,YAAY;AACvB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AssetFactory, AssetSourceCodec } from '@codexo/exojs';
|
|
2
|
+
import { AssetType } from '@codexo/exojs';
|
|
3
|
+
import type { AsepriteData } from './AsepriteData';
|
|
4
|
+
import { AsepriteSheet } from './AsepriteSheet';
|
|
5
|
+
/**
|
|
6
|
+
* Thrown when an Aseprite JSON document does not match the expected shape.
|
|
7
|
+
* `source` is the URL of the file being parsed.
|
|
8
|
+
*/
|
|
9
|
+
export declare class AsepriteFormatError extends Error {
|
|
10
|
+
readonly source: string;
|
|
11
|
+
constructor(source: string, message: string);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Aseprite JSON exports, together with the packed sheet they reference.
|
|
15
|
+
*
|
|
16
|
+
* The image URL is read from `meta.image` and resolved against the JSON file's
|
|
17
|
+
* own location; the texture is claimed by this sheet's dependency scope, so it
|
|
18
|
+
* lives exactly as long as the sheet does.
|
|
19
|
+
*/
|
|
20
|
+
export declare class AsepriteAssetType extends AssetType<AsepriteData, AsepriteSheet, undefined, string> {
|
|
21
|
+
readonly id = "asepriteSheet";
|
|
22
|
+
readonly _token: typeof AsepriteSheet;
|
|
23
|
+
readonly codec: AssetSourceCodec<AsepriteData, string>;
|
|
24
|
+
createFactory(): AssetFactory<AsepriteData, AsepriteSheet>;
|
|
25
|
+
}
|
|
26
|
+
/** The Aseprite sheet asset type. Install it through {@link asepriteExtension}. */
|
|
27
|
+
export declare const asepriteType: AsepriteAssetType;
|
|
28
|
+
//# sourceMappingURL=asepriteType.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asepriteType.d.ts","sourceRoot":"","sources":["../../src/asepriteType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAW,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAS,SAAS,EAAmB,MAAM,eAAe,CAAC;AAKlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA0ChD;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,SAAgB,MAAM,EAAE,MAAM,CAAC;gBAEZ,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAKnD;AAqCD;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,SAAS,CAAC,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC;IAC9F,SAAgB,EAAE,mBAAmB;IACrC,SAAyB,MAAM,uBAAiB;IAGhD,SAAyB,KAAK,EAAE,gBAAgB,CAAC,YAAY,EAAE,MAAM,CAAC,CAIpE;IAEK,aAAa,IAAI,YAAY,CAAC,YAAY,EAAE,aAAa,CAAC;CASlE;AAED,mFAAmF;AACnF,eAAO,MAAM,YAAY,mBAA0B,CAAC"}
|