Halftone Bloom

Free

A photo rendered as a field of glowing dots that blooms open, settles to a pale stage, then warms to your colour.

Organic & NatureWebGLauto-playinteractivemobile-friendly

Code

Updates live with your settings.

Preparing the code…

How to use

  1. 1

    Install the dependency

    npm i three

  2. 2

    Add the files

    Copy the files from the Code section into a folder named halftone-bloom/ in your project. They are plain TypeScript; the React wrapper is one file and the engine does not depend on it.

  3. 3

    Drop in the component

    Place <HalftoneBloom /> inside a positioned container with a size; it fills the container. Every setting is a prop, and changing a prop updates the running effect.

  4. 4

    Other frameworks

    Vue, Svelte, Astro or plain HTML: use the engine directly, or copy the AI Prompt and let your assistant write the wrapper for your stack. The prompt carries this exact code.

Props

PropTypeDefaultDescription
imagestring (URL)"lily.jpg"A light subject on a near-black background. The effect reads brightness only.
fitnumber 0.3–10.92Largest share of the height the picture may fill.
scalenumber 0.5–1.61Multiplier on the picture's size.
dotPitchnumber 3–24 px6Distance between dot centres.
dotSizenumber 0.3–0.90.58Largest dot radius as a share of the pitch.
blacknumber 0–0.50.06Brightness treated as black. Raise it if the background is grey.
whitenumber 0.4–11Brightness treated as white.
gammanumber 0.4–31.15Curve on the mid-tones. Higher makes mid dots smaller.
detailnumber 0–1.50.6Boosts edges and veins against their surroundings.
softennumber 0–20.25Extra blur when sampling, in mip levels. Smooths blotchy pictures.
liftnumber 0–10Floor for dark but coloured details so they keep their dots.
accentstring (#hex)"#d30078"Colour of the final wash. The deep-to-pale ramp is derived from it.
palestring (#hex)"#ffd9e8"Colour of the middle stage, before the wash.
backgroundstring (#hex)"#0a0a0a"Page colour painted behind the dots.
keepColornumber 0–10.7Share of the picture's own colour kept in the final stage.
saturationnumber 0–21.25Saturation of that colour. 1 is as shot.
vividbooleanfalseKeep the picture's own colours all the way through: no pale stage, no wash.
tintnumber 0–10Strength of two extra hues in the final stage.
tintShadowstring (#hex)"#ffffff"Laid over the dim dots.
tintLightstring (#hex)"#ffffff"Laid over the brightest dots.
glownumber 0–21Strength of the wide, soft haze behind the dots.
bloomnumber 0–10.24Glow around the brightest dots.
bloomRadiusnumber 0–10.9How far the bloom reaches.
bloomKneenumber 0–0.50.01How gradually dots enter the bloom. Wider stops halos flickering.
speednumber 0.25–3 x11 plays the bloom in about eight seconds.
reveal"radial" | "sweep" | "none""radial"Shape of the bloom-in.
twinklenumber 0–11Live shimmer kept once settled. 0 holds every dot steady.
swaynumber 0–11Breathing and sway of the whole picture.
hovernumber 0–11How much nearby dots swell toward the pointer.
loopbooleanfalseReplay the intro a few seconds after it settles.
trigger"load" | "inview" | "click""load"When the intro plays.
quietZonenumber 0–10How much the dots behind a headline dim. 0 turns the zone off.
quietZoneYnumber 0–10.53Vertical centre as a share of the height.
quietZoneWidthnumber 0.1–10.6Share of the host width.
quietZoneHeightnumber 0.05–10.44Share of the host height.
maxDprnumber 1–22Cap on device pixel ratio. 1 is roughly four times cheaper than 2 on retina screens.

Performance

Bundle
~160 KB gzipped, almost all of it three
Cost
Medium
Renders on
GPU (WebGL)
Reduced motion
Respected
  • Depends on three ^0.186.0.
  • One full-screen fragment shader plus a bloom pass; the cost scales with the canvas area, so cap maxDpr on large screens.
  • Pauses when off-screen or when the tab is hidden.
  • With prefers-reduced-motion the picture appears settled and nothing moves.

Related