@chrtco/sdk 0.10.46 → 0.10.48
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.
- package/CHANGELOG.md +22 -0
- package/README.md +29 -6
- package/dist/atlas/browser.cjs +339 -5
- package/dist/atlas/browser.cjs.map +1 -1
- package/dist/atlas/browser.d.cts +1 -1
- package/dist/atlas/browser.d.ts +1 -1
- package/dist/atlas/browser.js +339 -5
- package/dist/atlas/browser.js.map +1 -1
- package/dist/index.cjs +2865 -1895
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1443 -1167
- package/dist/index.d.ts +1443 -1167
- package/dist/index.js +2818 -1889
- package/dist/index.js.map +1 -1
- package/dist/symbol-families-De7sN-p5.d.cts +93 -0
- package/dist/symbol-families-De7sN-p5.d.ts +93 -0
- package/package.json +1 -1
- package/dist/symbol-families-D2Kx20HJ.d.cts +0 -47
- package/dist/symbol-families-D2Kx20HJ.d.ts +0 -47
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { F as FileSystemAdapter } from './fs-adapter-D5iwdb1Q.js';
|
|
2
|
-
import { C as ColorTableName } from './symbol-families-
|
|
3
|
-
export { S as S52_COLORS,
|
|
2
|
+
import { C as ColorTableName } from './symbol-families-De7sN-p5.js';
|
|
3
|
+
export { E as EINK_COLOR_TABLES, a as EINK_MONO_GREYS, S as S52_COLORS, b as S52_DAY, c as S52_DUSK, d as S52_EINK_COLOR, e as S52_EINK_MONO, f as S52_EINK_NIGHT, g as S52_NIGHT, h as SYMBOL_FAMILIES, i as SYMBOL_FAMILY_META, j as SymbolFamily, k as SymbolFamilyMeta, l as getColorTable, m as iconExpressionForFamily, n as isEinkColorTable, o as isEinkGreyTable, p as parseSymbolFamily, r as resolveColor } from './symbol-families-De7sN-p5.js';
|
|
4
4
|
import maplibregl from 'maplibre-gl';
|
|
5
5
|
import { ExpressionSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
6
6
|
|
|
@@ -862,8 +862,10 @@ interface OfflineHeartbeatOptions {
|
|
|
862
862
|
* from `GET /v1/offline/styles/{region}`.
|
|
863
863
|
*/
|
|
864
864
|
interface OfflineFetchStyleOptions {
|
|
865
|
-
/**
|
|
866
|
-
|
|
865
|
+
/** Colour palette. Default: `"DAY"`. `"EINK_COLOR"` / `"EINK_MONO"` are
|
|
866
|
+
* the e-paper variants (colour and monochrome e-ink); `"EINK_NIGHT"` is
|
|
867
|
+
* e-ink at night. */
|
|
868
|
+
palette?: "DAY" | "DUSK" | "NIGHT" | "EINK_COLOR" | "EINK_MONO" | "EINK_NIGHT";
|
|
867
869
|
/**
|
|
868
870
|
* URL scheme baked into the source. Default: `"mbtiles"` (iOS/Android via
|
|
869
871
|
* MLN Native). Use `"file"` for desktop (Win/macOS/Linux).
|
|
@@ -894,7 +896,7 @@ interface OfflineFetchStyleOptions {
|
|
|
894
896
|
*/
|
|
895
897
|
interface OfflineStyleResponse {
|
|
896
898
|
region: string;
|
|
897
|
-
palette: "DAY" | "DUSK" | "NIGHT";
|
|
899
|
+
palette: "DAY" | "DUSK" | "NIGHT" | "EINK_COLOR" | "EINK_MONO" | "EINK_NIGHT";
|
|
898
900
|
protocol: "mbtiles" | "file";
|
|
899
901
|
/** Resolved symbol-artwork family (lowercased), echoed from `?symbols=`. */
|
|
900
902
|
symbols?: ChrtSymbolSet;
|
|
@@ -1558,12 +1560,20 @@ declare class TileAuth {
|
|
|
1558
1560
|
|
|
1559
1561
|
/** Symbol-artwork families served by the Style API. */
|
|
1560
1562
|
type ChrtSymbolSet = "s52" | "s101" | "chrt" | "raster";
|
|
1561
|
-
/**
|
|
1562
|
-
|
|
1563
|
+
/**
|
|
1564
|
+
* Palette themes served by the Style API: the S-52 colour tables (`day`,
|
|
1565
|
+
* `dusk`, `night`) and CHRT's e-paper variants — `eink_color` for colour
|
|
1566
|
+
* e-ink (E Ink Kaleido 3) and `eink_mono` for monochrome e-ink panels and
|
|
1567
|
+
* monitors, `eink_night` for any e-ink screen at night (a black page). The
|
|
1568
|
+
* e-ink themes change portrayal as well as colour (heavier
|
|
1569
|
+
* lines, a heavy safety contour, depth steps by pattern in mono).
|
|
1570
|
+
*/
|
|
1571
|
+
type ChrtStyleTheme = "day" | "dusk" | "night" | "eink_color" | "eink_mono" | "eink_night";
|
|
1563
1572
|
interface StyleUrlOptions {
|
|
1564
|
-
/** Palette: "day" (default), "dusk",
|
|
1565
|
-
* default — for keys with a bound
|
|
1566
|
-
* style's default palette
|
|
1573
|
+
/** Palette: "day" (default), "dusk", "night", "eink_color", "eink_mono"
|
|
1574
|
+
* or "eink_night". Omit to get the style's default — for keys with a bound
|
|
1575
|
+
* CHRTstyle custom style, that's the style's default palette (the e-ink
|
|
1576
|
+
* themes are always available, bound style or not). */
|
|
1567
1577
|
theme?: ChrtStyleTheme;
|
|
1568
1578
|
/** Symbol-artwork family: `s52` (default PresLib set), `s101` (official
|
|
1569
1579
|
* S-101 Portrayal Catalogue symbols), `chrt` (the CHRT house set), or
|
|
@@ -2822,1321 +2832,1582 @@ declare class InteractClient {
|
|
|
2822
2832
|
}
|
|
2823
2833
|
|
|
2824
2834
|
/**
|
|
2825
|
-
*
|
|
2826
|
-
*
|
|
2827
|
-
*
|
|
2828
|
-
*
|
|
2829
|
-
* primaries). That is the quantity a dark-adapted eye responds to, and it is
|
|
2830
|
-
* the one `sounding-legibility.test.ts` already measures soundings in. Scaling
|
|
2831
|
-
* the sRGB-ENCODED channels instead would dim dark colours far more than
|
|
2832
|
-
* bright ones and shift every hue it touched.
|
|
2835
|
+
* Post-consolidation (2026-04): one consolidated PMTiles per region, all
|
|
2836
|
+
* S-57 classes as distinct MVT layers inside. The MapLibre style emits one
|
|
2837
|
+
* vector source (id = region) and N paint layers that reference it via
|
|
2838
|
+
* `source-layer` = S-57 class name.
|
|
2833
2839
|
*
|
|
2834
|
-
*
|
|
2835
|
-
*
|
|
2836
|
-
*
|
|
2837
|
-
* the two stay one family by construction rather than by two hand-typed hexes
|
|
2838
|
-
* that happen to agree.
|
|
2839
|
-
*/
|
|
2840
|
-
/** WCAG 2.x relative luminance of a `#rrggbb` colour, 0 (black) to 1 (white). */
|
|
2841
|
-
declare function relativeLuminance(hex: string): number;
|
|
2842
|
-
/** WCAG 2.x contrast ratio between two `#rrggbb` colours, 1 to 21. */
|
|
2843
|
-
declare function contrastRatio(a: string, b: string): number;
|
|
2844
|
-
/**
|
|
2845
|
-
* The same hue at `factor` times its linear light. `factor` above 1 can clip a
|
|
2846
|
-
* channel, which shifts the hue; nothing in the palettes brightens, so callers
|
|
2847
|
-
* pass 0–1.
|
|
2848
|
-
*/
|
|
2849
|
-
declare function scaleLinearLight(hex: string, factor: number): string;
|
|
2850
|
-
/**
|
|
2851
|
-
* `hex` dimmed, hue kept, until its luminance is at most `ceiling`. A colour
|
|
2852
|
-
* already at or under the ceiling comes back unchanged (lower-cased).
|
|
2840
|
+
* `buildSources()` returns either the legacy Mapbox MTS shape (preserved for
|
|
2841
|
+
* demos / external style export — see generateStyle comments) or the PMTiles
|
|
2842
|
+
* shape pointing at a single tile URL per region.
|
|
2853
2843
|
*/
|
|
2854
|
-
|
|
2844
|
+
/** Vector source emitted for the legacy Mapbox MTS path. */
|
|
2845
|
+
interface MapboxVectorSource {
|
|
2846
|
+
type: "vector";
|
|
2847
|
+
url: string;
|
|
2848
|
+
}
|
|
2855
2849
|
/**
|
|
2856
|
-
*
|
|
2857
|
-
*
|
|
2858
|
-
*
|
|
2859
|
-
* text. The brightest thing NIGHT draws on purpose.
|
|
2860
|
-
* `NIGHT_MUTED_INK` that ink at 43% of its linear light, which is how
|
|
2861
|
-
* S52_NIGHT.SNDG1 (the deeper soundings) was derived.
|
|
2862
|
-
* Everything that orients rather than navigates is drawn
|
|
2863
|
-
* at or under this, and `night-luminance.test.ts` holds
|
|
2864
|
-
* every visible NIGHT colour to it unless an exemption
|
|
2865
|
-
* names a reason.
|
|
2850
|
+
* Vector source emitted for the tiles.chrt.co PMTiles path. Uses an explicit
|
|
2851
|
+
* `tiles` array (not a TileJSON `url`) because the tile-worker serves raw MVT
|
|
2852
|
+
* bytes without a TileJSON descriptor.
|
|
2866
2853
|
*/
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2854
|
+
interface PmtilesVectorSource {
|
|
2855
|
+
type: "vector";
|
|
2856
|
+
tiles: string[];
|
|
2857
|
+
minzoom: number;
|
|
2858
|
+
maxzoom: number;
|
|
2859
|
+
/** The credit a renderer shows for this source (MapLibre's attribution control). */
|
|
2860
|
+
attribution?: string;
|
|
2861
|
+
}
|
|
2870
2862
|
/**
|
|
2871
|
-
*
|
|
2872
|
-
*
|
|
2873
|
-
*
|
|
2874
|
-
*
|
|
2875
|
-
* ===========================================================================
|
|
2876
|
-
*
|
|
2877
|
-
* `map.remove()` deletes `map.style`, and after that nearly every method that
|
|
2878
|
-
* touches the style throws rather than returning: `hasImage`, `addImage`,
|
|
2879
|
-
* `updateImage`, `getSource`, `addLayer` all fail with "Cannot read properties
|
|
2880
|
-
* of undefined (reading 'getImage')" and its siblings. Code that was handed a
|
|
2881
|
-
* map, awaited a decode, an IndexedDB read or a fetch, and then wrote to the
|
|
2882
|
-
* map, throws from wherever it resumed — usually a promise nobody is awaiting,
|
|
2883
|
-
* so the throw is an uncaught error with no caller to explain it.
|
|
2884
|
-
*
|
|
2885
|
-
* Measured in CHRTdesktop (chip 63, 2026-10-04): with the page's main thread
|
|
2886
|
-
* held at 6× CPU, the chart removed its map in the middle of a pan, and the
|
|
2887
|
-
* S-52 image loader resumed onto it:
|
|
2888
|
-
*
|
|
2889
|
-
* TypeError: Cannot read properties of undefined (reading 'getImage')
|
|
2890
|
-
* at Map.hasImage
|
|
2891
|
-
* at addImageToMap (s52-image-cache.ts)
|
|
2892
|
-
*
|
|
2893
|
-
* The rule, for anything in this package or the app that takes a map: after
|
|
2894
|
-
* an `await` (or in a `.then`, a frame callback, an `onload`), check this
|
|
2895
|
-
* before the first call on the map, and stop quietly if it says no. A removed
|
|
2896
|
-
* map is not an error to report — whoever removed it is building the next one.
|
|
2897
|
-
*
|
|
2898
|
-
* ⚠ `_removed`, NOT `style`. maplibre sets `_removed = true` as the last step
|
|
2899
|
-
* of `remove()` (typed on `Map` in maplibre-gl 4 and 5), so it is the fact,
|
|
2900
|
-
* where `style === undefined` is a consequence. Test doubles that never had a
|
|
2901
|
-
* `style` read as live, which is what they are. The app pins the maplibre side
|
|
2902
|
-
* of this (`map-live.test.ts`), so an upgrade that renames the field fails a
|
|
2903
|
-
* test rather than silently making every check say yes.
|
|
2904
|
-
*
|
|
2905
|
-
* Typed `object` so the structural map shapes the app passes around (a tile
|
|
2906
|
-
* census, an errored-tile tracker) can be asked too, not only `maplibregl.Map`.
|
|
2863
|
+
* Terrarium elevation, served as PNG from `CHRT_RELIEF`. Separate from the
|
|
2864
|
+
* vector shapes because MapLibre needs `type: "raster-dem"` and an explicit
|
|
2865
|
+
* `encoding` — a raster-dem source read as a plain raster renders the encoded
|
|
2866
|
+
* RGB as a garish false-colour image rather than as elevation.
|
|
2907
2867
|
*/
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
interface AtlasStyle {
|
|
2918
|
-
type: GeomType;
|
|
2919
|
-
paint: Record<string, unknown>;
|
|
2920
|
-
layout?: Record<string, unknown>;
|
|
2921
|
-
/** Nautical symbol ID for symbol-type layers */
|
|
2922
|
-
iconImage?: string;
|
|
2923
|
-
}
|
|
2924
|
-
/** One row in the S-52 lookup table */
|
|
2925
|
-
interface LookupEntry {
|
|
2926
|
-
/** S-57 object class acronym */
|
|
2927
|
-
objectClass: string;
|
|
2928
|
-
/** Human-readable name */
|
|
2929
|
-
name: string;
|
|
2930
|
-
/** Chart No. 1 section */
|
|
2931
|
-
category: NauticalCategory;
|
|
2932
|
-
/** S-52 display category */
|
|
2933
|
-
displayCategory: DisplayCategory;
|
|
2934
|
-
/** Default style using S-52 color tokens (resolved later) */
|
|
2935
|
-
style: AtlasStyle;
|
|
2936
|
-
/** Whether conditional symbology may override the style */
|
|
2937
|
-
hasConditional?: boolean;
|
|
2938
|
-
/** Attributes that affect styling */
|
|
2939
|
-
conditionalAttributes?: string[];
|
|
2940
|
-
/** INT1 / Chart No. 1 reference (e.g. "Q130.1") */
|
|
2941
|
-
int1Ref?: string;
|
|
2942
|
-
/** S-52 viewing group number */
|
|
2943
|
-
viewingGroup?: number;
|
|
2944
|
-
/** Minimum compilation scale for display (SCAMIN) */
|
|
2945
|
-
scamin?: number;
|
|
2946
|
-
/**
|
|
2947
|
-
* Mark this class as deliberately invisible (label-only or metadata-only)
|
|
2948
|
-
* so the layer-coverage audit doesn't flag its geometry-type gaps as bugs.
|
|
2949
|
-
*
|
|
2950
|
-
* Examples:
|
|
2951
|
-
* - SOUNDG: rendered as depth numbers via labels.ts, not as visible dots
|
|
2952
|
-
* - LNDRGN: region NAME labels only, no shape
|
|
2953
|
-
* - M_NPUB / M_NSYS / M_QUAL / M_SREL / DSID: S-57 metadata classes;
|
|
2954
|
-
* present for click-query attributes, never drawn
|
|
2955
|
-
*
|
|
2956
|
-
* Without this flag, `scripts/audit-layer-coverage.ts` reports the
|
|
2957
|
-
* thousands of features in these classes as "gaps" every week even
|
|
2958
|
-
* though the invisibility is intentional.
|
|
2959
|
-
*/
|
|
2960
|
-
auditIgnore?: boolean;
|
|
2961
|
-
}
|
|
2962
|
-
/** Resolved style ready for Mapbox GL (tokens → hex) */
|
|
2963
|
-
interface ResolvedStyle {
|
|
2964
|
-
type: GeomType;
|
|
2965
|
-
paint: Record<string, unknown>;
|
|
2966
|
-
layout?: Record<string, unknown>;
|
|
2967
|
-
minzoom?: number;
|
|
2968
|
-
maxzoom?: number;
|
|
2868
|
+
interface RasterDemSource {
|
|
2869
|
+
type: "raster-dem";
|
|
2870
|
+
tiles: string[];
|
|
2871
|
+
encoding: "terrarium";
|
|
2872
|
+
tileSize: number;
|
|
2873
|
+
minzoom: number;
|
|
2874
|
+
maxzoom: number;
|
|
2875
|
+
/** The credit a renderer shows for this source (MapLibre's attribution control). */
|
|
2876
|
+
attribution?: string;
|
|
2969
2877
|
}
|
|
2970
|
-
|
|
2878
|
+
type VectorSourceSpec = MapboxVectorSource | PmtilesVectorSource;
|
|
2879
|
+
type AnySourceSpec = VectorSourceSpec | RasterDemSource;
|
|
2880
|
+
/** CHRTland's vector land base. ADR 0023: its own archive, never chart data. */
|
|
2881
|
+
declare const LAND_REGION = "CHRT_LAND";
|
|
2882
|
+
/** CHRTland's terrarium relief. */
|
|
2883
|
+
declare const RELIEF_REGION = "CHRT_RELIEF";
|
|
2884
|
+
/** The world basemap under everything (completing-the-world-map, 2026-08-27). */
|
|
2885
|
+
declare const BASE_REGION = "CHRT_BASE";
|
|
2971
2886
|
/**
|
|
2972
|
-
*
|
|
2973
|
-
*
|
|
2974
|
-
*
|
|
2887
|
+
* CHRT_BASE's zoom range. 11 is the deepest zoom the archive's detail tier
|
|
2888
|
+
* carries honestly — the planet's inland water exists from z9 and is read at
|
|
2889
|
+
* z10 — and the world tier is tiled to the same depth so no layer vanishes
|
|
2890
|
+
* from a tile the detail tier creates. Above 11 the client overzooms, and
|
|
2891
|
+
* overzoomed inland water looks soft DELIBERATELY: it is "roughly where the
|
|
2892
|
+
* lakes are", not a surveyed shoreline. Must equal the builder's MAXZOOM
|
|
2893
|
+
* (tools/chrtbase-build/build.mjs).
|
|
2975
2894
|
*/
|
|
2976
|
-
declare const
|
|
2977
|
-
|
|
2895
|
+
declare const BASE_MINZOOM = 0;
|
|
2896
|
+
declare const BASE_MAXZOOM = 11;
|
|
2978
2897
|
/**
|
|
2979
|
-
*
|
|
2980
|
-
*
|
|
2898
|
+
* The credit the ONLINE CHRT_BASE source carries (owner wording, 2026-09-16).
|
|
2899
|
+
*
|
|
2900
|
+
* OpenStreetMap is named because the online archive's z9–11 detail tier IS
|
|
2901
|
+
* OSM-derived inland water (ODbL, `public/chrtbase-derivation.json`). The
|
|
2902
|
+
* app-embeddable offline bundle is a z0–6 cut that contains no OSM data and
|
|
2903
|
+
* carries `BASE_BUNDLE_ATTRIBUTION` instead (base-layers.ts) — one credit per
|
|
2904
|
+
* artefact, each naming exactly the data it holds.
|
|
2981
2905
|
*/
|
|
2982
|
-
declare const
|
|
2983
|
-
/** Get numeric draw priority for a layer (lower = drawn first / below) */
|
|
2984
|
-
declare function getDrawPriority(layerName: string): number;
|
|
2985
|
-
|
|
2986
|
-
/** S-52 display modes */
|
|
2987
|
-
type DisplayMode = "BASE" | "STANDARD" | "ALL";
|
|
2988
|
-
/** Check if a layer's display category is visible in the given mode */
|
|
2989
|
-
declare function isVisibleInMode(displayCategory: DisplayCategory, mode: DisplayMode): boolean;
|
|
2906
|
+
declare const BASE_ATTRIBUTION = "\u00A9 CHRT \u00B7 Made with Natural Earth \u00B7 \u00A9 OpenStreetMap contributors";
|
|
2990
2907
|
/**
|
|
2991
|
-
*
|
|
2908
|
+
* The credit the CHRT_LAND source carries. CHRTland's land, land use, roads,
|
|
2909
|
+
* places, peaks and marinas are OpenStreetMap via the Protomaps planet, and the
|
|
2910
|
+
* ODbL requires this notice wherever the map is shown (.chrt/legal.md
|
|
2911
|
+
* "Required notices"). Its other inputs — the ENC's charted land, USGS 3DEP
|
|
2912
|
+
* contours, GNIS names — are US federal public domain and owe none. Same
|
|
2913
|
+
* string as the offline land bundle's (offline-worker `LAND_PROVENANCE`).
|
|
2992
2914
|
*/
|
|
2993
|
-
declare
|
|
2994
|
-
declare function getCollisionSettings(viewingGroup?: number): {
|
|
2995
|
-
iconAllowOverlap: boolean;
|
|
2996
|
-
iconOptional: boolean;
|
|
2997
|
-
symbolSortKey?: number;
|
|
2998
|
-
};
|
|
2915
|
+
declare const LAND_ATTRIBUTION = "\u00A9 OpenStreetMap contributors";
|
|
2999
2916
|
/**
|
|
3000
|
-
*
|
|
2917
|
+
* The credit the CHRT_RELIEF source carries. USGS 3DEP elevation, public
|
|
2918
|
+
* domain (17 U.S.C. § 105) — no notice is required, so this is a courtesy that
|
|
2919
|
+
* names the source. There is no OpenStreetMap in it.
|
|
3001
2920
|
*/
|
|
3002
|
-
declare
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
declare function getLookupEntry(layerName: string): LookupEntry;
|
|
3006
|
-
|
|
2921
|
+
declare const RELIEF_ATTRIBUTION = "Elevation: USGS 3D Elevation Program";
|
|
2922
|
+
/** Terrarium tiles are 512 px; the default 256 would halve the apparent relief. */
|
|
2923
|
+
declare const RELIEF_TILE_SIZE = 512;
|
|
3007
2924
|
/**
|
|
3008
|
-
*
|
|
3009
|
-
*
|
|
3010
|
-
*
|
|
2925
|
+
* How `CHRT_RELIEF`'s PNGs encode elevation. MapLibre's raster-dem default is
|
|
2926
|
+
* `mapbox`, which decodes terrarium RGB into nonsense heights — so every
|
|
2927
|
+
* surface that describes this source (this registry, the tile-worker's
|
|
2928
|
+
* TileJSON) has to say it.
|
|
3011
2929
|
*/
|
|
2930
|
+
declare const RELIEF_ENCODING = "terrarium";
|
|
2931
|
+
type SourceMode = "mapbox" | "pmtiles";
|
|
3012
2932
|
/**
|
|
3013
|
-
*
|
|
3014
|
-
* "dangerous to my hull" for portrayal purposes.
|
|
2933
|
+
* Query parameter carrying the resolved build id on every tile URL.
|
|
3015
2934
|
*
|
|
3016
|
-
*
|
|
3017
|
-
* safety-contour-driven conditional symbology rule, so the rules can't
|
|
3018
|
-
* silently disagree with each other:
|
|
2935
|
+
* ── Why the build has to be IN THE URL ────────────────────────────────────
|
|
3019
2936
|
*
|
|
3020
|
-
*
|
|
3021
|
-
*
|
|
3022
|
-
*
|
|
3023
|
-
*
|
|
3024
|
-
*
|
|
3025
|
-
*
|
|
3026
|
-
* for the full IHO correspondence).
|
|
2937
|
+
* The Worker reports the build it served in the `X-Build-Id` RESPONSE HEADER
|
|
2938
|
+
* and sends `Cache-Control: private, max-age=3600`. A header is not part of a
|
|
2939
|
+
* cache key, so every build shares one URL: after a cutover, tiles the client
|
|
2940
|
+
* already fetched keep coming from its own HTTP cache — the old build — while
|
|
2941
|
+
* newly-panned-to tiles come from the new one, for up to the full hour. The
|
|
2942
|
+
* client renders TWO BUILDS AT ONCE.
|
|
3027
2943
|
*
|
|
3028
|
-
*
|
|
3029
|
-
* `
|
|
3030
|
-
*
|
|
2944
|
+
* On a nautical chart that is not a cosmetic seam. Measured live 2026-08-25,
|
|
2945
|
+
* cutting `CHRT_LAND` from `463b265e` to `dbb69074` (a build that deliberately
|
|
2946
|
+
* changes land extent): adjacent tiles disagreed about whether land was there,
|
|
2947
|
+
* at the seam between them. Putting the build in the key gives each build its
|
|
2948
|
+
* own cache namespace — old entries age out untouched, and the next style
|
|
2949
|
+
* build flips the whole viewport at once instead of tile by tile.
|
|
2950
|
+
*
|
|
2951
|
+
* ── Why a QUERY PARAMETER and not a path segment ──────────────────────────
|
|
2952
|
+
*
|
|
2953
|
+
* A path segment would be the tidier-looking URL and it is the wrong trade
|
|
2954
|
+
* here, for two reasons that are both about other people's code:
|
|
2955
|
+
*
|
|
2956
|
+
* 1. COMPATIBILITY IS PERMANENT, NOT "one release". iOS and desktop are
|
|
2957
|
+
* prod-only clients that ship on their own cadence. The Worker routes on
|
|
2958
|
+
* `url.pathname` (`TILE_ROUTE_PATH`) and reads only `?build=`, so a URL
|
|
2959
|
+
* carrying this parameter routes BYTE-IDENTICALLY to one without it. A
|
|
2960
|
+
* new path segment would instead need a second route regex kept alive
|
|
2961
|
+
* indefinitely.
|
|
2962
|
+
* 2. FIVE SEPARATE PATTERNS ALREADY MATCH THIS URL, and every one of them
|
|
2963
|
+
* ends `(?:\?.*)?$` — `src/lib/map/tile-token-client.ts` TILE_URL_PATH
|
|
2964
|
+
* and `src/site/chart/sail-tile-token.ts` (which decide whether a tile
|
|
2965
|
+
* gets its Bearer), `packages/sdk/src/tile-auth.ts` TILE_URL_PATH,
|
|
2966
|
+
* `public/chrt-tile-sw.js` TILE_URL_RE (which also reads the region out of
|
|
2967
|
+
* the URL to pick its per-region cache), and
|
|
2968
|
+
* `src/site/offline/pack-protocol.ts` TILE_URL (which rewrites a tile to
|
|
2969
|
+
* a downloaded pack). Their optional PATH segment, by contrast, is
|
|
2970
|
+
* `[a-z][a-z0-9-]*` — letter-first so it cannot be confused with the
|
|
2971
|
+
* numeric `{z}` — and build ids are hex (`463b265e`, `4de67273`). A build
|
|
2972
|
+
* in the path would miss every one of them, and a tile those patterns
|
|
2973
|
+
* miss does not merely go uncached: it goes out with NO BEARER and comes
|
|
2974
|
+
* back 401, which MapLibre records as a permanently errored tile. That is
|
|
2975
|
+
* the exact failure the `.png` drift caused on staging-sail (see
|
|
2976
|
+
* `chrt-tile-sw.js`).
|
|
2977
|
+
*
|
|
2978
|
+
* The query string is also what the caches this fix targets actually key on:
|
|
2979
|
+
* the browser HTTP cache, MapLibre's own tile cache, and the Service Worker's
|
|
2980
|
+
* `new Request(req.url)` entry key all include it.
|
|
2981
|
+
*
|
|
2982
|
+
* `v` rather than `build`: `?build=` is a taken name with a strict meaning on
|
|
2983
|
+
* the Worker (`?build=candidate`, employee-only, 400 on any other value).
|
|
3031
2984
|
*/
|
|
3032
|
-
declare const
|
|
3033
|
-
declare function depareColor(props: Record<string, unknown>, ct?: ColorTableName, safetyContourM?: number): string;
|
|
2985
|
+
declare const BUILD_PARAM = "v";
|
|
3034
2986
|
/**
|
|
3035
|
-
*
|
|
3036
|
-
*
|
|
3037
|
-
*
|
|
2987
|
+
* One tile-URL template — the single place a CHRT tile URL is spelled.
|
|
2988
|
+
*
|
|
2989
|
+
* `buildId` is encoded rather than interpolated raw: MapLibre substitutes
|
|
2990
|
+
* `{z}`/`{x}`/`{y}` by brace-matching the template, so an id containing a
|
|
2991
|
+
* brace would corrupt every tile request. Empty / whitespace-only ids emit no
|
|
2992
|
+
* parameter at all instead of a bare `?v=` that would key its own useless
|
|
2993
|
+
* cache namespace.
|
|
3038
2994
|
*/
|
|
3039
|
-
declare
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
declare
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
2995
|
+
declare function tileTemplate(base: string, region: string, extension: "mvt" | "png", buildId?: string): string;
|
|
2996
|
+
/** Canonical source id used in `generateStyle()` — matches the region name
|
|
2997
|
+
* of the one consolidated PMTiles served by the tile-worker for this region. */
|
|
2998
|
+
declare const DEFAULT_REGION = "NOAA_ENC";
|
|
2999
|
+
interface BuildSourcesOptions {
|
|
3000
|
+
/** Which tile path to emit. Default: "pmtiles" (the supported path post-Mapbox). */
|
|
3001
|
+
mode?: SourceMode;
|
|
3002
|
+
/** Chart region. Default: "NOAA_ENC". */
|
|
3003
|
+
region?: string;
|
|
3004
|
+
/**
|
|
3005
|
+
* Build id of the CHART region (`region`) — the `build_tag` a
|
|
3006
|
+
* `mint-tile-token` response hands back.
|
|
3007
|
+
*
|
|
3008
|
+
* Emitted as the {@link BUILD_PARAM} query parameter on that region's tile
|
|
3009
|
+
* template. See {@link tileTemplate} for why a build discriminator has to be
|
|
3010
|
+
* in the URL at all.
|
|
3011
|
+
*
|
|
3012
|
+
* ⚠ THIS COVERS THE CHART REGION ONLY. A token is minted for one chart
|
|
3013
|
+
* region and `CHRT_LAND` / `CHRT_RELIEF` ride it, so the JWT's `build_tag`
|
|
3014
|
+
* says nothing about a land cutover — the same blind spot that made the
|
|
3015
|
+
* Worker's edge-cache key wrong until `TILE_CACHE_VERSION` v3
|
|
3016
|
+
* (cloudflare/tile-worker/src/cache-encoding.ts). Pass {@link buildTags} to
|
|
3017
|
+
* discriminate the basemap sources too.
|
|
3018
|
+
*/
|
|
3019
|
+
buildTag?: string;
|
|
3020
|
+
/**
|
|
3021
|
+
* Resolved build id per region — `{ NOAA_ENC: "…", CHRT_LAND: "…" }`.
|
|
3022
|
+
*
|
|
3023
|
+
* The complete form of {@link buildTag}: every source this style declares
|
|
3024
|
+
* gets its own discriminator, so a `CHRT_LAND` promotion turns over the land
|
|
3025
|
+
* URLs without touching the chart's (and vice versa). An entry here wins
|
|
3026
|
+
* over `buildTag` for the same region.
|
|
3027
|
+
*
|
|
3028
|
+
* This is the mint response's `build_tags` map verbatim (claim contract
|
|
3029
|
+
* v1.7) — `TileTokenResponse.buildTags` in both `lib/map/tile-token-client.ts`
|
|
3030
|
+
* and the SDK's `tile-auth.ts`. The same map already keys the tile Service
|
|
3031
|
+
* Worker's per-region caches; passing it here puts the same identity in the
|
|
3032
|
+
* URL, so the layer above the Service Worker stops mixing builds too.
|
|
3033
|
+
*
|
|
3034
|
+
* A region absent from the map simply gets no discriminator — the URL it
|
|
3035
|
+
* has always had. That is a deliberate soft edge: an older mint response, or
|
|
3036
|
+
* a region with no servable build, must degrade to today's behaviour rather
|
|
3037
|
+
* than emit a URL pinned to a build nobody resolved.
|
|
3038
|
+
*/
|
|
3039
|
+
buildTags?: Readonly<Record<string, string>>;
|
|
3040
|
+
/** Override tile-worker origin (e.g. staging). Default: DEFAULT_TILE_BASE_URL. */
|
|
3041
|
+
tileBaseUrl?: string;
|
|
3042
|
+
/**
|
|
3043
|
+
* Emit the CHRTland vector land base as a second source (ADR 0023). Off by
|
|
3044
|
+
* default: it costs a source, and the region must be granted on the token.
|
|
3045
|
+
*/
|
|
3046
|
+
land?: boolean;
|
|
3047
|
+
/**
|
|
3048
|
+
* Emit CHRTland's terrarium relief as a raster-dem source. Separate from
|
|
3049
|
+
* `land` because relief needs a raster-capable worker AND a grant that
|
|
3050
|
+
* `land-regions.ts` still withholds.
|
|
3051
|
+
*/
|
|
3052
|
+
relief?: boolean;
|
|
3053
|
+
/**
|
|
3054
|
+
* Emit the CHRT_BASE world basemap as a third vector source — the dark
|
|
3055
|
+
* geography under everything, the tan jurisdiction fill, and the rough
|
|
3056
|
+
* inland water inside countries CHRT carries. Its layers sit UNDER the
|
|
3057
|
+
* no-coverage hatch's companions and everything else; see baseLayers().
|
|
3058
|
+
*/
|
|
3059
|
+
base?: boolean;
|
|
3060
|
+
}
|
|
3061
|
+
/**
|
|
3062
|
+
* Build the "sources" block for a CHRT style.
|
|
3063
|
+
*
|
|
3064
|
+
* - `mode: "mapbox"`: one mapbox:// url (kept for external style export only).
|
|
3065
|
+
* - `mode: "pmtiles"` (default): one vector tile endpoint for the region,
|
|
3066
|
+
* routed by the Worker to the one consolidated PMTiles:
|
|
3067
|
+
* `${tileBaseUrl}/v1/tiles/{region}/{z}/{x}/{y}.mvt`
|
|
3068
|
+
*
|
|
3069
|
+
* Pass `buildTag` / `buildTags` to pin each source's URL to the build it is
|
|
3070
|
+
* serving — without that, one URL is shared by every build and a cutover
|
|
3071
|
+
* leaves the client rendering two of them at once. See {@link BUILD_PARAM}.
|
|
3072
|
+
*/
|
|
3073
|
+
declare function buildSources(opts?: BuildSourcesOptions): Record<string, AnySourceSpec>;
|
|
3049
3074
|
|
|
3050
3075
|
/**
|
|
3051
|
-
*
|
|
3052
|
-
*
|
|
3076
|
+
* Builds Mapbox GL Style layer specs from S-52 lookup entries.
|
|
3077
|
+
* Wraps the existing atlas resolveStyle() and adds source/source-layer/filter.
|
|
3053
3078
|
*/
|
|
3054
3079
|
|
|
3080
|
+
interface StyleLayer {
|
|
3081
|
+
id: string;
|
|
3082
|
+
type: string;
|
|
3083
|
+
source: string;
|
|
3084
|
+
"source-layer": string;
|
|
3085
|
+
filter?: unknown[];
|
|
3086
|
+
paint: Record<string, unknown>;
|
|
3087
|
+
layout?: Record<string, unknown>;
|
|
3088
|
+
minzoom?: number;
|
|
3089
|
+
maxzoom?: number;
|
|
3090
|
+
metadata?: Record<string, unknown>;
|
|
3091
|
+
}
|
|
3055
3092
|
/**
|
|
3056
|
-
*
|
|
3057
|
-
*
|
|
3058
|
-
*
|
|
3059
|
-
* Exported (with the other tier builders below) for the build-side parity
|
|
3060
|
-
* test: CHRTbaremetal replicates these taxonomies as data in
|
|
3061
|
-
* tools/chrt-baremetal/server/src/tilebuild/placeNameTiers.ts to stamp
|
|
3062
|
-
* `tier` onto PLACENAME index features, and
|
|
3063
|
-
* placename-tier-parity.test.ts evaluates the two against shared
|
|
3064
|
-
* fixtures. Change a branch here and that test names the drift.
|
|
3093
|
+
* Build all Mapbox GL layers for a given S-57 object class.
|
|
3094
|
+
* Returns multiple layers (fill, outline, symbol, label, etc.).
|
|
3065
3095
|
*
|
|
3066
|
-
*
|
|
3067
|
-
*
|
|
3068
|
-
* 2 — Sea / Gulf (OBJNAM "Gulf of …" / "… Sea")
|
|
3069
|
-
* 3 — Bay / Sound / (CATSEA in {5 bay, 12 narrows} OR OBJNAM
|
|
3070
|
-
* Strait / Narrows " Bay" / " Sound" / " Strait")
|
|
3071
|
-
* 4 — Anchorage detail (OBJNAM contains "Anchorage Area")
|
|
3072
|
-
* 5 — Relief + default (CATSEA relief codes — authoritative — or
|
|
3073
|
-
* relief-term names, or anything uncategorised;
|
|
3074
|
-
* suppressed below z9 by the size curve)
|
|
3096
|
+
* Post-consolidation: all S-57 classes live as MVT layers inside one
|
|
3097
|
+
* consolidated PMTiles per region; `source` is always the region name.
|
|
3075
3098
|
*
|
|
3076
|
-
*
|
|
3077
|
-
*
|
|
3078
|
-
*
|
|
3079
|
-
*
|
|
3080
|
-
* (matches `s52-conditional.ts` precedent).
|
|
3099
|
+
* `opts.safetyContour` is the mariner's safety depth in metres — it drives
|
|
3100
|
+
* the §CSYM02 isolated-danger ring on hazard classes. Defaults to
|
|
3101
|
+
* `DEFAULT_SAFETY_CONTOUR_M`, the same default the SOUNDG two-shade rule
|
|
3102
|
+
* uses, so the ring and the sounding colour always agree.
|
|
3081
3103
|
*/
|
|
3082
|
-
declare function
|
|
3104
|
+
declare function buildLayersForClass(objectClass: string, ct: ColorTableName, sourceId?: string, opts?: {
|
|
3105
|
+
safetyContour?: number;
|
|
3106
|
+
}): StyleLayer[];
|
|
3083
3107
|
/**
|
|
3084
|
-
*
|
|
3085
|
-
*
|
|
3086
|
-
*
|
|
3087
|
-
*
|
|
3088
|
-
*
|
|
3089
|
-
* Tier 1/2 may fire via CATBUA when populated; OBJNAM length is the
|
|
3090
|
-
* fallback so unpopulated CATBUA still produces a usable hierarchy.
|
|
3108
|
+
* Get the full ordered list of object classes for style generation.
|
|
3109
|
+
* Uses S52_DRAW_ORDER as base, then adds any missing classes from the
|
|
3110
|
+
* S-52 lookup table so a newly-ingested class automatically gets styled
|
|
3111
|
+
* without touching this file.
|
|
3091
3112
|
*/
|
|
3092
|
-
declare function
|
|
3113
|
+
declare function getOrderedClasses(): string[];
|
|
3114
|
+
|
|
3093
3115
|
/**
|
|
3094
|
-
*
|
|
3095
|
-
*
|
|
3096
|
-
* 2 — Local point (else — "Bird Island", "Cottage Park")
|
|
3116
|
+
* CHART SIZING — five sliders over what the chart prints: LAND LABELS, WATER
|
|
3117
|
+
* LABELS, DEPTH NUMBERS, WAYPOINTS, CHART ICONS, 50–200 % (owner, 2026-10-05).
|
|
3097
3118
|
*
|
|
3098
|
-
*
|
|
3099
|
-
*
|
|
3100
|
-
*
|
|
3101
|
-
*
|
|
3119
|
+
* ===========================================================================
|
|
3120
|
+
* ONE MODEL, EVERY CLIENT
|
|
3121
|
+
* ===========================================================================
|
|
3122
|
+
*
|
|
3123
|
+
* The owner asked for the sliders on CHRTsail iOS (*"please add the following
|
|
3124
|
+
* as sizing sliders: land label size, water label size, waypoint size, chart
|
|
3125
|
+
* icon size"*) the same day a captain at a Raspberry Pi helm asked CHRTsail
|
|
3126
|
+
* desktop for *"the depth numbers to be bolder"* (chip 68). The decisions:
|
|
3127
|
+
* desktop and web ADOPT the iOS model rather than ship a control of their own,
|
|
3128
|
+
* and every platform gains a FIFTH slider, DEPTH NUMBERS, for the depth
|
|
3129
|
+
* figures. So this file is a port of `ChartSymbolSizing.swift` (chrt-co/sail,
|
|
3130
|
+
* #1038 at d5cd7060, read 2026-10-05) plus DEPTH NUMBERS as agreed with
|
|
3131
|
+
* CHRTKit's owner (sail, 2026-10-05: `depthNumbers`, `chart.depthNumberScale`,
|
|
3132
|
+
* the ladder and rules below). The classification tables and the collision
|
|
3133
|
+
* rules are copied, not re-derived; a disagreement between the two clients is
|
|
3134
|
+
* a bug in one of them.
|
|
3135
|
+
*
|
|
3136
|
+
* WAYPOINTS is in the vocabulary but not in this file's transform: waypoints
|
|
3137
|
+
* are the app's own marks (DOM, not style layers) and the app scales them.
|
|
3138
|
+
*
|
|
3139
|
+
* ===========================================================================
|
|
3140
|
+
* THE RULE THE PORT KEEPS — iOS's, verbatim in substance
|
|
3141
|
+
* ===========================================================================
|
|
3142
|
+
*
|
|
3143
|
+
* A bigger symbol may OVERLAP the chart. It may never DISPLACE it.
|
|
3144
|
+
*
|
|
3145
|
+
* 1. 100 % is the generated style, byte for byte (`applyChartSymbolScales`
|
|
3146
|
+
* returns the same object).
|
|
3147
|
+
* 2. An enlarged layer stops taking part in other symbols' placement
|
|
3148
|
+
* (`*-ignore-placement: true`): it may vanish itself, it removes nothing.
|
|
3149
|
+
* 3. Enlarged hazard text — CHRT's label band 100, `chrt:labelPriority` —
|
|
3150
|
+
* also gets `text-allow-overlap: true`: never dropped.
|
|
3151
|
+
* 4. The soundings keep CHRT's collision flags (a sounding layer that ignored
|
|
3152
|
+
* placement would stop decluttering itself) — and OUTRANK every label
|
|
3153
|
+
* above them: whenever ANY label slider (land, water, chart icons) is off
|
|
3154
|
+
* 100 %, every text label placed before the soundings, hazard text and
|
|
3155
|
+
* unclassified labels included, stops taking part in placement. A
|
|
3156
|
+
* sounding then gives way only to a shallower sounding. iOS's
|
|
3157
|
+
* `ChartSoundingsRule.outrankLabels`, chosen by its Boston Inner Harbor
|
|
3158
|
+
* census (z13–16, every slider at 50/100/150/200 %): every rule that only
|
|
3159
|
+
* protected the ENLARGED layer lost a shallow sounding, including on the
|
|
3160
|
+
* way DOWN — a sea-area name shrunk to 50 % fitted where it used to be
|
|
3161
|
+
* culled, got placed, and culled a sounding beneath it.
|
|
3162
|
+
*
|
|
3163
|
+
* Its cost, measured on this chart (bench, Boston, LAND 105 %): 46–56 %
|
|
3164
|
+
* more soundings at z11.5–13, aid names up to 3.6x, sea and island names
|
|
3165
|
+
* drawn twice — labels above the soundings stop culling each other as well
|
|
3166
|
+
* as the soundings.
|
|
3167
|
+
*
|
|
3168
|
+
* **THE ZOOM SPLIT — the soundings rule in force** (owner, 2026-10-06;
|
|
3169
|
+
* CHRTKit `ChartSoundingsRule.zoomSplit(harbourFrom: 14)`, sail 20f9f56bb;
|
|
3170
|
+
* `CHART_SOUNDINGS_RULE`). MapLibre has one collision index and no
|
|
3171
|
+
* groups, so a label class above the soundings either culls them or culls
|
|
3172
|
+
* nothing, its own kind included (the pile-up). Rule 4 is therefore kept
|
|
3173
|
+
* only for what orients the chart — sea-area, island and land-region
|
|
3174
|
+
* names, CHRTland and CHRT_BASE labels, and label band 100
|
|
3175
|
+
* (`keptAboveSoundings`). Every OTHER text label above the soundings
|
|
3176
|
+
* (buoy, beacon and fog-signal names, the dredged-area note) moves
|
|
3177
|
+
* directly BELOW them, in its served order, and its collision flags step
|
|
3178
|
+
* with zoom: CHRT's own below zoom 14, where it thins out round the
|
|
3179
|
+
* soundings, and `true` from 14, where it is always drawn and displaces
|
|
3180
|
+
* nothing — exactly what rule 4 draws there. Measured on the bench: 0
|
|
3181
|
+
* shoals uncovered beyond rule 4's own; buoy names 33 / 12 / 5 at
|
|
3182
|
+
* z14 / 15 / 16 against served 25 / 11 / 5, and 5–27 against 60–78 below.
|
|
3183
|
+
* Layer order cannot change with zoom, but flags can, so this is one
|
|
3184
|
+
* order with zoom-stepped flags, the same edits on every platform.
|
|
3185
|
+
*
|
|
3186
|
+
* Shrinking keeps every served flag on the layer that shrinks: a smaller box
|
|
3187
|
+
* can only free space (rule 4 covers what that freed space then admits).
|
|
3188
|
+
*
|
|
3189
|
+
* ===========================================================================
|
|
3190
|
+
* DEPTH NUMBERS — 0.10.3's toggle, as a slider
|
|
3191
|
+
* ===========================================================================
|
|
3192
|
+
*
|
|
3193
|
+
* DEPTH NUMBERS takes the depth figures (`DEPTH_FIGURE_CLASSES`: soundings,
|
|
3194
|
+
* contour values, the depth beside a rock, wreck or obstruction) away from
|
|
3195
|
+
* WATER LABELS and CHART ICONS, and keeps CHRT's collision flags on the
|
|
3196
|
+
* soundings and contour values. OFF 100 %, EITHER WAY, IT TRIGGERS THE ZOOM
|
|
3197
|
+
* SPLIT (owner, 2026-10-06, `labelSlidersOffStandard`: "a size control must
|
|
3198
|
+
* never remove a shoal, whichever way it's moved"). Bigger depth glyphs collide
|
|
3199
|
+
* with more of the labels placed before them: on the bench at Boston DEPTH
|
|
3200
|
+
* 140 % alone left 7 / 3 / 1 shoals uncovered at z12.3 / 13 / 14 — 0.10.3's
|
|
3201
|
+
* Large left 8 / 4 / 1. With the split: 0. Shrinking is a trigger by the same
|
|
3202
|
+
* rule, measured or not (`scripts/chart-bench/depth-numbers-census.ts`).
|
|
3203
|
+
* Above 100 %:
|
|
3204
|
+
*
|
|
3205
|
+
* A. **Depth figures go Semibold** — each served Regular face swapped for its
|
|
3206
|
+
* Semibold (`semiboldFontStack`, derived from the name as CHRTKit does).
|
|
3207
|
+
* Soundings already are; contour values and the depth beside a rock,
|
|
3208
|
+
* wreck or obstruction are Regular, and an enlarged Regular numeral
|
|
3209
|
+
* beside an enlarged Semibold one reads as two kinds of figure. There is no Bold glyph set on any CHRT glyph host
|
|
3210
|
+
* (`cloudflare/tile-worker/glyphs/GLYPHS.json`), so this is the heaviest
|
|
3211
|
+
* face a client may ask for.
|
|
3212
|
+
* B. **Halos grow half as fast as the glyph** (`haloFactor`), on depth
|
|
3213
|
+
* figures only and at DEPTH NUMBERS' own factor — a contour value's
|
|
3214
|
+
* half-rate size does not halve its halo again (CHRTKit,
|
|
3215
|
+
* `ChartDepthFigureRules.haloWidth`). A halo is the S-52 cut-out, and in
|
|
3216
|
+
* DUSK it is dark like a deeper sounding's fill, so it THICKENS that
|
|
3217
|
+
* numeral instead of cutting it out (`s-52.md` §8a). Grown in proportion,
|
|
3218
|
+
* the deeper DUSK soundings out-weighed the shoal ones beside them — the
|
|
3219
|
+
* two-shade rule backwards.
|
|
3220
|
+
* C. **The sounding collision padding shrinks as the soundings grow**
|
|
3221
|
+
* (`soundingPadding`), so about as many soundings are placed at 140 % as
|
|
3222
|
+
* at 100 %: CHRT's 6 px padding at 1.4x placed a quarter fewer (326 → 246
|
|
3223
|
+
* at Boston z14, chip 68); 3.5 px held z11.5–15 within ±5 %.
|
|
3224
|
+
* D. **Contour values grow at half rate** (`contourValueFactor`) — 0.10.3's
|
|
3225
|
+
* 1.2x beside 1.4x soundings, so a contour label still fits its line.
|
|
3226
|
+
* And rule 3 for the depth callouts beside rocks, wrecks and obstructions
|
|
3227
|
+
* (CHRTKit's call): never dropped, never displacing, so a hazard is never
|
|
3228
|
+
* drawn with its depth culled.
|
|
3229
|
+
*
|
|
3230
|
+
* Nothing here touches a label's TEXT, its colours (the §SOUNDG02 two shades),
|
|
3231
|
+
* its sort key, filter or zoom gate, or the layer set.
|
|
3102
3232
|
*/
|
|
3103
|
-
|
|
3233
|
+
|
|
3104
3234
|
/**
|
|
3105
|
-
*
|
|
3106
|
-
*
|
|
3107
|
-
*
|
|
3235
|
+
* Drawer order — iOS's `ChartSymbolSize.allCases` plus DEPTH NUMBERS.
|
|
3236
|
+
*
|
|
3237
|
+
* ⚠ DEPTH NUMBERS IS THE OWNER'S FIFTH SLIDER (2026-10-05), on every platform.
|
|
3238
|
+
* It takes the depth figures — soundings, contour values, the depth beside a
|
|
3239
|
+
* rock, wreck or obstruction — away from WATER LABELS and CHART ICONS, scales
|
|
3240
|
+
* them the way 0.10.3's DEPTH NUMBERS toggle did, and off 100 % — either way —
|
|
3241
|
+
* triggers the zoom split as LAND, WATER and CHART ICONS do (owner, 2026-10-06). 100 % on
|
|
3242
|
+
* every client by default. Name, wire and ladder as CHRTKit's shared model;
|
|
3243
|
+
* see `CHART_SYMBOL_SIZE_WIRE`.
|
|
3244
|
+
*/
|
|
3245
|
+
declare const CHART_SYMBOL_SIZES: readonly ["landLabels", "waterLabels", "depthNumbers", "waypoints", "chartIcons"];
|
|
3246
|
+
type ChartSymbolSize = (typeof CHART_SYMBOL_SIZES)[number];
|
|
3247
|
+
/** The account key each slider syncs under — iOS `SettingKey.*Scale.wireName`. */
|
|
3248
|
+
declare const CHART_SYMBOL_SIZE_WIRE: Readonly<Record<ChartSymbolSize, string>>;
|
|
3249
|
+
/** The row names — `ChartSymbolSize.label`, verbatim. */
|
|
3250
|
+
declare const CHART_SYMBOL_SIZE_LABELS: Readonly<Record<ChartSymbolSize, string>>;
|
|
3251
|
+
/** What each slider reaches, one line — `ChartSymbolSize.reach`, verbatim. */
|
|
3252
|
+
declare const CHART_SYMBOL_SIZE_REACH: Readonly<Record<ChartSymbolSize, string>>;
|
|
3253
|
+
/** `ChartSymbolScale` — integer percent throughout. */
|
|
3254
|
+
declare const CHART_SYMBOL_SCALE: {
|
|
3255
|
+
readonly min: 50;
|
|
3256
|
+
readonly max: 200;
|
|
3257
|
+
readonly standard: 100;
|
|
3258
|
+
/** The − / + step. */
|
|
3259
|
+
readonly buttonStep: 10;
|
|
3260
|
+
/** The slider's snap. */
|
|
3261
|
+
readonly sliderStep: 5;
|
|
3262
|
+
};
|
|
3263
|
+
type ChartSymbolScales = Readonly<Record<ChartSymbolSize, number>>;
|
|
3264
|
+
declare const STANDARD_CHART_SYMBOL_SCALES: ChartSymbolScales;
|
|
3265
|
+
declare function clampChartSymbolScale(percent: number): number;
|
|
3266
|
+
/** A slider position → the stored percent: nearest 5, clamped. */
|
|
3267
|
+
declare function snapChartSymbolScale(value: number): number;
|
|
3268
|
+
/** One press of − or +, from wherever the value is (125 % − is 115 %). */
|
|
3269
|
+
declare function stepChartSymbolScale(percent: number, presses: number): number;
|
|
3270
|
+
/**
|
|
3271
|
+
* A stored or synced value. Unreadable → `null` (the caller's default);
|
|
3272
|
+
* out of range → clamped, so a newer client's wider range never reaches the
|
|
3273
|
+
* renderer raw. A string must be a whole number — "140", not "140%".
|
|
3274
|
+
*/
|
|
3275
|
+
declare function decodeChartSymbolScale(raw: unknown): number | null;
|
|
3276
|
+
/** Text that names a place or a feature on LAND. */
|
|
3277
|
+
declare const LAND_TEXT_CLASSES: ReadonlySet<string>;
|
|
3278
|
+
/**
|
|
3279
|
+
* Text that names WATER, or states a clearance over it. LAKARE, RIVERS and
|
|
3280
|
+
* CANALS are here though CHRT files them under "Land": the label is the name
|
|
3281
|
+
* of water. SOUNDG and DEPCNT left for DEPTH NUMBERS (owner, 2026-10-05).
|
|
3282
|
+
*/
|
|
3283
|
+
declare const WATER_TEXT_CLASSES: ReadonlySet<string>;
|
|
3284
|
+
/**
|
|
3285
|
+
* Text that belongs to a charted point symbol — it follows CHART ICONS so it
|
|
3286
|
+
* keeps its em offset from the symbol it annotates.
|
|
3287
|
+
*/
|
|
3288
|
+
declare const SYMBOL_ANNOTATION_TEXT_CLASSES: ReadonlySet<string>;
|
|
3289
|
+
/** CHRT's hazard label band. Enlarged text in it is never dropped (rule 3). */
|
|
3290
|
+
declare const HAZARD_LABEL_PRIORITY = 100;
|
|
3291
|
+
/**
|
|
3292
|
+
* The depth figures — DEPTH NUMBERS' text. The labels the depth-unit switch
|
|
3293
|
+
* converts (`buildLabelLayer`): a sounding, a contour value, the depth beside a
|
|
3294
|
+
* rock, wreck or obstruction (that class's ICON stays CHART ICONS'). Not the
|
|
3295
|
+
* dredged-channel note: it is a sentence.
|
|
3296
|
+
*/
|
|
3297
|
+
declare const DEPTH_FIGURE_CLASSES: ReadonlySet<string>;
|
|
3298
|
+
/**
|
|
3299
|
+
* Contour values grow at half DEPTH NUMBERS' rate: a contour value rides its
|
|
3300
|
+
* line and needs a straight-enough run to fit, and shares rank 300 with the
|
|
3301
|
+
* soundings, which place first. 0.10.3's Large drew them 1.2x when it drew the
|
|
3302
|
+
* soundings 1.4x, for that reason; this is the same ratio as a slider.
|
|
3303
|
+
*/
|
|
3304
|
+
declare function contourValueFactor(depthNumbersFactor: number): number;
|
|
3305
|
+
/**
|
|
3306
|
+
* The font stacks a CHRT glyph host serves (`cloudflare/tile-worker/glyphs/
|
|
3307
|
+
* GLYPHS.json`; the test pins this copy to it). There is no Bold.
|
|
3308
|
+
*/
|
|
3309
|
+
declare const SERVED_FONT_STACKS: readonly string[];
|
|
3310
|
+
/**
|
|
3311
|
+
* Rule A: the served font stack with each Regular face swapped for its
|
|
3312
|
+
* Semibold — DERIVED from the served name, not typed, as CHRTKit does, so a
|
|
3313
|
+
* family that changes its face is followed rather than overridden. A swap
|
|
3314
|
+
* that would ask for a face no glyph host serves is refused (the face stays
|
|
3315
|
+
* Regular), as CHRTKit's `servedFontStacks` does. Semibold and Italic faces
|
|
3316
|
+
* are left as served (soundings are already Semibold, so A changes the
|
|
3317
|
+
* contour values and the three callouts). Anything that is not a plain list
|
|
3318
|
+
* of names — absent, or an expression — is returned untouched.
|
|
3319
|
+
*/
|
|
3320
|
+
declare function semiboldFontStack(font: unknown): unknown;
|
|
3321
|
+
/** The slider a layer's TEXT follows, or null (stays at 100 %, counted). */
|
|
3322
|
+
declare function textSliderFor(layer: StyleLayer): ChartSymbolSize | null;
|
|
3323
|
+
/** The slider a layer's ICON follows: every chart point symbol, no basemap one. */
|
|
3324
|
+
declare function iconSliderFor(layer: StyleLayer): ChartSymbolSize | null;
|
|
3325
|
+
/**
|
|
3326
|
+
* `value` × `factor`, keeping its zoom structure: the factor goes onto every
|
|
3327
|
+
* stop's OUTPUT, because MapLibre accepts `["zoom"]` only as the input of a
|
|
3328
|
+
* TOP-LEVEL `interpolate`/`step`. `null` for a shape this does not recognise —
|
|
3329
|
+
* the caller leaves that property at its served size rather than guess.
|
|
3330
|
+
* `undefined` (absent) is the renderer default × factor.
|
|
3331
|
+
*/
|
|
3332
|
+
declare function scaleSizeExpression(value: unknown, factor: number, fallback: number): unknown;
|
|
3333
|
+
/** Rule B: a halo grows half as fast as its glyph, and only above 100 %. */
|
|
3334
|
+
declare function haloFactor(factor: number): number;
|
|
3335
|
+
/**
|
|
3336
|
+
* CHRT's sounding collision padding, px (`labels.ts`). Read from the generated
|
|
3337
|
+
* layer where it is a number; this is the fallback and the test's anchor.
|
|
3338
|
+
*/
|
|
3339
|
+
declare const SERVED_SOUNDING_PADDING_PX = 6;
|
|
3340
|
+
/**
|
|
3341
|
+
* Rule C: px of padding taken off per unit of factor above 1. 6.25 puts 140 %
|
|
3342
|
+
* at 3.5 px — the value the chip-68 sweep chose — and reaches 0 at 196 %.
|
|
3343
|
+
* DEPTH NUMBERS alone (no rule 4) holds the soundings count to −9 % … +7 % of
|
|
3344
|
+
* the served chart across 120–200 %, z11.5–15 (bench, Boston, DAY, 1280×800 at
|
|
3345
|
+
* 1×; −9 % is z14 at 200 %). `.chrt/standards/s-52.md` §8a has the figures.
|
|
3346
|
+
*/
|
|
3347
|
+
declare const SOUNDING_PADDING_PER_FACTOR = 6.25;
|
|
3348
|
+
/** Rule C: the sounding padding at a DEPTH NUMBERS factor. */
|
|
3349
|
+
declare function soundingPadding(factor: number, served?: number): number;
|
|
3350
|
+
/** MapLibre's `text-padding` when a layer sets none. */
|
|
3351
|
+
declare const MAPLIBRE_DEFAULT_TEXT_PADDING_PX = 2;
|
|
3352
|
+
/**
|
|
3353
|
+
* Rule C on whatever the served `text-padding` is, as CHRTKit's
|
|
3354
|
+
* `ChartDepthFigureRules.soundingPadding` does: absent is MapLibre's 2 px; a
|
|
3355
|
+
* number is reduced; a zoom `interpolate` or `step` has each OUTPUT reduced;
|
|
3356
|
+
* any other shape is left as served. At or below 100 % it is the served value.
|
|
3357
|
+
*/
|
|
3358
|
+
declare function soundingPaddingValue(served: unknown, factor: number): unknown;
|
|
3359
|
+
/**
|
|
3360
|
+
* What the labels above the soundings do when LAND LABELS, WATER LABELS or
|
|
3361
|
+
* CHART ICONS leaves 100 % (the header's rule 4 and THE ZOOM SPLIT). CHRTKit's
|
|
3362
|
+
* `ChartSoundingsRule`, the two cases this client ships.
|
|
3363
|
+
*/
|
|
3364
|
+
type ChartSoundingsRule = {
|
|
3365
|
+
readonly kind: "outrankLabels";
|
|
3366
|
+
} | {
|
|
3367
|
+
readonly kind: "zoomSplit";
|
|
3368
|
+
readonly harbourFrom: number;
|
|
3369
|
+
readonly splitLights?: boolean;
|
|
3370
|
+
};
|
|
3371
|
+
/** Rule 4 as iOS first shipped it: every text label above the soundings yields. */
|
|
3372
|
+
declare const OUTRANK_LABELS: ChartSoundingsRule;
|
|
3373
|
+
/** The rule in force — the owner's split at zoom 14 (2026-10-06), CHRTKit's default. */
|
|
3374
|
+
declare const CHART_SOUNDINGS_RULE: ChartSoundingsRule;
|
|
3375
|
+
/**
|
|
3376
|
+
* Whether a label stays above the soundings under the zoom split: label band
|
|
3377
|
+
* 100 (hazard text), the CHRTland and CHRT_BASE labels, and sea-area, island
|
|
3378
|
+
* and land-region names. With `splittingLights`, light characteristics are
|
|
3379
|
+
* split like the buoy names despite being band 100 (measured, not shipped).
|
|
3380
|
+
*/
|
|
3381
|
+
declare function keptAboveSoundings(layer: StyleLayer, splittingLights?: boolean): boolean;
|
|
3382
|
+
/** `value` below zoom `z`, `true` from it — CHRTKit `fromZoom`. Absent is MapLibre's `false`. */
|
|
3383
|
+
declare function fromZoom(z: number, value: unknown): unknown[];
|
|
3384
|
+
/**
|
|
3385
|
+
* One generated layer at a set of scales. Returns the SAME object when nothing
|
|
3386
|
+
* reaches it (100 %, unclassified, not a symbol layer, or a size this cannot
|
|
3387
|
+
* multiply), so a standard chart is the generated chart, byte for byte.
|
|
3108
3388
|
*
|
|
3109
|
-
*
|
|
3389
|
+
* `yieldText` is rule 4, decided by the caller from the layer's position: the
|
|
3390
|
+
* layer is a label placed before the soundings, and some label slider is off
|
|
3391
|
+
* 100 %. Its text then takes no part in placement, whatever its own size.
|
|
3110
3392
|
*/
|
|
3111
|
-
declare function
|
|
3393
|
+
declare function applyChartSymbolScalesToLayer(layer: StyleLayer, scales: ChartSymbolScales, yieldText?: boolean): StyleLayer;
|
|
3112
3394
|
/**
|
|
3113
|
-
*
|
|
3114
|
-
*
|
|
3115
|
-
*
|
|
3395
|
+
* Every layer of a generated style at a set of scales, in draw order — rule 4
|
|
3396
|
+
* reads the order (MapLibre places the TOP of the style first, so "above the
|
|
3397
|
+
* soundings" is "placed before them"). Standard → the same array.
|
|
3116
3398
|
*/
|
|
3117
|
-
declare function
|
|
3399
|
+
declare function applyChartSymbolScales<L extends StyleLayer>(layers: readonly L[], scales: ChartSymbolScales | undefined, rule?: ChartSoundingsRule): L[];
|
|
3118
3400
|
/**
|
|
3119
|
-
*
|
|
3120
|
-
*
|
|
3121
|
-
*
|
|
3401
|
+
* The text labels the zoom split moves below the soundings at these scales,
|
|
3402
|
+
* in draw order — empty when nothing triggers the split
|
|
3403
|
+
* (`labelSlidersOffStandard`: LAND / WATER / DEPTH / ICONS off 100 %, either
|
|
3404
|
+
* way) or the rule does not split. For a client that reorders a live map.
|
|
3122
3405
|
*/
|
|
3123
|
-
declare function
|
|
3406
|
+
declare function demotedBelowSoundings(layers: readonly StyleLayer[], scales: ChartSymbolScales | undefined, rule?: ChartSoundingsRule): string[];
|
|
3124
3407
|
/**
|
|
3125
|
-
*
|
|
3126
|
-
*
|
|
3127
|
-
*
|
|
3408
|
+
* What no slider reaches, and what a slider reaches but cannot multiply —
|
|
3409
|
+
* iOS's `unclassified` / `unscalable`, for a test that fails when CHRT adds a
|
|
3410
|
+
* label class nobody has decided about.
|
|
3128
3411
|
*/
|
|
3129
|
-
declare function
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
textField: ExpressionSpecification | string;
|
|
3135
|
-
/** Text size in pixels */
|
|
3136
|
-
textSize: number | ExpressionSpecification;
|
|
3137
|
-
/** Text color (hex) or data-driven expression */
|
|
3138
|
-
textColor: string | ExpressionSpecification;
|
|
3139
|
-
/** Halo color for contrast */
|
|
3140
|
-
textHaloColor: string;
|
|
3141
|
-
/** Halo width — pixels or zoom-interpolation expression */
|
|
3142
|
-
textHaloWidth: number | ExpressionSpecification;
|
|
3143
|
-
/** Text offset [x, y] in ems */
|
|
3144
|
-
textOffset: [number, number];
|
|
3145
|
-
/** Font stack */
|
|
3146
|
-
textFont?: string[];
|
|
3147
|
-
/** Additional layout properties */
|
|
3148
|
-
layout?: Record<string, unknown>;
|
|
3149
|
-
/** Minimum zoom level for this label */
|
|
3150
|
-
minzoom?: number;
|
|
3151
|
-
}
|
|
3412
|
+
declare function chartSymbolSizingCensus(layers: readonly StyleLayer[]): {
|
|
3413
|
+
unclassified: string[];
|
|
3414
|
+
unscalable: string[];
|
|
3415
|
+
};
|
|
3416
|
+
|
|
3152
3417
|
/**
|
|
3153
|
-
*
|
|
3418
|
+
* Dominance fan-out collapse (P8 Phase 3.3 / D4 "axis 1").
|
|
3154
3419
|
*
|
|
3155
|
-
*
|
|
3156
|
-
*
|
|
3157
|
-
*
|
|
3420
|
+
* `makeBandVariants()` historically emitted, per (class, band): one
|
|
3421
|
+
* "not-dominated" layer plus up to five `-domBy{D}` copies that differ ONLY
|
|
3422
|
+
* in their dominance filter and a `maxzoom` of `dominatedVariantMaxzoom(D)`.
|
|
3423
|
+
* That fan existed because MapLibre filters could not read `["zoom"]`. They
|
|
3424
|
+
* can now (style-spec 24.8.5; buckets evaluate at the tile's `overscaledZ`),
|
|
3425
|
+
* so the whole fan folds into ONE layer per (class, band) whose filter
|
|
3426
|
+
* carries the zoom gate.
|
|
3427
|
+
*
|
|
3428
|
+
* **Construction principle — read before changing anything here.** The
|
|
3429
|
+
* collapsed filter is the literal `["any"]` UNION of the clauses the fan
|
|
3430
|
+
* already encoded: every variant the legacy emitter would have produced
|
|
3431
|
+
* contributes exactly one `["all", <its dominance filter>, ["<", ["zoom"],
|
|
3432
|
+
* <its maxzoom>]]` clause, and the dead-variant skip is mirrored too.
|
|
3433
|
+
* Equivalence is therefore *structural*, not re-derived — which matters,
|
|
3434
|
+
* because the two "obvious" hand-written forms are both wrong:
|
|
3435
|
+
*
|
|
3436
|
+
* 1. A `["match", ["get","_dominated_by_min"], 2,5, 3,7, 4,9, 5,11, 6,11, 24]`
|
|
3437
|
+
* threshold (the form the design doc proposed) uses band 6's *eligibility*
|
|
3438
|
+
* zoom 11. The real ceiling is `dominatedVariantMaxzoom("6") = 13` — band
|
|
3439
|
+
* 6's DATA floor. Using 11 reopens the z11–z12 void window that
|
|
3440
|
+
* `band-priority.ts` documents closing.
|
|
3441
|
+
* 2. That same form silently drops the legacy `_dominated: true` boolean,
|
|
3442
|
+
* which `dominatedByMinFilter("6")` still honours. A legacy-tagged feature
|
|
3443
|
+
* has no `_dominated_by_min`, so `match` falls to its default and the
|
|
3444
|
+
* feature renders FOREVER instead of dropping at z13.
|
|
3445
|
+
*
|
|
3446
|
+
* Deriving the gate from the emitter's own clauses avoids both by construction.
|
|
3447
|
+
* `band-collapse.test.ts` re-proves it on every CI run by differentially
|
|
3448
|
+
* evaluating legacy-vs-collapsed through MapLibre's real three gates.
|
|
3449
|
+
*
|
|
3450
|
+
* **Scope.** For FEATURE layers (fills, lines, feature symbols) this is
|
|
3451
|
+
* axis 1 ONLY: the per-band layers survive, with identical ids and identical
|
|
3452
|
+
* positions, so the band-major draw order is untouched. "Axis 2" (collapsing
|
|
3453
|
+
* the per-band copies into one layer per class) was evaluated and **KILLED**
|
|
3454
|
+
* for feature layers — it is unsound for the opaque-fill classes
|
|
3455
|
+
* (`DOMINANCE_EXEMPT_FILL_CLASSES` ≡ `OPAQUE_FILL_LAYERS`), where band-major
|
|
3456
|
+
* order is the ONLY thing separating the bands, and 15/15 class pairs are
|
|
3457
|
+
* provably unsatisfiable with one layer each. Do not reintroduce it there.
|
|
3458
|
+
* Evidence: `.chrt/perf/2026-07-14-p8-d4-spike.md`.
|
|
3459
|
+
*
|
|
3460
|
+
* LABEL layers are different (CHRTsail #121 — MapLibre Native iOS silently
|
|
3461
|
+
* collapses its whole render pass above 482 symbol layers, and the served
|
|
3462
|
+
* style carried 575): `makeCollapsedCrossBandLabel` folds a label's ×6 band
|
|
3463
|
+
* fan into ONE layer per class, and `collapsedOrientationGate` folds the
|
|
3464
|
+
* orientation fan's per-dominator variants into its per-cell layers. That is
|
|
3465
|
+
* NOT the killed axis 2, because what the fill argument protects — paint
|
|
3466
|
+
* order as the sole band separator — does not apply to labels: their
|
|
3467
|
+
* load-bearing order is the cross-class P4 priority ladder (each class keeps
|
|
3468
|
+
* exactly one layer in its ladder slot), and within-class placement priority
|
|
3469
|
+
* rides the `rank*1000 + within-key` symbol-sort-key that labels.ts
|
|
3470
|
+
* documents as designed to survive precisely this merge.
|
|
3471
|
+
*
|
|
3472
|
+
* **Load-bearing invariant.** A collapsed per-band FEATURE layer MUST keep
|
|
3473
|
+
* the `-band{B}` id segment: `custom-style.ts` `bandFloor()` parses
|
|
3474
|
+
* `/-band(\d)/` to clamp customer minzoom/scamin overrides to the band's
|
|
3475
|
+
* data floor, on the live public Style API path. Renaming the id silently
|
|
3476
|
+
* unclamps those overrides. Cross-band LABEL layers are the deliberate
|
|
3477
|
+
* exception: they carry every band floor INSIDE the filter (tile-zoom
|
|
3478
|
+
* clauses a customer override cannot touch), which supersedes the clamp —
|
|
3479
|
+
* `bandFloor()` returning 0 for a bare label id is correct, not a gap.
|
|
3480
|
+
* Both halves asserted in `band-collapse.test.ts`.
|
|
3158
3481
|
*/
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3482
|
+
|
|
3483
|
+
/**
|
|
3484
|
+
* Which emitter the style generator uses for the dominance fan.
|
|
3485
|
+
* `"legacy"` exists so CI can differentially prove the two equivalent (it is
|
|
3486
|
+
* the oracle in `band-collapse.test.ts`) and as a one-line rollback. It is an
|
|
3487
|
+
* internal knob — deliberately NOT on the exported `StyleGeneratorOptions`,
|
|
3488
|
+
* so it cannot reach `@chrtco/sdk` consumers via `ChrtStyleOptions`.
|
|
3489
|
+
*/
|
|
3490
|
+
type BandFanMode = "collapsed" | "legacy";
|
|
3491
|
+
|
|
3492
|
+
/**
|
|
3493
|
+
* Generates a complete Mapbox GL Style Specification v8 JSON
|
|
3494
|
+
* from the S-52 atlas definitions.
|
|
3495
|
+
*/
|
|
3496
|
+
|
|
3497
|
+
interface MapboxStyle {
|
|
3498
|
+
version: 8;
|
|
3499
|
+
name: string;
|
|
3500
|
+
metadata: Record<string, unknown>;
|
|
3501
|
+
sources: Record<string, unknown>;
|
|
3502
|
+
sprite?: string;
|
|
3503
|
+
glyphs: string;
|
|
3504
|
+
layers: StyleLayer[];
|
|
3505
|
+
}
|
|
3506
|
+
interface StyleGeneratorOptions extends BuildSourcesOptions {
|
|
3162
3507
|
/**
|
|
3163
|
-
*
|
|
3164
|
-
*
|
|
3165
|
-
*
|
|
3508
|
+
* When set, emit a "paper chart" style centered on the selected scale
|
|
3509
|
+
* band, with graceful coverage fallback: the requested band's layers
|
|
3510
|
+
* draw on top where its cells have data; coarser bands (driven by
|
|
3511
|
+
* `CHART_CASCADE_CODES`) fill gaps where the requested band has no
|
|
3512
|
+
* cells. Per-feature SCAMIN minzooms are preserved on every cascade
|
|
3513
|
+
* variant; `maxzoom` is dropped so the user can zoom in indefinitely.
|
|
3514
|
+
*
|
|
3515
|
+
* When omitted (default), continuous mode emits one layer copy per
|
|
3516
|
+
* source band with strict per-band zoom windows so exactly one band
|
|
3517
|
+
* renders at any given continuous zoom.
|
|
3518
|
+
*
|
|
3519
|
+
* `lockedBounds` (optional) restricts chart-mode rendering to a
|
|
3520
|
+
* specific bbox via a `["within"]` filter — applied ONLY to the
|
|
3521
|
+
* requested band's variants. Cascade fallback bands render across the
|
|
3522
|
+
* full viewport so a chart-Harbor user panning offshore still sees
|
|
3523
|
+
* Approach/Coastal data. The frontend pairs this with a translucent
|
|
3524
|
+
* grey overlay outside the bbox so the lock boundary is still visible
|
|
3525
|
+
* to the user (the fallback data is dimmed by the overlay but not
|
|
3526
|
+
* filtered out).
|
|
3527
|
+
*/
|
|
3528
|
+
chartMode?: {
|
|
3529
|
+
band: ScaleBand$1;
|
|
3530
|
+
lockedBounds?: BBox;
|
|
3531
|
+
};
|
|
3532
|
+
/**
|
|
3533
|
+
* Display unit for depth labels (SOUNDG soundings, DEPCNT contour
|
|
3534
|
+
* values). Source data is always meters (S-57 / VALSOU / VALDCO);
|
|
3535
|
+
* "feet" wraps the text-field expression with a unit conversion +
|
|
3536
|
+
* round so the rendered numbers match. Default "meters".
|
|
3537
|
+
*/
|
|
3538
|
+
depthUnits?: "meters" | "feet";
|
|
3539
|
+
/**
|
|
3540
|
+
* Which symbol artwork the style references. "s52" (default) uses the
|
|
3541
|
+
* PresLib-derived S-52 set; "s101" rewrites icon references to the
|
|
3542
|
+
* official S-101 Portrayal Catalogue symbols (s101: image namespace)
|
|
3543
|
+
* where a counterpart exists — see s101-style.ts. "chrt" applies the
|
|
3544
|
+
* CHRT house ATON/LIGHTS glyphs with colour-true tinting — see
|
|
3545
|
+
* chrt-style.ts. Selection logic differences are documented per module.
|
|
3546
|
+
*/
|
|
3547
|
+
symbolSet?: "s52" | "s101" | "chrt" | "raster";
|
|
3548
|
+
/**
|
|
3549
|
+
* The mariner's safety contour in metres — the depth below which a
|
|
3550
|
+
* feature is "dangerous to my hull". Drives both safety-contour
|
|
3551
|
+
* conditional symbology rules:
|
|
3552
|
+
*
|
|
3553
|
+
* - §SOUNDG02 — soundings shoaler than this render in the
|
|
3554
|
+
* high-contrast color; deeper soundings render in the muted color.
|
|
3555
|
+
* - §CSYM02 — isolated dangers (rocks / wrecks / obstructions)
|
|
3556
|
+
* shoaler than this get the DNGCIR01 danger ring.
|
|
3557
|
+
*
|
|
3558
|
+
* Default `DEFAULT_SAFETY_CONTOUR_M` (10 m).
|
|
3559
|
+
*
|
|
3560
|
+
* Does not affect the DEPARE depth-area shading, whose 2/5/10 m bands
|
|
3561
|
+
* are a separate S-52 concept.
|
|
3166
3562
|
*/
|
|
3167
3563
|
safetyContour?: number;
|
|
3168
3564
|
/**
|
|
3169
|
-
* When false, all soundings render in
|
|
3170
|
-
* true — emit the safety-contour case expression.
|
|
3565
|
+
* When false, all soundings render in a single shade. Default true.
|
|
3171
3566
|
*/
|
|
3172
3567
|
twoShadeSoundings?: boolean;
|
|
3173
3568
|
/**
|
|
3174
|
-
*
|
|
3175
|
-
*
|
|
3569
|
+
* Label model for the 9 orientation place-name classes (SEAARE, LNDRGN,
|
|
3570
|
+
* LAKARE, RIVERS, CANALS, BUAARE, AIRARE, LNDARE, PRDARE).
|
|
3571
|
+
*
|
|
3572
|
+
* "legacy" (default) — the per-cell-band orientation fan
|
|
3573
|
+
* (fanOrientationLabelByCellBand): one label per feature per band,
|
|
3574
|
+
* deconflicted only by `_label_anchor` tags and watermark opacity.
|
|
3575
|
+
*
|
|
3576
|
+
* "placename" — 2 PLACENAME symbol layers over the build-side
|
|
3577
|
+
* place-name index (CHRTbaremetal placeNameIndex.ts): one collision-
|
|
3578
|
+
* managed label per named place with a per-feature zoom window; the
|
|
3579
|
+
* orientation fan for those classes is NOT emitted. Requires tiles
|
|
3580
|
+
* built with the PLACENAME side index — on older tiles the layers
|
|
3581
|
+
* simply draw nothing (soft-fail is index-side), which is why the
|
|
3582
|
+
* default stays "legacy" until L2c's rebuild + Maine-coast visual
|
|
3583
|
+
* verification flips it (docs/design/chart-label-deconfliction.md
|
|
3584
|
+
* §2.3). Feature-label classes are untouched either way.
|
|
3585
|
+
*/
|
|
3586
|
+
labels?: "legacy" | "placename";
|
|
3587
|
+
/**
|
|
3588
|
+
* Font weight for SOUNDG labels. Default "semibold" — crisper numerals
|
|
3589
|
+
* at small sizes on screen.
|
|
3176
3590
|
*/
|
|
3177
3591
|
soundingFontWeight?: "regular" | "semibold";
|
|
3592
|
+
/**
|
|
3593
|
+
* CHART SIZING — the five sliders, in percent (50–200; `waypoints` is the
|
|
3594
|
+
* app's and is ignored here). Omitted, or every value 100, is byte-identical
|
|
3595
|
+
* to the style without it. Applied LAST, after the symbol-family rewrite, so
|
|
3596
|
+
* it sizes what the chosen family draws. Never changes a label's text,
|
|
3597
|
+
* colours, sort key, filter, zoom gate or the layer set — see
|
|
3598
|
+
* chart-symbol-sizing.ts.
|
|
3599
|
+
*/
|
|
3600
|
+
symbolScales?: ChartSymbolScales;
|
|
3601
|
+
/**
|
|
3602
|
+
* What the labels above the soundings do when LAND, WATER or CHART ICONS is
|
|
3603
|
+
* off 100 %, or DEPTH NUMBERS either way — `CHART_SOUNDINGS_RULE` (the owner's zoom split at 14) when
|
|
3604
|
+
* omitted. Rule 4 (`OUTRANK_LABELS`) is kept for measurement.
|
|
3605
|
+
*/
|
|
3606
|
+
soundingsRule?: ChartSoundingsRule;
|
|
3178
3607
|
}
|
|
3608
|
+
declare function generateStyle(palette?: ColorTableName, opts?: StyleGeneratorOptions & {
|
|
3609
|
+
bandFan?: BandFanMode;
|
|
3610
|
+
}): MapboxStyle;
|
|
3611
|
+
declare function generateStyleJSON(palette?: ColorTableName, opts?: StyleGeneratorOptions): string;
|
|
3612
|
+
/** Get summary stats about the generated style */
|
|
3613
|
+
declare function getStyleStats(style: MapboxStyle): {
|
|
3614
|
+
totalLayers: number;
|
|
3615
|
+
fillLayers: number;
|
|
3616
|
+
lineLayers: number;
|
|
3617
|
+
symbolLayers: number;
|
|
3618
|
+
circleLayers: number;
|
|
3619
|
+
sources: number;
|
|
3620
|
+
objectClasses: Set<string>;
|
|
3621
|
+
};
|
|
3622
|
+
|
|
3179
3623
|
/**
|
|
3180
|
-
*
|
|
3181
|
-
*
|
|
3182
|
-
*
|
|
3183
|
-
*
|
|
3184
|
-
*
|
|
3185
|
-
*
|
|
3186
|
-
*
|
|
3187
|
-
*
|
|
3188
|
-
*
|
|
3189
|
-
*
|
|
3190
|
-
*
|
|
3191
|
-
*
|
|
3192
|
-
*
|
|
3193
|
-
*
|
|
3194
|
-
*
|
|
3624
|
+
* The e-ink portrayal pass — what `EINK_COLOR`, `EINK_MONO` and `EINK_NIGHT`
|
|
3625
|
+
* change beyond their colour tables. Night is mono inverted: everything below
|
|
3626
|
+
* applies, the patterns and safety contour are drawn LIGHT (the patterns are
|
|
3627
|
+
* themed per palette, the contour takes the table's DEPSC), and the chart
|
|
3628
|
+
* background gets the no-coverage crosshatch, because a black no-data hole
|
|
3629
|
+
* on a black-water page would read as deep water.
|
|
3630
|
+
*
|
|
3631
|
+
* A colour table can only move colours. E-paper needs more than that (owner
|
|
3632
|
+
* decision 2026-10-05: CHRT serves the e-ink chart, clients never recolour it;
|
|
3633
|
+
* requirements in CHRTsail's e-ink product spec §3c):
|
|
3634
|
+
*
|
|
3635
|
+
* 1. MEANING UNCHANGED. Nothing here adds, removes or reorders a feature
|
|
3636
|
+
* class or changes a filter that decides WHICH features draw. It changes
|
|
3637
|
+
* how they look, and adds two kinds of OVERLAY layer (depth patterns,
|
|
3638
|
+
* the safety contour) that draw features the chart already draws.
|
|
3639
|
+
* 2. MONO STANDS ON ITS OWN. Depth steps become fill PATTERNS (mono only);
|
|
3640
|
+
* danger areas get a cross-hatch; the safety contour gets its own heavy
|
|
3641
|
+
* line; restricted/caution areas keep their dashes, now heavier.
|
|
3642
|
+
* 3. DEPTH IN AT MOST FOUR STEPS. The tables do the colour side (DEPMD ==
|
|
3643
|
+
* DEPDW). Mono shows three: drying (hatch), shallower than the safety
|
|
3644
|
+
* contour (stipple), safe (paper).
|
|
3645
|
+
* 4. SAFETY CONTOUR AND DANGERS EMPHASISED: a heavy black safety-contour
|
|
3646
|
+
* line; danger symbols drawn larger; danger areas cross-hatched.
|
|
3647
|
+
* 5. COVERAGE PORTRAYAL SURVIVES: the no-coverage crosshatch goes to full
|
|
3648
|
+
* strength rather than being dropped with the other translucency.
|
|
3649
|
+
* 6. ATTRIBUTION/CURRENCY METADATA: untouched — this pass never edits
|
|
3650
|
+
* `sources` or the metadata other than adding `chrt:eink`.
|
|
3651
|
+
* 7. SIZES FOR 150 ppi COLOUR / 300 ppi MONO: every line ×1.5 (min 1 px),
|
|
3652
|
+
* text ×1.15 with a solid paper halo, no translucency, no blur, no fades.
|
|
3653
|
+
*
|
|
3654
|
+
* Translucency is the thing e-paper cannot draw: a 10% magenta wash over pale
|
|
3655
|
+
* blue is a fifth grey in mono and nothing at all on Kaleido 3. So faint washes
|
|
3656
|
+
* (< 0.3) are dropped — every one of them is a CHRT addition over a feature
|
|
3657
|
+
* whose boundary and symbol S-52 already draws — and stronger ones are made
|
|
3658
|
+
* solid.
|
|
3659
|
+
*
|
|
3660
|
+
* Pure: takes a generated style, returns a new one. `generateStyle` applies it
|
|
3661
|
+
* for the e-ink tables, so the served style, the offline style and the SDK's
|
|
3662
|
+
* local `generateStyle` all carry the same portrayal.
|
|
3195
3663
|
*/
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
declare
|
|
3664
|
+
|
|
3665
|
+
/** The three e-ink fill patterns (house glyphs, registered with the world hatches). */
|
|
3666
|
+
declare const EINK_DOTS_PATTERN = "chrt:eink-dots";
|
|
3667
|
+
declare const EINK_HATCH_PATTERN = "chrt:eink-hatch";
|
|
3668
|
+
declare const EINK_DANGER_PATTERN = "chrt:eink-danger";
|
|
3669
|
+
/** The VALDCO values that ARE the safety contour, one per ladder. */
|
|
3670
|
+
declare function safetyContourValues(safetyContourM: number): number[];
|
|
3671
|
+
interface EinkPortrayalOptions {
|
|
3672
|
+
/** The mariner's safety contour, metres — the same value the generator used. */
|
|
3673
|
+
safetyContour?: number;
|
|
3674
|
+
}
|
|
3200
3675
|
/**
|
|
3201
|
-
*
|
|
3202
|
-
*
|
|
3203
|
-
* per-mechanism patches (SAFETY_CRITICAL_LABELS allow-overlap, the
|
|
3204
|
-
* band-5/6-only Harbor collision discipline) into one explicit ranking.
|
|
3205
|
-
*
|
|
3206
|
-
* Rank semantics: LOWER rank = higher priority. The rank drives two
|
|
3207
|
-
* mechanisms that must stay in agreement:
|
|
3208
|
-
*
|
|
3209
|
-
* 1. `symbol-sort-key` — every feature label carries
|
|
3210
|
-
* `rank*1000 + within-class-key`, so if label layers are ever merged
|
|
3211
|
-
* (the P8 style fan-out reduction), placement priority survives the
|
|
3212
|
-
* merge unchanged.
|
|
3213
|
-
* 2. Label LAYER ORDER — MapLibre places symbols topmost-layer-first, so
|
|
3214
|
-
* `style-generator.ts` emits feature-label layers lowest-priority
|
|
3215
|
-
* first: safety-critical classes end up topmost and claim collision
|
|
3216
|
-
* space before anything else. (`symbol-sort-key` alone cannot do
|
|
3217
|
-
* this — it only orders placement WITHIN a layer.)
|
|
3218
|
-
*
|
|
3219
|
-
* The ladder (safety-critical > nav-aids > depth field > structures >
|
|
3220
|
-
* ambient notes):
|
|
3221
|
-
*
|
|
3222
|
-
* 100 — Safety-critical: light characteristics (LIGHTS), hazard depth
|
|
3223
|
-
* callouts (UWTROC/OBSTRN/WRECKS VALSOU), overhead clearances
|
|
3224
|
-
* (CBLOHD/PIPOHD VERCLR). Irreducible mariner-safety text.
|
|
3225
|
-
* 200 — Nav-aid designations: buoy / beacon `R "4"` labels.
|
|
3226
|
-
* 250 — Auxiliary nav-aid info: fog signal type (FOGSIG).
|
|
3227
|
-
* 300 — Depth field: soundings, contour values. Individually droppable —
|
|
3228
|
-
* a hidden sounding has visible neighbors.
|
|
3229
|
-
* 400 — Structures: bridges, landmarks, piers, moorings, buildings.
|
|
3230
|
-
* 500 — Ambient annotation: seabed nature, magnetic variation, kelp.
|
|
3231
|
-
* 900 — Orientation names (SEAARE etc.) — not part of this ladder;
|
|
3232
|
-
* they keep their settled watermark model (cell-band fan +
|
|
3233
|
-
* dominance composition + `orientationLabelLayout`) and always
|
|
3234
|
-
* paint underneath feature labels.
|
|
3235
|
-
*
|
|
3236
|
-
* Safety guardrail: a lower rung never blocks a higher rung — placement
|
|
3237
|
-
* order guarantees the safety-critical label got the space first. Density
|
|
3238
|
-
* relief comes from dropping the LOWEST rung in a pile-up, never the top.
|
|
3239
|
-
*/
|
|
3240
|
-
declare const LABEL_PRIORITY: Record<string, number>;
|
|
3241
|
-
/**
|
|
3242
|
-
* Resolve the priority rank for an S-57 class's label. Orientation classes
|
|
3243
|
-
* report 900 regardless of ladder membership (PRDARE etc.) so the
|
|
3244
|
-
* layer-order sort in style-generator.ts can treat priority uniformly.
|
|
3245
|
-
*/
|
|
3246
|
-
declare function getLabelPriority(layerName: string): number;
|
|
3247
|
-
/**
|
|
3248
|
-
* Compose a `symbol-sort-key` from a class rank and an optional
|
|
3249
|
-
* within-class key expression. The within-class key is clamped to
|
|
3250
|
-
* [0, 999] so it can never bleed into a neighboring rank's band.
|
|
3676
|
+
* Apply the e-ink portrayal for `palette`. Returns the style unchanged for a
|
|
3677
|
+
* non-e-ink palette, so a caller may apply it unconditionally.
|
|
3251
3678
|
*/
|
|
3252
|
-
declare function
|
|
3679
|
+
declare function applyEinkPortrayal(style: MapboxStyle, palette: ColorTableName, opts?: EinkPortrayalOptions): MapboxStyle;
|
|
3680
|
+
|
|
3253
3681
|
/**
|
|
3254
|
-
*
|
|
3682
|
+
* Light arithmetic for the chart palettes: how much light a colour emits, and
|
|
3683
|
+
* how to dim a colour without changing its hue.
|
|
3255
3684
|
*
|
|
3256
|
-
*
|
|
3257
|
-
*
|
|
3258
|
-
*
|
|
3259
|
-
*
|
|
3685
|
+
* Everything here works in LINEAR light (WCAG 2.x relative luminance, sRGB
|
|
3686
|
+
* primaries). That is the quantity a dark-adapted eye responds to, and it is
|
|
3687
|
+
* the one `sounding-legibility.test.ts` already measures soundings in. Scaling
|
|
3688
|
+
* the sRGB-ENCODED channels instead would dim dark colours far more than
|
|
3689
|
+
* bright ones and shift every hue it touched.
|
|
3260
3690
|
*
|
|
3261
|
-
*
|
|
3262
|
-
*
|
|
3263
|
-
*
|
|
3691
|
+
* The one derivation the palettes rely on, and the reason this file exists:
|
|
3692
|
+
* NIGHT's deeper sounding SNDG1 (#897350) is SNDG2 (#c8aa78) at 43% of its
|
|
3693
|
+
* linear light. `labels.ts` builds its NIGHT secondary text the same way, so
|
|
3694
|
+
* the two stay one family by construction rather than by two hand-typed hexes
|
|
3695
|
+
* that happen to agree.
|
|
3264
3696
|
*/
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3697
|
+
/** WCAG 2.x relative luminance of a `#rrggbb` colour, 0 (black) to 1 (white). */
|
|
3698
|
+
declare function relativeLuminance(hex: string): number;
|
|
3699
|
+
/** WCAG 2.x contrast ratio between two `#rrggbb` colours, 1 to 21. */
|
|
3700
|
+
declare function contrastRatio(a: string, b: string): number;
|
|
3268
3701
|
/**
|
|
3269
|
-
*
|
|
3702
|
+
* The same hue at `factor` times its linear light. `factor` above 1 can clip a
|
|
3703
|
+
* channel, which shifts the hue; nothing in the palettes brightens, so callers
|
|
3704
|
+
* pass 0–1.
|
|
3270
3705
|
*/
|
|
3271
|
-
declare function
|
|
3272
|
-
textScale?: number;
|
|
3273
|
-
minzoom?: number | null;
|
|
3274
|
-
allowOverlap?: boolean;
|
|
3275
|
-
}): maplibregl.LayerSpecification;
|
|
3706
|
+
declare function scaleLinearLight(hex: string, factor: number): string;
|
|
3276
3707
|
/**
|
|
3277
|
-
*
|
|
3278
|
-
*
|
|
3279
|
-
* This explodes MultiPoints into individual Points with a `depth` property.
|
|
3708
|
+
* `hex` dimmed, hue kept, until its luminance is at most `ceiling`. A colour
|
|
3709
|
+
* already at or under the ceiling comes back unchanged (lower-cased).
|
|
3280
3710
|
*/
|
|
3281
|
-
declare function
|
|
3711
|
+
declare function capLuminance(hex: string, ceiling: number): string;
|
|
3282
3712
|
/**
|
|
3283
|
-
*
|
|
3284
|
-
* Adds `_lightLabel` property (e.g., "Fl(2) WR 4s 5M").
|
|
3713
|
+
* NIGHT's two ink levels, shared by every family's text and marks.
|
|
3285
3714
|
*
|
|
3286
|
-
*
|
|
3287
|
-
*
|
|
3288
|
-
*
|
|
3289
|
-
*
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
/**
|
|
3295
|
-
* Pre-process buoy/beacon GeoJSON to derive concise mariner-style labels.
|
|
3296
|
-
* Adds `_navAidLabel` property (e.g., 'R "8"', 'G "5"').
|
|
3297
|
-
*/
|
|
3298
|
-
declare function preprocessNavAids(fc: GeoJSON.FeatureCollection): GeoJSON.FeatureCollection;
|
|
3299
|
-
/** Check if a layer name needs nav aid preprocessing */
|
|
3300
|
-
declare function isNavAidLayer(layerName: string): boolean;
|
|
3301
|
-
/**
|
|
3302
|
-
* Pre-process water body polygon GeoJSON into centroid points for label placement.
|
|
3303
|
-
* Computes a simple average-coordinate centroid for each polygon feature that has OBJNAM.
|
|
3304
|
-
*/
|
|
3305
|
-
declare function preprocessWaterBodies(fc: GeoJSON.FeatureCollection): GeoJSON.FeatureCollection;
|
|
3306
|
-
/** MVT layer the build-side place-name index emits. */
|
|
3307
|
-
declare const PLACENAME_SOURCE_LAYER = "PLACENAME";
|
|
3308
|
-
/** Orientation classes whose names render italic (water voice). */
|
|
3309
|
-
declare const PLACENAME_WATER_CLASSES: readonly string[];
|
|
3310
|
-
/** Orientation classes whose names render upright (land voice). */
|
|
3311
|
-
declare const PLACENAME_LAND_CLASSES: readonly string[];
|
|
3312
|
-
/**
|
|
3313
|
-
* The 2 PLACENAME symbol layers. Layout contract (design §2.2): collision
|
|
3314
|
-
* ON (`allow-overlap: false`, `ignore-placement: false`,
|
|
3315
|
-
* `optional: true`), padding 4, `text-variable-anchor`, and
|
|
3316
|
-
* `symbol-sort-key` straight from the build-side `rank` — MapLibre places
|
|
3317
|
-
* LOWER sort keys first, and rank is minted lower-is-more-important
|
|
3318
|
-
* (tier major, bbox area minor), so when space runs out the biggest names
|
|
3319
|
-
* survive. That ranking is the per-zoom density governor P4 asked for.
|
|
3715
|
+
* `NIGHT_INK` S52_NIGHT.CHBLK — the palette's linework and navigation
|
|
3716
|
+
* text. The brightest thing NIGHT draws on purpose.
|
|
3717
|
+
* `NIGHT_MUTED_INK` that ink at 43% of its linear light, which is how
|
|
3718
|
+
* S52_NIGHT.SNDG1 (the deeper soundings) was derived.
|
|
3719
|
+
* Everything that orients rather than navigates is drawn
|
|
3720
|
+
* at or under this, and `night-luminance.test.ts` holds
|
|
3721
|
+
* every visible NIGHT colour to it unless an exemption
|
|
3722
|
+
* names a reason.
|
|
3320
3723
|
*/
|
|
3321
|
-
declare
|
|
3724
|
+
declare const NIGHT_INK: string;
|
|
3725
|
+
declare const NIGHT_MUTED_INK: string;
|
|
3322
3726
|
|
|
3323
3727
|
/**
|
|
3324
|
-
*
|
|
3325
|
-
* Thins dense GeoJSON feature sets by keeping only one representative
|
|
3326
|
-
* feature per grid cell per layer.
|
|
3327
|
-
*/
|
|
3328
|
-
interface DecimationOptions {
|
|
3329
|
-
/** Grid resolution (cells per axis). Default 80. */
|
|
3330
|
-
gridSize?: number;
|
|
3331
|
-
/** Zoom level below which decimation kicks in. Default 12. */
|
|
3332
|
-
zoomThreshold?: number;
|
|
3333
|
-
}
|
|
3334
|
-
/**
|
|
3335
|
-
* Zoom-adaptive grid resolution for decimation.
|
|
3336
|
-
*/
|
|
3337
|
-
declare function getGridSizeForZoom(zoom: number): number;
|
|
3338
|
-
/**
|
|
3339
|
-
* Decimate a GeoJSON FeatureCollection using spatial grid thinning.
|
|
3340
|
-
* Only runs when zoom < zoomThreshold. Returns the original FC otherwise.
|
|
3728
|
+
* Is this MapLibre map still there to be written to?
|
|
3341
3729
|
*
|
|
3342
|
-
*
|
|
3343
|
-
*
|
|
3344
|
-
*
|
|
3345
|
-
* @param bounds - Current viewport bounds
|
|
3346
|
-
* @param opts - Decimation options
|
|
3347
|
-
*/
|
|
3348
|
-
declare function decimateFeatures(fc: GeoJSON.FeatureCollection, layerName: string, currentZoom: number, bounds: {
|
|
3349
|
-
west: number;
|
|
3350
|
-
south: number;
|
|
3351
|
-
east: number;
|
|
3352
|
-
north: number;
|
|
3353
|
-
}, opts?: DecimationOptions): GeoJSON.FeatureCollection;
|
|
3354
|
-
/**
|
|
3355
|
-
* Get the max number of cells to load based on zoom level.
|
|
3356
|
-
*/
|
|
3357
|
-
declare function getMaxCellsForZoom(zoom: number): number;
|
|
3358
|
-
|
|
3359
|
-
/**
|
|
3360
|
-
* IHO S-52 / NOAA Chart No. 1 / INT1 nautical symbol SVGs.
|
|
3730
|
+
* ===========================================================================
|
|
3731
|
+
* ⚠ ASK AFTER EVERY AWAIT. A MAP CAN BE REMOVED WHILE YOU WERE WAITING.
|
|
3732
|
+
* ===========================================================================
|
|
3361
3733
|
*
|
|
3362
|
-
*
|
|
3363
|
-
*
|
|
3364
|
-
*
|
|
3365
|
-
*
|
|
3734
|
+
* `map.remove()` deletes `map.style`, and after that nearly every method that
|
|
3735
|
+
* touches the style throws rather than returning: `hasImage`, `addImage`,
|
|
3736
|
+
* `updateImage`, `getSource`, `addLayer` all fail with "Cannot read properties
|
|
3737
|
+
* of undefined (reading 'getImage')" and its siblings. Code that was handed a
|
|
3738
|
+
* map, awaited a decode, an IndexedDB read or a fetch, and then wrote to the
|
|
3739
|
+
* map, throws from wherever it resumed — usually a promise nobody is awaiting,
|
|
3740
|
+
* so the throw is an uncaught error with no caller to explain it.
|
|
3366
3741
|
*
|
|
3367
|
-
*
|
|
3368
|
-
*
|
|
3369
|
-
*
|
|
3370
|
-
* - PILLAR: Tall narrow buoy — used for cardinal, isolated danger, etc.
|
|
3371
|
-
* - SPAR: Tall thin pole buoy
|
|
3372
|
-
* - SPHERICAL: Round buoy — safe water marks
|
|
3373
|
-
* - BARREL: Barrel/tun shaped buoy
|
|
3374
|
-
* - SUPER: Large navigation buoy / LANBY
|
|
3742
|
+
* Measured in CHRTdesktop (chip 63, 2026-10-04): with the page's main thread
|
|
3743
|
+
* held at 6× CPU, the chart removed its map in the middle of a pan, and the
|
|
3744
|
+
* S-52 image loader resumed onto it:
|
|
3375
3745
|
*
|
|
3376
|
-
*
|
|
3377
|
-
*
|
|
3378
|
-
*
|
|
3379
|
-
* - East: cones base-to-base (diamond) ◆
|
|
3380
|
-
* - West: cones point-to-point (hourglass) ⊗
|
|
3746
|
+
* TypeError: Cannot read properties of undefined (reading 'getImage')
|
|
3747
|
+
* at Map.hasImage
|
|
3748
|
+
* at addImageToMap (s52-image-cache.ts)
|
|
3381
3749
|
*
|
|
3382
|
-
*
|
|
3750
|
+
* The rule, for anything in this package or the app that takes a map: after
|
|
3751
|
+
* an `await` (or in a `.then`, a frame callback, an `onload`), check this
|
|
3752
|
+
* before the first call on the map, and stop quietly if it says no. A removed
|
|
3753
|
+
* map is not an error to report — whoever removed it is building the next one.
|
|
3754
|
+
*
|
|
3755
|
+
* ⚠ `_removed`, NOT `style`. maplibre sets `_removed = true` as the last step
|
|
3756
|
+
* of `remove()` (typed on `Map` in maplibre-gl 4 and 5), so it is the fact,
|
|
3757
|
+
* where `style === undefined` is a consequence. Test doubles that never had a
|
|
3758
|
+
* `style` read as live, which is what they are. The app pins the maplibre side
|
|
3759
|
+
* of this (`map-live.test.ts`), so an upgrade that renames the field fails a
|
|
3760
|
+
* test rather than silently making every check say yes.
|
|
3761
|
+
*
|
|
3762
|
+
* Typed `object` so the structural map shapes the app passes around (a tile
|
|
3763
|
+
* census, an errored-tile tracker) can be asked too, not only `maplibregl.Map`.
|
|
3383
3764
|
*/
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
/**
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3765
|
+
declare function isMapLive(map: object): boolean;
|
|
3766
|
+
|
|
3767
|
+
/** S-52 display categories – controls default visibility */
|
|
3768
|
+
type DisplayCategory = "BASE" | "STANDARD" | "OTHER" | "MARINERS" | "META";
|
|
3769
|
+
/** Mapbox GL layer type we'll use for this entry */
|
|
3770
|
+
type GeomType = "fill" | "line" | "circle" | "symbol";
|
|
3771
|
+
/** Nautical groupings (loosely follows Chart No. 1 sections) */
|
|
3772
|
+
type NauticalCategory = "Depths" | "Land" | "Navigation Aids" | "Hazards" | "Regulated Areas" | "Infrastructure" | "Meta";
|
|
3773
|
+
/** Paint properties – a subset we actually use */
|
|
3774
|
+
interface AtlasStyle {
|
|
3775
|
+
type: GeomType;
|
|
3776
|
+
paint: Record<string, unknown>;
|
|
3777
|
+
layout?: Record<string, unknown>;
|
|
3778
|
+
/** Nautical symbol ID for symbol-type layers */
|
|
3779
|
+
iconImage?: string;
|
|
3396
3780
|
}
|
|
3397
|
-
/**
|
|
3398
|
-
interface
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
/**
|
|
3412
|
-
|
|
3413
|
-
/**
|
|
3414
|
-
|
|
3415
|
-
/** S-52
|
|
3416
|
-
|
|
3417
|
-
/**
|
|
3418
|
-
|
|
3419
|
-
/**
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
lineStyles?: SymbolLineStyle[];
|
|
3435
|
-
/** Fill regions in the SVG */
|
|
3436
|
-
fillElements?: SymbolFillElement[];
|
|
3437
|
-
/** Expanded navigational usage context (2-4 sentences) */
|
|
3438
|
-
usageContext?: string;
|
|
3439
|
-
/** Render size for documentation */
|
|
3440
|
-
renderSize?: string;
|
|
3441
|
-
}
|
|
3442
|
-
/** A logical grouping of related symbols */
|
|
3443
|
-
interface SymbolGroup {
|
|
3444
|
-
id: string;
|
|
3445
|
-
label: string;
|
|
3446
|
-
section: string;
|
|
3447
|
-
description: string;
|
|
3448
|
-
symbolIds: string[];
|
|
3781
|
+
/** One row in the S-52 lookup table */
|
|
3782
|
+
interface LookupEntry {
|
|
3783
|
+
/** S-57 object class acronym */
|
|
3784
|
+
objectClass: string;
|
|
3785
|
+
/** Human-readable name */
|
|
3786
|
+
name: string;
|
|
3787
|
+
/** Chart No. 1 section */
|
|
3788
|
+
category: NauticalCategory;
|
|
3789
|
+
/** S-52 display category */
|
|
3790
|
+
displayCategory: DisplayCategory;
|
|
3791
|
+
/** Default style using S-52 color tokens (resolved later) */
|
|
3792
|
+
style: AtlasStyle;
|
|
3793
|
+
/** Whether conditional symbology may override the style */
|
|
3794
|
+
hasConditional?: boolean;
|
|
3795
|
+
/** Attributes that affect styling */
|
|
3796
|
+
conditionalAttributes?: string[];
|
|
3797
|
+
/** INT1 / Chart No. 1 reference (e.g. "Q130.1") */
|
|
3798
|
+
int1Ref?: string;
|
|
3799
|
+
/** S-52 viewing group number */
|
|
3800
|
+
viewingGroup?: number;
|
|
3801
|
+
/** Minimum compilation scale for display (SCAMIN) */
|
|
3802
|
+
scamin?: number;
|
|
3803
|
+
/**
|
|
3804
|
+
* Mark this class as deliberately invisible (label-only or metadata-only)
|
|
3805
|
+
* so the layer-coverage audit doesn't flag its geometry-type gaps as bugs.
|
|
3806
|
+
*
|
|
3807
|
+
* Examples:
|
|
3808
|
+
* - SOUNDG: rendered as depth numbers via labels.ts, not as visible dots
|
|
3809
|
+
* - LNDRGN: region NAME labels only, no shape
|
|
3810
|
+
* - M_NPUB / M_NSYS / M_QUAL / M_SREL / DSID: S-57 metadata classes;
|
|
3811
|
+
* present for click-query attributes, never drawn
|
|
3812
|
+
*
|
|
3813
|
+
* Without this flag, `scripts/audit-layer-coverage.ts` reports the
|
|
3814
|
+
* thousands of features in these classes as "gaps" every week even
|
|
3815
|
+
* though the invisibility is intentional.
|
|
3816
|
+
*/
|
|
3817
|
+
auditIgnore?: boolean;
|
|
3449
3818
|
}
|
|
3450
|
-
/**
|
|
3451
|
-
interface
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3819
|
+
/** Resolved style ready for Mapbox GL (tokens → hex) */
|
|
3820
|
+
interface ResolvedStyle {
|
|
3821
|
+
type: GeomType;
|
|
3822
|
+
paint: Record<string, unknown>;
|
|
3823
|
+
layout?: Record<string, unknown>;
|
|
3824
|
+
minzoom?: number;
|
|
3825
|
+
maxzoom?: number;
|
|
3455
3826
|
}
|
|
3456
|
-
|
|
3457
|
-
/**
|
|
3458
|
-
*
|
|
3459
|
-
*
|
|
3460
|
-
*
|
|
3827
|
+
|
|
3828
|
+
/**
|
|
3829
|
+
* S-52 lookup table covering all S-57 object classes found in NOAA ENCs.
|
|
3830
|
+
* Colours reference S-52 tokens (resolved at render time).
|
|
3831
|
+
* INT1 references per NOAA Chart No. 1 (Ed 13).
|
|
3461
3832
|
*/
|
|
3462
|
-
declare const
|
|
3463
|
-
|
|
3464
|
-
|
|
3833
|
+
declare const S52_LOOKUP: Record<string, LookupEntry>;
|
|
3834
|
+
|
|
3835
|
+
/**
|
|
3836
|
+
* S-52 draw order: layers listed bottom → top.
|
|
3837
|
+
* Layers not in this list are inserted before point features.
|
|
3465
3838
|
*/
|
|
3466
|
-
declare
|
|
3839
|
+
declare const S52_DRAW_ORDER: string[];
|
|
3840
|
+
/** Get numeric draw priority for a layer (lower = drawn first / below) */
|
|
3841
|
+
declare function getDrawPriority(layerName: string): number;
|
|
3842
|
+
|
|
3843
|
+
/** S-52 display modes */
|
|
3844
|
+
type DisplayMode = "BASE" | "STANDARD" | "ALL";
|
|
3845
|
+
/** Check if a layer's display category is visible in the given mode */
|
|
3846
|
+
declare function isVisibleInMode(displayCategory: DisplayCategory, mode: DisplayMode): boolean;
|
|
3467
3847
|
/**
|
|
3468
|
-
*
|
|
3469
|
-
* live in `./symbols-browser.ts` (sub-export `@chrtco/sdk/atlas/browser`) —
|
|
3470
|
-
* they require a DOM (use `new Image()` + `map.addImage()`).
|
|
3848
|
+
* Convert S-52 SCAMIN (scale minimum) to Mapbox GL minzoom.
|
|
3471
3849
|
*/
|
|
3472
|
-
|
|
3473
|
-
declare function
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
/**
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
description?: string;
|
|
3486
|
-
attributeKey?: string;
|
|
3487
|
-
attributeValue?: number;
|
|
3488
|
-
}>;
|
|
3850
|
+
declare function scaminToMinZoom(scamin?: number): number | undefined;
|
|
3851
|
+
declare function getCollisionSettings(viewingGroup?: number): {
|
|
3852
|
+
iconAllowOverlap: boolean;
|
|
3853
|
+
iconOptional: boolean;
|
|
3854
|
+
symbolSortKey?: number;
|
|
3855
|
+
};
|
|
3856
|
+
/**
|
|
3857
|
+
* Get the resolved Mapbox GL style for a given S-57 layer.
|
|
3858
|
+
*/
|
|
3859
|
+
declare function resolveStyle(layerName: string, geomKind?: GeomType, ct?: ColorTableName, opts?: {
|
|
3860
|
+
safetyContour?: number;
|
|
3861
|
+
}): ResolvedStyle;
|
|
3862
|
+
declare function getLookupEntry(layerName: string): LookupEntry;
|
|
3489
3863
|
|
|
3490
3864
|
/**
|
|
3491
|
-
*
|
|
3865
|
+
* S-52 Conditional Symbology Procedures.
|
|
3866
|
+
* Each function takes feature properties and returns paint overrides (hex colours).
|
|
3867
|
+
* All expression builders accept an optional colorTable parameter.
|
|
3868
|
+
*/
|
|
3869
|
+
/**
|
|
3870
|
+
* Default safety contour in metres — the depth below which a feature is
|
|
3871
|
+
* "dangerous to my hull" for portrayal purposes.
|
|
3492
3872
|
*
|
|
3493
|
-
*
|
|
3494
|
-
*
|
|
3495
|
-
*
|
|
3496
|
-
* - Chart No. 1 sections (same organizational structure)
|
|
3497
|
-
* - Portrayal catalogue references (S-100 Portrayal Model)
|
|
3873
|
+
* This is the single source of truth for the *default* used by every
|
|
3874
|
+
* safety-contour-driven conditional symbology rule, so the rules can't
|
|
3875
|
+
* silently disagree with each other:
|
|
3498
3876
|
*
|
|
3499
|
-
*
|
|
3500
|
-
*
|
|
3501
|
-
* -
|
|
3502
|
-
*
|
|
3503
|
-
* -
|
|
3877
|
+
* - §SOUNDG02 — soundings shoaler than the contour get the
|
|
3878
|
+
* high-contrast shade (see `getLabelConfig` in labels.ts).
|
|
3879
|
+
* - §CSYM02 — isolated dangers shoaler than the contour get the
|
|
3880
|
+
* DNGCIR01 ring (see `buildLayersForClass` in layer-builder.ts).
|
|
3881
|
+
* - §DEPARE04 — the MS/MD shade boundary (owner decision 2026-08-21,
|
|
3882
|
+
* replacing a hardcoded 5 m middle cut; see the DEPARE block below
|
|
3883
|
+
* for the full IHO correspondence).
|
|
3504
3884
|
*
|
|
3505
|
-
*
|
|
3506
|
-
*
|
|
3885
|
+
* All are overridden by the user's setting (sounding panel slider,
|
|
3886
|
+
* `safetyContour` in the style options); this is only the fallback when
|
|
3887
|
+
* none is supplied. It matches `custom-style.ts`'s config default.
|
|
3507
3888
|
*/
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
featureClass: string;
|
|
3511
|
-
/** Human-readable name */
|
|
3512
|
-
name: string;
|
|
3513
|
-
/** S-57 6-char equivalent acronym, if any */
|
|
3514
|
-
s57Equivalent?: string;
|
|
3515
|
-
/** Chart No. 1 section letter */
|
|
3516
|
-
section: string;
|
|
3517
|
-
/** Group key for clustering */
|
|
3518
|
-
group: string;
|
|
3519
|
-
/** Feature category */
|
|
3520
|
-
category: "geo" | "meta" | "info";
|
|
3521
|
-
/** Description of the feature */
|
|
3522
|
-
description: string;
|
|
3523
|
-
/** S-100 Portrayal Catalogue reference */
|
|
3524
|
-
portrayalRef?: string;
|
|
3525
|
-
/** True if this feature has no S-57 equivalent */
|
|
3526
|
-
isNewInS101: boolean;
|
|
3527
|
-
/** Key attributes specific to this feature */
|
|
3528
|
-
attributes?: string[];
|
|
3529
|
-
}
|
|
3530
|
-
declare const S101_FEATURES: S101Feature[];
|
|
3531
|
-
declare const S101_CHART_SECTIONS: {
|
|
3532
|
-
id: string;
|
|
3533
|
-
label: string;
|
|
3534
|
-
description: string;
|
|
3535
|
-
}[];
|
|
3536
|
-
declare const S101_SYMBOL_GROUPS: {
|
|
3537
|
-
id: string;
|
|
3538
|
-
label: string;
|
|
3539
|
-
section: string;
|
|
3540
|
-
description: string;
|
|
3541
|
-
}[];
|
|
3542
|
-
|
|
3889
|
+
declare const DEFAULT_SAFETY_CONTOUR_M = 10;
|
|
3890
|
+
declare function depareColor(props: Record<string, unknown>, ct?: ColorTableName, safetyContourM?: number): string;
|
|
3543
3891
|
/**
|
|
3544
|
-
*
|
|
3545
|
-
*
|
|
3546
|
-
*
|
|
3547
|
-
* direct S-57/S-52 equivalent. The existing S-52 symbols are reused
|
|
3548
|
-
* where S-101 retains visual continuity with the S-57 portrayal.
|
|
3549
|
-
*
|
|
3550
|
-
* Reference: IHO S-101 Portrayal Catalogue (Ed 1.1.0)
|
|
3892
|
+
* The colour token of each `case` branch of `depareFillExpression`, in branch
|
|
3893
|
+
* order, then the fallback. `depth-area-opaque.ts` names the layers it splits
|
|
3894
|
+
* the expression into from this list, so the two read from one place.
|
|
3551
3895
|
*/
|
|
3896
|
+
declare const DEPARE_FILL_BRANCH_TOKENS: readonly ["DEPIT", "DEPVS", "DEPMS", "DEPMD"];
|
|
3897
|
+
declare const DEPARE_FILL_FALLBACK_TOKEN = "DEPDW";
|
|
3898
|
+
declare function depareFillExpression(ct?: ColorTableName, safetyContourM?: number): unknown[];
|
|
3899
|
+
declare function lightColor(props: Record<string, unknown>, ct?: ColorTableName): string;
|
|
3900
|
+
declare function lightFillExpression(ct?: ColorTableName): unknown[];
|
|
3901
|
+
declare function lateralColor(props: Record<string, unknown>, ct?: ColorTableName): string;
|
|
3902
|
+
declare function lateralFillExpression(ct?: ColorTableName): unknown[];
|
|
3903
|
+
declare function hazardColor(props: Record<string, unknown>, ct?: ColorTableName): string;
|
|
3904
|
+
declare function hazardFillExpression(ct?: ColorTableName): unknown[];
|
|
3905
|
+
declare function daymarkColor(props: Record<string, unknown>, ct?: ColorTableName): string;
|
|
3552
3906
|
|
|
3553
|
-
|
|
3907
|
+
/**
|
|
3908
|
+
* Label configurations for S-57 layers.
|
|
3909
|
+
* Defines which layers get text labels and how to extract label text.
|
|
3910
|
+
*/
|
|
3554
3911
|
|
|
3555
3912
|
/**
|
|
3556
|
-
*
|
|
3557
|
-
*
|
|
3558
|
-
* vector source (id = region) and N paint layers that reference it via
|
|
3559
|
-
* `source-layer` = S-57 class name.
|
|
3913
|
+
* Feature-class hierarchy for SEAARE labels. Returns a tier number 1-5 per
|
|
3914
|
+
* feature:
|
|
3560
3915
|
*
|
|
3561
|
-
*
|
|
3562
|
-
*
|
|
3563
|
-
*
|
|
3916
|
+
* Exported (with the other tier builders below) for the build-side parity
|
|
3917
|
+
* test: CHRTbaremetal replicates these taxonomies as data in
|
|
3918
|
+
* tools/chrt-baremetal/server/src/tilebuild/placeNameTiers.ts to stamp
|
|
3919
|
+
* `tier` onto PLACENAME index features, and
|
|
3920
|
+
* placename-tier-parity.test.ts evaluates the two against shared
|
|
3921
|
+
* fixtures. Change a branch here and that test names the drift.
|
|
3922
|
+
*
|
|
3923
|
+
* 1 — Ocean (OBJNAM contains "<X> Ocean" — CATSEA has no
|
|
3924
|
+
* ocean code; the attribute is 1/unset on oceans)
|
|
3925
|
+
* 2 — Sea / Gulf (OBJNAM "Gulf of …" / "… Sea")
|
|
3926
|
+
* 3 — Bay / Sound / (CATSEA in {5 bay, 12 narrows} OR OBJNAM
|
|
3927
|
+
* Strait / Narrows " Bay" / " Sound" / " Strait")
|
|
3928
|
+
* 4 — Anchorage detail (OBJNAM contains "Anchorage Area")
|
|
3929
|
+
* 5 — Relief + default (CATSEA relief codes — authoritative — or
|
|
3930
|
+
* relief-term names, or anything uncategorised;
|
|
3931
|
+
* suppressed below z9 by the size curve)
|
|
3932
|
+
*
|
|
3933
|
+
* Order matters: tier-4/5 demotions (anchorages, relief) run BEFORE the
|
|
3934
|
+
* promotion shims so "Bear Seamount" (contains " Sea") and "…Anchorage
|
|
3935
|
+
* Area" compound names can't bubble up into headline tiers.
|
|
3936
|
+
* `coalesce(CATSEA, catsea)` handles post-tippecanoe case variation
|
|
3937
|
+
* (matches `s52-conditional.ts` precedent).
|
|
3564
3938
|
*/
|
|
3565
|
-
|
|
3566
|
-
interface MapboxVectorSource {
|
|
3567
|
-
type: "vector";
|
|
3568
|
-
url: string;
|
|
3569
|
-
}
|
|
3939
|
+
declare function buildSeaAreaTierExpression(): ExpressionSpecification;
|
|
3570
3940
|
/**
|
|
3571
|
-
*
|
|
3572
|
-
*
|
|
3573
|
-
*
|
|
3941
|
+
* Built-up area tier (BUAARE): major city / town / neighborhood.
|
|
3942
|
+
* 1 — Major city (CATBUA=1 urban, or OBJNAM length <= 8)
|
|
3943
|
+
* 2 — Town (CATBUA=5 village, or OBJNAM length <= 14)
|
|
3944
|
+
* 3 — Neighborhood (longer compound names)
|
|
3945
|
+
*
|
|
3946
|
+
* Tier 1/2 may fire via CATBUA when populated; OBJNAM length is the
|
|
3947
|
+
* fallback so unpopulated CATBUA still produces a usable hierarchy.
|
|
3574
3948
|
*/
|
|
3575
|
-
|
|
3576
|
-
type: "vector";
|
|
3577
|
-
tiles: string[];
|
|
3578
|
-
minzoom: number;
|
|
3579
|
-
maxzoom: number;
|
|
3580
|
-
/** The credit a renderer shows for this source (MapLibre's attribution control). */
|
|
3581
|
-
attribution?: string;
|
|
3582
|
-
}
|
|
3949
|
+
declare function buildBuiltUpAreaTierExpression(): ExpressionSpecification;
|
|
3583
3950
|
/**
|
|
3584
|
-
*
|
|
3585
|
-
*
|
|
3586
|
-
*
|
|
3587
|
-
*
|
|
3951
|
+
* Land region tier (LNDRGN): major region vs. local point.
|
|
3952
|
+
* 1 — Major region (OBJNAM length <= 12 AND no comma — "Long Island", "Cape Cod")
|
|
3953
|
+
* 2 — Local point (else — "Bird Island", "Cottage Park")
|
|
3954
|
+
*
|
|
3955
|
+
* No CATLND analog for region scope, so OBJNAM is the only signal.
|
|
3956
|
+
* The comma-absence test is a heuristic: NOAA compound names like
|
|
3957
|
+
* "Boston Harbor, MA Castle Island" carry a comma and belong at deeper
|
|
3958
|
+
* zoom regardless of length.
|
|
3588
3959
|
*/
|
|
3589
|
-
|
|
3590
|
-
type: "raster-dem";
|
|
3591
|
-
tiles: string[];
|
|
3592
|
-
encoding: "terrarium";
|
|
3593
|
-
tileSize: number;
|
|
3594
|
-
minzoom: number;
|
|
3595
|
-
maxzoom: number;
|
|
3596
|
-
/** The credit a renderer shows for this source (MapLibre's attribution control). */
|
|
3597
|
-
attribution?: string;
|
|
3598
|
-
}
|
|
3599
|
-
type VectorSourceSpec = MapboxVectorSource | PmtilesVectorSource;
|
|
3600
|
-
type AnySourceSpec = VectorSourceSpec | RasterDemSource;
|
|
3601
|
-
/** CHRTland's vector land base. ADR 0023: its own archive, never chart data. */
|
|
3602
|
-
declare const LAND_REGION = "CHRT_LAND";
|
|
3603
|
-
/** CHRTland's terrarium relief. */
|
|
3604
|
-
declare const RELIEF_REGION = "CHRT_RELIEF";
|
|
3605
|
-
/** The world basemap under everything (completing-the-world-map, 2026-08-27). */
|
|
3606
|
-
declare const BASE_REGION = "CHRT_BASE";
|
|
3960
|
+
declare function buildLandRegionTierExpression(): ExpressionSpecification;
|
|
3607
3961
|
/**
|
|
3608
|
-
*
|
|
3609
|
-
*
|
|
3610
|
-
*
|
|
3611
|
-
*
|
|
3612
|
-
*
|
|
3613
|
-
* lakes are", not a surveyed shoreline. Must equal the builder's MAXZOOM
|
|
3614
|
-
* (tools/chrtbase-build/build.mjs).
|
|
3962
|
+
* Land area tier (LNDARE): major vs. local.
|
|
3963
|
+
* 1 — Major (OBJNAM length <= 12)
|
|
3964
|
+
* 2 — Local
|
|
3965
|
+
*
|
|
3966
|
+
* No category attribute. OBJNAM length is the only signal.
|
|
3615
3967
|
*/
|
|
3616
|
-
declare
|
|
3617
|
-
declare const BASE_MAXZOOM = 11;
|
|
3968
|
+
declare function buildLandAreaTierExpression(): ExpressionSpecification;
|
|
3618
3969
|
/**
|
|
3619
|
-
*
|
|
3620
|
-
*
|
|
3621
|
-
*
|
|
3622
|
-
* OSM-derived inland water (ODbL, `public/chrtbase-derivation.json`). The
|
|
3623
|
-
* app-embeddable offline bundle is a z0–6 cut that contains no OSM data and
|
|
3624
|
-
* carries `BASE_BUNDLE_ATTRIBUTION` instead (base-layers.ts) — one credit per
|
|
3625
|
-
* artefact, each naming exactly the data it holds.
|
|
3970
|
+
* Lake tier (LAKARE): lake vs. reservoir/pond.
|
|
3971
|
+
* 1 — Lake (CATLAK=1, or OBJNAM length <= 12)
|
|
3972
|
+
* 2 — Reservoir/pond (CATLAK in {2,3}, or longer name)
|
|
3626
3973
|
*/
|
|
3627
|
-
declare
|
|
3974
|
+
declare function buildLakeTierExpression(): ExpressionSpecification;
|
|
3628
3975
|
/**
|
|
3629
|
-
*
|
|
3630
|
-
*
|
|
3631
|
-
*
|
|
3632
|
-
* "Required notices"). Its other inputs — the ENC's charted land, USGS 3DEP
|
|
3633
|
-
* contours, GNIS names — are US federal public domain and owe none. Same
|
|
3634
|
-
* string as the offline land bundle's (offline-worker `LAND_PROVENANCE`).
|
|
3976
|
+
* River tier (RIVERS): major vs. local.
|
|
3977
|
+
* 1 — Major river (OBJNAM length <= 15 AND no comma)
|
|
3978
|
+
* 2 — Local creek (else)
|
|
3635
3979
|
*/
|
|
3636
|
-
declare
|
|
3980
|
+
declare function buildRiverTierExpression(): ExpressionSpecification;
|
|
3637
3981
|
/**
|
|
3638
|
-
*
|
|
3639
|
-
*
|
|
3640
|
-
*
|
|
3982
|
+
* Airport tier (AIRARE): major airport vs. small airstrip.
|
|
3983
|
+
* 1 — Major (OBJNAM length <= 25 — e.g. "Logan International Airport")
|
|
3984
|
+
* 2 — Airstrip
|
|
3641
3985
|
*/
|
|
3642
|
-
declare
|
|
3643
|
-
|
|
3644
|
-
|
|
3986
|
+
declare function buildAirportTierExpression(): ExpressionSpecification;
|
|
3987
|
+
interface LabelLayerConfig {
|
|
3988
|
+
/** Mapbox source layer type */
|
|
3989
|
+
type: "symbol";
|
|
3990
|
+
/** Text field expression or string */
|
|
3991
|
+
textField: ExpressionSpecification | string;
|
|
3992
|
+
/** Text size in pixels */
|
|
3993
|
+
textSize: number | ExpressionSpecification;
|
|
3994
|
+
/** Text color (hex) or data-driven expression */
|
|
3995
|
+
textColor: string | ExpressionSpecification;
|
|
3996
|
+
/** Halo color for contrast */
|
|
3997
|
+
textHaloColor: string;
|
|
3998
|
+
/** Halo width — pixels or zoom-interpolation expression */
|
|
3999
|
+
textHaloWidth: number | ExpressionSpecification;
|
|
4000
|
+
/** Text offset [x, y] in ems */
|
|
4001
|
+
textOffset: [number, number];
|
|
4002
|
+
/** Font stack */
|
|
4003
|
+
textFont?: string[];
|
|
4004
|
+
/** Additional layout properties */
|
|
4005
|
+
layout?: Record<string, unknown>;
|
|
4006
|
+
/** Minimum zoom level for this label */
|
|
4007
|
+
minzoom?: number;
|
|
4008
|
+
}
|
|
3645
4009
|
/**
|
|
3646
|
-
*
|
|
3647
|
-
*
|
|
3648
|
-
*
|
|
3649
|
-
*
|
|
4010
|
+
* Optional palette-and-data-driven options for label config.
|
|
4011
|
+
*
|
|
4012
|
+
* Currently used by SOUNDG to pick palette-aware text/halo colors and to
|
|
4013
|
+
* drive the S-52 safety-contour two-shade rule. Other classes ignore
|
|
4014
|
+
* these options.
|
|
3650
4015
|
*/
|
|
3651
|
-
|
|
3652
|
-
|
|
4016
|
+
interface LabelConfigOptions {
|
|
4017
|
+
/** S-52 colour table — drives palette-aware text and halo colors. */
|
|
4018
|
+
colorTable?: ColorTableName;
|
|
4019
|
+
/**
|
|
4020
|
+
* Safety contour depth in metres. Soundings shoaler than this render in
|
|
4021
|
+
* `SNDG2` (high-contrast); deeper soundings render in `SNDG1` (muted).
|
|
4022
|
+
* S-52 §SOUNDG02 conditional symbology.
|
|
4023
|
+
*/
|
|
4024
|
+
safetyContour?: number;
|
|
4025
|
+
/**
|
|
4026
|
+
* When false, all soundings render in `SNDG2` (single-shade). Default
|
|
4027
|
+
* true — emit the safety-contour case expression.
|
|
4028
|
+
*/
|
|
4029
|
+
twoShadeSoundings?: boolean;
|
|
4030
|
+
/**
|
|
4031
|
+
* When "semibold", SOUNDG labels use Open Sans Semibold for crisper
|
|
4032
|
+
* numerals at small sizes. Default "semibold".
|
|
4033
|
+
*/
|
|
4034
|
+
soundingFontWeight?: "regular" | "semibold";
|
|
4035
|
+
}
|
|
3653
4036
|
/**
|
|
3654
|
-
*
|
|
3655
|
-
*
|
|
3656
|
-
* ── Why the build has to be IN THE URL ────────────────────────────────────
|
|
4037
|
+
* Two-tier label rendering strategy for the band-priority style.
|
|
3657
4038
|
*
|
|
3658
|
-
*
|
|
3659
|
-
*
|
|
3660
|
-
*
|
|
3661
|
-
*
|
|
3662
|
-
* newly-panned-to tiles come from the new one, for up to the full hour. The
|
|
3663
|
-
* client renders TWO BUILDS AT ONCE.
|
|
4039
|
+
* `feature-band-gated` — emit one variant per source band, each gated to
|
|
4040
|
+
* its band's zoom window (the existing `makeBandVariants` behaviour). Right
|
|
4041
|
+
* for dense feature labels where seeing the same buoy designation or
|
|
4042
|
+
* sounding twice across overlapping bands is visual noise.
|
|
3664
4043
|
*
|
|
3665
|
-
*
|
|
3666
|
-
*
|
|
3667
|
-
*
|
|
3668
|
-
*
|
|
3669
|
-
*
|
|
3670
|
-
*
|
|
4044
|
+
* `orientation-cross-band` — emit a SINGLE label layer with no band
|
|
4045
|
+
* filter. The per-class `minzoom` is honoured. Right for orientation
|
|
4046
|
+
* "where am I" labels (sea-area names, land regions, cities) — these
|
|
4047
|
+
* must persist as the user zooms in, even if the broader-scope cell
|
|
4048
|
+
* carrying the OBJNAM is from a coarser band than the one rendering
|
|
4049
|
+
* features at the current zoom. Collision arbitration via
|
|
4050
|
+
* `ORIENTATION_BAND_SORT_KEY` gives the broader-scope (lower-band) copy
|
|
4051
|
+
* priority where the same OBJNAM exists in multiple bands.
|
|
4052
|
+
*/
|
|
4053
|
+
type LabelBehavior = "feature-band-gated" | "orientation-cross-band";
|
|
4054
|
+
declare const LABEL_BEHAVIOR: Record<string, LabelBehavior>;
|
|
4055
|
+
/** Returns the rendering strategy for an S-57 class. Unknown classes default to band-gated. */
|
|
4056
|
+
declare function getLabelBehavior(layerName: string): LabelBehavior;
|
|
4057
|
+
/**
|
|
4058
|
+
* Class-based label priority ladder — THE single collision-priority model
|
|
4059
|
+
* for feature labels (portrayal-excellence P4). Converges the previous
|
|
4060
|
+
* per-mechanism patches (SAFETY_CRITICAL_LABELS allow-overlap, the
|
|
4061
|
+
* band-5/6-only Harbor collision discipline) into one explicit ranking.
|
|
3671
4062
|
*
|
|
3672
|
-
*
|
|
4063
|
+
* Rank semantics: LOWER rank = higher priority. The rank drives two
|
|
4064
|
+
* mechanisms that must stay in agreement:
|
|
3673
4065
|
*
|
|
3674
|
-
*
|
|
3675
|
-
*
|
|
4066
|
+
* 1. `symbol-sort-key` — every feature label carries
|
|
4067
|
+
* `rank*1000 + within-class-key`, so if label layers are ever merged
|
|
4068
|
+
* (the P8 style fan-out reduction), placement priority survives the
|
|
4069
|
+
* merge unchanged.
|
|
4070
|
+
* 2. Label LAYER ORDER — MapLibre places symbols topmost-layer-first, so
|
|
4071
|
+
* `style-generator.ts` emits feature-label layers lowest-priority
|
|
4072
|
+
* first: safety-critical classes end up topmost and claim collision
|
|
4073
|
+
* space before anything else. (`symbol-sort-key` alone cannot do
|
|
4074
|
+
* this — it only orders placement WITHIN a layer.)
|
|
3676
4075
|
*
|
|
3677
|
-
*
|
|
3678
|
-
*
|
|
3679
|
-
* `url.pathname` (`TILE_ROUTE_PATH`) and reads only `?build=`, so a URL
|
|
3680
|
-
* carrying this parameter routes BYTE-IDENTICALLY to one without it. A
|
|
3681
|
-
* new path segment would instead need a second route regex kept alive
|
|
3682
|
-
* indefinitely.
|
|
3683
|
-
* 2. FIVE SEPARATE PATTERNS ALREADY MATCH THIS URL, and every one of them
|
|
3684
|
-
* ends `(?:\?.*)?$` — `src/lib/map/tile-token-client.ts` TILE_URL_PATH
|
|
3685
|
-
* and `src/site/chart/sail-tile-token.ts` (which decide whether a tile
|
|
3686
|
-
* gets its Bearer), `packages/sdk/src/tile-auth.ts` TILE_URL_PATH,
|
|
3687
|
-
* `public/chrt-tile-sw.js` TILE_URL_RE (which also reads the region out of
|
|
3688
|
-
* the URL to pick its per-region cache), and
|
|
3689
|
-
* `src/site/offline/pack-protocol.ts` TILE_URL (which rewrites a tile to
|
|
3690
|
-
* a downloaded pack). Their optional PATH segment, by contrast, is
|
|
3691
|
-
* `[a-z][a-z0-9-]*` — letter-first so it cannot be confused with the
|
|
3692
|
-
* numeric `{z}` — and build ids are hex (`463b265e`, `4de67273`). A build
|
|
3693
|
-
* in the path would miss every one of them, and a tile those patterns
|
|
3694
|
-
* miss does not merely go uncached: it goes out with NO BEARER and comes
|
|
3695
|
-
* back 401, which MapLibre records as a permanently errored tile. That is
|
|
3696
|
-
* the exact failure the `.png` drift caused on staging-sail (see
|
|
3697
|
-
* `chrt-tile-sw.js`).
|
|
4076
|
+
* The ladder (safety-critical > nav-aids > depth field > structures >
|
|
4077
|
+
* ambient notes):
|
|
3698
4078
|
*
|
|
3699
|
-
*
|
|
3700
|
-
*
|
|
3701
|
-
*
|
|
4079
|
+
* 100 — Safety-critical: light characteristics (LIGHTS), hazard depth
|
|
4080
|
+
* callouts (UWTROC/OBSTRN/WRECKS VALSOU), overhead clearances
|
|
4081
|
+
* (CBLOHD/PIPOHD VERCLR). Irreducible mariner-safety text.
|
|
4082
|
+
* 200 — Nav-aid designations: buoy / beacon `R "4"` labels.
|
|
4083
|
+
* 250 — Auxiliary nav-aid info: fog signal type (FOGSIG).
|
|
4084
|
+
* 300 — Depth field: soundings, contour values. Individually droppable —
|
|
4085
|
+
* a hidden sounding has visible neighbors.
|
|
4086
|
+
* 400 — Structures: bridges, landmarks, piers, moorings, buildings.
|
|
4087
|
+
* 500 — Ambient annotation: seabed nature, magnetic variation, kelp.
|
|
4088
|
+
* 900 — Orientation names (SEAARE etc.) — not part of this ladder;
|
|
4089
|
+
* they keep their settled watermark model (cell-band fan +
|
|
4090
|
+
* dominance composition + `orientationLabelLayout`) and always
|
|
4091
|
+
* paint underneath feature labels.
|
|
3702
4092
|
*
|
|
3703
|
-
*
|
|
3704
|
-
*
|
|
4093
|
+
* Safety guardrail: a lower rung never blocks a higher rung — placement
|
|
4094
|
+
* order guarantees the safety-critical label got the space first. Density
|
|
4095
|
+
* relief comes from dropping the LOWEST rung in a pile-up, never the top.
|
|
3705
4096
|
*/
|
|
3706
|
-
declare const
|
|
4097
|
+
declare const LABEL_PRIORITY: Record<string, number>;
|
|
3707
4098
|
/**
|
|
3708
|
-
*
|
|
3709
|
-
*
|
|
3710
|
-
*
|
|
3711
|
-
* `{z}`/`{x}`/`{y}` by brace-matching the template, so an id containing a
|
|
3712
|
-
* brace would corrupt every tile request. Empty / whitespace-only ids emit no
|
|
3713
|
-
* parameter at all instead of a bare `?v=` that would key its own useless
|
|
3714
|
-
* cache namespace.
|
|
4099
|
+
* Resolve the priority rank for an S-57 class's label. Orientation classes
|
|
4100
|
+
* report 900 regardless of ladder membership (PRDARE etc.) so the
|
|
4101
|
+
* layer-order sort in style-generator.ts can treat priority uniformly.
|
|
3715
4102
|
*/
|
|
3716
|
-
declare function
|
|
3717
|
-
/**
|
|
3718
|
-
*
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
/** Chart region. Default: "NOAA_ENC". */
|
|
3724
|
-
region?: string;
|
|
3725
|
-
/**
|
|
3726
|
-
* Build id of the CHART region (`region`) — the `build_tag` a
|
|
3727
|
-
* `mint-tile-token` response hands back.
|
|
3728
|
-
*
|
|
3729
|
-
* Emitted as the {@link BUILD_PARAM} query parameter on that region's tile
|
|
3730
|
-
* template. See {@link tileTemplate} for why a build discriminator has to be
|
|
3731
|
-
* in the URL at all.
|
|
3732
|
-
*
|
|
3733
|
-
* ⚠ THIS COVERS THE CHART REGION ONLY. A token is minted for one chart
|
|
3734
|
-
* region and `CHRT_LAND` / `CHRT_RELIEF` ride it, so the JWT's `build_tag`
|
|
3735
|
-
* says nothing about a land cutover — the same blind spot that made the
|
|
3736
|
-
* Worker's edge-cache key wrong until `TILE_CACHE_VERSION` v3
|
|
3737
|
-
* (cloudflare/tile-worker/src/cache-encoding.ts). Pass {@link buildTags} to
|
|
3738
|
-
* discriminate the basemap sources too.
|
|
3739
|
-
*/
|
|
3740
|
-
buildTag?: string;
|
|
3741
|
-
/**
|
|
3742
|
-
* Resolved build id per region — `{ NOAA_ENC: "…", CHRT_LAND: "…" }`.
|
|
3743
|
-
*
|
|
3744
|
-
* The complete form of {@link buildTag}: every source this style declares
|
|
3745
|
-
* gets its own discriminator, so a `CHRT_LAND` promotion turns over the land
|
|
3746
|
-
* URLs without touching the chart's (and vice versa). An entry here wins
|
|
3747
|
-
* over `buildTag` for the same region.
|
|
3748
|
-
*
|
|
3749
|
-
* This is the mint response's `build_tags` map verbatim (claim contract
|
|
3750
|
-
* v1.7) — `TileTokenResponse.buildTags` in both `lib/map/tile-token-client.ts`
|
|
3751
|
-
* and the SDK's `tile-auth.ts`. The same map already keys the tile Service
|
|
3752
|
-
* Worker's per-region caches; passing it here puts the same identity in the
|
|
3753
|
-
* URL, so the layer above the Service Worker stops mixing builds too.
|
|
3754
|
-
*
|
|
3755
|
-
* A region absent from the map simply gets no discriminator — the URL it
|
|
3756
|
-
* has always had. That is a deliberate soft edge: an older mint response, or
|
|
3757
|
-
* a region with no servable build, must degrade to today's behaviour rather
|
|
3758
|
-
* than emit a URL pinned to a build nobody resolved.
|
|
3759
|
-
*/
|
|
3760
|
-
buildTags?: Readonly<Record<string, string>>;
|
|
3761
|
-
/** Override tile-worker origin (e.g. staging). Default: DEFAULT_TILE_BASE_URL. */
|
|
3762
|
-
tileBaseUrl?: string;
|
|
3763
|
-
/**
|
|
3764
|
-
* Emit the CHRTland vector land base as a second source (ADR 0023). Off by
|
|
3765
|
-
* default: it costs a source, and the region must be granted on the token.
|
|
3766
|
-
*/
|
|
3767
|
-
land?: boolean;
|
|
3768
|
-
/**
|
|
3769
|
-
* Emit CHRTland's terrarium relief as a raster-dem source. Separate from
|
|
3770
|
-
* `land` because relief needs a raster-capable worker AND a grant that
|
|
3771
|
-
* `land-regions.ts` still withholds.
|
|
3772
|
-
*/
|
|
3773
|
-
relief?: boolean;
|
|
3774
|
-
/**
|
|
3775
|
-
* Emit the CHRT_BASE world basemap as a third vector source — the dark
|
|
3776
|
-
* geography under everything, the tan jurisdiction fill, and the rough
|
|
3777
|
-
* inland water inside countries CHRT carries. Its layers sit UNDER the
|
|
3778
|
-
* no-coverage hatch's companions and everything else; see baseLayers().
|
|
3779
|
-
*/
|
|
3780
|
-
base?: boolean;
|
|
3781
|
-
}
|
|
4103
|
+
declare function getLabelPriority(layerName: string): number;
|
|
4104
|
+
/**
|
|
4105
|
+
* Compose a `symbol-sort-key` from a class rank and an optional
|
|
4106
|
+
* within-class key expression. The within-class key is clamped to
|
|
4107
|
+
* [0, 999] so it can never bleed into a neighboring rank's band.
|
|
4108
|
+
*/
|
|
4109
|
+
declare function labelSortKey(rank: number, within?: unknown): ExpressionSpecification | number;
|
|
3782
4110
|
/**
|
|
3783
|
-
*
|
|
4111
|
+
* Extract the trailing designation token from a nav-aid OBJNAM.
|
|
3784
4112
|
*
|
|
3785
|
-
*
|
|
3786
|
-
* -
|
|
3787
|
-
*
|
|
3788
|
-
*
|
|
4113
|
+
* NOAA names channel aids "<waterway> <type> Buoy|Beacon <designation>"
|
|
4114
|
+
* where the designation is 1-4 alphanumerics: "4", "18A", "B", "BG".
|
|
4115
|
+
* Returns null when the name has no designation (trailing token is a
|
|
4116
|
+
* stopword type-name, or longer than 4 chars).
|
|
3789
4117
|
*
|
|
3790
|
-
*
|
|
3791
|
-
*
|
|
3792
|
-
*
|
|
4118
|
+
* This is the TS twin of `navAidDesignationTextExpression` — the GeoJSON
|
|
4119
|
+
* preprocessing path uses this function, the PMTiles path uses the GL
|
|
4120
|
+
* expression. Keep the two in agreement (see label-priority.test.ts).
|
|
3793
4121
|
*/
|
|
3794
|
-
declare function
|
|
3795
|
-
|
|
4122
|
+
declare function extractNavAidDesignation(objnam: string): string | null;
|
|
4123
|
+
/** Get label config for a given S-57 layer, or null if no labels */
|
|
4124
|
+
declare function getLabelConfig(layerName: string, opts?: LabelConfigOptions): LabelLayerConfig | null;
|
|
3796
4125
|
/**
|
|
3797
|
-
*
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
*
|
|
3806
|
-
*
|
|
3807
|
-
*
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
*
|
|
3812
|
-
*
|
|
3813
|
-
* It does not touch, and `depth-label-size.test.ts` holds every one of these
|
|
3814
|
-
* equal to the Standard style in every palette and every symbol family:
|
|
3815
|
-
*
|
|
3816
|
-
* - `text-field` — the number itself, its unit conversion, its rounding.
|
|
3817
|
-
* ENC content is never altered; a bigger "4" is still the cell's "4".
|
|
3818
|
-
* - `text-color` / `text-halo-color` — §SOUNDG02's two shades against the
|
|
3819
|
-
* safety contour, and the palette that draws them (red night included:
|
|
3820
|
-
* it IS the NIGHT chart). A depth number shoaler than the contour stays
|
|
3821
|
-
* the loud one.
|
|
3822
|
-
* - `symbol-sort-key` — shallowest wins a collision, at any size.
|
|
3823
|
-
* - `filter`, `minzoom`, `maxzoom`, layer ids and layer order — so the
|
|
3824
|
-
* resident layer set the desktop builds at boot is the same set, and a
|
|
3825
|
-
* switch is `setLayoutProperty` / `setPaintProperty` on layers already
|
|
3826
|
-
* there. No layer and no draw call is added; what costs more is GPU fill,
|
|
3827
|
-
* because a bigger glyph covers more pixels (about 6–7 % more blended
|
|
3828
|
-
* fragments per pixel on the chart bench — the PR has the numbers).
|
|
3829
|
-
*
|
|
3830
|
-
* ===========================================================================
|
|
3831
|
-
* WHICH LABELS ARE "DEPTH NUMBERS"
|
|
3832
|
-
* ===========================================================================
|
|
3833
|
-
*
|
|
3834
|
-
* Exactly the ones the depth-unit switch converts (`buildLabelLayer` in
|
|
3835
|
-
* `layer-builder.ts`): soundings, contour values, and the depth printed beside
|
|
3836
|
-
* a rock, wreck or obstruction. The unit switch already treats those three as
|
|
3837
|
-
* one claim — its own note says a rock's figure "is the SAME depth claim as a
|
|
3838
|
-
* sounding" — and a size switch that enlarged the soundings around a rock but
|
|
3839
|
-
* left the rock's own depth small would make the hazard the quietest number
|
|
3840
|
-
* on that part of the chart.
|
|
3841
|
-
*
|
|
3842
|
-
* Not the dredged-channel note (`DRGNOTE`): it is a sentence fitted inside
|
|
3843
|
-
* its own channel polygon at a computed size, and scaling it would stop it
|
|
3844
|
-
* fitting. Not the bridge note: a clearance is a height, not a depth.
|
|
3845
|
-
*
|
|
3846
|
-
* ===========================================================================
|
|
3847
|
-
* WHY NOT A BOLD FACE
|
|
3848
|
-
* ===========================================================================
|
|
4126
|
+
* Build a Mapbox symbol layer spec from a label config.
|
|
4127
|
+
*/
|
|
4128
|
+
declare function buildLabelLayer(layerId: string, sourceId: string, config: LabelLayerConfig, visible: boolean, overrides?: {
|
|
4129
|
+
textScale?: number;
|
|
4130
|
+
minzoom?: number | null;
|
|
4131
|
+
allowOverlap?: boolean;
|
|
4132
|
+
}): maplibregl.LayerSpecification;
|
|
4133
|
+
/**
|
|
4134
|
+
* Pre-process SOUNDG GeoJSON to extract Z coordinates as `depth` properties.
|
|
4135
|
+
* Soundings are MultiPoint with Z values in geometry.coordinates[][2].
|
|
4136
|
+
* This explodes MultiPoints into individual Points with a `depth` property.
|
|
4137
|
+
*/
|
|
4138
|
+
declare function preprocessSoundings(fc: GeoJSON.FeatureCollection): GeoJSON.FeatureCollection;
|
|
4139
|
+
/**
|
|
4140
|
+
* Pre-process LIGHTS GeoJSON to derive compact light characteristic labels.
|
|
4141
|
+
* Adds `_lightLabel` property (e.g., "Fl(2) WR 4s 5M").
|
|
3849
4142
|
*
|
|
3850
|
-
*
|
|
3851
|
-
*
|
|
3852
|
-
*
|
|
3853
|
-
*
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
4143
|
+
* KEEP IN STEP WITH `buildLightLabelExpression()` in layer-builder.ts — that
|
|
4144
|
+
* is the same label built as a GL expression for the tile path, which has no
|
|
4145
|
+
* JS preprocessing step. `light-label-parity.test.ts` asserts the two agree
|
|
4146
|
+
* on real tile features; if you change one, change both.
|
|
4147
|
+
*/
|
|
4148
|
+
declare function preprocessLights(fc: GeoJSON.FeatureCollection): GeoJSON.FeatureCollection;
|
|
4149
|
+
/** List of layers that have labels */
|
|
4150
|
+
declare const LABELED_LAYERS: Set<string>;
|
|
4151
|
+
/**
|
|
4152
|
+
* Pre-process buoy/beacon GeoJSON to derive concise mariner-style labels.
|
|
4153
|
+
* Adds `_navAidLabel` property (e.g., 'R "8"', 'G "5"').
|
|
4154
|
+
*/
|
|
4155
|
+
declare function preprocessNavAids(fc: GeoJSON.FeatureCollection): GeoJSON.FeatureCollection;
|
|
4156
|
+
/** Check if a layer name needs nav aid preprocessing */
|
|
4157
|
+
declare function isNavAidLayer(layerName: string): boolean;
|
|
4158
|
+
/**
|
|
4159
|
+
* Pre-process water body polygon GeoJSON into centroid points for label placement.
|
|
4160
|
+
* Computes a simple average-coordinate centroid for each polygon feature that has OBJNAM.
|
|
4161
|
+
*/
|
|
4162
|
+
declare function preprocessWaterBodies(fc: GeoJSON.FeatureCollection): GeoJSON.FeatureCollection;
|
|
4163
|
+
/** MVT layer the build-side place-name index emits. */
|
|
4164
|
+
declare const PLACENAME_SOURCE_LAYER = "PLACENAME";
|
|
4165
|
+
/** Orientation classes whose names render italic (water voice). */
|
|
4166
|
+
declare const PLACENAME_WATER_CLASSES: readonly string[];
|
|
4167
|
+
/** Orientation classes whose names render upright (land voice). */
|
|
4168
|
+
declare const PLACENAME_LAND_CLASSES: readonly string[];
|
|
4169
|
+
/**
|
|
4170
|
+
* The 2 PLACENAME symbol layers. Layout contract (design §2.2): collision
|
|
4171
|
+
* ON (`allow-overlap: false`, `ignore-placement: false`,
|
|
4172
|
+
* `optional: true`), padding 4, `text-variable-anchor`, and
|
|
4173
|
+
* `symbol-sort-key` straight from the build-side `rank` — MapLibre places
|
|
4174
|
+
* LOWER sort keys first, and rank is minted lower-is-more-important
|
|
4175
|
+
* (tier major, bbox area minor), so when space runs out the biggest names
|
|
4176
|
+
* survive. That ranking is the per-zoom density governor P4 asked for.
|
|
3857
4177
|
*/
|
|
4178
|
+
declare function buildPlaceNameLayers(sourceId: string, ct?: ColorTableName): maplibregl.LayerSpecification[];
|
|
3858
4179
|
|
|
3859
|
-
/** The two choices, in presentation order. */
|
|
3860
|
-
declare const DEPTH_LABEL_SIZES: readonly ["standard", "large"];
|
|
3861
|
-
type DepthLabelSize = (typeof DEPTH_LABEL_SIZES)[number];
|
|
3862
4180
|
/**
|
|
3863
|
-
*
|
|
3864
|
-
*
|
|
3865
|
-
*
|
|
4181
|
+
* Spatial grid-based feature decimation for performance at low zoom levels.
|
|
4182
|
+
* Thins dense GeoJSON feature sets by keeping only one representative
|
|
4183
|
+
* feature per grid cell per layer.
|
|
3866
4184
|
*/
|
|
3867
|
-
|
|
3868
|
-
/**
|
|
3869
|
-
|
|
3870
|
-
/**
|
|
3871
|
-
|
|
4185
|
+
interface DecimationOptions {
|
|
4186
|
+
/** Grid resolution (cells per axis). Default 80. */
|
|
4187
|
+
gridSize?: number;
|
|
4188
|
+
/** Zoom level below which decimation kicks in. Default 12. */
|
|
4189
|
+
zoomThreshold?: number;
|
|
4190
|
+
}
|
|
3872
4191
|
/**
|
|
3873
|
-
*
|
|
3874
|
-
*
|
|
3875
|
-
* ⚠ THIS IS THE ONE THAT DECIDES HOW MANY SOUNDINGS SURVIVE. MapLibre drops a
|
|
3876
|
-
* sounding whose box (glyphs + padding) overlaps one already placed — the
|
|
3877
|
-
* shallowest places first, so what drops is the deeper figure. A 1.4x numeral
|
|
3878
|
-
* inside Standard's 6 px padding lost a quarter of the soundings: bigger
|
|
3879
|
-
* numbers, fewer of them, which is not what was asked for. Trimming the
|
|
3880
|
-
* padding gives the box back.
|
|
3881
|
-
*
|
|
3882
|
-
* Measured 2026-10-05 on the chart bench (`scripts/chart-bench`, Boston, DAY,
|
|
3883
|
-
* 1280x800 at 1x), soundings placed, Standard → Large at this padding:
|
|
3884
|
-
*
|
|
3885
|
-
* z11.5 515 → 539 (+5%) z12.3 434 → 415 (−4%)
|
|
3886
|
-
* z13 374 → 366 (−2%) z14 326 → 311 (−5%)
|
|
3887
|
-
*
|
|
3888
|
-
* and at Standard's 6 px: 391 / 246 at z11.5 / z14 (−24% / −25%). 3 px kept
|
|
3889
|
-
* z14 level but put 17% MORE figures on the coastal view, which reads as
|
|
3890
|
-
* clutter rather than as the same chart drawn bigger.
|
|
4192
|
+
* Zoom-adaptive grid resolution for decimation.
|
|
3891
4193
|
*/
|
|
3892
|
-
declare
|
|
4194
|
+
declare function getGridSizeForZoom(zoom: number): number;
|
|
3893
4195
|
/**
|
|
3894
|
-
*
|
|
4196
|
+
* Decimate a GeoJSON FeatureCollection using spatial grid thinning.
|
|
4197
|
+
* Only runs when zoom < zoomThreshold. Returns the original FC otherwise.
|
|
3895
4198
|
*
|
|
3896
|
-
*
|
|
3897
|
-
*
|
|
3898
|
-
*
|
|
4199
|
+
* @param fc - Input FeatureCollection
|
|
4200
|
+
* @param layerName - S-57 layer name (affects priority logic)
|
|
4201
|
+
* @param currentZoom - Current map zoom level
|
|
4202
|
+
* @param bounds - Current viewport bounds
|
|
4203
|
+
* @param opts - Decimation options
|
|
3899
4204
|
*/
|
|
3900
|
-
declare function
|
|
3901
|
-
|
|
4205
|
+
declare function decimateFeatures(fc: GeoJSON.FeatureCollection, layerName: string, currentZoom: number, bounds: {
|
|
4206
|
+
west: number;
|
|
4207
|
+
south: number;
|
|
4208
|
+
east: number;
|
|
4209
|
+
north: number;
|
|
4210
|
+
}, opts?: DecimationOptions): GeoJSON.FeatureCollection;
|
|
3902
4211
|
/**
|
|
3903
|
-
*
|
|
3904
|
-
* Wraps the existing atlas resolveStyle() and adds source/source-layer/filter.
|
|
4212
|
+
* Get the max number of cells to load based on zoom level.
|
|
3905
4213
|
*/
|
|
4214
|
+
declare function getMaxCellsForZoom(zoom: number): number;
|
|
3906
4215
|
|
|
3907
|
-
interface StyleLayer {
|
|
3908
|
-
id: string;
|
|
3909
|
-
type: string;
|
|
3910
|
-
source: string;
|
|
3911
|
-
"source-layer": string;
|
|
3912
|
-
filter?: unknown[];
|
|
3913
|
-
paint: Record<string, unknown>;
|
|
3914
|
-
layout?: Record<string, unknown>;
|
|
3915
|
-
minzoom?: number;
|
|
3916
|
-
maxzoom?: number;
|
|
3917
|
-
metadata?: Record<string, unknown>;
|
|
3918
|
-
}
|
|
3919
4216
|
/**
|
|
3920
|
-
*
|
|
3921
|
-
* Returns multiple layers (fill, outline, symbol, label, etc.).
|
|
4217
|
+
* IHO S-52 / NOAA Chart No. 1 / INT1 nautical symbol SVGs.
|
|
3922
4218
|
*
|
|
3923
|
-
*
|
|
3924
|
-
*
|
|
4219
|
+
* Complete symbology suite following:
|
|
4220
|
+
* - IHO S-52 Presentation Library (Ed 4.0)
|
|
4221
|
+
* - IALA Maritime Buoyage System R1001 (Region B for US waters)
|
|
4222
|
+
* - NOAA Chart No. 1 (Ed 13) / INT1
|
|
3925
4223
|
*
|
|
3926
|
-
*
|
|
3927
|
-
*
|
|
3928
|
-
*
|
|
3929
|
-
*
|
|
4224
|
+
* Buoy shape terminology (US / Chart No. 1):
|
|
4225
|
+
* - CAN (Q20): Flat-top cylindrical buoy — Port mark in IALA-B (red)
|
|
4226
|
+
* - NUN (Q21): Conical/pointed-top buoy — Starboard mark in IALA-B (green)
|
|
4227
|
+
* - PILLAR: Tall narrow buoy — used for cardinal, isolated danger, etc.
|
|
4228
|
+
* - SPAR: Tall thin pole buoy
|
|
4229
|
+
* - SPHERICAL: Round buoy — safe water marks
|
|
4230
|
+
* - BARREL: Barrel/tun shaped buoy
|
|
4231
|
+
* - SUPER: Large navigation buoy / LANBY
|
|
4232
|
+
*
|
|
4233
|
+
* Cardinal mark topmark orientations (IALA):
|
|
4234
|
+
* - North: both cones point UP ▲▲
|
|
4235
|
+
* - South: both cones point DOWN ▼▼
|
|
4236
|
+
* - East: cones base-to-base (diamond) ◆
|
|
4237
|
+
* - West: cones point-to-point (hourglass) ⊗
|
|
4238
|
+
*
|
|
4239
|
+
* Each symbol is a compact SVG at 32×32 for Mapbox GL `map.addImage()`.
|
|
3930
4240
|
*/
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
4241
|
+
/** Color used in the SVG with its S-52 token name, hex, and usage */
|
|
4242
|
+
interface SymbolColor {
|
|
4243
|
+
token: string;
|
|
4244
|
+
hex: string;
|
|
4245
|
+
usage: string;
|
|
4246
|
+
}
|
|
4247
|
+
/** Line style used in the SVG */
|
|
4248
|
+
interface SymbolLineStyle {
|
|
4249
|
+
element: string;
|
|
4250
|
+
width: number;
|
|
4251
|
+
pattern?: string;
|
|
4252
|
+
color: string;
|
|
4253
|
+
}
|
|
4254
|
+
/** Fill element used in the SVG */
|
|
4255
|
+
interface SymbolFillElement {
|
|
4256
|
+
element: string;
|
|
4257
|
+
color: string;
|
|
4258
|
+
opacity?: number;
|
|
4259
|
+
}
|
|
4260
|
+
interface NauticalSymbol {
|
|
4261
|
+
id: string;
|
|
4262
|
+
label: string;
|
|
4263
|
+
/** INT1 / Chart No. 1 reference */
|
|
4264
|
+
int1Ref: string;
|
|
4265
|
+
/** Chart No. 1 section letter */
|
|
4266
|
+
section: string;
|
|
4267
|
+
getSvg: () => string;
|
|
4268
|
+
/** Generate SVG with theme-specific colors (for bridge icons etc.) */
|
|
4269
|
+
getThemedSvg?: (chblk: string, movable: string) => string;
|
|
4270
|
+
/** What this symbol represents on a chart */
|
|
4271
|
+
description?: string;
|
|
4272
|
+
/** S-52 Presentation Library symbol name */
|
|
4273
|
+
s52PlRef?: string;
|
|
4274
|
+
/** S-57 object class (e.g. "LNDMRK") when it can't be derived from s52PlRef's prefix */
|
|
4275
|
+
s57Class?: string;
|
|
4276
|
+
/** Grouping key for family clustering */
|
|
4277
|
+
group?: string;
|
|
4278
|
+
/** IDs of related variant symbols */
|
|
4279
|
+
variants?: string[];
|
|
4280
|
+
/** S-57 attribute that selects this variant */
|
|
4281
|
+
attributeKey?: string;
|
|
4282
|
+
/** Value of that attribute for this variant */
|
|
4283
|
+
attributeValue?: number;
|
|
4284
|
+
/** Example label strings seen on charts */
|
|
4285
|
+
labelExamples?: string[];
|
|
4286
|
+
/** What the color represents */
|
|
4287
|
+
colorMeaning?: string;
|
|
4288
|
+
/** Colors used in the SVG */
|
|
4289
|
+
colors?: SymbolColor[];
|
|
4290
|
+
/** Line/stroke styles used in the SVG */
|
|
4291
|
+
lineStyles?: SymbolLineStyle[];
|
|
4292
|
+
/** Fill regions in the SVG */
|
|
4293
|
+
fillElements?: SymbolFillElement[];
|
|
4294
|
+
/** Expanded navigational usage context (2-4 sentences) */
|
|
4295
|
+
usageContext?: string;
|
|
4296
|
+
/** Render size for documentation */
|
|
4297
|
+
renderSize?: string;
|
|
4298
|
+
}
|
|
4299
|
+
/** A logical grouping of related symbols */
|
|
4300
|
+
interface SymbolGroup {
|
|
4301
|
+
id: string;
|
|
4302
|
+
label: string;
|
|
4303
|
+
section: string;
|
|
4304
|
+
description: string;
|
|
4305
|
+
symbolIds: string[];
|
|
4306
|
+
}
|
|
4307
|
+
/** Chart No. 1 section metadata */
|
|
4308
|
+
interface ChartSection {
|
|
4309
|
+
id: string;
|
|
4310
|
+
label: string;
|
|
4311
|
+
description: string;
|
|
4312
|
+
}
|
|
4313
|
+
declare const NAUTICAL_SYMBOLS: NauticalSymbol[];
|
|
4314
|
+
/** S-57 object class → default symbol ID mapping.
|
|
4315
|
+
* Values are S-52 PL symbol names (matching SVG filenames in s52/point/).
|
|
4316
|
+
* Conditional expressions in getIconExpression() override these for classes
|
|
4317
|
+
* with attribute-dependent variants.
|
|
4318
|
+
*/
|
|
4319
|
+
declare const SYMBOL_MAP: Record<string, string>;
|
|
4320
|
+
/** Get the Mapbox icon-image expression for data-driven symbol selection.
|
|
4321
|
+
* Returns S-52 PL symbol names that correspond to SVG files in s52/point/.
|
|
4322
|
+
*/
|
|
4323
|
+
declare function getIconExpression(layerName: string): string | unknown[];
|
|
3934
4324
|
/**
|
|
3935
|
-
*
|
|
3936
|
-
*
|
|
3937
|
-
*
|
|
3938
|
-
* without touching this file.
|
|
4325
|
+
* Browser-only image loaders (`loadSymbolImages`, `loadThemedBridgeImages`)
|
|
4326
|
+
* live in `./symbols-browser.ts` (sub-export `@chrtco/sdk/atlas/browser`) —
|
|
4327
|
+
* they require a DOM (use `new Image()` + `map.addImage()`).
|
|
3939
4328
|
*/
|
|
3940
|
-
|
|
4329
|
+
/** Get inline SVG string for a symbol by ID (for the Atlas legend) */
|
|
4330
|
+
declare function getSymbolSvgString(symbolId: string): string | null;
|
|
4331
|
+
declare const CHART_SECTIONS: ChartSection[];
|
|
4332
|
+
declare const SYMBOL_GROUPS: SymbolGroup[];
|
|
4333
|
+
/** Generate a single SVG sprite sheet containing all symbols as <symbol> elements */
|
|
4334
|
+
declare function generateSpriteSheet(): string;
|
|
4335
|
+
/** Generate a JSON manifest mapping symbol IDs to metadata */
|
|
4336
|
+
declare function generateSpriteManifest(): Record<string, {
|
|
4337
|
+
label: string;
|
|
4338
|
+
int1Ref: string;
|
|
4339
|
+
section: string;
|
|
4340
|
+
group?: string;
|
|
4341
|
+
s52PlRef?: string;
|
|
4342
|
+
description?: string;
|
|
4343
|
+
attributeKey?: string;
|
|
4344
|
+
attributeValue?: number;
|
|
4345
|
+
}>;
|
|
3941
4346
|
|
|
3942
4347
|
/**
|
|
3943
|
-
*
|
|
3944
|
-
*
|
|
3945
|
-
* `makeBandVariants()` historically emitted, per (class, band): one
|
|
3946
|
-
* "not-dominated" layer plus up to five `-domBy{D}` copies that differ ONLY
|
|
3947
|
-
* in their dominance filter and a `maxzoom` of `dominatedVariantMaxzoom(D)`.
|
|
3948
|
-
* That fan existed because MapLibre filters could not read `["zoom"]`. They
|
|
3949
|
-
* can now (style-spec 24.8.5; buckets evaluate at the tile's `overscaledZ`),
|
|
3950
|
-
* so the whole fan folds into ONE layer per (class, band) whose filter
|
|
3951
|
-
* carries the zoom gate.
|
|
3952
|
-
*
|
|
3953
|
-
* **Construction principle — read before changing anything here.** The
|
|
3954
|
-
* collapsed filter is the literal `["any"]` UNION of the clauses the fan
|
|
3955
|
-
* already encoded: every variant the legacy emitter would have produced
|
|
3956
|
-
* contributes exactly one `["all", <its dominance filter>, ["<", ["zoom"],
|
|
3957
|
-
* <its maxzoom>]]` clause, and the dead-variant skip is mirrored too.
|
|
3958
|
-
* Equivalence is therefore *structural*, not re-derived — which matters,
|
|
3959
|
-
* because the two "obvious" hand-written forms are both wrong:
|
|
3960
|
-
*
|
|
3961
|
-
* 1. A `["match", ["get","_dominated_by_min"], 2,5, 3,7, 4,9, 5,11, 6,11, 24]`
|
|
3962
|
-
* threshold (the form the design doc proposed) uses band 6's *eligibility*
|
|
3963
|
-
* zoom 11. The real ceiling is `dominatedVariantMaxzoom("6") = 13` — band
|
|
3964
|
-
* 6's DATA floor. Using 11 reopens the z11–z12 void window that
|
|
3965
|
-
* `band-priority.ts` documents closing.
|
|
3966
|
-
* 2. That same form silently drops the legacy `_dominated: true` boolean,
|
|
3967
|
-
* which `dominatedByMinFilter("6")` still honours. A legacy-tagged feature
|
|
3968
|
-
* has no `_dominated_by_min`, so `match` falls to its default and the
|
|
3969
|
-
* feature renders FOREVER instead of dropping at z13.
|
|
3970
|
-
*
|
|
3971
|
-
* Deriving the gate from the emitter's own clauses avoids both by construction.
|
|
3972
|
-
* `band-collapse.test.ts` re-proves it on every CI run by differentially
|
|
3973
|
-
* evaluating legacy-vs-collapsed through MapLibre's real three gates.
|
|
4348
|
+
* IHO S-101 ENC Product Specification — Feature Catalogue
|
|
3974
4349
|
*
|
|
3975
|
-
*
|
|
3976
|
-
*
|
|
3977
|
-
*
|
|
3978
|
-
*
|
|
3979
|
-
*
|
|
3980
|
-
* (`DOMINANCE_EXEMPT_FILL_CLASSES` ≡ `OPAQUE_FILL_LAYERS`), where band-major
|
|
3981
|
-
* order is the ONLY thing separating the bands, and 15/15 class pairs are
|
|
3982
|
-
* provably unsatisfiable with one layer each. Do not reintroduce it there.
|
|
3983
|
-
* Evidence: `.chrt/perf/2026-07-14-p8-d4-spike.md`.
|
|
4350
|
+
* S-101 replaces S-57 as the data model for Electronic Navigational Charts.
|
|
4351
|
+
* This catalogue maps S-101 feature classes to:
|
|
4352
|
+
* - S-57 equivalents (where they exist)
|
|
4353
|
+
* - Chart No. 1 sections (same organizational structure)
|
|
4354
|
+
* - Portrayal catalogue references (S-100 Portrayal Model)
|
|
3984
4355
|
*
|
|
3985
|
-
*
|
|
3986
|
-
*
|
|
3987
|
-
*
|
|
3988
|
-
*
|
|
3989
|
-
*
|
|
3990
|
-
* NOT the killed axis 2, because what the fill argument protects — paint
|
|
3991
|
-
* order as the sole band separator — does not apply to labels: their
|
|
3992
|
-
* load-bearing order is the cross-class P4 priority ladder (each class keeps
|
|
3993
|
-
* exactly one layer in its ladder slot), and within-class placement priority
|
|
3994
|
-
* rides the `rank*1000 + within-key` symbol-sort-key that labels.ts
|
|
3995
|
-
* documents as designed to survive precisely this merge.
|
|
4356
|
+
* Key S-101 changes from S-57:
|
|
4357
|
+
* - CamelCase feature class names (DepthArea vs DEPARE)
|
|
4358
|
+
* - Complex/structured attributes (nested objects vs flat)
|
|
4359
|
+
* - New feature types for AIS, quality, under-keel clearance
|
|
4360
|
+
* - Removed/merged features for simplification
|
|
3996
4361
|
*
|
|
3997
|
-
*
|
|
3998
|
-
*
|
|
3999
|
-
* `/-band(\d)/` to clamp customer minzoom/scamin overrides to the band's
|
|
4000
|
-
* data floor, on the live public Style API path. Renaming the id silently
|
|
4001
|
-
* unclamps those overrides. Cross-band LABEL layers are the deliberate
|
|
4002
|
-
* exception: they carry every band floor INSIDE the filter (tile-zoom
|
|
4003
|
-
* clauses a customer override cannot touch), which supersedes the clamp —
|
|
4004
|
-
* `bandFloor()` returning 0 for a bare label id is correct, not a gap.
|
|
4005
|
-
* Both halves asserted in `band-collapse.test.ts`.
|
|
4006
|
-
*/
|
|
4007
|
-
|
|
4008
|
-
/**
|
|
4009
|
-
* Which emitter the style generator uses for the dominance fan.
|
|
4010
|
-
* `"legacy"` exists so CI can differentially prove the two equivalent (it is
|
|
4011
|
-
* the oracle in `band-collapse.test.ts`) and as a one-line rollback. It is an
|
|
4012
|
-
* internal knob — deliberately NOT on the exported `StyleGeneratorOptions`,
|
|
4013
|
-
* so it cannot reach `@chrtco/sdk` consumers via `ChrtStyleOptions`.
|
|
4362
|
+
* Reference: IHO S-101 Product Specification (Ed 1.1.0)
|
|
4363
|
+
* IHO S-100 Universal Hydrographic Data Model
|
|
4014
4364
|
*/
|
|
4015
|
-
|
|
4365
|
+
interface S101Feature {
|
|
4366
|
+
/** S-101 camelCase feature class name */
|
|
4367
|
+
featureClass: string;
|
|
4368
|
+
/** Human-readable name */
|
|
4369
|
+
name: string;
|
|
4370
|
+
/** S-57 6-char equivalent acronym, if any */
|
|
4371
|
+
s57Equivalent?: string;
|
|
4372
|
+
/** Chart No. 1 section letter */
|
|
4373
|
+
section: string;
|
|
4374
|
+
/** Group key for clustering */
|
|
4375
|
+
group: string;
|
|
4376
|
+
/** Feature category */
|
|
4377
|
+
category: "geo" | "meta" | "info";
|
|
4378
|
+
/** Description of the feature */
|
|
4379
|
+
description: string;
|
|
4380
|
+
/** S-100 Portrayal Catalogue reference */
|
|
4381
|
+
portrayalRef?: string;
|
|
4382
|
+
/** True if this feature has no S-57 equivalent */
|
|
4383
|
+
isNewInS101: boolean;
|
|
4384
|
+
/** Key attributes specific to this feature */
|
|
4385
|
+
attributes?: string[];
|
|
4386
|
+
}
|
|
4387
|
+
declare const S101_FEATURES: S101Feature[];
|
|
4388
|
+
declare const S101_CHART_SECTIONS: {
|
|
4389
|
+
id: string;
|
|
4390
|
+
label: string;
|
|
4391
|
+
description: string;
|
|
4392
|
+
}[];
|
|
4393
|
+
declare const S101_SYMBOL_GROUPS: {
|
|
4394
|
+
id: string;
|
|
4395
|
+
label: string;
|
|
4396
|
+
section: string;
|
|
4397
|
+
description: string;
|
|
4398
|
+
}[];
|
|
4016
4399
|
|
|
4017
4400
|
/**
|
|
4018
|
-
*
|
|
4019
|
-
*
|
|
4401
|
+
* S-101 Portrayal Catalogue — New Symbol SVGs
|
|
4402
|
+
*
|
|
4403
|
+
* These symbols represent features introduced in S-101 that have no
|
|
4404
|
+
* direct S-57/S-52 equivalent. The existing S-52 symbols are reused
|
|
4405
|
+
* where S-101 retains visual continuity with the S-57 portrayal.
|
|
4406
|
+
*
|
|
4407
|
+
* Reference: IHO S-101 Portrayal Catalogue (Ed 1.1.0)
|
|
4020
4408
|
*/
|
|
4021
4409
|
|
|
4022
|
-
|
|
4023
|
-
version: 8;
|
|
4024
|
-
name: string;
|
|
4025
|
-
metadata: Record<string, unknown>;
|
|
4026
|
-
sources: Record<string, unknown>;
|
|
4027
|
-
sprite?: string;
|
|
4028
|
-
glyphs: string;
|
|
4029
|
-
layers: StyleLayer[];
|
|
4030
|
-
}
|
|
4031
|
-
interface StyleGeneratorOptions extends BuildSourcesOptions {
|
|
4032
|
-
/**
|
|
4033
|
-
* When set, emit a "paper chart" style centered on the selected scale
|
|
4034
|
-
* band, with graceful coverage fallback: the requested band's layers
|
|
4035
|
-
* draw on top where its cells have data; coarser bands (driven by
|
|
4036
|
-
* `CHART_CASCADE_CODES`) fill gaps where the requested band has no
|
|
4037
|
-
* cells. Per-feature SCAMIN minzooms are preserved on every cascade
|
|
4038
|
-
* variant; `maxzoom` is dropped so the user can zoom in indefinitely.
|
|
4039
|
-
*
|
|
4040
|
-
* When omitted (default), continuous mode emits one layer copy per
|
|
4041
|
-
* source band with strict per-band zoom windows so exactly one band
|
|
4042
|
-
* renders at any given continuous zoom.
|
|
4043
|
-
*
|
|
4044
|
-
* `lockedBounds` (optional) restricts chart-mode rendering to a
|
|
4045
|
-
* specific bbox via a `["within"]` filter — applied ONLY to the
|
|
4046
|
-
* requested band's variants. Cascade fallback bands render across the
|
|
4047
|
-
* full viewport so a chart-Harbor user panning offshore still sees
|
|
4048
|
-
* Approach/Coastal data. The frontend pairs this with a translucent
|
|
4049
|
-
* grey overlay outside the bbox so the lock boundary is still visible
|
|
4050
|
-
* to the user (the fallback data is dimmed by the overlay but not
|
|
4051
|
-
* filtered out).
|
|
4052
|
-
*/
|
|
4053
|
-
chartMode?: {
|
|
4054
|
-
band: ScaleBand$1;
|
|
4055
|
-
lockedBounds?: BBox;
|
|
4056
|
-
};
|
|
4057
|
-
/**
|
|
4058
|
-
* Display unit for depth labels (SOUNDG soundings, DEPCNT contour
|
|
4059
|
-
* values). Source data is always meters (S-57 / VALSOU / VALDCO);
|
|
4060
|
-
* "feet" wraps the text-field expression with a unit conversion +
|
|
4061
|
-
* round so the rendered numbers match. Default "meters".
|
|
4062
|
-
*/
|
|
4063
|
-
depthUnits?: "meters" | "feet";
|
|
4064
|
-
/**
|
|
4065
|
-
* Which symbol artwork the style references. "s52" (default) uses the
|
|
4066
|
-
* PresLib-derived S-52 set; "s101" rewrites icon references to the
|
|
4067
|
-
* official S-101 Portrayal Catalogue symbols (s101: image namespace)
|
|
4068
|
-
* where a counterpart exists — see s101-style.ts. "chrt" applies the
|
|
4069
|
-
* CHRT house ATON/LIGHTS glyphs with colour-true tinting — see
|
|
4070
|
-
* chrt-style.ts. Selection logic differences are documented per module.
|
|
4071
|
-
*/
|
|
4072
|
-
symbolSet?: "s52" | "s101" | "chrt" | "raster";
|
|
4073
|
-
/**
|
|
4074
|
-
* The mariner's safety contour in metres — the depth below which a
|
|
4075
|
-
* feature is "dangerous to my hull". Drives both safety-contour
|
|
4076
|
-
* conditional symbology rules:
|
|
4077
|
-
*
|
|
4078
|
-
* - §SOUNDG02 — soundings shoaler than this render in the
|
|
4079
|
-
* high-contrast color; deeper soundings render in the muted color.
|
|
4080
|
-
* - §CSYM02 — isolated dangers (rocks / wrecks / obstructions)
|
|
4081
|
-
* shoaler than this get the DNGCIR01 danger ring.
|
|
4082
|
-
*
|
|
4083
|
-
* Default `DEFAULT_SAFETY_CONTOUR_M` (10 m).
|
|
4084
|
-
*
|
|
4085
|
-
* Does not affect the DEPARE depth-area shading, whose 2/5/10 m bands
|
|
4086
|
-
* are a separate S-52 concept.
|
|
4087
|
-
*/
|
|
4088
|
-
safetyContour?: number;
|
|
4089
|
-
/**
|
|
4090
|
-
* When false, all soundings render in a single shade. Default true.
|
|
4091
|
-
*/
|
|
4092
|
-
twoShadeSoundings?: boolean;
|
|
4093
|
-
/**
|
|
4094
|
-
* Label model for the 9 orientation place-name classes (SEAARE, LNDRGN,
|
|
4095
|
-
* LAKARE, RIVERS, CANALS, BUAARE, AIRARE, LNDARE, PRDARE).
|
|
4096
|
-
*
|
|
4097
|
-
* "legacy" (default) — the per-cell-band orientation fan
|
|
4098
|
-
* (fanOrientationLabelByCellBand): one label per feature per band,
|
|
4099
|
-
* deconflicted only by `_label_anchor` tags and watermark opacity.
|
|
4100
|
-
*
|
|
4101
|
-
* "placename" — 2 PLACENAME symbol layers over the build-side
|
|
4102
|
-
* place-name index (CHRTbaremetal placeNameIndex.ts): one collision-
|
|
4103
|
-
* managed label per named place with a per-feature zoom window; the
|
|
4104
|
-
* orientation fan for those classes is NOT emitted. Requires tiles
|
|
4105
|
-
* built with the PLACENAME side index — on older tiles the layers
|
|
4106
|
-
* simply draw nothing (soft-fail is index-side), which is why the
|
|
4107
|
-
* default stays "legacy" until L2c's rebuild + Maine-coast visual
|
|
4108
|
-
* verification flips it (docs/design/chart-label-deconfliction.md
|
|
4109
|
-
* §2.3). Feature-label classes are untouched either way.
|
|
4110
|
-
*/
|
|
4111
|
-
labels?: "legacy" | "placename";
|
|
4112
|
-
/**
|
|
4113
|
-
* Font weight for SOUNDG labels. Default "semibold" — crisper numerals
|
|
4114
|
-
* at small sizes on screen.
|
|
4115
|
-
*/
|
|
4116
|
-
soundingFontWeight?: "regular" | "semibold";
|
|
4117
|
-
/**
|
|
4118
|
-
* How big the depth figures are drawn — soundings, contour values and the
|
|
4119
|
-
* depth beside a rock, wreck or obstruction. "standard" (default) is
|
|
4120
|
-
* byte-identical to omitting it; "large" enlarges those labels only, and
|
|
4121
|
-
* never their text, colours, sort keys, filters or layer set. See
|
|
4122
|
-
* depth-label-size.ts.
|
|
4123
|
-
*/
|
|
4124
|
-
depthLabelSize?: DepthLabelSize;
|
|
4125
|
-
}
|
|
4126
|
-
declare function generateStyle(palette?: ColorTableName, opts?: StyleGeneratorOptions & {
|
|
4127
|
-
bandFan?: BandFanMode;
|
|
4128
|
-
}): MapboxStyle;
|
|
4129
|
-
declare function generateStyleJSON(palette?: ColorTableName, opts?: StyleGeneratorOptions): string;
|
|
4130
|
-
/** Get summary stats about the generated style */
|
|
4131
|
-
declare function getStyleStats(style: MapboxStyle): {
|
|
4132
|
-
totalLayers: number;
|
|
4133
|
-
fillLayers: number;
|
|
4134
|
-
lineLayers: number;
|
|
4135
|
-
symbolLayers: number;
|
|
4136
|
-
circleLayers: number;
|
|
4137
|
-
sources: number;
|
|
4138
|
-
objectClasses: Set<string>;
|
|
4139
|
-
};
|
|
4410
|
+
declare const S101_NEW_SYMBOLS: NauticalSymbol[];
|
|
4140
4411
|
|
|
4141
4412
|
declare const S101_SOURCE_COMMIT = "05063500e898544c90078ab78a61efc72b7e62f3";
|
|
4142
4413
|
|
|
@@ -4847,7 +5118,11 @@ declare const DEFAULT_CUSTOM_STYLE_CONFIG: CustomStyleConfig;
|
|
|
4847
5118
|
* fields fall back to the platform defaults. Never throws.
|
|
4848
5119
|
*/
|
|
4849
5120
|
declare function sanitizeCustomStyleConfig(raw: unknown): CustomStyleConfig;
|
|
4850
|
-
/**
|
|
5121
|
+
/**
|
|
5122
|
+
* Normalize a `?theme=` value to a colour table name; null for anything else.
|
|
5123
|
+
* Case-insensitive; `-` is accepted for `_` (`eink-mono` = `eink_mono`), so
|
|
5124
|
+
* the e-ink names survive either spelling a caller guesses.
|
|
5125
|
+
*/
|
|
4851
5126
|
declare function normalizeTheme(raw: string | null | undefined): ColorTableName | null;
|
|
4852
5127
|
interface ResolvedTheme {
|
|
4853
5128
|
palette: ColorTableName;
|
|
@@ -5215,7 +5490,8 @@ declare class OfflineError extends Error {
|
|
|
5215
5490
|
|
|
5216
5491
|
/** Options for `chrt.style()`. Extends the atlas style generator options. */
|
|
5217
5492
|
interface ChrtStyleOptions extends StyleGeneratorOptions {
|
|
5218
|
-
/**
|
|
5493
|
+
/** Colour palette: "DAY" (default), "DUSK", "NIGHT", or the e-paper
|
|
5494
|
+
* palettes "EINK_COLOR" / "EINK_MONO" / "EINK_NIGHT" (see `EINK_COLOR_TABLES`). */
|
|
5219
5495
|
palette?: ColorTableName;
|
|
5220
5496
|
}
|
|
5221
5497
|
declare class Chrt {
|
|
@@ -5504,4 +5780,4 @@ declare class Chrt {
|
|
|
5504
5780
|
warmTiles(region?: string): Promise<TileTokenResponse>;
|
|
5505
5781
|
}
|
|
5506
5782
|
|
|
5507
|
-
export { ALL_NAV_AID_LAYERS, ALL_WATER_BODY_LAYERS, AREA_QUERY_LAYERS, ATON_EXPRESSION_CLASSES, type AheadCoverageCell, type AheadFeatureProperties, type AheadOptions, type AheadResponse, type AlongRouteFeatureProperties, type AlongRouteOptions, type AlongRouteResponse, type AreaInspectResult, type AtlasStyle, type AttachOptions, BAND_CODE_ALIASES, BAND_DRAW_ORDER, BAND_PRIORITY_RANGES, BASE_ATTRIBUTION, BASE_BUNDLE_ATTRIBUTION, BASE_BUNDLE_ID, BASE_BUNDLE_MAXZOOM, BASE_BUNDLE_SCHEMA, BASE_BUNDLE_SOURCE_LAYERS, BASE_CLIENT_RASTER_BEFORE_ID, BASE_MAXZOOM, BASE_MINZOOM, BASE_REGION, type BBox, BRIDGE_QUERY_LAYERS, BUILD_MAXZOOM, BUILD_MINZOOM, BUILD_PARAM, type BandCode, type BandPriorityRange, type BridgeInspectResult, type BuildOfflineStyleOptions, type BuildSourcesOptions, CHART_BAND_CODES, CHART_CASCADE_CODES, CHART_SECTIONS, CHRTRASTER_REF_CROPS, CHRTRASTER_SVGS, CHRT_ATON_COLORS, CHRT_GLYPH_NAMES, CHRT_GLYPH_SVGS, CHRT_ICON_EXPRESSIONS, CHRT_ICON_PREFIX, CHRT_SDF_GLYPHS, CHRT_STYLE_MODES, type CandidateQueryOptions, type CandidatesEventContext, type CellDeletedEvent, type CellDetail, type CellEventData, type CellNewEvent, type CellUpdatedData, type CellUpdatedEvent, type CellsOptions, type CellsResponse, type ChartSection, Chrt, type ChrtConfig, ChrtError, type ChrtStyleMode, type ChrtStyleOptions, type ChrtStyleTheme, type ChrtSymbolSet, type ClickAnchor, ColorTableName, type CoverageOptions, type CoverageResponse, type CoverageRouteCell, type CoverageRouteOptions, type CoverageRouteResponse, type CoverageSource, type CustomStyleConfig, DEFAULT_CLICK_TOLERANCE, DEFAULT_CUSTOM_STYLE_CONFIG,
|
|
5783
|
+
export { ALL_NAV_AID_LAYERS, ALL_WATER_BODY_LAYERS, AREA_QUERY_LAYERS, ATON_EXPRESSION_CLASSES, type AheadCoverageCell, type AheadFeatureProperties, type AheadOptions, type AheadResponse, type AlongRouteFeatureProperties, type AlongRouteOptions, type AlongRouteResponse, type AreaInspectResult, type AtlasStyle, type AttachOptions, BAND_CODE_ALIASES, BAND_DRAW_ORDER, BAND_PRIORITY_RANGES, BASE_ATTRIBUTION, BASE_BUNDLE_ATTRIBUTION, BASE_BUNDLE_ID, BASE_BUNDLE_MAXZOOM, BASE_BUNDLE_SCHEMA, BASE_BUNDLE_SOURCE_LAYERS, BASE_CLIENT_RASTER_BEFORE_ID, BASE_MAXZOOM, BASE_MINZOOM, BASE_REGION, type BBox, BRIDGE_QUERY_LAYERS, BUILD_MAXZOOM, BUILD_MINZOOM, BUILD_PARAM, type BandCode, type BandPriorityRange, type BridgeInspectResult, type BuildOfflineStyleOptions, type BuildSourcesOptions, CHART_BAND_CODES, CHART_CASCADE_CODES, CHART_SECTIONS, CHART_SOUNDINGS_RULE, CHART_SYMBOL_SCALE, CHART_SYMBOL_SIZES, CHART_SYMBOL_SIZE_LABELS, CHART_SYMBOL_SIZE_REACH, CHART_SYMBOL_SIZE_WIRE, CHRTRASTER_REF_CROPS, CHRTRASTER_SVGS, CHRT_ATON_COLORS, CHRT_GLYPH_NAMES, CHRT_GLYPH_SVGS, CHRT_ICON_EXPRESSIONS, CHRT_ICON_PREFIX, CHRT_SDF_GLYPHS, CHRT_STYLE_MODES, type CandidateQueryOptions, type CandidatesEventContext, type CellDeletedEvent, type CellDetail, type CellEventData, type CellNewEvent, type CellUpdatedData, type CellUpdatedEvent, type CellsOptions, type CellsResponse, type ChartSection, type ChartSoundingsRule, type ChartSymbolScales, type ChartSymbolSize, Chrt, type ChrtConfig, ChrtError, type ChrtStyleMode, type ChrtStyleOptions, type ChrtStyleTheme, type ChrtSymbolSet, type ClickAnchor, ColorTableName, type CoverageOptions, type CoverageResponse, type CoverageRouteCell, type CoverageRouteOptions, type CoverageRouteResponse, type CoverageSource, type CustomStyleConfig, DEFAULT_CLICK_TOLERANCE, DEFAULT_CUSTOM_STYLE_CONFIG, DEFAULT_INSPECT_CLASS_RANK, DEFAULT_LABEL_SETTINGS, DEFAULT_NAV_AID_SETTINGS, DEFAULT_REGION, DEFAULT_SAFETY_CONTOUR_M, DEFAULT_SOUNDING_SETTINGS, DEFAULT_TILE_BASE_URL, DEFAULT_TILE_REGION, DEFAULT_WATER_BODY_SETTINGS, DEPARE_FILL_BRANCH_TOKENS, DEPARE_FILL_FALLBACK_TOKEN, DEPTH_FIGURE_CLASSES, DRAPEABLE_LAYER_TYPES, type DecodedAreaFeature, type DecodedBridge, type DecodedNavAid, type DecodedProperty, type DisplayCategory, type DisplayMode, EINK_DANGER_PATTERN, EINK_DOTS_PATTERN, EINK_HATCH_PATTERN, type FeatureCollection, type FeaturesOptions, type FetchStyleOptions, FileSystemAdapter, type FlashPattern, type FlashPhase, type GenerateCustomStyleOptions, type GeneratedCustomStyle, type GeoJsonFeature, type GeoJsonGeometry, type GeomType, HAZARD_LABEL_PRIORITY, INSPECT_CLASS_RANK, INSPECT_RANK_DEVIATIONS, type InspectCandidate, type InspectCandidateSet, type InspectEnrichment, type InspectEventContext, type InspectNotice, type InspectOptions, type InspectResult, type InspectTargetClass, type InspectableFeature, InteractClient, type InteractEntitlement, InteractError, type InteractErrorCode, type InteractHandle, type InteractMapLike, type InteractMapMouseEvent, LABELED_LAYERS, LABEL_BEHAVIOR, LABEL_LAYER_GROUPS, LABEL_PRIORITY, LAMP_CORE_LAYER_ID, LAMP_GLOW_LAYER_ID, LAMP_LAYER_IDS, LAMP_TICK_MS, LAND_ATTRIBUTION, LAND_BUILD_MAXZOOM, LAND_REGION, LAND_TEXT_CLASSES, type LabelBehavior, type LabelConfigOptions, type LabelLayerConfig, type LabelSettings, type LampLayer, type LookupEntry, MAPLIBRE_DEFAULT_TEXT_PADDING_PX, type MapLibreStyle, type MapboxStyle, type MapboxVectorSource, type MarineAlert, type MarineAlertsOptions, type MarineAlertsResponse, type MarineConditionsObservation, type MarineConditionsOptions, type MarineConditionsResponse, type MarineConditionsSeries, type MarineForecastOptions, type MarineForecastPeriod, type MarineForecastResponse, type MarineSeas, type MarineStation, type MarineSwellTrain, type MarineWind, type MarineZoneRef, NAUTICAL_SYMBOLS, NAV_AID_LAYER_GROUPS, NAV_AID_QUERY_LAYERS, NIGHT_INK, NIGHT_MUTED_INK, NON_SOLAS_DISCLAIMER, NON_SOLAS_DISCLAIMER_SHORT, type NauticalCategory, type NauticalSymbol, type NavAidInspectResult, type NavAidSettings, type NearbyMarineStation, OPAQUE_SPLIT_OF, OUTRANK_LABELS, type OfflineBundleResponse, type OfflineDownloadOptions, type OfflineDownloadProgress, type OfflineDownloadResult, OfflineError, type OfflineErrorCode, type OfflineFetchStyleOptions, type OfflineHeartbeatOptions, type OfflineRegionSummary, type OfflineRemoveOptions, OfflineStyleError, type OfflineStylePlatform, type OfflineStyleResponse, PLACENAME_LAND_CLASSES, PLACENAME_SOURCE_LAYER, PLACENAME_WATER_CLASSES, type ParsedSigseqTerms, type PmtilesVectorSource, type Poi, type PoiCoverage, type PoiDataset, type PoiOptions, type PoiResponse, type QueryFeatureProperties, type QueryOptions, type QueryResponse, RASTER_ATON_CLASSES, RASTER_GLYPH_NAMES, RASTER_ICON_PREFIX, RELIEF_ATTRIBUTION, RELIEF_ENCODING, RELIEF_REGION, RELIEF_TILE_SIZE, type ResolvedStyle, type ResolvedTheme, type S101ArtworkProvenance, type S101Feature, S101_AREA_FILL_NAMES, S101_CHART_SECTIONS, S101_FEATURES, S101_ICON_PREFIX, S101_LINE_STYLE_NAMES, S101_NEW_SYMBOLS, S101_NO_OFFICIAL_COUNTERPART, S101_SOURCE_COMMIT, S101_SYMBOL_GROUPS, S101_SYMBOL_NAMES, S52_ATON_LOOKUPS, S52_ATON_LOOKUPS_PAPER, S52_DRAW_ORDER, S52_LOOKUP, S52_PATTERN_SPRITE_PREFIX, SERVED_FONT_STACKS, SERVED_SOUNDING_PADDING_PX, SIGPER_TOLERANCE_SECONDS, SIGSEQ_MAX_TERMS, SOUNDING_LAYERS, SOUNDING_PADDING_PER_FACTOR, STANDARD_CHART_SYMBOL_SCALES, SYMBOL_ANNOTATION_TEXT_CLASSES, SYMBOL_GROUPS, SYMBOL_MAP, type ScaleBand, type SearchCoverageNotice, type SearchHit, type SearchOptions, type SearchResponse, type SectorArcFeature, type SectorArcFeatureCollection, type SectorInfo, type SigseqRefusal, type SigseqTerm, type SoundingSettings, type SourceMode, type StyleGeneratorOptions, type StyleLayer, type StyleUrlOptions, type SymbolGroup, TileAuth, type TileGroup, type TileGroupsResponse, TileTokenError, type TileTokenErrorCode, type TileTokenResponse, type TransformRequest, type TransformedRequest, type VectorSourceSpec, type VesselProfile, WATER_BODY_LAYER_GROUPS, WATER_TEXT_CLASSES, type WaterBodySettings, WeatherEndpoint, type WeatherReading, type WebhookEvent, type WebhookEventType, type WebhookPayload, applyBaseBundle, applyChartSymbolScales, applyChartSymbolScalesToLayer, applyChrtSymbolSet, applyColorTheme, applyCustomStyleSettings, applyEinkPortrayal, applyRasterSymbolSet, applyS101SymbolSet, atonIconExpression, bandFilterExpression, buildAirportTierExpression, buildBuiltUpAreaTierExpression, buildFlashPattern, buildLabelLayer, buildLakeTierExpression, buildLampLayers, buildLandAreaTierExpression, buildLandRegionTierExpression, buildLayersForClass, buildOfflineStyle, buildPlaceNameLayers, buildRiverTierExpression, buildSeaAreaTierExpression, buildSectorArcGeoJSON, buildSectorArcsFC, buildSectorsFromFeatures, buildSources, candidateRank, capLuminance, cellBandCharacters, cellBandMatch, chartSymbolSizingCensus, chrtAtonTintExpression, chrtHouseColor, chrtLightTintExpression, clampChartSymbolScale, collectCandidates, collectClickCandidates, combineWithBandFilter, contourValueFactor, contrastRatio, daymarkColor, decimateFeatures, decodeAreaFeatureProps, decodeBridgeProps, decodeCandidate, decodeChartSymbolScale, decodeNavAidProps, demotedBelowSoundings, depareColor, depareFillExpression, depthAreaClassLayerId, depthAreaSplitIds, deriveMarinerName, drapeHalves, drapedFirst, extractNavAidDesignation, featureIdentity, fromZoom, generateCustomStyle, generateSpriteManifest, generateSpriteSheet, generateStyle, generateStyleJSON, getAvailableLineSymbols, getAvailablePatterns, getAvailablePointSymbols, getCollisionSettings, getDrawPriority, getGridSizeForZoom, getIconExpression, getLabelBehavior, getLabelConfig, getLabelPriority, getLookupEntry, getMaxCellsForZoom, getOrderedClasses, getRasterSvg, getS52SvgString, getS52SymbolStats, getStyleStats, getSymbolSvgString, getThemedS101Svg, getThemedS52Svg, getTopmarkMeaning, haloFactor, hazardColor, hazardFillExpression, iconSliderFor, isDepthAreaClassLayerId, isDrapeable, isLabelLayerVisible, isMapLive, isNavAidLayer, isNavAidLayerVisible, isSoundingLayerVisible, isVisibleInMode, isWaterBodyLayerVisible, keptAboveSoundings, labelSortKey, lampRhythmColour, lampRhythmOpacity, lateralColor, lateralFillExpression, lightColor, lightFillExpression, lightsIconExpression, normalizeStyleMode, normalizeTheme, opaqueSplitBaseOf, paginate, parseListCodes, parseSigseqTerms, parseWebhook, patternSpriteId, preprocessLights, preprocessNavAids, preprocessSoundings, preprocessWaterBodies, rasterAtonIconExpression, relativeLuminance, resolveCustomTheme, resolveRasterImage, resolveS101Color, resolveStyle, resolveTargetClass, rhythmProperties, s101ArtworkProvenance, safetyContourValues, sanitizeCustomStyleConfig, scaleLinearLight, scaleSizeExpression, scaleSizeValue, scaminToMinZoom, sectorLimitToArcBearing, semiboldFontStack, snapChartSymbolScale, soundingPadding, soundingPaddingValue, splitOpaqueDepthAreas, stepChartSymbolScale, styleModeBand, terrainStackCount, textSliderFor, themeChrtGlyph, tileTemplate, uncoveredSectorArcs, withinBboxFilter, worldMinusBboxPolygon };
|