Skip to content

ThreeView Functions

This page describes all functions (methods) available on a ThreeView instance.

Adds a new resource layer to navara_three. This method is used for resource layers only (vector, raster, terrain, 3d-tiles). Each resource layer references a source via its source property. For mesh, light, and effect descriptors, use addMesh(), addLight(), and addEffect() respectively.

Syntax:

addLayer(l: LayerDescription): Layer

Parameters:

For layer configuration options, see Layer Types and each layer type page.

Returns:

Layer;

Returns a Layer instance for the added resource layer.

Example:

const source = view.addSource({
type: "raster-tile",
url: "https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg",
maxZoom: 23,
});
const layer = view.addLayer({
type: "raster",
source,
raster: {
color: new Color().setStyle("#cccccc"),
},
});

Registers a data source and returns a Source handle. A source describes where data comes from and how it is fetched/decoded; reference it from a resource layer via the layer’s source property (the handle or its id).

Syntax:

addSource(s: SourceDescription): Source

Parameters:

For the available source types and their fields, see About Source.

Returns:

Source;

A Source handle exposing id, type, update(s), and delete().

Example:

const imagery = view.addSource({
type: "raster-tile",
url: "https://example.com/{z}/{x}/{y}.png",
maxZoom: 19,
});
view.addLayer({ type: "raster", source: imagery });
// Later
imagery.update({ type: "raster-tile", url: "https://example.com/new/{z}/{x}/{y}.png" });
imagery.delete();

Adds a new mesh descriptor to navara_three. The mesh descriptor class must be registered with registerMesh() before calling this method.

Syntax:

addMesh<L = unknown>(l: MeshDescription): MeshHandle<L>

Returns:

MeshHandle<L>;

Returns a MeshHandle<L> for controlling the mesh descriptor.

Example:

// SkyMeshDesc must be registered
const skyHandle = view.addMesh<SkyMeshDesc>({ sky: {} });

Adds a new light descriptor to navara_three. The light descriptor class must be registered with registerLight() before calling this method.

Syntax:

addLight<L = unknown>(l: LightDescription): LightHandle<L>

Returns:

LightHandle<L>;

Returns a LightHandle<L> for controlling the light descriptor.

Example:

// SunLightDesc must be registered
const sunHandle = view.addLight<SunLightDesc>({ sun: { intensity: 1.0 } });

Adds a new effect descriptor to navara_three. The effect descriptor class must be registered with registerEffect() before calling this method.

Syntax:

addEffect<L = unknown>(l: EffectDescription): EffectHandle<L>

Returns:

EffectHandle<L>;

Returns a EffectHandle<L> for controlling the effect descriptor.

Example:

// FXAAEffectDesc must be registered
const fxaaHandle = view.addEffect<FXAAEffectDesc>({ fxaa: {} });

Updates an existing resource layer’s configuration by its ID. Only works for resource layers added via addLayer().

Syntax:

updateLayerById(id: string, l: LayerDescription): void

Parameters:

  • id: The unique identifier of the layer to update
  • l: Specifies the properties to update

Example:

const id = layer.id; // Get the layer ID from the addLayer return value
// `source` is the raster-tile source referenced by the layer.
view.updateLayerById(id, {
type: "raster",
source,
raster: {
color: new Color().setStyle("#ffffff"),
},
});

Updates an existing mesh descriptor’s configuration by its ID. Accepts the same descriptor shape as addMesh().

Syntax:

updateMeshById(id: string, updates: OmitType<MeshConfig | D["mesh"]>): void

Parameters:

  • id: The unique identifier of the mesh to update
  • updates: Configuration object with properties to update (same shape as addMesh())

Example:

const handle = view.addMesh<BoxMeshDesc>({ box: { width: 100 } });
view.updateMeshById(handle.id, { box: { width: 200 } });

Updates an existing light descriptor’s configuration by its ID. Accepts the same descriptor shape as addLight().

Syntax:

updateLightById(id: string, updates: OmitType<LightConfig | D["light"]>): void

Parameters:

  • id: The unique identifier of the light to update
  • updates: Configuration object with properties to update (same shape as addLight())

Example:

const handle = view.addLight<SunLightDesc>({ sun: { intensity: 1.0 } });
view.updateLightById(handle.id, { sun: { intensity: 0.5 } });

