react-three-game 0.0.46 → 0.0.47
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/.gitmodules +3 -0
- package/README.md +5 -0
- package/dist/index.d.ts +1 -0
- package/dist/tools/prefabeditor/PrefabEditor.js +4 -13
- package/dist/tools/prefabeditor/utils.d.ts +20 -0
- package/dist/tools/prefabeditor/utils.js +51 -0
- package/package.json +1 -1
- package/react-three-game-skill/.gitattributes +2 -0
- package/{skill → react-three-game-skill/react-three-game}/SKILL.md +126 -8
- package/src/index.ts +1 -0
- package/src/tools/prefabeditor/PrefabEditor.tsx +4 -19
- package/src/tools/prefabeditor/utils.ts +69 -0
- package/skill/package.json +0 -17
package/.gitmodules
ADDED
package/README.md
CHANGED
|
@@ -9,6 +9,11 @@ npm i react-three-game @react-three/fiber @react-three/rapier three
|
|
|
9
9
|

|
|
10
10
|

|
|
11
11
|
|
|
12
|
+
## Agent Skill
|
|
13
|
+
```bash
|
|
14
|
+
npx skills add https://github.com/prnthh/react-three-game-skill
|
|
15
|
+
```
|
|
16
|
+
|
|
12
17
|
## Usage
|
|
13
18
|
|
|
14
19
|
```jsx
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { default as PrefabRoot } from './tools/prefabeditor/PrefabRoot';
|
|
|
6
6
|
export { registerComponent } from './tools/prefabeditor/components/ComponentRegistry';
|
|
7
7
|
export { FieldRenderer, Input, Label, Vector3Input, ColorInput, StringInput, BooleanInput, SelectInput, } from './tools/prefabeditor/components/Input';
|
|
8
8
|
export * from './tools/prefabeditor/utils';
|
|
9
|
+
export type { ExportGLBOptions } from './tools/prefabeditor/utils';
|
|
9
10
|
export type { PrefabEditorRef } from './tools/prefabeditor/PrefabEditor';
|
|
10
11
|
export type { PrefabRootRef } from './tools/prefabeditor/PrefabRoot';
|
|
11
12
|
export type { Component } from './tools/prefabeditor/components/ComponentRegistry';
|
|
@@ -6,7 +6,7 @@ import { Physics } from "@react-three/rapier";
|
|
|
6
6
|
import EditorUI from "./EditorUI";
|
|
7
7
|
import { base, toolbar } from "./styles";
|
|
8
8
|
import { EditorContext } from "./EditorContext";
|
|
9
|
-
import {
|
|
9
|
+
import { exportGLB } from "./utils";
|
|
10
10
|
const DEFAULT_PREFAB = {
|
|
11
11
|
id: "prefab-default",
|
|
12
12
|
name: "New Prefab",
|
|
@@ -102,18 +102,9 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, onPrefabChange, chil
|
|
|
102
102
|
const sceneRoot = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root;
|
|
103
103
|
if (!sceneRoot)
|
|
104
104
|
return;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const url = URL.createObjectURL(blob);
|
|
109
|
-
const a = document.createElement('a');
|
|
110
|
-
a.href = url;
|
|
111
|
-
a.download = `${loadedPrefab.name || 'scene'}.glb`;
|
|
112
|
-
a.click();
|
|
113
|
-
URL.revokeObjectURL(url);
|
|
114
|
-
}, (error) => {
|
|
115
|
-
console.error('Error exporting GLB:', error);
|
|
116
|
-
}, { binary: true });
|
|
105
|
+
exportGLB(sceneRoot, {
|
|
106
|
+
filename: `${loadedPrefab.name || 'scene'}.glb`
|
|
107
|
+
});
|
|
117
108
|
};
|
|
118
109
|
useEffect(() => {
|
|
119
110
|
const canvas = document.querySelector('canvas');
|
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
import { GameObject, Prefab } from "./types";
|
|
2
|
+
import { Object3D } from 'three';
|
|
3
|
+
export interface ExportGLBOptions {
|
|
4
|
+
filename?: string;
|
|
5
|
+
binary?: boolean;
|
|
6
|
+
onComplete?: (result: ArrayBuffer | object) => void;
|
|
7
|
+
onError?: (error: any) => void;
|
|
8
|
+
}
|
|
2
9
|
/** Save a prefab as JSON file */
|
|
3
10
|
export declare function saveJson(data: Prefab, filename: string): void;
|
|
4
11
|
/** Load a prefab from JSON file */
|
|
5
12
|
export declare function loadJson(): Promise<Prefab | undefined>;
|
|
13
|
+
/**
|
|
14
|
+
* Export a Three.js scene or object to GLB format
|
|
15
|
+
* @param sceneRoot - The Three.js Object3D to export
|
|
16
|
+
* @param options - Export options
|
|
17
|
+
* @returns Promise that resolves when export is complete
|
|
18
|
+
*/
|
|
19
|
+
export declare function exportGLB(sceneRoot: Object3D, options?: ExportGLBOptions): Promise<ArrayBuffer | object>;
|
|
20
|
+
/**
|
|
21
|
+
* Export a Three.js scene to GLB and return the ArrayBuffer without downloading
|
|
22
|
+
* @param sceneRoot - The Three.js Object3D to export
|
|
23
|
+
* @returns Promise that resolves with the GLB data as ArrayBuffer
|
|
24
|
+
*/
|
|
25
|
+
export declare function exportGLBData(sceneRoot: Object3D): Promise<ArrayBuffer>;
|
|
6
26
|
/** Find a node by ID in the tree */
|
|
7
27
|
export declare function findNode(root: GameObject, id: string): GameObject | null;
|
|
8
28
|
/** Find the parent of a node by ID */
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
|
|
1
11
|
/** Save a prefab as JSON file */
|
|
2
12
|
export function saveJson(data, filename) {
|
|
3
13
|
const a = document.createElement('a');
|
|
@@ -34,6 +44,47 @@ export function loadJson() {
|
|
|
34
44
|
input.click();
|
|
35
45
|
});
|
|
36
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Export a Three.js scene or object to GLB format
|
|
49
|
+
* @param sceneRoot - The Three.js Object3D to export
|
|
50
|
+
* @param options - Export options
|
|
51
|
+
* @returns Promise that resolves when export is complete
|
|
52
|
+
*/
|
|
53
|
+
export function exportGLB(sceneRoot, options = {}) {
|
|
54
|
+
const { filename = 'scene.glb', binary = true, onComplete, onError } = options;
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
const exporter = new GLTFExporter();
|
|
57
|
+
exporter.parse(sceneRoot, (result) => {
|
|
58
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete(result);
|
|
59
|
+
resolve(result);
|
|
60
|
+
// Trigger download if filename is provided
|
|
61
|
+
if (filename) {
|
|
62
|
+
const blob = new Blob([result], { type: binary ? 'application/octet-stream' : 'application/json' });
|
|
63
|
+
const url = URL.createObjectURL(blob);
|
|
64
|
+
const a = document.createElement('a');
|
|
65
|
+
a.href = url;
|
|
66
|
+
a.download = filename;
|
|
67
|
+
a.click();
|
|
68
|
+
URL.revokeObjectURL(url);
|
|
69
|
+
}
|
|
70
|
+
}, (error) => {
|
|
71
|
+
console.error('Error exporting GLB:', error);
|
|
72
|
+
onError === null || onError === void 0 ? void 0 : onError(error);
|
|
73
|
+
reject(error);
|
|
74
|
+
}, { binary });
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Export a Three.js scene to GLB and return the ArrayBuffer without downloading
|
|
79
|
+
* @param sceneRoot - The Three.js Object3D to export
|
|
80
|
+
* @returns Promise that resolves with the GLB data as ArrayBuffer
|
|
81
|
+
*/
|
|
82
|
+
export function exportGLBData(sceneRoot) {
|
|
83
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
const result = yield exportGLB(sceneRoot, { filename: '', binary: true });
|
|
85
|
+
return result;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
37
88
|
/** Find a node by ID in the tree */
|
|
38
89
|
export function findNode(root, id) {
|
|
39
90
|
var _a;
|
package/package.json
CHANGED
|
@@ -1,14 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react-three-game
|
|
3
|
+
description: react-three-game, a JSON-first 3D game engine built on React Three Fiber, WebGPU, and Rapier Physics.
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# react-three-game
|
|
2
7
|
|
|
3
|
-
|
|
8
|
+
Instructions for the agent to follow when this skill is activated.
|
|
9
|
+
|
|
10
|
+
## When to use
|
|
11
|
+
|
|
12
|
+
generate 3D scenes, games and physics simulations in React.
|
|
4
13
|
|
|
5
|
-
##
|
|
14
|
+
## Agent Workflow: JSON → GLB
|
|
6
15
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
16
|
+
Agents can programmatically generate 3D assets:
|
|
17
|
+
|
|
18
|
+
1. Create a JSON prefab following the GameObject schema
|
|
19
|
+
2. Load it in `PrefabEditor` to render the Three.js scene
|
|
20
|
+
3. Export the scene to GLB format using `exportGLB` or `exportGLBData`
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { useRef, useEffect } from 'react';
|
|
24
|
+
import { PrefabEditor, exportGLBData } from 'react-three-game';
|
|
25
|
+
import type { PrefabEditorRef } from 'react-three-game';
|
|
26
|
+
|
|
27
|
+
const jsonPrefab = {
|
|
28
|
+
root: {
|
|
29
|
+
id: "scene",
|
|
30
|
+
children: [
|
|
31
|
+
{
|
|
32
|
+
id: "cube",
|
|
33
|
+
components: {
|
|
34
|
+
transform: { type: "Transform", properties: { position: [0, 0, 0] } },
|
|
35
|
+
geometry: { type: "Geometry", properties: { geometryType: "box", args: [1, 1, 1] } },
|
|
36
|
+
material: { type: "Material", properties: { color: "#ff0000" } }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
function AgentExporter() {
|
|
44
|
+
const editorRef = useRef<PrefabEditorRef>(null);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const timer = setTimeout(async () => {
|
|
48
|
+
const sceneRoot = editorRef.current?.rootRef.current?.root;
|
|
49
|
+
if (!sceneRoot) return;
|
|
50
|
+
|
|
51
|
+
const glbData = await exportGLBData(sceneRoot);
|
|
52
|
+
// glbData is an ArrayBuffer ready for upload/storage
|
|
53
|
+
}, 1000); // Wait for scene to render
|
|
54
|
+
|
|
55
|
+
return () => clearTimeout(timer);
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
return <PrefabEditor ref={editorRef} initialPrefab={jsonPrefab} />;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
12
61
|
|
|
13
62
|
## Core Concepts
|
|
14
63
|
|
|
@@ -120,7 +169,7 @@ import { GameCanvas, PrefabRoot } from 'react-three-game';
|
|
|
120
169
|
### Tree Manipulation Utilities
|
|
121
170
|
|
|
122
171
|
```typescript
|
|
123
|
-
import { findNode, updateNode, updateNodeById, deleteNode, cloneNode } from 'react-three-game';
|
|
172
|
+
import { findNode, updateNode, updateNodeById, deleteNode, cloneNode, saveJson, loadJson, exportGLB, exportGLBData } from 'react-three-game';
|
|
124
173
|
|
|
125
174
|
// Update a node by ID (optimized - avoids unnecessary object creation)
|
|
126
175
|
const updated = updateNodeById(root, nodeId, node => ({ ...node, disabled: true }));
|
|
@@ -133,6 +182,14 @@ const afterDelete = deleteNode(root, nodeId);
|
|
|
133
182
|
|
|
134
183
|
// Clone a node
|
|
135
184
|
const cloned = cloneNode(node);
|
|
185
|
+
|
|
186
|
+
// Save/load JSON
|
|
187
|
+
saveJson(prefab, 'my-scene');
|
|
188
|
+
const loaded = await loadJson();
|
|
189
|
+
|
|
190
|
+
// Export to GLB
|
|
191
|
+
await exportGLB(sceneRoot, { filename: 'my-scene.glb' });
|
|
192
|
+
const glbData = await exportGLBData(sceneRoot); // Returns ArrayBuffer
|
|
136
193
|
```
|
|
137
194
|
|
|
138
195
|
## Building Game Levels
|
|
@@ -360,6 +417,66 @@ The `PrefabEditorRef` provides:
|
|
|
360
417
|
- `setPrefab(prefab)` - update the prefab
|
|
361
418
|
- `screenshot()` - save canvas as PNG
|
|
362
419
|
- `exportGLB()` - export scene as GLB
|
|
420
|
+
- `rootRef` - reference to the Three.js scene root for programmatic GLB export
|
|
421
|
+
|
|
422
|
+
### Programmatic GLB Export
|
|
423
|
+
|
|
424
|
+
Export Three.js scenes to GLB format from JSON prefabs:
|
|
425
|
+
|
|
426
|
+
```tsx
|
|
427
|
+
import { useRef, useEffect } from 'react';
|
|
428
|
+
import { PrefabEditor, exportGLB, exportGLBData } from 'react-three-game';
|
|
429
|
+
import type { PrefabEditorRef } from 'react-three-game';
|
|
430
|
+
|
|
431
|
+
function ExportScene() {
|
|
432
|
+
const editorRef = useRef<PrefabEditorRef>(null);
|
|
433
|
+
|
|
434
|
+
const handleExport = async () => {
|
|
435
|
+
const sceneRoot = editorRef.current?.rootRef.current?.root;
|
|
436
|
+
if (!sceneRoot) return;
|
|
437
|
+
|
|
438
|
+
// Option 1: Export and trigger browser download
|
|
439
|
+
await exportGLB(sceneRoot, {
|
|
440
|
+
filename: 'my-scene.glb',
|
|
441
|
+
binary: true,
|
|
442
|
+
onComplete: (result) => console.log('Export complete'),
|
|
443
|
+
onError: (error) => console.error('Export failed', error)
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
// Option 2: Get raw ArrayBuffer without downloading
|
|
447
|
+
const glbData = await exportGLBData(sceneRoot);
|
|
448
|
+
// Upload to server, save to file system, etc.
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
return (
|
|
452
|
+
<>
|
|
453
|
+
<PrefabEditor ref={editorRef} initialPrefab={jsonPrefab} />
|
|
454
|
+
<button onClick={handleExport}>Export GLB</button>
|
|
455
|
+
</>
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
**Export Options:**
|
|
461
|
+
- `filename` - Output filename (triggers download if provided)
|
|
462
|
+
- `binary` - Export as binary GLB (true) or JSON glTF (false)
|
|
463
|
+
- `onComplete` - Callback when export succeeds
|
|
464
|
+
- `onError` - Callback when export fails
|
|
465
|
+
|
|
466
|
+
**Common Agent Pattern:**
|
|
467
|
+
```tsx
|
|
468
|
+
useEffect(() => {
|
|
469
|
+
// Wait for scene to fully render
|
|
470
|
+
const timer = setTimeout(async () => {
|
|
471
|
+
const sceneRoot = editorRef.current?.rootRef.current?.root;
|
|
472
|
+
if (sceneRoot) {
|
|
473
|
+
const glbData = await exportGLBData(sceneRoot);
|
|
474
|
+
// Process the ArrayBuffer
|
|
475
|
+
}
|
|
476
|
+
}, 1000);
|
|
477
|
+
return () => clearTimeout(timer);
|
|
478
|
+
}, []);
|
|
479
|
+
```
|
|
363
480
|
|
|
364
481
|
### Live Node Updates with useFrame
|
|
365
482
|
|
|
@@ -489,3 +606,4 @@ npm run dev # tsc --watch + docs site
|
|
|
489
606
|
npm run build # build to /dist
|
|
490
607
|
npm run release # build + publish
|
|
491
608
|
```
|
|
609
|
+
|
package/src/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ export {
|
|
|
26
26
|
|
|
27
27
|
// Prefab Editor - Styles & Utils
|
|
28
28
|
export * from './tools/prefabeditor/utils';
|
|
29
|
+
export type { ExportGLBOptions } from './tools/prefabeditor/utils';
|
|
29
30
|
|
|
30
31
|
// Prefab Editor - Types
|
|
31
32
|
export type { PrefabEditorRef } from './tools/prefabeditor/PrefabEditor';
|
|
@@ -6,8 +6,7 @@ import { Physics } from "@react-three/rapier";
|
|
|
6
6
|
import EditorUI from "./EditorUI";
|
|
7
7
|
import { base, toolbar } from "./styles";
|
|
8
8
|
import { EditorContext } from "./EditorContext";
|
|
9
|
-
import {
|
|
10
|
-
import { Group } from "three";
|
|
9
|
+
import { exportGLB } from "./utils";
|
|
11
10
|
|
|
12
11
|
export interface PrefabEditorRef {
|
|
13
12
|
screenshot: () => void;
|
|
@@ -115,23 +114,9 @@ const PrefabEditor = forwardRef<PrefabEditorRef, {
|
|
|
115
114
|
const sceneRoot = prefabRootRef.current?.root;
|
|
116
115
|
if (!sceneRoot) return;
|
|
117
116
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
(result) => {
|
|
122
|
-
const blob = new Blob([result as ArrayBuffer], { type: 'application/octet-stream' });
|
|
123
|
-
const url = URL.createObjectURL(blob);
|
|
124
|
-
const a = document.createElement('a');
|
|
125
|
-
a.href = url;
|
|
126
|
-
a.download = `${loadedPrefab.name || 'scene'}.glb`;
|
|
127
|
-
a.click();
|
|
128
|
-
URL.revokeObjectURL(url);
|
|
129
|
-
},
|
|
130
|
-
(error) => {
|
|
131
|
-
console.error('Error exporting GLB:', error);
|
|
132
|
-
},
|
|
133
|
-
{ binary: true }
|
|
134
|
-
);
|
|
117
|
+
exportGLB(sceneRoot, {
|
|
118
|
+
filename: `${loadedPrefab.name || 'scene'}.glb`
|
|
119
|
+
});
|
|
135
120
|
};
|
|
136
121
|
|
|
137
122
|
useEffect(() => {
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { GameObject, Prefab } from "./types";
|
|
2
|
+
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
|
|
3
|
+
import { Object3D } from 'three';
|
|
4
|
+
|
|
5
|
+
export interface ExportGLBOptions {
|
|
6
|
+
filename?: string;
|
|
7
|
+
binary?: boolean;
|
|
8
|
+
onComplete?: (result: ArrayBuffer | object) => void;
|
|
9
|
+
onError?: (error: any) => void;
|
|
10
|
+
}
|
|
2
11
|
|
|
3
12
|
/** Save a prefab as JSON file */
|
|
4
13
|
export function saveJson(data: Prefab, filename: string) {
|
|
@@ -33,6 +42,66 @@ export function loadJson(): Promise<Prefab | undefined> {
|
|
|
33
42
|
});
|
|
34
43
|
}
|
|
35
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Export a Three.js scene or object to GLB format
|
|
47
|
+
* @param sceneRoot - The Three.js Object3D to export
|
|
48
|
+
* @param options - Export options
|
|
49
|
+
* @returns Promise that resolves when export is complete
|
|
50
|
+
*/
|
|
51
|
+
export function exportGLB(
|
|
52
|
+
sceneRoot: Object3D,
|
|
53
|
+
options: ExportGLBOptions = {}
|
|
54
|
+
): Promise<ArrayBuffer | object> {
|
|
55
|
+
const {
|
|
56
|
+
filename = 'scene.glb',
|
|
57
|
+
binary = true,
|
|
58
|
+
onComplete,
|
|
59
|
+
onError
|
|
60
|
+
} = options;
|
|
61
|
+
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const exporter = new GLTFExporter();
|
|
64
|
+
|
|
65
|
+
exporter.parse(
|
|
66
|
+
sceneRoot,
|
|
67
|
+
(result) => {
|
|
68
|
+
onComplete?.(result);
|
|
69
|
+
resolve(result);
|
|
70
|
+
|
|
71
|
+
// Trigger download if filename is provided
|
|
72
|
+
if (filename) {
|
|
73
|
+
const blob = new Blob(
|
|
74
|
+
[result as ArrayBuffer],
|
|
75
|
+
{ type: binary ? 'application/octet-stream' : 'application/json' }
|
|
76
|
+
);
|
|
77
|
+
const url = URL.createObjectURL(blob);
|
|
78
|
+
const a = document.createElement('a');
|
|
79
|
+
a.href = url;
|
|
80
|
+
a.download = filename;
|
|
81
|
+
a.click();
|
|
82
|
+
URL.revokeObjectURL(url);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
(error) => {
|
|
86
|
+
console.error('Error exporting GLB:', error);
|
|
87
|
+
onError?.(error);
|
|
88
|
+
reject(error);
|
|
89
|
+
},
|
|
90
|
+
{ binary }
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Export a Three.js scene to GLB and return the ArrayBuffer without downloading
|
|
97
|
+
* @param sceneRoot - The Three.js Object3D to export
|
|
98
|
+
* @returns Promise that resolves with the GLB data as ArrayBuffer
|
|
99
|
+
*/
|
|
100
|
+
export async function exportGLBData(sceneRoot: Object3D): Promise<ArrayBuffer> {
|
|
101
|
+
const result = await exportGLB(sceneRoot, { filename: '', binary: true });
|
|
102
|
+
return result as ArrayBuffer;
|
|
103
|
+
}
|
|
104
|
+
|
|
36
105
|
/** Find a node by ID in the tree */
|
|
37
106
|
export function findNode(root: GameObject, id: string): GameObject | null {
|
|
38
107
|
if (root.id === id) return root;
|
package/skill/package.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@react-three-game/skills",
|
|
3
|
-
"version": "0.0.1",
|
|
4
|
-
"description": "Agent skill for working with react-three-game - a JSON-first 3D game engine",
|
|
5
|
-
"repository": {
|
|
6
|
-
"url": "https://github.com/prnth/react-three-game/tree/main/skill"
|
|
7
|
-
},
|
|
8
|
-
"keywords": [
|
|
9
|
-
"agentic",
|
|
10
|
-
"skill",
|
|
11
|
-
"react-three-fiber",
|
|
12
|
-
"game-engine",
|
|
13
|
-
"3d",
|
|
14
|
-
"webgpu"
|
|
15
|
-
],
|
|
16
|
-
"license": "MIT"
|
|
17
|
-
}
|