react-three-game 0.0.3 → 0.0.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.
- package/.github/workflows/nextjs.yml +99 -0
- package/README.md +100 -473
- package/package.json +3 -3
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Sample workflow for building and deploying a Next.js site to GitHub Pages
|
|
2
|
+
#
|
|
3
|
+
# To get started with Next.js see: https://nextjs.org/docs/getting-started
|
|
4
|
+
#
|
|
5
|
+
name: Deploy Next.js site to Pages
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
# Runs on pushes targeting the default branch
|
|
9
|
+
push:
|
|
10
|
+
branches: ["main"]
|
|
11
|
+
|
|
12
|
+
# Allows you to run this workflow manually from the Actions tab
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
|
|
15
|
+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
pages: write
|
|
19
|
+
id-token: write
|
|
20
|
+
|
|
21
|
+
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
|
22
|
+
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
|
23
|
+
concurrency:
|
|
24
|
+
group: "pages"
|
|
25
|
+
cancel-in-progress: false
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
# Build job
|
|
29
|
+
build:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- name: Checkout
|
|
33
|
+
uses: actions/checkout@v4
|
|
34
|
+
- name: Detect package manager
|
|
35
|
+
id: detect-package-manager
|
|
36
|
+
run: |
|
|
37
|
+
if [ -f "${{ github.workspace }}/yarn.lock" ]; then
|
|
38
|
+
echo "manager=yarn" >> $GITHUB_OUTPUT
|
|
39
|
+
echo "command=install" >> $GITHUB_OUTPUT
|
|
40
|
+
echo "runner=yarn" >> $GITHUB_OUTPUT
|
|
41
|
+
exit 0
|
|
42
|
+
elif [ -f "${{ github.workspace }}/package.json" ]; then
|
|
43
|
+
echo "manager=npm" >> $GITHUB_OUTPUT
|
|
44
|
+
echo "command=install" >> $GITHUB_OUTPUT
|
|
45
|
+
echo "runner=npx --no-install" >> $GITHUB_OUTPUT
|
|
46
|
+
exit 0
|
|
47
|
+
else
|
|
48
|
+
echo "Unable to determine package manager"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
- name: Setup Node
|
|
52
|
+
uses: actions/setup-node@v4
|
|
53
|
+
with:
|
|
54
|
+
node-version: "20"
|
|
55
|
+
cache: ${{ steps.detect-package-manager.outputs.manager }}
|
|
56
|
+
- name: Setup Pages
|
|
57
|
+
uses: actions/configure-pages@v5
|
|
58
|
+
with:
|
|
59
|
+
# Automatically inject basePath in your Next.js configuration file and disable
|
|
60
|
+
# server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized).
|
|
61
|
+
#
|
|
62
|
+
# You may remove this line if you want to manage the configuration yourself.
|
|
63
|
+
static_site_generator: next
|
|
64
|
+
- name: Restore cache
|
|
65
|
+
uses: actions/cache@v4
|
|
66
|
+
with:
|
|
67
|
+
path: |
|
|
68
|
+
docs/.next/cache
|
|
69
|
+
# Generate a new cache whenever packages or source files change.
|
|
70
|
+
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
|
|
71
|
+
# If source files changed but packages didn't, rebuild from a prior cache.
|
|
72
|
+
restore-keys: |
|
|
73
|
+
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-
|
|
74
|
+
- name: Install root dependencies
|
|
75
|
+
run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }}
|
|
76
|
+
- name: Build library
|
|
77
|
+
run: npm run build
|
|
78
|
+
- name: Install docs dependencies
|
|
79
|
+
working-directory: ./docs
|
|
80
|
+
run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }}
|
|
81
|
+
- name: Build Next.js docs
|
|
82
|
+
working-directory: ./docs
|
|
83
|
+
run: ${{ steps.detect-package-manager.outputs.runner }} next build
|
|
84
|
+
- name: Upload artifact
|
|
85
|
+
uses: actions/upload-pages-artifact@v3
|
|
86
|
+
with:
|
|
87
|
+
path: ./docs/out
|
|
88
|
+
|
|
89
|
+
# Deployment job
|
|
90
|
+
deploy:
|
|
91
|
+
environment:
|
|
92
|
+
name: github-pages
|
|
93
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
94
|
+
runs-on: ubuntu-latest
|
|
95
|
+
needs: build
|
|
96
|
+
steps:
|
|
97
|
+
- name: Deploy to GitHub Pages
|
|
98
|
+
id: deployment
|
|
99
|
+
uses: actions/deploy-pages@v4
|
package/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# react-three-game
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
> Generate entire game scenes from natural language. Zero boilerplate, 100% declarative, fully typesafe.
|
|
3
|
+
Component-based 3D game engine where everything is JSON. Built on React Three Fiber + WebGPU.
|
|
5
4
|
|
|
6
5
|
```bash
|
|
7
6
|
npm i react-three-game @react-three/fiber three
|
|
@@ -11,39 +10,11 @@ npm i react-three-game @react-three/fiber three
|
|
|
11
10
|
[](https://www.typescriptlang.org/)
|
|
12
11
|
[](https://react.dev/)
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
## Core Principle
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
**Traditional 3D engines force you to write imperative code.** Unity requires C# classes. Unreal needs Blueprints. Three.js demands manual scene graph manipulation. **AI agents struggle with all of these.**
|
|
19
|
-
|
|
20
|
-
**react-three-game is different:**
|
|
21
|
-
- ✅ **Everything is JSON** - AI can generate complete scenes without writing code
|
|
22
|
-
- ✅ **Component-based architecture** - Like Unity, but declarative and serializable
|
|
23
|
-
- ✅ **Visual prefab editor** - Export scenes as versionable JSON files
|
|
24
|
-
- ✅ **Built on React Three Fiber** - Leverage the entire React ecosystem
|
|
25
|
-
- ✅ **WebGPU renderer** - Cutting-edge graphics with Three.js r181+
|
|
26
|
-
|
|
27
|
-
### The Problem We Solve
|
|
28
|
-
|
|
29
|
-
```jsx
|
|
30
|
-
// ❌ Traditional Three.js - Imperative, verbose, AI-hostile
|
|
31
|
-
const scene = new THREE.Scene();
|
|
32
|
-
const geometry = new THREE.BoxGeometry();
|
|
33
|
-
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
|
|
34
|
-
const cube = new THREE.Mesh(geometry, material);
|
|
35
|
-
cube.position.set(0, 1, 0);
|
|
36
|
-
scene.add(cube);
|
|
37
|
-
|
|
38
|
-
// Physics? Even worse...
|
|
39
|
-
const body = new CANNON.Body({ mass: 1 });
|
|
40
|
-
body.addShape(new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5)));
|
|
41
|
-
world.addBody(body);
|
|
42
|
-
// Now sync transforms every frame... 😱
|
|
43
|
-
```
|
|
15
|
+
Scenes are JSON prefabs. Components are registered modules. Hierarchy is declarative.
|
|
44
16
|
|
|
45
17
|
```jsx
|
|
46
|
-
// ✅ react-three-game - Declarative, concise, AI-friendly
|
|
47
18
|
<PrefabRoot data={{
|
|
48
19
|
root: {
|
|
49
20
|
id: "cube",
|
|
@@ -57,19 +28,12 @@ world.addBody(body);
|
|
|
57
28
|
}} />
|
|
58
29
|
```
|
|
59
30
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## 🚀 Quick Start
|
|
31
|
+
## Quick Start
|
|
65
32
|
|
|
66
|
-
### Installation
|
|
67
33
|
```bash
|
|
68
34
|
npm install react-three-game @react-three/fiber @react-three/rapier three
|
|
69
35
|
```
|
|
70
36
|
|
|
71
|
-
### Your First Scene (30 seconds)
|
|
72
|
-
|
|
73
37
|
```jsx
|
|
74
38
|
import { GameCanvas, PrefabRoot } from 'react-three-game';
|
|
75
39
|
|
|
@@ -81,19 +45,12 @@ export default function App() {
|
|
|
81
45
|
id: "scene",
|
|
82
46
|
root: {
|
|
83
47
|
id: "root",
|
|
84
|
-
enabled: true,
|
|
85
|
-
visible: true,
|
|
86
48
|
components: {
|
|
87
|
-
transform: {
|
|
88
|
-
type: "Transform",
|
|
89
|
-
properties: { position: [0, 0, 0], rotation: [0, 0, 0], scale: [1, 1, 1] }
|
|
90
|
-
}
|
|
49
|
+
transform: { type: "Transform", properties: { position: [0, 0, 0] } }
|
|
91
50
|
},
|
|
92
51
|
children: [
|
|
93
52
|
{
|
|
94
53
|
id: "floor",
|
|
95
|
-
enabled: true,
|
|
96
|
-
visible: true,
|
|
97
54
|
components: {
|
|
98
55
|
transform: { type: "Transform", properties: { position: [0, -1, 0] } },
|
|
99
56
|
geometry: { type: "Geometry", properties: { geometryType: "box", args: [10, 0.5, 10] } },
|
|
@@ -103,8 +60,6 @@ export default function App() {
|
|
|
103
60
|
},
|
|
104
61
|
{
|
|
105
62
|
id: "player",
|
|
106
|
-
enabled: true,
|
|
107
|
-
visible: true,
|
|
108
63
|
components: {
|
|
109
64
|
transform: { type: "Transform", properties: { position: [0, 2, 0] } },
|
|
110
65
|
geometry: { type: "Geometry", properties: { geometryType: "sphere" } },
|
|
@@ -120,58 +75,27 @@ export default function App() {
|
|
|
120
75
|
}
|
|
121
76
|
```
|
|
122
77
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
---
|
|
126
|
-
|
|
127
|
-
## 🎮 Core Concepts
|
|
128
|
-
|
|
129
|
-
### 1. GameObjects & Components
|
|
130
|
-
|
|
131
|
-
Every object in your scene is a `GameObject` with modular components:
|
|
78
|
+
## GameObject Structure
|
|
132
79
|
|
|
133
80
|
```typescript
|
|
134
81
|
interface GameObject {
|
|
135
|
-
id: string;
|
|
136
|
-
enabled
|
|
137
|
-
visible
|
|
82
|
+
id: string;
|
|
83
|
+
enabled?: boolean;
|
|
84
|
+
visible?: boolean;
|
|
138
85
|
components: {
|
|
139
|
-
transform?: TransformComponent;
|
|
140
|
-
geometry?: GeometryComponent;
|
|
141
|
-
material?: MaterialComponent;
|
|
142
|
-
physics?: PhysicsComponent;
|
|
143
|
-
model?: ModelComponent;
|
|
144
|
-
// Add your own!
|
|
86
|
+
transform?: TransformComponent;
|
|
87
|
+
geometry?: GeometryComponent;
|
|
88
|
+
material?: MaterialComponent;
|
|
89
|
+
physics?: PhysicsComponent;
|
|
90
|
+
model?: ModelComponent;
|
|
145
91
|
};
|
|
146
|
-
children?: GameObject[];
|
|
92
|
+
children?: GameObject[];
|
|
147
93
|
}
|
|
148
94
|
```
|
|
149
95
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
### 2. Visual Prefab Editor
|
|
153
|
-
|
|
154
|
-
Run the built-in editor:
|
|
155
|
-
```jsx
|
|
156
|
-
import { PrefabEditor } from 'react-three-game';
|
|
157
|
-
|
|
158
|
-
<PrefabEditor />
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
- 🎨 Drag-and-drop 3D models
|
|
162
|
-
- 🔧 Edit transforms with gizmos
|
|
163
|
-
- 📦 Add/remove components
|
|
164
|
-
- 💾 Export JSON files
|
|
165
|
-
- ▶️ Toggle edit/play mode
|
|
166
|
-
|
|
167
|
-
**Pro tip:** Use this to generate scenes, then let AI modify the JSON.
|
|
168
|
-
|
|
169
|
-
### 3. Component System
|
|
170
|
-
|
|
171
|
-
Create custom components in minutes:
|
|
96
|
+
## Custom Components
|
|
172
97
|
|
|
173
98
|
```tsx
|
|
174
|
-
// MyLaserComponent.tsx
|
|
175
99
|
import { Component } from 'react-three-game';
|
|
176
100
|
|
|
177
101
|
const LaserComponent: Component = {
|
|
@@ -188,137 +112,23 @@ const LaserComponent: Component = {
|
|
|
188
112
|
defaultProperties: { damage: 10 }
|
|
189
113
|
};
|
|
190
114
|
|
|
191
|
-
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
Register it once, use everywhere:
|
|
195
|
-
```typescript
|
|
115
|
+
// Register
|
|
196
116
|
import { registerComponent } from 'react-three-game';
|
|
197
117
|
registerComponent(LaserComponent);
|
|
198
118
|
```
|
|
199
119
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
## 🏗️ Architecture
|
|
203
|
-
|
|
204
|
-
### GameObject Hierarchy
|
|
205
|
-
```
|
|
206
|
-
Scene Root
|
|
207
|
-
├─ Player (Dynamic Physics)
|
|
208
|
-
│ ├─ Camera
|
|
209
|
-
│ └─ Weapon (Model)
|
|
210
|
-
├─ Enemies (Instanced)
|
|
211
|
-
│ ├─ Enemy_01
|
|
212
|
-
│ ├─ Enemy_02
|
|
213
|
-
│ └─ Enemy_03
|
|
214
|
-
└─ Environment
|
|
215
|
-
├─ Ground (Fixed Physics)
|
|
216
|
-
└─ Obstacles
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### Transform Math (Critical!)
|
|
220
|
-
- **Local transforms** stored in JSON (relative to parent)
|
|
221
|
-
- **World transforms** computed at runtime (for rendering)
|
|
222
|
-
- **TransformControls** use world space, then convert back to local
|
|
223
|
-
- Helper: `computeParentWorldMatrix()` handles the math
|
|
224
|
-
|
|
225
|
-
### Instancing System
|
|
226
|
-
Render 1000s of objects efficiently:
|
|
227
|
-
```json
|
|
228
|
-
{
|
|
229
|
-
"components": {
|
|
230
|
-
"model": {
|
|
231
|
-
"type": "Model",
|
|
232
|
-
"properties": {
|
|
233
|
-
"filename": "tree.glb",
|
|
234
|
-
"instanced": true // ← Magic flag
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
```
|
|
240
|
-
Behind the scenes: drei's `<Merged>` + `<InstancedRigidBodies>` for physics.
|
|
241
|
-
|
|
242
|
-
---
|
|
243
|
-
|
|
244
|
-
## 🎯 Real-World Example
|
|
245
|
-
|
|
246
|
-
Here's what a complete multiplayer game looks like (coming from production code):
|
|
247
|
-
|
|
248
|
-
```jsx
|
|
249
|
-
import { GameCanvas, PrefabRoot } from 'react-three-game';
|
|
250
|
-
import { Physics } from '@react-three/rapier';
|
|
251
|
-
|
|
252
|
-
export default function Game() {
|
|
253
|
-
return (
|
|
254
|
-
<GameCanvas>
|
|
255
|
-
<Physics>
|
|
256
|
-
{/* Load entire scene from JSON */}
|
|
257
|
-
<PrefabRoot data={levelData} />
|
|
258
|
-
|
|
259
|
-
{/* Mix with React components */}
|
|
260
|
-
<Player controllable />
|
|
261
|
-
<Enemy position={[5, 0, -5]} />
|
|
262
|
-
<MovingPlatform path={[[0,0,0], [10,0,0]]} />
|
|
263
|
-
</Physics>
|
|
264
|
-
|
|
265
|
-
<ambientLight intensity={0.5} />
|
|
266
|
-
<directionalLight castShadow position={[10, 10, 5]} />
|
|
267
|
-
</GameCanvas>
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
**The power:** That `levelData` JSON can be:
|
|
273
|
-
- 🤖 Generated by AI from a prompt
|
|
274
|
-
- 🎨 Created in the visual editor
|
|
275
|
-
- 🔄 Version controlled in git
|
|
276
|
-
- 🌐 Loaded from a CMS
|
|
277
|
-
- 🧩 Composed from smaller prefabs
|
|
278
|
-
|
|
279
|
-
---
|
|
280
|
-
|
|
281
|
-
## 📦 What's Included
|
|
282
|
-
|
|
283
|
-
### Core Exports
|
|
284
|
-
|
|
285
|
-
```typescript
|
|
286
|
-
import {
|
|
287
|
-
// Rendering
|
|
288
|
-
GameCanvas, // WebGPU Canvas wrapper
|
|
289
|
-
PrefabRoot, // Scene renderer from JSON
|
|
290
|
-
PrefabEditor, // Visual editor component
|
|
291
|
-
|
|
292
|
-
// Utils
|
|
293
|
-
loadModel, // GLB/FBX loader with Draco
|
|
294
|
-
registerComponent, // Add custom components
|
|
295
|
-
getComponent, // Query component registry
|
|
296
|
-
|
|
297
|
-
// Types
|
|
298
|
-
Prefab, // Prefab JSON structure
|
|
299
|
-
GameObject, // Scene node type
|
|
300
|
-
Component, // Component interface
|
|
301
|
-
} from 'react-three-game';
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### Built-in Components
|
|
120
|
+
## Built-in Components
|
|
305
121
|
|
|
306
|
-
| Component | Properties |
|
|
307
|
-
|
|
308
|
-
| **Transform** | `position`, `rotation`, `scale` |
|
|
309
|
-
| **Geometry** | `geometryType`, `args` |
|
|
310
|
-
| **Material** | `color`, `texture`, `metalness`, `roughness` |
|
|
311
|
-
| **Physics** | `type
|
|
312
|
-
| **Model** | `filename`, `instanced` |
|
|
313
|
-
| **SpotLight** | `color`, `intensity`, `angle`, `penumbra` |
|
|
122
|
+
| Component | Properties |
|
|
123
|
+
|-----------|-----------|
|
|
124
|
+
| **Transform** | `position: [x,y,z]`, `rotation: [x,y,z]`, `scale: [x,y,z]` |
|
|
125
|
+
| **Geometry** | `geometryType: "box"\|"sphere"\|"plane"\|"cylinder"`, `args: number[]` |
|
|
126
|
+
| **Material** | `color: string`, `texture?: string`, `metalness?: number`, `roughness?: number` |
|
|
127
|
+
| **Physics** | `type: "dynamic"\|"fixed"` |
|
|
128
|
+
| **Model** | `filename: string`, `instanced?: boolean` |
|
|
129
|
+
| **SpotLight** | `color: string`, `intensity: number`, `angle: number`, `penumbra: number` |
|
|
314
130
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
---
|
|
318
|
-
|
|
319
|
-
## 🎨 Visual Editor
|
|
320
|
-
|
|
321
|
-
Import and use the prefab editor:
|
|
131
|
+
## Prefab Editor
|
|
322
132
|
|
|
323
133
|
```jsx
|
|
324
134
|
import { PrefabEditor } from 'react-three-game';
|
|
@@ -328,337 +138,154 @@ export default function EditorPage() {
|
|
|
328
138
|
}
|
|
329
139
|
```
|
|
330
140
|
|
|
331
|
-
|
|
332
|
-
- **📥 Import/Export** - Load/save JSON prefabs
|
|
333
|
-
- **🎮 Edit/Play Toggle** - Test physics in real-time
|
|
334
|
-
- **🔧 Transform Gizmos** - Translate/Rotate/Scale (T/R/S keys)
|
|
335
|
-
- **🌳 Scene Tree** - Drag to reorder, click to select
|
|
336
|
-
- **📋 Inspector** - Edit component properties
|
|
337
|
-
- **➕ Add Components** - Dropdown to attach new behaviors
|
|
338
|
-
|
|
339
|
-
### Workflow
|
|
340
|
-
1. Create scene in editor
|
|
341
|
-
2. Export JSON
|
|
342
|
-
3. Load in game: `<PrefabRoot data={require('./level1.json')} />`
|
|
343
|
-
4. Or generate variations with AI by modifying the JSON
|
|
344
|
-
|
|
345
|
-
---
|
|
141
|
+
Transform gizmos (T/R/S keys), drag-to-reorder tree, import/export JSON, edit/play toggle.
|
|
346
142
|
|
|
347
|
-
##
|
|
143
|
+
## Implementation Details
|
|
348
144
|
|
|
349
|
-
###
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
<PrefabRoot data={levelData} />
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
### Mixing Prefabs with React Components
|
|
358
|
-
|
|
359
|
-
```jsx
|
|
360
|
-
<Physics>
|
|
361
|
-
<PrefabRoot data={environment} /> {/* Static level geometry */}
|
|
362
|
-
<Player /> {/* Dynamic player logic */}
|
|
363
|
-
<AIEnemies /> {/* Procedural spawning */}
|
|
364
|
-
</Physics>
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
### Dynamic Instancing (1000+ Objects)
|
|
145
|
+
### Transform Hierarchy
|
|
146
|
+
- Local transforms stored in JSON (relative to parent)
|
|
147
|
+
- World transforms computed at runtime via matrix multiplication
|
|
148
|
+
- `computeParentWorldMatrix(root, targetId)` traverses tree for parent's world matrix
|
|
149
|
+
- TransformControls extract world matrix → compute parent inverse → derive new local transform
|
|
368
150
|
|
|
151
|
+
### GPU Instancing
|
|
152
|
+
Enable with `model.properties.instanced = true`:
|
|
369
153
|
```json
|
|
370
154
|
{
|
|
371
|
-
"
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
"
|
|
375
|
-
|
|
376
|
-
"
|
|
377
|
-
"type": "Model",
|
|
378
|
-
"properties": {
|
|
379
|
-
"filename": "tree.glb",
|
|
380
|
-
"instanced": true // ← Automatic GPU instancing
|
|
381
|
-
}
|
|
382
|
-
},
|
|
383
|
-
"physics": { "type": "Physics", "properties": { "type": "fixed" } }
|
|
155
|
+
"components": {
|
|
156
|
+
"model": {
|
|
157
|
+
"type": "Model",
|
|
158
|
+
"properties": {
|
|
159
|
+
"filename": "tree.glb",
|
|
160
|
+
"instanced": true
|
|
384
161
|
}
|
|
385
162
|
}
|
|
386
|
-
|
|
387
|
-
]
|
|
163
|
+
}
|
|
388
164
|
}
|
|
389
165
|
```
|
|
166
|
+
Uses drei's `<Merged>` + `<InstancedRigidBodies>` for physics. World-space transforms, terminal nodes.
|
|
390
167
|
|
|
391
|
-
###
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
import { Line } from '@react-three/drei';
|
|
397
|
-
|
|
398
|
-
const LaserBeam: Component = {
|
|
399
|
-
name: 'LaserBeam',
|
|
400
|
-
|
|
401
|
-
Editor: ({ component, onUpdate }) => (
|
|
402
|
-
<>
|
|
403
|
-
<label>Damage</label>
|
|
404
|
-
<input
|
|
405
|
-
type="number"
|
|
406
|
-
value={component.properties.damage}
|
|
407
|
-
onChange={e => onUpdate({ damage: +e.target.value })}
|
|
408
|
-
/>
|
|
409
|
-
<label>Color</label>
|
|
410
|
-
<input
|
|
411
|
-
type="color"
|
|
412
|
-
value={component.properties.color}
|
|
413
|
-
onChange={e => onUpdate({ color: e.target.value })}
|
|
414
|
-
/>
|
|
415
|
-
</>
|
|
416
|
-
),
|
|
417
|
-
|
|
418
|
-
View: ({ properties }) => (
|
|
419
|
-
<Line
|
|
420
|
-
points={[[0, 0, 0], [0, 0, -10]]}
|
|
421
|
-
color={properties.color}
|
|
422
|
-
lineWidth={3}
|
|
423
|
-
/>
|
|
424
|
-
),
|
|
425
|
-
|
|
426
|
-
defaultProperties: {
|
|
427
|
-
damage: 25,
|
|
428
|
-
color: '#ff0000'
|
|
429
|
-
}
|
|
430
|
-
};
|
|
168
|
+
### Model Loading
|
|
169
|
+
- Supports GLB/GLTF (Draco compression) and FBX
|
|
170
|
+
- Singleton loaders in `modelLoader.ts`
|
|
171
|
+
- Draco decoder from `https://www.gstatic.com/draco/v1/decoders/`
|
|
172
|
+
- Auto-loads when `model.properties.filename` detected
|
|
431
173
|
|
|
432
|
-
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
Then register it:
|
|
174
|
+
### WebGPU Renderer
|
|
436
175
|
```tsx
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
176
|
+
<Canvas gl={async ({ canvas }) => {
|
|
177
|
+
const renderer = new WebGPURenderer({ canvas, shadowMap: true });
|
|
178
|
+
await renderer.init(); // Required
|
|
179
|
+
return renderer;
|
|
180
|
+
}}>
|
|
441
181
|
```
|
|
182
|
+
Use `MeshStandardNodeMaterial` not `MeshStandardMaterial`.
|
|
442
183
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
---
|
|
446
|
-
|
|
447
|
-
## 🤝 Integrations
|
|
448
|
-
|
|
449
|
-
### React Three Fiber Ecosystem
|
|
450
|
-
All `@react-three/drei` helpers work seamlessly:
|
|
184
|
+
## Patterns
|
|
451
185
|
|
|
186
|
+
### Load External Prefabs
|
|
452
187
|
```jsx
|
|
453
|
-
import
|
|
454
|
-
|
|
455
|
-
<GameCanvas>
|
|
456
|
-
<Sky />
|
|
457
|
-
<OrbitControls />
|
|
458
|
-
<PrefabRoot data={scene} />
|
|
459
|
-
<ContactShadows />
|
|
460
|
-
</GameCanvas>
|
|
188
|
+
import levelData from './prefabs/arena.json';
|
|
189
|
+
<PrefabRoot data={levelData} />
|
|
461
190
|
```
|
|
462
191
|
|
|
463
|
-
###
|
|
464
|
-
Wrap your scene in `<Physics>`:
|
|
465
|
-
|
|
192
|
+
### Mix with React Components
|
|
466
193
|
```jsx
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
<
|
|
470
|
-
<
|
|
194
|
+
<Physics>
|
|
195
|
+
<PrefabRoot data={environment} />
|
|
196
|
+
<Player />
|
|
197
|
+
<AIEnemies />
|
|
471
198
|
</Physics>
|
|
472
199
|
```
|
|
473
200
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
```
|
|
484
|
-
Create a react-three-game prefab JSON for a platformer level with:
|
|
485
|
-
- A ground plane (10x10, fixed physics, grass texture)
|
|
486
|
-
- 5 floating platforms (dynamic physics)
|
|
487
|
-
- A player spawn point at [0, 5, 0]
|
|
488
|
-
- 3 collectible coins using sphere geometry
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
**Modify existing scenes:**
|
|
492
|
-
```
|
|
493
|
-
Take this prefab JSON and add:
|
|
494
|
-
- A spotlight pointing at the player spawn
|
|
495
|
-
- Convert all "box" geometry to "sphere"
|
|
496
|
-
- Scale all objects by 1.5x
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
**Generate component variations:**
|
|
500
|
-
```
|
|
501
|
-
Create 10 enemy prefab variants by:
|
|
502
|
-
- Randomizing position within bounds [[-10,10], [0,5], [-10,10]]
|
|
503
|
-
- Varying scale from 0.8 to 1.2
|
|
504
|
-
- Using colors from palette: ["#ff6b6b", "#ee5a6f", "#c44569"]
|
|
201
|
+
### Update Prefab Nodes
|
|
202
|
+
```typescript
|
|
203
|
+
function updatePrefabNode(root: GameObject, id: string, update: (node: GameObject) => GameObject): GameObject {
|
|
204
|
+
if (root.id === id) return update(root);
|
|
205
|
+
if (root.children) {
|
|
206
|
+
return { ...root, children: root.children.map(child => updatePrefabNode(child, id, update)) };
|
|
207
|
+
}
|
|
208
|
+
return root;
|
|
209
|
+
}
|
|
505
210
|
```
|
|
506
211
|
|
|
507
|
-
|
|
212
|
+
## AI Agent Reference
|
|
508
213
|
|
|
214
|
+
### Prefab JSON Schema
|
|
509
215
|
```typescript
|
|
510
216
|
{
|
|
511
217
|
"id": "unique-id",
|
|
512
218
|
"root": {
|
|
513
219
|
"id": "root-id",
|
|
514
|
-
"enabled": true,
|
|
515
|
-
"visible": true,
|
|
516
220
|
"components": {
|
|
517
221
|
"transform": {
|
|
518
222
|
"type": "Transform",
|
|
519
223
|
"properties": {
|
|
520
|
-
"position": [x, y, z], //
|
|
521
|
-
"rotation": [x, y, z], //
|
|
522
|
-
"scale": [x, y, z] //
|
|
224
|
+
"position": [x, y, z], // world units
|
|
225
|
+
"rotation": [x, y, z], // radians
|
|
226
|
+
"scale": [x, y, z] // multipliers
|
|
523
227
|
}
|
|
524
228
|
},
|
|
525
229
|
"geometry": {
|
|
526
230
|
"type": "Geometry",
|
|
527
231
|
"properties": {
|
|
528
232
|
"geometryType": "box" | "sphere" | "plane" | "cylinder" | "cone" | "torus",
|
|
529
|
-
"args": [/* geometry-specific
|
|
233
|
+
"args": [/* geometry-specific */]
|
|
530
234
|
}
|
|
531
235
|
},
|
|
532
236
|
"material": {
|
|
533
237
|
"type": "Material",
|
|
534
238
|
"properties": {
|
|
535
|
-
"color": "#rrggbb"
|
|
536
|
-
"texture": "/path/to/texture.jpg",
|
|
537
|
-
"metalness": 0.0-1.0,
|
|
538
|
-
"roughness": 0.0-1.0
|
|
239
|
+
"color": "#rrggbb",
|
|
240
|
+
"texture": "/path/to/texture.jpg",
|
|
241
|
+
"metalness": 0.0-1.0,
|
|
242
|
+
"roughness": 0.0-1.0
|
|
539
243
|
}
|
|
540
244
|
},
|
|
541
245
|
"physics": {
|
|
542
246
|
"type": "Physics",
|
|
543
247
|
"properties": {
|
|
544
|
-
"type": "dynamic" | "fixed"
|
|
248
|
+
"type": "dynamic" | "fixed"
|
|
545
249
|
}
|
|
546
250
|
},
|
|
547
251
|
"model": {
|
|
548
252
|
"type": "Model",
|
|
549
253
|
"properties": {
|
|
550
254
|
"filename": "/models/asset.glb",
|
|
551
|
-
"instanced": true
|
|
255
|
+
"instanced": true
|
|
552
256
|
}
|
|
553
257
|
}
|
|
554
258
|
},
|
|
555
|
-
"children": [/*
|
|
259
|
+
"children": [/* recursive GameObjects */]
|
|
556
260
|
}
|
|
557
261
|
}
|
|
558
262
|
```
|
|
559
263
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
## 🛠️ Development
|
|
264
|
+
## Development
|
|
563
265
|
|
|
564
|
-
### Local Setup
|
|
565
266
|
```bash
|
|
566
267
|
git clone https://github.com/prnthh/react-three-game.git
|
|
567
268
|
cd react-three-game
|
|
568
269
|
npm install
|
|
569
|
-
npm run dev
|
|
270
|
+
npm run dev # tsc --watch + Next.js docs
|
|
271
|
+
npm run build # TypeScript → /dist
|
|
272
|
+
npm publish # publish to npm
|
|
570
273
|
```
|
|
571
274
|
|
|
572
|
-
|
|
275
|
+
Project structure:
|
|
573
276
|
```
|
|
574
|
-
/src →
|
|
575
|
-
/shared → GameCanvas
|
|
277
|
+
/src → library source
|
|
278
|
+
/shared → GameCanvas
|
|
576
279
|
/tools
|
|
577
|
-
/prefabeditor →
|
|
578
|
-
/docs → Next.js
|
|
579
|
-
/app →
|
|
280
|
+
/prefabeditor → editor + PrefabRoot
|
|
281
|
+
/docs → Next.js site
|
|
282
|
+
/app → demo pages
|
|
580
283
|
```
|
|
581
284
|
|
|
582
|
-
|
|
583
|
-
```bash
|
|
584
|
-
npm run build # Compile TypeScript → /dist
|
|
585
|
-
npm publish # Publish to npm
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
---
|
|
589
|
-
|
|
590
|
-
## 🌟 Roadmap
|
|
285
|
+
## Tech Stack
|
|
591
286
|
|
|
592
|
-
|
|
593
|
-
- [x] Visual editor
|
|
594
|
-
- [x] Component registry
|
|
595
|
-
- [x] GPU instancing
|
|
596
|
-
- [x] Physics integration
|
|
597
|
-
- [ ] Input system (keyboard/gamepad/touch) - **Coming Soon**
|
|
598
|
-
- [ ] Multiplayer primitives (WebRTC sync)
|
|
599
|
-
- [ ] Animation system (state machines)
|
|
600
|
-
- [ ] Audio components (spatial sound)
|
|
601
|
-
- [ ] Particle effects
|
|
602
|
-
- [ ] AI behavior trees (as JSON!)
|
|
287
|
+
React 19 • Three.js r181 • TypeScript 5 • WebGPU • Rapier Physics
|
|
603
288
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
## 🤖 Why Developers AND AI Love This
|
|
607
|
-
|
|
608
|
-
### For Developers
|
|
609
|
-
- ✅ **Skip the boilerplate** - No manual scene graph management
|
|
610
|
-
- ✅ **React patterns** - Use hooks, context, state like normal React
|
|
611
|
-
- ✅ **Visual debugging** - See and edit your scene in real-time
|
|
612
|
-
- ✅ **Type safety** - Full TypeScript support
|
|
613
|
-
- ✅ **Hot reload** - Changes reflect instantly
|
|
614
|
-
|
|
615
|
-
### For AI Agents
|
|
616
|
-
- ✅ **Pure data** - No imperative code to generate
|
|
617
|
-
- ✅ **JSON schema** - Structured, validatable format
|
|
618
|
-
- ✅ **Compositional** - Build complex scenes from simple primitives
|
|
619
|
-
- ✅ **Version controllable** - Git-friendly text files
|
|
620
|
-
- ✅ **Deterministic** - Same JSON = same scene every time
|
|
621
|
-
|
|
622
|
-
---
|
|
623
|
-
|
|
624
|
-
## 📚 Examples
|
|
625
|
-
|
|
626
|
-
Check out `/docs/app/demo` for live examples:
|
|
627
|
-
- Basic scene with physics
|
|
628
|
-
- Model loading and instancing
|
|
629
|
-
- Custom component creation
|
|
630
|
-
- Multiplayer game prototype
|
|
631
|
-
|
|
632
|
-
---
|
|
633
|
-
|
|
634
|
-
## 🤝 Contributing
|
|
635
|
-
|
|
636
|
-
This is an **AI-first** project. We welcome:
|
|
637
|
-
- New built-in components
|
|
638
|
-
- Documentation improvements
|
|
639
|
-
- Example scenes/games
|
|
640
|
-
- AI prompt templates
|
|
641
|
-
- Bug reports
|
|
642
|
-
|
|
643
|
-
See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
|
|
644
|
-
|
|
645
|
-
---
|
|
646
|
-
|
|
647
|
-
## 📄 License
|
|
289
|
+
## License
|
|
648
290
|
|
|
649
291
|
MIT © [prnth](https://github.com/prnthh)
|
|
650
|
-
|
|
651
|
-
---
|
|
652
|
-
|
|
653
|
-
## 💬 Community
|
|
654
|
-
|
|
655
|
-
- 🐦 Twitter: [@prnth](https://twitter.com/prnth)
|
|
656
|
-
- 💼 GitHub Issues: [Report bugs](https://github.com/prnthh/react-three-game/issues)
|
|
657
|
-
- 💡 Discussions: [Share ideas](https://github.com/prnthh/react-three-game/discussions)
|
|
658
|
-
|
|
659
|
-
---
|
|
660
|
-
|
|
661
|
-
**Built with:** React 19 • Three.js r181 • TypeScript 5 • WebGPU • Rapier Physics
|
|
662
|
-
|
|
663
|
-
**Status:** Alpha v0.0.1 - API may change
|
|
664
|
-
**AI Prompt to Share:** "Build me a 3D game using react-three-game with [your features]"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-three-game",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Batteries included React Three Fiber game engine",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"watch": "tsc --watch",
|
|
10
10
|
"dev": "concurrently \"npm run watch\" \"cd docs && npm run dev\"",
|
|
11
11
|
"build": "tsc",
|
|
12
|
-
"
|
|
12
|
+
"release": "npm run build && npm publish --access public"
|
|
13
13
|
},
|
|
14
14
|
"keywords": [],
|
|
15
15
|
"author": "prnth",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"@react-three/fiber": "^9.0.0",
|
|
20
20
|
"react": "^18.0.0 || ^19.0.0",
|
|
21
21
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
22
|
-
"three": "^0.
|
|
22
|
+
"three": "^0.181.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@react-three/drei": "^10.7.7",
|