dithered-motif-site
Overview
Full pipeline for turning a described subject into an animated, pointer-reactive,
Bayer-dithered dot-field background: source image/video prompt -> frame
extraction -> canvas dither engine -> looping -> pointer interaction -> page
composition. Sourced from a working Higgsfield/Renaissance-oil-painting
implementation; the prompt style and the algorithm below are proven together,
but every stage generalizes to other visual styles as long as the subject
rule in Step 1 is respected.
The one rule everything else depends on: the subject must be made of many
small discrete elements (sparks, ash, tracery, a flock, a crowd, crops in a
field, repeated architecture). A solid object — one face, one animal, one
smooth mass — turns into an illegible grey blob when dithered, because the
dot field has no internal structure to latch onto. If the source is a solid
object, change the source; don't fight the dither settings.
Pipeline
- Image prompt (Higgsfield
nano_banana_pro) — see
references/image-prompts.md. Generate via the generate_image MCP tool
if available, or hand the user the filled prompt to paste manually.
- Video prompt (Higgsfield
seedance_2_0, image-to-video) — see
references/video-prompts.md. Locked-off camera language is
non-negotiable; a drifting subject cannot be fixed downstream.
- Frame extraction (ffmpeg) — see
references/frame-extraction.md.
- Dither engine — see
references/dither-engine.md for the full
algorithm/parameter spec and references/dither-engine.ts for a reference
TypeScript canvas implementation to adapt directly into the target repo
(React/Next.js <canvas> component or vanilla).
- Looping — crossfade-the-wrap for non-cyclic motifs (the common case);
scored-seam matching only for genuinely cyclic subjects. Covered in
references/dither-engine.md.
- Pointer interaction — displace sampling coordinates, not drawn output.
Covered in
references/dither-engine.md.
- Page composition — full-bleed canvas, legibility solution (scrim /
blend-mode / backing panel), canvas background = page ground color so
empty cells read as background, not white. Covered in
references/dither-engine.md.
Load-bearing gotchas (do not skip)
- Pin auto-levels for the whole sequence. Compute the 2nd/98th percentile
luma levels once, reuse for every frame. Recomputing per frame makes dot
density visibly pulse — this is the single easiest thing to get wrong.
- Invert is about the SOURCE, not the page theme. Dark subject on light
background -> invert so dots land on the subject. Light subject on dark
background -> don't invert. This is independent of whether the page itself
is light or dark mode.
- Crop before scale if the source has a painted/generated border baked
in (common with AI image models) — otherwise it dithers into a hard
rectangle sitting mid-page.
- Airiness = cell size vs dot fill, not dot count. If the result looks
heavy and flat, raise
pixelSize and lower dotScale together — do not
just add more dots.
- Most natural motifs have no true loop point. Don't hunt for a seam
that doesn't exist; crossfade the wrap instead (see reference doc for the
short-sequence edge case).
- Avoid radial ripple for pointer interaction on natural motifs — it
reads as a lens artifact sitting on top of the image, not something
happening to the subject. Match interaction shape to subject shape instead
(directional lean / rotational twist / gentle scatter).
mix-blend-mode: multiply for text legibility only works on light
grounds. On dark grounds use a scrim or backing panel instead.
Sanity checklist before shipping (from source material)
- Dot density constant across the whole loop — if it pulses, auto-levels
aren't pinned.
- No visible jump at the wrap — if there is, lengthen the crossfade.
- Headline readable at every point in the animation, not just one screenshot.
- Subject still reads as itself at the chosen
pixelSize — coarser is more
striking but there's a point where it dissolves.
- Looks right on a narrow viewport where the canvas is much smaller relative
to
pixelSize — small canvases usually need a finer grid.
References
references/image-prompts.md — Higgsfield nano_banana_pro prompt
patterns and three worked examples (molten forge sparks, cathedral rose
window, falling ash over a lost city).
references/video-prompts.md — Higgsfield seedance_2_0 image-to-video
settings and prompt patterns, worked examples matching the image prompts.
references/frame-extraction.md — ffmpeg commands for frame rate, crop,
and background-noise flattening.
references/dither-engine.md — full algorithm spec: buffer downscale,
luma conversion, auto-levels, invert, floor clamp, 8x8 Bayer quantization,
batched cell drawing, parameter table, color approaches (sampled / duotone
/ blended), looping, pointer interaction, page composition.
references/dither-engine.ts — reference TypeScript canvas implementation
of the engine above, meant to be adapted (not copy-pasted verbatim) into
the target app's component structure.
1---2name: dithered-motif-site3description: Use when building a "dithered particle-field" animated hero/background — a still or video subject made of many small discrete elements (sparks, falling ash, a rose window, a flock, crowds, falling particles, repeated architecture) rendered as an animated Bayer-dithered dot field on a canvas, with pointer-reactive warp, used as a full-bleed page background. Covers the whole manual pipeline: (1) writing Higgsfield `nano_banana_pro` image prompts and `seedance_2_0` (image-to-video) prompts whose SUBJECT is dither-compatible — the rule that a solid object (one face, one animal, one smooth mass) turns into an illegible grey blob and only "many small discrete elements" survives dithering, and that video prompts MUST demand a locked-off static camera or the loop becomes unusable; (2) ffmpeg frame extraction (~11fps, crop any painted border before scale, flatten background noise); (3) the canvas dither engine itself — downscale-to-buffer, Rec.709 luma, percentile auto-levels PINNED for the whole sequence (never recom4---56# dithered-motif-site78## Overview910Full pipeline for turning a described subject into an animated, pointer-reactive,11Bayer-dithered dot-field background: source image/video prompt -> frame12extraction -> canvas dither engine -> looping -> pointer interaction -> page13composition. Sourced from a working Higgsfield/Renaissance-oil-painting14implementation; the prompt style and the algorithm below are proven together,15but every stage generalizes to other visual styles as long as the **subject16rule** in Step 1 is respected.1718**The one rule everything else depends on:** the subject must be made of many19small discrete elements (sparks, ash, tracery, a flock, a crowd, crops in a20field, repeated architecture). A solid object — one face, one animal, one21smooth mass — turns into an illegible grey blob when dithered, because the22dot field has no internal structure to latch onto. If the source is a solid23object, change the source; don't fight the dither settings.2425## Pipeline26271. **Image prompt** (Higgsfield `nano_banana_pro`) — see28 `references/image-prompts.md`. Generate via the `generate_image` MCP tool29 if available, or hand the user the filled prompt to paste manually.302. **Video prompt** (Higgsfield `seedance_2_0`, image-to-video) — see31 `references/video-prompts.md`. Locked-off camera language is32 non-negotiable; a drifting subject cannot be fixed downstream.333. **Frame extraction** (ffmpeg) — see `references/frame-extraction.md`.344. **Dither engine** — see `references/dither-engine.md` for the full35 algorithm/parameter spec and `references/dither-engine.ts` for a reference36 TypeScript canvas implementation to adapt directly into the target repo37 (React/Next.js `<canvas>` component or vanilla).385. **Looping** — crossfade-the-wrap for non-cyclic motifs (the common case);39 scored-seam matching only for genuinely cyclic subjects. Covered in40 `references/dither-engine.md`.416. **Pointer interaction** — displace sampling coordinates, not drawn output.42 Covered in `references/dither-engine.md`.437. **Page composition** — full-bleed canvas, legibility solution (scrim /44 blend-mode / backing panel), canvas background = page ground color so45 empty cells read as background, not white. Covered in46 `references/dither-engine.md`.4748## Load-bearing gotchas (do not skip)4950- **Pin auto-levels for the whole sequence.** Compute the 2nd/98th percentile51 luma levels once, reuse for every frame. Recomputing per frame makes dot52 density visibly pulse — this is the single easiest thing to get wrong.53- **Invert is about the SOURCE, not the page theme.** Dark subject on light54 background -> invert so dots land on the subject. Light subject on dark55 background -> don't invert. This is independent of whether the page itself56 is light or dark mode.57- **Crop before scale** if the source has a painted/generated border baked58 in (common with AI image models) — otherwise it dithers into a hard59 rectangle sitting mid-page.60- **Airiness = cell size vs dot fill, not dot count.** If the result looks61 heavy and flat, raise `pixelSize` and lower `dotScale` together — do not62 just add more dots.63- **Most natural motifs have no true loop point.** Don't hunt for a seam64 that doesn't exist; crossfade the wrap instead (see reference doc for the65 short-sequence edge case).66- **Avoid radial ripple** for pointer interaction on natural motifs — it67 reads as a lens artifact sitting on top of the image, not something68 happening to the subject. Match interaction shape to subject shape instead69 (directional lean / rotational twist / gentle scatter).70- **`mix-blend-mode: multiply` for text legibility only works on light71 grounds.** On dark grounds use a scrim or backing panel instead.7273## Sanity checklist before shipping (from source material)7475- Dot density constant across the whole loop — if it pulses, auto-levels76 aren't pinned.77- No visible jump at the wrap — if there is, lengthen the crossfade.78- Headline readable at every point in the animation, not just one screenshot.79- Subject still reads as itself at the chosen `pixelSize` — coarser is more80 striking but there's a point where it dissolves.81- Looks right on a narrow viewport where the canvas is much smaller relative82 to `pixelSize` — small canvases usually need a finer grid.8384## References8586- `references/image-prompts.md` — Higgsfield `nano_banana_pro` prompt87 patterns and three worked examples (molten forge sparks, cathedral rose88 window, falling ash over a lost city).89- `references/video-prompts.md` — Higgsfield `seedance_2_0` image-to-video90 settings and prompt patterns, worked examples matching the image prompts.91- `references/frame-extraction.md` — ffmpeg commands for frame rate, crop,92 and background-noise flattening.93- `references/dither-engine.md` — full algorithm spec: buffer downscale,94 luma conversion, auto-levels, invert, floor clamp, 8x8 Bayer quantization,95 batched cell drawing, parameter table, color approaches (sampled / duotone96 / blended), looping, pointer interaction, page composition.97- `references/dither-engine.ts` — reference TypeScript canvas implementation98 of the engine above, meant to be adapted (not copy-pasted verbatim) into99 the target app's component structure.