@nayan-ui/engine 1.0.0-beta.4 → 1.0.0-beta.5
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 +135 -117
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,13 +4,29 @@
|
|
|
4
4
|
|
|
5
5
|
A fast 3D game engine for **React** and **React Native**. One TypeScript API on one Rust core: rendering (wgpu), physics (Rapier), skeletal and tween animation, particles, audio, haptics and 2D drawing.
|
|
6
6
|
|
|
7
|
-
**[Documentation](https://www.nayanui.com/game-engine)** · **[First game tutorial](https://www.nayanui.com/game-engine/first-game)** · **[API reference](https://www.nayanui.com/game-engine/api-reference)** · **[Guide for AI agents](https://www.nayanui.com/game-engine/agent-guide)**
|
|
7
|
+
**[Documentation](https://www.nayanui.com/game-engine)** · **[First game tutorial](https://www.nayanui.com/game-engine/first-game)** · **[API reference](https://www.nayanui.com/game-engine/api-reference)** · **[Guide for AI agents](https://www.nayanui.com/game-engine/agent-guide)** · **[Prebuilt games](https://www.nayanui.com/games)**
|
|
8
|
+
|
|
9
|
+
## Contents
|
|
10
|
+
|
|
11
|
+
- [Features](#features)
|
|
12
|
+
- [Install](#install)
|
|
13
|
+
- [Quick start](#quick-start)
|
|
14
|
+
- [Core concepts](#core-concepts)
|
|
15
|
+
- [Guides](#guides): [Entities](#entities) · [Game loop](#game-loop) · [Physics](#physics) · [Animation](#animation) · [Characters](#characters) · [Effects](#effects) · [Input](#input) · [Assets](#assets) · [Sound and haptics](#sound-and-haptics) · [Score and timers](#score-and-timers) · [Shapes in code](#shapes-in-code) · [Flat boards](#flat-boards-and-puzzles) · [Drawing](#drawing) · [Colors](#colors)
|
|
16
|
+
- [Performance](#performance)
|
|
17
|
+
- [Troubleshooting](#troubleshooting)
|
|
18
|
+
- [Prebuilt games](#prebuilt-games)
|
|
19
|
+
- [Learn more](#learn-more)
|
|
20
|
+
|
|
21
|
+
## Features
|
|
8
22
|
|
|
9
23
|
- **Native speed on phones.** Rendering, physics, animation, culling and audio mixing run in Rust. On iOS and Android the game loop follows the display's clock, and frames are drawn on the engine's own render thread, so your JavaScript never waits on the GPU.
|
|
10
24
|
- **Small API.** `useWorld` + `GameView` is a complete scene. Spawn entities, move them, animate them: the engine steps, draws and cleans up.
|
|
11
25
|
- **Fast loading.** Images, glTF models, fonts and sounds decode on native background threads, and procedural meshes can be cached on disk between launches.
|
|
12
26
|
- **Same code on the web.** The core compiles to WebAssembly and draws with WebGPU, falling back to WebGL2.
|
|
13
27
|
|
|
28
|
+
### Platforms
|
|
29
|
+
|
|
14
30
|
| Platform | Renders with | Needs |
|
|
15
31
|
| ----------- | ------------------------------ | --------------------------------------------------------- |
|
|
16
32
|
| iOS | Metal | A development or store build (Expo Go doesn't include it) |
|
|
@@ -78,7 +94,7 @@ export function BouncingBall() {
|
|
|
78
94
|
|
|
79
95
|
`useWorld` warms the engine up, creates the world (100 entity slots), runs your setup and disposes it on unmount. `GameView` draws it and steps it every frame.
|
|
80
96
|
|
|
81
|
-
##
|
|
97
|
+
## Core concepts
|
|
82
98
|
|
|
83
99
|
1. **Own** a world with `useWorld(capacity, setup)`, or create it yourself after `await warmUpEngine()` and `dispose()` it on unmount.
|
|
84
100
|
2. **Play** in `GameView`'s `onUpdate(dt)`: read input, move things, spawn. The world is stepped for you right after (call `world.update(dt)` yourself only to step it earlier or with another `dt`).
|
|
@@ -86,148 +102,79 @@ export function BouncingBall() {
|
|
|
86
102
|
4. **Batch per-frame moves** in `world.transforms`: they are applied in one native call when the world steps (`flush()` yourself before reading positions).
|
|
87
103
|
5. **Don't track disposal yourself**: check `world.isDisposed`. Cleanup calls are safe no-ops after `dispose()`.
|
|
88
104
|
|
|
89
|
-
##
|
|
105
|
+
## Guides
|
|
90
106
|
|
|
91
|
-
|
|
107
|
+
Each snippet assumes a `world` from `useWorld`.
|
|
92
108
|
|
|
93
|
-
|
|
94
|
-
- **Culling in Rust.** Everything outside the camera's view (and outside the light's box for shadows) is skipped every frame, so open levels and long tracks only pay for what is on screen. Don't cull scenery in JS.
|
|
95
|
-
- **Automatic quality.** `quality="auto"` (the default) starts at `high` and steps down (shadow detail first, then anti-aliasing, resolution last) only while the device can't keep up. `onStats` reports fps, update and render time, the quality chosen and the graphics backend.
|
|
96
|
-
- **Background loading.** `loadTexture`, `loadModel`, `loadFont` and `audio.load` decode on native threads in parallel, and meshes are registered with the renderer inside Rust.
|
|
97
|
-
- **Work between frames.** `afterNextFrame(fn)` runs `fn` right after the next frame leaves, so you can spread long setup work (map generation, mesh building) over several frames behind a loading screen.
|
|
98
|
-
- **Cached procedural assets.** `ProceduralCache` saves built geometry on disk keyed by a recipe, so later launches restore it instead of rebuilding; `peek(key)` returns a saved value without building anything.
|
|
109
|
+
### Entities
|
|
99
110
|
|
|
100
|
-
|
|
111
|
+
```ts
|
|
112
|
+
const box = world.spawn({ mesh: 'cube', position: [0, 1, 0], color: '#FF4757' });
|
|
113
|
+
world.set(box, { color: '#2ED573', scale: 2 }); // only the options you pass change
|
|
114
|
+
world.despawn(box);
|
|
115
|
+
```
|
|
101
116
|
|
|
102
|
-
-
|
|
103
|
-
- Move many things each frame through `world.transforms` and the `out` arguments of queries, which allocate nothing.
|
|
104
|
-
- Keep long one-off jobs out of gameplay frames: a single slow frame stalls Android's Hermes far longer than desktop JavaScript suggests.
|
|
117
|
+
Built-in meshes include `'cube'`, `'sphere'`, `'plane'` and `'cylinder'`.
|
|
105
118
|
|
|
106
|
-
|
|
119
|
+
### Game loop
|
|
107
120
|
|
|
108
|
-
|
|
121
|
+
```tsx
|
|
122
|
+
<GameView
|
|
123
|
+
source={world}
|
|
124
|
+
onUpdate={(dt) => {
|
|
125
|
+
world.transforms.set(player, { position: [x, 0, z] }); // batched, applied as the world steps
|
|
126
|
+
}}
|
|
127
|
+
/>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Physics
|
|
109
131
|
|
|
110
132
|
```ts
|
|
111
133
|
const ball = world.spawn({ mesh: 'sphere', position: [0, 5, 0], physics: { type: 'dynamic', bounce: 0.6 } });
|
|
112
134
|
const coin = world.spawn({ mesh: 'cylinder', position: [2, 1, 0], physics: { type: 'fixed', sensor: true } });
|
|
135
|
+
|
|
113
136
|
world.impulse(ball, [0, 4, 0]);
|
|
114
137
|
world.forEachCollision((a, b, { started }) => {
|
|
115
138
|
if (started && (a === coin || b === coin)) world.despawn(coin);
|
|
116
139
|
});
|
|
117
140
|
```
|
|
118
141
|
|
|
119
|
-
|
|
142
|
+
### Animation
|
|
143
|
+
|
|
144
|
+
Tweens run in Rust and return a Promise.
|
|
120
145
|
|
|
121
146
|
```ts
|
|
122
|
-
await world.animate(
|
|
147
|
+
await world.animate(box, { position: [2, 0, 3] }, { duration: 0.25, easing: 'back' });
|
|
123
148
|
world.animate(star, { scale: 1.2 }, { repeat: 'forever', yoyo: true });
|
|
124
149
|
```
|
|
125
150
|
|
|
126
|
-
|
|
151
|
+
### Characters
|
|
152
|
+
|
|
153
|
+
glTF clips play natively, with crossfades.
|
|
127
154
|
|
|
128
155
|
```ts
|
|
129
156
|
const hero = await loadModel(require('./hero.glb'));
|
|
130
|
-
console.log(hero.animations.map((clip) => clip.name)); // e.g. ['idle', 'walk', 'run']
|
|
131
157
|
const player = world.spawn({ mesh: hero });
|
|
132
|
-
|
|
133
|
-
world.playClip(player, '
|
|
158
|
+
|
|
159
|
+
world.playClip(player, 'idle');
|
|
160
|
+
world.playClip(player, 'run', { fade: 0.2 });
|
|
134
161
|
world.stopClip(player);
|
|
135
162
|
```
|
|
136
163
|
|
|
137
|
-
`world.sampleSkinnedVertices` reads chosen vertices of the next pose (for planting feet on uneven ground)
|
|
164
|
+
Clip names are in `hero.animations`. `world.sampleSkinnedVertices` reads chosen vertices of the next pose (for planting feet on uneven ground).
|
|
138
165
|
|
|
139
|
-
|
|
166
|
+
### Effects
|
|
140
167
|
|
|
141
168
|
```ts
|
|
142
169
|
import { effects } from '@nayan-ui/engine';
|
|
143
170
|
|
|
144
|
-
effects.confetti(world, {
|
|
145
|
-
|
|
146
|
-
colors: ['#FF4D4D', '#FFD933'],
|
|
147
|
-
size: 0.12,
|
|
148
|
-
speed: 6,
|
|
149
|
-
count: 40,
|
|
150
|
-
lifetime: 1.2,
|
|
151
|
-
gravity: -6
|
|
152
|
-
});
|
|
153
|
-
effects.dust(world, { position: [0, 0, 0], color: [0.8, 0.75, 0.65, 0.6], size: 0.3, speed: 1.5, count: 6, lifetime: 0.5 });
|
|
154
|
-
await effects.pop(world, piece, { scale: 1, color: '#FF4D4D' }); // swell, flash white, shrink away
|
|
155
|
-
world.despawn(piece);
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
Also available: `sparkle`, `shatter`, `splash`, `sparks`, `explosion` and `flash`.
|
|
159
|
-
|
|
160
|
-
**Per-frame movement without allocations**
|
|
161
|
-
|
|
162
|
-
```ts
|
|
163
|
-
import { type MutableQuat, quat } from '@nayan-ui/engine';
|
|
164
|
-
|
|
165
|
-
const turn: MutableQuat = [0, 0, 0, 1];
|
|
166
|
-
const at: [number, number, number] = [0, 0, 0];
|
|
167
|
-
|
|
168
|
-
function onUpdate(dt: number) {
|
|
169
|
-
world.position(player, at); // queries can fill an `out` array
|
|
170
|
-
quat.y(heading, turn);
|
|
171
|
-
world.transforms.transform(car, carX, 0, carZ, turn[0], turn[1], turn[2], turn[3]); // applied in one native call as the world steps
|
|
172
|
-
}
|
|
171
|
+
effects.confetti(world, { position: [0, 2, 0], colors: ['#FF4D4D', '#FFD933'], count: 40 });
|
|
172
|
+
await effects.pop(world, box, { scale: 1, color: '#FF4D4D' }); // swell, flash, shrink away
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
Also available: `dust`, `sparkle`, `shatter`, `splash`, `sparks`, `explosion` and `flash`.
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
import { createShape, lathe, merge, tube } from '@nayan-ui/engine';
|
|
179
|
-
|
|
180
|
-
// Built once per app (after warmUpEngine), at module scope.
|
|
181
|
-
const vase = createShape(
|
|
182
|
-
merge([
|
|
183
|
-
{
|
|
184
|
-
geometry: lathe(
|
|
185
|
-
[
|
|
186
|
-
[0, 0],
|
|
187
|
-
[0.4, 0.1],
|
|
188
|
-
[0.25, 0.8],
|
|
189
|
-
[0.3, 1]
|
|
190
|
-
],
|
|
191
|
-
{ segments: 24 }
|
|
192
|
-
)
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
geometry: tube(
|
|
196
|
-
[
|
|
197
|
-
[0.3, 0.9, 0],
|
|
198
|
-
[0.5, 0.7, 0],
|
|
199
|
-
[0.3, 0.5, 0]
|
|
200
|
-
],
|
|
201
|
-
{ radius: 0.04 }
|
|
202
|
-
),
|
|
203
|
-
color: [0.5, 0.25, 0.1]
|
|
204
|
-
} // part colors are 0..1 tuples
|
|
205
|
-
])
|
|
206
|
-
);
|
|
207
|
-
world.spawn({ mesh: vase, color: '#C8763A' });
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
Also available: `extrude`, `loft`, `block`, `ellipsoid`, `parametricSurface`, `Solid` and `shapeGeometry` for the built-in shapes.
|
|
211
|
-
|
|
212
|
-
**Score, lives and timers**
|
|
213
|
-
|
|
214
|
-
```ts
|
|
215
|
-
world.scoreboard.handlers = { onTimeUp: () => endGame('lose') }; // the game's rules
|
|
216
|
-
const stopListening = world.scoreboard.listen({ onScore: setScore, onSecond: setTime }); // UI follows along
|
|
217
|
-
world.scoreboard.reset(3, 60); // 3 lives and a stopped 60 s countdown for the ready screen
|
|
218
|
-
world.scoreboard.resume(); // Start
|
|
219
|
-
world.scoreboard.add(10);
|
|
220
|
-
const timer = world.after(0.5, spawnWave); // game time: pauses with the game
|
|
221
|
-
world.cancelTimer(timer);
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
**Flat boards and puzzles**: `frontLight` keeps camera-facing surfaces at their exact color
|
|
225
|
-
|
|
226
|
-
```tsx
|
|
227
|
-
<GameView source={world} camera={{ eye: [0, 0, 50], target: [0, 0, 0], fov: 1, ortho: 10 }} light={frontLight([-0.4, 0.6, 1], 0.5)} />
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
**Input**
|
|
177
|
+
### Input
|
|
231
178
|
|
|
232
179
|
```tsx
|
|
233
180
|
<GameView
|
|
@@ -237,46 +184,109 @@ world.cancelTimer(timer);
|
|
|
237
184
|
if (hit) world.animate(hit.entity, { scale: 1.2 }, { yoyo: true, repeat: 1 });
|
|
238
185
|
}}
|
|
239
186
|
onSwipe={(direction) => move(direction)}
|
|
240
|
-
onDrag={({ phase, x, y }) => drag(phase, x, y)}
|
|
241
187
|
/>
|
|
242
188
|
```
|
|
243
189
|
|
|
244
|
-
`onLongPress`, `onPinch`, the on-screen `Joystick` and `createKeyboardInput` (web)
|
|
190
|
+
Also available: `onDrag`, `onLongPress`, `onPinch`, the on-screen `Joystick` and `createKeyboardInput` (web).
|
|
245
191
|
|
|
246
|
-
|
|
192
|
+
### Assets
|
|
247
193
|
|
|
248
194
|
```ts
|
|
249
|
-
import {
|
|
195
|
+
import { loadFont, loadModel, loadTexture } from '@nayan-ui/engine';
|
|
250
196
|
|
|
251
|
-
const car = await loadModel(require('./car.glb'), { fit: 2 }); // or a URL
|
|
197
|
+
const car = await loadModel(require('./car.glb'), { fit: 2 }); // or a URL on the web
|
|
252
198
|
const crate = await loadTexture(require('./crate.png'));
|
|
253
199
|
const font = await loadFont(require('./Inter-Bold.ttf'));
|
|
254
|
-
|
|
200
|
+
|
|
201
|
+
world.spawn({ mesh: car });
|
|
255
202
|
world.spawn({ mesh: 'cube', texture: crate });
|
|
256
203
|
world.spawn({ text: '2048', font, position: [0, 2, 0], scale: 0.5 });
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Sound and haptics
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
import { audio, haptics } from '@nayan-ui/engine';
|
|
257
210
|
|
|
258
211
|
const sfx = audio.load({ coin: require('./coin.wav') });
|
|
259
212
|
sfx.play('coin');
|
|
260
213
|
haptics.impact(0.5);
|
|
214
|
+
|
|
261
215
|
audio.enabled = settings.sounds; // respect the player's preferences
|
|
262
216
|
haptics.enabled = settings.haptics;
|
|
263
217
|
```
|
|
264
218
|
|
|
265
|
-
|
|
219
|
+
### Score and timers
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
world.scoreboard.handlers = { onTimeUp: () => endGame('lose') };
|
|
223
|
+
world.scoreboard.listen({ onScore: setScore, onSecond: setTime }); // keep your UI in sync
|
|
224
|
+
world.scoreboard.reset(3, 60); // 3 lives, 60 s countdown
|
|
225
|
+
world.scoreboard.resume();
|
|
226
|
+
world.scoreboard.add(10);
|
|
227
|
+
|
|
228
|
+
const timer = world.after(0.5, spawnWave); // game time: pauses with the game
|
|
229
|
+
world.cancelTimer(timer);
|
|
230
|
+
```
|
|
266
231
|
|
|
267
|
-
|
|
232
|
+
### Shapes in code
|
|
233
|
+
|
|
234
|
+
Build a mesh once at module scope (after `warmUpEngine()`), then spawn it many times.
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
import { createShape, lathe } from '@nayan-ui/engine';
|
|
238
|
+
|
|
239
|
+
const vase = createShape(lathe([[0, 0], [0.4, 0.1], [0.25, 0.8], [0.3, 1]], { segments: 24 }));
|
|
240
|
+
world.spawn({ mesh: vase, color: '#C8763A' });
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Also available: `merge`, `tube`, `extrude`, `loft`, `block`, `ellipsoid`, `parametricSurface`, `Solid` and `shapeGeometry`.
|
|
244
|
+
|
|
245
|
+
### Flat boards and puzzles
|
|
246
|
+
|
|
247
|
+
`frontLight` keeps camera-facing surfaces at their exact color.
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
<GameView source={world} camera={{ eye: [0, 0, 50], target: [0, 0, 0], fov: 1, ortho: 10 }} light={frontLight([-0.4, 0.6, 1], 0.5)} />
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Drawing
|
|
254
|
+
|
|
255
|
+
A native paint canvas, also usable as a live texture inside games.
|
|
268
256
|
|
|
269
257
|
```tsx
|
|
270
258
|
import { DrawingCanvas, DrawingDocument } from '@nayan-ui/engine';
|
|
271
259
|
|
|
272
260
|
const paper = new DrawingDocument(512, 512);
|
|
273
261
|
paper.setBrush({ brushType: 'MARKER', color: '#e53935', width: 12, opacity: 1 });
|
|
262
|
+
|
|
274
263
|
<DrawingCanvas document={paper} mode="draw" />;
|
|
275
264
|
world.spawn({ mesh: 'plane', texture: paper.texture() }); // paint on a 3D object
|
|
276
265
|
```
|
|
277
266
|
|
|
278
267
|
Drawings save as SVG paths and export transparent PNG snapshots.
|
|
279
268
|
|
|
269
|
+
### Colors
|
|
270
|
+
|
|
271
|
+
Use CSS strings (`'#FF4757'`, `'rgba(0, 0, 0, 0.5)'`) or linear 0..1 tuples (`[1, 0.3, 0.3]`; channels above 1 glow). `toColor('#FF4757')` converts a CSS color to numbers.
|
|
272
|
+
|
|
273
|
+
## Performance
|
|
274
|
+
|
|
275
|
+
The engine is built so that a game written the obvious way stays smooth on mid-range Android phones.
|
|
276
|
+
|
|
277
|
+
- **Display clock and render thread (iOS and Android).** The display's vsync (`CADisplayLink` on iOS, `Choreographer` on Android) asks for each frame at 60 Hz. `onUpdate` steps the game and hands a copy of the frame to a native render thread, which culls, submits and presents it. The JS thread never waits on the GPU, and a frame that is still waiting when a newer one arrives is replaced, not queued. The clock stops while the app is in the background or the view is off screen. On the web, `requestAnimationFrame` drives the same loop.
|
|
278
|
+
- **Culling in Rust.** Everything outside the camera's view (and outside the light's box for shadows) is skipped every frame, so open levels and long tracks only pay for what is on screen. Don't cull scenery in JS.
|
|
279
|
+
- **Automatic quality.** `quality="auto"` (the default) starts at `high` and steps down (shadow detail first, then anti-aliasing, resolution last) only while the device can't keep up. `onStats` reports fps, update and render time, the quality chosen and the graphics backend.
|
|
280
|
+
- **Background loading.** `loadTexture`, `loadModel`, `loadFont` and `audio.load` decode on native threads in parallel, and meshes are registered with the renderer inside Rust.
|
|
281
|
+
- **Work between frames.** `afterNextFrame(fn)` runs `fn` right after the next frame leaves, so you can spread long setup work (map generation, mesh building) over several frames behind a loading screen.
|
|
282
|
+
- **Cached procedural assets.** `ProceduralCache` saves built geometry on disk keyed by a recipe, so later launches restore it instead of rebuilding; `peek(key)` returns a saved value without building anything.
|
|
283
|
+
|
|
284
|
+
Keep these habits:
|
|
285
|
+
|
|
286
|
+
- Build meshes once, at module scope or behind a cache, and spawn new entities from them. Mesh ids are app-wide and never freed (`getMeshIdLimit()` tells you how many there are), so never create a mesh per spawn or per frame.
|
|
287
|
+
- Move many things each frame through `world.transforms` and the `out` arguments of queries, which allocate nothing.
|
|
288
|
+
- Keep long one-off jobs out of gameplay frames: a single slow frame stalls Android's Hermes far longer than desktop JavaScript suggests.
|
|
289
|
+
|
|
280
290
|
## Troubleshooting
|
|
281
291
|
|
|
282
292
|
| Symptom | Fix |
|
|
@@ -287,6 +297,14 @@ Drawings save as SVG paths and export transparent PNG snapshots.
|
|
|
287
297
|
| An Android screenshot of the game view is blank | The engine draws into a `SurfaceView`: use `captureScreen(..., { handleGLSurfaceViewOnAndroid: true })`. |
|
|
288
298
|
| Out of mesh ids | A mesh is being created per spawn or per frame: build it once and reuse it (`getMeshIdLimit()`). |
|
|
289
299
|
|
|
300
|
+
## Prebuilt games
|
|
301
|
+
|
|
302
|
+
[@nayan-ui/games](https://www.nayanui.com/games) offers 53 ready-made 3D games built on this engine. Each is one component with the same props.
|
|
303
|
+
|
|
304
|
+
`@nayan-ui/games` is a **private package**. To use it in your application or website, reach out to [niranjan.devasani@gmail.com](mailto:niranjan.devasani@gmail.com).
|
|
305
|
+
|
|
306
|
+
**[Play them in your browser](https://www.nayanui.com/games)**
|
|
307
|
+
|
|
290
308
|
## Learn more
|
|
291
309
|
|
|
292
310
|
| Topic | Guide |
|
|
@@ -302,7 +320,7 @@ Drawings save as SVG paths and export transparent PNG snapshots.
|
|
|
302
320
|
|
|
303
321
|
## License
|
|
304
322
|
|
|
305
|
-
MIT
|
|
323
|
+
MIT
|
|
306
324
|
|
|
307
325
|
---
|
|
308
326
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nayan-ui/engine",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.5",
|
|
4
4
|
"description": "Fast 3D game engine for React and React Native: Rust and wgpu rendering, Rapier physics, animation, particle effects, audio, haptics and drawing.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"3d",
|