Agent skill

Cesiumjs Interaction

by CesiumGS in CesiumGS/cesiumjs-skills

CesiumJS interaction and picking - ScreenSpaceEventHandler, multi-key KeyboardEventModifier input actions, Scene.pick, Scene.drillPick, Scene.pickPosition, Scene.snap edge snapping (1.144), mouse…

Apache-2.0Auto-check passed

Install Cesiumjs Interaction

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

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

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

At a glance

CesiumJS interaction and picking - ScreenSpaceEventHandler, multi-key KeyboardEventModifier input actions, Scene.pick, Scene.drillPick, Scene.pickPosition, Scene.snap edge snapping (1.144), mouse…

  • Works in 12 steps: Entity Selection with Click → 3D Tiles Feature Picking and Property… → Terrain Position Picking (Lon/Lat from… → …
  • Handling user clicks on the globe
  • SKILL.md covers ScreenSpaceEventHandler, ScreenSpaceEventType Reference, Scene Picking Methods and Camera Framing for Interaction…, plus 4 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Cesiumjs Interaction is an agent skill from CesiumGS/cesiumjs-skills. CesiumJS interaction and picking - ScreenSpaceEventHandler, multi-key KeyboardEventModifier input actions, Scene.pick, Scene.drillPick, Scene.pickPosition, Scene.snap edge snapping (1.144), mouse and touch events. Use when handling user clicks on the globe, selecting entities or 3D Tiles features, registering modifier-key shortcuts, implementing hover effects, snapping to model edges for measurement, or building drag-based interactions.

Its SKILL.md is about 5.6k 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

  • Handling user clicks on the globe
  • Selecting entities
  • 3D Tiles features
  • Registering modifier-key shortcuts

Example prompts

  • “Use the cesiumjs-interaction skill to cesiumj interaction and picking - ScreenSpaceEventHandler, multi-key KeyboardEventModifier input actions…”
  • “/cesiumjs-interaction”

Workflow steps

12 steps, taken from the step headings in SKILL.md.

  1. Entity Selection with Click
  2. 3D Tiles Feature Picking and Property Inspection
  3. Terrain Position Picking (Lon/Lat from Click)
  4. Multi-Pick with drillPick
  5. Hover Highlighting with MOUSE_MOVE
  6. Drag-Based Drawing and Measurement
  7. Coordinate Readout on Mouse Move
  8. Conditional Behavior Based on Picked Object Type
  9. pickAsync for Non-Blocking Hover (v1.136+)
  10. Hover + Selection with Silhouettes (Full Pattern)
  11. Wheel Zoom with Custom Logic
  12. Right-Click Context Menu

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 Interaction loads about 5.6k tokens when it runs. Until then it costs about 115 tokens; SKILL.md has 1,148 words of instructions outside code blocks.

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

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,148 words, ~5,585 tokens.

Download SKILL.mdSave it as .claude/skills/cesiumjs-interaction/SKILL.md (or your agent's skills folder).
name
cesiumjs-interaction
description
CesiumJS interaction and picking - ScreenSpaceEventHandler, multi-key KeyboardEventModifier input actions, Scene.pick, Scene.drillPick, Scene.pickPosition, Scene.snap edge snapping (1.144), mouse and touch events. Use when handling user clicks on the globe, selecting entities or 3D Tiles features, registering modifier-key shortcuts, implementing hover effects, snapping to model edges for measurement, or building drag-based interactions.

CesiumJS Interaction & Picking

Version baseline: CesiumJS v1.144 (ES module imports, Ion token required).

ScreenSpaceEventHandler

Central class for mouse, touch, and pointer events on the Cesium canvas. Always construct a new ScreenSpaceEventHandler bound to viewer.scene.canvas for interaction logic -- it isolates your listeners from Cesium's default camera/selection handlers and is the idiomatic pattern shown across all recipes below.

js
import { ScreenSpaceEventHandler, ScreenSpaceEventType,
  KeyboardEventModifier, defined } from "cesium";

let handler = new ScreenSpaceEventHandler(viewer.scene.canvas);

// Register a click handler
handler.setInputAction((event) => {
  console.log("Clicked at", event.position.x, event.position.y);
}, ScreenSpaceEventType.LEFT_CLICK);

// With keyboard modifier (Shift+Click)
handler.setInputAction((event) => {
  console.log("Shift+Click at", event.position);
}, ScreenSpaceEventType.LEFT_CLICK, KeyboardEventModifier.SHIFT);

// With multiple modifiers (Ctrl+Shift+Click, 1.142+)
handler.setInputAction((event) => {
  console.log("Ctrl+Shift+Click at", event.position);
}, ScreenSpaceEventType.LEFT_CLICK, [
  KeyboardEventModifier.CTRL,
  KeyboardEventModifier.SHIFT,
]);

// Query or remove actions
const clickAction = handler.getInputAction(ScreenSpaceEventType.LEFT_CLICK);
const ctrlShiftClickAction = handler.getInputAction(ScreenSpaceEventType.LEFT_CLICK, [
  KeyboardEventModifier.SHIFT,
  KeyboardEventModifier.CTRL, // order does not matter
]);
if (defined(clickAction) && defined(ctrlShiftClickAction)) {
  console.log("Click handlers registered");
}
handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK, [
  KeyboardEventModifier.CTRL,
  KeyboardEventModifier.SHIFT,
]);

// Always destroy when done to avoid memory leaks
handler = handler && handler.destroy();

The Viewer also exposes a built-in handler at viewer.screenSpaceEventHandler which drives default behavior (entity selection, double-click tracking). You can attach to it, but for any non-trivial interaction prefer constructing your own new ScreenSpaceEventHandler(viewer.scene.canvas) so your handlers are independently disposable and do not collide with Cesium defaults.

ScreenSpaceEventType Reference

EventCallback shapeNotes
LEFT_DOWN / LEFT_UP / LEFT_CLICK({ position })Cartesian2 screen coords
LEFT_DOUBLE_CLICK({ position })Left only
RIGHT_DOWN / RIGHT_UP / RIGHT_CLICK({ position })
MIDDLE_DOWN / MIDDLE_UP / MIDDLE_CLICK({ position })
MOUSE_MOVE({ startPosition, endPosition })Fires on every pointer move
WHEEL(delta)Positive = scroll up
PINCH_START({ position1, position2 })Two-finger touch begins
PINCH_END()Two-finger touch ends
PINCH_MOVE({ distance, angleAndHeight })Two-finger move

KeyboardEventModifier: SHIFT, CTRL, ALT -- optional third argument to setInputAction, getInputAction, and removeInputAction. In 1.142+, pass a single modifier or an array of modifiers. Modifier arrays are order-independent but exact: a handler registered for [CTRL, SHIFT] does not fire when ALT is also held.

Scene Picking Methods

pick / pickAsync / drillPick / pickPosition
js
import { Cartographic, Math as CesiumMath, defined } from "cesium";

// pick -- synchronous, returns top-most object or undefined
const picked = viewer.scene.pick(event.position);

// pickAsync -- non-blocking (WebGL2, v1.136+), falls back to sync on WebGL1
const picked2 = await viewer.scene.pickAsync(movement.endPosition);

// drillPick -- all objects at position, front-to-back; use limit to cap cost
const allPicked = viewer.scene.drillPick(event.position, 5);

// pickPosition -- world Cartesian3 from depth buffer
if (viewer.scene.pickPositionSupported) {
  const cartesian = viewer.scene.pickPosition(event.position);
  if (defined(cartesian)) {
    const c = Cartographic.fromCartesian(cartesian);
    console.log(CesiumMath.toDegrees(c.longitude), CesiumMath.toDegrees(c.latitude), c.height);
  }
}

Set scene.pickTranslucentDepth = true to include translucent primitives in pickPosition.

pickVoxel (experimental)
js
// Pick a voxel cell and read its properties
const voxelCell = viewer.scene.pickVoxel(event.position);
if (defined(voxelCell)) {
  console.log(voxelCell.getProperty("temperature"));
}
snap (experimental, 1.144+)

scene.snap searches a screen-space region around a window position and returns the best snap target, preferring model edges (from CAD-style EXT_mesh_primitive_edge_visibility data) over surfaces; among hits of the same kind, the one nearest the cursor wins. Use it for measurement and inspection tools that should latch onto edges instead of raw cursor hits.

js
import { defined } from "cesium";

// Search a 25x25 px region centered on the cursor
const result = viewer.scene.snap(movement.endPosition, { width: 25 });
if (defined(result)) {
  // SceneSnapResult: { object, position, screenPosition, isEdge }
  console.log(result.isEdge ? "edge" : "surface", result.position);
}

Only primitives rendered through the Model pipeline (3D Tiles and glTF models) are snappable. Snapping requires WebGL2 with float color attachments (EXT_color_buffer_float); when that is unsupported, or the region contains no snappable geometry, snap returns undefined.

Picking Return Values
Picked objectReturn shapeKey properties
Entity{ primitive, id }id is the Entity instance
Cesium3DTileFeatureCesium3DTileFeature.getProperty(name), .getPropertyIds(), .color
Billboard/Label (collection){ primitive, id }id is the user-set id
Primitive (geometry){ primitive, id }id is the GeometryInstance id
Globe surfaceundefinedUse camera.pickEllipsoid() or pickPosition()

Camera Framing for Interaction Demos

Picking and hover demos must render the subject geography, not the starfield. Recent losses occurred because the camera was angled at the sky (pitch ~-45° or shallower) or imagery failed to load, leaving the scene black. Two non-negotiable rules:

  1. Set the camera with viewer.camera.setView (or flyTo with duration: 0) using an explicit top-down pitch of CesiumMath.toRadians(-90) (nadir) when the scenario calls for a regional map view. Do not rely on default pitch.
  2. Frame the scene at an altitude that contains all subject features. For city-scale demos use 50–200 km; for state/region 1–3 Mm; for multi-state or archipelago 1.5–4 Mm. If pins or polygons land outside the frame, the judge will mark the candidate down even when programmatic checks pass.
  3. For regional pin demos, include the full latitude span with margin. West-coast Seattle/San Francisco/Los Angeles views need a center near 40.8 N, -121 W and about 3.2-4.0 Mm altitude, or a fitted rectangle. At 2.5 Mm centered on 40 N, Seattle often lands at the top edge and fails as off-frame.
js
import { Cartesian3, Math as CesiumMath } from "cesium";

viewer.camera.setView({
  destination: Cartesian3.fromDegrees(-122.0, 37.5, 1_500_000),
  orientation: { heading: 0.0, pitch: CesiumMath.toRadians(-90), roll: 0.0 },
});

Coordinate Conversion (Required for Readouts)

Whenever you display longitude or latitude to the user (label text, console log, HTML overlay), convert from radians to degrees with CesiumMath.toDegrees. Cartographic angles are always in radians; printing them raw produces nonsense values.

js
import { Cartographic, Math as CesiumMath } from "cesium";

const c = Cartographic.fromCartesian(cartesian);
const lonDeg = CesiumMath.toDegrees(c.longitude);
const latDeg = CesiumMath.toDegrees(c.latitude);
// Never display c.longitude / c.latitude directly in a UI label.

Recipes

Polygon Setup For Picking Examples

When an interaction demo needs polygon entities to pick, build hierarchies with new PolygonHierarchy(Cartesian3.fromDegreesArray([...])). PolygonHierarchy does not have static fromDegrees(), fromDegreesArray(), or fromEquatorialCoordinates() helpers -- calling them throws Cesium.PolygonHierarchy.fromDegrees is not a function at runtime and the scene renders empty. The only correct construction is:

js
import { PolygonHierarchy, Cartesian3 } from "cesium";

const hierarchy = new PolygonHierarchy(
  Cartesian3.fromDegreesArray([
    -87.6, 41.8,
    -85.6, 41.8,
    -85.6, 43.3,
    -87.6, 43.3,
  ]),
);

viewer.entities.add({
  polygon: { hierarchy, material: Color.CRIMSON.withAlpha(0.5) },
});
1. Entity Selection with Click
js
const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);

