Skip to main content

Overview

The Threebox instance is the core object that bridges Three.js and Mapbox GL JS. It manages the Three.js scene, camera synchronization, rendering, and all 3D objects on your map.

Constructor

Create a Threebox instance inside a Mapbox GL JS custom layer:
var tb = new Threebox(map, glContext, options)

Parameters

map
mapboxgl.Map
required
The Mapbox GL JS map instance
glContext
WebGLRenderingContext
required
WebGL rendering context from Mapbox. Get it from map.getCanvas().getContext('webgl') or the gl parameter in onAdd(map, gl)
options
object
Configuration options for the Threebox instance

Configuration Options

Lighting

defaultLights
boolean
default:"false"
Adds default lighting to the scene:
  • THREE.AmbientLight at 75% intensity
  • Two THREE.DirectionalLight sources
Without lighting, most objects render as black.
realSunlight
boolean
default:"false"
Simulates sun position based on map center coordinates and datetime using SunCalc. Creates:
  • THREE.HemisphereLight
  • THREE.DirectionalLight positioned by sun calculations
Updates dynamically with tb.setSunlight(date, coords)
realSunlightHelper
boolean
default:"false"
Shows a visual helper for the sun light direction when realSunlight is enabled

Rendering

passiveRendering
boolean
default:"true"
Controls rendering behavior. When true, renders only when map updates. When false, continuously triggers repaints.
preserveDrawingBuffer
boolean
default:"false"
Preserves the drawing buffer for screenshots or image exports

Interaction

enableSelectingFeatures
boolean
default:"false"
Enables mouseover and selection of fill-extrusion layer features. Fires SelectedFeatureChange event.
enableSelectingObjects
boolean
default:"false"
Enables mouseover and selection of 3D objects. Fires SelectedChange event. Sets bbox option on created objects.
enableDraggingObjects
boolean
default:"false"
Allows dragging selected 3D objects:
  • Shift + drag: Move horizontally (x-y plane)
  • Ctrl + drag: Move vertically (z axis)
Fires ObjectDragged event with draggedAction: 'translate' or 'altitude'
enableRotatingObjects
boolean
default:"false"
Allows rotating selected 3D objects:
  • Alt + drag: Rotate around z-axis
Fires ObjectDragged event with draggedAction: 'rotate'
enableTooltips
boolean
default:"false"
Enables default tooltips on fill-extrusion features and 3D objects
enableHelpTooltips
boolean
default:"false"
Shows help tooltips during object manipulation (position, rotation, measurements)

Camera

orthographic
boolean
default:"false"
Uses THREE.OrthographicCamera instead of THREE.PerspectiveCamera
Pure orthographic view is not fully supported by Mapbox. Can cause issues with fill-extrusion layers. For orthographic-like view, use orthographic: false with fov: 2.5
fov
number
default:"28"
Field of view for THREE.PerspectiveCamera in degrees. Has no effect when orthographic: true.
  • Below 2.5 degrees: Polygon rendering issues
  • Above 45 degrees: Clipping and performance problems
  • Valid range: 0-60 degrees (Mapbox limitation)

Layers

multiLayer
boolean
default:"false"
Enables multiple 3D layers. Creates a default layer that automatically manages tb.update() calls. Recommended to set in constructor if using multiple layers.
sky
boolean
default:"false"
Adds atmospheric sky layer (Mapbox GL JS v2.0+). Automatically updates with realSunlight.
terrain
boolean
default:"false"
Adds terrain layer using mapbox-terrain-dem-v1 (Mapbox GL JS v2.0+). Automatically updates lighting with realSunlight.

Usage Examples

Basic Setup (Method 1: Context from onAdd)

map.addLayer({
  id: 'custom_layer',
  type: 'custom',
  renderingMode: '3d',
  onAdd: function (map, gl) {
    // Create Threebox instance
    window.tb = new Threebox(
      map,
      gl, // Get context from onAdd parameter
      { 
        defaultLights: true,
        enableSelectingObjects: true,
        enableDraggingObjects: true
      }
    );
    
    // Add 3D objects here
    var geometry = new THREE.BoxGeometry(30, 60, 120);
    let cube = new THREE.Mesh(geometry, new THREE.MeshPhongMaterial({ color: 0x660000 }));
    cube = tb.Object3D({ obj: cube, units: 'meters' });
    cube.setCoords([-3.460539968876, 40.4849214450]);
    tb.add(cube);
  },
  render: function (gl, matrix) {
    tb.update(); // Update Threebox scene
  }
});

