Add pixel-size fit and drag-to-reorder in the hierarchy
The aspect button now carries two offers, so it becomes a menu: fit one side to the texture ratio, or set both sides to the exact pixel size as a single undo step. Dropping a row on the outer quarter of another row inserts it into that gap instead of parenting into it, reordering among the siblings there. Order is the stored order, so ReorderObjectCommand is a splice; equal z falls back to tree order, which makes this the way to draw one object in front of another. Rejected on container content like the other structural edits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f40b8a0523
commit
4568c6581b
17 files changed
+416
-85
No files matched your search
@@ -106,7 +106,10 @@ shown on the node and editable in the inspector.
|
||||
|
||||
**Editor symbols are always on top.** The viewport draws scene content (sprites) in an
|
||||
`objects` layer and editor symbols (camera icon, labels) in an `overlay` layer above it, so a
|
||||
sprite can never hide a symbol regardless of z or hierarchy order.
|
||||
sprite can never hide a symbol regardless of z or hierarchy order. A viewport label keeps a
|
||||
constant size on screen however far you zoom, and both kinds of them – the object names of the
|
||||
Scene tab and the frame names of the Texture tab – read that size from one token
|
||||
(`Theme.viewportLabelSize`); the two `viewportLabel` styles differ in colour only.
|
||||
|
||||
**Z-order is part of the position.** `position.z` is the draw order of a scene object: higher
|
||||
`z` is drawn on top; objects with equal `z` keep their hierarchy (tree) order. It is edited in the
|
||||
@@ -120,6 +123,11 @@ subtree back. Re-parenting keeps the world position by recomputing the local one
|
||||
are rejected. In the **Scene objects** panel children are indented below their parent; drag a
|
||||
row onto another row to parent it, onto the empty space below the rows (or right-click →
|
||||
Unparent) to move it to the top level; the inspector offers the same as a **Parent** menu.
|
||||
Dragging into the **gap** above or below a row – its outer quarter, marked with a line instead of
|
||||
an outline – orders the object among *that* row's siblings rather than putting it inside, and
|
||||
re-parents it on the way when the gap belongs to another parent. Since equal `z` falls back to
|
||||
this order, that is also how two objects at the same depth are put in front of each other. A drag
|
||||
that lands where it started changes nothing and costs no undo step.
|
||||
Rows with children **fold**: click the chevron (or press ←/→, or double-click the row) to open
|
||||
and close a subtree, right-click → **Expand all** / **Collapse all** for the whole scene. A
|
||||
scene opens fully collapsed – which rows are open is view state of the panel, never stored in
|
||||
@@ -225,13 +233,17 @@ plain colour and comes back by itself on undo. Deleting the whole texture counts
|
||||
wearing *any* of its frames, not just the ones naming the texture directly.
|
||||
|
||||
**Fitting the sprite to the picture.** The *Width* and *Height* rows of a sprite carry a ↔ / ↕
|
||||
button that 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. Like ↺ and ↑ the buttons exist only
|
||||
when they would do something: no picture, an image not yet measured, or a sprite already in
|
||||
proportion means no button at all. Fitting is an ordinary property write, so on an object it
|
||||
becomes an override and it is one undo step. The comparison has a relative tolerance rather than
|
||||
being exact — of the 40 000 picture sizes up to 200 × 200, 3135 do not survive the round trip
|
||||
through a division, and an exact test would leave the button standing after its own click.
|
||||
button offering two things: **Fit to 64 × 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
|
||||
to 64 × 48 px** puts both sides at the picture's own pixel size. Like ↺ and ↑ the button exists
|
||||
only when it would do something, and follows the same rule for how many: no offer means no button,
|
||||
one is a direct click, both make it the menu form ↔ ▾. So a sprite without a picture, or one
|
||||
already in proportion *and* at pixel size, carries nothing. Either action is an ordinary property
|
||||
write, so on an object it becomes an override, and setting both sides is still one undo step. The
|
||||
proportions are compared with a relative tolerance rather than exactly — of the 40 000 picture
|
||||
sizes up to 200 × 200, 3135 do not survive the round trip through a division, and an exact test
|
||||
would leave the button standing after its own click. The pixel size is compared exactly, because
|
||||
those two numbers are written as they are.
|
||||
|
||||
Rendering a frame is a texture matrix on the fill, not a Pixi sub-texture — a Graphics fill
|
||||
ignores a `Texture`'s `frame` (measured, see `viewport/textureFill.ts`). One consequence is
|
||||
@@ -346,7 +358,7 @@ selected and switched back on.
|
||||
|
||||
```
|
||||
web/index.html Vite source page (dev) index.html built page (generated, served)
|
||||
src/core/model/ Project (object holders), Asset, SceneObject, hierarchy, walk (generic parent/child walks), instance (container content resolved from its template)
|
||||
src/core/model/ Project (object holders), Asset, SceneObject, hierarchy, walk (generic parent/child walks), instance (container content resolved from its template), container (the cycle guard)
|
||||
src/core/properties/ PropertySchema, resolve (the only override merge), collider/camera/text geometry, enabled
|
||||
src/core/commands/ undoable commands, CommandStack, SetBagValueCommand base, require.ts (validated lookups, and what an instance may not change), naming.ts
|
||||
src/core/graph/ graph model, NodeRegistry/NodeContext/values, interpreter; nodes/<category>/<Type>.ts
|
||||
@@ -362,6 +374,7 @@ src/editor/inspector/ Inspector panel, field factory, previewHandlers (scrub
|
||||
src/editor/panels/ AssetPanel, HierarchyPanel, Toolbar
|
||||
src/editor/graph/ GraphEditor (header + picker), GraphCanvas, NodeView, NodePalette
|
||||
src/editor/container/ ContainerEditor (header + picker), ContainerCanvas (a SceneViewport on a template)
|
||||
src/editor/texture/ TextureEditor (header + picker), TextureCanvas (picture + frames), SliceDialog, sheetView (the grid maths)
|
||||
api/ PHP backend data/projects/ persisted projects
|
||||
tests/ Vitest unit tests tools/ seed-*, e2e (steps in tools/e2e/), smoke-jumprun, lib/
|
||||
```
|
||||
@@ -390,8 +403,8 @@ npm run lint # ESLint, type-aware; --fix for the fixable half
|
||||
npm run format # Prettier over src, tests and tools
|
||||
npm run check # typecheck + lint + format:check + tests, what CI would run
|
||||
npm run build # writes dist/ and regenerates index.html
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 140 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
node tools/seed-jumprun.mjs && node tools/smoke-jumprun.mjs # the example game, played end to end
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 258 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
node tools/seed-jumprun.mjs && node tools/smoke-jumprun.mjs # 24 checks: the example game, played end to end
|
||||
```
|
||||
|
||||
**Prettier owns the formatting** (110 columns, single quotes, `.prettierrc.json`); Markdown is
|
||||
@@ -459,9 +472,8 @@ object in the selection (hierarchy rows too).
|
||||
|
||||
## Not yet
|
||||
|
||||
Reordering the hierarchy, several scenes in one run (a `Load scene` node – screens are containers
|
||||
Several scenes in one run (a `Load scene` node – screens are containers
|
||||
today), sound, auth, touch-optimised layout, graph comments/groups. A frame is always stretched to
|
||||
the sprite's `width` × `height`: no animation (nothing steps through a sheet's frames yet) and no nine-slice. ↔ / ↕ fit the
|
||||
proportions, but nothing sets a sprite to the picture's pixel size outright. Slicing cuts a
|
||||
regular grid only — no detection of where the sprites actually
|
||||
the sprite's `width` × `height`: no animation (nothing steps through a sheet's frames yet) and no
|
||||
nine-slice. Slicing cuts a regular grid only — no detection of where the sprites actually
|
||||
sit on the sheet. Unreferenced image files are never collected.
|
||||
Reference in new issue
Block a user