Updates an existing effect descriptor’s configuration by its ID. Accepts the same descriptor shape as addEffect().

Syntax:

updateEffectById(id: string, updates: OmitType<BuiltInEffectDescription | EffectConfig | D["effect"]>): void

Parameters:

  • id: The unique identifier of the effect to update
  • updates: Configuration object with properties to update (same shape as addEffect())

Example:

const handle = view.addEffect<SSAOEffectDesc>({ ssao: { radius: 0.5 } });
view.updateEffectById(handle.id, { ssao: { radius: 1.0 } });

Deletes a resource layer from the scene by its ID.

Syntax:

deleteLayerById(id: string): boolean

Parameters:

  • id: The unique identifier of the layer to delete

Returns: true if the layer was found and deleted, false otherwise.

Example:

const id = layer.id;
view.deleteLayerById(id);

Deletes a mesh descriptor from the scene by its ID.

Syntax:

deleteMeshById(id: string): boolean

Parameters:

  • id: The unique identifier of the mesh to delete

Returns: true if the mesh was found and deleted, false otherwise.

Example:

view.deleteMeshById(handle.id);

Deletes a light descriptor from the scene by its ID.

Syntax:

deleteLightById(id: string): boolean

Parameters:

  • id: The unique identifier of the light to delete

Returns: true if the light was found and deleted, false otherwise.

Example:

view.deleteLightById(handle.id);

Deletes an effect descriptor from the scene by its ID.

Syntax:

deleteEffectById(id: string): boolean

Parameters:

  • id: The unique identifier of the effect to delete

Returns: true if the effect was found and deleted, false otherwise.

Example:

view.deleteEffectById(handle.id);

Initializes the 3D engine and WASM modules, and starts the main rendering loop. You must call this method before using the view.

Syntax:

async init(): Promise<void>

Returns:

A Promise<void> that resolves when initialization is complete.

Example:

const view = new ThreeView();
await view.init();
// Add layers after init()
const osm = view.addSource({
type: "raster-tile",
url: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
maxZoom: 19,
});
view.addLayer({ type: "raster", source: osm });

Releases all resources and stops the rendering loop. Call this method when the view is no longer needed.

Syntax:

dispose(): void

Example:

// Cleanup on component unmount
view.dispose();

Changes the renderer size and updates the camera aspect ratio. Automatically called on window resize unless disableAutoResize is true.

Syntax:

resize(width?: number, height?: number, pixelRatio?: number): void

Parameters:

  • width: New width (pixels). Uses canvas size when omitted
  • height: New height (pixels). Uses canvas size when omitted
  • pixelRatio: Device pixel ratio

Example:

// Resize with explicit dimensions
view.resize(1920, 1080, 2);
// Resize using current canvas size (only updating pixel ratio)
view.resize(undefined, undefined, window.devicePixelRatio);

Sets the camera position and orientation immediately. Moves the camera directly without animation.

Syntax:

setCamera(camPos: CameraPosition): void

Parameters:

  • camPos: Camera position and orientation
type CameraPosition = {
lng?: number;
lat?: number;
height?: number;
pitch?: number;
heading?: number;
roll?: number;
distance?: number;
};
FieldTypeDescription
lngnumberLongitude (degrees)
latnumberLatitude (degrees)
heightnumberHeight above the ellipsoid (meters). When distance is also set, this is used as the target point elevation — the camera is placed distance meters from that elevated target.
pitchnumberPitch angle (degrees)
headingnumberHeading angle (degrees)
rollnumberRoll angle (degrees)
distancenumberDistance from the target point along the camera forward direction (meters). When specified, the camera is placed so that its forward ray reaches the lng/lat/height target from this distance. If omitted, height is used as the camera’s own altitude above the surface normal.

Example:

// Altitude-based: place the camera 1000 m above Tokyo along the surface normal
view.setCamera({
lng: 139.7671,
lat: 35.6812,
height: 1000,
pitch: -45,
heading: 0,
roll: 0,
});
// Distance-based: frame a mountain summit (height = 3776 m) from 5000 m away
view.setCamera({
lng: 138.7274,
lat: 35.3606,
height: 3776,
distance: 5000,
pitch: -20,
heading: 0,
});

