Skip to content
Babylon.js Getting Started — Build Your First 3D Scene in the Browser

Babylon.js Getting Started — Build Your First 3D Scene in the Browser

DodaTech Updated Jun 6, 2026 12 min read

Babylon.js is a powerful, open-source 3D engine that runs in your browser. This tutorial teaches you the core building blocks — engine, scene, camera, lights, meshes, materials, and the render loop — so you can create your first interactive 3D scene from scratch.

What You’ll Learn

By the end of this tutorial, you’ll set up a Babylon.js engine and scene, add and position 3D objects (boxes, spheres, cylinders, toruses), control an orbiting camera, light your scene with multiple light types, apply colors and materials, and run the render loop to create real-time 3D graphics in a browser.

New to 3D programming? No problem. This guide explains every 3D concept using everyday analogies. You just need basic HTML and JavaScript knowledge.

Why 3D in the Browser Matters

Websites used to be flat. Text, images, buttons — all on a 2D plane. But modern applications are increasingly three-dimensional: product viewers that let you rotate a car in 360°, architectural walkthroughs of buildings before they’re built, data visualizations that show complex relationships in 3D space, and interactive games that run without downloads.

Babylon.js makes all of this possible using WebGL and WebGPU — technologies built into every modern browser. No plugins, no installations. Your users just open a URL and see 3D.

Real-world use: Durga Antivirus Pro uses Babylon.js for its 3D threat visualization dashboard. When a network attack is detected, it renders the affected systems as 3D nodes with glowing connections, letting security analysts see the attack path in real time rather than reading through log files.

Where This Fits in Your Learning Path

    flowchart LR
    A["JavaScript & Web Basics"] --> B["**Babylon.js Getting Started**"]
    B --> C["Materials & Textures"]
    C --> D["Animation & Physics"]
    D --> E["GUI & Interaction"]
    E --> F["Importing & Assets"]
    style B fill:#f97316,stroke:#c2410c,color:#fff
    style A fill:#e5e7eb,stroke:#9ca3af,color:#374151
    style F fill:#22c55e,stroke:#16a34a,color:#22c55e
  

What is a 3D Engine?

Imagine you’re a film director. You need:

  • A stage (Scene) — where everything happens
  • A camera — how the audience sees the scene
  • Lights — so the audience can see the actors
  • Actors (Meshes) — the 3D objects in the scene
  • A camera crew (Render Loop) — capturing each frame 60 times per second

Babylon.js provides all of these. Your job is to arrange them.

The Engine and Scene

The Engine connects your code to the GPU. It handles rendering, window resizing, and WebGL context creation. You create one engine per canvas.

The Scene is a container for everything visual. Think of it as a folder that holds all your 3D objects, lights, and cameras.

const canvas = document.getElementById('renderCanvas')
const engine = new BABYLON.Engine(canvas, true, {
  preserveDrawingBuffer: true,
  stencil: true,
})
const scene = new BABYLON.Scene(engine)
scene.clearColor = new BABYLON.Color3(0.08, 0.08, 0.12) // dark background

Why stencil: true? You need it for shadows and advanced effects later. Enable it now even if you don’t use it immediately — it’s hard to add later.

Why preserveDrawingBuffer: true? Required for taking screenshots of your canvas. Turn it off for performance in production if you don’t need screenshots.

Cameras — How the User Sees the Scene

A camera defines the viewpoint. Without one, you’d see nothing. Babylon.js offers several types.

ArcRotateCamera (the most useful for beginners): This camera orbits around a target point. Drag to rotate, scroll to zoom. Think of it like a camera on a crane that always points at the center of the action.

const camera = new BABYLON.ArcRotateCamera(
  'camera1',
  -Math.PI / 2,  // alpha — horizontal angle (left/right)
  Math.PI / 3,   // beta — vertical angle (up/down)
  10,            // radius — distance from target
  new BABYLON.Vector3(0, 2, 0),  // target — what it looks at
  scene
)
camera.attachControl(canvas, true) // enable mouse/touch control

Camera types at a glance:

CameraBest ForControls
ArcRotateCameraOrbiting a modelDrag to rotate, scroll to zoom
FreeCameraFirst-person walkthroughWASD + mouse look
UniversalCameraCross-platform gamesWASD + gamepad + touch

Lights — Without Light, Everything is Black

In 3D rendering, objects reflect light. Without light sources, everything appears black regardless of color.

// HemisphericLight — ambient light from sky/ground
const hemi = new BABYLON.HemisphericLight(
  'hemi', new BABYLON.Vector3(0, 1, 0), scene
)
hemi.intensity = 0.7

// DirectionalLight — simulates sunlight (parallel rays)
const dirLight = new BABYLON.DirectionalLight(
  'dirLight', new BABYLON.Vector3(-1, -2, -1), scene
)
dirLight.position = new BABYLON.Vector3(2, 8, 4)
dirLight.intensity = 0.8

Light types:

LightAnalogyUse For
HemisphericLightOvercast skyBase ambient lighting (cheap)
DirectionalLightSunStrong directional shadows
PointLightLight bulbOmni-directional local light
SpotLightFlashlightCone-shaped beam

Meshes — The 3D Objects

Meshes are the actors on your stage. Babylon.js includes built-in shapes you can create with a single function call:

// Box — like a dice or crate
const box = BABYLON.MeshBuilder.CreateBox('box', { size: 2 }, scene)
box.position.set(-2.5, 1, 0)

// Sphere — like a ball
const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', {
  diameter: 1.8, segments: 32
}, scene)
sphere.position.set(2.5, 0.9, 0)

// Cylinder — like a can
const cylinder = BABYLON.MeshBuilder.CreateCylinder('cyl', {
  height: 1.8, diameter: 1.2
}, scene)
cylinder.position.set(0, 0.9, 2.5)

// Torus — like a donut
const torus = BABYLON.MeshBuilder.CreateTorus('torus', {
  diameter: 1.6, thickness: 0.4
}, scene)
torus.position.set(0, 1.5, -2.5)

What does segments: 32 mean on a sphere? It controls how many polygons the sphere is made of. More segments = smoother but more GPU work. 32 is a good balance. For a stylized low-poly look, use 8-12.

Moving and Rotating Meshes

Every mesh has position, rotation, and scaling — all using Vector3 (x, y, z):

// Position — where it is in 3D space
box.position = new BABYLON.Vector3(2, 1, 0)
sphere.position.y = 1

// Rotation — in radians, not degrees!
sphere.rotation.y += 0.01  // spin in render loop

// Scaling — stretch or shrink
cylinder.scaling = new BABYLON.Vector3(1, 2, 1)  // stretched vertically

Degrees vs Radians: Babylon.js uses radians for rotation. Convert degrees to radians:

const radians = BABYLON.Tools.ToRadians(45)  // 45 degrees
sphere.rotation.y = radians

Materials — Giving Objects Color

A material defines how a surface looks — its color, shininess, and transparency:

const boxMat = new BABYLON.StandardMaterial('boxMat', scene)
boxMat.diffuseColor = new BABYLON.Color3(0.9, 0.2, 0.2)  // red
boxMat.specularColor = new BABYLON.Color3(0.3, 0.3, 0.3) // shine highlights
boxMat.specularPower = 32                                  // how tight the shine is
box.material = boxMat

What is specularColor? It controls the color of shiny highlights. A red ball with white specular has white highlights. Black specular = matte surface, no shine.

The Render Loop — Making It Run

3D scenes don’t just sit there. They need to be rendered continuously — typically 60 times per second. This is called the render loop:

engine.runRenderLoop(() => {
  // Animate things here
  sphere.rotation.y += 0.01
  torus.rotation.z += 0.008
  box.rotation.x += 0.005
  box.rotation.y += 0.005

  scene.render()  // MUST call this every frame
})

// Handle window resize
window.addEventListener('resize', () => engine.resize())

Why do we need a loop? Unlike a static image, a 3D scene can change every frame — objects rotate, cameras move, animations play. The render loop tells Babylon.js “capture a new frame now.”


Common Mistakes Beginners Make

1. Forgetting camera.attachControl(canvas)

The camera won’t respond to mouse or touch input. You’ll be stuck looking at the same angle.

2. Not Calling scene.render() in the Loop

The most common cause of a blank or frozen scene. Without scene.render(), Babylon.js never draws anything.

3. Creating Meshes Without the Scene Parameter

// Wrong — mesh is created but not added to any scene
const box = BABYLON.MeshBuilder.CreateBox('box', { size: 2 })

// Correct — pass scene as the last argument
const box = BABYLON.MeshBuilder.CreateBox('box', { size: 2 }, scene)

4. Forgetting Lights

Everything will be black. Add at least one HemisphericLight.

5. Using Degrees Instead of Radians

// Wrong — rotation will be unexpectedly tiny
sphere.rotation.y = 45

// Correct
sphere.rotation.y = BABYLON.Tools.ToRadians(45)

6. Not Adding the Babylon.js Script

<!-- Must be included before your code -->
<script src="https://cdn.babylonjs.com/babylon.js"></script>

