Agent skill

Cesiumjs Primitives

by CesiumGS in CesiumGS/cesiumjs-skills

CesiumJS primitives and geometry - Primitive, GeometryInstance, Appearance, BufferPrimitive collections, GeoJsonPrimitive, Billboard/Label/PointPrimitive collections, built-in geometry shapes…

Apache-2.0Auto-check passed

Install Cesiumjs Primitives

skills CLI
$ npx skills add CesiumGS/cesiumjs-skills --skill cesiumjs-primitives -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install CesiumGS/cesiumjs-skills cesiumjs-primitives --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/CesiumGS/cesiumjs-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/cesiumjs-primitives .claude/skills/cesiumjs-primitives && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
cesiumjs-primitives
GitHub stars
189
Token cost
~7k tokens
SKILL.md length
1,494 words
Files
1
Skills in repo
14
Repo updated
First seen
Licence
Apache-2.0

At a glance

CesiumJS primitives and geometry - Primitive, GeometryInstance, Appearance, BufferPrimitive collections, GeoJsonPrimitive, Billboard/Label/PointPrimitive collections, built-in geometry shapes…

  • Works in 12 steps: Batch aggressively. Combine thousands of… → Use PerInstanceColorAppearance when each… → Set flat: true on… → …
  • Rendering performance-critical static
  • SKILL.md covers Architecture, Primitive, Batching Multiple Instances and Updating Per-Instance Attributes, plus 17 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Cesiumjs Primitives is an agent skill from CesiumGS/cesiumjs-skills. CesiumJS primitives and geometry - Primitive, GeometryInstance, Appearance, BufferPrimitive collections, GeoJsonPrimitive, Billboard/Label/PointPrimitive collections, built-in geometry shapes, ground primitives, classification. Use when rendering performance-critical static or vector geometry, loading GeoJSON without entities, creating custom shapes, batching draw calls, or using low-level collections.

Its SKILL.md is about 7k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

The repository describes itself as: Curated agent skills for CesiumJS development. The licence is Apache-2.0.

When your agent uses it

  • Rendering performance-critical static
  • Vector geometry
  • Loading GeoJSON without entities
  • Creating custom shapes

Example prompts

  • “Use the cesiumjs-primitives skill to cesiumj primitives and geometry - Primitive, GeometryInstance, Appearance, BufferPrimitive collections…”
  • “/cesiumjs-primitives”

Workflow steps

12 steps, taken from the first numbered list in SKILL.md.

  1. Batch aggressively. Combine thousands of GeometryInstances into one Primitive for a single draw call.
  2. Use PerInstanceColorAppearance when each instance only needs a distinct color.
  3. Set flat: true on PerInstanceColorAppearance when lighting is unneeded; uses FLAT_VERTEX_FORMAT.
  4. Set allowPicking: false on Primitives that will never be picked to save GPU memory.
  5. Keep asynchronous: true (default). Check primitive.ready before accessing instance attributes.
  6. Prefer fewer large collections for Billboard, Label, and PointPrimitive. Group by update frequency.
  7. Use BlendOption.OPAQUE on BillboardCollection/PointPrimitiveCollection when all items are opaque (up to 2x gain).
  8. Use buffer primitive collections for large vector data when flyweight updates are acceptable.
  9. Precompute buffer collection bounding volumes for large animated collections, but remember they are world-space in 1.142+.
  10. Use GroundPrimitive for terrain draping instead of entity heightReference.
  11. Separate fill and outline into two Primitives -- they cannot share a draw call.
  12. Match vertexFormat exactly to the appearance to skip unused vertex attribute computation.

What it can do on your machine

Read from SKILL.md and the folder at commit 5f4792c. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are javascript).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Cesiumjs Primitives loads about 7k tokens when it runs. Until then it costs about 106 tokens; SKILL.md has 1,494 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~106
When it runs · the whole SKILL.md, loaded when a task matches
~7k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from CesiumGS/cesiumjs-skills at commit 5f4792c, republished under its Apache-2.0 licence (© CesiumGS). 1,494 words, ~7,034 tokens.

Download SKILL.mdSave it as .claude/skills/cesiumjs-primitives/SKILL.md (or your agent's skills folder).
name
cesiumjs-primitives
description
CesiumJS primitives and geometry - Primitive, GeometryInstance, Appearance, BufferPrimitive collections, GeoJsonPrimitive, Billboard/Label/PointPrimitive collections, built-in geometry shapes, ground primitives, classification. Use when rendering performance-critical static or vector geometry, loading GeoJSON without entities, creating custom shapes, batching draw calls, or using low-level collections.

CesiumJS Primitives & Geometry

Applies to: CesiumJS v1.144+ (ES module imports, ?? instead of defaultValue)

Architecture

The Primitive API is the low-level rendering layer beneath the Entity API, trading convenience for performance.

Core formula: Primitive = GeometryInstance[] + Appearance

  • GeometryInstance -- positions a Geometry in world space with per-instance attributes (color, show).
  • Geometry -- vertex data describing a shape (polygon, box, ellipsoid, etc.).
  • Appearance -- GLSL shaders + render state + optional Material that shade the geometry.

Primitives are immutable after first render -- geometry cannot change, but per-instance attributes update via primitive.getGeometryInstanceAttributes(id).

Primitive

js
import {
  Viewer, Primitive, GeometryInstance, EllipseGeometry,
  EllipsoidSurfaceAppearance, Material, Cartesian3, Math as CesiumMath,
} from "cesium";

const viewer = new Viewer("cesiumContainer");
const scene = viewer.scene;

const primitive = scene.primitives.add(new Primitive({
  geometryInstances: new GeometryInstance({
    geometry: new EllipseGeometry({
      center: Cartesian3.fromDegrees(-100.0, 40.0),
      semiMinorAxis: 250000.0,
      semiMajorAxis: 400000.0,
      rotation: CesiumMath.PI_OVER_FOUR,
      vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, // must match appearance
    }),
    id: "myEllipse", // returned by Scene.pick()
  }),
  appearance: new EllipsoidSurfaceAppearance({ material: Material.fromType("Stripe") }),
}));
Key Options
OptionDefaultPurpose
geometryInstances--Single instance or array
appearance--Shading (Appearance subclass)
showtrueToggle visibility
modelMatrixMatrix4.IDENTITYTransform all instances
asynchronoustrueBuild geometry on web worker
releaseGeometryInstancestrueFree geometry after GPU upload
allowPickingtruefalse saves GPU memory
shadowsShadowMode.DISABLEDCast/receive shadows

Batching Multiple Instances

All instances in one Primitive share a single draw call.

js
import {
  Primitive, GeometryInstance, RectangleGeometry, EllipseGeometry,
  PerInstanceColorAppearance, ColorGeometryInstanceAttribute,
  Cartesian3, Rectangle, Color,
} from "cesium";

scene.primitives.add(new Primitive({
  geometryInstances: [
    new GeometryInstance({
      geometry: new RectangleGeometry({
        rectangle: Rectangle.fromDegrees(-140, 30, -100, 40),
        vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
      }),
      id: "rect",
      attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.RED.withAlpha(0.5)) },
    }),
    new GeometryInstance({
      geometry: new EllipseGeometry({
        center: Cartesian3.fromDegrees(-80, 35),
        semiMinorAxis: 200000.0,
        semiMajorAxis: 300000.0,
        vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
      }),
      id: "ellipse",
      attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.BLUE.withAlpha(0.5)) },
    }),
  ],
  appearance: new PerInstanceColorAppearance(),
}));
Batching Volume Geometry (CylinderGeometry Grid)

Volume geometry (Cylinder, Box, Ellipsoid) must be positioned via modelMatrix on each GeometryInstance. Use Matrix4.multiply to combine a world-space anchor with a local offset, then batch all instances into one Primitive.

js
import {
  Primitive, GeometryInstance, CylinderGeometry,
  PerInstanceColorAppearance, ColorGeometryInstanceAttribute,
  Cartesian3, Matrix4, Transforms, Color, Math as CesiumMath,
} from "cesium";

const center = Cartesian3.fromDegrees(-73.9857, 40.7580);
const anchorFrame = Transforms.eastNorthUpToFixedFrame(center, undefined, new Matrix4());
const instances = [];
const GRID = 10;
const SPACING = 50; // metres

for (let row = 0; row < GRID; row++) {
  for (let col = 0; col < GRID; col++) {
    const xOffset = (col - GRID / 2) * SPACING;
    const yOffset = (row - GRID / 2) * SPACING;
    // Combine anchor ENU frame with a local XYZ offset
    const modelMatrix = Matrix4.multiply(
      anchorFrame,
      Matrix4.fromTranslation(new Cartesian3(xOffset, yOffset, 100), new Matrix4()),
      new Matrix4(),
    );
    instances.push(new GeometryInstance({
      geometry: new CylinderGeometry({
        length: 200,
        topRadius: 8,
        bottomRadius: 8,
        vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
      }),
      modelMatrix,
      attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.fromRandom({ alpha: 1.0 })) },
    }));
  }
}

scene.primitives.add(new Primitive({
  geometryInstances: instances,
  appearance: new PerInstanceColorAppearance({ flat: true }),
}));

// Frame the grid so the full batch is visible -- a shallow pitch hides cylinders
// behind the foreground; a near-nadir pitch flattens them. Aim for ~-45° (-PI/4)
// at a range that covers the grid footprint (GRID * SPACING) with margin.
const range = GRID * SPACING * 3; // ~1500 m for a 10x10x50m grid
viewer.camera.lookAt(
  center,
  new Cartesian3(0, -range * 0.7, range * 0.7), // offset south + up for -45° pitch
);

Key patterns:

  • Matrix4.multiply(anchorFrame, Matrix4.fromTranslation(offset, result), result) -- compose the ENU frame at a geographic anchor with a local East/North/Up translation.
  • Color.fromRandom({ alpha: 1.0 }) produces fully-opaque random colours suitable for rainbow-coloured batches.
  • Framing matters: for a grid of vertical volumes, prefer a ~-45° (-CesiumMath.PI_OVER_FOUR, ~-0.785 rad) pitch at a range of roughly 3 * gridFootprint. Pitches shallower than ~-0.6 rad can push the grid off-screen or hide it behind buildings; nadir views flatten cylinders into dots and lose the batched "field" appearance. A -0.61 rad pitch is still shallow enough to leave the grid completely out of frame.
  • Verify visibility: after primitive.ready, prefer viewer.camera.flyToBoundingSphere(primitive._boundingSpheres[0], { duration: 0 }) (or viewer.flyTo(primitive)) over hand-tuned offsets if the scenario only requires "the batch is visible".

Updating Per-Instance Attributes

js
import { ColorGeometryInstanceAttribute, ShowGeometryInstanceAttribute } from "cesium";

// Wait for async geometry compilation
const removeListener = scene.postRender.addEventListener(() => {
  if (!primitive.ready) return;
  const attrs = primitive.getGeometryInstanceAttributes("rect");
  attrs.color = ColorGeometryInstanceAttribute.toValue(Color.YELLOW);
  attrs.show = ShowGeometryInstanceAttribute.toValue(true);
  removeListener();
});

PrimitiveCollection

Nestable container -- scene.primitives is itself a PrimitiveCollection.

js
import { PrimitiveCollection, BillboardCollection, LabelCollection } from "cesium";

const group = new PrimitiveCollection();
group.add(new BillboardCollection());
group.add(new LabelCollection());
scene.primitives.add(group);
group.show = false; // toggle all children

Choosing a Vector Data Path

NeedUse
Entity lifecycle, clustering, per-entity styling, time-dynamic valuesGeoJsonDataSource in cesiumjs-entities
One large GeoJSON object with low overhead and primitive-level performanceGeoJsonPrimitive in this skill
Tiled vector data, 3D Tiles LOD, metadata styling, feature pickingMVTDataProvider in cesiumjs-3d-tiles
Fully manual high-throughput point/polyline/polygon buffersBufferPointCollection, BufferPolylineCollection, BufferPolygonCollection

Buffer Primitive Collections (Experimental, 1.140+)

Use BufferPointCollection, BufferPolylineCollection, and BufferPolygonCollection for very large vector datasets where Entity/DataSource overhead is too high. These APIs were introduced in 1.140 (#13212) and refined through 1.142; they are experimental and use flyweight primitive objects: reuse one BufferPoint, BufferPolyline, or BufferPolygon when adding or iterating thousands of items.

js
import {
  BlendOption,
  BoundingSphere,
  BufferPoint,
  BufferPointCollection,
  BufferPointMaterial,
  Cartesian3,
  Color,
} from "cesium";

const positions = [
  Cartesian3.fromDegrees(-75.16, 39.95),
  Cartesian3.fromDegrees(-73.98, 40.75),
];

const points = scene.primitives.add(new BufferPointCollection({
  primitiveCountMax: positions.length,
  allowPicking: true,
  blendOption: BlendOption.TRANSLUCENT,
  boundingVolume: BoundingSphere.fromPoints(positions), // world space in 1.142+
}));

const point = new BufferPoint();
const material = new BufferPointMaterial({
  color: Color.CYAN.withAlpha(0.65),
  outlineColor: Color.WHITE.withAlpha(0.9),
  outlineWidth: 2,
  size: 10,
});

positions.forEach((position, featureId) => {
  points.add({
    position,
    featureId,
    material,
  }, point);
});

const picked = scene.pick(windowPosition);
if (picked?.collection === points) {
  console.log(picked.index, picked.primitive.featureId);
}

Breaking change (1.141, #13448): BufferPrimitiveCollection.modelMatrix, boundingVolume, and boundingVolumeWC are now readonly -- you may mutate the object in place, but reassigning the property (collection.modelMatrix = ...) throws. Update the existing matrix/volume instead of swapping in a new one.

1.142 notes:

  • boundingVolume is now world-space, not local/model-space. If you provide it manually, include the collection modelMatrix transform yourself.
  • Providing boundingVolume skips automatic recomputation; this helps large animated collections but makes you responsible for keeping the volume valid.
  • blendOption is supported on all three buffer collections and enables alpha from BufferPrimitiveMaterial#color; BufferPointCollection also honors outlineColor.alpha.
  • Use BlendOption.OPAQUE only when every material is fully opaque; use TRANSLUCENT or mixed blending when alpha varies.

In 1.143, BufferPointCollection no longer leaks outlineColor into the fill when outlineWidth is 0. Set the width to 0 to disable outlines; remove transparent-outline workarounds that would otherwise complicate batching.

GeoJsonPrimitive (Experimental, 1.142+)

GeoJsonPrimitive loads GeoJSON directly into buffer primitive collections, bypassing GeoJsonDataSource and the Entity layer. Prefer it for large static or bulk-updated vector datasets. Keep using GeoJsonDataSource when you need Entity conveniences, time-dynamic properties, clustering, or DataSource lifecycle integration.

js
import { GeoJsonPrimitive } from "cesium";

const counties = await GeoJsonPrimitive.fromUrl("/data/counties.geojson", {
  allowPicking: true,
});
scene.primitives.add(counties);

console.log(counties.featureCount);
console.log(counties.points);    // BufferPointCollection | undefined
console.log(counties.polylines); // BufferPolylineCollection | undefined
console.log(counties.polygons);  // BufferPolygonCollection | undefined

// Picking returns the GeoJsonPrimitive pick object, including source properties.
const picked = scene.pick(windowPosition);
if (picked?.parentPrimitive === counties) {
  const featureId = picked.primitive.featureId;
  console.log(counties.getId(featureId));
  console.log(counties.getProperties(featureId));
}

GeoJsonPrimitive.fromGeoJson(parsedObject) is available when the GeoJSON is already in memory. Source feature IDs are exposed through ids/getId(), and source properties through properties/getProperties().

Built-in Geometry Types (31)

All geometries take shape parameters and a vertexFormat matching the Appearance. Most have a paired *OutlineGeometry. Outlines require a separate Primitive.

Filled + Outline Pattern
js
import {
  Primitive, GeometryInstance, PolygonGeometry, PolygonOutlineGeometry,
  PolygonHierarchy, PerInstanceColorAppearance, ColorGeometryInstanceAttribute,
  Cartesian3, Color,
} from "cesium";

const positions = Cartesian3.fromDegreesArray([-115, 37, -115, 32, -107, 33, -102, 35]);

// Fill primitive
scene.primitives.add(new Primitive({
  geometryInstances: new GeometryInstance({
    geometry: new PolygonGeometry({
      polygonHierarchy: new PolygonHierarchy(positions),
      vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
    }),
    attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.CYAN.withAlpha(0.5)) },
  }),
  appearance: new PerInstanceColorAppearance(),
}));

// Outline primitive (separate draw call)
scene.primitives.add(new Primitive({
  geometryInstances: new GeometryInstance({
    geometry: new PolygonOutlineGeometry({ polygonHierarchy: new PolygonHierarchy(positions) }),
    attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.WHITE) },
  }),
  appearance: new PerInstanceColorAppearance({ flat: true }),
}));
Geometry Catalog

Every XxxGeometry has a matching XxxOutlineGeometry unless noted.

Surface (work with GroundPrimitive): CircleGeometry, CorridorGeometry, EllipseGeometry, PolygonGeometry, RectangleGeometry.

Volume (need modelMatrix): BoxGeometry (fromDimensions()), CylinderGeometry (cone when topRadius != bottomRadius), EllipsoidGeometry, SphereGeometry, FrustumGeometry, PlaneGeometry.

Path: CorridorGeometry (buffered path), PolylineVolumeGeometry (2D shape extruded along path), WallGeometry (vertical curtain).

Polygon: PolygonGeometry (holes via PolygonHierarchy), CoplanarPolygonGeometry (non-Earth-surface).

Line (no outline): PolylineGeometry (pixel-width), SimplePolylineGeometry (1px), GroundPolylineGeometry (GroundPolylinePrimitive only).

Positioning Off-Surface Geometry

Box, Ellipsoid, Cylinder, and Frustum need a modelMatrix on the GeometryInstance.

js
import { GeometryInstance, BoxGeometry, PerInstanceColorAppearance,
  ColorGeometryInstanceAttribute, Cartesian3, Matrix4, Transforms, Color } from "cesium";

const modelMatrix = Matrix4.multiplyByTranslation(
  Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-105, 40)),
  new Cartesian3(0, 0, 250000), new Matrix4(),
);
new GeometryInstance({
  geometry: BoxGeometry.fromDimensions({
    dimensions: new Cartesian3(400000, 300000, 500000),
    vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
  }),
  modelMatrix,
  id: "floatingBox",
  attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.CORAL) },
});

Appearances (7 Types)

AppearanceUse CaseMaterial?
PerInstanceColorAppearancePer-instance colorNo
MaterialAppearanceArbitrary geometry + MaterialYes
EllipsoidSurfaceAppearanceSurface geometry + Material (fewer attrs)Yes
PolylineColorAppearancePer-instance color polylinesNo
PolylineMaterialAppearancePolylines with MaterialYes
DebugAppearanceVisualize vertex attributesNo
AppearanceBase class / custom shadersOptional

The geometry vertexFormat must match the appearance. Use the appearance's static VERTEX_FORMAT. For PerInstanceColorAppearance without lighting, use FLAT_VERTEX_FORMAT.

MaterialAppearance Example
js
import { Primitive, GeometryInstance, WallGeometry, MaterialAppearance, Material, Cartesian3 } from "cesium";

scene.primitives.add(new Primitive({
  geometryInstances: new GeometryInstance({
    geometry: new WallGeometry({
      positions: Cartesian3.fromDegreesArrayHeights([-115, 44, 200000, -110, 44, 200000, -105, 44, 200000]),
      vertexFormat: MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat,
    }),
  }),
  appearance: new MaterialAppearance({
    material: Material.fromType("Checkerboard"),
    faceForward: true, // shade both sides
  }),
}));

GroundPrimitive

Drapes geometry onto terrain/3D Tiles. Supported: CircleGeometry, CorridorGeometry, EllipseGeometry, PolygonGeometry, RectangleGeometry. Add to scene.primitives (not scene.groundPrimitives -- both work but scene.primitives is the conventional target when using a public basemap without Ion terrain).

js
import { GroundPrimitive, GeometryInstance, PolygonGeometry, PolygonHierarchy,
  PerInstanceColorAppearance, ColorGeometryInstanceAttribute, ClassificationType,
  Cartesian3, Color } from "cesium";

scene.primitives.add(new GroundPrimitive({
  geometryInstances: new GeometryInstance({
    geometry: new PolygonGeometry({
      polygonHierarchy: new PolygonHierarchy(
        Cartesian3.fromDegreesArray([-112, 36, -112, 36.1, -111.9, 36.1]),
      ),
    }),
    id: "groundPolygon",
    attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.RED.withAlpha(0.5)) },
  }),
  appearance: new PerInstanceColorAppearance({ flat: true, translucent: true }),
  classificationType: ClassificationType.TERRAIN, // TERRAIN, CESIUM_3D_TILE, or BOTH
}));

GroundPolylinePrimitive

Drapes a polyline on terrain. Add to scene.primitives (not scene.groundPrimitives).

js
import { GroundPolylinePrimitive, GeometryInstance, GroundPolylineGeometry,
  PolylineColorAppearance, ColorGeometryInstanceAttribute, Cartesian3, Color } from "cesium";

scene.primitives.add(new GroundPolylinePrimitive({
  geometryInstances: new GeometryInstance({
    geometry: new GroundPolylineGeometry({
      positions: Cartesian3.fromDegreesArray([-112.13, 36.05, -112.09, 36.10, -112.13, 36.17]),
      width: 4.0,
      loop: true,
    }),
    attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.LIME.withAlpha(0.7)) },
  }),
  appearance: new PolylineColorAppearance(),
}));

ClassificationPrimitive

Highlights volumes classifying terrain or 3D Tiles. Valid: BoxGeometry, CylinderGeometry, EllipsoidGeometry, PolylineVolumeGeometry, SphereGeometry, plus extruded surface geometries.

js
import { ClassificationPrimitive, GeometryInstance, BoxGeometry, PerInstanceColorAppearance,
  ColorGeometryInstanceAttribute, ClassificationType, Cartesian3, Transforms, Color } from "cesium";

scene.primitives.add(new ClassificationPrimitive({
  geometryInstances: new GeometryInstance({
    geometry: BoxGeometry.fromDimensions({
      dimensions: new Cartesian3(100, 100, 50),
      vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
    }),
    modelMatrix: Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-75.59, 40.04, 25)),
    attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.YELLOW.withAlpha(0.5)) },
  }),
  classificationType: ClassificationType.BOTH,
}));

BillboardCollection

GPU-efficient viewport-aligned images -- far more performant than entities at scale.

Breaking change (1.140, #13253): BillboardCollection and LabelCollection now require WebGL 2, or WebGL 1 with ANGLE_instanced_arrays and MAX_VERTEX_TEXTURE_IMAGE_UNITS > 0. On unsupported devices they no longer render -- gate on scene.context.webgl2 (or feature-detect the extension) if you still target legacy WebGL 1 hardware.

Show full SKILL.md (598 more words)Show less
Basic Usage

Compatibility fix (1.143): billboard image loading no longer crashes when an application replaces the global Promise implementation. Use the public image property with a URL, loaded image, or canvas; use setImage for a Resource or callback. Do not branch on native Promise identity or retain compatibility shims for this bug.

js
import { BillboardCollection, Cartesian3, Color, NearFarScalar,
  HeightReference, HorizontalOrigin, VerticalOrigin } from "cesium";

const billboards = scene.primitives.add(new BillboardCollection({ scene }));
const b = billboards.add({
  position: Cartesian3.fromDegrees(-75.59, 40.04),
  image: "marker.png",
  horizontalOrigin: HorizontalOrigin.CENTER,
  verticalOrigin: VerticalOrigin.BOTTOM,
  heightReference: HeightReference.CLAMP_TO_GROUND,
  scaleByDistance: new NearFarScalar(1000, 1.5, 1e7, 0.3),
});
b.position = Cartesian3.fromDegrees(-75.60, 40.05); // update dynamically
billboards.remove(b);
PinBuilder -- Procedural Pin Images

PinBuilder generates canvas-based pin icons at runtime without external image files. Use fromColor for solid-colour pins or fromText for labelled pins. Pass the returned canvas as the billboard image.

When a scenario specifies an ordered list of cities/items and a colour-by-index scheme, iterate the source array in the given order and use the loop index directly as the HSL hue index. Re-ordering the source list (e.g. sorting by latitude) swaps which colour lands on which city and fails visual checks.

js
import { BillboardCollection, PinBuilder, Cartesian3, Color, VerticalOrigin } from "cesium";

const pinBuilder = new PinBuilder();
const cities = [
  { name: "Boston",       lng: -71.0589, lat: 42.3601 },
  { name: "New York",     lng: -74.0060, lat: 40.7128 },
  { name: "Philadelphia", lng: -75.1652, lat: 39.9526 },
  { name: "Washington DC",lng: -77.0369, lat: 38.9072 },
  { name: "Miami",        lng: -80.1918, lat: 25.7617 },
];

const billboards = scene.primitives.add(new BillboardCollection({ scene }));

cities.forEach((city, index) => {
  billboards.add({
    position: Cartesian3.fromDegrees(city.lng, city.lat),
    // Color.fromHsl(hue 0-1, saturation, lightness) produces evenly-spaced hues
    image: pinBuilder.fromColor(Color.fromHsl(index / cities.length, 0.8, 0.5), 48),
    verticalOrigin: VerticalOrigin.BOTTOM,
  });
});

// Text label pin: pinBuilder.fromText("A", Color.ROYALBLUE, 48)
// fromColor / fromText return a canvas -- pass directly as image

Color.fromHsl(hue, saturation, lightness) -- generates colours across the spectrum by varying hue (0–1 wraps full circle). Useful for rainbow-colouring N items: Color.fromHsl(i / n, 0.8, 0.5). Color.fromRandom({ alpha }) -- random hue/saturation/lightness with fixed alpha.

LabelCollection

js
import { LabelCollection, Cartesian3, Cartesian2, Color, LabelStyle, VerticalOrigin } from "cesium";

const labels = scene.primitives.add(new LabelCollection({ scene }));
labels.add({
  position: Cartesian3.fromDegrees(-75.59, 40.04, 300),
  text: "Philadelphia",
  font: "16px sans-serif",
  fillColor: Color.WHITE,
  outlineColor: Color.BLACK,
  outlineWidth: 2,
  style: LabelStyle.FILL_AND_OUTLINE,
  verticalOrigin: VerticalOrigin.BOTTOM,
  pixelOffset: new Cartesian2(0, -10),
});

PointPrimitiveCollection

js
import { PointPrimitiveCollection, Cartesian3, Color, NearFarScalar } from "cesium";

const points = scene.primitives.add(new PointPrimitiveCollection());
points.add({
  position: Cartesian3.fromDegrees(-75.59, 40.04),
  pixelSize: 10,
  color: Color.YELLOW,
  outlineColor: Color.BLACK,
  outlineWidth: 2,
  scaleByDistance: new NearFarScalar(1000, 1.0, 1e7, 0.1),
});

CloudCollection and PolylineCollection

js
import { CloudCollection, PolylineCollection, Cartesian3, Cartesian2, Color, Material } from "cesium";

// Procedural cumulus clouds
const clouds = scene.primitives.add(new CloudCollection());
clouds.add({
  position: Cartesian3.fromDegrees(-75.59, 40.04, 1500),
  scale: new Cartesian2(40, 12),
  maximumSize: new Cartesian3(40, 12, 15),
  slice: 0.36,
});

// Low-level polyline collection
const polylines = scene.primitives.add(new PolylineCollection());
polylines.add({
  positions: Cartesian3.fromDegreesArray([-75, 40, -70, 42, -65, 38]),
  width: 3.0,
  material: Material.fromType("Color", { color: Color.AQUA }),
});

Polyline via Primitive

js
import { Primitive, GeometryInstance, PolylineGeometry, PolylineColorAppearance,
  ColorGeometryInstanceAttribute, Cartesian3, Color, ArcType } from "cesium";

scene.primitives.add(new Primitive({
  geometryInstances: new GeometryInstance({
    geometry: new PolylineGeometry({
      positions: Cartesian3.fromDegreesArray([0, 0, 5, 0]),
      width: 10.0,
      vertexFormat: PolylineColorAppearance.VERTEX_FORMAT,
      arcType: ArcType.GEODESIC, // GEODESIC, RHUMB, or NONE
    }),
    attributes: { color: ColorGeometryInstanceAttribute.fromColor(Color.WHITE) },
  }),
  appearance: new PolylineColorAppearance({ translucent: false }),
}));

Enums

EnumValuesUsed By
ArcTypeGEODESIC, RHUMB, NONEPolylineGeometry, PolygonGeometry
CornerTypeROUNDED, MITERED, BEVELEDCorridorGeometry, PolylineVolumeGeometry
ClassificationTypeTERRAIN, CESIUM_3D_TILE, BOTHGroundPrimitive, ClassificationPrimitive
PrimitiveTypePOINTS, LINES, TRIANGLES, etc.Low-level Geometry
CloudTypeCUMULUSCloudCollection

Camera Framing for Primitive Scenes

Programmatic checks (primitive count, camera position) can pass while the visual output completely misses the rendered geometry. A few rules of thumb that recur in visual evaluations:

  • Volume-geometry grids (cylinders/boxes): use -PI/4 (-0.785 rad, -45°) pitch from a range of ~3 * gridFootprint. Pitches shallower than ~-0.6 rad can park the grid behind the camera or out of frame; pitches near -PI/2 flatten vertical extent and make the batch look like dots.
  • Surface polygons draped on terrain (GroundPrimitive): with steeper pitches (~-50°) and far ranges, the polygon shrinks to a thin strip at the bottom edge. Reduce range or use a flatter pitch so the polygon occupies the centre of the frame.
  • Continental polylines (Route 66, transcontinental routes): a near-nadir top-down view from ~5–6 Mm above the centroid keeps the full path visible.
  • Pin chains along a coast/route: centre the camera on the midpoint of the chain at a range that covers the chain's bounding box with margin on all sides.

When in doubt, viewer.flyTo(primitive) or viewer.camera.flyToBoundingSphere(primitive._boundingSpheres[0]) after primitive.ready will frame the batch automatically.

Performance Tips

  1. Batch aggressively. Combine thousands of GeometryInstances into one Primitive for a single draw call.
  2. Use PerInstanceColorAppearance when each instance only needs a distinct color.
  3. Set flat: true on PerInstanceColorAppearance when lighting is unneeded; uses FLAT_VERTEX_FORMAT.
  4. Set allowPicking: false on Primitives that will never be picked to save GPU memory.
  5. Keep asynchronous: true (default). Check primitive.ready before accessing instance attributes.
  6. Prefer fewer large collections for Billboard, Label, and PointPrimitive. Group by update frequency.
  7. Use BlendOption.OPAQUE on BillboardCollection/PointPrimitiveCollection when all items are opaque (up to 2x gain).
  8. Use buffer primitive collections for large vector data when flyweight updates are acceptable.
  9. Precompute buffer collection bounding volumes for large animated collections, but remember they are world-space in 1.142+.
  10. Use GroundPrimitive for terrain draping instead of entity heightReference.
  11. Separate fill and outline into two Primitives -- they cannot share a draw call.
  12. Match vertexFormat exactly to the appearance to skip unused vertex attribute computation.
  13. Use EllipsoidSurfaceAppearance over MaterialAppearance for surface geometry -- fewer vertex attributes.

See Also

  • cesiumjs-entities -- High-level Entity API wrapping primitives with time-dynamic properties.
  • cesiumjs-3d-tiles -- Use MVTDataProvider for tiled vector data as runtime 3D Tiles.
  • cesiumjs-materials-shaders -- Material (Fabric) system consumed by Appearances, post-processing.
  • cesiumjs-spatial-math -- Cartesian3, Matrix4, Transforms, coordinate conversions for positioning geometry.

© CesiumGS, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in skills/cesiumjs-primitives of CesiumGS/cesiumjs-skills.

Open the folder on GitHubat commit 5f4792c

Compare with similar skills

Cesiumjs Primitives next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Cesiumjs Primitives compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Cesiumjs Primitives this skillCesiumGS/cesiumjs-skills189—~7kAutomated safety check: PassApache-2.0
Agent Collective Intelligence Coordinatorruvnet/ruflo74k2 repos~1kAutomated safety check: PassMIT
Collection Digestoutline/outline41k—~498Automated safety check: PassCustom licence
Postman Collection Generatorsickn33/agentic-awesome-skills47k1 repos~1.4kAutomated safety check: PassMIT
Dossier Collectruvnet/ruflo74k—~1.1kAutomated safety check: NotesMIT
Author UI Primitivesremix-run/remix33k—~2.5kAutomated safety check: PassMIT

Similar skills

  • Agent skill for collective-intelligence-coordinator - invoke with $agent-collective-intelligence-coordinator

    74k GitHub starsUsed in 2 repos~1k tokens
    Auto-check passed
  • Collection Digest

    outline/outline

    Summarize what changed in an Outline collection since a date; use when the user asks what is new, what was updated, or wants a digest of recent documents.

    41k GitHub stars~498 tokensUpdated today
    Knowledge ManagementAuto-check passed
  • Postman Collection Generator

    sickn33/agentic-awesome-skills

    Generate complete, import-ready Postman Collection v2.1 JSON files from natural language API descriptions or cURL commands.

    47k GitHub starsUsed in 1 repo~1.4k tokens
    Auto-check passed
  • Dossier Collect

    ruvnet/ruflo

    Build a graph-structured dossier on a seed entity via parallel fan-out + recursive expansion across web, memory, knowledge-graph, codebase, ADR index, and git intel

    74k GitHub stars~1.1k tokensUpdated today
    DevelopmentAuto-check: notes
  • Author UI Primitives

    remix-run/remix

    Build idiomatic headless primitives in packages/ui for Remix.

    33k GitHub stars~2.5k tokensUpdated today
    DevelopmentAuto-check passed
  • Collecting Indicators Of Compromise

    mukul975/Anthropic-Cybersecurity-Skills

    Systematically collects, categorizes, and distributes indicators of compromise (IOCs) during and after security incidents to enable detection, blocking, and threat intelligence sharing.

    34k GitHub stars~2.7k tokensUpdated 1 mo ago
    SecurityAuto-check passed

More from CesiumGS/cesiumjs-skills

All 14 skills in this repo
  • Cesiumjs 3D Tiles

    CesiumGS/cesiumjs-skills

    CesiumJS 3D Tiles - Cesium3DTileset, compressed and CAD-style glTF content, MVTDataProvider, UrlTemplate3DTilesDataProvider, styling, metadata, feature picking, voxels, point clouds, I3S, Gaussian…

    189 GitHub stars~4.7k tokensUpdated 24 days ago
    Auto-check passed
  • Cesiumjs Core Utilities

    CesiumGS/cesiumjs-skills

    CesiumJS core utilities and networking - Resource, Color, Event, Request, RequestScheduler, error handling, helper functions, feature detection.

    189 GitHub stars~3.9k tokensUpdated 24 days ago
    Auto-check passed
  • Cesiumjs Materials Shaders

    CesiumGS/cesiumjs-skills

    CesiumJS materials and post-processing — Material, Fabric JSON, MaterialAppearance, ImageBasedLighting, PostProcessStage, PostProcessStageLibrary, bloom, depth of field, ambient occlusion, FXAA…

    189 GitHub stars~3.6k tokensUpdated 24 days ago
    Auto-check passed
  • Cesiumjs Spatial Math

    CesiumGS/cesiumjs-skills

    CesiumJS spatial math - Cartesian3, Cartographic, Matrix4, Quaternion, Transforms, Ellipsoid, BoundingSphere, projections, coordinate conversions.

    189 GitHub stars~4.6k tokensUpdated 24 days ago
    Auto-check passed
  • Cesiumjs Terrain Environment

    CesiumGS/cesiumjs-skills

    CesiumJS terrain, globe, and environment - TerrainProvider, Globe, sampleTerrain, atmosphere, sky, fog, lighting, shadows, panoramas.

    189 GitHub stars~5k tokensUpdated 24 days ago
    Auto-check passed
  • Cesiumjs Viewer Setup

    CesiumGS/cesiumjs-skills

    CesiumJS viewer setup - Viewer, CesiumWidget, widgets, Ion token, Scene configuration, SceneMode, factory helpers, geocoders, platform services.

    189 GitHub stars~5k tokensUpdated 24 days ago
    Auto-check passed

Questions about Cesiumjs Primitives

What does Cesiumjs Primitives do?

CesiumJS primitives and geometry - Primitive, GeometryInstance, Appearance, BufferPrimitive collections, GeoJsonPrimitive, Billboard/Label/PointPrimitive collections, built-in geometry shapes…. Cesiumjs Primitives is an agent skill from CesiumGS/cesiumjs-skills. CesiumJS primitives and geometry - Primitive, GeometryInstance, Appearance, BufferPrimitive collections, GeoJsonPrimitive, Billboard/Label/PointPrimitive collections, built-in geometry shapes, ground primitives, classification.

When should I use Cesiumjs Primitives?

Cesiumjs Primitives fits situations like: rendering performance-critical static; vector geometry; loading GeoJSON without entities; creating custom shapes.

How do I install Cesiumjs Primitives in Claude Code?

Run `npx skills add CesiumGS/cesiumjs-skills --skill cesiumjs-primitives -a claude-code`. Or copy the skill folder (skills/cesiumjs-primitives in CesiumGS/cesiumjs-skills) into .claude/skills/cesiumjs-primitives in your project. Claude Code loads it when a task matches its description.

How do I install Cesiumjs Primitives in Codex?

Run `npx skills add CesiumGS/cesiumjs-skills --skill cesiumjs-primitives -a codex`. Or copy the skill folder (skills/cesiumjs-primitives in CesiumGS/cesiumjs-skills) into .agents/skills/cesiumjs-primitives in your project. Codex loads it when a task matches its description.

Can I use Cesiumjs Primitives in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add CesiumGS/cesiumjs-skills --skill cesiumjs-primitives -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/cesiumjs-primitives, .gemini/skills/cesiumjs-primitives, .github/skills/cesiumjs-primitives and .opencode/skills/cesiumjs-primitives in your project.

What does Cesiumjs Primitives need to run?

SKILL.md names no scripts, command-line tools or credentials: Cesiumjs Primitives is instructions for the agent only.

Does Cesiumjs Primitives access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Cesiumjs Primitives safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Cesiumjs Primitives use?

Cesiumjs Primitives is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Cesiumjs Primitives use?

About 7k tokens (SKILL.md is roughly 28k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Cesiumjs Primitives?

Skills that share tags, products or a category with Cesiumjs Primitives: Agent Collective Intelligence Coordinator (ruvnet/ruflo, 74k stars), Collection Digest (outline/outline, 41k stars), Postman Collection Generator (sickn33/agentic-awesome-skills, 47k stars) and Dossier Collect (ruvnet/ruflo, 74k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Cesiumjs Primitives?

CesiumGS (a GitHub organization) maintains it in CesiumGS/cesiumjs-skills, which has 189 GitHub stars. The repository holds 14 skills in this directory. The repository was last updated on September 14, 2026.

Source: CesiumGS/cesiumjs-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.