Score

notation(...) — Timepoint Notation

Renders a fragment of staff-based notation directly inside an SVG element. Notes are spaced proportionally in time rather than rhythmically — the horizontal position of each notehead is what matters; durations are conveyed by extent lines, fermatas, and gaps. This style of notation is sometimes called timepoint notation or proportional notation; the same approach underpins works by Brown, Cardew, Lutosławski, and Penderecki.

A notation() cue can fire OSC on click and on playhead-pass, draw glisses between noteheads (including across staves in multi-stave systems), and carry articulations, dynamics, and per-note sample assignments.

For interactive creation and editing in the browser, see Timepoint Notation in the App.


Quick Start

Give an SVG element an id like:

notation(pitches:'~A4 ~C5 ~Eb5 ~G5')

Open in the browser → a treble clef and four noteheads render inside the element's bounding box, evenly spaced.


Syntax

notation(
  pitches:'~Bb3 ~Eb5 ~G4 ~Eb3',
  clef:treble,
  keysig:Eb,
  transp:Bb,
  height:34,
  spacing:22,
  extent:120,
  extentStyle:wavy,
  boxed:1,
  playhead:1,
  click:1,
  osc:/oscilla/notation/myUid/note,
  uid:myUid
)

Parameters

Key Default Description
pitches (required) — Space-separated list of pitches (see Pitch Syntax below)
clef treble treble or bass
keysig — Major key for key signature (e.g. Eb, G, F#); biases enharmonic spelling and renders accidentals
transp C Instrument transposition (e.g. Bb, Eb, F) — input pitches are sounding, the staff shows the written pitch
height 40 Staff height in SVG units
spacing 18 Horizontal gap between noteheads
extent — X-position where the cue's "extent line" ends (sustain bar past the noteheads); also dragable in edit mode
extentStyle block block, thin, dashed, wavy, dottedTrill, arrowed
boxed false Draw a rectangle outline around the whole fragment
boxRadius 0 Rounded corners on the bounding box
boxPadding 6 Padding from staff edges to the box
glisses — Array of gliss objects (see Glisses below)
articulations — Map of { noteIdx: ["staccato","accent",…] } — see Articulations
dynamics — Map of { noteIdx: "mf" } — see Dynamics
playhead (auto) When non-false, the playhead crossing each notehead emits OSC. As of v… playhead-trigger is on by default; the per-note Audio tab in edit mode lets you override per-note or per-stave.
click 1 When non-false, clicking a notehead emits OSC and plays its assigned sample (if any)
osc / oscaddr /oscilla/notation/<uid>/note OSC address; {i} is replaced with note index, {s} with stave index in multi-stave systems
uid (derived from id) Stable identifier used for persistence of edit-mode overrides

Pitch Syntax

~A4         → A above middle C
~Bb3        → B-flat below middle C
~F#5        → F-sharp above the staff
~Db5-31     → Db5, 31 cents flat (microtonal)
~A4+50      → A4, 50 cents sharp (quartertone)
60          → MIDI note number (middle C)

The ~ prefix is the conventional mark for a pitch literal. Cents deviation is appended as +N or -N; the renderer draws the cents value as a small superscript next to the notehead.

Pitches in pitches: are interpreted as sounding pitches — the actual frequency the player should hear. If transp: is set, the staff displays the corresponding written pitch (transposed up or down by the instrument's transposition interval).


OSC Output

Each notehead can emit an OSC trigger. Two sources:

Default address pattern: /oscilla/notation/<uid>/note

Args (single-stave): [noteIndex, midi, freqHz, cents, noteheadStyle, pitchName]

Args (multi-stave): [staveIndex, noteIndex, midi, freqHz, cents, pitchName]

Custom addresses can use {i} (note index) and {s} (stave index) — quote the address when it contains them, oscaddr:'/synth/note/{i}', as bare { is not part of the DSL's address token placeholders:

notation(pitches:'~C4 ~D4 ~E4', oscaddr:'/synth/note/{i}')

To enable / disable click and playhead triggers per-note or per-stave, use the Audio tab in the edit-mode popup (see Timepoint Notation in the App).


Glisses

Glisses (portamenti, slides, trill lines, custom contour lines) connect two noteheads, or a notehead to a free-floating point. Persistence is tied to uid; in edit mode, shift-drag from a notehead to draw one.

Authored DSL form:

notation(
  pitches:'~A4 ~G5 ~D4',
  glisses:[
    { from:{index:0}, to:{index:1}, style:straight }
  ]
)
Style Description
straight Plain line (default)
wavy Sinusoidal vibrato line
arrow Line ending in an arrowhead
dotted Dotted line
dashed Dashed line
trill Trill (tr + line)
portamento Curved bezier

Glisses can include intermediate breakpoints (breakpoints:[{x,y},…]) to bend through specific points; in edit mode, dragging the midline of a gliss creates a breakpoint.

For multi-stave systems, gliss endpoints carry a staveIdx as well as index:

glisses:[
  { from:{staveIdx:0, index:3}, to:{staveIdx:1, index:0}, style:wavy }
]

Articulations

Articulation marks render above (or below) each anchored note. Multiple marks on one note stack vertically.

notation(
  pitches:'~C5 ~D5 ~E5',
  articulations:{ 0:["staccato","accent"], 2:["fermata"] }
)

Available marks (SMuFL Bravura glyphs):

staccato, staccatissimo, accent, accentStaccato, tenuto, portato, tenutoAccent, marcato, marcatoStaccato, stress, unstress, laissezVibrer, fermata, fermataShort, fermataLong, fermataVeryLong, harmonic, snapPizz.

In edit mode, dblclick a notehead → Articulation tab to toggle marks across all selected notes.


Dynamics

A single dynamic sits below the staff at the anchored note's x-position.

notation(
  pitches:'~C5 ~D5 ~E5',
  dynamics:{ 0:"p", 2:"f" }
)

Available dynamics:

n (niente), ppppp, pppp, ppp, pp, p, mp, mf, f, ff, fff, ffff, fffff, fp, pf, sf, sfp, sfz, sffz, rf, rfz, fz.

In edit mode, dblclick a notehead → Dynamic tab.


Per-Note Samples

Each note can be assigned an audio sample to play on click and / or playhead-pass. Samples are picked from the project's /audio directory via the popup's Audio tab (see Timepoint Notation in the App).

The sample is played through the same engine as audio(…) cues, so it inherits gain and speed but currently bypasses FX routing.


Multi-Stave Systems

Piano, organ, and string-quartet layouts use notationSystem (see in-app notation docs) — multiple staves rendered as a single coordinated group with one shared extent line and bounding box spanning every stave. Cross-stave glisses use staveIdx in their endpoint addressing. Multi-stave systems are usually created via the topbar + Notation button, but can also be authored in the score svg as a JSON spec.


Examples

Simple progression:

notation(pitches:'~C4 ~D4 ~E4 ~F4 ~G4', height:32, spacing:24)

Bb clarinet (sounding pitches), with Eb major key signature:

notation(pitches:'~Bb3 ~D4 ~F4 ~Bb4', transp:Bb, keysig:Eb)

Microtonal cluster:

notation(pitches:'~A4 ~A4+33 ~A4+67 ~A4+100', height:36)

Sustained tones with extent line:

notation(
  pitches:'~G4 ~Bb4 ~D5',
  extent:200,
  extentStyle:wavy,
  spacing:30
)

Boxed cluster with playhead-trigger OSC:

notation(
  pitches:'~C4 ~D4 ~Eb4 ~F#4 ~G4',
  boxed:1,
  boxRadius:4,
  playhead:1,
  oscaddr:'/synth/cluster/{i}'
)

Edit-Mode Behaviour

When the topbar 🎼 (notation edit) toggle is on, every notation() cue gains drag handles and double-click affordances. Per-note overrides (positions, notehead styles, articulations, dynamics, samples, OSC flags) are persisted under the cue's uid in localStorage and (for session cues) in notation-cues.json. The score svg itself is never modified.

See Timepoint Notation in the App for the full set of edit-mode interactions.

Demo

See demo-score-follow — a reading line playing a stave note by note.

http://localhost:8001/?project=demo-score-follow

Tip: use ← → or ↑ ↓ to navigate the docs