aispritejs 0.5.6 → 0.5.8
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 +59 -231
- package/README_ZHTW.md +59 -228
- package/dist/atlas/index.cjs +24 -470
- package/dist/atlas/index.cjs.map +1 -1
- package/dist/atlas/index.js +13 -459
- package/dist/atlas/index.js.map +1 -1
- package/dist/chunk-6E4ILDBY.js +506 -0
- package/dist/chunk-6E4ILDBY.js.map +1 -0
- package/dist/chunk-QF5N7LOI.cjs +513 -0
- package/dist/chunk-QF5N7LOI.cjs.map +1 -0
- package/dist/index.cjs +21 -462
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -461
- package/dist/index.js.map +1 -1
- package/dist/pixi/index.cjs +3 -461
- package/dist/pixi/index.cjs.map +1 -1
- package/dist/pixi/index.js +2 -460
- package/dist/pixi/index.js.map +1 -1
- package/llms-full.txt +116 -435
- package/llms.txt +8 -38
- package/package.json +5 -3
- package/schemas/aispritejs-graph.schema.json +5 -4
|
@@ -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-6E4ILDBY.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/** 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\nexport function compileGraph(graph: SpriteGraph): CompiledGraph {\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 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 // 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 rawDef = def as { type: string; default?: unknown };\n if (rawDef.default !== undefined) {\n if (def.type === \"number\" && typeof rawDef.default !== \"number\") {\n throw new InvalidGraphError(\n `input \"${name}\" default must be a number (declared type \"number\"), got ${typeof rawDef.default}`,\n );\n }\n if (def.type === \"boolean\" && typeof rawDef.default !== \"boolean\") {\n throw new InvalidGraphError(\n `input \"${name}\" default must be a boolean (declared type \"boolean\"), got ${typeof rawDef.default}`,\n );\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 if (defaultDuration > MAX_DURATION) {\n throw new InvalidGraphError(\n `defaultFrameDuration must be ≤ ${MAX_DURATION} ms, 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 if (timing.duration !== undefined && timing.duration > MAX_DURATION) {\n throw new InvalidGraphError(\n `frame \"${key}\" duration must be ≤ ${MAX_DURATION} ms, 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 if (speed > MAX_SPEED) {\n throw new InvalidGraphError(`state \"${name}\" speed must be ≤ ${MAX_SPEED}, 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 && !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` 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 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 // Parallel registry of cleanup functions so clear() can detach abort hooks\n // as well as clearing the listener set (fixes SPR-R-01).\n const cleanups = new Map<(payload: P) => void, Unsubscribe>();\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 cleanups.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 cleanups.set(wrapped, cleanup);\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 // 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 for (const cleanup of [...cleanups.values()]) cleanup();\n // Each cleanup already removed its own entries; these clears make the\n // empty post-condition explicit. (A throwing cleanup would propagate and\n // skip them — listener callbacks and detach hooks are plain functions in\n // every documented path, so that trade-off is accepted over a try/finally.)\n listeners.clear();\n cleanups.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"]}
|
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/sprite/errors.ts
|
|
4
|
+
var SpriteAnimatorDisposedError = class extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super("aispritejs: animator has been disposed; this operation is not allowed");
|
|
7
|
+
this.name = "SpriteAnimatorDisposedError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var InvalidGraphError = class extends Error {
|
|
11
|
+
constructor(message) {
|
|
12
|
+
super(`aispritejs: invalid graph \u2014 ${message}`);
|
|
13
|
+
this.name = "InvalidGraphError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var UnknownInputError = class extends Error {
|
|
17
|
+
input;
|
|
18
|
+
constructor(input) {
|
|
19
|
+
super(`aispritejs: unknown input "${input}"; declare it in the graph's inputs block`);
|
|
20
|
+
this.name = "UnknownInputError";
|
|
21
|
+
this.input = input;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var InputTypeError = class extends Error {
|
|
25
|
+
input;
|
|
26
|
+
constructor(input, message) {
|
|
27
|
+
super(`aispritejs: input "${input}" \u2014 ${message}`);
|
|
28
|
+
this.name = "InputTypeError";
|
|
29
|
+
this.input = input;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// src/sprite/compile.ts
|
|
34
|
+
var DEFAULT_FRAME_DURATION = 100;
|
|
35
|
+
var MAX_DURATION = 864e5;
|
|
36
|
+
var MAX_SPEED = 1e3;
|
|
37
|
+
function isObject(v) {
|
|
38
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
39
|
+
}
|
|
40
|
+
function compileGraph(graph) {
|
|
41
|
+
if (Object.keys(graph.animations).length === 0) {
|
|
42
|
+
throw new InvalidGraphError("animations must declare at least one animation");
|
|
43
|
+
}
|
|
44
|
+
const stateEntries = Object.entries(graph.states);
|
|
45
|
+
if (stateEntries.length === 0) {
|
|
46
|
+
throw new InvalidGraphError("states must declare at least one state");
|
|
47
|
+
}
|
|
48
|
+
for (const [name, def] of Object.entries(graph.inputs)) {
|
|
49
|
+
if (def.type !== "number" && def.type !== "boolean" && def.type !== "trigger") {
|
|
50
|
+
throw new InvalidGraphError(
|
|
51
|
+
`input "${name}" has unknown type "${def.type}"`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
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
|
+
}
|
|
68
|
+
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
|
+
}
|
|
79
|
+
if (graph.frames) {
|
|
80
|
+
for (const [key, timing] of Object.entries(graph.frames)) {
|
|
81
|
+
if (!isObject(timing)) {
|
|
82
|
+
throw new InvalidGraphError(`frame "${key}" timing must be an object`);
|
|
83
|
+
}
|
|
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
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const initial = graph.initial ?? stateEntries[0][0];
|
|
97
|
+
if (!Object.hasOwn(graph.states, initial)) {
|
|
98
|
+
throw new InvalidGraphError(`initial state "${initial}" is not declared`);
|
|
99
|
+
}
|
|
100
|
+
const states = /* @__PURE__ */ new Map();
|
|
101
|
+
for (const [name, st] of stateEntries) {
|
|
102
|
+
const frameKeys = graph.animations[st.animation];
|
|
103
|
+
if (frameKeys === void 0 || !Object.hasOwn(graph.animations, st.animation)) {
|
|
104
|
+
throw new InvalidGraphError(`state "${name}" references unknown animation "${st.animation}"`);
|
|
105
|
+
}
|
|
106
|
+
if (frameKeys.length === 0) {
|
|
107
|
+
throw new InvalidGraphError(`animation "${st.animation}" (state "${name}") has no frames`);
|
|
108
|
+
}
|
|
109
|
+
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
|
+
}
|
|
118
|
+
const loop = st.loop === true;
|
|
119
|
+
if (loop && st.onEnd !== void 0) {
|
|
120
|
+
throw new InvalidGraphError(
|
|
121
|
+
`state "${name}" loops, so onEnd "${st.onEnd}" would never fire; set loop:false or drop onEnd`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
if (st.onEnd !== void 0 && !Object.hasOwn(graph.states, st.onEnd)) {
|
|
125
|
+
throw new InvalidGraphError(`state "${name}" onEnd target "${st.onEnd}" is not declared`);
|
|
126
|
+
}
|
|
127
|
+
const cumulative = [];
|
|
128
|
+
let running = 0;
|
|
129
|
+
for (const key of frameKeys) {
|
|
130
|
+
running += graph.frames?.[key]?.duration ?? defaultDuration;
|
|
131
|
+
cumulative.push(running);
|
|
132
|
+
}
|
|
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
|
+
});
|
|
150
|
+
}
|
|
151
|
+
const compiled = [];
|
|
152
|
+
graph.transitions.forEach((t, order) => {
|
|
153
|
+
if (!isObject(t)) {
|
|
154
|
+
throw new InvalidGraphError(`transition #${order} must be an object`);
|
|
155
|
+
}
|
|
156
|
+
if (t.when !== void 0 && !Array.isArray(t.when)) {
|
|
157
|
+
throw new InvalidGraphError(`transition #${order} "when" must be an array`);
|
|
158
|
+
}
|
|
159
|
+
if (t.from !== "*" && !Object.hasOwn(graph.states, t.from)) {
|
|
160
|
+
throw new InvalidGraphError(`transition #${order} from "${t.from}" is not a declared state`);
|
|
161
|
+
}
|
|
162
|
+
if (!Object.hasOwn(graph.states, t.to)) {
|
|
163
|
+
throw new InvalidGraphError(`transition #${order} to "${t.to}" is not a declared state`);
|
|
164
|
+
}
|
|
165
|
+
const conditions = [];
|
|
166
|
+
const triggers = [];
|
|
167
|
+
for (const c of t.when ?? []) {
|
|
168
|
+
const def = graph.inputs[c.input];
|
|
169
|
+
if (def === void 0 || !Object.hasOwn(graph.inputs, c.input)) {
|
|
170
|
+
throw new InvalidGraphError(
|
|
171
|
+
`transition #${order} condition references unknown input "${c.input}"`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
compileCondition(order, c.input, c.op, c.value, def.type, conditions, triggers);
|
|
175
|
+
}
|
|
176
|
+
compiled.push({
|
|
177
|
+
from: t.from,
|
|
178
|
+
to: t.to,
|
|
179
|
+
priority: t.priority ?? 0,
|
|
180
|
+
order,
|
|
181
|
+
conditions,
|
|
182
|
+
triggers
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
const candidatesByState = /* @__PURE__ */ new Map();
|
|
186
|
+
for (const [name] of stateEntries) {
|
|
187
|
+
const list = compiled.filter((t) => t.from === name || t.from === "*");
|
|
188
|
+
list.sort((a, b) => b.priority - a.priority || a.order - b.order);
|
|
189
|
+
candidatesByState.set(name, list);
|
|
190
|
+
}
|
|
191
|
+
return { initial, states, candidatesByState };
|
|
192
|
+
}
|
|
193
|
+
function compileCondition(order, input, op, value, kind, out, triggers) {
|
|
194
|
+
switch (op) {
|
|
195
|
+
case "Trigger": {
|
|
196
|
+
if (kind !== "trigger") {
|
|
197
|
+
throw new InvalidGraphError(
|
|
198
|
+
`transition #${order}: op Trigger requires a trigger input, but "${input}" is ${kind}`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
if (value !== void 0) {
|
|
202
|
+
throw new InvalidGraphError(
|
|
203
|
+
`transition #${order}: Trigger condition on "${input}" must not carry a value`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
out.push((s) => s.isPending(input));
|
|
207
|
+
triggers.push(input);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
case "GreaterThan":
|
|
211
|
+
case "LessThan": {
|
|
212
|
+
if (kind !== "number") {
|
|
213
|
+
throw new InvalidGraphError(
|
|
214
|
+
`transition #${order}: op ${op} requires a number input, but "${input}" is ${kind}`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
if (typeof value !== "number") {
|
|
218
|
+
throw new InvalidGraphError(
|
|
219
|
+
`transition #${order}: op ${op} on "${input}" needs a numeric value`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
const v = value;
|
|
223
|
+
out.push(
|
|
224
|
+
op === "GreaterThan" ? (s) => s.readNumber(input) > v : (s) => s.readNumber(input) < v
|
|
225
|
+
);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
case "Equals":
|
|
229
|
+
case "NotEquals": {
|
|
230
|
+
if (kind === "trigger") {
|
|
231
|
+
throw new InvalidGraphError(
|
|
232
|
+
`transition #${order}: op ${op} cannot apply to trigger input "${input}"`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
if (kind === "number") {
|
|
236
|
+
if (typeof value !== "number") {
|
|
237
|
+
throw new InvalidGraphError(
|
|
238
|
+
`transition #${order}: op ${op} on number input "${input}" needs a numeric value`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
const v2 = value;
|
|
242
|
+
out.push(
|
|
243
|
+
op === "Equals" ? (s) => s.readNumber(input) === v2 : (s) => s.readNumber(input) !== v2
|
|
244
|
+
);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (typeof value !== "boolean") {
|
|
248
|
+
throw new InvalidGraphError(
|
|
249
|
+
`transition #${order}: op ${op} on boolean input "${input}" needs a boolean value`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
const v = value;
|
|
253
|
+
out.push(
|
|
254
|
+
op === "Equals" ? (s) => s.readBoolean(input) === v : (s) => s.readBoolean(input) !== v
|
|
255
|
+
);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
default:
|
|
259
|
+
throw new InvalidGraphError(`transition #${order}: unknown operator "${op}"`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// src/sprite/emitter.ts
|
|
264
|
+
function createSignal() {
|
|
265
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
266
|
+
const cleanups = /* @__PURE__ */ new Map();
|
|
267
|
+
function on(handler, options) {
|
|
268
|
+
if (options?.signal?.aborted) return () => {
|
|
269
|
+
};
|
|
270
|
+
let detachAbort;
|
|
271
|
+
const cleanup = () => {
|
|
272
|
+
listeners.delete(wrapped);
|
|
273
|
+
cleanups.delete(wrapped);
|
|
274
|
+
if (detachAbort) {
|
|
275
|
+
detachAbort();
|
|
276
|
+
detachAbort = void 0;
|
|
277
|
+
}
|
|
278
|
+
};
|
|
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;
|
|
289
|
+
if (sig) {
|
|
290
|
+
const onAbort = () => cleanup();
|
|
291
|
+
sig.addEventListener("abort", onAbort, { once: true });
|
|
292
|
+
detachAbort = () => sig.removeEventListener("abort", onAbort);
|
|
293
|
+
}
|
|
294
|
+
return cleanup;
|
|
295
|
+
}
|
|
296
|
+
function emit(payload) {
|
|
297
|
+
if (listeners.size === 0) return;
|
|
298
|
+
for (const fn of [...listeners]) fn(payload);
|
|
299
|
+
}
|
|
300
|
+
function clear() {
|
|
301
|
+
for (const cleanup of [...cleanups.values()]) cleanup();
|
|
302
|
+
listeners.clear();
|
|
303
|
+
cleanups.clear();
|
|
304
|
+
}
|
|
305
|
+
return { on, emit, clear };
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// src/sprite/inputs.ts
|
|
309
|
+
function createInputStore(inputs) {
|
|
310
|
+
const kinds = /* @__PURE__ */ new Map();
|
|
311
|
+
const numberDefaults = /* @__PURE__ */ new Map();
|
|
312
|
+
const booleanDefaults = /* @__PURE__ */ new Map();
|
|
313
|
+
const numbers = /* @__PURE__ */ new Map();
|
|
314
|
+
const booleans = /* @__PURE__ */ new Map();
|
|
315
|
+
const triggers = /* @__PURE__ */ new Map();
|
|
316
|
+
for (const [name, def] of Object.entries(inputs)) {
|
|
317
|
+
kinds.set(name, def.type);
|
|
318
|
+
if (def.type === "number") {
|
|
319
|
+
const d = def.default ?? 0;
|
|
320
|
+
numberDefaults.set(name, d);
|
|
321
|
+
numbers.set(name, d);
|
|
322
|
+
} else if (def.type === "boolean") {
|
|
323
|
+
const d = def.default ?? false;
|
|
324
|
+
booleanDefaults.set(name, d);
|
|
325
|
+
booleans.set(name, d);
|
|
326
|
+
} else {
|
|
327
|
+
triggers.set(name, false);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function setInput(name, value) {
|
|
331
|
+
const kind = kinds.get(name);
|
|
332
|
+
if (kind === void 0) throw new UnknownInputError(name);
|
|
333
|
+
if (kind === "trigger") {
|
|
334
|
+
throw new InputTypeError(name, "is a Trigger; use fireTrigger()");
|
|
335
|
+
}
|
|
336
|
+
if (kind === "number") {
|
|
337
|
+
if (typeof value !== "number") {
|
|
338
|
+
throw new InputTypeError(name, `expects a number, received ${typeof value}`);
|
|
339
|
+
}
|
|
340
|
+
if (Number.isNaN(value)) {
|
|
341
|
+
throw new InputTypeError(name, "cannot be set to NaN");
|
|
342
|
+
}
|
|
343
|
+
numbers.set(name, value);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (typeof value !== "boolean") {
|
|
347
|
+
throw new InputTypeError(name, `expects a boolean, received ${typeof value}`);
|
|
348
|
+
}
|
|
349
|
+
booleans.set(name, value);
|
|
350
|
+
}
|
|
351
|
+
function fireTrigger(name) {
|
|
352
|
+
const kind = kinds.get(name);
|
|
353
|
+
if (kind === void 0) throw new UnknownInputError(name);
|
|
354
|
+
if (kind !== "trigger") {
|
|
355
|
+
throw new InputTypeError(name, "is not a Trigger; use setInput()");
|
|
356
|
+
}
|
|
357
|
+
triggers.set(name, true);
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
setInput,
|
|
361
|
+
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
|
+
readNumber: (name) => numbers.get(name),
|
|
366
|
+
readBoolean: (name) => booleans.get(name),
|
|
367
|
+
isPending: (name) => triggers.get(name) === true,
|
|
368
|
+
consume: (name) => {
|
|
369
|
+
triggers.set(name, false);
|
|
370
|
+
},
|
|
371
|
+
reset: () => {
|
|
372
|
+
for (const [name, d] of numberDefaults) numbers.set(name, d);
|
|
373
|
+
for (const [name, d] of booleanDefaults) booleans.set(name, d);
|
|
374
|
+
for (const name of triggers.keys()) triggers.set(name, false);
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// src/sprite/machine.ts
|
|
380
|
+
var NO_TRIGGERS = [];
|
|
381
|
+
function createSpriteAnimator(graph) {
|
|
382
|
+
const compiled = compileGraph(graph);
|
|
383
|
+
const store = createInputStore(graph.inputs);
|
|
384
|
+
const stateChange = createSignal();
|
|
385
|
+
const complete = createSignal();
|
|
386
|
+
let current = mustState(compiled.initial);
|
|
387
|
+
let elapsed = 0;
|
|
388
|
+
let completed = false;
|
|
389
|
+
let activeFrameIndex = 0;
|
|
390
|
+
let activeFrameKey = current.frameKeys[0];
|
|
391
|
+
let disposed = false;
|
|
392
|
+
function mustState(name) {
|
|
393
|
+
return compiled.states.get(name);
|
|
394
|
+
}
|
|
395
|
+
function enter(to, consume) {
|
|
396
|
+
const from = current.name;
|
|
397
|
+
for (let i = 0; i < consume.length; i++) {
|
|
398
|
+
store.consume(consume[i]);
|
|
399
|
+
}
|
|
400
|
+
current = mustState(to);
|
|
401
|
+
elapsed = 0;
|
|
402
|
+
completed = false;
|
|
403
|
+
activeFrameIndex = 0;
|
|
404
|
+
activeFrameKey = current.frameKeys[0];
|
|
405
|
+
if (to !== from) stateChange.emit({ to, from });
|
|
406
|
+
}
|
|
407
|
+
function resolve() {
|
|
408
|
+
const list = compiled.candidatesByState.get(current.name);
|
|
409
|
+
for (let i = 0; i < list.length; i++) {
|
|
410
|
+
const t = list[i];
|
|
411
|
+
let ok = true;
|
|
412
|
+
const conds = t.conditions;
|
|
413
|
+
for (let j = 0; j < conds.length; j++) {
|
|
414
|
+
if (!conds[j](store)) {
|
|
415
|
+
ok = false;
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (!ok) continue;
|
|
420
|
+
if (t.to === current.name && t.triggers.length === 0) continue;
|
|
421
|
+
return { to: t.to, triggers: t.triggers };
|
|
422
|
+
}
|
|
423
|
+
return void 0;
|
|
424
|
+
}
|
|
425
|
+
function update(deltaMs) {
|
|
426
|
+
if (disposed) throw new SpriteAnimatorDisposedError();
|
|
427
|
+
elapsed += (Number.isFinite(deltaMs) && deltaMs > 0 ? deltaMs : 0) * current.speed;
|
|
428
|
+
const chosen = resolve();
|
|
429
|
+
if (chosen) {
|
|
430
|
+
enter(chosen.to, chosen.triggers);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
const cs = current;
|
|
434
|
+
const n = cs.frameKeys.length;
|
|
435
|
+
let ended = false;
|
|
436
|
+
if (!cs.loop && elapsed >= cs.total) {
|
|
437
|
+
activeFrameIndex = n - 1;
|
|
438
|
+
ended = true;
|
|
439
|
+
} else {
|
|
440
|
+
const t = cs.loop ? elapsed % cs.total : elapsed;
|
|
441
|
+
let i = 0;
|
|
442
|
+
while (i < n - 1 && t >= cs.cumulative[i]) i++;
|
|
443
|
+
activeFrameIndex = i;
|
|
444
|
+
}
|
|
445
|
+
activeFrameKey = cs.frameKeys[activeFrameIndex];
|
|
446
|
+
if (ended && !completed) {
|
|
447
|
+
completed = true;
|
|
448
|
+
complete.emit(cs.name);
|
|
449
|
+
if (cs.onEnd !== void 0) enter(cs.onEnd, NO_TRIGGERS);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function reset() {
|
|
453
|
+
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 });
|
|
462
|
+
}
|
|
463
|
+
function dispose() {
|
|
464
|
+
if (disposed) return;
|
|
465
|
+
disposed = true;
|
|
466
|
+
stateChange.clear();
|
|
467
|
+
complete.clear();
|
|
468
|
+
}
|
|
469
|
+
return {
|
|
470
|
+
setInput(name, value) {
|
|
471
|
+
if (disposed) throw new SpriteAnimatorDisposedError();
|
|
472
|
+
store.setInput(name, value);
|
|
473
|
+
},
|
|
474
|
+
fireTrigger(name) {
|
|
475
|
+
if (disposed) throw new SpriteAnimatorDisposedError();
|
|
476
|
+
store.fireTrigger(name);
|
|
477
|
+
},
|
|
478
|
+
update,
|
|
479
|
+
reset,
|
|
480
|
+
dispose,
|
|
481
|
+
onStateChange(handler, options) {
|
|
482
|
+
if (disposed) return () => {
|
|
483
|
+
};
|
|
484
|
+
return stateChange.on((p) => handler(p.to, p.from), options);
|
|
485
|
+
},
|
|
486
|
+
onComplete(handler, options) {
|
|
487
|
+
if (disposed) return () => {
|
|
488
|
+
};
|
|
489
|
+
return complete.on(handler, options);
|
|
490
|
+
},
|
|
491
|
+
get activeState() {
|
|
492
|
+
return current.name;
|
|
493
|
+
},
|
|
494
|
+
get activeFrameKey() {
|
|
495
|
+
return activeFrameKey;
|
|
496
|
+
},
|
|
497
|
+
get activeFrameIndex() {
|
|
498
|
+
return activeFrameIndex;
|
|
499
|
+
},
|
|
500
|
+
get disposed() {
|
|
501
|
+
return disposed;
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
exports.InputTypeError = InputTypeError;
|
|
507
|
+
exports.InvalidGraphError = InvalidGraphError;
|
|
508
|
+
exports.SpriteAnimatorDisposedError = SpriteAnimatorDisposedError;
|
|
509
|
+
exports.UnknownInputError = UnknownInputError;
|
|
510
|
+
exports.createSpriteAnimator = createSpriteAnimator;
|
|
511
|
+
exports.isObject = isObject;
|
|
512
|
+
//# sourceMappingURL=chunk-QF5N7LOI.cjs.map
|
|
513
|
+
//# sourceMappingURL=chunk-QF5N7LOI.cjs.map
|