Skip to content
jvgomgPublic

About

Dithering effects for every layer of the web: core algorithms, a React component, and Next.js server rendering.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

A colour sweep fading to black, Bayer-dithered with ditherkit

ditherkit

Dithering effects for every layer of the web. A small toolkit of packages — pick the one that fits where you want the work to happen: browser, server, or algorithm layer.

ditherkit is a set of three npm packages for adding 1-bit and low-bit dithering effects to web projects. It supports Floyd-Steinberg, Atkinson, and threshold dithering with arbitrary color palettes, brightness / contrast pre-processing, and image resizing. Use it for retro visual styles, high-contrast photographic effects, accessibility-friendly image variants, or just because pixelated images look cool.

The packages are split so you only pay for what you use:

  • Interactive in the browser? Use @ditherkit/react.
  • Server-rendered and cached in a Next.js app? Use @ditherkit/next.
  • Non-React, build script, edge runtime, or custom pipeline? Use @ditherkit/core directly.

Packages

Package What it is When to reach for it
@ditherkit/core Pure algorithm functions. No DOM, no framework, zero runtime dependencies. Build scripts, Svelte/Vue/Solid apps, Cloudflare Workers, custom pipelines.
@ditherkit/react <DitheredImage /> React component backed by a shared Web Worker. Interactive use: live sliders, user uploads, real-time previews in any React app.
@ditherkit/next <DitheredImageSSR /> server component, withDitherkit config helper, and pre-built route handler subpaths for App Router and Pages Router. Server-renders via Sharp and caches with ISR. Production Next.js apps where images should be cached, SEO-visible, and CDN-friendly.

Quick start

Pre-release: the packages aren't published to npm yet, so the install commands below won't work until they are. To try ditherkit now, clone this repo and follow Development.

The most common path is a Next.js App Router app using @ditherkit/next:

pnpm add @ditherkit/next sharp
// next.config.ts — the ONE place ditherkit is configured
import type { NextConfig } from 'next'
import { withDitherkit } from '@ditherkit/next/config'

const config: NextConfig = {
  // your existing config
}

export default withDitherkit(config, {
  routeBase: '/api/dithered',
})
// app/page.tsx
import { DitheredImageSSR } from '@ditherkit/next'
import portrait from '@/assets/portrait.jpg'

export default function Page() {
  return (
    <DitheredImageSSR
      src={portrait}
      alt="A portrait, dithered on the server"
      algorithm="Atkinson"
      priority
    />
  )
}
// app/api/dithered/[cacheKey]/[...params]/route.ts
export { GET } from '@ditherkit/next/route/app'

That's the whole setup. withDitherkit writes a build-time env bridge that the component and the route handler both read at runtime — no factory call, no shared lib module. The component generates a deterministic URL, the route handler runs the Sharp + dithering pipeline, and next/image handles the rest.

For Pages Router, only the route file changes:

// pages/api/dithered/[cacheKey]/[...params].ts
export { default } from '@ditherkit/next/route/pages'

The withDitherkit call and <DitheredImageSSR /> import are identical between routers. See apps/example-next-pages for the mirror example.

For interactive client-side use, or for non-Next.js stacks, see the Getting started guide and the per-stack pages under apps/docs/content/stacks/.

Example apps

  • apps/example-next — Next.js App Router flagship. Demonstrates both kinds of src (imported StaticImageData and external URL) plus interactive client-side dithering with @ditherkit/react. Readable end-to-end in 60 seconds.
  • apps/example-next-pages — Next.js Pages Router mirror, feature-for-feature identical to the App Router example.

Both example apps use the singleton pattern: zero lib/ files, configuration declared once in next.config.ts via withDitherkit, and the route handler is a single re-export.

More examples for Vite, Astro, Remix, and Node CLI are planned — see the backlog § D for the full list.

Documentation

The documentation site lives at apps/docs and is built with Fumadocs. Content is MDX under apps/docs/content/:

  • /docs/getting-started — decision tree and first-working-example for each package
  • /docs/core — algorithm reference, color utilities, image adjustments
  • /docs/react — <DitheredImage /> props, the shared-singleton Web Worker architecture, recipes
  • /docs/next — <DitheredImageSSR />, route setup, ISR caching, StaticImageData cache keys, external URLs
  • /architecture — why three packages, dependency graph, under-the-hood internals
  • /stacks — per-stack status and integration guides (Next.js, React SPA, Remix, Astro, Svelte/Vue/Solid, Node CLI)

To browse the docs locally:

pnpm install
pnpm turbo dev --filter=docs

Then open http://localhost:3000.

Project structure

ditherkit/
├── packages/
│   ├── core/              # @ditherkit/core — pure algorithms
│   ├── react/             # @ditherkit/react — client component + Web Worker
│   └── next/              # @ditherkit/next — server component + ISR + Sharp
├── apps/
│   ├── docs/                # Fumadocs documentation site
│   ├── example-next/        # Next.js App Router flagship example
│   ├── example-next-pages/  # Next.js Pages Router mirror example
│   └── e2e/                 # Playwright e2e test suite
├── plans/
│   ├── docs-site-plan.md      # Design decisions for the docs site
│   └── docs-site-backlog.md   # State of work, organised by phase
├── AGENTS.md              # Instructions for AI coding agents
└── README.md              # This file

Development

This is a pnpm + Turborepo monorepo. Requires Node 22+ and pnpm 10+.

# Install dependencies for every workspace
pnpm install

# Build every package
pnpm turbo build

# Typecheck every workspace
pnpm turbo typecheck

# Run a dev server for the docs site (with live package rebuilds)
pnpm turbo dev --filter=docs

# Or the flagship example app
pnpm turbo dev --filter=example-next

# Run the Playwright e2e suite
pnpm turbo test

Each package is built with tsdown, and the apps use Next.js with Turbopack. Turbo's dependsOn: ["^build"] ensures package source is built before any downstream app consumes it.

Status

Pre-1.0. The core algorithms and the three packages are stable and production-usable, but the documentation site and example apps are still being built out. See plans/docs-site-backlog.md for the current state of work.

What works today:

  • All three dithering algorithms (Floyd-Steinberg, Atkinson, Threshold)
  • Arbitrary color palettes of any length
  • Brightness and contrast pre-processing
  • <DitheredImage /> in any React app with shared-worker optimisation and layout-shift-free sizing
  • <DitheredImageSSR /> in Next.js with ISR caching, WebP output, and automatic cache key generation from webpack content hashes
  • Full e2e test coverage on Vite + Next.js App Router + Next.js Pages Router fixtures

What's in flight:

  • Complete documentation site (content is written; deployment host hasn't been chosen)
  • More example apps: Vite, Astro, Remix, Node CLI
  • Interactive playground page with palette editor and URL state
  • Consolidation of the e2e fixtures into the example apps

License

MIT © James Greenaway.

About

Dithering effects for every layer of the web: core algorithms, a React component, and Next.js server rendering.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages