Oscilla supports bidirectional control flow: values can enter the system from external OSC sources, internal animations, UI elements, or other cues, and can be routed to any running cue instance.
This enables:
Control is treated as a first-class signal layer, separate from cue triggering and animation scheduling.
Oscilla introduces a shared control plane built from three components:
All control sources (OSC-in, o2p, UI, other cues) converge through the same mechanism.
Each controllable cue instance has a unique uid.
Parameters are addressed as:
cue:<uid>.<param>
Examples:
cue:synthA.ampcue:drone1.freqcue:rotor3.speedControl signals live in a global namespace:
<source>:<id>.<channel>
Examples:
o2p:sliderA.trotate:orb1.angleosc:/fader1These signals may be:
A target is any running cue instance that opts into control.
{
setParam(name, value, meta)
}
Targets are registered by uid when the cue starts, and unregistered on cleanup.
The ParamBus stores and distributes control values.
set(path, value, meta)
get(path, fallback)
subscribe(path, callback) → unsubscribe()
All control updates pass through a single function:
routeControl(uid, param, value, meta)
cue:<uid>.<param>The router does not automatically send OSC to avoid feedback loops.
External OSC control uses a single address:
/oscilla/set <uid> <param> <value>
Any cue that publishes a signal can modulate any other cue parameter.
Examples:
This is intentional and supported, not an accidental side effect.
Because control signals are routable, feedback loops are possible.
Oscilla does not prevent feedback. Instead, it makes it explicit and composable.
By introducing a shared control plane, Oscilla evolves from a trigger-based score system into a dynamic, signal-driven, executable score environment.