Morphiq

Components / Animations / Bitmap Image

Bitmap Image

An image thresholded into newsprint. The source is box-filtered down to the cell grid first, so every cell has a real antialiased grey before it is dithered — which is the difference between newsprint and broken JPEG.

Usage

import BitmapImage from '@/components/bitmap-image'

<BitmapImage
  src={photo}
  cell={4}
  dither="floyd"
  fit="cover"
/>

Installation

npx shadcn@latest add https://morphiq.prathampatel.design/r/bitmap-image.json

Model

(v) => String(v.dither).startsWith("bayer") ? "out = level(tone + (M(x, y)/n² − ½)/levels)" : v.dither === "none" ? "out = round(tone · (levels − 1)) / (levels − 1)" : "e = tone − out;  e spreads to unvisited neighbours by the kernel’s weights"

M the Bayer matrix, n its size · error diffusion carries each cell’s rounding error forward, so tone is conserved over area

Props

PropertyTypeDefaultDescription
cellnumber4Pixels per cell. Smaller is finer and costs more per frame.
levelsnumber2Tone steps. 2 is one-bit; higher posterises.
ditherDitherKernel'floyd'—
ditherAmountnumber10 passes the tone through untouched, 1 applies the kernel in full.
serpentinebooleantrueAlternate scan direction. Error-diffusion kernels only.
contrastnumber1.1—
brightnessnumber0—
invertbooleanfalse—
warpnumber0Flow-field shear, in cells.
cursorRadiusnumber160Reach of the pointer's influence, in px.
cursorStrengthnumber0Outward push at the centre of that reach, in px.
cursorLiftnumber0Luminance added at the centre of that reach.
colorstring'#e8e4dc'—
backgroundstring | null'#0a0b0e'null renders transparent.
pausedbooleanfalseStops the frame loop without unmounting.
respectReducedMotionbooleantrueHonour prefers-reduced-motion, and keep honouring it if it changes.
fullscreenbooleanfalsePosition the field to the viewport rather than its container.
srcstring——
altstring''As on <img>: describe the picture, or leave empty to mark it decorative.
fit'cover' | 'contain' | 'fill''cover'—
focusXnumber0.5Crop anchor, 0..1.
focusYnumber0.5—
onStatus(status: 'ready' | 'empty' | 'tainted') => void——