Start Contributing to Babylon.js
Introduction
Babylon.js is maintained on GitHub, a web-based hosting service for version control using Git. This page introduces GitHub and everything needed to make changes or additions to Babylon.js, from tool installation to testing, along with a brief description of why these steps are necessary. The steps are intended to be OS-agnostic, allowing users to develop the same way on Windows, Mac, and Linux.
Pre-Requisites
- Reading the contribution guidelines.
- An ability to code in TypeScript. Babylon.js is written in TypeScript and then compiled and distributed in JavaScript.
- Know how to use a Command Line Interpreter (CLI), used to issue Git commands.
Install Git
A quick option for Windows and Mac is the Git Home Page, and for all three operating systems, the Git Book.
You then need to configure the installation with your details using a CLI. You can use the CLI built into your computer or one of the many specialized ones for Git (Git Clients). If you use Visual Studio Code, the Terminal is a built-in CLI and can be opened with Ctrl +' or Terminal > New Terminal on the menu.
In your CLI configure git globally with your user name and email:
git config --global user.name "John Doe"git config --global user.email johndoe@example.comFork from GitHub
If you do not already have one, open a GitHub account with your email address, sign in, and go to the Babylon.js repository to fork it using the top button.
;
Clone to Local
Now, in your forked Babylon.js repository, use the "Clone or Download" button to find your repository address:

If the CLI you are using accepts pasting, use the copy icon to the right of the address. This will save a lot of typing. If not, enter this in the CLI:
git clone _**your repository address**_
The cloning may take some time.
Now you have a local repository and a remote repository on GitHub.
From the folder where you cloned Babylon.js into you can simply change your directory to the local repository using:
cd Babylon.jsand then find the name of your remote repository with:
git remote -v
You should find that it is called origin because it is the source of the cloned local version. The local branch is called master because it is your primary Babylon.js branch.
When the time comes, this will allow you to push changes from your local repository to your GitHub repository using:
git push origin masterKeeping The Local Version Up To Date
When it comes time to request that your changes be pulled into the main Babylon.js repository, the only differences between your version and the main one should be the changes you made. Of course, other people are making changes as well, so you need to keep your local master up to date with the main version. The main version, often called the upstream version, is another remote that your local repository can link to.
To do this, add the main version as a remote named upstream, making sure your CLI is in the Babylon.js directory:
git remote add upstream https://github.com/BabylonJS/Babylon.js.gitUsing
git remote -vyou can check that all remotes are active.

Now before pushing your fully committed master to your origin you can pull the upstream (main) version into your master with
git pull upstream masterYou can pull from upstream at any time provided any changes you have made are committed.
Editing and Building
Before embarking on editing or adding to Babylon.js please make sure you are familiar with the contribution guidelines.
Please note that some of these are checked on submission automatically by software, including
- The addition of comments to your code as described in Contribute to the API;
- Consistent coding style (linting).
Editing with Visual Studio Code
Visual Studio Code is a straightforward IDE with Git integration and is available for all three operating systems. It is worth a try, even though you may already have a favorite or recommended IDE.
You can install VSCode from their site: https://code.visualstudio.com/
More on using VSCode with Babylon.js
VSCode Extensions
If you are using VSCode, the repository comes with a list of recommended extensions. If you want to be able to debug entirely in VSCode you will need to install those extensions.
Adding files
When in doubt about where your files should be added then raise an issue in the Babylon.js repository or ask on the forum.
Commit
This can be done in Visual Studio Code using the source control icon on the left toolbar or with (Ctrl + Shift + G). After testing, some files other than those you have added or edited will appear in the source control section of VSCode. These should not be committed. Once you are ready to push to your repository these changes should be discarded. Only files you have actually changed or added should be in the commit.

