@thewhateverapp/tile-sdk 0.15.2 → 0.15.4

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.
Files changed (53) hide show
  1. package/dist/bridge/TileBridge.d.ts.map +1 -1
  2. package/dist/bridge/TileBridge.js +6 -2
  3. package/dist/excalibur/index.d.ts +48 -0
  4. package/dist/excalibur/index.d.ts.map +1 -0
  5. package/dist/excalibur/index.js +51 -0
  6. package/dist/react/ExcaliburGame.d.ts +109 -0
  7. package/dist/react/ExcaliburGame.d.ts.map +1 -0
  8. package/dist/react/ExcaliburGame.js +215 -0
  9. package/dist/react/index.js +3 -3
  10. package/dist/scene/index.d.ts +3 -41
  11. package/dist/scene/index.d.ts.map +1 -1
  12. package/dist/scene/index.js +1 -49
  13. package/dist/spec/schema.d.ts +12 -12
  14. package/package.json +7 -7
  15. package/dist/pixi/index.d.ts +0 -43
  16. package/dist/pixi/index.d.ts.map +0 -1
  17. package/dist/pixi/index.js +0 -46
  18. package/dist/react/PixiGame.d.ts +0 -138
  19. package/dist/react/PixiGame.d.ts.map +0 -1
  20. package/dist/react/PixiGame.js +0 -237
  21. package/dist/scene/SceneContext.d.ts +0 -173
  22. package/dist/scene/SceneContext.d.ts.map +0 -1
  23. package/dist/scene/SceneContext.js +0 -89
  24. package/dist/scene/SceneFromJson.d.ts +0 -34
  25. package/dist/scene/SceneFromJson.d.ts.map +0 -1
  26. package/dist/scene/SceneFromJson.js +0 -97
  27. package/dist/scene/SceneRenderer.d.ts +0 -29
  28. package/dist/scene/SceneRenderer.d.ts.map +0 -1
  29. package/dist/scene/SceneRenderer.js +0 -312
  30. package/dist/scene/camera/CameraController.d.ts +0 -6
  31. package/dist/scene/camera/CameraController.d.ts.map +0 -1
  32. package/dist/scene/camera/CameraController.js +0 -90
  33. package/dist/scene/components/ComponentRunner.d.ts +0 -22
  34. package/dist/scene/components/ComponentRunner.d.ts.map +0 -1
  35. package/dist/scene/components/ComponentRunner.js +0 -210
  36. package/dist/scene/effects/GlowFilter.d.ts +0 -38
  37. package/dist/scene/effects/GlowFilter.d.ts.map +0 -1
  38. package/dist/scene/effects/GlowFilter.js +0 -40
  39. package/dist/scene/effects/ParticleSystem.d.ts +0 -52
  40. package/dist/scene/effects/ParticleSystem.d.ts.map +0 -1
  41. package/dist/scene/effects/ParticleSystem.js +0 -107
  42. package/dist/scene/entities/EntityGraphics.d.ts +0 -26
  43. package/dist/scene/entities/EntityGraphics.d.ts.map +0 -1
  44. package/dist/scene/entities/EntityGraphics.js +0 -226
  45. package/dist/scene/input/InputManager.d.ts +0 -18
  46. package/dist/scene/input/InputManager.d.ts.map +0 -1
  47. package/dist/scene/input/InputManager.js +0 -86
  48. package/dist/scene/physics/PhysicsEngine.d.ts +0 -15
  49. package/dist/scene/physics/PhysicsEngine.d.ts.map +0 -1
  50. package/dist/scene/physics/PhysicsEngine.js +0 -260
  51. package/dist/scene/timeline/TimelineExecutor.d.ts +0 -6
  52. package/dist/scene/timeline/TimelineExecutor.d.ts.map +0 -1
  53. package/dist/scene/timeline/TimelineExecutor.js +0 -241
