Skip to content

World Tracking — Babylon.js

Integration of Monolook World with Babylon.js for surface detection and 3D content placement.

Requirements

  • Babylon.js loaded via CDN (window.BABYLON) or as npm module
  • Monolook World license key
  • HTTPS + Chrome on Android, or Monolook App / AppClip on iOS

HTML setup

html
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<canvas id="scene"></canvas>

Setup

js
import { Monolook } from 'monolook/world'

const BABYLON = window.BABYLON
const canvas  = document.getElementById('scene')

const engine = new BABYLON.Engine(canvas, true, {
  alpha: true,
  premultipliedAlpha: false,
  preserveDrawingBuffer: false,
  stencil: true,
})

const scene  = new BABYLON.Scene(engine)
scene.clearColor = new BABYLON.Color4(0.2, 0.2, 0.2, 1)
scene.useRightHandedSystem = true

const camera = new BABYLON.FreeCamera('camera', new BABYLON.Vector3(0, 1.2, 3), scene)
camera.minZ = 0.01
camera.maxZ = 100
camera.setTarget(BABYLON.Vector3.Zero())

const light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), scene)
light.intensity = 2.4

const cube = BABYLON.MeshBuilder.CreateBox('cube', { size: 0.35 }, scene)
cube.setEnabled(false)

const monolook = new Monolook({
  adapter: 'babylon',
  BABYLON,
  engine,
  scene,
  camera,
  domOverlayRoot: document.getElementById('dom_overlay'),
})

useRightHandedSystem = true is required for correct coordinate alignment.

Events and start

js
monolook.on('surfacefound', () => setStatus('Surface found — tap to place'))
monolook.on('select', placeCube)
monolook.on('sessionend', resetAfterSession)

await monolook.start({ mode: 'surface', licenseKey: '<WORLD_LICENSE_KEY>' })

cube.setEnabled(false)
monolook.startTracking()
monolook.setRenderLoop(() => monolook.updateTracking())
await monolook.enterAR()

Placement

js
function placeCube() {
  if (!monolook.isPresenting() || isPlaced) return
  const pose = monolook.getIndicatorPose()
  if (!pose?.visible) return

  isPlaced = true
  cube.position.set(pose.position.x, pose.position.y, pose.position.z)
  cube.setEnabled(true)
  monolook.pauseTracking()
  monolook.setIndicatorVisible(false)
}

Complete example

js
import { Monolook } from 'monolook/world'

const BABYLON = window.BABYLON
const canvas  = document.getElementById('scene')

const engine = new BABYLON.Engine(canvas, true, { alpha: true, premultipliedAlpha: false, stencil: true })
const scene  = new BABYLON.Scene(engine)
scene.clearColor = new BABYLON.Color4(0.2, 0.2, 0.2, 1)
scene.useRightHandedSystem = true

const camera = new BABYLON.FreeCamera('camera', new BABYLON.Vector3(0, 1.2, 3), scene)
camera.minZ = 0.01
camera.setTarget(BABYLON.Vector3.Zero())

new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), scene).intensity = 2.4

const cube = BABYLON.MeshBuilder.CreateBox('cube', { size: 0.35 }, scene)
cube.setEnabled(false)

const monolook = new Monolook({
  adapter: 'babylon',
  BABYLON, engine, scene, camera,
  domOverlayRoot: document.getElementById('dom_overlay'),
})

let isPlaced = false

monolook.on('surfacefound', () => !isPlaced && setStatus('Surface found — tap to place'))
monolook.on('select', placeCube)
monolook.on('sessionend', () => {
  isPlaced = false
  cube.setEnabled(true)
  scene.render()
})

async function startAR() {
  await monolook.start({ mode: 'surface', licenseKey: '<WORLD_LICENSE_KEY>' })
  isPlaced = false
  cube.setEnabled(false)
  monolook.startTracking()
  monolook.setRenderLoop(() => monolook.updateTracking())
  await monolook.enterAR()
}

function placeCube() {
  if (!monolook.isPresenting() || isPlaced) return
  const pose = monolook.getIndicatorPose()
  if (!pose?.visible) return

  isPlaced = true
  cube.position.set(pose.position.x, pose.position.y, pose.position.z)
  cube.setEnabled(true)
  monolook.pauseTracking()
  monolook.setIndicatorVisible(false)
}

document.getElementById('startButton').addEventListener('click', startAR)
window.addEventListener('pointerup', placeCube)
engine.runRenderLoop(() => { if (!monolook.isPresenting()) scene.render() })