Skip to main content

Overview

The extrusion feature allows you to create 3D shapes by extruding 2D polygons vertically. This is perfect for creating buildings, walls, terrain features, or any custom 3D geometry based on geographic coordinates.

Basic Usage

const extrusion = tb.extrusion({
  coordinates: [
    [
      [-122.4194, 37.7749],
      [-122.4184, 37.7749],
      [-122.4184, 37.7739],
      [-122.4194, 37.7739],
      [-122.4194, 37.7749]  // Close the polygon
    ]
  ],
  height: 100,
  materials: new THREE.MeshStandardMaterial({ color: 0x660000 })
});

extrusion.setCoords([-122.4194, 37.7749]);
tb.add(extrusion);

API Signature

tb.extrusion(options)

Options

ParameterTypeDefaultDescription
coordinatesArray[[[]]]Nested array of polygon coordinates (GeoJSON format)
geometryOptionsobject{}Three.js ExtrudeGeometry settings
heightnumber100Extrusion height
materialsTHREE.MaterialMeshPhongMaterialMaterial for the extruded shape
scalenumber | {x,y,z}1Scale factor
rotationnumber | {x,y,z}0Rotation in degrees
units'scene' | 'meters''scene'Coordinate system
anchorstring'center'Anchor point for positioning
bboxbooleantrueShow bounding box when selected
tooltipbooleantrueEnable tooltip
raycastedbooleantrueInclude in raycasting

Coordinate Format

Extrusions accept coordinates in GeoJSON polygon format:

Simple Polygon

const coordinates = [
  [  // Outer ring
    [-122.4194, 37.7749],  // Point 1
    [-122.4184, 37.7749],  // Point 2
    [-122.4184, 37.7739],  // Point 3
    [-122.4194, 37.7739],  // Point 4
    [-122.4194, 37.7749]   // Close the ring (same as Point 1)
  ]
];

Polygon with Holes

const coordinates = [
  [  // Outer ring
    [-122.4200, 37.7750],
    [-122.4180, 37.7750],
    [-122.4180, 37.7730],
    [-122.4200, 37.7730],
    [-122.4200, 37.7750]
  ],
  [  // Inner ring (hole)
    [-122.4195, 37.7745],
    [-122.4185, 37.7745],
    [-122.4185, 37.7735],
    [-122.4195, 37.7735],
    [-122.4195, 37.7745]
  ]
];
The first array is the outer boundary, and subsequent arrays define holes within the shape.

Creating Extrusions

Simple Building

const building = tb.extrusion({
  coordinates: [
    [
      [-73.9857, 40.7484],
      [-73.9847, 40.7484],
      [-73.9847, 40.7474],
      [-73.9857, 40.7474],
      [-73.9857, 40.7484]
    ]
  ],
  height: 200,
  materials: new THREE.MeshStandardMaterial({
    color: 0x2194ce,
    metalness: 0.5,
    roughness: 0.5
  }),
  units: 'meters'
});

building.setCoords([-73.9857, 40.7484]);
tb.add(building);

Building with Courtyard

const buildingWithCourtyard = tb.extrusion({
  coordinates: [
    // Outer perimeter
    [
      [-122.420, 37.775],
      [-122.418, 37.775],
      [-122.418, 37.773],
      [-122.420, 37.773],
      [-122.420, 37.775]
    ],
    // Courtyard (hole)
    [
      [-122.4195, 37.7745],
      [-122.4185, 37.7745],
      [-122.4185, 37.7735],
      [-122.4195, 37.7735],
      [-122.4195, 37.7745]
    ]
  ],
  height: 150,
  materials: new THREE.MeshStandardMaterial({ color: 0x8B4513 })
});

buildingWithCourtyard.setCoords([-122.419, 37.774]);
tb.add(buildingWithCourtyard);

Geometry Options

