skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
cesiumgs/cesiumjs-skills217 installs

cesiumjs-viewer-setup

CesiumJS viewer setup - Viewer, CesiumWidget, widgets, Ion token, Scene configuration, SceneMode, factory helpers, geocoders, platform services. Use when initializing a CesiumJS application, configuring viewer widgets, setting Ion access tokens, creating default terrain or imagery, or bootstrapping a 3D globe.

How do I install this agent skill?

npx skills add https://github.com/cesiumgs/cesiumjs-skills --skill cesiumjs-viewer-setup
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    This skill provides a comprehensive reference for initializing and configuring CesiumJS viewers, including integration with various platform services like Cesium Ion and Google Maps. It follows standard development practices for documentation and contains no malicious code.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

What does this agent skill do?

CesiumJS Viewer & Scene Setup

Reference for bootstrapping CesiumJS applications: Viewer, CesiumWidget, Ion/GoogleMaps/ITwinPlatform configuration, widgets, factory helpers, geocoder services, viewer mixins, Credits, and related enums.

Quick Start

import { Viewer, ImageryLayer, OpenStreetMapImageryProvider } from "cesium";
import "cesium/Build/Cesium/Widgets/widgets.css";

const viewer = new Viewer("cesiumContainer", {
  baseLayer: new ImageryLayer(new OpenStreetMapImageryProvider({
    url: "https://tile.openstreetmap.org/",
    maximumLevel: 18,
  })),
  baseLayerPicker: false,
});

Required HTML: <div id="cesiumContainer" style="width:100%;height:100vh"></div>

Use Cesium ion defaults (Terrain.fromWorldTerrain, ImageryLayer.fromWorldImagery, createOsmBuildingsAsync, Google Photorealistic 3D Tiles) only when the target runtime has the required ion or Google entitlement. For public/no-token examples, choose explicit public providers and URL-backed 3D Tiles.

Framing Loaded Content (Critical)

After adding a tileset, model, or data source, you must explicitly frame it. A Viewer constructed with default options starts the camera at a fixed view of Earth. It does NOT auto-zoom to primitives you add. Forgetting this is the most common cause of "I see only gray surface" or "the asset is a speck in the corner" failures.

const tileset = await Cesium3DTileset.fromUrl(url);
viewer.scene.primitives.add(tileset);

// Pick ONE of:
await viewer.zoomTo(tileset);                 // instant fit to bounding sphere
await viewer.flyTo(tileset, { duration: 0 }); // animated; duration 0 = instant

viewer.zoomTo / viewer.flyTo accept Entity, Entity[], EntityCollection, DataSource, ImageryLayer, Cesium3DTileset, VoxelPrimitive, Model, or TimeDynamicPointCloud. They use the target's bounding sphere, which works for tilesets with arbitrary local coordinate systems where computing an ECEF camera position by hand will miss the asset entirely.

When you do need an explicit camera position (e.g., to satisfy a heading/pitch specification), still use viewer.zoomTo(target, headingPitchRange) so the range is derived from the bounding sphere rather than guessed:

import { HeadingPitchRange, Math as CesiumMath } from "cesium";

await viewer.zoomTo(tileset, new HeadingPitchRange(
  CesiumMath.toRadians(45),   // heading
  CesiumMath.toRadians(-30),  // pitch
  /* range omitted -> auto-fit */
));

Ion & Platform Configuration

Cesium Ion

import { Ion } from "cesium";

Ion.defaultAccessToken = "YOUR_TOKEN";  // required for ion assets
Ion.defaultServer = "https://your-ion-server.example.com/"; // optional: self-hosted

IonResource

import { IonResource, Cesium3DTileset } from "cesium";

const resource = await IonResource.fromAssetId(96188);
const tileset = await Cesium3DTileset.fromUrl(resource);
viewer.scene.primitives.add(tileset);
await viewer.zoomTo(tileset);

Google Maps Platform

import { GoogleMaps, createGooglePhotorealistic3DTileset, Viewer, IonGeocodeProviderType } from "cesium";

GoogleMaps.defaultApiKey = "YOUR_GOOGLE_MAPS_API_KEY"; // optional: without key, served via ion

const viewer = new Viewer("cesiumContainer", {
  geocoder: IonGeocodeProviderType.GOOGLE, // required with Google 3D Tiles
});

