Hillshade
Horn's-method hillshade, ported from the sibling iOS app's HillshadeTileOverlay.swift: shadow-only output (black RGB, alpha = shadow depth) so it composites correctly over both light and dark basemaps without a separate light-mode palette, plus the three cleanup passes iOS added against real artifacts in Puget Sound data — despiked water, sea-surface noise, and flattened-valley noise all showing up as fake terrain.
elevations must be padded by exactly 1px of real neighbor data on every side of the width×height output area (a 3×3 kernel needs one ring of context per output pixel) — i.e. an ElevationTile of size (width+2)×(height+2). Getting that padding from adjacent tiles, not just clamping at this tile's own edge, is the caller's job (mirroring iOS's TerrainStore.elevationTile(margin:)); this function only shades.
Fixed light source (azimuth 315°/NW, altitude 45°) — not configurable, matching iOS: a single consistent light direction is what makes shading readable across differently-oriented terrain on the same map.
Properties
How far outside the output area ElevationTiles passed to shade must be padded with real neighbor data.