Agent skill

Cesiumjs Models Particles

by CesiumGS in CesiumGS/cesiumjs-skills

CesiumJS models, glTF, and particle effects - Model, KHRmeshoptcompression, CAD glTF extensions, EdgeDisplayMode, ModelAnimation, ModelNode, ParticleSystem, emitters, GPM extensions.

Apache-2.0Auto-check passedData & Analytics

Install Cesiumjs Models Particles

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

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

GitHub CLI
$ gh skill install CesiumGS/cesiumjs-skills cesiumjs-models-particles --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-models-particles .claude/skills/cesiumjs-models-particles && 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-models-particles
GitHub stars
189
Token cost
~5.9k tokens
SKILL.md length
1,518 words
Files
2
Skills in repo
14
Repo updated
First seen
Licence
Apache-2.0

At a glance

CesiumJS models, glTF, and particle effects - Model, KHRmeshoptcompression, CAD glTF extensions, EdgeDisplayMode, ModelAnimation, ModelNode, ParticleSystem, emitters, GPM extensions.

  • Works in 2 steps: Camera too close + shallow pitch → the… → Camera too steep / near-nadir → tall…
  • Loading compressed
  • SKILL.md covers Quick Reference, Loading a glTF/GLB Model, Readiness and Lifecycle and Animations, plus 10 more sections
  • Reaches raw.githubusercontent.com

What it does

Cesiumjs Models Particles is an agent skill from CesiumGS/cesiumjs-skills. CesiumJS models, glTF, and particle effects - Model, KHRmeshoptcompression, CAD glTF extensions, EdgeDisplayMode, ModelAnimation, ModelNode, ParticleSystem, emitters, GPM extensions. Use when loading compressed or CAD-style glTF/GLB models, controlling edge rendering, playing model animations, positioning particles, or working with geospatial positioning metadata.

Its SKILL.md is about 5.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `REFERENCE.md`).

It sits in Data & Analytics, covering Geospatial analysis and Positioning and messaging. The repository describes itself as: Curated agent skills for CesiumJS development. The licence is Apache-2.0.

When your agent uses it

  • Loading compressed
  • CAD-style glTF/GLB models
  • Controlling edge rendering
  • Playing model animations

Example prompts

  • “Use the cesiumjs-models-particles skill to cesiumj models, glTF, and particle effects - Model, KHRmeshoptcompression, CAD glTF extensions…”
  • “/cesiumjs-models-particles”

Workflow steps

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

  1. Camera too close + shallow pitch → the plume fills the frame and the map disappears behind it.
  2. Camera too steep / near-nadir → tall plumes flatten into a blob and the source geometry reads wrong.

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

    Hosts in commands or code, which the agent is likely to contact:

    • raw.githubusercontent.com

    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 Models Particles loads about 5.9k tokens when it runs. Until then it costs about 99 tokens; SKILL.md has 1,518 words of instructions outside code blocks.

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

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,518 words, ~5,855 tokens.

Download SKILL.mdSave it as .claude/skills/cesiumjs-models-particles/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
cesiumjs-models-particles
description
CesiumJS models, glTF, and particle effects - Model, KHR_meshopt_compression, CAD glTF extensions, EdgeDisplayMode, ModelAnimation, ModelNode, ParticleSystem, emitters, GPM extensions. Use when loading compressed or CAD-style glTF/GLB models, controlling edge rendering, playing model animations, positioning particles, or working with geospatial positioning metadata.

CesiumJS Models, glTF & Particle Effects

Version baseline: CesiumJS v1.144.

Quick Reference

ClassPurpose
ModelLow-level glTF/GLB primitive; positioned via modelMatrix
ModelAnimationActive animation instance on a model
ModelAnimationCollectionCollection at model.activeAnimations
ModelNodeNamed node with modifiable transform
ModelFeaturePer-feature styling/picking for feature-ID models
EdgeDisplayModeControls draft glTF edge-visibility rendering on Model/Cesium3DTileset
ParticleSystemBillboard-based particle manager (fire, smoke, rain)
ParticleSingle particle with position, velocity, life
ParticleBurstScheduled burst of particles
BoxEmitter / CircleEmitterEmit within box volume / flat disk
ConeEmitter / SphereEmitterEmit from cone tip / within sphere