Advanced Setup (Method 2: Context from Canvas)

// Create Threebox instance separately
window.tb = new Threebox(
  map,
  map.getCanvas().getContext('webgl'), // Get context from canvas
  { 
    defaultLights: true,
    realSunlight: true,
    realSunlightHelper: false,
    enableSelectingObjects: true,
    enableDraggingObjects: true,
    enableRotatingObjects: true,
    enableTooltips: true,
    fov: 45,
    sky: true,
    terrain: true
  }
);

// Add custom layer
map.addLayer({
  id: 'custom_layer',
  type: 'custom',
  renderingMode: '3d',
  onAdd: function (map, gl) {
    // Load and add 3D models
    tb.loadObj({
      obj: '/models/building.glb',
      type: 'gltf',
      scale: 20,
      units: 'meters',
      rotation: { x: 90, y: 0, z: 0 }
    }, function (model) {
      model.setCoords([-122.4194, 37.7749]);
      tb.add(model);
    });
  },
  render: function (gl, matrix) {
    tb.update();
  }
});

Multi-Layer Setup

// Initialize with multiLayer option
window.tb = new Threebox(
  map,
  map.getCanvas().getContext('webgl'),
  { 
    defaultLights: true,
    multiLayer: true // Automatic update management
  }
);

// No need to call tb.update() in each layer
map.addLayer({
  id: 'layer1',
  type: 'custom',
  renderingMode: '3d',
  onAdd: function (map, gl) {
    // Add objects to layer1
  },
  render: function (gl, matrix) {
    // tb.update() called automatically
  }
});

map.addLayer({
  id: 'layer2',
  type: 'custom',
  renderingMode: '3d',
  onAdd: function (map, gl) {
    // Add objects to layer2
  },
  render: function (gl, matrix) {
    // tb.update() called automatically
  }
});

Internal Structure

When initialized, Threebox creates:
// Three.js scene components
this.scene = new THREE.Scene();
this.world = new THREE.Group(); // Container for all 3D objects
this.renderer = new THREE.WebGLRenderer({
  alpha: true,
  antialias: true,
  canvas: map.getCanvas(),
  context: glContext
});

// Camera (PerspectiveCamera or OrthographicCamera)
this.camera = new THREE.PerspectiveCamera(fov, aspect, 0.1, 1e21);

// Camera synchronization
this.cameraSync = new CameraSync(map, camera, world);

// Raycaster for mouse interactions
this.raycaster = new THREE.Raycaster();

// Label renderer for CSS2D labels
this.labelRenderer = new LabelRenderer(map);

Key Properties

map
mapboxgl.Map
Reference to the Mapbox GL JS map instance
scene
THREE.Scene
The Three.js scene containing all 3D objects
world
THREE.Group
Group container for all Threebox objects. Access via tb.world.children
camera
THREE.Camera
Three.js camera (PerspectiveCamera or OrthographicCamera)
renderer
THREE.WebGLRenderer
Three.js WebGL renderer
lights
object
Light objects: ambientLight, dirLight, dirLightBack, dirLightHelper, hemiLight, pointLight
version
string
Threebox version number (currently ‘2.2.7’)

Resource Management

When using Threebox in a web application, always dispose of the instance before navigating to another page to prevent memory leaks.
// Dispose of all resources
await tb.dispose();
This cleans up:
  • All 3D objects and geometries
  • Materials and textures
  • WebGL context
  • Mapbox map instance
  • Event listeners

Next Steps

Custom Layers

Learn how to integrate Threebox with Mapbox custom layers

Camera Synchronization

Understand how Three.js and Mapbox cameras stay in sync

Coordinate Systems

Master coordinate conversions between lnglat, meters, and units

Build docs developers (and LLMs) love