Lightning
NewFreeBranching 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
Installation
pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/lightning.jsonNeeds 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/effectsimport { 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
TeslaViolet StormSolar FlareInkToxic
Props
| Name | Type | Default | Description |
|---|---|---|---|
| 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. |
| intensity | number | 1 | Overall brightness of the bolts. Range 0 to 2. |
| frequency | number | 14 | Strikes 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. |
| branching | number | 0.6 | How many forks leave the main channel. Range 0 to 1. |
| thickness | number | 1 | Width of the channel; 1 is a bright core about 1.5px wide. Range 0.4 to 3. |
| jaggedness | number | 0.65 | How far the channel wanders and kinks. Range 0 to 1.5. |
| glow | number | 1 | Strength and reach of the coloured glow around the bolt. Range 0 to 2. |
| flash | number | 0.5 | How much the whole scene swells with light on a strike. Always a soft swell, never a hard flash. Range 0 to 1. |
| haze | number | 0.8 | Faint ionised cloud that drifts and is lit from within by the bolts. Range 0 to 1.5. |
| pointerFollow | number | 0.6 | How much strikes lean toward the pointer, and how closely the pointer-mode tendril follows it. Range 0 to 1. |
| coreColor | string | '#f3f9ff' | The white-hot centre of the channel (the ink on a light look). A hex colour. |
| glowColor | string | '#4f8bff' | Colour of the glow around the bolt. A hex colour. |
| hazeColor | string | '#2a46c9' | Colour of the haze and the outer halo. A hex colour. |
| background | string | '#050816' | Page colour. A light colour switches to ink on paper. A hex colour. |
| grain | number | 0.35 | Film grain over the picture. Range 0 to 1. |
| transparent | boolean | false | Draw only the light so it sits over your own page: additive on dark pages, ink on light ones. |
| className | string | — | Extra class on the root element. The effect fills its parent: give the parent a height. |
| style | CSSProperties | — | Inline style on the root element. |
Files
What the command adds to your project, and where.
components/effects/lightning/lightning.tsxThe component.
components/effects/lightning/scene.tsxThe component.
components/effects/lightning/showcase.tsxThe component.
components/effects/lightning/poster.tsxThe component.
components/effects/lightning/look.tsThe component.
components/effects/lightning/bolt.tsThe component.
components/effects/lightning/sim.tsThe component.
components/effects/lightning/shaders.tsThe fragment shader, as a string. Edit it to change the picture.
components/effects/lightning/stage-styles.tsThe component.
lib/effect-runtime.tsShared 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.