React-babylonjs v3

Well, it’s been over a year since react-babylonjs v2 came out. There have been ~30 releases and ~50 github issues closed in the meantime - also some incredible PRs from the community. It’s really the ideas from random people that keep pushing the project forward! There has been lots of new functionality: instancing (and instancedMesh), more complete babylon API support (and changes to support Babylon 4.2 and React 17), improved declarative support for textures, hooks for AssetManager and SceneLoader (need Suspense), Cascaded Shadow Maps (from Dennemark), properly support quaternions in renderer, assigning to multiple properties declaratively (ie: textures), lots of new hooks (and fixes) like useHover, useHook, effect layers, behaviors (from hookex), add observable to before/after scene render - to allow PIXIjs in back/foreground, allow registering dynamic property assignment for renderer (ie: assign “hot pink” as a Color3 - see chromajs story), kebab property assignment (ie: rotation-x for external GUI library), various improvements to the code generation and many other changes.

Also hookex created a project that uses react-babylonjs to allow it to work with react-spring, which gives really nice animations and physics.

The primary reason though for a 3.0 release was to introduce 4 breaking changes:

  1. <model> is replaced by <Model> (host element to component) and it must now be enclosed in a React Suspense block. The model supplies loading progress with a context, so the fallback component on Suspense can report progress.
  2. Somewhere in v2 the fromInstance prop was introduced and the passed in instance would be automatically disposed (requiring a hack to patch the dispose method on the object otherwise). The new functionality is to not dispose and you can opt-in to dispose with disposeInstanceOnUnmount. ie:
<mesh name='box' fromInstance={mesh} rotation={props.rotation} disposeInstanceOnUnmount .../>
  1. When you got a ref using the React useRef hook in v2 you needed to use the hostInstance to access the babylon.js object. I found a method on the reconciler that allowed me hide the metadata the reconciler is using and provide functionality using standard references.
  2. Some hooks were renamed. ie: useBabylonScene is now just useScene, etc.

I also added some basic support in the Scene Explorer for showing the now hidden metadata from refs. To be able to show props not available on the babylonjs object (like shadow casting, nested property assigning, etc). I wanted, however, the properties read-only and that’s not supported for Custom Properties. I have a PR for the Scene Explorer to allow custom properties to be declared read-only if that seems like a useful addition then I can propose (it’s missing readonly slider and maybe others).

Upcoming goals are support for declarative NME and to revisit react-native support via Expo. React-native support was a goal after the 2.0 release, but was a really busy year and hoping to do that in earnest this year.

See you on the playground :slight_smile:

brianzinn/react-babylonjs (github.com)

7 Likes

Congrats to the release!
I can only recommend react-babylonjs! Brian is doing a great job and if you are missing features, he is there to help you!

1 Like

Wow @brianzinn,

amazing work as always! Can’t wait to use the new version! I can promise it will happen VERY soon :slight_smile:

Congrats buddy! this is so rad!

I am currently expanding my knowledge and skills. React.js is my next step. Since I would like to bring 3D worlds into my work in the future, I am even more pleased to see that you have already created a great framework for react and babyon!

I am working on Windows 10 with Visual Studio Code.

  • First I installed https://nodejs.org (with chocolatey) to be able to run the npm command in the terminal.

  • Next I opened a DOS Shell and run npm i react-babylonjs @babylonjs/core @babylonjs/gui

  • Created my first react app with

npx create-react-app my-app
cd my-app
npm start

When I start the react app with npm start I get an Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:67:19)
at Object.createHash (node:crypto:130:10)…
{
opensslErrorStack: [ ‘error:03000086:digital envelope routines::initialization error’ ],
library: ‘digital envelope routines’,
reason: ‘unsupported’,
code: ‘ERR_OSSL_EVP_UNSUPPORTED’
}

… heavy tobac! :slight_smile:

Do you know a simple, direct way to make all these things work?

Downgrade your node to LTS version (like 16.3.0) or change your package.json to:

"start": "react-scripts --openssl-legacy-provider start"

That’s a less secure SSL, but is fine for development purposes.

1 Like

Yeah, I could run the React Server for my-app.

But after installing some missing libraries like tsc-watch and tslib helper und starting from the root
react-babylonjs I get another arrror

