Community라이팅 & 에디팅github.com

tjst-t/boxloom

Boxloom 마크다운(.bx.md)으로 슬라이드 덱을 작성하고, 이를 네이티브 편집 가능한 PPTX로 변환합니다. 프레젠테이션/파워포인트/슬라이드를 Boxloom으로 만들거나 .bx.md 파일을 편집할 때 사용하세요. 구문, 콘텐츠 유형별 패턴 선택 방법, 레이아웃 엔진이 측정하는 밀도 제한, 그리고 확인 → 수정 루프를 다룹니다.

boxloom란 무엇인가요?

Boxloom은 콘텐츠의 '의미'와 '디자인'을 완전히 분리하여, 작성자는 오직 슬라이드가 전달하려는 정보(요점 목록, 옵션 비교, 날짜별 계획 등)에만 집중하고, 템플릿이 모든 색상, 글꼴 크기, 여백 및 위치를 결정하는 AI 에이전트 스킬입니다. 사용자는 `boxloom schema` 명령어로 현재 템플릿이 허용하는 블록, 속성, 규칙을 먼저 확인한 후, 마크다운(.bx.md) 파일을 작성하고 `boxloom check`로 오류를 수정한 뒤 `boxloom build`로 PPTX를 생성하는 명확한 워크플로우를 따릅니다. 이 스킬은 Claude Code, Cursor, Codex 등 터미널 기반 AI 코딩 에이전트에 적합하며, Go 1.24+ 환경에서 `go run ./cmd/boxloom` 명령어로 실행됩니다. 특히 다양한 콘텐츠 패턴(차트, 간트 차트, 프로세스, 조직도, 비교 블록 등)을 템플릿이 자동으로 시각화하여, 사용자는 마크다운 구문에만 집중하면 일관된 디자인의 프레젠테이션을 얻을 수 있습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/tjst-t/boxloom/tree/HEAD/skills/boxloom

Installed? Explore more 라이팅 & 에디팅 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

미리보기

스킬 README에서

alt text
alt

문서

Boxloom: 덱 작성하기

Boxloom은 의미와 모양을 분리합니다. 작성자는 콘텐츠가 무엇인지(포인트 목록, 옵션 비교, 날짜 계획)만 작성합니다. 템플릿이 모든 색상, 글꼴 크기, 여백 및 위치를 결정합니다. 하나의 예외(shapes, 최후의 수단)를 제외하고는 색상, 크기 또는 좌표를 절대 작성하지 않습니다.

루프는 항상 다음과 같습니다:

  1. boxloom schema — 현재 템플릿이 허용하는 내용을 읽습니다 (먼저 이 작업을 수행하세요).
  2. deck.bx.md를 작성합니다.
  3. boxloom check -format json deck.bx.md — 모든 오류를 수정하고, 가능한 모든 경고를 수정합니다.
  4. "ok": true이고 layout-overflow 경고가 없을 때까지 3을 반복합니다.
  5. 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+ 포인트): 순위, 시간에 따른 변화, 전체 중 비율, 분포, 두 양의 관계```chartcompare: 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 (아래)
모든 셀이 평점(지원/조건부/없음/위험)인 행 × 열```matrixcolumns: [A, B], rows: [{label, cells: [{status, text?}]}], 선택적 legend: {support: Good}. 열당 하나의 셀 (matrix-cells). 권장 옵션: emphasis: <열 제목 텍스트> (columns에 정확히 작성된 대로, matrix-emphasis) — 산문에서 "파란색 열"이라고 말하지 마세요. 일반 텍스트나 숫자인 셀은 matrix가 아닌 테이블입니다
날짜 없이 방향이 있는 3–7 단계 (하나의 출력이 다음의 입력)```processsteps: [{title, detail?, status?, emphasis?}], 선택적 caption. 번호(1. 2. …)와 화살표는 자동으로 추가됩니다. 긴 프로세스는 두 번째 행으로 넘어갑니다. status를 사용하는 경우, legend: {conditional: Needs approval} (figure-legend)에서 의미를 말하세요
두 개 이상의 옵션, 각각 장단점이 있음:::compare → :::option → :::pros / :::cons모든 옵션에 적용되는 3개 이상의 공유 기준이 있다면, 위의 matrix가 더 적합합니다
자식(및 손자)이 있는 부모: 팀 구성, 소유권```orgchartroot: {title, detail?}, units: [{title, detail?, members: [{title, detail?}]}]. 최대 3단계. 상자의 status에는 legend: {conditional: Two more people needed}가 필요합니다 — 차트 아래의 범례가 이를 설명합니다. :::note에서 외곽선 색상을 설명하지 마세요. 나란히 있는 관련 없는 팀에는 사용하지 마세요
개수가 줄어드는 단계 (방문 → 가입 → 유료)```funnelstages: [{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개 이상의 한 줄 그룹은 글머리 기호를 사용하세요. 두 개로 나뉜 하나의 주장에는 사용하지 마세요
요점을 보여주는 이미지 (스크린샷, 사진, 그림)![alt text](images/x.png "caption")만 포함하는 단락대체 텍스트는 필수입니다 (image-alt). 경로는 덱 파일을 기준으로 합니다. URL, 절대 경로 또는 .. 없음 (image-path). PNG 또는 JPEG만 가능 (image-format). 비율 유지, 절대 자르지 않음. 이미지 + 텍스트 나란히 → 이미지가 한 그룹에 있는 ::::columns 사용
비교되거나 순서대로 있는 2–6개의 이미지2–6개의 ![alt](path "caption")가 있는 하나의 단락갤러리가 됩니다 (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"]}')
"

루프는 다음과 같습니다:

  1. check 실행
  2. 모든 오류 수정
  3. 가능한 모든 경고 수정 (layout-overflow는 필수)
  4. "ok": true이고 layout-overflow 경고가 없을 때까지 반복
  5. 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

관련 스킬