8.0 KiB
8.0 KiB
Control protocol
solvecraft --control PORT (or SOLVECRAFT_CONTROL_PORT=PORT) listens on 127.0.0.1:PORT for
JSON lines. Each request is one line {"id": …, "method": "…", "params": {…}}; each reply is one
line {"id": …, "ok": true, "result": …} or {"id": …, "ok": false, "error": "…"}. Requests are
handled on the UI thread between frames; pointer and keyboard input is injected as real egui
events, one pointer event per frame.
Engine
| Method | Params | Result |
|---|---|---|
engine.execute |
command: command id, params: JSON object |
the command's result |
engine.script |
commands: [{command, params}, …] |
results, stops at the first error |
engine.commands |
— | every command: id, label, tab, panel, icon, shortcut, params doc, enabled |
document.inspect |
measure?: bool |
parameters, timeline (errors, timings), bodies, sketches, selection |
Commands never open dialogs when run this way. solvecraft-cli commands prints the same registry.
UI
| Method | Params | Notes |
|---|---|---|
ui.inspect |
— | UI state, what is hidden (visibility: bodies, origin and construction items, sketches; set it with the browser.visibility command), viewport rect, camera, active tool/dialog, hover, renderer, timings, live preview (active, busy, error, ms, bodies it stands in for) |
ui.set |
any UiState field (tab, perspective, showGrid, dark, …), and hiddenBodies, hiddenOrigin, hiddenSketches, shownSketches (whole lists; browser.visibility changes single items) |
dark: false switches to the light theme |
ui.view |
view: front, back, top, bottom, left, right, iso, home, fit; animate (bool, default false: snap) |
|
ui.start |
command |
like a toolbar click: starts the sketch tool or dialog for the command |
ui.click |
x, y (screen points), button?: left/right/middle, shift?, ctrl?, double? |
real pointer input |
ui.move |
x, y |
|
ui.drag |
x0, y0, x1, y1, button?, shift?, ctrl?, steps?, hold?, hold_end? |
press, move, release; a left drag on the model is a box selection (left to right: window, right to left: crossing); hold keeps the button down that many frames first (a right press-and-hold opens the marking menu, releasing over a direction picks it), hold_end that many frames at the end (a sketch drag shows its snap) |
ui.menu |
x?, y?, target?, close? |
with a point: open a context menu there as a right-click would (the viewport's marking menu, or a browser menu with target: {"type": "body", "name"} | {"type": "sketch", "id"} | {"type": "component", "id"}); without: the open menu (radial and items: id, label, shortcut, enabled) |
ui.menuPick |
item: id or label |
runs an item of the open menu, as clicking it does |
ui.rename |
text?, commit? (default true) |
finishes the rename box a Rename item opened |
ui.selection |
the selection, the open dialog's inputs, the hovered item, and the active sketch's drawn dimensions (dimensions: id and text centre, dimension_selected, dimension_editing) |
|
ui.worldToScreen |
points: [[x, y, z]…] world points |
their screen points |
ui.triad |
screen points of the 3D sketch move triad's handles (x, y, z, plane) |
|
ui.sketchToScreen |
points: [[x, y]…] in active-sketch coordinates |
their screen points (null when behind the camera) |
ui.dialogInput |
index |
what clicking an input's Select chip does: picks go to that input |
ui.at |
world: [x,y,z] | sketch: [x,y] | plane: "XY" | axis: "Z" | dimension: "d1" (its value text) | handle: "arrow" (a manipulator handle, see scenario::publish_handle) |
the screen point (a scenario step's target; see crates/ui-egui/src/scenario.rs) |
ui.handles |
prefix? |
the handles drawn last frame, [{name, x, y}]: toolbar buttons and drop-down items toolbar:<command id>, panel labels panel:<tab>:<panel>, browser rows row:<label> and fold arrows fold:<label>, manipulator handles |
ui.editFeature |
feature (id or name) |
what double-clicking a timeline item does: rolls back to it and opens its dialog filled in (sketches open in sketch mode) |
ui.scroll |
x, y, delta? |
wheel zoom at the cursor |
ui.key |
key (egui key name, Enter, Escape…), cmd?, shift? |
|
ui.text |
text |
typed text |
ui.screenshot |
path? |
PNG of the window (needs a presented frame) |
ui.render |
path, width?, height? |
CPU render of the model with the current camera (no window needed) |
ui.confirm |
accept?: bool |
answers the Delete confirmation (shown when a delete takes other features with it or makes some fail); without accept, what it lists |
ui.documents |
action?: new, switch, close, quit; index?; force? (close without asking); answer?: save, dont_save, cancel (answers "save changes?") |
the open designs (tabs): names, unsaved flags, the active one, a pending "save changes?" prompt, whether a quit is asking |
ui.file |
path; insert?: bool |
starts an interactive background Open or Insert; poll ui.inspect.file_busy for completion; the window stays responsive |
ui.home |
open?: bool; sample?: index |
the start page: show or hide it, open a built-in sample (once built); returns open and the recent designs |
ui.shortcut |
command, key?, replace? |
a command's key, or rebinds it ("" clears; a key another command uses is refused unless replace) |
ui.help |
item?: about, shortcuts (read only), report (copies diagnostics) |
the version, commit, build date and diagnostic text |
ui.prefs |
any of default_units, nav (fusion, solidworks, inventor, alias, tinkercad), zoom_reverse, zoom_to_cursor, orbit_cursor, look_at_anim, look_at_speed, msaa, length_decimals, angle_decimals, theme (dark, light, system), language (en, ja; see localization), ui_scale, up_axis (z, y), offer_stand_up; open (a page: General, Navigation, Keyboard Shortcuts, Design, Graphics, Sketch, Selection) opens the Preferences dialog there; button: ok, cancel, apply, defaults; stand_up: true stands up a just-opened Y-up file |
sets preferences (kept between runs), returns them all plus dialog (the open page or null), dark and stand_up_offer |
ui.capture |
action?: capture, revert, cancel |
answers the Capture Position question (asked when a command starts or the design is saved while components were moved without capturing); without action, what waits |
ui.window |
action: minimize, maximize, restore, toggle, close |
what the title bar's caption buttons do (on Windows and Linux the application bar is the title bar); close asks about unsaved designs first |
ui.agent_cursor |
show (bool), speed: a number from 1 to 5 (times the normal speed) or "instant" (no animation: the command runs at once and the pointer jumps to where it acted), follow_camera (bool); all optional |
the settings. While the cursor is shown, engine.execute first glides to the command's toolbar button and to each pick, then runs and replies; later requests wait their turn. "animate": false on a call skips it |
ui.resize |
width, height |
|
app.quit |
force? (quit without asking about unsaved designs) |
quitting (the window closes), asking (a "save changes?" prompt is open) |
MCP
solvecraft-cli mcp --connect 127.0.0.1:PORT bridges an MCP client (an AI agent) to this
channel; see mcp.md.
Example
{"id":1,"method":"engine.execute","params":{"command":"sketch.create","params":{"plane":"XY"}}}
{"id":2,"method":"engine.execute","params":{"command":"sketch.rectangle.two_point","params":{"p0":[0,0],"p1":[40,30]}}}
{"id":3,"method":"engine.execute","params":{"command":"solid.extrude","params":{"distance":20}}}
{"id":4,"method":"engine.execute","params":{"command":"solid.fillet","params":{"edges":[[0,0,10]],"radius":3}}}
{"id":5,"method":"ui.screenshot","params":{"path":"/tmp/part.png"}}