react-three-game 0.0.46 → 0.0.48
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/copilot-instructions.md +1 -1
- 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/components/AmbientLightComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/AmbientLightComponent.js +23 -0
- package/dist/tools/prefabeditor/components/GeometryComponent.js +7 -0
- package/dist/tools/prefabeditor/components/Input.js +23 -1
- package/dist/tools/prefabeditor/components/index.js +2 -0
- 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/react-three-game-skill/README.md +1 -0
- package/react-three-game-skill/react-three-game/SKILL.md +394 -0
- package/src/index.ts +1 -0
- package/src/tools/prefabeditor/PrefabEditor.tsx +4 -19
- package/src/tools/prefabeditor/components/AmbientLightComponent.tsx +40 -0
- package/src/tools/prefabeditor/components/GeometryComponent.tsx +7 -0
- package/src/tools/prefabeditor/components/Input.tsx +32 -3
- package/src/tools/prefabeditor/components/index.ts +2 -0
- package/src/tools/prefabeditor/utils.ts +69 -0
- package/skill/SKILL.md +0 -491
- package/skill/package.json +0 -17
package/skill/SKILL.md
DELETED
|
@@ -1,491 +0,0 @@
|
|
|
1
|
-
# react-three-game
|
|
2
|
-
|
|
3
|
-
A Claude Code skill for working with react-three-game, a JSON-first 3D game engine built on React Three Fiber, WebGPU, and Rapier Physics.
|
|
4
|
-
|
|
5
|
-
## When to Use This Skill
|
|
6
|
-
|
|
7
|
-
Use this skill when:
|
|
8
|
-
- Creating or modifying 3D game scenes with react-three-game
|
|
9
|
-
- Working with prefab JSON structures
|
|
10
|
-
- Setting up physics-enabled game objects
|
|
11
|
-
- Creating custom components with editor UI (see Editor Mode section)
|
|
12
|
-
|
|
13
|
-
## Core Concepts
|
|
14
|
-
|
|
15
|
-
### GameObject Structure
|
|
16
|
-
|
|
17
|
-
Every game object follows this schema:
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
interface GameObject {
|
|
21
|
-
id: string;
|
|
22
|
-
disabled?: boolean;
|
|
23
|
-
hidden?: boolean;
|
|
24
|
-
components?: Record<string, { type: string; properties: any }>;
|
|
25
|
-
children?: GameObject[];
|
|
26
|
-
}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### Prefab JSON Format
|
|
30
|
-
|
|
31
|
-
Scenes are defined as JSON prefabs with a root node containing children:
|
|
32
|
-
|
|
33
|
-
```json
|
|
34
|
-
{
|
|
35
|
-
"root": {
|
|
36
|
-
"id": "scene",
|
|
37
|
-
"children": [
|
|
38
|
-
{
|
|
39
|
-
"id": "my-object",
|
|
40
|
-
"components": {
|
|
41
|
-
"transform": { "type": "Transform", "properties": { "position": [0, 0, 0] } },
|
|
42
|
-
"geometry": { "type": "Geometry", "properties": { "geometryType": "box" } },
|
|
43
|
-
"material": { "type": "Material", "properties": { "color": "#ff0000" } }
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
]
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Built-in Components
|
|
52
|
-
|
|
53
|
-
| Component | Type | Key Properties |
|
|
54
|
-
|-----------|------|----------------|
|
|
55
|
-
| Transform | `Transform` | `position: [x,y,z]`, `rotation: [x,y,z]` (radians), `scale: [x,y,z]` |
|
|
56
|
-
| Geometry | `Geometry` | `geometryType`: box/sphere/plane/cylinder, `args`: dimension array |
|
|
57
|
-
| Material | `Material` | `color`, `texture?`, `metalness?`, `roughness?`, `repeat?`, `repeatCount?` |
|
|
58
|
-
| Physics | `Physics` | `type`: "dynamic" or "fixed" |
|
|
59
|
-
| Model | `Model` | `filename` (GLB/FBX path), `instanced?` for GPU batching |
|
|
60
|
-
| SpotLight | `SpotLight` | `color`, `intensity`, `angle`, `penumbra`, `distance?`, `castShadow?` |
|
|
61
|
-
| DirectionalLight | `DirectionalLight` | `color`, `intensity`, `castShadow?`, `targetOffset?: [x,y,z]` |
|
|
62
|
-
| Text | `Text` | `text`, `font`, `size`, `depth`, `width`, `align`, `color` |
|
|
63
|
-
|
|
64
|
-
### Geometry Args by Type
|
|
65
|
-
|
|
66
|
-
| geometryType | args array |
|
|
67
|
-
|--------------|------------|
|
|
68
|
-
| `box` | `[width, height, depth]` |
|
|
69
|
-
| `sphere` | `[radius, widthSegments, heightSegments]` |
|
|
70
|
-
| `plane` | `[width, height]` |
|
|
71
|
-
| `cylinder` | `[radiusTop, radiusBottom, height, radialSegments]` |
|
|
72
|
-
|
|
73
|
-
### Material Texture Options
|
|
74
|
-
|
|
75
|
-
```json
|
|
76
|
-
{
|
|
77
|
-
"type": "Material",
|
|
78
|
-
"properties": {
|
|
79
|
-
"color": "white",
|
|
80
|
-
"texture": "/textures/path/to/texture.png",
|
|
81
|
-
"repeat": true,
|
|
82
|
-
"repeatCount": [4, 4]
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
- Use `"color": "white"` with textures for accurate texture colors
|
|
88
|
-
- `repeatCount: [x, y]` tiles the texture; match to geometry dimensions for proper scaling
|
|
89
|
-
|
|
90
|
-
### Rotation Reference
|
|
91
|
-
|
|
92
|
-
Rotations use radians. Common values:
|
|
93
|
-
- `1.57` = 90° (π/2)
|
|
94
|
-
- `3.14` = 180° (π)
|
|
95
|
-
- `-1.57` = -90° (rotate plane flat: `rotation: [-1.57, 0, 0]`)
|
|
96
|
-
|
|
97
|
-
## Common Patterns
|
|
98
|
-
|
|
99
|
-
### Usage Modes
|
|
100
|
-
|
|
101
|
-
The library supports two modes:
|
|
102
|
-
|
|
103
|
-
**Play Mode** (default) - Immediate rendering without any editor UI. Use `GameCanvas` with `PrefabRoot` for a clean game experience.
|
|
104
|
-
|
|
105
|
-
**Editor Mode** - Visual GUI using `PrefabEditor` for scene inspection and custom component development. See the [Editor Mode](#editor-mode) section at the end of this document.
|
|
106
|
-
|
|
107
|
-
### Basic Scene Setup (Play Mode)
|
|
108
|
-
|
|
109
|
-
```jsx
|
|
110
|
-
import { Physics } from '@react-three/rapier';
|
|
111
|
-
import { GameCanvas, PrefabRoot } from 'react-three-game';
|
|
112
|
-
|
|
113
|
-
<GameCanvas>
|
|
114
|
-
<Physics>
|
|
115
|
-
<PrefabRoot data={prefabData} />
|
|
116
|
-
</Physics>
|
|
117
|
-
</GameCanvas>
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### Tree Manipulation Utilities
|
|
121
|
-
|
|
122
|
-
```typescript
|
|
123
|
-
import { findNode, updateNode, updateNodeById, deleteNode, cloneNode } from 'react-three-game';
|
|
124
|
-
|
|
125
|
-
// Update a node by ID (optimized - avoids unnecessary object creation)
|
|
126
|
-
const updated = updateNodeById(root, nodeId, node => ({ ...node, disabled: true }));
|
|
127
|
-
|
|
128
|
-
// Find a node
|
|
129
|
-
const node = findNode(root, nodeId);
|
|
130
|
-
|
|
131
|
-
// Delete a node
|
|
132
|
-
const afterDelete = deleteNode(root, nodeId);
|
|
133
|
-
|
|
134
|
-
// Clone a node
|
|
135
|
-
const cloned = cloneNode(node);
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## Building Game Levels
|
|
139
|
-
|
|
140
|
-
### Complete Prefab Structure
|
|
141
|
-
|
|
142
|
-
```json
|
|
143
|
-
{
|
|
144
|
-
"id": "level-id",
|
|
145
|
-
"name": "Level Name",
|
|
146
|
-
"root": {
|
|
147
|
-
"id": "root",
|
|
148
|
-
"enabled": true,
|
|
149
|
-
"visible": true,
|
|
150
|
-
"components": { ... },
|
|
151
|
-
"children": [ ... ]
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### Floor/Ground Pattern
|
|
157
|
-
|
|
158
|
-
```json
|
|
159
|
-
{
|
|
160
|
-
"id": "main-floor",
|
|
161
|
-
"components": {
|
|
162
|
-
"transform": { "type": "Transform", "properties": { "position": [0, -0.5, 0] } },
|
|
163
|
-
"geometry": { "type": "Geometry", "properties": { "geometryType": "box", "args": [40, 1, 40] } },
|
|
164
|
-
"material": { "type": "Material", "properties": { "color": "white", "texture": "/textures/GreyboxTextures/greybox_dark_grid.png", "repeat": true, "repeatCount": [20, 20] } },
|
|
165
|
-
"physics": { "type": "Physics", "properties": { "type": "fixed" } }
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Platform Pattern
|
|
171
|
-
|
|
172
|
-
Floating platforms use "fixed" physics and smaller box geometry:
|
|
173
|
-
|
|
174
|
-
```json
|
|
175
|
-
{
|
|
176
|
-
"id": "platform-1",
|
|
177
|
-
"components": {
|
|
178
|
-
"transform": { "type": "Transform", "properties": { "position": [-8, 2, -5] } },
|
|
179
|
-
"geometry": { "type": "Geometry", "properties": { "geometryType": "box", "args": [6, 0.5, 4] } },
|
|
180
|
-
"material": { "type": "Material", "properties": { "color": "white", "texture": "/textures/GreyboxTextures/greybox_teal_grid.png", "repeat": true, "repeatCount": [3, 2] } },
|
|
181
|
-
"physics": { "type": "Physics", "properties": { "type": "fixed" } }
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### Ramp Pattern
|
|
187
|
-
|
|
188
|
-
Rotate on the Z-axis to create inclined surfaces:
|
|
189
|
-
|
|
190
|
-
```json
|
|
191
|
-
{
|
|
192
|
-
"id": "ramp",
|
|
193
|
-
"components": {
|
|
194
|
-
"transform": { "type": "Transform", "properties": { "position": [-12, 1, -5], "rotation": [0, 0, 0.3] } },
|
|
195
|
-
"geometry": { "type": "Geometry", "properties": { "geometryType": "box", "args": [5, 0.3, 3] } },
|
|
196
|
-
"physics": { "type": "Physics", "properties": { "type": "fixed" } }
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### Wall Pattern
|
|
202
|
-
|
|
203
|
-
Tall thin boxes positioned at boundaries:
|
|
204
|
-
|
|
205
|
-
```json
|
|
206
|
-
{
|
|
207
|
-
"id": "wall-back",
|
|
208
|
-
"components": {
|
|
209
|
-
"transform": { "type": "Transform", "properties": { "position": [0, 3, -20] } },
|
|
210
|
-
"geometry": { "type": "Geometry", "properties": { "geometryType": "box", "args": [40, 7, 1] } },
|
|
211
|
-
"physics": { "type": "Physics", "properties": { "type": "fixed" } }
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Three-Point Lighting Setup
|
|
217
|
-
|
|
218
|
-
Good lighting uses main, fill, and accent lights:
|
|
219
|
-
|
|
220
|
-
```json
|
|
221
|
-
[
|
|
222
|
-
{ "id": "main-light", "components": { "transform": { "properties": { "position": [10, 15, 10] } }, "spotlight": { "type": "SpotLight", "properties": { "color": "#ffffff", "intensity": 200, "angle": 0.8, "castShadow": true } } } },
|
|
223
|
-
{ "id": "fill-light", "components": { "transform": { "properties": { "position": [-10, 12, -5] } }, "spotlight": { "type": "SpotLight", "properties": { "color": "#b0c4de", "intensity": 80, "angle": 0.9 } } } },
|
|
224
|
-
{ "id": "accent-light", "components": { "transform": { "properties": { "position": [0, 10, -15] } }, "spotlight": { "type": "SpotLight", "properties": { "color": "#ffd700", "intensity": 50, "angle": 0.4 } } } }
|
|
225
|
-
]
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
### Available Greybox Textures
|
|
229
|
-
|
|
230
|
-
Located in `/textures/GreyboxTextures/`:
|
|
231
|
-
- `greybox_dark_grid.png` - dark floors
|
|
232
|
-
- `greybox_light_grid.png` - light surfaces
|
|
233
|
-
- `greybox_teal_grid.png`, `greybox_purple_grid.png`, `greybox_orange_grid.png` - colored platforms
|
|
234
|
-
- `greybox_red_grid.png`, `greybox_blue_grid.png` - obstacles/hazards
|
|
235
|
-
- `greybox_yellow_grid.png`, `greybox_lime_grid.png`, `greybox_green_grid.png` - special areas
|
|
236
|
-
|
|
237
|
-
### Metallic/Special Materials
|
|
238
|
-
|
|
239
|
-
For goal platforms or special objects, use metalness and roughness:
|
|
240
|
-
|
|
241
|
-
```json
|
|
242
|
-
{
|
|
243
|
-
"type": "Material",
|
|
244
|
-
"properties": {
|
|
245
|
-
"color": "#FFD700",
|
|
246
|
-
"metalness": 0.8,
|
|
247
|
-
"roughness": 0.2
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### Text Component
|
|
253
|
-
|
|
254
|
-
3D text rendering using `three-text`. The Text component is non-composable (cannot have children).
|
|
255
|
-
|
|
256
|
-
| Property | Type | Default | Description |
|
|
257
|
-
|----------|------|---------|-------------|
|
|
258
|
-
| `text` | string | `"Hello World"` | Text content to display |
|
|
259
|
-
| `color` | string | `"#888888"` | Text color (hex or CSS color) |
|
|
260
|
-
| `font` | string | `"/fonts/NotoSans-Regular.ttf"` | Path to TTF font file |
|
|
261
|
-
| `size` | number | `0.5` | Font size in world units |
|
|
262
|
-
| `depth` | number | `0` | 3D extrusion depth (0 for flat text) |
|
|
263
|
-
| `width` | number | `5` | Text block width for wrapping/alignment |
|
|
264
|
-
| `align` | string | `"center"` | Horizontal alignment: `"left"`, `"center"`, `"right"` |
|
|
265
|
-
|
|
266
|
-
```json
|
|
267
|
-
{
|
|
268
|
-
"id": "title-text",
|
|
269
|
-
"components": {
|
|
270
|
-
"transform": { "type": "Transform", "properties": { "position": [0, 3, 0] } },
|
|
271
|
-
"text": {
|
|
272
|
-
"type": "Text",
|
|
273
|
-
"properties": {
|
|
274
|
-
"text": "Welcome",
|
|
275
|
-
"color": "#ffffff",
|
|
276
|
-
"size": 1,
|
|
277
|
-
"depth": 0.1,
|
|
278
|
-
"align": "center"
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
### Model Placement
|
|
286
|
-
|
|
287
|
-
GLB models don't need geometry/material components:
|
|
288
|
-
|
|
289
|
-
```json
|
|
290
|
-
{
|
|
291
|
-
"id": "tree-1",
|
|
292
|
-
"components": {
|
|
293
|
-
"transform": { "type": "Transform", "properties": { "position": [-12, 0, 10], "scale": [1.5, 1.5, 1.5] } },
|
|
294
|
-
"model": { "type": "Model", "properties": { "filename": "models/environment/tree.glb" } }
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
Available models: `models/environment/tree.glb`, `models/environment/servers.glb`, `models/environment/cubeart.glb`
|
|
300
|
-
|
|
301
|
-
## Editor Mode
|
|
302
|
-
|
|
303
|
-
Use editor mode when building scenes visually or creating custom components with inspector UI.
|
|
304
|
-
|
|
305
|
-
### Using the Visual Editor
|
|
306
|
-
|
|
307
|
-
```jsx
|
|
308
|
-
import { PrefabEditor } from 'react-three-game';
|
|
309
|
-
|
|
310
|
-
<PrefabEditor
|
|
311
|
-
initialPrefab={sceneData}
|
|
312
|
-
onPrefabChange={setSceneData}
|
|
313
|
-
/>
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
The editor provides a full GUI with:
|
|
317
|
-
- Scene hierarchy tree for navigating and selecting objects
|
|
318
|
-
- Component inspector panel for editing properties
|
|
319
|
-
- Transform gizmos for manipulating objects visually
|
|
320
|
-
- Keyboard shortcuts: **T** (Translate), **R** (Rotate), **S** (Scale)
|
|
321
|
-
|
|
322
|
-
### Programmatic Updates with PrefabEditor
|
|
323
|
-
|
|
324
|
-
Use the editor ref to update prefabs programmatically:
|
|
325
|
-
|
|
326
|
-
```jsx
|
|
327
|
-
import { useRef } from 'react';
|
|
328
|
-
import { PrefabEditor, updateNodeById } from 'react-three-game';
|
|
329
|
-
import type { PrefabEditorRef, Prefab } from 'react-three-game';
|
|
330
|
-
|
|
331
|
-
function Game() {
|
|
332
|
-
const editorRef = useRef<PrefabEditorRef>(null);
|
|
333
|
-
|
|
334
|
-
const movePlayer = () => {
|
|
335
|
-
if (!editorRef.current) return;
|
|
336
|
-
const prefab = editorRef.current.prefab;
|
|
337
|
-
const newRoot = updateNodeById(prefab.root, "player", node => ({
|
|
338
|
-
...node,
|
|
339
|
-
components: {
|
|
340
|
-
...node.components,
|
|
341
|
-
transform: {
|
|
342
|
-
...node.components!.transform!,
|
|
343
|
-
properties: { ...node.components!.transform!.properties, position: [5, 0, 0] }
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}));
|
|
347
|
-
editorRef.current.setPrefab({ ...prefab, root: newRoot });
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
return (
|
|
351
|
-
<PrefabEditor ref={editorRef} initialPrefab={sceneData}>
|
|
352
|
-
{/* Children render inside the Canvas - can use useFrame here */}
|
|
353
|
-
</PrefabEditor>
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
The `PrefabEditorRef` provides:
|
|
359
|
-
- `prefab` - current prefab state
|
|
360
|
-
- `setPrefab(prefab)` - update the prefab
|
|
361
|
-
- `screenshot()` - save canvas as PNG
|
|
362
|
-
- `exportGLB()` - export scene as GLB
|
|
363
|
-
|
|
364
|
-
### Live Node Updates with useFrame
|
|
365
|
-
|
|
366
|
-
To animate objects by updating the prefab JSON at runtime, pass a child component to `PrefabEditor` that uses `useFrame`:
|
|
367
|
-
|
|
368
|
-
```tsx
|
|
369
|
-
import { useRef } from "react";
|
|
370
|
-
import { useFrame } from "@react-three/fiber";
|
|
371
|
-
import { PrefabEditor, updateNodeById } from "react-three-game";
|
|
372
|
-
import type { Prefab, PrefabEditorRef } from "react-three-game";
|
|
373
|
-
|
|
374
|
-
// Animation component runs inside the editor's Canvas
|
|
375
|
-
function PlayerAnimator({ editorRef }: { editorRef: React.RefObject<PrefabEditorRef | null> }) {
|
|
376
|
-
const velocityRef = useRef({ x: 0, z: 0 });
|
|
377
|
-
|
|
378
|
-
useFrame(() => {
|
|
379
|
-
if (!editorRef.current) return;
|
|
380
|
-
|
|
381
|
-
const prefab = editorRef.current.prefab;
|
|
382
|
-
const newRoot = updateNodeById(prefab.root, "player", (node) => {
|
|
383
|
-
const transform = node.components?.transform?.properties;
|
|
384
|
-
if (!transform) return node;
|
|
385
|
-
|
|
386
|
-
const pos = transform.position as [number, number, number];
|
|
387
|
-
return {
|
|
388
|
-
...node,
|
|
389
|
-
components: {
|
|
390
|
-
...node.components,
|
|
391
|
-
transform: {
|
|
392
|
-
...node.components!.transform!,
|
|
393
|
-
properties: {
|
|
394
|
-
...transform,
|
|
395
|
-
position: [pos[0] + velocityRef.current.x * 0.02, pos[1], pos[2] + velocityRef.current.z * 0.02],
|
|
396
|
-
},
|
|
397
|
-
},
|
|
398
|
-
},
|
|
399
|
-
};
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
if (newRoot !== prefab.root) {
|
|
403
|
-
editorRef.current.setPrefab({ ...prefab, root: newRoot });
|
|
404
|
-
}
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
return null;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Usage
|
|
411
|
-
function Game() {
|
|
412
|
-
const editorRef = useRef<PrefabEditorRef>(null);
|
|
413
|
-
|
|
414
|
-
return (
|
|
415
|
-
<PrefabEditor ref={editorRef} initialPrefab={sceneData}>
|
|
416
|
-
<PlayerAnimator editorRef={editorRef} />
|
|
417
|
-
</PrefabEditor>
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
Key points:
|
|
423
|
-
- Pass animation components as `children` to `PrefabEditor` - they render inside the Canvas
|
|
424
|
-
- Access prefab via `editorRef.current.prefab` and update via `editorRef.current.setPrefab()`
|
|
425
|
-
- `updateNodeById` is optimized to avoid recreating unchanged branches
|
|
426
|
-
- Store mutable state (velocities, timers) in refs to avoid re-renders
|
|
427
|
-
|
|
428
|
-
### Creating a Custom Component
|
|
429
|
-
|
|
430
|
-
```tsx
|
|
431
|
-
import { Component, registerComponent, FieldRenderer, FieldDefinition } from 'react-three-game';
|
|
432
|
-
|
|
433
|
-
const myFields: FieldDefinition[] = [
|
|
434
|
-
{ name: 'speed', type: 'number', label: 'Speed', step: 0.1 },
|
|
435
|
-
{ name: 'enabled', type: 'boolean', label: 'Enabled' },
|
|
436
|
-
];
|
|
437
|
-
|
|
438
|
-
const MyComponent: Component = {
|
|
439
|
-
name: 'MyComponent',
|
|
440
|
-
Editor: ({ component, onUpdate }) => (
|
|
441
|
-
<FieldRenderer fields={myFields} values={component.properties} onChange={onUpdate} />
|
|
442
|
-
),
|
|
443
|
-
View: ({ properties, children }) => {
|
|
444
|
-
// Runtime behavior here
|
|
445
|
-
return <group>{children}</group>;
|
|
446
|
-
},
|
|
447
|
-
defaultProperties: { speed: 1, enabled: true }
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
registerComponent(MyComponent);
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
### Field Types for Editor UI
|
|
454
|
-
|
|
455
|
-
| Type | Description | Options |
|
|
456
|
-
|------|-------------|---------|
|
|
457
|
-
| `vector3` | X/Y/Z inputs | `snap?: number` |
|
|
458
|
-
| `number` | Numeric input | `min?`, `max?`, `step?` |
|
|
459
|
-
| `string` | Text input | `placeholder?` |
|
|
460
|
-
| `color` | Color picker | - |
|
|
461
|
-
| `boolean` | Checkbox | - |
|
|
462
|
-
| `select` | Dropdown | `options: { value, label }[]` |
|
|
463
|
-
| `custom` | Custom render function | `render: (props) => ReactNode` |
|
|
464
|
-
|
|
465
|
-
## Dependencies
|
|
466
|
-
|
|
467
|
-
Required peer dependencies:
|
|
468
|
-
- `@react-three/fiber`
|
|
469
|
-
- `@react-three/rapier`
|
|
470
|
-
- `three`
|
|
471
|
-
|
|
472
|
-
Install with:
|
|
473
|
-
```bash
|
|
474
|
-
npm i react-three-game @react-three/fiber @react-three/rapier three
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
## File Structure
|
|
478
|
-
|
|
479
|
-
```
|
|
480
|
-
/src → library source (published to npm)
|
|
481
|
-
/docs → Next.js demo site
|
|
482
|
-
/dist → built output
|
|
483
|
-
```
|
|
484
|
-
|
|
485
|
-
## Development Commands
|
|
486
|
-
|
|
487
|
-
```bash
|
|
488
|
-
npm run dev # tsc --watch + docs site
|
|
489
|
-
npm run build # build to /dist
|
|
490
|
-
npm run release # build + publish
|
|
491
|
-
```
|
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
|
-
}
|