@walkthru-earth/objex 1.3.0 → 1.4.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 (182) hide show
  1. package/LICENSE +5 -0
  2. package/README.md +20 -12
  3. package/dist/components/browser/FileTreeSidebar.svelte +32 -17
  4. package/dist/components/layout/AboutSheet.svelte +5 -2
  5. package/dist/components/layout/ConnectionDialog.svelte +1 -1
  6. package/dist/components/layout/SettingsSheet.svelte +237 -0
  7. package/dist/components/layout/SettingsSheet.svelte.d.ts +6 -0
  8. package/dist/components/layout/Sidebar.svelte +73 -6
  9. package/dist/components/layout/Sidebar.svelte.d.ts +4 -1
  10. package/dist/components/layout/StatusBar.svelte +1 -1
  11. package/dist/components/layout/TabBar.svelte +2 -2
  12. package/dist/components/ui/context-menu/context-menu-radio-group.svelte.d.ts +1 -1
  13. package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +1 -1
  14. package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +1 -1
  15. package/dist/components/ui/input/input.svelte.d.ts +1 -1
  16. package/dist/components/ui/resizable/index.d.ts +1 -1
  17. package/dist/components/ui/resizable/index.js +2 -2
  18. package/dist/components/ui/slider/index.d.ts +3 -0
  19. package/dist/components/ui/slider/index.js +5 -0
  20. package/dist/components/ui/slider/range-slider.svelte +94 -0
  21. package/dist/components/ui/slider/range-slider.svelte.d.ts +21 -0
  22. package/dist/components/ui/slider/slider.svelte +83 -0
  23. package/dist/components/ui/slider/slider.svelte.d.ts +7 -0
  24. package/dist/components/viewers/ArchiveViewer.svelte +2 -2
  25. package/dist/components/viewers/CodeViewer.svelte +31 -22
  26. package/dist/components/viewers/CogControls.svelte +338 -184
  27. package/dist/components/viewers/CogControls.svelte.d.ts +33 -10
  28. package/dist/components/viewers/CogViewer.svelte +320 -119
  29. package/dist/components/viewers/CopcViewer.svelte +1 -1
  30. package/dist/components/viewers/FlatGeobufViewer.svelte +1 -1
  31. package/dist/components/viewers/GeoParquetMapViewer.svelte +6 -6
  32. package/dist/components/viewers/GeoParquetMapViewer.svelte.d.ts +1 -1
  33. package/dist/components/viewers/ImageViewer.svelte +2 -2
  34. package/dist/components/viewers/MarkdownViewer.svelte +12 -9
  35. package/dist/components/viewers/MediaViewer.svelte +2 -2
  36. package/dist/components/viewers/ModelViewer.svelte +1 -1
  37. package/dist/components/viewers/MultiCogViewer.svelte +467 -102
  38. package/dist/components/viewers/MultiCogViewer.svelte.d.ts +1 -1
  39. package/dist/components/viewers/NotebookViewer.svelte +6 -3
  40. package/dist/components/viewers/PdfViewer.svelte +2 -2
  41. package/dist/components/viewers/PmtilesViewer.svelte +3 -6
  42. package/dist/components/viewers/RawViewer.svelte +6 -3
  43. package/dist/components/viewers/StacMapViewer.svelte +10 -2
  44. package/dist/components/viewers/StacMosaicViewer.svelte +1800 -362
  45. package/dist/components/viewers/StacMosaicViewer.svelte.d.ts +1 -1
  46. package/dist/components/viewers/StacTabViewer.svelte +24 -13
  47. package/dist/components/viewers/StacTabViewer.svelte.d.ts +1 -1
  48. package/dist/components/viewers/TableGrid.svelte +4 -4
  49. package/dist/components/viewers/TableStatusBar.svelte +1 -1
  50. package/dist/components/viewers/TableToolbar.svelte +1 -1
  51. package/dist/components/viewers/TableViewer.svelte +25 -17
  52. package/dist/components/viewers/TableViewer.svelte.d.ts +1 -0
  53. package/dist/components/viewers/ViewerRouter.svelte +16 -8
  54. package/dist/components/viewers/ZarrMapViewer.svelte +11 -9
  55. package/dist/components/viewers/ZarrViewer.svelte +4 -4
  56. package/dist/components/viewers/cog/ChannelPicker.svelte +83 -0
  57. package/dist/components/viewers/cog/ChannelPicker.svelte.d.ts +13 -0
  58. package/dist/components/viewers/cog/PixelInspectorPanel.svelte +87 -0
  59. package/dist/components/viewers/cog/PixelInspectorPanel.svelte.d.ts +17 -0
  60. package/dist/components/viewers/cog/buildRgbLayer.d.ts +78 -0
  61. package/dist/components/viewers/cog/buildRgbLayer.js +176 -0
  62. package/dist/components/viewers/map/AttributeTable.svelte +1 -1
  63. package/dist/components/viewers/map/MapContainer.svelte +37 -11
  64. package/dist/components/viewers/pmtiles/PmtilesArchiveView.svelte +1 -1
  65. package/dist/components/viewers/pmtiles/PmtilesTileInspector.svelte +1 -1
  66. package/dist/components/viewers/stac/StacDatetimeBar.svelte +175 -0
  67. package/dist/components/viewers/stac/StacDatetimeBar.svelte.d.ts +10 -0
  68. package/dist/components/viewers/stac/StacFilterPanel.svelte +243 -0
  69. package/dist/components/viewers/stac/StacFilterPanel.svelte.d.ts +14 -0
  70. package/dist/components/viewers/stac/StacItemInspector.svelte +223 -0
  71. package/dist/components/viewers/stac/StacItemInspector.svelte.d.ts +10 -0
  72. package/dist/components/viewers/stac/StacItemStrip.svelte +228 -0
  73. package/dist/components/viewers/stac/StacItemStrip.svelte.d.ts +12 -0
  74. package/dist/file-icons/index.d.ts +1 -1
  75. package/dist/file-icons/index.js +1 -1
  76. package/dist/i18n/ar.js +110 -2
  77. package/dist/i18n/en.js +110 -2
  78. package/dist/index.d.ts +2 -28
  79. package/dist/index.js +7 -23
  80. package/dist/query/engine.d.ts +10 -0
  81. package/dist/query/source.js +1 -1
  82. package/dist/query/stac-source-factory.d.ts +65 -0
  83. package/dist/query/stac-source-factory.js +77 -0
  84. package/dist/query/stac-source-parquet.d.ts +135 -0
  85. package/dist/query/stac-source-parquet.js +465 -0
  86. package/dist/query/wasm.d.ts +8 -0
  87. package/dist/query/wasm.js +304 -2
  88. package/dist/storage/presign.js +1 -1
  89. package/dist/storage/providers.js +5 -5
  90. package/dist/stores/config.svelte.d.ts +15 -0
  91. package/dist/stores/config.svelte.js +46 -0
  92. package/dist/stores/connections.svelte.d.ts +2 -2
  93. package/dist/stores/connections.svelte.js +1 -2
  94. package/dist/stores/files.svelte.d.ts +1 -1
  95. package/dist/stores/files.svelte.js +1 -1
  96. package/dist/stores/query-history.svelte.js +1 -1
  97. package/dist/stores/settings.svelte.d.ts +16 -1
  98. package/dist/stores/settings.svelte.js +104 -48
  99. package/dist/stores/tabs.svelte.d.ts +3 -0
  100. package/dist/stores/tabs.svelte.js +17 -0
  101. package/dist/utils/cog-histogram.d.ts +121 -0
  102. package/dist/utils/cog-histogram.js +424 -0
  103. package/dist/utils/cog.d.ts +200 -60
  104. package/dist/utils/cog.js +377 -114
  105. package/dist/utils/colormap-sprite.d.ts +0 -9
  106. package/dist/utils/colormap-sprite.js +0 -21
  107. package/dist/utils/deck.d.ts +16 -12
  108. package/dist/utils/deck.js +10 -4
  109. package/dist/utils/pmtiles-tile.js +2 -2
  110. package/dist/utils/{url.d.ts → signed-url.d.ts} +15 -1
  111. package/dist/utils/{url.js → signed-url.js} +32 -10
  112. package/dist/utils/url-state.d.ts +36 -0
  113. package/dist/utils/url-state.js +72 -2
  114. package/dist/utils/zarr-tab.d.ts +1 -2
  115. package/dist/utils/zarr-tab.js +1 -2
  116. package/dist/utils/zarr.d.ts +0 -17
  117. package/dist/utils/zarr.js +1 -45
  118. package/package.json +55 -84
  119. package/dist/components/browser/Breadcrumb.svelte +0 -50
  120. package/dist/components/browser/Breadcrumb.svelte.d.ts +0 -7
  121. package/dist/components/browser/CreateFolderDialog.svelte +0 -98
  122. package/dist/components/browser/CreateFolderDialog.svelte.d.ts +0 -6
  123. package/dist/components/browser/DeleteConfirmDialog.svelte +0 -90
  124. package/dist/components/browser/DeleteConfirmDialog.svelte.d.ts +0 -8
  125. package/dist/components/browser/DropZone.svelte +0 -83
  126. package/dist/components/browser/DropZone.svelte.d.ts +0 -7
  127. package/dist/components/browser/FileBrowser.svelte +0 -252
  128. package/dist/components/browser/FileBrowser.svelte.d.ts +0 -3
  129. package/dist/components/browser/FileRow.svelte +0 -117
  130. package/dist/components/browser/FileRow.svelte.d.ts +0 -9
  131. package/dist/components/browser/RenameDialog.svelte +0 -101
  132. package/dist/components/browser/RenameDialog.svelte.d.ts +0 -8
  133. package/dist/components/browser/SearchBar.svelte +0 -40
  134. package/dist/components/browser/SearchBar.svelte.d.ts +0 -6
  135. package/dist/components/browser/UploadButton.svelte +0 -65
  136. package/dist/components/browser/UploadButton.svelte.d.ts +0 -3
  137. package/dist/query/stac-geoparquet.d.ts +0 -31
  138. package/dist/query/stac-geoparquet.js +0 -136
  139. package/dist/utils/clipboard.d.ts +0 -13
  140. package/dist/utils/clipboard.js +0 -38
  141. package/dist/utils/cloud-url.d.ts +0 -27
  142. package/dist/utils/cloud-url.js +0 -61
  143. package/dist/utils/column-types.d.ts +0 -5
  144. package/dist/utils/column-types.js +0 -137
  145. package/dist/utils/connection-identity.d.ts +0 -51
  146. package/dist/utils/connection-identity.js +0 -97
  147. package/dist/utils/error.d.ts +0 -8
  148. package/dist/utils/error.js +0 -12
  149. package/dist/utils/evidence-context.d.ts +0 -22
  150. package/dist/utils/evidence-context.js +0 -56
  151. package/dist/utils/export.d.ts +0 -22
  152. package/dist/utils/export.js +0 -76
  153. package/dist/utils/file-sort.d.ts +0 -20
  154. package/dist/utils/file-sort.js +0 -41
  155. package/dist/utils/format.d.ts +0 -24
  156. package/dist/utils/format.js +0 -78
  157. package/dist/utils/geoarrow.d.ts +0 -32
  158. package/dist/utils/geoarrow.js +0 -672
  159. package/dist/utils/geometry-type.d.ts +0 -52
  160. package/dist/utils/geometry-type.js +0 -76
  161. package/dist/utils/hex.d.ts +0 -10
  162. package/dist/utils/hex.js +0 -27
  163. package/dist/utils/host-detection.d.ts +0 -23
  164. package/dist/utils/host-detection.js +0 -95
  165. package/dist/utils/local-storage.d.ts +0 -16
  166. package/dist/utils/local-storage.js +0 -37
  167. package/dist/utils/markdown-sql.d.ts +0 -30
  168. package/dist/utils/markdown-sql.js +0 -72
  169. package/dist/utils/notebook.d.ts +0 -59
  170. package/dist/utils/notebook.js +0 -211
  171. package/dist/utils/parquet-metadata.d.ts +0 -64
  172. package/dist/utils/parquet-metadata.js +0 -262
  173. package/dist/utils/stac-geoparquet.d.ts +0 -90
  174. package/dist/utils/stac-geoparquet.js +0 -223
  175. package/dist/utils/stac-hydrate.d.ts +0 -38
  176. package/dist/utils/stac-hydrate.js +0 -243
  177. package/dist/utils/stac.d.ts +0 -136
  178. package/dist/utils/stac.js +0 -176
  179. package/dist/utils/storage-url.d.ts +0 -90
  180. package/dist/utils/storage-url.js +0 -568
  181. package/dist/utils/wkb.d.ts +0 -43
  182. package/dist/utils/wkb.js +0 -359
