@anov/gis-skills-cli 0.0.0-stage → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +618 -0
  2. package/INSTALL.md +478 -0
  3. package/LICENSE +15 -0
  4. package/README.md +148 -2
  5. package/RELEASING.md +160 -0
  6. package/bin/anov-gis-skills.mjs +408 -0
  7. package/lib/mcp-config.mjs +273 -0
  8. package/package.json +42 -4
  9. package/skills/anovgis-analysis/SKILL.md +585 -0
  10. package/skills/anovgis-effects/SKILL.md +260 -0
  11. package/skills/anovgis-imagery-terrain/SKILL.md +505 -0
  12. package/skills/anovgis-layers/SKILL.md +627 -0
  13. package/skills/anovgis-materials/SKILL.md +635 -0
  14. package/skills/anovgis-models-3dtiles/SKILL.md +448 -0
  15. package/skills/anovgis-pitfalls/SKILL.md +561 -0
  16. package/skills/anovgis-popup-widget/SKILL.md +474 -0
  17. package/skills/anovgis-primitives/SKILL.md +482 -0
  18. package/skills/anovgis-vector-graphics/SKILL.md +602 -0
  19. package/skills/anovgis-viewer/SKILL.md +618 -0
  20. package/skills/using-anovgis/DEMO-MAP.md +64 -0
  21. package/skills/using-anovgis/DEMO-SKILL-MAP.md +248 -0
  22. package/skills/using-anovgis/DOMAINS.md +183 -0
  23. package/skills/using-anovgis/REFERENCE.md +114 -0
  24. package/skills/using-anovgis/SKILL.md +392 -0
  25. package/skills/using-anovgis/templates/README.md +154 -0
  26. package/skills/using-anovgis/templates/combo1-vue3-vite.md +295 -0
  27. package/skills/using-anovgis/templates/combo2-vue2-cli.md +119 -0
  28. package/skills/using-anovgis/templates/combo3-html-cdn.md +107 -0
  29. package/skills/using-anovgis/templates/combo4-vanilla-webpack.md +91 -0
  30. package/skills/using-anovgis/templates/wizard-profiles.md +105 -0
  31. package/vendor/cesiumjs-skills/LICENSE +201 -0
  32. package/vendor/cesiumjs-skills/NOTICE +18 -0
  33. package/vendor/cesiumjs-skills/skills/cesiumjs-3d-tiles/SKILL.md +465 -0
  34. package/vendor/cesiumjs-skills/skills/cesiumjs-camera/SKILL.md +500 -0
  35. package/vendor/cesiumjs-skills/skills/cesiumjs-core-utilities/SKILL.md +403 -0
  36. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/REFERENCE.md +397 -0
  37. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/SKILL.md +351 -0
  38. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/01-diffuse-tint.js +38 -0
  39. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/02-texture-swap.js +42 -0
  40. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/03-feature-id-tileset.js +29 -0
  41. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/04-translucent-override.js +37 -0
  42. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/05-vertex-displacement.js +49 -0
  43. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/06-metadata-ramp.js +34 -0
  44. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/07-voxel-shader.js +27 -0
  45. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/README.md +19 -0
  46. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/_sandcastle-template.html +9 -0
  47. package/vendor/cesiumjs-skills/skills/cesiumjs-entities/SKILL.md +389 -0
  48. package/vendor/cesiumjs-skills/skills/cesiumjs-imagery/SKILL.md +471 -0
  49. package/vendor/cesiumjs-skills/skills/cesiumjs-interaction/SKILL.md +423 -0
  50. package/vendor/cesiumjs-skills/skills/cesiumjs-materials-shaders/SKILL.md +292 -0
  51. package/vendor/cesiumjs-skills/skills/cesiumjs-models-particles/SKILL.md +423 -0
  52. package/vendor/cesiumjs-skills/skills/cesiumjs-primitives/SKILL.md +537 -0
  53. package/vendor/cesiumjs-skills/skills/cesiumjs-spatial-math/SKILL.md +358 -0
  54. package/vendor/cesiumjs-skills/skills/cesiumjs-terrain-environment/SKILL.md +401 -0
  55. package/vendor/cesiumjs-skills/skills/cesiumjs-time-properties/SKILL.md +353 -0
  56. package/vendor/cesiumjs-skills/skills/cesiumjs-viewer-setup/SKILL.md +434 -0
  57. package/vendor/cesiumjs-skills/skills/using-cesiumjs-skills/SKILL.md +35 -0
