VOLTAreference

Reference / Work in Studio

Designing a workbench pack

Work in Studio

Open in the workbench →
On this page · 6 sections

Build a whole workbench look — artwork, control faces and a matching workspace layout — and review it before anyone installs it.

What a pack holds#

A format-2 pack folder (and its .voltaskin zip) holds:

EntryRole
skin.jsonThe appearance: colours, shape, type, decorations, faces.
assets/<name>.pngArtwork the skin names by ID.
workspace.jsonOptional. A workspace layout the pack offers.
fonts/<file>.ttfOptional. The skin's own type.
manifest.jsonGenerated. Capabilities, the asset inventory and the workspace entry.

The manifest is never written by hand. Export and the authoring tools build it from the files. A pack that carries workspace.json lists it as "workspace": "workspace.json" and declares the workspace capability as OPTIONAL. An older build that lacks it keeps the user's own layout. An invalid workspace.json refuses the whole pack. Export v1 drops it and says so.

Appearance and workspace are applied separately#

Installing or importing a pack applies its appearance only. Your layout stays as it is. When the pack also offers a workspace, the import toast says so.

Display ▸ Appearance inspector has the pack picker and the two choices:

  • Apply appearance shows the pack's skin in the mode on screen. The layout does not change.
  • Preview workspace draws the offered layout as a diagram, at a laptop-sized window. Nothing changes.
  • Apply workspace sits under the preview. It replaces the layout as one layout-history step and turns the custom workspace on.
  • Return to previous layout puts back the arrangement the first applied pack workspace replaced, including whether the custom workspace was on. Display ▸ Workspace ▸ Undo layout also works.

The same two actions are shell commands (ShellCommand::ApplyPackWorkspace, ReturnToPreviousLayout; in the browser shell_command with {"type":"applyPackWorkspace","skin":…} / {"type":"returnToPreviousLayout"}), which the browser qualification harness drives.

A pack's skin may also carry "recommendedInteraction": gesture preferences it suggests. Like the workspace, it is only offered (Display ▸ Interaction, Use / Ignore), never applied by installing or selecting the skin (Interaction preferences).

The Appearance inspector#

For the appearance on screen, the inspector lists:

  • Assets. Each distinct image: its ID, size in texels, encoded bytes, decoded charge, and whether it is GPU-resident now. The heading shows the total against the 64 MiB residency budget.
  • Decoration slots. Each filled slot with its asset, placement (nine-slice or the fit) and opacity.
  • Materials. Each surface with a layer stack: the layer count, the baked tile's size, its settled opacity (and the authored one, if the check lowered it), the policy the final-composite check chose (direct, plate with its alpha, or lowered), the composite's luminance envelope and the reason. Two swatches follow. The first is the baked tile alone, repeating at its own scale, so a seam or a busy period shows. The second is the surface exactly as it paints, plate included. Baked tiles also appear in the asset list as tile:<surface>.
  • Control faces by scope. knob, fader, display, meter and every pane scope that differs. Each shows the face, a fallback recipe or the theme recipe, plus the skin report's warnings for that scope.
  • Control states. For each scope with its own face, the strip shows the control at rest, hover, pressed, focus and disabled. The controls' own painters draw it, so the protected value, focus and disabled layers are included. A built-in shows its recipes instead.

The inventory is read once per theme and skin-folder generation, never per frame.

The agent loop (MCP)#

  1. customization_catalog (optionally one section): everything a pack may name, plus every budget. It covers panes and node shapes, slots, keys, fits, anchors and opacity caps. It covers face kinds, primitives (with an example layer each), state inputs, mapping forms, colour roles, scopes and fallbacks. It also lists capabilities, asset and pack limits and interaction ranges. Its materials section has the layer sources (with an example each), layer and stack keys, colour roles, built-ins with their default colours, blends, wraps, samplings, readings, the limits (8 layers, 16 named materials, 512 px tiles) and the readability policies. Every value is read from the constant its validator enforces. Tests compile each listed item through its real parser.
  2. validate_skin_pack { json, assets?, workspace? } checks the whole pack without writing it. It uses the Import button's path: generated manifest, pack caps, whole-pack check. It returns ok, the refusal errors, the skin report, the generated manifest, each asset (size, bytes, charge, roles, supplied or kept), budgets used against allowed, and the workspace verdict. assets maps a file name to base64 PNG bytes or to { "path": … } inside the server's roots. A declared file the map leaves out is kept from the installed pack of the same name.
  3. preview_skin { json, assets?, workspace?, views?, states? } returns the skin sheet per mode. It adds the control-state sheet (every bound scope in every state) by default when the skin binds a face. With views it also captures real workbench views under the candidate pack and layout. preview_workspace { json | skin | preset, theme?, views? } captures a layout alone.
  4. write_skin_pack { json, assets?, workspace?, expect_hash? } validates again and installs only a clean pack. The folder is written beside the old one and swapped in. The old one moves to .removed/.
  5. read_workspace, validate_workspace and write_workspace handle the offered layout. validate_workspace reports the panes shown and hidden, depth and size against the limits, and the arrangement at narrow, laptop and wide windows. write_workspace re-checks and re-installs the whole pack with a regenerated manifest. It never applies the layout.

Hash contract#

  • read_skin returns hash (of skin.json, for write_skin) and pack_hash. pack_hash is SHA-256 over every installed file's path and SHA-256.
  • Replacing an installed pack needs expect_hash equal to the current pack_hash. Replacing an offered workspace needs the hash read_workspace returned. A value this session read or wrote counts.
  • A mismatch is refused. A refused or invalid write changes nothing on disk.

Previews are isolated#

The sheets render offscreen in the server process. Real views come from a volta-shot child process on the bundled bench song. It reads a temporary copy of the skin folder holding the candidate files. A candidate layout is handed over through --state, so it never enters anyone's preferences. The temporary folder is deleted afterwards. A preview does not count as a read for the hash contract. No preview reaches a running Studio's song, layout or command dispatch.

From a checkout, volta-shot --sheet --skin <folder>/skin.json writes sheet-<theme>.png, plus faces-<theme>.png when the skin binds faces.

Prismatic Eden#

ui/tests/fixtures/skins/prismatic-eden/ is the acceptance pack: an original psychedelic-garden workbench.

  • Art. Six PNGs drawn by closed-form functions in ui/tests/prismatic_eden.rs:
    • a nine-slice frame with a vine and prism flowers, in night and day versions;
    • a pane-header band with flowers and a rainbow ribbon;
    • a seamless marbled-ink tile;
    • a rainbow halo under knobs;
    • a faceted gem.
  • Materials. A named eden-ink stack sits behind every pane: the surface fill, the built-in marbled-ink in the skin's own colours, and the marble tile screened over it. Cards take optical-rings at low opacity. Each surface's policy is in the report and the inspector.
  • Faces. prism-petal is bound to macros.knob. Eight petals light in turn as the value rises, round a turning gem. stem is bound to mixer.fader: a rainbow stem with a bud cap.
  • Modes and workspace. Dark and light modes. The offered Eden workspace puts Macros on the left, Source and a Timeline/Rack/Scopes tab group in the middle, and the Mixer beneath.

Both modes load with no errors and no warnings. The test re-generates the art and manifest byte for byte, imports and re-exports the pack byte-identically, and drives the inspector and the Apply split in the real workbench.

Limits#

  • The inspector reads; it does not edit. JSON stays the editing surface. Validation is instant through the tools, and the real-view previews show the result.
  • A screenshot and a zero-warning load prove composition and admission, not taste or readability.