import { Engine , EngineOptions , FreeCamera , HemisphericLight , Mesh , MeshBuilder , Scene , SceneOptions , Vector3 , } from '@babylonjs/core' ; import { FC , useEffect , useRef } from 'react' ; import { SetRequired } from 'type-fest' ; type OnSceneReadyHandler = ( scene : Scene ) => void ; type OnRenderHandler = ( scene : Scene ) => void ; type SceneComponentProps = { canvasId : string ; antialias ? : boolean ; engineOptions ? : EngineOptions ; adaptToDeviceRatio ? : boolean ; sceneOptions ? : SceneOptions ; onRender : OnRenderHandler ; onSceneReady : OnSceneReadyHandler ; } ; type SceneComponentPropsIn = SetRequired < Partial < SceneComponentProps > , 'onRender' | 'onSceneReady' > ; const SceneComponent = ( props ) => { const reactCanvas = useRef ( null ) ; const _props = { canvasId : 'babylonjs-canvas' , ... props , } ; const { canvasId , antialias , engineOptions , adaptToDeviceRatio , sceneOptions , onRender , onSceneReady , ... rest } = _props ; useEffect ( ( ) => { if ( ! reactCanvas . current ) return ; const engine = new Engine ( reactCanvas . current , antialias , engineOptions , adaptToDeviceRatio ) ; const scene = new Scene ( engine , sceneOptions ) ; if ( scene . isReady ( ) ) { onSceneReady ( scene ) ; } else { scene . onReadyObservable . addOnce ( onSceneReady ) ; } engine . runRenderLoop ( ( ) => { onRender ( scene ) ; scene . render ( ) ; } ) ; const resize = ( ) => { scene . getEngine ( ) . resize ( ) ; } ; if ( window ) { window . addEventListener ( 'resize' , resize ) ; } return ( ) => { scene . getEngine ( ) . dispose ( ) ; if ( window ) { window . removeEventListener ( 'resize' , resize ) ; } } ; } , [ antialias , engineOptions , adaptToDeviceRatio , sceneOptions , onRender , onSceneReady ] ) ; return < canvas id = { canvasId } ref = { reactCanvas } { ... rest } />; } ; let box ; const onSceneReady = ( scene ) => { var camera = new FreeCamera ( 'camera1' , new Vector3 ( 0 , 5 , - 10 ) , scene ) ; camera . setTarget ( Vector3 . Zero ( ) ) ; const canvas = scene . getEngine ( ) . getRenderingCanvas ( ) ; camera . attachControl ( canvas , true ) ; var light = new HemisphericLight ( 'light' , new Vector3 ( 0 , 1 , 0 ) , scene ) ; light . intensity = 0.7 ; box = MeshBuilder . CreateBox ( 'box' , { size : 2 } , scene ) ; box . position . y = 1 ; MeshBuilder . CreateGround ( 'ground' , { width : 6 , height : 6 } , scene ) ; } ; /**
 * Will run on every frame render.  We are spinning the box on y-axis.
 */ const onRender = ( scene ) => { if ( box !== undefined ) { var deltaTimeInMillis = scene . getEngine ( ) . getDeltaTime ( ) ; const rpm = 10 ; box . rotation . y += ( rpm / 60 ) * Math . PI * 2 * ( deltaTimeInMillis / 1000 ) ; } } ; const App = ( ) => ( < div > < SceneComponent antialias onSceneReady = { onSceneReady } onRender = { onRender } / > < /div>); export default App ;