TachiSnap
TachiSnap — Pixel Snapper for animation pixel artists. Rust + WebAssembly client-side tool for cleaning up AI-generated…
Browser-based image and video dithering, audio visualisation, glitch art, and retro CRT/VHS filters. Runs in the browse…
Browser-based image and video creation for dithering, palette reduction, glitch art, print simulation, temporal effects, and filter-chain experimentation.
Audio-reactive too: drive visuals with live microphone or tab audio through per-filter, chain-wide, and screensaver patch panels.
Also useful for lightweight VJing and live visuals too: swap sources, keep output framing stable, and drive filters from live audio.
![]() |
![]() |
![]() |
![]() |
packages/ditherer-filters/src/gl/ pipeline (single context, pooled textures, JS-y sampling helpers) so new ports only need a shader + orchestration. Current consumers: rgbStripe (GL + WASM), Gaussian Blur (GL + WASM), Facet (WASM, 140× over JS via spatial-grid Voronoi), Bit Crush (WASM LUT), plus older WASM filters (Floyd-Steinberg, Ordered, Quantize, Levels, etc.). Each backend can be toggled from the settings pane; filters fall through cleanly on unsupported devices or when the palette isn't shader-portableDitherer can drive filter parameters from live audio analysis. You can patch metrics like level, bass, beat, spectral flux, or tempo phase into numeric filter controls either per filter, across the whole chain, or in screensaver mode.
Auto Viz and RerollRepresentative animated previews from the generated gallery:
npm run galleryThe React-independent browser engine is prepared for distribution through
GitHub Packages as @gyng/ditherer-filters; source and authenticated install
instructions live in
packages/ditherer-filters.
It exports the catalog, option metadata, palettes, Canvas2D/WebGL/WASM runtime,
stateful temporal sessions, capability checks, and a worker entry point.
import { createFilterSession } from "@gyng/ditherer-filters";
const session = createFilterSession([
{ id: "mono", filter: "Grayscale" },
{ id: "dither", filter: "Floyd-Steinberg" },
]);
const { canvas } = await session.process(inputCanvas);
outputContext.drawImage(canvas, 0, 0);
session.dispose();
Build and validate the distributable package with npm run build:lib and
npm run test:lib. The initial package target is modern browser bundlers and
accepts HTMLCanvasElement or OffscreenCanvas input.
npm install npm run dev npm run build npm run preview npm run lint npm run typecheck npm run test
Extra repo utilities:
npm run bench to run performance benchesnpm run bench:compare to compare benchmark runsnpm run report:presets to find duplicate or highly similar presetsnpm run gallery to regenerate docs/gallery/GALLERY.md and preview assetsnpm run build writes a static build to build/. The app uses base: "./" in Vite, so the output can be hosted from a subdirectory or copied to a static host without extra routing setup.
packages/ditherer-filters/src/filters/index.ts is the registry for filter metadata and worker-visible entriespackages/ditherer-filters/src/runtime.ts owns reusable chain execution and temporal statesrc/context/FilterContext.tsx connects the library runtime to React, sharing, audio modulation, previews, and worker orchestrationmore like this
TachiSnap — Pixel Snapper for animation pixel artists. Rust + WebAssembly client-side tool for cleaning up AI-generated…
search projects, people, and tags