aispritejs 0.1.1 → 0.1.3
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 +62 -4
- package/README_ZHTW.md +60 -3
- package/dist/atlas/index.cjs +60 -17
- package/dist/atlas/index.cjs.map +1 -1
- package/dist/atlas/index.d.cts +1 -1
- package/dist/atlas/index.d.ts +1 -1
- package/dist/atlas/index.js +60 -17
- package/dist/atlas/index.js.map +1 -1
- package/dist/index.cjs +31 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +31 -13
- package/dist/index.js.map +1 -1
- package/dist/pixi/index.cjs +31 -13
- package/dist/pixi/index.cjs.map +1 -1
- package/dist/pixi/index.d.cts +1 -1
- package/dist/pixi/index.d.ts +1 -1
- package/dist/pixi/index.js +31 -13
- package/dist/pixi/index.js.map +1 -1
- package/dist/{types-DKMFvfx9.d.cts → types-BS72pefJ.d.cts} +8 -2
- package/dist/{types-DKMFvfx9.d.ts → types-BS72pefJ.d.ts} +8 -2
- package/llms-full.txt +110 -5
- package/llms.txt +1 -1
- package/package.json +2 -1
- package/schemas/aispritejs-graph.schema.json +2 -1
package/dist/pixi/index.js.map
CHANGED
|
@@ -1 +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","../../src/pixi/animator.ts"],"names":["v"],"mappings":"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","file":"index.js","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 — a state\n * references a missing animation, a transition points at an unknown state, 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 every cross-reference the type system\n// cannot (animation existence, transition targets, operator/kind compatibility,\n// positive durations) and normalises the graph into a precomputed runtime form:\n// per-state cumulative frame timings and per-state transition candidate lists\n// sorted by (priority desc, declared-order asc). All allocation happens here,\n// once, so `update()` stays allocation-free.\n\nimport { InvalidGraphError } from \"./errors.js\";\nimport type { InputStore } from \"./inputs.js\";\nimport type { SpriteGraph } 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 animation: 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\nexport function compileGraph(graph: SpriteGraph): CompiledGraph {\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`. Validate so a bad input fails here, not silently.\n for (const [name, def] of Object.entries(graph.inputs)) {\n if (def.type !== \"number\" && def.type !== \"boolean\" && def.type !== \"trigger\") {\n throw new InvalidGraphError(\n `input \"${name}\" has unknown type \"${(def as { type: string }).type}\"`,\n );\n }\n }\n\n const defaultDuration = graph.defaultFrameDuration ?? DEFAULT_FRAME_DURATION;\n if (!(defaultDuration > 0)) {\n throw new InvalidGraphError(`defaultFrameDuration must be > 0, got ${defaultDuration}`);\n }\n\n if (graph.frames) {\n for (const [key, timing] of Object.entries(graph.frames)) {\n if (timing.duration !== undefined && !(timing.duration > 0)) {\n throw new InvalidGraphError(`frame \"${key}\" duration must be > 0, got ${timing.duration}`);\n }\n }\n }\n\n const initial = graph.initial ?? stateEntries[0]![0];\n if (!(initial in graph.states)) {\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 const frameKeys = graph.animations[st.animation];\n if (frameKeys === undefined) {\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 if (!(speed > 0)) {\n throw new InvalidGraphError(`state \"${name}\" speed must be > 0, got ${speed}`);\n }\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 && !(st.onEnd in graph.states)) {\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 states.set(name, {\n name,\n animation: st.animation,\n loop,\n speed,\n onEnd: st.onEnd,\n frameKeys,\n cumulative,\n total: running,\n });\n }\n\n // --- compile transitions ------------------------------------------------\n const compiled: CompiledTransition[] = [];\n graph.transitions.forEach((t, order) => {\n if (t.from !== \"*\" && !(t.from in graph.states)) {\n throw new InvalidGraphError(`transition #${order} from \"${t.from}\" is not a declared state`);\n }\n if (!(t.to in graph.states)) {\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 const def = graph.inputs[c.input];\n if (def === undefined) {\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.\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 const listeners = new Set<(payload: P) => void>();\n\n function on(handler: (payload: P) => void, options?: ListenerOptions): Unsubscribe {\n // An already-aborted signal means the listener is dead on arrival.\n if (options?.signal?.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 let wrapped: (payload: P) => void = handler;\n if (options?.once) {\n wrapped = (payload) => {\n cleanup();\n handler(payload);\n };\n }\n listeners.add(wrapped);\n\n const sig = options?.signal;\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.\n for (const fn of [...listeners]) fn(payload);\n }\n\n function clear(): void {\n listeners.clear();\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 return {\n setInput,\n fireTrigger,\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 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\nimport { type CompiledState, 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/**\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\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(): { to: string; triggers: readonly string[] } | 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 { to: t.to, triggers: t.triggers };\n }\n return undefined;\n }\n\n function update(deltaMs: number): void {\n if (disposed) throw new SpriteAnimatorDisposedError();\n\n // Advance the playback timer (negative dt clamped to 0 for determinism).\n elapsed += (deltaMs > 0 ? deltaMs : 0) * current.speed;\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 complete.emit(cs.name);\n if (cs.onEnd !== undefined) enter(cs.onEnd, NO_TRIGGERS);\n }\n }\n\n function reset(): void {\n if (disposed) throw new SpriteAnimatorDisposedError();\n const from = current.name;\n store.reset();\n current = mustState(compiled.initial);\n elapsed = 0;\n completed = false;\n activeFrameIndex = 0;\n activeFrameKey = current.frameKeys[0]!;\n if (from !== compiled.initial) stateChange.emit({ to: compiled.initial, from });\n }\n\n function dispose(): void {\n if (disposed) return;\n disposed = true;\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","// aispritejs/pixi — the PixiJS v8 renderer adapter. It binds the\n// renderer-agnostic core to a `PIXI.Sprite`: on each update it swaps the\n// sprite's texture to the core's active frame and (by default) applies that\n// frame's atlas anchor.\n//\n// `pixi.js` is imported **type-only**, so the built subpath contains no runtime\n// `pixi.js` require — the peer is needed only by the consumer who passes real\n// Sprite / Spritesheet instances. `pixi.js` is declared as an OPTIONAL\n// peerDependency; the core (`aispritejs`) never imports this module.\n\nimport type { Sprite, Spritesheet, Texture } from \"pixi.js\";\nimport { type SpriteGraph, createSpriteAnimator } from \"../sprite/index.js\";\n\n/**\n * Thrown by {@link createPixiSpriteAnimator} when the supplied textures are\n * missing one or more frame keys the graph's animations reference. Fail-fast at\n * construction, so `update()` never has to guard.\n *\n * @public\n */\nexport class MissingTextureError extends Error {\n readonly keys: readonly string[];\n constructor(keys: readonly string[]) {\n super(`aispritejs/pixi: no texture for frame key(s): ${keys.join(\", \")}`);\n this.name = \"MissingTextureError\";\n this.keys = keys;\n }\n}\n\n/** Frame-key → texture lookup. A PixiJS `Spritesheet` exposes one as `.textures`. */\nexport type TextureMap = Record<string, Texture>;\n\n/**\n * Options for {@link createPixiSpriteAnimator}.\n *\n * @public\n */\nexport interface PixiSpriteAnimatorOptions {\n /**\n * Apply each frame's atlas anchor (`texture.defaultAnchor`) to the sprite when\n * the frame changes — preserving non-centre / foot pivots. Default `true`.\n * Set `false` to manage the anchor yourself.\n */\n readonly applyAnchor?: boolean;\n}\n\n/**\n * A PixiJS-bound animator: the core machine plus a sprite whose texture tracks\n * the active frame.\n *\n * @public\n */\nexport interface PixiSpriteAnimator {\n /** The bound sprite, updated in place. */\n readonly sprite: Sprite;\n /** Run the core machine for `deltaMs`, then sync the sprite's texture. */\n update(deltaMs: number): void;\n /** Set a Number / Boolean input on the core machine. */\n setInput(name: string, value: number | boolean): void;\n /** Fire a Trigger on the core machine. */\n fireTrigger(name: string): void;\n /** Reset the core machine and re-sync the sprite. */\n reset(): void;\n /** Dispose the core machine. Idempotent. Does not destroy the sprite. */\n dispose(): void;\n /** Current state name. */\n readonly activeState: string;\n /** Current frame key. */\n readonly activeFrameKey: string;\n /** `true` once disposed. */\n readonly disposed: boolean;\n}\n\nfunction toTextureMap(src: Spritesheet | TextureMap): TextureMap {\n // A Spritesheet exposes its frame textures under `.textures`; a plain map is\n // used directly. (If you have a frame literally named \"textures\", pass\n // `spritesheet.textures` instead of the spritesheet.)\n const maybe = src as { textures?: unknown };\n if (maybe.textures && typeof maybe.textures === \"object\") {\n return maybe.textures as TextureMap;\n }\n return src as TextureMap;\n}\n\n/**\n * Bind an input-driven {@link SpriteGraph} to a PixiJS `Sprite`.\n *\n * @param sprite - a plain `Sprite` to drive; its `texture` (and, by default,\n * `anchor`) are updated in place. The adapter owns frame selection, so if a\n * *playing* `AnimatedSprite` is passed (it extends `Sprite`), its internal\n * playback is stopped to stop it fighting the adapter for the texture.\n * @param graph - the input-driven graph (same shape the core consumes).\n * @param textures - a `Spritesheet` or a frame-key → `Texture` map covering\n * every frame the graph references.\n * @param options - see {@link PixiSpriteAnimatorOptions}.\n * @returns a {@link PixiSpriteAnimator}.\n * @throws {@link MissingTextureError} if a referenced frame key has no texture.\n * @throws {@link InvalidGraphError} if the graph is invalid.\n *\n * @public\n */\nexport function createPixiSpriteAnimator(\n sprite: Sprite,\n graph: SpriteGraph,\n textures: Spritesheet | TextureMap,\n options?: PixiSpriteAnimatorOptions,\n): PixiSpriteAnimator {\n const map = toTextureMap(textures);\n const applyAnchor = options?.applyAnchor !== false;\n\n // The adapter owns the sprite's texture/anchor. An AnimatedSprite (which\n // extends Sprite, so the type permits it) drives its own texture from an\n // internal ticker; if it is playing it would fight our frame swaps. Stop it.\n // Structural check — pixi.js is type-only here, so no `instanceof`.\n const playable = sprite as { stop?: () => void };\n if (typeof playable.stop === \"function\") playable.stop();\n\n // Fail-fast: every frame key reachable from the graph must have a texture.\n const missing = new Set<string>();\n for (const frameKeys of Object.values(graph.animations)) {\n for (const key of frameKeys) {\n if (!(key in map)) missing.add(key);\n }\n }\n if (missing.size > 0) throw new MissingTextureError([...missing]);\n\n const core = createSpriteAnimator(graph);\n\n // Swap the sprite's texture (and anchor) only when the active frame changes.\n let boundKey = \"\";\n function sync(): void {\n const key = core.activeFrameKey;\n if (key === boundKey) return;\n boundKey = key;\n const tex = map[key]!; // verified present above\n sprite.texture = tex;\n if (applyAnchor && tex.defaultAnchor) {\n sprite.anchor.set(tex.defaultAnchor.x, tex.defaultAnchor.y);\n }\n }\n sync(); // bind the initial frame before the first update\n\n return {\n sprite,\n update(deltaMs) {\n core.update(deltaMs);\n sync();\n },\n setInput(name, value) {\n core.setInput(name, value);\n },\n fireTrigger(name) {\n core.fireTrigger(name);\n },\n reset() {\n core.reset();\n sync();\n },\n dispose() {\n core.dispose();\n },\n get activeState() {\n return core.activeState;\n },\n get activeFrameKey() {\n return core.activeFrameKey;\n },\n get disposed() {\n return core.disposed;\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/sprite/errors.ts","../../src/sprite/compile.ts","../../src/sprite/emitter.ts","../../src/sprite/inputs.ts","../../src/sprite/machine.ts","../../src/pixi/animator.ts"],"names":["v"],"mappings":"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","file":"index.js","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 — a state\n * references a missing animation, a transition points at an unknown state, 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 every cross-reference the type system\n// cannot (animation existence, transition targets, operator/kind compatibility,\n// positive durations) and normalises the graph into a precomputed runtime form:\n// per-state cumulative frame timings and per-state transition candidate lists\n// sorted by (priority desc, declared-order asc). All allocation happens here,\n// once, so `update()` stays allocation-free.\n\nimport { InvalidGraphError } from \"./errors.js\";\nimport type { InputStore } from \"./inputs.js\";\nimport type { SpriteGraph } 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 animation: 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\n/** @internal */\nexport function isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nexport function compileGraph(graph: SpriteGraph): CompiledGraph {\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`. Validate so a bad input fails here, not silently.\n for (const [name, def] of Object.entries(graph.inputs)) {\n if (def.type !== \"number\" && def.type !== \"boolean\" && def.type !== \"trigger\") {\n throw new InvalidGraphError(\n `input \"${name}\" has unknown type \"${(def as { type: string }).type}\"`,\n );\n }\n }\n\n const defaultDuration = graph.defaultFrameDuration ?? DEFAULT_FRAME_DURATION;\n if (!Number.isFinite(defaultDuration) || defaultDuration <= 0) {\n throw new InvalidGraphError(\n `defaultFrameDuration must be a finite number > 0, got ${defaultDuration}`,\n );\n }\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 (\n timing.duration !== undefined &&\n (!Number.isFinite(timing.duration) || timing.duration <= 0)\n ) {\n throw new InvalidGraphError(\n `frame \"${key}\" duration must be a finite number > 0, got ${timing.duration}`,\n );\n }\n }\n }\n\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 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 if (!Number.isFinite(speed) || speed <= 0) {\n throw new InvalidGraphError(\n `state \"${name}\" speed must be a finite number > 0, got ${speed}`,\n );\n }\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 states.set(name, {\n name,\n animation: st.animation,\n loop,\n speed,\n onEnd: st.onEnd,\n frameKeys,\n cumulative,\n total: running,\n });\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 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 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.\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 const listeners = new Set<(payload: P) => void>();\n\n function on(handler: (payload: P) => void, options?: ListenerOptions): Unsubscribe {\n // An already-aborted signal means the listener is dead on arrival.\n if (options?.signal?.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 let wrapped: (payload: P) => void = handler;\n if (options?.once) {\n wrapped = (payload) => {\n cleanup();\n handler(payload);\n };\n }\n listeners.add(wrapped);\n\n const sig = options?.signal;\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.\n for (const fn of [...listeners]) fn(payload);\n }\n\n function clear(): void {\n listeners.clear();\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 return {\n setInput,\n fireTrigger,\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 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\nimport { type CompiledState, 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/**\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\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(): { to: string; triggers: readonly string[] } | 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 { to: t.to, triggers: t.triggers };\n }\n return undefined;\n }\n\n function update(deltaMs: number): void {\n if (disposed) throw new SpriteAnimatorDisposedError();\n\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 elapsed += (Number.isFinite(deltaMs) && deltaMs > 0 ? deltaMs : 0) * current.speed;\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 complete.emit(cs.name);\n if (cs.onEnd !== undefined) enter(cs.onEnd, NO_TRIGGERS);\n }\n }\n\n function reset(): void {\n if (disposed) throw new SpriteAnimatorDisposedError();\n const from = current.name;\n store.reset();\n current = mustState(compiled.initial);\n elapsed = 0;\n completed = false;\n activeFrameIndex = 0;\n activeFrameKey = current.frameKeys[0]!;\n if (from !== compiled.initial) stateChange.emit({ to: compiled.initial, from });\n }\n\n function dispose(): void {\n if (disposed) return;\n disposed = true;\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","// aispritejs/pixi — the PixiJS v8 renderer adapter. It binds the\n// renderer-agnostic core to a `PIXI.Sprite`: on each update it swaps the\n// sprite's texture to the core's active frame and (by default) applies that\n// frame's atlas anchor.\n//\n// `pixi.js` is imported **type-only**, so the built subpath contains no runtime\n// `pixi.js` require — the peer is needed only by the consumer who passes real\n// Sprite / Spritesheet instances. `pixi.js` is declared as an OPTIONAL\n// peerDependency; the core (`aispritejs`) never imports this module.\n\nimport type { Sprite, Spritesheet, Texture } from \"pixi.js\";\nimport { type SpriteGraph, createSpriteAnimator } from \"../sprite/index.js\";\n\n/**\n * Thrown by {@link createPixiSpriteAnimator} when the supplied textures are\n * missing one or more frame keys the graph's animations reference. Fail-fast at\n * construction, so `update()` never has to guard.\n *\n * @public\n */\nexport class MissingTextureError extends Error {\n readonly keys: readonly string[];\n constructor(keys: readonly string[]) {\n super(`aispritejs/pixi: no texture for frame key(s): ${keys.join(\", \")}`);\n this.name = \"MissingTextureError\";\n this.keys = keys;\n }\n}\n\n/** Frame-key → texture lookup. A PixiJS `Spritesheet` exposes one as `.textures`. */\nexport type TextureMap = Record<string, Texture>;\n\n/**\n * Options for {@link createPixiSpriteAnimator}.\n *\n * @public\n */\nexport interface PixiSpriteAnimatorOptions {\n /**\n * Apply each frame's atlas anchor (`texture.defaultAnchor`) to the sprite when\n * the frame changes — preserving non-centre / foot pivots. Default `true`.\n * Set `false` to manage the anchor yourself.\n */\n readonly applyAnchor?: boolean;\n}\n\n/**\n * A PixiJS-bound animator: the core machine plus a sprite whose texture tracks\n * the active frame.\n *\n * @public\n */\nexport interface PixiSpriteAnimator {\n /** The bound sprite, updated in place. */\n readonly sprite: Sprite;\n /** Run the core machine for `deltaMs`, then sync the sprite's texture. */\n update(deltaMs: number): void;\n /** Set a Number / Boolean input on the core machine. */\n setInput(name: string, value: number | boolean): void;\n /** Fire a Trigger on the core machine. */\n fireTrigger(name: string): void;\n /** Reset the core machine and re-sync the sprite. */\n reset(): void;\n /** Dispose the core machine. Idempotent. Does not destroy the sprite. */\n dispose(): void;\n /** Current state name. */\n readonly activeState: string;\n /** Current frame key. */\n readonly activeFrameKey: string;\n /** `true` once disposed. */\n readonly disposed: boolean;\n}\n\nfunction toTextureMap(src: Spritesheet | TextureMap): TextureMap {\n // A Spritesheet exposes its frame textures under `.textures`; a plain map is\n // used directly. (If you have a frame literally named \"textures\", pass\n // `spritesheet.textures` instead of the spritesheet.)\n const maybe = src as { textures?: unknown };\n if (maybe.textures && typeof maybe.textures === \"object\") {\n return maybe.textures as TextureMap;\n }\n return src as TextureMap;\n}\n\n/**\n * Bind an input-driven {@link SpriteGraph} to a PixiJS `Sprite`.\n *\n * @param sprite - a plain `Sprite` to drive; its `texture` (and, by default,\n * `anchor`) are updated in place. The adapter owns frame selection, so if a\n * *playing* `AnimatedSprite` is passed (it extends `Sprite`), its internal\n * playback is stopped to stop it fighting the adapter for the texture.\n * @param graph - the input-driven graph (same shape the core consumes).\n * @param textures - a `Spritesheet` or a frame-key → `Texture` map covering\n * every frame the graph references.\n * @param options - see {@link PixiSpriteAnimatorOptions}.\n * @returns a {@link PixiSpriteAnimator}.\n * @throws {@link MissingTextureError} if a referenced frame key has no texture.\n * @throws {@link InvalidGraphError} if the graph is invalid.\n *\n * @public\n */\nexport function createPixiSpriteAnimator(\n sprite: Sprite,\n graph: SpriteGraph,\n textures: Spritesheet | TextureMap,\n options?: PixiSpriteAnimatorOptions,\n): PixiSpriteAnimator {\n const map = toTextureMap(textures);\n const applyAnchor = options?.applyAnchor !== false;\n\n // The adapter owns the sprite's texture/anchor. An AnimatedSprite (which\n // extends Sprite, so the type permits it) drives its own texture from an\n // internal ticker; if it is playing it would fight our frame swaps. Stop it.\n // Structural check — pixi.js is type-only here, so no `instanceof`.\n const playable = sprite as { stop?: () => void };\n if (typeof playable.stop === \"function\") playable.stop();\n\n // Fail-fast: every frame key reachable from the graph must have a texture.\n const missing = new Set<string>();\n for (const frameKeys of Object.values(graph.animations)) {\n for (const key of frameKeys) {\n if (!(key in map)) missing.add(key);\n }\n }\n if (missing.size > 0) throw new MissingTextureError([...missing]);\n\n const core = createSpriteAnimator(graph);\n\n // Swap the sprite's texture (and anchor) only when the active frame changes.\n let boundKey = \"\";\n function sync(): void {\n const key = core.activeFrameKey;\n if (key === boundKey) return;\n boundKey = key;\n const tex = map[key]!; // verified present above\n sprite.texture = tex;\n if (applyAnchor && tex.defaultAnchor) {\n sprite.anchor.set(tex.defaultAnchor.x, tex.defaultAnchor.y);\n }\n }\n sync(); // bind the initial frame before the first update\n\n return {\n sprite,\n update(deltaMs) {\n core.update(deltaMs);\n sync();\n },\n setInput(name, value) {\n core.setInput(name, value);\n },\n fireTrigger(name) {\n core.fireTrigger(name);\n },\n reset() {\n core.reset();\n sync();\n },\n dispose() {\n core.dispose();\n },\n get activeState() {\n return core.activeState;\n },\n get activeFrameKey() {\n return core.activeFrameKey;\n },\n get disposed() {\n return core.disposed;\n },\n };\n}\n"]}
|
|
@@ -234,9 +234,15 @@ interface SpriteAnimator {
|
|
|
234
234
|
reset(): void;
|
|
235
235
|
/** Release all listeners. Idempotent; subsequent mutators throw. */
|
|
236
236
|
dispose(): void;
|
|
237
|
-
/**
|
|
237
|
+
/**
|
|
238
|
+
* Subscribe to state changes. Returns an unsubscribe.
|
|
239
|
+
* @remarks After `dispose()` this returns a no-op unsubscribe and registers no listener.
|
|
240
|
+
*/
|
|
238
241
|
onStateChange(handler: StateChangeHandler, options?: ListenerOptions): Unsubscribe;
|
|
239
|
-
/**
|
|
242
|
+
/**
|
|
243
|
+
* Subscribe to non-looping clip completions. Returns an unsubscribe.
|
|
244
|
+
* @remarks After `dispose()` this returns a no-op unsubscribe and registers no listener.
|
|
245
|
+
*/
|
|
240
246
|
onComplete(handler: CompleteHandler, options?: ListenerOptions): Unsubscribe;
|
|
241
247
|
/** Current state name. */
|
|
242
248
|
readonly activeState: string;
|
|
@@ -234,9 +234,15 @@ interface SpriteAnimator {
|
|
|
234
234
|
reset(): void;
|
|
235
235
|
/** Release all listeners. Idempotent; subsequent mutators throw. */
|
|
236
236
|
dispose(): void;
|
|
237
|
-
/**
|
|
237
|
+
/**
|
|
238
|
+
* Subscribe to state changes. Returns an unsubscribe.
|
|
239
|
+
* @remarks After `dispose()` this returns a no-op unsubscribe and registers no listener.
|
|
240
|
+
*/
|
|
238
241
|
onStateChange(handler: StateChangeHandler, options?: ListenerOptions): Unsubscribe;
|
|
239
|
-
/**
|
|
242
|
+
/**
|
|
243
|
+
* Subscribe to non-looping clip completions. Returns an unsubscribe.
|
|
244
|
+
* @remarks After `dispose()` this returns a no-op unsubscribe and registers no listener.
|
|
245
|
+
*/
|
|
240
246
|
onComplete(handler: CompleteHandler, options?: ListenerOptions): Unsubscribe;
|
|
241
247
|
/** Current state name. */
|
|
242
248
|
readonly activeState: string;
|
package/llms-full.txt
CHANGED
|
@@ -32,6 +32,17 @@ Part of the **ai\*js** family: zero cross-package dependencies, framework-agnost
|
|
|
32
32
|
- **Visual ≠ logic.** This is strictly a *visual* animator. It is **not** a game-logic FSM and does **not** depend on `aifsmjs`. Drive it from any logic layer (plain code, an FSM, an ECS) — they compose by convention, never by dependency.
|
|
33
33
|
- **Tiny + fast.** O(1) input lookups, O(N) checks over transitions leaving the current state, no per-frame allocation.
|
|
34
34
|
|
|
35
|
+
## When you DON'T need aispritejs
|
|
36
|
+
|
|
37
|
+
`aispritejs` earns its keep when frame selection is **driven by runtime inputs** across **several visual states**. Below that threshold, reach for PixiJS directly — there is nothing to gain from a state machine:
|
|
38
|
+
|
|
39
|
+
- **A single sprite / one static image** → a plain PixiJS [`Sprite`](https://pixijs.download/release/docs/scene.Sprite.html). No animation, no graph.
|
|
40
|
+
- **One looping clip with no branching** (a coin spin, a torch flicker) → a PixiJS [`AnimatedSprite`](https://pixijs.download/release/docs/scene.AnimatedSprite.html) (`AnimatedSprite.fromFrames(...)`, `.play()`). One clip that always plays the same way needs no inputs.
|
|
41
|
+
- **No texture atlas** (you aren't packing frames into a spritesheet) → load images directly; `aispritejs` reads its frames from a PixiJS-v8 atlas (`animations` / `frames`).
|
|
42
|
+
- **No multi-state switching** — if your code already knows exactly which clip to play and just calls `.play()` / `.gotoAndStop()`, you don't need a transition graph.
|
|
43
|
+
|
|
44
|
+
Reach for `aispritejs` when you have **input-driven, multi-state visual switching backed by a texture atlas** — e.g. `idle ⇄ walk → jump`, or a one-shot hit FX fired by a trigger — where which frame is on screen is a function of `speed` / `isGrounded` / `attack`, not a hard-coded `play()` call.
|
|
45
|
+
|
|
35
46
|
## Mental model
|
|
36
47
|
|
|
37
48
|
```
|
|
@@ -40,7 +51,7 @@ inputs ─▶ [transition graph] ─▶ active state ─▶ (Δt) ─▶ active
|
|
|
40
51
|
|
|
41
52
|
- **Inputs** — `Number` (continuous, e.g. `speed`), `Boolean` (toggle, e.g. `isGrounded`), `Trigger` (one-shot; auto-resets after a transition consumes it, e.g. `jump` / `attack`).
|
|
42
53
|
- **States** — an animation key (into the atlas `animations`) + loop / on-end behaviour + optional speed multiplier.
|
|
43
|
-
- **Transitions** — from a state (or **Any State**) to another when conditions over inputs hold (`Equals` / `NotEquals` / `GreaterThan` / `LessThan`). The highest-priority satisfied transition wins.
|
|
54
|
+
- **Transitions** — from a state (or **Any State**) to another when conditions over inputs hold (`Equals` / `NotEquals` / `GreaterThan` / `LessThan` / `Trigger`). The highest-priority satisfied transition wins.
|
|
44
55
|
- **`update(dt)`** — advances the playback timer; evaluates transitions (switching state, firing `onStateChange`, consuming triggers); computes the current frame from the animation's per-frame durations + loop; fires `onComplete` when a non-looping clip ends.
|
|
45
56
|
|
|
46
57
|
## Quick start — core (zero-dep)
|
|
@@ -85,6 +96,50 @@ It swaps the texture only when the active frame changes, and honours per-frame `
|
|
|
85
96
|
|
|
86
97
|
Pass a plain `Sprite` — the adapter owns frame selection. (An `AnimatedSprite` is accepted since it extends `Sprite`, but its own playback is stopped on bind so it cannot fight the adapter for the texture.)
|
|
87
98
|
|
|
99
|
+
### Complete example — a 6-frame explosion (play-once FX)
|
|
100
|
+
|
|
101
|
+
The most common entry: a one-shot hit/impact FX (net-splash, muzzle flash) from a **6-frame explosion sprite sheet**, driven through the `/pixi` adapter. A `Trigger` fires a **non-looping** clip that plays once and auto-returns to a resting frame via `onEnd`. The full runnable version is [`examples/02-explosion-pixi/index.ts`](examples/02-explosion-pixi/index.ts) (`pnpm example:explosion`).
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { Assets, Sprite } from "pixi.js";
|
|
105
|
+
import { createPixiSpriteAnimator } from "aispritejs/pixi";
|
|
106
|
+
|
|
107
|
+
// A 6-frame explosion sprite sheet (PixiJS-v8 atlas): the `animations` block
|
|
108
|
+
// names the clip → its frame keys; `frames` carries per-frame durations.
|
|
109
|
+
const graph = {
|
|
110
|
+
animations: {
|
|
111
|
+
explosion: ["explosion_0", "explosion_1", "explosion_2", "explosion_3", "explosion_4", "explosion_5"],
|
|
112
|
+
idle: ["explosion_0"], // a 1-frame resting clip to hold between bursts
|
|
113
|
+
},
|
|
114
|
+
frames: {
|
|
115
|
+
explosion_0: { duration: 40 }, explosion_1: { duration: 40 }, explosion_2: { duration: 40 },
|
|
116
|
+
explosion_3: { duration: 40 }, explosion_4: { duration: 40 }, explosion_5: { duration: 40 },
|
|
117
|
+
},
|
|
118
|
+
inputs: { detonate: { type: "trigger" } },
|
|
119
|
+
states: {
|
|
120
|
+
idle: { animation: "idle", loop: true },
|
|
121
|
+
boom: { animation: "explosion", loop: false, onEnd: "idle" }, // play once → back to idle
|
|
122
|
+
},
|
|
123
|
+
transitions: [
|
|
124
|
+
{ from: "*", to: "boom", when: [{ input: "detonate", op: "Trigger" }], priority: 10 },
|
|
125
|
+
],
|
|
126
|
+
initial: "idle",
|
|
127
|
+
} as const;
|
|
128
|
+
|
|
129
|
+
// Load the packed sheet; its `.textures` cover every frame key the graph uses.
|
|
130
|
+
const sheet = await Assets.load("explosion.json"); // a PIXI.Spritesheet
|
|
131
|
+
const sprite = new Sprite();
|
|
132
|
+
const fx = createPixiSpriteAnimator(sprite, graph, sheet);
|
|
133
|
+
|
|
134
|
+
// Fire the one-shot trigger on impact:
|
|
135
|
+
fx.fireTrigger("detonate");
|
|
136
|
+
|
|
137
|
+
// Drive the burst from your PixiJS render loop (e.g. `app.ticker`), advancing by
|
|
138
|
+
// elapsed ms: `app.ticker.add((ticker) => fx.update(ticker.deltaMS))`.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`update(dt)` plays `explosion_0…explosion_5` once (honouring each frame's `duration`); on the tick that completes the clip it fires `onComplete` and, because `boom` declares `onEnd`, auto-transitions to `idle` in that **same** tick — so the last frame isn't held, and `activeState` reads `idle` right after. Re-`fireTrigger("detonate")` to replay. The same graph runs with no renderer — see [`examples/02-explosion-pixi/index.ts`](examples/02-explosion-pixi/index.ts), which exercises the real adapter headlessly with plain `Texture` / `Sprite` instances.
|
|
142
|
+
|
|
88
143
|
## Data format (atlas)
|
|
89
144
|
|
|
90
145
|
`aispritejs` reads a **PixiJS v8-native** spritesheet atlas (`meta` / `frames` / `animations`) — the same shape the family's sprite pipeline emits — augmented with an `aispritejs` **input-driven** control block:
|
|
@@ -168,7 +223,7 @@ Every subscription returns an unsubscribe function and accepts `{ signal }` (an
|
|
|
168
223
|
|
|
169
224
|
These rules are deterministic and frozen for the 1.x line once 1.0 ships:
|
|
170
225
|
|
|
171
|
-
- **`update(dt)` order** — advance the timer by `dt × speed` (
|
|
226
|
+
- **`update(dt)` order** — advance the timer by `dt × speed` (non-finite or non-positive `dt` clamps to `0`); evaluate transitions; recompute the active frame; fire `onComplete` for a finished non-looping clip and then any `onEnd` auto-transition. An explicit input transition therefore wins over end-of-clip behaviour on the same frame.
|
|
172
227
|
- **Transition resolution** — among the transitions leaving the current state (plus **Any-State** `from: "*"`), candidates are ordered by `priority` (desc) then declared order (asc); the **first effective** one is taken. All `when` conditions must hold (logical AND).
|
|
173
228
|
- **Self-transition rule** — a transition whose `to` equals the current state is *effective only if it consumes a Trigger*. A Number/Boolean self-loop is skipped, so it cannot reset the clip to frame 0 every frame. A trigger-bearing self-transition **restarts** the clip (e.g. re-attack) but does **not** fire `onStateChange` (the state name is unchanged).
|
|
174
229
|
- **Triggers** — `fireTrigger(name)` marks a trigger pending; it stays pending across frames until a transition that checks it is taken, which **consumes** it. One fire → at most one transition.
|
|
@@ -208,12 +263,15 @@ Behavioural `vitest` suites cover inputs, transitions, trigger consumption, fram
|
|
|
208
263
|
```bash
|
|
209
264
|
pnpm test # run once
|
|
210
265
|
pnpm coverage # with thresholds
|
|
211
|
-
pnpm example:platformer
|
|
266
|
+
pnpm example:platformer # renderer-free core demo
|
|
267
|
+
pnpm example:explosion # 6-frame play-once FX via the /pixi adapter
|
|
212
268
|
```
|
|
213
269
|
|
|
214
270
|
## Status
|
|
215
271
|
|
|
216
|
-
**v0.1.
|
|
272
|
+
**v0.1.3 — docs patch.** Adds a "When you DON'T need aispritejs" threshold and a complete, runnable 6-frame explosion (play-once FX) quickstart for the `/pixi` adapter; no source or API changes. v0.1.0 shipped all roadmap modules (1–4): the renderer-agnostic core (`.`), the PixiJS v8 adapter (`aispritejs/pixi`), the atlas parser (`aispritejs/atlas`), and the JSON Schema (`aispritejs/schema`); v0.1.1 added OIDC/SLSA publish provenance and v0.1.2 hardened validation — compile-time rejection of non-finite `speed` / `duration` / `defaultFrameDuration`, plus a runtime clamp of non-finite or non-positive `dt` (`dt <= 0`) to `0` in `update()`. See [CHANGELOG.md](CHANGELOG.md) for the full history. Zero runtime dependencies; the root import graph contains no `pixi.js`; `pixi.js` is an optional, type-only peer used only by the `/pixi` subpath.
|
|
273
|
+
|
|
274
|
+
`aispritejs` is the newest package in the **ai\*js** family and follows its **own independent version line** — the `0.1.x` series reflects this package's own maturation, not alignment with any sibling's version number. Low usage in a given game (e.g. one built on static sprites) is expected, not a defect.
|
|
217
275
|
|
|
218
276
|
## Roadmap
|
|
219
277
|
|
|
@@ -236,6 +294,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
236
294
|
|
|
237
295
|
## [Unreleased]
|
|
238
296
|
|
|
297
|
+
## [0.1.3] - 2026-06-05
|
|
298
|
+
|
|
299
|
+
### Added
|
|
300
|
+
|
|
301
|
+
- Docs: a "When you DON'T need aispritejs" threshold section and a complete, runnable 6-frame
|
|
302
|
+
explosion (play-once FX) `/pixi` quickstart (`examples/02-explosion-pixi`); no source/API changes.
|
|
303
|
+
|
|
304
|
+
## [0.1.2] - 2026-06-05
|
|
305
|
+
|
|
306
|
+
### Changed
|
|
307
|
+
|
|
308
|
+
- JSON Schema: `animations` now requires at least one entry (`minProperties: 1`), matching `states`
|
|
309
|
+
and the runtime (which already rejects an empty animations map via `InvalidGraphError`).
|
|
310
|
+
|
|
311
|
+
### Fixed
|
|
312
|
+
|
|
313
|
+
- Reject non-finite (`Infinity`/`NaN`) `speed`, `duration`, and `defaultFrameDuration` at compile
|
|
314
|
+
time (`InvalidGraphError`); clamp non-finite `dt` to 0 in `update()` — previously these silently
|
|
315
|
+
corrupted looping playback (frame stuck at 0 / `NaN` accumulation).
|
|
316
|
+
|
|
239
317
|
## [0.1.1] - 2026-06-03
|
|
240
318
|
|
|
241
319
|
First release published through the OIDC `publish.yml` pipeline (npm trusted
|
|
@@ -349,7 +427,9 @@ parser, and JSON Schema (roadmap modules 1–4).
|
|
|
349
427
|
/ lines (above the family floor of 95 / 90 / 100 / 100). Core gzip ≈ 3.5 KB.
|
|
350
428
|
- OIDC + SLSA provenance publish on tag-push.
|
|
351
429
|
|
|
352
|
-
[Unreleased]: https://github.com/yshengliao/aispritejs/compare/v0.1.
|
|
430
|
+
[Unreleased]: https://github.com/yshengliao/aispritejs/compare/v0.1.3...HEAD
|
|
431
|
+
[0.1.3]: https://github.com/yshengliao/aispritejs/compare/v0.1.2...v0.1.3
|
|
432
|
+
[0.1.2]: https://github.com/yshengliao/aispritejs/compare/v0.1.1...v0.1.2
|
|
353
433
|
[0.1.1]: https://github.com/yshengliao/aispritejs/compare/v0.1.0...v0.1.1
|
|
354
434
|
[0.1.0]: https://github.com/yshengliao/aispritejs/releases/tag/v0.1.0
|
|
355
435
|
|
|
@@ -459,4 +539,29 @@ classic `idle` / `walk` / `jump` graph and exercises every core idea:
|
|
|
459
539
|
The same `graph` object would drive a PixiJS sprite unchanged via the
|
|
460
540
|
`aispritejs/pixi` adapter — the core never knows a renderer exists.
|
|
461
541
|
|
|
542
|
+
## 02 — explosion (PixiJS v8 adapter)
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
pnpm example:explosion
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
[`02-explosion-pixi/index.ts`](examples/02-explosion-pixi/index.ts) is the most-common
|
|
549
|
+
entry: a **6-frame explosion sprite sheet** (net-splash / hit FX) bound through
|
|
550
|
+
the real `aispritejs/pixi` adapter:
|
|
551
|
+
|
|
552
|
+
- the atlas `animations` block lists the six frame keys, with per-frame `frames`
|
|
553
|
+
durations (a snappy ~40 ms/frame burst);
|
|
554
|
+
- a **Trigger** (`detonate`) fires an Any-State transition into a **non-looping**
|
|
555
|
+
`boom` state that **plays once** and auto-returns to a resting `idle` frame via
|
|
556
|
+
`onEnd`;
|
|
557
|
+
- `createPixiSpriteAnimator(sprite, graph, textures)` binds a real `PIXI.Sprite`;
|
|
558
|
+
each `update(dt)` swaps `sprite.texture` to the active frame and applies that
|
|
559
|
+
frame's atlas `defaultAnchor`;
|
|
560
|
+
- it runs headlessly in Node — the adapter only touches `sprite.texture` /
|
|
561
|
+
`sprite.anchor` / `texture.defaultAnchor`, so plain `PIXI.Texture` / `Sprite`
|
|
562
|
+
instances exercise the real API (no GPU or canvas needed).
|
|
563
|
+
|
|
564
|
+
This is the play-once FX shape to reach for when you have input-driven,
|
|
565
|
+
multi-state visual switching backed by a texture atlas.
|
|
566
|
+
|
|
462
567
|
---
|
package/llms.txt
CHANGED
|
@@ -12,7 +12,7 @@ Key guarantees: deterministic `update(dt)` (identical inputs + Δt ⇒ identical
|
|
|
12
12
|
- [README_ZHTW.md](README_ZHTW.md): Traditional Chinese mirror of the canonical README.
|
|
13
13
|
- [ROADMAP.md](ROADMAP.md): phased plan (v0.1.0 core → v0.2.0 PixiJS adapter → v0.3.0 atlas parser + JSON Schema → 1.0 freeze) and design invariants.
|
|
14
14
|
- [STABILITY.md](STABILITY.md): stability tier of every public symbol plus the pinned behavioural contract.
|
|
15
|
-
- [CHANGELOG.md](CHANGELOG.md): Keep a Changelog format; the 0.1.0 entry covers the core surface and CI guarantees.
|
|
15
|
+
- [CHANGELOG.md](CHANGELOG.md): Keep a Changelog format; the 0.1.1 entry notes SLSA build provenance (OIDC publish); the 0.1.0 entry covers the full core surface and CI guarantees.
|
|
16
16
|
- [CONTRIBUTING.md](CONTRIBUTING.md): quick-start commands, design principles, commit & PR style.
|
|
17
17
|
- [llms-full.txt](llms-full.txt): README + CHANGELOG + CONTRIBUTING + examples index concatenated into one file — load this when an AI agent needs the full context in a single fetch.
|
|
18
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aispritejs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Input-driven, renderer-agnostic 2D sprite animation runtime — a tiny, Rive-like visual state machine driven by Number / Boolean / Trigger inputs. JSON transition graph, deterministic update(dt), zero runtime dependencies. Browser / Node / Bun / Deno / WebView / Worker friendly.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sprite",
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"verify:llms": "node scripts/build-llms-full.mjs --check",
|
|
74
74
|
"coverage": "vitest run --coverage",
|
|
75
75
|
"example:platformer": "tsx examples/01-platformer-inputs/index.ts",
|
|
76
|
+
"example:explosion": "tsx examples/02-explosion-pixi/index.ts",
|
|
76
77
|
"prepublishOnly": "pnpm typecheck && pnpm lint && pnpm coverage && pnpm build && pnpm verify:exports && pnpm verify:llms && pnpm check:size"
|
|
77
78
|
},
|
|
78
79
|
"peerDependencies": {
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
"type": "object"
|
|
12
12
|
},
|
|
13
13
|
"animations": {
|
|
14
|
-
"description": "Animation name -> ordered list of frame keys (each non-empty).",
|
|
14
|
+
"description": "Animation name -> ordered list of frame keys (each non-empty). Must declare at least one animation.",
|
|
15
15
|
"type": "object",
|
|
16
|
+
"minProperties": 1,
|
|
16
17
|
"additionalProperties": {
|
|
17
18
|
"type": "array",
|
|
18
19
|
"items": { "type": "string" },
|