@@ -1,13 +1,18 @@
1
- import type { GetTileDataOptions, MinimalDataT } from '@developmentseed/deck.gl-geotiff';
2
- import type { RasterModule, RenderTileResult } from '@developmentseed/deck.gl-raster';
1
+ import type { GetTileDataOptions } from '@developmentseed/deck.gl-geotiff';
2
+ import type { MinimalTileData, RasterModule, RenderTileResult } from '@developmentseed/deck.gl-raster';
3
3
  import type { GeoTIFF as GeoTIFFType, Overview } from '@developmentseed/geotiff';
4
4
  import { GeoTIFF } from '@developmentseed/geotiff';
5
5
  import type { EpsgResolver } from '@developmentseed/proj';
6
6
  import type { Device } from '@luma.gl/core';
7
+ import { buildDataTypeLabel, type CogInfo, clampBounds, type GeoBounds, SF_LABELS, safeClamp } from '@walkthru-earth/objex-utils';
7
8
  import type maplibregl from 'maplibre-gl';
9
+ import { type GdalBandStats, type GdalImageStats, HISTOGRAM_BINS, type HistogramSnapshot, readGdalStats, type StreamHistogramOptions, streamHistogram } from './cog-histogram.js';
8
10
  import { type ColormapName } from './colormap-sprite.js';
9
- /** SampleFormat tag value human label. */
10
- export declare const SF_LABELS: Record<number, string>;
11
+ export declare function loadGeoTIFF(href: string, options?: {
12
+ chunkSize?: number;
13
+ cacheSize?: number;
14
+ }): Promise<GeoTIFFType>;
15
+ export { buildDataTypeLabel, type CogInfo, clampBounds, type GdalBandStats, type GdalImageStats, type GeoBounds, HISTOGRAM_BINS, type HistogramSnapshot, readGdalStats, SF_LABELS, type StreamHistogramOptions, safeClamp, streamHistogram };
11
16
  /**
12
17
  * Any of the 107 named ramps shipped in `@developmentseed/deck.gl-raster`'s
13
18
  * `colormaps.png` sprite (matplotlib + rio-tiler + cmocean). Rendering is
@@ -54,6 +59,57 @@ export declare function inspectCogTags(geotiff: GeoTIFFType): CogTagInfo;
54
59
  * palette-indexed uint COGs where the embedded ColorMap tag auto-renders.
55
60
  */
56
61
  export declare function needsCustomPipelineForConfig(geotiff: GeoTIFFType, config: BandConfig): boolean;
62
+ /**
63
+ * User-controlled tri-state for nodata handling.
64
+ *
65
+ * - `auto` — use the value parsed from the GeoTIFF's GDAL_NODATA tag (caller
66
+ * resolves via `readGdalNodata(geotiff)`).
67
+ * - `value` — explicit user-provided sentinel.
68
+ * - `off` — disable nodata filtering entirely.
69
+ *
70
+ * Default is `{ mode: 'auto' }`. The shader-level value is resolved at the
71
+ * viewer level (Auto pulls from the geotiff, Value uses `value`, Off → null).
72
+ */
73
+ export type NodataMode = 'auto' | 'value' | 'off';
74
+ export interface NodataConfig {
75
+ mode: NodataMode;
76
+ value?: number;
77
+ }
78
+ export declare const DEFAULT_NODATA_CONFIG: NodataConfig;
79
+ /**
80
+ * Read the GDAL_NODATA tag from a GeoTIFF.
81
+ *
82
+ * GDAL convention: the tag is an ASCII string serialized via `Number()`; the
83
+ * literal `"nan"` (case-insensitive) round-trips to JS `NaN`. The library's
84
+ * `geotiff.nodata` getter already performs that `Number(rawString)` conversion,
85
+ * so this helper just exposes the resulting `number | null` (preserving `NaN`)
86
+ * behind a stable name for callers that want to drive `NodataConfig`.
87
+ */
88
+ export declare function readGdalNodata(geotiff: GeoTIFFType): number | null;
89
+ /**
90
+ * Custom shader module that discards pixels whose `color.r` is NaN. Float COGs
91
+ * commonly encode nodata as NaN, but the shipped `FilterNoDataVal` does a
92
+ * `color.r == nodata.value` comparison which IEEE 754 always returns false for
93
+ * NaN. Mirrors the reference implementation in `src/render/shader-modules.ts`.
94
+ *
95
+ * Slots into a `RasterModule[]` render pipeline the same way as the upstream
96
+ * modules (e.g. `LinearRescale`).
97
+ */
98
+ export declare const FilterNaN: RasterModule["module"];
99
+ /**
100
+ * Pick the correct nodata-discard module for a resolved nodata value.
101
+ *
102
+ * - `NaN` → `FilterNaN` (IEEE 754: `x == NaN` is always false).
103
+ * - finite number → `FilterNoDataVal { value: nodata / sampleScale }`.
104
+ * - `null` / non-finite (e.g. ±Infinity) → no module (nodata off).
105
+ *
106
+ * `sampleScale` divides the raw nodata value to put it in the same coordinate
107
+ * space the shader sees after hardware normalization (e.g. 255 for r8unorm,
108
+ * 65535 for r16unorm). Pass `1` when the shader receives raw float values.
109
+ */
110
+ export declare function nodataModule(nodata: number | null, sampleScale?: number): RasterModule | null;
111
+ /** Resolve a tri-state `NodataConfig` against the auto-detected GDAL_NODATA value. */
112
+ export declare function resolveNodata(cfg: NodataConfig, autoNodata: number | null): number | null;
57
113
  /**
58
114
  * Min/max rescale values applied via the `LinearRescale` shader module. Values
59
115
  * are in normalized shader space [0, 1]. Default `{ min: 0, max: 1 }` is a
@@ -66,6 +122,46 @@ export interface RescaleConfig {
66
122
  export declare const DEFAULT_RESCALE: RescaleConfig;
67
123
  /** True when the rescale values would produce a visible change on the GPU. */
