@cssints/placeholder

Image placeholders for cssints: placeholder(path) reads an image while the build runs and gives an <image> to paint until the real one loads, either a gradient of the image's colours laid out as the image is (unpic-placeholder's radial gradients) or the image's ThumbHash as a tiny PNG data URL. It is one value member of cssints/plugin scope(), so it goes into backgroundImage (or maskImage). No runtime.

import { backgroundImage, cn, backgroundSize } from "cssints" with { type: "cssints" };
import { placeholder } from "@cssints/placeholder" with { type: "cssints" };

// placeholder(path, { mode? }): the path is relative to the working directory
export const hero = backgroundImage(placeholder("src/hero.jpg"));
export const card = cn(
  backgroundImage(placeholder("src/card.png", { mode: "thumbhash" })),
  backgroundSize("cover"),
);

For a PNG of four quadrants (red, blue / green, white):

/* mode "gradient" (the default): a 4 × 3 grid, a radial gradient per cell, brightest on top, over the average colour */
._11mb38d {
  background-image:
    radial-gradient(at 67% 100%, #ffffff, transparent 50%),
    radial-gradient(at 100% 100%, #ffffff, transparent 50%),
    radial-gradient(at 67% 50%, #bcbcff, transparent 50%),
    /* … one per cell, 12 in all … */ radial-gradient(at 100% 0, #0000ff, transparent 50%),
    linear-gradient(#bc96bc, #bc96bc);
}
/* mode "thumbhash": the ThumbHash rendered, 16 px on the long side, about 0.5 kB */
._179cifn {
  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAM…");
}

Formats

JPEG (baseline and progressive, through jpeg-js) and PNG (every colour type and bit depth, through pngjs), both plain JavaScript: nothing to compile, no native binary (sharp is not used). The format is read from the file's first bytes, not its name. WebP, AVIF, GIF and SVG are build errors that name the format (cssints: placeholder: src/hero.webp: a WebP image: JPEG and PNG are read): give a JPEG or PNG copy of the image (it can be small; only its colours are read).

Rules

Limits

cd packages/placeholder && bun run test        # colour extraction on synthetic pixels, fixtures through the engine (output, errors)
cd packages/placeholder && bun run typecheck   # and the type test, test/types/placeholder.ts

Credits

The gradient layout follows unpic-placeholder (MIT, Matt Kane). The thumbhash mode uses thumbhash (MIT, Evan Wallace), jpeg-js (BSD-3-Clause) and pngjs (MIT), dependencies. No code is copied.