When using a Git Client you should also check that you are only committing those files you have added or edited and not those produced in any testing build.
When using a CLI, you need to add any files you have added or edited before committing them. So only add those files you have changed. The full path to the files from the current directory has to be used.
For example in the top directory
git add path to file/file1.ts path to file/file2.ts path to file/file3.tsgit commit path to file/file1.ts path to file/file2.ts path to file/file3.ts -m "Description of Changes"
and in the directory containing file1.ts, file2.ts, file3.ts
git add file1.ts file2.ts file3.tsgit commit file1.ts file2.ts file3.ts -m "Description of Changes"
Install Node.js and NPM
Node.js and npm can be installed from the Node.js home page.
Babylon.js currently requires Node.js >=20.11.0 <23.0.0 and npm >=8.0.0.
To check your npm and node versions after Node.js is installed:
npm --versionnode --versionThe Build
Run npm install in the main directory. This will install everything needed to get started with the repository.
It is recommended to run npm run build:dev before starting to work to make sure everything is in the right place.
Using VSCode? Install the recommended extensions and start Run and Watch Dev Host (Dev) to compile and get started with the esm dev host. To use the classic UMD-based development (and have the BABYLON namespace available), run CDN Serve and watch (Dev).
To build the dev sources, shaders, and assets, run npm run build:dev.
To start the dev host, run npm run serve -w @tools/dev-host. This will start the dev host in http://localhost:1338 and will run the code located in the dev-host's src folder.
Note that this will not start watching the sources in the dev folder and will only watch for changes in the dev host src folder.
To start watching the dev packages, run npm run watch:dev in a new terminal window. This will make sure to watch all changes in the dev packages, including changes to shaders and assets, like scss files, images, and so on.
Following is a list of quick ways to get started with certain tasks, both in VSCode and command line. A quick way of finding a VSCode task: Ctrl+P (or Command+P on Mac), type "task", press the space button, and select the task you want to run.
Run the Babylon server
Using VSCode:
- Run "Run and watch Dev Server" from the Run and Debug Menu, OR
- Open the Command Palette, type "Run Task", select "CDN Serve and watch (Dev)"
Using command line:
- run
npm run watch:dev(If you want to make changes to the dev packages. Otherwise runnpm run build:dev) - run
npm run serve -w @tools/babylon-serverin a new terminal window
The Babylon server offers 2 variants - js and ts. To load the js version (the default one) navigate to http://localhost:1337. To use the TS version navigate to http://localhost:1337/index-ts.html. The files to edit are sceneJs.js and sceneTs.ts in the source folder of the Babylon server package.
As described in the next section, the Babylon server also offers playground-snippet debugging.
Debug a playground snippet
To debug a snippet, run the localhost:1338 server in debug mode and add the snippet to the index. For example:
http://localhost:1338#IQN716#9
If you started the server in VSCode you will be able to debug the code straight in your IDE.
Note that the loader will react to changes in the hash (and will reload the scene), but will not save new data. To do that, run the playground itself.
Run the dev host
Using VSCode:
- Run "Run and watch dev host (Dev)" from the Run and Debug Menu, OR
- Open the Command Palette, type "Run Task", select "Run and watch Dev Host (Dev)"
Using command line:
- run
npm run watch:dev(If you want to make changes to the dev packages. Otherwise runnpm run build:dev) - run
npm run serve -w @tools/dev-hostin a new terminal window
Open http://localhost:1338 in your browser.
Run the playground
Using VS Code:
- In the Run and Debug Menu, choose "Launch Playground" (Or "Playground development", in case you are making changes to the Playground code itself), OR
- Open the Command Palette, type "Run Task", select "Playground Serve for core (Dev)" (Or if you are just developing the playground itself, select "Playground Serve (Dev)")
Using command line:
- run
npm run watch:dev(If you want to make changes to the dev packages. Otherwise runnpm run build:dev) - Run
npm run serve -w @tools/babylon-serverin a new terminal window - Run
npm run serve -w @tools/playgroundin a new terminal window
Shortcuts?
- Run
npx build-tools --command dev-watch --watch-assets --watch-declarations --serve(watch and serve in one command) - Run
npm run serve -w @tools/playgroundin a new terminal window
Open http://localhost:1338 in your browser.
Run the sandbox
Using VS Code:
- In the Run and Debug Menu, choose "Launch Sandbox" (Or "Sandbox development", in case you are making changes to the Sandbox code itself), OR
- Open the Command Palette, type "Run Task", select "Sandbox Serve for core (Dev)" (Or if you are just developing the sandbox itself, select "Sandbox Serve (Dev)")
Using command line:
- run
npm run watch:dev(If you want to make changes to the dev packages. Otherwise runnpm run build:dev) - Run
npm run serve -w @tools/babylon-serverin a new terminal window - Run
npm run serve -w @tools/sandboxin a new terminal window
Shortcuts?
- Run
npx build-tools --command dev-watch --watch-assets --watch-declarations --serve(watch and serve in one command) - Run
npm run serve -w @tools/sandboxin a new terminal window
Open http://localhost:1339 in your browser.
Run the GUI editor
Using VS Code:
- In the Run and Debug Menu, choose "Launch GUI Editor" (Or "GUI Editor development", in case you are making changes to the GUI Editor code itself), OR
- Open the Command Palette, type "Run Task", select "GUI Editor Serve for core (Dev)" (Or if you are just developing the GUI Editor itself, select "GUI Editor Serve (Dev)")
Using command line:
- run
npm run watch:dev(If you want to make changes to the dev packages. Otherwise runnpm run build:dev) - Run
npm run serve -w @tools/babylon-serverin a new terminal window - Run
npm run serve -w @tools/gui-editorin a new terminal window
Shortcuts?
- Run
npx build-tools --command dev-watch --watch-assets --watch-declarations --serve(watch and serve in one command) - Run
npm run serve -w @tools/gui-editorin a new terminal window
Open http://localhost:1341 in your browser.
Run the Smart Filter Editor
Using VS Code, either:
- In the Run and Debug Menu, choose "Smart Filter Editor development" and click "Start Debugging (F5)"
- Open the Command Palette, type "Run Task", select "Smart Filter Editor Serve"
Using command line:
- Run
npm run watch:assets:smart-filtersin a terminal - Run
npm run watch:source:smart-filtersin another terminal - Run
npm run serve -w @tools/smart-filters-editorin a third terminal
Open http://localhost:1346 in your browser.
Run tests
Using VSCode:
- In the Run and Debug Menu, choose "Run and Debug unit tests (Dev)" for the Vitest unit suite, or one of the validation test launch configurations for Playwright-based browser tests.
- Open the Command Palette, type "Run Task", and select "Run visualization tests (Dev)" or "Launch visualization test runner (Dev)".
Using command line:
- Run
npm run test:unitornpm run test:visualization - Run
npm run testto execute the default root unit-test run
Link a public project to an external one
The example is linking core. Change the package name to anything else if needed.
- Build the public package you want to link:
npx nx run babylonjs:build(or es6 -npx nx run @babylonjs/core:build)
- Run
npm link -w [PACKAGE-NAME]- for examplenpm link -w @babylonjs/core
In your other project:
- Make sure you are linking to the right version (or use semver ranges)
- Run
npm link [PACKAGE-NAME]- for examplenpm link @babylonjs/core
When making changes to the linked package, make sure to repeat the build steps. There is no need to link again until you reinstall the public library.
Notes:
- This process will be simplified soon.
- You can link any package, not only the public one. However, you cannot rename the package. so if you link @dev/core you will need to add @dev/core to the dependencies of the external project.
Add a dependency to a project
Run npm install packageName -w @namespace/package (add -D to define a dev-dependency)
The package.json of the project should be changed.
Note: there is a bug in npm that, in certain cases, installs the dependency but doesn't add it to the package.json file. Run the command twice if that happens.
Edit Code
Once the test task (npm run start) has been launched, any saved changes in the TypeScript or shader files will automatically rebuild the associated JavaScript files. Simply refresh your browser to see the changes take effect and begin debugging your new code.
Hint: You may need to refresh the code before adding back a new breakpoint.
Repository structure
The repository is a monorepo. Every package has its own package.json and can be used independently, taking its dependencies into account.
Packages under packages/dev can be compiled together using the root TypeScript build, and dependent packages will be rebuilt automatically when needed.
Most packages share the same basic structure:
- src folder holds typescript files and assets
- test folder holds tests (See Testing)
- dist folder holds compiled files, including sourcemaps and declarations, and assets (if configured)
- optional public folder for public assets that will be hosted when the package is served (only where applicable)
The build/watch/test scripts will take this structure into account.
All references during development are to the src folder of the packages, but all references during builds are to the dist folders. That means that, in order to compile a package, its dependents need to be compiled already. This is mainly handled by the build process and the watchers.
Dependencies are hoisted to the main directory, so the repository only has a single package lock file and a single node_modules directory.
NPM workspaces mean that you can execute any npm command on the entire repository, on a specific package, or on the root package.
To run a specific npm command on the entire repository, run npm <command> -ws.
To run a specific npm command on a specific package, run npm <command> -w <package>.
To run a specific npm command on the root package, run npm <command>.
Read more about node workspaces - https://docs.npmjs.com/cli/using-npm/workspaces
Naming convention
- npm packages are always lowercase kebab-case (i.e. gui-editor)
- directories are in camel case (i.e. guiEditor)
Types of packages
There are 3 different types of packages:
dev packages
Packages with their name starting with @dev. These are the main packages that will be used on day-to-day work with the repository.
Those packages will hold raw assets in their dist directory, and are ready to be consumed by any packer (like webpack or rollup).
Tools packages
Packages with their name starting with @tools. Those packages hold tools that use the main repository.
Tools are, for example, the playground, the sandbox, node and GUI editor.
Public packages
The public-facing packages live under packages/public. They are the packages published to npm and are the only ones not marked private in their package.json.
Running scripts
To run a script in a package, you can either run npm run scriptname in the package directory or npm run scriptname -w @namespace/package-name in the main directory. This is the recommended way of working.
For example, to build the dev core library you will run:
npm run build -w @dev/coreIn the main directory.
If a script is missing from the package.json, you can either add it (not forgetting to commit the change) or run the script in the package directory using npx. For example, to use the installed TypeScript (and not the globally installed one), you can run:
npx tsc ....In the specific project's directory.
The following scripts should be available for most if not all packages:
- build
- compile
- clean
- test
- format
- lint
- watch (serve on tools)
This is a work in progress. The scripts will be added to all packages. Please let @RaananW on the forums know if any script is missing from a specific package that you are trying to use.
Initial source build and watch
To compile the dev code once in order to get the latest compiled code run:
npm run build:devTo start a watcher that will watch the source code of the dev packages, run one of the following npm scripts:
"format:check"; // check formatting,"format:fix"; // fix formatting,"lint:check"; // check linting,"lint:fix"; // fix linting,format:check and lint:check will run during CI once we have an issue-free repository.
Dealing with assets
The dev and lts packages treat binary assets as files that will be part of their dist folder. When packing those assets, the packer can decide what to do with them (for example, by using url-loader or file-loader in webpack). The assets, which include binary media files and (s)css files, are watched and automatically copied/processed when the package is watched. To explicitly watch the assets in a specific project, run the build-tools "process assets" task (which will be fully documented later):
npx build-tools -c process-assets --isCore --watchin the directory of the specific project. There should also be a build:assets and watch:assets script in the package.json of every package.
Shaders are also considered assets. They are processed differently, but they use the same script. Processing a shader (.fx file) will result in a TypeScript file, which will be compiled as part of the library during the build process. When building, build:assets will be executed before compile:source. The build script will take care of that for you. For example, @dev/core has the following scripts:
"build": "npm run clean && npm run compile","precompile": "npm run compile:assets","compile": "npm run compile:source","compile:source": "tsc -b tsconfig.build.json","compile:assets": "build-tools -c process-assets --isCore",Formatting and lint
We have a global eslint and prettier configuration in the root of the repository. This unifies code structure and formatting throughout the repository. It is running on both .js and .tsx files.
When using VSCode, it is recommended to use both the Prettier formatter extension and the ESLint host in order to lint in real time.
To run the linter using the command line, run:
npm run lintConfiguration options
Most packages in the repository don't need any extra configuration to compile. However, in certain cases you may want to control the way the files are compiled and served. A good example is enabling HTTPS support or changing the standard port used for the Babylon server or the tools.
There are a few options to pass configuration to the different packages.
Command line arguments
Both the build tools (explained later) and webpack (which is used to serve our tools) accept command line arguments. The following will be examples, but not full documentation of the different options and commands. The full list of options can be found further down the page.
When running the dev watcher, you can specify which packages will be watched. Using the standard way of starting dev watching (npm run watch:dev), you can do one of two things to add packages to the watcher:
# option 1, extend the npm run watch:dev commandnpm run watch:dev -- --packages core,gui# option 2, run the dev watcher directly (watching sources and assets)npx build-tools --command dev-watch --watch-assets --packages core,guiThe same goes when running the serve command manually. For example, to enable production mode of the Babylon server:
# option 1, use the npm run commandnpm run serve -w @tools/babylon-server -- --env=mode=production# option 2 - use webpack directly in the Babylon server package directorynpx webpack serve --env=mode=productionIn this specific case you have the task npm run serve:prod as well.
Using a .env file
When running both the playground and the Babylon server you have two servers running locally. The playground is being served, and the CDN is served on a different address. If we want to configure both of the servers at the same time, we can use a .env file to extend the command line arguments.
To use a .env file create a file called .env in the base directory of the repository. This file will be used automatically.
Think about the .env file as a way to extend process.env. The first important thing we need to know is that it will only be available during build time, but not in compiled code. So parameters set there are available in building scripts and in the build tools, but not in a .tsx file in the playground source directory. The variables are available globally.
To set a command line argument using the .env file, convert the parameter's name to upper case, and replace all - with _. For example, to set the packages from the example above, add this line to the .env file:
PACKAGES="core,gui"To always watch assets when running the dev watch you can set the following in your .env file:
WATCH_ASSETS=trueTo enable hot reload (another option existing in the webpack-enabled packages), add this line to the .env file:
ENABLE_HOT_RELOAD=trueENABLE_LIVE_RELOAD=trueTo set all (webpack) builds to production mode, set the following in the .env file:
NODE_ENV=productionOther optional variables you can set in the .env file are:
TOOLS_PORT=1338 # port for tools like the playground or the node editorCDN_PORT=1337 # port for the Babylon serverCDN_BASE_URL="https://cdn.babylonjs.com" # base URL for the CDN. Defaults to localhost:1337. Useful if you want to test against a snapshot or the stable nightlyENABLE_HTTPS=true # enable HTTPS for the Babylon server. Useful for WebXRENABLE_DEV_OVERLAY=true # shows the react dev overlayNote that the .env file should never be updated on the repository. It is ignored by git.
To get the list of all the available options in each command, find it in this documentation page.
Project linking
Projects' dependencies are defined in their package.json. However, when using dev or lts packages you can use a direct reference to the files instead of using the npm package itself. That means that you can (and should!) import directly from the needed library using its basic development package name. For example, these are the imports in the inspector (advancedDynamicTextureTreeItemComponent.tsx):
// load from coreimport { Nullable } from "core/types";import { Observer, Observable } from "core/Misc/observable";import { IExplorerExtensibilityGroup } from "core/Debug/debugLayer";
// load from guiimport { Control } from "gui/2D/controls/control";import { AdvancedDynamicTexture } from "gui/2D/advancedDynamicTexture";Using the dev package names (defined in the build tools) keeps local development pointed at the monorepo sources instead of published packages.
Serving the repository
There are two basic ways to use the dev code:
Dev Host
The dev host allows you to write code using TypeScript or JavaScript, pack it with webpack, and serve it in your browser. The only file that should not be renamed is index.ts, which is the main entry file.
The dev host is similar to the ES6 packages we offer—everything must be imported, and no BABYLON namespace is available. If you want to test a playground scene, see the Babylon server section below.
To run the dev host you execute the following command:
npm run serve -w @tools/dev-hostThis will start watching the dev-host src folder and will run the code in the dev-host's src folder.
When loading from the different packages in the dev host you will use the package from which you are loading. For example, if you load the scene object from the dev core package, you will use:
import { Scene } from "@dev/core";It is important to stay consistent when importing, i.e. not to mix published @babylonjs/* packages with local @dev/* packages for the same code path, as TypeScript will treat them as different copies.
The dev host is configured to be much more forgiving when developing. The best example is the noImplicitAny rule, which is set to false. This is done mainly so you can load .js files as well as TypeScript files. This is the reason the allowJs flag is set to true.
The current simple structure of the dev host allows you to copy code from the playground and make the changes needed to run it in the dev host. For example, this playground:
import { FreeCamera } from "@babylonjs/core/Cameras/freeCamera";import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight";import { Vector3 } from "@babylonjs/core/Maths/math.vector";import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder";import { Scene } from "@babylonjs/core/scene";const createScene = function () { // This creates a basic Babylon Scene object (non-mesh) const scene = new Scene(engine); // This creates and positions a free camera (non-mesh) const camera = new FreeCamera("camera1", new Vector3(0, 5, -10), scene); // This targets the camera to scene origin camera.setTarget(Vector3.Zero()); // This attaches the camera to the canvas camera.attachControl(canvas, true); // This creates a light, aiming 0,1,0 - to the sky (non-mesh) const light = new HemisphericLight("light", new Vector3(0, 1, 0), scene); // Default intensity is 1. Let's dim the light a small amount light.intensity = 0.7; // Our built-in 'sphere' shape. const sphere = MeshBuilder.CreateSphere("sphere", { diameter: 2, segments: 32 }, scene); // Move the sphere upward 1/2 its height sphere.position.y = 1; // Our built-in 'ground' shape. const ground = MeshBuilder.CreateGround("ground", { width: 6, height: 6 }, scene); return scene;};translates to this:
import { canvas, engine } from "./index";import { FreeCamera, HemisphericLight, MeshBuilder, Scene, Vector3 } from "@dev/core";
export const createScene = function () { // This creates a basic Babylon Scene object (non-mesh) const scene = new Scene(engine);
// This creates and positions a free camera (non-mesh) const camera = new FreeCamera("camera1", new Vector3(0, 5, -10), scene);
// This targets the camera to scene origin camera.setTarget(Vector3.Zero());
// This attaches the camera to the canvas camera.attachControl(canvas, true);
// This creates a light, aiming 0,1,0 - to the sky (non-mesh) const light = new HemisphericLight("light", new Vector3(0, 1, 0), scene);
// Default intensity is 1. Let's dim the light a small amount light.intensity = 0.7;
// Our built-in 'sphere' shape. const sphere = MeshBuilder.CreateSphere("sphere", { diameter: 2, segments: 32 }, scene);
// Move the sphere upward 1/2 its height sphere.position.y = 1;
// Our built-in 'ground' shape. MeshBuilder.CreateGround("ground", { width: 6, height: 6 }, scene);
return scene;};A simpler way to do that would be to load the entire @dev/core package as BABYLON:
import { canvas, engine } from "./index";import * as BABYLON from "@dev/core";
export const createScene = function () { // This creates a basic Babylon Scene object (non-mesh) const scene = new BABYLON.Scene(engine);
// This creates and positions a free camera (non-mesh) const camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
// This targets the camera to scene origin camera.setTarget(BABYLON.Vector3.Zero());
// This attaches the camera to the canvas camera.attachControl(canvas, true);
// This creates a light, aiming 0,1,0 - to the sky (non-mesh) const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
// Default intensity is 1. Let's dim the light a small amount light.intensity = 0.7;
// Our built-in 'sphere' shape. const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 2, segments: 32 }, scene);
// Move the sphere upward 1/2 its height sphere.position.y = 1;
// Our built-in 'ground' shape. BABYLON.MeshBuilder.CreateGround("ground", { width: 6, height: 6 }, scene);
return scene;};The catch here is that this is not the actual BABYLON namespace, this is just the core namespace and will not include the loaders, for example, even if imported.
This is an extended example of how to use the dev host to integrate GUI, Loaders and the inspector:
import { canvas, engine } from "./index";import "@dev/loaders";import { Inspector } from "@dev/inspector";import { ArcRotateCamera, CubeTexture, Scene, AppendSceneAsync } from "@dev/core";import { AdvancedDynamicTexture, Button } from "@dev/gui";
export const createScene = async function () { const scene = new Scene(engine); scene.createDefaultCameraOrLight(true); const hdrTexture = new CubeTexture("https://playground.babylonjs.com/textures/SpecularHDR.dds", scene); scene.createDefaultSkybox(hdrTexture, true, 10000);
// The first parameter can be used to specify which mesh to import. Here we import all meshes AppendSceneAsync("https://assets.babylonjs.com/meshes/webp/webp.gltf", scene).then((result) => { scene.activeCamera!.attachControl(canvas, false); // scene.activeCamera!.alpha += Math.PI; // camera +180° (scene.activeCamera as ArcRotateCamera).radius = 80; });
const advancedTexture = AdvancedDynamicTexture.CreateFullscreenUI("UI");
const button1 = Button.CreateSimpleButton("but1", "Click Me"); button1.width = "150px" button1.height = "40px"; button1.color = "white"; button1.cornerRadius = 20; button1.background = "green"; button1.onPointerUpObservable.add(function() { alert("you did it!"); }); advancedTexture.addControl(button1);
Inspector.Show(scene, {});
return scene;};The dev host is configured with hot reload and live reload, making sure that if you change any file in the dev host source directory, the dev host will update (or reload) the page. However, it will not react to changes to the source code in the dev packages, as it is using the compiled version of the dev packages.
If you want to watch the source code of the dev packages, you will need to start the watcher manually or use the configured VSCode tasks (more on that later). Using VSCode is recommended, but not required.
To compile the dev code once in order to get the latest code in the dev host see "Initial source build and watch".
Note about the dev host: it does not use best practices for production code. It is a tool for developing with the dev packages and is not meant to be used in production.
Babylon Server
The Babylon server is a direct copy of the Babylon CDN structure. It serves JavaScript files, along with sourcemaps and declarations.
Similar to the dev host, the Babylon server will take the latest compiled code from the current monorepo packages and serve it to the browser. The default address for the local CDN is http://localhost:1337.
The Babylon server's index.html has references to all of our public packages and has the BABYLON namespace populated, similar to how the playground works. If you want to debug a playground scene without starting the playground, edit the files sceneJs.js or sceneTs.ts in the babylon-server package and open http://localhost:1337/index.html or http://localhost:1337/index-ts.html.
To start the Babylon server, run:
npm run serve -w @tools/babylon-serverThis will start a new server on port 1337 and will host all the needed files, including a very simple index.html file to make sure the CDN is working.
The babylon-server package also serves all other files needed for tools like the playground to work correctly. It hosts the physics engine, earcut, the draco decoder, and more. See the public directory in the babylon-server package to see what files are available. Those files are served as static files.
As with the dev host, if you want to watch the source code of other packages, you will need to run the watcher/compile manually or use the configured VS Code tasks (more on that later). Using VSCode is recommended, but not required. See "Initial source build and watch" for dev code compilation and watch.
The Babylon server can be used wherever the compiled packages are needed, like the playground.
In order to use the Babylon server, run the Babylon server (npm run serve -w @tools/babylon-server), and start the playground in a different terminal. As always, there is a VS Code task and launch configuration for the playground.
A few notes:
- Regarding performance - minified code loads faster (or at least SHOULD load faster). Meaning that running the server in production mode (using
npm run serve:prod -w @tools/babylon-server) will help running code relying on the compiled packages faster. However, the actual build of the server will be roughly 2x slower than the dev build. If you want to use the server in order to work on tools like the GUI editor or the playground (working on and not with - i.e. editing those packages' code), it is recommended to run the Babylon server in production mode. - Regarding the packages created by babylon-server - The packages generated by the server are very similar to the public UMD packages, but they are not entirely the same. The babylon-server is not meant to be used in production! It is just a development tool.
As with any webpack-hosted package, there are a few properties that can be configured (using either the CLI or the .env file, as discussed above):
- mode: the type of build you will use. This can be either 'production' or 'development'. The default is 'development'.
- cdnPort: the port that the Babylon server will be hosted on. The default is 1337.
- enableHttps: whether or not to use https. The default is false.
- enableHotReload: whether or not to enable hot reload. The default is false. It is never enabled in production mode.
- enableLiveReload: whether or not to enable live reload. The default is false. It is never enabled in production mode.
Tools
We have several tools that we are hosting for our users. All of them (playground, sandbox, node editor and the GUI editor) are using the same architecture when it comes to referencing the core library - they use our UMD packages (the files that are hosted on our CDN). This is why, in order to get them to work you need to make sure the Babylon server is running in the background. See Babylon Server for more information.
All tools are packed and served with webpack, and are configured similarly.
To start the tools use the serve command:
npm run serve -w @tools/package-nameMost packages will work the same and are therefore not fully documented.
Notes:
- If the playground is served using HTTPS, the Babylon server must be HTTPS-Enabled as well.
- To load the dist files (and avoid using the babylon-server) add ?dist=true to the url.
- Local ports vary by tool. Use the relevant section above or the VS Code launch configuration for the exact URL.
Playground
The playground is not a public package, but is served on https://playground.babylonjs.com. It is a tool for developers to test their code and see how it works.
In order for it to work during production you will need to have a running Babylon server or use the dist query parameter.
To start the playground:
npm run serve -w @tools/playgroundThere are VS Code tasks that will allow you to both start the playground for playground development and to start the dev package watcher to also watch the dev packages. The first option is meant for developers working on the playground package, and the other is meant for developers of dev packages that want to test them on the playground.
Notes:
- when importing files from core, reference the
@dev/corepackage without setting the directory. The reason is that the class will eventually be loaded from the BABYLON namespace, available in the playground. - It is probably quicker to test your changes in the dev host instead of the playground.
Debugging
Every package at every stage can be fully debugged using either the browser (Chrome recommended) or the VS debugger.
To start the debugger using VS Code use the launch task you want to debug and run it. Note that it might take a little while for VS Code to initially load the files that it is debugging.
All packages are built with sourcemaps (when not in production mode), so opening the browser and choosing the file to debug will let you debug using TypeScript sources.
Unit tests can be debugged as well using the VS Code debugger. The built-in Vitest launch configurations run without file parallelism, which makes breakpoints predictable. Set the breakpoint beforehand and run the tests. The initial run might take some time, but once the debugger is connected it will stop at that breakpoint.
Contact us in the forum with any issues regarding debugging.
Until we fix all of the ESlint issues, make sure to press "Debug anyways" when running VS Code debugger tasks.
Watchers
See build-tools dev watcher
Adding a new package
To add a new package, follow the steps below:
- Choose the location of the package
- Add a new directory in the package category
- Add a package.json (you can copy a similar one from a different package). Make sure the package is marked "private" if it's not to be published.
- make sure you name your package correctly (i.e. @tools/package-name)
- Add your code using the schema described above (src for sources and assets, test for tests, etc.)
To install new dependencies to the package you can either add them to the package.json manually, or run npm install package-to-install -w @namespace/package-name in the package directory. Add -D to the command if you want to install dev dependencies.
Once this is done you can use this package in the workspace (using the -w argument when running npm commands).
You can reference this package in other packages to link them together. Once this is done (the package is added to the dependency list of another local package) it will be available in node_modules.
Building
To build each and every package available in the repository, run npm run build -w @namespace/package-name. There is, however, a quicker and more efficient way of building a package that has dependencies.
nx is integrated into the repository and can be used as a local build orchestrator to run builds much faster. When running an npm script using nx, it will automatically run the same command in local dependencies and in the right order. For example, when building a public package such as babylonjs-gui using npx nx run babylonjs-gui:build, nx will add the required dependent projects to the sequence automatically.
It will run the build in sequence (because of the predefined dependencies), but will skip building a package if it hasn't changed since the last build call. So calling npx nx run babylonjs:build will build the projects needed for that target and reuse anything that is already up to date when another package depends on it.
This should be used only when you want to build the public packages in the repository, and it will mainly be used by the CI. However, nx is available to you and is a very powerful tool. In the future, we might integrate it more deeply into the repository. To read more about nx: https://nx.dev/getting-started/intro
Testing
There are 3 types of tests configured in the repository:
- unit (Vitest)
- visualization (Playwright)
- integration (Playwright)
Each package can have a "test" folder with a specific structure. The structure of the test folder will allow tests to run automatically in the entire repository (and in a single package). The structure is as follows:
- unit tests are located in
test/unit.
All files must follow this schema:
(.*).test.{ts, tsx}, for example - materials.test.ts
At the repository level, the Vitest unit project automatically picks up files matching packages/**/test/unit/**/*.test.{ts,tsx}.
The default unit-test environment is node. When a unit test needs DOM APIs, switch the file to jsdom by adding a comment at the first line of the file. For example:
/** * @vitest-environment jsdom */This enables jsdom for that file and makes window and document available in the test. Browser-based visualization and integration tests run separately through Playwright rather than through the Vitest unit project.
Test results can be seen on the console. In CI, Vitest also emits a junit.xml report for test reporting.
Visualization tests will generate a report if any test failed. The report will open automatically after running the tests.
To run the repository's unit-test suite from the root, run npm run test or npm run test:unit in the main directory.
We are testing unit suites using Vitest. To learn more about the test runner and its API, read the Vitest documentation - https://vitest.dev/guide/
Unit testing
Apart from what's written before, there are a few things that need to be observed when writing unit tests.
- Unit tests are meant to test a specific unit or module. Anything else should be mocked. To read more about Vitest mocking, see https://vitest.dev/guide/mocking.html
- If you are testing the connection between two or more modules it is not a unit test and should probably be an integration test.
- Do not use browser-based Playwright tests as a substitute for unit tests. If
nodeis not enough, prefer@vitest-environment jsdombefore moving to visualization or integration coverage. - jsdom does not allow adding script tags to the DOM. Anything that needs to be added externally must be mocked.
To run all unit tests, run npm run test:unit from the repository root.
To run a specific unit test file, pass its path to Vitest from the repository root:
npm run test:unit -- packages/dev/core/test/unit/Math/babylon.math.vector.test.ts
To run tests matching part of the test name, use Vitest's -t filter:
npm run test:unit -- -t "material"
To debug the current test file from VS Code, use the "Run and Debug current unit test file (Dev)" launch configuration.
Visualization tests
Before running the visualization tests, you'll need to start the local server:
npm startRun all visualization tests (WebGL1, WebGL2 and WebGPU) using npm run test:visualization in the main directory.
Before your first test run
The tests are run using Playwright.
If you haven't already installed Playwright's browsers, please do so by running npx playwright install.
Running all tests
To run all visualization tests run npm run test:visualization in the main directory.
If you want to run only one specific engine, add the following:
npm run test:visualization -- --project="webgl2"If any error occurs during the test, the tests will continue and will eventually generate a report with all the failed tests. The report will open automatically after the tests are done.
You can stop the execution and still see the report (if any tests failed) by pressing Ctrl+C.
Adding a new test
To add a new test to the visualization tests, add the test data to packages/tools/tests/test/visualization/config.json
The best way to do that is to first create a playground, save it (using a local version of the playground, for example), and then add it at the end of the config file:
//...,{ "title": "My new visualization test", // the title of the test "playgroundId": "#ABCDEF#12", // the playground snippet id "referenceImage": "nameOfReferenceImage.png", // a name for the image snapshot that will be generated. Optional! "excludedEngines": ["webgl1"], // optional lists of engine you don't want the test to run on "renderCount": 2, // optional, the number of frames the scene should render. Default is 1. Good for animated scenes.},//...To generate the snapshot, run the test once. The simplest would be to open the UI and run the test. The snapshot will be generated in the tests/test/visualization/snapshots folder. Make sure to add the snapshot to the repository. See the next section to know how to run a single test.
Running specific tests
The recommended way to run a specific test is to use the UI. To do that run
npm run test:visualization:uiThis will show you the tests for all 3 engines and you will be able to run them one by one.
If you want to display only one specific engine, add the following:
npm run test:visualization:ui -- --project="webgl2"This will only show the tests for the webgl2 engine.
Note that when making changes to the list of tests the UI will reload to show it. So you can update the JSON while the UI is loaded without the need to run it again.
If you don't want to use the UI you can run an individual test by providing its title:
npm run test:visualization -- --project="webgl2" -g "Title Of The Test"Guidelines
A reminder to read the contribution guidelines.
Pull-Request
Pull Requests are automatically validated with linting and testing.
When you are happy that all testing has been validated, the guidelines have been followed, and only the necessary files have been committed, then push your local master to your origin GitHub repository with your Git client or from the CLI with:
git push origin masterOnce this has succeeded, visit your Babylon.js repository. If all your commits are ahead of the upstream Babylon.js:master, you can issue a pull request using the Contribute button shown below and follow the steps:

If some of your commits are behind the upstream Babylon.js:master, then you will need to run:
git pull upstream masterand then push into your repository again.
Check for Success
Once your pull-request has been issued, it needs to be checked, reviewed, approved, and merged. Find your pull-request in the list and open it:

Scroll down to the review panel. If there are any failures, a red cross indicates the area of failure. Click on details for more information:

Then click on the link under "Build job failed" to be taken to an Azure Pipelines page where you can see the output of your build job and understand better why it failed:


For any failures re-edit your local files, commit and push to your repository. The alterations will be automatically added to your pull-request and it will be re-checked.
It's Live
Once your pull-request has been merged, it will become live once the changes have been deployed into the Preview Release, usually overnight, though sometimes delayed by a couple of days.
Summary
App Install
Node.js and Git
Fork and Clone

Name Remotes and Pull

Local Install
npm installLocal Build and Serve
Using VSCode? Install the recommended extensions and start Run and Watch Dev Host (Dev) to compile and get started with the esm dev host. To use the classic UMD-based development (and have the BABYLON namespace available), run CDN Serve and watch (Dev).
To build the dev sources, shaders, and assets, run npm run build:dev.
To start the dev host, run npm run serve -w @tools/dev-host. This will start the dev host in http://localhost:1338 and will run the code located in the dev-host's src folder.
Note that this will not start watching the sources in the dev folder and will only watch for changes in the dev host src folder.
To start watching the dev packages, run npm run watch:dev in a new terminal window. This will make sure to watch all changes in the dev packages, including changes to shaders and assets, like scss files, images, and so on.
Edit
Change and save files including comments.
Test
Check if your code can be used in the local playground.
Success
Commit files you have added or edited but not those built.
Push Pull-Request Check