68
124
  export declare function isRescaleActive(cfg: RescaleConfig): boolean;
125
+ /**
126
+ * Pick a sensible default `RescaleConfig` for a freshly opened COG. The slider
127
+ * operates in normalized shader space [0, 1], but the GPU's hardware
128
+ * normalization (`r8unorm` / `r16unorm` in `MultiCOGLayer`, or the library
129
+ * default uint pipeline elsewhere) collapses raw integer values onto that
130
+ * range by dividing by the format's max (255 for uint8, 65535 for uint16).
131
+ *
132
+ * For uint8 visual COGs (Sentinel-2 `visual` TCI, NAIP `image`) the natural
133
+ * land brightness sits around raw 50-100, so `max: 0.3` (≈ raw 76) gives a
134
+ * nicely contrasted preview. For uint16 reflectance bands (Sentinel-2 raw
135
+ * `nir` / `swir16` / `red`, Landsat C2 L2 `*_B*`) typical land surfaces sit at
136
+ * raw 800-3000 (reflectance × 10000), which is `0.012-0.046` after r16unorm.
137
+ * `max: 0.3` would render those near-black; `max: 0.05` (≈ raw 3277) keeps
138
+ * vegetation, soil, and water in the visible range while leaving headroom for
139
+ * brighter targets.
140
+ *
141
+ * Float / int sample formats fall back to the conservative `{0, 1}` no-op so
142
+ * the user can dial in their own range via the slider.
143
+ */
144
+ export declare function defaultRescaleForGeotiff(geotiff: GeoTIFFType): RescaleConfig;
145
+ /**
146
+ * Build a 64-bin histogram of band 0 from a GeoTIFF's smallest overview, in
147
+ * the same shader-space [0, 1] coordinate system the rescale slider operates
148
+ * on (raw / 65535 for uint16, raw / 255 for uint8, raw clamped to [0, 1] for
149
+ * float). Used by viewers on the multi-asset MultiCOGLayer path to give the
150
+ * rescale slider a histogram backdrop without hooking per-tile sampling into
151
+ * the layer.
152
+ *
153
+ * Returns null if the smallest overview cannot be fetched. Skips the GeoTIFF's
154
+ * declared nodata value and non-finite values.
155
+ */
156
+ /**
157
+ * Walk a cumulative histogram (`HISTOGRAM_BIN_COUNT` bins covering [0, 1])
158
+ * and return the shader-space value at percentile `p` (0..1). Returns null
159
+ * when the histogram is empty. Linearly interpolates within the matching bin
160
+ * so the result is monotonic across calls with adjacent percentiles, instead
161
+ * of jumping in `1/HISTOGRAM_BIN_COUNT` increments.
162
+ */
163
+ export declare function percentileFromHistogram(histogram: Uint32Array | null, p: number): number | null;
164
+ export declare function buildHistogramFromGeotiff(geotiff: GeoTIFFType, signal?: AbortSignal): Promise<Uint32Array | null>;
69
165
  /**
70
166
  * Build a `getTileData` + `renderTile` pair that reuses the library-default
71
167
  * uint pipeline (via `inferRenderPipeline`) and appends `LinearRescale` to the
@@ -78,19 +174,30 @@ export declare function isRescaleActive(cfg: RescaleConfig): boolean;
78
174
  * tile's `GetTileDataOptions`, so the pipeline is built lazily on first call.
79
175
  */