Practice Questions

  1. What does engine.runRenderLoop() do? It calls a function every frame (typically 60 fps) to update and render the scene. You must call scene.render() inside it.

  2. Why does everything appear black if you don’t add lights? 3D rendering simulates light reflection. Without light sources, no light reaches the camera, so all surfaces appear black regardless of color.

  3. What is the difference between ArcRotateCamera and FreeCamera? ArcRotateCamera orbits around a fixed target — good for inspecting objects. FreeCamera moves freely through the scene like a first-person game.

  4. What does the segments parameter do on CreateSphere? It controls polygon resolution. Higher values (64+) produce smoother spheres but use more GPU power. Default 32 is a good balance.

  5. How do you convert degrees to radians in Babylon.js? Use BABYLON.Tools.ToRadians(degrees).

Challenge

Create a 3D scene with:

  • A ground plane
  • Five different mesh types (box, sphere, cylinder, torus, torus knot) arranged in a circle
  • Each mesh has a different color and rotates at a different speed
  • An ArcRotateCamera for orbit control
  • Both a HemisphericLight and a DirectionalLight
  • A UI panel that shows the name of whichever mesh the user clicks

FAQ

Why is my scene black / nothing visible?

Most likely you forgot to add a light, or the camera is pointing away from your meshes. Add a HemisphericLight and ensure your camera target is near your mesh positions.

Can I have multiple scenes?

Yes. Create multiple Scene objects and render them sequentially in the loop, or switch between them by setting scene.activeCamera.

What does stencil: true do in the Engine constructor?

It enables the stencil buffer, required for shadows, reflections, and some post-processing effects. Enable it when creating the engine even if you don’t use it immediately.

How do I switch cameras at runtime?

Set scene.activeCamera = newCamera, detach the old camera with oldCamera.detachControl(), and attach the new one with newCamera.attachControl(canvas).

My mesh has invisible faces from certain angles

That’s back-face culling — a performance optimization that skips rendering the inside of surfaces. Disable it with mesh.material.backFaceCulling = false if you need to see both sides.

Try It Yourself: 3D Scene Explorer

Run this complete HTML page to explore cameras, lights, and meshes interactively.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Babylon.js — 3D Scene Explorer</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    html, body { width: 100%; height: 100%; overflow: hidden; font-family: system-ui, sans-serif; }
    #renderCanvas { width: 100%; height: 100%; display: block; }
    #ui {
      position: absolute; top: 16px; left: 16px;
      background: rgba(0,0,0,0.75); color: #fff;
      padding: 16px 20px; border-radius: 8px; font-size: 14px;
      backdrop-filter: blur(4px); user-select: none;
      display: flex; flex-direction: column; gap: 10px; min-width: 200px;
    }
    #ui label { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
    #ui input[type="range"] { width: 100px; }
    #ui button {
      background: #4a6cf7; color: #fff; border: none;
      padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 13px;
    }
    #ui button:hover { background: #5f7cf7; }
    #ui select { background: #222; color: #fff; border: 1px solid #555; padding: 4px 8px; border-radius: 4px; font-size: 13px; }
    #ui hr { border: none; border-top: 1px solid #444; margin: 4px 0; }
  </style>
</head>
<body>
  <canvas id="renderCanvas"></canvas>
  <div id="ui">
    <strong>3D Scene Explorer</strong>
    <label>Camera <select id="cameraSelect"><option value="orbit">ArcRotate</option><option value="free">Free</option></select></label>
    <label>Light X <input type="range" id="lightX" min="-10" max="10" step="0.1" value="2" /></label>
    <label>Light Y <input type="range" id="lightY" min="0" max="20" step="0.1" value="8" /></label>
    <label>Intensity <input type="range" id="lightIntensity" min="0" max="2" step="0.05" value="0.8" /></label>
    <hr />
    <button id="wireframeToggle">Toggle Wireframe</button>
    <button id="resetCamera">Reset Camera</button>
  </div>
  <script src="https://cdn.babylonjs.com/babylon.js"></script>
  <script>
    const canvas = document.getElementById('renderCanvas')
    const engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true })
    const scene = new BABYLON.Scene(engine)
    scene.clearColor = new BABYLON.Color3(0.08, 0.08, 0.12)

    const orbitCam = new BABYLON.ArcRotateCamera('orbitCam', -Math.PI / 2, Math.PI / 3, 12, new BABYLON.Vector3(0, 1.5, 0), scene)
    orbitCam.lowerRadiusLimit = 3; orbitCam.upperRadiusLimit = 25
    const freeCam = new BABYLON.FreeCamera('freeCam', new BABYLON.Vector3(0, 4, -12), scene)
    freeCam.setTarget(BABYLON.Vector3.Zero()); freeCam.speed = 0.15
    scene.activeCamera = orbitCam; orbitCam.attachControl(canvas, true)

    const hemi = new BABYLON.HemisphericLight('hemi', new BABYLON.Vector3(0, 1, 0), scene)
    hemi.intensity = 0.3; hemi.diffuse = new BABYLON.Color3(0.8, 0.9, 1)
    const dirLight = new BABYLON.DirectionalLight('dirLight', new BABYLON.Vector3(-1, -1, -0.5), scene)
    dirLight.position = new BABYLON.Vector3(2, 8, 4); dirLight.intensity = 0.8

    const ground = BABYLON.MeshBuilder.CreateGround('ground', { width: 20, height: 20 }, scene)
    const groundMat = new BABYLON.StandardMaterial('groundMat', scene)
    groundMat.diffuseColor = new BABYLON.Color3(0.25, 0.25, 0.3); groundMat.specularColor = new BABYLON.Color3(0, 0, 0)
    ground.material = groundMat

    const box = BABYLON.MeshBuilder.CreateBox('box', { size: 1.8 }, scene)
    box.position.set(-2.5, 0.9, 0)
    const boxMat = new BABYLON.StandardMaterial('boxMat', scene)
    boxMat.diffuseColor = new BABYLON.Color3(0.9, 0.2, 0.2); boxMat.specularColor = new BABYLON.Color3(0.3, 0.3, 0.3); boxMat.specularPower = 32
    box.material = boxMat

    const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', { diameter: 1.8, segments: 32 }, scene)
    sphere.position.set(2.5, 0.9, 0)
    const sphereMat = new BABYLON.StandardMaterial('sphereMat', scene)
    sphereMat.diffuseColor = new BABYLON.Color3(0.2, 0.5, 0.9); sphereMat.specularColor = new BABYLON.Color3(0.5, 0.5, 0.5); sphereMat.specularPower = 64
    sphere.material = sphereMat

    const cyl = BABYLON.MeshBuilder.CreateCylinder('cyl', { height: 1.8, diameter: 1.2 }, scene)
    cyl.position.set(0, 0.9, 2.5)
    const cylMat = new BABYLON.StandardMaterial('cylMat', scene)
    cylMat.diffuseColor = new BABYLON.Color3(0.1, 0.8, 0.3); cylMat.specularColor = new BABYLON.Color3(0.2, 0.2, 0.2)
    cyl.material = cylMat

    const torus = BABYLON.MeshBuilder.CreateTorus('torus', { diameter: 1.6, thickness: 0.4, tessellation: 32 }, scene)
    torus.position.set(0, 1.5, -2.5); torus.rotation.x = Math.PI / 2
    const torusMat = new BABYLON.StandardMaterial('torusMat', scene)
    torusMat.diffuseColor = new BABYLON.Color3(0.9, 0.6, 0.1); torusMat.specularColor = new BABYLON.Color3(0.4, 0.4, 0.4)
    torus.material = torusMat

    document.getElementById('cameraSelect').addEventListener('change', () => {
      const c = scene.activeCamera; if (c) c.detachControl()
      scene.activeCamera = document.getElementById('cameraSelect').value === 'orbit' ? orbitCam : freeCam
      scene.activeCamera.attachControl(canvas, true)
    })
    document.getElementById('lightX').addEventListener('input', () => { dirLight.position.x = parseFloat(document.getElementById('lightX').value) })
    document.getElementById('lightY').addEventListener('input', () => { dirLight.position.y = parseFloat(document.getElementById('lightY').value) })
    document.getElementById('lightIntensity').addEventListener('input', () => { dirLight.intensity = parseFloat(document.getElementById('lightIntensity').value) })
    document.getElementById('wireframeToggle').addEventListener('click', () => { [box, sphere, cyl, torus].forEach(m => { m.material.wireframe = !m.material.wireframe }) })
    document.getElementById('resetCamera').addEventListener('click', () => { orbitCam.alpha = -Math.PI / 2; orbitCam.beta = Math.PI / 3; orbitCam.radius = 12; orbitCam.target = new BABYLON.Vector3(0, 1.5, 0) })

    engine.runRenderLoop(() => {
      sphere.rotation.y += 0.01; torus.rotation.z += 0.008; box.rotation.x += 0.005; box.rotation.y += 0.005
      scene.render()
    })
    window.addEventListener('resize', () => engine.resize())
  </script>
</body>
</html>

What to expect: Four 3D objects (box, sphere, cylinder, torus) on a ground plane, each with a different color, all slowly rotating. Use the panel to switch cameras, adjust the directional light, toggle wireframe mode, or reset the camera view.


What’s Next

TutorialWhat You’ll Learn
Materials & TexturesPBR materials, texture maps, environment lighting
Animation & PhysicsKeyframe animation, Havok physics engine
GUI & Interaction2D UI overlays, mesh picking, ActionManager
Importing & AssetsglTF/GLB import, asset containers, optimization

Related topics: JavaScript basics, WebGL fundamentals.

What’s Next

Congratulations on completing this Babylonjs Getting Started tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro