Terrain Viewer

State reference (URL & storage)

Every URL parameter the app reads, generated from the source at build time — state parameters mirrored by nuqs, instruction parameters read once on load, and the settings kept in localStorage

The tables on this page are generated from the app's source by docs/scripts/build-url-params.mjs, run before every docs build, so the deployed pages cannot drift (the tracked copies in git are refreshed by hand, pnpm run url-params, and may lag between releases). For how to compose a link or an iframe, see Embedding & URL parameters; for an interactive form over the same parameters, see URL as an API.

State parameters

Read and written by nuqs from QUERY_STATE_PARSERS in components/TerrainViewer.tsx. Booleans are true/false, lists are comma-separated, colours are hex, and a parameter at its default is omitted from the address bar. In the URL the terrain source keys are terrainSourceA…terrainSourceH; the same fields are sourceA…sourceH inside the code and inside a project preset's initialState (see lib/url-keys.ts), and the old URL spelling is still accepted.

ParameterTypeDefaultNote
projectstring""Embed/project convenience params: `project` looks up a named preset in lib/projects.json (see lib/project-config.ts); terrainUrl/basemapUrl let an embedder point straight at a raw tile/COG URL withou…
terrainUrlstring""
basemapUrlstring""
terrainTypestring""Explicit source type for terrainUrl/basemapUrl when it's a raw URL (not an existing source id) — type can't always be inferred from the URL shape alone (e.g.
basemapTypestring""
viewModeone of 2d | globe | 3d"3d"
appModeone of terrain | historical"terrain"Which sidebar layout the ModePicker (TerrainControlPanel.tsx) shows — "historical" strips it down to just basemap browsing.
splitStyleone of off | overlay | side-by-side"off"Master split control — replaces the old plain splitScreen boolean.
gridLayoutone of 2x1 | 3x1 | 4x1 | 1x2 | 2x2 | 3x2 | 4x2"2x1"Only meaningful once splitStyle !== "off"; "overlay" always behaves as "2x1" regardless of this value (see the splitContainer render below).
splitBlendModestring"difference""overlay"-only: pane B's CSS mix-blend-mode + opacity against pane A.
splitBlendModeEnabledbooleanfalseLets a picked blend mode be toggled off (falls back to plain "normal") without losing/resetting it — a quick way to flip back and forth between a blended and a plain overlay comparison for the same p…
overlayOpacitynumber1.0
splitRationumber0.5Split gutter position (overlay clip boundary / side-by-side divider) as a 0-1 ratio of the available width.
matchColorsToAbooleanfalse"overlay"-only: "Match Colors (View A as reference)" — live-samples both panes' CURRENTLY RENDERED canvases (whatever tiles are actually loaded in the viewport, re-sampled at most once/second) and re…
matchColorsColorSpacestring"rgb"Which color space the matching above is computed/applied in — "rgb" (default) is a live CSS filter; the others are a real per-pixel JS conversion, capped to a low working resolution (see HistogramMat…
showCaptureDatePillone of auto | off | date | source-date" as const"auto"Compare and Blend's "Show Capture Date" toggle — a small per-view pill for whichever views are actually on a dated historical source.
pillTerrainone of auto | always | never" as const"auto"What a view's pill names in a split: "auto" only when the views differ on it, "always", or "never" (Compare and Blend, Advanced).
pillBasemapone of auto | always | never" as const"auto"
pillModesone of auto | always | never" as const"auto"
terrainSourceCstring"mapterhorn"C-H only ever matter for gridLayout "2x2"/"3x1"/"3x2"/"4x1"/"4x2" — same shape as sourceA/B, just extra slots so bigger grids need no schema change.
terrainSourceDstring"mapterhorn"
terrainSourceEstring"mapterhorn"
terrainSourceFstring"mapterhorn"
terrainSourceGstring"mapterhorn"
terrainSourceHstring"mapterhorn"
basemapPerViewbooleantrue
basemapSourceAstring"esri"
basemapSourceBstring"google"
basemapSourceCstring"esri"
basemapSourceDstring"google"
basemapSourceEstring"esri"
basemapSourceFstring"google"
basemapSourceGstring"esri"
basemapSourceHstring"google"
overlayBasemapIdslist of string (comma-separated)[]'overlay'-role custom basemap sources currently stacked on top of the active basemap (see basemap-byod-section.tsx's checkbox list) — shared across A/B, only meaningful in split-or-radio basemap mode…
overlayBasemapIdsBlist of string (comma-separated)[]Per-view overlay lists for split / grid layouts when basemapPerView is on (view A keeps overlayBasemapIds), picked with the same grid toggle as the per-view basemaps.
overlayBasemapIdsClist of string (comma-separated)[]
overlayBasemapIdsDlist of string (comma-separated)[]
overlayBasemapIdsElist of string (comma-separated)[]
overlayBasemapIdsFlist of string (comma-separated)[]
overlayBasemapIdsGlist of string (comma-separated)[]
overlayBasemapIdsHlist of string (comma-separated)[]
dateinteger0The ONE scrubbed date (epoch ms) for whichever concrete historical source is active on this side (historicalActiveSource(A/B) below) — Wayback/HLS/GE-Historical/Planet/EOX-S2/Bing all share this sing…
dateAinteger0
dateBinteger0
dateCinteger0
dateDinteger0
dateEinteger0
dateFinteger0
dateGinteger0
dateHinteger0
historicalActiveSourcestring"wayback"Which concrete underlying source (wayback/hls/ge-historical/planet/ eox-s2) actually renders when basemapSource(A/B) === "historical" — the sidebar only ever exposes one combined "Historical Imagery"…
historicalActiveSourceAstring"wayback"
historicalActiveSourceBstring"wayback"
historicalActiveSourceCstring"wayback"
historicalActiveSourceDstring"wayback"
historicalActiveSourceEstring"wayback"
historicalActiveSourceFstring"wayback"
historicalActiveSourceGstring"wayback"
historicalActiveSourceHstring"wayback"
timelineSourceslist of string (comma-separated)["wayback", "ge-historical", "bing"]Which historical sources' ticks are aggregated onto the shared timeline (pill toggles in historical-timeline-panel.tsx) — independent of which single source is actually "active"/rendered on the map.
timelineCatalogslist of string (comma-separated)[]Catalogs whose items covering the view become timeline ticks (lib/timeline-catalogs.ts), picked from the timeline's Catalogs tree.
timelineSourcesAlist of string (comma-separated)["wayback", "ge-historical", "bing"]Per-side variants of timelineSources above — only meaningful when both basemapPerView AND splitStyle!=="off" are on (dualMode) AND the timeline's sync toggle is off, letting each active view aggregat…
timelineSourcesBlist of string (comma-separated)["wayback", "ge-historical", "bing"]
timelineSourcesClist of string (comma-separated)["wayback", "ge-historical", "bing"]
timelineSourcesDlist of string (comma-separated)["wayback", "ge-historical", "bing"]
timelineSourcesElist of string (comma-separated)["wayback", "ge-historical", "bing"]
timelineSourcesFlist of string (comma-separated)["wayback", "ge-historical", "bing"]
timelineSourcesGlist of string (comma-separated)["wayback", "ge-historical", "bing"]
timelineSourcesHlist of string (comma-separated)["wayback", "ge-historical", "bing"]
historicalTimelineCollapsedbooleanfalseWhether the historical timeline's full bar (header + track) is collapsed down to just the small floating clock-icon toggle button.
sidebarCollapsedbooleanfalseThe side panel, folded.
coverageOverlayslist of string (comma-separated)Coverage footprints drawn on the map (Source Info -> Coverage overlays).
drawingUrllist of string (comma-separated)[]Remote vector data in the Drawing tool, one layer per URL (comma- separated; nuqs encodes commas inside an item).
historicalControlsExpandedbooleantrueWhether the timeline's title/source-pills/resolution-chips header row is shown (true) or the panel is in its minimal, track-only mode with just a small floating cog+collapse chip (false).
resolutionClasseslist of string (comma-separated)["vhr", "medium"]Resolution-class filter alongside the source pills above — "vhr" (Wayback/GE Historical/Bing, sub-meter-ish) vs "medium" (HLS's 10-30m Landsat/Sentinel-2, Planet's ~4.7m monthly mosaic) — see SOURCE_…
colorRampstring"mby"colorRamp: parseAsString.withDefault("mby"),
customStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
customStopsDiscretebooleanfalse
showHillshadebooleantrueNative MapLibre Hillshade — its own independent viz mode, entirely separate from "Lighting Effects" (Matcap/Phong) below.
hillshadeOpacitynumber1.0
showLightingEffectsbooleanfalse"Lighting Effects" viz mode — master toggle/opacity, housing two sub-modes: Matcap first, Phong second (see lighting-effects-options-section.tsx).
lightingEffectsOpacitynumber1.0
showMatcapbooleanfalse"Matcap" sub-mode (lib/matcap-protocol.ts) — a plain raster overlay (draped over 3D terrain the same automatic way the raster basemap is) that looks up color from a material-capture image using the s…
matcapOpacitynumber1.0
matcapTextureIdstringDEFAULT_MATCAP_ID
matcapRotationDegnumber0"Sphere Rotation" — spins the matcap lookup independently of the map's own bearing (a raster tile is baked once per z/x/y, so it can't track live bearing the way a real-time GPU shader could).
matcapRendererone of raster | live" as const"live""raster" (default): lib/matcap-protocol.ts's plain raster-tile pipeline — drapes correctly over 3D terrain exaggeration AND globe, but every rotation/exaggeration change costs a real tile refetch.
matcapLightRelativeToCamerabooleantrue"Light Anchor", ported from Phong's phongLightRelativeToCamera — only meaningful in "live" (2D Fast): off (Absolute) samples the material by the tile-space normal, pinned to compass directions and id…
showPhongbooleantrue"Phong" sub-mode (lib/phong-protocol.ts) — a plain raster overlay doing real ambient+diffuse+specular shading from a compass-fixed light (state.illuminationDir/illuminationAlt below — the same fields…
phongOpacitynumber1.0
phongDiffuseStrengthnumber0.8
phongSpecularStrengthnumber0.2
phongFresnelStrengthnumber0Fresnel rim on the live Phong renderer: strength 0 = off, power = falloff.
phongFresnelPowernumber3
phongLightRelativeToCamerabooleantrueOff (default — briefly flipped to Camera on 2026-08-20, reverted the same day on the user's follow-up): illuminationDir is a compass azimuth, fixed to the world, matching maplibre's own hillshade ill…
phongLightCountinteger1Up to three Phong lights (live renderer): light 1 is the app light (illuminationDir/Alt) with its own colour; lights 2 and 3 have their own direction and colour and only affect Phong.
phongLight1Colorcolor"#ffffff"
phongLight2Dirnumber45
phongLight2Altnumber35
phongLight2Colorcolor"#4a90d9"
phongLight3Dirnumber135
phongLight3Altnumber35
phongLight3Colorcolor"#b8692e"
phongRendererone of raster | live" as const"live""raster" (default): lib/phong-protocol.ts's plain raster-tile pipeline — drapes correctly over 3D terrain exaggeration AND globe, but every light/strength/exaggeration change costs a real tile refetc…
showShadowsbooleanfalse"Shadows" sub-mode (lib/shadow-protocol.ts) — a plain binary raster mask: for each pixel, marches toward the sun's actual azimuth (state.illuminationDir/illuminationAlt below — same shared light as H…
shadowOpacitynumber0.6
shadowRadiusPxnumber32"Search Radius" — same convention as SVF/Openness: how many same-zoom pixels the single ray marches outward looking for an obstruction.
showBuildingShadowsbooleanfalseShadows cast by OSM buildings on flat ground at their foot (components/LayersAndSources/BuildingShadowLayer.tsx): heights from OpenFreeMap's building layer, same light as the other shadows.
buildingShadowOpacitynumber0.5
lightUseDatetimebooleanfalse"Datetime-based" light: when on, illuminationDir/illuminationAlt are driven from a physically-plausible sun position (see lib/solar-position.ts) computed from the viewport-center lat/lng + these day-…
lightTimeModeone of local | utc" as const"local"Which clock convention lightTimeOfDay is expressed in — "local": the real civil wall-clock time at the viewport lat/lng, including that location's actual DST rules (see lib/timezone.ts); "utc": UTC d…
vizSyncbooleantruePer-view visualization modes (lib/viz-views.ts): vizSync true draws every mode on every view; false draws each mode on the views listed in vizViews ("showSlope:AC;showLrm:B"), chosen with the view gr…
vizViewsstring""
showColorReliefbooleanfalse
colorReliefOpacitynumber0.35
showTerrainAnalysisbooleanfalseMaster toggles for what used to be one merged "Slope and More" viz mode, now split into Terrain Analysis (surface derivatives + neighborhood statistics: Slope/Aspect/Curvature/Det Hessian/Blobness/TP…
terrainAnalysisOpacitynumber1.0Master opacity for Terrain Analysis — composites (multiplies) with each sub-mode's own opacity below, rather than replacing it.
showReliefVisualizationbooleanfalse
reliefVisualizationOpacitynumber1.0
showSlopebooleantrue
slopeOpacitynumber1.0
slopeColorRampstring"slope-plantopo"
slopeSourceModeone of plantopo | client"client"
slopeMinDegreesnumber0
slopeMaxDegreesnumber55
slopeInvertColorRampbooleanfalse
slopeCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPSOnly read when slopeColorRamp === "custom" — see computeColorReliefPaint's dedicated branch for that ramp id in MapLayers.tsx.
slopeCustomStopsDiscretebooleanfalseWhen the custom ramp is selected, render its stops as hard discrete bands (each color holds until the next stop) instead of a continuous gradient.
showAspectbooleanfalse
aspectOpacitynumber0.5
aspectColorRampstring"aspect-compass"
aspectMinDegreesnumber0
aspectMaxDegreesnumber360
aspectShiftDegreesnumber0
aspectInvertColorRampbooleanfalse
aspectCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
aspectCustomStopsDiscretebooleanfalse
showTribooleanfalse
triOpacitynumber1.0
triColorRampstring"tri-default"
triMinnumber0
triMaxnumber50
triInvertColorRampbooleanfalse
triCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
triCustomStopsDiscretebooleanfalse
showCurvaturebooleanfalse
curvatureOpacitynumber1.0
curvatureModeone of combined | profile | plan | det-hessian | casorati | shape-index"combined"
curvatureColorRampstring"curvature-diverging"
curvatureMinnumber-1±1 matches Mean/Combined's defaultMagnitude (curvature-options-section.tsx).
curvatureMaxnumber1
curvatureInvertColorRampbooleanfalse
curvatureSymmetricbooleantrue
curvatureCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
curvatureCustomStopsDiscretebooleanfalse
showTpibooleanfalse
tpiOpacitynumber1.0
tpiColorRampstring"tpi-diverging"
tpiMinnumber-20
tpiMaxnumber20
tpiInvertColorRampbooleanfalse
tpiSymmetricbooleantrue
tpiCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
tpiCustomStopsDiscretebooleanfalse
showLrmbooleantrue
lrmOpacitynumber1.0
lrmColorRampstring"lrm-diverging"
lrmMinnumber-20
lrmMaxnumber20
lrmInvertColorRampbooleanfalse
lrmSymmetricbooleantrue
lrmRadiusnumber16
lrmCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
lrmCustomStopsDiscretebooleanfalse
showRoughnessbooleanfalse
roughnessOpacitynumber1.0
roughnessColorRampstring"roughness-default"
roughnessMinnumber0
roughnessMaxnumber50
roughnessInvertColorRampbooleanfalse
roughnessCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
roughnessCustomStopsDiscretebooleanfalse
showShapeIndexbooleanfalse
shapeIndexOpacitynumber1.0
shapeIndexColorRampstring"custom"
shapeIndexMinnumber-1
shapeIndexMaxnumber1
shapeIndexInvertColorRampbooleanfalse
shapeIndexSymmetricbooleantrue
shapeIndexCustomStopsramp-stopsDEFAULT_SHAPE_INDEX_CUSTOM_STOPS
shapeIndexCustomStopsDiscretebooleantrue
showBlobnessbooleanfalse
blobnessOpacitynumber1.0
blobnessColorRampstring"blobness-default"
blobnessMinnumber0
blobnessMaxnumber50
blobnessInvertColorRampbooleanfalse
blobnessCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
blobnessCustomStopsDiscretebooleanfalse
showEigenRatiobooleanfalse
eigenRatioOpacitynumber1.0
eigenRatioColorRampstring"eigen-ratio-default"
eigenRatioMinnumber0
eigenRatioMaxnumber100
eigenRatioInvertColorRampbooleanfalse
eigenRatioCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
eigenRatioCustomStopsDiscretebooleanfalse
showOrientationbooleanfalse
orientationOpacitynumber1.0
orientationColorRampstring"orientation-default"
orientationMinnumber0
orientationMaxnumber180
orientationInvertColorRampbooleanfalse
orientationCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
orientationCustomStopsDiscretebooleanfalse
showSvfbooleanfalse
svfOpacitynumber1.0
svfColorRampstring"svf-default"
svfMinnumber0
svfMaxnumber100
svfInvertColorRampbooleanfalse
svfRadiusnumber8
svfPrecisionone of precise | fast"fast"
svfCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
svfCustomStopsDiscretebooleanfalse
showOpennessbooleanfalse
opennessOpacitynumber1.0
opennessColorRampstring"openness-default"
opennessMinnumber-15
opennessMaxnumber15
opennessInvertColorRampbooleanfalse
opennessSymmetricbooleantrue
opennessRadiusnumber8
opennessModeone of positive | negative"positive"
opennessPrecisionone of precise | fast"fast"
opennessCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
opennessCustomStopsDiscretebooleanfalse
showLocalDominancebooleanfalseLocal Dominance (Hesse 2016) — Relief Visualization mode, see lib/local-dominance-protocol.ts.
localDominanceOpacitynumber1.0
localDominanceColorRampstring"local-dominance-default"
localDominanceMinnumber-5
localDominanceMaxnumber15
localDominanceInvertColorRampbooleanfalse
localDominanceSymmetricbooleanfalse
localDominanceMinRadiusnumber8
localDominanceMaxRadiusnumber32
localDominanceCustomStopsramp-stopsDEFAULT_SLOPE_CUSTOM_STOPS
localDominanceCustomStopsDiscretebooleanfalse
showPlaneSlicerbooleanfalsePlane Slicer — Tools: Elevation Picker sub-section.
showGeorefbooleantrueGeoreference tool (Tools): a plain image drawn on the map from control points.
georefImagestring""
georefGcpsstring""
georefTypestring"helmert"
georefOpacitynumber0.8
planeSlicerReferenceModeone of absolute | lrm"absolute"
planeSlicerValuenumber0Absolute and LRM keep independent threshold values — the two reference frames have wildly different natural ranges (metres of real elevation vs.
planeSlicerValueLrmnumber0
planeSlicerSideone of above | below"below"
planeSlicerColorstring"#3388ff"
planeSlicerOpacitynumber0.6
elevationPickerReferenceModeone of absolute | lrm"absolute"Same Absolute/LRM reference as Plane Slicer, for the Elevation Picker's point/profile sampling itself (lib/elevation-query.ts) — "LRM" here has no 3D-mesh equivalent (map.queryTerrainElevation() only…
showTellsDetectorbooleanfalseMaster on/off (Visualization Modes' "Tells (Mound Detector)" checkbox) — gates the sidebar's Mound Candidates section as well as the map layer.
tellsMarkersVisiblebooleantrueMound Candidates section's own "Show mound candidates" checkbox — a pure paint-visibility toggle for markers already being computed, independent of showTellsDetector so it can't also collapse the sec…
tellsStyleone of outline | byBlobness | byPlan | byDetHessian | byLrm"outline"
tellsOutlineColorcolor"#ef4444"
tellsScaleMarkersbooleantrueOnly meaningful with tellMeasureScale on: draw each marker at tellsScaleMultiplier x its measured diameter (real-world meters, zoom-scaled) instead of fixed px.
tellsScaleMultipliernumberTELLS_MEASURED_SCALE_MULTIPLIER_DEFAULT
tellSizenumber100
tellRadiusnumber4
tellMinReliefnumber1.5
tellBlobnessMinnumber0
tellPlanMinnumber0
tellDetHessianMinnumber0
tellMeasureScalebooleantrue
tellVetoResolutionone of fine | coarse"coarse"
tellsPolarityone of mounds | pits | both"mounds"Which extrema the detector reports: mounds (local maxima of the relief, the archaeological tell), pits (minima: quarries, sinkholes, craters, cisterns, robbed-out tombs) or both.
tellsPitColorcolor"#3b82f6"
tellsFrozenbooleanfalse"Frozen" pins the currently-computed candidates in place (snapshotted into a plain geojson source, see the tellsFrozenSnapshot state and TellsSource's frozen/frozenSnapshot props below) so panning/zo…
showContoursAndGraticulesbooleanfalse
showContoursbooleantrue
showContourLabelsbooleantrue
showGraticulesbooleanfalse
showRasterBasemapbooleanfalse
showBackgroundbooleanfalse
matchThemeColorsbooleantrueSky/horizon/fog colors for the Background + Fog/Sky mode (background- options-section.tsx) — URL-shareable state like every other viz-mode field, not a localStorage preference (was previously a plain…
skyColorcolor"#80ccff"
skyHorizonBlendnumber0.5
horizonColorcolor"#ccddff"
horizonFogBlendnumber0.5
fogColorcolor"#fcf0dd"
fogGroundBlendnumber0.2
backgroundLayerActivebooleantrue
rasterBasemapOpacitynumber1.0Viz-mode master opacity (the "Raster Basemap" checkbox's own slider) — composites (multiplies) with basemapSourceOpacity below for the single/split basemap layer, same pattern as Slope-and-More's mas…
basemapSourceOpacitynumber1.0Basemap-solo opacity (the "Basemap Opacity" slider inside the Basemap Source section) — only affects the single/split basemap layer, not overlays.
overlaysOpacitynumber1.0Every overlay basemap at once (the Overlays heading's pill); each overlay's own opacity (its pill) is the source's `opacity` in local storage.
overlaysStackone of under | relief | top" as const"under"Where every overlay sits in the layer stack: under the relief layers, above the colour relief ("relief") or above every terrain layer.
exaggerationnumber1
latnumber21.4208Whole-earth start, the same view handleGoHome resets to and historical mode already used.
lngnumber0
zoomnumber1.52
pitchnumber0-- try getting out of pitch 0 loop in 3d pitch: parseAsFloat.withDefault(60.001),
bearingnumber0
hillshadeMethodone of standard | combined | igor | basic | aspect-multidir | multidir-colors | duotone-nw-ne"combined"--
illuminationDirnumber315
illuminationAltnumber45
shadowColorcolor"#000000"shadowColor: parseAsString.withDefault("#000000"), highlightColor: parseAsString.withDefault("#FFFFFF"), accentColor: parseAsString.withDefault("#808080"),
highlightColorcolor"#FFFFFF"
accentColorcolor"#808080"
hillshadeExagnumber1.0graticuleColor: parseAsString.withDefault("#000"), graticuleColor: parseAsString, // don't use default to sync with theme
contourReferenceModeone of absolute | lrm" as const"absolute"Absolute ("real altitude") vs LRM ("height above/below the local neighborhood mean") — same reference concept Plane Slicer introduced (PLANE_SLICER_REFERENCE_MODES above), applied to what the contour…
showIsolinebooleanfalseThe Iso-line (Contours & GeoGrid): a line where a measure (the elevation, any derived mode, a light's shading) crosses a value, with a raster fill of the area above, or a line every interval of the m…
isolineMeasurestring"slope"
isolineModeone of value | interval" as const"value"
isolineValuenumber30
isolineIntervalnumber10
isolineFillbooleanfalse
isolineCliffbooleanfalseSlope at a value only: cliff teeth along the line, pointing into the steep area (both edges of a steep band get them).
isolineFillOpacitynumber0.35
isolineWeightnumber2
isolineColorstring"#ef4444"
contourMinornumber50
contourMajornumber200
contourMinorLrmnumber5Absolute and LRM keep independent interval values, same reasoning as planeSlicerValue/planeSlicerValueLrm — LRM's natural range (roughly ±100m of local relief) is much narrower than real elevation's,…
contourMajorLrmnumber20
contourWeightnumber1Multiplies both major and minor contour line-width — default (1) keeps today's major-vs-minor ratio, 2/4 make both proportionally bolder.
contourColorstring""Contour line / graticule colors — empty string means "auto" (theme-adaptive: the contour lines fall back to translucent black/white by theme, the grid to themeAntiColor).
customHypsoMinMaxbooleanfalse
hypsoSymmetricbooleanfalseMin/Max mirrored around 0 (one magnitude), like the curvature ramp: for height-above-ground or elevation-change grids (DSM − DTM, dh).
minElevationnumber0
maxElevationnumber8100
hypsoSliderMinBoundnumber-8000
hypsoSliderMaxBoundnumber5000
graticuleWidthnumber1.0
graticuleColorstring""
showGraticuleLabelsbooleanfalse
graticuleDensitynumber0
minimapMinimizedbooleantrue
placestring""A place name to show in the geocoder, expanded, as its placeholder: set by links that open a named site (the docs' Research References), so the view says where it is.
invertColorRampbooleanfalseKeyframe/360 animation state (animDuration, animLoopMode, animSmoothCamera, animPlaying, animPlaying360, animPose1, animPose2Delta) lives in its own nuqs hook inside CameraUtilities.tsx, not in this …
maxBoundsModeone of none | terrain | raster | union | custom"terrain"Max map bounds (Settings > Map Bounds) — constrains pan/zoom rather than a one-shot camera fly like the smart-zoom/fit-to-bounds features above.
maxBoundsBuffernumber0
maxBoundsWestnumber-180
maxBoundsSouthnumber-85
maxBoundsEastnumber180
maxBoundsNorthnumber85

346 parameters read from the app source at build time; 5 multi-line declarations not parsed.

Instruction parameters

Read once on load, never written by the app, left in place in the URL. They either load something or apply a one-time setting.

ParameterTypeEffect
projectstringA named preset from lib/projects.json: hidden panels, initial state, bundled sources.
terrainUrlstringView A's terrain as a URL, registered under a fixed id (older form of terrainSourceA=https://…).
basemapUrlstringView A's basemap as a URL (older form of basemapSource=https://…).
terrainTypestringType of URL terrain sources (cog, terrarium, terrainrgb, wms-raw, tilejson …) instead of the {z} guess.
basemapTypestringType of URL basemap sources (cog, tms, wms, wmts, tilejson) instead of the {z} guess.
viaTitilerbooleanRoute URL COGs through titiler (files not in Web Mercator).
addSourceslist of string (comma-separated)Library entries (by id) made available in the BYOD lists without being selected.
addTerrainUrllist of string (repeat the parameter)URL terrain sources made available without being selected (repeat the parameter).
addBasemapUrllist of string (repeat the parameter)URL basemaps made available without being selected (repeat the parameter).
addOverlayUrllist of string (repeat the parameter)URL overlays made available; overlayBasemapIds (state) turns overlays on.
openSectionslist of string (comma-separated)Sidebar sections expanded on load (general, terrainSource, hillshade, drawing …).
closeSectionslist of string (comma-separated)Sidebar sections collapsed on load.
scrollTostringSection key (or element id) the side panel opens and scrolls to.
startTourbooleanStarts the product walkthrough.
bookmarksGallerybooleanOpens the Bookmarks gallery modal on arrival.
openLibrarystringterrain | basemap - opens that Library modal (the curated dataset list) on arrival.
bookmarksUrlstringA bookmarks JSON (the Bookmarks section's export format) fetched and merged into the visitor's bookmarks; pair with openSections=bookmarks.

Stored settings (localStorage)

jotai atomWithStorage atoms: API keys, beta flags, panel folds, export preferences, the BYOD source lists. None of these is in the URL; a project export carries a curated subset.

localStorage keyDefaultNoteDefined in
mapboxKeyimport.meta.env.VITE_MAPBOX_ACCESS_TOKEN ?? ""These were hardcoded literals committed here — all moved to local, gitignored VITE_*_API_KEY / VITE_MAPBOX_ACCESS_TOKEN vars (see .env) instead, same pattern as hereKeyAtom below.lib/settings-atoms.ts
googleKeyimport.meta.env.VITE_GOOGLE_API_KEY ?? ""lib/settings-atoms.ts
mapzenKey"mapzen-xxxxxxx"lib/settings-atoms.ts
maptilerKeyimport.meta.env.VITE_MAPTILER_API_KEY ?? ""lib/settings-atoms.ts
hereKeyimport.meta.env.VITE_HERE_API_KEY ?? ""Unlike mapbox/maptiler/google above, no public demo key is committed here — HERE requires a paid account, so its default comes from a local, gitignored VITE_HERE_API_KEY (see .env) instead of a hardc…lib/settings-atoms.ts
planetKeyimport.meta.env.VITE_PLANET_API_KEY ?? ""Same gating pattern as hereKeyAtom — Planet's monthly mosaics require a paid account, so "planet" only appears as a Basemap option (raster-basemap- section.tsx) once a real key is set, from a local V…lib/settings-atoms.ts
planetAccessToken""lib/settings-atoms.ts
cesiumIonKeyimport.meta.env.VITE_CESIUM_ION_TOKEN ?? ""Cesium ion access token.lib/settings-atoms.ts
cesiumDetailOffset1Extra quantized-mesh levels to fetch per tile.lib/settings-atoms.ts
disabledStacPresets[]STAC catalogs the visitor has switched OFF in the Library's Catalogs section: stored as the exclusions rather than the inclusions so a preset added in a later release is on by default instead of sile…lib/settings-atoms.ts
savedStacCatalogs[]lib/settings-atoms.ts
customTimelineCatalogs[]lib/settings-atoms.ts
timelineFootprintsfalseThe timeline's Catalogs picker switches: item footprints drawn on the map, and only items dated within the timeline's window.lib/settings-atoms.ts
timelineWindowFilterfalselib/settings-atoms.ts
timelineFollowViewporttrueOff: the catalogs are not asked again as the map moves (the ticks stay).lib/settings-atoms.ts
coverageVisibletrueEvery coverage overlay hidden at once, the selection kept.lib/settings-atoms.ts
coverageOutlineOnlyfalseCoverage footprints as outlines only, twice as bold, no fill.lib/settings-atoms.ts
tickPicksKeeptruelib/settings-atoms.ts
coverageActiveExtentsfalselib/settings-atoms.ts
allmapsRemoveColor{ enabled: false, auto: true, autoGain: 0.5, color: "#fffff…lib/settings-atoms.ts
profileDockedfalselib/settings-atoms.ts
titilerEndpoint"https://titiler.xyz"lib/settings-atoms.ts
customBasemapLastType"auto"lib/settings-atoms.ts
osmBuildings3dfalselib/settings-atoms.ts
osmBuildingsStyleOSM_BUILDINGS_STYLE_DEFAULTlib/settings-atoms.ts
customTerrainLastType"auto"lib/settings-atoms.ts
maxResolution4096lib/settings-atoms.ts
exportResolutionMode"screen"lib/settings-atoms.ts
exportValueFormat"raw"lib/settings-atoms.ts
exportImageFormat"tiff"lib/settings-atoms.ts
exportZipfalselib/settings-atoms.ts
snapshotAction"download"lib/settings-atoms.ts
exportCrs"3857"lib/settings-atoms.ts
useCogProtocolVsTitilertruelib/settings-atoms.ts
useClientExporttrueDTM export mode: client-side (browser range-reads/tile-mosaic, no titiler, no server-side size limit) vs the original titiler-based export — see lib/client-export.ts.lib/settings-atoms.ts
colorRampType'classic'lib/settings-atoms.ts
licenseFilter'open-distribute' lib/settings-atoms.ts
highResTerraintruelib/settings-atoms.ts
cacheVizTilestrueGates lib/tile-result-cache.ts — the LRU of finished viz-mode tile bytes that makes re-toggling a mode instant instead of recomputing every visible tile.lib/settings-atoms.ts
geHiDpiTilestrueGoogle Earth Historical tiles built from one Keyhole level finer into 512 px images (Settings → Streaming): no vertical stretch away from the equator and a 2x image for HiDPI screens, for four times …lib/settings-atoms.ts
terrainAnalysisAdvancedtrueBasic/Advanced toggle, one per section (Terrain Analysis / Relief Visualization — terrain-analysis-section.tsx / relief-visualization-section.tsx): in "basic" mode each sub-mode collapses to just its…lib/settings-atoms.ts
reliefVisualizationAdvancedtruelib/settings-atoms.ts
lightingEffectsAdvancedtruelib/settings-atoms.ts
hasSeenTourfalseGuided product tour (components/TerrainControlPanel/product-tour.tsx).lib/settings-atoms.ts
customTerrainSources[]getOnInit: true reads localStorage synchronously on first render instead of the jotai default (hardcoded `[]` on first paint, real value applied post-mount via onMount).lib/settings-atoms.ts
isByodOpentruelib/settings-atoms.ts
customThemes[]lib/settings-atoms.ts
customBasemapSources[]lib/settings-atoms.ts
isBasemapByodOpentruelib/settings-atoms.ts
byodBasemapsOpentrueThe Basemap and Overlays groups of the basemap BYOD list, folded or not.lib/settings-atoms.ts
byodOverlaysOpentruelib/settings-atoms.ts
isHillshadeXYPadOpentruelib/settings-atoms.ts
bookmarksListHeightnullUser-dragged height (px) of the Bookmarks list's scroll area (bookmarks-section.tsx's drag handle below it) — null means "use the default max-h-64 clamp".lib/settings-atoms.ts
collapsedBookmarkGroups[]Ids of "project" (root) bookmarks whose children are currently folded away — bookmarks-section.tsx's file-tree-style collapse.lib/settings-atoms.ts
bookmarksViewMode"list"Sidebar bookmarks list presentation — "list" (default: the original tree of project rows with children indented beneath) or "grid" (flattened thumbnail tiles, a compact in-panel cousin of the gallery…lib/settings-atoms.ts
bookmarksFoldsOpen{ featured: true, own: true }lib/settings-atoms.ts
bookmarksGalleryViewMode"grid"Gallery MODAL presentation — "grid" (default: the original thumbnail cards) or "list" (compact rows: small thumbnail left, project + view name right).lib/settings-atoms.ts
vizModePinnedtruePins Visualization Modes open through "Fold all sections" (TerrainControlPanel.tsx) — that's the master on/off switchboard for every viz layer, so folding it away along with everything else hides the…lib/settings-atoms.ts
appMode"terrain"lib/settings-atoms.ts
isTransparentUitruelib/settings-atoms.ts
isExportSettingsOpenfalseDownload and Snapshot's own "Export settings" fold (see download-section.tsx).lib/settings-atoms.ts
snapshotIncludeTimelinefalseSnapshot / Copy / Share: keep the historical timeline in the picture, or (default) crop the strip it covers off the bottom - see captureMapScreenshot.lib/settings-atoms.ts
anim-render-quality'normal'lib/settings-atoms.ts
anim-fps60lib/settings-atoms.ts
anim-target-size-mb''lib/settings-atoms.ts
lastSeenChangelogAt"2026-08-01"ISO date ("YYYY-MM-DD") of the newest changelog entry's `<!-- released -->` marker the user has already seen — see lib/changelog.ts.lib/settings-atoms.ts
changelogView"changes""changes" (just what's new since last visit) vs "full" (every entry) — always defaults to "changes", regardless of whether there's currently anything unseen.lib/settings-atoms.ts
betaEnabled{ tells: false, georef: false }The beta gates.lib/settings-atoms.ts
galleryFlattenGroupstrueBookmarks gallery modal: on (default) flattens every group's cards into one continuous grid (each card's label prefixed with its project name) so nothing but the real bookmark count determines how mu…lib/settings-atoms.ts
galleryShowFeaturedtrueBookmarks gallery modal: whether the read-only Featured/preset strip (see lib/preset-bookmarks.ts) shows as its own section at the top of the gallery, alongside the visitor's own saved bookmarks.lib/settings-atoms.ts
splitRatio0.5Draggable A/B split-screen divider — persisted (like isSidebarOpenAtom) since it's a user layout preference, not per-session UI state.lib/layout-constants.ts
colorizeMapBordersfalseOutlines each active map pane in its resolved side color (SIDE_COLORS, overridden by sideColorOverridesAtom) — purely cosmetic, off by default so it doesn't surprise anyone not using the comparison/g…lib/layout-constants.ts
colorizeMapBordersInsettrueWhether that border sits inset 3px from the pane edge (default, reads as a frame) or flush against it — dropping the inset doubles the stroke width (border-2 -> border-4) so a flush border doesn't re…lib/layout-constants.ts
isComparisonMixAdvancedOpenfalseCompare and Blend section's own "Advanced" (capture date / colorize borders / side colors) collapsible — persisted like every other section-local collapse toggle (isBasemapByodOpenAtom etc.lib/layout-constants.ts
isSidebarOpentrue--- Persisted state ---components/TerrainControlPanel/TerrainControlPanel.tsx
sectionOpenDEFAULT_OPEN_STATEcomponents/TerrainControlPanel/TerrainControlPanel.tsx
sidebarScroll0components/TerrainControlPanel/TerrainControlPanel.tsx
drawingExportPerLayerfalseexportGeoJSON toggle (TerraDrawActions below): off (default) exports every layer's features flattened into one FeatureCollection — the existing behavior, and still the right default for "keep drawing…components/TerrainControlPanel/TerraDrawSystem.tsx
drawingExportScopenullcomponents/TerrainControlPanel/TerraDrawSystem.tsx
drawingLayers[DEFAULT_LAYER]Layer metadata (id/name/color/stroke width) is small enough to persist directly in localStorage — this doubles as the list of layer ids whose *geometry* gets hydrated from OPFS on mount (see hydrateP…components/TerrainControlPanel/TerraDrawSystem.tsx
activeLayerIdDEFAULT_LAYER.idcomponents/TerrainControlPanel/TerraDrawSystem.tsx
persistVectorLayerstruecomponents/TerrainControlPanel/TerraDrawSystem.tsx

82 stored settings read from the app source at build time. None is in the URL; a project export carries a curated subset.

On this page