# Esempi musicali in MEI con apparato critico nelle note

> Blocchi MEI 5 incisi nel testo su un rigo di 5 mm, varianti codificate con app, lem e rdg, e l’apparato per battuta e nota nelle note a piè di pagina.

- Versione HTML: https://postext.dev/it/cookbook/musicology-mei-apparatus
- Ricetta Nº 165 · Riquadri e note · Livello 2 (Intermedio) · Output: Canvas, PDF
- Generi: Articoli scientifici e testi accademici
- Richiede postext ≥ 1.54.0, postext-pdf ≥ 1.54.0 · provata con 1.54.0, postext-pdf 1.54.0 il 2026-10-22
- Pagine: [1](https://postext.dev/cookbook/musicology-mei-apparatus/en/p01.webp?v=cd2d6301), [2](https://postext.dev/cookbook/musicology-mei-apparatus/en/p02.webp?v=cd2d6301), [3](https://postext.dev/cookbook/musicology-mei-apparatus/en/p03.webp?v=cd2d6301), [4](https://postext.dev/cookbook/musicology-mei-apparatus/en/p04.webp?v=cd2d6301), [5](https://postext.dev/cookbook/musicology-mei-apparatus/en/p05.webp?v=cd2d6301)
- PDF: https://postext.dev/cookbook/musicology-mei-apparatus/en/musicology-mei-apparatus.pdf?v=cd2d6301
- Apri nella Sandbox: https://postext.dev/it/sandbox#recipe=musicology-mei-apparatus&lang=en (.postext: https://postext.dev/cookbook/musicology-mei-apparatus/en/musicology-mei-apparatus.postext)
- Ultimo aggiornamento: 2026-10-22
- Altre lingue: [en](https://postext.dev/en/cookbook/musicology-mei-apparatus.md), [es](https://postext.dev/es/cookbook/musicology-mei-apparatus.md), [ca](https://postext.dev/ca/cookbook/musicology-mei-apparatus.md), [de](https://postext.dev/de/cookbook/musicology-mei-apparatus.md), [fr](https://postext.dev/fr/cookbook/musicology-mei-apparatus.md), [pt](https://postext.dev/pt/cookbook/musicology-mei-apparatus.md), [zh](https://postext.dev/zh/cookbook/musicology-mei-apparatus.md), [ja](https://postext.dev/ja/cookbook/musicology-mei-apparatus.md), [ar](https://postext.dev/ar/cookbook/musicology-mei-apparatus.md)

## In breve

Un capitolo di uno studio sulla musica medievale. Brevi passi di un canone inglese del Duecento sono stampati come musica nel testo, e le note in fondo a ogni pagina registrano, battuta per battuta, dove le vecchie edizioni non concordano.

## Che cosa comporrai

Il capitolo 3 di uno studio su come gli antiquari inglesi lessero la musica medievale: cinque pagine di 156 × 234 mm su *Sumer is icumen in*, la rota di Reading, e sugli editori che la misero in partitura tra il 1776 e il 1889. Tre passi del canone sono incisi nel testo, in Leipzig su un rigo di 5 mm, con la numerazione delle battute della partitura di W. S. Rockstro, e ogni commento richiama il suo apparato a piè di pagina: «b. 40, n. 2 la ] sol Hw, Bu». Le note sono brevi e fitte come si conviene a un apparato, la musica occupa la giustezza del testo, e ogni lezione viene dall’articolo di Rockstro nel *Dictionary* di Grove, come il capitolo dichiara nel secondo paragrafo.

**Questa ricetta risponde a:**

- Come do agli esempi musicali un apparato critico delle varianti delle fonti nelle note a piè di pagina?
- Come faccio le note a piè di pagina?

## La risposta breve

````js
// script.js, righe 36–60
// In the Markdown each example is a ```mei fence. A variant is encoded where it stands,
// <app><lem>…</lem><rdg source="#Hw #Bu">…</rdg></app>: the staff shows the lemma, and
// the file keeps the reading for anyone who opens the encoding. The apparatus entry is a
// footnote cited from the paragraph that discusses the bar: `[^b40]: **b. 40, n. 2** A ] G`.
const scoreStyle = {
  staffSize: mm(5), // running-text examples: 4.5–5.5 mm
  musicFont: 'Leipzig', // lighter than Bravura, close to a 19th-century plate
  textFont: 'Crimson Pro', // the underlay in the book's own face
  barNumbers: 'system', // the apparatus is keyed by bar: number every system
  spacing: 0.95,
  systemGap: mm(4),
  marginTop: pt(4),
  marginBottom: pt(LEAD / 2),
  color: col('ink'),
  minSystemsAtBreak: 2, // never leave one system of an example alone at a page foot
};
const footnotes = {
  placement: 'column', // the foot of the page in one column
  numbering: 'chapter',
  fontSize: pt(8.5),
  lineHeight: pt(10.75),
  hangingIndent: em(1.2), // turnover lines align past the number
  spaceBetween: pt(2),
  separator: { width: 0.2, lineWidth: pt(0.5), color: col('rubric') },
};
````

## Ingredienti

**Insegna**

- [Notazione musicale](https://postext.dev/it/docs/music.md#una-partitura-nel-testo): Partiture scritte come testo in blocchi ```abc, ```musicxml, ```mei o ```humdrum, incise da Verovio alla larghezza della colonna e divise in sistemi che proseguono nella colonna o nella pagina seguente.
- [Note a piè di pagina](https://postext.dev/it/docs/document-format-notes-references.md#note-a-piè-di-pagina): Note citate con [^id] e composte al piede della colonna che le cita, o dopo il capitolo, numerate per capitolo o per tutto il libro.

**Usa anche**

- [Stile di partitura](https://postext.dev/it/docs/configuration-resources.md#stile-di-partitura)
- [Aperture progettate](https://postext.dev/it/docs/configuration-headings.md#estensione-e-grafica-avanzata)
- [Attributi dei titoli](https://postext.dev/it/docs/document-format.md#attributi-dei-titoli)
- [Testatine e folio](https://postext.dev/it/docs/configuration-headers-footers.md#intestazioni-e-piè-di-pagina)
- [Margini speculari](https://postext.dev/it/docs/configuration-page-layout.md#margini-speculari)
- [Testatine secondo il ruolo della pagina](https://postext.dev/it/docs/configuration-headers-footers.md#elementi-di-testo)
- [Stili di paragrafo](https://postext.dev/it/docs/configuration-styles.md#stili-di-paragrafo)
- [Tavolozza di colori semantica](https://postext.dev/it/docs/configuration-fonts-colors-viewers.md#tavolozza-dei-colori)
- [Colore della carta](https://postext.dev/it/docs/configuration-page-layout.md#pagina)
- [Vedove, orfane e righe corte](https://postext.dev/it/docs/configuration-page-flow.md#orfane-vedove-righe-finali-corte-e-regole-di-tenuta)
- [Esportazione in PDF](https://postext.dev/it/docs/configuration-pdf-output.md#generare-pdf)
- [Listati di codice](https://postext.dev/it/docs/configuration-styles.md#listati-di-codice)
- [Bilanciamento delle colonne](https://postext.dev/it/docs/configuration-page-flow.md#bilanciamento-delle-colonne)
- [Font incorporati nel PDF](https://postext.dev/it/docs/configuration-pdf-output.md#perché-un-provider-di-font)

**La configurazione in breve**

- [`bodyText`](https://postext.dev/it/docs/configuration-text.md#testo-corrente), [`colorPalette`](https://postext.dev/it/docs/configuration-fonts-colors-viewers.md#tavolozza-dei-colori), [`footer`](https://postext.dev/it/docs/configuration-headers-footers.md#intestazioni-e-piè-di-pagina), `footnotes`, [`header`](https://postext.dev/it/docs/configuration-headers-footers.md#intestazioni-e-piè-di-pagina), [`headings`](https://postext.dev/it/docs/configuration-headings.md#titoli), [`layout`](https://postext.dev/it/docs/configuration-page-layout.md#impaginazione), [`locale`](https://postext.dev/it/docs/configuration-language.md#sillabazione), [`page`](https://postext.dev/it/docs/configuration-page-layout.md#pagina), [`paragraphStyles`](https://postext.dev/it/docs/configuration-styles.md#stili-di-paragrafo), [`scoreStyle`](https://postext.dev/it/docs/configuration-resources.md#stile-di-partitura)

**API**

- [`buildDocumentWithFonts`](https://postext.dev/it/docs/configuration-programmatic-usage.md#caricare-i-font-prima-dellimpaginazione), [`decompressWoff2`](https://postext.dev/it/docs/configuration-pdf-output.md#provider-di-font-per-il-browser-fontsource--woff2), [`initMusicEngine`](https://postext.dev/it/docs/music.md#una-partitura-nel-testo), [`renderPageToCanvas`](https://postext.dev/it/docs/configuration-programmatic-usage.md#rasterizzare-una-pagina), [`renderToPdf`](https://postext.dev/it/docs/configuration-pdf-output.md#generare-pdf)

**Caratteri**

- Crimson Pro (OFL-1.1), Cormorant Garamond (OFL-1.1), Source Sans 3 (OFL-1.1)

## Preparazione

### 1 · Scrivi ogni esempio in MEI, con le sue varianti

Le impostazioni sono nella [risposta breve](https://postext.dev/it/cookbook/musicology-mei-apparatus.md#la-risposta-breve) qui sopra; la musica sta nel Markdown, un blocco ```` ```mei ```` per esempio. Dove due fonti divergono, la battuta contiene un `<app>` con la lezione accolta in `<lem>` e l’altra in `<rdg source="#Hw #Bu">`. Si incide il lemma: la battuta 40 dell’[esempio 3.3](https://postext.dev/cookbook/musicology-mei-apparatus/en/p05.webp?v=cd2d6301) mostra il la, e il sol di Hawkins e Burney resta nel file per chi apre la codifica. Dai a ogni blocco un `alt` nella lingua della pagina: è ciò che leggono della partitura uno screen reader e il PDF con tag.

### 2 · Lega l’apparato alle battute che il lettore vede

`barNumbers: 'system'` numera la prima battuta di ogni sistema, e il `<measure n="37">` di ogni blocco fa partire il conto da dove comincia il brano nell’edizione seguita: l’esempio 3.3 si apre quindi a 37, e una nota che dice «b. 40» rimanda a una battuta che il lettore trova. La voce d’apparato è una normale nota a piè di pagina, richiamata dal paragrafo che commenta la battuta: lemma, parentesi quadra di chiusura, variante, sigle in corsivo. Una nota non si può richiamare dall’interno di una partitura, perciò il richiamo va nella frase che nomina la lezione.

### 3 · Dimensiona la musica per il testo corrente

Un rigo di 5 mm in Leipzig sta in una giustezza di 116 mm con cinque o sei battute di 3/2 per sistema, e le undici battute dell’esempio 3.3 stanno in due sistemi. `textFont` compone il testo cantato in Crimson Pro, il carattere del testo, e `minSystemsAtBreak: 2` impedisce che una pagina finisca con un solo sistema di un esempio il cui resto passa alla pagina seguente. Il titolo di ogni esempio è un titolo di terzo livello, quindi non resta mai in fondo alla pagina senza la sua partitura.

### 4 · Lascia che una pagina con note finisca corta

```js
// script.js, righe 64–78
const opener = {
  enabled: true,
  minHeight: mm(50), // every chapter's text starts on the same grid line
  slot: { elements: [
    { kind: 'text', id: 'kicker', content: '{attr.kicker}', ...label, fontSize: pt(8.5),
      letterSpacing: pt(1.8), color: col('rubric'), align: 'left',
      placement: at('container', 'top-left', 0, 8) },
    { kind: 'text', id: 'title', content: '{titleText}', fontFamily: 'Cormorant Garamond',
      italic: true, fontWeight: 500, fontSize: pt(29), lineHeight: 1.05, color: col('ink'),
      align: 'left', overflow: 'wrap', // design text ends in an ellipsis by default
      placement: { ...at('#kicker', 'below', 0, 3), size: { width: mm(100), height: 'auto' } } },
    { kind: 'rule', id: 'rule', direction: 'horizontal', thickness: pt(1), color: col('rubric'),
      placement: { ...at('#title', 'below', 0, 5), size: { width: mm(14) } } },
  ] },
};
```

L’apertura abbassa il testo di 50 mm sotto un titolo in Cormorant corsivo. Più avanti, una pagina la cui riga seguente si porterebbe dietro una nota lunga finisce qualche riga prima, e `balancing: { maxLinesPerHeading: 1 }` impedisce al bilanciamento delle colonne di spostare quel vuoto sopra il titolo della sezione seguente, dove sembrerebbe una cesura nel ragionamento.

### 5 · Metti il libro sul verso e il capitolo sul recto

```js
// script.js, righe 82–99
const head = (id, content, parity, edge, x, extra = {}) => ({
  kind: 'text', id, content, parity, pages: 'body', // never on the opener
  ...label, fontSize: pt(7.5), letterSpacing: pt(1.3), color: col('muted'),
  placement: at('page', edge, x, 13), ...extra,
});
const folio = { color: col('rubric'), fontWeight: 700 };
const header = { elements: [
  head('verso-folio', '{pageNumber}', 'even', 'top-left', MARGIN.outer,
    { ...folio, align: 'left' }),
  head('verso-title', '{title}', 'even', 'top-left', MARGIN.outer + 8, { align: 'left' }),
  head('recto-title', '{chapterTitle}', 'odd', 'top-right', -(MARGIN.outer + 8),
    { align: 'right', overflow: 'ellipsis' }),
  head('recto-folio', '{pageNumber}', 'odd', 'top-right', -MARGIN.outer,
    { ...folio, align: 'right' }),
] };
// The opener carries a drop folio instead, centred under the text block.
const footer = { elements: [{ ...head('drop-folio', '{pageNumber}', 'all', 'bottom', 0,
  { ...folio, align: 'center', placement: at('page', 'bottom', 0, -11) }), pages: 'opener' }] };
```

I numeri di pagina in rosso di rubrica sul margine esterno, il libro sul verso e il capitolo sul recto; `pages: 'body'` li toglie dall’apertura, che ha un numero di pagina centrato al piede.

## La ricetta completa

Un unico file, composto a partire dalla cartella della ricetta con il testo di esempio e il kit comune del Ricettario già inclusi; costruisce la propria pagina. Per eseguirlo, mettilo in uno `<script type="module">` di una pagina vuota, oppure incollalo nel pannello JS di un nuovo pen di CodePen (come modulo). Importa postext da esm.sh: non c’è niente da installare né da compilare.

- Cartella della ricetta: https://github.com/drnachio/postext/tree/main/cookbook/musicology-mei-apparatus

### script.js

````js
// ═══ Postext Cookbook · Nº 165 · MEI music examples with a critical apparatus ═════
// https://postext.dev/en/cookbook/musicology-mei-apparatus
// Code: MIT · Text: original (CC BY 4.0) · Music: Sumer is icumen in, after Rockstro (PD)
// Fonts: Crimson Pro, Cormorant Garamond, Source Sans 3 (SIL OFL 1.1) · Needs postext ≥ 1.54.0
import {
  buildDocumentWithFonts, renderPageToCanvas, initMusicEngine,
} from 'https://esm.sh/postext';
import { renderToPdf, decompressWoff2 } from 'https://esm.sh/postext-pdf';

const LANG = 'en'; // @lang: the language of the sample document ('en' | 'es')
const RECIPE = 'musicology-mei-apparatus';

// ─── 1 · Design ─────────────────────────────────────────────────────────────
// #region palette: a rubric red for kickers, labels and the notes' rule; ink on cream
const palette = {
  ink: '#211d1a', // text and notation: a warm near-black
  rubric: '#8c2f1f', // the one accent, the red of the manuscript's rubrics
  muted: '#6c645b', // running heads, colophon
  rule: '#cbbfae', // hairlines
  paper: '#fcfaf6',
};
// col(id): a colour linked to its palette entry, with the entry's hex beside the id.
const col = (id) => ({ hex: palette[id], model: 'hex', paletteId: id });
const colorPalette = [
  ...Object.entries(palette).map(([id, hex]) => ({ id, name: id, value: { hex, model: 'hex' } })),
  // The engine's defaults link to main-color: point it at the accent, never the default blue.
  { id: 'main-color', name: 'accent (defaults)', value: { hex: palette.rubric, model: 'hex' } },
];
// #endregion
const MARGIN = { top: 22, bottom: 22, inner: 19, outer: 21 }; // 156 × 234 mm, mirrored
const LEAD = 14.5; // body leading in pt: the baseline grid
const at = (to, edge, x = 0, y = 0) => ({ anchor: { to, edge }, offset: { x: mm(x), y: mm(y) } });
const label = { fontFamily: 'Source Sans 3', fontWeight: 600, textTransform: 'uppercase' };

// #region answer: MEI examples engraved in the text, their apparatus in footnotes
// In the Markdown each example is a ```mei fence. A variant is encoded where it stands,
// <app><lem>…</lem><rdg source="#Hw #Bu">…</rdg></app>: the staff shows the lemma, and
// the file keeps the reading for anyone who opens the encoding. The apparatus entry is a
// footnote cited from the paragraph that discusses the bar: `[^b40]: **b. 40, n. 2** A ] G`.
const scoreStyle = {
  staffSize: mm(5), // running-text examples: 4.5–5.5 mm
  musicFont: 'Leipzig', // lighter than Bravura, close to a 19th-century plate
  textFont: 'Crimson Pro', // the underlay in the book's own face
  barNumbers: 'system', // the apparatus is keyed by bar: number every system
  spacing: 0.95,
  systemGap: mm(4),
  marginTop: pt(4),
  marginBottom: pt(LEAD / 2),
  color: col('ink'),
  minSystemsAtBreak: 2, // never leave one system of an example alone at a page foot
};
const footnotes = {
  placement: 'column', // the foot of the page in one column
  numbering: 'chapter',
  fontSize: pt(8.5),
  lineHeight: pt(10.75),
  hangingIndent: em(1.2), // turnover lines align past the number
  spaceBetween: pt(2),
  separator: { width: 0.2, lineWidth: pt(0.5), color: col('rubric') },
};
// #endregion

// #region opener: kicker, a Cormorant italic title and a short red rule, sunk 50 mm
const opener = {
  enabled: true,
  minHeight: mm(50), // every chapter's text starts on the same grid line
  slot: { elements: [
    { kind: 'text', id: 'kicker', content: '{attr.kicker}', ...label, fontSize: pt(8.5),
      letterSpacing: pt(1.8), color: col('rubric'), align: 'left',
      placement: at('container', 'top-left', 0, 8) },
    { kind: 'text', id: 'title', content: '{titleText}', fontFamily: 'Cormorant Garamond',
      italic: true, fontWeight: 500, fontSize: pt(29), lineHeight: 1.05, color: col('ink'),
      align: 'left', overflow: 'wrap', // design text ends in an ellipsis by default
      placement: { ...at('#kicker', 'below', 0, 3), size: { width: mm(100), height: 'auto' } } },
    { kind: 'rule', id: 'rule', direction: 'horizontal', thickness: pt(1), color: col('rubric'),
      placement: { ...at('#title', 'below', 0, 5), size: { width: mm(14) } } },
  ] },
};
// #endregion

// #region running-heads: book title on the verso, chapter on the recto, folios outside
const head = (id, content, parity, edge, x, extra = {}) => ({
  kind: 'text', id, content, parity, pages: 'body', // never on the opener
  ...label, fontSize: pt(7.5), letterSpacing: pt(1.3), color: col('muted'),
  placement: at('page', edge, x, 13), ...extra,
});
const folio = { color: col('rubric'), fontWeight: 700 };
const header = { elements: [
  head('verso-folio', '{pageNumber}', 'even', 'top-left', MARGIN.outer,
    { ...folio, align: 'left' }),
  head('verso-title', '{title}', 'even', 'top-left', MARGIN.outer + 8, { align: 'left' }),
  head('recto-title', '{chapterTitle}', 'odd', 'top-right', -(MARGIN.outer + 8),
    { align: 'right', overflow: 'ellipsis' }),
  head('recto-folio', '{pageNumber}', 'odd', 'top-right', -MARGIN.outer,
    { ...folio, align: 'right' }),
] };
// The opener carries a drop folio instead, centred under the text block.
const footer = { elements: [{ ...head('drop-folio', '{pageNumber}', 'all', 'bottom', 0,
  { ...folio, align: 'center', placement: at('page', 'bottom', 0, -11) }), pages: 'opener' }] };
// #endregion

const config = {
  locale: t({ en: 'en-gb', es: 'es' }), // the language of the hyphenation patterns
  colorPalette,
  page: { sizePreset: 'custom', width: mm(156), height: mm(234), dpi: 150,
    backgroundColor: col('paper'),
    margins: { top: mm(MARGIN.top), bottom: mm(MARGIN.bottom), left: mm(MARGIN.inner),
      right: mm(MARGIN.outer), mirror: true } }, // left = inner
  layout: { layoutType: 'single' },
  bodyText: { fontFamily: 'Crimson Pro', fontSize: pt(11), lineHeight: pt(LEAD),
    color: col('ink'), boldColor: col('ink'), italicColor: col('ink'), referenceColor: col('ink'),
    textAlign: 'justify', firstLineIndent: mm(4.5), indentAfterHeading: false,
    hyphenation: { enabled: true }, optimalLineBreaking: true,
    avoidWidows: true, avoidOrphans: true, avoidRunts: true },
  headings: { fontFamily: 'Crimson Pro', color: col('ink'),
    // A page whose next line cannot take its footnote ends short: at most one extra grid
    // line goes above a heading, the rest stays at the foot, as in a book with notes.
    balancing: { maxLinesPerHeading: 1 },
    levels: [
    { level: 1, advancedDesign: opener, marginBottom: pt(0),
      breakBefore: { enabled: true, parity: 'odd' } },
    { level: 2, fontFamily: 'Cormorant Garamond', fontSize: pt(14), lineHeight: pt(LEAD),
      fontWeight: 600, italic: true, color: col('ink'), marginTop: pt(LEAD), marginBottom: pt(3) },
    // The example labels: a heading keeps itself with the score under it.
    { level: 3, ...label, fontSize: pt(7.5), lineHeight: pt(LEAD), letterSpacing: pt(1.1),
      color: col('rubric'), marginTop: pt(LEAD / 2), marginBottom: pt(0) },
  ] },
  paragraphStyles: [
    { id: 'colophon', ...label, textTransform: 'none', fontWeight: 400, fontSize: pt(7.5),
      lineHeight: pt(10), color: col('muted'), textAlign: 'left', firstLineIndent: pt(0),
      marginTop: pt(LEAD) },
  ],
  scoreStyle,
  footnotes,
  header,
  footer,
};

// ─── 2 · Content ────────────────────────────────────────────────────────────
const markdown = `---
title: "The Antiquaries’ Middle Ages"
---

# The Reading Rota and Its Editors {kicker="Chapter 3"}

No piece of medieval music was printed, scored and argued over by English antiquaries as often as the six-voice rota *Sumer is icumen in*. It survives on a single leaf, fol. 11v of the miscellany that Humfrey Wanley described for the Earl of Oxford around 1709 and that is now British Library, Harley MS 978. Wanley called it the oldest piece of its kind he had seen. Between Sir John Hawkins’s *General History* of 1776 and the article that William Smyth Rockstro wrote for George Grove’s *Dictionary of Music and Musicians*, the rota went through at least five scores, each claiming to correct the last.

This chapter follows that sequence of editions and tests it at three places where the editors disagreed. The music examples are new transcriptions, and their critical apparatus stands in the notes: each entry gives the bar and the note, the reading adopted, a closing bracket, and the readings of the other witnesses.

## The witnesses and this edition

Four witnesses are cited. **H** is the manuscript. **Hw** is the score in the first volume of Hawkins’s *General History of the Science and Practice of Music* (1776). **Bu** is the score in the second volume of Charles Burney’s *General History of Music* (1782). **Ro** is Rockstro’s solution of the canon, printed with the first part of his article in the third volume of Grove’s *Dictionary*.[^ro]

The examples follow Ro in pitch, clefs and note values, since Rockstro is the only editor of the period who explains every substitution he made. The manuscript, he writes, uses only a C clef, the *B rotundum*, square black notes with tails, one square note without a tail, and black lozenges. He renders a tailed note as a dotted semibreve when it is perfect and as a semibreve when it is imperfect, the untailed square note as a semibreve, and the lozenges as minims, under a signature of perfect time with the lesser prolation, “closely corresponding with the Signature 3-2 in modern Music”.[^values] The readings of H, Hw and Bu below are those that Rockstro reports. This chapter has not collated the two eighteenth-century prints afresh, and where Rockstro is silent, the apparatus is silent too.

## The first phrase and a corrected note

### Example 3.1 · Cantus I, bars 1–7, with the English and Latin texts

\`\`\`mei {alt="Sumer is icumen in, the first voice, bars 1 to 7, with the English words and the Latin text Perspice Christicola"}
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="5.1">
<meiHead><fileDesc><titleStmt><title>Sumer is icumen in, Cantus I, bars 1–7</title></titleStmt><pubStmt/><sourceDesc><source xml:id="H"><bibl>BL Harley 978, f. 11v</bibl></source><source xml:id="Ro"><bibl>Rockstro, Grove iii</bibl></source></sourceDesc></fileDesc></meiHead>
<music><body><mdiv><score>
<scoreDef meter.count="3" meter.unit="2" keysig="1f"><staffGrp><staffDef n="1" lines="5" clef.shape="G" clef.line="2"/></staffGrp></scoreDef>
<section>
<measure n="1"><staff n="1"><layer n="1"><note pname="f" oct="5" dur="1"><verse n="1"><syl wordpos="i" con="d">Sum</syl></verse><verse n="2"><syl wordpos="i" con="d">Per</syl></verse></note><app><lem><note pname="e" oct="5" dur="2"><verse n="1"><syl wordpos="t">er</syl></verse><verse n="2"><syl wordpos="m" con="d">spi</syl></verse></note></lem><rdg source="#H"><note pname="f" oct="5" dur="2"><verse n="1"><syl wordpos="t">er</syl></verse><verse n="2"><syl wordpos="m" con="d">spi</syl></verse></note></rdg></app></layer></staff></measure>
<measure n="2"><staff n="1"><layer n="1"><note pname="d" oct="5" dur="1"><verse n="1"><syl>is</syl></verse><verse n="2"><syl wordpos="t">ce</syl></verse></note><note pname="e" oct="5" dur="2"><verse n="1"><syl wordpos="i" con="d">i</syl></verse><verse n="2"><syl wordpos="i" con="d">Chri</syl></verse></note></layer></staff></measure>
<measure n="3"><staff n="1"><layer n="1"><note pname="f" oct="5" dur="1"><verse n="1"><syl wordpos="m" con="d">cum</syl></verse><verse n="2"><syl wordpos="m" con="d">sti</syl></verse></note><note pname="f" oct="5" dur="2"><verse n="1"><syl wordpos="t">en</syl></verse><verse n="2"><syl wordpos="m" con="d">co</syl></verse></note></layer></staff></measure>
<measure n="4"><staff n="1"><layer n="1"><note pname="e" oct="5" dur="2" dots="1"><verse n="1"><syl>in,</syl></verse><verse n="2"><syl wordpos="t">la,</syl></verse></note><note pname="d" oct="5" dur="4"/><note pname="c" oct="5" dur="2"/></layer></staff></measure>
<measure n="5"><staff n="1"><layer n="1"><note pname="a" oct="4" dur="1"><verse n="1"><syl wordpos="i" con="d">Lhud</syl></verse><verse n="2"><syl>que</syl></verse></note><note pname="a" oct="4" dur="2"><verse n="1"><syl wordpos="t">e</syl></verse><verse n="2"><syl wordpos="i" con="d">dig</syl></verse></note></layer></staff></measure>
<measure n="6"><staff n="1"><layer n="1"><note pname="b" oct="4" dur="1"><verse n="1"><syl>sing</syl></verse><verse n="2"><syl wordpos="m" con="d">na</syl></verse></note><note pname="g" oct="4" dur="2"><verse n="1"><syl wordpos="i" con="d">cuc</syl></verse><verse n="2"><syl wordpos="m" con="d">ci</syl></verse></note></layer></staff></measure>
<measure n="7"><staff n="1"><layer n="1"><note pname="a" oct="4" dur="1" dots="1"><verse n="1"><syl wordpos="t">cu.</syl></verse><verse n="2"><syl wordpos="t">o.</syl></verse></note></layer></staff></measure>
</section></score></mdiv></body></music></mei>
\`\`\`

The opening is the best-documented phrase of the rota, because Rockstro returned to the leaf itself in the second part of his article and listed the erasures he could see. The scribe corrected his own work in the same ink, and the first correction falls on the second note.[^b1] Rockstro took the erasures as improvements made while the piece was being written down rather than as repairs of a faulty copy, and used them to support his view that the canon grew out of a popular tune that a trained musician adjusted until its phrases fitted against one another.

Two further decisions are visible in bars 2 and 4. The Latin text is printed in full where the manuscript abbreviates the name of Christ,[^b2] and the single tailed lozenge under the word *in* becomes a dotted minim and a crotchet.[^b4] The flat in the signature stands for the *B rotundum* of the manuscript, which Rockstro reads as a B flat throughout.[^bflat]

## The pes

### Example 3.2 · Pes, bars 1–8, as scored by Rockstro

\`\`\`mei {alt="Sumer is icumen in, the two lower voices of the pes, bars 1 to 8"}
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="5.1">
<meiHead><fileDesc><titleStmt><title>Sumer is icumen in, the pes, bars 1–8</title></titleStmt><pubStmt/><sourceDesc><source xml:id="Ro"><bibl>Rockstro, Grove iii</bibl></source></sourceDesc></fileDesc></meiHead>
<music><body><mdiv><score>
<scoreDef meter.count="3" meter.unit="2" keysig="1f"><staffGrp symbol="bracket" bar.thru="false"><staffDef n="1" lines="5" clef.shape="F" clef.line="4"/><staffDef n="2" lines="5" clef.shape="F" clef.line="4"/></staffGrp></scoreDef>
<section>
<measure n="1"><staff n="1"><layer n="1"><note pname="f" oct="3" dur="1" dots="1"><verse n="1"><syl>Sing</syl></verse></note></layer></staff><staff n="2"><layer n="1"><note pname="c" oct="4" dur="1" dots="1"><verse n="1"><syl>Sing</syl></verse></note></layer></staff></measure>
<measure n="2"><staff n="1"><layer n="1"><note pname="g" oct="3" dur="1" dots="1"><verse n="1"><syl wordpos="i" con="d">cuc</syl></verse></note></layer></staff><staff n="2"><layer n="1"><note pname="b" oct="3" dur="1" dots="1"><verse n="1"><syl wordpos="i" con="d">cuc</syl></verse></note></layer></staff></measure>
<measure n="3"><staff n="1"><layer n="1"><note pname="f" oct="3" dur="1" dots="1"><verse n="1"><syl wordpos="t">cu</syl></verse></note></layer></staff><staff n="2"><layer n="1"><note pname="c" oct="4" dur="1" dots="1"><verse n="1"><syl wordpos="t">cu.</syl></verse></note></layer></staff></measure>
<measure n="4"><staff n="1"><layer n="1"><note pname="g" oct="3" dur="1"><verse n="1"><syl>nu.</syl></verse></note><note pname="a" oct="3" dur="2"/></layer></staff><staff n="2"><layer n="1"><mRest/></layer></staff></measure>
<measure n="5"><staff n="1"><layer n="1"><note pname="c" oct="4" dur="1" dots="1"><verse n="1"><syl>Sing</syl></verse></note></layer></staff><staff n="2"><layer n="1"><note pname="f" oct="3" dur="1" dots="1"><verse n="1"><syl>Sing</syl></verse></note></layer></staff></measure>
<measure n="6"><staff n="1"><layer n="1"><note pname="b" oct="3" dur="1" dots="1"><verse n="1"><syl wordpos="i" con="d">cuc</syl></verse></note></layer></staff><staff n="2"><layer n="1"><note pname="g" oct="3" dur="1" dots="1"><verse n="1"><syl wordpos="i" con="d">cuc</syl></verse></note></layer></staff></measure>
<measure n="7"><staff n="1"><layer n="1"><note pname="c" oct="4" dur="1" dots="1"><verse n="1"><syl wordpos="t">cu.</syl></verse></note></layer></staff><staff n="2"><layer n="1"><note pname="f" oct="3" dur="1" dots="1"><verse n="1"><syl wordpos="t">cu</syl></verse></note></layer></staff></measure>
<measure n="8"><staff n="1"><layer n="1"><mRest/></layer></staff><staff n="2"><layer n="1"><note pname="g" oct="3" dur="1"><verse n="1"><syl>nu.</syl></verse></note><note pname="a" oct="3" dur="2"/></layer></staff></measure>
</section></score></mdiv></body></music></mei>
\`\`\`

Below the four voices of the canon the manuscript writes two short parts to be sung as a ground, each to the words *Sing cuccu nu*. The Latin rubric opens *Hanc rotam cantare possunt quatuor socii*: four companions can sing the round, not counting those who hold the pes. Each new voice begins “at the first note after the cross”, which Ro marks over bar 5. The first pes is repeated *faciens pausacionem in fine*, the second *pausans in medio et non in fine*.[^rubric] Ro follows the rubric exactly: the first pes rests in bar 8, the second in bar 4, so that one of the two lower voices is always sounding.

The pes is also where the eighteenth-century scores went most visibly wrong. According to Rockstro, Hawkins misread both of its ligatures and printed the passage incorrectly at every repetition; Burney corrected the mistake.[^lig] Neither ligature can be shown in a modern score, and Example 3.2 resolves both into separate notes, as Ro does.

Rockstro’s own analysis of the part-writing begins from this score. The fourth, sixth, seventh, eighth and twenty-fourth bars, he observes, are in strict two-part counterpoint “of irreproachable purity”, while the passage from bar 9 to bar 10 gives consecutive fifths between the first and third voices of the canon, and bars 37 to 39 three consecutive fifths between the first cantus and the second voice of the pes.[^fifths] For Rockstro the mixture of styles was the strongest argument for a melody older than its harmony.

## The question of date

The dates proposed for the leaf say as much about the editors as about the manuscript. Hawkins placed it in the middle of the fifteenth century, arguing that its notation was the *cantus figuratus* he credited to John Dunstable, who, Hawkins wrote, died in 1455; Rockstro called the reasoning an anachronism “absolutely worthless”.[^hawkins] Burney thought the piece not much later than the thirteenth or fourteenth century. Joseph Ritson referred the manuscript to the middle of the thirteenth, and Thomas Busby, reprinting Burney’s score note for note in 1819, returned it to the fifteenth.

The decisive arguments came from palaeography. In 1855 William Chappell published a coloured facsimile in *Popular Music of the Olden Time* and later argued that the leaf was written at Reading Abbey by a monk named John of Fornsete around 1226. In April 1862 Sir Frederick Madden noted on a flyleaf of the volume that the whole was of the thirteenth century and that its earlier part had been written at Reading about 1240, a date the Palaeographical Society adopted for its facsimile of 1878. On the Continent, Johann Nikolaus Forkel (1788), August Wilhelm Ambros (1862 and 1868) and Edmond de Coussemaker (1865) all wrote on the rota without seeing the manuscript, a point Rockstro makes against each of them in turn.[^continent] A more recent study puts the copying between 1261 and 1264.[^wulstan]

## “Cuccu” in bar 40

### Example 3.3 · Cantus I, bars 37–47

\`\`\`mei {alt="Sumer is icumen in, the first voice, bars 37 to 47, from Cuccu, cuccu to ne swik thu nauer nu"}
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="5.1">
<meiHead><fileDesc><titleStmt><title>Sumer is icumen in, Cantus I, bars 37–47</title></titleStmt><pubStmt/><sourceDesc><source xml:id="Hw"><bibl>Hawkins 1776</bibl></source><source xml:id="Bu"><bibl>Burney 1782</bibl></source><source xml:id="Ro"><bibl>Rockstro, Grove iii</bibl></source></sourceDesc></fileDesc></meiHead>
<music><body><mdiv><score>
<scoreDef meter.count="3" meter.unit="2" keysig="1f"><staffGrp><staffDef n="1" lines="5" clef.shape="G" clef.line="2"/></staffGrp></scoreDef>
<section>
<measure n="37"><staff n="1"><layer n="1"><note pname="c" oct="5" dur="1" dots="1"><verse n="1"><syl wordpos="i" con="d">Cuc</syl></verse></note></layer></staff></measure>
<measure n="38"><staff n="1"><layer n="1"><note pname="d" oct="5" dur="1" dots="1"><verse n="1"><syl wordpos="t">cu,</syl></verse></note></layer></staff></measure>
<measure n="39"><staff n="1"><layer n="1"><note pname="c" oct="5" dur="1" dots="1"><verse n="1"><syl wordpos="i" con="d">cuc</syl></verse></note></layer></staff></measure>
<measure n="40"><staff n="1"><layer n="1"><note pname="b" oct="4" dur="1"><verse n="1"><syl wordpos="t">cu.</syl></verse></note><app><lem><note pname="a" oct="4" dur="2"/></lem><rdg source="#Hw #Bu"><note pname="g" oct="4" dur="2"/></rdg></app></layer></staff></measure>
<measure n="41"><staff n="1"><layer n="1"><note pname="f" oct="4" dur="1"><verse n="1"><syl>Wel</syl></verse></note><note pname="a" oct="4" dur="2"><verse n="1"><syl wordpos="i" con="d">sing</syl></verse></note></layer></staff></measure>
<measure n="42"><staff n="1"><layer n="1"><note pname="b" oct="4" dur="1"><verse n="1"><syl wordpos="t">es</syl></verse></note><note pname="g" oct="4" dur="2"><verse n="1"><syl>thu</syl></verse></note></layer></staff></measure>
<measure n="43"><staff n="1"><layer n="1"><note pname="a" oct="4" dur="1" dots="1"><verse n="1"><syl wordpos="i" con="d">cuc</syl></verse></note></layer></staff></measure>
<measure n="44"><staff n="1"><layer n="1"><note pname="b" oct="4" dur="1"><verse n="1"><syl wordpos="t">cu,</syl></verse></note><note pname="c" oct="5" dur="2"><verse n="1"><syl>ne</syl></verse></note></layer></staff></measure>
<measure n="45"><staff n="1"><layer n="1"><note pname="a" oct="4" dur="1"><verse n="1"><syl>swik</syl></verse></note><note pname="c" oct="5" dur="2"><verse n="1"><syl>thu</syl></verse></note></layer></staff></measure>
<measure n="46"><staff n="1"><layer n="1"><note pname="g" oct="4" dur="1"><verse n="1"><syl wordpos="i" con="d">nau</syl></verse></note><note pname="e" oct="4" dur="2"><verse n="1"><syl wordpos="t">er</syl></verse></note></layer></staff></measure>
<measure n="47"><staff n="1"><layer n="1"><note pname="f" oct="4" dur="1" dots="1"><verse n="1"><syl>nu.</syl></verse></note></layer></staff></measure>
</section></score></mdiv></body></music></mei>
\`\`\`

The last passage of the tune shows how an error could travel. Hawkins and Burney, Rockstro reports, both print a G where the manuscript has an A in bar 40, on the second syllable of *cuccu*, and they do so each time the phrase returns in a new voice.[^b40] Against Hawkins’s faulty pes the G passes; against Burney’s corrected pes it makes what Rockstro calls “a horrible discord”. The variant is encoded in the source of Example 3.3 as a reading of Hw and Bu, while the engraved staff shows the lemma.

Both historians also fitted the words to the notes differently from the manuscript from bar 41 onwards, at *Wel singes thu cuccu, ne swik thu nauer nu*.[^b41] Rockstro gives no details of their underlay, and the example therefore records only the fact. The one modern copy Rockstro knew went further and left out the pes, reducing the rota to four parts.

:::paragraphs{style="colophon"}
Set in Crimson Pro, Cormorant Garamond and Source Sans 3 (SIL OFL); music in Leipzig, engraved by Verovio · Text: original, CC BY 4.0 · Music: *Sumer is icumen in* (13th century), after W. S. Rockstro’s score in Grove’s *Dictionary of Music and Musicians*, iii, 766–767 (public domain)
:::

[^ro]: W. S. Rockstro, “Sumer is icumen in”, in G. Grove (ed.), *A Dictionary of Music and Musicians*, iii, 765–768, continued in iv, 1–3 (London: Macmillan, 1900 printing). The score, iii, 766–767, is cited from the Wikisource transcription of that printing.

[^values]: Ro, iii, 765. The tailed lozenge on the first note of *in* is the one exception (see the note on bar 4).

[^b1]: **b. 1, n. 2** E ] F *H* before correction (“The second note on Stave 1 was originally an F”, Ro, iv, 1). The reading before correction is encoded as a variant in Example 3.1.

[^b2]: **b. 2, n. 2 – b. 4, n. 1** *Chri-sti-co-la* ] abbreviated with the Greek letters *chi* and *rho* *H*, Ro. Expanded as Rockstro glosses it, *Christicola* (iii, 765).

[^b4]: **b. 4, nn. 1–2** dotted minim, crotchet ] one lozenge with a tail *H*, the only tailed lozenge in the manuscript, which Rockstro could “scarcely conceive to be accidental” (iii, 765).

[^bflat]: **bb. 1–7, signature** B flat ] *B rotundum* *H*. The flat is printed in the signature, as in Ro.

[^rubric]: The rubric is quoted from the transcription and translation in the Wikipedia article “Sumer is icumen in”, which also gives the folio. Rockstro scores the canon “in exact accordance with the Latin directions” (iii, 765) but does not print them.

[^lig]: **Pes, bb. 1–8** both ligatures misread at every statement *Hw*; corrected *Bu* (Ro, iii, 765). Rockstro does not say how Hawkins read them, so no variant is encoded.

[^fifths]: Ro, iv, 2. The bar numbers refer to Rockstro’s score and to the examples of this chapter.

[^hawkins]: Ro, iii, 765. Rockstro dates Hawkins’s first volume 1770; the *General History* appeared in 1776.

[^continent]: Ro, iii, 768, and iv, 1, citing Forkel, *Allgemeine Geschichte der Musik*, ii, 490–500; Ambros, *Geschichte der Musik*, ii, 473–475; Coussemaker, *L’Art harmonique*, 144.

[^wulstan]: D. Wulstan, “‘Sumer is icumen in’: A Perpetual Puzzle-Canon?”, *Plainsong and Medieval Music* 9 (2000), 1–17, at 8. Wulstan proposes W. de Wycombe as the scribe.

[^b40]: **b. 40, n. 2** A ] G *Hw*, *Bu* (and Busby 1819, after *Bu*), at every entry of the phrase (Ro, iii, 765). Encoded as a variant in Example 3.3.

[^b41]: **bb. 41–47, underlay** as *H* ] text placed otherwise under the notes *Hw*, *Bu* (Ro, iii, 765).
`; // content.<lang>.md, inlined by the Cookbook

// ─── 3 · Fonts ──────────────────────────────────────────────────────────────
// Every face the design uses, loaded before the first build with the ones the config names.
const FONTS = {
  'Crimson Pro': ['400', '400i', '600', '600i', '700'],
  'Cormorant Garamond': ['500i', '600i'],
  'Source Sans 3': ['400', '600', '700'],
};

// ─── 4 · Build & show ───────────────────────────────────────────────────────
await initMusicEngine(); // Verovio, loaded only by books that hold a score
const doc = await buildDocumentWithFonts({ markdown }, config, kitFonts(FONTS));
showPages(doc, { title: t({ en: 'Music examples with a critical apparatus',
  es: 'Ejemplos musicales con aparato crítico' }) });
offerPdf(() => renderToPdf(doc, { fontProvider: fontsourceProvider }), `${RECIPE}.pdf`);

// ─── Kit ── helpers shared by every Cookbook recipe · postext.dev/cookbook ─────

// ─── Kit · core v1 ── the same in every recipe · postext.dev/cookbook
function mm(value) { return { value, unit: 'mm' }; }
function pt(value) { return { value, unit: 'pt' }; }
function em(value) { return { value, unit: 'em' }; }
/** The sample language's string: t({ en: 'Figure', es: 'Figura' }). */
function t(strings) { return strings[LANG] ?? Object.values(strings)[0]; }
/** A file in this recipe's assets folder, served from the Postext repo by jsDelivr. */
function asset(file) { return `https://cdn.jsdelivr.net/gh/drnachio/postext@main/cookbook/${RECIPE}/assets/${file}`; }

// ─── Kit · fonts v3 ── the same in every recipe · postext.dev/cookbook
// Postext loads the faces a config asks for before layout (prepareFonts,
// buildDocumentWithFonts) and asks the kit for the files: Fontsource's, the
// files the PDF embeds too.

/** The options of buildDocumentWithFonts / prepareFonts / withLoadedFonts:
 *  the Fontsource resolver, and the faces of FONTS loaded with the ones the
 *  config names. FONTS = { 'Family Name': ['400', '400i', '700'] }. */
function kitFonts(FONTS = {}) {
  const faces = Object.entries(FONTS).flatMap(([family, specs]) => specs.map((spec) =>
    ({ family, weight: parseInt(spec, 10), style: spec.endsWith('i') ? 'italic' : 'normal' })));
  return { resolve: fontsourceResolver, faces };
}

/** A face's Fontsource files, in a fixed order: latin, then latin-ext and greek
 *  when `text` needs them and the family ships them (kitSubsetsFor), each with
 *  its unicode-range. Null for a weight or slant Fontsource does not ship. */
async function fontsourceResolver(family, weight, style, { text = '' } = {}) {
  const id = fontsourceId(family);
  const meta = await fontsourceMeta(family);
  if (meta && !(meta.weights.includes(weight) && meta.styles.includes(style))) return null;
  kitStatus('Loading fonts…');
  const at = await fontsourceAt(id);
  return ['latin', ...kitSubsetsFor(text, meta)].map((subset) => ({
    source: `${at}files/${id}-${subset}-${weight}-${style}.woff2`,
    unicodeRange: kitRanges()[subset],
  }));
}

/** The unicode-range of each Fontsource file the kit loads (a function: the
 *  kit is inlined after the pen's code, which runs before a const would be set). */
function kitRanges() {
  return {
    latin: 'U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,'
      + 'U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD',
    'latin-ext': 'U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,'
      + 'U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF',
    greek: 'U+0370-03FF',
  };
}

/** For the cjk, arabic and comics blocks, which add their own files: the
 *  faces of `faces` = { 'Family Name': ['400', '400i', '700'] }. `text` is the sample:
 *  č ł † α χ also load latin-ext and greek files (kitSubsetsFor). With
 *  `optional`, a face Fontsource does not ship is skipped instead of failing.
 *  The files are added once all have loaded, in the order asked (latin, then
 *  latin-ext, then greek), whatever order they arrive in: the last one added
 *  wins a character two files hold. Resolves to the number of faces added. */
async function loadFonts(faces, text = '', { optional = false } = {}) {
  kitStatus('Loading fonts…');
  const ranges = kitRanges();
  const jobs = [];
  for (const [family, specs] of Object.entries(faces)) {
    const id = fontsourceId(family);
    const todo = [...new Set(specs)].map((spec) => [parseInt(spec, 10), spec.endsWith('i') ? 'italic' : 'normal'])
      .filter(([weight, style]) => !hasFace(family, weight, style)); // before any await
    const at = fontsourceAt(id);
    const meta = optional || /[^\0-ÿ]/u.test(text) ? await fontsourceMeta(family) : null;
    const subsets = ['latin', ...kitSubsetsFor(text, meta)];
    for (const [weight, style] of todo) {
      if (optional && !(meta?.weights.includes(weight) && meta.styles.includes(style))) continue;
      for (const subset of subsets) {
        const url = `${await at}files/${id}-${subset}-${weight}-${style}.woff2`;
        const face = new FontFace(family, `url(${url}) format('woff2')`,
          { weight: String(weight), style, unicodeRange: ranges[subset] });
        jobs.push(face.load().catch(() => {
          if (subset === 'latin' && !optional) throw new Error(`Fontsource has no ${family} ${weight} ${style}`);
        }));
      }
    }
  }
  const ready = await Promise.all(jobs).catch((error) => { kitFail(error); throw error; });
  return ready.filter((face) => face && document.fonts.add(face)).length;
}

/** A loaded FontFace covers this family, weight and style (fonts.check() would
 *  also say yes for families nobody declared). */
function hasFace(family, weight, style) {
  for (const face of document.fonts) {
    if (face.status !== 'loaded' || face.style !== style) continue;
    if (face.family.replace(/^["']|["']$/g, '') !== family) continue;
    const [low, high = low] = face.weight.split(' ').map(Number);
    if (weight >= low && weight <= high) return true;
  }
  return false;
}

/** The files beyond latin `text` needs that `meta`'s family ships. */
function kitSubsetsFor(text, meta) {
  return [[/[Ā-˿ᴀ-ᶿḀ-ỿ†ℓⱠ-Ɀ꜠-ꟿ]/u, 'latin-ext'], [/[Ͱ-Ͽ]/u, 'greek']]
    .filter(([re, x]) => re.test(text) && meta?.subsets?.includes(x)).map(([, x]) => x);
}

/** Fontsource's id for a family: 'Source Serif 4' → 'source-serif-4'. */
function fontsourceId(family) { return family.toLowerCase().replace(/\s+/g, '-'); }

/** A package's folder at the one version @5 names now (#766). */
function fontsourceAt(id, u = `https://cdn.jsdelivr.net/npm/@fontsource/${id}@`) {
  return (fontsourceAt.c ??= {})[id] ??= fetch(u + '5/package.json').then((r) => r.json())
    .then((p) => p.version || 5, () => 5).then((v) => `${u}${v}/`);
}

/** The family's Fontsource metadata (weights, styles, subsets), or null. */
function fontsourceMeta(family) {
  fontsourceMeta.cache ??= new Map();
  const id = fontsourceId(family);
  if (!fontsourceMeta.cache.has(id)) {
    fontsourceMeta.cache.set(id, fetch(`https://api.fontsource.org/v1/fonts/${id}`)
      .then((res) => (res.ok ? res.json() : null), () => null));
  }
  return fontsourceMeta.cache.get(id);
}

// ─── Kit · viewer v2 ── the same in every recipe · postext.dev/cookbook
/** The pages as spreads on a dark desk, page 1 alone, then verso | recto,
 *  each painted when it scrolls near. Other options go to renderPageToCanvas. */
function showPages(docs, { title, width = 460, ...render } = {}) {
  const root = viewer(title);
  const pages = [docs].flat().flatMap((doc) =>
    doc.pages.map((page) => ({ doc, page, n: (doc.pageIndexOffset ?? 0) + page.index })));
  const spreads = [];
  let verso = null;
  for (const p of pages) {
    if (p.n % 2 === 1) { if (verso) spreads.push([verso, null]); verso = p; }
    else { spreads.push([verso, p]); verso = null; }
  }
  if (verso) spreads.push([verso, null]);
  const density = Math.min(window.devicePixelRatio || 1, 2);
  showPages.painter?.disconnect();
  const painter = new IntersectionObserver((entries) => {
    for (const { isIntersecting, target } of entries) {
      if (!isIntersecting) continue;
      painter.unobserve(target);
      const { doc, page } = target.postext;
      renderPageToCanvas(page, doc, target, { ...render, scale: (width * density) / page.width });
    }
  }, { rootMargin: '800px' });
  showPages.painter = painter;
  root.replaceChildren(...spreads.map((pair) => {
    const spread = document.createElement('div');
    spread.className = 'pt-spread';
    for (const p of pair) {
      const figure = document.createElement('figure');
      if (p) {
        const label = p.page.pageLabel || String(p.n + 1);
        const canvas = document.createElement('canvas');
        canvas.postext = p;
        canvas.style.aspectRatio = `${p.page.width} / ${p.page.height}`;
        canvas.setAttribute('role', 'img');
        canvas.setAttribute('aria-label', `Page ${label}`);
        const folio = document.createElement('figcaption');
        folio.textContent = label;
        figure.append(canvas, folio);
        painter.observe(canvas);
      } else figure.className = 'pt-blank';
      spread.append(figure);
    }
    return spread;
  }));
  kitStatus(`${pages.length} ${pages.length === 1 ? 'page' : 'pages'}`);
  document.documentElement.dataset.postext = 'ready';
  return pages.length;
}

/** The desk, the bar and the error reporting, created once. */
function viewer(title) {
  if (!document.getElementById('pt-kit')) {
    document.head.insertAdjacentHTML('beforeend', `<style id="pt-kit">
      :root { color-scheme: dark; }
      body { margin: 0; background: #0e1014; color: #b9bcc4; font: 13px/1.45 system-ui, sans-serif; }
      #pt-bar { position: sticky; top: 0; z-index: 1; display: flex; flex-wrap: wrap; align-items: center;
        gap: 6px 16px; padding: 10px 16px; background: rgb(14 16 20 / .92); backdrop-filter: blur(6px);
        border-bottom: 1px solid #23262d; }
      #pt-bar strong { color: #f4f1ea; font-weight: 600; }
      #pt-actions { display: flex; gap: 12px; margin-left: auto; }
      #pt-actions a, #pt-actions button { color: #d8a21a; font: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
      #pages { display: grid; justify-items: center; gap: 48px; padding: 32px 16px 72px; }
      .pt-spread { display: flex; }
      .pt-spread figure { margin: 0; width: min(460px, 44vw); }
      .pt-spread canvas { display: block; width: 100%; background: #fff;
        box-shadow: 0 1px 2px rgb(0 0 0 / .5), 0 22px 44px -16px rgb(0 0 0 / .8); }
      .pt-spread figure:first-child canvas { box-shadow: inset -14px 0 14px -14px rgb(0 0 0 / .18), 0 1px 2px rgb(0 0 0 / .5), 0 22px 44px -16px rgb(0 0 0 / .8); }
      .pt-spread figcaption { margin-top: 10px; text-align: center; font: 600 10px/1 system-ui, sans-serif;
        letter-spacing: .18em; text-transform: uppercase; color: #6c7079; }
      .pt-blank { visibility: hidden; }
      @media (max-width: 760px) {
        .pt-spread { flex-direction: column; gap: 32px; }
        .pt-spread figure { width: min(460px, 92vw); }
        .pt-blank { display: none; }
      }
    </style>`);
    document.body.insertAdjacentHTML('afterbegin',
      '<header id="pt-bar"><strong id="pt-title"></strong><span id="pt-status" role="status"></span><span id="pt-actions"></span></header>');
    document.getElementById('pt-title').textContent = document.title || 'Postext';
    addEventListener('error', (event) => kitFail(event.error ?? event.message));
    addEventListener('unhandledrejection', (event) => kitFail(event.reason));
  }
  if (title) document.getElementById('pt-title').textContent = title;
  return document.getElementById('pages')
    ?? document.body.appendChild(Object.assign(document.createElement('main'), { id: 'pages' }));
}

function kitStatus(text) {
  viewer();
  document.getElementById('pt-status').textContent = text;
}

function kitFail(error) {
  document.documentElement.dataset.postext = 'error';
  kitStatus(`Error: ${error?.message ?? error}`);
}

// ─── Kit · pdf v3 ── the same in every recipe that exports a PDF
/** The Fontsource files the screen used, as TrueType, with their range and
 *  place: the nearest weight the family ships, upright with no italic;
 *  latin, then what its letters need (kitSubsetsFor). */
async function fontsourceProvider(family, weight, style, request) {
  const id = fontsourceId(family);
  const meta = await fontsourceMeta(family);
  const weights = meta?.weights?.length ? meta.weights : [400, 700];
  const w = weights.reduce((a, b) => (Math.abs(b - weight) < Math.abs(a - weight) ? b : a));
  const s = style === 'italic' && meta && !meta.styles.includes('italic') ? 'normal' : style;
  const text = String.fromCodePoint(...(request?.codePoints ?? []));
  const files = await Promise.all(['latin', ...kitSubsetsFor(text, meta)].map(async (subset, order) => {
    const res = await fetch(`${await fontsourceAt(id)}files/${id}-${subset}-${w}-${s}.woff2`);
    if (!res.ok) throw new Error(`Fontsource has no ${family} ${w} ${s} ${subset}`);
    return Object.assign(await decompressWoff2(new Uint8Array(await res.arrayBuffer())),
      { unicodeRange: kitRanges()[subset], order });
  }));
  return files.length === 1 ? files[0] : files;
}

/** A "Build the PDF" button; then "Open the PDF" (a new tab: CodePen's frame
 *  shows no PDFs) and a download link. */
function offerPdf(makePdf, filename) {
  viewer();
  const button = Object.assign(document.createElement('button'), { type: 'button', textContent: 'Build the PDF' });
  button.dataset.postextPdf = filename;
  button.addEventListener('click', async () => {
    button.disabled = true;
    button.textContent = 'Building the PDF…';
    try {
      const bytes = await makePdf();
      const url = URL.createObjectURL(new Blob([bytes], { type: 'application/pdf' }));
      const size = `${Math.max(1, Math.round(bytes.length / 1024))} KB`;
      button.replaceWith(
        Object.assign(document.createElement('a'), { href: url, target: '_blank', rel: 'noopener', textContent: 'Open the PDF ↗' }),
        Object.assign(document.createElement('a'), { href: url, download: filename, textContent: `Download ${filename} · ${size}` }));
    } catch (error) {
      button.disabled = false;
      button.textContent = 'Build the PDF';
      kitFail(error);
    }
  });
  document.getElementById('pt-actions').append(button);
}

// ─── /Kit ───────────────────────────────────────────────────────────────────────
````

## Varianti

### Numera tutte le battute

Un apparato con molte voci per sistema si segue meglio con un numero su ogni battuta.

```diff
-  barNumbers: 'system', // the apparatus is keyed by bar: number every system
+  barNumbers: 'every',
```

### Incidi gli esempi in Bravura

Le teste di nota più piene di Bravura si accordano con uno stile da incisione su lastra.

```diff
-  musicFont: 'Leipzig', // lighter than Bravura, close to a 19th-century plate
+  musicFont: 'Bravura',
```

## Errori frequenti

- MEI 5 scrive l’armatura come `keysig="1f"` su `scoreDef` o `staffDef`. L’attributo `key.sig` di MEI 4 viene ignorato senza avviso, e il bemolle sparisce.
- Dai a ogni `staffDef` il suo `lines="5"`: senza, note e chiavi vengono incise senza rigo.
- Si incide il `<lem>` di un `<app>`, non il `<rdg>`. Una variante che il lettore deve vedere sulla pagina va nella nota d’apparato o in un secondo esempio.

## Crediti

- Ricetta: Ignacio Ferro ([@drnachio](https://github.com/drnachio))
- Testo: The chapter text and the apparatus notes, in English and Spanish: Ignacio Ferro, CC-BY-4.0
- Testo: Sumer is icumen in (13th century), the music examples transcribed from W. S. Rockstro's score and the readings his article reports, in A Dictionary of Music and Musicians, ed. George Grove, vol. 3, pp. 765–768, and vol. 4, pp. 1–3 (Macmillan, 1900 printing), as transcribed on Wikisource: Anonymous; William Smyth Rockstro ([fonte](https://en.wikisource.org/wiki/A_Dictionary_of_Music_and_Musicians/Sumer_is_icumen_in)), pubblico dominio
- Testo: The Latin rubric of Harley MS 978, f. 11v, and the folio, as quoted in the Wikipedia article (fact check): Wikipedia contributors ([fonte](https://en.wikipedia.org/wiki/Sumer_is_icumen_in)), CC-BY-SA-4.0
- Caratteri: Crimson Pro (OFL-1.1), Cormorant Garamond (OFL-1.1), Source Sans 3 (OFL-1.1)
- Codice: MIT · Contenuto di esempio: CC-BY-4.0

## Ricette correlate

- [Nº 071 · Note al piede della colonna che le cita](https://postext.dev/it/cookbook/novel-footnotes-column-foot.md): I richiami [^id] del Markdown diventano note numerate al piede della colonna che le cita, con opzioni per una colonna, note a fine capitolo e numeri continui. · Livello 2 (Intermedio) · Narrativa, teatro e prosa letteraria
- [Nº 044 · Edizione critica: numeri di verso e note per verso](https://postext.dev/it/cookbook/critical-edition-line-numbers.md): Il Lycidas di Milton nel testo del 1645: lineNumbers stampa un numero ogni cinque versi nella colonna laterale, e ogni nota si apre su quel numero, come chip. · Livello 3 (Avanzato) · Poesia
- [Nº 163 · Un manuale di armonia con esempi musicali in ABC](https://postext.dev/it/cookbook/harmony-textbook-abc-examples.md): Un capitolo sulle cadenze i cui esempi sono blocchi ABC nel Markdown, incisi alla larghezza della colonna; uno di essi prosegue su due pagine. · Livello 2 (Intermedio) · Libri di testo
