/** * @license * SPDX-License-Identifier: Apache-2.0 */ import { forwardRef, useEffect, useRef } from 'react'; import { useMujocoWasm } from './MujocoProvider'; import { MujocoSimProvider } from './MujocoSimProvider'; import type { MujocoSimAPI, ReadyCallbackInput, SceneConfig, SelectionCallbackInput, StepCallbackInput, } from '../types'; export interface MujocoPhysicsProps { /** Scene/robot configuration. */ config: SceneConfig; /** Fires when model is loaded and API is ready. */ onReady?: (input: ReadyCallbackInput) => void; /** Fires on scene load failure. */ onError?: (error: Error) => void; /** Called each physics step. */ onStep?: (input: StepCallbackInput) => void; /** Called on body double-click selection. */ onSelection?: (input: SelectionCallbackInput) => void; /** Override model gravity. */ gravity?: [number, number, number]; /** Override model.opt.timestep. */ timestep?: number; /** mj_step calls per frame. */ substeps?: number; /** Declarative pause. */ paused?: boolean; /** Simulation speed multiplier. */ speed?: number; /** Interpolate rendered body poses between fixed physics steps. */ interpolate?: boolean; children: React.ReactNode; } /** * MujocoPhysics — physics provider for use inside a user-owned R3F Canvas. * * This is the R3F-idiomatic alternative to MujocoCanvas. Instead of wrapping * the Canvas, place this inside your own : * * ```tsx * * * * * * * * * ``` * * Forward ref exposes MujocoSimAPI. */ export const MujocoPhysics = forwardRef( function MujocoPhysics({ onError, children, ...props }, ref) { const { mujoco, status: wasmStatus, error: wasmError } = useMujocoWasm(); const onErrorRef = useRef(onError); onErrorRef.current = onError; useEffect(() => { if (wasmStatus === 'error') { onErrorRef.current?.(new Error(wasmError ?? 'WASM load failed')); } }, [wasmStatus, wasmError]); if (wasmStatus === 'error' || wasmStatus === 'loading' || !mujoco) { return null; } return ( {children} ); } );