Object tree: groups and the drawing order
Deploy web Studio / deploy (push) Successful in 1m5s

Groups: objects of type "group" draw nothing; members carry the group's id
in a new `group` field (groups nest). A hidden group hides everything in it
(Doc::hidden_in_groups, skipped by the driver), a locked one locks it in
the Studio. Removing a group moves its members up into its parent group.
isokit check warns about members of missing groups. New `order` op: the
whole object order at once (each id once), one undo step.

Studio object list as a tree in the document order, front first: each
group sits just after its members, so it draws as one block, and ground
pieces higher in the list lie on top. Groups fold open and shut; every row
has an eye and a lock (shown on hover or when set); a click on a group
selects all of it, so a drag on the map moves it all. Group / Ungroup
(Ctrl+G, Ctrl+Shift+G), Order up/down (Ctrl+] Ctrl+[, with Shift to the
front / back), drag rows above, below or into a group. Group panel: name,
zoom, ungroup, to front / back, lock, hide, delete with contents.

MCP: group field in the object schema, order op, guidance.

Tests: Rust 81 (ops: groups, order, removal; driver: nested hidden
groups), Studio 131, web 100.
This commit is contained in:
grabowski committed 2026-10-25 18:06:04 +07:00
1 parent 5ec164a633
commit 540b37020c
15 files changed
+573 -30

No files matched your search

+16
View File
@@ -387,6 +387,22 @@ try:
check(len(during) >= 2 and after and after[0] < 150 and tf == "",
f"a long pinch is drawn anew {len(during)} times on the way and sharp {round(after[0]) if after else None} ms after it ends")
pg.evaluate("__studio.view.fit()")
# groups in the web Studio (the same ops in WASM): two bushes grouped, the group hidden, undone
pg.locator('#objects li[data-id="bush-1"]').scroll_into_view_if_needed()
pg.locator('#objects li[data-id="bush-1"]').click()
pg.locator('#objects li[data-id="bush-2"]').click(modifiers=["Control"])
pg.keyboard.press("Control+g")
pg.wait_for_timeout(800)
g = [o for o in doc(pg)["objects"] if o["type"] == "group"]
members = sorted(o["id"] for o in doc(pg)["objects"] if g and o.get("group") == g[0]["id"])
pg.evaluate("id => __studio.op({op: 'update', id: id, patch: {hidden: true}})", g[0]["id"] if g else "")
pg.wait_for_timeout(800)
hid = pg.evaluate("() => document.querySelectorAll(`.iso-svg [data-obj='bush-1'], .iso-svg [data-obj='bush-2']`).length")
for _ in range(2):
pg.locator("#undo").click()
pg.wait_for_timeout(600)
check(len(g) == 1 and members == ["bush-1", "bush-2"] and hid == 0 and not any(o["type"] == "group" for o in doc(pg)["objects"]),
f"web Studio groups: {members} in {g[0]['id'] if g else None}, hidden with it, undone")
# ---------------------------------------------------------------- a system asking for less motion
# (Windows: Animation effects off): the view starts still, but the button stays and turns it on