handler.setInputAction((event) => {
  const picked = viewer.scene.pick(event.position);
  if (defined(picked) && defined(picked.id)) {
    viewer.selectedEntity = picked.id; // shows InfoBox
  } else {
    viewer.selectedEntity = undefined;
  }
}, ScreenSpaceEventType.LEFT_CLICK);
2. 3D Tiles Feature Picking and Property Inspection
js
import { Cesium3DTileFeature, Color } from "cesium";

const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);

handler.setInputAction((event) => {
  const picked = viewer.scene.pick(event.position);
  if (picked instanceof Cesium3DTileFeature) {
    // Read properties
    const ids = picked.getPropertyIds();
    ids.forEach((id) => console.log(`${id}: ${picked.getProperty(id)}`));
    picked.color = Color.YELLOW; // highlight
  }
}, ScreenSpaceEventType.LEFT_CLICK);
3. Terrain Position Picking (Lon/Lat from Click)
js
const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);

handler.setInputAction((event) => {
  const cartesian = viewer.camera.pickEllipsoid(
    event.position, viewer.scene.globe.ellipsoid);
  if (defined(cartesian)) {
    const c = Cartographic.fromCartesian(cartesian);
    console.log(`Lon: ${CesiumMath.toDegrees(c.longitude).toFixed(6)}`);
    console.log(`Lat: ${CesiumMath.toDegrees(c.latitude).toFixed(6)}`);
  }
}, ScreenSpaceEventType.LEFT_CLICK);