The Entity API exposes models through ModelGraphics (see cesiumjs-entities). The Primitive API uses Model.fromGltfAsync for full control over modelMatrix, animations, and node transforms.


Loading a glTF/GLB Model

Always use the async factory -- never call the constructor directly.

js
import { Model, Cartesian3, Transforms, HeadingPitchRoll, Math as CesiumMath } from "cesium";

const model = await Model.fromGltfAsync({ url: "path/to/model.glb" });
viewer.scene.primitives.add(model);
Public Sample Models

CesiumJS ships sample models usable without ion tokens:

https://raw.githubusercontent.com/CesiumGS/cesium/main/Apps/SampleData/models/CesiumAir/Cesium_Air.glb
https://raw.githubusercontent.com/CesiumGS/cesium/main/Apps/SampleData/models/CesiumMan/Cesium_Man.glb
https://raw.githubusercontent.com/CesiumGS/cesium/main/Apps/SampleData/models/CesiumMilkTruck/CesiumMilkTruck.glb

CesiumJS 1.143 decodes KHR_meshopt_compression automatically, including the v1 attribute codec and COLOR filter. Do not import a decoder or private loader helper. When loading compressed glTF, CAD-style lines/points/edges, or constant-LOD textures, read REFERENCE.md for the complete support and authoring matrix. The same loader behavior applies to glTF content inside 3D Tiles.

Positioned Model with Heading
js
const position = Cartesian3.fromDegrees(-123.074, 44.050, 5000);
const hpr = new HeadingPitchRoll(CesiumMath.toRadians(135), 0, 0);

const model = await Model.fromGltfAsync({
  url: "CesiumAir.glb",
  modelMatrix: Transforms.headingPitchRollToFixedFrame(position, hpr),
  minimumPixelSize: 128,  // never smaller than 128 px on screen
  maximumScale: 20000,    // cap for minimumPixelSize enlargement
  scale: 2.0,             // uniform scale multiplier
});
viewer.scene.primitives.add(model);

Visual eval framing: for model screenshots, the model must be fully inside the frame and recognizable, not clipped at the bottom edge. Use minimumPixelSize 256-400 for public sample aircraft, add a subtle silhouetteColor/silhouetteSize, and place the camera with explicit coordinates aimed at the known model position. Avoid shallow pitches that put the model below the frame or rely on viewer.flyTo(model), which is version-sensitive for Model primitives.

Avoiding Distorted Model Appearance

