# Exemples musicals en MEI amb aparat crític a les notes

> Blocs MEI 5 gravats dins del text amb un pentagrama de 5 mm, variants codificades amb app, lem i rdg, i l’aparat per compàs i nota en notes a peu de pàgina.

- Versió HTML: https://postext.dev/ca/cookbook/musicology-mei-apparatus
- Recepta Núm. 165 · Requadres i notes · Nivell 2 (Intermedi) · Sortides: Canvas, PDF
- Gèneres: Articles i treballs acadèmics
- Requereix postext ≥ 1.54.0, postext-pdf ≥ 1.54.0 · provada amb 1.54.0, postext-pdf 1.54.0 el 2026-10-22
- Pàgines: [1](https://postext.dev/cookbook/musicology-mei-apparatus/es/p01.webp?v=8847e03f), [2](https://postext.dev/cookbook/musicology-mei-apparatus/es/p02.webp?v=8847e03f), [3](https://postext.dev/cookbook/musicology-mei-apparatus/es/p03.webp?v=8847e03f), [4](https://postext.dev/cookbook/musicology-mei-apparatus/es/p04.webp?v=8847e03f), [5](https://postext.dev/cookbook/musicology-mei-apparatus/es/p05.webp?v=8847e03f)
- PDF: https://postext.dev/cookbook/musicology-mei-apparatus/es/musicology-mei-apparatus.pdf?v=8847e03f
- Obre al Sandbox: https://postext.dev/ca/sandbox#recipe=musicology-mei-apparatus&lang=es (.postext: https://postext.dev/cookbook/musicology-mei-apparatus/es/musicology-mei-apparatus.postext)
- Última actualització: 2026-10-22
- Altres idiomes: [en](https://postext.dev/en/cookbook/musicology-mei-apparatus.md), [es](https://postext.dev/es/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), [it](https://postext.dev/it/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)

## En poques paraules

Un capítol d’un estudi sobre música medieval. Passatges breus d’una rota anglesa del segle XIII s’imprimeixen com a música dins del text, i les notes al peu de cada pàgina recullen, compàs a compàs, on discrepen les edicions antigues.

## Què compondràs

El capítol 3 d’un estudi sobre com van llegir la música medieval els antiquaris anglesos: cinc pàgines de 156 × 234 mm sobre *Sumer is icumen in*, la rota de Reading, i els editors que la van posar en partitura entre 1776 i 1889. Tres passatges de la rota van gravats dins del text, en Leipzig i amb un pentagrama de 5 mm, amb la numeració de compassos de la partitura de W. S. Rockstro, i cada comentari cita el seu aparat al peu de la pàgina: «c. 40, n. 2 la ] sol Hw, Bu». Les notes són breus i denses, com pertoca a un aparat; la música ocupa la mesura del text, i cada lectura prové de l’article de Rockstro al *Dictionary* de Grove, cosa que el capítol declara al segon paràgraf.

**Aquesta recepta respon a:**

- Com dono als exemples musicals un aparat crític de variants de les fonts en notes a peu de pàgina?
- Com faig notes a peu de pàgina?

## La resposta curta

````js
// script.js, línies 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') },
};
````

## Ingredients

**Ensenya**