@@ -0,0 +1,423 @@
1
+ ---
2
+ name: cesiumjs-interaction
3
+ description: "CesiumJS interaction and picking - ScreenSpaceEventHandler, multi-key KeyboardEventModifier input actions, Scene.pick, Scene.drillPick, Scene.pickPosition, 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, or building drag-based interactions."
4
+ ---
5
+ # CesiumJS Interaction & Picking
6
+
7
+ Version baseline: CesiumJS v1.142 (ES module imports, Ion token required).
8
+
9
+ ## ScreenSpaceEventHandler
10
+
11
+ Central class for mouse, touch, and pointer events on the Cesium canvas.
12
+
13
+ ```js
14
+ import { ScreenSpaceEventHandler, ScreenSpaceEventType,
15
+ KeyboardEventModifier, defined } from "cesium";
16
+
17
+ let handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
18
+
19
+ // Register a click handler
20
+ handler.setInputAction((event) => {
21
+ console.log("Clicked at", event.position.x, event.position.y);
22
+ }, ScreenSpaceEventType.LEFT_CLICK);
23
+
24
+ // With keyboard modifier (Shift+Click)
25
+ handler.setInputAction((event) => {
26
+ console.log("Shift+Click at", event.position);
27
+ }, ScreenSpaceEventType.LEFT_CLICK, KeyboardEventModifier.SHIFT);
28
+
29
+ // With multiple modifiers (Ctrl+Shift+Click, 1.142+)
30
+ handler.setInputAction((event) => {
31
+ console.log("Ctrl+Shift+Click at", event.position);
32
+ }, ScreenSpaceEventType.LEFT_CLICK, [
33
+ KeyboardEventModifier.CTRL,
34
+ KeyboardEventModifier.SHIFT,
35
+ ]);
36
+
37
+ // Query or remove actions
38
+ const clickAction = handler.getInputAction(ScreenSpaceEventType.LEFT_CLICK);
39
+ const ctrlShiftClickAction = handler.getInputAction(ScreenSpaceEventType.LEFT_CLICK, [
40
+ KeyboardEventModifier.SHIFT,
41
+ KeyboardEventModifier.CTRL, // order does not matter
42
+ ]);
43
+ if (defined(clickAction) && defined(ctrlShiftClickAction)) {
44
+ console.log("Click handlers registered");
45
+ }
46
+ handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
47
+ handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK, [
48
+ KeyboardEventModifier.CTRL,
49
+ KeyboardEventModifier.SHIFT,
50
+ ]);
51
+
52
+ // Always destroy when done to avoid memory leaks
53
+ handler = handler && handler.destroy();
54
+ ```
55
+
56
+ The Viewer also has a built-in handler at `viewer.screenSpaceEventHandler` -- use it to avoid creating a second handler for simple cases.
57
+
58
+ ## ScreenSpaceEventType Reference
59
+
60
+ | Event | Callback shape | Notes |
61
+ |---|---|---|
62
+ | `LEFT_DOWN` / `LEFT_UP` / `LEFT_CLICK` | `({ position })` | Cartesian2 screen coords |
63
+ | `LEFT_DOUBLE_CLICK` | `({ position })` | Left only |
64
+ | `RIGHT_DOWN` / `RIGHT_UP` / `RIGHT_CLICK` | `({ position })` | |
65
+ | `MIDDLE_DOWN` / `MIDDLE_UP` / `MIDDLE_CLICK` | `({ position })` | |
66
+ | `MOUSE_MOVE` | `({ startPosition, endPosition })` | Fires on every pointer move |
67
+ | `WHEEL` | `(delta)` | Positive = scroll up |
68
+ | `PINCH_START` | `({ position1, position2 })` | Two-finger touch begins |
69
+ | `PINCH_END` | `()` | Two-finger touch ends |
70
+ | `PINCH_MOVE` | `({ distance, angleAndHeight })` | Two-finger move |
71
+
72
+ `KeyboardEventModifier`: `SHIFT`, `CTRL`, `ALT` -- optional third argument to
73
+ `setInputAction`, `getInputAction`, and `removeInputAction`. In 1.142+, pass a
74
+ single modifier or an array of modifiers. Modifier arrays are order-independent
75
+ but exact: a handler registered for `[CTRL, SHIFT]` does not fire when `ALT` is
76
+ also held.
77
+
78
+ ## Scene Picking Methods
79
+
80
+ ### pick / pickAsync / drillPick / pickPosition
81
+
82
+ ```js
83
+ import { Cartographic, Math as CesiumMath, defined } from "cesium";
84
+
85
+ // pick -- synchronous, returns top-most object or undefined
86
+ const picked = viewer.scene.pick(event.position);
87
+
88
+ // pickAsync -- non-blocking (WebGL2, v1.136+), falls back to sync on WebGL1
89
+ const picked2 = await viewer.scene.pickAsync(movement.endPosition);
90
+
91
+ // drillPick -- all objects at position, front-to-back; use limit to cap cost
92
+ const allPicked = viewer.scene.drillPick(event.position, 5);
93
+
94
+ // pickPosition -- world Cartesian3 from depth buffer
95
+ if (viewer.scene.pickPositionSupported) {
96
+ const cartesian = viewer.scene.pickPosition(event.position);
97
+ if (defined(cartesian)) {
98
+ const c = Cartographic.fromCartesian(cartesian);
99
+ console.log(CesiumMath.toDegrees(c.longitude), CesiumMath.toDegrees(c.latitude), c.height);
100
+ }
101
+ }
102
+ ```
103
+
104
+ Set `scene.pickTranslucentDepth = true` to include translucent primitives in `pickPosition`.
105
+
106
+ ### pickVoxel (experimental)
107
+
108
+ ```js
109
+ // Pick a voxel cell and read its properties
110
+ const voxelCell = viewer.scene.pickVoxel(event.position);
111
+ if (defined(voxelCell)) {
112
+ console.log(voxelCell.getProperty("temperature"));
113
+ }
114
+ ```
115
+
116
+ ### Picking Return Values
117
+
118
+ | Picked object | Return shape | Key properties |
119
+ |---|---|---|
120
+ | Entity | `{ primitive, id }` | `id` is the `Entity` instance |
121
+ | Cesium3DTileFeature | `Cesium3DTileFeature` | `.getProperty(name)`, `.getPropertyIds()`, `.color` |
122
+ | Billboard/Label (collection) | `{ primitive, id }` | `id` is the user-set id |
123
+ | Primitive (geometry) | `{ primitive, id }` | `id` is the `GeometryInstance` id |
124
+ | Globe surface | `undefined` | Use `camera.pickEllipsoid()` or `pickPosition()` |
125
+
126
+ ## Recipes
127
+
128
+ ### 1. Entity Selection with Click
129
+
130
+ ```js
131
+ handler.setInputAction((event) => {
132
+ const picked = viewer.scene.pick(event.position);
133
+ if (defined(picked) && defined(picked.id)) {
134
+ viewer.selectedEntity = picked.id; // shows InfoBox
135
+ } else {
136
+ viewer.selectedEntity = undefined;
137
+ }
138
+ }, ScreenSpaceEventType.LEFT_CLICK);
139
+ ```
140
+
141
+ ### 2. 3D Tiles Feature Picking and Property Inspection
142
+
143
+ ```js
144
+ import { Cesium3DTileFeature, Color } from "cesium";
145
+
146
+ handler.setInputAction((event) => {
147
+ const picked = viewer.scene.pick(event.position);
148
+ if (picked instanceof Cesium3DTileFeature) {
149
+ // Read properties
150
+ const ids = picked.getPropertyIds();
151
+ ids.forEach((id) => console.log(`${id}: ${picked.getProperty(id)}`));
152
+ picked.color = Color.YELLOW; // highlight
153
+ }
154
+ }, ScreenSpaceEventType.LEFT_CLICK);
155
+ ```
156
+
157
+ ### 3. Terrain Position Picking (Lon/Lat from Click)
158
+
159
+ ```js
160
+ handler.setInputAction((event) => {
161
+ const cartesian = viewer.camera.pickEllipsoid(
162
+ event.position, viewer.scene.globe.ellipsoid);
163
+ if (defined(cartesian)) {
164
+ const c = Cartographic.fromCartesian(cartesian);
165
+ console.log(`Lon: ${CesiumMath.toDegrees(c.longitude).toFixed(6)}`);
166
+ console.log(`Lat: ${CesiumMath.toDegrees(c.latitude).toFixed(6)}`);
167
+ }
168
+ }, ScreenSpaceEventType.LEFT_CLICK);
169
+ ```
170
+
171
+ For height on 3D content, use `scene.pickPosition` instead (see above).
172
+
173
+ ### 4. Multi-Pick with drillPick
174
+
175
+ ```js
176
+ import { EntityCollection, CallbackProperty, ColorMaterialProperty, Color } from "cesium";
177
+
178
+ const pickedEntities = new EntityCollection();
179
+ const highlightColor = Color.YELLOW.withAlpha(0.5);
180
+
181
+ // Make entity material react to selection state
182
+ function makePickable(entity, baseColor) {
183
+ entity.polygon.material = new ColorMaterialProperty(
184
+ new CallbackProperty((time, result) => {
185
+ return pickedEntities.contains(entity)
186
+ ? highlightColor.clone(result) : baseColor.clone(result);
187
+ }, false));
188
+ }
189
+
190
+ handler.setInputAction((movement) => {
191
+ const all = viewer.scene.drillPick(movement.endPosition);
192
+ pickedEntities.removeAll();
193
+ for (const p of all) {
194
+ if (defined(p.id)) pickedEntities.add(p.id);
195
+ }
196
+ }, ScreenSpaceEventType.MOUSE_MOVE);
197
+ ```
198
+
199
+ ### 5. Hover Highlighting with MOUSE_MOVE
200
+
201
+ ```js
202
+ import { Color } from "cesium";
203
+
204
+ const highlighted = { feature: undefined, originalColor: new Color() };
205
+
206
+ handler.setInputAction((movement) => {
207
+ if (defined(highlighted.feature)) {
208
+ highlighted.feature.color = highlighted.originalColor;
209
+ highlighted.feature = undefined;
210
+ }
211
+ const picked = viewer.scene.pick(movement.endPosition);
212
+ if (defined(picked) && defined(picked.color)) {
213
+ highlighted.feature = picked;
214
+ Color.clone(picked.color, highlighted.originalColor);
215
+ picked.color = Color.YELLOW;
216
+ }
217
+ }, ScreenSpaceEventType.MOUSE_MOVE);
218
+ ```
219
+
220
+ ### 6. Drag-Based Drawing and Measurement
221
+
222
+ ```js
223
+ import { Cartographic, EllipsoidGeodesic, Ellipsoid, Color } from "cesium";
224
+
225
+ const positions = [];
226
+
227
+ handler.setInputAction((event) => {
228
+ const cartesian = viewer.camera.pickEllipsoid(
229
+ event.position, viewer.scene.globe.ellipsoid);
230
+ if (!defined(cartesian)) return;
231
+ positions.push(cartesian);
232
+
233
+ if (positions.length === 2) {
234
+ viewer.entities.add({
235
+ polyline: { positions: positions.slice(), width: 3,
236
+ material: Color.RED, clampToGround: true },
237
+ });
238
+ const start = Cartographic.fromCartesian(positions[0]);
239
+ const end = Cartographic.fromCartesian(positions[1]);
240
+ const geodesic = new EllipsoidGeodesic(start, end, Ellipsoid.WGS84);
241
+ console.log(`Distance: ${(geodesic.surfaceDistance / 1000).toFixed(2)} km`);
242
+ positions.length = 0;
243
+ }
244
+ }, ScreenSpaceEventType.LEFT_CLICK);
245
+ ```
246
+
247
+ ### 7. Coordinate Readout on Mouse Move
248
+
249
+ ```js
250
+ import { HorizontalOrigin, VerticalOrigin, Cartesian2 } from "cesium";
251
+
252
+ const coordLabel = viewer.entities.add({
253
+ label: { show: false, showBackground: true, font: "14px monospace",
254
+ horizontalOrigin: HorizontalOrigin.LEFT, verticalOrigin: VerticalOrigin.TOP,
255
+ pixelOffset: new Cartesian2(15, 0) },
256
+ });
257
+
258
+ handler.setInputAction((movement) => {
259
+ const cartesian = viewer.camera.pickEllipsoid(
260
+ movement.endPosition, viewer.scene.globe.ellipsoid);
261
+ if (defined(cartesian)) {
262
+ const c = Cartographic.fromCartesian(cartesian);
263
+ coordLabel.position = cartesian;
264
+ coordLabel.label.show = true;
265
+ coordLabel.label.text =
266
+ `Lon: ${CesiumMath.toDegrees(c.longitude).toFixed(4)}\n` +
267
+ `Lat: ${CesiumMath.toDegrees(c.latitude).toFixed(4)}`;
268
+ } else {
269
+ coordLabel.label.show = false;
270
+ }
271
+ }, ScreenSpaceEventType.MOUSE_MOVE);
272
+ ```
273
+
274
+ ### 8. Conditional Behavior Based on Picked Object Type
275
+
276
+ ```js
277
+ import { Cesium3DTileFeature } from "cesium";
278
+
279
+ handler.setInputAction((event) => {
280
+ const picked = viewer.scene.pick(event.position);
281
+ if (!defined(picked)) {
282
+ console.log("No object picked");
283
+ } else if (picked instanceof Cesium3DTileFeature) {
284
+ console.log("3D Tile feature:", picked.getProperty("name"));
285
+ } else if (defined(picked.id) && defined(picked.id.position)) {
286
+ viewer.selectedEntity = picked.id; // Entity
287
+ } else if (defined(picked.primitive)) {
288
+ console.log("Primitive:", picked.primitive.constructor.name);
289
+ }
290
+ }, ScreenSpaceEventType.LEFT_CLICK);
291
+ ```
292
+
293
+ ### 9. pickAsync for Non-Blocking Hover (v1.136+)
294
+
295
+ ```js
296
+ const highlighted = { feature: undefined, originalColor: new Color() };
297
+
298
+ handler.setInputAction(async (movement) => {
299
+ if (defined(highlighted.feature)) {
300
+ highlighted.feature.color = highlighted.originalColor;
301
+ highlighted.feature = undefined;
302
+ }
303
+ const picked = await viewer.scene.pickAsync(movement.endPosition);
304
+ if (defined(picked) && defined(picked.color)) {
305
+ highlighted.feature = picked;
306
+ Color.clone(picked.color, highlighted.originalColor);
307
+ picked.color = Color.YELLOW;
308
+ }
309
+ }, ScreenSpaceEventType.MOUSE_MOVE);
310
+ ```
311
+
312
+ ### 10. Hover + Selection with Silhouettes (Full Pattern)
313
+
314
+ ```js
315
+ import { PostProcessStageLibrary, Color } from "cesium";
316
+
317
+ const scene = viewer.scene;
318
+ const silhouetteHover = PostProcessStageLibrary.createEdgeDetectionStage();
319
+ silhouetteHover.uniforms.color = Color.BLUE;
320
+ silhouetteHover.uniforms.length = 0.01;
321
+ silhouetteHover.selected = [];
322
+
323
+ const silhouetteSelect = PostProcessStageLibrary.createEdgeDetectionStage();
324
+ silhouetteSelect.uniforms.color = Color.LIME;
325
+ silhouetteSelect.uniforms.length = 0.01;
326
+ silhouetteSelect.selected = [];
327
+
328
+ scene.postProcessStages.add(
329
+ PostProcessStageLibrary.createSilhouetteStage([silhouetteHover, silhouetteSelect]));
330
+
331
+ let selectedFeature;
332
+
333
+ viewer.screenSpaceEventHandler.setInputAction((movement) => {
334
+ silhouetteHover.selected = [];
335
+ const picked = scene.pick(movement.endPosition);
336
+ if (defined(picked) && picked !== selectedFeature) {
337
+ silhouetteHover.selected = [picked];
338
+ }
339
+ }, ScreenSpaceEventType.MOUSE_MOVE);
340
+
341
+ viewer.screenSpaceEventHandler.setInputAction((event) => {
342
+ silhouetteSelect.selected = [];
343
+ const picked = scene.pick(event.position);
344
+ if (defined(picked)) {
345
+ selectedFeature = picked;
346
+ silhouetteSelect.selected = [picked];
347
+ silhouetteHover.selected = [];
348
+ } else {
349
+ selectedFeature = undefined;
350
+ }
351
+ }, ScreenSpaceEventType.LEFT_CLICK);
352
+ ```
353
+
354
+ ### 11. Wheel Zoom with Custom Logic
355
+
356
+ ```js
357
+ handler.setInputAction((delta) => {
358
+ // delta > 0 = scroll up (zoom in), delta < 0 = scroll out
359
+ const zoomAmount = delta > 0 ? 0.9 : 1.1;
360
+ viewer.camera.zoomIn(viewer.camera.positionCartographic.height * (1 - zoomAmount));
361
+ }, ScreenSpaceEventType.WHEEL);
362
+ ```
363
+
364
+ ### 12. Right-Click Context Menu
365
+
366
+ ```js
367
+ viewer.scene.canvas.addEventListener("contextmenu", (e) => e.preventDefault());
368
+
369
+ handler.setInputAction((event) => {
370
+ const picked = viewer.scene.pick(event.position);
371
+ if (defined(picked) && defined(picked.id)) {
372
+ showContextMenu(event.position, picked.id); // your app logic
373
+ }
374
+ }, ScreenSpaceEventType.RIGHT_CLICK);
375
+ ```
376
+
377
+ ### 13. Drag Interaction (Move an Entity)
378
+
379
+ ```js
380
+ let draggedEntity = null;
381
+ const sscc = viewer.scene.screenSpaceCameraController;
382
+
383
+ handler.setInputAction((event) => {
384
+ const picked = viewer.scene.pick(event.position);
385
+ if (defined(picked) && defined(picked.id)) {
386
+ draggedEntity = picked.id;
387
+ sscc.enableRotate = false;
388
+ sscc.enableTranslate = false;
389
+ }
390
+ }, ScreenSpaceEventType.LEFT_DOWN);
391
+
392
+ handler.setInputAction((movement) => {
393
+ if (!defined(draggedEntity)) return;
394
+ const cartesian = viewer.camera.pickEllipsoid(
395
+ movement.endPosition, viewer.scene.globe.ellipsoid);
396
+ if (defined(cartesian)) draggedEntity.position = cartesian;
397
+ }, ScreenSpaceEventType.MOUSE_MOVE);
398
+
399
+ handler.setInputAction(() => {
400
+ draggedEntity = null;
401
+ sscc.enableRotate = true;
402
+ sscc.enableTranslate = true;
403
+ }, ScreenSpaceEventType.LEFT_UP);
404
+ ```
405
+
406
+ ## Performance Tips
407
+
408
+ 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+).
409
+ 2. **Use `drillPick` with a `limit`** -- without one, it re-renders the scene for every overlapping object.
410
+ 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.
411
+ 4. **Enable `depthTestAgainstTerrain`** for accurate `pickPosition` results over terrain.
412
+ 5. **Destroy unused handlers** -- each one registers DOM listeners that leak memory if not cleaned up.
413
+ 6. **Throttle expensive hover logic** -- debounce to 50-100ms for operations beyond simple highlighting.
414
+ 7. **Check `scene.pickPositionSupported`** before using `pickPosition` -- falls back to `camera.pickEllipsoid` on unsupported GPUs.
415
+ 8. **Set `scene.pickTranslucentDepth = true` only when needed** -- adds an extra render pass.
416
+ 9. **Reuse result objects** -- pass a scratch `Cartesian3` to `pickPosition` to avoid GC pressure in MOUSE_MOVE.
417
+ 10. **Use `scene.requestRenderMode = true`** with picking to avoid unnecessary renders; call `scene.requestRender()` only on state changes.
418
+
419
+ ## See Also
420
+
421
+ - **cesiumjs-entities** -- Entity API, graphics types, DataSources
422
+ - **cesiumjs-3d-tiles** -- Cesium3DTileset, Cesium3DTileFeature, styling, metadata
423
+ - **cesiumjs-camera** -- Camera.pickEllipsoid, ScreenSpaceCameraController, flyTo