80
176
  export declare function createRescaledPipeline(geotiff: GeoTIFFType, rescale: RescaleConfig): {
81
- getTileData: (image: GeoTIFFType | Overview, options: GetTileDataOptions) => Promise<MinimalDataT>;
82
- renderTile: (data: MinimalDataT) => RenderTileResult;
177
+ getTileData: (image: GeoTIFFType | Overview, options: GetTileDataOptions) => Promise<MinimalTileData>;
178
+ renderTile: (data: MinimalTileData) => RenderTileResult;
83
179
  };
84
180
  export interface BandRenderPipelineOptions {
85
- /** Value treated as "no-data" and zeroed out by `FilterNoDataVal`. */
181
+ /**
182
+ * Resolved nodata value. `NaN` routes through `FilterNaN`, finite numbers
183
+ * through `FilterNoDataVal`, `null` / undefined / non-finite disables the
184
+ * nodata stage entirely.
185
+ */
86
186
  noDataVal?: number | null;
187
+ /**
188
+ * Hardware sample scale used to bring `noDataVal` into the shader's coord
189
+ * space. Defaults to 1 (raw float). Pass 255 for r8unorm, 65535 for r16unorm.
190
+ */
191
+ noDataSampleScale?: number;
87
192
  /** Linear rescale applied after no-data masking. Omit for no rescaling. */
88
193
  rescale?: RescaleConfig;
89
194
  }
