Textures: nine-slice scale per texture (#96); Repeat is the default fill

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
adminandClaude Opus 5 committed 2026-09-16 18:13:12 +02:00
1 parent 8b5332a164
commit c698297011
2 files changed
+14 -4

No files matched your search

+2 -2
@@ -12,7 +12,7 @@ npm run check # typecheck + lint + format:check + tests, the gate CI runs
# code is lost (tail's is reported), so a red run reads as green # code is lost (tail's is reported), so a red run reads as green
npm run build # writes dist/ and regenerates index.html npm run build # writes dist/ and regenerates index.html
./build.sh # the same under `set -o pipefail`, for callers that pipe the output ./build.sh # the same under `set -o pipefail`, for callers that pipe the output
node tools/seed-e2e.mjs && node tools/e2e.mjs # 958 editor checks, screenshots in /tmp/gm-e2e-*.png node tools/seed-e2e.mjs && node tools/e2e.mjs # 960 editor checks, screenshots in /tmp/gm-e2e-*.png
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step
./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh start [GM_STEPS] # the same run detached, see below
./e2e.sh status # live progress, or the last run's result ./e2e.sh status # live progress, or the last run's result
@@ -232,4 +232,4 @@ widths to find click points. The **render device is not in this repo** — `/dev
and a 1 GB `/dev/shm` come from `container.options` in the runner's own `config.yaml`, which and a 1 GB `/dev/shm` come from `container.options` in the runner's own `config.yaml`, which
applies to every job on that runner. Without them chromium falls back to llvmpipe, which gets applies to every job on that runner. Without them chromium falls back to llvmpipe, which gets
WebGL 1.0 only. Measured in the job container: `ANGLE (Intel, Vulkan 1.3.230, HD Graphics 630)`, WebGL 1.0 only. Measured in the job container: `ANGLE (Intel, Vulkan 1.3.230, HD Graphics 630)`,
WebGL 2.0, and the same 958 checks as here. WebGL 2.0, and the same 960 checks as here.
+12 -2
@@ -86,8 +86,9 @@ whole inside of a frame does not swallow the lines it holds. **All four at zero
not sliced at all** — it is drawn over the whole box, exactly as every sprite was before #41, and a not sliced at all** — it is drawn over the whole box, exactly as every sprite was before #41, and a
frame nobody sliced carries no border keys in the saved document. frame nobody sliced carries no border keys in the saved document.
**Fill** says how the parts *between* the corners fill their space: `Stretch` pulls them, `Repeat` **Fill** says how the parts *between* the corners fill their space: `Repeat` tiles them, `Stretch`
tiles them. One setting for the edges and the middle together, because a brick pattern that tiles pulls them. `Repeat` is the default, so only a `Stretch` is written into the saved document.
One setting for the edges and the middle together, because a brick pattern that tiles
along the top and stretches in the centre reads as a mistake. A tiled part is built as one quad per along the top and stretches in the centre reads as a mistake. A tiled part is built as one quad per
tile, each with the frame's own UVs and the last one cut off where the space ends — sampling past tile, each with the frame's own UVs and the last one cut off where the space ends — sampling past
1 with a repeating address mode would pull in the *neighbouring cell of the sheet*, which is the 1 with a repeating address mode would pull in the *neighbouring cell of the sheet*, which is the
@@ -100,6 +101,15 @@ corners meet at a seam. And a frame can never be given borders that leave *no* m
squeezed to leave at least one pixel, because a middle of no pixels has nothing to draw the space squeezed to leave at least one pixel, because a middle of no pixels has nothing to draw the space
between the corners with, and that would show as a hole rather than as an error. between the corners with, and that would show as a hole rather than as an error.
**Nine-slice scale** is a property of **the texture**, not of a frame: it says how many sprite units
one border pixel is drawn with, for every sliced frame the texture has. The default 1 draws a 16 px
border 16 units wide; at 2 the same border is 32 units, at 0.5 it is 8. The pixels a corner shows
stay the same — only its size on screen changes — so a pixel-art button can have chunky corners
without redrawing the sheet at twice the size. With `Repeat` the tiles scale along, because a border
drawn twice as big beside a pattern at its old size reads as two different pictures. The rule for a
sprite narrower than its borders applies to the scaled size: two 32-unit borders on a 20-unit box
become two of 10.
**Fitting the sprite to the picture.** The *Width* and *Height* rows of a sprite carry a ↔ / ↕ **Fitting the sprite to the picture.** The *Width* and *Height* rows of a sprite carry a ↔ / ↕
button offering two things: **Fit to 64 x 48** sets that one side from the other and the picture's button offering two things: **Fit to 64 x 48** sets that one side from the other and the picture's
proportions — the frame's rectangle when it wears a frame, the whole image otherwise — and **Set proportions — the frame's rectangle when it wears a frame, the whole image otherwise — and **Set