Action Editor
An action's steps can be edited two ways: as raw DSL text in the Code tab of the action's detail view, or in the pop-out Step Editor, a wider window with structured per-step forms, an address picker, and value pickers driven by the canonical mapping.
The Code tab suits quick edits and reading existing actions. For anything multi-step, the pop-out Step Editor is what you want.
The Code tab
The action's detail view has two tabs along the top: Notes (metadata) and Code (steps as DSL text). Switch to Code to see and edit the action's body.
The tab is a single text area:
- Monospace font, sized for ~16 lines of step text.
- Saves on blur: click out of the field, or press Tab.
- Edits in this tab are also visible in the pop-out Step Editor, and vice versa.
Parse errors
Below the text area, any DSL parse errors show in red, one line per error, formatted as Line N: <message>. The text area's border also turns red while errors exist. The Code tab won't save while any error is showing, so the file on disk keeps its last good content. Fix the reported line and click out again.
The same strip reports two problems that are not grammar: a step writing to a control that only reports its value, and a step naming a value the control has no position for. Both refuse the save.
Opening the Step Editor
The pencil icon at the right end of the tab bar (visible only on the Code tab, tooltip "Open Step Editor") opens the pop-out Step Editor window for the same file.
The Step Editor and the Code tab share the underlying .faction, and the Step Editor has its own explicit Save rather than autosaving. Edits made in the Step Editor are written to disk when you click Save in its footer, and show up in the Code tab on the next refresh.
The Step Editor window
The Step Editor is a separate window, 680×552 by default. Its header shows the window title Action Editor, the action's name beside it, an italic "unsaved" marker when there are pending edits, and a close button (X) at the far right.
While the Action Editor is open, the Library is dimmed and does not respond until you close it. Clicking the Library brings the Action Editor back to the front. The Fusor player is not affected.
Below the header is the Short ID field, then a scrollable stack of step cards with an Add step affordance at the bottom, then the footer.
The footer holds the save buttons, laid out as in the Domain Editor:
| Button | What it does |
|---|---|
| Cancel | Appears only while there are unsaved edits. Closes the window without writing. |
| Save | Writes the steps back to the .faction and keeps the window open. Disabled when there's nothing to save, and while the Short ID is invalid. |
| Save & Close | Commits and closes. When there's nothing to save, this button reads Close instead. A refused save does not close the window. |
Closing the window with unsaved edits, with the header's X or the window's own close, asks first: Save, Discard or Keep editing. Opening a different action while this one has unsaved edits asks the same. Cancel discards without asking.
Short ID
The Short ID is what names this action on the status line when it runs, fails, or is skipped: ACT2-Prerun aborted: ResetInEQ. The status line has room for about 40 characters in total, so it can't use the action's full name.
- 1–12 characters: letters, digits, space, dot, underscore, hyphen.
- Required. While it's empty or invalid the field is outlined red and Save is disabled.
- Pick something you would recognize at a glance mid-transition.
A step card
Every step is rendered as a card with one or more labeled field rows. The card header has:
- Type selector, a dropdown that changes the step's type. Switching type replaces the step's payload with a fresh default for that type (see Defaults below).
- Up arrow / Down arrow move the step up or down in the list. Disabled at the ends.
- Trash icon (red) deletes the step.
The fields under the header depend on the step type.
SET
| Field | Notes |
|---|---|
| Address | Grouped address picker. Filtered to writable addresses; telemetry-only addresses do not appear. See Address picker below. |
| Value | Context-aware. See Value input modes below. |
WAIT
| Field | Notes |
|---|---|
| Duration | Number input, milliseconds. |
WAIT_UNTIL
| Field | Notes |
|---|---|
| Address | Grouped address picker, over any address, writable or telemetry. |
| Condition | Operator dropdown (==, !=, >=, <=, >, <) + value input. The value side follows the same rules as a SET value, including the position picker on a control with a fixed number of positions. The operator + value combine into a predicate. |
| Timeout | Milliseconds. If the predicate is not satisfied in time, the action fails. |
CAPTURE
| Field | Notes |
|---|---|
| Name | Snapshot name. Used by a later RESTORE step, in this action or another one, because snapshots are session-scoped. |
| Addresses | Multi-address picker: pick one or more writable addresses to snapshot. |
RESTORE
| Field | Notes |
|---|---|
| Name | Snapshot name. Type a name or pick one from the suggestions, which list every CAPTURE name in this action and in the other actions in your library. When the name matches none of them, the line under the field reads No CAPTURE step in this action or the library uses this name. The warning does not block saving. The library suggestions are read when the editor opens. Referencing a name that was never captured, through a typo, a skipped IF branch, or a pair whose capture half did not run, fails the action at run time. In a fusor's post-run action, only a snapshot captured during the same run counts. |
IF
| Field | Notes |
|---|---|
| Address | Grouped address picker. |
| Condition | Operator + value, same shape as WAIT_UNTIL. |
| THEN | Nested step list (indented). Any step type, including a nested IF. |
| ELSE | Optional nested step list. Add it via + Add ELSE; remove it via the trash icon on the ELSE header. |
Value input modes
The Value field on SET, WAIT_UNTIL, and IF adapts to the address's control type. The Step Editor reads the canonical mapping at load time to pick the right input.
- Controls with a fixed number of positions → a searchable Select of the positions, listed by their readable names (
10%) in ladder order. See Picking a position by name below. - Trigger / Boolean controls, such as transport toggles → a Select dropdown of the address's symbolic names (
ON/OFF). - Other indexed controls, such as FX type → a searchable Select of all symbolic names defined for that address.
- Continuous controls with named points, such as EQ bands with
CUT,UNITY,BOOST→ a Select that lists each named point asName (numeric value), plus a Custom… option. Picking Custom switches to a number input clamped to[0.0, 1.0]with a Named link to return to the symbolic dropdown. - Continuous without named points → number input directly.
- Predicate values (the right-hand side of
WAIT_UNTIL/IFconditions) on any address with no fixed position count → free-form text input with a small dropdown of any symbolic shortcuts defined for the address.
Author symbolically where you can: UNITY survives mapping renumbering and says what it means. Numeric literals are a safe fallback.
Picking a position by name
Some controls have a fixed set of positions rather than a continuous range, and the mapping declares how many. Traktor's tempo range selector is one: fourteen positions, from ±2% to ±100%. For a control like this, the mapping also names the labels the DJ app uses for its positions.
On one of those controls the Value field is a searchable Select of the positions themselves, labeled the way the DJ app labels them (10%), rather than a box to type a number into. The same picker serves both sides of the editor:
- the Value field on a
SETstep, and - the value half of a
WAIT_UNTILorIFcondition. The operator dropdown beside it is unchanged.
The step stores the canonical symbolic name (RANGE_10), and the readable label is worked out for display, so an action stays portable. The label is a name, not a number: 10% is a position, and does not mean a value of 0.10.
When the names are yours: the Position names picker
Some fixed-position controls have names you choose rather than names the DJ app decides. Traktor's Mixer FX selector is one: five slots, and which effect is in each is up to you.
On one of those the Value field is joined by a second dropdown labeled Position names. It lists your step sets that have exactly as many labels as the control has positions, because a set of the wrong size cannot name this ladder. Pick one and the Value list reads out in your names (Flanger); clear it with the × and you are back to the shipped names (REVERB).
You can leave it unset. The shipped names are Traktor's factory slot defaults, which are correct until you rearrange your slots.
The choice is stored on the action rather than on the step, so every step in that action targeting the same address reads the same way, and it survives an edit in the Code tab where a per-step field would not. The step's own value is untouched: it still stores the position.
the position picker ships with automated coverage but has not been driven on the rig. Confirm the Select's labels and its behavior on the predicate side against the running Step Editor (bench S13 items 12-14).
Address picker
The Address field on SET, WAIT_UNTIL, CAPTURE, and IF opens a single popover with every canonical address organized by region:
- Incoming / Outgoing: role-addressed deck controls (see Role addresses).
- Deck A / Deck B / Deck C / Deck D: literal-deck controls.
- FX 1 – FX 4: global FX-unit controls. Units beyond what the active DJ app exposes are labeled unsupported.
- Common: master, crossfader, and other non-deck / non-FX-unit controls.
Each region is collapsible. The region containing the current value is expanded by default; the rest are collapsed with an item-count badge on the right so you can see how much is in each section at a glance. Clicking a region header toggles it.
The search box at the top filters items across every region simultaneously and auto-expands any region with matches. The currently selected item is highlighted blue with a check mark.
Role addresses
The Address picker offers role addresses (deck.incoming.* and deck.outgoing.*) for any deck-scoped control. Authoring against a role address keeps the action portable across decks: the role is resolved to a physical deck when the action runs, and roles swap on transition completion. Pick a literal deck address (deck.a.eq.high) only when you specifically need that physical deck regardless of role.
CAPTURE's multi-address picker
CAPTURE uses a multi-select variant of the same picker. The popover stays open while you pick, so you can add several addresses in one pass; click outside it or press Escape to close it. Each picked address leaves the list and appears as a chip above the popover trigger, labeled with its region: Incoming: EQ High, Deck C: Xfader Assign Left. Remove a chip via its × button.
Adding, reordering, removing
- Add a step. The + Add step affordance at the bottom of the step list adds a new
SETstep with empty address and value. - Add inside an IF branch. Each
IF.thenandIF.elselist has its own + Add step at the bottom. - Change a step's type. Use the Type selector on the step header. The step's payload resets to the default for that type, so your previous fields are not preserved across a type change.
- Reorder. Up / Down arrows on each step card. Disabled when the step is already at the start or end.
- Remove. Trash icon on the step card. Deletion is immediate within the Step Editor, and the change is not persisted until you click Save in the editor's footer.
Defaults when you add a step or change its type
When you add a new step or change a step's type, the Step Editor inserts the type's default payload:
| Type | Default |
|---|---|
SET | empty address, empty value |
WAIT | 100 ms |
WAIT_UNTIL | empty address, predicate == ON, timeout 5000 ms |
CAPTURE | empty name, no addresses |
RESTORE | empty name |
IF | empty address, predicate == ON, one empty SET step in then, no else |
These are starting points; fill in the real values before saving.
Save flow and round-trip
A round-trip looks like:
- Code tab → pencil → Step Editor opens, reads the
.factionfrom disk. - You edit step cards; the "unsaved" marker appears in the header.
- Save → the Step Editor writes the steps back to the file, then notifies the main app.
- The main app re-reads the file so the Code tab and any open fusor's pre-run row show the new content.
The Code tab and the Step Editor are two views of the same file. The Code tab autosaves on blur; the Step Editor saves explicitly. If you edit in both at once, the last save overwrites the other, so work in one at a time.
If the save is refused
Two problems are only caught at save time: a step writing to a control that only reports its value, and a step naming a value the control has no position for. Either one refuses the whole save, so the file on disk keeps its last good content.
The Step Editor shows the refusal in a red strip directly above the footer buttons, prefixed Save refused. The message names the step's address and the value it couldn't use, and lists the values that control does accept.
Nothing else changes. The unsaved marker stays, your edits stay in the window, and Save & Close leaves the window open. The strip stays put while you fix the step, so the list of accepted values is still on screen while you pick from it, and it clears on the next save that goes through.
Where to next
- Action Authoring Overview: the detail view, the Notes tab, and the create / duplicate / delete flow.
- Pack Authoring: group actions into an 8-slot pad-mode pack.
- Pre-run Actions: wire actions into a fusor's pre-run and post-run lists.