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
// 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
- Funciones
- Notación musicalEstilo de partituraVerso línea a líneaAperturas diseñadasAtributos de títuloTítulos numeradosEstilos de títuloCapítulos sin númeroCubiertas, portadas y colofonesMetadatos del documentoÍndice generalCabeceras y foliosCabeceras según el tipo de páginaEstilos de párrafoMárgenes simétricosPaleta de color semánticaColor del papelTextos, filetes y cajas en los diseños de páginaExportación a PDF
- También usa
- Columnas en un recuadro o en el textoListados de códigoFuentes incrustadas en el PDFCabeceras por secciónSuperíndices y subíndices
- 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
// # 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
// :::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
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
// ═══ 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íneaw:: 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
- Receta
- Ignacio Ferro
- Texto
- Amazing Grace: letra (1779, cinco de las seis estrofas, con la grafía de los Olney Hymns) · John Newton · dominio público
- Amazing Grace: la melodía New Britain (Southern Harmony, 1835), según la armonización de E. O. Excell de 1900, con cifrados añadidos · Traditional American; William Walker; Edwin O. Excell · dominio público
- Oh My Darling, Clementine: letra y melodía (Oliver Ditson, Boston, 1884) · Percy Montrose · dominio público
- Auld Lang Syne: letra (1788) y la melodía escocesa de Select Songs of Scotland de George Thomson (1799) · Robert Burns; traditional · dominio público
- Cumpleaños feliz: la melodía de Good Morning to All (Song Stories for the Kindergarten, Chicago, 1893); letra española popular · Mildred J. Hill; traditional · dominio público
- Martinillo: la melodía francesa de Frère Jacques (siglo XVIII) con la letra popular española · Traditional · dominio público
- La cucaracha: melodía, estribillo y copla según la transcripción de la Wikipedia en español; dos coplas populares mexicanas · Traditional · dominio público
- El prólogo, las notas a las canciones y los cifrados · Ignacio Ferro · CC BY 4.0
- Fuentes
- Spectral (SIL OFL 1.1) · Spectral SC (SIL OFL 1.1) · Fraunces (SIL OFL 1.1)
- Código
- MIT, como Postext
Editar este texto ↗ (se abre en una nueva pestaña)Carpeta de la receta en GitHub ↗ (se abre en una nueva pestaña)


