Files
solvecraft/docs/browser-api.md
T
Arjan Duijs 0690ee5875 Web app: run as a modelling editor inside another page that keeps the design files (#8517) (#11273)
* claim: #8517

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* web: editing embed for host pages (?embed=editor, #8517)

A host page that keeps the files itself and frames SolidCraft for modelling needs
the modelling UI without the application chrome. `?embed=editor` runs the web app
as such an embed:

- no application bar (logo, File menu, document tabs, update, help, report a bug)
  and no start page; the layout is docked;
- the ribbon, browser, timeline and properties stay; Ctrl+Z and Ctrl+Y still undo
  and redo;
- Ctrl+N, Ctrl+O, Ctrl+S, Ctrl+W and Ctrl+, are left to the host;
- nothing is kept in the browser (no stored designs, autosave, recovery prompt,
  preferences or leave-page prompt), as with the existing viewer embed.

The existing `?embed&open=` viewer embed is unchanged. SolveApp gets one flag,
`embed_editor`, for desktop and test hosts too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* control: document.export / document.import / document.saved for a host (#8517)

An editing embed's host keeps the design itself. Three control methods
(window.solidcraft.request in the browser; the desktop control channel too; not
the agent chat's, whose method list is unchanged):

- `document.export` -> {name, revision, dirty, format: "json", text}: the active
  design as a `.json` design file holds it. `revision` is the one
  `document.revision` answers, so a host that follows the design compares one number.
- `document.import {text, name?}`: replaces the active design with that text,
  timeline and parameters as saved, opened saved with a new `document_id`. It runs
  as a design opened in a tab of its own, with the old tab closed without asking,
  so whatever was open in the old design leaves with it. A text that does not read
  leaves the design as it was. Waits behind a file loading or a design change, as
  commands do, and evaluates on the window thread.
- `document.saved {revision}`: the host saved that revision; refused when the
  design has changed since.

They are control methods, not commands: they act on the app's open design. The
browser API test gets a round trip through all three.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: aduijs <7501203+aduijs@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 21:23:25 +00:00

3.5 KiB

Browser command API

After the browser app starts, window.solidcraft controls the design open in that tab. Calls use the same command ids, parameters, control handlers and undo history as the desktop control channel. No separate engine or server is started.

Call Result
solidcraft.request(method, params?) Any control method, such as ui.inspect, document.inspect or engine.batch
solidcraft.execute(command, params?) Run an engine command without opening its interactive dialog
solidcraft.commands() Discover commands, their parameters and current enablement
solidcraft.inspect(params?) Inspect the active document, optionally with {measure: true}

Every call returns a promise. It resolves to the control reply's result, or rejects with an Error. Omitted or null parameters become {}. Parameters must be JSON serializable and at most 16 MiB of JSON. At most 256 requests may be pending; excess requests reject without running. Requests run on the UI thread between frames. A hidden or suspended tab can delay completion; keep it active while driving the app. A reload ends the session and its pending work.

In the browser's developer console, on an empty design:

await solidcraft.commands();
await solidcraft.request("ui.home", {open: false});
await solidcraft.execute("solid.box", {
  length: 30, width: 20, height: 10, body_name: "Browser API box"
});
await solidcraft.inspect({measure: true});
await solidcraft.execute("edit.undo");
await solidcraft.execute("edit.redo");
await solidcraft.request("ui.inspect");

An agent with JavaScript evaluation access to this tab can make the same calls. The API does not register WebMCP tools or expose a network listener. Scripts executing in the page can use the API with the page's browser permissions. File paths refer to the browser's virtual file system, not arbitrary files on the user's computer. Native-only operations remain subject to the browser host's limitations; this API does not grant desktop filesystem or window access.

A host page that keeps the designs

?embed=editor runs the app as an editing embed: the ribbon, browser, timeline and properties, without the application bar or start page, and with nothing kept in the browser. A page that frames it from the same origin reaches this API as frame.contentWindow.solidcraft, keeps the designs itself and moves them with three control methods:

const app = frame.contentWindow.solidcraft;
const kept = await app.request("document.export"); // {name, revision, dirty, format: "json", text}
// ...the page stores kept.text, and says so:
await app.request("document.saved", {revision: kept.revision});
// ...and later puts it back, timeline and parameters as saved:
await app.request("document.import", {text: kept.text, name: "Bracket"});

The 16 MiB limit on parameters applies to document.import's text. A design that links other design files keeps those links as paths; the files themselves are not in text.

Verify a browser build

Build the app with trunk build in apps/solidcraft-web, then run from the repository root:

cargo xtask web-api-test --site dist/web

The test starts a local server and headless Chrome, discovers commands, creates a box in the live document, checks undo and redo, and verifies error handling and the pending-request limit. It also checks that Ctrl+Tab and Ctrl+Shift+Tab are left to the browser, which switches tabs with them. Set CHROME to a Chrome or Chromium executable if it is not installed in a usual location.