Skip to content

Babylon.js Project — Interactive 3D Product Viewer

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Babylon.js Project. We cover key concepts, practical examples, and best practices to help you master this topic.

This project walks through building a full-featured 3D product viewer with Babylon.js, combining model loading, interactive controls, GUI overlays, animations, and physics interactions.

What You'll Learn

By the end of this project, you will architect a 3D viewer application, load and display 3D models with PBR materials, implement orbit and zoom controls, build material switching UI, add physics-based interaction, and deploy a performant 3D web app.

Viewer Architecture

var ProductViewer = {
    scene: null,
    camera: null,
    engine: null,
    currentModel: null,
    config: {
        modelUrl: './models/product.glb',
        defaultColor: '#4ecdc4',
        autoRotate: true
    },

    init: function(canvasId) {
        this.engine = new BABYLON.Engine(document.getElementById(canvasId), true);
        this.scene = new BABYLON.Scene(this.engine);
        this.setupCamera();
        this.setupLighting();
        this.setupGUI();
        this.loadModel();
        this.engine.runRenderLoop(this.render.bind(this));
    },

    setupCamera: function() {
        this.camera = new BABYLON.ArcRotateCamera('camera', -Math.PI/2, Math.PI/3, 5, BABYLON.Vector3.Zero(), this.scene);
        this.camera.attachControl(this.engine.getRenderingCanvas(), true);
        this.camera.lowerRadiusLimit = 2;
        this.camera.upperRadiusLimit = 10;
    }
};

Material Switching

function switchMaterial(color) {
    if (!currentModel) return;

    currentModel.material = new BABYLON.PBRMaterial('pbr', scene);
    currentModel.material.albedoColor = BABYLON.Color3.FromHexString(color);
    currentModel.material.metallic = 0.6;
    currentModel.material.roughness = 0.3;
}

Common Mistakes

1. Not Handling Mobile Touch

Mobile users need touch-friendly controls. Use pinch-zoom and one-finger orbit.

2. No Loading State

Large models take time to load. Show a skeleton UI or loading spinner.

3. Not Disposing Previous Model

Switching models without disposing the previous one causes memory leaks.

4. Auto-Rotate During Interaction

Disable auto-rotate when the user interacts with the model or GUI.

5. Ignoring GUI Scale

GUI elements sized in pixels may be too small on 4K screens. Use adaptive sizing.

Practice Questions

Q1: How do you structure a Babylon.js application? A: Use a main controller object with methods for setup, loading, and interaction.

Q2: How do you switch between materials? A: Replace the mesh.material property with a new StandardMaterial or PBRMaterial.

Q3: How do you handle window resize? A: Call engine.resize() on window resize event.

Q4: How do you auto-rotate the camera? A: In the render loop, increment camera.alpha by a small amount.

Q5: How do you add environment Reflection? A: Use BABYLON.Scene.createDefaultEnvironment() with environmentTexture.

Challenge: Add a color picker that lets users change the product color. Also add a texture toggle (matte vs gloss) that changes the roughness and metallic values.

FAQ

What is the best format for 3D product models?

glTF (GLB) is the standard. It supports PBR materials, animations, and is web-optimized.

How do I optimize for mobile?

Use Draco-compressed glTF, reduce texture sizes, enable a lower render scale on mobile.

Can I use AR with Babylon.js?

Yes. Babylon.js supports WebXR for AR and VR.

How do I add a floor shadow?

Create a shadow-only ground or use a shadow generator with a transparent ground.

How do I export a viewer application?

Bundle with webpack or vite. Deploy to any static host.

Try It Yourself

Build a product viewer with material switching.

<!DOCTYPE html>
<html>
<head>
    <title>3D Product Viewer</title>
    <script src="https://cdn.babylonjs.com/babylon.js"></script>
    <style>
        body { margin: 0; overflow: hidden; font-family: sans-serif; }
        canvas { width: 100%; height: 100vh; display: block; }
        .ui { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); display: flex; gap: 10px; }
        .ui button { padding: 10px 20px; border: none; border-radius: 8px; color: white; font-weight: bold; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.2); }
        .ui .c1 { background: #4ecdc4; } .ui .c2 { background: #ff6b35; } .ui .c3 { background: #2a9d8f; } .ui .c4 { background: #e8a87c; }
        .ui button:hover { transform: scale(1.05); }
        .info { position: absolute; top: 20px; left: 20px; color: white; background: rgba(0,0,0,0.5); padding: 8px 16px; border-radius: 8px; font-size: 14px; }
    </style>
</head>
<body>
<div class="info">Drag to orbit | Scroll to zoom</div>
<div class="ui">
    <button class="c1" onclick="changeColor('#4ecdc4')">Teal</button>
    <button class="c2" onclick="changeColor('#ff6b35')">Orange</button>
    <button class="c3" onclick="changeColor('#2a9d8f')">Green</button>
    <button class="c4" onclick="changeColor('#e8a87c')">Sand</button>
</div>
<canvas id="renderCanvas"></canvas>
<script>
var canvas = document.getElementById('renderCanvas');
var engine = new BABYLON.Engine(canvas, true);
var scene = new BABYLON.Scene(engine);

var camera = new BABYLON.ArcRotateCamera('camera', -Math.PI/2, Math.PI/3, 6, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
camera.lowerRadiusLimit = 2;
camera.upperRadiusLimit = 12;

var light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 0.6;

var envLight = new BABYLON.DirectionalLight('env', new BABYLON.Vector3(-1, -2, -1), scene);
envLight.intensity = 0.4;

// Create a base model (sphere since we can't load external files easily)
var sphere = BABYLON.MeshBuilder.CreateSphere('product', { diameter: 1.5 }, scene);
sphere.position.y = 0.5;

var ground = BABYLON.MeshBuilder.CreateGround('ground', { width: 6, height: 6 }, scene);
var groundMat = new BABYLON.StandardMaterial('groundMat', scene);
groundMat.diffuseColor = new BABYLON.Color3(0.95, 0.95, 0.95);
ground.material = groundMat;

// PBR material for product
var pbr = new BABYLON.PBRMaterial('pbr', scene);
pbr.albedoColor = new BABYLON.Color3.FromHexString('#4ecdc4');
pbr.metallic = 0.5;
pbr.roughness = 0.3;
pbr.environmentIntensity = 0.7;
sphere.material = pbr;

// Auto-rotate
var autoRotate = true;
var lastInteraction = 0;

camera.onViewMatrixChangedObservable.add(function() {
    lastInteraction = Date.now();
    autoRotate = false;
});

scene.registerBeforeRender(function() {
    if (autoRotate) {
        camera.alpha += 0.005;
    } else if (Date.now() - lastInteraction > 3000) {
        autoRotate = true;
    }
});

function changeColor(hex) {
    pbr.albedoColor = BABYLON.Color3.FromHexString(hex);
}

window.addEventListener('resize', function() { engine.resize(); });
engine.runRenderLoop(function() { scene.render(); });
</script>
</body>
</html>

What's Next

Explore PixiJS for 2D rendering.

Getting Started — 2D rendering with PixiJS.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro