pixi-fusion 2.0.4 → 2.2.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.
@@ -1,6 +1,6 @@
1
1
  import React, { useCallback, useEffect, useMemo, useState } from "react";
2
- import { AssetsManagerContext } from "./AssetsManager.context";
3
2
  import { Assets } from "pixi.js";
3
+ import { AssetsManagerContext } from "./AssetsManager.context";
4
4
  export const AssetsManager = ({ children }) => {
5
5
  const [isFetching, setIsFetching] = useState(false);
6
6
  const [isFetched, setIsFetched] = useState(false);
@@ -6,6 +6,7 @@ export type GameContextValue = {
6
6
  readonly pause: () => void;
7
7
  readonly stop: () => void;
8
8
  readonly timeout: number;
9
+ readonly gameId: number;
9
10
  readonly status: GameStatus;
10
11
  readonly startTime: number | null;
11
12
  readonly pauseTime: number;
@@ -6,6 +6,7 @@ export const GameContext = createContext({
6
6
  start: () => { },
7
7
  stop: () => { },
8
8
  timeout: 0,
9
+ gameId: 0,
9
10
  status: GameStatus.READY,
10
11
  startTime: null,
11
12
  pauseTime: 0,
@@ -14,6 +15,7 @@ export const GameContext = createContext({
14
15
  export const GameContextProvider = ({ children, timeout: inputTimeout = 0, events }) => {
15
16
  const timerRef = useRef(null);
16
17
  const timeout = Math.max(0, inputTimeout);
18
+ const [gameId, setGemaId] = useState(0);
17
19
  const [status, setStatus] = useState(GameStatus.READY);
18
20
  const [startTime, setStartTime] = useState(null);
19
21
  const [endTime, setEndTime] = useState(null);
@@ -66,6 +68,7 @@ export const GameContextProvider = ({ children, timeout: inputTimeout = 0, event
66
68
  setEndTime(newEndTime);
67
69
  setPauseTime(newPauseTime);
68
70
  setPausedAtTime(newPausedAtTime);
71
+ setGemaId((current) => current++);
69
72
  if (timerRef.current) {
70
73
  clearTimeout(timerRef.current);
71
74
  }
@@ -118,7 +121,8 @@ export const GameContextProvider = ({ children, timeout: inputTimeout = 0, event
118
121
  stop,
119
122
  start,
120
123
  reset,
121
- pause
122
- }), [timeout, status, startTime, endTime, pauseTime, pause, reset, start, stop]);
124
+ pause,
125
+ gameId
126
+ }), [timeout, status, startTime, endTime, pauseTime, pause, reset, start, stop, gameId]);
123
127
  return React.createElement(GameContext.Provider, { value: contextValue }, children);
124
128
  };
@@ -1,6 +1,6 @@
1
1
  import { Body } from "matter-js";
2
- import { GameObjectPhysicalObjectConfig } from "./GameObjectPhysicalObjectConfig";
3
2
  import { Nullable } from "../types";
3
+ import { GameObjectPhysicalObjectConfig } from "./GameObjectPhysicalObjectConfig";
4
4
  export declare const usePhysicalObjectFromConfig: <PhysicalObjectType extends Nullable<Body> = Body>({ position, ...physicalObjectConfig }: GameObjectPhysicalObjectConfig) => {
5
5
  physicalObject: PhysicalObjectType;
6
6
  };
@@ -1,5 +1,5 @@
1
- import { useTickerCallback } from "./useTickerCallback";
2
1
  import { useCallback } from "react";
2
+ import { useTickerCallback } from "./useTickerCallback";
3
3
  export const useCollisionDetection = ({ objectA, objectB, onCollide, isEnabled }) => {
4
4
  const testForAABB = useCallback(() => {
5
5
  if (!objectA || !objectB) {
@@ -1,5 +1,5 @@
1
- import { useLayerContext } from "./useLayerContext";
2
1
  import { useEffect } from "react";
2
+ import { useLayerContext } from "./useLayerContext";
3
3
  export const useObject = ({ object, anchor, position, skew, scale, width, angle, alpha, visible = true }) => {
4
4
  const { addObject, removeObject } = useLayerContext();
5
5
  useEffect(() => {
@@ -1,5 +1,4 @@
1
1
  export * from "./game-context";
2
- export * from "./assets-manager";
3
2
  export * from "./world";
4
3
  export * from "./camera";
5
4
  export * from "./layer";
package/dist/src/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./game-context";
2
- export * from "./assets-manager";
3
2
  export * from "./world";
4
3
  export * from "./camera";
5
4
  export * from "./layer";
@@ -1,7 +1,7 @@
1
1
  import React, { useCallback, useEffect, useMemo, useState } from "react";
2
- import { StageContext } from "./Stage.context";
3
2
  import { useWorld } from "../hooks";
4
3
  import { Layer } from "../layer";
4
+ import { StageContext } from "./Stage.context";
5
5
  export const Stage = ({ children }) => {
6
6
  const { application } = useWorld();
7
7
  const [things, setThings] = useState([]);
@@ -1,21 +1,36 @@
1
- import React, { createRef, useEffect, useMemo, useState } from "react";
1
+ import React, { createRef, useCallback, useEffect, useLayoutEffect, useMemo, useState } from "react";
2
2
  import { Application } from "pixi.js";
3
- import { WorldContext } from "./World.context";
4
3
  import { Stage } from "../stage";
5
4
  import { AssetsManager } from "../assets-manager";
5
+ import { WorldContext } from "./World.context";
6
6
  export const World = ({ children, eventMode, size }) => {
7
7
  const canvasRef = createRef();
8
8
  const [applicationRef, setApplicationRef] = useState(null);
9
- const worldSize = useMemo(() => {
10
- if (size) {
11
- return { ...size };
12
- }
9
+ const [canvasSize, setCanvasSize] = useState(null);
10
+ const onCanvasRef = useCallback((ref) => {
11
+ const application = new Application();
12
+ application.init({ eventMode }).then(() => {
13
+ canvasRef.current = ref;
14
+ application.resizeTo = canvasRef.current;
15
+ application.resize();
16
+ setApplicationRef(application);
17
+ });
18
+ }, [canvasRef, eventMode]);
19
+ useLayoutEffect(() => {
13
20
  if (canvasRef?.current) {
14
21
  const { width, height } = canvasRef.current.getBoundingClientRect();
15
- return {
22
+ setCanvasSize({
16
23
  width,
17
24
  height
18
- };
25
+ });
26
+ }
27
+ }, [canvasRef]);
28
+ const worldSize = useMemo(() => {
29
+ if (size) {
30
+ return { ...size };
31
+ }
32
+ if (canvasSize) {
33
+ return canvasSize;
19
34
  }
20
35
  if (!applicationRef) {
21
36
  return {
@@ -24,24 +39,10 @@ export const World = ({ children, eventMode, size }) => {
24
39
  };
25
40
  }
26
41
  return {
27
- width: applicationRef.screen.width,
28
- height: applicationRef.screen.height
42
+ width: applicationRef?.screen.width,
43
+ height: applicationRef?.screen.height
29
44
  };
30
- }, [size, canvasRef, applicationRef]);
31
- useEffect(() => {
32
- if (!applicationRef) {
33
- const application = new Application();
34
- application.init().then(() => {
35
- setApplicationRef(application);
36
- });
37
- }
38
- }, [applicationRef]);
39
- useEffect(() => {
40
- if (applicationRef && canvasRef.current) {
41
- applicationRef.resizeTo = canvasRef.current;
42
- applicationRef.resize();
43
- }
44
- }, [canvasRef, applicationRef]);
45
+ }, [size, canvasSize, applicationRef]);
45
46
  const conextValue = useMemo(() => ({
46
47
  application: applicationRef,
47
48
  size: worldSize
@@ -58,13 +59,8 @@ export const World = ({ children, eventMode, size }) => {
58
59
  }
59
60
  };
60
61
  }, [canvasRef, applicationRef]);
61
- useEffect(() => {
62
- if (applicationRef) {
63
- applicationRef.stage.eventMode = eventMode;
64
- }
65
- }, [eventMode, applicationRef]);
66
62
  return (React.createElement(WorldContext.Provider, { value: conextValue },
67
63
  React.createElement(AssetsManager, null,
68
64
  React.createElement(Stage, null, children),
69
- React.createElement("div", { style: { width: "100%", height: "100%" }, ref: canvasRef }))));
65
+ React.createElement("div", { style: { width: "100%", height: "100%" }, ref: onCanvasRef }))));
70
66
  };
package/package.json CHANGED
@@ -5,22 +5,35 @@
5
5
  "url": "https://github.com/laverve/fusion/issues"
6
6
  },
7
7
  "dependencies": {
8
- "@types/matter-js": "^0.20.0",
8
+ "@types/matter-js": "^0.20.2",
9
9
  "matter-js": "^0.20.0",
10
- "pixi.js": "^8.8.0",
11
- "pixi-viewport": "^6.0.3"
10
+ "pixi-viewport": "^6.0.3",
11
+ "pixi.js": "^8.14.0"
12
12
  },
13
13
  "peerDependencies": {
14
- "react": "^19.0.0"
14
+ "react": "^19.x.x"
15
15
  },
16
16
  "devDependencies": {
17
- "@laverve/eslint-utils": "^5.1.11",
18
- "@laverve/test-utils": "^5.1.11",
19
- "@types/react": "^19.0.10",
20
- "husky": "9.1.7",
21
- "lint-staged": "^16.0.0",
22
- "ts-node": "^10.9.1",
23
- "typescript": "^5.7.3"
17
+ "@eslint-community/eslint-plugin-eslint-comments": "^4.5.0",
18
+ "@eslint/js": "9.39.1",
19
+ "@types/react": "^19.2.2",
20
+ "eslint": "^9.39.1",
21
+ "eslint-config-prettier": "^10.1.8",
22
+ "eslint-plugin-import": "^2.32.0",
23
+ "eslint-plugin-jest": "^29.0.1",
24
+ "eslint-plugin-jsonc": "^2.21.0",
25
+ "eslint-plugin-prettier": "^5.5.4",
26
+ "eslint-plugin-react": "^7.37.5",
27
+ "eslint-plugin-react-hooks": "^7.0.1",
28
+ "husky": "^9.1.7",
29
+ "jest": "^30.2.0",
30
+ "jest-watch-typeahead": "^3.0.1",
31
+ "lint-staged": "^16.2.6",
32
+ "react-app-polyfill": "^3.0.0",
33
+ "ts-jest": "^29.4.5",
34
+ "ts-node": "^10.9.2",
35
+ "typescript": "^5.9.3",
36
+ "typescript-eslint": "^8.46.3"
24
37
  },
25
38
  "description": "This module offers a set of common components needed for playing games.",
26
39
  "keywords": [
@@ -50,14 +63,14 @@
50
63
  "url": "https://github.com/laverve/fusion.git"
51
64
  },
52
65
  "scripts": {
53
- "lint": "eslint ./src/",
54
- "lint:fix": "eslint ./src/ --fix",
66
+ "lint": "eslint .",
67
+ "lint:fix": "eslint . --fix",
55
68
  "lint:staged": "lint-staged",
56
69
  "prepare": "husky",
57
70
  "test": "jest --passWithNoTests",
58
71
  "build": "tsc",
59
72
  "build:dev": "tsc -w"
60
73
  },
61
- "version": "2.0.4",
74
+ "version": "2.2.0",
62
75
  "webpack": "./src/index.ts"
63
76
  }
@@ -1,6 +1,6 @@
1
1
  import React, { PropsWithChildren, useCallback, useEffect, useMemo, useState } from "react";
2
- import { Asset, AssetsManagerContext, AssetsManagerContextValue } from "./AssetsManager.context";
3
2
  import { Assets } from "pixi.js";
3
+ import { Asset, AssetsManagerContext, AssetsManagerContextValue } from "./AssetsManager.context";
4
4
 
5
5
  export const AssetsManager: React.FC<PropsWithChildren> = ({ children }) => {
6
6
  const [isFetching, setIsFetching] = useState(false);
@@ -7,6 +7,7 @@ export type GameContextValue = {
7
7
  readonly pause: () => void;
8
8
  readonly stop: () => void;
9
9
  readonly timeout: number;
10
+ readonly gameId: number;
10
11
  readonly status: GameStatus;
11
12
  readonly startTime: number | null;
12
13
  readonly pauseTime: number;
@@ -27,6 +28,7 @@ export const GameContext = createContext<GameContextValue>({
27
28
  start: () => {},
28
29
  stop: () => {},
29
30
  timeout: 0,
31
+ gameId: 0,
30
32
  status: GameStatus.READY,
31
33
  startTime: null,
32
34
  pauseTime: 0,
@@ -45,6 +47,7 @@ export const GameContextProvider: React.FC<GameContextProviderProps> = ({
45
47
  }) => {
46
48
  const timerRef = useRef<NodeJS.Timeout>(null);
47
49
  const timeout = Math.max(0, inputTimeout);
50
+ const [gameId, setGemaId] = useState(0);
48
51
 
49
52
  const [status, setStatus] = useState(GameStatus.READY);
50
53
  const [startTime, setStartTime] = useState<number | null>(null);
@@ -107,6 +110,7 @@ export const GameContextProvider: React.FC<GameContextProviderProps> = ({
107
110
  setEndTime(newEndTime);
108
111
  setPauseTime(newPauseTime);
109
112
  setPausedAtTime(newPausedAtTime);
113
+ setGemaId((current) => current++);
110
114
 
111
115
  if (timerRef.current) {
112
116
  clearTimeout(timerRef.current);
@@ -169,9 +173,10 @@ export const GameContextProvider: React.FC<GameContextProviderProps> = ({
169
173
  stop,
170
174
  start,
171
175
  reset,
172
- pause
176
+ pause,
177
+ gameId
173
178
  }),
174
- [timeout, status, startTime, endTime, pauseTime, pause, reset, start, stop]
179
+ [timeout, status, startTime, endTime, pauseTime, pause, reset, start, stop, gameId]
175
180
  );
176
181
 
177
182
  return <GameContext.Provider value={contextValue}>{children}</GameContext.Provider>;
@@ -1,8 +1,8 @@
1
1
  import { Body } from "matter-js";
2
2
  import { useMemo } from "react";
3
+ import { Nullable } from "../types";
3
4
  import { GameObjectPhysicalObjectConfig } from "./GameObjectPhysicalObjectConfig";
4
5
  import { usePhysicalObject } from "./usePhysicalObject";
5
- import { Nullable } from "../types";
6
6
 
7
7
  export const usePhysicalObjectFromConfig = <PhysicalObjectType extends Nullable<Body> = Body>({
8
8
  position = { x: 0, y: 0 },
@@ -1,6 +1,6 @@
1
1
  import { Container } from "pixi.js";
2
- import { useTickerCallback } from "./useTickerCallback";
3
2
  import { useCallback } from "react";
3
+ import { useTickerCallback } from "./useTickerCallback";
4
4
 
5
5
  type UseCollisionDetectionOptions = {
6
6
  objectA?: Container | null;
@@ -1,6 +1,6 @@
1
1
  import { Sprite, SpriteOptions, TilingSprite } from "pixi.js";
2
- import { useLayerContext } from "./useLayerContext";
3
2
  import { useEffect } from "react";
3
+ import { useLayerContext } from "./useLayerContext";
4
4
 
5
5
  type UseObjectOptions = Omit<SpriteOptions, "texture"> & {
6
6
  object: Sprite | TilingSprite | null;
package/src/index.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./game-context";
2
- export * from "./assets-manager";
3
2
  export * from "./world";
4
3
  export * from "./camera";
5
4
  export * from "./layer";
@@ -1,8 +1,8 @@
1
1
  import React, { PropsWithChildren, useCallback, useEffect, useMemo, useState } from "react";
2
2
  import { Container } from "pixi.js";
3
- import { StageContext, StageContextValue } from "./Stage.context";
4
3
  import { useWorld } from "../hooks";
5
4
  import { Layer } from "../layer";
5
+ import { StageContext, StageContextValue } from "./Stage.context";
6
6
 
7
7
  export const Stage: React.FC<PropsWithChildren> = ({ children }) => {
8
8
  const { application } = useWorld();
@@ -1,8 +1,8 @@
1
- import React, { PropsWithChildren, createRef, useEffect, useMemo, useState } from "react";
1
+ import React, { PropsWithChildren, createRef, useCallback, useEffect, useLayoutEffect, useMemo, useState } from "react";
2
2
  import { Application, EventMode } from "pixi.js";
3
- import { WorldContextValue, WorldContext } from "./World.context";
4
3
  import { Stage } from "../stage";
5
4
  import { AssetsManager } from "../assets-manager";
5
+ import { WorldContextValue, WorldContext } from "./World.context";
6
6
 
7
7
  type WorldProps = {
8
8
  eventMode?: EventMode;
@@ -17,17 +17,38 @@ export const World: React.FC<PropsWithChildren & WorldProps> = ({ children, even
17
17
 
18
18
  const [applicationRef, setApplicationRef] = useState<Application | null>(null);
19
19
 
20
- const worldSize = useMemo(() => {
21
- if (size) {
22
- return { ...size };
23
- }
20
+ const [canvasSize, setCanvasSize] = useState<null | { width: number; height: number }>(null);
21
+
22
+ const onCanvasRef = useCallback(
23
+ (ref: HTMLDivElement) => {
24
+ const application = new Application();
25
+ application.init({ eventMode }).then(() => {
26
+ canvasRef.current = ref;
27
+ application.resizeTo = canvasRef.current;
28
+ application.resize();
29
+ setApplicationRef(application);
30
+ });
31
+ },
32
+ [canvasRef, eventMode]
33
+ );
24
34
 
35
+ useLayoutEffect(() => {
25
36
  if (canvasRef?.current) {
26
37
  const { width, height } = canvasRef.current.getBoundingClientRect();
27
- return {
38
+ setCanvasSize({
28
39
  width,
29
40
  height
30
- };
41
+ });
42
+ }
43
+ }, [canvasRef]);
44
+
45
+ const worldSize = useMemo(() => {
46
+ if (size) {
47
+ return { ...size };
48
+ }
49
+
50
+ if (canvasSize) {
51
+ return canvasSize;
31
52
  }
32
53
 
33
54
  if (!applicationRef) {
@@ -38,26 +59,10 @@ export const World: React.FC<PropsWithChildren & WorldProps> = ({ children, even
38
59
  }
39
60
 
40
61
  return {
41
- width: applicationRef.screen.width,
42
- height: applicationRef.screen.height
62
+ width: applicationRef?.screen.width,
63
+ height: applicationRef?.screen.height
43
64
  };
44
- }, [size, canvasRef, applicationRef]);
45
-
46
- useEffect(() => {
47
- if (!applicationRef) {
48
- const application = new Application();
49
- application.init().then(() => {
50
- setApplicationRef(application);
51
- });
52
- }
53
- }, [applicationRef]);
54
-
55
- useEffect(() => {
56
- if (applicationRef && canvasRef.current) {
57
- applicationRef.resizeTo = canvasRef.current;
58
- applicationRef.resize();
59
- }
60
- }, [canvasRef, applicationRef]);
65
+ }, [size, canvasSize, applicationRef]);
61
66
 
62
67
  const conextValue = useMemo<WorldContextValue>(
63
68
  () => ({
@@ -81,17 +86,11 @@ export const World: React.FC<PropsWithChildren & WorldProps> = ({ children, even
81
86
  };
82
87
  }, [canvasRef, applicationRef]);
83
88
 
84
- useEffect(() => {
85
- if (applicationRef) {
86
- applicationRef.stage.eventMode = eventMode;
87
- }
88
- }, [eventMode, applicationRef]);
89
-
90
89
  return (
91
90
  <WorldContext.Provider value={conextValue}>
92
91
  <AssetsManager>
93
92
  <Stage>{children}</Stage>
94
- <div style={{ width: "100%", height: "100%" }} ref={canvasRef} />
93
+ <div style={{ width: "100%", height: "100%" }} ref={onCanvasRef} />
95
94
  </AssetsManager>
96
95
  </WorldContext.Provider>
97
96
  );