Seeing the connections
A score can have one element driving another all over it — a fader setting a synth's pitch, a rotation setting another rotation's speed, a moving bar firing a cue as it passes. Written down, each of those is a few characters inside an element's id, scattered across thousands of units of score. The connections view draws them, and lets you make and break them.
The button is in the topbar, between reset-animations and the live console. Escape closes it.
The demo-connections demo (Demos → Control & I/O) is built to be read with it
open.
What you see
Every object that can take part in a connection gets a dashed frame with its ports on the edges — inlets on the left, outlets on the right — and a cord for every connection that exists. Cords can be clicked to select, and a selected cord can be deleted.
| solid cord | a signal: a value that follows, from a follow() |
| dashed cord | a trigger: an event, from trig:<uid> |
| dotted red cord | a reference that resolves to nothing, drawn dangling |
| filled port | something is connected here |
| hollow port | free — nothing is using it yet |
The cord carries what neither port shows: the range and curve of the mapping. On a long cord it also carries the source's name, so one arriving from off the side of the screen still says where it came from.
Cords do run off screen. A score is thousands of units wide and its objects are where the music puts them, not where a patcher would; scrolling to follow a cord is how you read it.
Hover a port for its name
Port names are shown on hover rather than all at once — a score of any size has far more ports than could be labelled legibly, and most of them are possibilities rather than facts. Hovering gives the full name and what the signal carries:
r1.angle — degrees, 0-360 (free)
prog.t — how far along the path, 0-1
Everything else in the view ignores the mouse, so objects underneath stay draggable while it is open.
Free ports are the useful part
The view shows every port each kind of cue could use, not only the ones your score does. Opening it on a score with no bindings at all still shows what is available to connect — which is usually the question worth asking.
A rotate() publishes angle, rad and norm, and takes a dur. An o2p()
publishes t, x, y, angle and p. A trans() publishes t, legT,
x and y. A synth() takes freq, amp, pan, cutoff and q. An
image() publishes index and t, and takes an index to pick its plate by.
A metro() publishes beat, phase and bar; a drag() publishes x and y.
A video() publishes time and t, and takes opacity and speed. A named
stopwatch() publishes elapsed, t and remaining; a fade() publishes
opacity and samples from, to and dur. The score's own playhead is a
source too, with no cue to declare: follow(transport.t, …) works anywhere.
Anything that moves can also fire a cue it passes over, and anything at all can
be fired by one.
To use a free port, write it into the score as a
follow() — or map(), which is
the same thing with the input range spelled out, for when a source is too slow
or too narrow to move the parameter on its own:
synth(uid:pad, freq: follow(fader.t, 90, 2000))
Making a connection
Drag from an outlet to an inlet. While you drag, every port that could receive
the cord is lit — a signal outlet can only land on a parameter, and a fires
outlet only on another object's fires inlet.
On drop, the connection is written into the score: the target cue gains a
follow(), saved the same way any edit in the DSL editor is saved. It is part of
the score from that moment, not something the view remembers. Dropping on an
inlet that is already driven replaces what was there — a parameter follows one
source. Dropping on empty space cancels.
drag r1.angle ──▶ sOsc.cutoff
synth(uid:sOsc, …, cutoff:follow(r1.angle))
Both ends must be on screen to drag between them, since you drop on what you
can see. On a wide score, that means arranging the view first — or writing the
follow() by hand, which is the same thing.
Removing a connection
Click a cord to select it — it thickens and takes a halo in its own colour — then press Delete or Backspace. Escape deselects without deleting, and clicking anywhere else drops the selection too.
Deleting is the mirror of making one: the parameter is removed from the score.
A signal cord takes its follow() with it, and the parameter goes back to
whatever the cue does on its own. A trigger cord takes the trig:, which hands
the cue back to the playhead.
What it cannot do is remember what was there before the connection. If a cue
read trig:auto and you dragged a cord onto it, deleting that cord leaves the
cue with no trig: at all, not with trig:auto again. Delete removes a
connection; it does not undo an edit.
It stops the transport
Opening the view pauses playback, and the button stays lit to say so.
The cords are drawn to where things are. In a running score the targets are rotating, translating and scrolling all at once, so a cord would have to be redrawn every frame against something that is itself moving. Stopping removes that problem rather than solving it — and a stopped score is the right state for reading wiring anyway. Closing the view resumes playback if it was running.
Objects that travel — a trans() bar, an o2p() dot — are framed at their
home position in the score, not wherever they had got to when you opened
the view. Otherwise a cord would flow left-to-right one moment and
right-to-left the next, and the patch would appear to change direction as you
read it.
Broken connections are visible
A reference that names something which does not exist is drawn as a dotted red cord ending in an open ring, labelled with what it was looking for. The same thing is reported in the console when the score loads:
[refs] 2 unresolved references, 1 suspect — these do nothing at all
✗ trig:<uid> — object trigger source: "nosuchthing" matches no element
in: synth(uid:sBad, …, trig:nosuchthing)
? signal binding source: "fx.tt" — unknown channel ".tt"
The second kind is worth knowing about: the source exists but the channel is misspelt, so the binding subscribes to something nothing ever writes. Before this, both failed in complete silence — the score loaded cleanly and simply did less than it should.
Tip: use ← → or ↑ ↓ to navigate the docs