A precise dot matrix driven by a living signal: waves, noise, a radar sweep, pointer pulses, or a word that emerges in dots, with a pointer lens and five colour themes.

  • shader
  • webgl
  • background
  • halftone
  • dots
  • dot matrix
  • hero
Preset

Installation

pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/halftone-signal.json

Needs a React + Tailwind project set up with shadcn. Copies the effect into your project, along with lib/effect-runtime.ts, the small WebGL layer it runs on. No other dependencies.

Or from npm

pnpm add @kagadmodyaa/effects
import { HalftoneSignal } from '@kagadmodyaa/effects/halftone-signal'

One package with every free effect, one import path each. No Tailwind or shadcn needed, and no stylesheet to import: the few layout rules an effect needs come with it. The npm package and the command above ship the same source.

Usage

The effect fills its parent, so give the parent a height and put your content above it. Choose a theme with preset; any prop you pass as well overrides the preset.

import { HalftoneSignal } from '@/components/effects/halftone-signal/halftone-signal'

export function Hero() {
  return (
    <section className="relative h-[560px] overflow-hidden">
      <HalftoneSignal className="absolute inset-0" />
      <div className="relative z-10">{/* your content */}</div>
    </section>
  )
}
<HalftoneSignal preset="Signal" signal={"noise"} />

Presets

  • Newsprint
  • Signal
  • Sunset
  • Mono Grid
  • Bloom

Props

NameTypeDefaultDescription
preset'Newsprint' | 'Signal' | 'Sunset' | 'Mono Grid' | 'Bloom'none (the defaults below)A named theme. Any prop you pass as well overrides the preset’s value.
signal'waves' | 'noise' | 'radar' | 'pulse' | 'image''noise'What drives the dots: interfering waves, flowing noise, a radar sweep, rings from the pointer, or a word / image.
text'HALFTONE' | 'SIGNAL' | 'DOTS' | 'BLOOM''HALFTONE'The word the dots spell in image mode (when src is not set).
speednumber1How fast the signal moves. 0 freezes it. Range 0 to 2.
contrastnumber1.35How hard the signal is pushed toward on and off. Range 0.4 to 3.
baselinenumber0Smallest dot size, so an idle grid stays faintly visible. Range 0 to 0.3.
invertbooleanfalseSwap light and dark in the signal.
shape'circle' | 'square' | 'plus''circle'Dot shape.
grid'square' | 'hex''square'Square rows or staggered (hex) rows.
anglenumber45Rotate the dot screen, like a print screen; 45 is the classic newsprint angle. Range 0 to 90 °.
cellSizenumber11Distance between dot centres, in CSS pixels. Range 6 to 40 px.
dotScalenumber1Dot size at full signal. 1 makes neighbouring dots just touch. Range 0.3 to 1.3.
ramp'solid' | 'duotone' | 'tritone''solid'Solid uses Colour A; duotone blends A to B by dot size; tritone runs A, B, C.
colorAstring'#1d1a16'First ramp colour: the small dots, or the only colour. A hex colour.
colorBstring'#1d1a16'Second ramp colour. A hex colour.
colorCstring'#d93f2a'Third ramp colour, and the colour dots take under the pointer lens. A hex colour.
backgroundstring'#efe6d2'Background colour. A light colour switches the dots to ink on paper. A hex colour.
glownumber0Soft glow around lit dots. Range 0 to 1.5.
grainnumber0.55Print grain: paper tooth and a slight irregularity in dot size. Range 0 to 1.
lensRadiusnumber170Size of the pointer lens, in CSS pixels. Range 40 to 400 px.
lensStrengthnumber0.9How strongly dots near the pointer grow, push away and shift colour. 0 also turns click rings off. Range 0 to 1.5.
classNamestring—Extra class on the root element. The effect fills its parent: give the parent a height.
styleCSSProperties—Inline style on the root element.

Files

What the command adds to your project, and where.

  • components/effects/halftone-signal/halftone-signal.tsx

    The component.

  • components/effects/halftone-signal/shaders.ts

    The fragment shader, as a string. Edit it to change the picture.

  • lib/effect-runtime.ts

    Shared by every shader effect: resizing, pausing, reduced motion, context loss and the no-WebGL fallback. Installed once.

Behaviour

  • Draws on a WebGL canvas that is created in the browser only, so there is nothing to hydrate differently.
  • Pauses while it is off screen or the tab is hidden, and lowers its resolution automatically if frames run slow.
  • With prefers-reduced-motion it draws one still frame instead of animating.
  • Without WebGL you see a still gradient in the same colours.
  • It is decorative: hidden from assistive technology, and it never takes focus or captures clicks.

See all effects