Mount a scene in a React Native development build.
Keep the scene in plain functions so React only mounts it. useWorld calls setupScene once with a fresh world after the engine loads, and builds a new one when its deps change.
scene.ts
React and React Native · shared engine API
scene.ts
import type { Camera, World } from "@nayan-ui/engine";export const camera: Camera = { eye: [8, 7, 10], target: [0, 1, 0], fov: 0.9 };export function setupScene(world: World) {world.spawn({ mesh: "cube", position: [0, -0.5, 0], scale: [16, 1, 16], color: "#404D59", physics: "fixed" });world.spawn({ mesh: "sphere", position: [0, 3, 0], color: "#33A6FF", physics: { type: "dynamic", bounce: 0.65 } });}/** Tapping the ball bounces it. */export function tapScene(world: World, x: number, y: number) {const hit = world.pick(x, y);if (hit) world.impulse(hit.entity, [0, 5, 0]);}
useWorld returns null until the world is ready and passes start-up failures to onError, such as a missing native module in Expo Go. paused stops updates and drawing but keeps the world.
GameScreen.tsx
React Native · iOS and Android
GameScreen.tsx
import { useState } from "react";import { Button, Text, View } from "react-native";import { GameView, useWorld } from "@nayan-ui/engine";import { camera, setupScene, tapScene } from "./scene";export default function GameScreen() {const [error, setError] = useState<string | null>(null);const [paused, setPaused] = useState(false);const world = useWorld(64, setupScene, [], (reason) => setError(reason.message));if (error) return <Text accessibilityRole="alert">{error}</Text>;if (!world) return <Text>Loading…</Text>;return (<View style={{ flex: 1 }}><Button title={paused ? "Resume" : "Pause"} onPress={() => setPaused((value) => !value)} /><GameView source={world} camera={camera} paused={paused} style={{ flex: 1 }}onTap={(x, y) => tapScene(world, x, y)} onError={(reason) => setError(reason.message)} /></View>);}
GameView already pauses while the app is in the background. Navigators keep unfocused screens mounted, so pass paused={!focused} from your navigator's focus hook.
FocusAwareGame.tsx
React Native · iOS and Android
FocusAwareGame.tsx
import { GameView, type World } from "@nayan-ui/engine";import { camera, tapScene } from "./scene";/** `focused` comes from your navigator, e.g. useIsFocused() from @react-navigation/native. */export function FocusAwareGame({ world, focused }: { world: World; focused: boolean }) {return (<GameView source={world} camera={camera} paused={!focused} style={{ flex: 1 }}onTap={(x, y) => tapScene(world, x, y)} />);}