react-three-game 0.0.14 → 0.0.15

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 CHANGED
@@ -64,7 +64,7 @@ npm install react-three-game @react-three/fiber @react-three/rapier three
64
64
  ```
65
65
 
66
66
  ```jsx
67
- import { GameCanvas, PrefabRoot } from 'react-three-game';
67
+ import { GameCanvas, PrefabRoot, ground } from 'react-three-game';
68
68
 
69
69
  export default function App() {
70
70
  return (
@@ -78,15 +78,13 @@ export default function App() {
78
78
  transform: { type: "Transform", properties: { position: [0, 0, 0] } }
79
79
  },
80
80
  children: [
81
- {
81
+ ground({
82
82
  id: "floor",
83
- components: {
84
- transform: { type: "Transform", properties: { position: [0, -1, 0] } },
85
- geometry: { type: "Geometry", properties: { geometryType: "box", args: [10, 0.5, 10] } },
86
- material: { type: "Material", properties: { color: "#2d5f2e" } },
87
- physics: { type: "Physics", properties: { type: "fixed" } }
88
- }
89
- },
83
+ position: [0, -1, 0],
84
+ size: 50,
85
+ texture: "/textures/GreyboxTextures/greybox_light_grid.png",
86
+ repeatCount: [25, 25]
87
+ }),
90
88
  {
91
89
  id: "player",
92
90
  components: {
@@ -109,8 +107,8 @@ export default function App() {
109
107
  ```typescript
110
108
  interface GameObject {
111
109
  id: string;
112
- enabled?: boolean;
113
- visible?: boolean;
110
+ disabled?: boolean;
111
+ hidden?: boolean;
114
112
  components: {
115
113
  transform?: TransformComponent;
116
114
  geometry?: GeometryComponent;
@@ -0,0 +1,35 @@
1
+ import type { GameObject } from "../tools/prefabeditor/types";
2
+ export type Vec3 = [number, number, number];
3
+ export interface GroundOptions {
4
+ /** GameObject id. Defaults to "ground". */
5
+ id?: string;
6
+ /** Plane size. Defaults to 50. */
7
+ size?: number;
8
+ /** Transform overrides. */
9
+ position?: Vec3;
10
+ rotation?: Vec3;
11
+ scale?: Vec3;
12
+ /** Material overrides. */
13
+ color?: string;
14
+ texture?: string;
15
+ /** When true, set repeat wrapping. Defaults to true if texture is provided. */
16
+ repeat?: boolean;
17
+ /** Texture repeat counts when repeat=true. Defaults to [25,25]. */
18
+ repeatCount?: [number, number];
19
+ /** Physics body type. Defaults to "fixed". */
20
+ physicsType?: "fixed" | "dynamic" | "kinematic";
21
+ /** Set true to hide the node. */
22
+ hidden?: boolean;
23
+ /** Set true to disable the node. */
24
+ disabled?: boolean;
25
+ }
26
+ /**
27
+ * Create a ready-to-use plane ground GameObject.
28
+ *
29
+ * Designed to reduce prefab boilerplate:
30
+ * - Transform (rotated to lie flat)
31
+ * - Geometry (plane)
32
+ * - Material (optional texture + repeat)
33
+ * - Physics (fixed by default)
34
+ */
35
+ export declare function ground(options?: GroundOptions): GameObject;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Create a ready-to-use plane ground GameObject.
3
+ *
4
+ * Designed to reduce prefab boilerplate:
5
+ * - Transform (rotated to lie flat)
6
+ * - Geometry (plane)
7
+ * - Material (optional texture + repeat)
8
+ * - Physics (fixed by default)
9
+ */
10
+ export function ground(options = {}) {
11
+ const { id = "ground", size = 50, position = [0, 0, 0], rotation = [-Math.PI / 2, 0, 0], scale = [1, 1, 1], color = "white", texture, repeat = texture ? true : false, repeatCount = [25, 25], physicsType = "fixed", hidden = false, disabled = false, } = options;
12
+ return {
13
+ id,
14
+ disabled,
15
+ hidden,
16
+ components: {
17
+ transform: {
18
+ type: "Transform",
19
+ properties: {
20
+ position,
21
+ rotation,
22
+ scale,
23
+ },
24
+ },
25
+ geometry: {
26
+ type: "Geometry",
27
+ properties: {
28
+ geometryType: "plane",
29
+ args: [size, size],
30
+ },
31
+ },
32
+ material: {
33
+ type: "Material",
34
+ properties: Object.assign(Object.assign({ color }, (texture ? { texture } : {})), (repeat ? { repeat: true, repeatCount } : {})),
35
+ },
36
+ physics: {
37
+ type: "Physics",
38
+ properties: {
39
+ type: physicsType,
40
+ },
41
+ },
42
+ },
43
+ };
44
+ }
package/dist/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export { default as PrefabEditor } from './tools/prefabeditor/PrefabEditor';
3
3
  export { default as PrefabRoot } from './tools/prefabeditor/PrefabRoot';
4
4
  export { DragDropLoader } from './tools/dragdrop/DragDropLoader';
5
5
  export { TextureListViewer, ModelListViewer, SoundListViewer, SharedCanvas, } from './tools/assetviewer/page';
6
+ export * from './helpers';
6
7
  export type { Prefab, GameObject } from './tools/prefabeditor/types';
package/dist/index.js CHANGED
@@ -4,3 +4,5 @@ export { default as PrefabEditor } from './tools/prefabeditor/PrefabEditor';
4
4
  export { default as PrefabRoot } from './tools/prefabeditor/PrefabRoot';
5
5
  export { DragDropLoader } from './tools/dragdrop/DragDropLoader';
6
6
  export { TextureListViewer, ModelListViewer, SoundListViewer, SharedCanvas, } from './tools/assetviewer/page';
7
+ // Helpers
8
+ export * from './helpers';
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
3
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
4
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -18,7 +19,7 @@ var __rest = (this && this.__rest) || function (s, e) {
18
19
  }
19
20
  return t;
20
21
  };
21
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
22
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
22
23
  import { Canvas, extend } from "@react-three/fiber";
23
24
  import { WebGPURenderer, MeshBasicNodeMaterial, MeshStandardNodeMaterial, SpriteNodeMaterial, PCFShadowMap } from "three/webgpu";
24
25
  import { Suspense, useState } from "react";
@@ -33,16 +34,15 @@ extend({
33
34
  export default function GameCanvas(_a) {
34
35
  var { loader = false, children } = _a, props = __rest(_a, ["loader", "children"]);
35
36
  const [frameloop, setFrameloop] = useState("never");
36
- const [loading, setLoading] = useState(true);
37
- return _jsxs(_Fragment, { children: [_jsx(Canvas, { shadows: { type: PCFShadowMap, }, frameloop: frameloop, gl: (_a) => __awaiter(this, [_a], void 0, function* ({ canvas }) {
38
- const renderer = new WebGPURenderer(Object.assign({ canvas: canvas,
39
- // @ts-expect-error futuristic
40
- shadowMap: true, antialias: true }, props));
41
- yield renderer.init().then(() => {
42
- setFrameloop("always");
43
- });
44
- return renderer;
45
- }), camera: {
46
- position: [0, 1, 5],
47
- }, children: _jsx(Suspense, { children: children }) }), loader ? _jsx(Loader, {}) : null] });
37
+ return _jsx(_Fragment, { children: _jsxs(Canvas, { style: { touchAction: 'none' }, shadows: { type: PCFShadowMap, }, frameloop: frameloop, gl: (_a) => __awaiter(this, [_a], void 0, function* ({ canvas }) {
38
+ const renderer = new WebGPURenderer(Object.assign({ canvas: canvas,
39
+ // @ts-expect-error futuristic
40
+ shadowMap: true, antialias: true }, props));
41
+ yield renderer.init().then(() => {
42
+ setFrameloop("always");
43
+ });
44
+ return renderer;
45
+ }), camera: {
46
+ position: [0, 1, 5],
47
+ }, children: [_jsx(Suspense, { children: children }), loader ? _jsx(Loader, {}) : null] }) });
48
48
  }
@@ -30,8 +30,6 @@ export default function EditorTree({ prefabData, setPrefabData, selectedId, setS
30
30
  var _a;
31
31
  const newNode = {
32
32
  id: crypto.randomUUID(),
33
- enabled: true,
34
- visible: true,
35
33
  components: {
36
34
  transform: {
37
35
  type: "Transform",
@@ -21,8 +21,6 @@ const PrefabEditor = ({ basePath, initialPrefab, onPrefabChange, children }) =>
21
21
  "name": "New Prefab",
22
22
  "root": {
23
23
  "id": "root",
24
- "enabled": true,
25
- "visible": true,
26
24
  "components": {
27
25
  "transform": {
28
26
  "type": "Transform",
@@ -49,13 +49,6 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
49
49
  setSelectedObject(null);
50
50
  }
51
51
  }, [selectedId]);
52
- // const [transformMode, setTransformMode] = useState<"translate" | "rotate" | "scale">("translate"); // Removed local state
53
- const updateNode = (updater) => {
54
- if (!selectedId || !onPrefabChange)
55
- return;
56
- const newRoot = updatePrefabNode(data.root, selectedId, updater);
57
- onPrefabChange(Object.assign(Object.assign({}, data), { root: newRoot }));
58
- };
59
52
  const onTransformChange = () => {
60
53
  if (!selectedId || !onPrefabChange)
61
54
  return;
@@ -158,7 +151,7 @@ function GameObjectRenderer({ gameObject, selectedId, onSelect, registerRef, loa
158
151
  }
159
152
  clickValid.current = false;
160
153
  };
161
- if (!gameObject.enabled || !gameObject.visible)
154
+ if (gameObject.disabled === true || gameObject.hidden === true)
162
155
  return null;
163
156
  // --- 2. If instanced, short-circuit to a tiny clean branch ---
164
157
  const isInstanced = !!((_c = (_b = (_a = gameObject.components) === null || _a === void 0 ? void 0 : _a.model) === null || _b === void 0 ? void 0 : _b.properties) === null || _c === void 0 ? void 0 : _c.instanced);
@@ -170,8 +163,6 @@ function GameObjectRenderer({ gameObject, selectedId, onSelect, registerRef, loa
170
163
  // --- 5. Render children (always relative transforms) ---
171
164
  const children = ((_d = gameObject.children) !== null && _d !== void 0 ? _d : []).map((child) => (_jsx(GameObjectRenderer, { gameObject: child, selectedId: selectedId, onSelect: onSelect, registerRef: registerRef, loadedModels: loadedModels, loadedTextures: loadedTextures, editMode: editMode, parentMatrix: worldMatrix }, child.id)));
172
165
  // --- 4. Wrap with physics if needed ---
173
- // Only wrap the core content (geometry/model), not children
174
- // Children should be siblings, not inside the physics body
175
166
  const physicsWrapped = wrapPhysicsIfNeeded(gameObject, core, ctx);
176
167
  // --- 6. Final group wrapper ---
177
168
  return (_jsxs("group", { ref: (el) => registerRef(gameObject.id, el), position: transformProps.position, rotation: transformProps.rotation, scale: transformProps.scale, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp, children: [physicsWrapped, children] }));
@@ -12,8 +12,8 @@ export interface Prefab {
12
12
  }
13
13
  export interface GameObject {
14
14
  id: string;
15
- enabled: boolean;
16
- visible: boolean;
15
+ disabled?: boolean;
16
+ hidden?: boolean;
17
17
  ref?: any;
18
18
  children?: GameObject[];
19
19
  components?: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-three-game",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "description": "Batteries included React Three Fiber game engine",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -15,8 +15,11 @@
15
15
  "author": "prnth",
16
16
  "license": "VPL",
17
17
  "type": "module",
18
+ "workspaces": ["docs"],
18
19
  "peerDependencies": {
19
20
  "@react-three/fiber": "^9.0.0",
21
+ "@react-three/drei": "^10.0.0",
22
+ "@react-three/rapier": "^2.0.0",
20
23
  "react": "^18.0.0 || ^19.0.0",
21
24
  "react-dom": "^18.0.0 || ^19.0.0",
22
25
  "three": "^0.181.0"
@@ -0,0 +1,95 @@
1
+ import type { GameObject } from "../tools/prefabeditor/types";
2
+
3
+ export type Vec3 = [number, number, number];
4
+
5
+ export interface GroundOptions {
6
+ /** GameObject id. Defaults to "ground". */
7
+ id?: string;
8
+
9
+ /** Plane size. Defaults to 50. */
10
+ size?: number;
11
+
12
+ /** Transform overrides. */
13
+ position?: Vec3;
14
+ rotation?: Vec3;
15
+ scale?: Vec3;
16
+
17
+ /** Material overrides. */
18
+ color?: string;
19
+ texture?: string;
20
+ /** When true, set repeat wrapping. Defaults to true if texture is provided. */
21
+ repeat?: boolean;
22
+ /** Texture repeat counts when repeat=true. Defaults to [25,25]. */
23
+ repeatCount?: [number, number];
24
+
25
+ /** Physics body type. Defaults to "fixed". */
26
+ physicsType?: "fixed" | "dynamic" | "kinematic";
27
+
28
+ /** Set true to hide the node. */
29
+ hidden?: boolean;
30
+ /** Set true to disable the node. */
31
+ disabled?: boolean;
32
+ }
33
+
34
+ /**
35
+ * Create a ready-to-use plane ground GameObject.
36
+ *
37
+ * Designed to reduce prefab boilerplate:
38
+ * - Transform (rotated to lie flat)
39
+ * - Geometry (plane)
40
+ * - Material (optional texture + repeat)
41
+ * - Physics (fixed by default)
42
+ */
43
+ export function ground(options: GroundOptions = {}): GameObject {
44
+ const {
45
+ id = "ground",
46
+ size = 50,
47
+ position = [0, 0, 0],
48
+ rotation = [-Math.PI / 2, 0, 0],
49
+ scale = [1, 1, 1],
50
+ color = "white",
51
+ texture,
52
+ repeat = texture ? true : false,
53
+ repeatCount = [25, 25],
54
+ physicsType = "fixed",
55
+ hidden = false,
56
+ disabled = false,
57
+ } = options;
58
+
59
+ return {
60
+ id,
61
+ disabled,
62
+ hidden,
63
+ components: {
64
+ transform: {
65
+ type: "Transform",
66
+ properties: {
67
+ position,
68
+ rotation,
69
+ scale,
70
+ },
71
+ },
72
+ geometry: {
73
+ type: "Geometry",
74
+ properties: {
75
+ geometryType: "plane",
76
+ args: [size, size],
77
+ },
78
+ },
79
+ material: {
80
+ type: "Material",
81
+ properties: {
82
+ color,
83
+ ...(texture ? { texture } : {}),
84
+ ...(repeat ? { repeat: true, repeatCount } : {}),
85
+ },
86
+ },
87
+ physics: {
88
+ type: "Physics",
89
+ properties: {
90
+ type: physicsType,
91
+ },
92
+ },
93
+ },
94
+ };
95
+ }
package/src/index.ts CHANGED
@@ -10,5 +10,8 @@ export {
10
10
  SharedCanvas,
11
11
  } from './tools/assetviewer/page';
12
12
 
13
+ // Helpers
14
+ export * from './helpers';
15
+
13
16
  // Types
14
17
  export type { Prefab, GameObject } from './tools/prefabeditor/types';
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import { Canvas, extend } from "@react-three/fiber";
2
4
  import { WebGPURenderer, MeshBasicNodeMaterial, MeshStandardNodeMaterial, SpriteNodeMaterial, PCFShadowMap } from "three/webgpu";
3
5
  import { Suspense, useState } from "react";
@@ -16,10 +18,10 @@ extend({
16
18
 
17
19
  export default function GameCanvas({ loader = false, children, ...props }: { loader?: boolean, children: React.ReactNode, props?: WebGPURendererParameters }) {
18
20
  const [frameloop, setFrameloop] = useState<"never" | "always">("never");
19
- const [loading, setLoading] = useState(true);
20
21
 
21
22
  return <>
22
23
  <Canvas
24
+ style={{ touchAction: 'none' }}
23
25
  shadows={{ type: PCFShadowMap, }}
24
26
  frameloop={frameloop}
25
27
  gl={async ({ canvas }) => {
@@ -42,7 +44,8 @@ export default function GameCanvas({ loader = false, children, ...props }: { loa
42
44
  <Suspense>
43
45
  {children}
44
46
  </Suspense>
47
+
48
+ {loader ? <Loader /> : null}
45
49
  </Canvas>
46
- {loader ? <Loader /> : null}
47
50
  </>;
48
51
  }
@@ -39,8 +39,6 @@ export default function EditorTree({ prefabData, setPrefabData, selectedId, setS
39
39
  const handleAddChild = (parentId: string) => {
40
40
  const newNode: GameObject = {
41
41
  id: crypto.randomUUID(),
42
- enabled: true,
43
- visible: true,
44
42
  components: {
45
43
  transform: {
46
44
  type: "Transform",
@@ -15,8 +15,6 @@ const PrefabEditor = ({ basePath, initialPrefab, onPrefabChange, children }: { b
15
15
  "name": "New Prefab",
16
16
  "root": {
17
17
  "id": "root",
18
- "enabled": true,
19
- "visible": true,
20
18
  "components": {
21
19
  "transform": {
22
20
  "type": "Transform",
@@ -59,15 +59,6 @@ export const PrefabRoot = forwardRef<Group, {
59
59
  }
60
60
  }, [selectedId]);
61
61
 
62
-
63
- // const [transformMode, setTransformMode] = useState<"translate" | "rotate" | "scale">("translate"); // Removed local state
64
-
65
- const updateNode = (updater: (node: GameObjectType) => GameObjectType) => {
66
- if (!selectedId || !onPrefabChange) return;
67
- const newRoot = updatePrefabNode(data.root, selectedId, updater);
68
- onPrefabChange({ ...data, root: newRoot });
69
- };
70
-
71
62
  const onTransformChange = () => {
72
63
  if (!selectedId || !onPrefabChange) return;
73
64
  const obj = objectRefs.current[selectedId];
@@ -167,7 +158,7 @@ export const PrefabRoot = forwardRef<Group, {
167
158
  loadedModels={loadedModels}
168
159
  loadedTextures={loadedTextures}
169
160
  editMode={editMode}
170
- parentMatrix={new Matrix4()} // 👈 identity = world root
161
+ parentMatrix={new Matrix4()}
171
162
  />
172
163
  </GameInstanceProvider>
173
164
 
@@ -242,7 +233,7 @@ function GameObjectRenderer({
242
233
  clickValid.current = false;
243
234
  };
244
235
 
245
- if (!gameObject.enabled || !gameObject.visible) return null;
236
+ if (gameObject.disabled === true || gameObject.hidden === true) return null;
246
237
 
247
238
  // --- 2. If instanced, short-circuit to a tiny clean branch ---
248
239
  const isInstanced = !!gameObject.components?.model?.properties?.instanced;
@@ -269,8 +260,6 @@ function GameObjectRenderer({
269
260
  ));
270
261
 
271
262
  // --- 4. Wrap with physics if needed ---
272
- // Only wrap the core content (geometry/model), not children
273
- // Children should be siblings, not inside the physics body
274
263
  const physicsWrapped = wrapPhysicsIfNeeded(gameObject, core, ctx);
275
264
 
276
265
  // --- 6. Final group wrapper ---
@@ -13,8 +13,8 @@ export interface Prefab {
13
13
 
14
14
  export interface GameObject {
15
15
  id: string;
16
- enabled: boolean;
17
- visible: boolean;
16
+ disabled?: boolean;
17
+ hidden?: boolean;
18
18
  ref?: any;
19
19
  children?: GameObject[];
20
20
  components?: {