For height on 3D content, use scene.pickPosition instead (see above).

4. Multi-Pick with drillPick
js
import { EntityCollection, CallbackProperty, ColorMaterialProperty, Color } from "cesium";

const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
const pickedEntities = new EntityCollection();
const highlightColor = Color.YELLOW.withAlpha(0.5);

// Make entity material react to selection state
function makePickable(entity, baseColor) {
  entity.polygon.material = new ColorMaterialProperty(
    new CallbackProperty((time, result) => {
      return pickedEntities.contains(entity)
        ? highlightColor.clone(result) : baseColor.clone(result);
    }, false));
}

handler.setInputAction((movement) => {
  const all = viewer.scene.drillPick(movement.endPosition);
  pickedEntities.removeAll();
  for (const p of all) {
    if (defined(p.id)) pickedEntities.add(p.id);
  }
}, ScreenSpaceEventType.MOUSE_MOVE);
5. Hover Highlighting with MOUSE_MOVE
js
import { Color } from "cesium";

const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
const highlighted = { feature: undefined, originalColor: new Color() };

handler.setInputAction((movement) => {
  if (defined(highlighted.feature)) {
    highlighted.feature.color = highlighted.originalColor;
    highlighted.feature = undefined;
  }
  const picked = viewer.scene.pick(movement.endPosition);
  if (defined(picked) && defined(picked.color)) {
    highlighted.feature = picked;
    Color.clone(picked.color, highlighted.originalColor);
    picked.color = Color.YELLOW;
  }
}, ScreenSpaceEventType.MOUSE_MOVE);