- [Notació musical](https://postext.dev/ca/docs/music.md#una-partitura-dins-del-text): Partitures escrites com a text en blocs ```abc, ```musicxml, ```mei o ```humdrum, gravades per Verovio a l'amplada de la columna i tallades en sistemes que continuen a la columna o la pàgina següent.
- [Notes a peu de pàgina](https://postext.dev/ca/docs/document-format-notes-references.md#notes-a-peu-de-pàgina): Notes citades amb [^id] i compostes al peu de la columna que les cita, o després del capítol, numerades per capítol o per tot el llibre.

**També fa servir**

- [Estil de partitura](https://postext.dev/ca/docs/configuration-resources.md#estil-de-partitura)
- [Obertures dissenyades](https://postext.dev/ca/docs/configuration-headings.md#extensió-i-disseny-avançat)
- [Atributs de títol](https://postext.dev/ca/docs/document-format.md#atributs-dencapçalament)
- [Capçaleres i folis](https://postext.dev/ca/docs/configuration-headers-footers.md#capçaleres-i-peus)
- [Marges simètrics](https://postext.dev/ca/docs/configuration-page-layout.md#marges-simètrics)
- [Capçaleres segons el tipus de pàgina](https://postext.dev/ca/docs/configuration-headers-footers.md#elements-de-text)
- [Estils de paràgraf](https://postext.dev/ca/docs/configuration-styles.md#estils-de-paràgraf)
- [Paleta de color semàntica](https://postext.dev/ca/docs/configuration-fonts-colors-viewers.md#paleta-de-colors)
- [Color del paper](https://postext.dev/ca/docs/configuration-page-layout.md#pàgina)
- [Vídues, òrfenes i línies curtes](https://postext.dev/ca/docs/configuration-page-flow.md#òrfenes-vídues-línies-curtes-i-regles-de-cohesió)
- [Exportació a PDF](https://postext.dev/ca/docs/configuration-pdf-output.md#generació-de-pdf)
- [Llistats de codi](https://postext.dev/ca/docs/configuration-styles.md#llistats-de-codi)
- [Equilibri de columnes](https://postext.dev/ca/docs/configuration-page-flow.md#equilibratge-de-columnes)
- [Fonts incrustades al PDF](https://postext.dev/ca/docs/configuration-pdf-output.md#per-què-un-proveïdor-de-fonts)

**La configuració d'un cop d'ull**

- [`bodyText`](https://postext.dev/ca/docs/configuration-text.md#text-de-cos), [`colorPalette`](https://postext.dev/ca/docs/configuration-fonts-colors-viewers.md#paleta-de-colors), [`footer`](https://postext.dev/ca/docs/configuration-headers-footers.md#capçaleres-i-peus), `footnotes`, [`header`](https://postext.dev/ca/docs/configuration-headers-footers.md#capçaleres-i-peus), [`headings`](https://postext.dev/ca/docs/configuration-headings.md#encapçalaments), [`layout`](https://postext.dev/ca/docs/configuration-page-layout.md#disposició), [`locale`](https://postext.dev/ca/docs/configuration-language.md#partició-de-mots), [`page`](https://postext.dev/ca/docs/configuration-page-layout.md#pàgina), [`paragraphStyles`](https://postext.dev/ca/docs/configuration-styles.md#estils-de-paràgraf), [`scoreStyle`](https://postext.dev/ca/docs/configuration-resources.md#estil-de-partitura)

**API**

- [`buildDocumentWithFonts`](https://postext.dev/ca/docs/configuration-programmatic-usage.md#carregar-les-fonts-abans-de-compondre), [`decompressWoff2`](https://postext.dev/ca/docs/configuration-pdf-output.md#proveïdor-de-fonts-al-navegador-fontsource--woff2), [`initMusicEngine`](https://postext.dev/ca/docs/music.md#una-partitura-dins-del-text), [`renderPageToCanvas`](https://postext.dev/ca/docs/configuration-programmatic-usage.md#renderitzar-una-pàgina-en-un-mapa-de-bits), [`renderToPdf`](https://postext.dev/ca/docs/configuration-pdf-output.md#generació-de-pdf)

**Tipus de lletra**

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

## Elaboració

### 1 · Escriu cada exemple en MEI, amb les seves variants

Els ajustos són [la resposta curta](https://postext.dev/ca/cookbook/musicology-mei-apparatus.md#la-resposta-curta) de dalt; la música va al Markdown, un bloc ```` ```mei ```` per exemple. On dues fonts discrepen, el compàs porta un `<app>` amb la lectura adoptada a `<lem>` i l’altra a `<rdg source="#Hw #Bu">`. El gravador imprimeix el lema: el c. 40 de l’[exemple 3.3](https://postext.dev/cookbook/musicology-mei-apparatus/es/p05.webp?v=8847e03f) mostra el la, i el sol de Hawkins i Burney continua a l’arxiu per a qui obri la codificació. Dona a cada bloc un `alt` en la llengua de la pàgina: és el que llegeixen de la partitura un lector de pantalla i el PDF etiquetat.

### 2 · Lliga l’aparat als compassos que veu el lector

`barNumbers: 'system'` numera el primer compàs de cada sistema, i el `<measure n="37">` de cada bloc comença el compte on comença el fragment a l’edició que segueix, de manera que l’exemple 3.3 obre al 37 i una nota que diu «c. 40» remet a un compàs que el lector troba. L’entrada de l’aparat és una nota a peu de pàgina corrent, citada des del paràgraf que comenta el compàs: lema, claudàtor de tancament, variant i sigles en cursiva. Una nota no es pot citar des de dins d’una partitura, així que la crida va a la frase que anomena la lectura.

### 3 · Ajusta la música al text corregut

Un pentagrama de 5 mm en Leipzig cap en una mesura de 116 mm amb cinc o sis compassos de 3/2 per sistema, i els onze compassos de l’exemple 3.3 queden en dos sistemes. `textFont` compon la lletra en Crimson Pro, la lletra del text, i `minSystemsAtBreak: 2` impedeix que una pàgina acabi amb un sol sistema d’un exemple mentre la resta passa a la següent. El rètol de cada exemple és un títol de tercer nivell, de manera que mai no es queda al peu d’una pàgina sense la seva partitura.

### 4 · Deixa que una pàgina amb notes acabi curta

```js
// script.js, línies 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’obertura baixa el text 50 mm sota un títol en Cormorant cursiva. Més endavant, una pàgina la línia següent de la qual arrossegaria una nota llarga acaba unes línies abans, i `balancing: { maxLinesPerHeading: 1 }` evita que l’equilibrat de columnes pugi aquest buit damunt del títol de la secció següent, on semblaria un tall en l’argument.

### 5 · Posa el llibre a la pàgina parella i el capítol a la senar

```js
// script.js, línies 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' }] };
```

Els folis van en vermell de rúbrica a la vora exterior, el llibre a la pàgina parella i el capítol a la senar; `pages: 'body'` els treu de l’obertura, que porta un foli centrat al peu.

## La recepta completa

Un sol fitxer, compost a partir de la carpeta de la recepta amb el text d'exemple i el kit comú del Receptari ja inclosos; construeix la seva pròpia pàgina. Per executar-lo, posa'l en un `<script type="module">` d'una pàgina buida o enganxa'l al tauler JS d'un pen nou de CodePen (com a mòdul). Importa postext des d'esm.sh, així que no cal instal·lar ni compilar res.

- Carpeta de la recepta: 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 = 'es'; // @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: "La Edad Media de los anticuarios"
---

# La rota de Reading y sus editores {kicker="Capítulo 3"}

Ninguna pieza de música medieval fue impresa, puesta en partitura y discutida por los anticuarios ingleses tantas veces como la rota a seis voces *Sumer is icumen in*. Se conserva en una sola hoja, el f. 11v de la miscelánea que Humfrey Wanley describió para el conde de Oxford hacia 1709 y que hoy es el manuscrito Harley 978 de la British Library. Wanley la tuvo por la pieza más antigua de su género que había visto. Entre la *General History* de sir John Hawkins, de 1776, y el artículo que William Smyth Rockstro escribió para el *Dictionary of Music and Musicians* de George Grove, la rota pasó por al menos cinco partituras, y cada una pretendía corregir la anterior.

Este capítulo sigue esa serie de ediciones y la pone a prueba en tres lugares en los que los editores discrepan. Los ejemplos musicales son transcripciones nuevas, y su aparato crítico va en las notas: cada entrada da el compás y la nota, la lectura adoptada, un corchete de cierre y las lecturas de los demás testimonios.

## Los testimonios y esta edición

Se citan cuatro testimonios. **H** es el manuscrito. **Hw** es la partitura del primer volumen de la *General History of the Science and Practice of Music* de Hawkins (1776). **Bu** es la del segundo volumen de la *General History of Music* de Charles Burney (1782). **Ro** es la solución del canon de Rockstro, publicada con la primera parte de su artículo en el tercer volumen del *Dictionary* de Grove.[^ro]

Los ejemplos siguen a Ro en las alturas, las claves y los valores, porque Rockstro es el único editor de la época que explica cada sustitución que hizo. Según él, el manuscrito solo emplea una clave de do, la *B rotundum*, notas cuadradas negras con plica, una nota cuadrada sin plica y rombos negros. Rockstro transcribe la nota con plica como semibreve con puntillo si es perfecta y como semibreve si es imperfecta, la nota cuadrada sin plica como semibreve y los rombos como mínimas, bajo un signo de tiempo perfecto con prolación menor que, dice, equivale casi al compás de 3/2 moderno.[^values] Las lecturas de H, Hw y Bu que siguen son las que da Rockstro. Este capítulo no ha vuelto a cotejar los dos impresos del siglo XVIII, y donde Rockstro calla, el aparato también calla.

## La primera frase y una nota corregida

### Ejemplo 3.1 · Cantus I, cc. 1–7, con los textos inglés y latino

\`\`\`mei {alt="Sumer is icumen in, primera voz, compases 1 a 7, con la letra inglesa y el texto latino 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>
\`\`\`

El comienzo es la frase mejor documentada de la rota, porque Rockstro volvió a la hoja en la segunda parte de su artículo y enumeró las raspaduras que podía ver. El copista corrigió su propio trabajo con la misma tinta, y la primera corrección cae en la segunda nota.[^b1] Rockstro leyó las raspaduras como mejoras hechas mientras se ponía la pieza por escrito, no como enmiendas de una copia defectuosa, y se sirvió de ellas para defender que el canon nació de una tonada popular que un músico formado retocó hasta que sus frases encajaron unas con otras.

En los cc. 2 y 4 se ven otras dos decisiones. El texto latino se imprime completo donde el manuscrito abrevia el nombre de Cristo,[^b2] y el único rombo con plica, bajo la palabra *in*, se convierte en una mínima con puntillo y una negra.[^b4] El bemol de la armadura representa la *B rotundum* del manuscrito, que Rockstro lee como si bemol en toda la pieza.[^bflat]

## El *pes*

### Ejemplo 3.2 · *Pes*, cc. 1–8, según la partitura de Rockstro

\`\`\`mei {alt="Sumer is icumen in, las dos voces graves del pes, compases 1 a 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>
\`\`\`

Bajo las cuatro voces del canon, el manuscrito escribe dos partes breves que se cantan como un bajo obstinado, ambas sobre las palabras *Sing cuccu nu*. La rúbrica latina empieza *Hanc rotam cantare possunt quatuor socii*: cuatro compañeros pueden cantar la rota, sin contar a quienes sostienen el *pes*. Cada voz nueva entra «en la primera nota después de la cruz», que Ro señala sobre el c. 5. El primer *pes* se repite *faciens pausacionem in fine*, y el segundo, *pausans in medio et non in fine*.[^rubric] Ro sigue la rúbrica al pie de la letra: el primer *pes* calla en el c. 8 y el segundo en el c. 4, de modo que siempre suena una de las dos voces graves.

El *pes* es también donde las partituras del siglo XVIII se equivocaron de forma más visible. Según Rockstro, Hawkins entendió mal sus dos ligaduras e imprimió el pasaje con errores en cada repetición; Burney lo corrigió.[^lig] Ninguna ligadura puede representarse en una partitura moderna, y el ejemplo 3.2 resuelve las dos en notas separadas, como Ro.

El análisis de la escritura a varias voces que hace Rockstro parte de esta partitura. Los cc. 4, 6, 7, 8 y 24 están, según él, en contrapunto estricto a dos voces «de una pureza irreprochable», mientras que el paso del c. 9 al 10 produce quintas paralelas entre la primera y la tercera voz del canon, y los cc. 37 a 39, tres quintas seguidas entre el primer *cantus* y la segunda voz del *pes*.[^fifths] Para Rockstro, esa mezcla de estilos era el mejor argumento a favor de una melodía más antigua que su armonía.

## La cuestión de la fecha

Las fechas propuestas para la hoja dicen tanto de los editores como del manuscrito. Hawkins la situó a mediados del siglo XV, porque veía en su notación el *cantus figuratus* que atribuía a John Dunstable, muerto en 1455 según él; Rockstro tachó el razonamiento de anacronismo «absolutamente inútil».[^hawkins] Burney creyó la pieza poco posterior a los siglos XIII o XIV. Joseph Ritson llevó el manuscrito a mediados del XIII, y Thomas Busby, que en 1819 reimprimió nota por nota la partitura de Burney, lo devolvió al XV.

Los argumentos decisivos vinieron de la paleografía. En 1855 William Chappell publicó un facsímil en color en *Popular Music of the Olden Time* y más tarde sostuvo que la hoja se escribió en la abadía de Reading, hacia 1226, por mano de un monje llamado John of Fornsete. En abril de 1862 sir Frederick Madden anotó en una guarda del volumen que todo él era del siglo XIII y que su parte más antigua se había copiado en Reading hacia 1240, fecha que la Palaeographical Society adoptó en su facsímil de 1878. En el continente, Johann Nikolaus Forkel (1788), August Wilhelm Ambros (1862 y 1868) y Edmond de Coussemaker (1865) escribieron sobre la rota sin haber visto el manuscrito, y Rockstro se lo reprocha a cada uno.[^continent] Un estudio más reciente sitúa la copia entre 1261 y 1264.[^wulstan]

## «Cuccu» en el c. 40

### Ejemplo 3.3 · Cantus I, cc. 37–47

\`\`\`mei {alt="Sumer is icumen in, primera voz, compases 37 a 47, de Cuccu, cuccu a 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>
\`\`\`

El último pasaje de la melodía muestra cómo podía viajar un error. Hawkins y Burney, dice Rockstro, imprimen un sol donde el manuscrito tiene un la en el c. 40, sobre la segunda sílaba de *cuccu*, y lo hacen cada vez que la frase vuelve en otra voz.[^b40] Contra el *pes* equivocado de Hawkins, el sol pasa; contra el *pes* corregido de Burney produce lo que Rockstro llama «una disonancia horrible». La variante está codificada en la fuente del ejemplo 3.3 como lectura de Hw y Bu, mientras que el pentagrama grabado muestra el lema.

Los dos historiadores, además, ajustaron las palabras a las notas de otro modo que el manuscrito a partir del c. 41, en *Wel singes thu cuccu, ne swik thu nauer nu*.[^b41] Rockstro no detalla cómo, y el ejemplo se limita a registrar el hecho. La única copia moderna que Rockstro conocía fue más lejos: suprimió el *pes* y dejó la rota en cuatro partes.

:::paragraphs{style="colophon"}
Compuesto en Crimson Pro, Cormorant Garamond y Source Sans 3 (SIL OFL); música en Leipzig, grabada con Verovio · Texto: original, CC BY 4.0 · Música: *Sumer is icumen in* (siglo XIII), según la partitura de W. S. Rockstro en el *Dictionary of Music and Musicians* de Grove, iii, 766–767 (dominio público)
:::

[^ro]: W. S. Rockstro, «Sumer is icumen in», en G. Grove (ed.), *A Dictionary of Music and Musicians*, iii, 765–768, continuado en iv, 1–3 (Londres: Macmillan, reimpresión de 1900). La partitura, iii, 766–767, se cita por la transcripción de Wikisource de esa reimpresión.

[^values]: Ro, iii, 765. El rombo con plica de la primera nota de *in* es la única excepción (véase la nota al c. 4).

[^b1]: **c. 1, n. 2** mi ] fa *H* antes de la corrección («The second note on Stave 1 was originally an F», Ro, iv, 1). La lectura anterior a la corrección está codificada como variante en el ejemplo 3.1.

[^b2]: **c. 2, n. 2 – c. 4, n. 1** *Chri-sti-co-la* ] abreviado con las letras griegas *ji* y *ro* *H*, Ro. Se desarrolla como lo glosa Rockstro, *Christicola* (iii, 765).

[^b4]: **c. 4, nn. 1–2** mínima con puntillo, negra ] un rombo con plica *H*, el único del manuscrito, que Rockstro no podía «concebir como accidental» (iii, 765).

[^bflat]: **cc. 1–7, armadura** si bemol ] *B rotundum* *H*. El bemol se imprime en la armadura, como en Ro.

[^rubric]: La rúbrica se cita por la transcripción y la traducción del artículo «Sumer is icumen in» de la Wikipedia en inglés, que también da el folio. Rockstro dice haber puesto el canon en partitura «en exacto acuerdo con las indicaciones latinas» (iii, 765), pero no las imprime.

[^lig]: ***Pes*, cc. 1–8** las dos ligaduras mal leídas en cada repetición *Hw*; corregidas *Bu* (Ro, iii, 765). Rockstro no dice cómo las leyó Hawkins, así que no se codifica ninguna variante.

[^fifths]: Ro, iv, 2. Los números de compás remiten a la partitura de Rockstro y a los ejemplos de este capítulo.

[^hawkins]: Ro, iii, 765. Rockstro fecha el primer volumen de Hawkins en 1770; la *General History* apareció en 1776.

[^continent]: Ro, iii, 768, e iv, 1, que cita a 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, en la p. 8. Wulstan propone a W. de Wycombe como copista.

[^b40]: **c. 40, n. 2** la ] sol *Hw*, *Bu* (y Busby 1819, que sigue a *Bu*), en cada entrada de la frase (Ro, iii, 765). Codificada como variante en el ejemplo 3.3.

[^b41]: **cc. 41–47, texto** como *H* ] palabras colocadas de otro modo bajo las notas *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 ───────────────────────────────────────────────────────────────────────
````

## Variants

### Numera tots els compassos

Un aparat amb moltes entrades per sistema se segueix millor amb un número a cada compàs.

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

### Grava els exemples en Bravura

Els caps de nota de Bravura, més gruixuts, lliguen amb un estil de gravat en planxa.

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

## Errors freqüents

- MEI 5 escriu l’armadura com a `keysig="1f"` a `scoreDef` o `staffDef`. L’atribut `key.sig` de MEI 4 s’ignora sense avís, i el bemoll desapareix.
- Posa `lines="5"` a cada `staffDef`: sense això, notes i claus es graven sense pentagrama.
- El gravador imprimeix el `<lem>` d’un `<app>`, no el `<rdg>`. Una variant que el lector hagi de veure a la pàgina va a la nota de l’aparat o en un segon exemple.

## Crèdits

- Recepta: Ignacio Ferro ([@drnachio](https://github.com/drnachio))
- Text: The chapter text and the apparatus notes, in English and Spanish: Ignacio Ferro, CC-BY-4.0
- Text: 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 ([font](https://en.wikisource.org/wiki/A_Dictionary_of_Music_and_Musicians/Sumer_is_icumen_in)), domini públic
- Text: The Latin rubric of Harley MS 978, f. 11v, and the folio, as quoted in the Wikipedia article (fact check): Wikipedia contributors ([font](https://en.wikipedia.org/wiki/Sumer_is_icumen_in)), CC-BY-SA-4.0
- Tipus de lletra: Crimson Pro (OFL-1.1), Cormorant Garamond (OFL-1.1), Source Sans 3 (OFL-1.1)
- Codi: MIT · Contingut d'exemple: CC-BY-4.0

## Relacionades

- [Núm. 071 · Notes al peu de la columna que les cita](https://postext.dev/ca/cookbook/novel-footnotes-column-foot.md): Les crides [^id] passen a notes numerades al peu de la columna que les cita, amb interruptors per a una columna, notes finals i numeració contínua. · Nivell 2 (Intermedi) · Narrativa, teatre i prosa literària
- [Núm. 044 · Edició crítica: numeració de versos i notes per vers](https://postext.dev/ca/cookbook/critical-edition-line-numbers.md): El Lycidas de Milton, text de 1645: lineNumbers numera els versos de cinc en cinc a la columna lateral, i cada nota s'obre amb el número del seu vers. · Nivell 3 (Avançat) · Poesia
- [Núm. 163 · Un manual d'harmonia amb exemples musicals en ABC](https://postext.dev/ca/cookbook/harmony-textbook-abc-examples.md): Un capítol sobre les cadències amb exemples en blocs ABC dins del Markdown, gravats a l'amplada de la columna; un d'ells continua a la pàgina següent. · Nivell 2 (Intermedi) · Llibres de text