Moves the camera in the specified direction by the specified amount.

Syntax:

moveCamera(move: CameraDirection, amount: number): void

Parameters:

  • move: Camera movement direction
  • amount: Amount to move (meters)

CameraDirection is an enum with the following values:

enum CameraDirection {
Forward,
Backward,
Left,
Right,
Up,
Down,
}

Example:

import ThreeView, { CameraDirection } from "@navaramap/three";
view.moveCamera(CameraDirection.Forward, 100);
view.moveCamera(CameraDirection.Up, 50);

Moves the camera with a custom direction vector.

Syntax:

moveCameraWithDirection(dir: number[], amount: number): void

Parameters:

  • dir: [x, y, z] direction vector
  • amount: Amount to move (meters)

Example:

view.moveCameraWithDirection([1, 0, 0], 100);

Animates the camera to a target position. Moves smoothly along a flight arc.

Syntax:

flyTo(
camPos: CameraPosition & Required<Pick<CameraPosition, "lng" | "lat" | "height">>,
duration?: number,
maxHeight?: number
): void

Parameters:

  • camPos: Target position. lng, lat, and height are required.
    • lng: Longitude (degrees) — required
    • lat: Latitude (degrees) — required
    • height: Height above the ellipsoid (meters) — required. When distance is also set, this is used as the target point elevation rather than the camera’s own altitude.
    • pitch: Pitch angle (degrees)
    • heading: Heading angle (degrees)
    • roll: Roll angle (degrees)
    • distance: Distance from the target point along the camera forward direction (meters). When specified, the camera is placed so that its forward ray reaches the lng/lat/height target from this distance. If omitted, height is used as the camera’s own altitude above the surface normal.
  • duration: Animation duration (milliseconds)
  • maxHeight: Maximum height during the flight arc (meters)

Example:

// Altitude-based: fly to Tokyo over 3 seconds (maximum height 5000 m)
view.flyTo(
{
lng: 139.7671,
lat: 35.6812,
height: 1000,
pitch: -45,
heading: 0,
},
3000,
5000
);
// Distance-based: approach Tokyo Tower (at ground level) from 2000 m away
view.flyTo(
{
lng: 139.7454,
lat: 35.6586,
height: 0,
distance: 2000,
pitch: -30,
heading: 45,
},
4000
);

Points the camera at a target position and places it at an offset position. The offset is specified in the East-North-Up (ENU) coordinate system.

Syntax:

lookAt(target: LatLngHeight, offset: Vector3): void

Parameters:

  • target: Target geodetic position
    • lng: Longitude (degrees)
    • lat: Latitude (degrees)
    • height: Height (meters)
  • offset: Offset from the target (ENU coordinate system, meters)
    • x: East direction
    • y: North direction
    • z: Up direction

Example:

import { Vector3 } from "three";
// Look down at Tokyo Tower from 1000m above
view.lookAt(
{ lng: 139.7454, lat: 35.6586, height: 0 },
new Vector3(0, 0, 1000) // 1000m directly above
);
// View from a diagonal behind
view.lookAt(
{ lng: 139.7454, lat: 35.6586, height: 0 },
new Vector3(500, -500, 500) // 500m east, 500m south, 500m up
);

Enables or disables camera follow mode. When enabled, the camera moves centered on the specified target position.

Syntax:

cameraFollow(enabled: boolean, target?: LatLngHeight, offset?: Vector3): void

Parameters:

  • enabled: Whether to enable follow mode
  • target: Target position to center on
    • lng: Longitude (degrees)
    • lat: Latitude (degrees)
    • height: Height (meters)
  • offset: Offset from the target (ENU coordinate system, meters)

Example:

import { Vector3 } from "three";
view.cameraFollow(
true,
{ lng: 139.7671, lat: 35.6812, height: 100 },
new Vector3(0, -200, 100) // 200m south, 100m up
);
// Disable follow mode
view.cameraFollow(false);

Enables or disables position-locked free-look. The camera stays planted at the target position while mouse drag rotates orientation in place. Useful for first-person-view “look around” controls where the eye must not move.

Syntax:

cameraFreeLook(enabled: boolean, target?: LatLngHeight): void

