Skip to content

fix(mapbox,google-maps): use css-dpr pixel sizing in overlaid mode to prevent basemap misalignment - #10370

Merged
chrisgervang merged 14 commits into
masterfrom
chr/deckgl-fix-evaluation
Aug 6, 2026
Merged

fix(mapbox,google-maps): use css-dpr pixel sizing in overlaid mode to prevent basemap misalignment#10370
chrisgervang merged 14 commits into
masterfrom
chr/deckgl-fix-evaluation

Conversation

@chrisgervang

@chrisgervang chrisgervang commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Passes pixelSizeSource: 'css-dpr' to the luma.gl canvas context in overlaid (non-interleaved) mode for both MapboxOverlay and GoogleMapsOverlay
  • Makes luma.gl derive pixel sizes using CSS dimensions × DPR, matching how Mapbox GL, MapLibre, and Google Maps compute their canvas drawing buffer dimensions
  • Fixes visible drift between the deck.gl overlay canvas and the basemap at fractional browser zoom levels (90%, 110%, 33%, etc.)
  • Adds unit coverage for both integrations and a fractional-zoom-alignment Vite app for side-by-side manual verification

Before
https://github.com/user-attachments/assets/2f68a865-fb81-40db-903b-5a1b86f0336b

After
https://github.com/user-attachments/assets/71145289-b5e2-4968-b2a7-feef35affb78

luma.gl dependency

