A sprite sorted by Y stood on the bottom of its box. With a shadow or
empty rows under the feet that is too low, so a figure slipped in
front of a tree it should stand behind. The line belongs to the frame,
not the texture, because one texture can hold several sprite sheets.
- New field `sortLine` on a frame: whole image pixels up from the
frame's bottom edge, 0 to the frame height. 0 is stored as nothing,
so old projects stay the same. Shrinking a frame keeps the line
inside it.
- `feetOf` in drawOrder.ts lifts a sprite by the same share of its
box. Scene view, game view, play and picking all use it. In an
animation the line of the frame shown right now counts.
- The texture tab draws the selected frame's line dashed in yellow
with a knob left of the frame. At 0 the line shares the bottom edge
with the nine-slice border and a resize handle, so the knob is
tested first. A line inside the frame can be dragged directly,
tested after the nine-slice lines.
- The inspector has a new "Sorting" section with a "Sort line"
field. Dragging or typing is one undo step each.
Limit: frames of one walk cycle need the same value, set by hand.
Otherwise the figure changes its place in the order while walking.
Tests:
- ./check.sh: 160 files, 2356 tests, CHECK EXIT 0 (before 2350).
- 6 new unit tests in tests/viewport/sort-by-y.test.ts.
- e2e 37 and 39-43: ALL PASSED, 162 checks. New check 37b-ii drags
the knob up 6 px and undoes it, plus the inspector row.
- Counter checks: if feetOf ignores the line, exactly the 3 order
tests fail. If the knob cannot be grabbed, 37b-ii fails.
- The e2e sum in the README is 1380, counted, not yet seen in CI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A tilemap layer was one piece in the draw order, so a figure stood
either in front of a whole layer of trees or behind all of it. For a
top-down game the trees in front of the figure's feet have to cover
it and the ones behind must not.
- A new "Sort by Y" box under the layer list sets `sortByY` on the
painted layer. Every change is its own undo step.
- Such a layer comes as one draw slot per row. On its `z`, the rows
and all objects on that `z` are sorted by where they stand: the
bottom of an object's box, the bottom of a row. Ties keep the
hierarchy order, and other `z` values are untouched.
- A layer drawn as one piece and the map's own node stay behind the
sorted ones on the same `z`, since neither has a single place to
stand. Ground belongs on a lower `z` or stays unsorted.
- A new tile property "Sort offset" (whole rows, -16 to 16) lets a
crown sort with the trunk below it.
- `TilemapField` draws a container per row for such a layer, and
picking takes the row into account, so a click picks what is drawn
in front. Scene view, game view and play share the same rule.
Limits: on a rotated map "down" is world Y. A layer sorted by Y costs
about one draw call per row and tile instead of one per tile.
Tests:
- ./check.sh: 160 files, 2350 tests, CHECK EXIT 0 (before 2340).
- 10 new unit tests in tests/viewport/sort-by-y.test.ts.
- e2e 39-43: ALL PASSED, 148 checks. New check 40p-iii ticks the box
and finds the slot of row 0, undo brings back the whole layer.
- Counter checks: without the Y sort 5 unit tests fail, with the
offset ignored 5, with no row in picking 1. If TilemapField draws
no rows, exactly 40p-iii fails in e2e.
- The e2e sum in the README is 1378, counted, not yet seen in CI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>