# CSS Grid로 악보 출력 하기

> Clean Markdown view of GeekNews topic #14594. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=14594](https://news.hada.io/topic?id=14594)
- GeekNews Markdown: [https://news.hada.io/topic/14594.md](https://news.hada.io/topic/14594.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2024-05-01T12:38:08+09:00
- Updated: 2024-05-01T12:38:08+09:00
- Original source: [cruncher.ch](https://cruncher.ch/blog/printing-music-with-css-grid/)
- Points: 11
- Comments: 2

## Topic Body

- 작은 모바일 화면에서 A4 PDF를 확대하며 연주하는 음악가들을 위해, 웹에서 유동적이고 반응형인 악보 렌더링이 필요함  
  
### Scribe 프로토타입  
- 과거에 JSON에서 SVG를 출력하는 Scribe라는 음악 렌더러를 프로토타입으로 제작했음   
- 원래 목표는 반응형 음악 렌더러를 제작하는 것이었으나 복잡한 다중 패스 레이아웃 엔진을 작성해야 해서 진전이 어려웠음  
- 이후 CSS Grid를 프로젝트에 도입하면서 Scribe에서 다루던 레이아웃 문제의 해답이 될 수 있을 것 같았음  
  
### .stave 클래스  
- 오선지는 그리드와 비슷함. 수직 축은 음높이, 수평 축은 시간임   
- .stave 클래스에서는 수직 축인 그리드 행을 정의  
- 표준 음높이 이름으로 고정 크기 그리드 행을 만들고 오선지를 그리는 배경 이미지를 사용  
- 트레블 음자리 오선에 대한 행 맵 예시:  
  ```css  
  .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%;  
  }  
  ```  
- 각 오선과 간격에 음높이 이름의 그리드 선이 생김  
  
#### 오선에 음높이 배치  
- 오선의 각 행에는 여러 음높이가 위치할 수 있음  
- DOM 요소가 올바른 행에 위치하도록 하기 위해 data-pitch 속성에 음높이 이름을 넣고 CSS로 data-pitch 값을 오선 행에 매핑  
  ```css  
  .stave > [data-pitch^="G"][data-pitch$="4"] { grid-row-start: G4; }  
  ```  
- 이 규칙은 'G'로 시작하고 '4'로 끝나는 음높이를 캡처해서 'G♭4', 'G4', 'G♯4' 등을 G4 행에 할당  
- 모든 오선 행에 대해 이를 수행해야 함  
- 이제 몇 가지 기호를 오선에 배치할 수 있음  
  
### .bar 클래스와 박자  
- 리듬을 처리하는 것은 좀 더 까다로움  
- 모든 종류의 리듬을 지원하는 명확한 최소 리듬 분할이 없음   
- 24열 당 1박자 접근법은 8분 음표, 16분 음표, 32분 음표 및 3연음표를 균등하게 배치할 수 있어 좋은 출발점임  
- 4박자를 4 × 24 = 96 그리드 열로 정의하고 시작과 끝에 열을 추가:  
  ```css  
  .bar {  
    column-gap: 0.03125em;  
    grid-template-columns:  
      [bar-begin]  
      max-content  
      repeat(96, minmax(max-content, auto))  
      max-content  
      [bar-end];  
  }  
  ```  
- ::before와 ::after로 마디선을 추가하고 data-pitch="B4"로 음자리 기호를 중앙에 배치  
  
#### 박자에 기호 배치   
- 이번에는 data-beat 속성을 사용하여 요소에 박자를 할당하고 CSS 규칙을 사용하여 박자를 그리드 열에 매핑  
- CSS 맵은 1/24박자마다 하나의 규칙으로 구성  
- 속성 ^= 시작 선택기를 사용하면 규칙이 오차 허용이 됨  
- .stave 클래스와 함께 사용하면 data-beat를 1~5 사이의 박자로, data-pitch를 음 이름으로 설정하여 박자와 음높이별로 기호를 배치할 수 있음  
  
### 유동적이고 반응형인 악보  
- 이러한 여러 마디를 flexbox 컨테이너에 넣으면 반응형 악보를 볼 수 있음   
- 아직 누락된 것들이 많지만 시작하기에 좋은 기반임  
- 이미 온라인 음악 렌더러보다 훨씬 우아하게 줄 바꿈이 됨  
  
#### 음표 사이의 공간  
- 서로 더 가까운 시간에 발생하는 음표 머리는 약간 더 가깝게 렌더링됨  
- 작은 column-gap에 의해 만들어진 미묘하고 의도적인 효과로, 기호 요소가 슬롯에 들어가는 일종의 시간 '에테르' 역할을 함  
- 열 자체는 음표 머리가 없으면 너비가 0이지만 박자가 더 멀리 떨어진 이벤트 사이에는 더 많은 열 간격(박자당 24개)이 있어 더 많은 거리가 생김  
- 기호의 여백을 조정하여 일정한 간격을 제어할 수 있음  
  
### 음자리와 박자 기호  
- 수직 및 수평 간격에 대해 별도 클래스를 사용한 이유는 다른 것을 건드리지 않고 하나를 교체할 수 있기 때문   
- 같은 멜로디를 베이스 음자리에 표시하려면 .stave 클래스를 같은 data-pitch 속성을 베이스 오선 행에 매핑하는 bass-stave 클래스로 교체하면 됨  
- CSS로 data-duration="5"를 .bar의 120 그리드 템플릿 열에 매핑하면 같은 오선에 5/4 박자 기호를 줄 수 있음  
  
### 코드와 가사  
- CSS Grid를 사용하면 악보 그리드 내에서 다른 기호도 정렬할 수 있음  
- 코드와 가사, 다이내믹 등을 시간이 지정된 이벤트와 정렬하고 확장할 수 있음  
  
### 음표 꼬리   
- 음표 꼬리, 코드, 일부 긴 쉼표는 data-duration 속성을 grid-column-end 범위 값에 매핑하여 열에 걸치게 만듦  
  
### 크기 조정  
- 전체 시스템은 em 단위로 크기가 지정되므로 font-size를 변경하는 것만으로 크기를 조정할 수 있음  
  
### Flex와 Grid의 한계  
- 완벽한 시스템은 아님. 한계점:  
  1. CSS는 줄 바꿈시 새 음자리/조표를 자동으로 배치할 수 없음  
  2. 새 줄의 새 음표에 묶음줄을 연결할 수 없음  
  3. 기울어진 음표 꼬리는 Grid가 배치한 후에야 정확한 위치를 알 수 있어 정렬이 어려움  
- 완전히 마무리하려면 약간의 정리 JavaScript가 필요하지만 CSS가 레이아웃 작업의 대부분을 처리하므로 JavaScript에서 할 레이아웃 작업이 훨씬 줄어듦  
  
###  사용자 정의 요소  
- 이 새로운 CSS 시스템을 중심으로 인터프리터를 작성하고  요소에 래핑함  
- 아직 프로덕션 준비는 안되었지만 반응형 리드 시트를 렌더링하고 드럼을 표기할 수 있어 흥미롭고 유용함  
- 콘텐츠의 데이터, src 속성으로 가져온 파일, 요소의 .data 속성에 설정된 JS 객체에서 악보를 렌더링함  
- 현재 개발 빌드는 웹 페이지에 파일을 가져와서 사용해 볼 수 있음  
  
### 앞으로 계획  
- Scribe 0.3의 개선사항 외에 장기적으로 조사하고 싶은 기능:  
  - SMuFL 글꼴 지원 - 악보 기호에 사용되는 글꼴 변경  
  - 중첩 시퀀스 지원 - 다중 파트 곡 활성화  
  - 분할 오선 렌더링 - 한 오선에 여러 파트 배치  
  - 다중 오선 렌더링 - 여러 개의 정렬된 오선에 여러 파트 배치  
  
### GN⁺의 의견  
- 웹에서 악보를 유동적이고 반응형으로 렌더링하는 것은 음악가와 음악 애호가 모두에게 매우 유용할 것 같음. PDF 악보를 작은 화면에서 확대/축소하며 보는 불편함을 해소해 줄 수 있을 것  
- CSS의 Grid와 Flex 레이아웃을 활용한 접근 방식이 흥미로움. 복잡한 레이아웃 엔진 없이도 CSS만으로 꽤 많은 부분을 해결할 수 있다는 것을 보여주는 좋은 예시  
- 하지만 악보의 특성상 CSS만으로는 한계가 있는 부분들도 있음. 줄 바꿈 시 자동으로 음자리나 조표를 배치한다든지, 묶음줄을 자동 연결하는 것 같이 음악적 문맥을 이해해야 하는 부분은 자바스크립트의 도움이 필요할 것  
- 리드 악보 렌더링과 드럼 악보 지원 등 이미 꽤 많은 부분을 구현했다고 하니, 조만간 충분히 쓸만한 수준으로 개선될 수 있을 것 같음. 오픈소스화 해서 개발이 지속된다면 MuseScore 같은 기존 악보 편집기의 좋은 대안이 될 수 있을 것  
- 앞으로 계획하고 있는 SMuFL 글꼴 지원, 다중 파트 및 다중 오선 렌더링 지원 등의 기능이 구현된다면 악보 표현의 완성도가 크게 높아질 것 같음. 기대가 되는 프로젝트

## Comments



### Comment 24995

- Author: roxie
- Created: 2024-05-06T21:19:19+09:00
- Points: 1

이러시는 이유가 있을거 아니예요

### Comment 24834

- Author: neo
- Created: 2024-05-01T12:38:08+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=40216057) 
- Sheet music 소프트웨어 개발자로부터 CSS 그리드를 이용한 악보 렌더링 방식에 대해 찬사가 있음
  - Soundslice라는 웹 기반 악보 렌더링 서비스를 10년 넘게 개발해 왔으며, 2014년에 최초로 "반응형" 웹 악보 렌더링을 구현했음
  - 관련 기술 상세 내용은 발표 영상 링크 참고: [https://www.youtube.com/watch?v=XH5EtQge_Bg](https://www.youtube.com/watch?v=XH5EtQge_Bg)
  - Soundslice의 반응형 악보 예시 링크: [https://www.soundslice.com/slices/zzNlc/](https://www.soundslice.com/slices/zzNlc/)
  - 웹 기반 편집기, 연습 기능, 사진/PDF에서 악보 데이터 추출하는 스캔 기능 등 다양한 툴을 제공함
  - CSS 그리드 방식은 가벼운 프로젝트에는 유용할 수 있지만, 풀 스코어의 복잡하고 미묘한 표현을 다 구현하기는 어려울 것임
- JavaScript 없이 CSS만으로 구현할 수 있도록 CSS 커뮤니티에 제안해보는 것도 좋을 듯함
  - 예를 들어 줄바꿈 시 음자리표 반복 표시는 sticky table header와 유사한데, 악보 외에도 활용될 수 있음 
- CSS의 attribute selector(`[...]`) 문법이 인상 깊었음. 예: `.stave > [data-pitch^="A"][data-pitch$="5"] { grid-row-start: A5; }`
- 음악 조판사 입장에서는 시각적으로 개선이 많이 필요해 보임. CSS만으로는 정밀도에 한계가 있어 어려울 듯함
  - 음표 기둥, 활, 붙임줄 등의 표현에 문제가 있음 
  - 대부분의 브라우저 악보는 SVG나 Canvas로 벡터 렌더링하여 핀포인트 정밀도를 구현함
  - CSS 외에 이미 Soundslice, Sibelius Cloud Publishing 등 브라우저에서 스케일러블한 악보를 구현하는 다른 도구들이 있음
- 처음에는 CSS로 악보를 표현하는 게 잘 안 될 것 같았는데, 간단한 방식으로 타이포그래피 품질이 인상적임. 작성자에게 찬사를 보냄
  - 다만 화음, 8/16분음표 간격, 파트 간 정렬 등 특수한 경우 잘 작동할지 우려됨. Lilypond는 이런 복잡한 표현에서 유연성이 입증됨
- CSS 그리드가 흥미로움. 예전에 가구 디자이너를 pure frontend JS로 CSS 그리드 활용해 구현한 적 있음: [https://alnvdl.github.io/2023/01/07/designing-furniture-using-the-css-grid.html](https://alnvdl.github.io/2023/01/07/designing-furniture-using-the-css-grid.html) 
- `&lt;scribe-music&gt;` 커스텀 엘리먼트도 기대됨
  - 몇 년 전 인턴이 VexFlow를 웹 컴포넌트로 래핑한 프로젝트 진행했었는데 유지보수 안 됨: [https://github.com/PolymerLabs/vexflow-elements/blob/web-components/demo/index.html](https://github.com/PolymerLabs/vexflow-elements/blob/web-components/demo/index.html)
  - 잘 관리되고 사용하기 쉬운 라이브러리가 웹 음악 표기법에 큰 도움이 될 것임
- Lilypond(lilypond.org)의 대안이 나온 것은 좋지만, 표기법이 매우 복잡해서 간결성의 이점은 오래가지 않을 듯함 
  - Asciidoc 매니아라면 Lilypond를 Asciidoc 툴체인에 통합하기 쉬움. DocBook PDF 파이프라인에서 사용 중이며, 출력물이 꽤 괜찮음. TeX과 유사함
- [https://www.musicxml.com](https://www.musicxml.com)과 [https://opensheetmusicdisplay.org](https://opensheetmusicdisplay.org) 를 상기시켜 줌. 훨씬 큰 비용이 들지만 완전한 솔루션임
- Impro-Visor([https://github.com/Impro-Visor/Impro-Visor](https://github.com/Impro-Visor/Impro-Visor))의 어설픈 악보 기능을 이것으로 대체할 수 있을지 궁금함
- CSS 벤치마크 같은 느낌