Models can appear stretched or warped when scale is applied non-uniformly or when the orientation matrix is built incorrectly. Common pitfalls:

  • Always use Transforms.headingPitchRollToFixedFrame (or the Entity API's headingPitchRollQuaternion) for ground-aligned orientation. Hand-rolled quaternions often invert pitch/roll axes and produce vertically stretched silhouettes.
  • Use scale (uniform) for size, not a non-uniform Matrix4.fromScale. A non-uniform scale baked into modelMatrix will distort the model. Reserve Matrix4.fromScale for per-node tweaks (e.g., stretching a single turret), not the whole model.
  • Pair minimumPixelSize with a sensible maximumScale. Without a cap, distant small models can balloon to fill the frame and look elongated when the camera is close.
Key Model.fromGltfAsync Options
OptionTypeDefault
urlstring|Resourcerequired
modelMatrixMatrix4IDENTITY
scalenumber1.0
minimumPixelSizenumber0.0
maximumScalenumber--
showbooleantrue
color / colorBlendMode / colorBlendAmountColor / ColorBlendMode / number-- / HIGHLIGHT / 0.5
edgeDisplayModeEdgeDisplayModeSURFACES_ONLY
silhouetteColor / silhouetteSizeColor / numberRED / 0.0
shadowsShadowModeENABLED
heightReferenceHeightReferenceNONE
customShaderCustomShader--
idany--
allowPickingbooleantrue

Readiness and Lifecycle

fromGltfAsync resolves once glTF JSON is parsed, but WebGL resources may still load. Wait for readyEvent before accessing animations, nodes, or boundingSphere.

js
const model = await Model.fromGltfAsync({ url: "robot.glb" });
viewer.scene.primitives.add(model);

model.readyEvent.addEventListener(() => {
  console.log("Bounding sphere:", model.boundingSphere);
});
js
// Synchronous check
if (model.ready) { const bs = model.boundingSphere; }

Animations

Managed through model.activeAnimations (ModelAnimationCollection).

Play by Name / Play All
js
model.readyEvent.addEventListener(() => {
  // Single animation
  const anim = model.activeAnimations.add({
    name: "Walk",                          // glTF animation name
    loop: Cesium.ModelAnimationLoop.REPEAT, // NONE | REPEAT | MIRRORED_REPEAT
    multiplier: 1.0,                       // playback speed (must be > 0)
  });
  anim.start.addEventListener((m, a) => console.log(`Started: ${a.name}`));

  // Or play all animations at once
  model.activeAnimations.addAll({
    loop: Cesium.ModelAnimationLoop.REPEAT,
    multiplier: 0.5,
  });
});

Additional add options: index, reverse, startTime, stopTime, delay, removeOnStop, animationTime (custom time callback).

Animations require viewer.clock.shouldAnimate = true to advance. A walking character will appear frozen mid-pose (or distorted if at the seam between keyframes) if the clock is stopped.

Animation Events
js
animation.start.addEventListener((model, animation) => { });
animation.update.addEventListener((model, animation, time) => { });
animation.stop.addEventListener((model, animation) => { });
// Collection-level
model.activeAnimations.animationAdded.addEventListener((model, anim) => { });
js
model.activeAnimations.remove(animation); // remove one
model.activeAnimations.removeAll();        // remove all

Model Nodes

Override named node transforms for procedural animation (e.g., turret rotation).

js
model.readyEvent.addEventListener(() => {
  const node = model.getNode("Turret");
  node.matrix = Cesium.Matrix4.fromScale(
    new Cesium.Cartesian3(5.0, 1.0, 1.0), node.matrix
  );
});

Properties: name (read-only), id (read-only index), show (boolean), matrix (Matrix4 -- set to undefined to restore original and re-enable glTF animations).


Coloring, Silhouettes, and Feature Picking

js
// Tint + silhouette
model.color = Cesium.Color.RED.withAlpha(0.5);
model.colorBlendMode = Cesium.ColorBlendMode.MIX;
model.colorBlendAmount = 0.5;
model.silhouetteColor = Cesium.Color.YELLOW;
model.silhouetteSize = 2.0;
Edge Display Mode (Experimental, 1.142+)

For glTF assets using the draft EXT_mesh_primitive_edge_visibility extension, EdgeDisplayMode controls whether extension-provided edges are hidden, composited over surfaces, or rendered alone. Models without the extension are unaffected.

js
import { EdgeDisplayMode, Model } from "cesium";

const model = await Model.fromGltfAsync({
  url: "/models/cad-part.glb",
  edgeDisplayMode: EdgeDisplayMode.SURFACES_AND_EDGES,
});
viewer.scene.primitives.add(model);

model.edgeDisplayMode = EdgeDisplayMode.EDGES_ONLY;       // CAD-style wireframe
model.edgeDisplayMode = EdgeDisplayMode.SURFACES_ONLY;    // default

When a glTF has EXT_mesh_features or EXT_structural_metadata, picking returns a ModelFeature:

js
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((movement) => {
  const picked = viewer.scene.pick(movement.endPosition);
  if (picked instanceof Cesium.ModelFeature) {
    picked.getPropertyIds().forEach((name) => {
      console.log(`${name}: ${picked.getProperty(name)}`);
    });
    picked.color = Cesium.Color.YELLOW;
  }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

Height Reference

js
// Primitive API -- scene is required for height reference
const model = await Model.fromGltfAsync({
  url: "truck.glb",
  heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
  scene: viewer.scene,
});

// Entity API
viewer.entities.add({
  position: Cartesian3.fromDegrees(-75.59, 40.03),
  model: { uri: "truck.glb", heightReference: Cesium.HeightReference.CLAMP_TO_GROUND },
});

Values: NONE, CLAMP_TO_GROUND, RELATIVE_TO_GROUND, CLAMP_TO_TERRAIN, RELATIVE_TO_TERRAIN, CLAMP_TO_3D_TILE, RELATIVE_TO_3D_TILE.


Particle Systems

ParticleSystem renders billboard-based effects. Position with modelMatrix (world) and emitterModelMatrix (local offset).

Always set viewer.clock.shouldAnimate = true before adding a particle system -- particles only move when the clock is running. A stopped clock produces a static "blob" at the emitter origin rather than a directional plume.

Producing a Legible Vertical Plume

A common failure mode is rendering a diffuse spherical blob instead of a recognizable rising column. To make plumes read as vertical:

  • Use CircleEmitter or a narrow ConeEmitter for upward-biased velocity. SphereEmitter and BoxEmitter radiate in all directions and produce blob-like shapes.
  • Bias velocity strongly upward -- emitters' local +Z is up in the modelMatrix frame; set modelMatrix via Transforms.eastNorthUpToFixedFrame so +Z is local up.
  • Use a multi-second minimumParticleLife / maximumParticleLife (e.g., 1.5-4.0) so particles travel far enough to form a visible column before fading.
  • Scale particles over their lifetime (startScale small, endScale 3-6x larger) so the plume widens with height, matching real smoke.
  • Keep the emitter footprint smaller than the visible plume. For crater smoke, use a small disk or point source; oversized ground ellipses read as the subject instead of a source marker.
  • Avoid solving clipping by making the plume huge. If the top is clipped, first increase camera range or lower particle life/speed/endScale; do not let the plume fill all four edges of the frame.
  • Wait for several seconds of simulation time before screenshotting -- the plume needs to develop. Advance the clock or use viewer.clock.shouldAnimate = true and wait.
Smoke Trail
js
import { ParticleSystem, CircleEmitter, Color, Cartesian2, Transforms, Cartesian3 } from "cesium";

viewer.clock.shouldAnimate = true; // required -- particles don't move on a stopped clock

const smokeSystem = new ParticleSystem({
  image: "smoke.png",
  startColor: Color.LIGHTGRAY.withAlpha(0.7),
  endColor: Color.WHITE.withAlpha(0.0),
  startScale: 1.0,
  endScale: 5.0,
  emissionRate: 10,
  minimumSpeed: 1.0,
  maximumSpeed: 4.0,
  minimumParticleLife: 1.2,
  maximumParticleLife: 3.0,
  imageSize: new Cartesian2(25, 25), // pixel size
  emitter: new CircleEmitter(2.0),   // radius in meters
  modelMatrix: Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-75.157, 39.978)),
  lifetime: 16.0,
  loop: true,
});
viewer.scene.primitives.add(smokeSystem);
Volcanic / Crater Smoke Calibration

For terrain-scale smoke such as Mount St. Helens, use an oblique camera and a restrained source marker. The marker should confirm the emitter location without becoming a giant ground disk, and the plume should fit entirely in frame with terrain visible underneath.

js
import { ParticleSystem, CircleEmitter, Color, Cartesian2, Transforms, Cartesian3 } from "cesium";

viewer.clock.shouldAnimate = true;

const sourcePosition = Cartesian3.fromDegrees(-122.1944, 46.1914, 2549);

viewer.entities.add({
  position: sourcePosition,
  point: {
    pixelSize: 10,
    color: Color.ORANGE,
    outlineColor: Color.BLACK,
    outlineWidth: 2,
  },
});

const craterSmoke = new ParticleSystem({
  image: createRadialParticle(48, "rgba(180,180,180,0.75)"),
  startColor: Color.LIGHTGRAY.withAlpha(0.65),
  endColor: Color.WHITE.withAlpha(0.0),
  startScale: 0.8,
  endScale: 4.0,
  emissionRate: 35,
  minimumSpeed: 20.0,
  maximumSpeed: 45.0,
  minimumParticleLife: 2.0,
  maximumParticleLife: 4.0,
  imageSize: new Cartesian2(22, 22),
  emitter: new CircleEmitter(35.0),
  modelMatrix: Transforms.eastNorthUpToFixedFrame(sourcePosition),
  lifetime: 20.0,
  loop: true,
});
viewer.scene.primitives.add(craterSmoke);

viewer.trackedEntity = undefined;
viewer.camera.lookAt(
  sourcePosition,
  new Cesium.HeadingPitchRange(
    Cesium.Math.toRadians(35),
    Cesium.Math.toRadians(-22),
    6500
  )
);

Use this pattern when a prompt asks for smoke over a named geographic source:

  • Prefer a point or small billboard marker over an ellipse unless the prompt specifically asks for a ground footprint.
  • Keep the plume top, base, and source marker visible at once. A clipped plume or missing marker is a framing failure even if particles are rendering.
  • Use an oblique pitch for tall plumes. Near-nadir views flatten the vertical volume into a gray blob.
Show full SKILL.md (573 more words)Show less
Emitter Types
js
import { BoxEmitter, CircleEmitter, ConeEmitter, SphereEmitter } from "cesium";

new BoxEmitter(new Cesium.Cartesian3(10, 10, 10));  // 3D box, velocity outward
new CircleEmitter(2.0);                              // flat disk, velocity +Z
new ConeEmitter(Cesium.Math.toRadians(30));          // cone tip, velocity toward base
new SphereEmitter(5.0);                              // sphere, velocity radiates out
Particle Bursts
js
const firework = new ParticleSystem({
  image: getParticleCanvas(),
  startColor: Color.RED,
  endColor: Color.RED.withAlpha(0.0),
  particleLife: 1.0,
  speed: 100.0,
  imageSize: new Cartesian2(7, 7),
  emissionRate: 0,  // bursts only
  emitter: new SphereEmitter(0.1),
  bursts: [
    new Cesium.ParticleBurst({ time: 0.0, minimum: 100, maximum: 200 }),
    new Cesium.ParticleBurst({ time: 2.0, minimum: 50, maximum: 100 }),
    new Cesium.ParticleBurst({ time: 4.0, minimum: 200, maximum: 300 }),
  ],
  lifetime: 6.0,
  loop: false,
  modelMatrix: Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-75.597, 40.038)),
});
viewer.scene.primitives.add(firework);
Update Callback (Gravity / Wind)

