LightningVein
A discharge branching across a dark sky, built by recursive displacement and deliberately flashing far slower than the real thing.
Options
-
sky#060507 -
css colour
The sky behind it. `auto` takes it from the page, which is almost always right: the strike should sit in your page rather than bring its own rectangle of night.
-
bolt#eaf2ff -
css colour
The channel itself. Near white with a little blue in it reads as hot; pure white reads as a drawn line.
-
halo#5d7fd4 -
css colour
The glow around the channel. Cooler and dimmer than the bolt, because air lit from the side scatters blue.
-
period9 -
3 to 60 s
Seconds from one strike to the next. Exactly periodic over this, and the lower bound is held well above anything WCAG 2.3.1 would count.
-
lean0.22 -
0 to 0.8
How far the strike wanders off vertical overall, as a share of the width. At 0 it falls straight down and looks drawn.
-
jitter0.16 -
0.02 to 0.5
The first displacement, as a share of the width. Every pass after it is half the one before, so this sets the character of the whole path.
-
detail6 -
3 to 8
How many times the path is subdivided. Six is sixty-four segments. Above seven the extra kinks are smaller than a pixel and cost without showing.
-
branches5 -
0 to 14
Limbs thrown off the main channel. At 0 it is a single stroke, which reads as a crack rather than a discharge.
-
weight2.2 -
0.6 to 6 px
Width of the main channel. The glow is drawn from this, so raising it thickens everything rather than only the core.
-
afterglow1.4 -
0 to 4 s
How long the channel stays faintly lit once the flash is over. This is most of what makes it read as a discharge rather than as a line that was switched off.
-
seed11 -
0 to 9999
Changes every bolt in the sequence without changing anything else about them.
What it needs
- Category
- Backdrops, an effect
- Dependencies
- None at all
- Browser
- No WebGL
- Frame budget
- ~0.5 ms · 0 context
- Pinned to
- v0.14.0
- Canvas 2D rather than a shader, because the subject is a path. A branching polyline is a handful of line segments to a canvas and a signed distance field to a fragment shader, which would be hundreds of distance tests per pixel for a shape that is mostly empty space
- The path is built by recursive midpoint displacement: one segment, push the midpoint along its normal, repeat on both halves with half the push. That gives kinks at every scale, which is what a discharge looks like. A wobble applied per step has detail at one scale only and reads as a scribble
- The push is along the segment normal rather than along x. Pushing along x gives a bolt that is only ever ragged left and right, which reads as a flag rather than as electricity
- Branches leave the channel and never rejoin it. They start below the head, because a branch off the very top has nothing above it to have come from
- Flashing is bounded on purpose and this is the one number not to raise. WCAG 2.3.1 is Level A and wants nothing flashing more than three times a second; real lightning flickers far faster. A strike here brightens at most twice and the next is a `period` away, which at the default is two brightenings in nine seconds
- Nothing is random at render time. The strike index comes from `t` by division, the bolt is built from a generator seeded on that index, and the same `t` always gives the same bolt. That is what lets the recorder seek and what closes the loop
- The glow is three strokes of increasing width rather than shadowBlur. shadowBlur on a path of a thousand points is the slowest thing a canvas can be asked to do, and the falloff is indistinguishable
- Built for a dark ground and declared as one. A discharge is light, and on a pale ground there is nothing for it to be brighter than
- The path is built once per strike and kept, not rebuilt per frame. Six passes over a growing array is a few thousand points of arithmetic for a shape that does not change while the strike burns
- Most frames draw nothing at all. Between strikes the envelope is under a thousandth and the renderer returns after clearing, so the resting cost of this backdrop is one fill
- Zero WebGL contexts, which is the quiet advantage of doing this in 2D. The one context budget is for the page as a whole, and a storm behind your content does not spend any of it, so a WebGL item elsewhere on the page is unaffected