Boxloom: 덱 작성하기
Boxloom은 의미와 모양을 분리합니다. 작성자는 콘텐츠가 무엇인지(포인트 목록, 옵션 비교, 날짜 계획)만 작성합니다. 템플릿이 모든 색상, 글꼴 크기, 여백 및 위치를 결정합니다. 하나의 예외(shapes, 최후의 수단)를 제외하고는 색상, 크기 또는 좌표를 절대 작성하지 않습니다.
루프는 항상 다음과 같습니다:
boxloom schema— 현재 템플릿이 허용하는 내용을 읽습니다 (먼저 이 작업을 수행하세요).deck.bx.md를 작성합니다.boxloom check -format json deck.bx.md— 모든 오류를 수정하고, 가능한 모든 경고를 수정합니다."ok": true이고layout-overflow경고가 없을 때까지 3을 반복합니다.boxloom build -o deck.pptx deck.bx.md(플래그는 파일 앞에 옵니다).
명령어는 저장소의 boxloom/ 디렉토리에서 실행합니다:
go run ./cmd/boxloom <schema|check|build|parse> … (Go 1.24+, 다른 종속성 없음).
1. 먼저 스키마를 읽으세요
boxloom schema [-template light|dark]는 하나의 JSON 문서를 출력합니다. 이 문서가 진리의 원천입니다. 이 파일과 스키마가 다르면 스키마가 우선합니다.
markdown.rules— 구문 규칙 (짧은 목록; 모두 준수하세요).markdown.frontMatter—---헤더에서 허용되는 키 (title은 필수).templates[].blocks— 이 템플릿이 알고 있는 펜스 블록 (:::name)으로,inside(어디에 나타날 수 있는지),contains(무엇을 포함하는지),minChildren을 포함합니다.templates[].subsystems— 그림 유형 (```name코드 블록)으로,markdown(추가 규칙) 및schema(irSchema내의 JSON 포인터로 허용된 모든 키 제공)를 포함합니다.- 나열되지 않은 것은 오류입니다. 블록 이름, 속성 또는 키를 임의로 만들지 마세요.
- 템플릿은 이름으로 선택됩니다 (머리말에서
template: light또는-template dark). 사용자 정의 템플릿은 경로로 전달되는 값 테이블 파일입니다:-template ./my.json(schema,check,build,fonts에 대해 작동하며, 예시examples/templates/forest.json). 덱을 사용자 정의 템플릿으로 빌드할 때는 동일한-template으로schema와check를 실행하세요 — 역할 이름과 텍스트 스타일은 해당 파일에서 가져옵니다. variant(# Title {variant=…})는 구문에 존재하지만, 현재 템플릿은 변형을 선언하지 않습니다 (templates[].variants는 비어 있음). 따라서 사용하지 마세요.
출력은 큽니다. 필요한 것만 보려면:
go run ./cmd/boxloom schema -template light > /tmp/schema.json
python3 -c "import json;d=json.load(open('/tmp/schema.json'));print(json.dumps({'rules':d['markdown']['rules'],'blocks':d['templates'][0]['blocks'],'subsystems':[(x['name'],x['markdown']) for x in d['templates'][0]['subsystems']]},ensure_ascii=False,indent=1))"
python3 -c "import json;d=json.load(open('/tmp/schema.json'));print(json.dumps(d['irSchema']['\$defs']['gantt'],ensure_ascii=False,indent=1))" # 모든 간트 키
2. 한 화면에 담은 구문
---
title: 보고 서비스를 새 클러스터로 이전
subtitle: 계획 및 옵션 (가상 예시)
author: 플랫폼 팀
date: 2026-11-11
confidential: 내부
conclaimer: 모든 이름과 수치는 가상입니다
template: light
---
# 기존 클러스터의 벤더 지원
:::lead
기존 클러스터는 2028년 3월에 벤더 지원이 종료되므로, 해당 클러스터에서 실행 중인 14개 서비스는 그 전에 이전해야 합니다.
:::
- 벤더는 **2028-03-31**에 보안 수정을 중단합니다
- 여전히 14개 서비스가 실행 중이며, 그중 9개는 코드 변경 없이 이전 가능합니다
- 이전에는 서비스 그룹당 약 6주가 소요됩니다
:::source
2026년 9월 벤더 지원 공지; 2026년 10월 기준 서비스 인벤토리
:::
:::notes
발표자 노트는 여기에 작성합니다. 일반 단락과 글머리 기호만 가능합니다.
:::
-
# Title은 슬라이드를 시작합니다. 제목을 한 줄에 맞는 짧은 헤드라인으로 유지하세요 ("기존 클러스터의 벤더 지원"); 줄 바꿈이 있는 제목은 경고됩니다 (title-wrap). 슬라이드가 전달하는 내용 — 결론 — 을 제목 바로 뒤:::lead에 문장으로 작성하세요 (1–2줄). 템플릿은 제목 아래, 본문 외부에 리드를 배치합니다. -
---는 슬라이드 구분 기호가 아닙니다 (오류입니다).##및 더 깊은 제목은 오류입니다 (그룹 제목은:::column Title로 작성하며, 하위 제목이 아닙니다). -
본문: 단락,
-/1.글머리 기호 (최대 두 수준),**emphasis**(한 종류의 강조만),`code`,[text](url), 의미 있는 줄 바꿈을 위한 후행\. 이탤릭체, 취소선, 각주, HTML은 없습니다. -
펜스 블록:
:::name으로 열고 같은 수의 콜론으로 닫습니다. 중첩할 때, 외부 펜스는 내부 펜스보다 콜론 하나 더를 사용합니다::::::compare ::::option 기존 클러스터 유지 :::pros - 올해 마이그레이션 작업 없음 ::: :::cons - 2028년 3월 이후 보안 수정 없음 ::: :::: ::::option 새 클러스터로 이전 :::pros - 2033년까지 지원 ::: :::cons - 서비스 그룹당 6주 작업 ::: :::: ::::: -
:::lead(슬라이드 메시지),:::notes(발표자 노트) 및:::source(슬라이드 숫자의 출처)는 슬라이드의 최상위 수준에 위치해야 하며, 각 슬라이드당 한 번씩만 사용합니다.:::lead는 콘텐츠 슬라이드에만 사용됩니다. -
머리말의
date,confidential및disclaimer는 덱에 대해 한 번만 작성합니다. 템플릿은 이를 표지에 배치하고 (confidential은 바닥글에도 배치). 모든 슬라이드의:::note에 "가상" / "기밀"을 반복하지 마세요. -
그림은 언어가 서브시스템 이름이고 본문이 제한된 YAML로 된 펜스 코드 블록입니다: 앵커/별칭 (
&,*) 없음, 태그 없음, 여러 줄 값 없음,|/>블록 없음; 부울은true/false만; 날짜는 문자열YYYY-MM또는YYYY-MM-DD; 범위2027-01 .. 2027-06.*,&,!로 시작하거나": "를 포함하는 값은 인용하세요 (예:text: ["**Slowest step**", 평균 5일]) — 흐름 항목의 시작 부분에 인용되지 않은**…**는 YAML 별칭으로 읽혀 거부됩니다.
3. 각 콘텐츠에 대한 패턴 선택
콘텐츠를 작성하기 전에 콘텐츠 유형을 결정하세요. 다음 규칙을 순서대로 적용하고 일치하는 첫 번째 규칙을 사용하세요. (전체 규칙 모음 및 좋은/나쁜 예시: docs/patterns.md §4.)
현재 사용 가능 (더 추가되었을 수 있으니 boxloom schema를 확인하세요):
| 콘텐츠 | 사용법 | 참고사항 |
|---|---|---|
| 챕터 구분 | # Part 2: How we migrate {type=section} | 제목 텍스트가 챕터 제목입니다. :::notes 외에는 아무것도 따라올 수 없습니다. 목차가 아닙니다 — 덱에 두 개 이상의 섹션이 있을 때 템플릿은 모든 섹션 슬라이드에 현재 섹션이 강조된 챕터 목록을 자체적으로 그립니다 |
| 슬라이드가 정확히 한 문장을 말하고, 증거는 다른 슬라이드에 있습니다 | # Migration must move two years earlier {type=statement} | 제목 텍스트가 문장입니다 (이것은 제목이 완전한 문장인 유일한 슬라이드 유형입니다). :::notes 및 :::source 외에는 아무것도 따라올 수 없습니다. 이유를 추가하려면 짧은 제목과 결론을 :::lead로 사용하는 일반 슬라이드를 사용하세요 |
| 비교할 시리즈 없이 강력하게 보여줄 1–4개의 숫자 | ::::stat → :::value 3 → 12 {unit=models} + 한 줄 레이블 내부 | 5개 이상의 숫자 또는 시계열은 차트/표이지 stat이 아닙니다. 값은 있는 그대로 작성되며 숫자를 포함해야 합니다. 값과 단위는 중간에 절대 나뉘지 않으므로 짧게 유지하세요 — 4개의 카드는 좁습니다 (stat-value) |
| 숫자의 시리즈(3+ 포인트): 순위, 시간에 따른 변화, 전체 중 비율, 분포, 두 양의 관계 | ```chart | compare: item / timeSeries / component / frequency / correlation — 차트 유형은 자동으로 선택됩니다 (절대 bar/line/pie를 작성하지 마세요). categories: [...], series: [{name, values: [...]}] (카테고리당 하나의 값, 인용되지 않은 숫자, 최대 3개 시리즈), 선택적 unit, emphasis: [category] (하나의 시리즈) 또는 하나의 시리즈에 emphasis: true, 시리즈가 전체의 일부일 때 stacked: true. correlation은 xAxis: {title, unit?}, yAxis 및 points: [[x, y], …]를 카테고리 대신 사용합니다. component (비율)는 1개의 시리즈와 ≤ 6개의 부분을 가집니다 — 작은 부분은 "Other"로 병합하세요 |
| 다른 사람의 말 | :::quote Source text + 내부 단어 | 출처 (제목 텍스트)는 필수입니다. 자신의 결론을 인용하지 마세요 |
| 일반 슬라이드 내에서 강조할 한 문장 | :::takeaway + 한 문장 | 슬라이드당 최대 하나, 보통 마지막 |
| 일반 텍스트 또는 숫자의 행 × 열 | GFM 테이블: | A | B | + | --- | --- | + 행 | 첫 번째 행은 헤더입니다. 모든 행은 열당 하나의 셀을 가집니다 (table-shape). 정렬 표시자 없음 (:--, --:는 오류입니다); 숫자 열은 자동으로 오른쪽 정렬됩니다. 셀은 인라인만 가능합니다. 테이블 바로 다음 줄 : caption은 캡션입니다. 마지막 행이 합계인 경우 해당 줄을 {total=last}로 끝내세요 (: Estimates {total=last} 또는 그냥 : {total=last}). 합계 행으로 그려집니다. 합계는 계산되지 않습니다 — 값을 작성하세요. 단위는 캡션이나 헤더에 한 번 넣고, 모든 셀에 넣지 마세요. 셀의 평점 → matrix (아래) |
| 모든 셀이 평점(지원/조건부/없음/위험)인 행 × 열 | ```matrix | columns: [A, B], rows: [{label, cells: [{status, text?}]}], 선택적 legend: {support: Good}. 열당 하나의 셀 (matrix-cells). 권장 옵션: emphasis: <열 제목 텍스트> (columns에 정확히 작성된 대로, matrix-emphasis) — 산문에서 "파란색 열"이라고 말하지 마세요. 일반 텍스트나 숫자인 셀은 matrix가 아닌 테이블입니다 |
| 날짜 없이 방향이 있는 3–7 단계 (하나의 출력이 다음의 입력) | ```process | steps: [{title, detail?, status?, emphasis?}], 선택적 caption. 번호(1. 2. …)와 화살표는 자동으로 추가됩니다. 긴 프로세스는 두 번째 행으로 넘어갑니다. status를 사용하는 경우, legend: {conditional: Needs approval} (figure-legend)에서 의미를 말하세요 |
| 두 개 이상의 옵션, 각각 장단점이 있음 | :::compare → :::option → :::pros / :::cons | 모든 옵션에 적용되는 3개 이상의 공유 기준이 있다면, 위의 matrix가 더 적합합니다 |
| 자식(및 손자)이 있는 부모: 팀 구성, 소유권 | ```orgchart | root: {title, detail?}, units: [{title, detail?, members: [{title, detail?}]}]. 최대 3단계. 상자의 status에는 legend: {conditional: Two more people needed}가 필요합니다 — 차트 아래의 범례가 이를 설명합니다. :::note에서 외곽선 색상을 설명하지 마세요. 나란히 있는 관련 없는 팀에는 사용하지 마세요 |
| 개수가 줄어드는 단계 (방문 → 가입 → 유료) | ```funnel | stages: [{label, value, note?}], 선택적 unit. value는 숫자 또는 텍스트입니다. 막대 너비는 계단식이며 비례하지 않습니다. 단계 간 전환율(↓ 45%)은 숫자 값에서 자동으로 그려집니다 — note에 작성하지 마세요. 단계가 떨어지는 이유에 note를 사용하세요. status에는 legend가 필요합니다. 증가하는 값은 경고됩니다 (funnel-increase) — 일반 단계에는 process를 사용하세요 |
| 시간에 따른 날짜 계획, 기간, 마감일, 상태 | ```gantt | 상태는 support, conditional, none, danger입니다 (역할, 색상 아님). 하드웨어/지원 위험 기간은 그룹 risk: A .. B입니다. 주석은 target을 통해 그룹/행 id를 가리킵니다. 서브시스템이 배치합니다 |
| 나란히 읽는 2–3개의 병렬 그룹 ("올해 / 내년 / 하지 않음") | ::::columns → :::column Group title (2 또는 3) | 각 그룹은 단락, 글머리 기호, 하나의 테이블, 하나의 이미지, 하나의 ```chart 또는 :::note를 포함합니다. 중첩된 columns, compare, gallery 또는 기타 그림은 없습니다. 차트 + 읽기 나란히: 차트는 한 그룹에, 주요 내용은 다른 그룹에 글머리 기호로 표시합니다. 너비는 숫자가 아닙니다: 주요 그룹 하나를 {role=main}으로 표시하거나 (다른 그룹은 지원) 모두 동일하게 둡니다. 4개 이상의 한 줄 그룹은 글머리 기호를 사용하세요. 두 개로 나뉜 하나의 주장에는 사용하지 마세요 |
| 요점을 보여주는 이미지 (스크린샷, 사진, 그림) | 만 포함하는 단락 | 대체 텍스트는 필수입니다 (image-alt). 경로는 덱 파일을 기준으로 합니다. URL, 절대 경로 또는 .. 없음 (image-path). PNG 또는 JPEG만 가능 (image-format). 비율 유지, 절대 자르지 않음. 이미지 + 텍스트 나란히 → 이미지가 한 그룹에 있는 ::::columns 사용 |
| 비교되거나 순서대로 있는 2–6개의 이미지 | 2–6개의 가 있는 하나의 단락 | 갤러리가 됩니다 (2–3개는 한 행, 4–6개는 그리드). 7개 이상은 오류입니다: 슬라이드를 나누세요 |
| 병렬 포인트 | 글머리 기호 | 최대 2단계 |
| 연결된 산문 | 단락 | 2–3문장 |
| 슬라이드가 말하는 것: 한두 문장으로 된 결론 | 콘텐츠 슬라이드 최상위 수준의 :::lead, 한 단락 | 모든 콘텐츠 슬라이드는 하나를 가집니다. 템플릿이 제목 바로 아래, 본문 외부에 배치합니다. 본문에서 공간을 차지합니다 (1줄 ≈ 32pt, 2줄 ≈ 57pt). 두 줄이 필요할 때 엔진은 줄 바꿈을 추가하지 않고 문장 끝(。) 또는, 실패할 경우 쉼표(、) 뒤에서 줄을 바꿉니다. 따라서 두 개의 짧은 문장이 가장 잘 읽힙니다. 글머리 기호의 요약이 아니라 그들이 증명하는 주장입니다 |
| 슬라이드의 숫자, 표, 그림 또는 인용문의 출처(출처, 표본 크기, 날짜) | 슬라이드 최상위 수준의 :::source, 한 단락 | 숫자, 표, 차트 또는 인용문을 표시하는 모든 슬라이드는 하나를 가집니다. 콘텐츠 및 명령문 슬라이드만 해당됩니다 (섹션 아님). 템플릿이 본문 아래, 바닥글 위에 배치합니다. 본문에서 공간을 차지합니다 (layout-overflow가 이를 계산합니다). 슬라이드당 하나: 여러 출처는 한 단락에 넣습니다 |
| 덱 전체의 날짜, 기밀성, 면책 조항 ("모든 수치는 가상입니다") | 머리말 date, confidential, disclaimer | 한 번 작성합니다. 표지에 표시됩니다 (그리고 바닥글에 confidential). |
| 주의사항 / 각주와 같은 설명 | :::note | 하나의 짧은 줄. 출처(:::source)용이 아니며, 덱 전체 면책 조항(머리말)용이 아니며, 결론이나 주요 숫자용이 절대 아닙니다. |
| 위치/링크가 의미를 전달하고 위의 어떤 것에도 맞지 않는 다이어그램 | ```shapes | 최후의 수단, §3.1 참조 |
위의 네 가지 그림 모두에서 텍스트, status (support, conditional, none, danger) 및 emphasis: true만 작성합니다. 위치, 크기 및 색상은 템플릿에서 제공됩니다. chart에서는 비교 대상과 숫자만 작성합니다. 차트는 값이 계속 편집 가능한 실제 PowerPoint 차트입니다. 제목이 전달하는 한 가지 요점을 강조하세요:
compare: timeSeries
unit: " 가입자"
categories: [4월, 5월, 6월, 7월, 8월, 9월]
emphasis: [9월]
series:
- name: 가입자
values: [120, 150, 180, 210, 250, 300]
4. 밀도 제한
레이아웃 엔진은 각 슬라이드의 여유 공간을 측정하고 초과분을 보고합니다. check는 제목, 리드, 본문, 출처를 합친 높이가 슬라이드 여유 공간을 초과할 때 layout-overflow를 보고합니다. 각 항목은 대략적인 포인트 단위 높이를 가집니다:
| 항목 | 대략적인 높이 |
|---|---|
| 제목 (한 줄) | 36pt |
:::lead (1줄 / 2줄) | 32pt / 57pt |
| 글머리 기호 항목 | 22pt |
| 일반 단락 줄 | 18pt |
:::source (한 줄) | 14pt |
| 이미지 | 이미지 비율에 따라 다름 |
layout-overflow 경고는 수정해야 합니다. 본문 줄 수를 줄이거나, 긴 포인트를 여러 슬라이드로 나누거나, 리드를 한 줄로 줄이세요.
5. 확인 → 수정 루프
check 명령어는 다음을 보고합니다:
error— 반드시 수정해야 합니다 (예: 알 수 없는 블록 이름, 누락된 필수 속성)warning— 수정을 권장합니다 (title-wrap,layout-overflow)info— 정보 제공용 메시지
JSON 출력 형식을 사용하여 오류를 한 번에 처리하세요:
go run ./cmd/boxloom check -format json deck.bx.md | python3 -c "
import json, sys
report = json.load(sys.stdin)
for item in report.get('errors', []):
print(f'ERROR: {item["message"]} at {item["location"]}')
"
루프는 다음과 같습니다:
check실행- 모든 오류 수정
- 가능한 모든 경고 수정 (
layout-overflow는 필수) "ok": true이고layout-overflow경고가 없을 때까지 반복build
6. 빌드
boxloom build -o 출력.pptx 덱.bx.md [-template 템플릿]
- 출력 파일 이름을 지정하려면
-o플래그를 사용하세요. - 사용자 정의 템플릿을 사용하려면
-template플래그를 추가하세요. - 플래그는 항상 파일 앞에 옵니다.
go run ./cmd/boxloom build -o output.pptx deck.bx.md -template light
7. 예제
examples/ 디렉토리에는 다음이 포함됩니다:
examples/decks/— 전체 덱 예제examples/templates/— 사용자 정의 템플릿 예제 (forest.json등)
덱을 검증하고 빌드하려면:
cd examples/decks
ls *.bx.md # 사용 가능한 덱 확인
go run ../../cmd/boxloom check -format json example.bx.md
go run ../../cmd/boxloom build -o example.pptx example.bx.md
