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

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 +637 -0
  2. package/INSTALL.md +481 -0
  3. package/LICENSE +15 -0
  4. package/README.md +148 -2
  5. package/RELEASING.md +162 -0
  6. package/bin/anov-gis-skills.mjs +470 -0
  7. package/lib/mcp-config.mjs +273 -0
  8. package/package.json +43 -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-models-particles
3
+ description: "CesiumJS models, glTF, and particle effects - Model, EdgeDisplayMode, ModelAnimation, ModelNode, ParticleSystem, emitters, GPM extensions. Use when loading glTF/GLB 3D models, controlling edge rendering, playing model animations, positioning particle effects like fire or smoke, or working with geospatial positioning metadata."
4
+ ---
5
+ # CesiumJS Models, glTF & Particle Effects
6
+
7
+ Version baseline: CesiumJS v1.142.
8
+
9
+ ## Quick Reference
10
+
11
+ | Class | Purpose |
12
+ |---|---|
13
+ | `Model` | Low-level glTF/GLB primitive; positioned via `modelMatrix` |
14
+ | `ModelAnimation` | Active animation instance on a model |
15
+ | `ModelAnimationCollection` | Collection at `model.activeAnimations` |
16
+ | `ModelNode` | Named node with modifiable transform |
17
+ | `ModelFeature` | Per-feature styling/picking for feature-ID models |
18
+ | `EdgeDisplayMode` | Controls draft glTF edge-visibility rendering on Model/Cesium3DTileset |
19
+ | `ParticleSystem` | Billboard-based particle manager (fire, smoke, rain) |
20
+ | `Particle` | Single particle with position, velocity, life |
21
+ | `ParticleBurst` | Scheduled burst of particles |
22
+ | `BoxEmitter` / `CircleEmitter` | Emit within box volume / flat disk |
23
+ | `ConeEmitter` / `SphereEmitter` | Emit from cone tip / within sphere |
24
+
25
+ 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.
26
+
27
+ ---
28
+
29
+ ## Loading a glTF/GLB Model
30
+
31
+ Always use the async factory -- never call the constructor directly.
32
+
33
+ ```js
34
+ import { Model, Cartesian3, Transforms, HeadingPitchRoll, Math as CesiumMath } from "cesium";
35
+
36
+ const model = await Model.fromGltfAsync({ url: "path/to/model.glb" });
37
+ viewer.scene.primitives.add(model);
38
+ ```
39
+
40
+ ### Positioned Model with Heading
41
+
42
+ ```js
43
+ const position = Cartesian3.fromDegrees(-123.074, 44.050, 5000);
44
+ const hpr = new HeadingPitchRoll(CesiumMath.toRadians(135), 0, 0);
45
+
46
+ const model = await Model.fromGltfAsync({
47
+ url: "CesiumAir.glb",
48
+ modelMatrix: Transforms.headingPitchRollToFixedFrame(position, hpr),
49
+ minimumPixelSize: 128, // never smaller than 128 px on screen
50
+ maximumScale: 20000, // cap for minimumPixelSize enlargement
51
+ scale: 2.0, // uniform scale multiplier
52
+ });
53
+ viewer.scene.primitives.add(model);
54
+ ```
55
+
56
+ ### Key `Model.fromGltfAsync` Options
57
+
58
+ | Option | Type | Default |
59
+ |---|---|---|
60
+ | `url` | `string\|Resource` | required |
61
+ | `modelMatrix` | `Matrix4` | `IDENTITY` |
62
+ | `scale` | `number` | `1.0` |
63
+ | `minimumPixelSize` | `number` | `0.0` |
64
+ | `maximumScale` | `number` | -- |
65
+ | `show` | `boolean` | `true` |
66
+ | `color` / `colorBlendMode` / `colorBlendAmount` | `Color` / `ColorBlendMode` / `number` | -- / `HIGHLIGHT` / `0.5` |
67
+ | `edgeDisplayMode` | `EdgeDisplayMode` | `SURFACES_ONLY` |
68
+ | `silhouetteColor` / `silhouetteSize` | `Color` / `number` | `RED` / `0.0` |
69
+ | `shadows` | `ShadowMode` | `ENABLED` |
70
+ | `heightReference` | `HeightReference` | `NONE` |
71
+ | `customShader` | `CustomShader` | -- |
72
+ | `id` | `any` | -- |
73
+ | `allowPicking` | `boolean` | `true` |
74
+
75
+ ---
76
+
77
+ ## Readiness and Lifecycle
78
+
79
+ `fromGltfAsync` resolves once glTF JSON is parsed, but WebGL resources may still load. Wait for `readyEvent` before accessing animations, nodes, or `boundingSphere`.
80
+
81
+ ```js
82
+ const model = await Model.fromGltfAsync({ url: "robot.glb" });
83
+ viewer.scene.primitives.add(model);
84
+
85
+ model.readyEvent.addEventListener(() => {
86
+ console.log("Bounding sphere:", model.boundingSphere);
87
+ });
88
+ ```
89
+
90
+ ```js
91
+ // Synchronous check
92
+ if (model.ready) { const bs = model.boundingSphere; }
93
+ ```
94
+
95
+ ---
96
+
97
+ ## Animations
98
+
99
+ Managed through `model.activeAnimations` (`ModelAnimationCollection`).
100
+
101
+ ### Play by Name / Play All
102
+
103
+ ```js
104
+ model.readyEvent.addEventListener(() => {
105
+ // Single animation
106
+ const anim = model.activeAnimations.add({
107
+ name: "Walk", // glTF animation name
108
+ loop: Cesium.ModelAnimationLoop.REPEAT, // NONE | REPEAT | MIRRORED_REPEAT
109
+ multiplier: 1.0, // playback speed (must be > 0)
110
+ });
111
+ anim.start.addEventListener((m, a) => console.log(`Started: ${a.name}`));
112
+
113
+ // Or play all animations at once
114
+ model.activeAnimations.addAll({
115
+ loop: Cesium.ModelAnimationLoop.REPEAT,
116
+ multiplier: 0.5,
117
+ });
118
+ });
119
+ ```
120
+
121
+ Additional `add` options: `index`, `reverse`, `startTime`, `stopTime`, `delay`, `removeOnStop`, `animationTime` (custom time callback).
122
+
123
+ ### Animation Events
124
+
125
+ ```js
126
+ animation.start.addEventListener((model, animation) => { });
127
+ animation.update.addEventListener((model, animation, time) => { });
128
+ animation.stop.addEventListener((model, animation) => { });
129
+ // Collection-level
130
+ model.activeAnimations.animationAdded.addEventListener((model, anim) => { });
131
+ ```
132
+
133
+ ```js
134
+ model.activeAnimations.remove(animation); // remove one
135
+ model.activeAnimations.removeAll(); // remove all
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Model Nodes
141
+
142
+ Override named node transforms for procedural animation (e.g., turret rotation).
143
+
144
+ ```js
145
+ model.readyEvent.addEventListener(() => {
146
+ const node = model.getNode("Turret");
147
+ node.matrix = Cesium.Matrix4.fromScale(
148
+ new Cesium.Cartesian3(5.0, 1.0, 1.0), node.matrix
149
+ );
150
+ });
151
+ ```
152
+
153
+ Properties: `name` (read-only), `id` (read-only index), `show` (boolean), `matrix` (Matrix4 -- set to `undefined` to restore original and re-enable glTF animations).
154
+
155
+ ---
156
+
157
+ ## Coloring, Silhouettes, and Feature Picking
158
+
159
+ ```js
160
+ // Tint + silhouette
161
+ model.color = Cesium.Color.RED.withAlpha(0.5);
162
+ model.colorBlendMode = Cesium.ColorBlendMode.MIX;
163
+ model.colorBlendAmount = 0.5;
164
+ model.silhouetteColor = Cesium.Color.YELLOW;
165
+ model.silhouetteSize = 2.0;
166
+ ```
167
+
168
+ ### Edge Display Mode (Experimental, 1.142+)
169
+
170
+ For glTF assets using the draft `EXT_mesh_primitive_edge_visibility` extension,
171
+ `EdgeDisplayMode` controls whether extension-provided edges are hidden, composited
172
+ over surfaces, or rendered alone. Models without the extension are unaffected.
173
+
174
+ ```js
175
+ import { EdgeDisplayMode, Model } from "cesium";
176
+
177
+ const model = await Model.fromGltfAsync({
178
+ url: "/models/cad-part.glb",
179
+ edgeDisplayMode: EdgeDisplayMode.SURFACES_AND_EDGES,
180
+ });
181
+ viewer.scene.primitives.add(model);
182
+
183
+ model.edgeDisplayMode = EdgeDisplayMode.EDGES_ONLY; // CAD-style wireframe
184
+ model.edgeDisplayMode = EdgeDisplayMode.SURFACES_ONLY; // default
185
+ ```
186
+
187
+ When a glTF has `EXT_mesh_features` or `EXT_structural_metadata`, picking returns a `ModelFeature`:
188
+
189
+ ```js
190
+ const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
191
+ handler.setInputAction((movement) => {
192
+ const picked = viewer.scene.pick(movement.endPosition);
193
+ if (picked instanceof Cesium.ModelFeature) {
194
+ picked.getPropertyIds().forEach((name) => {
195
+ console.log(`${name}: ${picked.getProperty(name)}`);
196
+ });
197
+ picked.color = Cesium.Color.YELLOW;
198
+ }
199
+ }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
200
+ ```
201
+
202
+ ---
203
+
204
+ ## Height Reference
205
+
206
+ ```js
207
+ // Primitive API -- scene is required for height reference
208
+ const model = await Model.fromGltfAsync({
209
+ url: "truck.glb",
210
+ heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
211
+ scene: viewer.scene,
212
+ });
213
+
214
+ // Entity API
215
+ viewer.entities.add({
216
+ position: Cartesian3.fromDegrees(-75.59, 40.03),
217
+ model: { uri: "truck.glb", heightReference: Cesium.HeightReference.CLAMP_TO_GROUND },
218
+ });
219
+ ```
220
+
221
+ Values: `NONE`, `CLAMP_TO_GROUND`, `RELATIVE_TO_GROUND`, `CLAMP_TO_TERRAIN`, `RELATIVE_TO_TERRAIN`, `CLAMP_TO_3D_TILE`, `RELATIVE_TO_3D_TILE`.
222
+
223
+ ---
224
+
225
+ ## Particle Systems
226
+
227
+ `ParticleSystem` renders billboard-based effects. Position with `modelMatrix` (world) and `emitterModelMatrix` (local offset).
228
+
229
+ ### Smoke Trail
230
+
231
+ ```js
232
+ import { ParticleSystem, CircleEmitter, Color, Cartesian2, Transforms, Cartesian3 } from "cesium";
233
+
234
+ const smokeSystem = new ParticleSystem({
235
+ image: "smoke.png",
236
+ startColor: Color.LIGHTGRAY.withAlpha(0.7),
237
+ endColor: Color.WHITE.withAlpha(0.0),
238
+ startScale: 1.0,
239
+ endScale: 5.0,
240
+ emissionRate: 10,
241
+ minimumSpeed: 1.0,
242
+ maximumSpeed: 4.0,
243
+ minimumParticleLife: 1.2,
244
+ maximumParticleLife: 3.0,
245
+ imageSize: new Cartesian2(25, 25), // pixel size
246
+ emitter: new CircleEmitter(2.0), // radius in meters
247
+ modelMatrix: Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-75.157, 39.978)),
248
+ lifetime: 16.0,
249
+ loop: true,
250
+ });
251
+ viewer.scene.primitives.add(smokeSystem);
252
+ ```
253
+
254
+ ### Emitter Types
255
+
256
+ ```js
257
+ import { BoxEmitter, CircleEmitter, ConeEmitter, SphereEmitter } from "cesium";
258
+
259
+ new BoxEmitter(new Cesium.Cartesian3(10, 10, 10)); // 3D box, velocity outward
260
+ new CircleEmitter(2.0); // flat disk, velocity +Z
261
+ new ConeEmitter(Cesium.Math.toRadians(30)); // cone tip, velocity toward base
262
+ new SphereEmitter(5.0); // sphere, velocity radiates out
263
+ ```
264
+
265
+ ### Particle Bursts
266
+
267
+ ```js
268
+ const firework = new ParticleSystem({
269
+ image: getParticleCanvas(),
270
+ startColor: Color.RED,
271
+ endColor: Color.RED.withAlpha(0.0),
272
+ particleLife: 1.0,
273
+ speed: 100.0,
274
+ imageSize: new Cartesian2(7, 7),
275
+ emissionRate: 0, // bursts only
276
+ emitter: new SphereEmitter(0.1),
277
+ bursts: [
278
+ new Cesium.ParticleBurst({ time: 0.0, minimum: 100, maximum: 200 }),
279
+ new Cesium.ParticleBurst({ time: 2.0, minimum: 50, maximum: 100 }),
280
+ new Cesium.ParticleBurst({ time: 4.0, minimum: 200, maximum: 300 }),
281
+ ],
282
+ lifetime: 6.0,
283
+ loop: false,
284
+ modelMatrix: Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-75.597, 40.038)),
285
+ });
286
+ viewer.scene.primitives.add(firework);
287
+ ```
288
+
289
+ ### Update Callback (Gravity / Wind)
290
+
291
+ The `updateCallback` runs per-particle per-frame for forces like gravity.
292
+
293
+ ```js
294
+ const gravityScratch = new Cesium.Cartesian3();
295
+ function applyGravity(particle, dt) {
296
+ Cesium.Cartesian3.normalize(particle.position, gravityScratch);
297
+ Cesium.Cartesian3.multiplyByScalar(gravityScratch, -9.8 * dt, gravityScratch);
298
+ particle.velocity = Cesium.Cartesian3.add(particle.velocity, gravityScratch, particle.velocity);
299
+ }
300
+
301
+ const system = new ParticleSystem({
302
+ image: "smoke.png",
303
+ emissionRate: 20,
304
+ emitter: new ConeEmitter(Cesium.Math.toRadians(45)),
305
+ updateCallback: applyGravity,
306
+ modelMatrix: Transforms.eastNorthUpToFixedFrame(Cartesian3.fromDegrees(-105, 40, 1000)),
307
+ });
308
+ viewer.scene.primitives.add(system);
309
+ ```
310
+
311
+ ---
312
+
313
+ ## Attaching Particles to a Moving Model
314
+
315
+ Sync `modelMatrix` each frame via `scene.preUpdate`. Use `emitterModelMatrix` for a local offset (e.g., exhaust pipe).
316
+
317
+ ```js
318
+ const entity = viewer.entities.add({
319
+ position: sampledPosition,
320
+ orientation: new Cesium.VelocityOrientationProperty(sampledPosition),
321
+ model: { uri: "truck.glb", minimumPixelSize: 64 },
322
+ });
323
+
324
+ // Local offset to exhaust pipe
325
+ const trs = new Cesium.TranslationRotationScale();
326
+ trs.translation = new Cesium.Cartesian3(-4.0, 0.0, 1.4);
327
+ const emitterModelMatrix = Cesium.Matrix4.fromTranslationRotationScale(trs, new Cesium.Matrix4());
328
+
329
+ const exhaust = new ParticleSystem({
330
+ image: "smoke.png",
331
+ startColor: Color.GRAY.withAlpha(0.7),
332
+ endColor: Color.TRANSPARENT,
333
+ emissionRate: 8,
334
+ speed: 2.0,
335
+ particleLife: 1.5,
336
+ imageSize: new Cartesian2(20, 20),
337
+ emitter: new CircleEmitter(0.5),
338
+ emitterModelMatrix: emitterModelMatrix,
339
+ });
340
+ viewer.scene.primitives.add(exhaust);
341
+
342
+ viewer.scene.preUpdate.addEventListener((scene, time) => {
343
+ exhaust.modelMatrix = entity.computeModelMatrix(time, new Cesium.Matrix4());
344
+ });
345
+ ```
346
+
347
+ ---
348
+
349
+ ## Canvas-Based Particle Images
350
+
351
+ Generate particle textures dynamically instead of loading image files.
352
+
353
+ ```js
354
+ function createCircleImage() {
355
+ const c = document.createElement("canvas");
356
+ c.width = c.height = 20;
357
+ const ctx = c.getContext("2d");
358
+ ctx.beginPath();
359
+ ctx.arc(10, 10, 10, 0, Math.PI * 2);
360
+ ctx.fillStyle = "#fff";
361
+ ctx.fill();
362
+ return c;
363
+ }
364
+
365
+ // Pass canvas directly as image
366
+ new ParticleSystem({ image: createCircleImage(), /* ...other options */ });
367
+ ```
368
+
369
+ ---
370
+
371
+ ## Entity API Model (ModelGraphics)
372
+
373
+ For simpler use cases, add a model through the Entity API (see cesiumjs-entities for full coverage).
374
+
375
+ ```js
376
+ const entity = viewer.entities.add({
377
+ name: "Aircraft",
378
+ position: Cartesian3.fromDegrees(-123.074, 44.050, 5000),
379
+ orientation: Cesium.Transforms.headingPitchRollQuaternion(
380
+ Cartesian3.fromDegrees(-123.074, 44.050, 5000),
381
+ new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(135), 0, 0)
382
+ ),
383
+ model: {
384
+ uri: "CesiumAir.glb",
385
+ minimumPixelSize: 128,
386
+ maximumScale: 20000,
387
+ silhouetteColor: Color.RED,
388
+ silhouetteSize: 2.0,
389
+ },
390
+ });
391
+ viewer.trackedEntity = entity;
392
+ ```
393
+
394
+ ---
395
+
396
+ ## GPM Extension (NGA_gpm_local)
397
+
398
+ 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.
399
+
400
+ ---
401
+
402
+ ## Performance Tips
403
+
404
+ 1. **Use `.glb` over `.gltf`** -- binary format avoids extra HTTP requests and is smaller on the wire.
405
+ 2. **Enable Draco compression** (`KHR_draco_mesh_compression`) for 80-90% smaller meshes.
406
+ 3. **Use KTX2/Basis textures** (`KHR_texture_basisu`) for GPU-compressed textures; keep dimensions power-of-two.
407
+ 4. **Set `minimumPixelSize` carefully** -- large values force enlargement of distant models, increasing draw cost.
408
+ 5. **Limit silhouettes** -- extra rendering pass per silhouetted model; more than 256 may cause stencil artifacts.
409
+ 6. **Reuse scratch `Matrix4` objects** -- avoid allocating every frame when syncing particle systems to moving entities.
410
+ 7. **Keep emission rates low** -- each particle is a billboard; rates above 200/s can hurt frame rate. Use bursts for short effects.
411
+ 8. **Prefer pixel-sized particles** (`sizeInMeters: false`, default) -- meter-sized particles are expensive at close range.
412
+ 9. **Set finite `lifetime`** on particle systems -- `Number.MAX_VALUE` (default) prevents pool cleanup.
413
+ 10. **Disable picking for decorations** -- `allowPicking: false` saves GPU memory on models that need no interaction.
414
+ 11. **Destroy when done** -- `viewer.scene.primitives.remove(model)` then `model.destroy()` to free WebGL resources.
415
+
416
+ ---
417
+
418
+ ## See Also
419
+
420
+ - **cesiumjs-custom-shader** -- GLSL authoring for `Model.customShader` (struct reference, feature IDs, metadata, vertex displacement)
421
+ - **cesiumjs-materials-shaders** -- ImageBasedLighting, post-processing stages for models
422
+ - **cesiumjs-entities** -- Entity API ModelGraphics, data sources, time-dynamic properties
423
+ - **cesiumjs-3d-tiles** -- Cesium3DTileset (uses Model internally), clipping, styling