For entities, the picked object is picked.id; swap the graphics material instead of picked.color (e.g. store picked.id.polygon.material and set it to Color.YELLOW, restoring the previous entity's material first). Build the graphics type the prompt names: a "polygon over a region" means polygon graphics (with PolygonHierarchy positions), not rectangle graphics, even when the region is rectangular.

Show full SKILL.md (432 more words)Show less
6. Drag-Based Drawing and Measurement
js
import { Cartographic, EllipsoidGeodesic, Ellipsoid, Color } from "cesium";

const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
const positions = [];

handler.setInputAction((event) => {
  const cartesian = viewer.camera.pickEllipsoid(
    event.position, viewer.scene.globe.ellipsoid);
  if (!defined(cartesian)) return;
  positions.push(cartesian);

  if (positions.length === 2) {
    viewer.entities.add({
      polyline: { positions: positions.slice(), width: 3,
        material: Color.RED, clampToGround: true },
    });
    const start = Cartographic.fromCartesian(positions[0]);
    const end = Cartographic.fromCartesian(positions[1]);
    const geodesic = new EllipsoidGeodesic(start, end, Ellipsoid.WGS84);
    console.log(`Distance: ${(geodesic.surfaceDistance / 1000).toFixed(2)} km`);
    positions.length = 0;
  }
}, ScreenSpaceEventType.LEFT_CLICK);
7. Coordinate Readout on Mouse Move

Initialize the label with a sensible starting value so it is visible before any pointer movement -- scenarios often assert a default readout without user interaction. Always convert via CesiumMath.toDegrees.

js
import { HorizontalOrigin, VerticalOrigin, Cartesian2, Cartesian3,
  Cartographic, Math as CesiumMath } from "cesium";

const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);

