feat: support the sky style property - #4534
Conversation
Globe phase 11a of the design proposal (maplibre#4525): Platform SDK: the GLFW app. Oracle: The GLFW app by hand. Consolidates from core/projection-property: - feat(glfw): toggle the globe with F9 - refactor(core): second review pass over the globe branch - refactor(core): name the projection types
…phase 7) Globe phase 7 of the design proposal (maplibre#4525): Tile cover: convex volumes, horizon plane, wrap, no world copies. Oracle: antimeridian-lod, tile-count assertions in tile_cover.test.cpp. Consolidates from core/projection-property: - feat(core): unproject, anchored zoom and constrain on the globe - feat(core): render lines on the globe (Metal) - feat(core): cover the globe with the tiles the camera can see - refactor(core): review pass over the globe branch - feat(core): let the globe zoom out below zero toward the poles - perf(core): cover the globe without heap allocations per tile - fix(core): cover the globe with the tiles GL JS covers - refactor(core): second review pass over the globe branch - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list
Globe phase 8 of the design proposal (maplibre#4525): Symbols and collision. Oracle: The collision-*, text-* and icon-text-* globe tests. Consolidates from core/projection-property: - feat(core): render lines on the globe (Metal) - feat(core): render symbols on the globe (Metal) - feat(core): cover the globe with the tiles the camera can see - feat(core): hand the globe over to Mercator at high zoom - refactor(core): review pass over the globe branch - perf(core): project each line-label vertex once per symbol on the globe - fix(core): hide a line label with any vertex behind the globe - fix(core): project neighbour tile borders with the Mercator matrix on the globe - refactor(core): second review pass over the globe branch - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list
Globe phase 9a of the design proposal (maplibre#4525): Remaining layer families on Metal: lines. Oracle: The line globe tests. Consolidates from core/projection-property: - feat(core): render lines on the globe (Metal) - feat(core): render raster, hillshade and color-relief layers on the globe (Metal) - feat(core): render symbols on the globe (Metal) - refactor(core): review pass over the globe branch - fix(core): keep globe line widths in pixels at high latitude - test(core): port GL JS's checks into the globe unit tests - refactor(core): second review pass over the globe branch - test(core): port five more GL JS globe render tests - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list
…phase 9b) Globe phase 9b of the design proposal (maplibre#4525): Remaining layer families on Metal: circle, heatmap. Oracle: The circle and heatmap globe tests. Consolidates from core/projection-property: - feat(core): render circles and heatmaps on the globe (Metal) - feat(core): render raster, hillshade and color-relief layers on the globe (Metal) - feat(core): render symbols on the globe (Metal) - refactor(core): review pass over the globe branch - refactor(core): second review pass over the globe branch - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list
… 9e) Globe phase 9e of the design proposal (maplibre#4525): The blend: the globe preset's transition to Mercator between zoom 11 and 12, keeping tiles across the hand-off. Oracle: zoom-transition; Map.GlobeHandOffKeepsTiles. Consolidates from core/projection-property: - feat(core): hand the globe over to Mercator at high zoom - refactor(core): review pass over the globe branch - perf(core): keep tiles across the globe's Mercator hand-off - test(core): port GL JS's checks into the globe unit tests - refactor(core): second review pass over the globe branch - refactor(core): name the projection types - test(core): port five more GL JS globe render tests - test(core): run the globe hand-off test on its own run loop - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list
…lobe on Metal (globe phase 9c) Globe phase 9c of the design proposal (maplibre#4525): Remaining layer families on Metal: raster, hillshade, color-relief; the globe tile mesh. Oracle: raster-planet, raster-pole, hillshade, color-relief globe tests. Consolidates from core/projection-property: - feat(core): render raster, hillshade and color-relief layers on the globe (Metal) - feat(core): render fill-extrusions on the globe (Metal) - refactor(core): review pass over the globe branch - feat(core): let the globe zoom out below zero toward the poles - refactor(core): second review pass over the globe branch - test(core): port five more GL JS globe render tests - test(core): port the GL JS globe raster tests - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list - test(core): unignore the globe tests Linux OpenGL renders
… 9d) Globe phase 9d of the design proposal (maplibre#4525): Remaining layer families on Metal: fill-extrusion, with the depth prepass 3D layers need. Oracle: The fill-extrusion globe tests. Consolidates from core/projection-property: - feat(core): render fill-extrusions on the globe (Metal) - feat(core): render symbols on the globe (Metal) - refactor(core): review pass over the globe branch - perf(core): draw the globe depth prepass only when a 3D layer needs it - fix(core): coarsen a subdivided polygon that would overflow a segment instead of dropping the tile - refactor(core): second review pass over the globe branch - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list
Globe phase 12c of the design proposal (maplibre#4525): Corrective tail: collision debug boxes. Oracle: The collision-box globe tests. Consolidates from core/projection-property: - fix(core): draw collision boxes on the globe
…hase 9f) Globe phase 9f of the design proposal (maplibre#4525): Stencil clip masks drawn from the globe tile meshes, culled on the far side. Oracle: Every globe test with overlapping tiles; fill-planet-tiles on an iPhone. Consolidates from core/projection-property: - feat(core): clip layers to their tiles on the globe (Metal) - test(core): port five more GL JS globe render tests - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list - fix(core): cull the far side of the globe clip masks
Globe phase 10c of the design proposal (maplibre#4525): WebGPU globe prelude variant, clip mask, cull modes. Oracle: The globe tests on the WebGPU manifests (Dawn and wgpu). Consolidates from core/projection-property: - feat(core): render the globe on Vulkan, WebGPU and OpenGL - refactor(core): review pass over the globe branch - refactor(core): second review pass over the globe branch - perf(core): drop the globe's mesh caches when the style goes back to Mercator - fix(webgpu): honour the drawables' cull modes - fix(core): cull the far side of the globe clip masks
… to every shader group (globe phase 10d) Globe phase 10d of the design proposal (maplibre#4525): Phase 10, after the three backend ports: the shader-group lookup takes the projection variant as a required parameter ahead of the attribute name on the base class and on the Metal, OpenGL, Vulkan and WebGPU implementations, and every caller passes it explicitly Oracle: compiles on all four backends; render tests unchanged on every manifest Consolidates from core/projection-property: - refactor(core): second review pass over the globe branch - fix(core): draw the Vulkan globe clip mask with the whole projection block
Globe phase 9i of the design proposal (maplibre#4525): CustomLayerRenderParameters carry the projection; custom drawable layers project on the globe; the depth prepass runs for them. Oracle: custom; test/api/custom_layer.test.cpp. Consolidates from core/projection-property: - feat(core): hand custom layers the globe projection - test(core): port GL JS's checks into the globe unit tests - refactor(core): second review pass over the globe branch - fix(core): project custom drawable layers on the globe - fix(core): run the globe depth prepass for custom layers
…hase 12b) Globe phase 12b of the design proposal (maplibre#4525): Corrective tail: image sources. Oracle: The ported GL JS globe raster tests. Consolidates from core/projection-property: - feat(core): render raster, hillshade and color-relief layers on the globe (Metal) - refactor(core): second review pass over the globe branch - test(core): port five more GL JS globe render tests - fix(core): draw image sources on the globe by their own quad - test(core): port the GL JS globe raster tests - fix(core): draw tile borders on the globe - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list - test(core): unignore the globe tests Linux OpenGL renders
…d macOS (globe phase 12g) Globe phase 12g of the design proposal (maplibre#4525): Corrective tail: Map::isLocationOccluded and the SDKs' view-based annotations. Oracle: Transform.GlobeLocationOcclusion; MLNAnnotationViewTests. Consolidates from core/projection-property: - refactor(core): review pass over the globe branch - refactor(core): second review pass over the globe branch - fix(core): treat a coordinate behind the globe as offscreen on iOS and macOS
…timeridian (globe phase 12h) Globe phase 12h of the design proposal (maplibre#4525): Corrective tail: the tile cover's wrap across the antimeridian. Oracle: Transform.GlobeCenterLongitudeStaysContinuous; TileCover.GlobeCoverSurvivesTheAntimeridian. Consolidates from core/projection-property: - fix(core): keep the globe's center longitude continuous across the antimeridian
Globe phase 11b of the design proposal (maplibre#4525): Platform SDK: iOS example app and the iOS Metal expectations an iPhone rasterizes differently. Oracle: iOS render tests on device; the example app. Consolidates from core/projection-property: - test(core): iOS Metal expectations for the globe tests an iPhone rasterizes differently - feat(ios): add a globe style to the example app
Globe phase 11c of the design proposal (maplibre#4525): Platform SDK: Android test app. Oracle: compileOpenglDebugKotlin; the test app. Consolidates from core/projection-property: - feat(android): add a globe example to the test app
Globe phase 12a of the design proposal (maplibre#4525): Corrective tail: layer translation on the sphere. Oracle: The *-translate globe tests. Consolidates from core/projection-property: - refactor(core): second review pass over the globe branch - fix(core): apply *-translate on the globe - test(core): port the GL JS globe raster tests - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list - test(core): unignore the globe tests Linux OpenGL renders - test(core): rerender the Linux OpenGL expectations without the mask bug
…or the globe (globe phase 5) Globe phase 5 of the design proposal (maplibre#4525): Subdivision at the generators, tile meshes with pole caps, granularity through the worker. Oracle: fill-planet-tiles, fill-seams, fill-planet-pole. Consolidates from core/projection-property: - feat(core): subdivide fill and line geometry for the globe - feat(core): tile meshes with pole caps for the globe background; paint 2D layers in order on the globe - feat(core): unproject, anchored zoom and constrain on the globe - feat(core): render raster, hillshade and color-relief layers on the globe (Metal) - feat(core): render fill-extrusions on the globe (Metal) - refactor(core): review pass over the globe branch - fix(core): coarsen a subdivided polygon that would overflow a segment instead of dropping the tile - perf(core): stop copying every line feature's coordinates on Mercator - test(core): port GL JS's checks into the globe unit tests - refactor(core): second review pass over the globe branch - fix(core): draw tile borders on the globe - fix(core): include <limits> for the segment vertex cap - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list - build(core): include earcut in subdivision.cpp without MSVC's conversion warnings
…e phase 6) Globe phase 6 of the design proposal (maplibre#4525): Unproject, gestures, easeTo/flyTo, constrain. Oracle: Unit tests on TransformState (ray-sphere, horizon clamp, pan); the GLFW app by hand. Consolidates from core/projection-property: - feat(core): unproject, anchored zoom and constrain on the globe - feat(core): render raster, hillshade and color-relief layers on the globe (Metal) - refactor(core): review pass over the globe branch - feat(core): let the globe zoom out below zero toward the poles - fix(core): keep minzoom-0 layers and image sources at negative globe zoom - perf(core): cache the globe view state on the transform state - fix(core): treat an unknown projection name as Mercator - test(core): port GL JS's checks into the globe unit tests - refactor(core): second review pass over the globe branch - refactor(core): name the projection types - test(core): keep maxBounds on the globe - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list
Globe phase 9g of the design proposal (maplibre#4525): The location indicator layer family on the globe, rebuilt on projection change, quads without an image left undrawn. Oracle: LocationIndicator.{Mercator,Globe}PuckAtItsLocation. Consolidates from core/projection-property: - fix(core): place the location indicator on the globe - test(core): skip the location-indicator tests where the layer is not registered - fix(core): rebuild the location indicator when the projection changes - test(core): skip the globe puck test on OpenGL's own location indicator renderer - fix(core): keep a location indicator quad without an image out of the draw
Globe phase 9h of the design proposal (maplibre#4525): The debug layer's tile borders on the globe. Oracle: debug-tile-borders. Consolidates from core/projection-property: - fix(core): draw tile borders on the globe - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS antimeridian and seam tests - test(core): unignore the globe tests Linux OpenGL renders - test(core): rerender the Linux OpenGL expectations without the mask bug
Globe phase 10a of the design proposal (maplibre#4525): OpenGL globe prelude variant, clip masks, uniform-block tables, Linux OpenGL expectations. Oracle: The globe tests on the Linux OpenGL manifest. Consolidates from core/projection-property: - feat(core): render the globe on Vulkan, WebGPU and OpenGL - refactor(core): review pass over the globe branch - feat(core): clip layers to their tiles on the globe (OpenGL) - fix(core): skip uniform blocks a shader variant does not reference on OpenGL - refactor(core): second review pass over the globe branch - test(core): port five more GL JS globe render tests - fix(gl): set the stencil mode of a 3D layer group that has no clip tiles - test(core): render the globe tests on Linux OpenGL - test(core): keep only the tests OpenGL has not rendered in its ignore list - test(core): put the Linux OpenGL expectations where the runner looks - fix(gl): bind the projection block for every shader that projects through it - test(core): unignore the globe tests Linux OpenGL renders - fix(core): cull the far side of the globe clip masks - test(core): rerender the Linux OpenGL expectations without the mask bug - test(core): bundle the Linux OpenGL expectations for the Bazel render test - refactor(gl): drop the duplicate drawable include from the context - build(gl): forward-declare the GL passes before befriending them
Globe phase 10b of the design proposal (maplibre#4525): Vulkan globe prelude variant and clip mask. Oracle: The globe tests on the Vulkan manifests. Consolidates from core/projection-property: - feat(core): render the globe on Vulkan, WebGPU and OpenGL - refactor(core): review pass over the globe branch - refactor(core): second review pass over the globe branch - fix(core): cull the far side of the globe clip masks
… (globe phase 12f) Globe phase 12f of the design proposal (maplibre#4525): Corrective tail: variable anchors and the ported text tests. Oracle: The text-* globe tests. Consolidates from core/projection-property: - test(core): port five more GL JS globe render tests - fix(core): place variable-anchor labels where the globe collides them - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list - test(core): unignore the globe tests Linux OpenGL renders
…globe phase 12d) Globe phase 12d of the design proposal (maplibre#4525): Corrective tail: camera behaviours. Oracle: The ported GL JS camera unit tests. Consolidates from core/projection-property: - fix(core): ease, fly and fit bounds on the globe the way GL JS does - fix(core): zoom around an anchor near the globe's horizon the way GL JS does
…be phase 12e) Globe phase 12e of the design proposal (maplibre#4525): Corrective tail: the antimeridian and seam tests, with the three residuals ignored for their stated reasons. Oracle: antimeridian-overdraw, fill-seams. Consolidates from core/projection-property: - test(core): port GL JS's checks into the globe unit tests - test(core): port five more GL JS globe render tests - fix(core): draw antimeridian-crossing geometry once on the globe - test(core): port the GL JS antimeridian and seam tests - test(core): port the GL JS globe text tests - test(core): unignore the globe tests Linux OpenGL renders - test(core): ignore the three antimeridian-overdraw residuals with their reasons
… UBO (globe phase 1) Globe phase 1 of the design proposal (maplibre#4525): Seam: ProjectionBase + ProjectionData through LayerTweaker into the UBOs, Mercator only, all four backends. Oracle: Every existing render test, every manifest, pixel-identical (allowed unchanged). Consolidates from core/projection-property: - refactor(core): introduce the projection seam behind TransformState - feat(core): carry ProjectionData into a per-drawable projection UBO on all backends - refactor(core): review pass over the globe branch - test(core): port GL JS's checks into the globe unit tests - refactor(core): second review pass over the globe branch
…l family to it (globe phase 2) Globe phase 2 of the design proposal (maplibre#4525): Prelude functions on all four backends (Mercator variant only); the fill family switched to projectTile. Oracle: Same: every existing render test pixel-identical. Consolidates from core/projection-property: - feat(core): add projectTile() to the shader preludes and switch the fill family to it
Globe phase 3 of the design proposal (maplibre#4525): projection root property: parser, codegen, expression type, Style API, transition scalar plumbed to the (still Mercator) transform. Oracle: Unit tests on parser and expression; render tests unchanged. Consolidates from core/projection-property: - feat(core): parse the projection root style property - refactor(core): review pass over the globe branch - fix(core): treat an unknown projection name as Mercator - test(core): port GL JS's checks into the globe unit tests - refactor(core): second review pass over the globe branch - test(core): expect the warning for a non-object projection - fix(node): convert projection definitions in expression results
…hase 4) Globe phase 4 of the design proposal (maplibre#4525): Globe prelude variant + VerticalPerspectiveProjection project/tile-matrix on Metal, fill and background only, no subdivision. Oracle: First ported GL JS globe render tests (fill-planet-solid, background) on the macOS Metal manifest. Consolidates from core/projection-property: - feat(core): render fill and background on the globe (Metal) - feat(core): tile meshes with pole caps for the globe background; paint 2D layers in order on the globe - refactor(core): review pass over the globe branch - test(core): port GL JS's checks into the globe unit tests - refactor(core): second review pass over the globe branch - test(core): port five more GL JS globe render tests - docs(core): describe the globe in the projections section - refactor(core): say why the globe's depth offset is subtracted in clip space - test(core): render the globe tests on Linux OpenGL - test(core): port the GL JS globe text tests - test(core): keep only the tests OpenGL has not rendered in its ignore list
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 72e094d08f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const shaders::SkyPropsUBO props = { | ||
| .sky_color = evaluated->get<style::SkyColor>(), | ||
| .horizon_color = evaluated->get<style::SkyHorizonColor>(), | ||
| .horizon = horizon, | ||
| .horizon_normal = normal, | ||
| .viewport_size = {{static_cast<float>(viewportSize.width), static_cast<float>(viewportSize.height)}}, | ||
| .sky_horizon_blend = evaluated->get<style::SkyHorizonBlend>() * viewportSize.height * 0.5f, |
There was a problem hiding this comment.
Apply the exposed fog properties during rendering
When a style or runtime SDK sets fog-color, fog-ground-blend, or horizon-fog-blend, the values and their transitions are evaluated but never consumed by the renderer: this uniform setup reads only SkyColor, SkyHorizonColor, SkyHorizonBlend, and later SkyAtmosphereBlend. Consequently, the three advertised fog APIs silently have no visual effect, particularly in the terrain/globe scenes they are intended to configure; pass their evaluated values into the relevant sky/fog rendering path.
Useful? React with 👍 / 👎.
72e094d to
e57ca56
Compare
Add the sky root-property model, parsing, transitions, observers, dynamic lookup, generated style bindings, and build registration for all seven properties. Keep terrain-dependent fog properties available to the style model while their pixel rendering remains deferred to Terrain3D.
Add the shared sky render pass plus planar-gradient and physical atmosphere shaders for OpenGL. Integrate projection transitions, depth state, and lighting in the common renderer path.
Port the sky and physical atmosphere shaders to Metal and register their drawable and build-system integration.
Port the sky and physical atmosphere shaders to Vulkan and register their drawable and build-system integration.
Port the sky and physical atmosphere shaders to WebGPU and register their drawable and Bazel/CMake integration.
Cover defaults, setters, transitions, expressions, style replacement and removal, and representative planar and globe GPU output.
Generate Android sky style APIs for all seven root properties, including expressions and transitions. Wire nullable style access, JNI ownership, changelog coverage, and instrumentation tests.
Generate iOS and macOS sky APIs with expression and transition support. Expose nullable style access, framework headers, changelogs, and generated tests.
Apply the pinned clang-format hook to generated Android sky registration and Darwin umbrella imports.
e57ca56 to
39a9e28
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 39a9e28994
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| void Style::setProjection(std::unique_ptr<Projection> projection) { | ||
| impl->setProjection(std::move(projection)); | ||
| } | ||
|
|
||
| Projection* Style::getProjection() { |
There was a problem hiding this comment.
Preserve projection edits during style revalidation
Both new projection mutation entry points omit impl->mutated = true, unlike the corresponding sky and other mutable-style APIs. When a URL-loaded style receives a cached response followed by a refreshed response, changing the projection through getProjection()->setType(...) or setProjection(...) therefore leaves the guard in Style::Impl::loadURL disabled, allowing the later response to silently overwrite the application’s projection choice; mark these paths as mutations.
Useful? React with 👍 / 👎.
| mat4 matrix; | ||
| matrix::perspective(matrix, | ||
| state.getFieldOfView(), | ||
| static_cast<double>(size.width) / size.height, | ||
| 0.5, | ||
| cameraToCenterDistance + radius * 2.0); |
There was a problem hiding this comment.
Apply the flipped viewport mode to the globe matrix
When a map is configured with ViewportMode::FlippedY, the Mercator matrix flips Y via Camera::getWorldToCamera, but this newly introduced globe matrix is built identically for both viewport modes. Consequently globe rendering and globe screen/coordinate conversion retain the default Y orientation in embedding environments that require a flipped viewport, even though changing the mode invalidates the matrices; incorporate state.getViewportMode() into this matrix construction.
Useful? React with 👍 / 👎.
Addresses #4414.
Summary
skyroot properties:sky-colorhorizon-colorfog-colorfog-ground-blendhorizon-fog-blendsky-horizon-blendatmosphere-blendThe behavior and defaults follow MapLibre GL JS PR #3645, with the physical atmosphere updated to match the current GL JS sky pass.
Dependency and deferred terrain fog
This is intentionally stacked on draft globe PR #4533 at
6bddd1111f4d41a5d3130d9a78375b97b9e2a35d. A visibleatmosphere-blendimplementation needs the globe camera matrices, depth pass, and projection-transition state introduced there. The sky-only review range is the globe head through this branch.The three fog-related properties are fully parsed, evaluated, transitioned, and exposed through the native SDKs, but do not yet affect pixels. Native still lacks the Terrain3D fog compositor that would consume
fog-color,fog-ground-blend, andhorizon-fog-blend. That rendering work should follow Terrain3D issue #252 / draft Terrain3D PR #4190 as a separate PR. Planarsky-color,horizon-color, andsky-horizon-blend, plus globeatmosphere-blend, are rendered here.Validation
pre-commitsuite on every changed file: passed, including pinned clang-format and buildifiermbgl-test-runner, andmbgl-render-test-runner: passedThe full 1,058-test native suite was also started and showed no failures before reaching the existing
Map.StyleNetworkErrorRetryexponential-backoff test; that long network-retry run was stopped rather than reported as a full-suite pass. Metal is the runtime render backend exercised locally; OpenGL, Vulkan, and WebGPU have compile coverage in this validation. A full Android Gradle build was not available because this checkout has no Android SDK.AI assistance
OpenAI Codex using GPT-5.6 Sol with ultra reasoning assisted with repository analysis, implementation, test generation, diff review, and validation under Clay Warren's direction. The prompts asked it to implement #4414 using MapLibre GL JS #3645 as the behavior oracle, assess the #4533 dependency, cover the native render backends and mobile APIs, keep commits reviewable, and run proportionate upstream checks.
This PR is intentionally a draft. Clay Warren must personally read and review all AI-assisted code before marking it ready for maintainer review.