142 named public exports, including classes, helpers, component contracts and TypeScript data structures, audited against the shared engine entry point.
Every public export is listed below. Signatures come from built declarations. Gameplay APIs are shared; host styles and asset sources follow the platform guides.
Use declarations to look up types. Use the runnable examples and linked guides for setup, behavior and cleanup.
Import runtime APIs and types from one entry
React and React Native · shared engine API
import { GameView, useWorld, type Entity, type EntityOptions } from "@nayan-ui/engine";const ball: EntityOptions = { mesh: "sphere", color: "#33B3FF", physics: "dynamic" };export function Ball() {let handle: Entity | null = null;const world = useWorld(16, (w) => { handle = w.spawn(ball); });return world && <GameView source={world} onTap={() => handle !== null && world.impulse(handle, [0, 4, 0])} />;}
Usage and examples: /game-engine/world-entities.
| Export | Kind | Guide |
|---|---|---|
| World | Runtime API | /game-engine/world-entities |
| isEngineAvailable | Runtime API | /game-engine/world-entities |
world/World declarations
React and React Native · shared engine API
/** True when the engine's native code is linked into this build (it is not in Expo Go). */export declare const isEngineAvailable: boolean;/*** A game world, simulated by the Rust core: entities, motion, Rapier physics, collisions,* animations and raycasts at a fixed 60 Hz, with rendering smoothed between steps. Pass it to `<GameView>`.** ```ts* const world = new World(500);* const ball = world.spawn({ mesh: "sphere", position: [0, 5, 0], physics: "dynamic" });* world.set(ball, { color: [1, 0, 0] });* ```*/export declare class World implements RenderSource {readonly capacity: number;readonly matrices: Float32Array;readonly colors: Float32Array;readonly regions: Float32Array;readonly ranges: Uint32Array;constructor(capacity: number);/** True once `dispose()` has run. Cleanup calls (despawn, set, has, queries, stopping animations* and timers) are safe no-ops afterwards, so late animation promises and timers need no guard.*/get isDisposed(): boolean;/** Live entities (text letters count too). */get count(): number;/** Adds an entity (one native call; text adds one per letter). Throws if the world is full or an option is invalid. */spawn(options?: EntityOptions): Entity;/*** Changes an entity (one native call). Only the options you pass change; `null` removes.* Returns false if the entity is gone, the world is disposed, or an option was rejected (the others still apply).*/set(e: Entity, options: EntityOptions): boolean;/*** This world's shared draw-only transform batch (created on first use). Queue per-frame moves with* its allocation-free methods; the next `update()` applies them first (or `flush()` them yourself* before reading positions or animating).*/get transforms(): TransformBatch;/** Reusable draw-only transforms; use set() for text entities and flush before animations/queries. */createTransformBatch(): TransformBatch;/** Removes an entity and anything attached to it. Returns false if it was already gone. */despawn(e: Entity): boolean;/** A one-off push: jump, explosion, knockback (dynamic bodies only). */impulse(e: Entity, impulse: Vec3): void;/** Native world backing this render source; bone palettes stay in Rust. */get nativeWorld(): number;/** Play a named GLB clip. Re-selecting it changes speed without restarting; `time` explicitly seeks.* `fade` crossfades from the current pose (seconds). A speed of zero holds a pose for a ready screen.*/playClip(entity: Entity, clip: string, options?: ClipOptions): boolean;/** Hold the current GLB pose, or return to its bind pose with `reset`. */stopClip(entity: Entity, reset?: boolean): boolean;/** Sample selected animated vertices in model space for foot contact and attachments.* Reuse both arrays. `after` previews the interpolated pose following the next update.*/sampleSkinnedVertices(entity: Entity, vertices: Uint32Array, output: Float32Array, after?: number): boolean;/*** Animates in Rust, with no per-frame JS: from where things are to `to`, or through keyframes.* Each property (position, rotation, scale, color, shake) runs on its own, so a piece can move* while it pulses; animating a property again replaces only that property. Pass several entities* to animate them together (with `stagger` for waves). Resolves when every part has finished, been* replaced or stopped, or its entity was despawned.** ```ts* await world.animate(piece, { position: [2, 0, 3] }, { duration: 0.25, easing: "back" });* world.animate(coin, { scale: 1.2 }, { repeat: "forever", yoyo: true }); // pulse* world.animate(piece, [{ moveBy: [1, 1.5, 0] }, { moveBy: [2, 0, 0] }], { path: "smooth" }); // hop* world.animate(card, { turn: [0, Math.PI, 0] }); // flip* world.animate(tiles, { scale: 1 }, { stagger: 0.03, easing: "back" }); // reveal a board* world.animate(cursor, { position: [x, 0, z] }, { spring: true }); // follows the finger smoothly* world.animate(wrongTile, { shake: 0.15 }, { duration: 0.4 });* ```*/animate(targets: Entity | readonly Entity[], to: AnimateTarget | readonly Keyframe[], options?: AnimateOptions): Promise<void>;/** Stops every animation on the entity where it is (their promises resolve). */stopAnimation(e: Entity): void;/*** Particles: many small, short-lived pieces flying out of a point (explosions, sparks, dust,* confetti). One native call; they fall, spin, shrink away and clean themselves up. `endSize` and* `endColor` grow / shrink and recolor them over their life (fire cooling, smoke thinning out).* Returns how many were spawned (fewer if the world is nearly full).*/burst(options: BurstOptions): number;/*** Runs `fn` after `seconds` of `update` time (game time: it pauses when updates stop). The clock is* kept in Rust, so there's no JS timer list to scan every frame. Due callbacks run inside `update`,* earliest first. Returns the timer's id for `cancelTimer`; `cancelTimers()` drops every pending one.* After `dispose()` it does nothing and returns 0.** ```ts* world.after(0.3, () => checkMatches());* ```*/after(seconds: number, fn: () => void): number;/** Drops one pending `after` timer so its callback never runs. Returns false if it already ran or was dropped. */cancelTimer(id: number): boolean;/** Drops every pending `after` timer: their callbacks never run (a new round, a reset). */cancelTimers(): void;/** Score, lives and the game clock, kept in Rust (created on first use). */get scoreboard(): Scoreboard;/** How many times `update` has run. GameView reads it to step the world only when `onUpdate` didn't. */get updateCount(): number;/** Timers waiting to fire. */get timerCount(): number;/*** Current simulated position (relative to the parent when attached), or null if the entity is gone.* Pass `out` to avoid allocating every frame.*/position(e: Entity, out?: [number,number,number]): [number,number,number] | null;/** Where the entity was last drawn, in world space (parents and smoothing included), or null if it's gone. */worldPosition(e: Entity, out?: [number,number,number]): [number,number,number] | null;/** Current velocity, or null if the entity is gone. Pass `out` to avoid allocating every frame. */velocity(e: Entity, out?: [number,number,number]): [number,number,number] | null;/** True while the entity exists (false after `dispose()`). */has(e: Entity): boolean;/*** First solid (non-sensor) collider along the ray whose layer is in `mask`, as of the last update.* Pass `out` to reuse a hit object every frame.*/raycast(origin: Vec3, direction: Vec3, maxDistance: number, mask?: number, out?: RaycastHit): RaycastHit | null;/*** The entity under a point of the GameView (e.g. a tap's `x, y`), tested against what was last* drawn. Needs no physics. Returns null if nothing pickable is there. Pass `out` to reuse a hit object.*/pick(x: number, y: number, out?: PickHit): PickHit | null;/*** Where a world position appears in the GameView, in points from its top-left, or null if it's behind* the camera (or nothing has been drawn yet). Place React Native views over 3D objects with it.* Pass `out` to avoid allocating every frame.*/toScreen(position: Vec3, out?: [number,number]): [number,number] | null;/*** Where a GameView point (a finger's `x, y`) lands on a plane, or null if the plane is behind the* camera or edge-on. Defaults to the ground (y = 0). Drag a piece across a board with it:* `world.screenToWorld(x, y, { point: [0, pieceHeight, 0] })`. 2D games looking down -z use* `{ normal: [0, 0, 1] }`. Like `toScreen`, it needs a drawn frame (null before the first one).* Pass `out` to avoid allocating every frame.*/screenToWorld(x: number, y: number, plane?: ScreenPlane, out?: [number,number,number]): [number,number,number] | null;/** Called by GameView after drawing a frame, with the camera matrix and the view size in points. */setView(viewProj: Float32Array, width: number, height: number): void;/** Default [0, -9.81, 0]. */get gravity(): Vec3;set gravity(g: Vec3);/** Keeps moving non-physics entities inside [minX, minZ, maxX, maxZ]. Physics bodies need walls. */get bounds(): Bounds | null;set bounds(b: Bounds | null);/** Impact sounds pan and fade relative to this entity (usually the player). */get listener(): Entity | null;set listener(e: Entity | null);/*** Advances the simulation (fixed 60 Hz steps), resolves finished animations, runs due timers and* scoreboard handlers, and refreshes what GameView draws. `GameView` calls it for you each frame;* call it yourself from `onUpdate` only to step with a different `dt` (it is then not stepped twice).*/update(dt: number): void;/*** Calls `fn` for each touch that started or ended during the last `update`. `info` is reused:* copy what you need. Either entity may already be despawned by an earlier callback.*/forEachCollision(fn: (a: Entity, b: Entity, info: CollisionInfo) => void): void;/*** Frees the native world. Pending animation promises resolve and timers are dropped. Later cleanup* calls and queries are no-ops (see `isDisposed`); `spawn` and `update` throw.*/dispose(): void;}
Usage and examples: /game-engine/world-entities.
| Export | Kind | Guide |
|---|---|---|
| quat | Runtime API | /game-engine/world-entities |
| MutableQuat | TypeScript type | /game-engine/world-entities |
world/quat declarations
React and React Native · shared engine API
/** A writable quaternion; pass one as `out` to reuse it instead of allocating. */export type MutableQuat = [number,number,number,number];/*** Quaternion helpers for `rotation` options, keyframes and geometry parts ([x, y, z, w]). Every* function takes an optional `out` so per-frame code can reuse one array instead of allocating.** ```ts* world.set(car, { rotation: quat.y(heading) });* const spin = quat.multiply(quat.y(yaw), quat.x(pitch), scratch); // pitch first, then yaw* ```*/export declare const quat: {/** No rotation. */identity: Quat;/** Rotation by `angle` radians around the unit axis (x, y, z). */axisAngle(x: number, y: number, z: number, angle: number, out?: MutableQuat): MutableQuat;/** Rotation around the x axis (pitch). */x(angle: number, out?: MutableQuat): MutableQuat;/** Rotation around the y axis (yaw, heading). */y(angle: number, out?: MutableQuat): MutableQuat;/** Rotation around the z axis (roll; spin for 2D games looking down -z). */z(angle: number, out?: MutableQuat): MutableQuat;/** `a` after `b`: `b` turns first. `out` may be `a` or `b`. */multiply(a: Quat, b: Quat, out?: MutableQuat): MutableQuat;/** Turns around x, then y, then z (radians): the same as `multiply(z(z), multiply(y(y), x(x)))`. */fromEuler(x: number, y: number, z: number, out?: MutableQuat): MutableQuat;/** Shortest-path interpolation from `a` (t = 0) to `b` (t = 1). */slerp(a: Quat, b: Quat, t: number, out?: MutableQuat): MutableQuat;};
Usage and examples: /game-engine/camera-lighting.
| Export | Kind | Guide |
|---|---|---|
| toColor | Runtime API | /game-engine/camera-lighting |
| ColorInput | TypeScript type | /game-engine/camera-lighting |
world/color declarations
React and React Native · shared engine API
/** A color as an option takes it: `[r, g, b]` / `[r, g, b, a]` (0..1, channels above 1 glow) or a CSS string. */export type ColorInput = Color | string;/*** Any color input as an `[r, g, b, a]` tuple (0..1), with its alpha multiplied by `alpha`. Use it when* you need the numbers (to brighten, mix or fade a theme color); options take strings directly.** ```ts* toColor('#FF4757'); // [1, 0.278, 0.341, 1]* toColor('#FF4757', 0.5); // half see-through* ```*/export declare function toColor(color: ColorInput, alpha?: number): [number,number,number,number];
Usage and examples: /game-engine/particles.
| Export | Kind | Guide |
|---|---|---|
| effects | Runtime API | /game-engine/particles |
| DustOptions | TypeScript type | /game-engine/particles |
| EffectOptions | TypeScript type | /game-engine/particles |
| FlashOptions | TypeScript type | /game-engine/particles |
| PopOptions | TypeScript type | /game-engine/particles |
world/effects declarations
React and React Native · shared engine API
/** Shared options of the layered effects (confetti, sparkle, shatter, splash, sparks, explosion). */export type EffectOptions = {position: Vec3;/** One color (CSS string or tuple), or several to pick from at random. */colors: ColorInput | readonly ColorInput[];/** Typical particle size. */size: number;/** Top speed. */speed: number;/** About how many particles (a few extra go to the flash and puffs). */count: number;/** Seconds. */lifetime: number;/** Vertical acceleration (negative falls). Default 0. */gravity?: number;/** Main direction. Default up. */direction?: Vec3;/** Half-angle of the cone around `direction`. Default π (every direction). */spread?: number;/** A brief glow at the source. Default true. */flash?: boolean;};/** A soft cloud of puffs that swell and fade: landing dust, kicked-up sand, sawdust, steam, muzzle smoke. */export type DustOptions = {position: Vec3;/** Start color (alpha is how thick it looks), or several to pick from. */color: ColorInput | readonly ColorInput[];/** Puff size at the start. */size: number;/** Top speed. */speed: number;count: number;/** Seconds. */lifetime: number;/** Default up. */direction?: Vec3;/** Half-angle around `direction`. Default π. */spread?: number;/** Default 0 (dust hangs; positive rises like smoke). */gravity?: number;/** How much each puff grows by the end. Default 2. */endSize?: number;/** Color at the end. Default: a single `color` faded to transparent; several colors keep theirs. */endColor?: ColorInput;/** Default "puff" (blended); "flame" adds light instead. */mesh?: BurstOptions['mesh'];};/** One glow that swells and fades at a point: a hit, a strike, a muzzle flash. */export type FlashOptions = {position: Vec3;/** Use channels above 1 to glow (see `effects.hot`). */color: ColorInput;size: number;/** Seconds. Default 0.22. */lifetime?: number;/** How much it grows by the end. Default 2.2. */endSize?: number;/** Default: `color` faded to transparent. */endColor?: ColorInput;/** Default "flame" (adds light); "sphere" or "puff" for a solid or soft flash. */mesh?: BurstOptions['mesh'];/** Glows drawn at once (slightly scattered when `speed` > 0). Default 1. */count?: number;/** Default 0. */speed?: number;};/** The cleared-piece pop: swell, flash white, settle, shrink away. */export type PopOptions = {/** Its scale at rest (what it has now): one number, or per axis. */scale: number | Vec3;/** Its color at rest, to return to after the white flash. Omit to flash `flash` only (or nothing). */color?: ColorInput;/** Parts to flash white as well (a group's visible children, whose rest color is white). */flash?: readonly Entity[];/** Seconds before it starts. Default 0. */delay?: number;/** Seconds it takes. Default `effects.POP_TIME`. */duration?: number;};type Rgba = [number,number,number,number];/*** Ready-made effects. Each is one call; particles then live, fall, shrink and recolor in Rust.** ```ts* effects.confetti(world, { position, colors: [RED, GOLD], size: 0.12, speed: 6, count: 40, lifetime: 1.2, gravity: -6 });* effects.dust(world, { position: feet, color: [0.8, 0.75, 0.65, 0.6], size: 0.3, speed: 1.5, count: 6, lifetime: 0.5 });* effects.flash(world, { position: hit, color: effects.hot(ORANGE), size: 0.8 });* await effects.pop(world, candy, { scale: 1, color: RED });* world.despawn(candy);* ```*/export declare const effects: {/** Celebration: tumbling paper, glints and a pop of light (wins, level-ups). */confetti: typeof confetti;/** Reward glitter: bright beads and glints (pickups, perfect moves). */sparkle: typeof sparkle;/** Breaking apart: chunks, crumbs, a glow and dust (bricks, crates, glass). `mesh` shapes the chunks. */shatter: typeof shatter;/** Liquid: droplets and mist (water, juice, paint). */splash: typeof splash;/** Hot metal: additive streaks and beads (scrapes, strikes, electricity). */sparks: typeof sparks;/** Fiery blast: flash, fireball cooling to smoke, embers and optional debris. */explosion: typeof explosion;/** Soft swelling puffs: dust, sand, sawdust, steam, smoke. */dust: typeof dust;/** One swelling glow: hits, strikes, muzzle flashes. */flash: typeof flash;/** The cleared-piece animation: swell, flash white, settle, shrink to nothing. */pop: typeof pop;/** Default `pop` duration in seconds. */POP_TIME: number;/** The same hue made self-lit (brightest channel lifted to `peak`), for glows. */hot: typeof hot;/** Part way (`t`, 0..1) to white. */pale: typeof pale;};
Usage and examples: /game-engine/scoreboard-timers.
| Export | Kind | Guide |
|---|---|---|
| Scoreboard | Runtime API | /game-engine/scoreboard-timers |
| ScoreboardHandlers | TypeScript type | /game-engine/scoreboard-timers |
world/Scoreboard declarations
React and React Native · shared engine API
export type ScoreboardHandlers = {/** The score changed (points, time-based points, reset). */onScore?: (score: number) => void;onLives?: (lives: number) => void;/** The whole seconds shown changed: time left for a countdown, elapsed otherwise. */onSecond?: (seconds: number) => void;/** A countdown reached 0 (the clock stops). */onTimeUp?: () => void;/** Lives went from above 0 to 0. */onLivesOut?: () => void;};/*** Score, lives and the game clock, kept and advanced in Rust by `world.update`: countdowns, elapsed* time and time-based points (survival, distance) cost no JS per frame. Handlers run from `update`* only when something they show changed. Set `handlers` for the game's own rules, and `listen` for* anything else that follows along (a UI showing the score), so neither replaces the other.** ```ts* world.scoreboard.handlers = { onTimeUp: () => end(true) };* const stop = world.scoreboard.listen({ onScore: setScore, onSecond: setTime });* world.scoreboard.reset(3);* world.scoreboard.startCountdown(60);* world.scoreboard.add(10);* ```*/export declare class Scoreboard {/** The game's own handlers. `listen` adds more without replacing these. */handlers: ScoreboardHandlers;/** @internal */constructor(world: number);get score(): number;get best(): number;get lives(): number;/** Seconds left (countdown) or elapsed, fractional. */get seconds(): number;/** Whole seconds as shown: rounded up while counting down, down while counting up. */get shownSeconds(): number;get running(): boolean;/** Adds points (negative to take away). Returns the score. */add(points: number): number;set(score: number): number;addLives(n: number): number;setLives(n: number): void;/** Counts `seconds` down to 0 (then `onTimeUp`), earning `pointsPerSecond` meanwhile. */startCountdown(seconds: number, pointsPerSecond?: number): void;/** Counts up from 0, earning `pointsPerSecond` (survival and distance scores). */startClock(pointsPerSecond?: number): void;stop(): void;resume(): void;/** Time bonus (or penalty) on the clock. */addTime(seconds: number): void;/*** Adds `pointsPerSecond` for each whole second saved: the seconds left on a countdown, or* `expectedSeconds` minus the seconds elapsed on a clock counting up. Returns the score.*/awardTimeBonus(pointsPerSecond: number, expectedSeconds?: number): number;/*** A new run: score 0, `lives`, clock stopped at 0. With `countdownSeconds`, the stopped clock shows* that countdown in full (a ready screen); `resume()` starts it.*/reset(lives?: number, countdownSeconds?: number): void;/*** Adds handlers alongside `handlers` (and other listeners); they run after them, in order of* listening. Returns a function that removes them.*/listen(handlers: ScoreboardHandlers): () => void;/** @internal Runs handlers for what changed since the last call. */dispatch(): void;}
Usage and examples: /game-engine/world-entities.
world/types declarations
React and React Native · shared engine API
/** Opaque entity handle. Handles of despawned entities are safely ignored. */export type Entity = number & {readonly __entity: unique symbol;};export type Color = readonly [number,number,number] | readonly [number,number,number,number];export type Quat = readonly [number,number,number,number];/** Playback for one entity using a skeletal animation embedded in a loaded model. */export interface ClipOptions {/** Repeat the clip. Default true. */loop?: boolean;/** Playback rate; zero holds a pose. Default 1. */speed?: number;/** Crossfade from the current pose, in seconds. Default 0.15. */fade?: number;/** Seek to this time in seconds. Omit to retain playback when reselecting a clip. */time?: number;}/** Plane used by screenToWorld; defaults to the ground through the origin. */export interface ScreenPlane {point?: Vec3;normal?: Vec3;}/*** - `dynamic`: moved by physics (gravity, collisions, impulses).* - `kinematic`: moved by you; pushes dynamic bodies out of the way.* - `fixed`: never moves (floors, walls).*/export type BodyType = 'dynamic' | 'kinematic' | 'fixed';export type PhysicsOptions = {type: BodyType;/** Default: matches the mesh (spheres get a ball, cylinders a cylinder, ...; anything else a box). */shape?: 'ball' | 'box' | 'cylinder' | 'capsule' | 'cone';/** Ball, cylinder, capsule or cone radius. Default: from the entity's size. */radius?: number;/** Cylinder, capsule or cone height (total). Default: from the entity's size. */height?: number;/** Box size (full width, height, depth). Default: the entity's size. */size?: Vec3;/** Layer bits this collider is on. Default 1. */layer?: number;/** Layers it interacts with. Either side's mask is enough. Default: all. */mask?: number;/** Reports touches but doesn't push: pickups, trigger zones. */sensor?: boolean;/** How grippy, default 0.5. */friction?: number;/** Bounciness 0..1, default 0. */bounce?: number;/** Mass per volume, default 1. */density?: number;/** Slows movement over time (air resistance), default 0. */drag?: number;/** Slows spinning over time, default 0.05. */angularDrag?: number;/** Multiplier on world gravity, default 1. */gravityScale?: number;/** Stays upright: never tumbles. */upright?: boolean;/** Stops fast, small bodies passing through walls. */ccd?: boolean;/** 2D games: stays in its XY plane (moves in x/y, spins only around z). Keep the camera looking down -z. */planar?: boolean;};/** Sound/haptic the core plays by itself when the entity hits something solid. */export type ImpactFeedback = {/** A loaded sound, e.g. `sfx.get("bump")`. Omit for haptics only. */sound?: Sound;/** Slower impacts are silent. Default 1. */minSpeed?: number;/** Full volume and strength at this speed. Default 10. */maxSpeed?: number;/** Volume at full strength, 0..2. Default 1. */volume?: number;/** Vibration at full strength, 0..1. Default 0 (none). */haptic?: number;};/*** Everything about an entity. `spawn` and `set` take the same options; in `set`, only what you* pass changes, and `null` removes something (physics, parent, follow, bob, lifetime, impact).*/export type EntityOptions = {/** A built-in shape or a model from `loadModel`. Default "cube". */mesh?: Shape | Model;/** An image from `loadTexture`, drawn on the mesh (`null` = none). In `set`, pass `mesh` with it. */texture?: Texture | null;/** Part of the texture to show, [u0, v0, u1, v1] from 0..1 (sprite sheets, card atlases). */textureRegion?: readonly [number,number,number,number];/** 3D text instead of a mesh (needs `font`). Letters are 1 unit tall at scale 1. */text?: string;/** A font from `loadFont`, for `text`. */font?: Font;/** Text alignment around `position`. Default "center". */align?: TextAlign;/** Extra space between letters, in ems. Default 0. */letterSpacing?: number;/** Digits all as wide as the widest, so changing scores and timers don't shift. Default false. */tabular?: boolean;/** Relative to the parent when attached. */position?: Vec3;rotation?: Quat;/** A number scales uniformly. Children scale with their parent. Visual only after the body exists. */scale?: Vec3 | number;/*** A CSS color (`'#FF4757'`, `'rgba(…)'`) or a 0..1 tuple. Alpha below 1 makes it see-through. Tuple* channels above 1 glow: at 2 it's self-lit, ignoring light and shadow (fire, lamps).*/color?: ColorInput;/** Units per second. */velocity?: Vec3;/** Sets horizontal speed [x, z] and keeps the vertical one: steer a body and it still falls. */groundVelocity?: readonly [number,number];/** Units per second², for entities without a dynamic body (falling debris, thrown items). */acceleration?: Vec3;/** Radians per second around each axis. */spin?: Vec3;/** Visual bob: the drawn position moves by amplitude * sin(phase), phase advancing at `speed`. */bob?: {amplitude: Vec3;speed: number;phase?: number;} | null;/** Chase `target` along the ground at `speed`. */follow?: {target: Entity;speed: number;} | null;/** Seconds until it shrinks away and is despawned. */lifetime?: number | null;/** Attach to another entity: it moves, turns and scales with the parent and is despawned with it. Visual only. */parent?: Entity | null;physics?: BodyType | PhysicsOptions | null;impact?: ImpactFeedback | null;/** Whether `pick` can hit it. Default true. */pickable?: boolean;};export type Easing = 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' | 'back' | 'bounce' | 'elastic';/** What `animate` changes. Anything left out stays as it is (and keeps any animation it already has). */export type AnimateTarget = {position?: Vec3;rotation?: Quat;scale?: Vec3 | number;/** A CSS color or a 0..1 tuple. */color?: ColorInput;/** Move by this offset from where the animation starts (instead of to a `position`). */moveBy?: Vec3;/** Turn by these angles (radians around x, y, z) from the starting rotation. 2π spins once; more spins more. */turn?: Vec3;/** Shake by up to this distance, fading out. Only the drawn position shakes (hits, wrong moves). */shake?: number;};/** A step of a keyframed animation: values to pass through, and when (0..1 of the duration; default evenly spaced). */export type Keyframe = AnimateTarget & {at?: number;};export type SpringOptions = {/** How strongly it pulls toward the target. Default 170. */stiffness?: number;/** How quickly it calms down. Lower bounces more. Default 26 (no overshoot). */damping?: number;/** Heavier moves slower and swings further. Default 1. */mass?: number;};export type AnimateOptions = {/** Seconds (ignored by springs). Default 0.3. */duration?: number;/** Seconds before it starts. Default 0. */delay?: number;/** Default "easeOut". "back" overshoots, "bounce" bounces, "elastic" springs. */easing?: Easing;/** Extra runs after the first, or "forever". Default 0. */repeat?: number | 'forever';/** Every other run plays backwards (pulses, ping-pong). */yoyo?: boolean;/** With several entities: extra delay for each next one, in seconds (waves, board reveals). */stagger?: number;/** "smooth" moves along a curve through the keyframes (arcs, hops) instead of straight lines. */path?: 'linear' | 'smooth';/*** Physically simulated motion instead of a fixed duration: true (smooth), "bouncy", or your own* settings. Interrupting a spring with another keeps its speed, so it never jerks.*/spring?: boolean | 'bouncy' | SpringOptions;};export type BurstOptions = {position: Vec3;/** How many particles. Default 16. */count?: number;/** Main direction. Default up. */direction?: Vec3;/** Half-angle of the cone around `direction`, in radians. Default π (every direction). */spread?: number;/** Default "cube". */mesh?: Shape | Model;/** Particle size. Default 0.15. */size?: number;/** Top speed. Default 5. */speed?: number;/** Seconds. Default 0.8. */lifetime?: number;/** Vertical acceleration. Default -9.81 (falls); 0 floats. */gravity?: number;/** One color (CSS string or tuple), or up to 4 to pick from at random. Default white. */color?: ColorInput | readonly ColorInput[];/** Size at the end of each particle's life, as a multiple of its start size: above 1 grows (smoke), below shrinks (embers). Default 1. */endSize?: number;/** Color every particle shifts to over its life, e.g. flame to dark red; an alpha below 1 fades it out. Default: keeps its color. */endColor?: ColorInput;};export type CollisionInfo = {/** True when the touch started; false when it ended. */started: boolean;/** A sensor was involved. */sensor: boolean;/** Impact speed (0 when a touch ends). */speed: number;};export type RaycastHit = {entity: Entity;distance: number;normal: [number,number,number];point: [number,number,number];};export type PickHit = {entity: Entity;/** Where the tap ray hit the entity's bounding box, in world space. */point: [number,number,number];distance: number;};export type Bounds = readonly [minX: number,minZ: number,maxX: number,maxZ: number];
Usage and examples: /game-engine/game-view.
| Export | Kind | Guide |
|---|---|---|
| afterNextFrame | Runtime API | /game-engine/game-view |
| GameView | Runtime API | /game-engine/game-view |
| DragEvent | TypeScript type | /game-engine/game-view |
| GameViewProps | TypeScript type | /game-engine/game-view |
| GameViewStats | TypeScript type | /game-engine/game-view |
| OverlayTouchPhase | TypeScript type | /game-engine/game-view |
| PinchEvent | TypeScript type | /game-engine/game-view |
| SwipeDirection | TypeScript type | /game-engine/game-view |
render/GameView declarations
React and React Native · shared engine API
/*** Runs `fn` right after the next frame a GameView hands to the screen, on the same display clock* (the native one where the platform has it): the time a frame leaves is the best moment for* background work, such as loading in slices. With no GameView running it falls back to* requestAnimationFrame. Returns a function that cancels it.** ```ts* const cancel = afterNextFrame(() => buildNextChunk());* ```*/export declare function afterNextFrame(fn: () => void): () => void;export type GameViewStats = {fps: number;/** Mean time spent in `onUpdate` per frame, in milliseconds. */updateMs: number;/** Average milliseconds per frame spent drawing (CPU side, including waiting on the GPU). */renderMs: number;/** The quality level drawn with (with `quality="auto"`, the one it settled on so far). */quality: RenderQuality;/** The graphics API drawing: "vulkan", "gl" (OpenGL ES) or "metal". */backend: string;};export type SwipeDirection = 'left' | 'right' | 'up' | 'down';export type OverlayTouchPhase = 'start' | 'move' | 'end' | 'cancel';export type DragEvent = {phase: 'start' | 'move' | 'end';/** Finger position in the view, in points. */x: number;y: number;/** Distance moved since the drag started, in points. */dx: number;dy: number;/** On "end": the drag was interrupted (a second finger started a pinch, or the system took the touch). Put a held piece back. */cancelled?: boolean;};export type PinchEvent = {phase: 'start' | 'move' | 'end';/** Finger spread relative to the start: 2 = twice as far apart (zoom in). */scale: number;/** Radians the two fingers turned since the start, clockwise on screen. */rotation: number;/** Midpoint between the fingers in the view, in points. */x: number;y: number;};export type GameViewProps = {/** What to draw (usually a `World`). Changing it restarts the view; never pass a disposed world. */source: RenderSource;/*** Your game loop, called once per frame before drawing, with the elapsed seconds (capped at 0.1;* 0 until the first frame is on screen, so nothing plays out unseen): read input, spawn, move the* camera. The world (and `overlay`) is stepped for you right after; call `world.update(dt)` here* yourself only to step it at a different point or with a different `dt`.*/onUpdate?: (dt: number) => void;/** Mutate this object (e.g. `camera.eye`) from `onUpdate`; it is read every frame. */camera?: Camera;light?: Light;/** Sky / clear color: a CSS color or linear 0..1 RGB (alpha ignored). Also the fog color. Default dark navy. */background?: ColorInput;/** Distance fog density towards `background` (e.g. 0.02). Default 0 (off). */fog?: number;/*** Resolution, anti-aliasing and shadow quality. "auto" (default) starts at "high", steps down only* while the GPU really can't keep up (shadow detail first, then anti-aliasing, resolution last) and* steps back up once frames are smooth again, so every phone gets the best look it can hold.*/quality?: RenderQualitySetting;/** Suspend updates and drawing while keeping the native surface mounted. */paused?: boolean;style?: ViewStyle;/** A quick tap, at `x, y` points in the view. `world.pick(x, y)` finds what was tapped. */onTap?: (x: number, y: number) => void;/** A quick flick in one direction (2048, runners, sliding puzzles). */onSwipe?: (direction: SwipeDirection) => void;/** Finger down, moving and up (aiming, dragging pieces, slicing). */onDrag?: (drag: DragEvent) => void;/** A finger held still for half a second (pick up, show moves). No tap follows. */onLongPress?: (x: number, y: number) => void;/** Two fingers spreading, pinching or turning (zoom and rotate a board). Ends any drag in progress. */onPinch?: (pinch: PinchEvent) => void;/** Host primary action for keyboard input, such as Start/Stop or Play Again. */onPrimaryAction?: () => void;/*** A screen-space layer drawn over the scene by the renderer (scoreboards, buttons): usually a second* `World`, in points from the view's top-left with y up (so on screen y <= 0) and z toward the viewer* within -100..100. Unlit (flat faces show their exact color) and always in front. Stepped each* frame like `source`.*/overlay?: RenderSource;/*** Touches for the overlay, in points in the view. Return true from "start" to claim the touch (a* button was hit): its moves and end come here, and the game gets no drag, tap or swipe for it.* "cancel" when the system takes the touch.*/onOverlayTouch?: (phase: OverlayTouchPhase, x: number, y: number) => boolean | void;/** Called once a second. */onStats?: (stats: GameViewStats) => void;/** GPU setup failures and rendering errors. Defaults to console.error. */onError?: (error: Error) => void;};export declare function GameView(props: GameViewProps): import("react").JSX.Element;
Usage and examples: /game-engine/world-entities.
| Export | Kind | Guide |
|---|---|---|
| useWorld | Runtime API | /game-engine/world-entities |
| WorldSetup | TypeScript type | /game-engine/world-entities |
render/useWorld declarations
React and React Native · shared engine API
/** What `useWorld`'s setup may return: a cleanup, run just before the world is disposed. */export type WorldSetup = (world: World) => void | (() => void);/*** A `World` owned by a component: the engine is warmed up (needed on the web, cheap on mobile), the* world is created with `capacity` entity slots and handed to `setup` to fill, and it is disposed on* unmount. A change in `deps` replaces it with a fresh one. Returns null until it's ready (one frame),* and while the engine is unavailable (Expo Go) or failed to start (`onError`, console by default).** ```tsx* const world = useWorld(100, (w) => {* w.spawn({ mesh: 'plane', scale: [20, 1, 20], color: '#4C9A4C', physics: 'fixed' });* w.spawn({ mesh: 'sphere', position: [0, 4, 0], color: '#3399FF', physics: 'dynamic' });* });* return world && <GameView source={world} style={{ flex: 1 }} />;* ```*/export declare function useWorld(capacity: number, setup?: WorldSetup, deps?: DependencyList, onError?: (error: Error) => void): World | null;
Usage and examples: /game-engine/camera-lighting.
| Export | Kind | Guide |
|---|---|---|
| frontLight | Runtime API | /game-engine/camera-lighting |
render/light declarations
React and React Native · shared engine API
/*** A light for flat, front-facing scenes (boards, puzzles, 2D games looking down -z): surfaces facing* the camera (+z) are lit at exactly 1, so flat panels show their color unchanged, while rounded* shapes keep their shading (lighter toward the light, darker away). Shadows are off.** ```tsx* <GameView source={world} light={frontLight([-0.45, 0.6, 1], 0.5)} />* ```*/export declare function frontLight(direction: [number,number,number], ambient: number): Light;
Usage and examples: /game-engine/cache-performance.
| Export | Kind | Guide |
|---|---|---|
| warmUpEngine | Runtime API | /game-engine/cache-performance |
| getMeshIdLimit | Runtime API | /game-engine/cache-performance |
render/meshes declarations
React and React Native · shared engine API
type V3 = readonly [number,number,number];/** One past the highest mesh id in use: per-frame scans of a source's ranges stop here. */export declare const getMeshIdLimit: () => number;/*** Initializes the shared core and built-in meshes. Await before using the engine on the web.* Mobile initialization remains synchronous and also warms the GPU on a background thread.* Repeat calls reuse initialization and mesh registration.*/export declare function warmUpEngine(): Promise<void>;
Usage and examples: /game-engine/cache-performance.
| Export | Kind | Guide |
|---|---|---|
| TransformBatch | TypeScript type | /game-engine/cache-performance |
| TransformOptions | TypeScript type | /game-engine/cache-performance |
world/TransformBatch declarations
React and React Native · shared engine API
export type TransformOptions = Pick<EntityOptions, 'position' | 'rotation' | 'scale' | 'color'>;/*** Explicit draw-only updates, applied in one native call by `flush()`. `world.update` flushes* `world.transforms` before stepping; flush yourself before reading positions or animating. Records and scratch storage are reused; values are* copied when queued, never retained by reference. The scalar methods (`position`, `rotation`,* `scale`, `color`, `transform`) allocate nothing; consecutive calls for the same entity share one* record.** ```ts* const batch = world.transforms;* for (const p of pieces) batch.transform(p.entity, p.x, 0, p.z, 0, p.qy, 0, p.qw);* batch.flush();* ```*/export declare class TransformBatch {constructor(commit: (data: Float64Array, count: number) => number);position(entity: Entity, x: number, y: number, z: number): void;/** Rotation quaternion [x, y, z, w]. */rotation(entity: Entity, x: number, y: number, z: number, w: number): void;/** Uniform scale, or per axis. */scale(entity: Entity, x: number, y?: number, z?: number): void;/** RGBA color; alpha defaults to 1. */color(entity: Entity, r: number, g: number, b: number, a?: number): void;/** Position and rotation together (the common per-frame update for a moving piece). */transform(entity: Entity, x: number, y: number, z: number, qx: number, qy: number, qz: number, qw: number): void;/** Queued records (merged per entity). */get size(): number;set(entity: Entity, options: TransformOptions): void;flush(): number;clear(): void;}
Usage and examples: /game-engine/game-view.
| Export | Kind | Guide |
|---|---|---|
| RenderQuality | TypeScript type | /game-engine/game-view |
| RenderQualitySetting | TypeScript type | /game-engine/game-view |
render/quality declarations
React and React Native · shared engine API
export type RenderQuality = 'high' | 'medium' | 'low' | 'lowest';/** `"auto"` starts at "high" and steps down only while the device really can't keep up. */export type RenderQualitySetting = RenderQuality | 'auto';
Usage and examples: /game-engine/models-textures.
| Export | Kind | Guide |
|---|---|---|
| AssetSource | TypeScript type | /game-engine/models-textures |
assets/source declarations
React and React Native · shared engine API
/** Browser assets use URLs (including URLs emitted by Vite/webpack imports). */export type AssetSource = number | string;
Usage and examples: /game-engine/models-textures.
| Export | Kind | Guide |
|---|---|---|
| loadModel | Runtime API | /game-engine/models-textures |
| Model | TypeScript type | /game-engine/models-textures |
| ModelOptions | TypeScript type | /game-engine/models-textures |
| ModelClip | TypeScript type | /game-engine/models-textures |
| LoadedModel | TypeScript type | /game-engine/models-textures |
assets/model declarations
React and React Native · shared engine API
export type ModelOptions = {/** Move the model's bounding box center to the origin, so `position` is its middle. Default true. */center?: boolean;/** Scale it so its largest side is this long (e.g. 1 to match the built-in shapes). Default: keep its size. */fit?: number;/*** How glossy, 0..1: a sharp sun highlight and a reflection of the sky that grows at grazing angles.* 0 is matte; around 0.8 reads as car paint or glass. Default 0.*/shine?: number;};/** A loaded model: pass it as an entity's `mesh`. Colliders sized from the mesh fit its bounding box. */export type Model = {/** Bounding box size [x, y, z] at scale 1 (after `fit`). */readonly size: Vec3;/** Mesh id in the core. */readonly id: number;};/** An animation embedded in a loaded GLB. */export type ModelClip = {readonly name: string;readonly duration: number;};export type LoadedModel = Model & {readonly animations: readonly ModelClip[];readonly jointCount: number;};/*** Initializes the engine automatically. Loads a glTF model once; pass it as an entity's `mesh`. Meshes, node transforms, material colors* and the base color texture are kept (one texture per model); skeletal animation clips are available through `animations` and `World.playClip`.* Every entity using the model is drawn in one instanced draw call.** ```ts* const tree = await loadModel(require("./assets/tree.glb"), { fit: 2 });* world.spawn({ mesh: tree, position: [0, 1, 0], physics: "fixed" });* ```*/export declare function loadModel(source: AssetSource, options?: ModelOptions): Promise<LoadedModel>;
Usage and examples: /game-engine/cache-performance.
| Export | Kind | Guide |
|---|---|---|
| clearAssetCache | Runtime API | /game-engine/cache-performance |
assets/AssetCache declarations
React and React Native · shared engine API
/*** Explicitly removes the engine's saved geometry and original model/texture/font/audio files.* Also clears temporary download bytes. Existing worlds and loaded handles remain usable;* registrations are session resources and will be rebuilt/reloaded on a future app launch.* Custom ProceduralStorage adapters belong to their host and are not cleared by this function.* Rejects if storage cannot be cleared, allowing a settings screen to report the failure.*/export declare function clearAssetCache(): Promise<void>;
Usage and examples: /game-engine/cache-performance.
| Export | Kind | Guide |
|---|---|---|
| ProceduralCache | Runtime API | /game-engine/cache-performance |
| ProceduralStorage | TypeScript type | /game-engine/cache-performance |
assets/ProceduralCache declarations
React and React Native · shared engine API
/** Optional storage override. The engine selects a best-effort platform cache by default. */export interface ProceduralStorage {read(key: string): Uint8Array | null;write(key: string, bytes: Uint8Array): void | Promise<void>;/*** The store itself verifies every record's integrity (the engine's own Rust store checksums each* one with SHA-256), so the cache needn't checksum and scan them again in JS. Geometry is still* validated by the core when it's registered.*/readonly verified?: boolean;}/*** Persists the output of a deterministic model factory, including nested model arrays/objects.* Hits register saved vertices directly: no procedural tessellation, painting or optimization.* Imported/skinned/textured models are intentionally excluded; their own loaders retain their rigs.*/export declare class ProceduralCache {readonly revision: string;constructor(revision: string, storage?: ProceduralStorage | undefined);get stats(): {hits: number;builds: number;invalid: number;failures: number;pendingWrites: number;};flush(): Promise<void>;/*** A value already cached (in memory, or saved by an earlier launch), without building anything:* undefined when there is none yet. Lets work that's spread over many frames (a level generated* step by step) skip itself entirely when a saved result exists, then save with `get`.*/peek<T>(key: string): T | undefined;get<T>(key: string, build: () => T): T;}
Usage and examples: /game-engine/models-textures.
| Export | Kind | Guide |
|---|---|---|
| loadTexture | Runtime API | /game-engine/models-textures |
| Texture | TypeScript type | /game-engine/models-textures |
assets/texture declarations
React and React Native · shared engine API
/** A loaded image. Pass it as an entity's `texture`. */export type Texture = {readonly id: number;readonly width: number;readonly height: number;};/*** Initializes the engine automatically. Loads a PNG or JPEG once (up to 4096 x 4096). Use it on any entity: `{ mesh: "cube", texture }`.* The entity's `color` tints it; `textureRegion` shows part of it (sprite sheets, card atlases).** ```ts* const crate = await loadTexture(require("./assets/crate.png"));* world.spawn({ mesh: "cube", texture: crate });* ```*/export declare function loadTexture(source: AssetSource): Promise<Texture>;
Usage and examples: /game-engine/solid-modelling.
| Export | Kind | Guide |
|---|---|---|
| Solid | Runtime API | /game-engine/solid-modelling |
| solidGeometry | Runtime API | /game-engine/solid-modelling |
| createSolid | Runtime API | /game-engine/solid-modelling |
| optimizeGeometry | Runtime API | /game-engine/solid-modelling |
| createGeometryLods | Runtime API | /game-engine/solid-modelling |
| getGeometryStats | Runtime API | /game-engine/solid-modelling |
| deformGeometry | Runtime API | /game-engine/solid-modelling |
| DisplacementOptions | TypeScript type | /game-engine/solid-modelling |
| SolidOptions | TypeScript type | /game-engine/solid-modelling |
| OptimizeOptions | TypeScript type | /game-engine/solid-modelling |
| GeometryStats | TypeScript type | /game-engine/solid-modelling |
assets/modelling declarations
React and React Native · shared engine API
type Node = {readonly kind: 'sphere';readonly radius: number;} | {readonly kind: 'ellipsoid';readonly radii: Vec3;} | {readonly kind: 'box';readonly size: Vec3;readonly radius: number;} | {readonly kind: 'capsule';readonly start: Vec3;readonly end: Vec3;readonly radius: number;} | {readonly kind: 'cylinder';readonly radius: number;readonly height: number;} | {readonly kind: 'torus';readonly radius: number;readonly tube: number;} | {readonly kind: 'union';readonly a: Node;readonly b: Node;readonly blend: number;} | {readonly kind: 'subtract' | 'intersect';readonly a: Node;readonly b: Node;} | {readonly kind: 'transform';readonly child: Node;readonly position: Vec3;readonly rotation: Quat;readonly scale: Vec3;} | {readonly kind: 'paint';readonly child: Node;readonly color: Color;} | {readonly kind: 'shell';readonly child: Node;readonly thickness: number;} | {readonly kind: 'displace';readonly child: Node;readonly amplitude: number;readonly frequency: number;readonly seed: number;readonly octaves: number;};/*** An immutable, code-authored solid. Join primitives into a single surface, blend organic forms,* drill holes, hollow shells and add reproducible rock/terrain detail before tessellating once.* Distances use world units; primitives are centered at the origin, cylinders/tori use the Y axis.** const torso = Solid.ellipsoid([0.5, 0.7, 0.3]).paint([0.5, 0.1, 0.9]);* const neck = Solid.capsule([0, 0.5, 0], [0, 0.9, 0], 0.15);* const geometry = solidGeometry(torso.blend(neck, 0.15), { resolution: 48 });*/export declare class Solid {static sphere(radius?: number): Solid;static ellipsoid(radii: Vec3): Solid;/** Full width/height/depth. Rounding stays inside these dimensions. */static box(size: Vec3, radius?: number): Solid;static capsule(start: Vec3, end: Vec3, radius: number): Solid;static cylinder(radius: number, height: number): Solid;/** Major radius to the tube center; minor radius of the tube itself. */static torus(radius: number, tube: number): Solid;/** Balanced union for many parts; avoids building a deeply nested operation chain. */static union(...solids: readonly Solid[]): Solid;union(other: Solid): Solid;/** Smoothly weld overlapping forms; blend controls the transition width in world units. */blend(other: Solid, blend: number): Solid;subtract(other: Solid): Solid;intersect(other: Solid): Solid;translate(position: Vec3): Solid;rotate(rotation: Quat): Solid;scale(scale: number | Vec3): Solid;/** Vertex colors blend with the surface at smooth joins. Apply after subtract() to color cut walls. */paint(color: Color): Solid;/** A shell centered on the original surface; thickness is its full wall thickness. */shell(thickness: number): Solid;/** Seeded fractal value noise. Use a resolution fine enough to sample its smallest features. */displace(options: DisplacementOptions): Solid;/** Serializable recipe for caching or inspecting a generated asset. */toJSON(): Node;}export interface DisplacementOptions {amplitude: number;frequency?: number;seed?: number;/** 1..6 octaves. Default 3. */octaves?: number;}export interface SolidOptions {/** Cells across the longest dimension, 8..128. Default 48. Higher costs cubic sampling work. */resolution?: number;/** Planar UV projection. Use parametricSurface/loft for explicitly authored UVs. Default xy. */uv?: 'xy' | 'xz' | 'yz';}/** Tessellates into editable, unregistered geometry. Prefer createSolid() for automatic model reuse. */export declare function solidGeometry(solid: Solid, options?: SolidOptions): Geometry;/*** Tessellates, cleans and registers a solid once, then returns its cached model on later calls* with the same recipe/options. White vertex colors can be tinted per spawned entity. Temporary* intermediate meshes consume no IDs. Prepared solids persist automatically when platform storage* is available; storage failure falls back to building. Call after warmUpEngine(), before spawning a run.*/export declare function createSolid(solid: Solid, options?: SolidOptions & ShapeOptions): Model;export interface OptimizeOptions {/** Target triangle fraction in (0,1]. Default 1: lossless cleanup, welding and GPU cache ordering. */ratio?: number;/** Maximum relative error, 0..1, against the largest dimension, with attribute error included. Default 0.001. */error?: number;/** Keep open borders fixed, useful for separately generated terrain chunks. Default true. */lockBorders?: boolean;}/*** Returns new geometry, preserving the input and its normal/color/UV seams. Removes degenerate* triangles and unused/identical vertices, simplifies within the error bound, then orders buffers* for GPU reuse. The error bound may prevent reaching the requested ratio. Opaque static meshes only:* do not use on skinning buffers or meshes whose vertex indices are used by external code.*/export declare function optimizeGeometry(geometry: Geometry, options?: OptimizeOptions): Geometry;/*** Independently simplifies the original at each requested ratio, avoiding accumulated error.* Cache/register the results once. The caller selects a level when camera distance changes.*/export declare function createGeometryLods(geometry: Geometry, ratios?: readonly number[], options?: Omit<OptimizeOptions, 'ratio'>): Geometry[];export interface GeometryStats {vertices: number;triangles: number;/** CPU geometry bytes, excluding registration/driver copies. */bytes: number;bounds: {min: Vec3;max: Vec3;size: Vec3;} | null;}/** Cheap counts and bounds without registering a mesh. */export declare function getGeometryStats(geometry: Geometry): GeometryStats;/** Copies/sculpts one smooth surface and updates its normals. Deform hard-edged parts separately. */export declare function deformGeometry(geometry: Geometry, deform: (position: Vec3, uv: readonly [number,number]) => Vec3): Geometry;
Usage and examples: /game-engine/surfaces-lofts.
| Export | Kind | Guide |
|---|---|---|
| loft | Runtime API | /game-engine/surfaces-lofts |
| block | Runtime API | /game-engine/surfaces-lofts |
| ellipsoid | Runtime API | /game-engine/surfaces-lofts |
| smoothCurve | Runtime API | /game-engine/surfaces-lofts |
| LoftSection | TypeScript type | /game-engine/surfaces-lofts |
| LoftOptions | TypeScript type | /game-engine/surfaces-lofts |
assets/loft declarations
React and React Native · shared engine API
export interface LoftSection {z: number;bottom: number;top: number;/** Half the width at the lower corners. */width: number;topWidth?: number;/** Superellipse exponent, 2 = oval, larger values = boxier corners. Default 4. */square?: number;}export interface LoftOptions {around?: number;smoothness?: number;color?: Color | ((position: Vec3, normal: Vec3) => Color);}/*** Smooth closed body through rounded rectangular cross sections along Z. Useful for vehicle* shells, cabins, shoes and fairings. Caps have separate flat normals and planar UVs; sides have* continuous longitudinal UVs and a welded seam. Input sections may increase or decrease in Z.*/export declare function loft(sections: readonly LoftSection[], options?: LoftOptions): Geometry;/** A rounded rectangular cross-section with flat front/back caps, centered at the origin. */export declare function block(w: number, h: number, d: number, square?: number, color?: LoftOptions['color']): Geometry;/** An exact ellipsoid with analytic normals, rather than capped/truncated poles. */export declare function ellipsoid(radii: Vec3, color?: LoftOptions['color'], around?: number): Geometry;/** Smooth Hermite interpolation through increasing [x,value] points; clamped beyond the ends. */export declare function smoothCurve(points: readonly (readonly [number,number])[]): (x: number) => number;
Usage and examples: /game-engine/surfaces-lofts.
| Export | Kind | Guide |
|---|---|---|
| parametricSurface | Runtime API | /game-engine/surfaces-lofts |
| ParametricSurfaceOptions | TypeScript type | /game-engine/surfaces-lofts |
assets/surface declarations
React and React Native · shared engine API
export interface ParametricSurfaceOptions {uSegments?: number;vSegments?: number;/** Match the first/last positions and smooth their normals, keeping separate 0/1 UVs. */wrapU?: boolean;wrapV?: boolean;color?: SurfaceColor;}/*** Samples an arbitrary surface on u/v in [0,1]. Winding follows dP/du cross dP/dv.* Use for terrain, cloth, wings, twisted ribbons and custom mathematical forms. Wrapped edges* retain texture seams; coincident pole vertices share normals. Degenerate triangles are omitted.*/export declare function parametricSurface(sample: (u: number, v: number) => Vec3, options?: ParametricSurfaceOptions): Geometry;
Usage and examples: /game-engine/procedural-geometry.
assets/shape declarations
React and React Native · shared engine API
type P2 = [number,number];/*** A 2D outline, built like an SVG path: x right, y down. Solids made from it* (`extrude`, `lathe`) are flipped upright, so a path drawn the way it looks on screen stands the* same way in the world. Coordinates are in world units: a 1 x 1 path makes a 1 unit wide shape.** ```ts* const heart = Path.fromSVG("M0.5 0.9 C0 0.5 0 0.1 0.25 0.1 C0.4 0.1 0.5 0.25 0.5 0.3 C0.5 0.25 0.6 0.1 0.75 0.1 C1 0.1 1 0.5 0.5 0.9 Z");* const star = new Path().addStar(0, 0, 0.5, 0.22, 5);* ```*/export declare class Path {/** Starts a new contour at (x, y). */moveTo(x: number, y: number): this;lineTo(x: number, y: number): this;/** A quadratic Bézier through control point (cx, cy) to (x, y). */quadraticTo(cx: number, cy: number, x: number, y: number): this;/** A cubic Bézier through control points (c1x, c1y) and (c2x, c2y) to (x, y). */cubicTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): this;/*** An elliptical arc to (x, y), as in SVG's `A` command: radii rx, ry, the ellipse turned `rotation`* radians, and the flags choosing which of the four possible arcs.*/arcTo(rx: number, ry: number, rotation: number, largeArc: boolean, sweep: boolean, x: number, y: number): this;/** Closes the current contour back to its first point. */close(): this;/** A closed polygon through `points`. */addPolygon(points: readonly (readonly [number,number])[], close?: boolean): this;addRect(x: number, y: number, width: number, height: number): this;/** A rectangle with corners rounded by `radius` (or [rx, ry]). */addRoundedRect(x: number, y: number, width: number, height: number, radius: number | readonly [number,number]): this;/** An ellipse filling the box. */addOval(x: number, y: number, width: number, height: number): this;addCircle(cx: number, cy: number, radius: number): this;/** A star with `points` tips at `outer` radius and notches at `inner`, the first tip pointing up. */addStar(cx: number, cy: number, outer: number, inner: number, points?: number): this;/** A regular polygon with `sides` corners, the first pointing up. */addRegularPolygon(cx: number, cy: number, radius: number, sides: number): this;/*** Parses SVG path data (`d`): M L H V C S Q T A Z, absolute and relative. Paste paths from Figma,* Illustrator or any icon set (scale them with `fit` on the shape, or `transform` here).*/static fromSVG(d: string): Path;/** A copy moved by (dx, dy) and scaled by sx, sy (about the origin, before moving). */transform(sx: number, sy?: number, dx?: number, dy?: number): Path;/** The flattened contours (curves turned into points), y down as drawn. */toContours(): P2[][];/** [minX, minY, maxX, maxY], or undefined for an empty path. */bounds(): [number,number,number,number] | undefined;}/*** Shape geometry, before it's registered: 11 floats per vertex (position, normal, color, uv) and* triangle indices. Builders return it; `merge` combines it; `createShape` turns it into a mesh.*/export type Geometry = MeshGeometry;/** A built-in shape's geometry (unit-sized, centered), to `merge` with others. */export declare function shapeGeometry(shape: Exclude<Shape, 'none' | 'puff' | 'flame'>, options?: {color?: Color;}): Geometry;export type ExtrudeOptions = {/** How deep, in the path's units. 0 = a flat, one-sided face (facing +Z). Default 0.2. */depth?: number;/** SVG fill rules: "nonzero" (the default winding rule) or "evenodd" (every inner contour is a hole). */fillRule?: 'nonzero' | 'evenodd';/** Vertex color (multiplies the entity's color). Default white. */color?: Color;};/*** A 2D path filled and pushed into a solid, facing +Z: badges, coins, leaves, hearts, stars, logos,* fruit slices. Holes follow the fill rule. Textures map across the front face.*/export declare function extrude(path: Path, options?: ExtrudeOptions): Geometry;/** Where a color function is asked about: `u` around (0..1), `v` along (0..1), and the surface there. */export type SurfacePoint = {u: number;v: number;position: Vec3;normal: Vec3;};/** A flat color, or one per point of the surface: blushes, stripes, speckles, spots. */export type SurfaceColor = Color | ((p: SurfacePoint) => Color);/** A flat color, or one per point of a round face: `r` from its center (0) to its rim (1), `angle` around it. */export type FaceColor = Color | ((r: number, angle: number) => Color);export type LatheOptions = {/** Steps around the axis. Default 32. */segments?: number;/** How far around, in radians: TAU (default) is a full turn; Math.PI a half, for a cut fruit. */sweep?: number;/** Color of the outside: one color, or a function of the surface point (u around, v down the profile). Default white. */color?: SurfaceColor;/*** Pushes the surface out (or in, if negative) along its normal by this much at (u, v): peel dimples,* ribs, ridges, bumps. Normals are recomputed so the bumps catch the light. Make it repeat in u* (equal at u = 0 and 1) to avoid a seam.*/displace?: (u: number, v: number) => number;/** Color of the flat ends where the profile stops away from the axis (the face of a fruit cut across). Default `color`. */capColor?: FaceColor;/** Rings across each end cap, for patterned `capColor`. Default 1, or 12 for a function. */capRings?: number;/*** Color of the faces where a partial sweep is cut open (the flesh of a fruit cut through its core).* As a function: `r` from the axis (0) to the skin (1) at that height, and the height `y`. Default `color`.*/cutColor?: Color | ((r: number, y: number) => Color);/** Steps from the axis to the skin across each cut face, for a detailed `cutColor`. Default 12 for a function. */cutSteps?: number;};/*** Recolors geometry point by point (in place, and returned): two-tone leaves, painted tips, stripes on* an extrusion. `u` and `v` are the texture coordinates there.*/export declare function recolor(geometry: Geometry, color: (p: SurfacePoint) => Color): Geometry;/*** Recomputes corner-angle-weighted normals in place, welding UV seams and poles at 1e-5 units.* Uses Rust when available. Call on a sculpted surface before merging caps or other hard edges:* coincident vertices share a normal. Degenerate faces leave the original normals intact.*/export declare function smoothNormals(g: Geometry): Geometry;/*** Spins a profile around the vertical axis, like a potter's wheel: fruit (apples, oranges, lemons,* pears, cherries), vases, bottles, bowls, chess pieces, spinning tops. The profile is a `Path`* (x = distance from the axis, y down, as drawn) or [radius, height] points (y up), top to bottom.* Open ends away from the axis are capped. With `sweep` < TAU the cut faces are closed too.*/export declare function lathe(profile: Path | readonly (readonly [number,number])[], options?: LatheOptions): Geometry;export type TubeOptions = {/** Radius, or a function of t (0 at the first point, 1 at the last) for tapering: bananas, horns, tails. Default 0.1. */radius?: number | ((t: number) => number);/*** The cross-section: a radius multiplier at each point around (0..1, repeating), e.g. ridges for a* banana or a star for a churro. Default round.*/shape?: (around: number) => number;/** Steps around the tube. Default 12. */sides?: number;/** Steps between each pair of points (the path is smoothed through them). Default 8. */smoothness?: number;/** Cap the ends (where the radius isn't 0). Default true. */caps?: boolean;/** Join the last point to the first with a smooth, untwisted seam; no end caps. Default false. */closed?: boolean;/** Color: one, or a function of the surface point (u around, v = t along). Default white. */color?: SurfaceColor;/** Color of the end caps (the face of a cut banana). Default `color`. */capColor?: FaceColor;};/*** A tube along a smooth curve through `points`: bananas, stems, chillies, worms, snakes, ropes,* pipes, tentacles, candy canes.*/export declare function tube(points: readonly Vec3[], options?: TubeOptions): Geometry;export type GeometryPart = {geometry: Geometry;position?: Vec3;/** A quaternion [x, y, z, w], as entities use. */rotation?: Quat;scale?: Vec3 | number;/** Multiplies the part's vertex colors: an apple's red body, brown stem and green leaf in one mesh. */color?: Color;};/*** Bakes parts into one geometry, each scaled, rotated, moved and colored. One mesh draws in one* instanced call and moves, spins and slices as one entity.*/export declare function merge(parts: readonly GeometryPart[]): Geometry;export type ShapeOptions = {/** Clean/optimize before upload, or simplify within an error bound. Built once, then shared. Default false. */optimize?: boolean | OptimizeOptions;/** Move the bounding box's center to the origin, so `position` is the middle. Default true. */center?: boolean;/** Scale so the largest side is this long (1 matches the built-in shapes). Default: keep the size. */fit?: number;/** How glossy, 0..1 (as for models): around 0.6 for a waxy apple, 0.85 for glass. Default 0. */shine?: number;};/*** Registers geometry as a mesh: pass the result as an entity's `mesh` (or a burst's), with any* `texture`, physics and picking. Colliders default to a box holding the shape. Mesh ids are* shared by models, fonts and shapes (about 4,080) and live for the whole app. Equal geometry/options* automatically reuse preparation and registration; input buffers may still be edited for a later* call. Material variants remain independent. Build geometry during scene setup, outside onUpdate.** ```ts* const orange = createShape(lathe(orangeProfile, { color: [1, 0.55, 0.1] }), { fit: 1, shine: 0.3 });* world.spawn({ mesh: orange, position: [0, 2, 0], physics: "dynamic" });* ```*/export declare function createShape(geometry: Geometry, options?: ShapeOptions): Model;
Usage and examples: /game-engine/text-fonts.
| Export | Kind | Guide |
|---|---|---|
| loadFont | Runtime API | /game-engine/text-fonts |
| measureText | Runtime API | /game-engine/text-fonts |
| Font | TypeScript type | /game-engine/text-fonts |
| FontOptions | TypeScript type | /game-engine/text-fonts |
| TextAlign | TypeScript type | /game-engine/text-fonts |
| TextLayout | TypeScript type | /game-engine/text-fonts |
assets/font declarations
React and React Native · shared engine API
export type FontOptions = {/** How deep letters are extruded, as a fraction of the font size. 0 = flat. Default 0.2. */depth?: number;/** Characters to prewarm (space and ? are always included). Other font-supported characters load* once when text is measured or laid out. Fewer = faster startup and fewer unused meshes. Default: DEFAULT_CHARS. */chars?: string;/** Weight (e.g. 400, 600) for a variable font, such as the device's system font. Default: the font's own. */weight?: number;};type Glyph = {mesh: number;advance: number;};/** A loaded font. Use it on an entity with `text`: `{ text: "2048", font }`. */export type Font = {readonly id: number;/** Height of capital letters at scale 1. */readonly capHeight: number;/** Cached mesh (-1 = nothing drawn, e.g. space) and advance per character. Grows as text is used. */readonly glyphs: ReadonlyMap<string, Glyph>;};/*** Initializes the engine automatically. Loads a TrueType / OpenType font (.ttf / .otf) for 3D text. The source/depth/weight are cached independently of the requested prewarm characters. Letters are real meshes: lit, shadowed,* and every copy of a letter on screen is drawn in one call. At scale 1, letters are 1 unit tall (em).* Additional Unicode glyphs are built on demand from the same font and cached. The font must contain* an outline for the character; missing characters still use ?, including unsupported emoji.** ```ts* const font = await loadFont(require("./assets/Inter-Bold.ttf"), { chars: "0123456789" });* world.spawn({ text: "2048", font, scale: 0.5, color: [1, 1, 1] });* ```*/export declare function loadFont(source: AssetSource, options?: FontOptions): Promise<Font>;export type TextAlign = 'left' | 'center' | 'right';export type TextLayout = {/** Extra space between letters, in ems (at scale 1, letters are 1 em tall). Default 0. */letterSpacing?: number;/** Digits all as wide as the widest, so changing numbers (scores, timers) don't shift. Default false. */tabular?: boolean;};/** A line's advance in ems, with the same Unicode glyph loading, spacing and fallbacks as rendering. */export declare function measureText(font: Font, text: string, options?: TextLayout): number;
Usage and examples: /game-engine/audio-haptics.
| Export | Kind | Guide |
|---|---|---|
| audio | Runtime API | /game-engine/audio-haptics |
| AudioPlayOptions | TypeScript type | /game-engine/audio-haptics |
| Sound | TypeScript type | /game-engine/audio-haptics |
| SoundBank | TypeScript type | /game-engine/audio-haptics |
| SoundSource | TypeScript type | /game-engine/audio-haptics |
| Voice | TypeScript type | /game-engine/audio-haptics |
media/audio declarations
React and React Native · shared engine API
/** A decoded sound in the core's mixer. */export type Sound = number & {readonly __sound: unique symbol;};/** A playing instance of a sound (for `audio.stop`). */export type Voice = number & {readonly __voice: unique symbol;};export type AudioPlayOptions = {/** 0..2. Default 1. */volume?: number;/** -1 left .. 1 right. Default 0. */pan?: number;/** Playback speed (also shifts pitch). Default 1. */pitch?: number;/** Repeat until stopped (music, engines, ambience). */loop?: boolean;};/** A `require("./file.wav")` asset, or a URI. WAV, PCM or float, mono or stereo. */export type SoundSource = AssetSource;/** Named sounds. Plays are ignored until `ready` resolves (usually a few milliseconds). */export declare class SoundBank<K extends string> {/** Resolves when every sound has loaded (failures are logged and skipped). */readonly ready: Promise<void>;constructor(sources: Record<K, SoundSource>);/** The sound, once loaded (e.g. for an entity's `impact.sound`). */get(name: K): Sound | undefined;play(name: K, options?: AudioPlayOptions): Voice | null;}export declare const audio: {/** Initializes the engine and loads named sounds into its mixer. Each asset decodes once per session. */load<K extends string>(sources: Record<K, SoundSource>): SoundBank<K>;/** Plays a sound (low latency: mixed in Rust on the audio thread). Returns null if it couldn't play. */play(sound: Sound, { volume: v, pan, pitch, loop }?: AudioPlayOptions): Voice | null;stop(voice: Voice | null | undefined): void;muted: boolean;/** The inverse of `muted`, matching `haptics.enabled` (e.g. `audio.enabled = settings.enableSounds`). */enabled: boolean;/** Master volume, 0..2. */volume: number;/** True once the device's audio output is running. */readonly running: boolean;};
Usage and examples: /game-engine/audio-haptics.
| Export | Kind | Guide |
|---|---|---|
| haptics | Runtime API | /game-engine/audio-haptics |
| HapticTap | TypeScript type | /game-engine/audio-haptics |
media/haptics declarations
React and React Native · shared engine API
export type HapticTap = {/** Seconds from now. */time: number;/** 0..1 */intensity: number;/** 0 (dull thud) .. 1 (crisp click). */sharpness: number;};export declare const haptics: {/** Set false to silence all haptics (e.g. a settings toggle). */enabled: boolean;/** True if the device has a haptic actuator (false on simulators). */readonly supported: boolean;/** A single tap. Rapid repeats (< 35 ms apart) are dropped so collisions don't buzz. */impact(intensity?: number, sharpness?: number): void;/** A light, crisp tick for UI selection. */selection(): void;notify(type: "success" | "warning" | "error"): void;/** Any sequence of taps. */play(taps: readonly HapticTap[]): void;};
Usage and examples: /game-engine/input-picking.
| Export | Kind | Guide |
|---|---|---|
| Joystick | Runtime API | /game-engine/input-picking |
| useJoystick | Runtime API | /game-engine/input-picking |
| JoystickState | TypeScript type | /game-engine/input-picking |
| JoystickProps | TypeScript type | /game-engine/input-picking |
input/Joystick declarations
React and React Native · shared engine API
export type JoystickState = {x: number;y: number;};export declare function useJoystick(): JoystickState;export interface JoystickProps {state: JoystickState;size?: number;style?: CSSProperties;}export declare function Joystick({ state, size, style }: JoystickProps): import("react").JSX.Element;
Usage and examples: /game-engine/input-picking.
| Export | Kind | Guide |
|---|---|---|
| createKeyboardInput | Runtime API | /game-engine/input-picking |
| KeyboardInputMode | TypeScript type | /game-engine/input-picking |
| KeyboardInputOptions | TypeScript type | /game-engine/input-picking |
input/keyboard declarations
React and React Native · shared engine API
export type KeyboardInputMode = 'pointer' | 'drag' | 'swipe';export interface KeyboardInputOptions {mode?: KeyboardInputMode;enabled?: () => boolean;/** Optional primary control, in CSS pixels relative to the input surface. */primary?: () => {x: number;y: number;};}/** Browser keyboard adapter. Reuses pointer input, including engine gestures and raw contact surfaces. */export declare function createKeyboardInput(surface: HTMLElement, options?: KeyboardInputOptions): {cancel: () => void;dispose(): void;};
Usage and examples: /game-engine/render-source.
| Export | Kind | Guide |
|---|---|---|
| MAX_MESHES | Runtime API | /game-engine/render-source |
| Camera | TypeScript type | /game-engine/render-source |
| Light | TypeScript type | /game-engine/render-source |
| RenderSource | TypeScript type | /game-engine/render-source |
| Shape | TypeScript type | /game-engine/render-source |
| Vec3 | TypeScript type | /game-engine/render-source |
types declarations
React and React Native · shared engine API
export type Vec3 = readonly [number,number,number];/** Number of mesh ids: built-in shapes (0..15), then loaded models, glyphs and textured variants. */export declare const MAX_MESHES = 4096;/** What the renderer draws. `World` implements it; so can any custom simulation. */export interface RenderSource {/** Native world id, when this source supports skeletal characters. */readonly nativeWorld?: number;/** Column-major mat4 per instance (16 floats), grouped by mesh. Only the first `count` are valid. */readonly matrices: Float32Array;/** RGBA per instance (4 floats), same order as `matrices`. Alpha below 1 draws see-through. */readonly colors: Float32Array;/** Texture region per instance (u0 v0 u1 v1), same order. Optional: the whole texture by default. */readonly regions?: Float32Array;/*** `[first, count]` per mesh id, in instances: opaque instances at `ranges[2 * mesh]`, transparent ones* at `ranges[2 * (MAX_MESHES + mesh)]`. Shorter arrays just have no transparent part.*/readonly ranges: Uint32Array;/** Total number of valid instances. */readonly count: number;/** Maximum number of instances (sizes the GPU buffers). */readonly capacity: number;/** Called by GameView after each frame with the camera it drew with (for picking and `toScreen`). */setView?(viewProj: Float32Array, width: number, height: number): void;/*** Steps the source. When present, GameView calls it once a frame after `onUpdate`, unless* `onUpdate` already did (`updateCount` changed) or the source is disposed.*/update?(dt: number): void;/** How many times `update` has run. */readonly updateCount?: number;readonly isDisposed?: boolean;}/*** Built-in shapes, each 1 unit across before scaling. "none" isn't drawn (groups, pivots, trigger zones).* "puff" is a soft, round sprite that always faces the camera and is always see-through: overlapping* puffs blend into smoke, dust, steam and clouds. "flame" is the same sprite drawn additively: it adds* light to what's behind it, so overlapping flames build up to a hot white core and stay bright over* smoke (fire, sparks, explosions, magic, glows). Use them as a burst's `mesh`.*/export type Shape = 'cube' | 'sphere' | 'plane' | 'cylinder' | 'cone' | 'capsule' | 'torus' | 'roundedBox' | 'puff' | 'flame' | 'none';export type Camera = {eye: [number,number,number];target: [number,number,number];/** Vertical field of view in radians (ignored when `ortho` is set). */fov: number;/** Orthographic: half the visible height in world units. Board and puzzle games look flat and tidy. */ortho?: number;/*** Chase an entity: each frame the target moves toward it and the eye keeps `offset` from the target.* `smoothing` is roughly the seconds it takes to catch up (0 = rigid, default 0.15).*/follow?: {target: Entity;offset: Vec3;smoothing?: number;} | null;/** Shake strength in world units (e.g. 0.3 for a hit). Fades out by itself. */shake?: number;};export type Light = {/** Direction *towards* the light. Need not be normalized. */direction: [number,number,number];/** 0..1 ambient term. */ambient: number;/** Cast shadows (one directional shadow map centred on the camera target). Default true. */shadows?: boolean;/** Half-size in world units of the shadowed area around the camera target. Default 30. */shadowExtent?: number;/*** Color and brightness of the light, multiplying both sun and ambient: e.g. [0.35, 0.38, 0.6] for* moonlight, or a CSS color. Glowing colors (channels above 1) aren't affected. Alpha, if given, is* ignored. Default [1, 1, 1].*/color?: ColorInput;};
Usage and examples: /game-engine/drawing.
| Export | Kind | Guide |
|---|---|---|
| DrawingDocument | Runtime API | /game-engine/drawing |
| DrawingBrush | TypeScript type | /game-engine/drawing |
| DrawingBrushOptions | TypeScript type | /game-engine/drawing |
| DrawingControls | TypeScript type | /game-engine/drawing |
| DrawingState | TypeScript type | /game-engine/drawing |
| DrawingSnapshot | TypeScript type | /game-engine/drawing |
| SavedDrawingPath | TypeScript type | /game-engine/drawing |
| DrawingTool | TypeScript type | /game-engine/drawing |
| DrawingShape | TypeScript type | /game-engine/drawing |
| DrawingShapePreview | TypeScript type | /game-engine/drawing |
| DrawingSymmetry | TypeScript type | /game-engine/drawing |
| DrawingLayer | TypeScript type | /game-engine/drawing |
| DrawingProject | TypeScript type | /game-engine/drawing |
| DrawingStroke | TypeScript type | /game-engine/drawing |
| DrawingSample | TypeScript type | /game-engine/drawing |
| DrawingCoverageOptions | TypeScript type | /game-engine/drawing |
drawing/DrawingDocument declarations
React and React Native · shared engine API
export type DrawingBrush = 'NORMAL' | 'MARKER' | 'PENCIL' | 'CALLIGRAPHY' | 'WATERCOLOR' | 'NEON' | 'CRAYON' | 'SPRINKLING';export type DrawingShape = 'line' | 'arrow' | 'rectangle' | 'square' | 'rounded-rectangle' | 'circle' | 'ellipse' | 'triangle' | 'right-triangle' | 'diamond' | 'pentagon' | 'hexagon' | 'octagon' | 'star' | 'heart' | 'trapezoid' | 'parallelogram' | 'cross' | 'speech-bubble' | 'cloud';export interface DrawingShapePreview {kind: DrawingShape;name: string;path: string;filledPath: string;canFill: boolean;}export type DrawingTool = 'brush' | 'fill' | 'picker' | DrawingShape;export type DrawingSymmetry = 'none' | 'vertical' | 'horizontal' | 'both';export interface DrawingLayer {id: number;name: string;visible: boolean;locked: boolean;opacity: number;}export interface DrawingProject {version: 2;width: number;height: number;activeLayer: number;layers: DrawingLayer[];paths: SavedDrawingPath[];}export interface DrawingBrushOptions {brushType: DrawingBrush;color: string;width: number;opacity: number;isEraser?: boolean;pressure?: boolean;smoothing?: number;tool?: DrawingTool;symmetry?: DrawingSymmetry;filled?: boolean;tolerance?: number;}export interface DrawingState {controls: DrawingControls;count: number;canUndo: boolean;canRedo: boolean;revision: number;width: number;height: number;pixelWidth: number;pixelHeight: number;zoom: number;layers: DrawingLayer[];activeLayer: number;editable: boolean;isDrawing: boolean;tool: DrawingTool | null;pickedColor: string | null;error: string | null;}/** Native document settings; React may display this snapshot but never owns the tool state. */export interface DrawingControls {tool: 'brush' | 'eraser' | 'move' | 'shape';brushType: DrawingBrush;color: string;width: number;opacity: number;shape: DrawingShape;filled: boolean;pressure: boolean;smoothing: number;}export interface DrawingSnapshot {base64: string;width: number;height: number;}/** A committed stroke's geometry in document coordinates, for colliders, tracing and scoring. */export interface DrawingStroke {/** Position in the document's stroke list; pass `index + 1` as `from` to read only newer strokes. */index: number;layerId: number;color: string;/** Painted width in document units, including the brush's width factor. */width: number;opacity: number;isEraser: boolean;brushType: string;/** `fill`: `outline` is the painted shape. `stroke`: `outline` is the centreline. */style: 'fill' | 'stroke';/** [x, y, width, height] of the painted outline. */bounds: [number,number,number,number];/*** Smoothed gesture centrelines as flat [x0, y0, x1, y1, ...] arrays: one per symmetry copy, for* brush strokes drawn this session. Empty for loaded strokes, fills and shapes; use `outline`.*/lines: number[][];/** Flattened contours of the painted path as flat [x0, y0, ...] arrays. */outline: {points: number[];closed: boolean;}[];}/** The composited ink under a document point (straight alpha; transparent paper is alpha 0). */export interface DrawingSample {color: string;alpha: number;}export interface DrawingCoverageOptions {/** Document rectangle to measure; defaults to the whole paper. */x?: number;y?: number;width?: number;height?: number;/** Minimum ink alpha (0..1) that counts as painted. Default 0.5. */minAlpha?: number;}export interface SavedDrawingPath {path: string;color: string;width: number | string;opacity?: number;style?: 'fill' | 'stroke';isEraser?: boolean;brushType?: string;touchPoints?: unknown[] | null;[key: string]: unknown;}/*** A native art document. Touches and live rendering never subscribe to React state.** Games use the same document without `DrawingCanvas`: bind `texture()` to any entity, feed* `input(..., 'document')` from the game's own touches or world hits, and read `strokes()`,* `sample()` and `coverage()` for colliders and scoring. Create one document per game screen and* `clear()` it on replay; `dispose()` it on unmount (this also frees its texture).*/export declare class DrawingDocument {readonly id: number;readonly width: number;readonly height: number;constructor(width: number, height: number, pixelRatio?: number);get isDisposed(): boolean;setBrush(options: DrawingBrushOptions): null;updateControls(options: Partial<DrawingControls> & {reset?: boolean;}): DrawingState;/** Atomic import: errors leave the current artwork intact, including unknown legacy metadata. */load(paths: string | readonly SavedDrawingPath[] | DrawingProject): DrawingState;get state(): DrawingState;exportPaths(): string;/** Rust checks idleness and revision atomically; autosave never finishes a live stroke. */setEditingEnabled(enabled: boolean): DrawingState;captureDraft(afterRevision?: number): {project: string;revision: number;width: number;height: number;} | null;/** Browser change stream. Native canvases deliver changes directly from their display clock. */readChange(): DrawingState | null;exportSVG(): string;/** Full editable project: preserves layer order, visibility, locks and original SVG metadata. */exportProject(): string;layer(action: 'add' | 'duplicate' | 'select' | 'update' | 'move' | 'delete' | 'clear', options?: Partial<DrawingLayer> & {index?: number;}): DrawingState;fill(x: number, y: number, tolerance?: number): DrawingState;shapeCatalog(): DrawingShapePreview[];addShape(kind: DrawingShape, x: number, y: number, endX: number, endY: number, filled?: boolean): DrawingState;snapshot(): DrawingSnapshot;undo(): DrawingState;redo(): DrawingState;clear(): DrawingState;invalidateView(): DrawingState;resetView(): DrawingState;/** Fit the full artwork or fill the viewport width without changing saved dimensions. */setViewFit(fit: 'contain' | 'width'): DrawingState;finish(): DrawingState;cancel(): DrawingState;/*** Feeds one pointer sample: 0 begin, 1 move, 2 end, 3 cancel. `view` coordinates are relative to* a `DrawingCanvas` and follow its zoom/pan (browser pointer sampling; native canvases feed* touches straight into the Rust core). `document` coordinates skip the view mapping, for games* that convert their own touches or world hits (e.g. a raycast's texture UV × document size).*/input(phase: 0 | 1 | 2 | 3, x: number, y: number, pressure?: number, space?: 'view' | 'document'): void;/*** A live texture of the artwork (transparent paper, straight alpha), usable as any entity's* `texture`. In-progress strokes appear immediately; only changed rows are uploaded each frame.* Created once per document and freed by `dispose()`. Its pixels are not readable through* texture APIs; use `sample()`, `coverage()` or `snapshot()`.*/texture(): Texture;/** Committed strokes from index `from`, flattened to `tolerance` document units (default 0.5). */strokes(options?: {from?: number;tolerance?: number;}): DrawingStroke[];/** The ink under a document point, or null off the paper. Includes an in-progress stroke. */sample(x: number, y: number): DrawingSample | null;/** Fraction (0..1) of a document rectangle covered by ink, for colouring and scratch-off scoring. */coverage(options?: DrawingCoverageOptions): number;transform(dx: number, dy: number, scale?: number): DrawingState;/** Browser presentation; iOS and Android use native display clocks with automatic suspension. */present(width: number, height: number, background?: string, pixelRatio?: number): boolean;dispose(): void;}
Usage and examples: /game-engine/drawing.
| Export | Kind | Guide |
|---|---|---|
| DrawingCanvas | Runtime API | /game-engine/drawing |
| DrawingCanvasProps | TypeScript type | /game-engine/drawing |
drawing/DrawingCanvas declarations
React and React Native · shared engine API
export declare const DrawingCanvas: import("react").MemoExoticComponent<({ document: drawing, mode, background, active, onError, onChange, style }: DrawingCanvasProps) => import("react").JSX.Element>;export interface DrawingCanvasProps {document: DrawingDocument;mode?: 'draw' | 'move' | 'view';background?: string;active?: boolean;onChange?: (state: DrawingState) => void;onError?: (error: Error) => void;style?: ViewStyle;}