@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,471 @@
1
+ ---
2
+ name: cesiumjs-imagery
3
+ description: "CesiumJS imagery layers - ImageryProvider, ImageryLayer, ImageryLayerCollection, WMS, WMTS, Bing, OpenStreetMap, ArcGIS, Mapbox, tile discard policies. Use when adding or swapping base map layers, configuring imagery providers, layering multiple map sources, or creating split-screen imagery comparisons."
4
+ ---
5
+ # CesiumJS Imagery Layers
6
+
7
+ > CesiumJS v1.142 -- Imagery providers supply raster tile data rendered on the Globe
8
+ > or draped over a Cesium3DTileset. The three core abstractions are **ImageryProvider**
9
+ > (fetches tiles), **ImageryLayer** (display settings), and
10
+ > **ImageryLayerCollection** (ordered stack on the globe).
11
+
12
+ ```
13
+ ImageryProvider (abstract -- fetches tile images)
14
+ -> ImageryLayer (wraps one provider; alpha, brightness, split, etc.)
15
+ -> ImageryLayerCollection (ordered stack; index 0 = base layer)
16
+ -> Globe / Cesium3DTileset
17
+ ```
18
+
19
+ Layers render bottom-to-top. Index 0 is the **base layer**, stretched to fill
20
+ the globe even if its rectangle does not cover the entire world.
21
+
22
+ ## Quick Start and ImageryLayer Factories
23
+
24
+ When creating a viewer for imagery work, disable unneeded widgets so the imagery
25
+ is the visual focus. Use `camera.setView` (not `flyTo`) when you need the camera
26
+ in position immediately — `flyTo` animates and may not finish before your code
27
+ continues.
28
+
29
+ ```js
30
+ import { Viewer, ImageryLayer, IonImageryProvider, IonWorldImageryStyle, Math as CesiumMath } from "cesium";
31
+
32
+ // Clean viewer -- disable widgets that distract from imagery
33
+ const viewer = new Viewer("cesiumContainer", {
34
+ animation: false,
35
+ timeline: false,
36
+ navigationHelpButton: false,
37
+ navigationInstructionsInitiallyVisible: false,
38
+ });
39
+
40
+ // Position camera immediately (no animation)
41
+ viewer.camera.setView({
42
+ destination: Cesium.Cartesian3.fromDegrees(-73.0, 41.0, 1500000),
43
+ orientation: {
44
+ heading: 0.0,
45
+ pitch: CesiumMath.toRadians(-90), // look straight down
46
+ roll: 0.0,
47
+ },
48
+ });
49
+
50
+ // Explicit base layer choice
51
+ const viewer2 = new Viewer("cesiumContainer", {
52
+ baseLayer: ImageryLayer.fromWorldImagery(),
53
+ });
54
+
55
+ // fromProviderAsync -- wraps any async provider; returns ImageryLayer immediately
56
+ const nightLayer = ImageryLayer.fromProviderAsync(
57
+ IonImageryProvider.fromAssetId(3812), // Earth at Night
58
+ );
59
+ nightLayer.alpha = 0.5;
60
+ nightLayer.brightness = 2.0;
61
+ viewer.imageryLayers.add(nightLayer);
62
+
63
+ // fromWorldImagery with style override
64
+ const roadLayer = ImageryLayer.fromWorldImagery({
65
+ style: IonWorldImageryStyle.ROAD,
66
+ });
67
+ viewer.imageryLayers.add(roadLayer);
68
+ ```
69
+
70
+ ### Camera Height Reference for Imagery Scenes
71
+
72
+ Use `camera.setView` with these approximate heights:
73
+
74
+ | Scale | Height (m) | Example |
75
+ |---|---|---|
76
+ | Street / block | 500–2,000 | Downtown intersection |
77
+ | City | 5,000–25,000 | Washington DC, Paris |
78
+ | Metro area | 50,000–200,000 | Greater London |
79
+ | Region / state | 300,000–1,500,000 | Florida, Japan |
80
+ | Continent | 3,000,000–8,000,000 | Europe, North America |
81
+
82
+ For top-down (map-style) views set `pitch: CesiumMath.toRadians(-90)`.
83
+ For oblique 3D views set `pitch: CesiumMath.toRadians(-35)` to `CesiumMath.toRadians(-60)`.
84
+
85
+ ## ImageryLayerCollection API
86
+
87
+ Access via `viewer.imageryLayers` (same as `viewer.scene.imageryLayers`).
88
+
89
+ ```js
90
+ const layers = viewer.imageryLayers;
91
+
92
+ layers.add(myLayer); // add on top
93
+ layers.add(myLayer, 0); // add at index
94
+ layers.addImageryProvider(provider); // create layer + add
95
+
96
+ layers.raise(myLayer); // move up one
97
+ layers.lower(myLayer); // move down one
98
+ layers.raiseToTop(myLayer); // move to top
99
+ layers.lowerToBottom(myLayer); // move to bottom
100
+
101
+ layers.remove(myLayer); // remove and destroy
102
+ layers.remove(myLayer, false); // remove without destroying
103
+ layers.removeAll();
104
+
105
+ const count = layers.length;
106
+ const base = layers.get(0);
107
+ const idx = layers.indexOf(myLayer);
108
+ const has = layers.contains(myLayer);
109
+ ```
110
+
111
+ Events: `layerAdded(layer, index)`, `layerRemoved(layer, index)`,
112
+ `layerMoved(layer, newIndex, oldIndex)`, `layerShownOrHidden(layer, index, show)`.
113
+
114
+ ## ImageryLayer Display Properties
115
+
116
+ Properties accept a number or a per-tile callback `(frameState, layer, x, y, level) => value`.
117
+
118
+ | Property | Default | Notes |
119
+ |---|---|---|
120
+ | `alpha` | 1.0 | 0 = transparent, 1 = opaque |
121
+ | `brightness` | 1.0 | < 1 darker, > 1 brighter |
122
+ | `contrast` | 1.0 | < 1 lower, > 1 higher |
123
+ | `hue` | 0.0 | Shift in radians |
124
+ | `saturation` | 1.0 | < 1 desaturated, > 1 oversaturated |
125
+ | `gamma` | 1.0 | Gamma correction |
126
+ | `show` | true | Visibility toggle |
127
+ | `splitDirection` | `SplitDirection.NONE` | LEFT, RIGHT, or NONE |
128
+ | `nightAlpha` / `dayAlpha` | 1.0 | Requires `Globe.enableLighting` |
129
+
130
+ Additional options: `rectangle`, `minimumTerrainLevel` / `maximumTerrainLevel`,
131
+ `cutoutRectangle`, `colorToAlpha` / `colorToAlphaThreshold`,
132
+ `minificationFilter` / `magnificationFilter` (LINEAR default, or NEAREST).
133
+
134
+ ```js
135
+ // Adjust appearance at runtime
136
+ layer.alpha = 0.7;
137
+ layer.brightness = 1.3;
138
+ layer.contrast = 1.5;
139
+ layer.saturation = 0.5;
140
+ layer.gamma = 1.2;
141
+ ```
142
+
143
+ ## Swapping the Base Layer
144
+
145
+ Remove the default base layer and replace it at index 0. The replacement becomes
146
+ the new base layer, stretched to fill the globe.
147
+
148
+ ```js
149
+ import { ImageryLayer, OpenStreetMapImageryProvider } from "cesium";
150
+
151
+ // Remove default Bing aerial
152
+ viewer.imageryLayers.remove(viewer.imageryLayers.get(0));
153
+
154
+ // Add OSM as new base layer at index 0
155
+ const osmLayer = new ImageryLayer(
156
+ new OpenStreetMapImageryProvider({
157
+ url: "https://tile.openstreetmap.org/",
158
+ maximumLevel: 19,
159
+ credit: "OpenStreetMap contributors",
160
+ }),
161
+ );
162
+ viewer.imageryLayers.add(osmLayer, 0);
163
+ ```
164
+
165
+ ## Imagery Providers
166
+
167
+ ### IonImageryProvider
168
+
169
+ ```js
170
+ // Always use fromAssetId (async factory); never call constructor directly
171
+ const layer = ImageryLayer.fromProviderAsync(
172
+ IonImageryProvider.fromAssetId(3812),
173
+ );
174
+ viewer.imageryLayers.add(layer);
175
+ ```
176
+
177
+ ### OpenStreetMapImageryProvider
178
+
179
+ Extends UrlTemplateImageryProvider for Slippy tile servers.
180
+
181
+ ```js
182
+ const osm = new OpenStreetMapImageryProvider({
183
+ url: "https://tile.openstreetmap.org/",
184
+ maximumLevel: 19,
185
+ credit: "OpenStreetMap contributors",
186
+ // retinaTiles: true, // request @2x tiles
187
+ });
188
+ viewer.imageryLayers.addImageryProvider(osm);
189
+ ```
190
+
191
+ ### UrlTemplateImageryProvider
192
+
193
+ The most flexible provider. Placeholders: `{x}`, `{y}`, `{z}`, `{s}`,
194
+ `{reverseX/Y/Z}`, `{west/south/east/northDegrees}`,
195
+ `{west/south/east/northProjected}`, `{width}`, `{height}`.
196
+
197
+ ```js
198
+ import { UrlTemplateImageryProvider, GeographicTilingScheme, buildModuleUrl } from "cesium";
199
+
200
+ // TMS-style with Geographic tiling
201
+ const tms = new UrlTemplateImageryProvider({
202
+ url: buildModuleUrl("Assets/Textures/NaturalEarthII") + "/{z}/{x}/{reverseY}.jpg",
203
+ tilingScheme: new GeographicTilingScheme(),
204
+ maximumLevel: 5,
205
+ });
206
+ viewer.imageryLayers.addImageryProvider(tms);
207
+
208
+ // Carto Positron with subdomains
209
+ const positron = new UrlTemplateImageryProvider({
210
+ url: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png",
211
+ subdomains: "abcd",
212
+ credit: "Map tiles by CartoDB, under CC BY 3.0. Data by OpenStreetMap, under ODbL.",
213
+ });
214
+
215
+ // Custom tags for time-varying data
216
+ const custom = new UrlTemplateImageryProvider({
217
+ url: "https://yourserver/{Time}/{z}/{y}/{x}.png",
218
+ customTags: {
219
+ Time: (imageryProvider, x, y, level) => "20240101",
220
+ },
221
+ });
222
+ ```
223
+
224
+ ### WebMapServiceImageryProvider (WMS)
225
+
226
+ ```js
227
+ import { WebMapServiceImageryProvider, ImageryLayer, Rectangle } from "cesium";
228
+
229
+ const wms = new WebMapServiceImageryProvider({
230
+ url: "https://basemap.nationalmap.gov:443/arcgis/services/USGSHydroCached/MapServer/WMSServer",
231
+ layers: "0",
232
+ rectangle: Rectangle.fromDegrees(-180, -90, 180, 90),
233
+ // parameters: { transparent: true, format: "image/png" },
234
+ // crs: "EPSG:4326", // WMS >= 1.3.0
235
+ // srs: "EPSG:4326", // WMS 1.1.x
236
+ });
237
+ viewer.imageryLayers.add(new ImageryLayer(wms));
238
+ ```
239
+
240
+ ### WebMapTileServiceImageryProvider (WMTS)
241
+
242
+ Required options: `url`, `layer`, `style`, `tileMatrixSetID`.
243
+
244
+ ```js
245
+ import { WebMapTileServiceImageryProvider, Credit } from "cesium";
246
+
247
+ const wmts = new WebMapTileServiceImageryProvider({
248
+ url: "https://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/WMTS",
249
+ layer: "USGSShadedReliefOnly",
250
+ style: "default",
251
+ format: "image/jpeg",
252
+ tileMatrixSetID: "default028mm",
253
+ maximumLevel: 19,
254
+ credit: new Credit("U. S. Geological Survey"),
255
+ });
256
+ viewer.imageryLayers.addImageryProvider(wmts);
257
+ ```
258
+
259
+ **GetFeatureInfo (1.140+, #13196):** `WebMapTileServiceImageryProvider` now supports
260
+ `pickFeatures` for both KVP and RESTful WMTS services. Enable it with the new
261
+ constructor options `enablePickFeatures`, `getFeatureInfoFormats`,
262
+ `getFeatureInfoUrl`, and `getFeatureInfoParameters`; then call
263
+ `provider.pickFeatures(x, y, level, longitude, latitude)` (the same signature WMS
264
+ uses) to query attributes at a location.
265
+
266
+ ### ArcGisMapServerImageryProvider
267
+
268
+ ```js
269
+ import { ArcGisMapServerImageryProvider, ArcGisMapService, ArcGisBaseMapType, ImageryLayer } from "cesium";
270
+
271
+ ArcGisMapService.defaultAccessToken = "<YOUR_ARCGIS_TOKEN>";
272
+
273
+ // From basemap type enum: SATELLITE, OCEANS, HILLSHADE
274
+ const arcgis = ImageryLayer.fromProviderAsync(
275
+ ArcGisMapServerImageryProvider.fromBasemapType(ArcGisBaseMapType.SATELLITE),
276
+ );
277
+ viewer.imageryLayers.add(arcgis);
278
+
279
+ // From a specific MapServer URL
280
+ const streets = ImageryLayer.fromProviderAsync(
281
+ ArcGisMapServerImageryProvider.fromUrl(
282
+ "https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer",
283
+ ),
284
+ );
285
+ ```
286
+
287
+ ### BingMapsImageryProvider
288
+
289
+ ```js
290
+ import { BingMapsImageryProvider, BingMapsStyle, ImageryLayer } from "cesium";
291
+
292
+ const bing = ImageryLayer.fromProviderAsync(
293
+ BingMapsImageryProvider.fromUrl("https://dev.virtualearth.net", {
294
+ key: "<YOUR_BING_KEY>",
295
+ mapStyle: BingMapsStyle.AERIAL_WITH_LABELS_ON_DEMAND,
296
+ }),
297
+ );
298
+ viewer.imageryLayers.add(bing);
299
+ ```
300
+
301
+ Styles: `AERIAL`, `AERIAL_WITH_LABELS_ON_DEMAND`, `ROAD_ON_DEMAND`,
302
+ `CANVAS_DARK`, `CANVAS_LIGHT`, `CANVAS_GRAY`.
303
+
304
+ ### MapboxStyleImageryProvider
305
+
306
+ ```js
307
+ import { MapboxStyleImageryProvider, ImageryLayer } from "cesium";
308
+
309
+ const mapbox = new MapboxStyleImageryProvider({
310
+ styleId: "streets-v11",
311
+ accessToken: "<YOUR_MAPBOX_TOKEN>",
312
+ // tilesize: 512, scaleFactor: true // retina
313
+ });
314
+ viewer.imageryLayers.add(new ImageryLayer(mapbox));
315
+ ```
316
+
317
+ ### SingleTileImageryProvider
318
+
319
+ ```js
320
+ import { SingleTileImageryProvider, ImageryLayer, Rectangle } from "cesium";
321
+
322
+ const logo = ImageryLayer.fromProviderAsync(
323
+ SingleTileImageryProvider.fromUrl("/images/overlay.png", {
324
+ rectangle: Rectangle.fromDegrees(-75.0, 28.0, -67.0, 29.75),
325
+ }),
326
+ );
327
+ viewer.imageryLayers.add(logo);
328
+ ```
329
+
330
+ > **1.140+ (#13297):** `OffscreenCanvas` is now an accepted `ImageryTypes` value,
331
+ > so you can feed a worker-rendered or dynamically-drawn `OffscreenCanvas`
332
+ > wherever an image source is expected -- useful for procedurally generated or
333
+ > live-updating overlays without round-tripping through a data URL.
334
+
335
+ ## Split-Screen Comparison
336
+
337
+ ```js
338
+ import { ImageryLayer, IonImageryProvider, SplitDirection } from "cesium";
339
+
340
+ // Add an overlay that only appears on the left side of the split
341
+ const nightLayer = ImageryLayer.fromProviderAsync(IonImageryProvider.fromAssetId(3812));
342
+ nightLayer.splitDirection = SplitDirection.LEFT;
343
+ viewer.imageryLayers.add(nightLayer);
344
+
345
+ viewer.scene.splitPosition = 0.5; // 0-1 fraction of viewport width
346
+ ```
347
+
348
+ `SplitDirection`: `LEFT` (-1), `NONE` (0), `RIGHT` (1).
349
+
350
+ ## Cutout Rectangle
351
+
352
+ ```js
353
+ import { Rectangle } from "cesium";
354
+
355
+ const cutout = Rectangle.fromDegrees(-90, 20, -70, 40);
356
+
357
+ // Cut a hole in the base layer to reveal imagery beneath
358
+ const base = viewer.imageryLayers.get(0);
359
+ base.cutoutRectangle = cutout;
360
+ ```
361
+
362
+ ## Color-to-Alpha
363
+
364
+ ```js
365
+ import { Color } from "cesium";
366
+
367
+ const baseLayer = viewer.imageryLayers.get(0);
368
+ baseLayer.colorToAlpha = new Color(0.0, 0.016, 0.059); // dark ocean blue
369
+ baseLayer.colorToAlphaThreshold = 0.2; // tolerance (0-1)
370
+ ```
371
+
372
+ ## Draping Imagery on 3D Tiles
373
+
374
+ ```js
375
+ import { Cesium3DTileset, ImageryLayer, IonImageryProvider } from "cesium";
376
+
377
+ const tileset = await Cesium3DTileset.fromUrl("/path/to/tileset.json");
378
+ viewer.scene.primitives.add(tileset);
379
+
380
+ const labelLayer = ImageryLayer.fromProviderAsync(
381
+ IonImageryProvider.fromAssetId(2411391),
382
+ );
383
+ tileset.imageryLayers.add(labelLayer); // drape on tileset, not globe
384
+ labelLayer.show = false; // toggle off
385
+ ```
386
+
387
+ ## Debugging Providers
388
+
389
+ ```js
390
+ import { TileCoordinatesImageryProvider, GridImageryProvider, ImageryLayer, Color } from "cesium";
391
+
392
+ // Show x/y/level labels on every tile
393
+ viewer.imageryLayers.add(new ImageryLayer(
394
+ new TileCoordinatesImageryProvider({ color: Color.YELLOW }),
395
+ ));
396
+ // Wireframe grid overlay
397
+ viewer.imageryLayers.add(new ImageryLayer(new GridImageryProvider()));
398
+ ```
399
+
400
+ ## Tile Discard Policies
401
+
402
+ | Policy | Behavior |
403
+ |---|---|
404
+ | `DiscardEmptyTileImagePolicy` | Discards zero-byte images (Bing Maps default) |
405
+ | `DiscardMissingTileImagePolicy` | Compares pixels against a known "missing" tile |
406
+ | `NeverTileDiscardPolicy` | Never discards (use when server always returns valid tiles) |
407
+
408
+ ```js
409
+ import { NeverTileDiscardPolicy, UrlTemplateImageryProvider } from "cesium";
410
+
411
+ const provider = new UrlTemplateImageryProvider({
412
+ url: "https://my-server/{z}/{x}/{y}.png",
413
+ tileDiscardPolicy: new NeverTileDiscardPolicy(),
414
+ });
415
+ ```
416
+
417
+ ## Error Handling
418
+
419
+ ```js
420
+ const layer = ImageryLayer.fromProviderAsync(IonImageryProvider.fromAssetId(3812));
421
+ viewer.imageryLayers.add(layer);
422
+
423
+ // Provider creation failure
424
+ layer.errorEvent.addEventListener((error) => {
425
+ console.error("Layer creation failed:", error);
426
+ });
427
+
428
+ // Provider resolved -- listen for per-tile errors
429
+ layer.readyEvent.addEventListener((provider) => {
430
+ provider.errorEvent.addEventListener((tileError) => {
431
+ console.warn("Tile error:", tileError.message);
432
+ });
433
+ });
434
+ ```
435
+
436
+ ## Time-Dynamic WMTS
437
+
438
+ Pass `clock` and `times` (a `TimeIntervalCollection`) for time-varying layers.
439
+
440
+ ```js
441
+ import { WebMapTileServiceImageryProvider, TimeIntervalCollection, JulianDate, Credit } from "cesium";
442
+
443
+ const times = TimeIntervalCollection.fromIso8601({
444
+ iso8601: "2015-07-30/2017-06-16/P1D",
445
+ dataCallback: (interval) => ({ Time: JulianDate.toIso8601(interval.start) }),
446
+ });
447
+ const weather = new WebMapTileServiceImageryProvider({
448
+ url: "https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/AMSR2_Snow_Water_Equivalent/default/{Time}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png",
449
+ layer: "AMSR2_Snow_Water_Equivalent", style: "default",
450
+ tileMatrixSetID: "2km", maximumLevel: 5, format: "image/png",
451
+ clock: viewer.clock, times: times,
452
+ credit: new Credit("NASA Global Imagery Browse Services for EOSDIS"),
453
+ });
454
+ viewer.imageryLayers.addImageryProvider(weather);
455
+ ```
456
+
457
+ ## Performance Tips
458
+
459
+ 1. **Limit simultaneous layers** -- 2-3 is typical; each layer multiplies tile requests and GPU texture memory.
460
+ 2. **Set `hasAlphaChannel: false`** on opaque providers to reduce memory and upload time.
461
+ 3. **Use `minimumTerrainLevel` / `maximumTerrainLevel`** to skip tile fetches at irrelevant zoom levels.
462
+ 4. **Prefer `ImageryLayer.fromProviderAsync`** over manual await -- avoids blank globe during provider load.
463
+ 5. **Set tight `rectangle` bounds** on regional providers to prevent out-of-extent tile requests.
464
+ 6. **Reuse provider instances** -- remove with `destroy: false` and re-add instead of recreating.
465
+ 7. **Use `NeverTileDiscardPolicy`** when tiles are always valid; pixel comparison adds overhead.
466
+ 8. **Choose NEAREST filtering** only for classified raster data; LINEAR (default) is faster.
467
+
468
+ ## See Also
469
+
470
+ - **cesiumjs-viewer-setup** -- Viewer constructor, Ion token, `createWorldImageryAsync`
471
+ - **cesiumjs-terrain-environment** -- Globe, terrain providers, atmosphere, lighting