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.
@@ -37,7 +37,33 @@ var MAX_SPEED = 1e3;
37
37
  function isObject(v) {
38
38
  return typeof v === "object" && v !== null && !Array.isArray(v);
39
39
  }
40
+ function assertString(v, what) {
41
+ if (typeof v !== "string") {
42
+ throw new InvalidGraphError(`${what} must be a string, got ${typeof v}`);
43
+ }
44
+ }
45
+ function assertPositive(v, what, max, unit) {
46
+ if (!Number.isFinite(v) || v <= 0) {
47
+ throw new InvalidGraphError(`${what} must be a finite number > 0, got ${v}`);
48
+ }
49
+ if (v > max) throw new InvalidGraphError(`${what} must be \u2264 ${max}${unit}, got ${v}`);
50
+ }
51
+ function assertGraphShape(graph) {
52
+ if (!isObject(graph)) throw new InvalidGraphError("graph must be an object");
53
+ for (const key of ["animations", "inputs", "states"]) {
54
+ if (!isObject(graph[key])) throw new InvalidGraphError(`${key} must be an object`);
55
+ }
56
+ if (!Array.isArray(graph.transitions)) {
57
+ throw new InvalidGraphError("transitions must be an array");
58
+ }
59
+ for (const [name, list] of Object.entries(graph.animations)) {
60
+ if (!Array.isArray(list)) {
61
+ throw new InvalidGraphError(`animation "${name}" must be an array of frame keys`);
62
+ }
63
+ }
64
+ }
40
65
  function compileGraph(graph) {
66
+ assertGraphShape(graph);
41
67
  if (Object.keys(graph.animations).length === 0) {
42
68
  throw new InvalidGraphError("animations must declare at least one animation");
43
69
  }
@@ -46,59 +72,38 @@ function compileGraph(graph) {
46
72
  throw new InvalidGraphError("states must declare at least one state");
47
73
  }
48
74
  for (const [name, def] of Object.entries(graph.inputs)) {
49
- if (def.type !== "number" && def.type !== "boolean" && def.type !== "trigger") {
75
+ const type = def?.type;
76
+ if (type !== "number" && type !== "boolean" && type !== "trigger") {
77
+ throw new InvalidGraphError(`input "${name}" has unknown type "${type}"`);
78
+ }
79
+ const d = def.default;
80
+ if (d !== void 0 && (type === "number" && typeof d !== "number" || type === "boolean" && typeof d !== "boolean")) {
50
81
  throw new InvalidGraphError(
51
- `input "${name}" has unknown type "${def.type}"`
82
+ `input "${name}" default must be a ${type} (declared type "${type}"), got ${typeof d}`
52
83
  );
53
84
  }
54
- const rawDef = def;
55
- if (rawDef.default !== void 0) {
56
- if (def.type === "number" && typeof rawDef.default !== "number") {
57
- throw new InvalidGraphError(
58
- `input "${name}" default must be a number (declared type "number"), got ${typeof rawDef.default}`
59
- );
60
- }
61
- if (def.type === "boolean" && typeof rawDef.default !== "boolean") {
62
- throw new InvalidGraphError(
63
- `input "${name}" default must be a boolean (declared type "boolean"), got ${typeof rawDef.default}`
64
- );
65
- }
66
- }
67
85
  }
68
86
  const defaultDuration = graph.defaultFrameDuration ?? DEFAULT_FRAME_DURATION;
69
- if (!Number.isFinite(defaultDuration) || defaultDuration <= 0) {
70
- throw new InvalidGraphError(
71
- `defaultFrameDuration must be a finite number > 0, got ${defaultDuration}`
72
- );
73
- }
74
- if (defaultDuration > MAX_DURATION) {
75
- throw new InvalidGraphError(
76
- `defaultFrameDuration must be \u2264 ${MAX_DURATION} ms, got ${defaultDuration}`
77
- );
78
- }
87
+ assertPositive(defaultDuration, "defaultFrameDuration", MAX_DURATION, " ms");
79
88
  if (graph.frames) {
80
89
  for (const [key, timing] of Object.entries(graph.frames)) {
81
90
  if (!isObject(timing)) {
82
91
  throw new InvalidGraphError(`frame "${key}" timing must be an object`);
83
92
  }
84
- if (timing.duration !== void 0 && (!Number.isFinite(timing.duration) || timing.duration <= 0)) {
85
- throw new InvalidGraphError(
86
- `frame "${key}" duration must be a finite number > 0, got ${timing.duration}`
87
- );
88
- }
89
- if (timing.duration !== void 0 && timing.duration > MAX_DURATION) {
90
- throw new InvalidGraphError(
91
- `frame "${key}" duration must be \u2264 ${MAX_DURATION} ms, got ${timing.duration}`
92
- );
93
+ if (timing.duration !== void 0) {
94
+ assertPositive(timing.duration, `frame "${key}" duration`, MAX_DURATION, " ms");
93
95
  }
94
96
  }
95
97
  }
98
+ if (graph.initial !== void 0) assertString(graph.initial, "initial");
96
99
  const initial = graph.initial ?? stateEntries[0][0];
97
100
  if (!Object.hasOwn(graph.states, initial)) {
98
101
  throw new InvalidGraphError(`initial state "${initial}" is not declared`);
99
102
  }
100
103
  const states = /* @__PURE__ */ new Map();
101
104
  for (const [name, st] of stateEntries) {
105
+ assertString(st?.animation, `state "${name}" animation`);
106
+ if (st.onEnd !== void 0) assertString(st.onEnd, `state "${name}" onEnd`);
102
107
  const frameKeys = graph.animations[st.animation];
103
108
  if (frameKeys === void 0 || !Object.hasOwn(graph.animations, st.animation)) {
104
109
  throw new InvalidGraphError(`state "${name}" references unknown animation "${st.animation}"`);
@@ -107,14 +112,7 @@ function compileGraph(graph) {
107
112
  throw new InvalidGraphError(`animation "${st.animation}" (state "${name}") has no frames`);
108
113
  }
109
114
  const speed = st.speed ?? 1;
110
- if (!Number.isFinite(speed) || speed <= 0) {
111
- throw new InvalidGraphError(
112
- `state "${name}" speed must be a finite number > 0, got ${speed}`
113
- );
114
- }
115
- if (speed > MAX_SPEED) {
116
- throw new InvalidGraphError(`state "${name}" speed must be \u2264 ${MAX_SPEED}, got ${speed}`);
117
- }
115
+ assertPositive(speed, `state "${name}" speed`, MAX_SPEED, "");
118
116
  const loop = st.loop === true;
119
117
  if (loop && st.onEnd !== void 0) {
120
118
  throw new InvalidGraphError(
@@ -130,23 +128,7 @@ function compileGraph(graph) {
130
128
  running += graph.frames?.[key]?.duration ?? defaultDuration;
131
129
  cumulative.push(running);
132
130
  }
133
- states.set(name, {
134
- name,
135
- animation: st.animation,
136
- loop,
137
- speed,
138
- onEnd: st.onEnd,
139
- // `frameKeys` is aliased directly from `graph.animations[st.animation]`
140
- // without copying. The declared `readonly` typing makes mutation a
141
- // compile-time error for typed callers, but callers holding the raw JSON
142
- // object can mutate it at runtime. Callers must NOT mutate the atlas
143
- // `animations` arrays while a machine built from that graph is alive;
144
- // doing so desyncs `frameKeys` from the precomputed `cumulative` timings
145
- // and can cause `frameKeys[activeFrameIndex]` to yield `undefined`.
146
- frameKeys,
147
- cumulative,
148
- total: running
149
- });
131
+ states.set(name, { name, loop, speed, onEnd: st.onEnd, frameKeys, cumulative, total: running });
150
132
  }
151
133
  const compiled = [];
152
134
  graph.transitions.forEach((t, order) => {
@@ -156,6 +138,13 @@ function compileGraph(graph) {
156
138
  if (t.when !== void 0 && !Array.isArray(t.when)) {
157
139
  throw new InvalidGraphError(`transition #${order} "when" must be an array`);
158
140
  }
141
+ assertString(t.from, `transition #${order} "from"`);
142
+ assertString(t.to, `transition #${order} "to"`);
143
+ if (t.priority !== void 0 && !Number.isInteger(t.priority)) {
144
+ throw new InvalidGraphError(
145
+ `transition #${order} priority must be an integer, got ${t.priority}`
146
+ );
147
+ }
159
148
  if (t.from !== "*" && !Object.hasOwn(graph.states, t.from)) {
160
149
  throw new InvalidGraphError(`transition #${order} from "${t.from}" is not a declared state`);
161
150
  }
@@ -165,6 +154,11 @@ function compileGraph(graph) {
165
154
  const conditions = [];
166
155
  const triggers = [];
167
156
  for (const c of t.when ?? []) {
157
+ assertString(
158
+ c?.input,
159
+ `transition #${order} condition "input"`
160
+ );
161
+ assertString(c.op, `transition #${order} condition "op"`);
168
162
  const def = graph.inputs[c.input];
169
163
  if (def === void 0 || !Object.hasOwn(graph.inputs, c.input)) {
170
164
  throw new InvalidGraphError(
@@ -262,30 +256,25 @@ function compileCondition(order, input, op, value, kind, out, triggers) {
262
256
 
263
257
  // src/sprite/emitter.ts
264
258
  function createSignal() {
265
- const listeners = /* @__PURE__ */ new Set();
266
- const cleanups = /* @__PURE__ */ new Map();
259
+ const listeners = /* @__PURE__ */ new Map();
267
260
  function on(handler, options) {
268
- if (options?.signal?.aborted) return () => {
261
+ const once = options?.once;
262
+ const sig = options?.signal;
263
+ if (sig?.aborted) return () => {
269
264
  };
270
265
  let detachAbort;
271
266
  const cleanup = () => {
272
267
  listeners.delete(wrapped);
273
- cleanups.delete(wrapped);
274
268
  if (detachAbort) {
275
269
  detachAbort();
276
270
  detachAbort = void 0;
277
271
  }
278
272
  };
279
- let wrapped = handler;
280
- if (options?.once) {
281
- wrapped = (payload) => {
282
- cleanup();
283
- handler(payload);
284
- };
285
- }
286
- listeners.add(wrapped);
287
- cleanups.set(wrapped, cleanup);
288
- const sig = options?.signal;
273
+ const wrapped = (payload) => {
274
+ if (once) cleanup();
275
+ handler(payload);
276
+ };
277
+ listeners.set(wrapped, cleanup);
289
278
  if (sig) {
290
279
  const onAbort = () => cleanup();
291
280
  sig.addEventListener("abort", onAbort, { once: true });
@@ -295,12 +284,28 @@ function createSignal() {
295
284
  }
296
285
  function emit(payload) {
297
286
  if (listeners.size === 0) return;
298
- for (const fn of [...listeners]) fn(payload);
287
+ let failure;
288
+ for (const fn of [...listeners.keys()]) {
289
+ if (!listeners.has(fn)) continue;
290
+ try {
291
+ fn(payload);
292
+ } catch (error) {
293
+ failure ??= { error };
294
+ }
295
+ }
296
+ if (failure) throw failure.error;
299
297
  }
300
298
  function clear() {
301
- for (const cleanup of [...cleanups.values()]) cleanup();
302
- listeners.clear();
303
- cleanups.clear();
299
+ try {
300
+ for (const cleanup of [...listeners.values()]) {
301
+ try {
302
+ cleanup();
303
+ } catch {
304
+ }
305
+ }
306
+ } finally {
307
+ listeners.clear();
308
+ }
304
309
  }
305
310
  return { on, emit, clear };
306
311
  }
@@ -359,9 +364,6 @@ function createInputStore(inputs) {
359
364
  return {
360
365
  setInput,
361
366
  fireTrigger,
362
- // `!` is sound: every declared input is seeded at construction and the
363
- // compiler validates that conditions only read declared inputs of the
364
- // matching kind, so these reads always hit a present entry.
365
367
  readNumber: (name) => numbers.get(name),
366
368
  readBoolean: (name) => booleans.get(name),
367
369
  isPending: (name) => triggers.get(name) === true,
@@ -389,6 +391,8 @@ function createSpriteAnimator(graph) {
389
391
  let activeFrameIndex = 0;
390
392
  let activeFrameKey = current.frameKeys[0];
391
393
  let disposed = false;
394
+ let dispatching = false;
395
+ const mailbox = [];
392
396
  function mustState(name) {
393
397
  return compiled.states.get(name);
394
398
  }
@@ -418,13 +422,13 @@ function createSpriteAnimator(graph) {
418
422
  }
419
423
  if (!ok) continue;
420
424
  if (t.to === current.name && t.triggers.length === 0) continue;
421
- return { to: t.to, triggers: t.triggers };
425
+ return t;
422
426
  }
423
427
  return void 0;
424
428
  }
425
- function update(deltaMs) {
426
- if (disposed) throw new SpriteAnimatorDisposedError();
427
- elapsed += (Number.isFinite(deltaMs) && deltaMs > 0 ? deltaMs : 0) * current.speed;
429
+ function processUpdate(deltaMs) {
430
+ const next = elapsed + (Number.isFinite(deltaMs) && deltaMs > 0 ? deltaMs : 0) * current.speed;
431
+ if (Number.isFinite(next)) elapsed = next;
428
432
  const chosen = resolve();
429
433
  if (chosen) {
430
434
  enter(chosen.to, chosen.triggers);
@@ -445,24 +449,45 @@ function createSpriteAnimator(graph) {
445
449
  activeFrameKey = cs.frameKeys[activeFrameIndex];
446
450
  if (ended && !completed) {
447
451
  completed = true;
448
- complete.emit(cs.name);
449
- if (cs.onEnd !== void 0) enter(cs.onEnd, NO_TRIGGERS);
452
+ try {
453
+ complete.emit(cs.name);
454
+ } finally {
455
+ if (cs.onEnd !== void 0 && !disposed) enter(cs.onEnd, NO_TRIGGERS);
456
+ }
457
+ }
458
+ }
459
+ function processReset() {
460
+ store.reset();
461
+ enter(compiled.initial, NO_TRIGGERS);
462
+ }
463
+ function run(first, dt) {
464
+ dispatching = true;
465
+ try {
466
+ first(dt);
467
+ while (mailbox.length > 0) {
468
+ const m = mailbox.shift();
469
+ if (m.kind === "update") processUpdate(m.dt);
470
+ else processReset();
471
+ }
472
+ } finally {
473
+ dispatching = false;
474
+ mailbox.length = 0;
450
475
  }
451
476
  }
477
+ function update(deltaMs) {
478
+ if (disposed) throw new SpriteAnimatorDisposedError();
479
+ if (dispatching) mailbox.push({ kind: "update", dt: deltaMs });
480
+ else run(processUpdate, deltaMs);
481
+ }
452
482
  function reset() {
453
483
  if (disposed) throw new SpriteAnimatorDisposedError();
454
- const from = current.name;
455
- store.reset();
456
- current = mustState(compiled.initial);
457
- elapsed = 0;
458
- completed = false;
459
- activeFrameIndex = 0;
460
- activeFrameKey = current.frameKeys[0];
461
- if (from !== compiled.initial) stateChange.emit({ to: compiled.initial, from });
484
+ if (dispatching) mailbox.push({ kind: "reset" });
485
+ else run(processReset, 0);
462
486
  }
463
487
  function dispose() {
464
488
  if (disposed) return;
465
489
  disposed = true;
490
+ mailbox.length = 0;
466
491
  stateChange.clear();
467
492
  complete.clear();
468
493
  }
@@ -507,7 +532,8 @@ exports.InputTypeError = InputTypeError;
507
532
  exports.InvalidGraphError = InvalidGraphError;
508
533
  exports.SpriteAnimatorDisposedError = SpriteAnimatorDisposedError;
509
534
  exports.UnknownInputError = UnknownInputError;
535
+ exports.assertGraphShape = assertGraphShape;
510
536
  exports.createSpriteAnimator = createSpriteAnimator;
511
537
  exports.isObject = isObject;
512
- //# sourceMappingURL=chunk-QF5N7LOI.cjs.map
513
- //# sourceMappingURL=chunk-QF5N7LOI.cjs.map
538
+ //# sourceMappingURL=chunk-GEQWS7FY.cjs.map
539
+ //# sourceMappingURL=chunk-GEQWS7FY.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sprite/errors.ts","../src/sprite/compile.ts","../src/sprite/emitter.ts","../src/sprite/inputs.ts","../src/sprite/machine.ts"],"names":["v"],"mappings":"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","file":"chunk-GEQWS7FY.cjs","sourcesContent":["// aispritejs — named error classes. Named errors instead of bare throws let\n// callers branch on failure mode (e.g. distinguish a typo'd input from a\n// post-dispose call) and keep stack traces meaningful.\n\n/**\n * Thrown by `setInput` / `fireTrigger` / `update` / `reset` after the animator\n * has been disposed.\n *\n * @public\n */\nexport class SpriteAnimatorDisposedError extends Error {\n constructor() {\n super(\"aispritejs: animator has been disposed; this operation is not allowed\");\n this.name = \"SpriteAnimatorDisposedError\";\n }\n}\n\n/**\n * Thrown by `createSpriteAnimator` when the graph fails validation — the graph\n * or one of its blocks has the wrong shape, a state/transition/condition\n * identifier is not a string, a state references a missing animation, a\n * transition points at an unknown state or has a non-integer priority, a\n * condition uses an operator the input kind does not support, a duration is\n * non-positive, and so on. Fail-fast: an invalid graph never produces a\n * half-built animator.\n *\n * @public\n */\nexport class InvalidGraphError extends Error {\n constructor(message: string) {\n super(`aispritejs: invalid graph — ${message}`);\n this.name = \"InvalidGraphError\";\n }\n}\n\n/**\n * Thrown by `setInput` / `fireTrigger` when the named input is not declared in\n * the graph's `inputs` block.\n *\n * @public\n */\nexport class UnknownInputError extends Error {\n readonly input: string;\n constructor(input: string) {\n super(`aispritejs: unknown input \"${input}\"; declare it in the graph's inputs block`);\n this.name = \"UnknownInputError\";\n this.input = input;\n }\n}\n\n/**\n * Thrown when an input is used against its kind — `setInput` with the wrong\n * value type, `setInput` on a Trigger, or `fireTrigger` on a non-Trigger.\n *\n * @public\n */\nexport class InputTypeError extends Error {\n readonly input: string;\n constructor(input: string, message: string) {\n super(`aispritejs: input \"${input}\" — ${message}`);\n this.name = \"InputTypeError\";\n this.input = input;\n }\n}\n","// aispritejs — graph compiler. Validates the graph's shape and every\n// cross-reference the type system cannot (identifier types, animation\n// existence, transition targets, operator/kind compatibility, integer\n// priorities, positive durations) and normalises the graph into a precomputed\n// runtime form: per-state cumulative frame timings and per-state transition\n// candidate lists sorted by (priority desc, declared-order asc). All allocation\n// happens here, once, so `update()` stays allocation-free.\n\nimport { InvalidGraphError } from \"./errors.js\";\nimport type { InputStore } from \"./inputs.js\";\nimport type { InputDef, SpriteGraph, StateDef, TransitionCondition } from \"./types.js\";\n\n/** A compiled condition: a closure that reads the live store and returns a boolean. */\nexport type ConditionFn = (store: InputStore) => boolean;\n\nexport interface CompiledTransition {\n readonly from: string;\n readonly to: string;\n readonly priority: number;\n /** Declared index — the deterministic tie-break when priorities are equal. */\n readonly order: number;\n /** AND-ed at runtime; empty means \"matches unconditionally\". */\n readonly conditions: readonly ConditionFn[];\n /** Trigger input names this transition consumes when taken. */\n readonly triggers: readonly string[];\n}\n\nexport interface CompiledState {\n readonly name: string;\n readonly loop: boolean;\n readonly speed: number;\n readonly onEnd: string | undefined;\n readonly frameKeys: readonly string[];\n /** `cumulative[i]` = summed duration of frames `0..i`; last entry === `total`. */\n readonly cumulative: readonly number[];\n readonly total: number;\n}\n\nexport interface CompiledGraph {\n readonly initial: string;\n readonly states: ReadonlyMap<string, CompiledState>;\n readonly candidatesByState: ReadonlyMap<string, readonly CompiledTransition[]>;\n}\n\nconst DEFAULT_FRAME_DURATION = 100;\n/** Maximum allowed frame / default-frame duration in ms (24 hours). */\nconst MAX_DURATION = 86_400_000;\n/** Maximum allowed state speed multiplier (1000× normal). */\nconst MAX_SPEED = 1_000;\n\n/** @internal */\nexport function isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/**\n * Throw {@link InvalidGraphError} naming `what` unless `v` is a string. Runs\n * before every `Object.hasOwn` lookup, which would otherwise stringify a number\n * or an array and resolve it to a declared name.\n */\nfunction assertString(v: unknown, what: string): void {\n if (typeof v !== \"string\") {\n throw new InvalidGraphError(`${what} must be a string, got ${typeof v}`);\n }\n}\n\n/** Throw {@link InvalidGraphError} unless `v` is a finite number in `(0, max]`. */\nfunction assertPositive(v: number, what: string, max: number, unit: string): void {\n if (!Number.isFinite(v) || v <= 0) {\n throw new InvalidGraphError(`${what} must be a finite number > 0, got ${v}`);\n }\n if (v > max) throw new InvalidGraphError(`${what} must be ≤ ${max}${unit}, got ${v}`);\n}\n\n/**\n * @internal Structural guard: the graph and its containers have the shapes the\n * compiler (and the Pixi adapter's texture scan) iterate, so misuse from\n * untyped callers is an {@link InvalidGraphError}, never a bare `TypeError`.\n */\nexport function assertGraphShape(graph: SpriteGraph): void {\n if (!isObject(graph)) throw new InvalidGraphError(\"graph must be an object\");\n for (const key of [\"animations\", \"inputs\", \"states\"] as const) {\n if (!isObject(graph[key])) throw new InvalidGraphError(`${key} must be an object`);\n }\n if (!Array.isArray(graph.transitions)) {\n throw new InvalidGraphError(\"transitions must be an array\");\n }\n for (const [name, list] of Object.entries(graph.animations)) {\n if (!Array.isArray(list)) {\n throw new InvalidGraphError(`animation \"${name}\" must be an array of frame keys`);\n }\n }\n}\n\nexport function compileGraph(graph: SpriteGraph): CompiledGraph {\n assertGraphShape(graph);\n if (Object.keys(graph.animations).length === 0) {\n throw new InvalidGraphError(\"animations must declare at least one animation\");\n }\n\n const stateEntries = Object.entries(graph.states);\n if (stateEntries.length === 0) {\n throw new InvalidGraphError(\"states must declare at least one state\");\n }\n\n // Inputs: types are enforced by TS, but a graph loaded from untyped JSON can\n // still carry a bad `type` or a `default` whose typeof mismatches the kind.\n // Validate so a bad input fails here, not silently in the store.\n for (const [name, def] of Object.entries(graph.inputs)) {\n // `?.`: a null / non-object entry from untyped JSON reports an unknown type.\n const type = (def as InputDef | null)?.type;\n if (type !== \"number\" && type !== \"boolean\" && type !== \"trigger\") {\n throw new InvalidGraphError(`input \"${name}\" has unknown type \"${type}\"`);\n }\n // Validate `default` typeof matches the declared kind (schema constraint in\n // code). A wrong-typed default would be adopted unvalidated and silently\n // misevaluate conditions (e.g. \"5\" === 5 is false for Equals).\n const d = (def as { default?: unknown }).default;\n if (\n d !== undefined &&\n ((type === \"number\" && typeof d !== \"number\") ||\n (type === \"boolean\" && typeof d !== \"boolean\"))\n ) {\n throw new InvalidGraphError(\n `input \"${name}\" default must be a ${type} (declared type \"${type}\"), got ${typeof d}`,\n );\n }\n }\n\n const defaultDuration = graph.defaultFrameDuration ?? DEFAULT_FRAME_DURATION;\n assertPositive(defaultDuration, \"defaultFrameDuration\", MAX_DURATION, \" ms\");\n\n if (graph.frames) {\n for (const [key, timing] of Object.entries(graph.frames)) {\n if (!isObject(timing as unknown)) {\n throw new InvalidGraphError(`frame \"${key}\" timing must be an object`);\n }\n if (timing.duration !== undefined) {\n assertPositive(timing.duration, `frame \"${key}\" duration`, MAX_DURATION, \" ms\");\n }\n }\n }\n\n if (graph.initial !== undefined) assertString(graph.initial, \"initial\");\n const initial = graph.initial ?? stateEntries[0]![0];\n if (!Object.hasOwn(graph.states, initial)) {\n throw new InvalidGraphError(`initial state \"${initial}\" is not declared`);\n }\n\n // --- compile states -----------------------------------------------------\n const states = new Map<string, CompiledState>();\n for (const [name, st] of stateEntries) {\n // `?.`: a null / non-object state entry fails the animation-type check.\n assertString((st as StateDef | null)?.animation, `state \"${name}\" animation`);\n if (st.onEnd !== undefined) assertString(st.onEnd, `state \"${name}\" onEnd`);\n const frameKeys = graph.animations[st.animation];\n if (frameKeys === undefined || !Object.hasOwn(graph.animations, st.animation)) {\n throw new InvalidGraphError(`state \"${name}\" references unknown animation \"${st.animation}\"`);\n }\n if (frameKeys.length === 0) {\n throw new InvalidGraphError(`animation \"${st.animation}\" (state \"${name}\") has no frames`);\n }\n const speed = st.speed ?? 1;\n assertPositive(speed, `state \"${name}\" speed`, MAX_SPEED, \"\");\n const loop = st.loop === true;\n if (loop && st.onEnd !== undefined) {\n throw new InvalidGraphError(\n `state \"${name}\" loops, so onEnd \"${st.onEnd}\" would never fire; set loop:false or drop onEnd`,\n );\n }\n if (st.onEnd !== undefined && !Object.hasOwn(graph.states, st.onEnd)) {\n throw new InvalidGraphError(`state \"${name}\" onEnd target \"${st.onEnd}\" is not declared`);\n }\n\n const cumulative: number[] = [];\n let running = 0;\n for (const key of frameKeys) {\n running += graph.frames?.[key]?.duration ?? defaultDuration;\n cumulative.push(running);\n }\n\n // `frameKeys` is aliased directly from `graph.animations[st.animation]`\n // without copying. The declared `readonly` typing makes mutation a\n // compile-time error for typed callers, but callers holding the raw JSON\n // object can mutate it at runtime. Callers must NOT mutate the atlas\n // `animations` arrays while a machine built from that graph is alive;\n // doing so desyncs `frameKeys` from the precomputed `cumulative` timings\n // and can cause `frameKeys[activeFrameIndex]` to yield `undefined`.\n states.set(name, { name, loop, speed, onEnd: st.onEnd, frameKeys, cumulative, total: running });\n }\n\n // --- compile transitions ------------------------------------------------\n const compiled: CompiledTransition[] = [];\n graph.transitions.forEach((t, order) => {\n if (!isObject(t as unknown)) {\n throw new InvalidGraphError(`transition #${order} must be an object`);\n }\n if (t.when !== undefined && !Array.isArray(t.when)) {\n throw new InvalidGraphError(`transition #${order} \"when\" must be an array`);\n }\n assertString(t.from, `transition #${order} \"from\"`);\n assertString(t.to, `transition #${order} \"to\"`);\n if (t.priority !== undefined && !Number.isInteger(t.priority)) {\n throw new InvalidGraphError(\n `transition #${order} priority must be an integer, got ${t.priority}`,\n );\n }\n if (t.from !== \"*\" && !Object.hasOwn(graph.states, t.from)) {\n throw new InvalidGraphError(`transition #${order} from \"${t.from}\" is not a declared state`);\n }\n if (!Object.hasOwn(graph.states, t.to)) {\n throw new InvalidGraphError(`transition #${order} to \"${t.to}\" is not a declared state`);\n }\n\n const conditions: ConditionFn[] = [];\n const triggers: string[] = [];\n for (const c of t.when ?? []) {\n // `?.`: a null / non-object condition fails the input-type check.\n assertString(\n (c as TransitionCondition | null)?.input,\n `transition #${order} condition \"input\"`,\n );\n assertString(c.op, `transition #${order} condition \"op\"`);\n const def = graph.inputs[c.input];\n if (def === undefined || !Object.hasOwn(graph.inputs, c.input)) {\n throw new InvalidGraphError(\n `transition #${order} condition references unknown input \"${c.input}\"`,\n );\n }\n compileCondition(order, c.input, c.op, c.value, def.type, conditions, triggers);\n }\n\n compiled.push({\n from: t.from,\n to: t.to,\n priority: t.priority ?? 0,\n order,\n conditions,\n triggers,\n });\n });\n\n // --- group candidates per state (own + Any-State), sorted ---------------\n const candidatesByState = new Map<string, readonly CompiledTransition[]>();\n for (const [name] of stateEntries) {\n const list = compiled.filter((t) => t.from === name || t.from === \"*\");\n // Stable by construction (declared order), but make the tie-break explicit.\n list.sort((a, b) => b.priority - a.priority || a.order - b.order);\n candidatesByState.set(name, list);\n }\n\n return { initial, states, candidatesByState };\n}\n\nfunction compileCondition(\n order: number,\n input: string,\n op: string,\n value: number | boolean | undefined,\n kind: \"number\" | \"boolean\" | \"trigger\",\n out: ConditionFn[],\n triggers: string[],\n): void {\n switch (op) {\n case \"Trigger\": {\n if (kind !== \"trigger\") {\n throw new InvalidGraphError(\n `transition #${order}: op Trigger requires a trigger input, but \"${input}\" is ${kind}`,\n );\n }\n if (value !== undefined) {\n throw new InvalidGraphError(\n `transition #${order}: Trigger condition on \"${input}\" must not carry a value`,\n );\n }\n out.push((s) => s.isPending(input));\n triggers.push(input);\n return;\n }\n case \"GreaterThan\":\n case \"LessThan\": {\n if (kind !== \"number\") {\n throw new InvalidGraphError(\n `transition #${order}: op ${op} requires a number input, but \"${input}\" is ${kind}`,\n );\n }\n if (typeof value !== \"number\") {\n throw new InvalidGraphError(\n `transition #${order}: op ${op} on \"${input}\" needs a numeric value`,\n );\n }\n const v = value;\n out.push(\n op === \"GreaterThan\" ? (s) => s.readNumber(input) > v : (s) => s.readNumber(input) < v,\n );\n return;\n }\n case \"Equals\":\n case \"NotEquals\": {\n if (kind === \"trigger\") {\n throw new InvalidGraphError(\n `transition #${order}: op ${op} cannot apply to trigger input \"${input}\"`,\n );\n }\n if (kind === \"number\") {\n if (typeof value !== \"number\") {\n throw new InvalidGraphError(\n `transition #${order}: op ${op} on number input \"${input}\" needs a numeric value`,\n );\n }\n const v = value;\n out.push(\n op === \"Equals\" ? (s) => s.readNumber(input) === v : (s) => s.readNumber(input) !== v,\n );\n return;\n }\n // kind === \"boolean\"\n if (typeof value !== \"boolean\") {\n throw new InvalidGraphError(\n `transition #${order}: op ${op} on boolean input \"${input}\" needs a boolean value`,\n );\n }\n const v = value;\n out.push(\n op === \"Equals\" ? (s) => s.readBoolean(input) === v : (s) => s.readBoolean(input) !== v,\n );\n return;\n }\n default:\n throw new InvalidGraphError(`transition #${order}: unknown operator \"${op}\"`);\n }\n}\n","// aispritejs — a tiny single-payload typed signal. This is the package's OWN\n// emitter; it deliberately does NOT import `aieventjs` or any sibling (P0\n// zero-cross-package rule). Two instances back `onStateChange` and\n// `onComplete`.\n\nimport type { ListenerOptions, Unsubscribe } from \"./types.js\";\n\n/**\n * A typed fan-out of one payload `P`. `emit` is allocation-free in the common\n * case; it snapshots listeners only when there is at least one, so a handler\n * that unsubscribes (or a `once` handler) cannot corrupt the in-flight\n * iteration. A listener removed during a dispatch is skipped for the rest of it.\n * If listeners throw, the rest still run and the first error is rethrown.\n */\nexport interface Signal<P> {\n on(handler: (payload: P) => void, options?: ListenerOptions): Unsubscribe;\n emit(payload: P): void;\n /** Drop every listener (used by `dispose`). */\n clear(): void;\n}\n\nexport function createSignal<P>(): Signal<P> {\n // Each listener maps to its cleanup function so clear() can detach abort\n // hooks as well as emptying the registry (fixes SPR-R-01).\n const listeners = new Map<(payload: P) => void, Unsubscribe>();\n\n function on(handler: (payload: P) => void, options?: ListenerOptions): Unsubscribe {\n const once = options?.once;\n const sig = options?.signal;\n // An already-aborted signal means the listener is dead on arrival.\n if (sig?.aborted) return () => {};\n\n let detachAbort: (() => void) | undefined;\n // One teardown shared by the unsubscribe return, the once-wrapper, and the\n // abort handler, so every path also detaches the abort listener — a `once`\n // handler that passed a `{ signal }` must not leave the abort listener\n // attached after it fires.\n const cleanup: Unsubscribe = () => {\n listeners.delete(wrapped);\n if (detachAbort) {\n detachAbort();\n detachAbort = undefined;\n }\n };\n\n // Always wrap, so every registration has its own identity in `listeners`\n // even when the same handler is subscribed more than once.\n const wrapped = (payload: P): void => {\n if (once) cleanup();\n handler(payload);\n };\n listeners.set(wrapped, cleanup);\n\n if (sig) {\n const onAbort = () => cleanup();\n sig.addEventListener(\"abort\", onAbort, { once: true });\n detachAbort = () => sig.removeEventListener(\"abort\", onAbort);\n }\n\n return cleanup;\n }\n\n function emit(payload: P): void {\n if (listeners.size === 0) return;\n // Snapshot so a handler that unsubscribes (including the once-wrapper)\n // during dispatch does not perturb this pass, but re-check membership so a\n // listener removed mid-dispatch (by a re-entrant emit that already fired a\n // once-wrapper, by dispose(), or by an aborted signal) is not called.\n // A throwing listener must not starve the rest: call every listener, then\n // rethrow the first error once the pass is complete.\n let failure: { error: unknown } | undefined;\n for (const fn of [...listeners.keys()]) {\n if (!listeners.has(fn)) continue;\n try {\n fn(payload);\n } catch (error) {\n failure ??= { error };\n }\n }\n if (failure) throw failure.error;\n }\n\n function clear(): void {\n // Run each cleanup so abort hooks are detached from caller AbortSignals\n // (SPR-R-01). Snapshot the values first because cleanup() mutates the map.\n // A throwing cleanup (e.g. a misbehaving AbortSignal.removeEventListener)\n // must not abort the iteration and must not prevent the map from being\n // fully emptied — mirror the aifsmjs dispose() try/catch + finally pattern.\n try {\n for (const cleanup of [...listeners.values()]) {\n try {\n cleanup();\n } catch {\n // Swallow per-cleanup errors; every registered cleanup must still run.\n }\n }\n } finally {\n // Guarantee an empty post-condition even if the loop itself somehow throws.\n listeners.clear();\n }\n }\n\n return { on, emit, clear };\n}\n","// aispritejs — the input store. Holds Number / Boolean values and Trigger\n// pending flags with O(1) lookup. All declared inputs are seeded at\n// construction so reads are total (the compiler guarantees every condition\n// references a declared input of the matching kind, so the non-null reads\n// below are sound).\n\nimport { InputTypeError, UnknownInputError } from \"./errors.js\";\nimport type { InputDef } from \"./types.js\";\n\nexport interface InputStore {\n /** Set a Number/Boolean input. Throws on unknown name or kind mismatch. */\n setInput(name: string, value: number | boolean): void;\n /** Mark a Trigger pending. Throws on unknown name or non-Trigger. */\n fireTrigger(name: string): void;\n /** Read a Number input (caller guarantees `name` is a declared Number). */\n readNumber(name: string): number;\n /** Read a Boolean input (caller guarantees `name` is a declared Boolean). */\n readBoolean(name: string): boolean;\n /** Whether a Trigger is currently pending. */\n isPending(name: string): boolean;\n /** Consume (reset) a pending Trigger after a transition takes it. */\n consume(name: string): void;\n /** Restore every input to its declared default and clear all triggers. */\n reset(): void;\n}\n\ntype Kind = \"number\" | \"boolean\" | \"trigger\";\n\nexport function createInputStore(inputs: Readonly<Record<string, InputDef>>): InputStore {\n const kinds = new Map<string, Kind>();\n const numberDefaults = new Map<string, number>();\n const booleanDefaults = new Map<string, boolean>();\n const numbers = new Map<string, number>();\n const booleans = new Map<string, boolean>();\n const triggers = new Map<string, boolean>();\n\n for (const [name, def] of Object.entries(inputs)) {\n kinds.set(name, def.type);\n if (def.type === \"number\") {\n const d = def.default ?? 0;\n numberDefaults.set(name, d);\n numbers.set(name, d);\n } else if (def.type === \"boolean\") {\n const d = def.default ?? false;\n booleanDefaults.set(name, d);\n booleans.set(name, d);\n } else {\n triggers.set(name, false);\n }\n }\n\n function setInput(name: string, value: number | boolean): void {\n const kind = kinds.get(name);\n if (kind === undefined) throw new UnknownInputError(name);\n if (kind === \"trigger\") {\n throw new InputTypeError(name, \"is a Trigger; use fireTrigger()\");\n }\n if (kind === \"number\") {\n if (typeof value !== \"number\") {\n throw new InputTypeError(name, `expects a number, received ${typeof value}`);\n }\n if (Number.isNaN(value)) {\n throw new InputTypeError(name, \"cannot be set to NaN\");\n }\n numbers.set(name, value);\n return;\n }\n // kind === \"boolean\"\n if (typeof value !== \"boolean\") {\n throw new InputTypeError(name, `expects a boolean, received ${typeof value}`);\n }\n booleans.set(name, value);\n }\n\n function fireTrigger(name: string): void {\n const kind = kinds.get(name);\n if (kind === undefined) throw new UnknownInputError(name);\n if (kind !== \"trigger\") {\n throw new InputTypeError(name, \"is not a Trigger; use setInput()\");\n }\n triggers.set(name, true);\n }\n\n // `!` is sound: every declared input is seeded at construction and the\n // compiler validates that conditions only read declared inputs of the\n // matching kind, so these reads always hit a present entry.\n return {\n setInput,\n fireTrigger,\n readNumber: (name) => numbers.get(name)!,\n readBoolean: (name) => booleans.get(name)!,\n isPending: (name) => triggers.get(name) === true,\n consume: (name) => {\n triggers.set(name, false);\n },\n reset: () => {\n for (const [name, d] of numberDefaults) numbers.set(name, d);\n for (const [name, d] of booleanDefaults) booleans.set(name, d);\n for (const name of triggers.keys()) triggers.set(name, false);\n },\n };\n}\n","// aispritejs — the input-driven visual state machine (the \"RiveSpriteStateMachine\"\n// engine), exposed only through the `createSpriteAnimator` factory. Implemented\n// as closures, not a class, so methods never depend on `this` and the\n// constructor surface stays hidden (family convention: public API = createX).\n//\n// Determinism: the only state advanced by `update` is `elapsed` (by `dt * speed`)\n// plus the input store; transitions are resolved over precomputed, deterministically\n// ordered candidate lists. Identical input + dt sequences therefore yield identical\n// frame sequences. The no-transition path allocates nothing.\n//\n// Run-to-completion: `update()` / `reset()` own the machine's state, so a call\n// made while one is already dispatching (from an `onStateChange` / `onComplete`\n// listener) is queued in a FIFO mailbox and runs after the current call's last\n// notification (ai*js family rule for state-owning dispatchers).\n\nimport { type CompiledState, type CompiledTransition, compileGraph } from \"./compile.js\";\nimport { createSignal } from \"./emitter.js\";\nimport { SpriteAnimatorDisposedError } from \"./errors.js\";\nimport { createInputStore } from \"./inputs.js\";\nimport type {\n CompleteHandler,\n ListenerOptions,\n SpriteAnimator,\n SpriteGraph,\n StateChangeHandler,\n Unsubscribe,\n} from \"./types.js\";\n\ninterface StateChangePayload {\n readonly to: string;\n readonly from: string;\n}\n\nconst NO_TRIGGERS: readonly string[] = [];\n\n/** A nested `update()` / `reset()` waiting for the current dispatch to finish. */\ntype Queued = { readonly kind: \"update\"; readonly dt: number } | { readonly kind: \"reset\" };\n\n/**\n * Build a renderer-agnostic visual animator from an input-driven graph.\n *\n * @param graph - inputs, states, transitions, animations (+ optional per-frame\n * timings). Validated eagerly; an invalid graph throws {@link InvalidGraphError}\n * and no animator is returned.\n * @returns a {@link SpriteAnimator}.\n *\n * @public\n */\nexport function createSpriteAnimator(graph: SpriteGraph): SpriteAnimator {\n const compiled = compileGraph(graph);\n const store = createInputStore(graph.inputs);\n const stateChange = createSignal<StateChangePayload>();\n const complete = createSignal<string>();\n\n let current: CompiledState = mustState(compiled.initial);\n let elapsed = 0;\n let completed = false;\n let activeFrameIndex = 0;\n // Every compiled state has >= 1 frame (validated), so frame 0 always exists.\n let activeFrameKey: string = current.frameKeys[0]!;\n let disposed = false;\n let dispatching = false;\n const mailbox: Queued[] = [];\n\n // `name` is always an initial / transition `to` / `onEnd` target, all\n // validated to exist by compileGraph, so the lookup never misses.\n function mustState(name: string): CompiledState {\n return compiled.states.get(name)!;\n }\n\n /** Enter `to`, optionally consuming the triggers the taking transition used. */\n function enter(to: string, consume: readonly string[]): void {\n const from = current.name;\n for (let i = 0; i < consume.length; i++) {\n store.consume(consume[i]!);\n }\n current = mustState(to);\n elapsed = 0;\n completed = false;\n activeFrameIndex = 0;\n activeFrameKey = current.frameKeys[0]!;\n // A self-re-entry (to === from) restarts the clip but is not a state change.\n if (to !== from) stateChange.emit({ to, from });\n }\n\n /**\n * First *effective* transition leaving `current` (own + Any-State), in\n * (priority desc, declared order) — or `undefined`. A transition whose target\n * equals the current state is effective only if it consumes a Trigger (a\n * Number/Boolean self-loop would otherwise restart the clip every frame).\n */\n function resolve(): CompiledTransition | undefined {\n // Every state has a candidate list (built for all states by compileGraph).\n const list = compiled.candidatesByState.get(current.name)!;\n for (let i = 0; i < list.length; i++) {\n const t = list[i]!;\n let ok = true;\n const conds = t.conditions;\n for (let j = 0; j < conds.length; j++) {\n if (!conds[j]!(store)) {\n ok = false;\n break;\n }\n }\n if (!ok) continue;\n if (t.to === current.name && t.triggers.length === 0) continue;\n return t;\n }\n return undefined;\n }\n\n function processUpdate(deltaMs: number): void {\n // Advance the playback timer (non-finite or non-positive dt clamped to 0 for determinism).\n // NOTE: `elapsed` accumulates without bound in looping states (intentional design choice).\n // Drift from floating-point accumulation is sub-ULP-relevant only after continuous play\n // on the order of years; a periodic reset (e.g. on state entry) would be premature.\n // A step that would overflow `elapsed` to Infinity (whose `% total` is NaN) is\n // dropped: clamped to no progress, like an invalid dt.\n const next = elapsed + (Number.isFinite(deltaMs) && deltaMs > 0 ? deltaMs : 0) * current.speed;\n if (Number.isFinite(next)) elapsed = next;\n\n // Evaluate input-driven transitions first; an explicit transition wins over\n // implicit end-of-clip behaviour.\n const chosen = resolve();\n if (chosen) {\n enter(chosen.to, chosen.triggers);\n return;\n }\n\n // Compute the active frame from accumulated time vs cumulative durations.\n const cs = current;\n const n = cs.frameKeys.length;\n let ended = false;\n if (!cs.loop && elapsed >= cs.total) {\n activeFrameIndex = n - 1;\n ended = true;\n } else {\n const t = cs.loop ? elapsed % cs.total : elapsed;\n let i = 0;\n // First index whose cumulative end exceeds t (i < n-1 keeps it in range,\n // and t < total guarantees a match no later than the last frame).\n while (i < n - 1 && t >= cs.cumulative[i]!) i++;\n activeFrameIndex = i;\n }\n activeFrameKey = cs.frameKeys[activeFrameIndex]!;\n\n // Fire onComplete once for a finished non-looping clip, then auto-transition.\n if (ended && !completed) {\n completed = true;\n try {\n complete.emit(cs.name);\n } finally {\n // A reset() / update() from an onComplete handler is queued (it runs\n // after this), so only dispose() can intervene here. Runs in `finally`\n // so a throwing handler cannot wedge the machine on its last frame\n // (`completed` is already set, so no later tick would).\n if (cs.onEnd !== undefined && !disposed) enter(cs.onEnd, NO_TRIGGERS);\n }\n }\n }\n\n function processReset(): void {\n store.reset();\n // Restarts the initial clip; notifies only if the state actually changes.\n enter(compiled.initial, NO_TRIGGERS);\n }\n\n /**\n * Run `first(dt)` to completion, then drain the calls its listeners queued,\n * in order. dispose() empties the mailbox, which ends the drain. A throw drops\n * whatever is still queued and propagates from this (outermost) call. Takes\n * `dt` separately so the per-frame path allocates no closure.\n */\n function run(first: (dt: number) => void, dt: number): void {\n dispatching = true;\n try {\n first(dt);\n while (mailbox.length > 0) {\n const m = mailbox.shift()!;\n if (m.kind === \"update\") processUpdate(m.dt);\n else processReset();\n }\n } finally {\n dispatching = false;\n mailbox.length = 0;\n }\n }\n\n function update(deltaMs: number): void {\n if (disposed) throw new SpriteAnimatorDisposedError();\n if (dispatching) mailbox.push({ kind: \"update\", dt: deltaMs });\n else run(processUpdate, deltaMs);\n }\n\n function reset(): void {\n if (disposed) throw new SpriteAnimatorDisposedError();\n if (dispatching) mailbox.push({ kind: \"reset\" });\n else run(processReset, 0);\n }\n\n function dispose(): void {\n if (disposed) return;\n disposed = true;\n mailbox.length = 0;\n stateChange.clear();\n complete.clear();\n }\n\n return {\n setInput(name, value) {\n if (disposed) throw new SpriteAnimatorDisposedError();\n store.setInput(name, value);\n },\n fireTrigger(name) {\n if (disposed) throw new SpriteAnimatorDisposedError();\n store.fireTrigger(name);\n },\n update,\n reset,\n dispose,\n onStateChange(handler: StateChangeHandler, options?: ListenerOptions): Unsubscribe {\n if (disposed) return () => {};\n return stateChange.on((p) => handler(p.to, p.from), options);\n },\n onComplete(handler: CompleteHandler, options?: ListenerOptions): Unsubscribe {\n if (disposed) return () => {};\n return complete.on(handler, options);\n },\n get activeState() {\n return current.name;\n },\n get activeFrameKey() {\n return activeFrameKey;\n },\n get activeFrameIndex() {\n return activeFrameIndex;\n },\n get disposed() {\n return disposed;\n },\n };\n}\n"]}