Commit Graph
9 Commits
Author SHA1 Message Date
grabowski 540b37020c 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.
2026-10-25 18:06:04 +07:00
grabowski 19f4c83ae8 Multi-select, select joined walls and fences, pond with swimming fish
Deploy web Studio / deploy (push) Successful in 1m27s
Selection: S.sel stays the object picked last; S.selIds holds everything
selected.
- In the object list, Ctrl+click adds or removes an object and
  Shift+click selects a range.
- On the map, Ctrl/Shift+click toggles an object and Shift+drag draws a
  box that selects what lies wholly inside it (locked and hidden objects
  are left out).
- Ctrl+A selects everything that is not locked; Esc selects nothing.
- Clicking a wall or fence a second time selects every piece of the same
  type joined to it; another click goes back to that one piece.
- Dragging one selected object moves them all, together with the windows
  and doors on them, as one undo step. Arrow keys, R (turns the group
  about its middle), Ctrl+D, Delete, Lock and Hide all work on the whole
  selection.
- When all selected objects share a type, the property form edits them
  all; fields where they differ show "mixed".
- The agent's system prompt lists the selected objects.

The viewer outlines several objects with selectObj([ids]) and passes the
click event to onPick. A batch op now answers `ids`, one per operation,
so the copies from a group duplicate get selected.

Pond (Nature): natural, round or square, with a stone or grass edge,
fish, lily pads, spreading ripples and reed clumps. The fish come from a
new Swim primitive (script: s.swim). One matrix maps the object's frame
to the screen. Each fish turns round its ellipse with a CSS rotation,
so off-screen pausing and reduced motion apply as for the other
animations. The house demo gets a koi pond in the back garden.

Tests: ponds in every shape and rotation have the right number of fish,
no NaN and no depth-sort cycles, and stay inside their rectangle.
check_studio covers list and map multi-select, a group drag undone in
one step, joined-fence selection, a mixed-value form applied to all, box
select, delete and undo, Ctrl+A, Esc, and a new pond's fish.
2026-10-24 18:36:39 +07:00
grabowski e4017ce2a8 Fences join like walls, fence designs, draw runs corner by corner
Deploy web Studio / deploy (push) Successful in 3m52s
Joints: line_joint (util.rhai) applies the house-wall rules to fences and
site walls, so pieces never overlap and the depth sort stays clean.
- A corner is closed: the thicker piece (or, if equal, the one along
  world x) runs through, and the other stops at its face.
- On a straight run, two pieces share one post.
- At a T, the stem stops at the other piece's face without a post of its
  own.
- A fence that ends at a site or house wall stops at the wall's face.

Fence designs (prop style): mesh, wooden boards, steel bars, mesh on a
stone base, cobble wall, and brick wall with pillars. Board, stone and
brick joints are drawn on the face turned to the viewer. Brick pillars
are separate sprites.

Studio: line prefabs (walls, fences, hedges, roads) can be drawn as a
run by clicking corner after corner. Double-click or Enter ends the run,
clicking the first corner closes it, and Backspace drops the last
corner. A run is one undo step. A drag still draws one piece. Corners
and ends snap onto the ends and lines of the pieces they meet, and a
marker shows where the next corner will snap.

The house demo gets a brick front wall with gate pillars and wooden side
fences in place of the old east fence, which ran over the road. Tests
cover every design's corners, Ts, straight runs and wall stops, with no
depth-sort cycles in any rotation, plus site walls. check_studio draws
and closes a fence run, undoes it in one step, snaps a dragged spur,
and picks a design.
2026-10-24 18:07:40 +07:00
grabowski 7962249191 Middle mouse button only moves the camera
Deploy web Studio / deploy (push) Successful in 3m9s
A press with the middle (or any other non-left) mouse button never reaches
the Studio's drag, place or select handlers: dragging pans the view even
on a selected object or while placing, and a click selects nothing. A
middle click no longer starts the browser's autoscroll.

check_studio covers a middle-drag on the selected truck (it stays put,
the view moves), a middle click on another object (the selection is
kept), and a middle-drag while placing (nothing is placed).
2026-10-24 17:52:23 +07:00
grabowski 95ea4a8512 Build your own house: walls, windows, doors, floors, roof, stairs, furniture
Deploy web Studio / deploy (push) Successful in 3m27s
House parts (stdlib isokit/house): house_wall drawn along a line, with ends
that adapt at corners, T-junctions and straight runs so no two walls
overlap; window and door that sit on a wall and cut its opening (door
styles panel, glass, double, sliding, opening; swing and hinge by
rotation); floor (boards, tiles, carpet, stone); roof (hip, gable, flat,
optional solar); stairs.

