DSL Inspector
The DSL Inspector is a built-in browser-side authoring tool that lets you add, edit, and remove cue behaviour directly in the running score — without leaving the browser or editing SVG files by hand. Changes are written back to score.svg immediately.
It is the recommended way to author cues during the composition and testing phase.
Enabling the Inspector
Click the pencil icon (✏) in the top bar to toggle the inspector on and off.
When active:
- hovering over SVG elements shows a tooltip with their current cue DSL
- clicking an element opens the editor panel
Closing the editor panel (×, Cancel) also switches inspector mode off — the topbar icon unhighlights and normal score interaction resumes. Creating an object with the + tool switches it on.
Inspecting Elements
With the inspector on, hover over any SVG element to see its cue definition in a tooltip:
data-oscilla="rotate(dur:2, uid:myShape, trig:auto)"
Elements with no cue show no tooltip. Elements with cues show the full DSL string.
Editing an Existing Cue
Click any element that has a cue to open the editor panel on the right side of the screen.
A group is a region: clicking anywhere inside a group's bounding box — between its members, on empty space — targets the group itself, the innermost one when groups nest, with its ancestors offered in the target breadcrumb. An element you actually click still wins over any group whose box happens to overlap it. Layers, and any group whose box covers the whole view (a page-colour rect inside a title group makes that group's box the entire score), never count as click regions; reach those through a member or the breadcrumb.
The panel shows one cue block for each cue on the element (most elements have one). Each block contains:
- labelled form fields for every parameter currently set on the cue
- an Add param dropdown — selecting a parameter adds its field immediately. Object-literal params (
env,filter,delay,reverb) arrive prepopulated with a working template (e.g.{a:0.02, d:0, s:1, r:0.1}) so you edit values instead of typing the structure - a × remove button to remove that cue entirely
If an element's DSL fails to parse (a typo, an unbalanced paren), the panel still opens — the broken expression appears as an ⚠ unparsed DSL block: a raw text editor with live parse feedback, saved back verbatim. Nothing is lost, and once fixed it reopens as normal fields.
The live preview at the bottom of the panel shows the serialized DSL as you type — it updates with every keystroke.
Click Save to SVG to write the change to score.svg. The change takes effect immediately in the browser (the animation restarts) without a full page reload.
Adding a Cue to a Plain Element
Click any SVG element that does not already have a cue (it must have an id attribute). The panel opens in Add Cue mode:
- Type in the search box to filter cue types
- Click a cue type to open its parameter form
- Fill in the required parameters
- Click Save to SVG
The element's id is used as the cue's uid. The cue is stored in a data-oscilla attribute (not in the id itself), so the element keeps its original identifier.
New audio cues default to trig:playhead. Primary-source fields — src (audio), path (audioPool / audioImpulse), file (video) — are always visible in the form, even while empty, so they can't disappear from a saved cue that lacks them.
Favourites — your own presets
Any cue you have tuned can be kept as a favourite: press ☆ favourite in
its block header, give it a name, Enter. From then on + Add cue offers it
as a chip above the cue-type list, on any element in any project; one click
applies it exactly as picking a cue type does (a uid is assigned from the
element, and a propagate() favourite gets fresh member uids each time).
× on a chip forgets it.
Favourites live in a plain text file beside your projects,
~/oscilla-projects/dsl-favourites.txt (wherever your projects folder is),
one per line:
# Oscilla favourite cues — one per line, "name: dsl"
breathe: propagate(scale(values:[1,${1}], dur:${2}, mode:alternate, trig:playhead, uid:br), rnd(0.6, 1.6), rnd(0.8, 2.5))
fade in: fade(from:0, to:1, dur:4, trig:playhead)
pause(dur:4, count:true)
Edit it by hand as freely as with the button: the name is everything before
the first colon, the DSL everything after; a line with no name is named after
its cue; # starts a comment. Saving a favourite under an existing name
replaces that line. A project can also carry its own dsl-favourites.txt,
which the picker shows alongside (read-only from the GUI) — handy for the cues
a particular piece is built from.
Creating Score Objects — the "+" Tool
The + button in the top bar (next to the inspector icon) creates new SVG elements directly on the score — no Inkscape round-trip needed for a quick trigger box or label.
- Click + — the button highlights and the cursor becomes a crosshair (press Esc or click + again to cancel)
- Click anywhere on the score — it doesn't matter what's under the click: background images, page rects, and empty canvas all work
- The Create Element panel opens with the click point pre-filled:
- rect / ellipse:
x,y,width,height(default 10×10) and a fill color - text: the text content, font family, font size, and color
- rehearsal / notes: a mark letter or note text — score furniture, not cues
- mic: an audio input source, drawn as a small microphone (see below)
- rect / ellipse:
- Click Create
The element appears immediately, is appended to score.svg, and draws above all existing layers. It gets a unique plain id (rect-k3j9ab1-style), and the panel drops straight into Add Cue mode so you can attach behaviour right away. Creating also switches the inspector on, so the new object stays clickable for further editing.
The placement point is clamped into the score's viewBox, so a click outside the rendered band still produces a visible element.
The mic object
mic is not a shape — it is an adc() cue with a drawing, so
placing one gives the score an ear. It writes an element whose id is the cue:
adc(uid:adc)
The fields are that cue's parameters:
| Field | What it does |
|---|---|
| uid | the name the rest of the score binds to — follow(adc.amp, …) |
| channel | mix (mono, or both channels summed), left, or right |
| size | height in score units; the drawing scales to it |
| colour | the microphone's colour |
| hidden | still listens, but is not drawn |
Because it is a real element rather than an invisible system source, it appears in the
connections view as an object with its ten outlets, and cords
run from it like any other. A hidden mic still has a position and a size, so it still
has somewhere to anchor those cords — which is why hiding uses visibility, not
display:none.
For a stereo pair, place two: one ch: left with uid left, one ch: right with uid
right. They share a single microphone permission prompt between them.
Inkscape warning: the element is written to
score.svgon disk. If the score is open in Inkscape at the time, do File → Revert there before saving from Inkscape, or its next save will overwrite the new element.
Editing Object Geometry & Appearance
Clicking a rect, ellipse, circle, text, line, or image element (with a plain id) shows an Object section at the bottom of the editor panel — in both the cue editor and Add Cue modes. It edits the element itself, independent of its cues:
- position and dimensions (
x/y/width/height, or the shape's equivalents) fill(orstrokefor lines) — a color picker when the current value is a hex color- for
<text>: font size, font family, and the text content itself (single-run text only — texts containing tspans are left alone)
Changes apply live as you type. Click Apply object to SVG to persist them — the element's attributes are patched in place in score.svg, leaving its data-oscilla and everything else untouched. The same Inkscape File → Revert caveat applies.
Composite Cues — Multiple Cues per Element
An element can carry more than one cue. For example: an audio trigger that also behaves as a draggable panel, or a shape that both fades and sends an OSC message.
To add a second cue to an element that already has one:
- Click the element to open its editor
- Click + Add cue (visible below the cue blocks, always in view)
- Search for and select the new cue type
- The new cue is placed in a wrapper
<g>element that Oscilla creates automatically around the original element inscore.svg
Each cue lives on its own element so that transform operations (scale, rotate, o2p) do not conflict with each other. The panel shows all ancestor cues together, labelled with the element they live on:
rotate() · myShape-rotate-a3f1 ← lives on the wrapper <g>
scale() ← lives on the original element
When you click Save to SVG, each cue is written to its correct element.
Cue Types
The page cue is edited as its pattern (intro, or Pseq([pageA:5, pageB:5], 1) …) plus an optional after action, with the pattern written first and bare, the way the parser expects it.
The inspector supports all standard cue types. Use the Add Cue search to see the full list:
| Category | Cues |
|---|---|
| Animation | rotate, scale, fade, color, o2p |
| Audio | audio, audioPool, audioImpulse |
| Media | video, synth, osc, midi, metro |
| Text & nav | text, nav, page, ui, ext |
| Transport | pause, speed, stopwatch, pin |
| Interaction | drag, button |
| Marks | draw |
The audio-family schemas match the session-layer audio object editor: speed, pan, and amp accept rand() / birand() / pattern expressions, and filter / delay / reverb take object literals — see audio shared features.
The speed cue exposes both of its runtime forms (value, uid, loop, dur, add, revtrig) and the editor writes the right one automatically: setting dur or add saves the keyed trigger/ramp form, otherwise the positional marker form the position watcher expects — see speed(). Saving rebuilds the speed watcher map immediately, so marker edits apply without a reload.
Audio & Video File Upload
The audio cue's src field and the video cue's file field each have
a Browse… button. Clicking it opens a file picker; the selected file is
uploaded to the project's audio/ or video/ folder and the filename is
filled in automatically (WAV uploads are transcoded to FLAC when ffmpeg is
available).
If a file with the same name already exists in the project, no duplicate is made — the field is pointed at the existing project file.
Supported formats — audio: .flac, .wav, .ogg, .mp3, .aif ·
video: .mp4, .webm, .ogg, .mov, .m4v
Removing Cues
- × remove on an individual cue block: removes that cue from
_allCues(saves on next Save to SVG) - Remove all: clears
data-oscillafrom the element and all its ancestor wrappers immediately
Freeze Animations
The snowflake icon (❄) in the top bar freezes all running animations in place. This makes it easy to click on animated elements that would otherwise be moving. Click again to unfreeze and restart all animations.
A freeze is a state, not a snapshot: an animation that starts while the
freeze is on — a page opening with a trig:auto cue, the playhead reaching a
cluster — is held with the rest and released with them.
Fader Preset Panel
The fader icon in the top bar opens the Fader Presets panel. This lets you place pre-built o2p fader groups (horizontal or vertical, in counts of 1–24) directly into the score by clicking a placement point.
Placed faders are inserted into score.svg and visible immediately. Reload the score to activate their o2p cues.
Extent Handle
Audio-family cues (audio, audioPool, audioImpulse, synth) can extend their active trigger region past the element with the extent parameter — see extent.
While inspector mode is on, the extent line's end bar in the score is draggable directly — resizing applies live and persists to score.svg on release, without opening the editor panel. Dragging it back to the element's right edge clears the extent (plain bounding-box mode).
With the editor panel open, a grip above the element does the same, and the extent (score units) field can be typed; Save to SVG persists it. The line itself is saved into score.svg as a real element, so the region marking survives outside the app (Inkscape, exports, print).
Page Buttons
The button cue's trigger field holds a whole cue — the one the button
fires. Beside it an open page… dropdown lists the project's pages; picking
one writes page(<name>) into the field, so a shape that opens a page is one
click: add button, choose the page, save. The chips under the field give the
other common triggers — nav(scroll) and nav(scrollPaused@A) to come back
to the score, pause(4), audio(src:…).
mode defaults to overlay, which keeps the shape you drew and lays an
invisible hit area over it. Clear it to get an HTML button in place of the
shape, styled by the style(…) field. See button().
Path Pick Mode
The o2p cue's path parameter has a pick button. When active, the next SVG element you click has its id inserted into the path field. This avoids having to type element ids by hand.
Waypoint Pick Mode
The trans cue's to field has a click score button. Arm it and every
click on the score appends a waypoint to the list — [x, y] in the edited
element's own coordinates, the same frame trans() measures against, so a
click lands the element's centre exactly where you pointed. Shift+click
appends the clicked element's id instead of coordinates. Each pick drops a
numbered marker on the score so the route is visible while you work; the
markers are view-only and vanish when the panel closes. Press Esc or the
button (now reading done) to finish; the list stays editable by hand.
Coordinate Readout
While the inspector is active, a small chip in the bottom corner shows the
score coordinates under the mouse (SVG user units — the same units used
for [x, y] waypoints in trans(to:…) and for object geometry):
x 4700 · y 100 click = copy · alt+click score = insert
- Click the chip to copy
[x, y]to the clipboard - Alt+click anywhere on the score to insert
[x, y]directly into the last text field you focused in the editor panel — clicking at the end of an existing list like[t-b1]tucks the pair inside it:[t-b1, [4700, 100]]
The readout tracks zoom and scroll, so what you see is always the authored coordinate you would type.
How Changes Are Saved
The inspector writes directly to score.svg on disk via the server API. There is no separate save step — Save to SVG is the save.
The file watcher is suppressed for 10 seconds after each save so the page does not auto-reload. Animations restart immediately using the new parameters, and saved cues are (re)registered with the playhead trigger system live — a newly added trig:playhead cue arms without a reload.
If you are working in local folder mode (File System Access API), changes are written to the locally-opened score.svg instead of the server. A project that exists on the server (in the projects folder) always loads from the server — a remembered local folder with the same name is released automatically, so edits made in Inkscape to the served copy are never shadowed by a stale duplicate elsewhere.
In page mode the edits go to the page's own file, pages/<id>.svg, not to
score.svg: the editor names the file with every write, and the server
refuses any name that is not a page or score file of the project.
Keyboard and Interaction Notes
- The inspector intercepts
pointerdownevents in capture mode so it fires before drag overlays - Animated elements with hit-label overlays are still clickable — the inspector searches the full element stack under the cursor
- The inspector panel does not block OSC or WebSocket messages while open
Tip: use ← → or ↑ ↓ to navigate the docs