Saltar al contenido principal
Receta número 164

Recetario · Capítulo 9 · Publicaciones completas

Un cancionero con melodía, letra y acordes

Cada canción es un bloque ABC: melodía, cifrados sobre el pentagrama y primera estrofa bajo las notas, grabados al ancho de columna con un estilo de partitura.

En esta página
Salida
Canvas · PDF
Postext
Probada con Postext 1.54.0
Requiere ≥ 1.54.0 · postext-pdf ≥ 1.54.0
Licencia
Actualizada el 22 oct 2026
Código MIT · Texto CC BY 4.0

pp. 2–3 de 5

  • Formato 148 × 210 mm
  • 1 columna
  • Spectral 10,3/14
  • Fraunces
  • Spectral SC
  • 5 páginas
  • Nivel
  • Postext 1.54.0
  • Compuesto en 335 ms
  • 164 líneas de código

En pocas palabras

Un cancionero pequeño para una merienda. Cada canción se escribe como texto en una notación musical llamada ABC, y Postext dibuja el pentagrama, las notas, los acordes de guitarra y la letra bajo las notas.

Lo que vas a componer

El Cancionero de la merienda, un cuadernillo en A5 para la tarde de un cumpleaños: una portada en rojo granza, una nota para quien canta con el índice, tres canciones y, al final, de dónde viene cada una. Cada canción se abre bajo un número grande en granza, el título en Fraunces y una línea de créditos en versalitas. Debajo, la melodía en un pentagrama de 5,5 mm con la fuente musical Leland, los acordes de guitarra sobre los compases y la primera estrofa bajo las notas en Spectral, la letra del libro. Las coplas restantes van a dos columnas. Como las tres canciones son cortas, dos de ellas comparten página. La edición inglesa es un cancionero de sobremesa con tres canciones largas, una por página.

Esta receta responde a

  • ¿Cómo compongo un cancionero con la melodía, la letra bajo las notas y los cifrados de acordes?

La respuesta corta

script.js · líneas 33–50en el código completo
// A song is an ```abc fence in the Markdown: the melody, its chords written "G" before the note
// they fall on, and the first verse on a w: line under it. The look is set here, once.
const scoreStyle = {
  staffSize: mm(5.5), // a songbook rastral; the words under it come out at about 8 pt
  musicFont: 'Leland', // lighter noteheads than Bravura, close to Spectral's colour
  textFont: TEXT, // words and chord names in the text face, not the engraver's Times
  spacing: 1, // the engraver's own: five or six bars of 3/4 to a system on this measure
  barNumbers: 'none', // a table of singers counts verses, not bars
  systemGap: mm(4.5), // room for the chord names between one system's words and the next
  marginTop: pt(4),
  marginBottom: pt(LEAD),
  color: col('ink'),
  minSystemsAtBreak: 2, // never a lone system at a page foot or head
};
// Two habits of Verovio's ABC reader shape the w: lines. Every sung note takes the next
// syllable in order: the `_` and `*` holds are read as nothing, so the second note of a
// slurred pair (B/G/ under "-ing") gets a no-break space, which prints nothing. A tied note
// takes none. `~` joins two syllables on one note: "de~a-trás".

Ingredientes

Tipografía
Spectral, Spectral SC, Fraunces (SIL OFL 1.1)
Recursos
Ninguno: todas las imágenes se dibujan en código

Elaboración

#1 · Escribe la canción y define la partitura una sola vez

