All tutorials
Tab 4 of 6 · Skin

Bind exported strips to plugin parameters as one skin.json

The Skin tab assembles a multi-control skin.json manifest that binds several already-exported filmstrip PNGs to plugin parameters for a whole GUI. It doesn't render any pixels — it references strips you already exported from the Create or Batch tab, reads their dimensions to prefill fields, and writes the JSON.

Skin-level metadata

Fields describing the whole skin, not any one control. These become the top-level properties of the exported skin.json.

  • Name — the skin's name, default My Skin. Free text; also sanitized (invalid filename characters replaced with underscores) to produce the output file name.
  • Author (optional) — free text, blank by default. Passed straight through to the manifest as typed.
  • Base width — the design resolution (in pixels) that per-control bounds are authored against. Default 80, range 1–8192. Auto-seeded from the first control's frame width when you add your first control, but freely editable afterward.
  • Base height — same as Base width, for height. Default 80, range 1–8192. Auto-seeded from the first control's frame height.
  • Window background (optional) — a relative file name, blank by default. Type it directly, or click the ... button to open the standard image picker, which fills the field with just the picked file's name. Left blank, it's omitted from the manifest entirely rather than written as an empty string.

Controls list

The list of control bindings that becomes skin.json's controls[] array, plus the commands to add and remove entries.

  • Controls list — each row displays as {Id} · {Type} · {ParameterId}, e.g. cutoff · RotaryKnob · param. Selecting a row loads it into the detail editor on the right and enables Remove selected.
  • Add from strip… — opens the image picker, then runs the same strip-layout detector used on the Import tab against the chosen file. Auto-fills Id, Parameter id, Type, Asset, Frames, Frame W/H, and Stack direction from the detection result, and sets Bounds W/H to the detected frame size. Shows an error status if the image fails to load.
  • Add blank — adds a new control using its class defaults (Id control, Type RotaryKnob, Parameter id param, Frames 64, Frame W/H 80, Stack Vertical, Bounds W/H 80) for you to fill in manually.
  • Remove selected — disabled until a control is selected. Removes the selected entry and re-selects a neighboring one (or none, if the list is now empty).

Per-control editor — Control

Shown only when a control is selected; otherwise the right panel reads "Select or add a control to edit it." Edits the selected control's identity fields.

  • Id — free text, default control on a blank control. Falls back to the literal string control on export if left blank. Also used as the fallback for Parameter id if that field is blank.
  • Type — a dropdown listing RotaryKnob, VerticalFader, HorizontalSlider, Meter, Button, and Toggle, default RotaryKnob. On export these map to the lower-case manifest strings knob, vfader, hslider, meter, button, and toggle respectively.
  • Parameter id — free text, default param. The host/plugin parameter identifier (e.g. an APVTS id in a JUCE plugin) that the control reads and writes at runtime.

Per-control editor — Asset

Points the control at the actual strip PNG file(s) and describes that strip's frame geometry.

  • Strip file (1x, relative) — a relative file name, e.g. cutoff_64frames.png, blank by default. This is a text field, not a file picker — type the exact name of a strip already exported from Create or Batch.
  • @2x file (optional) — a relative file name for the HiDPI variant, e.g. cutoff_64frames@2x.png, blank by default. Omitted from the manifest if left blank.
  • Frames — the number of frames in the strip, default 64, range 1–512. Clamped to at least 1 on export regardless of what's typed.
  • Frame W — the pixel width of one frame cell, default 80, range 1–8192. Clamped to at least 1 on export.
  • Frame H — the pixel height of one frame cell, default 80, range 1–8192. Clamped to at least 1 on export.
  • Stack direction — Vertical or Horizontal, default Vertical. Describes whether the strip's frames run top-to-bottom or left-to-right; serializes as vertical or horizontal.

Per-control editor — Bounds (base-resolution px)

The on-screen placement rectangle for this control within the skin's overall design canvas (the Base width/Base height set at skin level).

  • X — left-edge position in base-resolution pixels, default 0.0. No minimum or maximum, so negative values are allowed.
  • Y — top-edge position in base-resolution pixels, default 0.0. No minimum or maximum, so negative values are allowed.
  • W — width of the on-screen rectangle, default 80.0 (or the detected frame width, when added from a strip). Minimum 0; clamped to at least 0 on export.
  • H — height of the on-screen rectangle, default 80.0 (or the detected frame height, when added from a strip). Minimum 0; clamped to at least 0 on export.

Per-control editor — Value range (optional)

A collapsible section that maps the control's on-screen sweep to the parameter's numeric range for the host.

  • Min — blank by default (the "0" shown is placeholder watermark text, not a value). Left blank or non-numeric, it's omitted from the manifest rather than defaulting to 0.
  • Max — blank by default (watermark "1"). Same optional parse-or-omit behavior as Min.
  • Default — blank by default (watermark "0.5"). Same optional parse-or-omit behavior as Min.

Export

Finalizes the manifest and writes it to disk, plus the running status line shared by every command in this tab.

  • Status line — reports the outcome of the last action: add-from-strip success, failure, or ambiguous-detection warning; add-blank; or export success/failure.
  • Export skin.json… — disabled until at least one control is in the list. Opens a folder picker, then writes <sanitized Name>.skin.json into the chosen folder. On success the status line reports the control count and file name; on failure it shows the error message.
Tip: The Type dropdown's on-screen order (RotaryKnob, VerticalFader, HorizontalSlider, Meter, Button, Toggle) doesn't match the exported strings — they map to knob, vfader, hslider, meter, button, and toggle respectively. If you're matching a manifest against loader code by hand, work from the lower-case strings, not the dropdown order.
Tip: Id and Parameter id are independent fields that are never auto-synced after you edit them separately — if you rename one, check the other. Likewise, only the very first control you add seeds the skin-level Base width/Base height from its frame size; adding a second, differently-sized control won't re-seed those fields, so set them by hand if your controls vary in size.
Tip: "Add from strip…" can mis-detect an ambiguous strip's frame count — if the status message warns the detection is low-confidence, double-check Frames, Frame W, and Frame H manually before exporting. Also note that Asset and @2x file are typed by hand, not chosen with a file picker, so a typo won't be caught until the manifest fails to load at runtime.
Tip: Exporting always overwrites any existing file of the same name in the target folder with no confirmation prompt, so double-check the Name field before re-exporting into the same folder. Also, this tab has no UI for grid/sprite layout, per-control background, or skin version, even though the manifest schema supports them — controls added here always export as a plain (non-grid) strip with no per-control background.