Imprimindo partituras com CSS Grid
(cruncher.ch)- Para músicos que tocam ampliando PDFs A4 em telas pequenas de celular, é necessário um renderizador de partituras fluido e responsivo na web
Protótipo Scribe
- No passado, foi criado como protótipo um renderizador musical chamado Scribe, que gerava SVG a partir de JSON
- O objetivo original era criar um renderizador musical responsivo, mas o progresso foi difícil porque seria preciso escrever um mecanismo de layout complexo de múltiplas passagens
- Depois, ao introduzir CSS Grid no projeto, pareceu que isso poderia ser a resposta para os problemas de layout tratados no Scribe
Classe .stave
- A pauta é parecida com uma grade. O eixo vertical é a altura das notas, e o eixo horizontal é o tempo
- Na classe
.stave, são definidas as linhas da grade no eixo vertical - São criadas linhas de grade de tamanho fixo com nomes de notas padrão, usando uma imagem de fundo para desenhar a pauta
- Exemplo de mapa de linhas para uma pauta em clave de sol:
.stave { display: grid; row-gap: 0; grid-template-rows: [A5] 0.25em [G5] 0.25em [F5] 0.25em [E5] 0.25em [D5] 0.25em [C5] 0.25em [B4] 0.25em [A4] 0.25em [G4] 0.25em [F4] 0.25em [E4] 0.25em [D4] 0.25em [C4] 0.25em ; background-image: url('/path/to/stave.svg'); background-repeat: no-repeat; background-size: 100% 2.25em; background-position: 0 50%; } - Cada linha e cada espaço da pauta passa a ter uma linha de grade com o nome de uma nota
Posicionando alturas na pauta
- Várias alturas podem ser posicionadas em cada linha da pauta
- Para colocar elementos do DOM na linha correta, o nome da nota é colocado no atributo
data-pitch, e o CSS mapeia esse valor para a linha da pauta.stave > [data-pitch^="G"][data-pitch$="4"] { grid-row-start: G4; } - Essa regra captura alturas que começam com
Ge terminam com4, atribuindoG♭4,G4,G♯4etc. à linha G4 - Isso precisa ser feito para todas as linhas da pauta
- A partir daí, já é possível posicionar alguns símbolos na pauta
Classe .bar e ritmo
- Lidar com o ritmo é um pouco mais complicado
- Não existe uma divisão rítmica mínima claramente definida que suporte todos os tipos de ritmo
- A abordagem de 24 colunas por batida é um bom ponto de partida, pois permite posicionar colcheias, semicolcheias, fusas e tercinas de forma uniforme
- Definindo 4 batidas como 4 × 24 = 96 colunas de grade e adicionando colunas no início e no fim:
.bar { column-gap: 0.03125em; grid-template-columns: [bar-begin] max-content repeat(96, minmax(max-content, auto)) max-content [bar-end]; } - Barras de compasso são adicionadas com
::beforee::after, e a clave é centralizada comdata-pitch="B4"
Posicionando símbolos no tempo
- Desta vez, o atributo
data-beaté usado para atribuir uma batida aos elementos, e regras CSS mapeiam a batida para colunas da grade - O mapa em CSS consiste em uma regra para cada 1/24 de batida
- O seletor de atributo de início
^=torna as regras tolerantes a imprecisões - Usando isso junto com a classe
.stave, é possível posicionar símbolos por batida e por altura, definindodata-beatcomo uma batida entre 1 e 5 edata-pitchcomo o nome da nota
Partituras fluidas e responsivas
- Colocando vários desses compassos dentro de um contêiner flexbox, é possível ter uma partitura responsiva
- Ainda faltam muitas coisas, mas já é uma boa base para começar
- A quebra de linha já funciona de forma muito mais elegante do que nos renderizadores musicais online existentes
Espaço entre as notas
- As cabeças de nota que ocorrem em tempos mais próximos são renderizadas um pouco mais próximas entre si
- Esse é um efeito sutil e intencional criado pelo pequeno
column-gap, que funciona como uma espécie de "éter" temporal no qual os elementos simbólicos se encaixam - As próprias colunas têm largura 0 quando não há cabeça de nota, mas eventos mais distantes no tempo têm mais espaços entre colunas (24 por batida), o que gera maior distância
- É possível controlar o espaçamento constante ajustando as margens dos símbolos
Claves e fórmulas de compasso
- O motivo de usar classes separadas para espaçamento vertical e horizontal é que uma pode ser trocada sem mexer na outra
- Para exibir a mesma melodia em clave de fá, basta trocar a classe
.stavepor uma classebass-staveque mapeie os mesmos atributosdata-pitchpara as linhas da pauta de clave de fá - Mapeando
data-duration="5"em CSS para 120 colunas no template de grade de.bar, a mesma pauta pode receber uma fórmula de compasso 5/4
Acordes e letras
- Com CSS Grid, também é possível alinhar outros símbolos dentro da grade da partitura
- Acordes, letras, dinâmicas etc. podem ser alinhados e expandidos junto com eventos temporizados
Hastes das notas
- Hastes das notas, acordes e algumas pausas longas se estendem por colunas ao mapear o atributo
data-durationpara um valor de intervalo emgrid-column-end
Escalonamento
- Todo o sistema é dimensionado em unidades
em, então é possível redimensioná-lo apenas alterandofont-size
Limites de Flex e Grid
- Não é um sistema perfeito. Limitações:
- O CSS não consegue posicionar automaticamente uma nova clave/armadura em uma quebra de linha
- Não consegue conectar barras de união a novas notas em uma nova linha
- Hastes inclinadas só têm sua posição exata conhecida depois que o Grid faz o posicionamento, o que dificulta o alinhamento
- Para finalizar tudo por completo, será preciso um pouco de JavaScript de organização, mas como o CSS faz a maior parte do trabalho de layout, a quantidade de layout a ser feita em JavaScript fica muito menor
Elemento personalizado
- Foi escrito um interpretador em torno desse novo sistema em CSS e encapsulado em um elemento
- Ainda não está pronto para produção, mas já consegue renderizar lead sheets responsivos e notação de bateria, o que o torna interessante e útil
- A partitura é renderizada a partir de dados do conteúdo, de arquivos carregados via atributo
srce de objetos JS definidos na propriedade.datado elemento - No momento, o build de desenvolvimento pode ser importado em uma página web para testes
Planos futuros
- Além das melhorias do Scribe 0.3, há recursos que se pretende investigar no longo prazo:
- Suporte a fontes SMuFL - trocar a fonte usada para símbolos musicais
- Suporte a sequências aninhadas - viabilizar músicas com múltiplas partes
- Renderização de pauta dividida - posicionar várias partes em uma única pauta
- Renderização de múltiplas pautas - posicionar várias partes em várias pautas alinhadas
Opinião do GN⁺
- Renderizar partituras de forma fluida e responsiva na web parece ser algo muito útil tanto para músicos quanto para amantes da música. Isso pode resolver o incômodo de ficar ampliando e reduzindo partituras em PDF em telas pequenas
- A abordagem usando layouts Grid e Flex do CSS é interessante. É um bom exemplo de como o CSS sozinho já consegue resolver bastante coisa sem um mecanismo de layout complexo
- Mas, pelas características da notação musical, há pontos em que o CSS sozinho tem limitações. Partes que exigem compreensão do contexto musical, como posicionar automaticamente claves ou armaduras em quebras de linha, ou conectar barras de união automaticamente, vão precisar da ajuda do JavaScript
- Como já foram implementadas várias partes, como renderização de lead sheets e suporte a partitura de bateria, parece possível que isso evolua em breve para um nível bastante utilizável. Se virar open source e o desenvolvimento continuar, pode se tornar uma boa alternativa a editores de partitura existentes como o MuseScore
- Se forem implementados recursos planejados como suporte a fontes SMuFL, múltiplas partes e renderização de múltiplas pautas, a qualidade da representação musical deve aumentar bastante. É um projeto promissor
2 comentários
Deve haver um motivo para você estar fazendo isso, né?
Comentários no Hacker News
[...]) do CSS pareceu impressionante. Ex.:.stave > [data-pitch^="A"][data-pitch$="5"] { grid-row-start: A5; }<scribe-music>também gera expectativa