or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

3d-tiles.mdanimation.mdindex.mdspatial-indexing.mdterrain.mdtile-layers.mdvector-tiles.md
tile.json

3d-tiles.mddocs/

3D Tiles Rendering

Layer for rendering 3D Tiles format data including buildings, photogrammetry, point clouds, and other 3D geospatial content with efficient streaming and level-of-detail management.

Capabilities

Tile3DLayer

Layer for rendering OGC 3D Tiles with automatic content loading, frustum culling, and hierarchical level-of-detail.

/**
 * Layer for rendering 3D Tiles format data
 * Supports buildings, photogrammetry, point clouds, and other 3D content
 */
class Tile3DLayer extends CompositeLayer {
  constructor(props: Tile3DLayerProps);
}

interface Tile3DLayerProps<DataT = unknown> extends CompositeLayerProps {
  /** URL to the 3D tileset JSON file */
  data: string;
  
  /** Color accessor for point clouds */
  getPointColor?: Accessor<DataT, Color>;
  
  /** Global radius of all points in pixels */
  pointSize?: number;
  
  /** Loader for decoding tiles (deprecated - use loaders instead) */
  loader?: typeof Tiles3DLoader;
  
  /** Called when Tileset JSON file is loaded */
  onTilesetLoad?: (tileset: Tileset3D) => void;
  
  /** Called when a tile in the tileset hierarchy is loaded */
  onTileLoad?: (tile: Tile3D) => void;
  
  /** Called when a tile is unloaded */
  onTileUnload?: (tile: Tile3D) => void;
  
  /** Called when a tile fails to load */
  onTileError?: (tile: Tile3D, url: string, message: string) => void;
  
  /** (Experimental) Accessor to change color of mesh based on properties */
  _getMeshColor?: (tile: Tile3D) => Color;
}

type Accessor<DataT, ValueT> = ValueT | ((d: DataT, info?: any) => ValueT);
type Color = [r: number, g: number, b: number] | [r: number, g: number, b: number, a: number];

Usage Examples:

import { Tile3DLayer } from "@deck.gl/geo-layers";

// Basic 3D building tiles
const buildingLayer = new Tile3DLayer({
  id: '3d-buildings',
  data: 'https://tiles.example.com/buildings/tileset.json',
  
  onTilesetLoad: tileset => {
    console.log('Tileset loaded:', tileset.root);
    console.log('Bounding volume:', tileset.boundingVolume);
  },
  
  onTileLoad: tile => {
    console.log(`Tile loaded: ${tile.id}, LOD: ${tile.lodMetricValue}`);
  },
  
  onTileError: (tile, error) => {
    console.error(`Failed to load tile ${tile.id}:`, error);
  },
  
  pickable: true
});

// Photogrammetry with point styling
const photogrammetryLayer = new Tile3DLayer({
  id: 'photogrammetry',
  data: 'https://tiles.example.com/photogrammetry/tileset.json',
  
  // Color point clouds based on tile properties  
  getPointColor: [120, 120, 255, 255],
  pointSize: 1.5,
  
  onTileLoad: tile => {
    console.log(`Loaded tile: ${tile.id}, Type: ${tile.type}`);
  },
  
  pickable: true
});

// Point cloud visualization
const pointCloudLayer = new Tile3DLayer({
  id: 'point-cloud',
  data: 'https://tiles.example.com/lidar/tileset.json',
  
  pointSize: 2, // Point size in pixels
  getPointColor: [255, 128, 0, 255], // Orange points
  
  onTileLoad: tile => {
    console.log(`Loaded point cloud tile: ${tile.id}`);
    console.log(`Content type: ${tile.content?.type}`);
  },
  
  pickable: true
});

// Custom mesh coloring
const coloredMeshLayer = new Tile3DLayer({
  id: 'colored-mesh',
  data: 'https://tiles.example.com/buildings/tileset.json',
  
  // Experimental mesh coloring based on tile properties
  _getMeshColor: tile => {
    // Color buildings based on height or other properties
    if (tile.boundingVolume?.sphere?.[2] > 100) {
      return [255, 0, 0]; // Red for tall buildings
    }
    return [100, 100, 255]; // Blue for regular buildings
  },
  
  pointSize: 1.0,
  pickable: true
});

3D Tiles Specification Support

Tileset Structure

Support for standard 3D Tiles tileset.json format and tile hierarchy.

interface Tileset3D {
  /** Root tile of the tileset */
  root: Tile3DHeader;
  
  /** Tileset metadata */
  asset: {
    version: string;
    tilesetVersion?: string;
    gltfUpAxis?: 'X' | 'Y' | 'Z';
  };
  
  /** Bounding volume for entire tileset */
  boundingVolume: BoundingVolume;
  
  /** Geometric error for the tileset */
  geometricError: number;
  
  /** Properties metadata */
  properties?: {[key: string]: any};
  
  /** Extensions used by the tileset */
  extensions?: {[key: string]: any};
  
  /** Extra data */
  extras?: any;
}

interface Tile3DHeader {
  /** Tile identifier */
  id: string;
  
  /** Bounding volume of the tile */
  boundingVolume: BoundingVolume;
  
  /** Geometric error of this tile */
  geometricError: number;
  
  /** Refinement strategy ('ADD' or 'REPLACE') */
  refine?: 'ADD' | 'REPLACE';
  
  /** Transform matrix for tile positioning */
  transform?: number[];
  
  /** Content information */
  content?: TileContent;
  
  /** Child tiles */
  children?: Tile3DHeader[];
  
  /** Level-of-detail metric value */
  lodMetricValue?: number;
  
  /** Whether tile is currently selected for rendering */
  selected: boolean;
  