can you please give me a hand?

after you downgrade node you need to delete your “node_modules” directory and “npm install” again. There is a typescript template as well if you are working in typescript:

npx create-react-app your-app-name --template typescript

after some try and errors I could finally run an example! … oh that’s so surprising and exciting if things start living! :slight_smile:

here is the full road map of my journey for others who wants to try, too:

  1. install node.js https://nodejs.org
  2. npx create-react-app my-app
    cd my-app
  3. edit package.json and change “start” parameter to “react-scripts --openssl-legacy-provider start”
  4. goto folter src and edit App.js (make a backup of this file first)
import logo from './logo.svg';
import './App.css';


import React, { useRef, useState } from 'react'
import { Engine, Scene, useBeforeRender, useClick, useHover } from 'react-babylonjs'
import { Vector3, Color3 } from '@babylonjs/core'

const DefaultScale = new Vector3(1, 1, 1);
const BiggerScale = new Vector3(1.25, 1.25, 1.25);

const SpinningBox = (props) => {
  // access Babylon scene objects with same React hook as regular DOM elements
  const boxRef = useRef(null);

  const [clicked, setClicked] = useState(false);
  useClick(
    () => setClicked(clicked => !clicked),
    boxRef
  );

  const [hovered, setHovered] = useState(false);
  useHover(
    () => setHovered(true),
    () => setHovered(false),
    boxRef
  );

  // This will rotate the box on every Babylon frame.
  const rpm = 5;
  useBeforeRender((scene) => {
    if (boxRef.current) {
      // Delta time smoothes the animation.
      var deltaTimeInMillis = scene.getEngine().getDeltaTime();
      boxRef.current.rotation.y += ((rpm / 60) * Math.PI * 2 * (deltaTimeInMillis / 1000));
    }
  });

  return (<box name={props.name} ref={boxRef} size={2} position={props.position} scaling={clicked ? BiggerScale : DefaultScale}>
    <standardMaterial name={`${props.name}-mat`} diffuseColor={hovered ? props.hoveredColor : props.color} specularColor={Color3.Black()} />
  </box>);
}

/*
export const SceneWithSpinningBoxes = () => (
  <div>
    <Engine antialias adaptToDeviceRatio canvasId='babylonJS' >
      <Scene>
        <arcRotateCamera name="camera1" target={Vector3.Zero()} alpha={Math.PI / 2} beta={Math.PI / 4} radius={8} />
        <hemisphericLight name='light1' intensity={0.7} direction={Vector3.Up()} />
        <SpinningBox name='left' position={new Vector3(-2, 0, 0)}
          color={Color3.FromHexString('#EEB5EB')} hoveredColor={Color3.FromHexString('#C26DBC')}
        />
        <SpinningBox name='right' position={new Vector3(2, 0, 0)}
          color={Color3.FromHexString('#C8F4F9')} hoveredColor={Color3.FromHexString('#3CACAE')}
        />
      </Scene>
    </Engine>
  </div>
)
*/

function App() {
	return (
  <div>
    <Engine antialias adaptToDeviceRatio canvasId='babylonJS' >
      <Scene>
        <arcRotateCamera name="camera1" target={Vector3.Zero()} alpha={Math.PI / 2} beta={Math.PI / 4} radius={8} />
        <hemisphericLight name='light1' intensity={0.7} direction={Vector3.Up()} />
        <SpinningBox name='left' position={new Vector3(-2, 0, 0)}
          color={Color3.FromHexString('#EEB5EB')} hoveredColor={Color3.FromHexString('#C26DBC')}
        />
        <SpinningBox name='right' position={new Vector3(2, 0, 0)}
          color={Color3.FromHexString('#C8F4F9')} hoveredColor={Color3.FromHexString('#3CACAE')}
        />
      </Scene>
    </Engine>
  </div>
  );
}

/*
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}
*/

export default App;

  1. goto back to folder my-app and run the command npm start

This is the output:

thank’s brianzinn! :slight_smile:

Crash course to React:

Refactoring my example after this crash course:

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
			  Test ReactBabylon
        </p>

        <SceneWithSpinningBoxes>
          
        </SceneWithSpinningBoxes>

      </header>
    </div>
  )
  
  
}
1 Like