Skip to content

feat(extensions): add StrokeStyleExtension for dashed strokes on SDF layers#9976

Open
chrisgervang wants to merge 8 commits intomasterfrom
claude/implement-feature-9864-rWt7o
Open

feat(extensions): add StrokeStyleExtension for dashed strokes on SDF layers#9976
chrisgervang wants to merge 8 commits intomasterfrom
claude/implement-feature-9864-rWt7o

Conversation

@chrisgervang
Copy link
Collaborator

@chrisgervang chrisgervang commented Feb 1, 2026

Summary

Implements feature request #9864 - adds StrokeStyleExtension to enable dashed strokes on SDF-based layers.

Supported Layers

  • ScatterplotLayer: Dashed circle strokes using angle-based calculation around the circumference
  • TextBackgroundLayer: Dashed rectangle strokes using perimeter-based calculation (including rounded corners)

New Props (via extension)

  • getDashArray: [dashSize, gapSize] relative to stroke width
  • dashGapPickable: Whether gaps are pickable (default: false)

Usage

import {ScatterplotLayer} from '@deck.gl/layers';
import {StrokeStyleExtension} from '@deck.gl/extensions';

new ScatterplotLayer({
  stroked: true,
  getDashArray: [3, 2],
  extensions: [new StrokeStyleExtension({dash: true})]
});

https://claude.ai/code/session_01KsGs1v7AGFNXyvMUhjaiFm


Note

Medium Risk
Opt-in shader injection adds new dashed-stroke rendering/picking paths for ScatterplotLayer and TextBackgroundLayer, which could introduce subtle visual or picking regressions for layers using the extension. Changes are otherwise additive with new docs/tests/examples to validate output.

Overview
Adds a new StrokeStyleExtension that enables dashed strokes for SDF-based stroked layers, exposing getDashArray and dashGapPickable and injecting layer-specific shader code for ScatterplotLayer (angle-based dashes) and TextBackgroundLayer (perimeter/rounded-corner dashes).

Exports the extension from @deck.gl/extensions, documents it in the extensions API reference and TOC, and adds an example app plus new unit and golden-image render tests covering dashed filled and stroked-only scatterplots.

Written by Cursor Bugbot for commit ffa78a6. This will update automatically on new commits. Configure here.

@chrisgervang chrisgervang changed the title feat(extensions): add StrokeStyleExtension for dashed circle strokes feat(extensions): add StrokeStyleExtension for dashed strokes on SDF layers Feb 1, 2026
@chrisgervang chrisgervang added this to the v9.3 milestone Feb 2, 2026
@chrisgervang chrisgervang force-pushed the claude/implement-feature-9864-rWt7o branch from 105108f to 4fb089b Compare February 6, 2026 16:26
claude and others added 7 commits February 27, 2026 11:08
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>
…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>
…eStyleExtension

- Fix corner angle formulas to correctly produce angles in range [0, PI/2]
- Fix edge detection to use distance-based comparison instead of diagonal-based
  which failed for non-square rectangles
- Simplify test app data for clearer demonstration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@chrisgervang chrisgervang force-pushed the claude/implement-feature-9864-rWt7o branch from 71c76f9 to c30b251 Compare February 27, 2026 19:08
For ScatterplotLayer with both fill and stroke, dash gaps now correctly
show the fill color instead of discarding the fragment. Also re-applies
autoHighlight effect to the fill color in gaps.

Test app updates:
- Use shared vite.config.local.mjs instead of custom config
- Add fill-only comparison circle for size comparison
- Enable autoHighlight on comparison circle

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

@cursor cursor bot left a comment

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 2 potential issues.

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

// In dash gap - discard unless picking gaps
if (!(strokeStyle.dashGapPickable && bool(picking.isActive))) {
discard;
}
Copy link

Choose a reason for hiding this comment

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

TextBackgroundLayer dash gaps discard fill color

High Severity

The textBackgroundDashShaders unconditionally discards fragments in dash gaps, but TextBackgroundLayer always has a fill. This creates transparent holes at the rectangle's edge where the fill color should show through. The scatterplot shader correctly handles this by setting a strokeStyle_inDashGap flag and overriding the color with vFillColor in an fs:#main-end injection, but the TextBackgroundLayer shader has no such fs:#main-end injection — it just discards.

Additional Locations (1)

Fix in Cursor Fix in Web

* Detect which layer type this is to use the appropriate shader injections
*/
private getLayerType(layer: Layer<StrokeStyleExtensionProps>): SupportedLayerType {
const layerName = layer.constructor.name;
Copy link

Choose a reason for hiding this comment

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

Layer detection uses minifiable constructor.name instead of layerName

Medium Severity

getLayerType reads layer.constructor.name for detection, but JavaScript class names get mangled in minified production builds. deck.gl layers provide a static layerName property (e.g. 'ScatterplotLayer') specifically to survive minification — the framework's own toString() method uses (this.constructor as typeof Layer).layerName for this reason. The prop-based fallback ('radiusScale' in layer.props) mitigates this but is less reliable and could match unintended layers.

Fix in Cursor Fix in Web

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.

2 participants