@fxi/zartigl 0.5.0 → 0.7.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.
@@ -0,0 +1,918 @@
1
+ /** Throws unless the index was written for this catalog entry and source. */
2
+ export declare function assertGeoVideoIndexIdentity(source: CatalogGeoVideoArchiveSource, index: GeoVideoIndex, entry: CatalogEntry): void;
3
+
4
+ /** Particle backdrop off: see BackdropStyle. */
5
+ export declare const BACKDROP_OFF: Readonly<BackdropStyle>;
6
+
7
+ /**
8
+ * Solid color under the particle trails, drawn on valid data cells only: it
9
+ * keeps particles readable over a light basemap. Off by default; an object
10
+ * without `enabled` is on.
11
+ */
12
+ declare interface BackdropStyle {
13
+ enabled: boolean;
14
+ /** Hex color, `#rgb` or `#rrggbb`. */
15
+ color: string;
16
+ opacity: number;
17
+ }
18
+
19
+ /**
20
+ * `u_solid` uniform: straight RGB in [0, 1] and opacity. Alpha is 0 when the
21
+ * backdrop is off, which also skips the draw.
22
+ */
23
+ export declare function backdropVec4(backdrop: BackdropStyle): [number, number, number, number];
24
+
25
+ declare interface CatalogEntry {
26
+ id: string;
27
+ aliases?: string[];
28
+ title: LocalizedText;
29
+ description?: LocalizedText;
30
+ category: string;
31
+ tags?: string[];
32
+ kind: "scalar" | "vector";
33
+ sources: CatalogSource[];
34
+ /** Default source, plus the layer's base style. */
35
+ defaults: LayerStyleInput & {
36
+ sourceId: string;
37
+ querySourceId?: string;
38
+ };
39
+ }
40
+
41
+ /**
42
+ * An incremental archive of calendar-aligned artifacts listed by a mutable
43
+ * index; zartigl resolves it to the chunk covering the requested time.
44
+ */
45
+ declare interface CatalogGeoVideoArchiveSource extends CatalogSourceBase {
46
+ type: "geovideo";
47
+ indexUrl: string;
48
+ manifestUrl?: never;
49
+ }
50
+
51
+ /** One published artifact. */
52
+ declare interface CatalogGeoVideoSource extends CatalogSourceBase {
53
+ type: "geovideo";
54
+ manifestUrl: string;
55
+ indexUrl?: never;
56
+ }
57
+
58
+ declare type CatalogSource = CatalogZarrSource | CatalogWmtsSource | CatalogGeoVideoSource | CatalogGeoVideoArchiveSource;
59
+
60
+ declare interface CatalogSourceBase {
61
+ id: string;
62
+ title: LocalizedText;
63
+ provenance?: CatalogSourceProvenance;
64
+ temporal?: CatalogTemporalSummary;
65
+ }
66
+
67
+ declare interface CatalogSourceProvenance {
68
+ provider: string;
69
+ identifiers?: Record<string, string>;
70
+ }
71
+
72
+ declare interface CatalogTemporalSummary {
73
+ cadence?: string;
74
+ mode: "historical" | "near-real-time" | "analysis-forecast" | "fixed";
75
+ start?: string;
76
+ end?: string;
77
+ }
78
+
79
+ declare type CatalogVariables = {
80
+ kind: "scalar";
81
+ value: string;
82
+ } | {
83
+ kind: "vector";
84
+ u?: string;
85
+ v?: string;
86
+ derivation?: CatalogVectorDerivation;
87
+ };
88
+
89
+ declare interface CatalogVectorDerivation {
90
+ kind: "direction_magnitude";
91
+ direction_variable: string;
92
+ magnitude_variable: string;
93
+ direction_convention: "from" | "toward";
94
+ output_direction: "from" | "toward";
95
+ }
96
+
97
+ declare interface CatalogWmtsSource extends CatalogSourceBase {
98
+ type: "wmts";
99
+ capabilitiesUrl: string;
100
+ baseUrl?: string;
101
+ layer: string;
102
+ tileMatrixSet?: string;
103
+ format?: string;
104
+ style?: string;
105
+ tileUrlTemplate?: string;
106
+ }
107
+
108
+ declare interface CatalogZarrSource extends CatalogSourceBase {
109
+ type: "zarr";
110
+ endpoints: {
111
+ field: string;
112
+ pointSeries?: string;
113
+ };
114
+ variables: CatalogVariables;
115
+ }
116
+
117
+ /**
118
+ * `vec3 gradeColor(vec3 c, vec4 g)` of `colorGradeVec4`; GLSL ES 1.0 and
119
+ * 3.0. It contains VIBRANCE_GLSL: include one or the other, never both.
120
+ */
121
+ export declare const COLOR_GRADE_GLSL: string;
122
+
123
+ export declare const COLOR_GRADE_OFF: Readonly<ColorGrade>;
124
+
125
+ export declare const COLOR_GRADE_VIBRANT: Readonly<ColorGrade>;
126
+
127
+ /**
128
+ * Optional color grade applied when particle trails are composited
129
+ * (`shaders/color-grade.glsl`): more intense highlights, deeper shadows and
130
+ * richer colors, without hard clipping. Off by default; when off, the
131
+ * composite returns the trail colors unchanged.
132
+ */
133
+ export declare interface ColorGrade {
134
+ enabled: boolean;
135
+ /** Mid-tone lift [0, 4]; 0 keeps the tones. */
136
+ exposure: number;
137
+ /** S-curve strength [0, 1]. */
138
+ contrast: number;
139
+ /** Vibrance-weighted saturation [-1, 1]. */
140
+ saturation: number;
141
+ /** Push of the bright half toward white [0, 1]. */
142
+ highlights: number;
143
+ }
144
+
145
+ /** Style `particles.grade` of a color grade: a preset when it is one. */
146
+ export declare function colorGradeToGrade(input: Partial<ColorGrade>): ParticleGrade;
147
+
148
+ /** `u_grade` uniform: (exposure, contrast, saturation, highlights). */
149
+ export declare function colorGradeVec4(grade: ColorGrade): [number, number, number, number];
150
+
151
+ export declare type ColorRampInput = string | string[] | Record<number, string>;
152
+
153
+ declare interface CoordArrays {
154
+ time: Float64Array | Float32Array;
155
+ vertical: Float32Array;
156
+ latitude: Float32Array;
157
+ longitude: Float32Array;
158
+ }
159
+
160
+ export declare function createColorRampTexture(gl: WebGL2RenderingContext, ramp?: ColorRampInput): WebGLTexture;
161
+
162
+ /** The frame source decoding `manifest`: scalar or vector by its encoding. */
163
+ export declare function createGeoVideoFrameSource(manifest: GeoVideoManifest, options?: {
164
+ cacheSize?: number;
165
+ }): GeoVideoScalarSource | GeoVideoVectorSource;
166
+
167
+ export declare function createProgram(gl: WebGL2RenderingContext, vertSource: string, fragSource: string): WebGLProgram;
168
+
169
+ export declare function createShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader;
170
+
171
+ /** Trail length in frames for a 0–1 `fade`. */
172
+ export declare function fadeToFrames(fade: number): number;
173
+
174
+ /** Per-frame trail opacity multiplier for a 0–1 `fade`. */
175
+ export declare function fadeToOpacity(fade: number): number;
176
+
177
+ /**
178
+ * One immutable chunk of a GeoVideo archive, independent of the catalog: a
179
+ * manifest and the range of its encoded samples.
180
+ */
181
+ export declare interface GeoVideoArchiveChunk extends GeoVideoChunkSpan {
182
+ /** Stable identity of the chunk content (the index chunk key). */
183
+ key: string;
184
+ /** Absolute manifest URL. */
185
+ manifestUrl: string;
186
+ /** Encoded samples, when the index lists them. */
187
+ samples?: number;
188
+ provisional?: boolean;
189
+ }
190
+
191
+ /** One decoded time step of an archive. */
192
+ export declare interface GeoVideoArchiveFrame<TFrame = GeoVideoFrameData> {
193
+ /** Stable identity: archive id, chunk key and step. */
194
+ key: string;
195
+ chunk: GeoVideoArchiveChunk;
196
+ /** Step within the chunk. */
197
+ step: number;
198
+ time: number;
199
+ data: TFrame;
200
+ grid: GeoVideoGrid;
201
+ manifest: GeoVideoManifest;
202
+ }
203
+
204
+ /**
205
+ * The frames bracketing a time, possibly from two chunks: display
206
+ * a·(1 − mix) + b·mix. `b` is `a` with mix 0 in discrete mode or on a step.
207
+ */
208
+ export declare interface GeoVideoArchiveSample<TFrame = GeoVideoFrameData> {
209
+ time: number;
210
+ a: GeoVideoArchiveFrame<TFrame>;
211
+ b: GeoVideoArchiveFrame<TFrame>;
212
+ mix: number;
213
+ }
214
+
215
+ /**
216
+ * Several chunks of a GeoVideo archive as one continuous timeline. Every
217
+ * sample request is independent: aborting one leaves the decodes another
218
+ * request needs. Manifests are cached; chunk sources are kept open in a
219
+ * bounded LRU and released when evicted. The archive answers instants; it
220
+ * neither drives a clock nor picks other archives (see pairChunkSpan).
221
+ */
222
+ export declare class GeoVideoArchiveSource<TFrame = GeoVideoFrameData> {
223
+ readonly id: string;
224
+ /** Chunks sorted by start, without empty ranges. */
225
+ readonly chunks: readonly GeoVideoArchiveChunk[];
226
+ private readonly maxOpenChunks;
227
+ private readonly frameCacheSize;
228
+ private readonly prefetchAt;
229
+ private readonly maxGap;
230
+ private readonly loadManifest;
231
+ private readonly createFrameSource;
232
+ private readonly manifests;
233
+ private readonly open;
234
+ constructor(options: GeoVideoArchiveSourceOptions<TFrame>);
235
+ /** First and last sample of the archive, or null without chunks. */
236
+ get range(): [number, number] | null;
237
+ /** The chunk whose sample range holds `time`, or null. */
238
+ chunkAt(time: number): GeoVideoArchiveChunk | null;
239
+ /** Every step time of the archive; loads all chunk manifests. */
240
+ steps(request?: GeoVideoFrameRequest): Promise<Float64Array>;
241
+ /**
242
+ * The frames bracketing `time`, decoded; null out of coverage (before the
243
+ * first step, after the last, or in a gap wider than `maxGap`).
244
+ */
245
+ sample(time: number, request?: GeoVideoFrameRequest & {
246
+ mode?: GeoVideoSampleMode;
247
+ }): Promise<GeoVideoArchiveSample<TFrame> | null>;
248
+ /** Open `chunk` and decode its first frame ahead of a request. */
249
+ prefetch(chunk: GeoVideoArchiveChunk): void;
250
+ /** Release every open chunk source; later requests reopen them. */
251
+ release(): void;
252
+ private chunkIndexAt;
253
+ private gapLimit;
254
+ private prefetchAfter;
255
+ private manifest;
256
+ /** The open chunk, pinned for a running sample listed in `used`. */
257
+ private acquire;
258
+ /** The open chunk, opened when needed, most recently used; not pinned. */
259
+ private touch;
260
+ private frame;
261
+ /** Release least recently used chunks beyond the bound, unless in use. */
262
+ private trim;
263
+ private close;
264
+ }
265
+
266
+ export declare interface GeoVideoArchiveSourceOptions<TFrame> {
267
+ /** Archive identity, the prefix of every frame key. */
268
+ id: string;
269
+ chunks: readonly GeoVideoArchiveChunk[];
270
+ /** Chunk sources kept open (decoder, video element); at least 2. */
271
+ maxOpenChunks?: number;
272
+ /** Decoded frames cached per chunk source. */
273
+ frameCacheSize?: number;
274
+ /**
275
+ * Progress through a chunk past which the next chunk is opened and its
276
+ * first frame decoded; above 1 disables prefetching.
277
+ */
278
+ prefetchAt?: number;
279
+ /**
280
+ * Longest gap bridged between the last step of a chunk and the first of
281
+ * the next one, in ms. By default 1.5 times the largest step interval at
282
+ * that boundary, and no bridge when both neighbouring chunks hold a
283
+ * single step (no cadence known). Unbridged gaps are out of coverage.
284
+ */
285
+ maxGap?: number;
286
+ loadManifest?: (url: string) => Promise<GeoVideoManifest>;
287
+ createFrameSource?: (manifest: GeoVideoManifest, options: {
288
+ cacheSize: number;
289
+ }) => GeoVideoFrameReader<TFrame>;
290
+ }
291
+
292
+ export declare type GeoVideoBounds = [
293
+ west: number,
294
+ south: number,
295
+ east: number,
296
+ north: number
297
+ ];
298
+
299
+ /**
300
+ * Fixed-period GeoVideo sources, one per chunk. They keep the archive source
301
+ * id, which the chunk manifests carry as their identity.
302
+ */
303
+ export declare function geoVideoChunkSources(source: CatalogGeoVideoArchiveSource, index: GeoVideoIndex, entry: CatalogEntry): CatalogGeoVideoSource[];
304
+
305
+ /** First and last encoded sample of a chunk, UTC milliseconds. */
306
+ export declare interface GeoVideoChunkSpan {
307
+ start: number;
308
+ end: number;
309
+ }
310
+
311
+ /** Scalar values (NaN invalid) or u/v components (NaN invalid). */
312
+ export declare type GeoVideoFrameData = Float32Array | GeoVideoVectorFrame;
313
+
314
+ /** The part of a frame source an archive reads. */
315
+ export declare interface GeoVideoFrameReader<TFrame> {
316
+ frame(index: number, request?: GeoVideoFrameRequest): Promise<TFrame>;
317
+ release(): void;
318
+ }
319
+
320
+ /** Options of one frame request. */
321
+ export declare interface GeoVideoFrameRequest {
322
+ /** Abandons this request only; the decode stops once no request needs it. */
323
+ signal?: AbortSignal;
324
+ }
325
+
326
+ /**
327
+ * GeoVideo frames read one time step at a time (seek, no playback): video
328
+ * and static mask loading, luma readback, a serial decode queue, and a small
329
+ * LRU cache of decoded frames. Requests for the same step share one decode;
330
+ * each can be abandoned with its own signal, and the decode is dropped once
331
+ * no request waits for it. cancelAll() aborts every pending decode.
332
+ * Subclasses turn the luma codes of a frame into values.
333
+ */
334
+ export declare abstract class GeoVideoFrameSource<TFrame> {
335
+ /** Grid size; the video stacks `planes` grids vertically. */
336
+ readonly width: number;
337
+ readonly height: number;
338
+ protected readonly manifest: GeoVideoManifest;
339
+ protected readonly times: Float64Array;
340
+ private readonly planes;
341
+ private readonly cacheSize;
342
+ private readonly reader;
343
+ private video;
344
+ private mask;
345
+ private initPromise;
346
+ private presented;
347
+ private primed;
348
+ /** Serializes seeks: the previous decode, settled or not, runs first. */
349
+ private queue;
350
+ /** LRU of decoded and pending steps. */
351
+ private readonly frames;
352
+ /** Pending decodes, including those the LRU already evicted. */
353
+ private readonly pending;
354
+ constructor(manifest: GeoVideoManifest, planes: number, options?: {
355
+ cacheSize?: number;
356
+ });
357
+ /** Codes of the stacked planes and the per-cell mask to frame values. */
358
+ protected abstract decodeCodes(codes: Uint8Array, mask: Uint8Array, threshold: number): TFrame;
359
+ init(): Promise<void>;
360
+ /** Abort every pending frame decode; frames already decoded stay cached. */
361
+ cancelAll(): void;
362
+ /** Release the video element and GL context; a later init() reloads them. */
363
+ release(): void;
364
+ /**
365
+ * One decode per time step, cached and shared by concurrent requests.
366
+ * Aborting `request.signal` rejects this request with an AbortError; the
367
+ * decode goes on while another request waits for it.
368
+ */
369
+ frame(index: number, request?: GeoVideoFrameRequest): Promise<TFrame>;
370
+ private enqueue;
371
+ /** A request left; drop the decode when it was the last one waiting. */
372
+ private leave;
373
+ private drop;
374
+ private load;
375
+ private loadMask;
376
+ private loadVideo;
377
+ /** Seek to a frame and wait until it is presented. */
378
+ private presentFrame;
379
+ /**
380
+ * Some mobile browsers expose no decoded pixels to WebGL until playback
381
+ * started once. A muted play/pause primes the decoder, only when needed:
382
+ * playback would otherwise buffer far beyond the requested frame.
383
+ */
384
+ private primeDecoder;
385
+ /**
386
+ * Seek, read back and decode one step. `signal` aborts it between steps;
387
+ * a seek already started completes first, keeping the queue serial.
388
+ */
389
+ protected decode(index: number, signal: AbortSignal): Promise<TFrame>;
390
+ }
391
+
392
+ /**
393
+ * Grid of decoded frame values. `bounds` are the outer cell edges
394
+ * [west, south, east, north] in degrees, so cell (column i, row j) is
395
+ * centered at west + (i + 0.5)·dx, north − (j + 0.5)·dy with
396
+ * dx = (east − west) / width and dy = (north − south) / height; an east
397
+ * below west crosses the antimeridian (east + 360). Row 0 is the northern
398
+ * row, values are row-major.
399
+ */
400
+ export declare interface GeoVideoGrid {
401
+ width: number;
402
+ height: number;
403
+ bounds: GeoVideoBounds;
404
+ rowOrder: "north-to-south";
405
+ }
406
+
407
+ export declare function geoVideoGrid(manifest: GeoVideoManifest): GeoVideoGrid;
408
+
409
+ /** Mutable listing of an archive's published chunks, written by the renderer. */
410
+ export declare interface GeoVideoIndex {
411
+ schemaVersion: 1;
412
+ type: "geovideo-index";
413
+ catalogEntryId: string;
414
+ sourceId: string;
415
+ updatedAt: string | null;
416
+ chunks: GeoVideoIndexChunk[];
417
+ }
418
+
419
+ /** One immutable, calendar-aligned artifact of a GeoVideo archive. */
420
+ export declare interface GeoVideoIndexChunk {
421
+ period: {
422
+ start: string;
423
+ end: string;
424
+ };
425
+ /** First and last encoded sample. */
426
+ start: string;
427
+ end: string;
428
+ samples: number;
429
+ key: string;
430
+ /** Relative to the index URL. */
431
+ manifestUrl: string;
432
+ provisional?: boolean;
433
+ }
434
+
435
+ /**
436
+ * Catalog-free chunk descriptors of an index, manifest URLs resolved
437
+ * against the index URL, in index order.
438
+ */
439
+ export declare function geoVideoIndexChunks(index: GeoVideoIndex, indexUrl: string): GeoVideoArchiveChunk[];
440
+
441
+ export declare interface GeoVideoManifest {
442
+ schemaVersion: 3;
443
+ id: string;
444
+ type: "geovideo";
445
+ projection: "equirectangular";
446
+ bounds: GeoVideoBounds;
447
+ media: {
448
+ url: string;
449
+ mimeType: "video/mp4" | string;
450
+ width: number;
451
+ height: number;
452
+ fps: number;
453
+ durationSeconds: number;
454
+ codec: "h264" | string;
455
+ };
456
+ encoding: GeoVideoScalarEncoding | GeoVideoVectorEncoding;
457
+ mask: {
458
+ kind: "static-validity";
459
+ url: string;
460
+ mimeType: "image/png" | string;
461
+ width: number;
462
+ height: number;
463
+ threshold: number;
464
+ };
465
+ timeline: GeoVideoRangeTimeline | GeoVideoSnapshotLoopTimeline | GeoVideoSampleSequenceTimeline;
466
+ provenance: {
467
+ catalogEntryId: string;
468
+ inputSourceId: string;
469
+ provider?: string;
470
+ identifiers?: Record<string, string>;
471
+ variables: string[];
472
+ generatedAt: string;
473
+ };
474
+ style: {
475
+ palette: string;
476
+ colorDomain: [number, number];
477
+ unit?: string;
478
+ logScale?: boolean;
479
+ vibrance?: number;
480
+ };
481
+ }
482
+
483
+ declare interface GeoVideoRangeTimeline {
484
+ kind: "range";
485
+ dateStart: string;
486
+ dateEnd: string;
487
+ interpolation: "linear" | "nearest";
488
+ }
489
+
490
+ /** Interpolate between bracketing steps, or hold the last step at or before. */
491
+ export declare type GeoVideoSampleMode = "interpolate" | "discrete";
492
+
493
+ declare interface GeoVideoSampleSequenceTimeline {
494
+ kind: "sample-sequence";
495
+ values: string[];
496
+ }
497
+
498
+ export declare interface GeoVideoScalarEncoding {
499
+ kind: "scalar-luma";
500
+ bits: 8;
501
+ codeMin: number;
502
+ codeMax: number;
503
+ valueMin: number;
504
+ valueMax: number;
505
+ transfer: "linear";
506
+ colorSpace: "bt709";
507
+ colorRange: "limited" | "full";
508
+ }
509
+
510
+ /**
511
+ * Scalar-luma GeoVideo read frame by frame (seek, no playback), for values
512
+ * sampled on the GPU rather than the styled playback of GeoVideoLayer.
513
+ */
514
+ export declare class GeoVideoScalarSource extends GeoVideoFrameSource<Float32Array> {
515
+ private readonly encoding;
516
+ constructor(manifest: GeoVideoManifest, options?: {
517
+ cacheSize?: number;
518
+ });
519
+ protected decodeCodes(codes: Uint8Array, mask: Uint8Array, threshold: number): Float32Array;
520
+ }
521
+
522
+ declare interface GeoVideoSnapshotLoopTimeline {
523
+ kind: "snapshot-loop";
524
+ date: string;
525
+ }
526
+
527
+ export declare function geoVideoTimelineValues(manifest: GeoVideoManifest): number[];
528
+
529
+ /**
530
+ * u and v stacked vertically in luma (u rows on top). Each component maps
531
+ * [-valueDomain, valueDomain] to [codeMin, codeMax]; "sqrt" stores
532
+ * sign(x)·sqrt(|x|/valueDomain) to keep precision on slow flows. The static
533
+ * mask covers one component (media height / 2).
534
+ */
535
+ export declare interface GeoVideoVectorEncoding {
536
+ kind: "vector-luma";
537
+ bits: 8;
538
+ codeMin: number;
539
+ codeMax: number;
540
+ valueDomain: number;
541
+ transfer: "linear" | "sqrt";
542
+ layout: "stacked-uv";
543
+ colorSpace: "bt709";
544
+ colorRange: "limited" | "full";
545
+ }
546
+
547
+ /** Decoded u/v planes of one frame, NaN where the static mask is invalid. */
548
+ export declare interface GeoVideoVectorFrame {
549
+ u: Float32Array;
550
+ v: Float32Array;
551
+ }
552
+
553
+ /**
554
+ * VectorLayer field source backed by a vector-luma GeoVideo: each time step is
555
+ * one video frame, decoded on demand (frame by frame, no playback) into a
556
+ * single chunk covering the whole grid.
557
+ */
558
+ export declare class GeoVideoVectorSource extends GeoVideoFrameSource<GeoVideoVectorFrame> implements VectorFieldSource {
559
+ private readonly encoding;
560
+ private readonly coords;
561
+ constructor(manifest: GeoVideoManifest, options?: {
562
+ cacheSize?: number;
563
+ });
564
+ getValueDomain(): number;
565
+ getCoords(): {
566
+ time: Float64Array;
567
+ vertical: Float32Array;
568
+ latitude: Float32Array;
569
+ longitude: Float32Array;
570
+ };
571
+ getDimensions(): string[];
572
+ getChunkShape(): number[];
573
+ findDepthIndex(): number;
574
+ findTimeIndex(time: string | number): number;
575
+ getChunksForBounds(_variable: string, timeIdx: number, depthIdx: number): Array<{
576
+ timeIdx: number;
577
+ depthIdx: number;
578
+ latIdx: number;
579
+ lonIdx: number;
580
+ latRange: [number, number];
581
+ lonRange: [number, number];
582
+ latSize: number;
583
+ lonSize: number;
584
+ }>;
585
+ fetchSpatialChunkResult(variable: string, selection: {
586
+ timeIndex: number;
587
+ }): Promise<ZarrChunkFetchResult>;
588
+ protected decodeCodes(codes: Uint8Array, mask: Uint8Array, threshold: number): GeoVideoVectorFrame;
589
+ }
590
+
591
+ export declare function getPalettes(): PaletteMeta[];
592
+
593
+ /** Color grade of a style `particles.grade`; an object tunes the vibrant one. */
594
+ export declare function gradeToColorGrade(grade: ParticleGrade | undefined): ColorGrade;
595
+
596
+ /** Vibrant grade values; each one left out takes the vibrant preset's. */
597
+ declare interface GradeTuning {
598
+ /** Mid-tone lift [0, 4]. */
599
+ exposure?: number;
600
+ /** S-curve strength [0, 1]. */
601
+ contrast?: number;
602
+ /** Vibrance-weighted saturation [-1, 1]. */
603
+ saturation?: number;
604
+ /** Push of the bright half toward white [0, 1]. */
605
+ highlights?: number;
606
+ }
607
+
608
+ export declare function isGeoVideoArchiveSource(source: CatalogSource): source is CatalogGeoVideoArchiveSource;
609
+
610
+ /** A `#rgb` or `#rrggbb` color. */
611
+ export declare const isHexColor: (value: unknown) => value is string;
612
+
613
+ /** A partial style: any key left out takes the value below it. */
614
+ declare interface LayerStyleInput {
615
+ palette?: string;
616
+ renderMode?: StyleRenderMode;
617
+ particles?: ParticleStyleInput;
618
+ raster?: Partial<RasterStyle>;
619
+ }
620
+
621
+ export declare function loadGeoVideoIndex(url: string, signal?: AbortSignal): Promise<GeoVideoIndex>;
622
+
623
+ export declare function loadGeoVideoManifest(source: string | GeoVideoManifest, signal?: AbortSignal): Promise<GeoVideoManifest>;
624
+
625
+ declare type LocalizedText = Record<string, string>;
626
+
627
+ /**
628
+ * The chunk of `current`'s archive that follows it inside `range`, or with
629
+ * `loop`, the first one inside it, with the time playback resumes at.
630
+ */
631
+ export declare function nextChunk<T extends CatalogSource>(chunks: readonly T[], current: CatalogSource, options?: {
632
+ range?: readonly [number, number] | null;
633
+ loop?: boolean;
634
+ }): {
635
+ source: T;
636
+ time: number;
637
+ } | null;
638
+
639
+ /**
640
+ * The chunk following the one that ends at `currentEnd` inside `range`, or
641
+ * with `loop`, the first one inside it, with the time playback resumes at.
642
+ */
643
+ export declare function nextChunkSpan<T extends GeoVideoChunkSpan>(chunks: readonly T[], currentEnd: number, options?: {
644
+ range?: readonly [number, number] | null;
645
+ loop?: boolean;
646
+ }): {
647
+ chunk: T;
648
+ time: number;
649
+ } | null;
650
+
651
+ /**
652
+ * The candidate whose sample range overlaps `chunk` the most: archives
653
+ * sampled at different hours (six-hourly from 00:00, daily at 12:00) still
654
+ * pair by calendar period. Null when none overlaps.
655
+ */
656
+ export declare function pairChunk<T extends CatalogSource>(chunk: CatalogSource, candidates: readonly T[]): T | null;
657
+
658
+ /**
659
+ * The candidate whose sample range overlaps `span` the most: archives
660
+ * sampled at different hours (six-hourly from 00:00, daily at 12:00) still
661
+ * pair by calendar period. Null when none overlaps.
662
+ */
663
+ export declare function pairChunkSpan<T extends GeoVideoChunkSpan>(span: GeoVideoChunkSpan, candidates: readonly T[]): T | null;
664
+
665
+ export declare interface PaletteMeta {
666
+ id: string;
667
+ label: string;
668
+ tags: string[];
669
+ colors: string[];
670
+ }
671
+
672
+ /** Particle trail color grade: a preset, or the vibrant one tuned. */
673
+ declare type ParticleGrade = "off" | "vibrant" | GradeTuning;
674
+
675
+ declare interface ParticleStyle {
676
+ /** Particles per device pixel, (0, 0.2]. */
677
+ density: number;
678
+ /** Css px per frame for the fastest value of the field, (0, 10]. */
679
+ speed: number;
680
+ /** Trail length, [0, 1] (longer when higher). */
681
+ fade: number;
682
+ /** Trail color grade; replaced as a whole, not merged. */
683
+ grade: ParticleGrade;
684
+ /** Solid color under the trails; replaced as a whole, not merged. */
685
+ backdrop: BackdropStyle;
686
+ }
687
+
688
+ /** Partial particle style; a partial backdrop takes the defaults' keys. */
689
+ declare type ParticleStyleInput = Partial<Omit<ParticleStyle, "backdrop">> & {
690
+ backdrop?: Partial<BackdropStyle>;
691
+ };
692
+
693
+ /** `float random(uvec3 v)`, an integer hash in [0, 1); GLSL ES 3.0. */
694
+ export declare const RANDOM_GLSL: string;
695
+
696
+ declare interface RasterStyle {
697
+ opacity: number;
698
+ logScale: boolean;
699
+ /** Vibrance adjustment, [-1, 1]. */
700
+ vibrance: number;
701
+ /** Fixed physical-value domain; null follows the data. */
702
+ colorDomain: [number, number] | null;
703
+ }
704
+
705
+ /**
706
+ * Complete backdrop from partial input. Missing or invalid values take the
707
+ * defaults, opacity is clamped; `enabled` defaults to true when any input is
708
+ * given, so `{ opacity: 0.2 }` means "on".
709
+ */
710
+ export declare function resolveBackdrop(input?: Partial<BackdropStyle>): BackdropStyle;
711
+
712
+ /**
713
+ * Complete grade from partial input. Missing or non-finite values take the
714
+ * vibrant preset, others are clamped to their range; `enabled` defaults to
715
+ * true when any input is given, so `{}` means "vibrant".
716
+ */
717
+ export declare function resolveColorGrade(input?: Partial<ColorGrade>): ColorGrade;
718
+
719
+ export declare function resolveColorRamp(input: ColorRampInput, options?: {
720
+ reverse?: boolean;
721
+ }): Record<number, string>;
722
+
723
+ export declare type ScalarColorDomain = [number, number];
724
+
725
+ /**
726
+ * Layer style: how a layer looks, with the same keys in the catalog
727
+ * `defaults`, the engines and story views. Playback (how time moves) is not
728
+ * part of it, so `particles.speed` is always the particle speed.
729
+ */
730
+ declare type StyleRenderMode = "particles" | "raster" | "raster+particles";
731
+
732
+ /**
733
+ * Camera-aware per-frame fade opacity: eases toward a short retention while
734
+ * the camera moves, then back to the configured one. Smoothstep avoids
735
+ * visible slope changes at both ends.
736
+ */
737
+ export declare class TrailFade {
738
+ private base;
739
+ private moving;
740
+ private from;
741
+ private to;
742
+ private start;
743
+ private duration;
744
+ constructor(base: number);
745
+ /** Configured opacity, applied at once unless the camera moves. */
746
+ setBase(base: number): void;
747
+ setMoving(moving: boolean, now: number): void;
748
+ value(now: number): number;
749
+ }
750
+
751
+ export declare function validateGeoVideoIndex(value: unknown): GeoVideoIndex;
752
+
753
+ export declare function validateGeoVideoManifest(value: unknown): GeoVideoManifest;
754
+
755
+ export declare function validateScalarColorDomain(domain: ScalarColorDomain | null): ScalarColorDomain | null;
756
+
757
+ /**
758
+ * Field source contract used by VectorLayer. ZarrSource satisfies it; frame
759
+ * sources such as GeoVideoVectorSource implement it to feed decoded frames.
760
+ */
761
+ declare type VectorFieldSource = Pick<ZarrSource, "init" | "cancelAll" | "getCoords" | "getDimensions" | "getChunkShape" | "findTimeIndex" | "findDepthIndex" | "getChunksForBounds" | "fetchSpatialChunkResult"> & {
762
+ /**
763
+ * Fixed symmetric component domain [-d, d]. When provided, it replaces the
764
+ * per-frame min/max so speed and color normalization stay stable in time.
765
+ */
766
+ getValueDomain?(): number;
767
+ };
768
+
769
+ /** `vec3 applyVibrance(vec3 c, float v)`; GLSL ES 1.0 and 3.0. */
770
+ export declare const VIBRANCE_GLSL: string;
771
+
772
+ declare interface ZarrAttrs {
773
+ _ARRAY_DIMENSIONS?: string[];
774
+ units?: string;
775
+ standard_name?: string;
776
+ long_name?: string;
777
+ calendar?: string;
778
+ positive?: "up" | "down" | string;
779
+ [key: string]: unknown;
780
+ }
781
+
782
+ declare interface ZarrChunkFetchResult {
783
+ data: Float32Array;
784
+ missing: boolean;
785
+ status?: number;
786
+ url: string;
787
+ }
788
+
789
+ declare interface ZarrPointSample {
790
+ axisValue: number;
791
+ time?: number;
792
+ depth?: number;
793
+ values: Record<string, number>;
794
+ }
795
+
796
+ declare interface ZarrPointSeriesResult {
797
+ longitude: number;
798
+ latitude: number;
799
+ depth?: number;
800
+ time?: number;
801
+ points: ZarrPointSample[];
802
+ }
803
+
804
+ declare class ZarrSource {
805
+ private root;
806
+ private meta;
807
+ private coords;
808
+ private initPromise;
809
+ private verticalName;
810
+ private timeUnits;
811
+ private timeCalendar;
812
+ private cache;
813
+ private maxCacheSize;
814
+ private abortControllers;
815
+ private bloscCodecCache;
816
+ constructor(root: string, maxCacheSize?: number);
817
+ init(): Promise<void>;
818
+ private getArrayMeta;
819
+ private getAttrs;
820
+ getDimensionSeparator(variable: string): string;
821
+ getShape(variable: string): number[];
822
+ getChunkShape(variable: string): number[];
823
+ getCoords(): CoordArrays;
824
+ getTimeDimension(): ZarrTimeDimension;
825
+ getVerticalDimension(variable?: string): ZarrVerticalDimension | undefined;
826
+ hasVariable(variable: string): boolean;
827
+ getVariableAttrs(variable: string): ZarrAttrs;
828
+ getDimensions(variable: string): string[];
829
+ findNearestIndex(array: Float32Array | Float64Array, value: number): number;
830
+ findTimeIndex(time: string | number): number;
831
+ /**
832
+ * Convert a Unix-ms timestamp to the native time units used by this zarr
833
+ * (read from the time variable's .zattrs "units" field).
834
+ * Unsupported units are rejected during initialization rather than guessed.
835
+ */
836
+ private msToZarrTime;
837
+ private zarrTimeToMs;
838
+ private parseTimeEncoding;
839
+ private findNearestLongitudeIndex;
840
+ private sampleVariableAt;
841
+ private getFlatOffset;
842
+ findDepthIndex(depth: number): number;
843
+ sampleTimeSeries(options: {
844
+ variables: string[];
845
+ longitude: number;
846
+ latitude: number;
847
+ depth?: number;
848
+ timeStartIndex?: number;
849
+ timeEndIndex?: number;
850
+ stride?: number;
851
+ stopAfterMissingSamples?: number;
852
+ }): Promise<ZarrPointSeriesResult>;
853
+ sampleVerticalProfile(options: {
854
+ variables: string[];
855
+ longitude: number;
856
+ latitude: number;
857
+ time: string | number;
858
+ maxDepths?: number;
859
+ stride?: number;
860
+ stopAfterMissingSamples?: number;
861
+ }): Promise<ZarrPointSeriesResult>;
862
+ /** Return the actual name of the vertical dimension ("depth" or "elevation"). */
863
+ getVerticalDimName(): string;
864
+ /**
865
+ * Get chunk indices that intersect a geographic bounding box.
866
+ */
867
+ getChunksForBounds(variable: string, timeIdx: number, depthIdx: number, bounds: {
868
+ west: number;
869
+ south: number;
870
+ east: number;
871
+ north: number;
872
+ }): Array<{
873
+ timeIdx: number;
874
+ depthIdx: number;
875
+ latIdx: number;
876
+ lonIdx: number;
877
+ latRange: [number, number];
878
+ lonRange: [number, number];
879
+ latSize: number;
880
+ lonSize: number;
881
+ }>;
882
+ fetchChunk(variable: string, indices: number[]): Promise<Float32Array>;
883
+ /**
884
+ * Fetch one latitude/longitude chunk and extract the requested time/vertical
885
+ * plane from it. Logical coordinate indices are converted to physical Zarr
886
+ * chunk indices before fetching.
887
+ */
888
+ fetchSpatialChunkResult(variable: string, selection: {
889
+ timeIndex: number;
890
+ verticalIndex: number;
891
+ latitudeChunkIndex: number;
892
+ longitudeChunkIndex: number;
893
+ }): Promise<ZarrChunkFetchResult>;
894
+ fetchChunkResult(variable: string, indices: number[]): Promise<ZarrChunkFetchResult>;
895
+ cancelAll(): void;
896
+ private cacheChunk;
897
+ private getBloscCodec;
898
+ private decompress;
899
+ private loadCoordinates;
900
+ }
901
+
902
+ declare interface ZarrTimeDimension {
903
+ min: number;
904
+ max: number;
905
+ step?: number;
906
+ size: number;
907
+ units: string;
908
+ values: number[];
909
+ }
910
+
911
+ declare interface ZarrVerticalDimension {
912
+ name: string;
913
+ label: "depth" | "pressure" | string;
914
+ units?: string;
915
+ values: number[];
916
+ }
917
+
918
+ export { }