const tileset = await createGooglePhotorealistic3DTileset({
  onlyUsingWithGoogleGeocoder: true,
});
viewer.scene.primitives.add(tileset);

iTwin Platform (experimental)

import { ITwinPlatform, ITwinData } from "cesium";

ITwinPlatform.defaultAccessToken = "YOUR_ITWIN_TOKEN";
const tileset = await ITwinData.createTilesetForIModel(viewer, "imodel-id");

// 1.140+ (#13208): Reality Data of type GaussianSplat3DTiles is now supported
const splats = await ITwinData.createTilesetForRealityDataId(
  iTwinId,
  realityDataId,
  ITwinPlatform.RealityDataType.GaussianSplat3DTiles,
);
viewer.scene.primitives.add(splats);

Viewer Constructor Options

new Viewer(container, options?) -- container is a DOM element or its string ID.

Widget Toggles

OptionDefaultPurpose
animationtruePlayback controls
baseLayerPickertrueImagery/terrain switcher
fullscreenButtontrueFullscreen toggle
vrButtonfalseWebVR toggle
geocoderIonGeocodeProviderType.DEFAULTSearch bar (false to hide)
homeButtontrueReset to home view
infoBoxtrueEntity info popup
sceneModePickertrue2D/3D/Columbus toggle
selectionIndicatortrueSelection reticle
timelinetrueTime scrubber
navigationHelpButtontrueMouse/touch help
projectionPickerfalsePerspective/ortho toggle

Scene & Rendering

OptionDefaultPurpose
sceneModeSceneMode.SCENE3DInitial scene mode
scene3DOnlyfalseLock to 3D, saves GPU memory per geometry instance
shadowsfalseShadow casting
terrainShadowsShadowMode.RECEIVE_ONLYTerrain shadow mode
requestRenderModefalseRender only on changes
maximumRenderTimeChange0.0Max sim-time delta for render
msaaSamples4MSAA (1 to disable)
orderIndependentTranslucencytrueTranslucent ordering
mapMode2DMapMode2D.INFINITE_SCROLL2D scroll behavior

Pair requestRenderMode: true with scene3DOnly: true for low-power / dashboard apps; both are commonly required together when the scenario calls for GPU savings.

Layers & Terrain

OptionDefaultPurpose
baseLayerImageryLayer.fromWorldImagery()Base imagery (false for none; needs baseLayerPicker: false)
terrainnoneAsync terrain helper (cannot combine with terrainProvider)
terrainProviderEllipsoidTerrainProviderSync terrain provider
globenew Globe()false for no globe (space scenes)
skyBoxauto (WGS84)false disables sky/sun/moon
skyAtmosphereauto (WGS84)false disables limb glow

Minimal Viewer (No Widgets)

import { Viewer, ImageryLayer, OpenStreetMapImageryProvider } from "cesium";

const viewer = new Viewer("cesiumContainer", {
  baseLayer: new ImageryLayer(new OpenStreetMapImageryProvider({
    url: "https://tile.openstreetmap.org/",
    maximumLevel: 18,
  })),
  animation: false, baseLayerPicker: false, fullscreenButton: false,
  geocoder: false, homeButton: false, infoBox: false,
  sceneModePicker: false, selectionIndicator: false,
  timeline: false, navigationHelpButton: false,
});

CesiumWidget (Lightweight Alternative)

No UI widgets, no Knockout dependency. Suitable for custom UIs or embedding.

import { CesiumWidget, Ion } from "cesium";
Ion.defaultAccessToken = "YOUR_TOKEN";

const widget = new CesiumWidget("cesiumContainer", { shouldAnimate: true });
// Exposes: widget.scene, widget.camera, widget.entities

SceneMode Enum

ValueDescription
SceneMode.SCENE3DStandard 3D globe (default)
SceneMode.SCENE2DTop-down orthographic map
SceneMode.COLUMBUS_VIEW2.5D flat map with height
SceneMode.MORPHINGTransitioning between modes
import { Viewer, SceneMode } from "cesium";

const viewer = new Viewer("cesiumContainer", { sceneMode: SceneMode.SCENE2D });
viewer.scene.morphTo3D(2.0);          // animated transition
viewer.scene.morphToColumbusView(2.0);

