Skip to content

Hello world with Babylon.js ​

This tutorial will guide you through creating a simple 3D scene using Babylon.js in JSAR.

Step 1: Create a new HTML file ​

Create a new HTML file and add the following code:

html
<html>
<head>
  <meta charset="utf-8">
  <title>My first Babylon.js app</title>
</head>
<body>
  <script type="module" src="/main.js"></script>
</body>
</html>

Step 2: Specifiy the Babylon.js importmap ​

Specify the Babylon.js importmap in the HTML file:

html
<html>
<head>
  <meta charset="utf-8">
  <title>My first Babylon.js app</title>
  <script type="importmap">
    {
      "imports": {
        "babylonjs": "http://ar.rokidcdn.com/web-assets/yodaos-jsar/dist/babylon/umd/babylonjs/babylon.js",
        "babylonjs-gltf-loader": "http://ar.rokidcdn.com/web-assets/yodaos-jsar/dist/babylon/umd/babylonjs-loaders/babylon.glTFFileLoader.js"
      }
    }
  </script>
</head>
<body>
  <!-- ... -->
</body>
</html>

Note that, to use Babylon.js in JSAR's multiview stereo rendering, you will need to use the Babylon.js version provided by JSAR as shown above.

Step 3: Create a Babylon.js scene ​

Create a new file named main.js and add the following code:

js
import 'babylonjs';
import 'babylonjs-gltf-loader';

async function createScene(engine) {
  const scene = new BABYLON.Scene(engine);
  scene.autoClear = false;
  scene.autoClearDepthAndStencil = false;
  scene.blockMaterialDirtyMechanism = true;
  scene.performancePriority = BABYLON.ScenePerformancePriority.Intermediate;

  scene.createDefaultSkybox();
  scene.createDefaultCamera(true);

  // Run the render loop
  engine.runRenderLoop(() => scene.render());
  return scene;
}

let engine;
if (!navigator.gl) {
  const canvas = document.createElement('canvas');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  document.body.appendChild(canvas);
  engine = new BABYLON.Engine(canvas, true, {
    xrCompatible: true
  });
} else {
  engine = new BABYLON.Engine(navigator.gl, true, {
    xrCompatible: true
  });
}
engine.disableUniformBuffers = true;

createScene(engine).then(scene => {
  scene.createDefaultLight();

  // Your scene initialization code here
});

Note that, in JSAR, the canvas element is not available in the WebGLRenderer constructor. Instead, you can use the navigator.gl object to get the WebGL context.

Step 4: Load a 3D model ​

Next, use BABYLON.SceneLoader to load a 3D model into the scene:

js
createScene(engine).then(scene => {
  scene.createDefaultLight();

  // Append glTF model to scene.
  BABYLON.SceneLoader.Append("https://ar.rokidcdn.com/web-assets/pages/models/", "floating_fox.glb", scene, () => {
    // Loaded
    console.info('Model loaded', scene.meshes);
  });
});

Step 5: Fit the size ​

After you have initialized the scene, it's better to fit the scene size to the proper size, like this:

js
function fitTo(root, targetSize = 1) {
  const boundingVectors = root.getHierarchyBoundingVectors(true);
  const totalSize = boundingVectors.max.subtract(boundingVectors.min);
  const scalingFactor = Math.min(targetSize / totalSize.x, targetSize / totalSize.y, targetSize / totalSize.z);
  root.scaling.multiplyInPlace(new BABYLON.Vector3(scalingFactor, scalingFactor, scalingFactor));
}

Then, call the fitTo function after you have added the cube to the scene:

js
fitTo(scene.rootNodes[0], 0.3);

The above code will fit the scene to the size of 0.3 meters in the host world space.

Step 6: Create XR content ​

Unlike Three.js, you don't need to use navigator.xr directly to request an XR session. Instead, you should use the related Babylon.js APIs to create XR content. Here is an example:

js
async function createScene(engine) {
  const scene = new BABYLON.Scene(engine);
  // ...

  // Create XR experience and enter XR
  const { baseExperience, renderTarget } = await scene.createDefaultXRExperienceAsync({
    disableDefaultUI: true,
    disablePointerSelection: true,
    disableNearInteraction: true,
    disableHandTracking: true,
    disableTeleportation: true,
    outputCanvasOptions: {
      renderingContext: navigator.gl,
    },
  });
  await baseExperience.enterXRAsync('immersive-ar', 'local', renderTarget, {
    optionalFeatures: [],
  });
  return scene;
}

Step 7: Run the app ​

Now you can run the app in the JSAR environment, follow the instructions in the Quick Start / Run guide to run the HTML in your device.

Summary ​

The following is the complete code for the HTML and JavaScript files

js
<html>
<head>
  <meta charset="utf-8">
  <title>My first Babylon.js app</title>
  <script type="importmap">
    {
      "imports": {
        "babylonjs": "http://ar.rokidcdn.com/web-assets/yodaos-jsar/dist/babylon/umd/babylonjs/babylon.js",
        "babylonjs-gltf-loader": "http://ar.rokidcdn.com/web-assets/yodaos-jsar/dist/babylon/umd/babylonjs-loaders/babylon.glTFFileLoader.js"
      }
    }
  </script>
</head>
<body>
  <script type="module" src="/main.js"></script>
</body>
</html>
js
import 'babylonjs';
import 'babylonjs-gltf-loader';

async function createScene(engine) {
  const scene = new BABYLON.Scene(engine);
  scene.autoClear = false;
  scene.autoClearDepthAndStencil = false;
  scene.blockMaterialDirtyMechanism = true;
  scene.performancePriority = BABYLON.ScenePerformancePriority.Intermediate;

  scene.createDefaultSkybox();
  scene.createDefaultCamera(true);

  // Run the render loop
  engine.runRenderLoop(() => scene.render());

  // Create XR experience and enter XR
  const { baseExperience, renderTarget } = await scene.createDefaultXRExperienceAsync({
    disableDefaultUI: true,
    disablePointerSelection: true,
    disableNearInteraction: true,
    disableHandTracking: true,
    disableTeleportation: true,
    outputCanvasOptions: {
      renderingContext: navigator.gl,
    },
  });
  await baseExperience.enterXRAsync('immersive-ar', 'local', renderTarget, {
    optionalFeatures: [],
  });
  return scene;
}

let engine;
if (!navigator.gl) {
  const canvas = document.createElement('canvas');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  document.body.appendChild(canvas);
  engine = new BABYLON.Engine(canvas, true, {
    xrCompatible: true
  });
} else {
  engine = new BABYLON.Engine(navigator.gl, true, {
    xrCompatible: true
  });
}
engine.disableUniformBuffers = true;

function fitTo(root, targetSize = 1) {
  const boundingVectors = root.getHierarchyBoundingVectors(true);
  const totalSize = boundingVectors.max.subtract(boundingVectors.min);
  const scalingFactor = Math.min(targetSize / totalSize.x, targetSize / totalSize.y, targetSize / totalSize.z);
  root.scaling.multiplyInPlace(new BABYLON.Vector3(scalingFactor, scalingFactor, scalingFactor));
}

createScene(engine).then(scene => {
  scene.createDefaultLight();

  // Append glTF model to scene.
  BABYLON.SceneLoader.Append("https://ar.rokidcdn.com/web-assets/pages/models/", "floating_fox.glb", scene, () => {
    // Loaded
    console.info('Model loaded', scene.meshes);
    fitTo(scene.rootNodes[0], 0.3);
  });
}).catch(err => {
  console.error(err);
});

Apache 2.0 License.
Built with ❤️ using Trae 2.0.