90
195
  /**
91
196
  * Build a `renderPipeline` array for `MultiCOGLayer` / raster mosaics.
92
- * Combines optional `FilterNoDataVal` + `LinearRescale` stages in the order
93
- * the GPU expects (no-data mask first, then rescale).
197
+ * Combines an optional nodata-discard module + `LinearRescale` in the order
198
+ * the GPU expects (no-data mask first, then rescale). The nodata module is
199
+ * selected by `nodataModule()` so NaN sentinels route through `FilterNaN`
200
+ * instead of the always-false `==` comparison in `FilterNoDataVal`.
94
201
  */
95
202
  export declare function buildBandRenderPipeline(opts?: BandRenderPipelineOptions): RasterModule[];
96
203
  /**
@@ -110,7 +217,7 @@ export declare function normalizeCogGeotiff(geotiff: GeoTIFFType): void;
110
217
  * Spread into `new COGLayer({ ..., ...resolved })` to activate.
111
218
  *
112
219
  * COGLayer's data-prop types are a discriminated XOR and the four pipelines we
113
- * dispatch to return different DataT shapes (`CustomTileData`, `MinimalDataT`).
220
+ * dispatch to return different DataT shapes (`CustomTileData`, `MinimalTileData`).
114
221
  * Typing this as `Record<string, any>` matches the `customProps` pattern
115
222
  * already used at the COGLayer boundary and keeps the dispatch site simple.
116
223
  */
@@ -120,11 +227,6 @@ export interface SelectCogPipelineOptions {
120
227
  bandConfig?: BandConfig | null;
121
228
  /** Linear rescale GPU module values. No-op when omitted or at defaults. */
122
229
  rescale?: RescaleConfig;
123
- /**
124
- * Forwarded to the CPU bake factories in single-band mode; receives a
125
- * 64-bin histogram of normalized data after each tile for slider UI.
126
- */
127
- onHistogram?: (bins: Uint32Array) => void;
128
230
  }
129
231
  /**
130
232
  * Decide which getTileData/renderTile pair COGLayer should use for a GeoTIFF.
@@ -143,29 +245,6 @@ export interface SelectCogPipelineOptions {
143
245
  * viewers can call it per sub-COG without re-implementing the decision tree.
144
246
  */
145
247
  export declare function selectCogPipeline(geotiff: GeoTIFFType, opts?: SelectCogPipelineOptions): ResolvedCogPipeline;
146
- export interface GeoBounds {
147
- west: number;
148
- south: number;
149
- east: number;
150
- north: number;
151
- }
152
- export interface CogInfo {
153
- width: number;
154
- height: number;
155
- bandCount: number;
156
- dataType: string;
157
- bounds: GeoBounds;
158
- downsampled?: boolean;
159
- }
160
- /** Safely clamp a number to a range, treating NaN/Infinity as the fallback. */
161
- export declare function safeClamp(v: number, lo: number, hi: number, fallback: number): number;
162
- /** Clamp geographic bounds to valid MapLibre web-Mercator range. */
163
- export declare function clampBounds(b: GeoBounds): GeoBounds;
164
- /**
165
- * Build a data-type label from GeoTIFF sample format and bits per sample.
166
- * e.g. "uint8", "float32", "int16"
167
- */
168
- export declare function buildDataTypeLabel(sampleFormat: number, bitsPerSample: number): string;
169
248
  /**
170
249
  * Query the GPU's MAX_TEXTURE_SIZE from MapLibre's WebGL context.
171
250
  * Falls back to 4096 (lowest common denominator for mobile GPUs).
@@ -215,6 +294,16 @@ export interface CustomTileData {
215
294
  * lookup. `undefined` for RGB tiles.
216
295
  */