The geometryOptions parameter accepts Three.js ExtrudeGeometry settings:
const extrusion = tb.extrusion({
  coordinates: [[
    [-122.4194, 37.7749],
    [-122.4184, 37.7749],
    [-122.4184, 37.7739],
    [-122.4194, 37.7739],
    [-122.4194, 37.7749]
  ]],
  geometryOptions: {
    depth: 100,           // Extrusion depth
    bevelEnabled: true,   // Enable beveled edges
    bevelThickness: 2,    // Bevel depth
    bevelSize: 2,         // Bevel height
    bevelSegments: 3,     // Bevel smoothness
    steps: 1,             // Depth subdivisions
    curveSegments: 12     // Curve smoothness
  },
  materials: new THREE.MeshStandardMaterial({ color: 0x660000 })
});
Use bevelEnabled: true to create rounded edges on buildings and other architectural features.

Advanced Examples

Multi-Material Extrusion

// Different materials for walls and top
const materials = [
  new THREE.MeshStandardMaterial({ color: 0x808080 }), // Walls
  new THREE.MeshStandardMaterial({ color: 0x404040 })  // Top/Bottom
];

const building = tb.extrusion({
  coordinates: [[
    [-122.4194, 37.7749],
    [-122.4184, 37.7749],
    [-122.4184, 37.7739],
    [-122.4194, 37.7739],
    [-122.4194, 37.7749]
  ]],
  height: 200,
  materials: materials
});

From GeoJSON Feature

function extrudeGeoJSON(feature, height, color) {
  return tb.extrusion({
    coordinates: feature.geometry.coordinates,
    height: height || feature.properties.height || 100,
    materials: new THREE.MeshStandardMaterial({
      color: color || feature.properties.color || 0x660000
    }),
    units: 'meters'
  });
}

// Use with GeoJSON feature
const buildingFeature = {
  type: 'Feature',
  geometry: {
    type: 'Polygon',
    coordinates: [[
      [-122.4194, 37.7749],
      [-122.4184, 37.7749],
      [-122.4184, 37.7739],
      [-122.4194, 37.7739],
      [-122.4194, 37.7749]
    ]]
  },
  properties: {
    height: 150,
    color: 0x2194ce
  }
};

const building = extrudeGeoJSON(buildingFeature);
building.setCoords([-122.4189, 37.7744]);
tb.add(building);

Complex Shape with Custom Geometry

const complexBuilding = tb.extrusion({
  coordinates: [
    [  // L-shaped building
      [-122.420, 37.775],
      [-122.419, 37.775],
      [-122.419, 37.774],
      [-122.418, 37.774],
      [-122.418, 37.773],
      [-122.420, 37.773],
      [-122.420, 37.775]
    ]
  ],
  geometryOptions: {
    depth: 100,
    bevelEnabled: true,
    bevelThickness: 1,
    bevelSize: 1,
    bevelSegments: 2
  },
  materials: new THREE.MeshStandardMaterial({
    color: 0x996633,
    metalness: 0.3,
    roughness: 0.7
  })
});

complexBuilding.setCoords([-122.419, 37.774]);
tb.add(complexBuilding);

Working with Vector2

You can also use Three.js Vector2 arrays directly:
const points = [
  new THREE.Vector2(0, 0),
  new THREE.Vector2(100, 0),
  new THREE.Vector2(100, 100),
  new THREE.Vector2(0, 100),
  new THREE.Vector2(0, 0)
];

const extrusion = tb.extrusion({
  coordinates: points,
  height: 50,
  materials: new THREE.MeshStandardMaterial({ color: 0xff0000 }),
  units: 'scene'
});

Common Patterns

City Block Generator

function createCityBlock(center, blockSize, buildingCount) {
  const buildings = [];
  const spacing = blockSize / buildingCount;
  
  for (let i = 0; i < buildingCount; i++) {
    for (let j = 0; j < buildingCount; j++) {
      const x = center[0] + (i - buildingCount/2) * spacing;
      const y = center[1] + (j - buildingCount/2) * spacing;
      const size = spacing * 0.8;
      
      const building = tb.extrusion({
        coordinates: [[
          [x, y],
          [x + size, y],
          [x + size, y + size],
          [x, y + size],
          [x, y]
        ]],
        height: Math.random() * 200 + 50,
        materials: new THREE.MeshStandardMaterial({
          color: Math.random() * 0xffffff
        })
      });
      
      building.setCoords([x + size/2, y + size/2]);
      tb.add(building);
      buildings.push(building);
    }
  }
  
  return buildings;
}

// Create a 5x5 grid of buildings
const cityBlock = createCityBlock([-122.4194, 37.7749], 0.01, 5);

Terrain Feature

function createWall(start, end, height, thickness) {
  // Calculate perpendicular offset for thickness
  const dx = end[0] - start[0];
  const dy = end[1] - start[1];
  const len = Math.sqrt(dx*dx + dy*dy);
  const offsetX = -dy / len * thickness;
  const offsetY = dx / len * thickness;
  
  return tb.extrusion({
    coordinates: [[
      [start[0], start[1]],
      [end[0], end[1]],
      [end[0] + offsetX, end[1] + offsetY],
      [start[0] + offsetX, start[1] + offsetY],
      [start[0], start[1]]
    ]],
    height: height,
    materials: new THREE.MeshStandardMaterial({
      color: 0x8B7355,
      roughness: 0.9
    })
  });
}

const wall = createWall(
  [-122.420, 37.775],
  [-122.418, 37.775],
  10,
  0.0001
);

wall.setCoords([-122.419, 37.775]);
tb.add(wall);

Implementation Details

The extrusion feature uses Three.js geometry classes internally:
src/objects/extrusion.js:14-25
function extrusion(opt) {
  opt = utils._validate(opt, Objects.prototype._defaults.extrusion);
  let shape = extrusion.prototype.buildShape(opt.coordinates);
  let geometry = extrusion.prototype.buildGeometry(shape, opt.geometryOptions);
  let mesh = new THREE.Mesh(geometry, opt.materials);
  opt.obj = mesh;
  return new Object3D(opt);
}

Building the Shape

src/objects/extrusion.js:28-39
buildShape: function (coords) {
  if (coords[0] instanceof (THREE.Vector2 || THREE.Vector3)) 
    return new THREE.Shape(coords);
  
  let shape = new THREE.Shape();
  for (let i = 0; i < coords.length; i++) {
    if (i === 0) {
      shape = new THREE.Shape(this.buildPoints(coords[0], coords[0]));
    } else {
      shape.holes.push(new THREE.Path(this.buildPoints(coords[i], coords[0])));
    }
  }
  return shape;
}

Converting Coordinates

src/objects/extrusion.js:41-49
buildPoints: function (coords, initCoords) {
  const points = [];
  let init = utils.projectToWorld([initCoords[0][0], initCoords[0][1], 0]);
  for (let i = 0; i < coords.length; i++) {
    let pos = utils.projectToWorld([coords[i][0], coords[i][1], 0]);
    points.push(new THREE.Vector2(
      utils.toDecimal((pos.x - init.x), 9), 
      utils.toDecimal((pos.y - init.y), 9)
    ));
  }
  return points;
}
Coordinates are converted to world space and normalized to prevent floating-point precision issues.

Performance Considerations

  • Keep polygon vertex count reasonable (< 100 vertices)
  • Simplify complex shapes when possible
  • Use bevel settings sparingly for better performance
  • Share materials across multiple extrusions
  • Use simpler materials for distant objects
  • Consider texture atlases for many buildings
  • Group extrusions with similar properties
  • Consider merging geometries for static scenes
  • Use instancing for repeated shapes

Next Steps

Primitives

Create spheres, lines, and tubes

Materials & Lighting

Configure materials and scene lighting

Build docs developers (and LLMs) love