Media & effects
Dot Shader
Interactive GPU dot matrix background with cursor proximity shader dynamics
detent-dot-shader
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 4
- Wave
- phase-4-canvas
- Group
- Media & effects
Demo surface
Interactive dot matrix
Move the pointer across the canvas to see proximity illumination, radial repulsion and the lens bulge. The wobble behind this text is the ambient wave.
5.3 KB gzip for the class module
Variants
Everything inside the shader is real, selectable, keyboard-reachable light DOM above two
aria-hidden decorative layers. paused is demonstrated at runtime below: the last frame is
kept and the loop stops. The component emits no events, so this demo only reports its own state.
Pause target
Recorded states
expandedrecorded state; no setterreduced motionrecorded state; no setter
Usage
Import
import '/components/dot-shader/define.js';
// or register it yourself
import { DetentDotShader } from '/components/dot-shader/dot-shader.js';
Attributes
accent-colorcursor-radiusdistortion-strengthdot-colordot-sizeinteractivemax-scaleoverlaypausedspacingspeedwave-intensity
Properties
No properties are recorded for this component.
Slots
default
Events
No events are recorded for this component.
Example
Runnable example: site/examples/dot-shader.ts. The snippet below is generated from the catalogued attributes.
<detent-dot-shader
accent-color="#00F0FF"
cursor-radius="180"
distortion-strength="0.35"
dot-color="rgba(255, 255, 255, 0.15)"
dot-size="1.5"
interactive
max-scale="2.2"
overlay
paused
spacing="22"
speed="1"
wave-intensity="0.25"
></detent-dot-shader>
Source
The pinned upstream source for this row:
src/components/ui/DotShader.tsxsha256 eb2c3f2d3905…
Native files
The native module and its artifacts:
src/components/dot-shader/dot-shader.tssrc/components/dot-shader/styles.csssrc/components/dot-shader/define.tsdocs/components/dot-shader.mdsite/examples/dot-shader.tstests/browser/dot-shader.spec.tsevidence/components/dot-shader.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
accent-color | accentColor | string | '#00F0FF' | Kebab-case attribute; camelCase property. |
cursor-radius | cursorRadius | number | 180 | Kebab-case attribute; camelCase property. |
distortion-strength | distortionStrength | number | 0.35 | Kebab-case attribute; camelCase property. |
dot-color | dotColor | string | 'rgba(255, 255, 255, 0.15)' | Kebab-case attribute; camelCase property. |
dot-size | dotSize | number | 1.5 | Kebab-case attribute; camelCase property. |
interactive | interactive | boolean | true | Presence semantics: present means true, absent means false. |
max-scale | maxScale | number | 2.2 | Kebab-case attribute; camelCase property. |
overlay | overlay | boolean | true | Presence semantics: present means true, absent means false. |
paused | — | — | — | Recorded in the catalog as an attribute. |
spacing | spacing | number | 22 | Kebab-case attribute; camelCase property. |
speed | speed | number | 1 | Kebab-case attribute; camelCase property. |
wave-intensity | waveIntensity | number | 0.25 | Kebab-case attribute; camelCase property. |
Properties
No property-only values are recorded for this component.
Events
No custom events are recorded for this component.
Slots
| Slot | Notes |
|---|---|
default | Consumer content; rendered through a slot, never re-created. |
CSS customisation
- React `children`/`ReactNode` props become DOM slots; caller content stays light DOM.
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- The WebGL/GLSL point shader is not ported; the Canvas 2D renderer (upstream fallback) is the only path. Headless WebKit exposes no WebGL, so the GPU path cannot be verified on the three required engines, and recorded features 1 and 6 are therefore not delivered (see evidenceGaps). Owner accepted this gap on 2026-10-29; every other recorded feature is implemented and pixel-verified.
- Each colour alpha is applied once; the pinned 2D fallback also multiplied the same alpha into globalAlpha, painting the documented default at an effective 0.0225 alpha (invisible).
- A document visibilitychange pause is added because PC-10.6 requires it; the source stops only for reduced motion, paused and offscreen.
- paused is exposed as attribute and property with the pinned source default false (the row recorded no default).
- The derived state is published as surface[data-state] and surface[data-motion] because a native element needs a DOM-observable hook where React owned it upstream.
What it does
An interactive dot-matrix background: cursor-proximity illumination, radial repulsion, a lens bulge and an ambient wave, painted into a canvas that sits beneath the caller's slotted content.
Upstream behaviour
- Hardware-accelerated WebGL point primitive vertex & fragment shader with Canvas 2D fallback
- Interactive cursor proximity illumination transitioning smoothly to accent color
- Magnetic/gravitational radial repulsion with smooth exponential damping
- Dynamic scale expansion creating a 3D lens bulge around the cursor
- Ambient wave undulation breathing subtle life into the background when idle
- Zero CPU overhead during rendering via GPU vertex shader positioning
- Supports wrapping arbitrary children without interfering with pointer interactions
- Full prefers-reduced-motion compliance freezing displacement and waves
Differences from upstream
- React `children`/`ReactNode` props become DOM slots; caller content stays light DOM.
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- The WebGL/GLSL point shader is not ported; the Canvas 2D renderer (upstream fallback) is the only path. Headless WebKit exposes no WebGL, so the GPU path cannot be verified on the three required engines, and recorded features 1 and 6 are therefore not delivered (see evidenceGaps). Owner accepted this gap on 2026-10-29; every other recorded feature is implemented and pixel-verified.
- Each colour alpha is applied once; the pinned 2D fallback also multiplied the same alpha into globalAlpha, painting the documented default at an effective 0.0225 alpha (invisible).
- A document visibilitychange pause is added because PC-10.6 requires it; the source stops only for reduced motion, paused and offscreen.
- paused is exposed as attribute and property with the pinned source default false (the row recorded no default).
- The derived state is published as surface[data-state] and surface[data-motion] because a native element needs a DOM-observable hook where React owned it upstream.