From cesiumjs-skills
Loads 3D Tiles tilesets and Mapbox Vector Tiles as runtime 3D Tiles in CesiumJS. Covers async factory methods, LOD options, styling, metadata, voxels, point clouds, clipping planes/polygons, and feature picking.
How this skill is triggered — by the user, by Claude, or both
Slash command
/cesiumjs-skills:cesiumjs-3d-tilesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Version baseline: CesiumJS v1.142 (ES module imports, async factory methods).
Version baseline: CesiumJS v1.142 (ES module imports, async factory methods).
Always use async factory methods -- never call the constructor directly.
import { Cesium3DTileset, HeadingPitchRange, Math as CesiumMath } from "cesium";
// From a URL
const tileset = await Cesium3DTileset.fromUrl(
"https://example.com/tileset.json",
{ maximumScreenSpaceError: 16 }, // lower = higher quality
);
viewer.scene.primitives.add(tileset);
viewer.zoomTo(tileset, new HeadingPitchRange(
0.0, CesiumMath.toRadians(-25.0), tileset.boundingSphere.radius * 2.0,
));
// From Cesium ion
const tileset = await Cesium3DTileset.fromIonAssetId(75343);
viewer.scene.primitives.add(tileset);
// Google Photorealistic 3D Tiles
import { createGooglePhotorealistic3DTileset } from "cesium";
const google3D = await createGooglePhotorealistic3DTileset({
onlyUsingWithGoogleGeocoder: true,
});
viewer.scene.primitives.add(google3D);
// OSM Buildings
import { createOsmBuildingsAsync } from "cesium";
const osmBuildings = await createOsmBuildingsAsync();
viewer.scene.primitives.add(osmBuildings);
| Option | Default | Purpose |
|---|---|---|
maximumScreenSpaceError | 16 | LOD quality threshold (pixels) |
cacheBytes | 536870912 | Tile cache trim target (bytes) |
maximumCacheOverflowBytes | 536870912 | Extra cache headroom |
shadows | ShadowMode.ENABLED | Shadow casting/receiving |
modelMatrix | Matrix4.IDENTITY | Root transform |
clippingPlanes | undefined | ClippingPlaneCollection |
clippingPolygons | undefined | ClippingPolygonCollection (WebGL 2) |
enableCollision | false | Camera collision with tileset surface |
pointCloudShading | undefined | Point attenuation options object |
classificationType | undefined | TERRAIN, CESIUM_3D_TILE, or BOTH |
dynamicScreenSpaceError | true | Horizon LOD optimization |
foveatedScreenSpaceError | true | Center-screen tile priority |
preloadFlightDestinations | true | Prefetch tiles at flight target |
featureIdLabel | "featureId_0" | EXT_mesh_features ID set label |
backFaceCulling | true | Cull back faces per glTF material |
edgeDisplayMode | EdgeDisplayMode.SURFACES_ONLY | Render glTF edge-visibility data when present |
MVTDataProvider loads {z}/{x}/{y} Mapbox Vector Tile .mvt/.pbf
templates and converts tile payloads into runtime 3D Tiles. Use it when vector
data is naturally tiled and you want 3D Tiles styling, metadata picking, and LOD
instead of a single GeoJSON primitive.
For one in-memory or URL-backed GeoJSON object, prefer GeoJsonPrimitive in
cesiumjs-primitives. For Entity/DataSource conveniences, prefer
GeoJsonDataSource in cesiumjs-entities.
import {
Cesium3DTileStyle,
MVTDataProvider,
Rectangle,
} from "cesium";
const provider = await MVTDataProvider.fromUrl(
"https://example.com/tiles/{z}/{x}/{y}.pbf",
{
minZoom: 4,
maxZoom: 14,
extent: Rectangle.fromDegrees(-125, 24, -66, 50),
featureIdProperty: "id",
},
);
viewer.scene.primitives.add(provider);
// The provider owns a generated Cesium3DTileset.
provider.tileset.style = new Cesium3DTileStyle({
color: {
conditions: [
["${kind} === 'park'", "color('seagreen', 0.65)"],
["${kind} === 'water'", "color('steelblue', 0.55)"],
["true", "color('white', 0.45)"],
],
},
});
Feature properties are encoded as EXT_structural_metadata, so standard
3D Tiles styling and picking patterns apply:
const picked = viewer.scene.pick(windowPosition);
if (picked && typeof picked.getProperty === "function") {
console.log(picked.getProperty("name"));
}
Notes:
{z}, {x}, and {y} placeholders; tile URLs are parsed from /z/x/y.provider.show proxies visibility to the generated tileset.EXT_mesh_polygon and 3DTILES_content_gltf_vector support; treat this path as experimental.tileset.loadProgress.addEventListener((pending, processing) => {
if (pending === 0 && processing === 0) console.log("Loaded");
});
tileset.initialTilesLoaded.addEventListener(() => { /* first view ready */ });
tileset.allTilesLoaded.addEventListener(() => { /* all visible tiles ready */ });
tileset.tileLoad.addEventListener((tile) => { /* tile content loaded */ });
tileset.tileUnload.addEventListener((tile) => { /* tile evicted from cache */ });
tileset.tileFailed.addEventListener(({ url, message }) => {
console.error(`Tile ${url}: ${message}`);
});
// Per-frame manual styling
tileset.tileVisible.addEventListener((tile) => {
const content = tile.content;
for (let i = 0; i < content.featuresLength; i++) {
content.getFeature(i).color = Cesium.Color.fromRandom();
}
});
tileset.show = false; // toggle visibility
tileset.maximumScreenSpaceError = 8; // increase quality
const { center, radius } = tileset.boundingSphere;
import { Matrix4, Cartesian3 } from "cesium";
tileset.modelMatrix = Matrix4.fromTranslation(new Cartesian3(0, 0, 100));
Assign a Cesium3DTileStyle to tileset.style. Expressions reference feature
properties with ${PropertyName}.
import { Cesium3DTileStyle } from "cesium";
// Color by height conditions
tileset.style = new Cesium3DTileStyle({
color: {
conditions: [
["${Height} >= 100", "color('purple', 0.5)"],
["${Height} >= 50", "color('red')"],
["true", "color('blue')"],
],
},
show: "${Height} > 0",
});
// Use defines to simplify repeated sub-expressions
tileset.style = new Cesium3DTileStyle({
defines: { material: "${feature['building:material']}" },
color: {
conditions: [
["${material} === null", "color('white')"],
["${material} === 'glass'", "color('skyblue', 0.5)"],
["${material} === 'brick'", "color('indianred')"],
["true", "color('white')"],
],
},
});
// Show/hide by property
tileset.style = new Cesium3DTileStyle({
show: "${feature['building']} === 'office'",
});
// Point cloud styling
tileset.style = new Cesium3DTileStyle({
color: "vec4(${Temperature})",
pointSize: "${Temperature} * 2.0",
});
tileset.style = undefined; // reset to default appearance
import { Cesium3DTileColorBlendMode } from "cesium";
tileset.colorBlendMode = Cesium3DTileColorBlendMode.REPLACE; // HIGHLIGHT | REPLACE | MIX
tileset.colorBlendAmount = 0.5; // only used with MIX
edgeDisplayMode controls edges contributed by the draft glTF
EXT_mesh_primitive_edge_visibility extension. Tiles without that extension
render normally regardless of this setting.
import { Cesium3DTileset, EdgeDisplayMode } from "cesium";
const tileset = await Cesium3DTileset.fromUrl("/cad/tileset.json", {
edgeDisplayMode: EdgeDisplayMode.SURFACES_AND_EDGES,
});
viewer.scene.primitives.add(tileset);
// CAD-style wireframe for content that carries edge-visibility data.
tileset.edgeDisplayMode = EdgeDisplayMode.EDGES_ONLY;
// Default rendering: hide extension-provided edges.
tileset.edgeDisplayMode = EdgeDisplayMode.SURFACES_ONLY;
Scene.pick returns Cesium3DTileFeature for 3D Tiles features. Modifications
persist until the owning tile is evicted from the cache.
import {
ScreenSpaceEventHandler, ScreenSpaceEventType,
Cesium3DTileFeature, Color,
} from "cesium";
const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
// Hover: read properties
handler.setInputAction((movement) => {
const feature = viewer.scene.pick(movement.endPosition);
if (feature instanceof Cesium3DTileFeature) {
const ids = feature.getPropertyIds();
for (const id of ids) console.log(`${id}: ${feature.getProperty(id)}`);
feature.color = Color.YELLOW; // highlight
}
}, ScreenSpaceEventType.MOUSE_MOVE);
// Click: inspect a single property
handler.setInputAction((movement) => {
const feature = viewer.scene.pick(movement.position);
if (feature instanceof Cesium3DTileFeature) {
console.log("Height:", feature.getProperty("Height"));
feature.setProperty("selected", true); // write custom property
feature.show = false; // hide individual feature
}
}, ScreenSpaceEventType.LEFT_CLICK);
// Searches: batch table -> content -> tile -> subtree -> group -> tileset
const value = feature.getPropertyInherited("semanticOrPropertyName");
ClippingPlaneCollection clips via half-space planes in the tileset's local
coordinate system.
import {
ClippingPlane, ClippingPlaneCollection,
Cartesian3, Color, Matrix4,
} from "cesium";
const clippingPlanes = new ClippingPlaneCollection({
planes: [new ClippingPlane(new Cartesian3(0.0, 0.0, -1.0), 0.0)],
edgeWidth: 1.0,
edgeColor: Color.WHITE,
unionClippingRegions: false, // false = intersection (AND); true = union (OR)
});
const tileset = await Cesium3DTileset.fromUrl(url, { clippingPlanes });
// Or: tileset.clippingPlanes = clippingPlanes;
// Offset the clip boundary at runtime
clippingPlanes.modelMatrix = Matrix4.fromTranslation(new Cartesian3(0, 0, 50));
clippingPlanes.get(0).distance = 25.0;
ClippingPolygonCollection clips using arbitrary polygons. WebGL 2 only.
import { ClippingPolygon, ClippingPolygonCollection, Cartesian3 } from "cesium";
const polygon = new ClippingPolygon({
positions: Cartesian3.fromDegreesArray([
-105.0077, 39.7519, -105.0095, 39.7504,
-105.0071, 39.7513, -105.0077, 39.7519,
]),
});
tileset.clippingPolygons = new ClippingPolygonCollection({
polygons: [polygon],
inverse: false, // false = clip inside polygon; true = clip outside
});
// Also works on the globe
viewer.scene.globe.clippingPolygons = new ClippingPolygonCollection({
polygons: [polygon],
});
const tileset = await Cesium3DTileset.fromUrl(pointCloudUrl, {
pointCloudShading: {
attenuation: true, // scale points by geometric error
geometricErrorScale: 1.0,
maximumAttenuation: 10, // max pixel size; undefined = maximumScreenSpaceError
eyeDomeLighting: true, // depth-aware edge enhancement
eyeDomeLightingStrength: 1.0,
eyeDomeLightingRadius: 1.0,
backFaceCulling: false, // requires normals in point data
normalShading: true,
},
});
viewer.scene.primitives.add(tileset);
// Runtime adjustment
tileset.pointCloudShading.eyeDomeLightingStrength = 2.0;
VoxelPrimitive renders volumetric data from a Cesium3DTilesVoxelProvider.
Shapes: BOX, CYLINDER, ELLIPSOID (see VoxelShapeType).
import { VoxelPrimitive, Cesium3DTilesVoxelProvider, CustomShader } from "cesium";
const provider = await Cesium3DTilesVoxelProvider.fromUrl("voxel/tileset.json");
const voxelPrimitive = new VoxelPrimitive({
provider,
customShader: new CustomShader({
fragmentShaderText: `void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
material.diffuse = fsInput.metadata.a.rgb;
material.alpha = fsInput.metadata.a.a;
}`,
}),
});
viewer.scene.primitives.add(voxelPrimitive);
voxelPrimitive.nearestSampling = true;
viewer.camera.flyToBoundingSphere(voxelPrimitive.boundingSphere, { duration: 0 });
// For voxel shader authoring — struct availability, raymarching semantics, metadata
// access — see the cesiumjs-custom-shader skill. This skill covers VoxelPrimitive setup.
// Optional inspector widget
viewer.extend(Cesium.viewerVoxelInspectorMixin);
viewer.voxelInspector.viewModel.voxelPrimitive = voxelPrimitive;
Load Esri I3S scene layers (3D Objects, IntegratedMesh, Building Scene Layer).
import { I3SDataProvider, ArcGISTiledElevationTerrainProvider, Ellipsoid, Rectangle } from "cesium";
const geoidService = await ArcGISTiledElevationTerrainProvider.fromUrl(
"https://tiles.arcgis.com/tiles/.../EGM2008/ImageServer",
);
const i3sProvider = await I3SDataProvider.fromUrl(
"https://tiles.arcgis.com/tiles/.../SceneServer/layers/0",
{ geoidTiledTerrainProvider: geoidService },
);
viewer.scene.primitives.add(i3sProvider);
const center = Rectangle.center(i3sProvider.extent);
center.height = 5000.0;
viewer.camera.setView({
destination: Ellipsoid.WGS84.cartographicToCartesian(center),
});
Loaded as standard 3D Tiles; CesiumJS handles KHR_gaussian_splatting automatically.
const splats = await Cesium3DTileset.fromIonAssetId(3667783);
viewer.scene.primitives.add(splats);
viewer.zoomTo(splats);
Drape tileset geometry as a classification overlay on terrain or other tilesets.
import { Cesium3DTileset, ClassificationType } from "cesium";
const classified = await Cesium3DTileset.fromUrl(url, {
classificationType: ClassificationType.BOTH, // TERRAIN | CESIUM_3D_TILE | BOTH
});
viewer.scene.primitives.add(classified);
import { Cartographic, Cartesian3, Matrix4 } from "cesium";
const cartographic = Cartographic.fromCartesian(tileset.boundingSphere.center);
const surface = Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0);
const offset = Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, heightOffset);
const translation = Cartesian3.subtract(offset, surface, new Cartesian3());
tileset.modelMatrix = Matrix4.fromTranslation(translation);
maximumScreenSpaceError as high as acceptable (16 default; 32+ for mobile).dynamicScreenSpaceError: true for street-level views with large tilesets.foveatedScreenSpaceError: true to prioritize center-screen tiles.cacheBytes and maximumCacheOverflowBytes to device memory (512 MB each default).preloadFlightDestinations: true to prefetch tiles at the camera flight target.skipLevelOfDetail: true for large replacement-refined tilesets to reduce memory.maximumScreenSpaceError below 4 -- diminishing returns, many more tile requests.attenuation and eyeDomeLighting to fill gaps and add depth.enableCollision: false unless camera collision or CLAMP_TO_GROUND on tiles is needed.show: false and preloadWhenHidden: true.tileFailed to log errors; call trimLoadedTiles() after large camera jumps.Cesium3DTileset.customShader and VoxelPrimitive.customShader (struct reference, feature IDs, metadata)npx claudepluginhub cesiumgs/cesiumjs-skills --plugin cesiumjs-skillsSets up CesiumJS Viewer and Scene configuration including Ion tokens, Google Maps, iTwin, widgets, and geocoders. Use when initializing a 3D globe application.
Adds 3D layers including SceneLayer, IntegratedMeshLayer, PointCloudLayer, VoxelLayer, and DimensionLayer to ArcGIS SceneView for buildings, LiDAR, volumetric data, glTF models, and measurements.
Guides users through first interactions with the Cesium 3D globe via MCP tools, including camera navigation, entity creation, and layer loading.