  /** Whether tile content is loaded */
  contentLoaded: boolean;
}

interface BoundingVolume {
  /** Bounding box [centerX, centerY, centerZ, halfSizeX, halfSizeY, halfSizeZ] */
  box?: number[];
  
  /** Bounding sphere [centerX, centerY, centerZ, radius] */
  sphere?: number[];
  
  /** Bounding region [west, south, east, north, minHeight, maxHeight] */
  region?: number[];
}

interface TileContent {
  /** URI to tile content */
  uri?: string;
  
  /** Content bounding volume (optional override) */
  boundingVolume?: BoundingVolume;
  
  /** Content type */
  type?: 'b3dm' | 'i3dm' | 'pnts' | 'cmpt' | 'glb' | 'gltf';
}

Content Type Support

Batch 3D Model (B3DM)

Support for textured 3D models like buildings with batch tables for feature data.

interface B3DMContent {
  /** GLTF model data */
  gltf: any;
  
  /** Batch table with feature properties */
  batchTable?: {
    [property: string]: any[];
  };
  
  /** Number of features in the batch */
  featuresLength: number;
}

B3DM Example:

const buildingsLayer = new Tile3DLayer({
  id: 'buildings-b3dm',
  data: 'https://tiles.example.com/manhattan/tileset.json',
  
  onTileLoad: tile => {
    if (tile.content?.batchTable) {
      console.log('Building features:', tile.content.featuresLength);
      console.log('Properties:', Object.keys(tile.content.batchTable));
    }
  },
  
  getColor: (object, {index}) => {
    // Color buildings based on batch properties
    const height = object?.batchTable?.Height?.[index] || 0;
    return height > 100 ? [255, 0, 0] : [100, 100, 255];
  },
  
  pickable: true
});

Instanced 3D Model (I3DM)

Support for instanced models with per-instance transformations.

interface I3DMContent {
  /** GLTF model template */
  gltf: any;
  
  /** Instance positions and orientations */
  instances: {
    positions: Float32Array;
    normals?: Float32Array;
    scales?: Float32Array;
  };
  
  /** Number of instances */
  instancesLength: number;
  
  /** Batch table for instance properties */
  batchTable?: {[property: string]: any[]};
}

Point Cloud (PNTS)

Support for point cloud data with positions, colors, and classifications.

interface PNTSContent {
  /** Point positions */
  positions: Float32Array;
  
  /** Point colors (optional) */
  colors?: Uint8Array;
  
  /** Point normals (optional) */
  normals?: Float32Array;
  
  /** Point classifications (optional) */
  classifications?: Uint8Array;
  
  /** Number of points */
  pointsLength: number;
  
  /** Feature table with point properties */
  featureTable?: {[property: string]: any};
}

Point Cloud Example:

const lidarLayer = new Tile3DLayer({
  id: 'lidar-points',
  data: 'https://tiles.example.com/lidar/tileset.json',
  
  pointSize: 1.5,
  
  onTileLoad: tile => {
    if (tile.content?.pointsLength) {
      console.log(`Loaded ${tile.content.pointsLength} points`);
      
      // Access point cloud data
      const positions = tile.content.positions;
      const colors = tile.content.colors;
      const classifications = tile.content.classifications;
    }
  },
  
  // Custom point styling based on classification
  getPointColor: (object, {index}) => {
    const classification = object?.classifications?.[index] || 0;
    switch (classification) {
      case 2: return [139, 69, 19];   // Ground - brown
      case 5: return [0, 255, 0];     // Vegetation - green  
      case 6: return [70, 130, 180];  // Building - blue
      case 9: return [128, 128, 128]; // Water - gray
      default: return [255, 255, 255]; // Other - white
    }
  },
  
  pickable: true
});

Performance Optimization

Level-of-Detail Management

3D Tiles automatically manages LOD based on distance and screen space error.

interface LODProps {
  /** Maximum screen space error in pixels */
  maximumScreenSpaceError?: number;
  
  /** Maximum number of requests for loading tiles */
  maxRequests?: number;
  
  /** Tile cache size limit */
  tileCacheSize?: number;
  
  /** Skip levels of detail for faster initial loading */
  skipLevelOfDetail?: boolean;
}

LOD Configuration:

// High detail for close inspection
const highDetailLayer = new Tile3DLayer({
  id: 'high-detail',
  data: 'https://tiles.example.com/detailed/tileset.json',
  maximumScreenSpaceError: 2, // Very low error threshold
  maxRequests: 20,
  tileCacheSize: 200
});

// Performance optimized for overview
const performanceLayer = new Tile3DLayer({
  id: 'performance',
  data: 'https://tiles.example.com/overview/tileset.json',
  maximumScreenSpaceError: 16, // Higher error threshold
  maxRequests: 6,
  skipLevelOfDetail: true,
  tileCacheSize: 50
});

Memory Management

// Monitor tile loading and memory usage
const monitoredLayer = new Tile3DLayer({
  id: 'monitored',
  data: 'https://tiles.example.com/large/tileset.json',
  
  onTileLoad: tile => {
    console.log(`Loaded: ${tile.id}, Memory: ${getApproxMemoryUsage(tile)}`);
  },
  
  onTileUnload: tile => {
    console.log(`Unloaded: ${tile.id}`);
  },
  
  tileCacheSize: 100, // Limit cache size
  maxRequests: 8
});

function getApproxMemoryUsage(tile) {
  // Rough memory estimation
  if (tile.content?.gltf) {
    return `~${Math.round(JSON.stringify(tile.content.gltf).length / 1024)}KB`;
  }
  return 'Unknown';
}