Skip to content
Development
Skill

/cesiumjs-terrain-environment

CesiumJS terrain, globe, and environment - TerrainProvider, Globe, sampleTerrain, atmosphere, sky, fog, lighting, shadows, panoramas. Use when configuring terrain providers, querying terrain heights, customizing atmosphere or sky rendering, adding panoramas, or adjusting scene

From plugin
cesiumjs-skills
17815 skills1 hook1 MCP
Install
$ npx -y skills add CesiumGS/cesiumjs-skills --skill cesiumjs-terrain-environment --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/cesiumjs-terrain-environment

Context preview

The summary Claude sees to decide when to auto-load this skill.

CesiumJS terrain, globe, and environment - TerrainProvider, Globe, sampleTerrain, atmosphere, sky, fog, lighting, shadows, panoramas. Use when configuring terrain providers, querying terrain heights, customizing atmosphere or sky rendering, adding panoramas, or adjusting scene

SKILL.md

cesiumjs-terrain-environment.SKILL.md
name: cesiumjs-terrain-environment
description: "CesiumJS terrain, globe, and environment - TerrainProvider, Globe, sampleTerrain, atmosphere, sky, fog, lighting, shadows, panoramas. Use when configuring terrain providers, querying terrain heights, customizing atmosphere or sky rendering, adding panoramas, or adjusting scene lighting and shadows."

CesiumJS Terrain, Globe & Environment

Version baseline: CesiumJS v1.144 | ES module imports (`import { ... } from "cesium";`)

Terrain Providers

Terrain is served through `TerrainProvider` implementations. Use async factory methods (`fromIonAssetId`, `fromUrl`), not the constructor directly.

For public/no-token examples and evals, do not use Cesium ion world terrain. Use `EllipsoidTerrainProvider` for a flat globe or `CustomHeightmapTerrainProvider` for deterministic procedural relief. Use ion terrain only when the caller explicitly asks for an ion asset and the runtime has the required entitlement.

Public / No-Token Terrain

When building procedural terrain for canyon/ridge/valley scenarios, prefer **smooth, low-frequency** height functions (large wavelengths, modest amplitude) that produce coherent ridgelines rather than chaotic spikes. Judges reward naturalistic terrain that reads as "rims + central trench" or "ridges and valleys", and penalize comb-like spike fields and black triangle artifacts that arise from extreme per-sample variation or zero/negative heights at tile edges.

Key rules to avoid the comb/spike failure mode seen in past losses:

  • Normalize coordinates: use `(x + col/width)` and `(y + row/height)` so the

function is continuous across tile boundaries. Multiply the normalized value by a **small** frequency constant (`0.4` to `1.0`), not by `width`/`height` or large integers.

  • Keep a positive baseline height (e.g. `+1200`) so subtracting a trench term

never produces negative heights at tile edges (negative/NaN heights produce the black triangle artifact reported in losses).

  • Combine 2-3 low-frequency sinusoids of different orientations and a single

Gaussian trench rather than stacking many high-frequency terms.

  • Amplitude budget: ridges in the hundreds of meters, trench depth comparable,

total relief usually < 2000 m for canyon scenarios.

import { CustomHeightmapTerrainProvider } from "cesium";

// Smooth canyon-style relief: low-frequency sinusoid + gentle noise.
// Avoid: high-frequency Math.sin with no smoothing → comb/spike artifacts.
viewer.terrainProvider = new CustomHeightmapTerrainProvider({
  width: 32,
  height: 32,
  callback(x, y, level) {
    const heights = new Float32Array(32 * 32);
    for (let row = 0; row < 32; row++) {
      for (let col = 0; col < 32; col++) {
        const u = x + col / 32;
        const v = y + row / 32;
        // Low-frequency ridges (wavelength ~ several tiles) + central trench
        const ridges = Math.cos(u * 0.6) * 600 + Math.sin(v * 0.5) * 500;
        const trench = -Math.exp(-Math.pow(v - 0.5, 2) * 12) * 800;
        heights[row * 32 + col] = 1200 + ridges + trench;
      }
    }
    return heights;
  },
});

Cesium Ion World Terrain

import { Viewer, Terrain } from "cesium";

const viewer = new Viewer("cesiumContainer", {
  terrain: Terrain.fromWorldTerrain({
    requestVertexNormals: true, // smoother lighting
    requestWaterMask: true,     // ocean water effect
  }),
});

CesiumTerrainProvider from Ion Asset / URL

import { CesiumTerrainProvider } from "cesium";

// By Ion asset ID (e.g. 3956 = Arctic DEM)
const tp = await CesiumTerrainProvider.fromIonAssetId(3956, {
  requestVertexNormals: true,
});
viewer.scene.globe.terrainProvider = tp;

// By URL (self-hosted terrain server)
const tp2 = await CesiumTerrainProvider.fromUrl(
  "https://my-server.example.com/terrain",
  { requestVertexNormals: true },
);

EllipsoidTerrainProvider (Flat Globe)

import { EllipsoidTerrainProvider } from "cesium";
// Flat ellipsoid -- no terrain data, useful for 2D/Columbus or testing
viewer.scene.globe.terrainProvider = new EllipsoidTerrainProvider();

CustomHeightmapTerrainProvider (Procedural)

import { CustomHeightmapTerrainProvider } from "cesium";

viewer.scene.globe.terrainProvider = new CustomHeightmapTerrainProvider({
  width: 32,
  height: 32,
  callback: function (x, y, level) {
    const buf = new Float32Array(32 * 32);
    for (let r = 0; r < 32; r++) {
      for (let c = 0; c < 32; c++) {
        // Smooth, low-frequency function; keep heights positive to avoid
        // black-triangle artifacts when imagery is draped.
        buf[r * 32 + c] = 800 + Math.sin((x + c / 32) * 0.8) * 400;
      }
    }
    return buf;
  },
});

Sampling Terrain Heights

Both functions mutate the input `Cartographic[]` in place (setting `.height`) and return a promise resolving to the same array.

import { sampleTerrain, sampleTerrainMostDetailed, Cartographic } from "cesium";

const positions = [
  Cartographic.fromDegrees(86.925145, 27.988257), // Mt Everest
  Cartographic.fromDegrees(87.0, 28.0),
];

// Fixed LOD level -- fast, approximate
await sampleTerrain(viewer.scene.globe.terrainProvider, 11, positions);

// Max available LOD -- slower, most precise
// Requires provider.availability (e.g. CesiumTerrainProvider)
await sampleTerrainMostDetailed(viewer.scene.globe.terrainProvider, positions);
// positions[0].height is now populated

// Pass true as 3rd arg to reject on tile failure instead of undefined heights
await sampleTerrainMostDetailed(provider, positions, true);

Clamped-Height Callback Correctness (1.143+)

CesiumJS 1.143 fixes the internal `Scene.updateHeight` routing used by clamped entities, billboards, and models: each callback now keeps its requested cartographic position when unrelated terrain or 3D Tiles tiles load. Prefer public `HeightReference` values and upgrade to 1.143+ rather than calling the private `Scene.updateHeight` method or filtering mismatche

Read more
Ships withcesiumjs-skills

Curated agent skills for CesiumJS development — 14 domain skills covering ~551 public symbols across the CesiumJS v1.143 API surface.

Get the whole plugin
Stats
178
Stars
21
Forks
Active
Maintenance
JavaScript
Language
Apache-2.0
License
5d ago
Last commit
5mo ago
Created

Repo: CesiumGS/cesiumjs-skills

Other skills on cesiumjs-skills.