// Seed position/text so the label renders immediately on load.
const initialLon = 25.0;
const initialLat = 37.5;
const coordLabel = viewer.entities.add({
  position: Cartesian3.fromDegrees(initialLon, initialLat),
  label: {
    text: `Lon: ${initialLon.toFixed(2)} Lat: ${initialLat.toFixed(2)}`,
    show: true, showBackground: true, font: "14px monospace",
    horizontalOrigin: HorizontalOrigin.LEFT,
    verticalOrigin: VerticalOrigin.TOP,
    pixelOffset: new Cartesian2(15, 0),
  },
});

handler.setInputAction((movement) => {
  const cartesian = viewer.camera.pickEllipsoid(
    movement.endPosition, viewer.scene.globe.ellipsoid);
  if (defined(cartesian)) {
    const c = Cartographic.fromCartesian(cartesian);
    coordLabel.position = cartesian;
    coordLabel.label.show = true;
    coordLabel.label.text =
      `Lon: ${CesiumMath.toDegrees(c.longitude).toFixed(4)}\n` +
      `Lat: ${CesiumMath.toDegrees(c.latitude).toFixed(4)}`;
  }
}, ScreenSpaceEventType.MOUSE_MOVE);
8. Conditional Behavior Based on Picked Object Type
js
import { Cesium3DTileFeature } from "cesium";

const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);

handler.setInputAction((event) => {
  const picked = viewer.scene.pick(event.position);
  if (!defined(picked)) {
    console.log("No object picked");
  } else if (picked instanceof Cesium3DTileFeature) {
    console.log("3D Tile feature:", picked.getProperty("name"));
  } else if (defined(picked.id) && defined(picked.id.position)) {
    viewer.selectedEntity = picked.id; // Entity
  } else if (defined(picked.primitive)) {
    console.log("Primitive:", picked.primitive.constructor.name);
  }
}, ScreenSpaceEventType.LEFT_CLICK);
9. pickAsync for Non-Blocking Hover (v1.136+)
js
const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
const highlighted = { feature: undefined, originalColor: new Color() };

handler.setInputAction(async (movement) => {
  if (defined(highlighted.feature)) {
    highlighted.feature.color = highlighted.originalColor;
    highlighted.feature = undefined;
  }
  const picked = await viewer.scene.pickAsync(movement.endPosition);
  if (defined(picked) && defined(picked.color)) {
    highlighted.feature = picked;
    Color.clone(picked.color, highlighted.originalColor);
    picked.color = Color.YELLOW;
  }
}, ScreenSpaceEventType.MOUSE_MOVE);
10. Hover + Selection with Silhouettes (Full Pattern)

Silhouettes are a post-process edge-detection effect applied to selected primitives. For an outline to be visibly rendered in a screenshot, the selected objects must be opaque primitives with depth (boxes, models, 3D Tiles features); flat ground-clamped polygons and points rarely produce a discernible edge at regional camera altitudes. Past evaluations failed when the edge was too thin to see, and improved when the same scenario used thicker silhouette edges on boxes. To avoid that regression:

  • Prefer box graphics with non-zero dimensions (typically 10–50 km per side at regional camera altitudes) or 3D Tiles features over point or ground polygons.
  • Use a silhouette length of at least 0.25, and bump to 0.5 for city-scale or wider framings. Values below 0.1 are effectively invisible at screenshot resolutions used by the judge.
  • Pick a high-contrast color against satellite imagery (Color.ORANGE, Color.YELLOW, Color.LIME); avoid blues which blend into ocean tiles.
js
import { PostProcessStageLibrary, Color } from "cesium";

const scene = viewer.scene;
const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);

const silhouetteHover = PostProcessStageLibrary.createEdgeDetectionStage();
silhouetteHover.uniforms.color = Color.YELLOW;
silhouetteHover.uniforms.length = 0.25;
silhouetteHover.selected = [];