Scene Configuration

const scene = viewer.scene;
scene.globe.depthTestAgainstTerrain = true; // entities interact with terrain
scene.globe.enableLighting = true;          // sun-based lighting

// Key sub-objects
scene.camera;           // Camera
scene.primitives;       // PrimitiveCollection
scene.groundPrimitives; // PrimitiveCollection (ground-clamped)
scene.imageryLayers;    // ImageryLayerCollection
scene.postProcessStages;

scene.requestRender();  // trigger frame in requestRenderMode

Important: never touch scene.globe.* or scene.skyAtmosphere.* when the matching constructor option was set to false. Disabling these in the Viewer options leaves the corresponding property as undefined on the scene, and accessing .enableLighting, .depthTestAgainstTerrain, .show, or any other field throws TypeError: Cannot set properties of undefined. For space scenes, configure once in the constructor and do not mutate those properties afterward (see "Space Scene" below).

Factory Helpers

createOsmBuildingsAsync

import { createOsmBuildingsAsync, Cesium3DTileStyle } from "cesium";

// Default styling (colors from OSM tags)
const tileset = await createOsmBuildingsAsync();
viewer.scene.primitives.add(tileset);

// Custom style
const styled = await createOsmBuildingsAsync({
  style: new Cesium3DTileStyle({
    color: { conditions: [
      ["${feature['building']} === 'hospital'", "color('#0000FF')"],
      [true, "color('#ffffff')"],
    ]},
  }),
});

createGooglePhotorealistic3DTileset

import { createGooglePhotorealistic3DTileset, IonGeocodeProviderType } from "cesium";

// Must use Google geocoder
const viewer = new Viewer("cesiumContainer", { geocoder: IonGeocodeProviderType.GOOGLE });
const tileset = await createGooglePhotorealistic3DTileset({ onlyUsingWithGoogleGeocoder: true });
viewer.scene.primitives.add(tileset);

Terrain.fromWorldTerrain / fromWorldBathymetry

Preferred for the terrain constructor option. Non-blocking with error events.

import { Viewer, Terrain } from "cesium";

// World terrain with normals and water
const viewer = new Viewer("cesiumContainer", {
  terrain: Terrain.fromWorldTerrain({ requestVertexNormals: true, requestWaterMask: true }),
});

// Bathymetry (ocean floor)
const viewer2 = new Viewer("cesiumContainer", {
  terrain: Terrain.fromWorldBathymetry({ requestVertexNormals: true }),
});

Terrain Event Handling

import { Terrain, CesiumTerrainProvider } from "cesium";

const terrain = new Terrain(CesiumTerrainProvider.fromUrl("https://my-terrain.example.com"));
viewer.scene.setTerrain(terrain);

terrain.readyEvent.addEventListener((provider) => {
  viewer.scene.globe.enableLighting = true;
});
terrain.errorEvent.addEventListener((error) => console.error("Terrain failed:", error));

createWorldTerrainAsync / createWorldImageryAsync

Lower-level: return raw providers. Use when you need the provider directly.

import { createWorldTerrainAsync, createWorldImageryAsync, IonWorldImageryStyle } from "cesium";

const terrainProvider = await createWorldTerrainAsync({ requestVertexNormals: true });
viewer.terrainProvider = terrainProvider;

const imageryProvider = await createWorldImageryAsync({ style: IonWorldImageryStyle.AERIAL_WITH_LABELS });

IonWorldImageryStyle: AERIAL (default) | AERIAL_WITH_LABELS | ROAD

Geocoder Configuration

The geocoder option accepts false, an IonGeocodeProviderType, or a GeocoderService[].

IonGeocodeProviderType: DEFAULT | GOOGLE (required with Google tiles) | BING

import { Viewer, CartographicGeocoderService, IonGeocoderService, OpenCageGeocoderService } from "cesium";

// Multiple services (searched in order)
const viewer = new Viewer("cesiumContainer", {
  geocoder: [
    new CartographicGeocoderService(), // accepts "lat, lon" input
    new IonGeocoderService({ scene: viewer.scene }),
  ],
});

Custom GeocoderService

const myGeocoder = {
  async geocode(input, type) {
    // type: GeocodeType.SEARCH or GeocodeType.AUTOCOMPLETE
    const resp = await fetch(`https://api.example.com/search?q=${input}`);
    const data = await resp.json();
    return data.map((item) => ({
      displayName: item.name,
      destination: Cartesian3.fromDegrees(item.lon, item.lat),
    }));
  },
};
const viewer = new Viewer("cesiumContainer", { geocoder: [myGeocoder] });

Viewer Mixins

import { Viewer, viewerDragDropMixin, viewerCesium3DTilesInspectorMixin,
  viewerCesiumInspectorMixin, viewerPerformanceWatchdogMixin, viewerVoxelInspectorMixin } from "cesium";

const viewer = new Viewer("cesiumContainer");

// Drag-and-drop CZML/GeoJSON/KML loading
viewer.extend(viewerDragDropMixin, { dropTarget: "cesiumContainer", clearOnDrop: true });
viewer.dropError.addEventListener((handler, name, error) => console.error(error));

viewer.extend(viewerCesium3DTilesInspectorMixin);    // 3D Tiles debug panel
viewer.extend(viewerCesiumInspectorMixin);            // general scene inspector
viewer.extend(viewerPerformanceWatchdogMixin);        // low-FPS warning
viewer.extend(viewerVoxelInspectorMixin);             // voxel debug panel

Key Viewer Properties & Methods

PropertyType
viewer.sceneScene
viewer.cameraCamera
viewer.entitiesEntityCollection
viewer.dataSourcesDataSourceCollection
viewer.imageryLayersImageryLayerCollection
viewer.terrainProviderTerrainProvider
viewer.clock / clockViewModelClock / ClockViewModel
viewer.canvasHTMLCanvasElement
viewer.screenSpaceEventHandlerScreenSpaceEventHandler
viewer.selectedEntity / trackedEntityEntity
viewer.shadowsboolean
viewer.resolutionScalenumber (default 1.0)
await viewer.flyTo(entity, { duration: 3.0, offset: headingPitchRange }); // animated
await viewer.zoomTo(tileset);   // instant; uses bounding sphere
viewer.destroy();               // free all resources

Credit & FrameRateMonitor

import { Credit, FrameRateMonitor } from "cesium";

// Custom credit (showOnScreen = true)
viewer.creditDisplay.addStaticCredit(new Credit("Data by Example Corp", true));

// Monitor frame rate
const monitor = FrameRateMonitor.fromScene(viewer.scene);
monitor.lowFrameRate.addEventListener(() => console.warn("Low FPS"));
monitor.nominalFrameRate.addEventListener(() => console.log("FPS recovered"));

Common Patterns

Production Viewer with Terrain and OSM Buildings

import { Ion, Viewer, Terrain, createOsmBuildingsAsync, Cartesian3, Math as CesiumMath } from "cesium";

Ion.defaultAccessToken = "YOUR_TOKEN";
const viewer = new Viewer("cesiumContainer", {
  terrain: Terrain.fromWorldTerrain(), animation: false, timeline: false,
});

viewer.scene.primitives.add(await createOsmBuildingsAsync());
viewer.scene.camera.flyTo({
  destination: Cartesian3.fromDegrees(-74.019, 40.6912, 750),
  orientation: { heading: CesiumMath.toRadians(20), pitch: CesiumMath.toRadians(-20) },
});

Loading and Framing a Sample 3D Tileset

When the tileset's local coordinate frame is unknown (sample assets, discrete-LOD demos), do NOT hand-compute an ECEF camera position; you will miss the asset and render a blank gray surface. Use viewer.zoomTo with a HeadingPitchRange to derive a fitted view from the tileset's bounding sphere.

import { Cesium3DTileset, HeadingPitchRange, Math as CesiumMath } from "cesium";

const tileset = await Cesium3DTileset.fromUrl(url);
viewer.scene.primitives.add(tileset);

await viewer.zoomTo(
  tileset,
  new HeadingPitchRange(
    CesiumMath.toRadians(45),
    CesiumMath.toRadians(-30),
    // omit range -> Cesium auto-fits the bounding sphere
  ),
);

Space Scene (No Globe)

Disable the globe and atmosphere via constructor options only. The scene's globe and skyAtmosphere properties become undefined, so any later viewer.scene.globe.<anything> = ... or viewer.scene.skyAtmosphere.show = false will throw Cannot set properties of undefined. Configure lighting, depth-test-against-terrain, atmosphere visibility, and similar options in the constructor or skip them entirely for a space scene.

const viewer = new Viewer("cesiumContainer", {
  globe: false,           // viewer.scene.globe will be undefined
  skyAtmosphere: false,   // viewer.scene.skyAtmosphere will be undefined
  baseLayerPicker: false,
  baseLayer: false,       // no imagery layer is needed without a globe
});

// Safe post-construction tweaks (skyBox/sun/moon remain defined):
viewer.scene.skyBox.show = true;  // default star field
viewer.scene.sun.show = false;
viewer.scene.moon.show = false;

// DO NOT do this, throws because globe/skyAtmosphere are undefined:
// viewer.scene.globe.enableLighting = true;
// viewer.scene.skyAtmosphere.show = false;

Explicit Render Mode (Low Power Dashboard)

Pair with scene3DOnly: true when 2D/Columbus View is not needed; this is the canonical low-GPU configuration.

const viewer = new Viewer("cesiumContainer", {
  requestRenderMode: true,
  maximumRenderTimeChange: Infinity,
  scene3DOnly: true,
  animation: false,
  timeline: false,
});
// Call viewer.scene.requestRender() after programmatic changes

Custom Base Layer

import { Viewer, ImageryLayer, OpenStreetMapImageryProvider } from "cesium";

const viewer = new Viewer("cesiumContainer", {
  baseLayerPicker: false,
  baseLayer: new ImageryLayer(new OpenStreetMapImageryProvider({
    url: "https://tile.openstreetmap.org/",
  })),
});

Columbus View with Web Mercator

import { Viewer, SceneMode, WebMercatorProjection } from "cesium";

const viewer = new Viewer("cesiumContainer", {
  sceneMode: SceneMode.COLUMBUS_VIEW, mapProjection: new WebMercatorProjection(),
});

Performance Tips

  1. Set requestRenderMode: true for mostly-static apps. Reduces CPU/GPU and battery drain. Call scene.requestRender() after changes.
  2. Use scene3DOnly: true when 2D/Columbus View is not needed. Saves GPU memory per geometry instance. Commonly required alongside requestRenderMode for dashboard/low-power scenarios.
  3. Disable unused widgets (animation: false, timeline: false) to reduce DOM overhead.
  4. Set msaaSamples: 1 on low-power devices. Default 4 balances quality.
  5. Lower resolutionScale (e.g., 0.75) on HiDPI displays for better frame rates.
  6. Prefer Terrain.fromWorldTerrain() over await createWorldTerrainAsync(); it is non-blocking and exposes error events.
  7. Enable requestVertexNormals: true on terrain for proper lighting at negligible cost.
  8. Call viewer.destroy() when removing from DOM to free WebGL contexts.
  9. Limit imagery layers to 2-3. Each adds a texture lookup per fragment.

Framing Checklist (Avoid Blank / Off-Frame Renders)

Before declaring a viewer-setup task complete, verify:

  1. After adding any tileset, model, GeoJSON/KML/CZML data source, or entity collection: await viewer.zoomTo(target) or await viewer.flyTo(target) was called.
  2. For tilesets with unknown local frames, the camera is derived from the bounding sphere (HeadingPitchRange), not a hand-picked Cartesian3.fromDegrees(...).
  3. If the scenario specifies a heading/pitch, those are passed via HeadingPitchRange to zoomTo/flyTo rather than set on camera.flyTo with a guessed destination.
  4. A required base imagery layer is actually present (count == 1) when the scenario expects a visible map under the asset.
  5. When globe: false or skyAtmosphere: false is set in constructor options, no later code accesses viewer.scene.globe.* or viewer.scene.skyAtmosphere.*; both are undefined and will throw.

See Also

  • cesiumjs-camera -- Camera positioning, flyTo, lookAt, navigation constraints
  • cesiumjs-entities -- Entity API, data sources, GeoJSON/KML/CZML loading
  • cesiumjs-imagery -- Imagery providers, layer management, split-screen
  • cesiumjs-terrain-environment -- Terrain providers, Globe, atmosphere, sky, lighting

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/cesiumgs/cesiumjs-skills/cesiumjs-viewer-setup">View cesiumjs-viewer-setup on skillZs</a>