Skip to content

feat(core): Viewport classes depend on math.gl projectionEngine - #10872

Merged
Pessimistress merged 9 commits into
codex/async-view-resolutionfrom
codex/crs-descriptor-integration
Oct 20, 2026
Merged

Pessimistress merged 9 commits into
codex/async-view-resolutionfrom
codex/crs-descriptor-integration

Conversation

@Pessimistress

@Pessimistress Pessimistress commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

For #10739

TL;DR

  • Offload CustomProjectionViewport CRS handling to math.gl
  • Moderate breaking changes to base Viewport class (remove assumptions about coordinate system and projection mode)
  • Existing geospatial viewports (WebMercator, FirstPerson, Globe) are refactored but expect no behavioral change

Change List

  • Depend on published @math.gl/projection alpha.17
  • Share CRS resolution with synchronous access to loaded descriptors
  • Base Viewport adds crs: CRSDescriptor property, drops longitude latitude, no longer contains web-mercator projection as geospatial fallback
  • Rewrite WebMercatorViewport, FirstPersonViewport with CRS descriptor. Custom CRS OSMTile512 describes MVT coordinate space.
  • Rewrite GlobeViewport with standard geocentric CRS. World-space axes now match proj=geocent and are aligned to deck.gl common space with viewMatrix. Winding direction is not affected. Add earthModel option to switch between WGS84 ellipsoid and v9.4/maplibre sphere.
  • CustomProjectionViewport drops projection, toBounds and getDistanceScale options. Use math.gl-resolved CRS descriptor to handle coordinate conversion, normalization, bounds, and distance scales.
  • CustomProjectionViewport drops fromCrs in preparation for layer-owned source CRS
  • Add projectPosition(position, {sourceCrs}) for explicit input CRS conversion
  • Tests, docs, and upgrade guide

Note

High Risk
Breaking changes to base Viewport geospatial defaults and CustomProjectionView API, plus broad refactors of Mercator, globe, and projection shaders that affect coordinate conversion and meter sizing across the stack.

Overview
This PR moves deck.gl’s viewport and experimental custom-projection stack onto @math.gl/projection CRS descriptors, instead of app-supplied converters and implicit Mercator from longitude/latitude.

_CustomProjectionView / viewport / controller now take a required crs (EPSG, PROJ, etc.), resolve it asynchronously via initialize(), and treat layer positions, camera center, picking, and maxBounds as WGS84. Conversion, normalization, rendering bounds, and ground-meter scales come from the descriptor; projection, fromCrs/toCrs, getDistanceScale, and toBounds are removed. ProjectionConverter is dropped from public exports.

The base Viewport gains optional crs, targetToCommonMatrix, and projectPosition(..., { sourceCrs }); it no longer auto-selects Web Mercator from lat/lng. WebMercatorViewport, FirstPersonViewport, and GlobeViewport wire in built-in descriptors (OSMTile512, geocentric globe CRS) while keeping their existing camera/shader behavior. resolveCRS caches math.gl loads; ViewManager tracks failed view init so retries work after errors.

Aggregation uses a lightweight AggregationViewport for linear scaling of preprojected coordinates. Shader project_size_to_pixel drops a custom-geospatial special case; meter sizing follows descriptor Jacobian / texture sampling. Docs, upgrade guide, custom-projection demo, and tests are updated accordingly.

Reviewed by Cursor Bugbot for commit 98bd478. Bugbot is set up for automated code reviews on this repo. Configure here.

@Pessimistress
Pessimistress requested a review from ibgreen October 15, 2026 18:00

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread modules/core/src/viewports/first-person-viewport.ts
Comment thread modules/core/src/viewports/custom-projection-viewport.ts
@coveralls

coveralls commented Oct 15, 2026 •

Copy link
Copy Markdown

Coverage Status

Coverage is 83.74% — codex/crs-descriptor-integration into codex/async-view-resolution. No base build found for codex/async-view-resolution.

@greptile-apps

greptile-apps Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[High impact] The latest changes appear safe to merge with the dependent caller fix in PR #10874.

Summary