El estilo de partitura es la respuesta corta de arriba. En el Markdown cada canción es un bloque ```abc: las líneas de cabecera dan el compás, la figura de referencia y la tonalidad; un acorde entre comillas ("C7"B) se imprime sobre la nota que lo sigue, y una línea w: bajo la música pone una sílaba bajo cada nota, separadas con guiones. Una canción con estribillo y copla son dos líneas de música, cada una con su w:. El tamaño del pentagrama, la fuente musical, la letra de las palabras, los números de compás y el espacio entre sistemas salen de scoreStyle: las tres canciones casan y los bloques solo llevan música.

#2 · Abre cada canción con su número y sus créditos

script.js · líneas 66–81en el código completo
// # Amazing Grace {credit="Words John Newton, 1779 · Tune New Britain, American, 1835"}
// The songs run on, three lines apart: a short song shares its page with the next one.
const at = (to, edge, x = 0, y = 0) => ({ anchor: { to, edge }, offset: { x: mm(x), y: mm(y) } });
const text = (id, content, font, size, color, placement, extra = {}) => ({ kind: 'text', id,
  content, fontFamily: font, fontSize: pt(size), color: col(color), align: 'left', placement,
  ...extra });
const songHead = { enabled: true, minHeight: mm(21), slot: { elements: [
  text('number', '{number}', DISPLAY, 26, 'madder', at('container', 'top-left', 0, 1),
    { fontWeight: 600, lineHeight: 1 }),
  text('title', '{titleText}', DISPLAY, 21, 'ink', { ...at('container', 'top-left', 12, 2),
    size: { width: mm(100) } }, { fontWeight: 600, lineHeight: 1.05 }),
  text('credit', '{attr.credit}', LABEL, 8.4, 'madder', { ...at('#title', 'below', 0, 2.2),
    size: { width: mm(100) } }, { fontWeight: 600, letterSpacing: pt(0.6) }),
] } };
const songs = { level: 1, numberingTemplate: '{1}', advancedDesign: songHead,
  marginTop: pt(LEAD * 3), marginBottom: pt(0), breakBefore: { enabled: false } };

La canción es un título de primer nivel con un atributo credit, y su diseño compone con él el número, el título y la línea de créditos. minHeight da a todas la misma cabeza de 21 mm, así que los pentagramas empiezan a la misma altura. Las canciones van seguidas, con tres líneas de aire sobre cada título, y una partitura nunca se corta antes de su segundo sistema (minSystemsAtBreak: 2): Cumpleaños feliz y Martinillo caben en la misma página, y La cucaracha pasa entera a la siguiente.

#3 · Pon las demás coplas a dos columnas

script.js · líneas 54–62en el código completo
// :::columns{count=2} holds one :::verse block per stanza; each line of the stanza is a
// line of Markdown, the turned lines indented two spaces (one em). A hymn in long lines
// (Amazing Grace) drops the columns: its stanzas stand one under another, centred.
const verse = { id: 'verse', fontSize: pt(9.4), lineHeight: pt(13), hyphenation: false,
  marginBottom: pt(13 / 2) };
const chorus = { id: 'chorus', fontSize: pt(9.4), lineHeight: pt(13), italic: true,
  hyphenation: false, marginBottom: pt(LEAD / 2) };
const colophon = { id: 'colophon', fontFamily: LABEL, fontSize: pt(7.8), lineHeight: pt(11),
  color: col('muted'), textAlign: 'left', firstLineIndent: pt(0), marginTop: pt(LEAD * 2) };

Cada copla es un bloque :::verse, así que sus versos cortan donde los cortó la tradición y el segundo y el cuarto entran un cuadratín. Un grupo :::columns{count=2 gap=4mm} las pone una al lado de otra a 9,4 pt. Cuenta antes los caracteres: los octosílabos de La cucaracha caben de sobra en una columna de 55 mm; los versos largos de Amazing Grace, en la edición inglesa, no, y por eso esa canción deja las estrofas en un solo bloque centrado.

#4 · Deja tranquilos los elementos fijos

script.js · líneas 119–131en el código completo
const head = (id, content, parity, edge, x, style = {}) => ({
  kind: 'text', id, content, parity, pages: 'all', // a song's first page carries them too
  fontFamily: LABEL, fontSize: pt(8.4), fontWeight: 600, letterSpacing: pt(0.9),
  color: col('muted'), ...style,
  placement: { anchor: { to: 'page', edge }, offset: { x: mm(x), y: mm(12.5) } },
});
const folio = { fontFamily: TEXT, fontWeight: 600, letterSpacing: pt(0), color: col('madder') };
const header = { elements: [
  head('verso-folio', '{pageNumber}', 'even', 'top-left', OUTER, folio),
  head('verso-title', '{title}', 'even', 'top-left', OUTER + 8),
  head('recto-song', '{chapterTitle}', 'odd', 'top-right', -(OUTER + 8)),
  head('recto-folio', '{pageNumber}', 'odd', 'top-right', -OUTER, folio),
] };

Las cabeceras están en todas las páginas de canciones: el título del libro en la página par y la canción en la impar, con el folio en el granza de los números. La portada y la nota para quien canta las quitan con un header vacío en sus estilos de título.

La receta completa

Sandbox
// ═══ Postext Cookbook · Nº 164 · Songbook: melody, words under the notes, chords ═══════
// https://postext.dev/en/cookbook/songbook-melody-words-chords
// Code: MIT · Words and tunes: public domain (see the notes in each edition) · Prose: CC BY 4.0
// Fonts: Spectral, Spectral SC, Fraunces (SIL OFL 1.1); Leland (music) · 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 = 'songbook-melody-words-chords';

// ─── 1 · Design ─────────────────────────────────────────────────────────────
const palette = { // every colour in the config links to one of these
  ink: '#211e1b', // text and notes: a warm near-black
  madder: '#8a3324', // the one accent: song numbers, the title page, credit lines
  tint: '#f1e7d8', // the subtitle on the madder ground (8.2:1)
  rule: '#cbbca6', // hairlines
  muted: '#675e55', // running heads, notes and the colophon (5.9:1 on the paper)
  paper: '#fbf8f1', // a cream stock
};
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, so nothing prints blue.
  { id: 'main-color', name: 'madder (defaults)', value: { hex: palette.madder, model: 'hex' } },
];
const [TEXT, LABEL, DISPLAY] = ['Spectral', 'Spectral SC', 'Fraunces'];
const LEAD = 14; // pt: the body's leading
const OUTER = 15; // mm: the outer margin, where the running heads and folios align

// #region answer: the score style: a 5 mm staff in Leland, the words in the book's face
// A song is an ```abc fence in the Markdown: the melody, its chords written "G" before the note
// they fall on, and the first verse on a w: line under it. The look is set here, once.
const scoreStyle = {
  staffSize: mm(5.5), // a songbook rastral; the words under it come out at about 8 pt
  musicFont: 'Leland', // lighter noteheads than Bravura, close to Spectral's colour
  textFont: TEXT, // words and chord names in the text face, not the engraver's Times
  spacing: 1, // the engraver's own: five or six bars of 3/4 to a system on this measure
  barNumbers: 'none', // a table of singers counts verses, not bars
  systemGap: mm(4.5), // room for the chord names between one system's words and the next
  marginTop: pt(4),
  marginBottom: pt(LEAD),
  color: col('ink'),
  minSystemsAtBreak: 2, // never a lone system at a page foot or head
};
// Two habits of Verovio's ABC reader shape the w: lines. Every sung note takes the next
// syllable in order: the `_` and `*` holds are read as nothing, so the second note of a

