@yagejs/core 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -195,6 +195,13 @@ declare class Entity {
195
195
  readonly name: string;
196
196
  /** Tags for group queries. */
197
197
  readonly tags: Set<string>;
198
+ /**
199
+ * Stable identity key, scene-scoped. Set at spawn-time when
200
+ * `options.key` is passed to `scene.spawn` / `entity.spawnChild`;
201
+ * `undefined` otherwise. Used with `scene.findByKey` and as a stable
202
+ * id in persistent stores (e.g. `defineSet<string>("world.opened")`).
203
+ */
204
+ readonly key?: string;
198
205
  private components;
199
206
  private _destroyed;
200
207
  private _scene;
@@ -240,13 +247,13 @@ declare class Entity {
240
247
  * this.spawnChild("hp", EnemyHealthBar);
241
248
  * ```
242
249
  */
243
- spawnChild(name: string): Entity;
244
- spawnChild<E extends Entity>(name: string, Class: new () => E): E;
250
+ spawnChild(name: string, options?: SpawnOptions): Entity;
251
+ spawnChild<E extends Entity>(name: string, Class: new () => E, options?: SpawnOptions): E;
245
252
  spawnChild<E extends Entity, P>(name: string, Class: new () => E & {
246
253
  setup(params: P): void;
247
- }, params: P): E;
248
- spawnChild<P>(name: string, blueprint: Blueprint<P>, params: P): Entity;
249
- spawnChild(name: string, blueprint: Blueprint<void>): Entity;
254
+ }, params: P, options?: SpawnOptions): E;
255
+ spawnChild<P>(name: string, blueprint: Blueprint<P>, params: P, options?: SpawnOptions): Entity;
256
+ spawnChild(name: string, blueprint: Blueprint<void>, options?: SpawnOptions): Entity;
250
257
  /** Remove a named child. Returns the detached entity. */
251
258
  removeChild(name: string): Entity;
252
259
  /** Get a child by name. Throws if not found. */
@@ -290,11 +297,24 @@ declare class Entity {
290
297
  afterRestore?(data: unknown, resolve: SnapshotResolver): void;
291
298
  /** Check if this entity's class implements a given trait. Acts as a type guard. */
292
299
  hasTrait<T>(token: TraitToken<T>): this is this & T;
300
+ /**
301
+ * Return the stable key, or throw if this entity was spawned without one.
302
+ * Use inside component `setup()` when the component depends on identity
303
+ * (e.g. reading from a `defineSet` keyed by entity id).
304
+ */
305
+ requireKey(): string;
293
306
  /**
294
307
  * Internal: set the scene and callbacks. Called by Scene.spawn().
295
308
  * @internal
296
309
  */
297
310
  _setScene(scene: Scene | null, callbacks: EntityCallbacks | null): void;
311
+ /**
312
+ * Internal: assign the stable identity key. Called by `Scene._registerKey`
313
+ * during spawn. Throws if the entity already has a key — keys are
314
+ * immutable for an entity's lifetime.
315
+ * @internal
316
+ */
317
+ _setKey(key: string): void;
298
318
  }
299
319
 
300
320
  /** Filter criteria for entity queries. All fields are AND'd together. */
@@ -311,6 +331,28 @@ interface EntityFilter {
311
331
  /** Apply a filter to an iterable of entities. Skips destroyed entities. */
312
332
  declare function filterEntities(entities: Iterable<Entity>, filter: EntityFilter): Entity[];
313
333
 
334
+ /**
335
+ * Options accepted by the trailing argument of `Scene.spawn` and
336
+ * `Entity.spawnChild`.
337
+ */
338
+ interface SpawnOptions {
339
+ /**
340
+ * Stable per-scene identity key. Looked up via `Scene.findByKey` and used
341
+ * as a stable id in persistent stores (e.g. `defineSet<string>("world.opened")`).
342
+ *
343
+ * Identity is opt-in — most entities (bullets, particles, transient enemies)
344
+ * never need a key. Pass one only for entities whose state should persist
345
+ * across save/load or cross-scene navigation, or that game code looks up
346
+ * by name (chests, doors, named NPCs).
347
+ *
348
+ * Heads-up: don't name a top-level setup-params field `key`. The 2-arg
349
+ * `spawn(Class, X)` form looks at `X`'s shape to disambiguate params from
350
+ * options — an `X` whose only own keys are SpawnOptions fields routes
351
+ * to options. If your params shape clashes (e.g. `setup(p: { key: number })`),
352
+ * use the explicit 3-arg form `spawn(Class, params, options)`.
353
+ */
354
+ key?: string;
355
+ }
314
356
  /**
315
357
  * Scenes own entities and define lifecycle hooks.
316
358
  * Each scene is a self-contained world with its own entity pool.
@@ -339,6 +381,7 @@ declare abstract class Scene {
339
381
  private _entityEventHandlers?;
340
382
  private _entityEventObserver?;
341
383
  private _scopedServices?;
384
+ private _identityIndex?;
342
385
  /** Access the EngineContext. */
343
386
  get context(): EngineContext;
344
387
  /** Whether this scene is effectively paused (manual pause or paused by stack). */
@@ -355,16 +398,51 @@ declare abstract class Scene {
355
398
  * The actual resolution is deferred until first property access.
356
399
  */
357
400
  protected service<T extends object>(key: ServiceKey<T>): T;
358
- /** Spawn a new entity in this scene. */
359
- spawn(name?: string): Entity;
360
- spawn<P>(blueprint: Blueprint<P>, params: P): Entity;
361
- spawn(blueprint: Blueprint<void>): Entity;
401
+ /**
402
+ * Spawn a new entity in this scene.
403
+ *
404
+ * Pass `{ key }` in the trailing options to register a stable per-scene
405
+ * identity key, looked up later via `scene.findByKey`. The key is assigned
406
+ * before `setup()` runs, so `entity.requireKey()` is safe inside it.
407
+ *
408
+ * Runtime routing for the 2-arg class form (`spawn(Class, X)`):
409
+ * - If the class doesn't declare `setup` → `X` is options.
410
+ * - Else if `X`'s own keys are exactly SpawnOptions fields (`{ key }`) →
411
+ * `X` is options. Covers both `setup(params = {})` keyed without
412
+ * params and `setup()` (no real params) keyed.
413
+ * - Else → `X` is params (forwarded to `setup`).
414
+ * The 3-arg form is always unambiguous: `spawn(Class, params, options)`.
415
+ *
416
+ * Don't name a top-level setup-params field `key` — the shape check would
417
+ * misroute it. If you must, use the 3-arg form.
418
+ */
419
+ spawn(name?: string, options?: SpawnOptions): Entity;
420
+ /**
421
+ * Spawn from a blueprint. **Note**: blueprint params must not include a
422
+ * top-level `key: string` field — the runtime can't disambiguate it from
423
+ * `SpawnOptions`. If your params do, use the explicit 3-arg form
424
+ * (`spawn(bp, params, { key })`) so options arrives in the trailing slot.
425
+ */
426
+ spawn<P>(blueprint: Blueprint<P>, params: P, options?: SpawnOptions): Entity;
427
+ spawn(blueprint: Blueprint<void>, options?: SpawnOptions): Entity;
362
428
  /** Spawn an entity subclass with setup params. */
363
429
  spawn<E extends Entity, P>(Class: new () => E & {
364
430
  setup(params: P): void;
365
- }, params: P): E;
431
+ }, params: P, options?: SpawnOptions): E;
366
432
  /** Spawn an entity subclass without setup params. */
367
- spawn<E extends Entity>(Class: new () => E): E;
433
+ spawn<E extends Entity>(Class: new () => E, options?: SpawnOptions): E;
434
+ /**
435
+ * Look up an entity by its stable identity key, scoped to this scene.
436
+ * Returns `undefined` for unknown or already-destroyed entities.
437
+ */
438
+ findByKey<E extends Entity = Entity>(key: string): E | undefined;
439
+ /**
440
+ * Internal: register a key on a freshly spawned entity. Throws on
441
+ * duplicate so callers (Scene.spawn) can abort before adding to
442
+ * `this.entities` or emitting `entity:created`.
443
+ * @internal
444
+ */
445
+ _registerKey(entity: Entity, key: string): void;
368
446
  /**
369
447
  * Add an existing entity to this scene (used by Entity.addChild for auto-scene-membership).
370
448
  * @internal
@@ -450,7 +528,9 @@ declare abstract class Scene {
450
528
  */
451
529
  _flushDestroyQueue(): void;
452
530
  /**
453
- * Destroy all entities — used during scene exit.
531
+ * Destroy all entities — used during scene exit. Clears the identity
532
+ * index in bulk; per-entity key removal in `_flushDestroyQueue` is the
533
+ * in-game path.
454
534
  * @internal
455
535
  */
456
536
  _destroyAllEntities(): void;
@@ -550,6 +630,12 @@ interface EngineEvents {
550
630
  };
551
631
  "engine:started": undefined;
552
632
  "engine:stopped": undefined;
633
+ "screen:fullscreen": {
634
+ active: boolean;
635
+ };
636
+ "screen:orientation": {
637
+ type: OrientationType;
638
+ };
553
639
  }
554
640
  /** Typed publish/subscribe event bus. */
555
641
  declare class EventBus<E = EventMap> {
@@ -840,6 +926,22 @@ declare function createRandomService(seed?: number): RandomService;
840
926
  */
841
927
  declare const globalRandom: RandomService;
842
928
 
929
+ /**
930
+ * Mirrors `GamepadAxisKey` from `@yagejs/input` as a local union so the
931
+ * Inspector contract gets compile-time literal checking without taking a
932
+ * runtime dependency on the input package.
933
+ */
934
+ type InspectorGamepadAxisKey = "leftX" | "leftY" | "rightX" | "rightY" | "leftTrigger" | "rightTrigger";
935
+ /**
936
+ * Options for synthetic pointer injection. Pass `id` / `type` / `isPrimary`
937
+ * to drive a non-primary, touch, or pen pointer in deterministic tests. All
938
+ * fields are optional and default to a primary mouse pointer with `id: 1`.
939
+ */
940
+ interface InspectorPointerOpts {
941
+ id?: number;
942
+ type?: "mouse" | "pen" | "touch";
943
+ isPrimary?: boolean;
944
+ }
843
945
  /** Backward-compatible summary snapshot returned by query helpers. */
844
946
  interface EntitySnapshot {
845
947
  id: number;
@@ -955,19 +1057,48 @@ interface CameraSnapshot {
955
1057
  zoom: number;
956
1058
  rotation: number;
957
1059
  }
1060
+ /**
1061
+ * Per-pointer entry in {@link InputStateSnapshot.pointers}. Mirrors the runtime
1062
+ * `PointerInfo` shape from `@yagejs/input`. Touch pointers vanish from the
1063
+ * array once their last button releases; mouse pointers persist.
1064
+ */
1065
+ interface PointerSnapshot {
1066
+ /** `PointerEvent.pointerId`, or the synthetic id passed via `firePointer*`. */
1067
+ id: number;
1068
+ x: number;
1069
+ y: number;
1070
+ type: "mouse" | "pen" | "touch";
1071
+ isPrimary: boolean;
1072
+ buttons: number[];
1073
+ down: boolean;
1074
+ }
958
1075
  interface InputStateSnapshot {
959
1076
  keys: string[];
960
1077
  actions: string[];
1078
+ /**
1079
+ * Aggregate / primary-pointer view, retained for back-compat. `x` / `y` track
1080
+ * the primary pointer's screen position; `buttons` / `down` reflect the
1081
+ * any-pointer aggregate that drives the `MouseLeft`/`Middle`/`Right` action codes.
1082
+ *
1083
+ * For multi-touch state, read {@link InputStateSnapshot.pointers}.
1084
+ */
961
1085
  mouse: {
962
1086
  x: number;
963
1087
  y: number;
964
1088
  buttons: number[];
965
1089
  down: boolean;
966
1090
  };
1091
+ /** All currently-tracked pointers (one per active mouse, pen, or finger). */
1092
+ pointers: PointerSnapshot[];
967
1093
  gamepad: {
968
- buttons: number[];
1094
+ /** Currently-held gamepad codes (e.g. `"GamepadA"`, `"GamepadLT"`). */
1095
+ buttons: string[];
1096
+ /**
1097
+ * Axis state keyed by `${padIndex}:${axisName}` (axisName is a
1098
+ * `GamepadAxisKey` from `@yagejs/input`).
1099
+ */
969
1100
  axes: Array<{
970
- index: number;
1101
+ key: string;
971
1102
  value: number;
972
1103
  }>;
973
1104
  };
@@ -1039,8 +1170,23 @@ declare class Inspector {
1039
1170
  mouseMove: (x: number, y: number) => void;
1040
1171
  mouseDown: (button?: 0 | 1 | 2) => void;
1041
1172
  mouseUp: (button?: 0 | 1 | 2) => void;
1042
- gamepadButton: (idx: number, pressed: boolean) => void;
1043
- gamepadAxis: (idx: number, value: number) => void;
1173
+ /**
1174
+ * Inject a synthetic pointer-move with full pointer addressing. Pass `opts`
1175
+ * with `id` / `type: "touch"` to drive a specific finger; defaults match
1176
+ * the primary mouse pointer (same as `mouseMove`).
1177
+ */
1178
+ pointerMove: (x: number, y: number, opts?: InspectorPointerOpts) => void;
1179
+ /**
1180
+ * Inject a synthetic pointer-down. With `opts.id` and `opts.type: "touch"`
1181
+ * this drives a multi-touch contact, exercising `getPointers()`,
1182
+ * per-pointer event hooks, and the any-pointer aggregate for `MouseLeft`.
1183
+ */
1184
+ pointerDown: (button?: 0 | 1 | 2, opts?: InspectorPointerOpts) => void;
1185
+ pointerUp: (button?: 0 | 1 | 2, opts?: {
1186
+ id?: number;
1187
+ }) => void;
1188
+ gamepadButton: (code: string, pressed: boolean) => void;
1189
+ gamepadAxis: (side: InspectorGamepadAxisKey, value: number) => void;
1044
1190
  tap: (code: string, frames?: number) => void;
1045
1191
  hold: (code: string, frames: number) => void;
1046
1192
  fireAction: (name: string, frames?: number) => void;
@@ -2230,6 +2376,19 @@ interface RendererAdapter {
2230
2376
  x: number;
2231
2377
  y: number;
2232
2378
  };
2379
+ /**
2380
+ * Hit-test at virtual-space coordinates and return `true` when the topmost
2381
+ * interactive container under `(x, y)` is parented (directly or through any
2382
+ * ancestor) to a container marked via {@link markPointerConsumeContainer}.
2383
+ * Optional — when absent, the input plugin's UI auto-consume fallback is a
2384
+ * no-op.
2385
+ *
2386
+ * Implemented by `@yagejs/renderer` over Pixi's `EventBoundary`. The input
2387
+ * plugin calls this on `pointerdown` drains to auto-claim presses that land
2388
+ * on UI surfaces (UIPanel backgrounds, decorative UIText, etc.) without
2389
+ * requiring per-component handler boilerplate.
2390
+ */
2391
+ hitTestUI?(x: number, y: number): boolean;
2233
2392
  }
2234
2393
  /**
2235
2394
  * Well-known service key for the current renderer's pointer-input adapter.
@@ -2239,6 +2398,36 @@ interface RendererAdapter {
2239
2398
  */
2240
2399
  declare const RendererAdapterKey: ServiceKey<RendererAdapter>;
2241
2400
 
2401
+ /**
2402
+ * Cross-package WeakSet for marking display containers (Pixi `Container`s in
2403
+ * the canonical setup) as "swallow pointer input." The `@yagejs/input`
2404
+ * package's drain step consults this set via the renderer's optional
2405
+ * `hitTestUI(x, y)` — when the topmost interactive container under a
2406
+ * `pointerdown` is parented to a marked container, the pointer is auto-claimed
2407
+ * (`consumePointer`-equivalent), so the press never propagates to gameplay
2408
+ * action-map edges like `MouseLeft`.
2409
+ *
2410
+ * Lives in `@yagejs/core` so the renderer (read side) and the UI / sprite
2411
+ * components (write side) can both reach it without circular imports.
2412
+ *
2413
+ * Untyped on `Container` to keep `@yagejs/core` free of any Pixi dependency.
2414
+ * Callers pass their `Pixi.Container` instances directly; `WeakSet` accepts
2415
+ * any object reference.
2416
+ */
2417
+ /**
2418
+ * Mark a display container as a UI-input surface. Idempotent. Call from a
2419
+ * component's `onAdd` (or equivalent) after the underlying Pixi container is
2420
+ * created.
2421
+ */
2422
+ declare function markPointerConsumeContainer(container: object): void;
2423
+ /**
2424
+ * Remove the mark. Call from a component's `onDestroy` for symmetry, or to
2425
+ * implement an opt-out (`consumeInput: false`) escape hatch on UI primitives.
2426
+ */
2427
+ declare function unmarkPointerConsumeContainer(container: object): void;
2428
+ /** Whether a container has been marked as a UI-input surface. */
2429
+ declare function isPointerConsumeContainer(container: object): boolean;
2430
+
2242
2431
  /** Create a fully wired Engine for integration tests. */
2243
2432
  declare function createTestEngine(config?: EngineConfig): Promise<Engine>;
2244
2433
  /** Create a lightweight mock scene with EngineContext for unit tests. */
@@ -2255,6 +2444,178 @@ declare function createMockEntity(name?: string): {
2255
2444
  /** Advance the game loop by N frames (manual tick). */
2256
2445
  declare function advanceFrames(engine: Engine, n: number, dtMs?: number): void;
2257
2446
 
2447
+ /**
2448
+ * Atom — minimal reactive cell.
2449
+ *
2450
+ * Signal-shaped: `get`, `set`, `subscribe`. Identity-based change detection
2451
+ * (`Object.is`); subscribers are notified only when the value actually changes.
2452
+ */
2453
+ interface Atom<T> {
2454
+ get(): T;
2455
+ set(next: T): void;
2456
+ subscribe(listener: (value: T) => void): () => void;
2457
+ }
2458
+ declare function createAtom<T>(initial: T): Atom<T>;
2459
+
2460
+ /**
2461
+ * Store — object-shaped reactive store with shallow merge.
2462
+ *
2463
+ * `get()` returns a `Readonly<T>` whose reference is stable between sets.
2464
+ * `set(partial)` merges keys via spread and notifies only when at least one key
2465
+ * changed (Object.is per key). Mutation through the snapshot bypasses
2466
+ * subscribers — TypeScript's `Readonly<T>` enforces the contract; do not reach
2467
+ * into nested objects to mutate them, use `set` instead.
2468
+ */
2469
+ interface Store<T extends object> {
2470
+ get(): Readonly<T>;
2471
+ set(partial: Partial<T>): void;
2472
+ subscribe(listener: () => void): () => void;
2473
+ }
2474
+ declare function createStore<T extends object>(initial: T): Store<T>;
2475
+
2476
+ /**
2477
+ * A codec converts a value between its in-memory representation and a JSON-safe
2478
+ * representation that adapters can stringify. Codecs are pure functions; they
2479
+ * don't read or write storage.
2480
+ */
2481
+ interface Codec<T> {
2482
+ encode(value: T): unknown;
2483
+ decode(raw: unknown): T;
2484
+ }
2485
+ /** Identity codec — pass-through for plain JSON-serializable values. */
2486
+ declare function jsonCodec<T>(): Codec<T>;
2487
+ /** Set ↔ array. */
2488
+ declare function setCodec<K>(): Codec<Set<K>>;
2489
+ /** Map ↔ entries array. */
2490
+ declare function mapCodec<K, V>(): Codec<Map<K, V>>;
2491
+ /** Date ↔ ISO string. */
2492
+ declare function dateCodec(): Codec<Date>;
2493
+
2494
+ /**
2495
+ * Common persistence shape implemented by every defineX output. The save layer
2496
+ * accepts anything matching this structural type — stores don't depend on the
2497
+ * save layer.
2498
+ */
2499
+ interface PersistentLike {
2500
+ readonly id: string;
2501
+ readonly version: number;
2502
+ serialize(): {
2503
+ version: number;
2504
+ data: unknown;
2505
+ };
2506
+ hydrate(payload: {
2507
+ version: number;
2508
+ data: unknown;
2509
+ }): void;
2510
+ subscribe(listener: () => void): () => void;
2511
+ }
2512
+ /**
2513
+ * Reset every persistent store created by defineStore / defineSet / defineMap /
2514
+ * defineCounter back to its defaults. Test-only.
2515
+ *
2516
+ * @internal
2517
+ */
2518
+ declare function _resetAllStoresForTesting(): void;
2519
+ /**
2520
+ * Drop every persistent store from the internal registry. Use only when you
2521
+ * intend to redefine stores with the same ids (e.g. between test files that
2522
+ * share a module namespace via Vitest's module cache).
2523
+ *
2524
+ * @internal
2525
+ */
2526
+ declare function _clearStoreRegistryForTesting(): void;
2527
+ interface DefineStoreOptions<T> {
2528
+ /** Schema version. Defaults to 1. Bump when shape changes; provide `migrate`. */
2529
+ version?: number;
2530
+ /** Factory producing the default value. Called on creation and on `reset()`. */
2531
+ defaults: () => T;
2532
+ /** Codec for `T`. Defaults to identity (jsonCodec). */
2533
+ codec?: Codec<T>;
2534
+ /**
2535
+ * Migrate previously-stored data to the current version. Receives the raw
2536
+ * decoded payload and the version it was written at. Called when
2537
+ * `payload.version < version` during `hydrate`.
2538
+ */
2539
+ migrate?: (old: unknown, fromVersion: number) => T;
2540
+ }
2541
+ interface PersistentStore<T extends object> extends Store<T>, PersistentLike {
2542
+ reset(): void;
2543
+ }
2544
+ /** Thrown by `hydrate` when stored data is from a newer version than this build. */
2545
+ declare class StoreVersionTooNewError extends Error {
2546
+ readonly storeId: string;
2547
+ readonly storedVersion: number;
2548
+ readonly currentVersion: number;
2549
+ constructor(storeId: string, storedVersion: number, currentVersion: number);
2550
+ }
2551
+ /** Thrown by `hydrate` when stored data is older than the current version and no `migrate` is configured. */
2552
+ declare class StoreMigrationMissingError extends Error {
2553
+ readonly storeId: string;
2554
+ readonly storedVersion: number;
2555
+ readonly currentVersion: number;
2556
+ constructor(storeId: string, storedVersion: number, currentVersion: number);
2557
+ }
2558
+ declare function defineStore<T extends object>(id: string, opts: DefineStoreOptions<T>): PersistentStore<T>;
2559
+ interface PersistentSet<K> extends PersistentLike {
2560
+ has(key: K): boolean;
2561
+ add(key: K): void;
2562
+ remove(key: K): void;
2563
+ clear(): void;
2564
+ size(): number;
2565
+ values(): IterableIterator<K>;
2566
+ reset(): void;
2567
+ }
2568
+ interface DefineSetOptions<K> {
2569
+ version?: number;
2570
+ defaults?: () => Iterable<K>;
2571
+ /**
2572
+ * Migrate older stored data to the current version. Receives the raw decoded
2573
+ * payload (a `K[]` from setCodec) and the version it was written at. Required
2574
+ * when bumping `version`; otherwise older payloads throw at hydrate.
2575
+ */
2576
+ migrate?: (old: unknown, fromVersion: number) => Set<K>;
2577
+ }
2578
+ declare function defineSet<K>(id: string, opts?: DefineSetOptions<K>): PersistentSet<K>;
2579
+ interface PersistentMap<K, V> extends PersistentLike {
2580
+ has(key: K): boolean;
2581
+ get(key: K): V | undefined;
2582
+ set(key: K, value: V): void;
2583
+ remove(key: K): void;
2584
+ clear(): void;
2585
+ size(): number;
2586
+ entries(): IterableIterator<[K, V]>;
2587
+ reset(): void;
2588
+ }
2589
+ interface DefineMapOptions<K, V> {
2590
+ version?: number;
2591
+ defaults?: () => Iterable<[K, V]>;
2592
+ /**
2593
+ * Migrate older stored data to the current version. Receives the raw decoded
2594
+ * payload (a `[K, V][]` from mapCodec) and the version it was written at.
2595
+ * Required when bumping `version`; otherwise older payloads throw at hydrate.
2596
+ */
2597
+ migrate?: (old: unknown, fromVersion: number) => Map<K, V>;
2598
+ }
2599
+ declare function defineMap<K, V>(id: string, opts?: DefineMapOptions<K, V>): PersistentMap<K, V>;
2600
+ interface PersistentCounter extends PersistentLike {
2601
+ value(): number;
2602
+ set(n: number): void;
2603
+ increment(by?: number): void;
2604
+ decrement(by?: number): void;
2605
+ reset(): void;
2606
+ }
2607
+ interface DefineCounterOptions {
2608
+ version?: number;
2609
+ defaults?: () => number;
2610
+ /**
2611
+ * Migrate older stored data to the current version. Receives the raw decoded
2612
+ * payload (a number) and the version it was written at. Required when
2613
+ * bumping `version`; otherwise older payloads throw at hydrate.
2614
+ */
2615
+ migrate?: (old: unknown, fromVersion: number) => number;
2616
+ }
2617
+ declare function defineCounter(id: string, opts?: DefineCounterOptions): PersistentCounter;
2618
+
2258
2619
  declare const VERSION = "0.0.0";
2259
2620
 
2260
- export { AssetHandle, type AssetLoader, AssetManager, AssetManagerKey, type Blueprint, type CameraSnapshot, Component, type ComponentClass, ComponentFixedUpdateSystem, type ComponentStateSnapshot, ComponentUpdateSystem, type EasingFunction, Engine, type EngineConfig, EngineContext, type EngineEvents, EngineKey, type EngineSnapshot, Entity, type EntityCallbacks, type EntityFilter, type EntitySnapshot, ErrorBoundary, ErrorBoundaryKey, type ErrorSnapshot, EventBus, EventBusKey, type EventLogEntry, type EventMap, EventToken, GameLoop, type GameLoopCallbacks, type GameLoopConfig, GameLoopKey, type InputStateSnapshot, Inspector, InspectorKey, type InspectorTimeController, type Interpolatable, type Keyframe, type KeyframeAnimationDef, KeyframeAnimator, type KeyframeTrackOptions, LoadingScene, type LogEntry, LogLevel, Logger, type LoggerConfig, LoggerKey, MathUtils, Phase, type PhysicsSnapshot, type Plugin, Process, ProcessComponent, type ProcessOptions, ProcessSlot, type ProcessSlotConfig, ProcessSystem, ProcessSystemKey, QueryCache, QueryCacheKey, QueryResult, RandomKey, type RandomService, type RendererAdapter, RendererAdapterKey, SERIALIZABLE_KEY, Scene, SceneHookRegistry, SceneHookRegistryKey, type SceneHooks, SceneManager, SceneManagerKey, type SceneSnapshot, type SceneTransition, type SceneTransitionContext, type SceneTransitionKind, type SceneTransitionOptions, type ScopedProcessQueue, Sequence, SerializableRegistry, ServiceKey, type ServiceKeyOptions, type ServiceScope, type SmoothDampResult, type SnapshotResolver, System, SystemScheduler, SystemSchedulerKey, type SystemSnapshot, TimerEntity, TraitToken, Transform, type TransformData, Tween, type UINodeSnapshot, type UITreeSnapshot, VERSION, Vec2, type Vec2Like, type WorldEntitySnapshot, type WorldSceneSnapshot, _resetEntityIdCounter, advanceFrames, createDefaultRandomSeed, createKeyframeTrack, createMockEntity, createMockScene, createRandomService, createTestEngine, defineBlueprint, defineEvent, defineTrait, easeInOutQuad, easeInQuad, easeLinear, easeOutBounce, easeOutQuad, filterEntities, getSerializableType, globalRandom, interpolate, isSerializable, makeEntityScopedQueue, makeGlobalScopedQueue, makeSceneScopedQueue, normalizeSeed, resolveTransition, serializable, trait };
2621
+ export { AssetHandle, type AssetLoader, AssetManager, AssetManagerKey, type Atom, type Blueprint, type CameraSnapshot, type Codec, Component, type ComponentClass, ComponentFixedUpdateSystem, type ComponentStateSnapshot, ComponentUpdateSystem, type DefineCounterOptions, type DefineMapOptions, type DefineSetOptions, type DefineStoreOptions, type EasingFunction, Engine, type EngineConfig, EngineContext, type EngineEvents, EngineKey, type EngineSnapshot, Entity, type EntityCallbacks, type EntityFilter, type EntitySnapshot, ErrorBoundary, ErrorBoundaryKey, type ErrorSnapshot, EventBus, EventBusKey, type EventLogEntry, type EventMap, EventToken, GameLoop, type GameLoopCallbacks, type GameLoopConfig, GameLoopKey, type InputStateSnapshot, Inspector, InspectorKey, type InspectorTimeController, type Interpolatable, type Keyframe, type KeyframeAnimationDef, KeyframeAnimator, type KeyframeTrackOptions, LoadingScene, type LogEntry, LogLevel, Logger, type LoggerConfig, LoggerKey, MathUtils, type PersistentCounter, type PersistentLike, type PersistentMap, type PersistentSet, type PersistentStore, Phase, type PhysicsSnapshot, type Plugin, type PointerSnapshot, Process, ProcessComponent, type ProcessOptions, ProcessSlot, type ProcessSlotConfig, ProcessSystem, ProcessSystemKey, QueryCache, QueryCacheKey, QueryResult, RandomKey, type RandomService, type RendererAdapter, RendererAdapterKey, SERIALIZABLE_KEY, Scene, SceneHookRegistry, SceneHookRegistryKey, type SceneHooks, SceneManager, SceneManagerKey, type SceneSnapshot, type SceneTransition, type SceneTransitionContext, type SceneTransitionKind, type SceneTransitionOptions, type ScopedProcessQueue, Sequence, SerializableRegistry, ServiceKey, type ServiceKeyOptions, type ServiceScope, type SmoothDampResult, type SnapshotResolver, type SpawnOptions, type Store, StoreMigrationMissingError, StoreVersionTooNewError, System, SystemScheduler, SystemSchedulerKey, type SystemSnapshot, TimerEntity, TraitToken, Transform, type TransformData, Tween, type UINodeSnapshot, type UITreeSnapshot, VERSION, Vec2, type Vec2Like, type WorldEntitySnapshot, type WorldSceneSnapshot, _clearStoreRegistryForTesting, _resetAllStoresForTesting, _resetEntityIdCounter, advanceFrames, createAtom, createDefaultRandomSeed, createKeyframeTrack, createMockEntity, createMockScene, createRandomService, createStore, createTestEngine, dateCodec, defineBlueprint, defineCounter, defineEvent, defineMap, defineSet, defineStore, defineTrait, easeInOutQuad, easeInQuad, easeLinear, easeOutBounce, easeOutQuad, filterEntities, getSerializableType, globalRandom, interpolate, isPointerConsumeContainer, isSerializable, jsonCodec, makeEntityScopedQueue, makeGlobalScopedQueue, makeSceneScopedQueue, mapCodec, markPointerConsumeContainer, normalizeSeed, resolveTransition, serializable, setCodec, trait, unmarkPointerConsumeContainer };