Lily# The language — a reference for .lys

01

How to read this

This is a reference to the .lys language as Lily# 0.8.0 accepts it. Every example here is run through lysc check when the page is built — the build fails if one does not compile. Where a claim is about something subtle, the page says how it was measured.

Three ideas run through the whole language, and most surprises dissolve once you have them:

  • Music lives inside a part. A file is a set of declarations. A bare note at the top level is an error, and that is what lets a top-level key or time always mean “the file's default” with no ambiguity.
  • Order carries meaning; clauses do not. A score is a vertical stack of bands. A lyric row under a staff is that staff's verse because it is under it — not because a clause says so.
  • Anything that changes the playing order lives in the form. Repeats and endings are written there, never among the notes.

There is one canonical way to write each idea. Where the language could have been clever it is usually explicit instead.

02

A file at a glance

The smallest complete document is four lines:

part melody { clef treble }
section Main { melody { c4 d e f | g2 g | } }
form main { Main }
score main { staff melody }

Everything else is optional, and top-level settings come first:

// comments are // to end of line, or /* … */
title    "Song"
composer "Composer"
tempo    120                 // also: tempo "Allegro" 4 = 96, tempo 120 swing
time     4/4                 // default 4/4; engraves as C, and 2/2 as cut-C
key      c major             // default c major; all church modes work
octave   absolute            // optional; relative is the default — see Pitches
pitch    written             // optional; concert = the letters are what SOUNDS — see Transposing instruments

fonts { serif "Georgia" }    // optional, a face per kind of text
paper { size a4 }            // optional, page geometry

part rightHand { clef treble }
part leftHand  { clef bass octave 3 }

phrase motif { c4 d e f | }  // optional reusable music

section Main {
  rightHand { motif g2 g | }   // a section binds music to each part by name
  leftHand  { c2 c | g2 g | }
}

form main { Main }           // the playing order

score main "out" {           // one or more render blocks
  grandStaff { staff rightHand  staff leftHand }
}

The declaration order above is the conventional one. Parts must be declared before the sections that use them, and a score names a form.

03

Lexical rules

