Ir al contenido
learn

Diario

  • Misión y plan
  • Código del curso: renderizado sin navegador, check.sh, CI en Linux, Windows y macOS
  • Lección 1: primer pentagrama, primera tablatura
  • Lección 2: técnicas de guitarra
  • Lección 3: armaduras, compases, claves y afinaciones
  • Lección 4: caso práctico, el chatbot de GA escribe VexTab
  • Lección 5: los propios objetos de VexFlow, una voz estricta
  • Lección 6: TabStave y TabNote
  • Lección 7: renderizar en React, probar con Playwright
  • Lección 8: pasar GA de VexFlow 4 a 5

Lo que el curso encontró en el software que enseña, y en el código de Guitar Alchemist que lo usa. Los enlaces a VexTab apuntan a 3a5e00d, el commit a partir del cual se construyó el 4.0.5 de npm; los de VexFlow a 0ca6f88, el 5.0.0 que incluye; los de GA a 17ccee6. Cada medida es una salida de check.sh, comparada en CI. Todavía no se ha comunicado nada a los proyectos; una búsqueda en las issues de VexTab y de VexFlow no encontró ningún informe previo de estos puntos.

Lo esperado Lo que pasa Dónde Medida Estado
strings=4 dimensiona el dibujo para cuatro líneas de tablatura La opción sigue siendo una cadena; VexFlow calcula la altura del pentagrama como ("4" + 4) * 13 StaveBuilder.ts:141, VexTabParser.ts:86-89, VexFlow stave.ts:142 Dibujo de 712 px de alto para strings=4, 842 para 5, 1102 para 7, frente a 270 para seis cuerdas; lo mismo en Chrome Reproducido con Node y en Chrome (lección 3)
$G$ después de un acorde dibuja el texto G Cualquier texto que coincida con un nombre de nota sustituye el número de traste de la cuerda más grave del acorde, y no se dibuja ninguna anotación ArticulationBuilder.ts:362, :461 $G$ $C$ $D$ sobre tres acordes: 0 anotaciones, 3 números de traste sustituidos; $.big.G$ y $D $ se dibujan como texto Reproducido. Documentado como una función para notas sueltas; una trampa para los nombres de acorde (lección 2)
$.italic.let ring$ está en cursiva VexTab pasa el estilo como tercer argumento de VexFlow 5, el grosor ArticulationBuilder.ts:298-302, VexFlow element.ts:392 El SVG dice font-weight="italic", sin font-style Reproducido
El logotipo vexflow.com está centrado y en cursiva Se mide antes de fijar su fuente, así que se coloca con el ancho de la fuente equivocada, y sale recto por la misma razón que arriba ArtistRenderer.ts:262-266 x = 187,78 en un dibujo de 600 px con notación (Chrome: 188,52), Reproducido con Node y en Chrome (H2)
X/6 es una nota apagada en la cuerda 6 El analizador léxico lee X como un nombre de nota, así que 6 pasa a ser una octava: la notación dibuja una cabeza de nota en x donde iría si6, en y = 0, medio fuera del dibujo vextab.jison:84, NoteBuilder.ts:264-266 Misma posición en Chrome, a menos de 0,67 px Reproducido con Node y en Chrome (H3). La tablatura es correcta
La afinación eb de VexFlow es la estándar medio tono más baja La cuerda 6 es Db/3, un tono más baja VexFlow tuning.ts:16 La cuerda 6 al aire se dibuja como do♯3 (escrito), donde se quería mi♭3; la línea no ha cambiado en main de VexFlow Reproducido (lección 3)
V dibuja un vibrato áspero VexTab llama a setHarsh solo si existe, y el Vibrato de VexFlow 5 no lo tiene ArticulationBuilder.ts:635-640, VexFlow vibrato.ts 7v y 8V dibujan los mismos tres glifos U+EAB0 Reproducido
Cinco negras en un compás de 4/4 se rechazan Se dibujan: las voces de VexTab están en modo soft ArtistRenderer.ts:67 l01-overfull se renderiza Reproducido. Deliberado, por lo que dice el código (lección 1)
Los bloques vextab del chatbot de GA son VexTab Usan un formato de tokens de GA, string/fret, sin tabstave ni notes GA PlayableNotationFormatter.cs:15-25, :59-71 12 de 12 bloques (8 acordes para principiantes, el ejemplo del prompt, 3 pruebas e2e) rechazados por VexTab 4.0.5 y por el parser F# de GA Corregido upstream por #736, fusionada el 2026-09-25: los bloques son VexTab de verdad, y VexTab 4.0.5 dibuja los 10 bloques del formateador 2026-09-25
El cliente de chat de GA dibuja los bloques vextab, como afirma su prueba e2e MemoizedVexTab los imprime en un <pre> GA MemoizedVexTab.tsx:11-28, vextab-rendering.spec.ts:94-99 Leído, no ejecutado; la prueba unitaria es it.skip Corregido por #736: el cliente analiza el bloque y dibuja un pentagrama de tablatura con VexFlow 4.2.5. La especificación e2e no se ejecuta en ningún workflow de GA, y no podía pasar tal como está escrita 2026-09-25
El campo de traza notation.renderer de GA dice qué dibujó la notación Es la constante "vexflow" GA OrchestratedChatApplicationService.cs:336 45 trazas de referencia: 44 con added_count 0, una con 8 Retirado por #736: las trazas cuentan ahora los bloques y los que lee el parser de GA; las 45 trazas de referencia siguen fijando el campo antiguo hasta que se vuelvan a grabar 2026-09-25
El parser F# de GA lee lo que escribe su generador, y los ejemplos de su gramática str, ch y pint se comen el espacio en blanco que los sigue, incluido el espacio con el que empieza la siguiente opción de tabstave GA VexTabParser.fs:22-29, :330 La ida y vuelta falla en la columna 51 o 52 para 6 de 6 textos analizables; 0 de 4 ejemplos EBNF se analizan Corregido por #736: los separadores son explícitos, y una prueba de ida y vuelta y los ejemplos de la gramática pasan 2026-09-25
El parser F# de GA acepta VexTab Difiere en las técnicas (después de la cuerda), los bemoles (b), las duraciones en mitad de línea, las series de trastes, los taps, las anotaciones y las tonalidades menores GA VexTabParser.fs:85, :239-244, :413-420 De 32 textos, el parser de GA acepta 6 y VexTab 17; coinciden en «ok» en 4 Corregido en lo esencial por #736: las siete diferencias listadas han desaparecido; faltan todavía las líneas stave y voice, las ligaduras, los legatos, los tresillos y algunas duraciones 2026-09-25
Pregunta Hipótesis, escrita antes de medir Resultado Veredicto
¿El renderizado sin navegador (jsdom, texto medido con opentype.js) coloca los glifos donde lo hace Chrome? H1: a menos de 1,0 px en x y en y para cada elemento de texto de l01-notation, l02-chords y l03-keys, si Chrome carga Bravura y Academico (hypotheses.md, confirmado en 284eb7e antes de cualquier ejecución en el navegador) 157 elementos de texto en cinco dibujos: |dx| máx. 0,74 px, |dy| máx. 0,67 px, tamaños iguales (browser-2026-09-24.txt). Las dos primeras ejecuciones estaban mal, mira la entrada Confirmada
¿El logotipo descentrado es un artefacto del entorno sin navegador? H2: Chrome lo dibuja con una x a menos de 1 px de 187,78. No a ciegas Chrome: 188,52 Confirmada
¿Chrome también dibuja X/6 en la octava 6? H3: sí, en la misma y. No a ciegas Misma posición, dentro de los 0,67 px de arriba Confirmada
¿El dibujo de 712 px de strings=4 es un artefacto de jsdom? H4: el SVG de Chrome mide 712 px de alto. No a ciegas 600 × 712 Confirmada

El vextab 4.0.5 de npm se publicó el 2026-01-18; sus fuentes son idénticas al commit 3a5e00d de 0xfe/vextab (comprobado archivo por archivo con SHA-1). Su dist/main.prod.js incluye VexFlow 5.0.0, Vex.Flow.BUILD.ID 0ca6f889…, y recrea encima el espacio de nombres Vex.Flow de VexFlow 4. Instalar vexflow a su lado no cambia nada para VexTab; el curso fija vexflow 5.0.0 de todos modos, para la lección 5. GA, en cambio, usa VexFlow ^4.2.5, y distribuye un vexflow.js 4.2.5 para la API de su chatbot.

El bundle quiere window, self, document y getComputedStyle; jsdom se los da. Lo que no da es la medición de texto: VexFlow mide cada glifo con un canvas. Primer intento, node-canvas 3.2.3 con registerFont sobre los archivos OTF de Bravura y Academico: en Windows no carga estas fuentes de tipo CFF y mide en silencio con una fuente sans-serif de reserva. Sustituido por un pequeño contexto que mide con opentype.js a partir de los mismos archivos OTF (lib/env.cjs), pasado a VexFlow con Element.setTextMeasurementCanvas. La salida es la misma en los tres sistemas operativos de la CI, así que los SVG pueden compararse byte a byte tras renumerar los identificadores y redondear a dos decimales.

2026-09-24 — Sin navegador frente a Chrome

Sección titulada «2026-09-24 — Sin navegador frente a Chrome»

