KQ-1526 · MOIRE/BAND
Moire Band
Two ribbons of fine parallel wires drift and turn over across the box, drawn per pixel in one WebGL2 pass with optional content above, and wherever they overlap broad interference fringes bloom and slide far faster than the wires move. The fringes are computed, not aliased: each grating is a short Fourier series of its wire and their product is expanded into sum and difference terms, each filtered by its own frequency, so the moire survives at any scale. The pointer sets the twist on a curve that is fine near the middle (calm wide bands) and coarse at the ends (racing fringes), followed on springs.glide; the first sighting brings the twist in from wider on springs.drift. It is a slider: arrows, Page Up and Down, Home and End.
Waylight Optics
Light, measured twice
twist 6.0° · steady fringes
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/moire-band
Props
- children
- React.ReactNode
- default —
- The content above the ribbons: a hero line, a heading, a call to action.
- wireCount
- number
- default 40
- Wires in each ribbon, 8 to 120.
- spacing
- number
- default 3.5
- Distance between neighbouring wires, in px; ribbons wider than 80% of the box tighten to fit.
- twist
- number
- default 6
- The twist between the two ribbons, in degrees, where the band starts; changing it moves the band there.
- value
- number
- default —
- The twist when you control it, in degrees; pair with `onValueChange`.
- onValueChange
- (degrees: number) => void
- default —
- Fires from the pointer or the keys that turned the twist, with the new twist in degrees.
- maxTwist
- number
- default 24
- The furthest the pointer or keys can turn the twist either way, in degrees.
- drift
- number
- default 0.35
- How restless the ribbons are, 0 (still) to 1.
- roll
- number
- default 0.5
- How far each ribbon turns over as it runs, 0 (flat) to 1 (edge-on at its narrowest).
- wireWidth
- number
- default 0.4
- A wire's width as a share of the spacing, 0.15 to 0.7.
- tint
- string | readonly [string, string]
- default ["var(--foreground)", "var(--accent-bright)"]
- The wires' colour, or one colour for each ribbon, as CSS colours.
- interactive
- boolean
- default true
- The pointer and keys turn the twist.
- intro
- boolean
- default true
- The first time the band comes into view, the twist arrives from wider so the fringes spread into calm bands.
- paused
- boolean
- default false
- Hold the ribbons still; the twist still turns.
- label
- string
- default "Ribbon twist"
- Names the twist control for assistive technology.
- seed
- number
- default 2
- Seeds the ribbons' curves and turns, so two bands never match.
- dpr
- number
- default 2
- Cap on the canvas's device pixel ratio, at most 2.
- disabled
- boolean
- default false
- Shows the band but takes no input.
- className
- string
- default "h-full w-full"
- Sizes and shapes the box.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | — | The content above the ribbons: a hero line, a heading, a call to action. |
| wireCount | number | 40 | Wires in each ribbon, 8 to 120. |
| spacing | number | 3.5 | Distance between neighbouring wires, in px; ribbons wider than 80% of the box tighten to fit. |
| twist | number | 6 | The twist between the two ribbons, in degrees, where the band starts; changing it moves the band there. |
| value | number | — | The twist when you control it, in degrees; pair with `onValueChange`. |
| onValueChange | (degrees: number) => void | — | Fires from the pointer or the keys that turned the twist, with the new twist in degrees. |
| maxTwist | number | 24 | The furthest the pointer or keys can turn the twist either way, in degrees. |
| drift | number | 0.35 | How restless the ribbons are, 0 (still) to 1. |
| roll | number | 0.5 | How far each ribbon turns over as it runs, 0 (flat) to 1 (edge-on at its narrowest). |
| wireWidth | number | 0.4 | A wire's width as a share of the spacing, 0.15 to 0.7. |
| tint | string | readonly [string, string] | ["var(--foreground)", "var(--accent-bright)"] | The wires' colour, or one colour for each ribbon, as CSS colours. |
| interactive | boolean | true | The pointer and keys turn the twist. |
| intro | boolean | true | The first time the band comes into view, the twist arrives from wider so the fringes spread into calm bands. |
| paused | boolean | false | Hold the ribbons still; the twist still turns. |
| label | string | "Ribbon twist" | Names the twist control for assistive technology. |
| seed | number | 2 | Seeds the ribbons' curves and turns, so two bands never match. |
| dpr | number | 2 | Cap on the canvas's device pixel ratio, at most 2. |
| disabled | boolean | false | Shows the band but takes no input. |
| className | string | "h-full w-full" | Sizes and shapes the box. |