Furniture (stdlib isokit/furniture): chair, sofa / armchair, table with
chairs, desk with monitor and chair, TV, bed, cupboard, bookshelf, kitchen
run, bathtub, shower, toilet, washbasin, plant, rug, floor lamp.

Cut-open levels: on gf / 1f the walls in front of a room are cut low
(rooms are found by their floors), the roof becomes an outline on the
floor, and storeys above are left out. A part's storey comes from z
(storey_h, default 3 m).

Scripting: objects_of, objects_at, objects_on, mount_of, mounted, frame,
to_world, to_local, local_of. Prefab meta: shape (line / rect), mount,
storey.

Studio: drag to draw lines and rectangles (walls, roads, fences, hedges,
floors, areas, buildings, roofs). The Room tool draws a floor plus walls,
without doubling walls that already stand on an edge. Windows and doors
snap onto walls with a hover preview, and they move, turn, copy and
delete with their wall in one undo step. New parts land on the storey
the view shows. Palette categories collapse, and the palette scrolls
apart from the object list.

The MCP instructions explain house building, and list_prefabs shows
sits_on. examples/house is a furnished bungalow; the web Studio gets a
House demo button. Tests: wall corners and junctions, zero depth-sort
cycles in every view, cut levels, and the house demo in every view;
check_studio covers the room / window / door / storey flow, check_web
the House demo.
2026-10-24 17:39:04 +07:00
grabowski 1a1b62d475 studio: agent window, a chat with a model that edits the scene
Deploy web Studio / deploy (push) Successful in 3m3s
✦ Agent in the Studio's top bar opens a floating chat window. The model
(any OpenAI-compatible endpoint with tool calling; default B4L's inference
server, https://inference.p0.contact/v1) gets the 15 MCP tools plus two page
tools (select_object, set_view) and the Studio's state (selection, level,
rotation) in its system prompt. Answers and reasoning stream in; tool calls
show as rows with arguments and results; object ids link to the object;
Stop ends a turn; Undo takes the agent's edits back. The window moves by
its title bar and resizes at its top-left corner.

- studio/agent.js: shared by both front ends (waits for studio.js's
  isokit:studio event); MCP over /mcp or isokit.mcp in the web Studio
- isokit studio: /api/agent/{config,models,chat} relay the calls on their
  own threads (ureq, chunked and flushed per read), so the key stays on the
  machine and the endpoint needs no CORS; settings from ISOKIT_LLM_URL /
  _KEY / _MODEL or agent.json in the user's config folder
- web Studio: calls the endpoint from the page with a key kept in the
  browser; build_web.py --agent-url names a same-site relay as default; the
  deploy builds with /llm/v1, which deploy/Caddyfile forwards to the
  inference server (its nginx refuses the CORS preflight)
- tools/mock_llm.py + tools/agent_checks.py: the agent window checks in both
  check_studio.py and check_web.py
2026-10-23 19:35:53 +07:00
grabowski c647f39059 studio: version text in the status bar, favicon
Deploy web Studio / deploy (push) Successful in 3m15s
The status bar ends with "isokit <engine version>"; the web build adds
the commit (linked on Gitea), its date as a tooltip and a "+" when built
from a tree with uncommitted changes (build_web.py writes a
<meta name="isokit-build"> from GITHUB_SHA or git). /api/meta now carries
"engine". studio/favicon.svg (isometric cube in the accent green) is
served by `isokit studio` (also on /view) and copied into the web build.
check_web.py and check_studio.py check both.
2026-10-23 17:08:48 +07:00
grabowski 5eb60d2a0c isokit: web Studio (engine as WASM, projects in the browser or a live folder)
- isokit-wasm: wasm-bindgen build of the engine; a project in memory behind
  the same JSON API as `isokit studio`, plus the MCP tools
- isokit-project: Store trait (FsStore folder, MemStore memory) under a
  generic Workspace; Project::from_files; shared Studio API module (api.rs)
  used by serve.rs and the WASM build; web_time for clocks in the browser
- studio.js runs on a pluggable backend (window.IsoKitBackend); no Studio
  keys while a dialog is open
- web/: projects in IndexedDB, new/demo/delete, zip export/import (stored and
  deflated), folder import by drop or picker, folders opened live via File
  System Access with outside edits followed, code editor, page build and
  preview, two tabs in step, isokit.mcp() and WebMCP registration
- tools/build_web.py -> dist/web (static), tools/check_web.py (44 checks)
2026-10-22 17:00:42 +07:00
grabowski 564aeb75f6 isokit: project layer, Studio GUI, MCP server, viewer, CLI, demo project and docs 2026-10-22 15:29:07 +07:00