Hipótesis escritas y confirmadas primero en un commit (284eb7e). Después, los mismos cinco archivos pasados por el bundle de navegador en Chrome 153 sin interfaz, releyendo cada <text> (browser/).

La primera ejecución dio una diferencia de 204 px en el logotipo y glifos ilegibles: la página de prueba no tenía <meta charset="utf-8">, Chrome decodificó el bundle como Windows-1252, y cada punto de código SMuFL se convirtió en caracteres corruptos. Un error de medición, no un resultado. La segunda ejecución estaba desfasada en un elemento en l02-vibrato-mute: compare.mjs omitía los elementos <text> sin atributo y, y VexFlow no escribe ninguno cuando y vale 0, que es el caso del glifo de la nota apagada. Corregido leyendo cada atributo por separado, con uno ausente como 0. La tercera ejecución es la de la tabla: 0,74 px como mucho, en el logotipo.

Clon parcial (sin blobs, disperso) de GA en 17ccee6, nueve archivos. El formateador C# compila por separado; los tres archivos F# compilan sin cambios con FParsec 1.1.1 sobre .NET 10, como lo referencia GA. Resultados en la lección 4. Lo que esperaba al empezar: que los bloques del chatbot usaran un dialecto antiguo de VexTab. Lo que salió: no usan ningún dialecto de VexTab, el cliente no los dibuja, y el propio parser de GA rechaza la salida de su propio generador. VexTab, mientras tanto, lee sin problemas la salida del generador de GA. No se ha enviado nada a GA: los hallazgos están en el informe para el usuario, que decide.

  • #736, fusionada el 2026-09-25, corrige las cinco filas de GA. Cada cambio tiene una prueba que falla con el código antiguo: 51 de las 57 pruebas de ida y vuelta, 22 de las 35 pruebas del formateador, la prueba de trazas y 4 pruebas de dibujo del cliente.
  • El parser. str, ch y pint ya no consumen los espacios que los siguen. El mismo defecto hacía que key=G seguido de un salto de línea leyera la n del notes de la línea siguiente como un becuadro. El parser y el generador siguen ahora a VexTab donde el tutorial y vextab.jison son claros: técnicas entre trastes (5h7/3), @ para los bemoles en las notas, key=Am, duraciones a mitad de línea, series de trastes, taps, anotaciones como elementos de nota, el orden de los indicadores de duración de VexTab. Pasados por el banco de este curso sobre 25 textos, GA y VexTab 4.0.5 coinciden ahora en todos; para los 20 que ambos aceptan, el texto que GA vuelve a escribir dibuja un SVG idéntico byte a byte al del original. Sin hacer, y listado en la PR: las líneas stave y voice, las ligaduras, los legatos, los tresillos, las duraciones :1 :2 :4 :64, y X como nombre de nota.
  • El chatbot. Sus bloques son ahora VexTab: do abierto se escribe tabstave / notes :w (3/5.2/4.0/3.1/2.0/1), y el prompt pide esa forma. MemoizedVexTab analiza un bloque y dibuja un pentagrama de tablatura con VexFlow 4.2.5; un bloque que no puede dibujar entero queda como texto, y data-renderer en el bloque dice qué ve el lector. La constante notation.renderer ha desaparecido: el servidor no dibuja nada, así que las trazas dan ahora notation.vextab.block_count y valid_count.
  • Lo que el curso dejaba por verificar. Ningún workflow de GA ejecuta las especificaciones Playwright de ga-client: ci.yml solo pasa el linter y construye el cliente. Y vextab-rendering.spec.ts no podía pasar tal como está escrita, porque su beforeEach hace clic en una pestaña «AI Chat Assistant» que ya no existe. Leído en los workflows y la especificación de GA, sin ejecutar.
  • Las 45 trazas de referencia fijan el campo antiguo notation.renderer; vienen de ejecuciones reales y hay que volver a grabarlas en una máquina que tenga el modelo. Leyendo el cliente de chat, la misma sesión encontró que /ai-copilot fallaba en su primer renderizado; lo corrige #737.
  • La afinación eb en un navegador: el valor está en la tabla de VexFlow y el dibujo sin navegador muestra do♯3, pero la comparación con el navegador no incluía l03-tuning.
  • Firefox y Safari: la comparación con el navegador solo se hizo en Chrome sin interfaz, en Windows.
  • Si VexFlow 4, tal como lo usa GA, tiene el orden de argumentos de setFont que hacía de italic un estilo en él: no comprobado, ya que el curso fija VexFlow 5.
  • ¿La sustitución del traste por anotaciones con nombre de nota debe aplicarse a los acordes, o solo a las notas sueltas? El código la aplica a la cuerda más grave de cualquier grupo de notas.
  • ¿Debería VexTab convertir strings= en número y pasar el número? Ya existe un parseInt, una línea por encima de la que lo olvida.