217
296
  nodataSentinel?: number;
297
+ /**
298
+ * Per-tile 64-bin normalized histogram (0..1, nodata excluded) baked during
299
+ * single-band CPU decoding. `undefined` for RGB tiles. deck.gl's TileLayer
300
+ * caches the returned tile object, so this array is retained alongside the
301
+ * bitmap without a rebake on pan/zoom revisits. Summing the histograms of
302
+ * currently-visible tiles, via the TileLayer `onViewportLoad` hook, gives a
303
+ * cloud-native "histogram of what COG tiles the viewport currently shows at
304
+ * the active overview level", matching COG pyramid behavior.
305
+ */
306
+ histogram?: Uint32Array;
218
307
  }
219
308
  type Texture = import('@luma.gl/core').Texture;
220
309
  /**
@@ -223,18 +312,27 @@ type Texture = import('@luma.gl/core').Texture;
223
312
  * Signed int (2) and float (3) need custom getTileData/renderTile.
224
313
  */
225
314
  export declare function needsCustomPipeline(geotiff: GeoTIFFType): boolean;
226
- /** Shared options for the CPU tile-baking factories. */
227
- export interface CustomGetTileDataOptions {
228
- /**
229
- * Called after each baked tile with a 64-bin histogram of normalized
230
- * single-band values (0..1, nodata excluded). Bins accumulate across
231
- * tiles; receivers should treat the array as monotonically growing and
232
- * debounce UI updates. Never invoked in RGB mode.
233
- */
234
- onHistogram?: (bins: Uint32Array) => void;
235
- }
236
- /** Number of histogram buckets produced by the CPU bake. */
237
- export declare const HISTOGRAM_BIN_COUNT = 64;
315
+ /**
316
+ * Shared options for the CPU tile-baking factories.
317
+ *
318
+ * The previous `onHistogram` callback accumulated a single closure-owned buffer
319
+ * across every tile ever baked, which grew unbounded on pan/zoom and never
320
+ * reflected "what the viewport currently shows". Histograms are now attached
321
+ * per tile to `CustomTileData.histogram` and aggregated by the viewer from
322
+ * TileLayer's `onViewportLoad(visibleTiles)` hook, matching COG overview-level
323
+ * behavior (few big tiles when zoomed out, small AOI-scoped tiles when zoomed
324
+ * in) and reusing deck.gl's tile cache for free.
325
+ */
326
+ export type CustomGetTileDataOptions = Record<string, never>;
327
+ /**
328
+ * Number of histogram buckets produced by the CPU bake.
329
+ *
330
+ * Canonical value lives in `./cog-histogram.ts` as `HISTOGRAM_BINS`; this
331
+ * is kept as an alias so existing CogViewer / StacMosaicViewer imports
332
+ * continue to compile. Both names resolve to the same number — see
333
+ * `./cog-histogram.ts` for the streaming histogram + GDAL stats reader.
334
+ */
335
+ export declare const HISTOGRAM_BIN_COUNT: number;
238
336
  /**
239
337
  * Create custom getTileData for non-uint COGs.
240
338
  * Reads band 0, normalizes using GDAL statistics / per-tile adaptive stretch,
@@ -243,7 +341,7 @@ export declare const HISTOGRAM_BIN_COUNT = 64;
243
341
  * `colormaps.png`. Reserves `r = 0` for nodata so `FilterNoDataVal` can
244
342
  * discard those fragments before the ramp sample.
245
343
  */