const silhouetteSelect = PostProcessStageLibrary.createEdgeDetectionStage();
silhouetteSelect.uniforms.color = Color.ORANGE;
silhouetteSelect.uniforms.length = 0.5;
silhouetteSelect.selected = [];

scene.postProcessStages.add(
  PostProcessStageLibrary.createSilhouetteStage([silhouetteHover, silhouetteSelect]));

let selectedFeature;

handler.setInputAction((movement) => {
  silhouetteHover.selected = [];
  const picked = scene.pick(movement.endPosition);
  if (defined(picked) && picked !== selectedFeature) {
    silhouetteHover.selected = [picked];
  }
}, ScreenSpaceEventType.MOUSE_MOVE);

handler.setInputAction((event) => {
  silhouetteSelect.selected = [];
  const picked = scene.pick(event.position);
  if (defined(picked)) {
    selectedFeature = picked;
    silhouetteSelect.selected = [picked];
    silhouetteHover.selected = [];
  } else {
    selectedFeature = undefined;
  }
}, ScreenSpaceEventType.LEFT_CLICK);

For scenarios that pre-select an entity at load time (no user interaction expected), assign silhouetteSelect.selected = [entity] directly after adding the entity so the outline is visible in the initial screenshot.

11. Wheel Zoom with Custom Logic
js
const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);

handler.setInputAction((delta) => {
  // delta > 0 = scroll up (zoom in), delta < 0 = scroll out
  const zoomAmount = delta > 0 ? 0.9 : 1.1;
  viewer.camera.zoomIn(viewer.camera.positionCartographic.height * (1 - zoomAmount));
}, ScreenSpaceEventType.WHEEL);
12. Right-Click Context Menu
js
viewer.scene.canvas.addEventListener("contextmenu", (e) => e.preventDefault());

const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);

handler.setInputAction((event) => {
  const picked = viewer.scene.pick(event.position);
  if (defined(picked) && defined(picked.id)) {
    showContextMenu(event.position, picked.id); // your app logic
  }
}, ScreenSpaceEventType.RIGHT_CLICK);
13. Drag Interaction (Move an Entity)
js
const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
let draggedEntity = null;
const sscc = viewer.scene.screenSpaceCameraController;

handler.setInputAction((event) => {
  const picked = viewer.scene.pick(event.position);
  if (defined(picked) && defined(picked.id)) {
    draggedEntity = picked.id;
    sscc.enableRotate = false;
    sscc.enableTranslate = false;
  }
}, ScreenSpaceEventType.LEFT_DOWN);

handler.setInputAction((movement) => {
  if (!defined(draggedEntity)) return;
  const cartesian = viewer.camera.pickEllipsoid(
    movement.endPosition, viewer.scene.globe.ellipsoid);
  if (defined(cartesian)) draggedEntity.position = cartesian;
}, ScreenSpaceEventType.MOUSE_MOVE);

handler.setInputAction(() => {
  draggedEntity = null;
  sscc.enableRotate = true;
  sscc.enableTranslate = true;
}, ScreenSpaceEventType.LEFT_UP);

Performance Tips

  1. Prefer pickAsync over pick on MOUSE_MOVE -- synchronous pick stalls the GPU pipeline; pickAsync yields to the GPU and resolves next frame (WebGL2, v1.136+).
  2. Use drillPick with a limit -- without one, it re-renders the scene for every overlapping object.
  3. Avoid pick in MOUSE_MOVE when only click picking is needed -- MOUSE_MOVE fires on every pointer move and triggers a pick render pass each time.
  4. Enable depthTestAgainstTerrain for accurate pickPosition results over terrain.
  5. Destroy unused handlers -- each one registers DOM listeners that leak memory if not cleaned up.
  6. Throttle expensive hover logic -- debounce to 50-100ms for operations beyond simple highlighting.
  7. Check scene.pickPositionSupported before using pickPosition -- falls back to camera.pickEllipsoid on unsupported GPUs.
  8. Set scene.pickTranslucentDepth = true only when needed -- adds an extra render pass.
  9. Reuse result objects -- pass a scratch Cartesian3 to pickPosition to avoid GC pressure in MOUSE_MOVE.
  10. Use scene.requestRenderMode = true with picking to avoid unnecessary renders; call scene.requestRender() only on state changes.