El script.js compuesto funciona tal cual: pégalo como script de módulo en cualquier página o abre la receta en CodePen. Carpeta de la receta en GitHub ↗ (se abre en una nueva pestaña)

Variantes

#Graba en Bravura

Bravura tiene cabezas de nota más gruesas y aire de plancha grabada; le va a un himnario compuesto en una letra más oscura.

-  musicFont: 'Leland', // lighter noteheads than Bravura, close to Spectral's colour
+  musicFont: 'Bravura',

#Numera los compases

Un coro ensaya por números de compás; imprime uno al comienzo de cada sistema.

-  barNumbers: 'none', // a table of singers counts verses, not bars
+  barNumbers: 'system',

Errores frecuentes

Error frecuente

Un estilo de título hereda el salto de página de su nivel

Una entrada de headingStyles toma de su nivel de título todo lo que no fija, también breakBefore. Un índice o un colofón con estilo sobre un H1 tras un :::pagebreak hereda la paridad 'odd' y cae detrás de una página en blanco. Dale a ese estilo breakBefore: { enabled: false }. Estilos de título →

  • El lector ABC de Verovio no hace caso de las marcas _ y * de una línea w:: cada nota toma la sílaba siguiente. Bajo la segunda nota de una ligadura escribe un espacio de no separación (U+00A0) como sílaba propia; no imprime nada. Las notas ligadas por - no toman sílaba.
  • ~ une dos sílabas bajo una misma nota (de~a-trás), pero el grabador las imprime con un espacio normal, sin el signo de sinalefa.
  • Escribe los acordes sin ♭ ni ♯ cuando puedas: la mayoría de las letras de texto no tienen esos signos y la página tira de una fuente del sistema. Elige tonalidades con acordes naturales (sol, do, re7, mi menor) o escribe «si bemol» en el texto.

Créditos

Texto
Fuentes
Spectral (SIL OFL 1.1) · Spectral SC (SIL OFL 1.1) · Fraunces (SIL OFL 1.1)
SandboxPDF