feat(extensions): add StrokeStyleExtension for dashed strokes on SDF layers#9976
feat(extensions): add StrokeStyleExtension for dashed strokes on SDF layers#9976chrisgervang wants to merge 6 commits intomasterfrom
Conversation
| pos = arcBottomLeft + leftEdge + arcTopLeft + topEdge + angle / (PI * 0.5) * arcTopRight; | ||
| } | ||
| // Right edge | ||
| else if (pixelPos.x >= max(pixelPos.y, height - pixelPos.y) && pixelPos.y >= rBottomRight && pixelPos.y <= height - rTopRight) { |
There was a problem hiding this comment.
Incorrect edge detection for non-square rounded rectangles
Medium Severity
The strokeStyle_getPerimeterPosition function uses diagonal-based region detection instead of distance-based detection for determining which edge a pixel belongs to. Conditions like pixelPos.y >= max(pixelPos.x, width - pixelPos.x) for the top edge and pixelPos.x >= max(pixelPos.y, height - pixelPos.y) for the right edge fail for non-square rectangles. For a 200x100 rectangle, a pixel at (100, 99) is 1 pixel from the top but gets classified as "right edge" because 99 >= 100 is false. The non-rounded version strokeStyle_getRectPerimeterPosition correctly uses actual distance calculations.
Add a new StrokeStyleExtension that enables rendering dashed strokes on ScatterplotLayer circle outlines. This implements feature request #9864. The extension uses shader injection to calculate dash patterns based on the angle around the circle's circumference. It supports: - getDashArray accessor: [solidLength, gapLength] relative to stroke width - dashGapPickable prop: controls whether gaps are pickable When a circle is both stroked and filled, the fill color shows through the gaps. When only stroked (no fill), fragments in gaps are discarded. https://claude.ai/code/session_01KsGs1v7AGFNXyvMUhjaiFm
…ndLayer Add support for dashed strokes on TextBackgroundLayer rectangles in addition to ScatterplotLayer circles. The extension now auto-detects the layer type and uses the appropriate shader injection: - ScatterplotLayer: angle-based dash calculation around circle circumference - TextBackgroundLayer: perimeter-based dash calculation around rectangle edges No performance impact on ScatterplotLayer since each layer type gets only its specific shader code at compile time. https://claude.ai/code/session_01KsGs1v7AGFNXyvMUhjaiFm
…calculation The perimeter position calculation now properly accounts for rounded corners in TextBackgroundLayer. When borderRadius is set: - Corner arcs are included in the perimeter length calculation - Position along corner arcs uses angle-based interpolation - Each corner can have a different radius (vec4 borderRadius) This ensures dash patterns flow smoothly around rounded corners without discontinuities. https://claude.ai/code/session_01KsGs1v7AGFNXyvMUhjaiFm
Add comprehensive documentation for the new StrokeStyleExtension including: - Usage examples for ScatterplotLayer and TextBackgroundLayer - API reference for getDashArray and dashGapPickable props - Explanation of how dash calculation works for circles vs rectangles - Comparison table with PathStyleExtension - Details on rounded corner support for TextBackgroundLayer https://claude.ai/code/session_01KsGs1v7AGFNXyvMUhjaiFm
- Add examples/stroke-style-test for interactive testing - Apply linter formatting to test file Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
105108f to
4fb089b
Compare
| vec2 cornerCenter = vec2(rBottomLeft, rBottomLeft); | ||
| vec2 toPixel = pixelPos - cornerCenter; | ||
| float angle = atan(toPixel.x, -toPixel.y); // 0 at bottom, PI/2 at left | ||
| pos = (PI * 0.5 - angle) / (PI * 0.5) * arcBottomLeft; |
There was a problem hiding this comment.
Corner angle formulas produce wrong perimeter positions
High Severity
The bottom-left and top-left corner arc angle calculations in strokeStyle_getPerimeterPosition are incorrect. In both corners, the atan arguments produce results in the range (-PI/2, 0), but the formulas assume the range (0, PI/2). For the bottom-left corner, atan(toPixel.x, -toPixel.y) yields (-PI/2, 0) since toPixel.x < 0 and -toPixel.y > 0, causing positions to be offset by +arcBottomLeft. For the top-left corner, the same issue causes positions to decrease through the arc instead of increasing, creating a direction reversal. Both produce visible dash pattern discontinuities at these corners.
Additional Locations (1)
…sion docs TextBackgroundLayer is an internal layer without its own documentation page. Link to TextLayer instead since TextBackgroundLayer is used internally by it. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>


Summary
Implements feature request #9864 - adds
StrokeStyleExtensionto enable dashed strokes on SDF-based layers.Supported Layers
New Props (via extension)
getDashArray:[dashSize, gapSize]relative to stroke widthdashGapPickable: Whether gaps are pickable (default:false)Usage
https://claude.ai/code/session_01KsGs1v7AGFNXyvMUhjaiFm
Note
Medium Risk
Introduces new shader injections and layer type detection that affect rendering/picking behavior for supported layers; risk is contained to opt-in usage via the new extension.
Overview
Adds a new
StrokeStyleExtensionthat enables dashed stroke rendering for SDF-based layers by injecting layer-specific shader code and wiring a new instancedinstanceDashArraysattribute plus adashGapPickableuniform.Updates the public extensions surface (
modules/extensions/src/index.ts) and docs navigation to include the new extension, and adds a runnable Vite example.Extends test coverage with new unit tests for attribute/uniform updates and adds new render golden test cases for dashed
ScatterplotLayervariants (plus a minor formatting-only change in the scatterplot fragment shader).Written by Cursor Bugbot for commit 71c76f9. This will update automatically on new commits. Configure here.