For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to any URL or sending an Accept: text/markdown header. The dithercn agent skill, for building any dither on the engine, is at /.well-known/agent-skills/dithercn/SKILL.md.
dithercn

Scroll reveal image

An image that sharpens from coarse dithered blocks to the full photo as you scroll it into view.

Controls
Preset
Ink
Ends on
First blocks24×

Installation

pnpm dlx shadcn@latest add https://dithercn.dev/r/scroll-reveal-image.json

Usage

import { ScrollRevealImage } from "@/components/dithercn/scroll-reveal-image";
 
export function Chapter() {
  return (
    <ScrollRevealImage
      src="/photos/launch.jpg"
      alt="The launch pad at dawn"
      className="aspect-video w-full rounded-xl"
    />
  );
}

Progress follows the scroll position, not a timer. When the top of the image enters at the bottom of the viewport it is a few large blocks. It sharpens in nine steps to full dither detail, then the photo dissolves in cell by cell. It is finished when its top edge is 30% down the viewport. Scroll back and it runs in reverse.

start and finish move those two points, as a share of the viewport height from the top. Inside a scrolling panel, pass the panel's ref as scrollRoot, as the demo above does.

Examples

In a long read

The image resolves as the reader reaches it. finish={0.4} completes it a little lower on the screen.

Ending on dither

end="dither" stops at full dither detail and never shows the photo. A later start on the second image staggers the pair.

Props

Takes every look prop of Dither image (preset, color, palette, method, cell, contrast, brightness, normalize, sharpen, invert, fit), plus:

PropTypeDefault
src*

Image URL. Cross-origin images need CORS headers.

Type: stringDefault –
alt*

Describes the image. Pass "" when it is decorative.

Type: stringDefault –
end

Finish on the original photo, or on the finest dither.

Type: "photo" | "dither"Default "photo"
coarsest

How many cells wide the first blocks are.

Type: numberDefault 24
start

Where the image's top edge is when the reveal starts, 0 (top) to 1 (bottom of the viewport).

Type: numberDefault 1
finish

Where the top edge is when the reveal finishes.

Type: numberDefault 0.3
scrollRoot

The scrolling element, when it is not the page.

Type: RefObject<HTMLElement | null>Default –
progress

Set the progress yourself, 0 to 1, instead of following the scroll.

Type: numberDefault –
onProgressChange

Called when the progress changes.

Type: (progress: number) => voidDefault –
ratio

Width over height.

Type: numberDefault The image's ratio

Notes

  • Under reduced motion the image is shown finished: the photo, or the fine dither with end="dither".
  • The root has role="img" and your alt text as its label, so screen readers hear the image once, whatever stage it is at. data-stage is coarse, fine or photo.
  • Each coarseness is dithered once and cached, so scrolling back and forth costs nothing after the first pass. Scroll handling only runs while the image is near the viewport, at most once per frame.