Templates
Create a template from scratch
Build a Universal Controller MIDI template from an empty schema. Covers required fields, validation, and how to drop the file into your library.
Updated
Sometimes none of the 48 bundled mappings fit and customising one of them feels like fighting the file. Building a template from scratch is roughly ten minutes of typing, one validation pass, and a hot-reload. The schema is small and forgiving — you'll spend more time deciding what notes to use than wrestling the file format.
The minimum viable template
Every field on the schema has a default, so the smallest valid file is shorter than you'd expect. Save the JSON below as My Template.json in your user library folder and the app picks it up on next load. No buttons, no axes, but it loads — and you can wire it up in the UI from there.
{
"name": "My Template",
"schema_version": 2,
"midi_channel": 0,
"deadzone": 0.05,
"poll_hz": 100,
"buttons": {},
"axes": {},
"hats": {}
} Drop the file into Settings → Reveal library while the app is running. Templates hot-reload — no restart needed. The status strip flashes green for a successful load, red with a message for a validation failure.
Field-by-field reference
Here's every top-level field, its type, and whether it's required. Use this as your scaffolding checklist:
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | Shown in the dropdown; under 50 chars |
schema_version | integer | yes | Must be 2 right now |
midi_channel | 0–15 | no | Defaults to 0 |
deadzone | 0.0–1.0 | no | Defaults to 0.05 |
poll_hz | 30–250 | no | Defaults to 100 |
buttons | object | no | String-indexed button to MIDI note |
axes | object | no | String-indexed axis to MIDI CC |
hats | object | no | Named D-pad directions to MIDI notes |
left_stick_corners | object | no | Defaults to enabled: false |
right_stick_corners | object | no | Same shape as left |
touchpad | object | no | enabled + x_cc + y_cc |
osc | object | no | Routes axes/buttons to OSC instead of MIDI |
l2_haptic_effect | string|null | no | PS5 only |
r2_haptic_effect | string|null | no | PS5 only |
Filling in the meat
Work in this order to avoid getting lost:
- Buttons — keys are controller button indices (
"0"through"16"), values are MIDI note numbers0–127. - Axes — same shape but values are MIDI CC numbers. Sticks and triggers route through this.
- Hats — D-pad. Four named keys:
up,down,left,right. - Stick corners — only if you want note grids from sticks (see stick corners).
- Touchpad / OSC / Haptics — optional sections. Set
enabled: falseif unused.
A complete-but-minimal mapping that actually does something interesting:
{
"name": "Snare Roll Special",
"schema_version": 2,
"midi_channel": 1,
"deadzone": 0.04,
"poll_hz": 150,
"buttons": { "0": 38, "1": 40, "2": 42, "3": 44 },
"axes": { "4": 1, "5": 11 },
"hats": { "up": 78, "down": 79, "left": 80, "right": 81 },
"left_stick_corners": {
"enabled": true,
"n": 4,
"notes": [60, 64, 67, 72],
"r_enter": 0.9,
"r_exit": 0.7
},
"l2_haptic_effect": "trigger_click",
"r2_haptic_effect": null
} Validation
The app validates on load and surfaces errors in the bottom status strip. The common ones:
schema_versionmissing or not2— template ignored.- MIDI note out of range — clamped silently to
0–127, but you'll see a warning. - Duplicate
name— second one wins; rename to avoid surprises. - Invalid JSON — the template is skipped entirely; the rest of your library still loads.
JSON keys are strings even when they look like numbers. { "buttons": {0: 36} } is invalid — it must be { "buttons": { "0": 36 } }. Quote everything.
The schema is intentionally flat. No nesting beyond one level, no inheritance, no conditional layers. Flat schemas are easy to diff, easy to migrate, easy to validate. The trade-off — you can't share fragments between templates — is worth paying.
Real-world template patterns
- Drum kit starter — 16 entries in
buttonsmapped to GM drum notes 36–51, no axes, no corners. Done in five minutes. - Pure-CC controller — empty
buttons, 8 entries inaxestied to your favourite plugin's CCs. Hands stay on the sticks. - Single-stick melody — left stick corners at
n: 16with a chromatic octave, everything else disabled. Maximalist minimalism. - OSC-only template — empty MIDI sections, the
oscblock does all the work. Great for lighting consoles. - Hybrid podcast rig — face buttons fire stingers, touchpad is mic-mute toggle, sticks are ducker/EQ CCs.
Ship it
Happy with the mapping? Either keep it local, or share to the marketplace so the next person doesn't have to reinvent it. Need to fold in an existing controller export first? See import a .tsi file.