Point handles for routes and outlines; Area corners; bus goes round right
Deploy web Studio / deploy (push) Successful in 1m4s
Deploy web Studio / deploy (push) Successful in 1m4s
Studio: one selected object with pts (a route, an outlined area) shows a handle on each point and a + in the middle of each side: drag a point to move it, drag a + to add one there, double-click a point to remove it (open routes keep 2, outlines 3). Points snap to the grid and onto wall, fence and road ends, at any angle; one undo step each. Handles keep their screen size (new viewer callback onView on every redraw) and follow re-renders and selection. The viewer captures the pointer, so a double- click targets the drawing: the last point pressed is remembered instead. Prefab meta `outline`: the prefab draws pts as its outline. Area has it: Edit corners turns its rectangle into four points, Rectangle again removes them. Routes: where a path doubles back, the lane offset puts a point on each side, so it rounds into a U-turn instead of a diagonal across the lanes. The streets demo bus now runs east, three quarters round the roundabout (clockwise, left-hand traffic), down south street, turns and comes back by the short way, instead of going round the wrong way on its way out. Tests: Rust 81 (a doubling-back route: each mover once, no sort cycles), Studio 134 (corners, move, add, remove, undo), web 100.
This commit is contained in:
1 parent
540b37020c
commit
c8becc2e59
12 files changed
+189
-11
No files matched your search
@@ -661,6 +661,41 @@ with sync_playwright() as p:
|
||||
pg.evaluate("__studio.select(null)")
|
||||
pg.wait_for_timeout(300)
|
||||
|
||||
# point handles: the yard (an area, 24 x 18 m at 14, 4) gets corners; one is dragged, a point is
|
||||
# added by dragging the + of a side and removed again by a double-click; undos restore the rectangle
|
||||
pg.evaluate("__studio.view.focus([14, 4, 0], 1.6)")
|
||||
pg.wait_for_timeout(400)
|
||||
pg.evaluate("__studio.select('yard')")
|
||||
pg.wait_for_timeout(400)
|
||||
pg.locator('#right button[data-act="pts"]').click()
|
||||
pg.wait_for_timeout(900)
|
||||
y0 = obj("yard").get("pts")
|
||||
nh = pg.evaluate("() => [document.querySelectorAll('.st-hpt').length, document.querySelectorAll('.st-hmid').length]")
|
||||
check(y0 == [[-12, -9], [12, -9], [12, 9], [-12, 9]] and nh == [4, 4], f"Edit corners: the yard becomes 4 points with handles: {y0}, {nh}")
|
||||
def handle_drag(a, b):
|
||||
pg.mouse.move(*at(*a))
|
||||
pg.mouse.down()
|
||||
pg.mouse.move(*at((a[0] + b[0]) / 2, (a[1] + b[1]) / 2), steps=4)
|
||||
pg.mouse.move(*at(*b), steps=4)
|
||||
pg.mouse.up()
|
||||
pg.wait_for_timeout(900)
|
||||
handle_drag((26, 13), (24, 16))
|
||||
y1 = obj("yard")["pts"]
|
||||
handle_drag((14, -5), (14, -8))
|
||||
y2 = obj("yard")["pts"]
|
||||
pg.mouse.dblclick(*at(14, -8))
|
||||
pg.wait_for_timeout(900)
|
||||
y3 = obj("yard")["pts"]
|
||||
check(y1[2] == [10, 12] and y2 == [[-12, -9], [0, -12], [12, -9], [10, 12], [-12, 9]] and y3 == [[-12, -9], [12, -9], [10, 12], [-12, 9]],
|
||||
f"handles move a corner {y1[2]}, add a point on a side {y2[1] if len(y2) > 4 else y2}, a double-click removes it ({len(y3)} left)")
|
||||
pg.screenshot(path=str(OUT / "studio-handles.jpg"), type="jpeg", quality=80)
|
||||
for _ in range(4):
|
||||
pg.locator("#undo").click()
|
||||
pg.wait_for_timeout(700)
|
||||
check("pts" not in obj("yard"), "four undos give the yard its rectangle back")
|
||||
pg.evaluate("__studio.select(null)")
|
||||
pg.wait_for_timeout(300)
|
||||
|
||||
# an agent edits over MCP: the open Studio follows
|
||||
init = mcp({"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "test", "version": "0"}}})
|
||||
check(init["result"]["serverInfo"]["name"] == "isokit", "MCP initialize")
|
||||
|
||||
Reference in new issue
Block a user