@walkthru-earth/objex 1.3.1 → 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 (184) 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 +263 -112
  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 +1 -1
  44. package/dist/components/viewers/StacMosaicViewer.svelte +1760 -408
  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 +177 -20
  104. package/dist/utils/cog.js +361 -76
  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/cog-pure.d.ts +0 -25
  144. package/dist/utils/cog-pure.js +0 -35
  145. package/dist/utils/column-types.d.ts +0 -5
  146. package/dist/utils/column-types.js +0 -137
  147. package/dist/utils/connection-identity.d.ts +0 -51
  148. package/dist/utils/connection-identity.js +0 -97
  149. package/dist/utils/error.d.ts +0 -8
  150. package/dist/utils/error.js +0 -12
  151. package/dist/utils/evidence-context.d.ts +0 -22
  152. package/dist/utils/evidence-context.js +0 -56
  153. package/dist/utils/export.d.ts +0 -22
  154. package/dist/utils/export.js +0 -76
  155. package/dist/utils/file-sort.d.ts +0 -20
  156. package/dist/utils/file-sort.js +0 -41
  157. package/dist/utils/format.d.ts +0 -24
  158. package/dist/utils/format.js +0 -78
  159. package/dist/utils/geoarrow.d.ts +0 -32
  160. package/dist/utils/geoarrow.js +0 -672
  161. package/dist/utils/geometry-type.d.ts +0 -52
  162. package/dist/utils/geometry-type.js +0 -76
  163. package/dist/utils/hex.d.ts +0 -10
  164. package/dist/utils/hex.js +0 -27
  165. package/dist/utils/host-detection.d.ts +0 -23
  166. package/dist/utils/host-detection.js +0 -95
  167. package/dist/utils/local-storage.d.ts +0 -16
  168. package/dist/utils/local-storage.js +0 -37
  169. package/dist/utils/markdown-sql.d.ts +0 -30
  170. package/dist/utils/markdown-sql.js +0 -72
  171. package/dist/utils/notebook.d.ts +0 -59
  172. package/dist/utils/notebook.js +0 -211
  173. package/dist/utils/parquet-metadata.d.ts +0 -64
  174. package/dist/utils/parquet-metadata.js +0 -262
  175. package/dist/utils/stac-geoparquet.d.ts +0 -90
  176. package/dist/utils/stac-geoparquet.js +0 -223
  177. package/dist/utils/stac-hydrate.d.ts +0 -38
  178. package/dist/utils/stac-hydrate.js +0 -243
  179. package/dist/utils/stac.d.ts +0 -136
  180. package/dist/utils/stac.js +0 -176
  181. package/dist/utils/storage-url.d.ts +0 -90
  182. package/dist/utils/storage-url.js +0 -568
  183. package/dist/utils/wkb.d.ts +0 -43
  184. 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';
8
- import { buildDataTypeLabel, type CogInfo, clampBounds, type GeoBounds, SF_LABELS, safeClamp } from './cog-pure.js';
9
+ import { type GdalBandStats, type GdalImageStats, HISTOGRAM_BINS, type HistogramSnapshot, readGdalStats, type StreamHistogramOptions, streamHistogram } from './cog-histogram.js';
9
10
  import { type ColormapName } from './colormap-sprite.js';
10
- export { buildDataTypeLabel, type CogInfo, clampBounds, type GeoBounds, SF_LABELS, safeClamp };
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
  */
@@ -217,8 +324,15 @@ export declare function needsCustomPipeline(geotiff: GeoTIFFType): boolean;
217
324
  * in) and reusing deck.gl's tile cache for free.
218
325
  */
219
326
  export type CustomGetTileDataOptions = Record<string, never>;
220
- /** Number of histogram buckets produced by the CPU bake. */
221
- export declare const HISTOGRAM_BIN_COUNT = 64;
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;
222
336
  /**
223
337
  * Create custom getTileData for non-uint COGs.
224
338
  * Reads band 0, normalizes using GDAL statistics / per-tile adaptive stretch,
@@ -247,19 +361,33 @@ export declare function createCustomGetTileData(geotiff: GeoTIFFType, _opts?: Cu
247
361
  * fall back to the plain grayscale image.
248
362
  */
249
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
+ }
250
380
  /**
251
381
  * Create a configurable getTileData that respects BandConfig.
252
382
  * Supports RGB mode (multi-band → R,G,B with alpha=255, fully baked) and
253
383
  * single-band mode (band N normalized into the `r` channel; the ramp is
254
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.
255
389
  */
256
- export declare function createConfigurableGetTileData(geotiff: GeoTIFFType, config: BandConfig, _opts?: CustomGetTileDataOptions): (image: GeoTIFFType | Overview, options: {
257
- x: number;
258
- y: number;
259
- pool: unknown;
260
- signal?: AbortSignal;
261
- device: Device;
262
- }) => Promise<CustomTileData>;
390
+ export declare function createConfigurableGetTileData(geotiff: GeoTIFFType, config: BandConfig, _opts?: CustomGetTileDataOptions): ConfigurableTileLoader;
263
391
  export interface PixelValue {
264
392
  lng: number;
265
393
  lat: number;
@@ -282,8 +410,37 @@ export declare function createEpsgResolver(): EpsgResolver;
282
410
  * code is not present in the database.
283
411
  */
284
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;
285
435
  /**
286
436
  * Read pixel values at a given lng/lat from a GeoTIFF.
287
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.
288
443
  */
289
- export declare function readPixelAtLngLat(geotiff: GeoTIFFType, lng: number, lat: number, proj4Def: string | null, pool: any, signal?: AbortSignal): Promise<PixelValue | null>;
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>;