Branching lightning bolts and crackling arcs: a white-hot core, coloured glow, forks, return strokes, afterglow and a soft scene flash, as a storm, an arc between two points or a bolt that reaches for the pointer.

  • shader
  • webgl
  • lightning
  • electric
  • arc
  • storm
  • hero
  • hover
Preset

Installation

pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/lightning.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 { Lightning } from '@kagadmodyaa/effects/lightning'

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

Use it like any other component. Choose a theme with preset; any prop you pass as well overrides the preset.

import { useRef } from 'react'
import { Lightning, type LightningHandle } from '@/components/effects/lightning/lightning'

export function Hero() {
  const bolts = useRef<LightningHandle>(null)
  return (
    <section className="relative h-[640px] overflow-hidden">
      {/* a storm behind a headline: fills its parent, strikes from the top edge */}
      <Lightning ref={bolts} preset="Tesla" frequency={12} className="absolute inset-0" />
      <div className="relative z-10 mx-auto max-w-xl px-6 pt-32 text-center text-white">
        <h1 className="text-6xl font-semibold tracking-tight">Call down the storm.</h1>
        <button onClick={() => bolts.current?.strike()}>Strike</button>
      </div>
    </section>
  )
}

// An arc between two points (fractions of the box, y down), drawn only as light over your own page:
//   <Lightning mode="arc" transparent source={[0.15, 0.5]} target={[0.85, 0.5]} className="absolute inset-0" />
// A tendril that reaches for the pointer from the top centre, click to strike:
//   <Lightning mode="pointer" preset="Violet Storm" className="absolute inset-0" />
// Presets: Tesla, Violet Storm, Solar Flare, Ink (the light one: ink on paper), Toxic.
// The stage above is <LightningShowcase />, also exported, with a headline, a Strike button and an arc between two buttons.
<Lightning preset="Violet Storm" mode={"storm"} />

Presets

  • Tesla
  • Violet Storm
  • Solar Flare
  • Ink
  • Toxic

Props

NameTypeDefaultDescription
preset'Tesla' | 'Violet Storm' | 'Solar Flare' | 'Ink' | 'Toxic'none (the defaults below)A named theme. Any prop you pass as well overrides the preset’s value.
mode'storm' | 'arc' | 'pointer''storm'storm: bolts strike from the top edge. arc: a continuous crackling arc between two points. pointer: a tendril reaches for the pointer and a click strikes.
intensitynumber1Overall brightness of the bolts. Range 0 to 2.
frequencynumber14Strikes per minute in storm and pointer modes. Strikes are never closer than about half a second, so at most two flashes a second. Range 0 to 60 /min.
branchingnumber0.6How many forks leave the main channel. Range 0 to 1.
thicknessnumber1Width of the channel; 1 is a bright core about 1.5px wide. Range 0.4 to 3.
jaggednessnumber0.65How far the channel wanders and kinks. Range 0 to 1.5.
glownumber1Strength and reach of the coloured glow around the bolt. Range 0 to 2.
flashnumber0.5How much the whole scene swells with light on a strike. Always a soft swell, never a hard flash. Range 0 to 1.
hazenumber0.8Faint ionised cloud that drifts and is lit from within by the bolts. Range 0 to 1.5.
pointerFollownumber0.6How much strikes lean toward the pointer, and how closely the pointer-mode tendril follows it. Range 0 to 1.
coreColorstring'#f3f9ff'The white-hot centre of the channel (the ink on a light look). A hex colour.
glowColorstring'#4f8bff'Colour of the glow around the bolt. A hex colour.
hazeColorstring'#2a46c9'Colour of the haze and the outer halo. A hex colour.
backgroundstring'#050816'Page colour. A light colour switches to ink on paper. A hex colour.
grainnumber0.35Film grain over the picture. Range 0 to 1.
transparentbooleanfalseDraw only the light so it sits over your own page: additive on dark pages, ink on light ones.
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/lightning/lightning.tsx

    The component.

  • components/effects/lightning/scene.tsx

    The component.

  • components/effects/lightning/showcase.tsx

    The component.

  • components/effects/lightning/poster.tsx

    The component.

  • components/effects/lightning/look.ts

    The component.

  • components/effects/lightning/bolt.ts

    The component.

  • components/effects/lightning/sim.ts

    The component.

  • components/effects/lightning/shaders.ts

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

  • components/effects/lightning/stage-styles.ts

    The component.

  • lib/effect-runtime.ts

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

Behaviour

  • Bolts are generated procedurally: a main channel built by midpoint-style displacement with thinner forks fanning off it. Each strike is timed like the real thing: a leader runs down the channel in a fraction of a second, a white-hot stroke, one return stroke, then an afterglow that fades over a second or two. Between strikes a storm has faint crackles near the top edge and drifting haze lit from within.
  • Storm mode strikes from the top edge at the set frequency (strikes per minute), sometimes twice in quick succession. Arc mode keeps a continuous arc between source and target that wriggles smoothly, with a thinner second strand, forks that come and go and glowing end points; strike() makes it surge. Pointer mode reaches a tendril most of the way toward the pointer from the source (the top centre) and a click or tap strikes at that point.
  • Photosensitivity: strikes are never closer than about half a second, so the scene swells at most twice in any second, and a swell is soft (about 60 ms up, 200 ms down), not a hard flash. The return stroke does not flash the scene, and an arc only drifts in brightness. Set flash to 0 for none at all.
  • Lines are drawn analytically, so they stay crisp at any resolution and never shimmer: a thin channel loses brightness instead of aliasing. Dark looks add light in linear space (a strong core goes to white while the glow keeps its hue); Ink is dark graphite strokes on warm paper with no glow, for light pages. With transparent on, only the light is drawn, so it can sit over your own page.
  • It fills its parent and pauses off screen and in a background tab, lowers its resolution automatically if frames run slow, and under prefers-reduced-motion draws one frozen bolt with no flashing. Without WebGL, and before the first frame, you see a poster of a bolt with its forks in the same colours.
  • Click or tap the stage (not a button or link) to strike toward that point; clickToStrike={false} turns that off. ref.current.strike() fires one from code.

See all effects