Files
skills/docs/media/audio/control-surface-schema/README.md
2026-05-29 08:20:56 +01:00

8.2 KiB

@suaveplan/control-surface-schema - Universal canonical schema for DAW-style control surfaces: ControlSurface root, ControlNode (Group | Control) discriminated union, 18 ControlKind variants, 6 Binding variants, 4 GroupLayout variants, Zod validators, forward migrations, DFS traversal, duplicate-id and binding-reference cross-check. Zero runtime deps beyond error, types, tslib, zod.

Universal canonical schema for DAW-style control surfaces. Owns the ControlSurface root document, the ControlNode = Group | Control discriminated tree, the 18 ControlKind variants, the 6 Binding variants, the 4 GroupLayout variants, and the Zod schemas / validators / forward migrations every renderer reads. Zero runtime dependencies beyond @suaveplan/error, @suaveplan/types, tslib, and zod.

Documentation tree

  • constants — The constants module owns the single source of truth for the current schema version of `@suaveplan/control-surface-sche…
    • constants — The constants module owns the single source of truth for the current schema version of `@suaveplan/control-surface-sche…
  • error-codes — This module owns the stable error-code registry for @suaveplan/control-surface-schema. Every entrypoint of the packag…
    • error-codes — This module owns the stable error-code registry for @suaveplan/control-surface-schema. Every entrypoint of the packag…
  • identity — The identity module owns the structural cross-checks that run after a candidate surface passes its Zod parse: duplicate…
    • identity — The identity module owns the structural cross-checks that run after a candidate surface passes its Zod parse: duplicate…
  • schemas — This module owns the Zod schemas that mirror every TypeScript type in the package: TransformSchema, BindingSchema,…
    • control-surface-schema — This module owns the Zod schemas that mirror every TypeScript type in the package: TransformSchema, BindingSchema,…
  • upgrade — This module owns upgradeSurface and the MigrationRegistry chain that walks an older schema-version document forward…
    • upgrade — This module owns upgradeSurface and the MigrationRegistry chain that walks an older schema-version document forward…
  • validate — This module exports validateSurface — the canonical entrypoint for parsing and structurally cross-validating a `Contr…
    • validate — This module exports validateSurface — the canonical entrypoint for parsing and structurally cross-validating a `Contr…
  • walk — This module exports walkSurface — the canonical depth-first traversal helper for ControlSurface documents. Every cr…
    • walk — This module exports walkSurface — the canonical depth-first traversal helper for ControlSurface documents. Every cr…

Install

bun add @suaveplan/control-surface-schema

Quick start

import {
    CURRENT_SCHEMA_VERSION,
    validateSurface,
    walkSurface,
} from "@suaveplan/control-surface-schema";

const result = validateSurface({
    id: "surface-1",
    name: "Empty",
    version: CURRENT_SCHEMA_VERSION,
    createdAt: Date.now(),
    updatedAt: Date.now(),
    skin: { id: "default" },
    root: {
        type: "group",
        id: "root",
        layout: { kind: "absolute" },
        transform: { position: { x: 0, y: 0 } },
        children: [],
    },
});

if (result.error !== undefined) throw result.error;
walkSurface(result.surface, (node) => console.log(node.id));

Surface document shape

ControlSurface
├── id, name, version, createdAt, updatedAt
├── skin: { id; vars? }
└── root: ControlNode
    ├── Group  { type; id; layout; transform; children[]; label?; collapsible? }
    └── Control { type; id; kind; transform; label?; appearance?; binding?; range?; behaviour? }

The 18 ControlKind literals: knob, slider-v, slider-h, button-momentary, button-latching, switch-2, switch-3, led, digital-display, meter-vu, meter-peak, meter-spectral, xy-pad, jog-wheel, piano-key, drum-pad, text-label, image.

The 6 Binding variants: pluginParam, transport, midiOut, midiIn, dmx, compound (flat-only).

The 4 GroupLayout variants: grid, absolute, stack, free3d — only free3d admits z-axis transforms.

Worked examples

4-pad drum machine (grid layout, drum-pad kind)

const drumMachine = {
    id: "drum-4",
    name: "4-pad",
    version: CURRENT_SCHEMA_VERSION,
    createdAt: 0,
    updatedAt: 0,
    skin: { id: "default" },
    root: {
        type: "group",
        id: "root",
        layout: { kind: "grid", columns: 4, rows: 1, gap: 8 },
        transform: { position: { x: 0, y: 0 } },
        children: Array.from({ length: 4 }, (_, i) => ({
            type: "control",
            id: `pad-${i}`,
            kind: "drum-pad",
            transform: { position: { x: 0, y: 0 } },
            binding: { kind: "midiOut", portId: "out", channel: 9, cc: 60 + i },
        })),
    },
};

8-channel mixer (stack-row of stack-columns)

const mixer = {
    /* … */
    root: {
        type: "group",
        id: "mixer",
        layout: { kind: "stack", direction: "row", gap: 4 },
        transform: { position: { x: 0, y: 0 } },
        children: Array.from({ length: 8 }, (_, ch) => ({
            type: "group",
            id: `ch-${ch}`,
            layout: { kind: "stack", direction: "column", gap: 2 },
            transform: { position: { x: 0, y: 0 } },
            children: [
                {
                    type: "control",
                    id: `ch-${ch}-vol`,
                    kind: "slider-v",
                    transform: { position: { x: 0, y: 0 } },
                    binding: {
                        kind: "pluginParam",
                        pluginId: "mixer",
                        paramPath: `channels/${ch}/volume`,
                        curve: "log",
                    },
                },
            ],
        })),
    },
};

Piano keyboard (absolute layout, piano-key kind)

const piano = {
    /* … */
    root: {
        type: "group",
        id: "keyboard",
        layout: { kind: "absolute" },
        transform: { position: { x: 0, y: 0 } },
        children: Array.from({ length: 88 }, (_, key) => ({
            type: "control",
            id: `key-${21 + key}`,
            kind: "piano-key",
            transform: { position: { x: key * 22, y: 0 } },
            binding: { kind: "midiOut", portId: "out", channel: 0, cc: 21 + key },
        })),
    },
};

Traktor-style DJ surface (3D free layout)

const traktor = {
    /* … */
    root: {
        type: "group",
        id: "deck",
        layout: { kind: "free3d" },
        transform: { position: { x: 0, y: 0 } },
        children: [
            {
                type: "control",
                id: "jog",
                kind: "jog-wheel",
                transform: { position: { x: 0, y: 0, z: 0.1 } },
                binding: { kind: "midiOut", portId: "deck-a", channel: 0, cc: 32 },
            },
        ],
    },
};

Modules