The pixel art side bar showed every tool option all the time, the
palette used only part of the column width and "Remove" could only
drop the last colour. Now each tool shows what it needs, the palette
fills the column and any colour can be removed.
- Options per tool live in toolOptions.ts. Brush shows for pencil,
eraser, line and unfilled shapes. Filled shapes shows for rectangle
and ellipse. Contiguous shows for fill. Picker has none.
- All options share one row with a fixed height, so nothing below
jumps when the tool changes.
- The palette picks its column count from the width and stretches the
swatches until the row ends flush. At 1280 px that is 11 per row
instead of 8.
- The colour field takes the space the two buttons leave, so "Remove"
is no longer cut off.
- "Remove" deletes the selected colour. Pixels of that colour turn
transparent, later indices move down by one in every image that uses
the palette, and palette plus images change in one undo step.
Transparent itself cannot be removed.
Decisions:
- Pixels of a removed colour become transparent, like erasing
(chosen by the user before the build).
Findings:
- The Filled checkbox slid away under the pointer. The brush button
sat to its left and vanished when Filled turned on, so the second
click missed. The brush button now sits to the right, and a check
clicks the same spot twice.
- One start-up FAIL "debug hook present" came back never in three
later runs. It is the known start flake.
Tests:
- ./check.sh: 141 files, 2080 tests, exit 0 (before 140 / 2070)
- 10 new unit tests in tests/editor/pixel-palette.test.ts
- GM_STEPS=48 (fresh seed): ALL PASSED, 40 checks, 4 of them new
- Counter-check: indices not shifting and brush always visible make
4 unit tests and exactly the 2 matching e2e checks fail
- Check total 1282 (1278 + 4) in README and wiki, computed
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Textures are uploaded files named by their content, so they cannot
be edited in place. Pixel art is therefore its own asset type, like
vector art. Its pixels live in the project and the tab rasters them
into a texture that sprites, tiles and animations can use.
- New asset types Pixel art and Palette. The first pixel art of a
project gets a palette with the 16 PICO-8 colours in the same undo
step. Every pixel is a palette index, 0 is transparent.
- Each layer on each frame is its own file data/pixels/<sha256>.px.
The project only holds the names, so undo swaps names. The browser
computes the hash and uploads new cels before the project is saved.
- New route POST ?r=pixels in api/lib/PixelStore.php. It answers 201
and 422 for broken data. data/pixels/ is git-ignored.
- Tools: pencil, eraser, fill (contiguous or all pixels of a colour),
eyedropper, line, rectangle and ellipse (outline or filled), brush
size 1 to 8.
- Layers can be added, deleted, renamed, reordered, hidden, faded and
merged down. Frames can be added, duplicated, deleted and reordered,
with onion skin and a small playing preview.
- Zoom 1x to 32x in whole steps, grid from 8x, a 3x3 tile preview and
Resize... with a 3x3 anchor.
- All frames sit side by side in one image. Each frame is a region
like a cut texture frame, so texture rows offer "Asset / Frame 2"
and the context menu has Create animation from frames.
Decisions:
- Merging down drops the opacity of the upper layer. Indexed colours
know no blends.
- Only the last palette colour can be removed. Otherwise the indices
of every image using the palette would shift.
- Undo stores the whole layer per stroke instead of pixel diffs.
- Alt+click picks a colour. It is a mouse gesture, not a shortcut.
Follow-up issues: #197 import from texture, #198 selection and
flipping, #199 PNG export, #200 more tools.
Tests:
- ./check.sh: 136 files, 2049 tests (before 135 / 2011). 34 new in
tests/core/pixel-art.test.ts, 4 from the icon tables.
- e2e module 48 fresh: ALL PASSED, 29 checks, console empty.
- Counter-probes bite: five on the unit tests, upload order (2 tests
fail) and cels not uploaded in the browser (1 check fails).
- Check total 1259 in README is computed (1232 measured in CI + 27).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>