Parameters:

  • enabled: Whether to enable free-look mode
  • target: Target position the camera is locked to
    • lng: Longitude (degrees)
    • lat: Latitude (degrees)
    • height: Height (meters)

When the target moves between calls (e.g. the player walks), the camera translates with it; orientation is preserved. Mouse wheel zoom is disabled in this mode (the camera is at zero distance from the pivot).

Example:

// Lock the camera at the player's eye position; drag to look around
view.cameraFreeLook(true, { lng: 139.7671, lat: 35.6812, height: 105 });
// Disable free-look mode
view.cameraFreeLook(false);

Synchronously gets the terrain height at a specified geodetic position. Returns undefined if terrain data has not yet been loaded.

Syntax:

sampleTerrainHeight(pos: LatLngHeight): number | undefined

Parameters:

  • pos: Geodetic position
    • lat: Latitude (radians)
    • lng: Longitude (radians)
    • height: Ignored

Returns:

Terrain height (meters), or undefined if terrain data is not available

Example:

// Specify latitude and longitude in radians
const lat = degreeToRadian(35.6812);
const lng = degreeToRadian(139.7671);
const height = view.sampleTerrainHeight({
lat,
lng,
height: 0,
});
if (height !== undefined) {
console.log(`Terrain height: ${height}m`);
} else {
console.log("Terrain data has not been loaded yet");
}

Monitors terrain height changes at a specific position. The callback is invoked whenever the terrain data is updated.

Syntax:

observeTerrainHeightAt(pos: LatLng, cb: (height: number) => void): () => void

Parameters:

  • pos: Position to monitor
    • lat: Latitude (radians)
    • lng: Longitude (radians)
  • cb: Callback invoked when the height is updated

Returns:

A cleanup function to stop monitoring

Example:

// Specify latitude and longitude in radians
const lat = degreeToRadian(35.6812);
const lng = degreeToRadian(139.7671);
const cleanup = view.observeTerrainHeightAt({ lat, lng }, (height) => {
console.log(`Terrain height updated: ${height}m`);
});
// Stop monitoring later
cleanup();

Rotates the camera around a specified axis. Specifying a zero vector uses the default axis.

Syntax:

rotateAroundAxis(axis: Vector3, angle: number): void

Parameters:

  • axis: Rotation axis
  • angle: Rotation angle (radians)

Example:

import { Vector3 } from "three";
// Rotate 45 degrees around the Y axis
view.rotateAroundAxis(new Vector3(0, 1, 0), Math.PI / 4);

Rotates the camera around the current look-at point or the center of the view.

Syntax:

rotateAround(angle: number): void

Parameters:

  • angle: Rotation angle (radians)

Example:

// Rotate 45 degrees
view.rotateAround(Math.PI / 4);
// Auto-rotation animation
const animate = () => {
view.rotateAround(0.005);
requestAnimationFrame(animate);
};
animate();

Forces the scene to re-render on the next frame. Used to manually trigger an update when animation: false.

Syntax:

forceUpdate(): void

Example:

view.forceUpdate();

Picks the terrain position at the given screen coordinates. Uses the same CSS pixel coordinates as clientX and clientY from mouse events.

Syntax:

pickTerrainPosition(x: number, y: number): Vector3 | null

Parameters:

  • x: Screen X coordinate (CSS pixels, same as MouseEvent.clientX)
  • y: Screen Y coordinate (CSS pixels, same as MouseEvent.clientY)

Returns:

World position (ECEF coordinates), or null if no terrain is hit

Example:

// Get terrain coordinates at the click position
view.on("click", (event) => {
const position = view.pickTerrainPosition(event.clientX, event.clientY);
if (position) {
console.log(`ECEF coordinates: ${position.x}, ${position.y}, ${position.z}`);
} else {
console.log("No terrain hit");
}
});

Picks the world position at the given screen coordinates using the full scene depth buffer. Unlike pickTerrainPosition(), this method reads from the combined depth texture that includes all rendered geometry (terrain, meshes, etc.), so it returns a hit even when non-terrain objects are in front of the terrain.

Syntax:

pickDepthPosition(x: number, y: number): Vector3 | null

