canvas-fx
@johnhenry/canvas-fx puts pixel effects on images, video, canvases,
pixel art you write as text, your own drawing elements (a game, a
visualization), and, experimentally, live HTML. Put the source in a
<pixel-canvas> and list the effects like CSS filter:
<pixel-canvas width="160" effects="adjust(contrast 1.3) palette(gameboy, ordered)"> <img src="photo.jpg" alt="Our cat"></pixel-canvas>Effects run left to right: the contrast is raised, then the photo is reduced
to the Game Boy’s four greens. Before the script loads, or if the image
can’t be read, the plain <img> shows, so nothing is lost.
Install
Section titled “Install”No install is needed: load it from a CDN. One script registers every element:
<script type="module" src="https://cdn.jsdelivr.net/npm/@johnhenry/canvas-fx/src/global.mjs"></script>pixel-canvas/global.mjs alone is enough for the effects attribute.
With npm:
npm install @johnhenry/canvas-fx<!-- In <head>, before any <script type="module"> or modulepreload. --><script type="importmap"> { "imports": { "@johnhenry/canvas-fx/global.mjs": "https://cdn.jsdelivr.net/npm/@johnhenry/[email protected]/src/global.mjs" } }</script><script type="module"> import * as canvasFxGlobalMjs from "@johnhenry/canvas-fx/global.mjs";</script>import "@johnhenry/canvas-fx/global.mjs"; // registers every elementcanvas-fx has no dependencies, so no import map is needed. It ships
TypeScript declarations and a custom-elements.json manifest.
Effects
Section titled “Effects”| Effect | What it does |
|---|---|
mosaic(size) |
Pixelate into blocks |
palette(colors, dither, count) |
Limit to a palette (Game Boy, PICO-8, 1-bit, any colors, or auto from the image), with dithering |
grid(size, color, line) |
Grid lines between cells; a transparent color cuts the image into tiles |
adjust(brightness, contrast, saturation, hue) |
Tone and color, like the CSS filter functions |
halftone(size, angle, ink, paper) |
Printed dots |
outline(threshold, ink, paper) |
Line art from edges |
crt(scanlines, mask, glow) |
An old screen |
chroma-key(color, tolerance, softness) |
Make a color transparent (green screen) |
glitch(amount, rate) |
Animated digital breakup |
wave(amplitude, wavelength, speed) |
Rows rippling along a moving wave |
lens(radius, zoom) |
A magnifying glass that follows the pointer |
spotlight(radius, softness, dim) |
Light around the pointer, the rest dimmed |
glyphs(cell, chars, font, mode, color, background) |
The image as text characters (ASCII art), chosen by brightness or by shape from the real font |
Every effect is also an element (<pixel-mosaic size="4">, …) to wrap
around the source; wrapped effects run from the inside out, then the
attribute’s list.
- Your own effects:
definePixelEffect(name, fn)registers both forms;<pixel-shader>anddefinePixelShader()run GLSL on the GPU. - Animation:
fpson the canvas drives effects that change over time, withplay()/pause(); videos and sprites redraw every frame. - Your own sources: any element with a
canvasproperty that firesframechange(a game, a visualization) can be the source. - Pixel art as text:
<pixel-sprite>, one character per pixel, with animation frames. - Theme from a picture:
swatches="3" swatches-target="html"publishes the result’s most common colors as--pixel-swatch-1…3. - On the GPU:
gpuruns the whole chain on WebGL2 when every effect in it can (most built-ins, every shader): uploaded once, a shader per effect, nothing read back.renderersays whether it ran there. - Following the pointer: effects get the pointer, in the image’s
pixels;
lens()andspotlight()use it, and the canvas redraws as it moves. - Transitions:
transition="400ms"animates changes toeffects, interpolating numbers or cross-fading to a different list. - Chaining: a
<pixel-canvas>can be another’s source. - Saving:
toBlob(),toGIF()(an animated GIF, exact colors for pixel art),record()(video), andcaptureStream(). - As text:
glyphs()draws the image in characters, andtoText()gives the result back as a string, one line per row. - Live HTML (experimental):
<pixel-canvas html>draws its own HTML content through the effects and keeps it interactive. See Live HTML.
- A cross-origin image without CORS can’t be read. The canvas taints,
the
<pixel-canvas>fireserrorand shows the original image. Serve images with CORS (crossoriginon the<img>), or from your own origin. - Effects run on the CPU, once per redraw. For video, keep the working
size small (
width="160") and scale up with CSS; the result is drawn withimage-rendering: pixelated, so it stays crisp. - Randomness must be repeatable. Write effects with
random(seed), notMath.random(), or a paused canvas flickers on every redraw. - The GPU path is all or nothing per chain. One CPU-only step
(
glitch,palette(auto), Floyd–Steinberg, a JavaScript effect) runs the whole chain on the CPU; checkrenderer. - Recording captures what’s drawn. Effects that change over time need
fps(or a playing video) to animate whiletoGIF()orrecord()captures. glyphs()measures the font. Its brightness ramp follows each character’s real ink, not the order you list them in; a font that hasn’t loaded yet draws in a fallback, then redraws. Quote character sets with spaces or commas:glyphs(8, ' .,:').- Tags are fixed per page.
definePixelEffect("x", …)registers<pixel-x>; defining the same name twice keeps the first.
Family
Section titled “Family”- domkit, where canvas-fx started. Its
<frame-timer>is the clock animated sources usually run on, and its<hot-key>,<gamepad-input>, and<swipe-input>drive what’s drawn. canvas-fx doesn’t import domkit; they meet in the page. - data-plot, plots written as HTML: any element can be
one of its marks, so a
<pixel-sprite>can be a point on a plot. - forsnaken, a snake game made of HTML elements, is a consumer: its
game element is a custom source, shown through
effects="grid(…)".
Source: github.com/johnhenry/canvas-fx.