How to integrate the project exported from Babylon Editor into react

I am a react developer. And my task is to connect a project from Babylon Editor. In search of a solution to this problem, I found only one question (How to incorporate project.editorproject (from Babylonjs Editor export) into React project?) and not a single tutorial. There are a lot of questions, including how to integrate a project with a creatreact app. Babylon the editor supplies the typescript. Do I need to translate the entire project into typescript? It would be desirable to see an example of the integration of such a project.

Adding @julien-moreau the editor daddy to the rescue.

Hi @Pavel_Bero !
You are right the link your shared is outdated and is related to an old version of the editor.

Once you have created a project (empty, or whatever), the only thing to do is to transform the Game class as a React component. Here is a complete example with:

index.html:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Babylon.js Generated Template</title>

    <script src="./dist/bundle.js" type="text/javascript"></script>

    <style rel="stylesheet" type="text/css">
        html,
        body {
            overflow: hidden;
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }

        #gameContainer {
            position: absolute;
            width: 100%;
            height: 100%;
            top: 0;
            touch-action: none;
            -ms-touch-action: none;
        }

        #renderCanvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <div id="gameContainer"></div>

    <script type="text/javascript">
        game.initialize();
    </script>
</body>

</html>

game.tsx (previously game.ts):

import { render } from "react-dom";
import * as React from "react";

import "@babylonjs/materials";
import { BabylonFileLoaderConfiguration, Engine, Nullable, Scene, SceneLoader } from "@babylonjs/core";

import * as CANNON from "cannon";

import { runScene } from "./scenes/scene";

/**
 * Defines the function called in the index.html file that initializes the game
 * as a React component.
 */
export function initialize(): void {
    render(<Game />, document.getElementById("gameContainer"));
}

/**
 * The class now becomes a react component.
 */
export class Game extends React.Component {
    /**
     * Defines the engine used to draw the game using Babylon.JS and WebGL
     */
    public engine: Engine;
    /**
     * Defines the scene used to store and draw elements in the canvas.
     */
    public scene: Scene;

    private _canvasRef: Nullable<HTMLCanvasElement> = null;

    /**
     * Renders the component.
     */
    public render(): React.ReactNode {
        return (
            <canvas ref={(r) => this._canvasRef = r} id="renderCanvas" />
        );
    }

    /**
     * Called on the component did mount.
     */
    public componentDidMount(): void {
        if (!this._canvasRef) {
            throw new Error("Failed to get canvas reference.");
        }

        this.engine = new Engine(this._canvasRef, true);
        this.scene = new Scene(this.engine);

        this._bindEvents();
        this._load();
    }

    /**
     * Loads the first scene.
     */
    private _load(): void {
        const rootUrl = "./scenes/scene/";

        BabylonFileLoaderConfiguration.LoaderInjectedPhysicsEngine = CANNON;

        SceneLoader.Append(rootUrl, "scene.babylon", this.scene, () => {
            this.scene.executeWhenReady(() => {
                // Attach camera.
                if (!this.scene.activeCamera) {
                    throw new Error("No camera defined in the scene. Please add at least one camera in the project or create one yourself in the code.");
                }
                this.scene.activeCamera.attachControl(this.engine.getRenderingCanvas(), false);

                // Run the scene to attach scripts etc.
                runScene(this.scene, rootUrl);

                // Render.
                this.engine.runRenderLoop(() => this.scene.render());
            });
        }, undefined, (_, message) => {
            console.error(message);
        }, "babylon");
    }

    /**
     * Binds the required events for a full experience.
     */
    private _bindEvents(): void {
        window.addEventListener("resize", () => this.engine.resize());
    }
}

package.json (using webpack 5)

{
    "name": "babylonjs-editor-generated-template",
    "version": "4.1.0",
    "description": "Generated Template by BabylonJS Editor v4.1",
    "scripts": {
        "clean": "rimraf build declaration dist",
        "compile": "tsc -p .",
        "build": "webpack --mode production",
        "watch": "webpack --mode development --watch",
        "webserver": "http-server -p 1338 -c-1"
    },
    "license": "(Apache-2.0)",
    "devDependencies": {
        "@types/node": "17.0.0",
        "@types/webpack": "5.28.0",
        "@types/react": "17.0.37",
        "@types/react-dom": "17.0.11",
        "typescript": "4.5.4",
        "http-server": "0.12.1",
        "webpack": "5.65.0",
        "webpack-cli": "4.9.1",
        "ts-loader": "9.2.6",
        "raw-loader": "4.0.2",
        "babel-loader": "8.2.3",
        "babylonjs-editor-webpack-progress": "1.0.1"
    },
    "dependencies": {
        "rimraf": "3.0.2",
        "@babylonjs/core": "4.2.0",
        "@babylonjs/loaders": "4.2.0",
        "@babylonjs/materials": "4.2.0",
        "@babylonjs/post-processes": "4.2.0",
        "@babylonjs/procedural-textures": "4.2.0",
        "@babylonjs/gui": "4.2.0",
        "cannon": "0.6.2",
        "earcut": "2.2.3",
        "react": "17.0.2",
        "react-dom": "17.0.2"
    }
}

and the new webpack.config.js to include .tsx files support:

const path = require("path");
const webpack = require("webpack");
const editor = require("babylonjs-editor-webpack-progress");

module.exports = (_, argv) => {
	const entryPath = path.join(__dirname, "src/game.tsx");
	const package = require("./package.json");

	return {
		// we output both a minified version & a non minified version on production build
		entry: { "bundle": entryPath },
		output: {
			filename: `bundle.js`,
			path: path.join(__dirname, "dist"),
			library: "game",
			libraryTarget: "umd",
		},
		module: {
			rules: [
				{
					test: /\.ts(x?)?$/,
					loader: "ts-loader",
					exclude: [
						path.join(__dirname, "node_modules"),
						path.join(__dirname, "dist"),
						path.join(__dirname, "projects"),
						path.join(__dirname, "scenes"),
					],
				},
				{
					test: /\.fx?$/,
					loader: "raw-loader",
				},
			],
		},
		resolve: {
			extensions: [".ts", ".tsx", ".js"],
		},
		plugins: [
			new webpack.BannerPlugin({
				banner: `${package.name} ${package.version} ${new Date().toString()}`,
			}),
			new webpack.WatchIgnorePlugin({
				paths: [/\.js$/, /\.d\.ts$/],
			}),
			editor.createProgressPlugin(new webpack.ProgressPlugin()),
		],
		optimization: {
			minimize: false,
			usedExports: true,
		},
		devtool: "source-map",
	};
};

Don’t forget to add "jsx": "react" (or other) in the tsconfig.json to add the support of JSX in your project

2 Likes