@nayan-ui/engine 0.0.0-stage → 1.0.0-beta.3
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/LICENSE +21 -0
- package/NayanEngine.podspec +28 -0
- package/README.md +210 -2
- package/lib/module/assets/AssetBytesCache.js +76 -0
- package/lib/module/assets/AssetCache.js +19 -0
- package/lib/module/assets/AssetLoader.js +52 -0
- package/lib/module/assets/CacheGeneration.js +7 -0
- package/lib/module/assets/IndexedDbCache.web.js +149 -0
- package/lib/module/assets/ProceduralCache.js +222 -0
- package/lib/module/assets/font.js +136 -0
- package/lib/module/assets/loft.js +142 -0
- package/lib/module/assets/model.js +74 -0
- package/lib/module/assets/modelling.js +254 -0
- package/lib/module/assets/shape.js +926 -0
- package/lib/module/assets/source.js +58 -0
- package/lib/module/assets/source.web.js +22 -0
- package/lib/module/assets/storage.js +4 -0
- package/lib/module/assets/storage.shared.js +36 -0
- package/lib/module/assets/storage.web.js +37 -0
- package/lib/module/assets/surface.js +47 -0
- package/lib/module/assets/texture.js +66 -0
- package/lib/module/drawing/DrawingCanvas.js +38 -0
- package/lib/module/drawing/DrawingCanvas.web.js +206 -0
- package/lib/module/drawing/DrawingDocument.js +256 -0
- package/lib/module/drawing/types.js +4 -0
- package/lib/module/globals.d.ts +12 -0
- package/lib/module/index.js +36 -0
- package/lib/module/input/Joystick.js +84 -0
- package/lib/module/input/Joystick.web.js +93 -0
- package/lib/module/input/keyboard.js +250 -0
- package/lib/module/media/audio-worklet.js +34 -0
- package/lib/module/media/audio.js +94 -0
- package/lib/module/media/haptics.js +82 -0
- package/lib/module/media/output.web.js +66 -0
- package/lib/module/native/BrowserEngine.js +551 -0
- package/lib/module/native/EngineBridge.js +4 -0
- package/lib/module/native/NativeNayanEngine.js +7 -0
- package/lib/module/native/NativeNayanEngine.web.js +62 -0
- package/lib/module/native/prepare.js +7 -0
- package/lib/module/native/prepare.web.js +17 -0
- package/lib/module/native/spec/NativeNayanEngine.js +17 -0
- package/lib/module/package.json +1 -0
- package/lib/module/render/GameView.js +249 -0
- package/lib/module/render/camera.js +34 -0
- package/lib/module/render/host.js +39 -0
- package/lib/module/render/host.web.js +104 -0
- package/lib/module/render/meshes.js +159 -0
- package/lib/module/render/quality.js +112 -0
- package/lib/module/render/responder.js +4 -0
- package/lib/module/render/responder.web.js +97 -0
- package/lib/module/render/touch.js +185 -0
- package/lib/module/types.js +30 -0
- package/lib/module/world/Scoreboard.js +143 -0
- package/lib/module/world/TransformBatch.js +126 -0
- package/lib/module/world/World.js +690 -0
- package/lib/module/world/desc.js +186 -0
- package/lib/module/world/effects.js +451 -0
- package/lib/module/world/quat.js +86 -0
- package/lib/module/world/types.js +4 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/assets/AssetBytesCache.d.ts +7 -0
- package/lib/typescript/src/assets/AssetCache.d.ts +9 -0
- package/lib/typescript/src/assets/AssetLoader.d.ts +11 -0
- package/lib/typescript/src/assets/CacheGeneration.d.ts +3 -0
- package/lib/typescript/src/assets/IndexedDbCache.web.d.ts +20 -0
- package/lib/typescript/src/assets/ProceduralCache.d.ts +33 -0
- package/lib/typescript/src/assets/font.d.ts +53 -0
- package/lib/typescript/src/assets/loft.d.ts +31 -0
- package/lib/typescript/src/assets/model.d.ts +48 -0
- package/lib/typescript/src/assets/modelling.d.ts +157 -0
- package/lib/typescript/src/assets/shape.d.ts +203 -0
- package/lib/typescript/src/assets/source.d.ts +10 -0
- package/lib/typescript/src/assets/source.web.d.ts +8 -0
- package/lib/typescript/src/assets/storage.d.ts +2 -0
- package/lib/typescript/src/assets/storage.shared.d.ts +7 -0
- package/lib/typescript/src/assets/storage.web.d.ts +7 -0
- package/lib/typescript/src/assets/surface.d.ts +17 -0
- package/lib/typescript/src/assets/texture.d.ts +30 -0
- package/lib/typescript/src/drawing/DrawingCanvas.d.ts +5 -0
- package/lib/typescript/src/drawing/DrawingCanvas.web.d.ts +4 -0
- package/lib/typescript/src/drawing/DrawingDocument.d.ts +210 -0
- package/lib/typescript/src/drawing/types.d.ts +12 -0
- package/lib/typescript/src/index.d.ts +42 -0
- package/lib/typescript/src/input/Joystick.d.ts +20 -0
- package/lib/typescript/src/input/Joystick.web.d.ts +13 -0
- package/lib/typescript/src/input/keyboard.d.ts +17 -0
- package/lib/typescript/src/media/audio.d.ts +46 -0
- package/lib/typescript/src/media/haptics.d.ts +22 -0
- package/lib/typescript/src/media/output.web.d.ts +4 -0
- package/lib/typescript/src/native/BrowserEngine.d.ts +8 -0
- package/lib/typescript/src/native/EngineBridge.d.ts +22 -0
- package/lib/typescript/src/native/NativeNayanEngine.d.ts +5 -0
- package/lib/typescript/src/native/NativeNayanEngine.web.d.ts +10 -0
- package/lib/typescript/src/native/prepare.d.ts +3 -0
- package/lib/typescript/src/native/prepare.web.d.ts +2 -0
- package/lib/typescript/src/native/spec/NativeNayanEngine.d.ts +182 -0
- package/lib/typescript/src/render/GameView.d.ts +95 -0
- package/lib/typescript/src/render/camera.d.ts +6 -0
- package/lib/typescript/src/render/host.d.ts +29 -0
- package/lib/typescript/src/render/host.web.d.ts +16 -0
- package/lib/typescript/src/render/meshes.d.ts +45 -0
- package/lib/typescript/src/render/quality.d.ts +46 -0
- package/lib/typescript/src/render/responder.d.ts +2 -0
- package/lib/typescript/src/render/responder.web.d.ts +40 -0
- package/lib/typescript/src/render/touch.d.ts +26 -0
- package/lib/typescript/src/types.d.ts +72 -0
- package/lib/typescript/src/world/Scoreboard.d.ts +65 -0
- package/lib/typescript/src/world/TransformBatch.d.ts +39 -0
- package/lib/typescript/src/world/World.d.ts +199 -0
- package/lib/typescript/src/world/desc.d.ts +17 -0
- package/lib/typescript/src/world/effects.d.ts +156 -0
- package/lib/typescript/src/world/quat.d.ts +31 -0
- package/lib/typescript/src/world/types.d.ts +233 -0
- package/lib/web/audio-worklet.js +29 -0
- package/lib/web/engine_core_bg.wasm +0 -0
- package/lib/web/index.js +7974 -0
- package/lib/web/types/src/assets/AssetBytesCache.d.ts +6 -0
- package/lib/web/types/src/assets/AssetCache.d.ts +8 -0
- package/lib/web/types/src/assets/AssetLoader.d.ts +10 -0
- package/lib/web/types/src/assets/CacheGeneration.d.ts +2 -0
- package/lib/web/types/src/assets/IndexedDbCache.d.ts +19 -0
- package/lib/web/types/src/assets/ProceduralCache.d.ts +32 -0
- package/lib/web/types/src/assets/font.d.ts +52 -0
- package/lib/web/types/src/assets/loft.d.ts +30 -0
- package/lib/web/types/src/assets/model.d.ts +47 -0
- package/lib/web/types/src/assets/modelling.d.ts +156 -0
- package/lib/web/types/src/assets/shape.d.ts +202 -0
- package/lib/web/types/src/assets/source.d.ts +7 -0
- package/lib/web/types/src/assets/storage.d.ts +6 -0
- package/lib/web/types/src/assets/storage.shared.d.ts +6 -0
- package/lib/web/types/src/assets/surface.d.ts +16 -0
- package/lib/web/types/src/assets/texture.d.ts +29 -0
- package/lib/web/types/src/drawing/DrawingCanvas.d.ts +3 -0
- package/lib/web/types/src/drawing/DrawingDocument.d.ts +209 -0
- package/lib/web/types/src/drawing/types.d.ts +11 -0
- package/lib/web/types/src/index.d.ts +41 -0
- package/lib/web/types/src/input/Joystick.d.ts +12 -0
- package/lib/web/types/src/input/keyboard.d.ts +16 -0
- package/lib/web/types/src/media/audio.d.ts +45 -0
- package/lib/web/types/src/media/haptics.d.ts +21 -0
- package/lib/web/types/src/media/output.d.ts +3 -0
- package/lib/web/types/src/native/BrowserEngine.d.ts +7 -0
- package/lib/web/types/src/native/EngineBridge.d.ts +21 -0
- package/lib/web/types/src/native/NativeNayanEngine.d.ts +9 -0
- package/lib/web/types/src/native/prepare.d.ts +1 -0
- package/lib/web/types/src/native/spec/NativeNayanEngine.d.ts +181 -0
- package/lib/web/types/src/render/GameView.d.ts +94 -0
- package/lib/web/types/src/render/camera.d.ts +5 -0
- package/lib/web/types/src/render/host.d.ts +15 -0
- package/lib/web/types/src/render/meshes.d.ts +44 -0
- package/lib/web/types/src/render/quality.d.ts +45 -0
- package/lib/web/types/src/render/responder.d.ts +39 -0
- package/lib/web/types/src/render/touch.d.ts +25 -0
- package/lib/web/types/src/types.d.ts +71 -0
- package/lib/web/types/src/world/Scoreboard.d.ts +64 -0
- package/lib/web/types/src/world/TransformBatch.d.ts +38 -0
- package/lib/web/types/src/world/World.d.ts +198 -0
- package/lib/web/types/src/world/desc.d.ts +16 -0
- package/lib/web/types/src/world/effects.d.ts +155 -0
- package/lib/web/types/src/world/quat.d.ts +30 -0
- package/lib/web/types/src/world/types.d.ts +232 -0
- package/native/android/CMakeLists.txt +34 -0
- package/native/android/NayanEngineSpec.h +15 -0
- package/native/android/build.gradle +26 -0
- package/native/android/codegen/CMakeLists.txt +3 -0
- package/native/android/proguard-rules.pro +2 -0
- package/native/android/src/main/java/com/nayanui/engine/EngineSurfaceView.java +234 -0
- package/native/android/src/main/java/com/nayanui/engine/EngineSurfaceViewManager.java +45 -0
- package/native/android/src/main/java/com/nayanui/engine/NayanEnginePackage.java +24 -0
- package/native/core/build/EngineCore.xcframework/Info.plist +43 -0
- package/native/core/build/EngineCore.xcframework/ios-arm64/libengine_core.a +0 -0
- package/native/core/build/EngineCore.xcframework/ios-arm64-simulator/libengine_core.a +0 -0
- package/native/core/build/android/arm64-v8a/libengine_core.a +0 -0
- package/native/core/build/android/armeabi-v7a/libengine_core.a +0 -0
- package/native/core/build/android/x86/libengine_core.a +0 -0
- package/native/core/build/android/x86_64/libengine_core.a +0 -0
- package/native/core/include/drawing-licenses.txt +58 -0
- package/native/core/include/engine_core.h +322 -0
- package/native/cpp/NayanEngineModule.cpp +827 -0
- package/native/cpp/NayanEngineModule.h +144 -0
- package/native/cpp/generated/NayanEngineSpecJSI.cpp +2 -0
- package/native/cpp/generated/NayanEngineSpecJSI.h +921 -0
- package/native/ios/NayanEngineProvider.h +5 -0
- package/native/ios/NayanEngineProvider.mm +21 -0
- package/native/ios/NayanEngineSurface.mm +223 -0
- package/native/scripts/check-package.mjs +39 -0
- package/package.json +162 -4
- package/react-native.config.js +18 -0
- package/src/native/spec/NativeNayanEngine.ts +226 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { type Camera, type Light, type RenderSource } from '../types';
|
|
2
|
+
import type { Color } from '../world/types';
|
|
3
|
+
import { type ViewStyle } from './host';
|
|
4
|
+
import { type RenderQuality, type RenderQualitySetting } from './quality';
|
|
5
|
+
export type GameViewStats = {
|
|
6
|
+
fps: number;
|
|
7
|
+
/** Mean time spent in `onUpdate` per frame, in milliseconds. */
|
|
8
|
+
updateMs: number;
|
|
9
|
+
/** Average milliseconds per frame spent drawing (CPU side, including waiting on the GPU). */
|
|
10
|
+
renderMs: number;
|
|
11
|
+
/** The quality level drawn with (with `quality="auto"`, the one it settled on so far). */
|
|
12
|
+
quality: RenderQuality;
|
|
13
|
+
/** The graphics API drawing: "vulkan", "gl" (OpenGL ES) or "metal". */
|
|
14
|
+
backend: string;
|
|
15
|
+
};
|
|
16
|
+
export type SwipeDirection = 'left' | 'right' | 'up' | 'down';
|
|
17
|
+
export type OverlayTouchPhase = 'start' | 'move' | 'end' | 'cancel';
|
|
18
|
+
export type DragEvent = {
|
|
19
|
+
phase: 'start' | 'move' | 'end';
|
|
20
|
+
/** Finger position in the view, in points. */
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
/** Distance moved since the drag started, in points. */
|
|
24
|
+
dx: number;
|
|
25
|
+
dy: number;
|
|
26
|
+
/** On "end": the drag was interrupted (a second finger started a pinch, or the system took the touch). Put a held piece back. */
|
|
27
|
+
cancelled?: boolean;
|
|
28
|
+
};
|
|
29
|
+
export type PinchEvent = {
|
|
30
|
+
phase: 'start' | 'move' | 'end';
|
|
31
|
+
/** Finger spread relative to the start: 2 = twice as far apart (zoom in). */
|
|
32
|
+
scale: number;
|
|
33
|
+
/** Radians the two fingers turned since the start, clockwise on screen. */
|
|
34
|
+
rotation: number;
|
|
35
|
+
/** Midpoint between the fingers in the view, in points. */
|
|
36
|
+
x: number;
|
|
37
|
+
y: number;
|
|
38
|
+
};
|
|
39
|
+
export type GameViewProps = {
|
|
40
|
+
/** What to draw (usually a `World`). Changing it restarts the view; never pass a disposed world. */
|
|
41
|
+
source: RenderSource;
|
|
42
|
+
/**
|
|
43
|
+
* Your game loop, called once per frame before drawing, with the elapsed seconds (capped at 0.1;
|
|
44
|
+
* 0 until the first frame is on screen, so nothing plays out unseen).
|
|
45
|
+
* Step your simulation here, e.g. `world.update(dt)`, then read input, spawn, move the camera.
|
|
46
|
+
*/
|
|
47
|
+
onUpdate?: (dt: number) => void;
|
|
48
|
+
/** Mutate this object (e.g. `camera.eye`) from `onUpdate`; it is read every frame. */
|
|
49
|
+
camera?: Camera;
|
|
50
|
+
light?: Light;
|
|
51
|
+
/** Sky / clear color, linear 0..1 RGB (alpha ignored). Also the fog color. Default dark navy. */
|
|
52
|
+
background?: Color;
|
|
53
|
+
/** Distance fog density towards `background` (e.g. 0.02). Default 0 (off). */
|
|
54
|
+
fog?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Resolution, anti-aliasing and shadow quality. "auto" (default) starts at "high", steps down only
|
|
57
|
+
* while the GPU really can't keep up (shadow detail first, then anti-aliasing, resolution last) and
|
|
58
|
+
* steps back up once frames are smooth again, so every phone gets the best look it can hold.
|
|
59
|
+
*/
|
|
60
|
+
quality?: RenderQualitySetting;
|
|
61
|
+
/** Suspend updates and drawing while keeping the native surface mounted. */
|
|
62
|
+
paused?: boolean;
|
|
63
|
+
style?: ViewStyle;
|
|
64
|
+
/** A quick tap, at `x, y` points in the view. `world.pick(x, y)` finds what was tapped. */
|
|
65
|
+
onTap?: (x: number, y: number) => void;
|
|
66
|
+
/** A quick flick in one direction (2048, runners, sliding puzzles). */
|
|
67
|
+
onSwipe?: (direction: SwipeDirection) => void;
|
|
68
|
+
/** Finger down, moving and up (aiming, dragging pieces, slicing). */
|
|
69
|
+
onDrag?: (drag: DragEvent) => void;
|
|
70
|
+
/** A finger held still for half a second (pick up, show moves). No tap follows. */
|
|
71
|
+
onLongPress?: (x: number, y: number) => void;
|
|
72
|
+
/** Two fingers spreading, pinching or turning (zoom and rotate a board). Ends any drag in progress. */
|
|
73
|
+
onPinch?: (pinch: PinchEvent) => void;
|
|
74
|
+
/** Host primary action for keyboard input, such as Start/Stop or Play Again. */
|
|
75
|
+
onPrimaryAction?: () => void;
|
|
76
|
+
/**
|
|
77
|
+
* A screen-space layer drawn over the scene by the renderer (scoreboards, buttons): usually a second
|
|
78
|
+
* `World`, in points from the view's top-left with y up (so on screen y <= 0) and z toward the viewer
|
|
79
|
+
* within -100..100. Unlit (flat faces show their exact color) and always in front. Step it yourself
|
|
80
|
+
* (`overlay.update(dt)` in `onUpdate`).
|
|
81
|
+
*/
|
|
82
|
+
overlay?: RenderSource;
|
|
83
|
+
/**
|
|
84
|
+
* Touches for the overlay, in points in the view. Return true from "start" to claim the touch (a
|
|
85
|
+
* button was hit): its moves and end come here, and the game gets no drag, tap or swipe for it.
|
|
86
|
+
* "cancel" when the system takes the touch.
|
|
87
|
+
*/
|
|
88
|
+
onOverlayTouch?: (phase: OverlayTouchPhase, x: number, y: number) => boolean | void;
|
|
89
|
+
/** Called once a second. */
|
|
90
|
+
onStats?: (stats: GameViewStats) => void;
|
|
91
|
+
/** GPU setup failures and rendering errors. Defaults to console.error. */
|
|
92
|
+
onError?: (error: Error) => void;
|
|
93
|
+
};
|
|
94
|
+
export declare function GameView(props: GameViewProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Camera, RenderSource } from '../types';
|
|
2
|
+
/** `camera.follow`: ease the target toward the entity (where it was last drawn) and keep the eye at the offset. */
|
|
3
|
+
export declare function follow(camera: Camera, source: RenderSource, out: [number, number, number], dt: number): void;
|
|
4
|
+
/** `camera.shake`: a jittered copy of the camera; the strength fades by itself. */
|
|
5
|
+
export declare function shake(camera: Camera, out: Camera, dt: number): Camera;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type CSSProperties } from 'react';
|
|
2
|
+
import { createTouchResponder } from './touch';
|
|
3
|
+
export { createTouchResponder };
|
|
4
|
+
export type ViewStyle = CSSProperties;
|
|
5
|
+
export declare const pixelRatio: () => number;
|
|
6
|
+
export declare function useActive(): boolean;
|
|
7
|
+
interface SurfaceProps {
|
|
8
|
+
surfaceId: number;
|
|
9
|
+
style?: CSSProperties;
|
|
10
|
+
onSize: (width: number, height: number) => void;
|
|
11
|
+
onError: (error: Error) => void;
|
|
12
|
+
touch?: ReturnType<typeof createTouchResponder>;
|
|
13
|
+
onPrimaryAction?: () => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function Surface({ surfaceId, style, onSize, onError, touch, onPrimaryAction }: SurfaceProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare const VERTEX_FLOATS = 11;
|
|
2
|
+
type V3 = readonly [number, number, number];
|
|
3
|
+
export declare class Builder {
|
|
4
|
+
vertices: number[];
|
|
5
|
+
indices: number[];
|
|
6
|
+
/** Adds a vertex, returns its index. */
|
|
7
|
+
vertex(p: V3, n: V3, u: number, v: number): number;
|
|
8
|
+
/** Two triangles, counter-clockwise a b c d as seen from the front. */
|
|
9
|
+
quad(a: number, b: number, c: number, d: number): void;
|
|
10
|
+
/**
|
|
11
|
+
* A (rows + 1) x (cols + 1) vertex grid; `at(u, v)` gives position and normal. u runs along a row and
|
|
12
|
+
* v down the rows; the grid faces the side from which u goes right and v goes down.
|
|
13
|
+
*/
|
|
14
|
+
grid(rows: number, cols: number, at: (u: number, v: number) => [V3, V3]): void;
|
|
15
|
+
/** A flat disc at height y facing up (+1) or down (-1). */
|
|
16
|
+
disc(y: number, radius: number, facing: 1 | -1, segments: number): void;
|
|
17
|
+
}
|
|
18
|
+
/** Render-ready geometry: VERTEX_FLOATS floats per vertex, u32 triangle indices. */
|
|
19
|
+
export type MeshGeometry = {
|
|
20
|
+
vertices: Float32Array;
|
|
21
|
+
indices: Uint32Array;
|
|
22
|
+
};
|
|
23
|
+
/** What the renderer draws for a mesh id: geometry, and a texture id (see `loadTexture`) if any. */
|
|
24
|
+
/** `shine` 0..1: how glossy (sun highlight and sky reflection), 0 = matte. */
|
|
25
|
+
export type MeshInfo = {
|
|
26
|
+
geometry: MeshGeometry;
|
|
27
|
+
texture?: number;
|
|
28
|
+
shine?: number;
|
|
29
|
+
};
|
|
30
|
+
/** Registers what a mesh id draws (loaded models, glyphs, textured variants). */
|
|
31
|
+
export declare function registerMesh(mesh: number, info: MeshInfo, uploadGeometry?: boolean): void;
|
|
32
|
+
/** One past the highest mesh id in use: per-frame scans of a source's ranges stop here. */
|
|
33
|
+
export declare const getMeshIdLimit: () => number;
|
|
34
|
+
/** Generates the built-in shapes in the Rust core and registers them with the native renderer (once). */
|
|
35
|
+
export declare function uploadBuiltInMeshes(): void;
|
|
36
|
+
/**
|
|
37
|
+
* Initializes the shared core and built-in meshes. Await before using the engine on the web.
|
|
38
|
+
* Mobile initialization remains synchronous and also warms the GPU on a background thread.
|
|
39
|
+
* Repeat calls reuse initialization and mesh registration.
|
|
40
|
+
*/
|
|
41
|
+
export declare function warmUpEngine(): Promise<void>;
|
|
42
|
+
/** What to draw for a mesh id, or undefined ("none", or unknown). Built-in shapes use native geometry. */
|
|
43
|
+
export declare function meshInfo(mesh: number): MeshInfo | undefined;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type RenderQuality = 'high' | 'medium' | 'low' | 'lowest';
|
|
2
|
+
/** `"auto"` starts at "high" and steps down only while the device really can't keep up. */
|
|
3
|
+
export type RenderQualitySetting = RenderQuality | 'auto';
|
|
4
|
+
export type QualityLevel = {
|
|
5
|
+
/** Most device pixels drawn per point (the screen's own ratio when lower). */
|
|
6
|
+
maxPixelRatio: number;
|
|
7
|
+
/** MSAA samples: 4 or 1 (off). */
|
|
8
|
+
samples: 1 | 4;
|
|
9
|
+
/** Shadow map width and height in texels. */
|
|
10
|
+
shadowSize: number;
|
|
11
|
+
/** 3x3 filtered (soft) shadow edges, or a single tap (hard). */
|
|
12
|
+
softShadows: boolean;
|
|
13
|
+
};
|
|
14
|
+
/** From best looking to cheapest; "auto" walks down this list only as far as it must. */
|
|
15
|
+
export declare const QUALITIES: readonly RenderQuality[];
|
|
16
|
+
export declare const QUALITY_LEVELS: Record<RenderQuality, QualityLevel>;
|
|
17
|
+
/** One second of frames, as the frame loop measured it. */
|
|
18
|
+
export type FrameReport = {
|
|
19
|
+
/** The typical (median) time between frames, in ms: hiccups (garbage collection, a busy JS frame) don't move it. */
|
|
20
|
+
frameMs: number;
|
|
21
|
+
/** The typical (median) time spent drawing a frame, in ms (including any wait for the screen). */
|
|
22
|
+
renderMs: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Picks the level for "auto": starts at the best, steps down one level after `SLOW_SECONDS`
|
|
26
|
+
* consecutive seconds whose typical frame misses ~50 fps while drawing took most of it, and steps
|
|
27
|
+
* back up after `FAST_SECONDS` smooth seconds. A level that fails again soon after being restored
|
|
28
|
+
* becomes the ceiling, so it never bounces.
|
|
29
|
+
*/
|
|
30
|
+
export declare class AutoQuality {
|
|
31
|
+
private index;
|
|
32
|
+
/** The best level it may return to (raised past a level that keeps failing). */
|
|
33
|
+
private ceiling;
|
|
34
|
+
private started;
|
|
35
|
+
private changed;
|
|
36
|
+
private raisedAt;
|
|
37
|
+
private slow;
|
|
38
|
+
private fast;
|
|
39
|
+
get quality(): RenderQuality;
|
|
40
|
+
/** Feeds one second of frames; returns true when the level changed. */
|
|
41
|
+
report(now: number, frames: FrameReport): boolean;
|
|
42
|
+
private moved;
|
|
43
|
+
}
|
|
44
|
+
/** The middle value of `values` (sorted in place). */
|
|
45
|
+
export declare function median(values: number[]): number;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { PointerEvent as ReactPointerEvent } from 'react';
|
|
2
|
+
type Touch = {
|
|
3
|
+
pageX: number;
|
|
4
|
+
pageY: number;
|
|
5
|
+
};
|
|
6
|
+
interface Event {
|
|
7
|
+
nativeEvent: Touch & {
|
|
8
|
+
locationX: number;
|
|
9
|
+
locationY: number;
|
|
10
|
+
touches: Touch[];
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
interface Gesture {
|
|
14
|
+
dx: number;
|
|
15
|
+
dy: number;
|
|
16
|
+
}
|
|
17
|
+
interface Callbacks {
|
|
18
|
+
onStartShouldSetPanResponder: () => boolean;
|
|
19
|
+
onMoveShouldSetPanResponder: () => boolean;
|
|
20
|
+
onPanResponderGrant: (event: Event) => void;
|
|
21
|
+
onPanResponderMove: (event: Event, gesture: Gesture) => void;
|
|
22
|
+
onPanResponderRelease: (event: Event, gesture: Gesture) => void;
|
|
23
|
+
onPanResponderTerminate: (event: Event, gesture: Gesture) => void;
|
|
24
|
+
}
|
|
25
|
+
export interface PanResponderInstance {
|
|
26
|
+
panHandlers: {
|
|
27
|
+
onPointerDown: (event: ReactPointerEvent<HTMLDivElement>) => void;
|
|
28
|
+
onPointerMove: (event: ReactPointerEvent<HTMLDivElement>) => void;
|
|
29
|
+
onPointerUp: (event: ReactPointerEvent<HTMLDivElement>) => void;
|
|
30
|
+
onPointerCancel: (event: ReactPointerEvent<HTMLDivElement>) => void;
|
|
31
|
+
onLostPointerCapture: (event: ReactPointerEvent<HTMLDivElement>) => void;
|
|
32
|
+
};
|
|
33
|
+
cancel: () => void;
|
|
34
|
+
}
|
|
35
|
+
/** Adapt DOM pointer capture to the gesture recognizer used on mobile. Coordinates stay in CSS pixels. */
|
|
36
|
+
export declare const PanResponder: {
|
|
37
|
+
create(callbacks: Callbacks): PanResponderInstance;
|
|
38
|
+
};
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DragEvent, OverlayTouchPhase, PinchEvent, SwipeDirection } from './GameView';
|
|
2
|
+
import { type PanResponderInstance } from './responder';
|
|
3
|
+
declare const TAP_SLOP = 10;
|
|
4
|
+
declare const TAP_TIME = 300;
|
|
5
|
+
declare const SWIPE_DISTANCE = 30;
|
|
6
|
+
declare const SWIPE_SPEED = 0.3;
|
|
7
|
+
declare const LONG_PRESS_TIME = 500;
|
|
8
|
+
type Handlers = {
|
|
9
|
+
onTap?: (x: number, y: number) => void;
|
|
10
|
+
onSwipe?: (direction: SwipeDirection) => void;
|
|
11
|
+
onDrag?: (drag: DragEvent) => void;
|
|
12
|
+
onLongPress?: (x: number, y: number) => void;
|
|
13
|
+
onPinch?: (pinch: PinchEvent) => void;
|
|
14
|
+
onOverlayTouch?: (phase: OverlayTouchPhase, x: number, y: number) => boolean | void;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Creates a PanResponder that recognizes taps, swipes, drags, long presses and pinches.
|
|
18
|
+
* `getHandlers` is called on each event so the caller can swap handlers without recreating the responder.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createTouchResponder(getHandlers: () => Handlers): {
|
|
21
|
+
responder: PanResponderInstance;
|
|
22
|
+
dispose: () => void;
|
|
23
|
+
cancel: () => void;
|
|
24
|
+
};
|
|
25
|
+
export { TAP_SLOP, TAP_TIME, SWIPE_DISTANCE, SWIPE_SPEED, LONG_PRESS_TIME };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Color, Entity } from './world/types';
|
|
2
|
+
export type Vec3 = readonly [number, number, number];
|
|
3
|
+
/** Number of mesh ids: built-in shapes (0..15), then loaded models, glyphs and textured variants. */
|
|
4
|
+
export declare const MAX_MESHES = 4096;
|
|
5
|
+
/** What the renderer draws. `World` implements it; so can any custom simulation. */
|
|
6
|
+
export interface RenderSource {
|
|
7
|
+
/** Native world id, when this source supports skeletal characters. */
|
|
8
|
+
readonly nativeWorld?: number;
|
|
9
|
+
/** Column-major mat4 per instance (16 floats), grouped by mesh. Only the first `count` are valid. */
|
|
10
|
+
readonly matrices: Float32Array;
|
|
11
|
+
/** RGBA per instance (4 floats), same order as `matrices`. Alpha below 1 draws see-through. */
|
|
12
|
+
readonly colors: Float32Array;
|
|
13
|
+
/** Texture region per instance (u0 v0 u1 v1), same order. Optional: the whole texture by default. */
|
|
14
|
+
readonly regions?: Float32Array;
|
|
15
|
+
/**
|
|
16
|
+
* `[first, count]` per mesh id, in instances: opaque instances at `ranges[2 * mesh]`, transparent ones
|
|
17
|
+
* at `ranges[2 * (MAX_MESHES + mesh)]`. Shorter arrays just have no transparent part.
|
|
18
|
+
*/
|
|
19
|
+
readonly ranges: Uint32Array;
|
|
20
|
+
/** Total number of valid instances. */
|
|
21
|
+
readonly count: number;
|
|
22
|
+
/** Maximum number of instances (sizes the GPU buffers). */
|
|
23
|
+
readonly capacity: number;
|
|
24
|
+
/** Called by GameView after each frame with the camera it drew with (for picking and `toScreen`). */
|
|
25
|
+
setView?(viewProj: Float32Array, width: number, height: number): void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Built-in shapes, each 1 unit across before scaling. "none" isn't drawn (groups, pivots, trigger zones).
|
|
29
|
+
* "puff" is a soft, round sprite that always faces the camera and is always see-through: overlapping
|
|
30
|
+
* puffs blend into smoke, dust, steam and clouds. "flame" is the same sprite drawn additively: it adds
|
|
31
|
+
* light to what's behind it, so overlapping flames build up to a hot white core and stay bright over
|
|
32
|
+
* smoke (fire, sparks, explosions, magic, glows). Use them as a burst's `mesh`.
|
|
33
|
+
*/
|
|
34
|
+
export type Shape = 'cube' | 'sphere' | 'plane' | 'cylinder' | 'cone' | 'capsule' | 'torus' | 'roundedBox' | 'puff' | 'flame' | 'none';
|
|
35
|
+
/** Mesh ids of the built-in shapes, as the core and renderer know them. */
|
|
36
|
+
export declare const SHAPE_MESH: Record<Shape, number>;
|
|
37
|
+
export type Camera = {
|
|
38
|
+
eye: [number, number, number];
|
|
39
|
+
target: [number, number, number];
|
|
40
|
+
/** Vertical field of view in radians (ignored when `ortho` is set). */
|
|
41
|
+
fov: number;
|
|
42
|
+
/** Orthographic: half the visible height in world units. Board and puzzle games look flat and tidy. */
|
|
43
|
+
ortho?: number;
|
|
44
|
+
/**
|
|
45
|
+
* Chase an entity: each frame the target moves toward it and the eye keeps `offset` from the target.
|
|
46
|
+
* `smoothing` is roughly the seconds it takes to catch up (0 = rigid, default 0.15).
|
|
47
|
+
*/
|
|
48
|
+
follow?: {
|
|
49
|
+
target: Entity;
|
|
50
|
+
offset: Vec3;
|
|
51
|
+
smoothing?: number;
|
|
52
|
+
} | null;
|
|
53
|
+
/** Shake strength in world units (e.g. 0.3 for a hit). Fades out by itself. */
|
|
54
|
+
shake?: number;
|
|
55
|
+
};
|
|
56
|
+
export type Light = {
|
|
57
|
+
/** Direction *towards* the light. Need not be normalized. */
|
|
58
|
+
direction: [number, number, number];
|
|
59
|
+
/** 0..1 ambient term. */
|
|
60
|
+
ambient: number;
|
|
61
|
+
/** Cast shadows (one directional shadow map centred on the camera target). Default true. */
|
|
62
|
+
shadows?: boolean;
|
|
63
|
+
/** Half-size in world units of the shadowed area around the camera target. Default 30. */
|
|
64
|
+
shadowExtent?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Color and brightness of the light, multiplying both sun and ambient: e.g. [0.35, 0.38, 0.6] for
|
|
67
|
+
* moonlight. Glowing colors (channels above 1) aren't affected. Alpha, if given, is ignored.
|
|
68
|
+
* Default [1, 1, 1].
|
|
69
|
+
*/
|
|
70
|
+
color?: Color;
|
|
71
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export type ScoreboardHandlers = {
|
|
2
|
+
/** The score changed (points, time-based points, reset). */
|
|
3
|
+
onScore?: (score: number) => void;
|
|
4
|
+
onLives?: (lives: number) => void;
|
|
5
|
+
/** The whole seconds shown changed: time left for a countdown, elapsed otherwise. */
|
|
6
|
+
onSecond?: (seconds: number) => void;
|
|
7
|
+
/** A countdown reached 0 (the clock stops). */
|
|
8
|
+
onTimeUp?: () => void;
|
|
9
|
+
/** Lives went from above 0 to 0. */
|
|
10
|
+
onLivesOut?: () => void;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Score, lives and the game clock, kept and advanced in Rust by `world.update`: countdowns, elapsed
|
|
14
|
+
* time and time-based points (survival, distance) cost no JS per frame. Handlers run from `update`
|
|
15
|
+
* only when something they show changed.
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* world.scoreboard.handlers = { onScore: setScore, onSecond: setTime, onTimeUp: () => end(true) };
|
|
19
|
+
* world.scoreboard.reset(3);
|
|
20
|
+
* world.scoreboard.startCountdown(60);
|
|
21
|
+
* world.scoreboard.add(10);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare class Scoreboard {
|
|
25
|
+
private readonly world;
|
|
26
|
+
handlers: ScoreboardHandlers;
|
|
27
|
+
private readonly state;
|
|
28
|
+
/** @internal */
|
|
29
|
+
constructor(world: number);
|
|
30
|
+
private op;
|
|
31
|
+
get score(): number;
|
|
32
|
+
get best(): number;
|
|
33
|
+
get lives(): number;
|
|
34
|
+
/** Seconds left (countdown) or elapsed, fractional. */
|
|
35
|
+
get seconds(): number;
|
|
36
|
+
/** Whole seconds as shown: rounded up while counting down, down while counting up. */
|
|
37
|
+
get shownSeconds(): number;
|
|
38
|
+
get running(): boolean;
|
|
39
|
+
/** Adds points (negative to take away). Returns the score. */
|
|
40
|
+
add(points: number): number;
|
|
41
|
+
set(score: number): number;
|
|
42
|
+
addLives(n: number): number;
|
|
43
|
+
setLives(n: number): void;
|
|
44
|
+
/** Counts `seconds` down to 0 (then `onTimeUp`), earning `pointsPerSecond` meanwhile. */
|
|
45
|
+
startCountdown(seconds: number, pointsPerSecond?: number): void;
|
|
46
|
+
/** Counts up from 0, earning `pointsPerSecond` (survival and distance scores). */
|
|
47
|
+
startClock(pointsPerSecond?: number): void;
|
|
48
|
+
stop(): void;
|
|
49
|
+
resume(): void;
|
|
50
|
+
/** Time bonus (or penalty) on the clock. */
|
|
51
|
+
addTime(seconds: number): void;
|
|
52
|
+
/**
|
|
53
|
+
* Adds `pointsPerSecond` for each whole second saved: the seconds left on a countdown, or
|
|
54
|
+
* `expectedSeconds` minus the seconds elapsed on a clock counting up. Returns the score.
|
|
55
|
+
*/
|
|
56
|
+
awardTimeBonus(pointsPerSecond: number, expectedSeconds?: number): number;
|
|
57
|
+
/**
|
|
58
|
+
* A new run: score 0, `lives`, clock stopped at 0. With `countdownSeconds`, the stopped clock shows
|
|
59
|
+
* that countdown in full (a ready screen); `resume()` starts it.
|
|
60
|
+
*/
|
|
61
|
+
reset(lives?: number, countdownSeconds?: number): void;
|
|
62
|
+
/** @internal Runs handlers for what changed since the last call. */
|
|
63
|
+
dispatch(): void;
|
|
64
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Entity, EntityOptions } from './types';
|
|
2
|
+
export type TransformOptions = Pick<EntityOptions, 'position' | 'rotation' | 'scale' | 'color'>;
|
|
3
|
+
export declare const TRANSFORM_STRIDE = 16;
|
|
4
|
+
/**
|
|
5
|
+
* Explicit draw-only updates, applied in one native call by `flush()`. Flush before reading
|
|
6
|
+
* positions, animating, or stepping the world. Records and scratch storage are reused; values are
|
|
7
|
+
* copied when queued, never retained by reference. The scalar methods (`position`, `rotation`,
|
|
8
|
+
* `scale`, `color`, `transform`) allocate nothing; consecutive calls for the same entity share one
|
|
9
|
+
* record.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* const batch = world.transforms;
|
|
13
|
+
* for (const p of pieces) batch.transform(p.entity, p.x, 0, p.z, 0, p.qy, 0, p.qw);
|
|
14
|
+
* batch.flush();
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare class TransformBatch {
|
|
18
|
+
private readonly commit;
|
|
19
|
+
private data;
|
|
20
|
+
private count;
|
|
21
|
+
constructor(commit: (data: Float64Array, count: number) => number);
|
|
22
|
+
private record;
|
|
23
|
+
position(entity: Entity, x: number, y: number, z: number): void;
|
|
24
|
+
/** Rotation quaternion [x, y, z, w]. */
|
|
25
|
+
rotation(entity: Entity, x: number, y: number, z: number, w: number): void;
|
|
26
|
+
/** Uniform scale, or per axis. */
|
|
27
|
+
scale(entity: Entity, x: number, y?: number, z?: number): void;
|
|
28
|
+
/** RGBA color; alpha defaults to 1. */
|
|
29
|
+
color(entity: Entity, r: number, g: number, b: number, a?: number): void;
|
|
30
|
+
/** Position and rotation together (the common per-frame update for a moving piece). */
|
|
31
|
+
transform(entity: Entity, x: number, y: number, z: number, qx: number, qy: number, qz: number, qw: number): void;
|
|
32
|
+
/** Queued records (merged per entity). */
|
|
33
|
+
get size(): number;
|
|
34
|
+
set(entity: Entity, options: TransformOptions): void;
|
|
35
|
+
private writeColor;
|
|
36
|
+
flush(): number;
|
|
37
|
+
clear(): void;
|
|
38
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { type RenderSource, type Vec3 } from '../types';
|
|
2
|
+
import { Scoreboard } from './Scoreboard';
|
|
3
|
+
import { TransformBatch } from './TransformBatch';
|
|
4
|
+
import type { AnimateOptions, AnimateTarget, Bounds, BurstOptions, ClipOptions, CollisionInfo, Entity, EntityOptions, Keyframe, PickHit, RaycastHit, ScreenPlane } from './types';
|
|
5
|
+
/** True when the engine's native code is linked into this build (it is not in Expo Go). */
|
|
6
|
+
export declare const isEngineAvailable: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* A game world, simulated by the Rust core: entities, motion, Rapier physics, collisions,
|
|
9
|
+
* animations and raycasts at a fixed 60 Hz, with rendering smoothed between steps. Pass it to `<GameView>`.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* const world = new World(500);
|
|
13
|
+
* const ball = world.spawn({ mesh: "sphere", position: [0, 5, 0], physics: "dynamic" });
|
|
14
|
+
* world.set(ball, { color: [1, 0, 0] });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare class World implements RenderSource {
|
|
18
|
+
readonly capacity: number;
|
|
19
|
+
readonly matrices: Float32Array;
|
|
20
|
+
readonly colors: Float32Array;
|
|
21
|
+
readonly regions: Float32Array;
|
|
22
|
+
readonly ranges: Uint32Array;
|
|
23
|
+
private readonly events;
|
|
24
|
+
private readonly eventFloats;
|
|
25
|
+
private readonly finished;
|
|
26
|
+
private readonly scratch;
|
|
27
|
+
private readonly desc;
|
|
28
|
+
private anim;
|
|
29
|
+
private readonly burstDesc;
|
|
30
|
+
private readonly info;
|
|
31
|
+
/** Promise resolvers of running animations, by animation id. */
|
|
32
|
+
private readonly pending;
|
|
33
|
+
/** Callbacks of pending `after` timers, by timer id (the core counts the time). */
|
|
34
|
+
private readonly timers;
|
|
35
|
+
/** Timers for a native core built before `after` existed: [fire time, callback], on `clock`. */
|
|
36
|
+
private fallbackTimers;
|
|
37
|
+
private fallbackTimerId;
|
|
38
|
+
private transformsValue;
|
|
39
|
+
private clock;
|
|
40
|
+
private scoreboardValue;
|
|
41
|
+
private readonly texts;
|
|
42
|
+
private readonly id;
|
|
43
|
+
private disposed;
|
|
44
|
+
private gravityValue;
|
|
45
|
+
private boundsValue;
|
|
46
|
+
private listenerValue;
|
|
47
|
+
constructor(capacity: number);
|
|
48
|
+
private get native();
|
|
49
|
+
/** True once `dispose()` has run. Cleanup calls (despawn, set, has, queries, stopping animations
|
|
50
|
+
* and timers) are safe no-ops afterwards, so late animation promises and timers need no guard.
|
|
51
|
+
*/
|
|
52
|
+
get isDisposed(): boolean;
|
|
53
|
+
/** Live entities (text letters count too). */
|
|
54
|
+
get count(): number;
|
|
55
|
+
/** Adds an entity (one native call; text adds one per letter). Throws if the world is full or an option is invalid. */
|
|
56
|
+
spawn(options?: EntityOptions): Entity;
|
|
57
|
+
/**
|
|
58
|
+
* Changes an entity (one native call). Only the options you pass change; `null` removes.
|
|
59
|
+
* Returns false if the entity is gone, the world is disposed, or an option was rejected (the others still apply).
|
|
60
|
+
*/
|
|
61
|
+
set(e: Entity, options: EntityOptions): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* This world's shared draw-only transform batch (created on first use). Queue per-frame moves with
|
|
64
|
+
* its allocation-free methods after `update()`, then `flush()` once before the frame is drawn.
|
|
65
|
+
*/
|
|
66
|
+
get transforms(): TransformBatch;
|
|
67
|
+
/** Reusable draw-only transforms; use set() for text entities and flush before animations/queries. */
|
|
68
|
+
createTransformBatch(): TransformBatch;
|
|
69
|
+
/** Removes an entity and anything attached to it. Returns false if it was already gone. */
|
|
70
|
+
despawn(e: Entity): boolean;
|
|
71
|
+
/** A one-off push: jump, explosion, knockback (dynamic bodies only). */
|
|
72
|
+
impulse(e: Entity, impulse: Vec3): void;
|
|
73
|
+
private resolveMesh;
|
|
74
|
+
private encodeColor;
|
|
75
|
+
/** Updates a text entity's letters in place, growing or shrinking only when needed. */
|
|
76
|
+
private buildText;
|
|
77
|
+
/** Native world backing this render source; bone palettes stay in Rust. */
|
|
78
|
+
get nativeWorld(): number;
|
|
79
|
+
/** Play a named GLB clip. Re-selecting it changes speed without restarting; `time` explicitly seeks.
|
|
80
|
+
* `fade` crossfades from the current pose (seconds). A speed of zero holds a pose for a ready screen.
|
|
81
|
+
*/
|
|
82
|
+
playClip(entity: Entity, clip: string, options?: ClipOptions): boolean;
|
|
83
|
+
/** Hold the current GLB pose, or return to its bind pose with `reset`. */
|
|
84
|
+
stopClip(entity: Entity, reset?: boolean): boolean;
|
|
85
|
+
/** Sample selected animated vertices in model space for foot contact and attachments.
|
|
86
|
+
* Reuse both arrays. `after` previews the interpolated pose following the next update.
|
|
87
|
+
*/
|
|
88
|
+
sampleSkinnedVertices(entity: Entity, vertices: Uint32Array, output: Float32Array, after?: number): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Animates in Rust, with no per-frame JS: from where things are to `to`, or through keyframes.
|
|
91
|
+
* Each property (position, rotation, scale, color, shake) runs on its own, so a piece can move
|
|
92
|
+
* while it pulses; animating a property again replaces only that property. Pass several entities
|
|
93
|
+
* to animate them together (with `stagger` for waves). Resolves when every part has finished, been
|
|
94
|
+
* replaced or stopped, or its entity was despawned.
|
|
95
|
+
*
|
|
96
|
+
* ```ts
|
|
97
|
+
* await world.animate(piece, { position: [2, 0, 3] }, { duration: 0.25, easing: "back" });
|
|
98
|
+
* world.animate(coin, { scale: 1.2 }, { repeat: "forever", yoyo: true }); // pulse
|
|
99
|
+
* world.animate(piece, [{ moveBy: [1, 1.5, 0] }, { moveBy: [2, 0, 0] }], { path: "smooth" }); // hop
|
|
100
|
+
* world.animate(card, { turn: [0, Math.PI, 0] }); // flip
|
|
101
|
+
* world.animate(tiles, { scale: 1 }, { stagger: 0.03, easing: "back" }); // reveal a board
|
|
102
|
+
* world.animate(cursor, { position: [x, 0, z] }, { spring: true }); // follows the finger smoothly
|
|
103
|
+
* world.animate(wrongTile, { shake: 0.15 }, { duration: 0.4 });
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
animate(targets: Entity | readonly Entity[], to: AnimateTarget | readonly Keyframe[], options?: AnimateOptions): Promise<void>;
|
|
107
|
+
private encodeKeyframe;
|
|
108
|
+
/** Stops every animation on the entity where it is (their promises resolve). */
|
|
109
|
+
stopAnimation(e: Entity): void;
|
|
110
|
+
/**
|
|
111
|
+
* Particles: many small, short-lived pieces flying out of a point (explosions, sparks, dust,
|
|
112
|
+
* confetti). One native call; they fall, spin, shrink away and clean themselves up. `endSize` and
|
|
113
|
+
* `endColor` grow / shrink and recolor them over their life (fire cooling, smoke thinning out).
|
|
114
|
+
* Returns how many were spawned (fewer if the world is nearly full).
|
|
115
|
+
*/
|
|
116
|
+
burst(options: BurstOptions): number;
|
|
117
|
+
/**
|
|
118
|
+
* Runs `fn` after `seconds` of `update` time (game time: it pauses when updates stop). The clock is
|
|
119
|
+
* kept in Rust, so there's no JS timer list to scan every frame. Due callbacks run inside `update`,
|
|
120
|
+
* earliest first. Returns the timer's id for `cancelTimer`; `cancelTimers()` drops every pending one.
|
|
121
|
+
* After `dispose()` it does nothing and returns 0.
|
|
122
|
+
*
|
|
123
|
+
* ```ts
|
|
124
|
+
* world.after(0.3, () => checkMatches());
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
after(seconds: number, fn: () => void): number;
|
|
128
|
+
/** Drops one pending `after` timer so its callback never runs. Returns false if it already ran or was dropped. */
|
|
129
|
+
cancelTimer(id: number): boolean;
|
|
130
|
+
/** Drops every pending `after` timer: their callbacks never run (a new round, a reset). */
|
|
131
|
+
cancelTimers(): void;
|
|
132
|
+
/** Score, lives and the game clock, kept in Rust (created on first use). */
|
|
133
|
+
get scoreboard(): Scoreboard;
|
|
134
|
+
/** Timers waiting to fire. */
|
|
135
|
+
get timerCount(): number;
|
|
136
|
+
/** Resolves the promises of animations the core reports as ended, then runs due timers. */
|
|
137
|
+
private resolveFinished;
|
|
138
|
+
private runFallbackTimers;
|
|
139
|
+
/**
|
|
140
|
+
* Current simulated position (relative to the parent when attached), or null if the entity is gone.
|
|
141
|
+
* Pass `out` to avoid allocating every frame.
|
|
142
|
+
*/
|
|
143
|
+
position(e: Entity, out?: [number, number, number]): [number, number, number] | null;
|
|
144
|
+
/** Where the entity was last drawn, in world space (parents and smoothing included), or null if it's gone. */
|
|
145
|
+
worldPosition(e: Entity, out?: [number, number, number]): [number, number, number] | null;
|
|
146
|
+
/** Current velocity, or null if the entity is gone. Pass `out` to avoid allocating every frame. */
|
|
147
|
+
velocity(e: Entity, out?: [number, number, number]): [number, number, number] | null;
|
|
148
|
+
/** True while the entity exists (false after `dispose()`). */
|
|
149
|
+
has(e: Entity): boolean;
|
|
150
|
+
/**
|
|
151
|
+
* First solid (non-sensor) collider along the ray whose layer is in `mask`, as of the last update.
|
|
152
|
+
* Pass `out` to reuse a hit object every frame.
|
|
153
|
+
*/
|
|
154
|
+
raycast(origin: Vec3, direction: Vec3, maxDistance: number, mask?: number, out?: RaycastHit): RaycastHit | null;
|
|
155
|
+
/**
|
|
156
|
+
* The entity under a point of the GameView (e.g. a tap's `x, y`), tested against what was last
|
|
157
|
+
* drawn. Needs no physics. Returns null if nothing pickable is there. Pass `out` to reuse a hit object.
|
|
158
|
+
*/
|
|
159
|
+
pick(x: number, y: number, out?: PickHit): PickHit | null;
|
|
160
|
+
/**
|
|
161
|
+
* Where a world position appears in the GameView, in points from its top-left, or null if it's behind
|
|
162
|
+
* the camera (or nothing has been drawn yet). Place React Native views over 3D objects with it.
|
|
163
|
+
* Pass `out` to avoid allocating every frame.
|
|
164
|
+
*/
|
|
165
|
+
toScreen(position: Vec3, out?: [number, number]): [number, number] | null;
|
|
166
|
+
/**
|
|
167
|
+
* Where a GameView point (a finger's `x, y`) lands on a plane, or null if the plane is behind the
|
|
168
|
+
* camera or edge-on. Defaults to the ground (y = 0). Drag a piece across a board with it:
|
|
169
|
+
* `world.screenToWorld(x, y, { point: [0, pieceHeight, 0] })`. 2D games looking down -z use
|
|
170
|
+
* `{ normal: [0, 0, 1] }`. Like `toScreen`, it needs a drawn frame (null before the first one).
|
|
171
|
+
* Pass `out` to avoid allocating every frame.
|
|
172
|
+
*/
|
|
173
|
+
screenToWorld(x: number, y: number, plane?: ScreenPlane, out?: [number, number, number]): [number, number, number] | null;
|
|
174
|
+
/** Called by GameView after drawing a frame, with the camera matrix and the view size in points. */
|
|
175
|
+
setView(viewProj: Float32Array, width: number, height: number): void;
|
|
176
|
+
private copyScratch;
|
|
177
|
+
/** Default [0, -9.81, 0]. */
|
|
178
|
+
get gravity(): Vec3;
|
|
179
|
+
set gravity(g: Vec3);
|
|
180
|
+
/** Keeps moving non-physics entities inside [minX, minZ, maxX, maxZ]. Physics bodies need walls. */
|
|
181
|
+
get bounds(): Bounds | null;
|
|
182
|
+
set bounds(b: Bounds | null);
|
|
183
|
+
/** Impact sounds pan and fade relative to this entity (usually the player). */
|
|
184
|
+
get listener(): Entity | null;
|
|
185
|
+
set listener(e: Entity | null);
|
|
186
|
+
/** Advances the simulation (fixed 60 Hz steps), resolves finished animations, refreshes what GameView draws. */
|
|
187
|
+
update(dt: number): void;
|
|
188
|
+
/**
|
|
189
|
+
* Calls `fn` for each touch that started or ended during the last `update`. `info` is reused:
|
|
190
|
+
* copy what you need. Either entity may already be despawned by an earlier callback.
|
|
191
|
+
*/
|
|
192
|
+
forEachCollision(fn: (a: Entity, b: Entity, info: CollisionInfo) => void): void;
|
|
193
|
+
/**
|
|
194
|
+
* Frees the native world. Pending animation promises resolve and timers are dropped. Later cleanup
|
|
195
|
+
* calls and queries are no-ops (see `isDisposed`); `spawn` and `update` throw.
|
|
196
|
+
*/
|
|
197
|
+
dispose(): void;
|
|
198
|
+
}
|