# Ejemplos musicales en MEI con aparato crítico en las notas

> Bloques MEI 5 grabados en el texto con un pentagrama de 5 mm, variantes codificadas con app, lem y rdg, y el aparato por compás y nota en notas al pie.

- Versión HTML: https://postext.dev/es/cookbook/musicology-mei-apparatus
- Receta N.º 165 · Recuadros y notas · Nivel 2 (Intermedio) · Salidas: Canvas, PDF
- Géneros: Artículos y trabajos académicos
- Requiere postext ≥ 1.54.0, postext-pdf ≥ 1.54.0 · probada con 1.54.0, postext-pdf 1.54.0 el 2026-10-22
- Páginas: [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
- Abrir en el Sandbox: https://postext.dev/es/sandbox#recipe=musicology-mei-apparatus&lang=es (.postext: https://postext.dev/cookbook/musicology-mei-apparatus/es/musicology-mei-apparatus.postext)
- Última actualización: 2026-10-22
- Otros idiomas: [en](https://postext.dev/en/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), [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 pocas palabras

Un capítulo de un estudio sobre música medieval. Pasajes breves de una rota inglesa del siglo XIII se imprimen como música dentro del texto, y las notas al pie de cada página recogen, compás a compás, dónde discrepan las ediciones antiguas.

## Lo que vas a componer

El capítulo 3 de un estudio sobre cómo leyeron la música medieval los anticuarios ingleses: cinco páginas de 156 × 234 mm sobre *Sumer is icumen in*, la rota de Reading, y los editores que la pusieron en partitura entre 1776 y 1889. Tres pasajes de la rota van grabados en el texto, en Leipzig y con un pentagrama de 5 mm, con la numeración de compases de la partitura de W. S. Rockstro, y cada comentario cita su aparato al pie de la página: «c. 40, n. 2 la ] sol Hw, Bu». Las notas son breves y densas, como corresponde a un aparato; la música ocupa la medida del texto, y cada lectura procede del artículo de Rockstro en el *Dictionary* de Grove, cosa que el capítulo declara en su segundo párrafo.

**Esta receta responde a:**

- ¿Cómo doy a los ejemplos musicales un aparato crítico de variantes de las fuentes en notas al pie?
- ¿Cómo hago notas al pie?

## La respuesta corta

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

## Ingredientes

**Enseña**

- [Notación musical](https://postext.dev/es/docs/music.md#una-partitura-en-el-texto): Partituras escritas como texto en bloques ```abc, ```musicxml, ```mei o ```humdrum, grabadas por Verovio al ancho de la columna y cortadas en sistemas que siguen en la columna o la página siguiente.
- [Notas al pie](https://postext.dev/es/docs/document-format-notes-references.md#notas-al-pie): Notas citadas con [^id] y compuestas al pie de la columna que las cita, o tras el capítulo, numeradas por capítulo o por todo el libro.

**También usa**

- [Estilo de partitura](https://postext.dev/es/docs/configuration-resources.md#estilo-de-partitura)
- [Aperturas diseñadas](https://postext.dev/es/docs/configuration-headings.md#apertura-a-toda-página-y-diseño-avanzado)
- [Atributos de título](https://postext.dev/es/docs/document-format.md#atributos-de-encabezado)
- [Cabeceras y folios](https://postext.dev/es/docs/configuration-headers-footers.md#cabeceras-y-pies)
- [Márgenes simétricos](https://postext.dev/es/docs/configuration-page-layout.md#márgenes-simétricos-espejo)
- [Cabeceras según el tipo de página](https://postext.dev/es/docs/configuration-headers-footers.md#elementos-de-texto)
- [Estilos de párrafo](https://postext.dev/es/docs/configuration-styles.md#estilos-de-párrafo)
- [Paleta de color semántica](https://postext.dev/es/docs/configuration-fonts-colors-viewers.md#paleta-de-colores)
- [Color del papel](https://postext.dev/es/docs/configuration-page-layout.md#página)
- [Viudas, huérfanas y líneas cortas](https://postext.dev/es/docs/configuration-page-flow.md#huérfanas-viudas-líneas-cortas-y-reglas-de-cohesión)
- [Exportación a PDF](https://postext.dev/es/docs/configuration-pdf-output.md#generación-de-pdf)
- [Listados de código](https://postext.dev/es/docs/configuration-styles.md#listados-de-código)
- [Equilibrado de columnas](https://postext.dev/es/docs/configuration-page-flow.md#equilibrado-de-columnas)
- [Fuentes incrustadas en el PDF](https://postext.dev/es/docs/configuration-pdf-output.md#por-qué-un-proveedor-de-fuentes)

**La configuración de un vistazo**

- [`bodyText`](https://postext.dev/es/docs/configuration-text.md#texto-base), [`colorPalette`](https://postext.dev/es/docs/configuration-fonts-colors-viewers.md#paleta-de-colores), [`footer`](https://postext.dev/es/docs/configuration-headers-footers.md#cabeceras-y-pies), `footnotes`, [`header`](https://postext.dev/es/docs/configuration-headers-footers.md#cabeceras-y-pies), [`headings`](https://postext.dev/es/docs/configuration-headings.md#encabezados), [`layout`](https://postext.dev/es/docs/configuration-page-layout.md#disposición), [`locale`](https://postext.dev/es/docs/configuration-language.md#separación-silábica), [`page`](https://postext.dev/es/docs/configuration-page-layout.md#página), [`paragraphStyles`](https://postext.dev/es/docs/configuration-styles.md#estilos-de-párrafo), [`scoreStyle`](https://postext.dev/es/docs/configuration-resources.md#estilo-de-partitura)

**API**

- [`buildDocumentWithFonts`](https://postext.dev/es/docs/configuration-programmatic-usage.md#cargar-las-fuentes-antes-de-componer), [`decompressWoff2`](https://postext.dev/es/docs/configuration-pdf-output.md#proveedor-de-fuentes-en-el-navegador-fontsource--woff2), [`initMusicEngine`](https://postext.dev/es/docs/music.md#una-partitura-en-el-texto), [`renderPageToCanvas`](https://postext.dev/es/docs/configuration-programmatic-usage.md#renderizar-una-página-como-mapa-de-bits), [`renderToPdf`](https://postext.dev/es/docs/configuration-pdf-output.md#generación-de-pdf)

**Tipografías**

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

## Elaboración

### 1 · Escribe cada ejemplo en MEI, con sus variantes

Los ajustes son [la respuesta corta](https://postext.dev/es/cookbook/musicology-mei-apparatus.md#la-respuesta-corta) de arriba; la música va en el Markdown, un bloque ```` ```mei ```` por ejemplo. Donde dos fuentes discrepan, el compás lleva un `<app>` con la lectura adoptada en `<lem>` y la otra en `<rdg source="#Hw #Bu">`. El grabador imprime el lema: el c. 40 del [ejemplo 3.3](https://postext.dev/cookbook/musicology-mei-apparatus/es/p05.webp?v=8847e03f) muestra el la, y el sol de Hawkins y Burney sigue en el archivo para quien abra la codificación. Da a cada bloque un `alt` en el idioma de la página: es lo que leen de la partitura un lector de pantalla y el PDF etiquetado.

### 2 · Ata el aparato a los compases que ve el lector

`barNumbers: 'system'` numera el primer compás de cada sistema, y el `<measure n="37">` de cada bloque arranca la cuenta donde empieza el fragmento en la edición que sigue, así que el ejemplo 3.3 abre en el 37 y una nota que dice «c. 40» remite a un compás que el lector encuentra. La entrada del aparato es una nota al pie corriente, citada desde el párrafo que comenta el compás: lema, corchete de cierre, variante y siglas en cursiva. Una nota no puede citarse desde dentro de una partitura, así que la llamada va en la frase que nombra la lectura.

### 3 · Ajusta la música al texto corrido

Un pentagrama de 5 mm en Leipzig cabe en una medida de 116 mm con cinco o seis compases de 3/2 por sistema, y los once compases del ejemplo 3.3 quedan en dos sistemas. `textFont` compone la letra en Crimson Pro, la letra del texto, y `minSystemsAtBreak: 2` impide que una página acabe con un solo sistema de un ejemplo mientras el resto pasa a la siguiente. El rótulo de cada ejemplo es un título de tercer nivel, de modo que nunca se queda al pie de una página sin su partitura.

### 4 · Deja que una página con notas acabe corta

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

La apertura baja el texto 50 mm bajo un título en Cormorant cursiva. Más adelante, una página cuya línea siguiente arrastraría una nota larga acaba unas líneas antes, y `balancing: { maxLinesPerHeading: 1 }` evita que el equilibrado de columnas suba ese hueco encima del título de la sección siguiente, donde parecería un corte en el argumento.

### 5 · Pon el libro en la página par y el capítulo en la impar

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

Los folios van en rojo de rúbrica en el borde exterior, el libro en la página par y el capítulo en la impar; `pages: 'body'` los quita de la apertura, que lleva un folio centrado al pie.

## La receta completa

Un solo archivo, compuesto a partir de la carpeta de la receta con el texto de ejemplo y el kit común del Recetario ya incluidos; construye su propia página. Para ejecutarlo, ponlo en un `<script type="module">` de una página vacía o pégalo en el panel JS de un pen nuevo de CodePen (como módulo). Importa postext desde esm.sh, así que no hay nada que instalar ni compilar.

- Carpeta de la receta: 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 ───────────────────────────────────────────────────────────────────────
````

## Variantes

### Numera todos los compases

Un aparato con muchas entradas por sistema se sigue mejor con un número en cada compás.

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

### Graba los ejemplos en Bravura

Las cabezas de nota de Bravura, más gruesas, casan con un estilo de grabado en plancha.

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

## Errores frecuentes

- MEI 5 escribe la armadura como `keysig="1f"` en `scoreDef` o `staffDef`. El atributo `key.sig` de MEI 4 se ignora sin aviso, y el bemol desaparece.
- Pon `lines="5"` en cada `staffDef`: sin él, notas y claves se graban sin pentagrama.
- El grabador imprime el `<lem>` de un `<app>`, no el `<rdg>`. Una variante que el lector deba ver en la página va en la nota del aparato o en un segundo ejemplo.

## Créditos

- Receta: Ignacio Ferro ([@drnachio](https://github.com/drnachio))
- Texto: El texto del capítulo y las notas del aparato, en inglés y en español: Ignacio Ferro, CC-BY-4.0
- Texto: Sumer is icumen in (siglo XIII): los ejemplos, transcritos de la partitura de W. S. Rockstro y las lecturas que da su artículo, en A Dictionary of Music and Musicians, ed. George Grove, vol. 3, págs. 765–768, y vol. 4, págs. 1–3 (Macmillan, reimpresión de 1900), según la transcripción de Wikisource: Anonymous; William Smyth Rockstro ([fuente](https://en.wikisource.org/wiki/A_Dictionary_of_Music_and_Musicians/Sumer_is_icumen_in)), dominio público
- Texto: La rúbrica latina del manuscrito Harley 978, f. 11v, y el folio, citados en el artículo de Wikipedia (comprobación): Wikipedia contributors ([fuente](https://en.wikipedia.org/wiki/Sumer_is_icumen_in)), CC-BY-SA-4.0
- Tipografías: Crimson Pro (OFL-1.1), Cormorant Garamond (OFL-1.1), Source Sans 3 (OFL-1.1)
- Código: MIT · Contenido de ejemplo: CC-BY-4.0

## Relacionadas

- [N.º 071 · Notas al pie de la columna que las cita](https://postext.dev/es/cookbook/novel-footnotes-column-foot.md): Las llamadas [^id] pasan a notas numeradas al pie de la columna que las cita, con interruptores para una columna, notas finales y numeración continua. · Nivel 2 (Intermedio) · Narrativa, teatro y prosa literaria
- [N.º 044 · Edición crítica: numeración de versos y notas por verso](https://postext.dev/es/cookbook/critical-edition-line-numbers.md): El Lycidas de Milton, texto de 1645: lineNumbers numera los versos de cinco en cinco en la columna lateral, y cada nota se abre con el número de su verso. · Nivel 3 (Avanzado) · Poesía
- [N.º 163 · Un manual de armonía con ejemplos musicales en ABC](https://postext.dev/es/cookbook/harmony-textbook-abc-examples.md): Un capítulo sobre las cadencias cuyos ejemplos son bloques ABC en el Markdown, grabados al ancho de la columna; uno de ellos sigue en la página siguiente. · Nivel 2 (Intermedio) · Libros de texto
