dfh
v0.4.0
Published
Dot Frame Helper — a small, intuitive npm package for creating pixel art (dot art), usable from both the API and the CLI.
Readme
DFH
Dot Frame Helper — a small, intuitive npm package for creating pixel art (dot art), usable from both the API and the CLI.
- Dot — pixel art itself
- Frame — a single still image / one cel of an animation (handles both)
- Helper — lightness. Assists your craft through both an API and a CLI
Features
- Intuitive API — chainable methods that mirror the act of drawing
- API & CLI parity — the same "verbs" (
dot,line,rect,fill, …) work from code and the shell - Multiple color formats —
'#rgb','#rrggbb','#rrggbbaa',0xrrggbb,[r, g, b],[r, g, b, a],'transparent', or palette index - Transparent backgrounds — first-class alpha; export PNG/SVG with transparency
- Multiple exporters — PNG, SVG, GIF, ASCII, JSON
- Deterministic — identical inputs produce identical outputs (great for tests/CI)
- Small core — core has zero runtime deps; only PNG/GIF use tiny libraries
Install
npm install dfh
# or
pnpm add dfhThe CLI is available after install via dfh, or via npx dfh.
Quick start (API)
import { Canvas, Palette } from 'dfh';
const pal = Palette.from(['#000', '#fff', '#e74c3c', '#3498db']);
const c = new Canvas(16, 16);
c.use(pal)
.bg('transparent') // transparent background
.dot(0, 0, '#000') // hex string
.line(0, 0, 15, 15, 0xe74c3c) // hex number
.rect(2, 2, 6, 6, [52, 152, 219])// RGB array
.fill(8, 8, pal.index(0)) // explicit palette index
.erase(0, 0);
await c.toPNG('out.png', { scale: 8 });
c.toSVG('out.svg', { scale: 8 });
console.log(c.toASCII());Animation
import { Animation } from 'dfh';
const anim = new Animation(16, 16, { fps: 8 });
anim.add(f => f.dot(0, 0, '#000'))
.add(f => f.dot(1, 0, '#000'))
.add(f => f.dot(2, 0, '#000'));
await anim.toGIF('walk.gif');Importing an image
Dot-ify an existing PNG: downscale by block-averaging and optionally reduce colors (bit-depth presets or median-cut to N colors, with optional Floyd–Steinberg dithering).
import { importImage, Canvas } from 'dfh';
const { canvas } = await importImage('photo.png', {
scale: 8, // source pixels per output dot
colors: 16, // 'full' | 'rgb565' | 'rgb332' | 'rgb222' | N
dither: true, // Floyd–Steinberg
background: '#fff', // flatten transparency
});
await canvas.toPNG('pixel.png', { scale: 4 });
// or via the static helper
const c = await Canvas.fromImage('photo.png', { scale: 8, colors: 'rgb565' });Quick start (CLI)
# Create a new canvas
dfh new 16x16 -o sprite.json --bg transparent
# Draw (chain operations)
dfh draw sprite.json \
--bg transparent \
--dot 0,0 '#000' \
--line 0,0 15,15 0xe74c3c \
--rect 2,2 6,6 '[52,152,219]' \
--fill 8,8 '#000' \
--erase 0,0
# Export
dfh export sprite.json out.png --scale 8
dfh export sprite.json out.svg --scale 8
dfh ascii sprite.json
# Import a PNG (downscale + quantize)
dfh import photo.png -o sprite.json --scale 8 --colors 16 --dither
dfh import photo.png -o sprite.json --scale 4 --colors rgb565
dfh import photo.png -o sprite.json --scale 2 --palette palette.json
# Import directly to PNG/SVG (output format chosen by extension)
dfh import photo.png -o dot.png --scale 8 --colors 16 --dither --export-scale 8
dfh import photo.png -o dot.svg --scale 8 --colors 32Colors
dfh accepts many color formats. All of the following are equivalent to opaque red:
| Format | Example |
|--------|---------|
| Short hex | '#f00' |
| Hex | '#ff0000' |
| Hex with alpha | '#ff0000ff' |
| Hex number | 0xff0000 |
| RGB array | [255, 0, 0] |
| RGBA array | [255, 0, 0, 255] |
For transparency, use 'transparent', 'none', or null.
When a palette is attached with c.use(pal), small integers (0–pal.length - 1) are treated as palette indices. Use pal.index(n) to be explicit, or prefix with @ on the CLI (@2).
API reference
Canvas
| Method | Description |
|--------|-------------|
| new Canvas(w, h, opts?) | Create a transparent canvas |
| .use(palette) | Attach a palette |
| .bg(color) | Fill background (supports transparent) |
| .dot(x, y, color) | Set a single pixel |
| .line(x0, y0, x1, y1, color) | Draw a line |
| .rect(x, y, w, h, color, opts?) | Draw a rectangle ({ fill: true }) |
| .circle(cx, cy, r, color, opts?) | Draw a circle |
| .fill(x, y, color) | Flood fill (bucket) |
| .erase(x, y) | Erase a pixel (make transparent) |
| .clear() | Clear the whole canvas |
| .get(x, y) | Get [r, g, b, a] |
| .paste(src, x, y) | Composite another canvas |
| .crop(x, y, w, h) | Return a new cropped canvas |
| .toPNG(path?, opts?) | Export PNG (Buffer if no path) |
| .toSVG(path?, opts?) | Export SVG (string if no path) |
| .toASCII() | Return an ASCII representation |
| .toJSON() | Deterministic JSON serialization |
| Canvas.fromJSON(json) | Reconstruct a canvas |
ExportOptions
| Option | Description |
|--------|-------------|
| scale | Output scale (default 1) |
| background | Fill transparent pixels with this color |
| title | (toSVG only) Accessible name, emitted as the SVG <title> element |
Palette
const pal = Palette.from(['#000', '#fff', '#e74c3c']);
pal[2]; // '#e74c3c'
pal.index(2); // tagged index for Canvas
pal.add('#34495e');Animation
| Method | Description |
|--------|-------------|
| new Animation(w, h, { fps?, bg? }) | Create an animation |
| .add(frame?) | Append a frame (Canvas or (f) => void) |
| .frame(i) | Get frame i |
| .length | Frame count |
| .toGIF(path?, opts?) | Export GIF |
| .toJSON() / .fromJSON() | Serialize / reconstruct |
CLI reference
| Command | Description |
|---------|-------------|
| dfh new <WxH> -o <file> | Create a new canvas |
| dfh draw <file> ... | Apply drawing operations in place |
| dfh export <file> <out> | Export to PNG/SVG (by extension) |
| dfh ascii <file> | Print the canvas to the terminal |
| dfh anim new <WxH> | Create an animation |
| dfh anim add <file> ... | Append a frame with operations |
| dfh anim export <file> <out> | Export to GIF |
Global options
--palette <file>— shared palette JSON ({ "colors": [...] })--scale <n>— output scale--bg <color>— fill transparent pixels--quiet— suppress progress--dry-run— do not write files
Color syntax on the CLI
- Hex:
'#000','#ff0088'(quote recommended) - Hex number:
0xff0088 - RGB array:
'[52,152,219]'(quote required) - Transparent:
transparent/none - Palette index:
@2
Agent skill
DFH ships a ready-to-use agent skill (skills/dfh/SKILL.md) that teaches coding agents how to generate pixel art with DFH — color format tables, CLI recipes, and export examples. It is included both in this repository and in the published npm package.
Install it into your agent's skills directory:
# from the installed npm package
cp -r node_modules/dfh/skills/dfh ~/.claude/skills/ # Claude Code
cp -r node_modules/dfh/skills/dfh ~/.copilot/skills/ # GitHub Copilot CLI
# or from a clone of this repository
cp -r skills/dfh <your-agent-skills-dir>/Once installed, ask your agent something like "create a pixel-art sprite with dfh" and it will pick up the bundled recipes automatically.
License
MIT © otoneko.