@@ -28,10 +28,10 @@ declare const ActionSchema: z.ZodObject<{
28
28
  $action: z.ZodEnum<["emit", "setState", "sequence", "openTile", "openFull", "navigate", "dismiss", "fx"]>;
29
29
  payload: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
30
30
  }, "strip", z.ZodTypeAny, {
31
- $action: "navigate" | "setState" | "emit" | "fx" | "sequence" | "openTile" | "openFull" | "dismiss";
31
+ $action: "navigate" | "setState" | "emit" | "sequence" | "openTile" | "openFull" | "dismiss" | "fx";
32
32
  payload?: Record<string, unknown> | undefined;
33
33
  }, {
34
- $action: "navigate" | "setState" | "emit" | "fx" | "sequence" | "openTile" | "openFull" | "dismiss";
34
+ $action: "navigate" | "setState" | "emit" | "sequence" | "openTile" | "openFull" | "dismiss" | "fx";
35
35
  payload?: Record<string, unknown> | undefined;
36
36
  }>;
37
37
  declare const PropValueSchema: z.ZodType<unknown>;
@@ -347,11 +347,11 @@ export declare const OverlaySpecSchema: z.ZodObject<{
347
347
  offsetMs: z.ZodOptional<z.ZodNumber>;
348
348
  scale: z.ZodOptional<z.ZodNumber>;
349
349
  }, "strip", z.ZodTypeAny, {
350
- scale?: number | undefined;
351
350
  offsetMs?: number | undefined;
352
- }, {
353
351
  scale?: number | undefined;
352
+ }, {
354
353
  offsetMs?: number | undefined;
354
+ scale?: number | undefined;
355
355
  }>>;
356
356
  freezeWhen: z.ZodOptional<z.ZodType<unknown, z.ZodTypeDef, unknown>>;
357
357
  }, "strip", z.ZodTypeAny, {
@@ -360,8 +360,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
360
360
  toleranceMs: number;
361
361
  onSeek: "recompute";
362
362
  transform?: {
363
- scale?: number | undefined;
364
363
  offsetMs?: number | undefined;
364
+ scale?: number | undefined;
365
365
  } | undefined;
366
366
  freezeWhen?: unknown;
367
367
  }, {
@@ -370,8 +370,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
370
370
  toleranceMs: number;
371
371
  onSeek: "recompute";
372
372
  transform?: {
373
- scale?: number | undefined;
374
373
  offsetMs?: number | undefined;
374
+ scale?: number | undefined;
375
375
  } | undefined;
376
376
  freezeWhen?: unknown;
377
377
  }>;
@@ -702,14 +702,14 @@ export declare const OverlaySpecSchema: z.ZodObject<{
702
702
  transform: z.ZodOptional<z.ZodString>;
703
703
  }, "strip", z.ZodTypeAny, {
704
704
  id: string;
705
- type: "realtime" | "keyspace" | "host";
706
705
  target: string;
706
+ type: "realtime" | "keyspace" | "host";
707
707
  channel: string;
708
708
  transform?: string | undefined;
709
709
  }, {
710
710
  id: string;
711
- type: "realtime" | "keyspace" | "host";
712
711
  target: string;
712
+ type: "realtime" | "keyspace" | "host";
713
713
  channel: string;
714
714
  transform?: string | undefined;
715
715
  }>, "many">>;
@@ -726,8 +726,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
726
726
  toleranceMs: number;
727
727
  onSeek: "recompute";
728
728
  transform?: {
729
- scale?: number | undefined;
730
729
  offsetMs?: number | undefined;
730
+ scale?: number | undefined;
731
731
  } | undefined;
732
732
  freezeWhen?: unknown;
733
733
  };
@@ -787,8 +787,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
787
787
  } | undefined;
788
788
  subscriptions?: {
789
789
  id: string;
790
- type: "realtime" | "keyspace" | "host";
791
790
  target: string;
791
+ type: "realtime" | "keyspace" | "host";
792
792
  channel: string;
793
793
  transform?: string | undefined;
794
794
  }[] | undefined;
@@ -805,8 +805,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
805
805
  toleranceMs: number;
806
806
  onSeek: "recompute";
807
807
  transform?: {
808
- scale?: number | undefined;
809
808
  offsetMs?: number | undefined;
809
+ scale?: number | undefined;
810
810
  } | undefined;