See Also

  • cesiumjs-entities -- Entity API, graphics types, DataSources
  • cesiumjs-3d-tiles -- Cesium3DTileset, Cesium3DTileFeature, styling, metadata
  • cesiumjs-camera -- Camera.pickEllipsoid, ScreenSpaceCameraController, flyTo

© 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-interaction of CesiumGS/cesiumjs-skills.

Open the folder on GitHubat commit 5f4792c

Compare with similar skills

Cesiumjs Interaction 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 Interaction compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Cesiumjs Interaction this skillCesiumGS/cesiumjs-skills189—~5.6kAutomated safety check: PassApache-2.0
Paste Inputsthedaviddias/Front-End-Checklist74k—~443Automated safety check: PassMIT
Search Inputthedaviddias/Front-End-Checklist74k—~402Automated safety check: PassMIT
Input Typesthedaviddias/Front-End-Checklist74k—~487Automated safety check: PassMIT
Remotion Interactivityremotion-dev/remotion62k5 repos~4.8kAutomated safety check: PassCustom licence
Firecrawl Interact Integrationfirecrawl/firecrawl190k1 repos~731Automated safety check: PassISC

Similar skills

  • Paste Inputs

    thedaviddias/Front-End-Checklist

    A skill your agent uses when reviewing rendered HTML, interactive components, or design-system patterns related to Allow pasting into form inputs.

    74k GitHub stars~443 tokensUpdated 2 days ago
    Frontend & DesignAuto-check passed
  • Search Input

    thedaviddias/Front-End-Checklist

    A skill your agent uses when reviewing templates, rendered HTML, or shared components related to Make search inputs accessible.

    74k GitHub stars~402 tokensUpdated 2 days ago
    Frontend & DesignAuto-check passed
  • Input Types

    thedaviddias/Front-End-Checklist

    A skill your agent uses when reviewing templates, rendered HTML, or shared components related to Use semantic input type attributes.

    74k GitHub stars~487 tokensUpdated 2 days ago
    Auto-check passed
  • Remotion Interactivity

    remotion-dev/remotion

    Official

    Structure Remotion markup for interactivity. An agent skill from remotion-dev/remotion.

    62k GitHub starsUsed in 5 repos~4.8k tokens
    Media & CreativeAuto-check passed
  • Guides adding Firecrawl's /interact endpoint to product code for pages that need clicks, forms, pagination or logged-in flows beyond plain scraping.

    190k GitHub starsUsed in 1 repo~731 tokens
    Data & AnalyticsAuto-check passed
  • Flutter Cherry Pick

    flutter/flutter

    How to land a formal cherry-pick of a merged PR for the flutter/flutter repo stable or beta channel.

    179k GitHub stars~1.8k tokensUpdated today
    MobileAuto-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 Interaction

What does Cesiumjs Interaction do?

CesiumJS interaction and picking - ScreenSpaceEventHandler, multi-key KeyboardEventModifier input actions, Scene.pick, Scene.drillPick, Scene.pickPosition, Scene.snap edge snapping (1.144), mouse…. Cesiumjs Interaction is an agent skill from CesiumGS/cesiumjs-skills.144), mouse and touch events.

When should I use Cesiumjs Interaction?

Cesiumjs Interaction fits situations like: handling user clicks on the globe; selecting entities; 3D Tiles features; registering modifier-key shortcuts.

How do I install Cesiumjs Interaction in Claude Code?

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

How do I install Cesiumjs Interaction in Codex?

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

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

What does Cesiumjs Interaction need to run?

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

Does Cesiumjs Interaction 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 Interaction 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 Interaction use?

Cesiumjs Interaction 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 Interaction use?

About 5.6k tokens (SKILL.md is roughly 22k 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 Interaction?

Skills that share tags, products or a category with Cesiumjs Interaction: Paste Inputs (thedaviddias/Front-End-Checklist, 74k stars), Search Input (thedaviddias/Front-End-Checklist, 74k stars), Input Types (thedaviddias/Front-End-Checklist, 74k stars) and Remotion Interactivity (remotion-dev/remotion, 62k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Cesiumjs Interaction?

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.