Numeric raster encoding and palettes

Keep numeric pixel encoding in Channel and raster colors in Layer presentation.

Raw Markdown

Rule

A raster Channel declares a validated, versioned pixel_delivery. Its kind is scalar, categorical, imagery, or vector field, and its sampling mode says whether inspection reads the rendered tile, a request variant, frame metadata, or a runtime field. A raster is paletteable only when the contract is scalar with sampling.mode=rendered-tile and contains a presentation-neutral value_encoding. That nested contract records the pixel codec, numeric range, validity or NoData channel, quantity, and unit. It does not contain colors.

The Layer owns rasterScalarColorRamp, including optional per-stop opacity, plus overall opacity and resampling. A Data Product may provide a recommended palette for newly created Layers, but changing that default must not recolor existing maps.

A shared palette is an ordered normalized colour ramp: every stop has a strictly increasing 0..1 position, color, and optional opacity. Its coordinate is never a provider's temperature, population, or other physical unit. The first and last stops may sit inside that domain. Renderers clamp values outside them to the nearest edge colour, while catalog strips leave the outside segment neutral so the active interpolation range remains visible. The catalog records applicability through uses and does not assign a separate scale kind: the ordered stops themselves fully determine interpolation. Layer also owns rasterScalarPaletteTransform (linear or log), which maps the Channel's declared physical range to that normalized coordinate. The renderer derives physical stops only when rendering and producing legends; picker previews show the normalized ramp. Legacy rasterScalarPalette physical stops remain readable for saved maps and Original snapshots. Existing Layer styles without the normalized field keep their established quantity-specific mapping; residential population density defaults to logarithmic mapping for new palette choices.

The administrator catalog editor keeps the exact normalized gradient strip and may also lease the application's sole persistent Mapbox host for an interactive draft preview. The administrator chooses a Map from their personal library; the preview activates that Map's persisted basemap, basemap configuration, visibility, contrast, projection, atmosphere, and viewport, then applies the unsaved normalized ramp to an explicitly selected visible numeric-raster Layer; the highest layer is the initial selection. It honors per-stop opacity, never creates a second Mapbox instance, and never mutates a persisted Map or Layer. The preview also exposes the Layer-owned linear or logarithmic value scale and initializes it from the selected Layer; logarithmic mapping is available only for a non-negative physical range. Changing it remains local to the preview. While a numeric Layer is selected, the editor annotates every normalized color stop with the physical value derived from that Layer's Channel range, unit, and active linear or logarithmic transform. These annotations are preview-only and are never stored in the shared normalized ramp. An existing shared palette can be cloned into an independent draft; the clone copies its stops and applicability but receives a new unique stable ID before it can be created, so saved Layers continue to reference the original preset. The same preview exposes local-only basemap-style, Mapbox light-preset, Standard theme, and semantic-object visibility controls. They initialize from the selected Map and never persist their draft values back to it.

When a provider-backed Layer is created, its resolved initial palette is also copied to rasterScalarOriginalPalette. A multi-channel add carries distinct snapshots in rasterScalarOriginalPalettes, keyed by immutable Channel export key, until the resulting Layers resolve their own binding. The palette picker exposes the applicable immutable snapshot as Original; later choices replace only rasterScalarColorRamp. Layers created before these fields use their semantic quantity default as the compatibility snapshot on the first change.

Supported path

Encoded r8-linear and rg16-linear tile pyramids use the shared scalar palette controls, legend, and Mapbox raster-color path. Provider alpha remains authoritative for transparent NoData pixels. Invalid or incomplete encoding is fail-closed rather than guessed from image contents.

Generic raster tiles use one immutable frame identity containing URL, tile size, native zoom range, and bounds. Camera movement never recreates that frame. A new temporal or period frame uses one explicit swap policy: progressive first-tile crossfade for ordinary bands, or atomic source-loaded cutover for a different data selection. Period-specific tiles use the atomic policy so the complete previous viewport remains until the replacement is ready.

A scalar Channel whose source contains meaningful values above the Web Mercator latitude limit may declare the fixed mapbox-globe-poles-v3 polar_caps contract. Each immutable band then includes north and south RGBA encoded azimuthal textures in addition to its tile pyramid. The Layer palette is applied to all three surfaces together. A full-world CanvasSource must not be reused as the pole texture: the cap needs a square azimuthal disc, which would otherwise produce radial sectors from unrelated pixels. The dedicated texture is published to the version-pinned polar compositor at zoom <= 5. That custom layer alpha-composites above Mapbox's default pole instead of replacing it, so transparent NoData pixels preserve the basemap. The regular CanvasSource body remains the only scalar surface during the 5 < zoom < 6 morph and in Mercator. The v3 texture edge samples exactly ±85° because that is where Mapbox GL 3.26's native pole fan meets its globe tile mesh; using the mathematical Web Mercator limit at ±85.0511287798066° creates a visible latitude seam. Its azimuth is not rotated: texture bottom-center is longitude 0° at the north edge and top-center is longitude 0° at the south edge. Pixels outside the mesh's unit disc repeat the closest ring value so linear filtering cannot mix transparent corners into the visible boundary.

Polar rendering is a shared scalar-surface responsibility, not a publisher availability gate. Whenever a globe pole is visible, the renderer derives an edge-clamped pole texture from the already accepted Mercator surface. This is the same visual continuation used by Mapbox native raster tiles and prevents a white cap for Channels whose source has no truthful data beyond ±85°. A valid native polar_caps frame atomically replaces that fallback. Failure to fetch one native cap never hides the accepted Mercator surface; it retains the fallback and retries the enhancement independently. Pole visibility is probed from Mapbox's projected ±85° boundary in addition to the regular viewport sampling grid. If that boundary is visible, the initial scalar revision covers one complete longitude ring and publishes the pole texture before any camera movement.

The shared picker may offer continuous ramps and solid-color ramps. A solid ramp keeps one hue while interpolating from its light tint to its saturated color across the numeric domain. Per-stop opacity belongs to Layer presentation; provider alpha remains authoritative for NoData pixels.

Boundary

RGB and true-color imagery is presentation data, not a scalar field. It remains an ordinary imagery raster unless the provider supplies an explicit numeric encoding contract. Its hover may expose truthful frame metadata, never a guessed value. An exact provider RGBA-to-category color_interpretation may describe immutable image colours for truthful inspection, but it is decoding metadata rather than a recolouring palette. The shared inspection rules are documented in raster pixel inspection. Never put a Layer presentation palette in Channel endpoint configuration.

Checklist for a new raster integration

categorical, or a vector field.

declare codec, range, validity channel, quantity, and unit in the nested value_encoding.

Original snapshots are copied into each new Layer.

4.99, 5, 5.5, 6, and 6.01.

polar caps; otherwise verify the renderer-owned edge-clamped fallback.

  1. Declare pixel_delivery@1 and decide whether pixels are imagery, scalar,
  2. For numeric pixels, choose rendered-tile or request-variant sampling and
  3. Put the recommended palette in Data Product defaults so the active and
  4. Verify palette switching, legend values, provider alpha, and globe zooms
  5. If the provider has values beyond ±85°, publish and verify both native
  6. Add fail-closed render-contract tests and catalog migration tests.