811
811
  freezeWhen?: unknown;
812
812
  };
@@ -866,8 +866,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
866
866
  } | undefined;
867
867
  subscriptions?: {
868
868
  id: string;
869
- type: "realtime" | "keyspace" | "host";
870
869
  target: string;
870
+ type: "realtime" | "keyspace" | "host";
871
871
  channel: string;
872
872
  transform?: string | undefined;
873
873
  }[] | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thewhateverapp/tile-sdk",
3
- "version": "0.15.2",
3
+ "version": "0.15.4",
4
4
  "description": "SDK for building interactive tiles on The Whatever App platform",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -13,9 +13,9 @@
13
13
  "types": "./dist/react/index.d.ts",
14
14
  "import": "./dist/react/index.js"
15
15
  },
16
- "./pixi": {
17
- "types": "./dist/pixi/index.d.ts",
18
- "import": "./dist/pixi/index.js"
16
+ "./excalibur": {
17
+ "types": "./dist/excalibur/index.d.ts",
18
+ "import": "./dist/excalibur/index.js"
19
19
  },
20
20
  "./spec": {
21
21
  "types": "./dist/spec/index.d.ts",
@@ -70,10 +70,10 @@
70
70
  },
71
71
  "peerDependencies": {
72
72
  "react": "^18.0.0",
73
- "pixi.js": "^7.0.0"
73
+ "excalibur": "^0.29.0"
74
74
  },
75
75
  "peerDependenciesMeta": {
76
- "pixi.js": {
76
+ "excalibur": {
77
77
  "optional": true
78
78
  }
79
79
  },
@@ -82,8 +82,8 @@
82
82
  "@types/node": "^20.0.0",
83
83
  "@types/react": "^18.2.48",
84
84
  "eslint": "^9.39.1",
85
+ "excalibur": "^0.29.3",
85
86
  "next": "^14.2.0",
86
- "pixi.js": "^7.4.2",
87
87
  "typescript": "^5.3.3"
88
88
  }
89
89
  }
@@ -1,43 +0,0 @@
1
- /**
2
- * Pixi.js game components for tile-sdk
3
- *
4
- * Import from '@thewhateverapp/tile-sdk/pixi' to use pixi.js features.
5
- * This uses pixi.js directly (no @pixi/react) for better stability.
6
- *
7
- * @example
8
- * ```tsx
9
- * import { PixiGame, usePixiApp, useGameLoop } from '@thewhateverapp/tile-sdk/pixi';
10
- * import * as PIXI from 'pixi.js';
11
- *
12
- * function MyGame() {
13
- * return (
14
- * <PixiGame width={256} height={554}>
15
- * <GameContent />
16
- * </PixiGame>
17
- * );
18
- * }
19
- *
20
- * function GameContent() {
21
- * const app = usePixiApp();
22
- *
23
- * useEffect(() => {
24
- * if (!app) return;
25
- * const graphics = new PIXI.Graphics();
26
- * graphics.beginFill(0xff0000);
27
- * graphics.drawRect(100, 100, 50, 50);
28
- * graphics.endFill();
29
- * app.stage.addChild(graphics);
30
- * return () => graphics.destroy();
31
- * }, [app]);
32
- *
33
- * useGameLoop((delta) => {
34
- * // Game logic runs every frame
35
- * });
36
- *
37
- * return null;
38
- * }
39
- * ```
40
- */
41
- export { PixiGame, usePixiApp, useApp, useGameLoop, useGameState, useGameInput, useInitialized, Container, Graphics, Text, Sprite, TILE_WIDTH, TILE_HEIGHT, } from '../react/PixiGame.js';
42
- export type { PixiGameProps } from '../react/PixiGame.js';
43
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pixi/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EACL,QAAQ,EACR,UAAU,EACV,MAAM,EACN,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,cAAc,EAEd,SAAS,EACT,QAAQ,EACR,IAAI,EACJ,MAAM,EAEN,UAAU,EACV,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1,46 +0,0 @@
1
- 'use client';
2
- /**
3
- * Pixi.js game components for tile-sdk
4
- *
5
- * Import from '@thewhateverapp/tile-sdk/pixi' to use pixi.js features.
6
- * This uses pixi.js directly (no @pixi/react) for better stability.
7
- *
8
- * @example
9
- * ```tsx
10
- * import { PixiGame, usePixiApp, useGameLoop } from '@thewhateverapp/tile-sdk/pixi';
11
- * import * as PIXI from 'pixi.js';
12
- *
13
- * function MyGame() {
14
- * return (
15
- * <PixiGame width={256} height={554}>
16
- * <GameContent />
17
- * </PixiGame>
18
- * );
19
- * }
20
- *
21
- * function GameContent() {
22
- * const app = usePixiApp();
23
- *
24
- * useEffect(() => {
25
- * if (!app) return;
26
- * const graphics = new PIXI.Graphics();
27
- * graphics.beginFill(0xff0000);
28
- * graphics.drawRect(100, 100, 50, 50);
29
- * graphics.endFill();
30
- * app.stage.addChild(graphics);
31
- * return () => graphics.destroy();
32
- * }, [app]);
33
- *
34
- * useGameLoop((delta) => {
35
- * // Game logic runs every frame
36
- * });
37
- *
38
- * return null;
39
- * }
40
- * ```
41
- */
42
- export { PixiGame, usePixiApp, useApp, useGameLoop, useGameState, useGameInput, useInitialized,
43
- // Re-exported PIXI classes
44
- Container, Graphics, Text, Sprite,
45
- // Constants
46
- TILE_WIDTH, TILE_HEIGHT, } from '../react/PixiGame.js';
@@ -1,138 +0,0 @@
1
- /**
2
- * PixiGame - Direct pixi.js integration without @pixi/react
3
- *
4
- * This component creates a PIXI.Application imperatively and provides
5
- * it via React context. This avoids react-reconciler issues that plague
6
- * @pixi/react.
7
- *
8
- * @example
9
- * ```tsx
10
- * import { PixiGame, usePixiApp, useGameLoop } from '@thewhateverapp/tile-sdk/pixi';
11
- *
12
- * function MyGame() {
13
- * return (
14
- * <PixiGame>
15
- * <GameContent />
16
- * </PixiGame>
17
- * );
18
- * }
19
- *
20
- * function GameContent() {
21
- * const app = usePixiApp();
22
- * const containerRef = useRef<PIXI.Container | null>(null);
23
- *
24
- * useEffect(() => {
25
- * if (!app) return;
26
- * const container = new PIXI.Container();
27
- * app.stage.addChild(container);
28
- * containerRef.current = container;
29
- * return () => {
30
- * app.stage.removeChild(container);
31
- * container.destroy();
32
- * };
33
- * }, [app]);
34
- *
35
- * useGameLoop((delta) => {
36
- * // Game logic here
37
- * });
38
- *
39
- * return null; // No React children needed - pixi manages rendering
40
- * }
41
- * ```
42
- */
43
- import React, { type ReactNode } from 'react';
44
- import * as PIXI from 'pixi.js';
45
- export { Container, Graphics, Text, Sprite } from 'pixi.js';
46
- /**
47
- * Tile dimensions - standard tile size
48
- */
49
- export declare const TILE_WIDTH = 256;
50
- export declare const TILE_HEIGHT = 554;
51
- /**
52
- * Hook to get the PIXI Application
53
- */
54
- export declare function usePixiApp(): PIXI.Application | null;
55
- /**
56
- * Hook to get the PIXI Application (alias for backwards compatibility)
57
- */
58
- export declare function useApp(): PIXI.Application | null;
59
- /**
60
- * useGameLoop - Run a callback every frame
61
- *
62
- * @param callback - Function called every frame with delta time (in frames, ~1 at 60fps)
63
- * @param enabled - Whether the loop is active (default: true)
64
- */
65
- export declare function useGameLoop(callback: (delta: number) => void, enabled?: boolean): void;
66
- export interface PixiGameProps {
67
- children: ReactNode;
68
- /** Width in pixels (default: 256 for tile) */
69
- width?: number;
70
- /** Height in pixels (default: 554 for tile) */
71
- height?: number;
72
- /** Background color (default: black) */
73
- background?: number;
74
- /** Stage options */
75
- options?: {
76
- antialias?: boolean;
77
- resolution?: number;
78
- autoDensity?: boolean;
79
- };
80
- /** Whether game is paused */
81
- paused?: boolean;
82
- /** Callback when Application is ready */
83
- onMount?: (app: PIXI.Application) => void;
84
- }
85
- /**
86
- * PixiGame - Main wrapper component for pixi.js games
87
- *
88
- * Creates a PIXI.Application and provides it via context.
89
- * Children can use usePixiApp() to access the app and create pixi objects.
90
- */
91
- export declare function PixiGame({ children, width, height, background, options, paused, onMount, }: PixiGameProps): React.JSX.Element;
92
- /**
93
- * useGameState - Helper for managing game state with refs
94
- *
95
- * Returns a ref and a forceUpdate function for when you need to trigger re-renders.
96
- * Use refs for continuous game state (position, velocity) to avoid re-render loops.
97
- */
98
- export declare function useGameState<T extends object>(initialState: T): [React.MutableRefObject<T>, () => void];
99
- /**
100
- * useGameInput - Simple keyboard input hook for games
101
- *
102
- * Returns a ref with currently pressed keys.
103
- */
104
- export declare function useGameInput(): React.MutableRefObject<Record<string, boolean>>;
105
- /**
106
- * useInitialized - Helper hook for tracking game object initialization
107
- *
108
- * Returns an initRef that should be set to true AFTER all game objects are
109
- * created in useEffect, and checked as the FIRST line in useGameLoop.
110
- *
111
- * @example
112
- * ```tsx
113
- * function GameContent() {
114
- * const app = usePixiApp();
115
- * const initRef = useInitialized();
116
- * const playerRef = useRef<PIXI.Graphics | null>(null);
117
- *
118
- * useEffect(() => {
119
- * if (!app) return;
120
- * const player = new PIXI.Graphics();
121
- * // ... setup player ...
122
- * playerRef.current = player;
123
- * initRef.current = true; // Set AFTER all refs are ready
124
- * return () => {
125
- * initRef.current = false;
126
- * player.destroy();
127
- * };
128
- * }, [app]);
129
- *
130
- * useGameLoop((delta) => {
131
- * if (!initRef.current || !playerRef.current) return; // REQUIRED!
132
- * // ... safe to use playerRef.current ...
133
- * });
134
- * }
135
- * ```
136
- */
137
- export declare function useInitialized(): React.MutableRefObject<boolean>;
138
- //# sourceMappingURL=PixiGame.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PixiGame.d.ts","sourceRoot":"","sources":["../../src/react/PixiGame.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EAAE,EAOZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAGhC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,UAAU,MAAM,CAAC;AAC9B,eAAO,MAAM,WAAW,MAAM,CAAC;AAY/B;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAAC,WAAW,GAAG,IAAI,CAMpD;AAED;;GAEG;AACH,wBAAgB,MAAM,IAAI,IAAI,CAAC,WAAW,GAAG,IAAI,CAEhD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EACjC,OAAO,GAAE,OAAc,QAexB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,SAAS,CAAC;IACpB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB;IACpB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,CAAC;IACF,6BAA6B;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yCAAyC;IACzC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC;CAC3C;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,KAAkB,EAClB,MAAoB,EACpB,UAAqB,EACrB,OAAY,EACZ,MAAc,EACd,OAAO,GACR,EAAE,aAAa,qBAqFf;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAC3C,YAAY,EAAE,CAAC,GACd,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,CASzC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,oDAwB3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,cAAc,IAAI,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAEhE"}
@@ -1,237 +0,0 @@
1
- 'use client';
2
- /**
3
- * PixiGame - Direct pixi.js integration without @pixi/react
4
- *
5
- * This component creates a PIXI.Application imperatively and provides
6
- * it via React context. This avoids react-reconciler issues that plague
7
- * @pixi/react.
8
- *
9
- * @example
10
- * ```tsx
11
- * import { PixiGame, usePixiApp, useGameLoop } from '@thewhateverapp/tile-sdk/pixi';
12
- *
13
- * function MyGame() {
14
- * return (
15
- * <PixiGame>
16
- * <GameContent />
17
- * </PixiGame>
18
- * );
19
- * }
20
- *
21
- * function GameContent() {
22
- * const app = usePixiApp();
23
- * const containerRef = useRef<PIXI.Container | null>(null);
24
- *
25
- * useEffect(() => {
26
- * if (!app) return;
27
- * const container = new PIXI.Container();
28
- * app.stage.addChild(container);
29
- * containerRef.current = container;
30
- * return () => {
31
- * app.stage.removeChild(container);
32
- * container.destroy();
33
- * };
34
- * }, [app]);
35
- *
36
- * useGameLoop((delta) => {
37
- * // Game logic here
38
- * });
39
- *
40
- * return null; // No React children needed - pixi manages rendering
41
- * }
42
- * ```
43
- */
44
- import React, { createContext, useContext, useRef, useEffect, useState, useCallback, } from 'react';
45
- import * as PIXI from 'pixi.js';
46
- // Re-export PIXI classes for convenience
47
- export { Container, Graphics, Text, Sprite } from 'pixi.js';
48
- /**
49
- * Tile dimensions - standard tile size
50
- */
51
- export const TILE_WIDTH = 256;
52
- export const TILE_HEIGHT = 554;
53
- const PixiContext = createContext(null);
54
- /**
55
- * Hook to get the PIXI Application
56
- */
57
- export function usePixiApp() {
58
- const context = useContext(PixiContext);
59
- if (!context) {
60
- throw new Error('usePixiApp must be used within a PixiGame component');
61
- }
62
- return context.app;
63
- }
64
- /**
65
- * Hook to get the PIXI Application (alias for backwards compatibility)
66
- */
67
- export function useApp() {
68
- return usePixiApp();
69
- }
70
- /**
71
- * useGameLoop - Run a callback every frame
72
- *
73
- * @param callback - Function called every frame with delta time (in frames, ~1 at 60fps)
74
- * @param enabled - Whether the loop is active (default: true)
75
- */
76
- export function useGameLoop(callback, enabled = true) {
77
- const context = useContext(PixiContext);
78
- const callbackRef = useRef(callback);
79
- callbackRef.current = callback;
80
- useEffect(() => {
81
- if (!context || !enabled)
82
- return;
83
- const wrappedCallback = (delta) => {
84
- callbackRef.current(delta);
85
- };
86
- return context.addTickerCallback(wrappedCallback);
87
- }, [context, enabled]);
88
- }
89
- /**
90
- * PixiGame - Main wrapper component for pixi.js games
91
- *
92
- * Creates a PIXI.Application and provides it via context.
93
- * Children can use usePixiApp() to access the app and create pixi objects.
94
- */
95
- export function PixiGame({ children, width = TILE_WIDTH, height = TILE_HEIGHT, background = 0x000000, options = {}, paused = false, onMount, }) {
96
- const containerRef = useRef(null);
97
- const appRef = useRef(null);
98
- const tickerCallbacksRef = useRef(new Set());
99
- const [isReady, setIsReady] = useState(false);
100
- // Create PIXI Application
101
- useEffect(() => {
102
- if (!containerRef.current)
103
- return;
104
- const app = new PIXI.Application({
105
- width,
106
- height,
107
- backgroundColor: background,
108
- antialias: options.antialias ?? true,
109
- resolution: options.resolution ?? (typeof window !== 'undefined' ? window.devicePixelRatio : 1),
110
- autoDensity: options.autoDensity ?? true,
111
- });
112
- containerRef.current.appendChild(app.view);
113
- appRef.current = app;
114
- // Add master ticker callback that calls all registered callbacks
115
- app.ticker.add((delta) => {
116
- for (const callback of tickerCallbacksRef.current) {
117
- callback(delta);
118
- }
119
- });
120
- setIsReady(true);
121
- onMount?.(app);
122
- return () => {
123
- setIsReady(false);
124
- tickerCallbacksRef.current.clear();
125
- app.destroy(true, { children: true, texture: true, baseTexture: true });
126
- appRef.current = null;
127
- };
128
- }, []); // Only run once on mount
129
- // Handle size changes
130
- useEffect(() => {
131
- if (appRef.current) {
132
- appRef.current.renderer.resize(width, height);
133
- }
134
- }, [width, height]);
135
- // Handle background color changes
136
- useEffect(() => {
137
- if (appRef.current) {
138
- appRef.current.renderer.background.color = background;
139
- }
140
- }, [background]);
141
- // Handle pause state
142
- useEffect(() => {
143
- if (appRef.current) {
144
- if (paused) {
145
- appRef.current.ticker.stop();
146
- }
147
- else {
148
- appRef.current.ticker.start();
149
- }
150
- }
151
- }, [paused]);
152
- // Context value with app and ticker registration
153
- const contextValue = {
154
- app: appRef.current,
155
- addTickerCallback: useCallback((callback) => {
156
- tickerCallbacksRef.current.add(callback);
157
- return () => {
158
- tickerCallbacksRef.current.delete(callback);
159
- };
160
- }, []),
161
- };
162
- return (React.createElement("div", { ref: containerRef, style: { width, height } }, isReady && (React.createElement(PixiContext.Provider, { value: contextValue }, children))));
163
- }
164
- /**
165
- * useGameState - Helper for managing game state with refs
166
- *
167
- * Returns a ref and a forceUpdate function for when you need to trigger re-renders.
168
- * Use refs for continuous game state (position, velocity) to avoid re-render loops.
169
- */
170
- export function useGameState(initialState) {
171
- const stateRef = useRef(initialState);
172
- const [, setTick] = useState(0);
173
- const forceUpdate = useCallback(() => {
174
- setTick((t) => t + 1);
175
- }, []);
176
- return [stateRef, forceUpdate];
177
- }
178
- /**
179
- * useGameInput - Simple keyboard input hook for games
180
- *
181
- * Returns a ref with currently pressed keys.
182
- */
183
- export function useGameInput() {
184
- const keysRef = useRef({});
185
- useEffect(() => {
186
- const handleKeyDown = (e) => {
187
- keysRef.current[e.key] = true;
188
- keysRef.current[e.code] = true;
189
- };
190
- const handleKeyUp = (e) => {
191
- keysRef.current[e.key] = false;
192
- keysRef.current[e.code] = false;
193
- };
194
- window.addEventListener('keydown', handleKeyDown);
195
- window.addEventListener('keyup', handleKeyUp);
196
- return () => {
197
- window.removeEventListener('keydown', handleKeyDown);
198
- window.removeEventListener('keyup', handleKeyUp);
199
- };
200
- }, []);
201
- return keysRef;
202
- }
203
- /**
204
- * useInitialized - Helper hook for tracking game object initialization
205
- *
206
- * Returns an initRef that should be set to true AFTER all game objects are
207
- * created in useEffect, and checked as the FIRST line in useGameLoop.
208
- *
209
- * @example
210
- * ```tsx
211
- * function GameContent() {
212
- * const app = usePixiApp();
213
- * const initRef = useInitialized();
214
- * const playerRef = useRef<PIXI.Graphics | null>(null);
215
- *
216
- * useEffect(() => {
217
- * if (!app) return;
218
- * const player = new PIXI.Graphics();
219
- * // ... setup player ...
220
- * playerRef.current = player;
221
- * initRef.current = true; // Set AFTER all refs are ready
222
- * return () => {
223
- * initRef.current = false;
224
- * player.destroy();
225
- * };
226
- * }, [app]);
227
- *
228
- * useGameLoop((delta) => {
229
- * if (!initRef.current || !playerRef.current) return; // REQUIRED!
230
- * // ... safe to use playerRef.current ...
231
- * });
232
- * }
233
- * ```
234
- */
235
- export function useInitialized() {
236
- return useRef(false);
237
- }