The base branch already uses @luma.gl/* ^9.4.0-alpha.4, which includes the css-dpr canvas sizing support and the follow-up fix to observe content-box and use Math.floor (visgl/luma.gl#2676). This PR does not change luma.gl dependencies.

Impact by environment

Environment Effect
Pure deck.gl (standalone, no basemap) No change — default pixelSizeSource remains 'exact'
Mapbox/MapLibre overlaid Fixed — overlay canvas now matches basemap sizing
Mapbox/MapLibre interleaved No change — deck sets width: null, height: null, map owns canvas
Google Maps non-interleaved (raster & vector positioning) Fixed — same treatment
Google Maps interleaved (WebGL overlay) No change — gl prop present, deviceProps not injected
ArcGIS No change — renders to an external FBO

Root cause

At fractional browser zoom, window.devicePixelRatio becomes non-integer. Mapbox/MapLibre compute canvas pixel size as Math.floor(cssWidth * dpr) (via implicit truncation), while exact device-pixel-content-box sizing can report a different physical pixel count. This can give the deck.gl overlay and basemap different drawing buffer dimensions, causing visible misalignment.

Using luma.gl's css-dpr mode observes the CSS content box and derives the pixel size with the same floor-based calculation as the basemap.

Test plan

  • Unit tests verify pixelSizeSource: 'css-dpr' for overlaid Mapbox and non-interleaved Google Maps
  • Verify no regression at 100% browser zoom with Mapbox overlay
  • Verify drawing buffer dimensions match at fractional DPR
  • Manually verify Mapbox overlay alignment at fractional browser zoom levels (50%, 25%, etc.)
  • Verify Google Maps overlay renders correctly at fractional zoom
  • Verify standalone deck.gl (no basemap) continues to use exact pixel sizing
  • Verify interleaved mode is unaffected

Closes #10173

🤖 Generated with Claude Code


Note

Medium Risk
Changes canvas sizing for all overlaid Mapbox/MapLibre and non-interleaved Google Maps integrations; standalone Deck and interleaved mode are unchanged. The required luma.gl behavior is already present on the base branch.

Overview
Overlaid basemap overlays now pass pixelSizeSource: 'css-dpr' into luma’s createCanvasContext so Deck’s canvas buffer is sized like Mapbox/MapLibre/Google (CSS size × DPR), instead of relying on exact device-pixel-content-box sizing that can disagree at fractional browser zoom.

MapboxOverlay applies this whenever Deck owns its own canvas (default overlaid mode). GoogleMapsOverlay does the same only when no external gl is supplied (non-interleaved); interleaved WebGL sharing is unchanged. User deviceProps / createCanvasContext are merged so callers can still extend options.

Adds a fractional-zoom-alignment Vite test app (Mapbox + diagnostic panel) and unit tests asserting css-dpr on overlaid Mapbox and non-interleaved Google Maps Deck creation.

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

… prevent basemap misalignment

At fractional browser zoom levels, luma.gl's exact device-pixel-content-box sizing
diverges from the Math.round(css * dpr) approach used by Mapbox GL, MapLibre, and
Google Maps, causing visible drift between the deck.gl overlay canvas and the basemap.

Pass pixelSizeSource: 'css-dpr' when creating the canvas context in overlaid (non-interleaved)
mode so luma.gl derives pixel sizes using the same rounding as the underlying basemap.

Depends on visgl/luma.gl#2588 (pixelSizeSource prop, merged to master, pending release).

Closes #10173

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chrisgervang
chrisgervang requested a review from ibgreen June 12, 2026 00:11
chrisgervang and others added 2 commits June 11, 2026 17:11
…release

The pixelSizeSource prop is available in luma.gl >9.3.3 (visgl/luma.gl#2588)
but not yet in the currently pinned @luma.gl/core@9.3.3 types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
luma.gl 9.3.4 ships the pixelSizeSource prop (visgl/luma.gl#2588),
so the ts-expect-error suppression is no longer needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chrisgervang chrisgervang changed the title fix(mapbox,google-maps): use css-dpr pixel sizing to prevent basemap misalignment at fractional zoom fix(mapbox,google-maps): use css-dpr pixel sizing in overlaid mode to prevent basemap misalignment Jun 13, 2026
@coveralls

coveralls commented Jun 13, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 83.755% (+0.007%) from 83.748% — chr/deckgl-fix-evaluation into master

@chrisgervang
chrisgervang marked this pull request as ready for review June 13, 2026 23:37
chrisgervang and others added 2 commits June 18, 2026 20:58
- Update yarn.lock to pull in @luma.gl/core 9.3.5 which includes the
  css-dpr observer box fix (visgl/luma.gl#2676)
- Add test/apps/fractional-zoom-alignment for manual verification of
  issue #10173 (basemap misalignment at fractional browser zoom)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…uation

Resolved conflicts: took @loaders.gl ^4.4.3 (from master) and
@luma.gl ^9.3.4 (from this branch).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chrisgervang chrisgervang added this to the v9.4 milestone Jun 28, 2026
chrisgervang and others added 2 commits July 3, 2026 16:48
…mode

Add unit tests confirming that MapboxOverlay and GoogleMapsOverlay pass
pixelSizeSource: 'css-dpr' through deviceProps.createCanvasContext when
creating their own Deck instance, ensuring the luma.gl canvas context
uses content-box sizing to stay aligned with the basemap.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
chrisgervang and others added 2 commits July 29, 2026 13:50
…uation

Resolved conflicts: took @luma.gl ^9.4.0-alpha.1 from master.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
// The basemap owns the shared canvas in interleaved mode; Deck only forwards the preferred DPR.
// In non-interleaved mode this still feeds the luma canvas context that Deck creates.
useDevicePixels: props.useDevicePixels ?? true,
...(!props.gl && {

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.

This is pretty crazy that we have to write nested code like this just to override or pass a prop.
A result of the unfortunate prop type overloading in luma CanvasContext.
I will see if we can propose improved props in luma.gl

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

😬 yeah.. I held my breath a bit pushing this one up. Lmk if you figure something out

@chrisgervang chrisgervang Jul 31, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Left comments on the RFC, thanks for following up!

@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 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 9f47e2b. Configure here.

Comment thread modules/google-maps/src/utils.ts
@chrisgervang
chrisgervang merged commit 8b23c85 into master Aug 6, 2026
6 checks passed
@chrisgervang
chrisgervang deleted the chr/deckgl-fix-evaluation branch August 6, 2026 01:20
Pessimistress pushed a commit that referenced this pull request Aug 7, 2026
… prevent basemap misalignment (#10370)

* fix(mapbox,google-maps): use css-dpr pixel sizing in overlaid mode to prevent basemap misalignment

At fractional browser zoom levels, luma.gl's exact device-pixel-content-box sizing
diverges from the Math.round(css * dpr) approach used by Mapbox GL, MapLibre, and
Google Maps, causing visible drift between the deck.gl overlay canvas and the basemap.

Pass pixelSizeSource: 'css-dpr' when creating the canvas context in overlaid (non-interleaved)
mode so luma.gl derives pixel sizes using the same rounding as the underlying basemap.

Depends on visgl/luma.gl#2588 (pixelSizeSource prop, merged to master, pending release).

Closes #10173

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(mapbox): add ts-expect-error for pixelSizeSource pending luma.gl release

The pixelSizeSource prop is available in luma.gl >9.3.3 (visgl/luma.gl#2588)
but not yet in the currently pinned @luma.gl/core@9.3.3 types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: bump @luma.gl to 9.3.4 and remove ts-expect-error workaround

luma.gl 9.3.4 ships the pixelSizeSource prop (visgl/luma.gl#2588),
so the ts-expect-error suppression is no longer needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: bump @luma.gl to 9.3.5 and add fractional-zoom test app

- Update yarn.lock to pull in @luma.gl/core 9.3.5 which includes the
  css-dpr observer box fix (visgl/luma.gl#2676)
- Add test/apps/fractional-zoom-alignment for manual verification of
  issue #10173 (basemap misalignment at fractional browser zoom)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(mapbox,google-maps): verify pixelSizeSource css-dpr in overlaid mode

Add unit tests confirming that MapboxOverlay and GoogleMapsOverlay pass
pixelSizeSource: 'css-dpr' through deviceProps.createCanvasContext when
creating their own Deck instance, ensuring the luma.gl canvas context
uses content-box sizing to stay aligned with the basemap.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

[Bug] Misalignment/drift in MapboxOverlay at fractional zoom levels

3 participants