aispritejs 0.5.8 → 0.6.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 -7
- package/README_ZHTW.md +11 -7
- package/dist/atlas/index.cjs +42 -48
- package/dist/atlas/index.cjs.map +1 -1
- package/dist/atlas/index.d.cts +6 -3
- package/dist/atlas/index.d.ts +6 -3
- package/dist/atlas/index.js +35 -41
- package/dist/atlas/index.js.map +1 -1
- package/dist/{chunk-QF5N7LOI.cjs → chunk-GEQWS7FY.cjs} +122 -96
- package/dist/chunk-GEQWS7FY.cjs.map +1 -0
- package/dist/{chunk-6E4ILDBY.js → chunk-NBMU2UNJ.js} +122 -97
- package/dist/chunk-NBMU2UNJ.js.map +1 -0
- package/dist/index.cjs +6 -6
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +1 -1
- package/dist/pixi/index.cjs +20 -12
- package/dist/pixi/index.cjs.map +1 -1
- package/dist/pixi/index.d.cts +17 -7
- package/dist/pixi/index.d.ts +17 -7
- package/dist/pixi/index.js +19 -11
- package/dist/pixi/index.js.map +1 -1
- package/dist/{types-BS72pefJ.d.cts → types-Dr7yXTRQ.d.cts} +29 -8
- package/dist/{types-BS72pefJ.d.ts → types-Dr7yXTRQ.d.ts} +29 -8
- package/llms-full.txt +50 -14
- package/package.json +25 -10
- package/dist/chunk-6E4ILDBY.js.map +0 -1
- package/dist/chunk-QF5N7LOI.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Input-driven, renderer-agnostic 2D sprite animation runtime. A JSON graph maps Number/Boolean/Trigger inputs to visual states and frames; adapters bind the chosen frame to a renderer.
|
|
4
4
|
|
|
5
|
-
> **Status: 0.
|
|
5
|
+
> **Status: 0.6.0 - stable family-aligned surface.** Core, PixiJS adapter, atlas parser, and JSON Schema subpath are shipped.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -25,8 +25,8 @@ const anim = createSpriteAnimator({
|
|
|
25
25
|
},
|
|
26
26
|
initial: "idle",
|
|
27
27
|
states: {
|
|
28
|
-
idle: { animation: "idle" },
|
|
29
|
-
run: { animation: "run", speed: 1 },
|
|
28
|
+
idle: { animation: "idle", loop: true },
|
|
29
|
+
run: { animation: "run", loop: true, speed: 1 },
|
|
30
30
|
jump: { animation: "jump", loop: false, onEnd: "idle" },
|
|
31
31
|
},
|
|
32
32
|
transitions: [
|
|
@@ -64,13 +64,14 @@ view.dispose(); // disposes core animator; does not destroy the Pixi sprite
|
|
|
64
64
|
- `loadAtlas(atlas, control?)` parses and creates a `SpriteAnimator`.
|
|
65
65
|
- `aispritejs/schema` exports `schemas/aispritejs-graph.schema.json` for editor/CI validation.
|
|
66
66
|
- Parser validation is structural (`InvalidAtlasError`); compiler validation is semantic (`InvalidGraphError`).
|
|
67
|
+
- An explicit `control` gets the same structural checks as a control block inside the atlas, and its `initial` / `defaultFrameDuration` must be a string / number (an atlas's own block drops wrong-typed ones).
|
|
67
68
|
|
|
68
69
|
## Core API
|
|
69
70
|
|
|
70
|
-
- `createSpriteAnimator(graph)` returns a `SpriteAnimator
|
|
71
|
+
- `createSpriteAnimator(graph)` returns a `SpriteAnimator`; a malformed or invalid graph throws `InvalidGraphError` and builds nothing.
|
|
71
72
|
- `setInput(name, value)` accepts Number/Boolean inputs.
|
|
72
73
|
- `fireTrigger(name)` consumes Trigger inputs on transition.
|
|
73
|
-
- `update(deltaMs)` advances time, transitions, frame index, and `onEnd`.
|
|
74
|
+
- `update(deltaMs)` advances time, transitions, frame index, and `onEnd`. A negative, non-finite, or overflowing step is clamped to no progress.
|
|
74
75
|
- `reset()` returns to the initial state.
|
|
75
76
|
- `dispose()` is idempotent; mutators throw `SpriteAnimatorDisposedError` afterward.
|
|
76
77
|
- `onStateChange(handler, options?)` and `onComplete(handler, options?)` support `once` and `signal`.
|
|
@@ -78,10 +79,12 @@ view.dispose(); // disposes core animator; does not destroy the Pixi sprite
|
|
|
78
79
|
## Sharp Edges
|
|
79
80
|
|
|
80
81
|
- Non-looping states with `onEnd` transition during the same `update()` tick that completes the clip.
|
|
82
|
+
- `reset()`/`update()` called from inside `onStateChange`/`onComplete` run after the current update finishes (including its `onEnd` auto-transition); a `reset()` from `onComplete` therefore yields `onStateChange(onEndTarget, from)` then `onStateChange(initial, onEndTarget)`, ending in the initial state; `dispose()` from a listener stops the update immediately.
|
|
81
83
|
- `AnimatedSprite` is accepted by the Pixi adapter because it extends `Sprite`, but playback is stopped on bind so it cannot fight the adapter.
|
|
82
|
-
- Every
|
|
84
|
+
- Every frame key in every declared animation must exist in the texture map/spritesheet — including an animation no state references — or the adapter throws `MissingTextureError` at construction. A `null` / `undefined` entry counts as missing.
|
|
85
|
+
- A texture map with an object under the key `textures` is read as a `Spritesheet`; if a frame is literally named `textures`, pass the `Spritesheet` (or `{ textures: map }`) instead of the bare map.
|
|
83
86
|
- `duration`, `defaultFrameDuration`, and state `speed` must be finite numbers greater than zero.
|
|
84
|
-
-
|
|
87
|
+
- `initial`, state `animation` / `onEnd`, transition `from` / `to`, and condition `input` / `op` must be strings, and a transition `priority` must be an integer.
|
|
85
88
|
|
|
86
89
|
## AI Context
|
|
87
90
|
|
package/README_ZHTW.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Input-driven、renderer-agnostic 的 2D sprite animation runtime。JSON graph 會把 Number/Boolean/Trigger inputs 對應到 visual states 與 frames;adapter 再把選到的 frame 綁到 renderer。
|
|
4
4
|
|
|
5
|
-
> **狀態:0.
|
|
5
|
+
> **狀態:0.6.0 - 穩定 family-aligned API。** Core、PixiJS adapter、atlas parser、JSON Schema subpath 都已發布。
|
|
6
6
|
|
|
7
7
|
## 安裝
|
|
8
8
|
|
|
@@ -25,8 +25,8 @@ const anim = createSpriteAnimator({
|
|
|
25
25
|
},
|
|
26
26
|
initial: "idle",
|
|
27
27
|
states: {
|
|
28
|
-
idle: { animation: "idle" },
|
|
29
|
-
run: { animation: "run", speed: 1 },
|
|
28
|
+
idle: { animation: "idle", loop: true },
|
|
29
|
+
run: { animation: "run", loop: true, speed: 1 },
|
|
30
30
|
jump: { animation: "jump", loop: false, onEnd: "idle" },
|
|
31
31
|
},
|
|
32
32
|
transitions: [
|
|
@@ -64,13 +64,14 @@ view.dispose(); // dispose core animator;不 destroy Pixi sprite
|
|
|
64
64
|
- `loadAtlas(atlas, control?)` parse 後直接建立 `SpriteAnimator`。
|
|
65
65
|
- `aispritejs/schema` 匯出 `schemas/aispritejs-graph.schema.json`,可用於 editor/CI validation。
|
|
66
66
|
- Parser 做 structural validation(`InvalidAtlasError`);compiler 做 semantic validation(`InvalidGraphError`)。
|
|
67
|
+
- 明確傳入的 `control` 會套用與 atlas 內嵌 control block 相同的 structural 檢查,且 `initial` / `defaultFrameDuration` 必須分別是 string / number(atlas 自己的 block 則會略過型別錯誤的欄位)。
|
|
67
68
|
|
|
68
69
|
## 核心 API
|
|
69
70
|
|
|
70
|
-
- `createSpriteAnimator(graph)` 回傳 `SpriteAnimator
|
|
71
|
+
- `createSpriteAnimator(graph)` 回傳 `SpriteAnimator`;graph 結構錯誤或無效時丟出 `InvalidGraphError`,不會建立任何 animator。
|
|
71
72
|
- `setInput(name, value)` 接受 Number/Boolean inputs。
|
|
72
73
|
- `fireTrigger(name)` 觸發 Trigger input,transition 後會消耗。
|
|
73
|
-
- `update(deltaMs)` 推進時間、transition、frame index 與 `onEnd
|
|
74
|
+
- `update(deltaMs)` 推進時間、transition、frame index 與 `onEnd`。負數、非 finite 或會溢位的 step 一律視為不前進。
|
|
74
75
|
- `reset()` 回到 initial state。
|
|
75
76
|
- `dispose()` 可重複呼叫;dispose 後 mutators 會丟 `SpriteAnimatorDisposedError`。
|
|
76
77
|
- `onStateChange(handler, options?)` 與 `onComplete(handler, options?)` 支援 `once` 與 `signal`。
|
|
@@ -78,10 +79,13 @@ view.dispose(); // dispose core animator;不 destroy Pixi sprite
|
|
|
78
79
|
## 注意事項
|
|
79
80
|
|
|
80
81
|
- 非 loop state 若有 `onEnd`,會在 clip 完成的同一個 `update()` tick 轉場。
|
|
82
|
+
- 在 `onStateChange`/`onComplete` 內呼叫的 `reset()`/`update()` 會排入佇列,等目前這次 update(包含其 `onEnd` 自動轉場)結束後才執行;因此在 `onComplete` 呼叫 `reset()` 會先觸發 `onStateChange(onEndTarget, from)`,再觸發 `onStateChange(initial, onEndTarget)`,最後停在 initial state;在 listener 內呼叫 `dispose()` 則會立刻停止這次 update。
|
|
81
83
|
- Pixi adapter 接受 `AnimatedSprite`,因為它 extends `Sprite`;bind 時會 stop playback,避免跟 adapter 搶 texture。
|
|
82
|
-
-
|
|
84
|
+
- 每個 animation(即使沒有任何 state 參照到它)裡的每個 frame key 都必須存在於 texture map/spritesheet,否則 adapter 會在 construction 時丟 `MissingTextureError`。值為 `null` / `undefined` 的 entry 也視為缺少。
|
|
85
|
+
- texture map 若在 `textures` key 下放了物件,會被當成 `Spritesheet` 讀取;若真的有 frame 叫 `textures`,請傳入 `Spritesheet`(或 `{ textures: map }`),不要直接傳 map。
|
|
83
86
|
- `duration`、`defaultFrameDuration`、state `speed` 都必須是 finite 且大於 0。
|
|
84
|
-
-
|
|
87
|
+
- `initial`、state 的 `animation` / `onEnd`、transition 的 `from` / `to`、condition 的 `input` / `op` 都必須是 string,transition `priority` 必須是整數。
|
|
88
|
+
- `animations` 不可為空物件(`minProperties: 1`);`duration`、`defaultFrameDuration` 上限為 86,400,000 ms(24 小時),state `speed` 上限為 1000——schema 與 runtime 已一致。
|
|
85
89
|
|
|
86
90
|
## AI Context
|
|
87
91
|
|
package/dist/atlas/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkGEQWS7FY_cjs = require('../chunk-GEQWS7FY.cjs');
|
|
4
4
|
|
|
5
5
|
// src/atlas/parse.ts
|
|
6
6
|
var InvalidAtlasError = class extends Error {
|
|
@@ -10,10 +10,16 @@ var InvalidAtlasError = class extends Error {
|
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
12
|
function isForeignStates(states) {
|
|
13
|
-
return
|
|
13
|
+
return chunkGEQWS7FY_cjs.isObject(states) && typeof states.initial === "string" && chunkGEQWS7FY_cjs.isObject(states.definitions);
|
|
14
|
+
}
|
|
15
|
+
function typeName(v) {
|
|
16
|
+
return v === null ? "null" : Array.isArray(v) ? "array" : typeof v;
|
|
17
|
+
}
|
|
18
|
+
function assertEntry(v, what) {
|
|
19
|
+
if (!chunkGEQWS7FY_cjs.isObject(v)) throw new InvalidAtlasError(`${what} must be an object, got ${typeName(v)}`);
|
|
14
20
|
}
|
|
15
21
|
function assertAnimations(value) {
|
|
16
|
-
if (!
|
|
22
|
+
if (!chunkGEQWS7FY_cjs.isObject(value)) {
|
|
17
23
|
throw new InvalidAtlasError("`animations` must be an object of frame-key lists");
|
|
18
24
|
}
|
|
19
25
|
for (const [name, list] of Object.entries(value)) {
|
|
@@ -23,25 +29,44 @@ function assertAnimations(value) {
|
|
|
23
29
|
}
|
|
24
30
|
return value;
|
|
25
31
|
}
|
|
32
|
+
function assertControlShape(src, p) {
|
|
33
|
+
if (!chunkGEQWS7FY_cjs.isObject(src.inputs)) throw new InvalidAtlasError(`${p}inputs must be an object`);
|
|
34
|
+
if (!chunkGEQWS7FY_cjs.isObject(src.states)) throw new InvalidAtlasError(`${p}states must be an object`);
|
|
35
|
+
if (!Array.isArray(src.transitions)) {
|
|
36
|
+
throw new InvalidAtlasError(`${p}transitions must be an array`);
|
|
37
|
+
}
|
|
38
|
+
for (const [key, val] of Object.entries(src.inputs)) assertEntry(val, `${p}input entry "${key}"`);
|
|
39
|
+
for (const [key, val] of Object.entries(src.states)) assertEntry(val, `${p}state entry "${key}"`);
|
|
40
|
+
src.transitions.forEach((entry, i) => {
|
|
41
|
+
assertEntry(entry, `${p}transitions[${i}]`);
|
|
42
|
+
const when = entry.when;
|
|
43
|
+
if (Array.isArray(when)) {
|
|
44
|
+
when.forEach((cond, j) => assertEntry(cond, `${p}transitions[${i}].when[${j}]`));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
26
48
|
function parseAtlas(atlas, control) {
|
|
27
|
-
if (!
|
|
49
|
+
if (!chunkGEQWS7FY_cjs.isObject(atlas)) {
|
|
28
50
|
throw new InvalidAtlasError("atlas must be an object");
|
|
29
51
|
}
|
|
30
52
|
const animations = assertAnimations(atlas.animations);
|
|
31
53
|
const frames = atlas.frames;
|
|
32
|
-
if (frames !== void 0 && !
|
|
54
|
+
if (frames !== void 0 && !chunkGEQWS7FY_cjs.isObject(frames)) {
|
|
33
55
|
throw new InvalidAtlasError("`frames`, if present, must be an object keyed by frame key");
|
|
34
56
|
}
|
|
35
|
-
if (
|
|
36
|
-
for (const [key, entry] of Object.entries(frames)) {
|
|
37
|
-
if (!chunkQF5N7LOI_cjs.isObject(entry)) {
|
|
38
|
-
const actualType = entry === null ? "null" : Array.isArray(entry) ? "array" : typeof entry;
|
|
39
|
-
throw new InvalidAtlasError(`frame entry "${key}" must be an object, got ${actualType}`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
57
|
+
if (chunkGEQWS7FY_cjs.isObject(frames)) {
|
|
58
|
+
for (const [key, entry] of Object.entries(frames)) assertEntry(entry, `frame entry "${key}"`);
|
|
42
59
|
}
|
|
43
60
|
let resolved;
|
|
44
|
-
if (control) {
|
|
61
|
+
if (control != null) {
|
|
62
|
+
if (!chunkGEQWS7FY_cjs.isObject(control)) throw new InvalidAtlasError("control must be an object");
|
|
63
|
+
assertControlShape(control, "control.");
|
|
64
|
+
if (control.initial !== void 0 && typeof control.initial !== "string") {
|
|
65
|
+
throw new InvalidAtlasError("control.initial must be a string");
|
|
66
|
+
}
|
|
67
|
+
if (control.defaultFrameDuration !== void 0 && typeof control.defaultFrameDuration !== "number") {
|
|
68
|
+
throw new InvalidAtlasError("control.defaultFrameDuration must be a number");
|
|
69
|
+
}
|
|
45
70
|
resolved = control;
|
|
46
71
|
} else {
|
|
47
72
|
if (isForeignStates(atlas.states)) {
|
|
@@ -49,47 +74,16 @@ function parseAtlas(atlas, control) {
|
|
|
49
74
|
"atlas `states` is event-driven (has `initial`/`definitions`); pass an aispritejs control block as the second argument"
|
|
50
75
|
);
|
|
51
76
|
}
|
|
52
|
-
if (!
|
|
77
|
+
if (!chunkGEQWS7FY_cjs.isObject(atlas.inputs) || !chunkGEQWS7FY_cjs.isObject(atlas.states) || !Array.isArray(atlas.transitions)) {
|
|
53
78
|
throw new InvalidAtlasError(
|
|
54
79
|
"atlas has no aispritejs control block (inputs/states/transitions); pass one as the second argument"
|
|
55
80
|
);
|
|
56
81
|
}
|
|
57
|
-
|
|
58
|
-
if (!chunkQF5N7LOI_cjs.isObject(val)) {
|
|
59
|
-
const actualType = val === null ? "null" : Array.isArray(val) ? "array" : typeof val;
|
|
60
|
-
throw new InvalidAtlasError(`input entry "${key}" must be an object, got ${actualType}`);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
for (const [key, val] of Object.entries(atlas.states)) {
|
|
64
|
-
if (!chunkQF5N7LOI_cjs.isObject(val)) {
|
|
65
|
-
const actualType = val === null ? "null" : Array.isArray(val) ? "array" : typeof val;
|
|
66
|
-
throw new InvalidAtlasError(`state entry "${key}" must be an object, got ${actualType}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
const rawTransitions = atlas.transitions;
|
|
70
|
-
for (let i = 0; i < rawTransitions.length; i++) {
|
|
71
|
-
const entry = rawTransitions[i];
|
|
72
|
-
if (!chunkQF5N7LOI_cjs.isObject(entry)) {
|
|
73
|
-
const actualType = entry === null ? "null" : Array.isArray(entry) ? "array" : typeof entry;
|
|
74
|
-
throw new InvalidAtlasError(`transitions[${i}] must be an object, got ${actualType}`);
|
|
75
|
-
}
|
|
76
|
-
if (Array.isArray(entry.when)) {
|
|
77
|
-
const rawWhen = entry.when;
|
|
78
|
-
for (let j = 0; j < rawWhen.length; j++) {
|
|
79
|
-
const cond = rawWhen[j];
|
|
80
|
-
if (!chunkQF5N7LOI_cjs.isObject(cond)) {
|
|
81
|
-
const actualType = cond === null ? "null" : Array.isArray(cond) ? "array" : typeof cond;
|
|
82
|
-
throw new InvalidAtlasError(
|
|
83
|
-
`transitions[${i}].when[${j}] must be an object, got ${actualType}`
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
82
|
+
assertControlShape(atlas, "");
|
|
89
83
|
resolved = {
|
|
90
84
|
inputs: atlas.inputs,
|
|
91
85
|
states: atlas.states,
|
|
92
|
-
transitions:
|
|
86
|
+
transitions: atlas.transitions,
|
|
93
87
|
...typeof atlas.initial === "string" ? { initial: atlas.initial } : {},
|
|
94
88
|
...typeof atlas.defaultFrameDuration === "number" ? { defaultFrameDuration: atlas.defaultFrameDuration } : {}
|
|
95
89
|
};
|
|
@@ -105,7 +99,7 @@ function parseAtlas(atlas, control) {
|
|
|
105
99
|
};
|
|
106
100
|
}
|
|
107
101
|
function loadAtlas(atlas, control) {
|
|
108
|
-
return
|
|
102
|
+
return chunkGEQWS7FY_cjs.createSpriteAnimator(parseAtlas(atlas, control));
|
|
109
103
|
}
|
|
110
104
|
|
|
111
105
|
exports.InvalidAtlasError = InvalidAtlasError;
|
package/dist/atlas/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/atlas/parse.ts"],"names":["isObject","createSpriteAnimator"],"mappings":"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","file":"index.cjs","sourcesContent":["// aispritejs/atlas — parse a PixiJS-v8-native atlas into a SpriteGraph the core\n// can consume. The atlas supplies the universal `animations` / `frames` blocks;\n// the input-driven control (`inputs` / `states` / `transitions`) comes either\n// from the atlas itself (the augmented shape in the README) or from a separate\n// `control` argument.\n//\n// A foreign, event-driven `states` block (the FSM shape `{ initial, definitions }`\n// emitted by other tools) is detected and ignored — `aispritejs` never adopts\n// it. The canonical structure is described by `schemas/aispritejs-graph.schema.json`,\n// shipped alongside this module; the checks below mirror it (fail-fast, no\n// runtime schema-validator dependency).\n//\n// Pure and zero-dependency: it imports only the core (same package) and returns\n// a plain SpriteGraph. `loadAtlas` additionally builds the animator, surfacing\n// semantic errors (InvalidGraphError) eagerly.\n\nimport { isObject } from \"../sprite/compile.js\";\nimport {\n type FrameTiming,\n type InputDef,\n type SpriteAnimator,\n type SpriteGraph,\n type StateDef,\n type TransitionDef,\n createSpriteAnimator,\n} from \"../sprite/index.js\";\n\n/**\n * Thrown when an atlas is structurally unusable — not an object, missing or\n * malformed `animations`, or carrying no `aispritejs` control block (and none\n * supplied separately). Semantic problems (unknown transition targets, etc.)\n * surface later as {@link InvalidGraphError} from the core.\n *\n * @public\n */\nexport class InvalidAtlasError extends Error {\n constructor(message: string) {\n super(`aispritejs/atlas: ${message}`);\n this.name = \"InvalidAtlasError\";\n }\n}\n\n/**\n * The `aispritejs` input-driven control block — everything in a {@link SpriteGraph}\n * except the universal `animations` / `frames` that come from the atlas. Supply\n * this as the second argument to drive an atlas whose own `states` block is\n * foreign (event-driven) or absent.\n *\n * @public\n */\nexport interface SpriteControl {\n readonly inputs: Readonly<Record<string, InputDef>>;\n readonly states: Readonly<Record<string, StateDef>>;\n readonly transitions: readonly TransitionDef[];\n readonly initial?: string;\n readonly defaultFrameDuration?: number;\n}\n\n/**\n * True for the foreign, event-driven `states` shape `{ initial, definitions }`.\n * Decisive: an `aispritejs` `states` is a flat map whose values are objects, so\n * a *string* `states.initial` only ever appears in the foreign wrapper.\n */\nfunction isForeignStates(states: unknown): boolean {\n return isObject(states) && typeof states.initial === \"string\" && isObject(states.definitions);\n}\n\nfunction assertAnimations(value: unknown): Record<string, readonly string[]> {\n if (!isObject(value)) {\n throw new InvalidAtlasError(\"`animations` must be an object of frame-key lists\");\n }\n for (const [name, list] of Object.entries(value)) {\n if (!Array.isArray(list) || list.some((k) => typeof k !== \"string\")) {\n throw new InvalidAtlasError(`animation \"${name}\" must be an array of frame-key strings`);\n }\n }\n return value as Record<string, readonly string[]>;\n}\n\n/**\n * Parse a (possibly augmented) PixiJS-v8 atlas into a {@link SpriteGraph}.\n *\n * @param atlas - a parsed atlas object: `animations` (required) + optional\n * `frames`, and — for the augmented shape — `inputs` / `states` / `transitions`.\n * @param control - an explicit {@link SpriteControl} that supplies (or overrides)\n * the input-driven graph. Required when the atlas has no `aispritejs` control\n * block or its `states` is foreign (event-driven).\n * @returns a {@link SpriteGraph} ready for `createSpriteAnimator`.\n * @throws {@link InvalidAtlasError} on a structurally unusable atlas.\n *\n * @public\n */\nexport function parseAtlas(atlas: unknown, control?: SpriteControl): SpriteGraph {\n if (!isObject(atlas)) {\n throw new InvalidAtlasError(\"atlas must be an object\");\n }\n\n const animations = assertAnimations(atlas.animations);\n const frames = atlas.frames;\n if (frames !== undefined && !isObject(frames)) {\n throw new InvalidAtlasError(\"`frames`, if present, must be an object keyed by frame key\");\n }\n if (isObject(frames)) {\n for (const [key, entry] of Object.entries(frames)) {\n if (!isObject(entry)) {\n const actualType = entry === null ? \"null\" : Array.isArray(entry) ? \"array\" : typeof entry;\n throw new InvalidAtlasError(`frame entry \"${key}\" must be an object, got ${actualType}`);\n }\n }\n }\n\n let resolved: SpriteControl;\n if (control) {\n resolved = control;\n } else {\n if (isForeignStates(atlas.states)) {\n throw new InvalidAtlasError(\n \"atlas `states` is event-driven (has `initial`/`definitions`); pass an aispritejs control block as the second argument\",\n );\n }\n if (!isObject(atlas.inputs) || !isObject(atlas.states) || !Array.isArray(atlas.transitions)) {\n throw new InvalidAtlasError(\n \"atlas has no aispritejs control block (inputs/states/transitions); pass one as the second argument\",\n );\n }\n for (const [key, val] of Object.entries(atlas.inputs)) {\n if (!isObject(val)) {\n const actualType = val === null ? \"null\" : Array.isArray(val) ? \"array\" : typeof val;\n throw new InvalidAtlasError(`input entry \"${key}\" must be an object, got ${actualType}`);\n }\n }\n for (const [key, val] of Object.entries(atlas.states)) {\n if (!isObject(val)) {\n const actualType = val === null ? \"null\" : Array.isArray(val) ? \"array\" : typeof val;\n throw new InvalidAtlasError(`state entry \"${key}\" must be an object, got ${actualType}`);\n }\n }\n const rawTransitions = atlas.transitions as unknown[];\n for (let i = 0; i < rawTransitions.length; i++) {\n const entry = rawTransitions[i];\n if (!isObject(entry)) {\n const actualType = entry === null ? \"null\" : Array.isArray(entry) ? \"array\" : typeof entry;\n throw new InvalidAtlasError(`transitions[${i}] must be an object, got ${actualType}`);\n }\n // Validate each `when` item is an object (sibling of F-5).\n // A null/non-object item here would otherwise cause a bare TypeError at\n // compile.ts when it attempts to destructure `c.input`.\n if (Array.isArray(entry.when)) {\n const rawWhen = entry.when as unknown[];\n for (let j = 0; j < rawWhen.length; j++) {\n const cond = rawWhen[j];\n if (!isObject(cond)) {\n const actualType = cond === null ? \"null\" : Array.isArray(cond) ? \"array\" : typeof cond;\n throw new InvalidAtlasError(\n `transitions[${i}].when[${j}] must be an object, got ${actualType}`,\n );\n }\n }\n }\n }\n resolved = {\n inputs: atlas.inputs as Record<string, InputDef>,\n states: atlas.states as Record<string, StateDef>,\n transitions: rawTransitions as readonly TransitionDef[],\n ...(typeof atlas.initial === \"string\" ? { initial: atlas.initial } : {}),\n ...(typeof atlas.defaultFrameDuration === \"number\"\n ? { defaultFrameDuration: atlas.defaultFrameDuration }\n : {}),\n };\n }\n\n return {\n animations,\n ...(frames ? { frames: frames as Record<string, FrameTiming> } : {}),\n inputs: resolved.inputs,\n states: resolved.states,\n transitions: resolved.transitions,\n ...(resolved.initial !== undefined ? { initial: resolved.initial } : {}),\n ...(resolved.defaultFrameDuration !== undefined\n ? { defaultFrameDuration: resolved.defaultFrameDuration }\n : {}),\n };\n}\n\n/**\n * Parse an atlas and build a {@link SpriteAnimator} in one step — the fail-fast\n * \"load\" entry. Structural problems throw {@link InvalidAtlasError}; semantic\n * problems throw {@link InvalidGraphError} from the core.\n *\n * @public\n */\nexport function loadAtlas(atlas: unknown, control?: SpriteControl): SpriteAnimator {\n return createSpriteAnimator(parseAtlas(atlas, control));\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/atlas/parse.ts"],"names":["isObject","createSpriteAnimator"],"mappings":"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","file":"index.cjs","sourcesContent":["// aispritejs/atlas — parse a PixiJS-v8-native atlas into a SpriteGraph the core\n// can consume. The atlas supplies the universal `animations` / `frames` blocks;\n// the input-driven control (`inputs` / `states` / `transitions`) comes either\n// from the atlas itself (the augmented shape in the README) or from a separate\n// `control` argument.\n//\n// A foreign, event-driven `states` block (the FSM shape `{ initial, definitions }`\n// emitted by other tools) is detected and ignored — `aispritejs` never adopts\n// it. The canonical structure is described by `schemas/aispritejs-graph.schema.json`,\n// shipped alongside this module; the checks below mirror it (fail-fast, no\n// runtime schema-validator dependency).\n//\n// Pure and zero-dependency: it imports only the core (same package) and returns\n// a plain SpriteGraph. `loadAtlas` additionally builds the animator, surfacing\n// semantic errors (InvalidGraphError) eagerly.\n\nimport { isObject } from \"../sprite/compile.js\";\nimport {\n type FrameTiming,\n type InputDef,\n type SpriteAnimator,\n type SpriteGraph,\n type StateDef,\n type TransitionDef,\n createSpriteAnimator,\n} from \"../sprite/index.js\";\n\n/**\n * Thrown when an atlas is structurally unusable — not an object, missing or\n * malformed `animations`, or carrying no `aispritejs` control block (and none\n * supplied separately). Semantic problems (unknown transition targets, etc.)\n * surface later as {@link InvalidGraphError} from the core.\n *\n * @public\n */\nexport class InvalidAtlasError extends Error {\n constructor(message: string) {\n super(`aispritejs/atlas: ${message}`);\n this.name = \"InvalidAtlasError\";\n }\n}\n\n/**\n * The `aispritejs` input-driven control block — everything in a {@link SpriteGraph}\n * except the universal `animations` / `frames` that come from the atlas. Supply\n * this as the second argument to drive an atlas whose own `states` block is\n * foreign (event-driven) or absent.\n *\n * @public\n */\nexport interface SpriteControl {\n readonly inputs: Readonly<Record<string, InputDef>>;\n readonly states: Readonly<Record<string, StateDef>>;\n readonly transitions: readonly TransitionDef[];\n readonly initial?: string;\n readonly defaultFrameDuration?: number;\n}\n\n/**\n * True for the foreign, event-driven `states` shape `{ initial, definitions }`.\n * Decisive: an `aispritejs` `states` is a flat map whose values are objects, so\n * a *string* `states.initial` only ever appears in the foreign wrapper.\n */\nfunction isForeignStates(states: unknown): boolean {\n return isObject(states) && typeof states.initial === \"string\" && isObject(states.definitions);\n}\n\n/** `typeof`, but naming `null` and arrays, for \"got <type>\" messages. */\nfunction typeName(v: unknown): string {\n return v === null ? \"null\" : Array.isArray(v) ? \"array\" : typeof v;\n}\n\nfunction assertEntry(v: unknown, what: string): void {\n if (!isObject(v)) throw new InvalidAtlasError(`${what} must be an object, got ${typeName(v)}`);\n}\n\nfunction assertAnimations(value: unknown): Record<string, readonly string[]> {\n if (!isObject(value)) {\n throw new InvalidAtlasError(\"`animations` must be an object of frame-key lists\");\n }\n for (const [name, list] of Object.entries(value)) {\n if (!Array.isArray(list) || list.some((k) => typeof k !== \"string\")) {\n throw new InvalidAtlasError(`animation \"${name}\" must be an array of frame-key strings`);\n }\n }\n return value as Record<string, readonly string[]>;\n}\n\n/**\n * Structural checks shared by the atlas's own control block (`p` = `\"\"`) and an\n * explicit `control` argument (`p` = `\"control.\"`): object `inputs` / `states`,\n * array `transitions`, and object entries / `when` items, so a malformed block\n * is an {@link InvalidAtlasError} on either path. Semantic checks stay with the\n * compiler ({@link InvalidGraphError}).\n */\nfunction assertControlShape(src: Record<string, unknown>, p: string): void {\n if (!isObject(src.inputs)) throw new InvalidAtlasError(`${p}inputs must be an object`);\n if (!isObject(src.states)) throw new InvalidAtlasError(`${p}states must be an object`);\n if (!Array.isArray(src.transitions)) {\n throw new InvalidAtlasError(`${p}transitions must be an array`);\n }\n for (const [key, val] of Object.entries(src.inputs)) assertEntry(val, `${p}input entry \"${key}\"`);\n for (const [key, val] of Object.entries(src.states)) assertEntry(val, `${p}state entry \"${key}\"`);\n src.transitions.forEach((entry: unknown, i) => {\n assertEntry(entry, `${p}transitions[${i}]`);\n // A null/non-object `when` item would otherwise reach the compiler as a\n // malformed condition (sibling of F-5).\n const when = (entry as { when?: unknown }).when;\n if (Array.isArray(when)) {\n when.forEach((cond: unknown, j) => assertEntry(cond, `${p}transitions[${i}].when[${j}]`));\n }\n });\n}\n\n/**\n * Parse a (possibly augmented) PixiJS-v8 atlas into a {@link SpriteGraph}.\n *\n * @param atlas - a parsed atlas object: `animations` (required) + optional\n * `frames`, and — for the augmented shape — `inputs` / `states` / `transitions`.\n * @param control - an explicit {@link SpriteControl} that supplies (or overrides)\n * the input-driven graph. Required when the atlas has no `aispritejs` control\n * block or its `states` is foreign (event-driven). When supplied (not\n * `undefined` / `null`) it gets the same structural checks as an embedded\n * block, and a wrong-typed `initial` / `defaultFrameDuration` is rejected\n * rather than dropped.\n * @returns a {@link SpriteGraph} ready for `createSpriteAnimator`.\n * @throws {@link InvalidAtlasError} on a structurally unusable atlas or control.\n *\n * @public\n */\nexport function parseAtlas(atlas: unknown, control?: SpriteControl): SpriteGraph {\n if (!isObject(atlas)) {\n throw new InvalidAtlasError(\"atlas must be an object\");\n }\n\n const animations = assertAnimations(atlas.animations);\n const frames = atlas.frames;\n if (frames !== undefined && !isObject(frames)) {\n throw new InvalidAtlasError(\"`frames`, if present, must be an object keyed by frame key\");\n }\n if (isObject(frames)) {\n for (const [key, entry] of Object.entries(frames)) assertEntry(entry, `frame entry \"${key}\"`);\n }\n\n let resolved: SpriteControl;\n if (control != null) {\n // Same structural checks as the embedded block, plus typed optional\n // fields: an explicit control is never silently trimmed.\n if (!isObject(control)) throw new InvalidAtlasError(\"control must be an object\");\n assertControlShape(control, \"control.\");\n if (control.initial !== undefined && typeof control.initial !== \"string\") {\n throw new InvalidAtlasError(\"control.initial must be a string\");\n }\n if (\n control.defaultFrameDuration !== undefined &&\n typeof control.defaultFrameDuration !== \"number\"\n ) {\n throw new InvalidAtlasError(\"control.defaultFrameDuration must be a number\");\n }\n resolved = control;\n } else {\n if (isForeignStates(atlas.states)) {\n throw new InvalidAtlasError(\n \"atlas `states` is event-driven (has `initial`/`definitions`); pass an aispritejs control block as the second argument\",\n );\n }\n if (!isObject(atlas.inputs) || !isObject(atlas.states) || !Array.isArray(atlas.transitions)) {\n throw new InvalidAtlasError(\n \"atlas has no aispritejs control block (inputs/states/transitions); pass one as the second argument\",\n );\n }\n assertControlShape(atlas, \"\");\n // Wrong-typed optional fields in the atlas itself are dropped (lenient).\n resolved = {\n inputs: atlas.inputs as Record<string, InputDef>,\n states: atlas.states as Record<string, StateDef>,\n transitions: atlas.transitions as readonly TransitionDef[],\n ...(typeof atlas.initial === \"string\" ? { initial: atlas.initial } : {}),\n ...(typeof atlas.defaultFrameDuration === \"number\"\n ? { defaultFrameDuration: atlas.defaultFrameDuration }\n : {}),\n };\n }\n\n return {\n animations,\n ...(frames ? { frames: frames as Record<string, FrameTiming> } : {}),\n inputs: resolved.inputs,\n states: resolved.states,\n transitions: resolved.transitions,\n ...(resolved.initial !== undefined ? { initial: resolved.initial } : {}),\n ...(resolved.defaultFrameDuration !== undefined\n ? { defaultFrameDuration: resolved.defaultFrameDuration }\n : {}),\n };\n}\n\n/**\n * Parse an atlas and build a {@link SpriteAnimator} in one step — the fail-fast\n * \"load\" entry. Structural problems throw {@link InvalidAtlasError}; semantic\n * problems throw {@link InvalidGraphError} from the core.\n *\n * @public\n */\nexport function loadAtlas(atlas: unknown, control?: SpriteControl): SpriteAnimator {\n return createSpriteAnimator(parseAtlas(atlas, control));\n}\n"]}
|
package/dist/atlas/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as InputDef, S as StateDef, T as TransitionDef, a as SpriteAnimator, b as SpriteGraph } from '../types-
|
|
1
|
+
import { I as InputDef, S as StateDef, T as TransitionDef, a as SpriteAnimator, b as SpriteGraph } from '../types-Dr7yXTRQ.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Thrown when an atlas is structurally unusable — not an object, missing or
|
|
@@ -33,9 +33,12 @@ interface SpriteControl {
|
|
|
33
33
|
* `frames`, and — for the augmented shape — `inputs` / `states` / `transitions`.
|
|
34
34
|
* @param control - an explicit {@link SpriteControl} that supplies (or overrides)
|
|
35
35
|
* the input-driven graph. Required when the atlas has no `aispritejs` control
|
|
36
|
-
* block or its `states` is foreign (event-driven).
|
|
36
|
+
* block or its `states` is foreign (event-driven). When supplied (not
|
|
37
|
+
* `undefined` / `null`) it gets the same structural checks as an embedded
|
|
38
|
+
* block, and a wrong-typed `initial` / `defaultFrameDuration` is rejected
|
|
39
|
+
* rather than dropped.
|
|
37
40
|
* @returns a {@link SpriteGraph} ready for `createSpriteAnimator`.
|
|
38
|
-
* @throws {@link InvalidAtlasError} on a structurally unusable atlas.
|
|
41
|
+
* @throws {@link InvalidAtlasError} on a structurally unusable atlas or control.
|
|
39
42
|
*
|
|
40
43
|
* @public
|
|
41
44
|
*/
|
package/dist/atlas/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as InputDef, S as StateDef, T as TransitionDef, a as SpriteAnimator, b as SpriteGraph } from '../types-
|
|
1
|
+
import { I as InputDef, S as StateDef, T as TransitionDef, a as SpriteAnimator, b as SpriteGraph } from '../types-Dr7yXTRQ.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Thrown when an atlas is structurally unusable — not an object, missing or
|
|
@@ -33,9 +33,12 @@ interface SpriteControl {
|
|
|
33
33
|
* `frames`, and — for the augmented shape — `inputs` / `states` / `transitions`.
|
|
34
34
|
* @param control - an explicit {@link SpriteControl} that supplies (or overrides)
|
|
35
35
|
* the input-driven graph. Required when the atlas has no `aispritejs` control
|
|
36
|
-
* block or its `states` is foreign (event-driven).
|
|
36
|
+
* block or its `states` is foreign (event-driven). When supplied (not
|
|
37
|
+
* `undefined` / `null`) it gets the same structural checks as an embedded
|
|
38
|
+
* block, and a wrong-typed `initial` / `defaultFrameDuration` is rejected
|
|
39
|
+
* rather than dropped.
|
|
37
40
|
* @returns a {@link SpriteGraph} ready for `createSpriteAnimator`.
|
|
38
|
-
* @throws {@link InvalidAtlasError} on a structurally unusable atlas.
|
|
41
|
+
* @throws {@link InvalidAtlasError} on a structurally unusable atlas or control.
|
|
39
42
|
*
|
|
40
43
|
* @public
|
|
41
44
|
*/
|
package/dist/atlas/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isObject, createSpriteAnimator } from '../chunk-
|
|
1
|
+
import { isObject, createSpriteAnimator } from '../chunk-NBMU2UNJ.js';
|
|
2
2
|
|
|
3
3
|
// src/atlas/parse.ts
|
|
4
4
|
var InvalidAtlasError = class extends Error {
|
|
@@ -10,6 +10,12 @@ var InvalidAtlasError = class extends Error {
|
|
|
10
10
|
function isForeignStates(states) {
|
|
11
11
|
return isObject(states) && typeof states.initial === "string" && isObject(states.definitions);
|
|
12
12
|
}
|
|
13
|
+
function typeName(v) {
|
|
14
|
+
return v === null ? "null" : Array.isArray(v) ? "array" : typeof v;
|
|
15
|
+
}
|
|
16
|
+
function assertEntry(v, what) {
|
|
17
|
+
if (!isObject(v)) throw new InvalidAtlasError(`${what} must be an object, got ${typeName(v)}`);
|
|
18
|
+
}
|
|
13
19
|
function assertAnimations(value) {
|
|
14
20
|
if (!isObject(value)) {
|
|
15
21
|
throw new InvalidAtlasError("`animations` must be an object of frame-key lists");
|
|
@@ -21,6 +27,22 @@ function assertAnimations(value) {
|
|
|
21
27
|
}
|
|
22
28
|
return value;
|
|
23
29
|
}
|
|
30
|
+
function assertControlShape(src, p) {
|
|
31
|
+
if (!isObject(src.inputs)) throw new InvalidAtlasError(`${p}inputs must be an object`);
|
|
32
|
+
if (!isObject(src.states)) throw new InvalidAtlasError(`${p}states must be an object`);
|
|
33
|
+
if (!Array.isArray(src.transitions)) {
|
|
34
|
+
throw new InvalidAtlasError(`${p}transitions must be an array`);
|
|
35
|
+
}
|
|
36
|
+
for (const [key, val] of Object.entries(src.inputs)) assertEntry(val, `${p}input entry "${key}"`);
|
|
37
|
+
for (const [key, val] of Object.entries(src.states)) assertEntry(val, `${p}state entry "${key}"`);
|
|
38
|
+
src.transitions.forEach((entry, i) => {
|
|
39
|
+
assertEntry(entry, `${p}transitions[${i}]`);
|
|
40
|
+
const when = entry.when;
|
|
41
|
+
if (Array.isArray(when)) {
|
|
42
|
+
when.forEach((cond, j) => assertEntry(cond, `${p}transitions[${i}].when[${j}]`));
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
24
46
|
function parseAtlas(atlas, control) {
|
|
25
47
|
if (!isObject(atlas)) {
|
|
26
48
|
throw new InvalidAtlasError("atlas must be an object");
|
|
@@ -31,15 +53,18 @@ function parseAtlas(atlas, control) {
|
|
|
31
53
|
throw new InvalidAtlasError("`frames`, if present, must be an object keyed by frame key");
|
|
32
54
|
}
|
|
33
55
|
if (isObject(frames)) {
|
|
34
|
-
for (const [key, entry] of Object.entries(frames)) {
|
|
35
|
-
if (!isObject(entry)) {
|
|
36
|
-
const actualType = entry === null ? "null" : Array.isArray(entry) ? "array" : typeof entry;
|
|
37
|
-
throw new InvalidAtlasError(`frame entry "${key}" must be an object, got ${actualType}`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
56
|
+
for (const [key, entry] of Object.entries(frames)) assertEntry(entry, `frame entry "${key}"`);
|
|
40
57
|
}
|
|
41
58
|
let resolved;
|
|
42
|
-
if (control) {
|
|
59
|
+
if (control != null) {
|
|
60
|
+
if (!isObject(control)) throw new InvalidAtlasError("control must be an object");
|
|
61
|
+
assertControlShape(control, "control.");
|
|
62
|
+
if (control.initial !== void 0 && typeof control.initial !== "string") {
|
|
63
|
+
throw new InvalidAtlasError("control.initial must be a string");
|
|
64
|
+
}
|
|
65
|
+
if (control.defaultFrameDuration !== void 0 && typeof control.defaultFrameDuration !== "number") {
|
|
66
|
+
throw new InvalidAtlasError("control.defaultFrameDuration must be a number");
|
|
67
|
+
}
|
|
43
68
|
resolved = control;
|
|
44
69
|
} else {
|
|
45
70
|
if (isForeignStates(atlas.states)) {
|
|
@@ -52,42 +77,11 @@ function parseAtlas(atlas, control) {
|
|
|
52
77
|
"atlas has no aispritejs control block (inputs/states/transitions); pass one as the second argument"
|
|
53
78
|
);
|
|
54
79
|
}
|
|
55
|
-
|
|
56
|
-
if (!isObject(val)) {
|
|
57
|
-
const actualType = val === null ? "null" : Array.isArray(val) ? "array" : typeof val;
|
|
58
|
-
throw new InvalidAtlasError(`input entry "${key}" must be an object, got ${actualType}`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
for (const [key, val] of Object.entries(atlas.states)) {
|
|
62
|
-
if (!isObject(val)) {
|
|
63
|
-
const actualType = val === null ? "null" : Array.isArray(val) ? "array" : typeof val;
|
|
64
|
-
throw new InvalidAtlasError(`state entry "${key}" must be an object, got ${actualType}`);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
const rawTransitions = atlas.transitions;
|
|
68
|
-
for (let i = 0; i < rawTransitions.length; i++) {
|
|
69
|
-
const entry = rawTransitions[i];
|
|
70
|
-
if (!isObject(entry)) {
|
|
71
|
-
const actualType = entry === null ? "null" : Array.isArray(entry) ? "array" : typeof entry;
|
|
72
|
-
throw new InvalidAtlasError(`transitions[${i}] must be an object, got ${actualType}`);
|
|
73
|
-
}
|
|
74
|
-
if (Array.isArray(entry.when)) {
|
|
75
|
-
const rawWhen = entry.when;
|
|
76
|
-
for (let j = 0; j < rawWhen.length; j++) {
|
|
77
|
-
const cond = rawWhen[j];
|
|
78
|
-
if (!isObject(cond)) {
|
|
79
|
-
const actualType = cond === null ? "null" : Array.isArray(cond) ? "array" : typeof cond;
|
|
80
|
-
throw new InvalidAtlasError(
|
|
81
|
-
`transitions[${i}].when[${j}] must be an object, got ${actualType}`
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
80
|
+
assertControlShape(atlas, "");
|
|
87
81
|
resolved = {
|
|
88
82
|
inputs: atlas.inputs,
|
|
89
83
|
states: atlas.states,
|
|
90
|
-
transitions:
|
|
84
|
+
transitions: atlas.transitions,
|
|
91
85
|
...typeof atlas.initial === "string" ? { initial: atlas.initial } : {},
|
|
92
86
|
...typeof atlas.defaultFrameDuration === "number" ? { defaultFrameDuration: atlas.defaultFrameDuration } : {}
|
|
93
87
|
};
|
package/dist/atlas/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/atlas/parse.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// aispritejs/atlas — parse a PixiJS-v8-native atlas into a SpriteGraph the core\n// can consume. The atlas supplies the universal `animations` / `frames` blocks;\n// the input-driven control (`inputs` / `states` / `transitions`) comes either\n// from the atlas itself (the augmented shape in the README) or from a separate\n// `control` argument.\n//\n// A foreign, event-driven `states` block (the FSM shape `{ initial, definitions }`\n// emitted by other tools) is detected and ignored — `aispritejs` never adopts\n// it. The canonical structure is described by `schemas/aispritejs-graph.schema.json`,\n// shipped alongside this module; the checks below mirror it (fail-fast, no\n// runtime schema-validator dependency).\n//\n// Pure and zero-dependency: it imports only the core (same package) and returns\n// a plain SpriteGraph. `loadAtlas` additionally builds the animator, surfacing\n// semantic errors (InvalidGraphError) eagerly.\n\nimport { isObject } from \"../sprite/compile.js\";\nimport {\n type FrameTiming,\n type InputDef,\n type SpriteAnimator,\n type SpriteGraph,\n type StateDef,\n type TransitionDef,\n createSpriteAnimator,\n} from \"../sprite/index.js\";\n\n/**\n * Thrown when an atlas is structurally unusable — not an object, missing or\n * malformed `animations`, or carrying no `aispritejs` control block (and none\n * supplied separately). Semantic problems (unknown transition targets, etc.)\n * surface later as {@link InvalidGraphError} from the core.\n *\n * @public\n */\nexport class InvalidAtlasError extends Error {\n constructor(message: string) {\n super(`aispritejs/atlas: ${message}`);\n this.name = \"InvalidAtlasError\";\n }\n}\n\n/**\n * The `aispritejs` input-driven control block — everything in a {@link SpriteGraph}\n * except the universal `animations` / `frames` that come from the atlas. Supply\n * this as the second argument to drive an atlas whose own `states` block is\n * foreign (event-driven) or absent.\n *\n * @public\n */\nexport interface SpriteControl {\n readonly inputs: Readonly<Record<string, InputDef>>;\n readonly states: Readonly<Record<string, StateDef>>;\n readonly transitions: readonly TransitionDef[];\n readonly initial?: string;\n readonly defaultFrameDuration?: number;\n}\n\n/**\n * True for the foreign, event-driven `states` shape `{ initial, definitions }`.\n * Decisive: an `aispritejs` `states` is a flat map whose values are objects, so\n * a *string* `states.initial` only ever appears in the foreign wrapper.\n */\nfunction isForeignStates(states: unknown): boolean {\n return isObject(states) && typeof states.initial === \"string\" && isObject(states.definitions);\n}\n\nfunction assertAnimations(value: unknown): Record<string, readonly string[]> {\n if (!isObject(value)) {\n throw new InvalidAtlasError(\"`animations` must be an object of frame-key lists\");\n }\n for (const [name, list] of Object.entries(value)) {\n if (!Array.isArray(list) || list.some((k) => typeof k !== \"string\")) {\n throw new InvalidAtlasError(`animation \"${name}\" must be an array of frame-key strings`);\n }\n }\n return value as Record<string, readonly string[]>;\n}\n\n/**\n * Parse a (possibly augmented) PixiJS-v8 atlas into a {@link SpriteGraph}.\n *\n * @param atlas - a parsed atlas object: `animations` (required) + optional\n * `frames`, and — for the augmented shape — `inputs` / `states` / `transitions`.\n * @param control - an explicit {@link SpriteControl} that supplies (or overrides)\n * the input-driven graph. Required when the atlas has no `aispritejs` control\n * block or its `states` is foreign (event-driven).\n * @returns a {@link SpriteGraph} ready for `createSpriteAnimator`.\n * @throws {@link InvalidAtlasError} on a structurally unusable atlas.\n *\n * @public\n */\nexport function parseAtlas(atlas: unknown, control?: SpriteControl): SpriteGraph {\n if (!isObject(atlas)) {\n throw new InvalidAtlasError(\"atlas must be an object\");\n }\n\n const animations = assertAnimations(atlas.animations);\n const frames = atlas.frames;\n if (frames !== undefined && !isObject(frames)) {\n throw new InvalidAtlasError(\"`frames`, if present, must be an object keyed by frame key\");\n }\n if (isObject(frames)) {\n for (const [key, entry] of Object.entries(frames)) {\n if (!isObject(entry)) {\n const actualType = entry === null ? \"null\" : Array.isArray(entry) ? \"array\" : typeof entry;\n throw new InvalidAtlasError(`frame entry \"${key}\" must be an object, got ${actualType}`);\n }\n }\n }\n\n let resolved: SpriteControl;\n if (control) {\n resolved = control;\n } else {\n if (isForeignStates(atlas.states)) {\n throw new InvalidAtlasError(\n \"atlas `states` is event-driven (has `initial`/`definitions`); pass an aispritejs control block as the second argument\",\n );\n }\n if (!isObject(atlas.inputs) || !isObject(atlas.states) || !Array.isArray(atlas.transitions)) {\n throw new InvalidAtlasError(\n \"atlas has no aispritejs control block (inputs/states/transitions); pass one as the second argument\",\n );\n }\n for (const [key, val] of Object.entries(atlas.inputs)) {\n if (!isObject(val)) {\n const actualType = val === null ? \"null\" : Array.isArray(val) ? \"array\" : typeof val;\n throw new InvalidAtlasError(`input entry \"${key}\" must be an object, got ${actualType}`);\n }\n }\n for (const [key, val] of Object.entries(atlas.states)) {\n if (!isObject(val)) {\n const actualType = val === null ? \"null\" : Array.isArray(val) ? \"array\" : typeof val;\n throw new InvalidAtlasError(`state entry \"${key}\" must be an object, got ${actualType}`);\n }\n }\n const rawTransitions = atlas.transitions as unknown[];\n for (let i = 0; i < rawTransitions.length; i++) {\n const entry = rawTransitions[i];\n if (!isObject(entry)) {\n const actualType = entry === null ? \"null\" : Array.isArray(entry) ? \"array\" : typeof entry;\n throw new InvalidAtlasError(`transitions[${i}] must be an object, got ${actualType}`);\n }\n // Validate each `when` item is an object (sibling of F-5).\n // A null/non-object item here would otherwise cause a bare TypeError at\n // compile.ts when it attempts to destructure `c.input`.\n if (Array.isArray(entry.when)) {\n const rawWhen = entry.when as unknown[];\n for (let j = 0; j < rawWhen.length; j++) {\n const cond = rawWhen[j];\n if (!isObject(cond)) {\n const actualType = cond === null ? \"null\" : Array.isArray(cond) ? \"array\" : typeof cond;\n throw new InvalidAtlasError(\n `transitions[${i}].when[${j}] must be an object, got ${actualType}`,\n );\n }\n }\n }\n }\n resolved = {\n inputs: atlas.inputs as Record<string, InputDef>,\n states: atlas.states as Record<string, StateDef>,\n transitions: rawTransitions as readonly TransitionDef[],\n ...(typeof atlas.initial === \"string\" ? { initial: atlas.initial } : {}),\n ...(typeof atlas.defaultFrameDuration === \"number\"\n ? { defaultFrameDuration: atlas.defaultFrameDuration }\n : {}),\n };\n }\n\n return {\n animations,\n ...(frames ? { frames: frames as Record<string, FrameTiming> } : {}),\n inputs: resolved.inputs,\n states: resolved.states,\n transitions: resolved.transitions,\n ...(resolved.initial !== undefined ? { initial: resolved.initial } : {}),\n ...(resolved.defaultFrameDuration !== undefined\n ? { defaultFrameDuration: resolved.defaultFrameDuration }\n : {}),\n };\n}\n\n/**\n * Parse an atlas and build a {@link SpriteAnimator} in one step — the fail-fast\n * \"load\" entry. Structural problems throw {@link InvalidAtlasError}; semantic\n * problems throw {@link InvalidGraphError} from the core.\n *\n * @public\n */\nexport function loadAtlas(atlas: unknown, control?: SpriteControl): SpriteAnimator {\n return createSpriteAnimator(parseAtlas(atlas, control));\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/atlas/parse.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// aispritejs/atlas — parse a PixiJS-v8-native atlas into a SpriteGraph the core\n// can consume. The atlas supplies the universal `animations` / `frames` blocks;\n// the input-driven control (`inputs` / `states` / `transitions`) comes either\n// from the atlas itself (the augmented shape in the README) or from a separate\n// `control` argument.\n//\n// A foreign, event-driven `states` block (the FSM shape `{ initial, definitions }`\n// emitted by other tools) is detected and ignored — `aispritejs` never adopts\n// it. The canonical structure is described by `schemas/aispritejs-graph.schema.json`,\n// shipped alongside this module; the checks below mirror it (fail-fast, no\n// runtime schema-validator dependency).\n//\n// Pure and zero-dependency: it imports only the core (same package) and returns\n// a plain SpriteGraph. `loadAtlas` additionally builds the animator, surfacing\n// semantic errors (InvalidGraphError) eagerly.\n\nimport { isObject } from \"../sprite/compile.js\";\nimport {\n type FrameTiming,\n type InputDef,\n type SpriteAnimator,\n type SpriteGraph,\n type StateDef,\n type TransitionDef,\n createSpriteAnimator,\n} from \"../sprite/index.js\";\n\n/**\n * Thrown when an atlas is structurally unusable — not an object, missing or\n * malformed `animations`, or carrying no `aispritejs` control block (and none\n * supplied separately). Semantic problems (unknown transition targets, etc.)\n * surface later as {@link InvalidGraphError} from the core.\n *\n * @public\n */\nexport class InvalidAtlasError extends Error {\n constructor(message: string) {\n super(`aispritejs/atlas: ${message}`);\n this.name = \"InvalidAtlasError\";\n }\n}\n\n/**\n * The `aispritejs` input-driven control block — everything in a {@link SpriteGraph}\n * except the universal `animations` / `frames` that come from the atlas. Supply\n * this as the second argument to drive an atlas whose own `states` block is\n * foreign (event-driven) or absent.\n *\n * @public\n */\nexport interface SpriteControl {\n readonly inputs: Readonly<Record<string, InputDef>>;\n readonly states: Readonly<Record<string, StateDef>>;\n readonly transitions: readonly TransitionDef[];\n readonly initial?: string;\n readonly defaultFrameDuration?: number;\n}\n\n/**\n * True for the foreign, event-driven `states` shape `{ initial, definitions }`.\n * Decisive: an `aispritejs` `states` is a flat map whose values are objects, so\n * a *string* `states.initial` only ever appears in the foreign wrapper.\n */\nfunction isForeignStates(states: unknown): boolean {\n return isObject(states) && typeof states.initial === \"string\" && isObject(states.definitions);\n}\n\n/** `typeof`, but naming `null` and arrays, for \"got <type>\" messages. */\nfunction typeName(v: unknown): string {\n return v === null ? \"null\" : Array.isArray(v) ? \"array\" : typeof v;\n}\n\nfunction assertEntry(v: unknown, what: string): void {\n if (!isObject(v)) throw new InvalidAtlasError(`${what} must be an object, got ${typeName(v)}`);\n}\n\nfunction assertAnimations(value: unknown): Record<string, readonly string[]> {\n if (!isObject(value)) {\n throw new InvalidAtlasError(\"`animations` must be an object of frame-key lists\");\n }\n for (const [name, list] of Object.entries(value)) {\n if (!Array.isArray(list) || list.some((k) => typeof k !== \"string\")) {\n throw new InvalidAtlasError(`animation \"${name}\" must be an array of frame-key strings`);\n }\n }\n return value as Record<string, readonly string[]>;\n}\n\n/**\n * Structural checks shared by the atlas's own control block (`p` = `\"\"`) and an\n * explicit `control` argument (`p` = `\"control.\"`): object `inputs` / `states`,\n * array `transitions`, and object entries / `when` items, so a malformed block\n * is an {@link InvalidAtlasError} on either path. Semantic checks stay with the\n * compiler ({@link InvalidGraphError}).\n */\nfunction assertControlShape(src: Record<string, unknown>, p: string): void {\n if (!isObject(src.inputs)) throw new InvalidAtlasError(`${p}inputs must be an object`);\n if (!isObject(src.states)) throw new InvalidAtlasError(`${p}states must be an object`);\n if (!Array.isArray(src.transitions)) {\n throw new InvalidAtlasError(`${p}transitions must be an array`);\n }\n for (const [key, val] of Object.entries(src.inputs)) assertEntry(val, `${p}input entry \"${key}\"`);\n for (const [key, val] of Object.entries(src.states)) assertEntry(val, `${p}state entry \"${key}\"`);\n src.transitions.forEach((entry: unknown, i) => {\n assertEntry(entry, `${p}transitions[${i}]`);\n // A null/non-object `when` item would otherwise reach the compiler as a\n // malformed condition (sibling of F-5).\n const when = (entry as { when?: unknown }).when;\n if (Array.isArray(when)) {\n when.forEach((cond: unknown, j) => assertEntry(cond, `${p}transitions[${i}].when[${j}]`));\n }\n });\n}\n\n/**\n * Parse a (possibly augmented) PixiJS-v8 atlas into a {@link SpriteGraph}.\n *\n * @param atlas - a parsed atlas object: `animations` (required) + optional\n * `frames`, and — for the augmented shape — `inputs` / `states` / `transitions`.\n * @param control - an explicit {@link SpriteControl} that supplies (or overrides)\n * the input-driven graph. Required when the atlas has no `aispritejs` control\n * block or its `states` is foreign (event-driven). When supplied (not\n * `undefined` / `null`) it gets the same structural checks as an embedded\n * block, and a wrong-typed `initial` / `defaultFrameDuration` is rejected\n * rather than dropped.\n * @returns a {@link SpriteGraph} ready for `createSpriteAnimator`.\n * @throws {@link InvalidAtlasError} on a structurally unusable atlas or control.\n *\n * @public\n */\nexport function parseAtlas(atlas: unknown, control?: SpriteControl): SpriteGraph {\n if (!isObject(atlas)) {\n throw new InvalidAtlasError(\"atlas must be an object\");\n }\n\n const animations = assertAnimations(atlas.animations);\n const frames = atlas.frames;\n if (frames !== undefined && !isObject(frames)) {\n throw new InvalidAtlasError(\"`frames`, if present, must be an object keyed by frame key\");\n }\n if (isObject(frames)) {\n for (const [key, entry] of Object.entries(frames)) assertEntry(entry, `frame entry \"${key}\"`);\n }\n\n let resolved: SpriteControl;\n if (control != null) {\n // Same structural checks as the embedded block, plus typed optional\n // fields: an explicit control is never silently trimmed.\n if (!isObject(control)) throw new InvalidAtlasError(\"control must be an object\");\n assertControlShape(control, \"control.\");\n if (control.initial !== undefined && typeof control.initial !== \"string\") {\n throw new InvalidAtlasError(\"control.initial must be a string\");\n }\n if (\n control.defaultFrameDuration !== undefined &&\n typeof control.defaultFrameDuration !== \"number\"\n ) {\n throw new InvalidAtlasError(\"control.defaultFrameDuration must be a number\");\n }\n resolved = control;\n } else {\n if (isForeignStates(atlas.states)) {\n throw new InvalidAtlasError(\n \"atlas `states` is event-driven (has `initial`/`definitions`); pass an aispritejs control block as the second argument\",\n );\n }\n if (!isObject(atlas.inputs) || !isObject(atlas.states) || !Array.isArray(atlas.transitions)) {\n throw new InvalidAtlasError(\n \"atlas has no aispritejs control block (inputs/states/transitions); pass one as the second argument\",\n );\n }\n assertControlShape(atlas, \"\");\n // Wrong-typed optional fields in the atlas itself are dropped (lenient).\n resolved = {\n inputs: atlas.inputs as Record<string, InputDef>,\n states: atlas.states as Record<string, StateDef>,\n transitions: atlas.transitions as readonly TransitionDef[],\n ...(typeof atlas.initial === \"string\" ? { initial: atlas.initial } : {}),\n ...(typeof atlas.defaultFrameDuration === \"number\"\n ? { defaultFrameDuration: atlas.defaultFrameDuration }\n : {}),\n };\n }\n\n return {\n animations,\n ...(frames ? { frames: frames as Record<string, FrameTiming> } : {}),\n inputs: resolved.inputs,\n states: resolved.states,\n transitions: resolved.transitions,\n ...(resolved.initial !== undefined ? { initial: resolved.initial } : {}),\n ...(resolved.defaultFrameDuration !== undefined\n ? { defaultFrameDuration: resolved.defaultFrameDuration }\n : {}),\n };\n}\n\n/**\n * Parse an atlas and build a {@link SpriteAnimator} in one step — the fail-fast\n * \"load\" entry. Structural problems throw {@link InvalidAtlasError}; semantic\n * problems throw {@link InvalidGraphError} from the core.\n *\n * @public\n */\nexport function loadAtlas(atlas: unknown, control?: SpriteControl): SpriteAnimator {\n return createSpriteAnimator(parseAtlas(atlas, control));\n}\n"]}
|