Files
OneCAD/docs/plugins.md
William Dunn 41f0c3d0c6 docs: browser runtime design (craft-libs, workers, #1221) (#1258)
A design note for SolidCraft in the browser: tiered storage, a SharedWorker job broker, GPU dispatch and in-browser agent control through the same engine commands, with the generic pieces in craft-libs. Linked from the MCP and web getting-started docs.
2026-10-14 22:34:48 -04:00

6.7 KiB

Plugins (design)

Design companion to #1221: sandboxed WebAssembly plugins with a WIT interface, the same run(command, args) JSON as MCP and the control protocol. Browser hosting is in web-runtime.md.

This document adds parametric timeline features: a generic host-owned feature shell that plugins fill with parameters, display metadata, and rebuild logic, without a second timeline model or a private geometry API.

Goals (unchanged from #1221)

  • Sandboxed by default: manifest permissions, fuel/memory limits on desktop, broker enforcement on web.
  • Any language that compiles to Wasm components; Rust first.
  • One command surface: plugins change the model only through engine commands (undoable, journaled).
  • Versioned WIT world (solidcraft:[email protected]).

Two plugin shapes

Shape Timeline Rebuild Milestone
One-shot Optional; often no persistent feature N/A 1 (first ship)
Parametric One Plugin feature row per plugin instance Host calls plugin on param/timeline rebuild 2

One-shot plugins call execute(params) once; they may emit ordinary native features (sketch, extrude, …) inside that transaction. Parametric plugins still use run() inside rebuild; the difference is that the document records a single feature whose params the user edits later.

Generic feature shell (host-owned)

Add one variant to the parametric document (name illustrative):

FeatureKind::Plugin {
  plugin_id: String,           // "gear_generator"
  api_version: u32,            // matches WIT world
  params: Value,               // JSON owned by the plugin schema
  display: PluginDisplay,      // timeline + browser presentation
  provenance: PluginProvenance, // optional: manifest hash, build id
}

PluginDisplay (stored in the file, not recomputed from plugin code at open):

Field Role
label Primary timeline / browser text
icon_id Host icon registry name (same system as feature_icon)
tooltip Hover text, inspect type string
type_name Fusion-like feature type for power users

The timeline renders any Plugin feature through one code path: read display, draw icon + label, wire suppress/rename/delete/reorder like built-in features. No per-plugin egui in milestone 2.

Optional later: parameter_schema() in WIT returns { id, label, kind, min, max, … } so the host renders sliders and dimension rows without custom UI per plugin.

WIT entry points (phase 2 additions)

Milestone 1 (#1221): manifest(), execute(params) -> result<string, string>.

Milestone 2 parametric:

Export Purpose
evaluate(params, ctx) -> result<string, string> Rebuild: plugin runs run() commands; result is success JSON or error
parameter_schema() -> string Optional JSON schema for generic parameter UI
fallback_policy() -> string Declares missing-plugin behaviour (see below)

ctx is host-provided read-only hints (configuration name, units, feature id); plugins must not rely on it for correctness.

Inside evaluate, the plugin uses the same run(command, args) import as one-shot mode. The host applies commands to the current eval context (or a scratch session merged by the host). No second registry of geometry ops.

Rebuild flow

Timeline rebuild reaches FeatureKind::Plugin
  -> load plugin (wasmtime desktop / broker web) if permitted + present
  -> evaluate(stored params)
       -> plugin calls run("sketch.line", …), run("solid.extrude", …), …
  -> host merges geometry like any native feature
  -> errors surface on the feature row like native eval errors

Param changes (parameter panel, parameters.change, config switch) re-run evaluate for affected plugin features only when dependencies say so (same invalidation rules as native features).

Missing plugin and API drift

Manifest declares fallback_policy:

Policy Behaviour
recorded_mesh Optional B-rep or mesh blob stored beside params; open works, edit disabled without plugin
recorded_script Stored list of native commands; rebuild without plugin if every command is built-in
suppress_with_warning Feature suppressed; user sees clear message
error_on_rebuild Hard fail on eval (strict teams)

Design files shared in CollabCraft should prefer a policy that opens safely (recorded_mesh or recorded_script). CI for plugins (#1221) should include: uninstall plugin, reopen file, assert document still opens and policy matches manifest.

Icons and metadata

Plugins declare allowed icon_id values in manifest(); the host rejects unknown ids. Icons stay in the app registry so untrusted plugins cannot inject arbitrary raster assets into the tree without a reviewed icon pack.

Rename by the user updates the feature user label; display.label remains the default from creation unless the plugin updates it via a host callback (optional future).

Command naming: prefer plugin_id.function in run() or registered command aliases to avoid collisions (#1221 discussion).

Group header variant (lighter-weight v2a)

Before full evaluate, a stepping stone: one-shot plugin creates a feature folder whose header carries PluginDisplay metadata while children are ordinary native features. Rebuild does not need the plugin until the user edits plugin-owned params on the header. Migrates cleanly to full FeatureKind::Plugin when evaluate lands.

Relationship to craft-libs

Plugin document model and eval stay in SolidCraft (crates/doc, crates/engine). craft-libs provides worker/broker hosting only (web-runtime.md). Neutral serde types (VersionedParams, PluginDisplay) may move to a shared crate later if multiple apps need them; CAD plugins remain SolidCraft-specific.

Phasing

  1. WIT + wasmtime host + one-shot execute + permissions tests (#1221 milestone 1).
  2. FeatureKind::Plugin + PluginDisplay + timeline generic row + evaluate + fallback policy.
  3. Web broker runs same WIT; parametric features offline only if plugin module cached and policy allows.
  4. Parameter schema UI, cloud-signed plugin index, inspector extensions.

Tests (parametric)

  • Create plugin feature, change param, rebuild, measure geometry (oracle or bbox).
  • Undo/redo across plugin eval.
  • Remove plugin binary, reopen design, assert fallback policy.
  • Icon id from manifest appears on timeline (scenario or screenshot harness).