A rig is three things.

A manifest names the parameters and the instrument each one uses. A renderer receives the current values and draws the result. The registry exposes it to the library. Nothing else in the workspace knows which rig it is showing.

The manifest

id          The URL slug, and the export's rigId
title       The sidebar path, Storybook-style: Examples/SVG.
            Each slash is a foldable folder, and name is the leaf
parameters  The controls. A parameter's id is its key in the JSON
animation   Optional tracks that drive numeric parameters over time

Every parameter carries a stable id, a label, a group and a defaultValue. What else it carries depends on its kind, and Controls is the reference for that.

The renderer

The application registers renderers in domain modules under src/modules/: SVG in Vector, HTML in Web, and Three.js in Scene. A module supplies its preview, editor, import/export adapters and specialized controls. The shell loads it on demand; the library reads generated metadata and cached thumbnails without starting its engine.

For a public integration, pass controlled values to the relevant SDK instance. No application registry is required. Choose an SDK for its renderer and lifecycle contract.

The shell must not learn rig names. A branch on rig.name in the chrome is the thing this arrangement exists to prevent. The inspector, the timeline, the snapshots and the export bind to the manifest, and a rig that needs different behaviour declares it instead of being special-cased upstream.

Custom controls

The inspector’s standard fields come from one renderer, ParameterField. It covers the numeric variants, color with alpha and channels, curves, radial profiles, gradients, vectors, ranges, choices, text, resources, lists and composites, plus actions and per-number value sources. A rig usually needs none of its own.

Inside the application, a custom control connects to session state through an adapter. Public @paramrig/controls components receive values and callbacks from the host and never access that session directly. A control owes four things:

  • Read the current value from the session snapshot, and write with session.setValue(id, next).
  • Wrap a pointer drag in beginGesture() and endGesture(), so undo records the whole drag as one step. Escape, pointer cancellation and unmounting mid-drag call cancelGesture().
  • Give every grab handle a hit helper of 32px, or 44px on a coarse pointer. The gauge field takes the whole box, and a 12px click target is not one of the options.
  • Offer something that is not a drag: a numeric field, a button, or arrow keys.

Documents are rigs too

A vector drawing or a 3D scene can carry its own controls without a registry entry at all: the document declares them, and vectorManifest() or sceneManifest() presents it to the rest of the app as an ordinary rig. See Binding a drawing and Binding a scene.