first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,210 @@
# @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`.
<!-- begin:auto-docs -->
## Documentation tree
- [constants](./src/constants/constants.md) — The constants module owns the single source of truth for the current schema version of `@suaveplan/control-surface-sche…
- [constants](./src/constants/constants.md) — The constants module owns the single source of truth for the current schema version of `@suaveplan/control-surface-sche…
- [error-codes](./src/error-codes/error-codes.md) — This module owns the stable error-code registry for `@suaveplan/control-surface-schema`. Every entrypoint of the packag…
- [error-codes](./src/error-codes/error-codes.md) — This module owns the stable error-code registry for `@suaveplan/control-surface-schema`. Every entrypoint of the packag…
- [identity](./src/identity/identity.md) — The identity module owns the structural cross-checks that run after a candidate surface passes its Zod parse: duplicate…
- [identity](./src/identity/identity.md) — The identity module owns the structural cross-checks that run after a candidate surface passes its Zod parse: duplicate…
- [schemas](./src/schemas/control-surface-schema.md) — This module owns the Zod schemas that mirror every TypeScript type in the package: `TransformSchema`, `BindingSchema`,…
- [control-surface-schema](./src/schemas/control-surface-schema.md) — This module owns the Zod schemas that mirror every TypeScript type in the package: `TransformSchema`, `BindingSchema`,…
- [upgrade](./src/upgrade/upgrade.md) — This module owns `upgradeSurface` and the `MigrationRegistry` chain that walks an older schema-version document forward…
- [upgrade](./src/upgrade/upgrade.md) — This module owns `upgradeSurface` and the `MigrationRegistry` chain that walks an older schema-version document forward…
- [validate](./src/validate/validate.md) — This module exports `validateSurface` — the canonical entrypoint for parsing and structurally cross-validating a `Contr…
- [validate](./src/validate/validate.md) — This module exports `validateSurface` — the canonical entrypoint for parsing and structurally cross-validating a `Contr…
- [walk](./src/walk/walk.md) — This module exports `walkSurface` — the canonical depth-first traversal helper for `ControlSurface` documents. Every cr…
- [walk](./src/walk/walk.md) — This module exports `walkSurface` — the canonical depth-first traversal helper for `ControlSurface` documents. Every cr…
<!-- end:auto-docs -->
## Install
```bash
bun add @suaveplan/control-surface-schema
```
## Quick start
```ts
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
```text
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)
```ts
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)
```ts
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)
```ts
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)
```ts
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
- [Constants](./src/constants.md) — `CURRENT_SCHEMA_VERSION`.
- [Error codes](./src/error-codes.md) — `CONTROL_SURFACE_SCHEMA_CODES`, `SchemaError`.
- [Transform types](./src/types/transform.md)
- [Binding types](./src/types/binding.md)
- [Range types](./src/types/range.md)
- [Action types](./src/types/action.md)
- [Behaviour types](./src/types/behaviour.md)
- [Appearance types](./src/types/appearance.md)
- [Control-kind types](./src/types/control-kind.md)
- [Group-layout types](./src/types/group-layout.md)
- [Control-node types](./src/types/control-node.md)
- [Control-surface types](./src/types/control-surface.md)
- [Validate](./src/validate/validate.md)
- [Upgrade](./src/upgrade/upgrade.md)
- [Walk](./src/walk/walk.md)
- [Identity](./src/identity/identity.md)