react-three-game 0.0.45 → 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/assets/architecture.png +0 -0
- package/dist/index.d.ts +1 -0
- package/dist/tools/prefabeditor/PrefabEditor.js +4 -13
- package/dist/tools/prefabeditor/PrefabRoot.js +8 -3
- package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +2 -0
- package/dist/tools/prefabeditor/components/ComponentRegistry.js +5 -0
- package/dist/tools/prefabeditor/components/GeometryComponent.js +1 -0
- package/dist/tools/prefabeditor/components/MaterialComponent.js +3 -2
- package/dist/tools/prefabeditor/components/ModelComponent.js +1 -0
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +1 -0
- package/dist/tools/prefabeditor/components/TextComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/TextComponent.js +103 -0
- package/dist/tools/prefabeditor/components/TransformComponent.js +1 -0
- package/dist/tools/prefabeditor/components/index.js +3 -1
- package/dist/tools/prefabeditor/utils.d.ts +20 -0
- package/dist/tools/prefabeditor/utils.js +51 -0
- package/package.json +3 -2
- package/react-three-game-skill/.gitattributes +2 -0
- package/react-three-game-skill/react-three-game/SKILL.md +609 -0
- package/src/index.ts +1 -0
- package/src/tools/prefabeditor/PrefabEditor.tsx +4 -19
- package/src/tools/prefabeditor/PrefabRoot.tsx +11 -2
- package/src/tools/prefabeditor/components/ComponentRegistry.ts +8 -0
- package/src/tools/prefabeditor/components/GeometryComponent.tsx +1 -0
- package/src/tools/prefabeditor/components/MaterialComponent.tsx +1 -2
- package/src/tools/prefabeditor/components/ModelComponent.tsx +1 -0
- package/src/tools/prefabeditor/components/PhysicsComponent.tsx +1 -0
- package/src/tools/prefabeditor/components/TextComponent.tsx +136 -0
- package/src/tools/prefabeditor/components/TransformComponent.tsx +1 -0
- package/src/tools/prefabeditor/components/index.ts +3 -1
- package/src/tools/prefabeditor/utils.ts +69 -0
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/assets/architecture.png
CHANGED
|
Binary file
|
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');
|
|
@@ -11,7 +11,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
11
11
|
import { MapControls, TransformControls, useHelper } from "@react-three/drei";
|
|
12
12
|
import { forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
13
13
|
import { BoxHelper, Euler, Matrix4, Quaternion, SRGBColorSpace, TextureLoader, Vector3, } from "three";
|
|
14
|
-
import { getComponent, registerComponent } from "./components/ComponentRegistry";
|
|
14
|
+
import { getComponent, registerComponent, getNonComposableKeys } from "./components/ComponentRegistry";
|
|
15
15
|
import components from "./components";
|
|
16
16
|
import { loadModel } from "../dragdrop/modelLoader";
|
|
17
17
|
import { GameInstance, GameInstanceProvider, useInstanceCheck } from "./InstanceProvider";
|
|
@@ -245,13 +245,15 @@ function computeParentWorldMatrix(root, targetId) {
|
|
|
245
245
|
return result !== null && result !== void 0 ? result : IDENTITY;
|
|
246
246
|
}
|
|
247
247
|
function renderCoreNode(gameObject, ctx, parentMatrix) {
|
|
248
|
-
var _a, _b, _c;
|
|
248
|
+
var _a, _b, _c, _d;
|
|
249
249
|
const geometry = (_a = gameObject.components) === null || _a === void 0 ? void 0 : _a.geometry;
|
|
250
250
|
const material = (_b = gameObject.components) === null || _b === void 0 ? void 0 : _b.material;
|
|
251
251
|
const model = (_c = gameObject.components) === null || _c === void 0 ? void 0 : _c.model;
|
|
252
|
+
const text = (_d = gameObject.components) === null || _d === void 0 ? void 0 : _d.text;
|
|
252
253
|
const geometryDef = geometry && getComponent("Geometry");
|
|
253
254
|
const materialDef = material && getComponent("Material");
|
|
254
255
|
const modelDef = model && getComponent("Model");
|
|
256
|
+
const textDef = text && getComponent("Text");
|
|
255
257
|
const contextProps = {
|
|
256
258
|
loadedModels: ctx.loadedModels,
|
|
257
259
|
loadedTextures: ctx.loadedTextures,
|
|
@@ -263,7 +265,7 @@ function renderCoreNode(gameObject, ctx, parentMatrix) {
|
|
|
263
265
|
const leaves = [];
|
|
264
266
|
if (gameObject.components) {
|
|
265
267
|
Object.entries(gameObject.components)
|
|
266
|
-
.filter(([k]) => !
|
|
268
|
+
.filter(([k]) => !getNonComposableKeys().includes(k))
|
|
267
269
|
.forEach(([key, comp]) => {
|
|
268
270
|
if (!(comp === null || comp === void 0 ? void 0 : comp.type))
|
|
269
271
|
return;
|
|
@@ -285,6 +287,9 @@ function renderCoreNode(gameObject, ctx, parentMatrix) {
|
|
|
285
287
|
else if (geometry && (geometryDef === null || geometryDef === void 0 ? void 0 : geometryDef.View)) {
|
|
286
288
|
core = (_jsxs("mesh", { castShadow: true, receiveShadow: true, children: [_jsx(geometryDef.View, Object.assign({ properties: geometry.properties }, contextProps)), material && (materialDef === null || materialDef === void 0 ? void 0 : materialDef.View) && (_jsx(materialDef.View, Object.assign({ properties: material.properties }, contextProps), "material")), leaves] }));
|
|
287
289
|
}
|
|
290
|
+
else if (text && (textDef === null || textDef === void 0 ? void 0 : textDef.View)) {
|
|
291
|
+
core = (_jsxs(_Fragment, { children: [_jsx(textDef.View, Object.assign({ properties: text.properties }, contextProps)), leaves] }));
|
|
292
|
+
}
|
|
288
293
|
else {
|
|
289
294
|
core = _jsx(_Fragment, { children: leaves });
|
|
290
295
|
}
|
|
@@ -10,7 +10,9 @@ export interface Component {
|
|
|
10
10
|
}>;
|
|
11
11
|
defaultProperties: any;
|
|
12
12
|
View?: FC<any>;
|
|
13
|
+
nonComposable?: boolean;
|
|
13
14
|
}
|
|
14
15
|
export declare function registerComponent(component: Component): void;
|
|
15
16
|
export declare function getComponent(name: string): Component | undefined;
|
|
16
17
|
export declare function getAllComponents(): Record<string, Component>;
|
|
18
|
+
export declare function getNonComposableKeys(): string[];
|
|
@@ -11,3 +11,8 @@ export function getComponent(name) {
|
|
|
11
11
|
export function getAllComponents() {
|
|
12
12
|
return Object.assign({}, REGISTRY);
|
|
13
13
|
}
|
|
14
|
+
export function getNonComposableKeys() {
|
|
15
|
+
return Object.values(REGISTRY)
|
|
16
|
+
.filter(c => c.nonComposable)
|
|
17
|
+
.map(c => c.name.toLowerCase());
|
|
18
|
+
}
|
|
@@ -3,7 +3,7 @@ import { SingleTextureViewer, TextureListViewer } from '../../assetviewer/page';
|
|
|
3
3
|
import { useEffect, useState } from 'react';
|
|
4
4
|
import { FieldRenderer, Input } from './Input';
|
|
5
5
|
import { useMemo } from 'react';
|
|
6
|
-
import {
|
|
6
|
+
import { RepeatWrapping, ClampToEdgeWrapping, SRGBColorSpace, NearestFilter, LinearFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter, LinearMipmapNearestFilter, LinearMipmapLinearFilter } from 'three';
|
|
7
7
|
function TexturePicker({ value, onChange, basePath }) {
|
|
8
8
|
const [textureFiles, setTextureFiles] = useState([]);
|
|
9
9
|
const [showPicker, setShowPicker] = useState(false);
|
|
@@ -117,12 +117,13 @@ function MaterialComponentView({ properties, loadedTextures }) {
|
|
|
117
117
|
return _jsx("meshStandardMaterial", { color: "red", wireframe: true });
|
|
118
118
|
}
|
|
119
119
|
const { color, wireframe = false } = properties;
|
|
120
|
-
return (_jsx("meshStandardMaterial", { color: color, wireframe: wireframe, map: finalTexture, transparent: !!finalTexture
|
|
120
|
+
return (_jsx("meshStandardMaterial", { color: color, wireframe: wireframe, map: finalTexture, transparent: !!finalTexture }, (_a = finalTexture === null || finalTexture === void 0 ? void 0 : finalTexture.uuid) !== null && _a !== void 0 ? _a : 'no-texture'));
|
|
121
121
|
}
|
|
122
122
|
const MaterialComponent = {
|
|
123
123
|
name: 'Material',
|
|
124
124
|
Editor: MaterialComponentEditor,
|
|
125
125
|
View: MaterialComponentView,
|
|
126
|
+
nonComposable: true,
|
|
126
127
|
defaultProperties: {
|
|
127
128
|
color: '#ffffff',
|
|
128
129
|
wireframe: false
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { FieldRenderer } from "./Input";
|
|
3
|
+
import { Text } from 'three-text/three/react';
|
|
4
|
+
import { useRef, useState, useCallback } from 'react';
|
|
5
|
+
// Initialize HarfBuzz path for font shaping
|
|
6
|
+
Text.setHarfBuzzPath('/fonts/hb.wasm');
|
|
7
|
+
function TextComponentEditor({ component, onUpdate, }) {
|
|
8
|
+
const fields = [
|
|
9
|
+
{
|
|
10
|
+
name: 'text',
|
|
11
|
+
type: 'string',
|
|
12
|
+
label: 'Text',
|
|
13
|
+
placeholder: 'Enter text...',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'color',
|
|
17
|
+
type: 'color',
|
|
18
|
+
label: 'Color',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'font',
|
|
22
|
+
type: 'string',
|
|
23
|
+
label: 'Font',
|
|
24
|
+
placeholder: '/fonts/NotoSans-Regular.ttf',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'size',
|
|
28
|
+
type: 'number',
|
|
29
|
+
label: 'Size',
|
|
30
|
+
min: 0.01,
|
|
31
|
+
step: 0.1,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'depth',
|
|
35
|
+
type: 'number',
|
|
36
|
+
label: 'Depth',
|
|
37
|
+
min: 0,
|
|
38
|
+
step: 0.1,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'width',
|
|
42
|
+
type: 'number',
|
|
43
|
+
label: 'Width',
|
|
44
|
+
min: 0,
|
|
45
|
+
step: 0.5,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'align',
|
|
49
|
+
type: 'select',
|
|
50
|
+
label: 'Align',
|
|
51
|
+
options: [
|
|
52
|
+
{ value: 'left', label: 'Left' },
|
|
53
|
+
{ value: 'center', label: 'Center' },
|
|
54
|
+
{ value: 'right', label: 'Right' },
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
return (_jsx(FieldRenderer, { fields: fields, values: component.properties, onChange: onUpdate }));
|
|
59
|
+
}
|
|
60
|
+
function TextComponentView({ properties }) {
|
|
61
|
+
const { text = '', font, size, depth, width, align, color } = properties;
|
|
62
|
+
const textContent = String(text || '');
|
|
63
|
+
const meshRef = useRef(null);
|
|
64
|
+
const [offset, setOffset] = useState([0, 0, 0]);
|
|
65
|
+
const handleLoad = useCallback((_geometry, info) => {
|
|
66
|
+
if (info === null || info === void 0 ? void 0 : info.planeBounds) {
|
|
67
|
+
const bounds = info.planeBounds;
|
|
68
|
+
// Calculate X offset based on alignment
|
|
69
|
+
let centerX = 0;
|
|
70
|
+
if (align === 'center') {
|
|
71
|
+
centerX = -(bounds.min.x + bounds.max.x) / 2;
|
|
72
|
+
}
|
|
73
|
+
else if (align === 'right') {
|
|
74
|
+
centerX = -bounds.max.x;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// left alignment
|
|
78
|
+
centerX = -bounds.min.x;
|
|
79
|
+
}
|
|
80
|
+
const centerY = -(bounds.min.y + bounds.max.y) / 2;
|
|
81
|
+
setOffset([centerX, centerY, 0]);
|
|
82
|
+
}
|
|
83
|
+
}, [align]);
|
|
84
|
+
if (!textContent)
|
|
85
|
+
return null;
|
|
86
|
+
return (_jsx("group", { position: offset, children: _jsx(Text, { ref: meshRef, font: font, size: size, depth: depth, layout: { align, width }, color: color, onLoad: handleLoad, children: textContent }) }));
|
|
87
|
+
}
|
|
88
|
+
const TextComponent = {
|
|
89
|
+
name: 'Text',
|
|
90
|
+
Editor: TextComponentEditor,
|
|
91
|
+
View: TextComponentView,
|
|
92
|
+
nonComposable: true,
|
|
93
|
+
defaultProperties: {
|
|
94
|
+
text: 'Hello World',
|
|
95
|
+
color: '#888888',
|
|
96
|
+
font: '/fonts/NotoSans-Regular.ttf',
|
|
97
|
+
size: 0.5,
|
|
98
|
+
depth: 0,
|
|
99
|
+
width: 5,
|
|
100
|
+
align: 'center',
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
export default TextComponent;
|
|
@@ -5,6 +5,7 @@ import PhysicsComponent from './PhysicsComponent';
|
|
|
5
5
|
import SpotLightComponent from './SpotLightComponent';
|
|
6
6
|
import DirectionalLightComponent from './DirectionalLightComponent';
|
|
7
7
|
import ModelComponent from './ModelComponent';
|
|
8
|
+
import TextComponent from './TextComponent';
|
|
8
9
|
export default [
|
|
9
10
|
GeometryComponent,
|
|
10
11
|
TransformComponent,
|
|
@@ -12,5 +13,6 @@ export default [
|
|
|
12
13
|
PhysicsComponent,
|
|
13
14
|
SpotLightComponent,
|
|
14
15
|
DirectionalLightComponent,
|
|
15
|
-
ModelComponent
|
|
16
|
+
ModelComponent,
|
|
17
|
+
TextComponent
|
|
16
18
|
];
|
|
@@ -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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-three-game",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.47",
|
|
4
4
|
"description": "Batteries included React Three Fiber game engine",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"@react-three/rapier": ">=2.0.0",
|
|
25
25
|
"react": ">=18.0.0",
|
|
26
26
|
"react-dom": ">=18.0.0",
|
|
27
|
-
"three": ">=0.182.0"
|
|
27
|
+
"three": ">=0.182.0",
|
|
28
|
+
"three-text": ">=0.4.4"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@react-three/drei": "^10.7.7",
|