Parameters:

  • x: Screen X coordinate (CSS pixels, same as MouseEvent.clientX)
  • y: Screen Y coordinate (CSS pixels, same as MouseEvent.clientY)

Returns:

World position (ECEF coordinates), or null if nothing is hit

Example:

view.on("click", (event) => {
const position = view.pickDepthPosition(event.clientX, event.clientY);
if (position) {
console.log(`ECEF coordinates: ${position.x}, ${position.y}, ${position.z}`);
} else {
console.log("Nothing hit");
}
});

Registers a custom mesh descriptor class.

Syntax:

registerMesh(name: string, meshClass: MeshDescConstructor): void

Parameters:

  • name: Name of the mesh descriptor to register
  • meshClass: Constructor of the mesh descriptor

Example:

class CustomMeshDesc extends MeshDesc {
onCreate() {
// Custom implementation
}
}
view.registerMesh("customMesh", CustomMeshDesc);

Registers a custom light descriptor class.

Syntax:

registerLight(name: string, lightClass: LightDescConstructor): void

Parameters:

  • name: Name of the light descriptor to register
  • lightClass: Constructor of the light descriptor

Example:

class CustomLightDesc extends LightDesc {
onCreate() {
// Custom implementation
}
}
view.registerLight("customLight", CustomLightDesc);

Registers a custom effect descriptor class.

Syntax:

registerEffect(name: string, effectClass: EffectDescConstructor): void

Parameters:

  • name: Name of the effect descriptor to register
  • effectClass: Constructor of the effect descriptor

Example:

class CustomEffectDesc extends EffectDesc {
onCreate() {
// Custom implementation
}
}
view.registerEffect("customEffect", CustomEffectDesc);

Registers a plugin. Must be called before view.init().

Syntax:

addPlugin(plugin: Plugin): this

Parameters:

  • plugin: A Plugin instance

Example:

const view = new ThreeView({});
view.addPlugin(pluginA).addPlugin(pluginB);
await view.init();

Registers a font family composed of multiple faces. Each face covers a set of unicode ranges and points to a separate font file URL (ttf, otf, woff, or woff2). Once a family is registered, a text layer can reference it by its family name through material.font; only the faces whose unicode ranges cover the characters in the label’s text are downloaded.

Face priority and fallback:

  • Faces are evaluated in the order they appear in faces. For each codepoint in text, the first face whose unicodeRanges contain the codepoint is used — so if ranges overlap, the earlier entry wins.
  • Codepoints that are not covered by any face fall back to the first face (faces[0]). This means the first face may also be downloaded for uncovered characters, even if its declared unicodeRanges do not include them.

To make this behavior predictable, put the face you want used as the fallback at index 0. Then order the remaining faces after it so that, when their ranges overlap, earlier entries have higher priority.

Returns the ThreeView instance so calls can be chained.

Syntax:

addFontFamily(family: FontFamily): this

Parameters:

  • family: A FontFamily object.
    • family: Unique name used to reference the family from material.font.
    • faces: Array of FontFace entries, each with:
      • url: URL of the font file.
      • unicodeRanges: Array of { from, to } code point ranges (inclusive) covered by this face.

Example:

view.addFontFamily({
family: "MapFont",
faces: [
{
url: "/fonts/latin.woff2",
unicodeRanges: [{ from: 0x0000, to: 0x024f }],
},
{
url: "/fonts/cjk.woff2",
unicodeRanges: [{ from: 0x4e00, to: 0x9fff }],
},
],
});
const source = view.addSource({
type: "geojson",
url: "/cities.geojson",
});
const layer = view.addLayer({
type: "vector",
source,
text: {
font: "MapFont",
},
});
layer.on("featureUpdated", ({ evaluator }) => {
evaluator.evaluate(
({ properties }) => {
const name = properties?.["name"] as string | undefined;
return { text: name ?? "", show: !!name };
},
{ filters: ["name"] },
);
});

Unregisters a previously added font family by name. Text layers that still reference the family will no longer be able to resolve it.

Returns the ThreeView instance so calls can be chained.

Syntax:

removeFontFamily(family: string): this

Parameters:

  • family: The family name passed to addFontFamily().

Example:

view.removeFontFamily("MapFont");

