Kiste
DE

KistePix

A full pixel editor — layers, animation, custom palettes, GIF and sprite-sheet export. About 5700 lines of Kiste in a single file, no external library.

KistePix painting

Build it yourself, for free

KistePix is open source. Download the source, open it in the Kiste IDE and build your own KistePix — simple enough for anyone. It’s the very same code the finished version is built from.

Prefer a ready-made one-click program, with no building at all? You’ll find it at kistepix.com.

How it’s built

KistePix is a pure Kiste program — a single file of about 5700 lines, with no game or graphics engine. It uses the built-in modules gui (windows, canvas, controls), bild (pixel buffers, PNG/GIF), datei, json and pfad (saving/loading), bytes (hex colours) and mathe. The code is German, because Kiste is.

What’s inside

  • Layers with opacity and ordering, composited live
  • Animation with frames, a timeline, onion skinning and per-frame duration
  • Custom palettes (up to 256 colours) to load and save
  • Tools: pen, eraser, fill, line, rectangle, circle, selection, lasso, eyedropper, mirror & symmetry
  • Undo/redo, zoom & pan, transparency checkerboard
  • Export as PNG, animated GIF and sprite sheet (with Aseprite JSON that Godot, Unity or Phaser read directly)
  • Bilingual interface (German/English) and its own help window

Drawing all layers at once

Instead of setting pixel after pixel, KistePix mixes every visible layer into one flat memory buffer and writes it to the canvas in a single call. That keeps drawing smooth even on large images.

// Every layer is mixed into ONE flat RGBA buffer and then written
// to the canvas in a single call — the cost no longer depends on
// the canvas size.
bild.setze_puffer(komposit_bild, komposit_puf)

Undo without eating memory

A full image snapshot per brush stroke would be far too expensive. Instead KistePix remembers only the changed pixels — index and old value — in a ring buffer. A “generation mark” stops the same pixel being recorded twice in one step.

funktion undo_erfasse(idx, alt) {
    wenn d_offen == falsch { gib }
    nimm mk = d_mark
    wenn mk[idx] == d_gen { gib }     // already recorded in this step
    mk[idx] = d_gen
    // remember only the pixel index and its OLD value:
    ai[w] = idx
    av[w] = alt
    d_len = d_len + 1
}

Exporting the animation

Each frame has its own duration. On export that becomes an animated GIF with matching delays — or a sprite sheet plus JSON for game engines.

funktion exportiere_gif(pfad, faktor) {
    nimm bilder = liste.gefüllt(länge(frames), 0)
    nimm dauern = liste.gefüllt(länge(frames), 0)   // one delay per frame
    für f = 0 bis länge(frames) - 1 {
        bilder[f] = frame_als_bild(f, faktor, 0)
        dauern[f] = frames[f].dauer div 10          // ms -> 1/100 s (GIF unit)
    }
    bild.schreibe_gif_animiert_dauern(pfad, bilder, dauern)
}

Sprite sheets for game engines

For games, KistePix exports every frame as one sprite sheet — a wide image with all frames side by side — and automatically writes a companion .json in the Aseprite schema. Godot, Unity or Phaser read it directly, including each frame’s duration. An animation in KistePix becomes a ready-made game asset with no detours.

funktion exportiere_blatt(pfad, faktor, transparent) {
    nimm n = länge(frames)
    nimm img = bild.neu(n * LEIN_B * faktor, LEIN_H * faktor)
    für f = 0 bis n - 1 {
        // draw each frame side by side into the sheet …
    }
    bild.schreibe_png(img, pfad)
    // companion JSON in the Aseprite schema — Godot/Unity/Phaser read it directly:
    datei.schreibe(mit_json(pfad), blatt_json_text(pfad, faktor))
}

KistePix shows how far a single Kiste program can go: a complete creative tool that holds its own against the usual pixel editors — open to read, change and build yourself.