fix(extensions): align billboard, 3D, justified, and offset dashes - #10580
Merged
Conversation
chrisgervang
marked this pull request as ready for review
August 21, 2026 23:15
Greptile SummaryThe PR aligns dash coordinates and phase across PathLayer rendering modes without changing the public API.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| modules/extensions/src/path-style/path-style-extension.ts | Adds projection-aware CPU dash metrics and targeted invalidation for high-precision path dashes. |
| modules/extensions/src/path-style/shaders.glsl.ts | Normalizes dash units, guards short justified runs, and preserves phase through offset widening. |
| modules/layers/src/path-layer/path-layer-vertex.glsl.ts | Applies rendered 3D arclength and clipping-aware dash coordinates across the GLSL extrusion paths. |
| modules/layers/src/path-layer/path-layer.wgsl.ts | Mirrors the GLSL arclength, clipping-bound, and dash-coordinate behavior for WebGPU. |
| modules/layers/src/path-layer/path-layer.ts | Tracks tessellation and projection inputs so dash metrics are invalidated without unnecessary retessellation. |
| modules/layers/src/path-layer/path-tesselator.ts | Exposes rendered segment traversal order for continuous CPU phase calculation. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Path geometry] --> B[PathTessellator]
B --> C[CPU dash metrics]
C --> D[instanceDashOffsets]
B --> E[PathLayer segment attributes]
D --> F[Dash shaders]
E --> F
F --> G[3D and billboard arclength]
G --> H[Clipping and offset correction]
H --> I[Consistent rendered dash phase]
Reviews (34): Last reviewed commit: "test(render): document PathStyle dash ex..." | Re-trigger Greptile
Pessimistress
approved these changes
Aug 22, 2026
chrisgervang
force-pushed
the
claude/deck-gl-path-dashing-2jnq8i-2
branch
2 times, most recently
from
August 22, 2026 01:09
1d25bdf to
6720bf7
Compare
chrisgervang
force-pushed
the
claude/deck-gl-path-dashing-2jnq8i-2
branch
3 times, most recently
from
August 22, 2026 22:15
a62c717 to
b123295
Compare
…ension Adds a render-test matrix and an interactive app for PathStyleExtension dashing, covering segment density, dash arrays, corners, zoom levels, device pixel ratio, 3D elevation and billboard/flat parity. The golden images record current behavior, defects included, so that subsequent work shows up as a direct image diff. Measured from these goldens with getDashArray [4, 5]: - Six strips drawing the identical straight line diverge purely by vertex count. 1, 2 and 4 segments dash correctly at a 43.4px period, 12 segments drifts to 55.4px, and 40 and 120 segments render fully solid. Dash phase restarts at every vertex, so once a segment is shorter than one dash period nothing is discarded. - dashJustified collapses the same way; justification is also per segment. - highPrecisionDash renders all six strips identically and correctly, confirming the continuous-arclength mechanism works and is merely opt-in. - billboard: true combined with highPrecisionDash is broken: the same geometry renders solid when dense and at a 52.0px period, 1.5x too long, when sparse, against 34.8px for the flat copy. - Dash length grows along paths that climb in Z, because the CPU accumulates 3D distance while the shader coordinate measures 2D. No source changes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014GipN1niYRgRuLVat2wujw
chrisgervang
force-pushed
the
claude/deck-gl-path-dashing-2jnq8i-2
branch
2 times, most recently
from
August 23, 2026 19:44
2d981ba to
0b63723
Compare
chrisgervang
force-pushed
the
claude/deck-gl-path-dashing-2jnq8i-2
branch
from
August 24, 2026 00:05
0b63723 to
340db32
Compare
chrisgervang
force-pushed
the
claude/deck-gl-path-dashing-2jnq8i-2
branch
from
August 24, 2026 00:12
340db32 to
d73780d
Compare
Dashing measured its along-path coordinate in units that differ between the two extrusion branches of the path layer, so the same geometry dashed differently depending on the billboard prop. At the point the dash shaders run, `width` is in common units for a flat path but already in pixels for a billboarded one, because the clip-space conversion happens inside getLineJoinOffset. That conversion also folds in project.focalDistance, which scales the half-width the segment delta is divided by but not the delta itself. Two consequences, both visible in the render tests: dividing the CPU-side dash offsets by width.x dropped a whole factor of project.scale when billboarded, and the dash period came out focalDistance times too long. On a MapView at z14 a billboarded path rendered solid when dense and at a 52.0px period when sparse, against 34.8px for the flat copy of the same line. Both now measure 34.8px. Everything is normalized through one half-width-in-pixels quantity that is correct in either branch. getDashArray is documented relative to the stroke, which flat paths already honored, so the billboard case is corrected onto the flat one rather than the other way round. Also: - The shader now scales its along-segment coordinate by the 3D-to-2D arclength ratio, so it agrees with the CPU-side offsets, which have always accumulated 3D distance. Previously the two advanced at different rates and the pattern broke up at every joint: on a path descending 900 units over a 720 unit run, dash spacing had a relative standard deviation of 0.134, now 0.012. Both vPathLength and vPathPosition.y are scaled alike, so the fragment shader joint tests are unaffected. Billboard mode is excluded, having already resolved the segment to its screen projection. Mirrored in path-layer.wgsl.ts. - dashJustified guarded against segments shorter than half a dash period, which rounded to zero periods, made unitLength infinite and rendered the segment solid. - The offset shaders now rescale vDashOffset alongside vPathPosition.y and vPathLength, so a dashed offset line stays in phase with an unoffset one. The render case that covers this used 40 segments, where every strip collapsed to solid via the segment-density defect and the image proved nothing; it now uses 2 segments and all four offsets share one dash phase. - getDashArray is documented relative to half the stroke width, which is what it has always measured. Golden images updated for the billboard, 3D and offset cases. Flat, non- billboarded dashing is byte-identical. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014GipN1niYRgRuLVat2wujw
chrisgervang
force-pushed
the
claude/deck-gl-path-dashing-2jnq8i-2
branch
from
August 26, 2026 22:56
d73780d to
3a72563
Compare
# Conflicts: # test/bench/path-style-extension.bench.js # test/render/golden-images/path-dash-3d-billboard-pitched-rounded.png # test/render/golden-images/path-dash-3d-billboard.png # test/render/golden-images/path-dash-3d-flat-antialiasing.png # test/render/golden-images/path-dash-3d-flat.png # test/render/golden-images/path-dash-billboard-map-z10.png # test/render/golden-images/path-dash-billboard-map-z14.png # test/render/golden-images/path-dash-billboard-map-z18.png # test/render/golden-images/path-dash-billboard-pitched.png # test/render/golden-images/path-dash-offset-mode-path.png # test/render/golden-images/path-dash-offset.png # test/render/test-cases/path-dash.spec.ts
chrisgervang
commented
Aug 31, 2026
chrisgervang
left a comment
Collaborator
Author
There was a problem hiding this comment.
Comments for a follow up refactor. Merging as-is for a baseline fix
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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 c38672a. Configure here.
# Conflicts: # test/render/golden-images/path-dash-clipped-composition.png
chrisgervang
added a commit
that referenced
this pull request
Aug 31, 2026
# Conflicts: # modules/extensions/src/path-style/shaders.glsl.ts # test/modules/extensions/path.spec.ts # test/modules/layers/path-antialiasing.spec.ts # test/render/golden-images/path-dash-3d-billboard-pitched-rounded.png # test/render/golden-images/path-dash-3d-billboard.png # test/render/golden-images/path-dash-3d-flat-antialiasing.png # test/render/golden-images/path-dash-3d-flat.png # test/render/golden-images/path-dash-billboard-map-z10.png # test/render/golden-images/path-dash-billboard-map-z14.png # test/render/golden-images/path-dash-billboard-map-z18.png # test/render/golden-images/path-dash-billboard-pitched.png # test/render/golden-images/path-dash-clipped-composition.png
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Stack position: Part 2 of 6; base
masterafter #10579 merged. The test-only clipped-composition baseline #10625, option-typing cleanup #10616, and generalViewport#equalsprerequisite #10611 are merged intomasterand synchronized here.Goal
Align dash coordinates and phase across flat, billboarded, elevated, normalized, justified, and offset paths without changing the public API.
How to read the image diffs
This change improves how the renderer measures distance along a dashed line.
Changes
DASH_ENABLED.PathTessellatorgeometry, including Globe subdivision, antimeridian cuts, closed paths, binary paths, and partial updates.getDashOffsets; use private rendered-path metrics internally and reject unreadable GPU-only geometry unless explicit offsets are supplied.getDashArrayvalues are relative to half the effective path width; for example,[4, 5]on a 10 px path produces 20 px dashes and 25 px gaps.Benchmark results
GPU measurements use the same Apple M1 Max/ANGLE Metal/WebGL2, 3840×2160, 20-sample method as the merged baseline #10579. Production timing was measured at
3b6a81d40e. Direct commit6affdb4d2bonly supplies the CPU benchmark viewport fixture; direct commitsae0924f452,85f58ab05f, and50f3053053add phase-preserving clipping, visible cap/joint bounds, and offset-coordinate consistency. These benchmark variants do not execute billboard clipping or combine offset with dashing. The bounds fix does add one dash-only varying to the flat dash variants, so the historical table is the closest measured reference rather than a post-fix A/B.Plain and offset-only timing stayed effectively unchanged from part 1, confirming that
DASH_ENABLEDkeeps the new arclength work out of those shaders. Correct rendered 3D arclength increased the sparse dash pass by about 0.16 ms; the overdraw-heavy result remained within 0.005 ms of the prior layer.For 100,000 segments, normalized rendered-path metrics took about 2.9 ms at this head; the compatibility helper took about 1.5 ms for nested XYZ and 3.1 ms for flat XYZ. Path mode is the only mode that performs this CPU phase pass.
Correctness measurements improved at the same time: elevated-spacing relative standard deviation fell from 0.134 to 0.012 (about 91%), billboard and flat periods both became 34.8 px, and offsets 0/2/4/8 all retained the same 43.4 px period.
Validation
yarn lintpassed, and the affected-test pre-commit gate passed 15/15.Note
Medium Risk
Changes core PathLayer vertex shaders and PathStyleExtension attribute updates used by many map visualizations; behavior shifts are intentional but will alter existing dash rendering and golden images.
Overview
PathStyleExtension and PathLayer now measure dash length and phase in a single coordinate system so patterns stay consistent when geometry is tessellated, elevated, billboarded, offset, or clipped.
High-precision dashes no longer derive phase from a per-path
getPathtransform. A CPUcalculateDashMetricspass walks normalized tessellated segments (via newgetPathSegmentIndices), projects positions with shader-matching logic (projectRenderedPathPosition), and fillsinstanceDashOffsets. PathLayer tracks projection/tessellation inputs and invalidates only those metrics when the viewport ormodelMatrixchanges, without retessellating on every pan/zoom. GPU-only binary paths must supplydata.attributes.instanceDashOffsetsor the layer throws a clear error.Shaders (GLSL/WGSL, gated by
DASH_ENABLED) scale dash periods to half-width in pixels, correct billboard vs flat extrusion, advance along true 3D arclength, preserve phase whenclipLineshortens billboard segments (vPathBounds), fix short justified segments, and keep offset widening from drifting dash phase. Docs clarify thatgetDashArrayis relative to half stroke width.Tests and render-suite comments/goldens are updated to assert the corrected behavior (continuous phase on dense polylines, billboard parity, 3D elevation, clipping composition, offsets).
Reviewed by Cursor Bugbot for commit 5c51ecc. Bugbot is set up for automated code reviews on this repo. Configure here.