Babylon.js Getting Started: Your First 3D Scene
Babylon.js runs in any modern browser without plugins or special build tools. You can start with a single HTML file and a script tag, or use a full npm-based project with bundlers like Vite or Webpack. Both approaches produce the same result: a canvas element powered by the WebGL or WebGPU rendering context that Babylon.js manages for you.
Step 1: Set Up the Project
The fastest way to start is with a plain HTML file. Create an index.html file and add a <canvas> element with an id you can reference. Include Babylon.js from the CDN by adding a script tag pointing to the latest UMD build. The CDN URL follows the pattern https://cdn.babylonjs.com/babylon.js for the core, with additional files for loaders and other modules.
For a production project, install via npm instead. Run npm install @babylonjs/core to get the core package. If you need to load glTF models, also install @babylonjs/loaders. The npm packages are tree-shakeable, so your bundler will only include the modules you actually import, keeping the final bundle size smaller than the full CDN build.
Your HTML needs one critical element: a <canvas> tag. This canvas is where Babylon.js renders everything. Style it to fill the viewport with CSS (width: 100%; height: 100%;) and make sure the body has no margin or padding so the canvas covers the full browser window. Give the canvas an id like renderCanvas so your JavaScript can find it.
Step 2: Create the Engine and Scene
The Engine is the bridge between Babylon.js and the browser's rendering context. Create it by passing the canvas element and a boolean for antialiasing: new BABYLON.Engine(canvas, true). The engine handles the WebGL context, manages frame timing, and provides the render loop mechanism.
The Scene is the container for everything in your 3D world. Create it by passing the engine: new BABYLON.Scene(engine). The scene manages the render pipeline, tracks all meshes and lights, handles picking (clicking on 3D objects), and runs the physics simulation if enabled. Every mesh, camera, and light you create will be registered with this scene automatically.
You should also handle window resizing. Add an event listener for the resize event that calls engine.resize(). Without this, the canvas will render at the wrong resolution after the browser window changes size, producing a blurry or stretched image.
Step 3: Add a Camera
Without a camera, nothing renders. The ArcRotateCamera is the best choice for getting started because it orbits around a target point and responds to mouse drag and scroll wheel input. Create one with new BABYLON.ArcRotateCamera("camera", Math.PI / 4, Math.PI / 3, 10, BABYLON.Vector3.Zero(), scene). The parameters set the horizontal angle (alpha), vertical angle (beta), distance from target (radius), and the target position.
After creating the camera, attach it to the canvas with camera.attachControl(canvas, true). The second parameter prevents the default browser behavior (like scrolling the page) when the user interacts with the canvas. You can also set limits on the camera: camera.lowerBetaLimit prevents the camera from going below the ground plane, and camera.lowerRadiusLimit prevents it from zooming too close.
For a first-person perspective instead, use new BABYLON.FreeCamera("camera", new BABYLON.Vector3(0, 1.6, -5), scene). The FreeCamera responds to WASD keys for movement and mouse for looking around. Set camera.speed to control movement speed and camera.angularSensibility for mouse sensitivity.
Step 4: Add Lighting
A scene with no lights renders entirely black. The HemisphericLight provides soft ambient illumination that simulates light bouncing from the sky and ground. Create one with new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene). The direction vector points upward, indicating the light comes from above. Set the intensity property to control brightness, with 1.0 being the default.
For more dramatic lighting, add a DirectionalLight that simulates sunlight. Directional lights cast parallel rays from a specific direction, and they support shadow mapping. Create one with new BABYLON.DirectionalLight("sun", new BABYLON.Vector3(-1, -2, -1), scene). The direction vector points from the light source toward the scene, so negative Y means light coming from above.
To enable shadows, create a ShadowGenerator attached to the directional light and add meshes as shadow casters. The shadow generator supports several algorithms including PCF (soft shadows), PCSS (contact-hardening shadows), and cascaded shadow maps for large outdoor scenes.
Step 5: Create Meshes
The MeshBuilder API creates primitive shapes with a single function call. BABYLON.MeshBuilder.CreateBox("box", {size: 2}, scene) creates a 2-unit cube. Other primitives include CreateSphere, CreateCylinder, CreateGround, CreatePlane, CreateTorus, and CreateDisc. Each accepts an options object that controls dimensions, tessellation, and other shape-specific parameters.
The CreateGround mesh is particularly useful for getting started: BABYLON.MeshBuilder.CreateGround("ground", {width: 20, height: 20}, scene) creates a flat plane that serves as a floor. Position your box above it with box.position.y = 1 so it sits on top of the ground rather than intersecting it.
Every mesh has a position, rotation, and scaling property, each a Vector3. Position uses world units (meters by convention), rotation uses radians, and scaling multiplies the mesh dimensions. You can also use mesh.rotate() and mesh.translate() for incremental transformations relative to the mesh's current orientation.
Step 6: Apply Materials
Meshes without materials render in a default white. The StandardMaterial provides basic surface properties: diffuseColor sets the base color, specularColor controls highlight color, and emissiveColor makes the surface glow. Create a material with new BABYLON.StandardMaterial("mat", scene) and assign it with mesh.material = mat.
For textures, set the diffuseTexture property to a new BABYLON.Texture with the image path. Babylon.js handles texture loading asynchronously, so the mesh will render with a placeholder until the image finishes downloading. You can also set bumpTexture for normal mapping, specularTexture for per-pixel specular control, and ambientTexture for ambient occlusion.
For physically accurate rendering, use PBRMaterial instead. Set albedoColor or albedoTexture for the base color, metallic (0 to 1) for how metallic the surface appears, and roughness (0 to 1) for how rough or smooth it looks. PBR materials respond to environment lighting via scene.environmentTexture, which you can set to an HDR image for realistic reflections.
Step 7: Run the Render Loop
Everything so far has been setup. To see results, start the render loop: engine.runRenderLoop(function() { scene.render(); }). This tells the engine to call scene.render() on every frame, which evaluates animations, updates physics, performs culling, and issues draw calls. The loop synchronizes with the display's refresh rate using requestAnimationFrame internally.
At this point, you should see your scene in the browser. The camera responds to mouse input, the light illuminates the meshes, and the materials give them color and texture. If the canvas appears black, check that you created a camera and a light. If the canvas is blank, check the browser console for errors, which usually indicate a missing file path or a JavaScript syntax error.
To add animation, modify mesh properties inside the render loop or use the built-in animation system. For example, box.rotation.y += 0.01 inside the render callback rotates the box continuously. For production code, use the Animation class or scene.onBeforeRenderObservable for frame-rate-independent updates.
The core Babylon.js pattern is always the same: create an engine from a canvas, create a scene from the engine, add a camera and a light, build or load meshes, apply materials, and start the render loop. Every complex Babylon.js project is built on this same foundation.