The updateCallback runs per-particle per-frame for forces like gravity.

js
const gravityScratch = new Cesium.Cartesian3();
function applyGravity(particle, dt) {
  Cesium.Cartesian3.normalize(particle.position, gravityScratch);
  Cesium.Cartesian3.multiplyByScalar(gravityScratch, -9.8 * dt, gravityScratch);
  particle.velocity = Cesium.Cartesian3.add(particle.velocity, gravityScratch, particle.velocity);
}

const system = new ParticleSystem({
  image: "smoke.png",
  emissionRate: 20,
  emitter: new ConeEmitter(Cesium.Math.toRadians(45)),
  updateCallback: applyGravity,
  modelMatrix: Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-105, 40, 1000)),
});
viewer.scene.primitives.add(system);
Framing Particle Effects So the Map Is Visible

Particle effects should stand out against the map underneath, not against the sky or a featureless background. Two common framing failures:

  1. Camera too close + shallow pitch → the plume fills the frame and the map disappears behind it.
  2. Camera too steep / near-nadir → tall plumes flatten into a blob and the source geometry reads wrong.

Use viewer.camera.lookAt with HeadingPitchRange to anchor on the emitter and dial in an oblique view that keeps the map context visible:

js
const position = Cartesian3.fromDegrees(-122.1944, 46.1914, 2549);
viewer.trackedEntity = undefined;
viewer.camera.lookAt(
  position,
  new Cesium.HeadingPitchRange(
    Cesium.Math.toRadians(35),   // heading
    Cesium.Math.toRadians(-22),  // oblique pitch preserves plume height
    6500                         // increase range until top and base fit
  )
);

Guidelines:

  • Pitch in the -35° to -60° range for short, ground-hugging effects where map context matters more than vertical extent.
  • Pitch in the -10° to -30° range for tall plumes where vertical volume matters (e.g., volcanic columns).
  • Verify the marker/source is in-frame by including a billboard or point at the emitter location; if the camera is wrong, the marker will be missing from the screenshot and the issue is obvious.
  • Keep background terrain visible around the plume. If particles touch multiple image edges, reduce particle scale/life/speed or increase camera range before taking the screenshot.
  • Reset viewer.trackedEntity = undefined before lookAt, or the tracked entity's reference frame will override your camera transform.

Attaching Particles to a Moving Model

Sync modelMatrix each frame via scene.preUpdate. Use emitterModelMatrix for a local offset (e.g., exhaust pipe).

js
const entity = viewer.entities.add({
  position: sampledPosition,
  orientation: new Cesium.VelocityOrientationProperty(sampledPosition),
  model: { uri: "truck.glb", minimumPixelSize: 64 },
});

// Local offset to exhaust pipe
const trs = new Cesium.TranslationRotationScale();
trs.translation = new Cesium.Cartesian3(-4.0, 0.0, 1.4);
const emitterModelMatrix = Cesium.Matrix4.fromTranslationRotationScale(trs, new Cesium.Matrix4());

const exhaust = new ParticleSystem({
  image: "smoke.png",
  startColor: Color.GRAY.withAlpha(0.7),
  endColor: Color.TRANSPARENT,
  emissionRate: 8,
  speed: 2.0,
  particleLife: 1.5,
  imageSize: new Cartesian2(20, 20),
  emitter: new CircleEmitter(0.5),
  emitterModelMatrix: emitterModelMatrix,
});
viewer.scene.primitives.add(exhaust);

viewer.scene.preUpdate.addEventListener((scene, time) => {
  exhaust.modelMatrix = entity.computeModelMatrix(time, new Cesium.Matrix4());
});

Canvas-Based Particle Images

Generate particle textures dynamically instead of loading image files. A radial gradient produces soft, realistic edges for smoke and water effects.

js
// Soft radial-gradient particle (smoke, water, fog)
function createRadialParticle(size = 32, colorStop = "rgba(200,200,200,0.9)") {
  const c = document.createElement("canvas");
  c.width = c.height = size;
  const ctx = c.getContext("2d");
  const half = size / 2;
  const grad = ctx.createRadialGradient(half, half, 0, half, half, half);
  grad.addColorStop(0, colorStop);
  grad.addColorStop(1, "rgba(0,0,0,0)");
  ctx.fillStyle = grad;
  ctx.fillRect(0, 0, size, size);
  return c;
}

// Solid circle (high-contrast, fireworks, sparks)
function createCircleImage(size = 20) {
  const c = document.createElement("canvas");
  c.width = c.height = size;
  const ctx = c.getContext("2d");
  ctx.beginPath();
  ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
  ctx.fillStyle = "#fff";
  ctx.fill();
  return c;
}

// Pass canvas directly as image
new ParticleSystem({ image: createRadialParticle(), /* ...other options */ });

Use Color.fromCssColorString for specific particle colors when named colors don't suffice:

js
startColor: Cesium.Color.fromCssColorString("#66ccff").withAlpha(0.95),
endColor: Cesium.Color.WHITE.withAlpha(0.0),

Entity API Model (ModelGraphics)

For simpler use cases, add a model through the Entity API (see cesiumjs-entities for full coverage).

js
const entity = viewer.entities.add({
  name: "Aircraft",
  position: Cartesian3.fromDegrees(-123.074, 44.050, 5000),
  orientation: Cesium.Transforms.headingPitchRollQuaternion(
    Cartesian3.fromDegrees(-123.074, 44.050, 5000),
    new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(135), 0, 0)
  ),
  model: {
    uri: "CesiumAir.glb",
    minimumPixelSize: 128,
    maximumScale: 20000,
    silhouetteColor: Color.RED,
    silhouetteSize: 2.0,
  },
});
viewer.trackedEntity = entity;

Framing trade-off with viewer.trackedEntity: tracking centers the model but uses an auto-computed range derived from the bounding sphere, which often produces a too-close, low-context shot. For prompts that ask for both the model and map context (terrain, landmarks, labels), prefer viewer.camera.flyTo / lookAt to a manually chosen position and clear viewer.trackedEntity = undefined first.


GPM Extension (NGA_gpm_local)

CesiumJS experimentally supports the NGA Geospatial Positioning Metadata glTF extension. Types: AnchorPointDirect, AnchorPointIndirect, CorrelationGroup, GltfGpmLocal, Spdcf. Parsed automatically when loading a glTF with NGA_gpm_local -- the API is experimental and subject to change.


Performance Tips

  1. Use .glb over .gltf -- binary format avoids extra HTTP requests and is smaller on the wire.
  2. Enable Draco compression (KHR_draco_mesh_compression) for 80-90% smaller meshes.
  3. Use KTX2/Basis textures (KHR_texture_basisu) for GPU-compressed textures; keep dimensions power-of-two.
  4. Set minimumPixelSize carefully -- large values force enlargement of distant models, increasing draw cost.
  5. Limit silhouettes -- extra rendering pass per silhouetted model; more than 256 may cause stencil artifacts.
  6. Reuse scratch Matrix4 objects -- avoid allocating every frame when syncing particle systems to moving entities.
  7. Match emission rate to effect density -- dense jets (fountains, fire) may need rates of 200-1000/s; diffuse smoke works well at 10-60/s. Profile on target hardware.
  8. Prefer pixel-sized particles (sizeInMeters: false, default) -- meter-sized particles are expensive at close range.
  9. Set finite lifetime on particle systems -- Number.MAX_VALUE (default) prevents pool cleanup.
  10. Disable picking for decorations -- allowPicking: false saves GPU memory on models that need no interaction.
  11. Destroy when done -- viewer.scene.primitives.remove(model) then model.destroy() to free WebGL resources.

See Also

  • cesiumjs-custom-shader -- GLSL authoring for Model.customShader (struct reference, feature IDs, metadata, vertex displacement)
  • cesiumjs-materials-shaders -- ImageBasedLighting, post-processing stages for models
  • cesiumjs-entities -- Entity API ModelGraphics, data sources, time-dynamic properties
  • cesiumjs-3d-tiles -- Cesium3DTileset (uses Model internally), clipping, styling

© 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

SKILL.md and 1 other file in skills/cesiumjs-models-particles of CesiumGS/cesiumjs-skills.

  • SKILL.md
  • REFERENCE.md

Open the folder on GitHubat commit 5f4792c

Compare with similar skills

Cesiumjs Models Particles 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 Models Particles compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Cesiumjs Models Particles this skillCesiumGS/cesiumjs-skills189—~5.9kAutomated safety check: PassApache-2.0
Jqte Fit Positioningfranklee16/academic-research-skills2231 repos~464Automated safety check: PassNone
Jfqa Workflowbrycewang-stanford/Awesome-Journal-Skills1.2k—~1.4kAutomated safety check: PassMIT
Antv L7antvis/L74.1k—~1.4kAutomated safety check: PassMIT
Portaljs Add Geodatopian/portaljs2.4k1 repos~1.7kAutomated safety check: PassMIT
Thematic Mapzzhonglei/GeoCode-Release189—~3.1kAutomated safety check: PassMIT

Similar skills

  • Jqte Fit Positioning

    franklee16/academic-research-skills

    A skill your agent uses to judge whether a manuscript fits 《数量经济技术经济研究》 (JQTE) and to decide how to frame its contribution — measurement, forecasting, or method-application versus clean causal…

    223 GitHub starsUsed in 1 repo~464 tokens
    Data & AnalyticsAuto-check passed
  • Jfqa Workflow

    brycewang-stanford/Awesome-Journal-Skills

    A skill your agent uses when routing a Journal of Financial and Quantitative Analysis (JFQA) manuscript — decides which jfqa- skill to use next across topic selection, literature positioning…

    1.2k GitHub stars~1.4k tokensUpdated 12 days ago
    Data & AnalyticsAuto-check passed
  • Antv L7

    antvis/L7

    Comprehensive guide for AntV L7 geospatial visualization library.

    4.1k GitHub stars~1.4k tokensUpdated 1 mo ago
    Data & AnalyticsAuto-check passed
  • Portaljs Add Geo

    datopian/portaljs

    Auto-ingest a geospatial file (GeoJSON, Shapefile, GeoPackage, KML/KMZ, FlatGeobuf, CSV-with-geometry) into a PortalJS portal on the user's own machine, with no server.

    2.4k GitHub starsUsed in 1 repo~1.7k tokens
    Data & AnalyticsAuto-check passed
  • Thematic Map

    zzhonglei/GeoCode-Release

    Create well-designed maps that follow standard cartographic conventions.

    189 GitHub stars~3.1k tokensUpdated 5 days ago
    Data & AnalyticsAuto-check passed
  • Rs Paper Pipeline

    thinson/RS-PaperClaw

    A skill your agent uses when operating or maintaining the RS-PaperClaw pipeline that fetches remote-sensing arXiv papers, creates per-paper issues, builds daily digests, reconciles issue sets, and…

    228 GitHub stars~319 tokensUpdated yesterday
    Data & AnalyticsAuto-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 25 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 25 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 25 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 25 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 25 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 25 days ago
    Auto-check passed

Questions about Cesiumjs Models Particles

What does Cesiumjs Models Particles do?

CesiumJS models, glTF, and particle effects - Model, KHRmeshoptcompression, CAD glTF extensions, EdgeDisplayMode, ModelAnimation, ModelNode, ParticleSystem, emitters, GPM extensions. Cesiumjs Models Particles is an agent skill from CesiumGS/cesiumjs-skills. CesiumJS models, glTF, and particle effects - Model, KHRmeshoptcompression, CAD glTF extensions, EdgeDisplayMode, ModelAnimation, ModelNode, ParticleSystem, emitters, GPM extensions.

When should I use Cesiumjs Models Particles?

Cesiumjs Models Particles fits situations like: loading compressed; CAD-style glTF/GLB models; controlling edge rendering; playing model animations.

How do I install Cesiumjs Models Particles in Claude Code?

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

How do I install Cesiumjs Models Particles in Codex?

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

Can I use Cesiumjs Models Particles 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-models-particles -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-models-particles, .gemini/skills/cesiumjs-models-particles, .github/skills/cesiumjs-models-particles and .opencode/skills/cesiumjs-models-particles in your project.

What does Cesiumjs Models Particles need to run?

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

Does Cesiumjs Models Particles access the network?

SKILL.md names 1 domain. In commands or code: raw.githubusercontent.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Cesiumjs Models Particles 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 Models Particles use?

Cesiumjs Models Particles 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 Models Particles use?

About 5.9k tokens (SKILL.md is roughly 23k 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 Models Particles?

Skills that share tags, products or a category with Cesiumjs Models Particles: Jqte Fit Positioning (franklee16/academic-research-skills, 223 stars), Jfqa Workflow (brycewang-stanford/Awesome-Journal-Skills, 1.2k stars), Antv L7 (antvis/L7, 4.1k stars) and Portaljs Add Geo (datopian/portaljs, 2.4k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Cesiumjs Models Particles?

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.