Updates the memory-pressure SSE degrade range at runtime. min is the resting multiplier applied even without budget pressure (a value greater than 1 coarsens far tiles at rest); max is the ceiling the dynamic degrade can climb to under memory pressure. The next traversal re-selects tile LODs with the new range. Setting min = max = 1 fully disables the pressure degrade.

Syntax:

setSseMultiplierRange(min: number, max: number): void

Parameters:

  • min: Resting (base) SSE multiplier applied without budget pressure
  • max: Ceiling the dynamic memory-pressure degrade can climb to

Example:

// Keep far tiles slightly coarse at rest, allow degrading up to 8x under pressure
view.setSseMultiplierRange(1.5, 8.0);
// Disable the memory-pressure degrade entirely
view.setSseMultiplierRange(1, 1);

Returns a snapshot of engine memory usage (WASM buffer bytes, GPU estimates, retained tile counts). Returns undefined before init().

Syntax:

memoryStats(): MemoryStats | undefined

Returns:

A plain MemoryStats object, or undefined before init():

type MemoryStats = {
// Total bytes of tile payloads, geometry, and DEM buffers in WASM linear memory
bufferTotalBytes: number;
// Bytes held in the JS-side buffer store (fetched MVT pbf and worker-built
// geometry that never enter WASM linear memory). Not part of bufferTotalBytes.
externalBufferBytes: number;
// Number of buffers tracked by the buffer store
bufferCount: number;
// Estimated GPU bytes (textures, geometry, render targets)
gpuBytesEst: number;
// CPU bytes outside the buffer store (chiefly feature-attribute tables)
externalCpuBytes: number;
// Reserved bytes for in-flight fetches (released when they land)
reservedBytes: number;
// Configured tile-cache budget; undefined when budgeting is disabled
budgetBytes: number | undefined;
// Cumulative count of evicted tiles
evictedCount: number;
// Current memory-pressure SSE multiplier (1 = no pressure)
sseMultiplier: number;
// Retained (deactivated but cached) tile counts per pipeline
retainedVector: number;
retainedTerrain: number;
retainedRaster: number;
retainedTiles3d: number;
};

Example:

const stats = view.memoryStats();
if (stats) {
const MB = 1024 * 1024;
console.log(`WASM buffers: ${(stats.bufferTotalBytes / MB).toFixed(1)} MB`);
console.log(`GPU estimate: ${(stats.gpuBytesEst / MB).toFixed(1)} MB`);
console.log(`evicted: ${stats.evictedCount}, sse x${stats.sseMultiplier}`);
}

Returns a snapshot of worker-side memory: per-tile-worker WASM heaps (point-in-time samples from the pool’s post-task probes — this call also requests fresh probes, whose results show up on the next call) and the font worker’s heap/cache breakdown. Returns undefined before init().

Syntax:

async workerMemoryStats(): Promise<WorkerMemoryStats | undefined>

Returns:

A Promise resolving to a WorkerMemoryStats object, or undefined before init():

type WorkerMemoryStats = {
// Tile-worker pool heaps (undefined per slot until first probed)
tileWorkers:
| {
// Last probed WASM heap per slot (undefined = not probed yet)
perSlot: (number | undefined)[];
// Sum of the probed heaps
totalBytes: number;
// The per-worker budget slots are recycled against
maxWorkerHeapBytes: number;
}
| undefined;
// Font worker heap/cache breakdown; undefined while no font is in use
fontWorker:
| {
// Total WASM linear memory of the font worker (never shrinks)
heapBytes: number;
fontCount: number;
atlasCount: number;
glyphCount: number;
// Raw font file bytes held by the cache
fontBytes: number;
// Monochrome (SDF/MSDF) atlas pixel bytes
atlasBytes: number;
// COLRv1 color atlas pixel bytes
colorAtlasBytes: number;
// Configured cache budget; undefined when unlimited
budgetBytes?: number;
}
| undefined;
};

Example:

const stats = await view.workerMemoryStats();
if (stats?.tileWorkers) {
const MB = 1024 * 1024;
console.log(`tile workers: ${(stats.tileWorkers.totalBytes / MB).toFixed(1)} MB`);
}
if (stats?.fontWorker) {
console.log(`font atlas bytes: ${stats.fontWorker.atlasBytes}`);
}