ThingRule
Comments// to end of line and /* block */
CaseEverything is case-sensitive. Treble is not treble; it is an unknown symbol and an error, never a silent fallback.
IdentifiersAny Unicode letters. phrase 動機 { … } is fine.
StringsDouble quotes: "Für Elise"
NumbersIntegers, and decimals as values (3.5). A decimal is never a duration — c4.5 is an error, c4. is a dotted quarter.
UnitsGlued to the number: 210mm, 8.5in. A space (210 mm) is an error that names the glued spelling.
Annotation prefix@. The backslash is used for one thing only: a string number (c'\3).

Whitespace and newlines are not significant. You can put a whole part on one line or one bar per line; the samples on the showcase page do both.

04

Pitches and octaves

Note names are Dutch: c d e f g a b, sharp is, flat es.

WrittenMeans
cis fisC♯, F♯
ees besE♭, B♭
cisis desesC𝄪, D𝄫
' ,octave up / down, repeatable (c'', c,,)

Two octave modes

Relative (the default). Each bare pitch takes the octave nearest the previous note — an interval of a fourth or less — and '/, shift from there. Compact, but one wrong mark moves everything after it.

Absolute. Write octave absolute at the top level, in a part header, or mid-music. Bare c is then C4 (or CN in a part that says octave N) and the marks are absolute offsets from it: c' is C5, c, is C3, resolved independently per note. A wrong octave stays one wrong note instead of cascading.

Write relative. It is the default, it is shorter, and it is how a person reads music anyway — each note against the one before it. Reach for absolute when something other than a person is doing the writing: a generator, an importer, or an AI producing a score it cannot hear back. There the guarantee that a mistake stays local is worth the extra marks; at the keyboard it usually is not. part bass { octave 3 } re-anchors a low part so its commas do not pile up.

Sections restore the file-level mode, so a mid-music switch does not leak.

engraved example
Show the whole file
// Relative is the DEFAULT: each bare pitch takes the octave nearest the note before
// it. `octave absolute` switches that off and anchors a bare c to C4 (or to the part's
// `octave N`), so a wrong octave never cascades — worth it when a generator is writing,
// not by hand.
octave absolute
time 4/4
part melody { clef treble }
section A { melody { c4 c' c'' c, | e g e' g, | } }
form main { ~A }
score main { staff melody }

05

Durations

WrittenMeans
1 2 4 8 16 32 64 128whole, half, quarter, …
4. 4..dotted, double-dotted
(omitted)reuse the previous note's duration
c4:8tremolo — repeat the note in eighths for its length

A duration is glued to what it lengthens: c4, <c e g>4. It never sits on a chord member — <c e g2> is an error.

The bare duration

A duration standing alone repeats the previous note, chord or slash at the new length, and sets the running default:

bes8 8 8 8        // four B♭ eighths, written once
<c e g>4 4        // the chord again
/4 4 4 4          // four beats of slash comping

Rests are transparent to it. With nothing before it to repeat, it is an error. Reaching back across a barline only warns — because that shape is also what a dropped pitch letter looks like (4 g f e meant as a4 g f e), so open a measure with the event itself.

06

Notes, rests, chords

WrittenMeans
fis8F♯ eighth
r4quarter rest
s4invisible spacer rest
R1full-measure rest
a,4@resta rest printed where the note a, would sit
<c e g>4chord
<c 3 5>4the same triad by scale degree
<1 3 5>2degrees only — anchored on the key's tonic
/4slash note — pitchless rhythm, silent, on the middle line
qthe previous chord again
q'…an octave up (q,, two down)

Repeating a chord — and why there are two ways

A bare duration and a q both repeat what came before, and for the plain case they are the same music — <c e g>4 4 and <c e g>4 q4 engrave and play identically. They differ in what they are, and that is what decides which one you can modify:

  • A bare duration is a LENGTH. “The previous event again, this long.” It cannot be displaced, because a length has nothing to move — 4' is not a spelling.
  • q is an EVENT. “This chord again.” It takes its own duration, its own post-events (q@staccato — the original's are never copied), and octave marks.

The displacement accumulates along the chain: q' q plays the chord an octave up both times, q' q' climbs by one and then two, and a bare duration in the run repeats the chord where the last q left it. A q with no chord before it warns and occupies its time silently; notes and rests are transparent to it, and the run does not leak across a part, section or phrase body.

Octave marks on q are Lily#'s own — LilyPond's q takes none.

engraved example
Show the whole file
// A duration standing alone repeats the previous event at the new length, and `q`
// repeats the previous CHORD. Only `q` can be displaced: q' is an octave up.
time 4/4
part melody { clef treble }
section A {
  melody { c8 8 8 8 c4 4 | <c e g>4 q q' q | }
}
form main { ~A }
score main { staff melody }
engraved example
Show the whole file
// Rests, spacers, a full-measure rest, a pitched rest, chords by letter and by
// scale degree, and the pitchless slash note.
octave absolute
time 4/4
key c major
part melody { clef treble }
section A {
  melody {
    c4 r4 s4 g4 | R1 | c4 a,4@rest d4 r4 |
    <c e g>4 <c 3 5>4 <1 3 5>2 | /4 4 8 8 4 |
  }
}
form main { ~A }
score main { staff melody }

A rest normally places itself: middle line, voiced position inside a voice span, clear of what sounds with it. @rest on a note overrides that — the rest sits where that pitch would and nothing moves it again, which is how two voices' colliding rests get pulled apart. The pitch never sounds and prints no accidental. On anything but a note it is an error.

Chord octaves — the anchor model

One rule: a mark moves only what it is attached to. The anchor is the first member's bare letter (or the key tonic for a degrees-only chord), resolved nearest the running frame; members sit at or above it, so order is free except the first slot. The chord never moves the frame itself — only a mark after the > does.

WrittenSoundsNext bare c
<c e g> = <c g e>C4 E4 G4C4
<c' e g>C5 E4 G4 — the mark moved that note onlyC4
<c e g>'4C5 E5 G5 — after the >, it moves the chord and the frameC5

Arpeggios — written-out broken chords

<< … >> plays its members in sequence, equally subdividing the group's total. Members take no durations of their own — a bare number inside is always a scale degree.

<< c e g >>      // c, then e and g stacked above it — a triplet of eighths after c4
<< 8 5 3 1 >>    // degrees only: descending from the octave
<< c r e >>      // a rest is a gap — an equal share
<< c e g >>2     // a duration after >> is the group's TOTAL
<< c e g >>'     // marks after >> shift the group and propagate
<< c . d >>4     // a SPACED dot holds the member before it one more share: 2:1, the swing figure
<< c . . d >>4   // 3:1 — c8. d16 (never glued: c. would be a duration dot, 3. a decimal)
<< c@accent e\3 g( a) >>   // a member carries scripts, string numbers, fingering, dynamics, slur marks
<< c e g >>4\2   // on the group: a dynamic, a chord name, a string number (every member's);
                 //   a ~ or ( written after >> hangs on the last member

The tuplet is spelled the way engraving convention spells it — the member count against the power of two below it (3:2, 5:4, 7:4), a dotted total against 3 (2:3, 4:3) — from the total number of shares.

This is not LilyPond's << >>. Parallel voices are voice { } { } in Lily#, and a \\ inside is an error.

engraved example
Show the whole file
// `<< … >>` writes a broken chord out: the members play in sequence and divide the
// group's total. A bare number inside is a scale degree, never a duration.
octave absolute
time 4/4
key c major
part melody { clef treble }
section A {
  melody { << c e g >>4 << c 3 5 >>4 << 8 5 3 1 >>2 | << c e g >>2 << c r e >>2 | }
}
form main { ~A }
score main { staff melody }

07

Ties, slurs, beams

c4~ | c4 d e f       // tie — same pitch, with ~
c4( d e f)           // slur — different pitches, with ( )
<c e>4( <d f>)       // a slur may bind chords too
c8[ d e f]           // manual beam; beaming is automatic otherwise
c4@phrasingSlur d( e) f g@!phrasingSlur   // a phrasing slur over a whole phrase; ordinary slurs may sit inside

A tie whose next note is a different pitch warns and tells you to use a slur instead. Beaming follows the meter unless you bracket it yourself. A phrasing slur is a spanner: its end is required, and one may be open per voice.

engraved example
Show the whole file
// A tie joins the SAME pitch, a slur joins different ones, and square brackets
// beam by hand where the meter's own beaming is not what you want.
octave absolute
time 4/4
part melody { clef treble }
section A {
  melody { c4~ c4 d4( e4) | <c e>4( <d f>4) c8[ d e f] | }
}
form main { ~A }
score main { staff melody }

08

Annotations

Attach with @; one note may take several (c4@staccato@p). Two suffixes force a side: .up and .down (c4@staccato.up, @f.up). An annotation that takes a value puts it in parentheses: @finger(3), @fig(6 4), @text("dolce").

FamilyNames
Articulations@staccato @staccatissimo @accent @tenuto @marcato @fermata @portato
String technique@upbow @downbow @flageolet — always above
Ornaments@trill @mordent @prall @turn @reverseturn
Dynamics@ppp @pp @p @mp @mf @f @ff @fff, and @sfz @sf @fp @rfz @fz
Hairpins@cresc @decresc @dim — placed on the starting note, running to the next dynamic. No .up/.down: a hairpin is always below.
Stems@stemUp @stemDown — on a beamed note the beam's shared direction wins
Accidental style@courtesy (parenthesised), @editorial
Effects@arpeggio @glissando @cross @dead @fall @doit @breath @caesura
Half ties@laissezVibrer, @repeatTie
With a value@finger(3) @fig(6 4) @bend(half) @notehead(triangle) @feather(right) @text("dolce") @mark("A") @chord(Dm) @frame(032010) @pluck(i) @ottava(bassa)

Spanners — the end is required

These open on one note and must be closed on another. A spanner nobody closes draws nothing at all, its word included, and says so:

OpensCloses
@textSpan("poco rit."), or the sugar @rit @accel @rall@!textSpan / @!rit …
@ottava, @ottava(bassa), @quindicesima@!ottava closes any of them
@startTrillSpan@stopTrillSpan
@sustain, @sostenuto, @unaCorda@!sustain, @!sostenuto, @!unaCorda (@treCorde is the last one's release, spelled as the printed word)

These take no argument. @ped, @ped(off), @una(corda) do not exist. A pedal change — release and press again on the same note — is the pedal's name again while it is down: in c4@sustain d e f | g4@sustain a b c@!sustain the second @sustain re-pedals, and the bracket draws its notch there (@!sustain@sustain on one note means the same).

The dot after a name is placement, not an argument

@fermata.up is a fermata forced above. It follows that @notehead.x does not work — an argument always goes in parentheses: @notehead(cross).

engraved example
Show the whole file
// Articulations, ornaments and dynamics attach with '@'. A hairpin goes on the
// note it starts from and runs to the next dynamic. '.up' forces the side.
octave absolute
time 4/4
part melody { clef treble }
section A {
  melody {
    c4@staccato d4@accent e4@tenuto f4@marcato |
    g4@trill a4@mordent b4@fermata c'4@staccato.up |
    c'4@p@cresc b4 a4 g4@f | f4@f@decresc e4 d4 c4@p |
  }
}
form main { ~A }
score main { staff melody }
engraved example
Show the whole file
// A spanner opens on one note and MUST be closed on another: one that is never
// closed draws nothing at all and says so.
octave absolute
time 4/4
part rh { clef treble }
part lh { clef bass octave 3 }
section A {
  rh {
    c'4@ottava d' e' f' | g'4 a' b' c''@!ottava |
    c'4@rit b a g@!rit | c'1 |
  }
  lh {
    c4@sustain e g e | c4@sustain e g e |   // a second @sustain while down re-pedals
    c4@sustain e g e | c1@!sustain |
  }
}
form main { ~A }
score main { grandStaff { staff rh  staff lh } }

09

Tuplets, grace notes, voices, cues

tuplet 3/2 { c8 d e }                          // 3 in the time of 2
tuplet 3/2 { c8 d tuplet 3/2 { e16 f g } }     // nesting is allowed

grace        { d16 e } f4     // grace notes before f
acciaccatura { a16 }    b4    // slashed
appoggiatura { c8 }     d4    // unslashed

voice { c'2 d } { e2 f }      // `voice` opens the span ONCE; each further { } is another voice

repeat unfold 8 { ground }        // write the body out 8 times
repeat percent 2 { c4 d e f | }   // repeat the previous measure
repeat tremolo 8 { c16 e } |      // N x the pair: 8 x two 16ths fills a 4/4 bar

repeat is only for unfold / percent / tremolo — things that abbreviate notes. It is not how a repeat sign is written; see Forms.

Cue notes

A cue is a region, not an annotation, so there is no @cue:

c4 cue { e4 f } g4 |            // small notes, a voice of their own
c4 cue bass { e4 f } g4 |       // drawn in another instrument's clef; the staff's clef returns

A slur or tie may not cross the region's edge — close it inside the cue, or keep both ends outside. Two adjacent cue blocks are two voices, so a span cannot run from one into the next either.

engraved example
Show the whole file
// Tuplets nest, grace notes come in three flavours, and `voice { } { }` opens a
// span of simultaneous voices on ONE staff.
octave absolute
time 4/4
part melody { clef treble }
section A {
  melody {
    tuplet 3/2 { c8 d e } tuplet 3/2 { f8 g a } c'2 |
    grace { d16 e } f4 acciaccatura { a16 } b4 appoggiatura { c'8 } d'4 r4 |
    voice { g'2 a'2 } { c'2 c'2 } |
  }
}
form main { ~A }
score main { staff melody }

10

Barlines and breaks

In the musicDraws
|single
||double
|.final
!dashed

A written | closes exactly one measure, and a measure with nothing in it is an empty one. So { | | | | } is four empty bars and { | c1 } is an empty bar then c1. An empty bar fills itself with a full-measure spacer, on the page and in playback, so it is never diagnosed — which is what lets a rhythm staff say nothing for pages at a time.

Typed barlines close nothing: || and |. decorate the bar behind them, and a | landing where the meter just auto-filled a bar merely confirms it. That is why a trailing c1 | is one bar, not two.

The repeat barlines |: :| :|: are not music items. Writing one among the notes is refused, with a message naming the form to write instead.

Forcing where a line or page turns

Four bare words, written in the music (or in the form). At a bar line they end the system there; inside a bar, break splits that bar across two systems. They are spelled in camelCase and, like everything else, are case-sensitive — nobreak is not a word.

WordMeans
breakend the system here
noBreakdo not end the system here
pageBreakend the page here
noPageBreakdo not end the page here

Line and page breaking are otherwise automatic — Lily# uses LilyPond's Knuth-Plass line breaking and its page-breaking search — so these are for the places where you disagree with the result, not for laying a score out by hand.

engraved example
Show the whole file
// Every written '|' closes exactly one measure, so a bar with nothing in it is an
// empty bar. '||' and '|.' decorate the bar behind them; '!' is dashed.
octave absolute
time 4/4
part melody { clef treble }
section A {
  melody { c1 | | d1 || e1 ! f1 |. }
}
form main { ~A }
score main { staff melody }

11

Parts

A part is declared once and carries what stays true for it. Attributes are written bare, with no =.

part melody { clef treble }
part bass   { clef bass octave 3 }
part gtr    { clef treble_8 tuning guitar }
part fl     { clef treble instrument flute }
part cl     { instrument clarinet "Clarinet in Bb" }
part sing   { clef treble transpose d }
AttributeTakes
cleftreble bass alto tenor treble_8 treble^8 bass_8 soprano mezzosoprano baritone percussion. A clef only draws the staff — it never changes which octave a bare letter means; that is octave's job, or the instrument preset's.
octaveabsolute, or a number that re-anchors the base (octave 3 for a low part)
keythis part's own key signature (time and tempo are shared by every part, so they are written at the top level or in a section header)
instrumenta preset name, a quoted display label, or both — see below
transposea pitch, not a number of steps: it renames c to that pitch and moves every written note with it. This moves the PAGE — for a transposing instrument, name the preset instead. Writing a number is an error that says so.
transpositionan octave marker — 8va 8vb 15ma 15mb. A different thing from transpose, and it does not take a pitch.
pitchconcert or written — this part's convention for a transposing instrument, overriding the top-level pitch. Without a transposing instrument it changes nothing. See Transposing instruments.
tuninga tuning name; makes the part tablature-capable
midiInstrumenta quoted General MIDI sound, midiInstrument "acoustic bass" — what playback sounds like, overriding the preset's
pedaltext ("Ped. … *"), bracket (the default) or mixed — how this part's pedal marks are drawn

Part names are ordinary identifiers and may not be reserved words — except the four clef words treble bass alto tenor, which are allowed, so a part called bass is fine.

instrument — one word, several answers

Naming an instrument is not just a label. The preset settles everything a part needs to know about itself, and each of those can still be overridden by writing it explicitly:

It setsWhich shows up as
the clefviola reads alto, cello and bass read bass, guitar reads treble_8
the octave anchorwhere a relative part's bare letters land
the tuningwhich strings a tab row has — hence the fret numbers
the MIDI programwhat playback sounds like
the sounding octavethe bass family sounds an octave below its notation, a piccolo an octave above
the printed namethe label beside the staff
part gt { instrument guitar }                  // preset: clef, tuning, sound, label
part bs { instrument bass "Bass" }             // preset, with the label overridden
part v1 { clef treble instrument "1st Violin" } // label only — no preset behaviour

A bare word is the preset; a quoted string is the display label; both together set the preset and rename it. A quoted string alone is a free-text name and carries no preset behaviour — the clef and the rest come from whatever else the header says.

Transposing instruments

Write what the player reads, and the preset makes it sound right. Naming a transposing instrument is enough — the part prints exactly the notes you typed, and playback (and a tab's frets, which read the same one value) shifts to where the instrument really is. A part cannot print at one pitch and play at an unrelated one.

PresetWritten C sounds
clarinet trumpet soprano-saxB♭ — a major 2nd down
clarinet-aA — a minor 3rd down
hornF — a perfect 5th down
alto-saxE♭ — a major 6th down
tenor-saxB♭ — a major 9th down
baritone-saxE♭ — an octave and a major 6th down
bass and its familyan octave down
piccoloan octave up
trumpet-c flute oboe trombone …as written

A bare name takes the common member of its family — clarinet and trumpet are the B♭ ones, horn is in F — because that is the instrument someone means when they say no more. The others have their own spellings. Every saxophone needs one (alto-sax, not alto): the plain voice-range words are already the choral presets. Guitar and vocal tenor carry their octave on the treble_8 clef instead of here, which is why their parts print the little 8 under the clef and this table does not list them.

Or write what sounds, and let the part be transposed for you. A top-level pitch concert says the letters are concert pitch: every chromatically transposing part is then printed the way its player reads it, pitches and key signature together — an alto-sax part of a piece in C major prints its c' as a', in A major, and still plays C. The default, pitch written, is the first convention above. Octave-only instruments (bass, piccolo, a transposition 8vb) keep their notation under both, as a printed concert score keeps them. To print one score at concert pitch whichever way the file is written — the conductor's score — put the same words on that score: score main "full" pitch concert { … }.

An explicit transpose is a different thing: it moves the written notes by hand. Its argument is a PITCH, not a number of steps — it renames c to that pitch and shifts every note by the same interval, so part cl { clef treble transpose bes } prints c d e f as B♭ C D E♭ — and it composes with the instrument's own shift. Do not confuse it with transposition, which takes an octave marker (8va / 8vb / 15ma / 15mb) and overrides the preset's written-to-sounding octave.

engraved example
Show the whole file
// One word sets several things at once: each part's clef, the octave its bare letters
// anchor to, its tuning (so its frets), what it sounds, and its printed name. Neither
// part below says `clef`, `octave` or `tuning` — the preset already did, which is why the
// same letters land at C4 on the guitar and at C3 on the bass.
time 4/4
part gt { instrument guitar }
part bs { instrument bass "Bass" }
section A {
  gt { c4 e g e | }
  bs { c4 e g e | }
}
form main { ~A }
score main {
  staff gt  tab gt
  staff bs  tab bs
}

12

Phrases

Named music, declared with phrase and used by its bare name:

phrase motif { c4 d e f | }
section Main { melody { motif g2 g | } }

Each phrase body evaluates in a fresh frame — default octave, pitch and duration are reset — so a phrase means the same notes at every call. A reference is one item to the relative chain, exactly like a chord: the next note is relative to the phrase's anchor (its first note's bare letter, shifted by the reference's marks), never to how the body happens to end.

A trailing ' or , on a reference shifts that play's octave. There is no per-reference transposition: a motif quoted at another interval is written out, because transpose is a property of a part, not of a quotation.

13

Sections

A section binds music to each part by name, and is the unit the form orders. Section boundaries reset the relative frame.

section Verse {
  partial 8                       // optional pickup, for every part at once
  melody { a'8 | c4 d8 e8. f16 e8 |  }
  bass   { r8  | a4 e8 a4. |  }
  chords prog  { | Am | }         // a chord row lives here too (the pickup holds none)
  lyrics words sings melody { A- | las my love you do | }
}

A section prints a rehearsal label by default. ~ on a form reference hides it for that play (form main { ~Verse Chorus }). The tilde belongs to the reference only — section ~A { … } is an error.

14

Lyrics

sings binds a lyric track to the part it sings. It is a property of the track, not of one place in the file, so it may be spelled at the definition, on the score row, or both — the same one property, written wherever it reads best.

// on the definition
lyrics words sings melody { Hap- py birth- day | to you | }
score main { staff melody  lyrics words }

// or on the score row, leaving the definition bare
lyrics words { Hap- py birth- day | to you | }
score main { staff melody  lyrics words sings melody }

Spelling it on the row is what lets ONE track serve several staves. Place the same lyrics row under each staff and bind it there — the words are written once and appear under every voice that sings them, which is what a homophonic chorale wants:

score main {
  staff sop "Soprano"
  lyrics verse sings sop
  staff alt "Alto"
  lyrics verse sings alt
}
engraved example
Show the whole file
// `sings` is a property of the lyric TRACK, and it can be spelled at either site:
// on the definition, on the score row, or both. Spelling it on the ROW is what lets
// ONE set of words serve several staves — here the same track is placed twice.
octave absolute
time 4/4
key c major
part sop { clef treble }
part alt { clef treble }
section A {
  sop { c'4 c' b a | g1 | }
  alt { e4 e g f | e1 | }
  lyrics verse { Sing- ing a song | now | }
}
form main { ~A }
score main {
  staff sop "Soprano"
  lyrics verse sings sop
  staff alt "Alto"
  lyrics verse sings alt
}
WrittenMeans
spacenext syllable
-joins syllables of one word
~ or _hold the previous syllable over one more note (a ~ glued on both sides, va~ga, puts two syllables on one note)
__draw the extender line; takes no note
|mirrors the music's barlines

A slur or a tie holds its syllable, as in LilyPond. The notes inside a slur (after its first) and a note a tie arrives at take no syllable of their own, so c4( d e) f sung to la __ lu puts lu on f. A slur written only to mark phrasing over a lyric line would swallow its syllables — write that one as @phrasingSlur … @!phrasingSlur, which holds none; the warning says so when it happens.

Barlines follow the same rule as music: every written | closes one bar, the one that opens the run included. That leading | is how a verse skips the rest bar its melody opens with.

The score places the row by order. A bound lyrics NAME row directly below the staff engraving its part is that staff's verse, and a run of rows stacks as verses. Elsewhere it shows only the words, at the melody's rhythm, without engraving the melody. Several tracks may sing one part — two languages, two names. Inside a staff group a row must sing the staff directly above it; write the binding at the row to say which.

engraved example
Show the whole file
// A lyric track sings a part. '-' joins syllables of one word, '~' holds the previous
// syllable over one more note, and '|' mirrors the music's barlines.
octave absolute
time 4/4
key f major
part melody { clef treble }
section A {
  melody { f4 g a bes | c'2 a4 f4 | g4 a bes a | f1 | }
  lyrics words sings melody {
    Sing- ing all the | day ~ long, |
    ev- ery word a | song |
  }
}
form main { ~A }
score main { staff melody  lyrics words }

15

Chords and chord rows

A chords NAME { … } row holds chord symbols as they print. Placed directly above a staff, they align over it by timing; placed on their own, they draw a staff-less grid of barlines.

chords prog { Cmaj7 | Am7 | Dm7 | G7 | F#m7-5 B7-9 | }
WrittenMeans
one entry in a bartakes the bar
two entries in 4/4halves; four, beats — entries divide the bar on the meter's beat grid
.hold the previous chord one more beat (never across a barline)
r Rprint “N.C.” in that slot
sprint nothing

How a symbol is spelled

You type the symbol, not an encoding: Cmaj7, Am7, G7sus4, C/G, Bb7/D, F#7. One rule is worth knowing before it surprises you:

an altered tension takes + or −, never # or b

So a half-diminished chord is F#m7-5, a flat ninth is C7-9, a sharp five is A7+5. The reason is that # and b belong to the root and the bass — without that split, Bb9 could not say whether it means B♭ with a ninth or B with a flat ninth. Written the other way (F#m7b5) the suffix is not a quality Lily# knows: it prints as typed, but carries no chord.

The registered qualities: m min dim aug 7 maj7 maj m7 min7 mmaj7 dim7 m7-5 + 6 m6 min6 9 maj9 m9 min9 sus2 sus4 sus 7sus4 7-5 7+5 7-9 7+9 7+11 add9 11 13 m11 min11 m13 min13 maj13. A quality outside that list still prints in a chord row — the row keeps whatever suffix you wrote — but it has no interval set, so playback sounds only its root and @chord on a note refuses it.

Entries carry no durations — the grid does the arithmetic. Barlines in the source are drawn and follow the same bare-barline rule as music and lyrics. A |: in a chord row is a repeat like any other and belongs in the form; the repeat barlines the form composes still reach the row and draw there.

The same named row can be used twice — above a staff in one score, and as a standalone chart in another — so a progression is written once.

A row the score places also sounds. In the MIDI (and in the editor's playback) it plays on a track of its own, NAME (chords), softer than the melody, each symbol over exactly the span it prints over: . holds it, r is silence. A symbol names a chord but voices none, so Lily# uses one voicing everywhere — every tone between G3 and G4, a slash bass an octave below (G7/B sounds B2 G3 B3 D4 F4). A row no score places is silent.

What you write and what it prints are two different choices

A chord has three representations in Lily# — a symbol (Cmaj7), a degree of the key (Imaj7), and the notes (<c e g b>) — and the language keeps the one you type separate from the one that prints. Both spellings resolve to the same structure, so everything downstream — the printed name, the degree, playback, transposition — is one road.

You writeScore itemIt prints
chords p { Cmaj7 }chords pCmaj7
chords p { Cmaj7 }chords p as romanImaj7
chords p { Imaj7 }chords pCmaj7
chords p { Imaj7 }chords p as romanImaj7
<c e g>4@chordstaff …C — derived from the notes
c4@chord(Dm)staff …Dm — stated on the note

So a chart written in degrees prints absolute names by default, and one written in names prints degrees under as roman. A degree is read against the key in force at that bar, which is why a modulation re-reads them rather than freezing them.

One progression printed four ways

Rows one and two above are the same chords part, placed twice in one score with different display. Row three is written in degrees. The staff underneath carries no chord symbols of its own — each is derived from the notes by a bare @chord.

The name a bare @chord derives

A bare @chord reads the symbol off the notes. The root comes from the pitches, not from whichever member you typed first — the members are tried as the root from the bass upward, and the first that names a registered quality wins. If that root is not the lowest sounding note, the chord is an inversion and the lowest note prints as the slash bass.

WrittenSoundsPrints
<c e g>C4 E4 G4C
<e g c> (absolute)E4 G4 C4C — c is still the lowest
<e g c> (relative)E4 G4 C5C/E
<e, g, c> (relative)E3 G3 C5C/E

The bass is tried first, and that is what keeps this safe. Some sets read as more than one chord: <c e g a> is C6 from C and Am7 from A. Preferring the bass settles it the way the voicing already suggests — C6 when c is at the bottom, Am7 when a is — and it is why <c e g b> is Cmaj7 rather than something rooted higher up. Another root is only ever consulted when the bass names nothing at all.

Where the notes are genuinely ambiguous, say which you mean: <e g, b d>@chord prints G6 (g is the bass), and <e g, b d>@chord(Em7/G) prints Em7/G. Watch the octaves rather than the written order — under octave absolute, <e g b d> puts d below e and so reads Em7/D.

What completion offers

Inside a chords { } block, and inside a @chord(…) argument, completion offers the current key's diatonic chords — each degree's triad and seventh (and, among the names, the suspended forms) — read against the key in force at that point. Hovering a chord symbol, or a chord or << >> in the music, shows its name, its degree and its pitches (Dm (IIm) D4 F4 A4).

  • In a chords { } block you get both vocabularies: all seven degrees as names first (C D E F G A B …), then all seven as degrees (I II III …), so each list can be scanned on its own.
  • In a @chord(…) argument you get the names only. The annotation reads the absolute-symbol grammar alone, so @chord(V7) is refused — the completion offers nothing it would then reject.
  • What it inserts is the symbol — Dm7, Imaj7 — not the notes. The entry format is the printed form, for a row and an annotation alike.

16

Forms — the playing order

A form lists sections in the order they are played and printed. This is where repeats live, because a repeat is a change to the order.

form main { Intro Main Main "Main (reprise)" Coda }
form main { |: Body [1. ~First] :| [2. ~Second] }
form main { |: A :|*3 }
form practice { Verse }        // a second form = a second output
WrittenMeans
|: … :|repeat; count defaults to the number of endings, or 2
:|*Nan explicit play count
[1. Name]a volta ending. The opening [ is required; the closing ] is optional and draws the right-hand cap
~Namehide that play's rehearsal label
Name' Name,shift that play's octave — one section quoted at two octaves is ~B ~B'
"Label"a custom printed label for that play

An ending needs a repeat to be an ending of: written without one, no bracket is drawn and a warning says the 1. prints nothing.

Navigation marks

Signs (segno, coda) engrave at the start of the following section; text directives (fine, to coda, dc, ds, and dc al fine, ds al coda) engrave at the end of the section just played.

form main { A segno  B to coda  C ds al coda  coda D }

The same bare words may also be written in a section's music at a barline boundary. They are landmarks, never note modifiers, so c4@segno is an error and putting one mid-measure warns.

The reserved form name main writes to the input file's name; any other form name becomes the output file name unless a "basename" overrides it.

engraved example
Show the whole file
// A repeat changes the playing ORDER, so it lives in the form, never in the music.
// The endings name sections; the bracket and the repeat dots are drawn from this.
octave absolute
time 3/4
key g major
part melody { clef treble }
section Body   { melody { d'4 g' fis' | g'2. | } }
section First  { melody { a'2. | } }
section Second { melody { g'2.@fermata | } }
form main { |: ~Body [1. ~First] :| [2. ~Second] }
score main { staff melody }

17

Scores

A score binds a form to a set of rows. It is a vertical stack of bands: what a row means comes from where it sits.

score main "out" {
  chords prog                     // a chord row above ...
  staff melody "Melody"           // ... the staff it belongs to
  lyrics words                    // ... and that staff's verse below it
}
ItemRow it draws
staff NAMEa notation staff for that part
staff NAME "Label"…with a printed name
staff NAME as lines N…with N staff lines (1–5). as lines 1 is a rhythm staff
staff NAME as removeEmpty true…hidden in systems where it only rests (all: in the first system too)
tab NAMEtablature — see below
chords NAMEa chord row
lyrics NAMEa lyric row
ossia NAMEa small alternative staff
NAME (bare)played to MIDI only, never engraved — a click track, a cue part
title / composerrestate the file's metadata for this score alone
paper NAME / fonts NAME / layout NAMEuse a named block for this score

A staff's display name is always a quoted string, so a bare word after staff NAME is always another score item — staff flute click is flute's staff plus the MIDI-only click part. Position never changes what a word means.

Grouping staves

GroupLeft edgeBarlines between stavesFor
grandStaffbracedrawn throughone instrument on two staves
staffGroupbracketdrawn throughone family
choirStaffbracketnot drawn throughindependent voices

staffGroup reverses the word order on purpose — it is not a slip for groupStaff: the other …Staff items each produce a staff, while a staff group produces a group of staves.

Two more put several parts on one staff, and take bare part names: condensedStaff { fl1 fl2 } gives each part its own voice of a single staff; combinedStaff { fl1 fl2 } merges them the way an orchestral score condenses two players — unisons become one notehead marked a2, different notes in the same rhythm within a ninth become one voice of chords, a lone part is marked Solo. The chord case is the usual outcome, not a corner; use condensedStaff when the lines must stay visibly separate.

Because these are score items, one source prints both the condensed score and the separate parts:

score main "full"  { condensedStaff { fl1 fl2 } }
score main "parts" { staff fl1  staff fl2 }

18

Tablature

Give a part a tuning and render it with tab:

part gt { clef treble_8 tuning guitar }

score main {
  staff gt        // the notation
  tab gt          // the tablature under it
}

A tab standing beside a staff prints fret numbers only — the staff above it already carries the meter, stems, beams, rests and ties. A tab on its own carries the meter, stems, rests and ties itself (beams are not drawn yet). That is the default; say which you want with tab gt as numbers or tab gt as full.

\N pins a note to string N when the automatic choice is not the one your fingers want: c'\2. Technique letters (@tap @hammeron @pulloff @pluck(i)) print on the tab, because they are ink a guitarist reads there.

19

Paper and fonts

Both are optional blocks whose defaults equal LilyPond's, so an absent block changes nothing. Both can also be named at the top level and referenced (or partly overridden) per score.

paper {
  size b5                    // width, height AND scaled margins, by name
  paperWidth 210mm           // bare numbers are staff spaces; units are GLUED
  paperHeight 0              // 0 = one content-driven page
  leftMargin 15mm  rightMargin 15mm  topMargin 10mm  bottomMargin 10mm
  indent 15mm  shortIndent 0
  raggedRight                // a bare flag: do not justify
  spacingIncrement 1.2
  systemSystemSpacing { basicDistance 12  minimumDistance 8  padding 1  stretchability 60 }
}

The staff-spacing family lives here, not in override. Unknown keys are an error; a key set twice warns and the last wins.

fonts {
  serif "Georgia"                      // the two generic families together are
  sans  "Verdana"                      //   "the whole document's text"
  lyricText "Charis SIL" "Noto Serif CJK JP"   // several names = a fallback chain
  tempo "Playfair Display"             // one role beats the group it belongs to
  embedded                             // subset the named faces into the PDF
}

Keys are a generic family, a group, or a single role, and the narrower spelling wins in either source order. Groups map to roles as: header → title, composer, instrument · lyrics → lyricText, stanza · chords → chordName, fretFrame, figuredBass · marks → tempo, mark, pedal, navigation, text, dynamics, partCombine · numbers → barNumber, fingering, tuplet, volta, ottava, bend, tabTechnique · notation → clefOctave, meter, tabFret.

The keyword is fonts, plural, and it takes a block — there is no font keyword and no one-line form. A named face is measured as well as drawn, so naming one that a machine lacks makes the page machine-dependent; a missing face warns rather than passing quietly.

20

Override / revert

override NoteHead.color = red
c4 d e f |
revert NoteHead.color
once override Stem.transparent = true    // 'once' applies to the next note only
c4 d e f |

The syntax accepts any Grob.property, but the vocabulary is deliberately four properties: NoteHead.transparent, Stem.transparent, NoteHead.color, Stem.color. Anything outside that list is refused with a message listing what is supported, rather than silently doing nothing. The list grows, and each addition removes one error.

Grob names are PascalCase and properties are lisp-case; both are case-sensitive.

engraved example
Show the whole file
// The override vocabulary is four properties. `once` applies to the next note only,
// and `revert` puts the default back.
octave absolute
time 4/4
part melody { clef treble }
section A {
  melody {
    override NoteHead.color = red
    c4 d e f |
    revert NoteHead.color
    once override Stem.transparent = true
    g4 a b c' |
  }
}
form main { ~A }
score main { staff melody }

21

Reserved words

section form using tab ossia transpose octave pitch instrument percussion drummap
score part staff grandStaff staffGroup choirStaff condensedStaff combinedStaff
voice phrase repeat break noBreak pageBreak noPageBreak partial cue embedded fonts paper layout
title composer tempo time key clef
major minor ionian dorian phrygian lydian mixolydian aeolian locrian
treble bass alto tenor treble_8 bass_8 soprano mezzosoprano baritone
tuplet grace acciaccatura appoggiatura lyrics chords tuning
override revert once
segno fine coda dc ds al to
ppp pp p mp mf ff fff

The four clef words treble bass alto tenor are the exception: they may still be used as part, section and phrase names. Single letters a–g are pitches and r/R/s are rests — note that f is a pitch, while @f still works because dynamics resolve from the annotation's text. Articulation, ornament and mark names are not reserved at all; they resolve from the @name text, so they stay free for your own identifiers.

22

Diagnostics

Lily# would rather refuse than quietly do the wrong thing, and its messages are written to be acted on. A few worth knowing, quoted as the compiler prints them:

You wroteIt says
c4 g. a4This '.' belongs to nothing. A duration dot needs a number in front of it - write g4., not g. …
c4.5'4.5' is not a duration - a duration is a whole number (c4, c8), lengthened by dots…
<c e g2>A chord member can't carry a duration - members share one, written after the closing '>': <c e g>2. …
4 g f e opening a part's musicA bare duration repeats the previous note, chord or slash - and nothing repeatable comes before this one…
c4 d e f :|':|' is a repeat, so it belongs in the form, not in the music…
repeat volta 2 { … }'repeat volta' is LilyPond's spelling. In Lily# a repeat is written in the form…
\relative { … }Lily# is relative by default — drop '\relative …'; switch modes with 'octave absolute'.
clef TrebleUnknown clef 'Treble'. clef names are case-sensitive; known: alto, baritone, bass, …
fonts "Georgia"fonts binds a face per text role, so it takes a block…
paperWidth 210 mmmm is a unit, and a unit is spelled glued to its number: 210mm, one word.
override Beam.thickness = 2'Beam.thickness' is not supported in this version of Lily# — this 'override' would change nothing. Supported: NoteHead.color, NoteHead.transparent, Stem.color, Stem.transparent. …
c4@rit d e f (never closed)a text spanner is never closed, so neither its word nor its line is drawn; write '@!rit' (or '@!textSpan') on the note it should reach…
c4~ d4the note after a tie '~' does not repeat the tied pitch; a tie joins two notes of the same pitch - use a slur '( )' to connect different pitches
a slur crossing a cue edgea slur cannot cross a cue boundary…

Warnings are for things that are legal but probably not what you meant; errors are for things with no defensible reading.

23

Coming from LilyPond

Lily#'s engraving engine is a port of LilyPond's, but the language is deliberately not LilyPond's. LilyPond's backslash commands are rejected outright, with a message naming the Lily# spelling.

LilyPondLily#
\relative c' { … }relative is the default; or octave absolute
\new Staff, \new Voicepart declarations and score rows
<< … \\ … >>voice { … } { … }
<< … >> (parallel)in Lily# this spelling is a written-out arpeggio
\repeat volta 2 { … }form main { |: A :| }
\alternative[1. B] :| [2. C] in the form
c4\staccato, c4-.c4@staccato
c:maj7, fis:m7.5-Cmaj7, F#m7-5 — the printed symbol, with +/- for an altered tension
q (no marks)q, and q' to repeat the chord an octave up
\versionnothing; there is no version pragma
\includeusing "other.lys"

Chord entry is the sharpest difference and the one most worth knowing: LilyPond asks you to encode a chord, Lily# asks you to type it as it prints.

24

Rough edges

Measured against Lily# 0.8.0 while this page was built. These are real and current; they are listed here rather than smoothed over.

One typo can still produce three diagnostics. c4@bend.half reports the stray dot, then @bend missing its argument, then an undefined variable half. The middle line now names the fix — @bend(half) — but the other two remain.

Collapsing them means letting the parser eat the .half, and the obvious rule for that (an argument-taking name followed by a dot) is wrong: @ottava.bassa is a legitimate dotted name, and ottava is in the same vocabulary. The correct test is whether the whole dotted name is known, and that lives downstream.

lysc ly cannot express a displaced q. LilyPond's q takes no octave marks, and wrapping it in \transpose does not work either: LilyPond expands chord repetitions after transposition, so the wrapper moves an empty placeholder and the expansion then fills in the untransposed pitches (measured against 2.26.0 — it compiles and changes nothing). The twin writes a plain q and warns; write the chord out by hand if the twin must match.

A chart that is nothing but a rhythm staff opens with a small gap. A one-line staff draws no clef, but the room for one is reserved per score rather than per staff, so a score with no other staff to fill it leaves the space empty. In a multi-staff score the reservation is right and nothing shows.

Documented gaps that are known and tracked: cross-staff beam layout and a LilyPond-to-Lily# converter. The long tail of specialist notation — early music, microtonal, clusters, ambitus — is deliberately out of scope.