246
- export declare function createCustomGetTileData(geotiff: GeoTIFFType, opts?: CustomGetTileDataOptions): (image: GeoTIFFType | Overview, options: {
344
+ export declare function createCustomGetTileData(geotiff: GeoTIFFType, _opts?: CustomGetTileDataOptions): (image: GeoTIFFType | Overview, options: {
247
345
  x: number;
248
346
  y: number;
249
347
  pool: unknown;
@@ -263,19 +361,33 @@ export declare function createCustomGetTileData(geotiff: GeoTIFFType, opts?: Cus
263
361
  * fall back to the plain grayscale image.
264
362
  */
265
363
  export declare function buildCustomRenderTile(config: BandConfig, rescale?: RescaleConfig): (data: CustomTileData) => RenderTileResult;
364
+ /**
365
+ * Stable getTileData factory tied to a GeoTIFF identity. Returns a wrapper with
366
+ * a frozen `getTileData` reference and an `updateConfig` mutator. Identity must
367
+ * stay stable so deck.gl's TileLayer cache (keyed in part by function identity)
368
+ * is preserved across band/ramp swaps.
369
+ */
370
+ export interface ConfigurableTileLoader {
371
+ getTileData: (image: GeoTIFFType | Overview, options: {
372
+ x: number;
373
+ y: number;
374
+ pool: unknown;
375
+ signal?: AbortSignal;
376
+ device: Device;
377
+ }) => Promise<CustomTileData>;
378
+ updateConfig: (next: BandConfig) => void;
379
+ }
266
380
  /**
267
381
  * Create a configurable getTileData that respects BandConfig.
268
382
  * Supports RGB mode (multi-band → R,G,B with alpha=255, fully baked) and
269
383
  * single-band mode (band N normalized into the `r` channel; the ramp is
270
384
  * applied downstream by the GPU `Colormap` module via `buildCustomRenderTile`).
385
+ *
386
+ * The returned `getTileData` reference is stable across `updateConfig` calls.
387
+ * deck.gl's TileLayer treats a changed `getTileData` identity as a cache
388
+ * invalidation, so reusing this loader across band/ramp swaps preserves tiles.
271
389
  */
272
- export declare function createConfigurableGetTileData(geotiff: GeoTIFFType, config: BandConfig, opts?: CustomGetTileDataOptions): (image: GeoTIFFType | Overview, options: {
273
- x: number;
274
- y: number;
275
- pool: unknown;
276
- signal?: AbortSignal;
277
- device: Device;
278
- }) => Promise<CustomTileData>;
390
+ export declare function createConfigurableGetTileData(geotiff: GeoTIFFType, config: BandConfig, _opts?: CustomGetTileDataOptions): ConfigurableTileLoader;
279
391
  export interface PixelValue {
280
392
  lng: number;
281
393
  lat: number;
@@ -298,9 +410,37 @@ export declare function createEpsgResolver(): EpsgResolver;
298
410
  * code is not present in the database.
299
411
  */
300
412
  export declare function resolveProj4Def(crs: number | unknown, _signal: AbortSignal): Promise<string | null>;
413
+ /**
414
+ * Standard Web Mercator ground resolution (meters per screen pixel) at a given
415
+ * zoom and latitude. Equivalent to MapLibre's `metersPerPixel`. Use this to
416
+ * pick a COG overview level that matches what's painted on screen.
417
+ */
418
+ export declare function mapResolutionMetersPerPixel(zoom: number, latitude: number): number;
419
+ /**
420
+ * Pick the coarsest overview whose pixel size is ≤ `targetMetersPerPixel`,
421
+ * matching lazycogs' `_select_overview`. Walks `geotiff.overviews` in
422
+ * finest → coarsest order (the documented sort) and returns the last entry
423
+ * that still satisfies the constraint. Returns `null` to mean "use full
424
+ * resolution" (either the COG has no overviews, the target is already finer
425
+ * than native, or every overview is coarser than the target — never
426
+ * upsample).
427
+ *
428
+ * The COG's affine `a` component is the X-pixel-size in the COG's native CRS
429
+ * units. For Web Mercator and other meter-based CRSes this is meters/pixel
430
+ * and lines up directly with `mapResolutionMetersPerPixel`. For degree-based
431
+ * CRSes (EPSG:4326) the comparison is against degrees/pixel, so callers
432
+ * should derive the target in the same units.
433
+ */
434
+ export declare function selectOverviewForResolution(geotiff: GeoTIFFType, targetMetersPerPixel: number): Overview | null;
301
435
  /**
302
436
  * Read pixel values at a given lng/lat from a GeoTIFF.
303
437
  * Converts WGS84 → source CRS → pixel coords, fetches the tile, reads all bands.
438
+ *
439
+ * If `options.overview` is supplied, the read happens against that overview
440
+ * level instead of the full-resolution image (so the inspected value matches
441
+ * the overview deck.gl is currently painting on screen). Pass `null` /
442
+ * `undefined` to keep the legacy full-resolution behaviour.
304
443
  */
305
- export declare function readPixelAtLngLat(geotiff: GeoTIFFType, lng: number, lat: number, proj4Def: string | null, pool: any, signal?: AbortSignal): Promise<PixelValue | null>;
306
- export {};
444
+ export declare function readPixelAtLngLat(geotiff: GeoTIFFType, lng: number, lat: number, proj4Def: string | null, pool: any, signal?: AbortSignal, options?: {
445
+ overview?: Overview | null;
446
+ }): Promise<PixelValue | null>;