Reactylon Framework

repository·main·Indexed 42 days ago

https://github.com/simonedevit/reactylon

A React framework for building 3D and XR experiences using Babylon.js. It enables developers to use declarative JSX instead of imperative code to target web, mobile, and VR/AR/MR headsets from a single codebase. Key features include automatic object disposal, scene injection, and full TypeScript support. The ecosystem includes the `create-reactylon-app` CLI for project scaffolding and the `babel-plugin-reactylon` for JSX-to-Babylon compilation.

Tokens
7.6K
Snippets
27
Records
39
Agent score
52%

What's inside Reactylon

  1. Overview of Reactylon features

    main

    Reactylon is a React framework for 3D and XR that provides a declarative syntax for Babylon.js. Key capabilities include:

    • Declarative Babylon.js: Use JSX to define 3D entities.
    • Automatic Object Management: Automatically handles the disposal of meshes, cameras, and lights to prevent memory leaks.
    • Scene Injection: The Babylon.js scene object is automatically injected into components, reducing boilerplate.
    • Automatic Hierarchy: Components are automatically added/removed to their correct parents in the Babylon.js scene graph.
    • Cross-Platform: Supports web (PWA), mobile (via React Native/Babylon Native), and VR/AR/MR headsets from a single codebase.
    • Full TypeScript Support: Provides type-safe props for Babylon.js entities.
  2. Reactylon Ecosystem components

    main

    Reactylon relies on two primary tools for its developer experience:

    • create-reactylon-app: A zero-config CLI for scaffolding new projects.
    • babel-plugin-reactylon: A Babel plugin that handles the JSX-to-Babylon compilation. This enables ergonomic declarative components while ensuring the output remains fast and tree-shakeable.
  3. Install Reactylon via create-reactylon-app

    main

    The fastest way to bootstrap a new project is using the create-reactylon-app CLI. This command scaffolds a full React 19 project that includes a preconfigured Babylon.js engine, physics support, and a starter scene with zero manual configuration.

    npx create-reactylon-app my-app
  4. Use Reactylon JSX elements in React

    main
    Reactylon extends the standard JSX namespace to allow using Babylon.js and Babylon GUI components as intrinsic elements (e.g., <mesh />, <sphere />). This works for both React 18 and React 19. The library automatically handles certain properties, such as injecting transformNode into physicsAggregate and extending advancedDynamicTexture with AdvancedDynamicTextureProps.
  5. How manualRenderLoop works in the Engine component

    main

    By default, Reactylon starts a continuous Babylon.js render loop via engine.runRenderLoop(...) once all child Scene components are marked as ready.

    If you provide a manualRenderLoop function, Reactylon will not call engine.runRenderLoop. Instead, it will invoke your callback exactly once at the moment the render loop would normally start.

    Your callback receives two arguments:

    1. renderFrame: A function that renders a single frame using Reactylon's internal rules (e.g., multi-scene view selection). You can call this manually to step rendering deterministically.
    2. engine: The Babylon.js engine instance (WebGLEngine or WebGPUEngine).

    This is primarily intended for tests (deterministic stepping) or advanced integrations that require full control over scheduling.

    <Engine
      manualRenderLoop={(renderFrame, engine) => {
        // Example: Manually stepping the frame once
        renderFrame();
        
        // Or setting up your own custom loop
        const myLoop = () => {
          renderFrame();
          requestAnimationFrame(myLoop);
        };
        myLoop();
      }}
    >
      <Scene />
    </Engine>
  6. Use multiple canvases with the Engine component

    main

    To use multiple canvases, set the isMultipleCanvas prop to true on the Engine component.

    Important Requirement: When isMultipleCanvas is enabled, every child Scene component must be provided with its own canvas prop. If a Scene is missing a canvas prop while isMultipleCanvas is true, Reactylon will log an error.

    When isMultipleCanvas is false (default), all child Scene components will share the single canvas created by the Engine component.

    <Engine isMultipleCanvas={true}>
      <Scene canvas={canvasElement1} />
      <Scene canvas={canvasElement2} />
    </Engine>
  7. Create your first 3D scene with JSX

    main

    Reactylon allows you to write Babylon.js scenes using declarative JSX. You wrap your scene components in an <Engine> and a <Scene> component. Within the <Scene>, you can declare lights, meshes, and other Babylon.js entities as components. Reactylon automatically manages the scene graph, parent-child relationships, and object disposal.

    import { Engine, Scene } from 'reactylon';
    
    const App = () => (
        <Engine>
            <Scene>
                <hemisphericLight name="light" intensity={0.8} />
                <box name="box" options={{ size: 2 }} positionY={1} />
            </Scene>
        </Engine>
    );
  8. Troubleshooting: Missing SceneContext.Provider

    main
    If you encounter the error Missing SceneContext.Provider in the tree when calling hooks like useEngine, useScene, or useCanvas, it means your component is not a child of the SceneContext.Provider. Ensure that you have initialized your store with createBabylonStore and passed it to a SceneContext.Provider at the top level of your React application.
  9. Manage GUI hierarchy with GuiHost.addChild and GuiHost.removeChild

    main

    Use these static methods to manage the parent-child relationships of Babylon.js GUI controls. GuiHost abstracts the differences between various container types (like Grids, Buttons, or standard Containers).

    addChild(parentInstance, child)

    • Button3D: If the parent is a Button3D (and not a HolographicButton), the child is assigned to the .content property.
    • Grid (row/column): If the parent is a grid type, it uses addControl(child, 0, 0).
    • Standard Containers: Calls the .addControl(child) method on the parent.
    • Error Handling: Prevents nesting an AdvancedDynamicTexture inside another AdvancedDynamicTexture.

    removeChild(parentInstance, child)

    • Calls .removeControl(child) on the parentInstance if it exists.
    // Adding a control to a parent
    GuiHost.addChild(parentContainer, newButton);
    
    // Removing a control
    GuiHost.removeChild(parentContainer, newButton);
  10. useModel parameters and return value

    main

    The useModel hook accepts the following arguments:

    ParameterTypeDescription
    urlstring | File | ArrayBufferViewThe URL, File, or ArrayBufferView of the model to load.
    options (optional)ImportMeshOptionsConfiguration options for the Babylon.js ImportMeshAsync function.
    onCreate (optional)(model: ISceneLoaderAsyncResult) => voidA callback function executed once the model is successfully loaded and enabled.
    key (optional)stringA unique identifier used to invalidate the cache and force a reload.

    Returns:

    Returns an ISceneLoaderAsyncResult object containing the imported meshes, transforms, and other Babylon.js model data.

  11. Update GUI event triggers with GuiHost.commitUpdate

    main

    To update the event handlers (triggers) of an existing GUI element, use GuiHost.commitUpdate. This is typically used in conjunction with GuiHost.prepareUpdate to implement a reactive update cycle.

    commitUpdate iterates through the keys in the updatePayload that match GuiTriggers and updates the element's internal _triggerCallbacks.

    Parameters:

    • instance: The AugmentedGuiElement to be updated.
    • updatePayload: An UpdatePayload object containing new callback functions for the triggers.
    // Example of committing an update to a trigger
    const payload: UpdatePayload = {
      // Assuming 'click' is a valid GuiTrigger
      click: (evt, state) => {
        console.log('New click handler:', evt);
      }
    };
    
    GuiHost.commitUpdate(myGuiElement, payload);
  12. Use the Scene component to manage Babylon.js scenes

    main

    The Scene component is the primary container for a Babylon.js scene within a Reactylon application. It initializes the Babylon Scene object, manages the engine connection, and provides a context for child components to interact with the scene, physics, and XR experiences.

    Key capabilities include:

    • Physics Integration: Configure gravity and physics plugins via physicsOptions.
    • WebXR Support: Enable default XR experiences using xrDefaultExperienceOptions.
    • GUI 3D Management: Enable the GUI3DManager by setting isGui3DManager to true.
    • Lifecycle Hooks: Use onSceneReady to perform actions once the Babylon scene is fully initialized.
    • Multi-Canvas/Scene Support: If using multiple canvases or scenes, the component handles input control and audio switching automatically when a canvas is clicked.
    import { Scene } from 'reactylon';
    
    function MyApp() {
      return (
        <Scene
          canvas={myCanvasElement}
          sceneOptions={{ /* Babylon SceneOptions */ }}
          onSceneReady={(scene) => {
            console.log('Scene is ready:', scene);
          }}
          physicsOptions={{
            gravity: new Vector3(0, -9.8, 0),
            plugin: myPhysicsPlugin
          }}
          xrDefaultExperienceOptions={{
            // WebXRDefaultExperienceOptions
          }}
          isGui3DManager={true}
        >
          {/* Your declarative Babylon.js components go here */}
        </Scene>
      );
    }