Moves viewport coordinate conversion and distance scales onto math.gl CRS descriptors. The latest changes let a fresh, equal view retry failed initialization.

  • Viewports use explicit coordinate systems instead of guessing a map projection.
  • Custom planar views resolve a target CRS and convert WGS84 positions through it.
  • Aggregation scales coordinates that are already packed into the target CRS.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Receive view descriptor] --> B{Equal previous view?}
  B -->|No| D[Initialize new view]
  B -->|Yes| C{Previous initialization failed?}
  C -->|No| E[Keep previous view]
  C -->|Yes, fresh instance| D
  D -->|Success| F[Rebuild viewports]
  D -->|Failure| G[Record failed view and report error]
Loading

Reviews (6) · Last reviewed commit: "address comments" · Reviewed by Greptile

Comment thread modules/core/src/viewports/viewport.ts Outdated
Comment thread test/modules/core/shaderlib/project/preprojection-altitude.spec.ts Outdated

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread modules/core/src/viewports/viewport.ts
Comment thread modules/core/src/views/custom-projection-view.ts Outdated

@ibgreen ibgreen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving the descriptor integration as a step in the stacked CRS work. Moving normalization, rendering bounds and local scale estimation into math.gl is the right ownership boundary; deck.gl should retain camera/common-space conventions and GPU scale-field resources. Resolving asynchronously in View and consuming synchronously in Viewport also makes sense.

There is still room to improve math.gl usage: standard built-in descriptors should eventually come from a synchronous math.gl factory/export, and future source-CRS work should consider math.gl's direct CRS-pair converters rather than always routing through WGS84. Inline comments capture these follow-ups and cache retry behavior.

Known limitation: the existing unresolved base Viewport({crs}) shader-origin issue remains in this commit. The author has assigned it to #10874; this approval of the stacked integration does not mean that path is ready to release independently. Please retain regression coverage for finite GPU uniforms and CPU/GPU agreement when completing that work.

Validation: reviewed the viewport/CRS integration, related tests and documentation, and math.gl v5.0.0-alpha.17 descriptor/scale implementation. GitHub CI for this exact head passes test-coverage, test-webgpu, test-python and test-website. Local tests were not run because the environment's configured network proxy was unavailable.

/** Standard geocentric metre coordinates on the existing deck.gl sphere.
* Common-space orientation and radius remain the responsibility of GlobeViewport.
*/
export const GLOBE_CRS: CRSDescriptor = {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking math.gl follow-up: can we upstream a synchronous descriptor factory/export for this standard geocentric sphere (and WGS84), then keep only deck-specific common-space orientation and OSMTile512 adaptation here? Calling the geocentric plugin directly preserves synchronous built-in construction, which is useful, but manually assembling units, bounds, normalization and conversion adapters duplicates the descriptor contract implemented by math.gl getCRS. A parity test against getCRS for the same sphere definition would help prevent drift until a synchronous API exists. Preserve the current radius/altitude semantics when doing this.

const geographic =
sourceCrs.signature === WGS84_CRS.signature
? position
: sourceCrs.converter.WGS84.to(position);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking for this WGS84-oriented step: for the upcoming arbitrary source-CRS pipeline, consider preparing math.gl direct source-to-target converters during async resolution. alpha.17 getCRS(definition, {converters: [...]}) already supports these. Always converting source -> WGS84 -> target adds two conversions, including an avoidable inverse/forward round trip when source and target are identical, and can introduce intermediate datum/domain constraints. Keep the dispatch through built-in viewport hooks where Mercator altitude or globe orientation requires it; the generic/custom path is the candidate for direct conversion.

Comment thread modules/core/src/utils/crs.ts Outdated

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread modules/core/src/views/custom-projection-view.ts

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5a955fc. Configure here.

Comment thread modules/core/src/views/custom-projection-view.ts
@Pessimistress
Pessimistress merged commit 6fee6dc into codex/async-view-resolution Oct 20, 2026
8 checks passed
@Pessimistress
Pessimistress deleted the codex/crs-descriptor-integration branch October 20, 2026 00:29
@Pessimistress
Pessimistress restored the codex/crs-descriptor-integration branch October 20, 2026 18:14
@chrisgervang chrisgervang mentioned this pull request Oct 22, 2026
47 of 56 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants