목적: REFERENCE.md의 한국 공문서 표준을 kordoc
markdownToHwpx(src/hwpx/generator.ts)의 '공문서 모드(gongmun mode)' 로 구현하기 위한 기술 스펙. 대상 파일:/Users/chris_gomdori/workspace/kordoc/src/hwpx/generator.ts작성일: 2026-06-19
generator.ts 코드에서 직접 확인한 단위 매핑 — 새 모드는 이 규약을 그대로 따른다.
| 개념 | 함수/속성 | 단위 규약 | 실측 예 (현재 코드) |
|---|---|---|---|
| 글자 크기 | charPr(id, height, …) → <hh:charPr height="…"> |
height = pt × 100 | 1000=10pt, 900=9pt, 1800=18pt(h1), 1400=14pt(h2), 1200=12pt(h3), 1100=11pt(h4) |
| 줄간격 | paraPr(id, {lineSpacing}) → <hh:lineSpacing type="PERCENT" value="…"> |
퍼센트 정수 | 160(기본), 180(h1), 130(코드) |
| 들여쓰기(좌여백/내어쓰기) | paraPr(id, {indent}) → <hh:margin indent="…"> |
HWPUNIT | 400(코드블록), 600(인용/리스트) |
| 문단 위/아래 간격 | {spaceBefore, spaceAfter} → <hh:margin prev/next> |
HWPUNIT | 800/200(h1) |
| 정렬 | {align} → <hh:align horizontal="…"> |
LEFT/CENTER/RIGHT/JUSTIFY |
기본 JUSTIFY |
| 용지·여백 | generateSecPr() → <hp:pagePr><hp:margin> |
HWPUNIT, 1mm ≈ 283.46 HWPUNIT | width=59528(210mm), height=84188(297mm) |
HWPUNIT 환산 상수: 1mm = 7200/25.4 ≈ 283.465 HWPUNIT. 1pt = 100 (charPr height). 1타(영문·숫자 1자 폭) ≈ 본문 글자폭의 절반 = 약 0.5em. 12pt 본문 기준 1em ≈ 12pt ≈ 1200 charPr-height이나, 들여쓰기(paraPr indent)는 폭 HWPUNIT 이므로 별도 환산 필요(아래 2장).
⚠️ 현재 generator의 secPr 여백은 비표준이다. 코드 주석/값: 위 30mm(8504)/아래 15mm(4252)/좌 20mm(5670)/우 15mm(4252). REFERENCE 검증 결과 공식값은 위 20 / 아래 10 / 좌 20 / 우 20mm. 공문서 모드에서는 이 값을 교체해야 한다(3.3 참조).
현재 파서(parseMarkdownToBlocks)는 리스트를 indent = floor(선행공백/2)로 잡고 ordered(숫자) / 비순서(-*+)만 구분한다(generator.ts L207-213). 공문서 8단계는 들여쓰기 깊이(0~7) 로 1:1 대응시키되, 부호 종류는 깊이별 고정 매핑으로 강제한다(마크다운의 1./- 종류 무시).
| MD 들여쓰기 depth | 공문서 단계 | 출력 부호 | 카운터 진행 |
|---|---|---|---|
| 0 | 1 첫째 | 1. 2. … |
아라비아 |
| 1 | 2 둘째 | 가. 나. … |
가나다 → (소진 시) 거/너/더 |
| 2 | 3 셋째 | 1) 2) … |
아라비아 |
| 3 | 4 넷째 | 가) 나) … |
가나다 |
| 4 | 5 다섯째 | (1) (2) … |
아라비아 (괄호 3글자) |
| 5 | 6 여섯째 | (가) (나) … |
가나다 (괄호 3글자) |
| 6 | 7 일곱째 | ① ② … |
원숫자 U+2460+ |
| 7 | 8 여덟째 | ㉮ ㉯ … |
원한글 U+326E+ |
- 레벨별 독립 카운터 + 상위 번호 변경 시 하위 리셋(현재
orderedCounters가 이미 indent별 카운터 + 하위 리셋 로직 보유, L580-639 — 재사용). - 가나다 시퀀스:
['가'..'하'](14자) 소진 후거/너/더…단모음 연속(REFERENCE 1.5). 구현: 초성 인덱스 배열 + 중성 순환. - 원숫자:
String.fromCodePoint(0x2460 + n)(①⑳ = U+2460U+2473). 원한글:String.fromCodePoint(0x326E + n)(㉮~㉻). - 5·6단계는 반드시 괄호 3글자 문자열(
(+숫자/한글+)), 단일 유니코드 ⑴/㈎ 금지. - 항목이 1개뿐인 레벨은 부호 미부여(REFERENCE 1.2) — 같은 depth·같은 부모에서 형제 수=1이면 부호 없이 내용만. (2-pass: 1차에서 형제 수 집계, 2차에서 부호 결정.)
현재 generator는 리스트를 indentPrefix + marker + text로 하나의 run에 합쳐 공백 들여쓰기로 표현(L636-637). 공문서 모드는 공백 들여쓰기 대신 paraPr indent + 내어쓰기를 써야 줄바꿈 정렬(REFERENCE 1.3)이 깨지지 않는다. 따라서:
- 텍스트 =
부호 + 1타공백 + 내용(한 run), 들여쓰기는 paraPr로(아래 b장). - 1타 공백은 부호 뒤 실제 공백 1개(
가. 내용)로 출력.
REFERENCE: 2타 = 한글 1자 = 영문·숫자 2자, 1타 = 영문·숫자 1자 폭 ≈ 0.5 한글자. 본문 15pt 기준:
- 한글 1자 폭 ≈ 1em ≈ 15pt ≈ 약 1417 HWPUNIT (15pt × 283.465/72 × ... → 실용 근사
1자폭 ≈ height/100 × 283.465/2.835). 실무 근사: 1타 ≈ 한글 글자폭의 1/2 ≈ 700~750 HWPUNIT(15pt), 2타 ≈ 1400~1500 HWPUNIT. - 단순·안정 구현 권장값: 2타 = 1400 HWPUNIT(≈한글 1자, 15pt 기준), 1타 = 700 HWPUNIT. (글자크기 가변 시
2타 = round(height × 1.4)식으로 동적 산출 가능하나, 한글 표준 실무는 고정 폭 들여쓰기로 충분.)
각 단계마다 좌여백(left) = 누적 2타 + 내어쓰기(indent 음수) = 부호폭+1타 를 둔다. <hh:margin left="…" indent="…"> — left는 문단 전체 좌여백, indent는 첫 줄 추가 들여쓰기(음수면 내어쓰기/hanging).
현재
paraPr()는indent만 받고left=0고정(L378). 공문서 모드는paraPr헬퍼에left파라미터를 추가해야 한다.
| 단계 | 부호 | 누적 들여(타) | left (HWPUNIT) | 부호폭+1타 (hanging indent, 음수) | lineSpacing |
|---|---|---|---|---|---|
| 1 | 1. | 0 | 0 | -2100 (부호 2타+1타 ≈ 3타) | 공문서 기본(아래) |
| 2 | 가. | 2 | 1400 | -2100 | 〃 |
| 3 | 1) | 4 | 2800 | -2100 | 〃 |
| 4 | 가) | 6 | 4200 | -2100 | 〃 |
| 5 | (1) | 8 | 5600 | -2800 (3글자 부호 → 4타) | 〃 |
| 6 | (가) | 10 | 7000 | -2800 | 〃 |
| 7 | ① | 12 | 8400 | -2100 | 〃 |
| 8 | ㉮ | 14 | 9800 | -2100 | 〃 |
- hanging indent:
<hh:margin left="L" indent="-H">→ 첫 줄은L-H(부호가 더 왼쪽), 둘째 줄부터L(내용 첫 글자에 맞춰 정렬). 이것이 REFERENCE 1.3 "둘째 줄 내용 첫 글자 정렬"을 paraPr로 구현하는 방법. - 단순화 옵션(내어쓰기 생략 가능): "왼쪽 기본선 시작도 무방"(REFERENCE 1.3)이므로, indent 없이
left=누적2타만 줘도 규정 위반 아님. 권장은 hanging(가독성).
REFERENCE 2.3: 단일 표준값 없음 → 프리셋으로 분기(아래 e장). 공문서 모드 기본 본문 줄간격:
- 기안문/통지: 160% (보고서 관행·가독성). 또는 시스템 호환 위해 130%.
- 큰글자 서식 준용: 130% 이상(법정 하한).
- 현재
paraPr기본 lineSpacing=160(L372) — 기안문엔 그대로 두되 프리셋에서 override.
코드에 단일값 하드코딩 금지(검증 confirmed). 프리셋 파라미터로 노출.
REFERENCE 2.2: 본문 크기 법정 강제 없음 → 프리셋 값. height = pt×100.
| 요소 | charPr id(현재) | 권장 height (공문서 모드) | pt |
|---|---|---|---|
| 본문 | 0 (CHAR_NORMAL) | 1500 | 15pt (보고서 관행) 또는 1400=14pt |
| 볼드/이탤릭/볼드이탤릭 | 1/2/3 | 본문과 동일 height | 15pt |
| 인라인코드 | 4 (CHAR_CODE) | 1300 | 13pt (본문보다 약간 작게) |
| 문서 제목(h1) | 5 (CHAR_H1) | 2000 | 20pt |
| 대분류(h2) | 6 (CHAR_H2) | 1600 | 16pt |
| 소제목(h3) | 7 (CHAR_H3) | 1500 | 15pt |
| h4~h6 | 8 (CHAR_H4) | 1400 | 14pt |
| 표 헤더 | 9 | 1400~1500 | 본문 |
| 인용 | 10 | 1500 | 본문 |
현재 코드는 본문 1000(10pt). 공문서 모드는 본문 1500(15pt) 로 올려야 보고서 관행과 일치. 프리셋에서 설정.
REFERENCE 2.1: 본문 글꼴 비강제, 명조 vs 맑은고딕 갈림. 현재 header fontfaces는 HANGUL id0=함초롬바탕, id1=함초롬돋움, id2=HY견고딕(잔존 — 아래 참조).
- 기안문/통지/회의록(명조 관행): 본문 = 함초롬바탕(id0) 유지. 제목 = 함초롬돋움(id1) bold.
- 개조식·보고서·계획서(실측 폰트 프리셋, v4.0.1): 본문 = 휴먼명조, 제목 = HY헤드라인M(자체 굵기).
bodyFont: 'gothic'명시 시 본문 맑은 고딕. - (v4.0.1 제거) bold 시 fontId=2(견고딕/Arial Black) 강제 치환 — "정체모를 폰트" QA 결함으로 확정되어 삭제. 굵기는
<hh:bold/>정본 요소가 담당하고 폰트는 항상 원 폰트 유지 (실측 양식들도 원 폰트 + bold 요소). fontfaces의 HY견고딕(id2)은 id 안정성을 위해 잔존하나 기본 경로에서 참조하지 않음.
REFERENCE 2.5: 본문 검정 기본. 현재 charPr textColor 기본 #000000 — 유지. 강조는 bold(부분 색은 theme 옵션으로 이미 지원).
REFERENCE 2.7 실측: 법정 8단계는 본문과 동일(기본값 무변경), □/ㅇ/- 계열 전자결재 기안문은 □=HY견고딕 +2~3pt bold · ㅇ=한컴돋움 bold · -=휴먼명조 본문. 프리셋 기본값을 바꾸지 않고 명시 옵션으로 적용한다.
- 옵션:
levels: { [depth 0~7]: { font?, pt?(6~60), bold? } }— CLI--levels "0=HY견고딕/17/bold,1=한컴돋움/15/bold,2=휴먼명조/14"(/구분: 숫자=pt,bold·b=굵게,plain=굵게 해제, 그 외=글꼴명), MCPlevels객체. 셋 다 비면 무시. - 방출(
gen-levels.ts): 지정 단계마다 charPr 한 쌍(보통·굵게)을 docframe charPr 뒤 id 에, 글꼴은 정적 fontface 뒤에 append(프로필 append 글꼴 뒤). charPr 의 fontRef 는 한글·라틴만 단계 글꼴, 그 외 언어는 본문 글꼴 id(비실측 0·rich 4) — 비실측 프리셋의 HANJA 이하 1종 언어 테이블에 없는 id 를 가리키지 않는다(프로필 append 규약과 동일). 장평은 본문 항목과 같은 95%. - 적용(
gen-section.ts renderListItem): 지정 depth 의 항목은 전용 charPr, 인라인**강조**는 같은 단계의 bold 짝. 실측 프리셋의 □(GJ_CHAR_DAE)·보도자료 각주(12pt)보다 우선(명시 옵션). h2 말머리□(헤딩)·개조식 h3 □ 는 헤딩 charPr 그대로 — levels 는 리스트 항목 전용. - 내어쓰기(
levelIndent7번째 인자markerHeight): 부호폭은 그 단계 글자 크기로 계산해 둘째 줄이 내용 첫 글자에 정렬된다(17pt1.은 12pt 보다 넓게). 두 자리 부호 변형(10.)도 같은 기준.computeGongmunFitPlan은 지정 단계를 장평 변형에서 제외(개조식 □ 와 같은 취급). - 미지정이면 charPr·fontface 가 늘지 않아 기존 산출물 바이트 불변(테스트
gongmun-levels.test.ts).
| 표기 | 자동화 | 방법 | 주의 |
|---|---|---|---|
| 날짜 정규화 | ✅ 가능 | 텍스트 정규식 YYYY[-./]M[-./]D → YYYY. M. D. (월·일 0제거, 끝점, 점 뒤 1칸) |
본문 전 토큰 치환은 오탐 위험 → 명시 마커(예: {{date:2026-06-19}})나 결문 시행/접수란만 적용 권장 |
| 시각 정규화 | ✅ 가능 | HH시 MM분/H:M → HH:MM(24시각, 0표기) |
〃 |
| 붙임 표시 | ◐ 부분 | 붙임: → 붙임(쌍점 제거) + 2타 보장. 1개면 번호 제거 |
의미 파악 필요. 마커(붙임 블록) 권장 |
| 끝 표시 | ✅ 가능 | 본문 마지막 단락 뒤 자동 ∨∨끝. 단락 추가. 표로 끝나면 표 다음 단락에 끝. |
표 중간끝(이하 빈칸)은 자동 판별 불가 → 옵션 |
| 2타/1타 들여쓰기 | ✅ 가능 | b장 paraPr 매핑으로 자동 | — |
| 금액 한글 병기 | ◐ 부분 | 숫자→한글수 변환은 가능하나 "필요 시"라 자동화는 오버. 옵션 | — |
| 물결표/낫표/가운뎃점 | △ 수동 | 의미 의존 — 자동 치환 위험. 작성자 입력 유지 | 사전 등재어 판별 불가 |
| 개조식 종결 | ✗ 변환 / ◐ 검수 | 문체 변환(고쳐 쓰기)은 LLM 영역, 엔진 범위 밖. 검수는 v4.9.1부터 munche-lint.ts 가 경고로 노출(서술형 종결·당위·수사·항목 길이 — 보고서·계획서·개조식 프리셋 한정, gaejosik-munche.md) |
생성은 막지 않음 |
권장: 들여쓰기·끝·날짜/시각·붙임 쌍점제거는 자동. 금액/문장부호는 옵션 또는 수동. 자동 치환은 결문·붙임·끝 같은 구조적 위치에 한정하고 본문 자유텍스트 전역 치환은 피한다.
MarkdownToHwpxOptions에 gongmun?: { preset: 'report'|'official'|'plan'|'notice'|'minutes' } 추가. 프리셋이 charPr height·paraPr lineSpacing/margin·secPr 여백·끝표시 자동삽입 여부를 분기.
| 항목 | 보고서(report) | 기안문(official) | 계획서(plan) | 통지(notice) | 회의록(minutes) |
|---|---|---|---|---|---|
| 본문 글꼴 | 함초롬바탕(명조) | 함초롬바탕 / 맑은고딕 | 함초롬바탕 | 함초롬바탕 | 함초롬바탕 |
| 본문 height | 1500 (15pt) | 1500 | 1500 | 1500 | 1400 |
| 본문 줄간격 | 160 | 160 (또는 130 호환) | 160 | 160 | 130 |
| 제목 height (h1) | 2000~2200 | 1500 (제목줄) | 2000 | 1500 | 1500 |
| 최상위 부호 | Ⅰ.Ⅱ.Ⅲ + □○-· |
1. 가. 1) … |
Ⅰ.Ⅱ 또는 1. |
1. 가. |
진행순서 번호 |
| 항목 모드 | 보고서식(□○-·) | 표준 8단계 | 혼용 | 표준 8단계 | 안건별 |
| 여백 (mm) | 위15/아래15/좌우20 (정부3.0 관행) | 위20/아래10/좌우20 (공식) | 위20/아래10/좌우20 | 위20/아래10/좌우20 | 위20/아래10/좌우20 |
| 끝 표시 자동 | ✗ (보고서는 끝 안 씀) | ✅ 끝. |
◐ | ✅ 끝. |
✗ |
| 결문(발신명의 등) | ✗ | ✅ (4.3 구조) | ✗ | ✅ | ✗ |
| 쪽번호 | 중앙 하단 | 중앙 하단 | 중앙 하단 | 중앙 하단 | 중앙 하단 |
| 날짜/시각 정규화 | ◐ | ✅ | ◐ | ✅ | ✅ |
| 특징 | 개조식 명사형, 1건1매 | 두문·본문·결문, 8단계 | 5W2H 골격 | 경어 종결 | 법정 9요소 표 |
- 기안문/통지: 시행규칙 8단계(
1. 가. 1) 가) (1) (가) ① ㉮) 적용. - 보고서: 최상위 로마숫자
Ⅰ.Ⅱ.Ⅲ+ 항목□(대)○(중)-(소)·(세) — 관행. depth→부호 매핑을 프리셋별로 분기.
현재(generator.ts L505): top=8504(30mm) bottom=4252(15mm) left=5670(20mm) right=4252(15mm)
공문서 표준으로 교체: top=5670(20mm) bottom=2835(10mm) left=5670(20mm) right=5670(20mm)
머리말/꼬리말: header=0 footer=0 (현재 2835 → 0)
환산: 20mm=5669.3→5670, 10mm=2834.6→2835. (1mm=283.465 HWPUNIT)
paraPr()헬퍼에left파라미터 추가(현재 left=0 고정) — b-2 hanging indent용.- 공문서 본문용 paraPr 8종(단계별 left/indent) + 프리셋별 lineSpacing 추가(현재 paraProperties itemCnt 확장).
parseMarkdownToBlocks리스트 처리: depth→공문서 단계 매핑, 레벨별 부호 생성기(가나다·원숫자·괄호조합·단모음연속) 추가. 공백 prefix(L636) 대신 paraPr 들여쓰기로 전환.- 단일 형제 레벨 부호 생략(2-pass 형제 집계).
charPr본문 height 1000→프리셋값(1500 등).generateSecPr여백 표준값으로 교체(위20/아래10/좌우20, 머리말·꼬리말 0).끝./결문 자동삽입(official/notice 프리셋), 날짜/시각 정규화 유틸.- 옵션 타입
gongmun추가.
위 (b) 장의 left/indent 산식은 HWPX 출력 형식과 한컴 렌더 의미를 실측으로 정정했다. 실제 한컴이 만든 공문서 HWPX(「아차산메아리」 게재 요청의 건.hwpx 등)를 디코드해 확인한 결과:
<hh:margin>은 속성형이 아니라 자식요소형이다. 한컴은<hh:margin indent="…" left="…">(속성)를 무시하고, 다음 자식요소만 읽는다 (xmlns:hc="http://www.hancom.co.kr/hwpml/2011/core"선언 필수):<hh:margin> <hc:intent value="-2250" unit="HWPUNIT"/> <!-- 첫 줄 들여쓰기, 음수=내어쓰기 --> <hc:left value="1500" unit="HWPUNIT"/> <!-- 왼쪽 여백(단계 누적) --> <hc:right value="0" unit="HWPUNIT"/> <hc:prev value="0" unit="HWPUNIT"/> <!-- 문단 위 간격 --> <hc:next value="0" unit="HWPUNIT"/> <!-- 문단 아래 간격 --> </hh:margin>
- 내어쓰기 의미 정정:
<hc:intent>음수 = 첫 줄은left에서 시작하고 둘째 줄부터|intent|만큼 오른쪽으로 들여쓴다(내용 첫 글자 정렬). (이전 스펙의 "first line = left+indent" 모델은 오해였음.) - 올바른 산식 (
levelIndent):left = depth × 2타(누적),intent = -(부호폭 + 1타). 1타 = bodyHeight/2 HWPUNIT.- 예(15pt, bodyHeight=1500): depth0
left=0 intent=-2250, depth1left=1500 intent=-2250, depth2left=3000 …— 실파일의left누적 + 음수intent패턴과 동일.
- 예(15pt, bodyHeight=1500): depth0
- 용지 여백(
<hp:pagePr><hp:margin>)은 속성형이 맞다(실파일도 속성형). 실파일 실측 =left=5669 right=5669 top=5669 bottom=2835 header=0 footer=0= 위20/좌우20/아래10·머리말꼬리말0 → 본 스펙 공식값과 일치. - 본문 글꼴 크기: 실측 공문(광진구)은 height=1000(10pt). 보고서 관행(14~15pt)과 별개로 일반 공문 본문은 더 작은 경우가 많음 →
bodyPt옵션으로 조정 가능.
교훈: HWPX는 XML 유효성·라운드트립 통과만으로 렌더 정확성을 보장하지 못한다. 서식(여백·들여쓰기)은 반드시 한글/한컴으로 실제 렌더를 확인하거나, 실제 한컴 산출 파일과 구조를 대조할 것.
실제 정부 보고서 양식 hwpx(「2_보고서 양식」)를 디코드해 실측한 값으로 구현한 여섯 번째 프리셋.
별칭: 개조식·개조식보고서·정부보고서·정부표준개조식보고서. 구현: src/hwpx/gaejosik.ts(순수 로직·실측 상수) + gen-gaejosik.ts(표지·목차·장헤더 XML).
| 요소 | 폰트 | 크기 | 문단 위 | charPr id |
|---|---|---|---|---|
| □ 대항목 | HY헤드라인M | 16pt | 15pt | 11 (bold 12) |
| ○ 중항목 | 휴먼명조 | 15pt(본문) | 10pt | 0~3 |
| - 소항목 (하이픈) | 휴먼명조 | 15pt | 6pt | 0~3 |
| ※ 참고 | 한양중고딕 | 13pt | 3pt | 13 (bold 14) |
| 장 헤더 로마숫자 | 휴먼명조 bold 흰색 | 17pt | — | 15 |
| 장 헤더 제목 | HY헤드라인M | 17pt | — | 16 |
| 표지 제목 / 날짜·기관명 | HY헤드라인M | 30 / 25pt | — | 17 / 18 |
| 목차 라벨 / 로마 / 항목 | 헤드라인M bold / 한양신명조 bold / 헤드라인M | 28 / 21 / 18pt | — | 19 / 20 / 21 |
| 표 셀 | 맑은 고딕 | 12pt | — | 22 (bold 23) |
| 표지 바 셀 빈 문단 | (본문) | 6pt | — | 24 (paraPr 21, 줄간격 70%) |
색: 장헤더 음영·표지 진한 바 #193AAA, 셀 테두리 #006699, 표지 연한 바 #A0B4E6, 제목 셀 #F2F2F2+상하선 #A6A6A6, 목차 박스 0.4mm #514BAC. (borderFill 3~8, 표 헤더행 음영 #E6E6E6은 9)
여백: 실측값(상하 15mm·좌우 20mm) 기본 — GAEJOSIK_MARGINS, margins로 조정 가능. (v4.0.2 문서 정정: 종전 "공식값 기본" 서술은 코드와 불일치 — 코드는 v3.17부터 실측 15mm)
표지 수직 배치(실측): 빈 5 → 제목 표 → 빈 5 → 날짜 → 빈 4(25pt 행) → 기관명.
표지 장식 바 셀: 전용 6pt charPr·줄간격 70% — 기본(15pt·160%)이면 줄높이가 바 높이(818)를 넘어 한컴이 행을 3배로 확장한다 (실측 원본도 전용 소형 charPr 사용).
표지 제목 자동 축소: 30pt로 2줄 초과 시(simulateWrap keep 판정) 25pt(charPr 18) — 꼬리 한두 글자 3줄행 방지, 원본 관행(긴 제목 25pt)과 일치.
목차 항목: "Ⅷ." 실폭 내어쓰기 — 제목 줄바꿈 시 로마숫자 밑 감김 방지. 목차 박스 셀은 수직 CENTER(실측).
장 헤더 문단: keepWithNext — 쪽 하단 고아 헤더 방지.
볼드 정본: <hh:bold/> 자식 요소 방출(실측 한컴 파일은 속성 없이 요소만) + bold="1" 속성 병기 — keepFontOnBold 계열(단일 웨이트 폰트)의 macOS 한컴 non-bold 렌더 방지.
fonts: { body, heading, ref, table }— 역할별 글꼴명 오버라이드. gaejosik fontfaces의 id 3(heading)/4(body)/5(ref)/7(table)을 치환. 개조식 외 프리셋은 body만(bodyFont보다 우선). CLI--fonts "body=나눔명조,heading=나눔고딕", MCP generate_documentfonts.sizes: { dae, cham, chapter, coverTitle, coverSub, tocLabel, tocRoman, tocItem, table }— 요소별 pt 절대값 오버라이드(미지정은 bodyPt 비례). 들여쓰기·표 측정·표지 축소 판정에도 일관 반영. CLI--sizes "dae=16,table=12", MCPsizes.chapterFit— 장 헤더 제목 칸을 글자 실폭(fonts.heading글꼴 폭표·sizes.chapter반영, 앞 공백만큼 뒤 여백 + 셀 여백·조판 여유 582)에 맞춘다. 기본 꺼짐(제목 칸이 본문 폭까지). 본문 폭을 넘는 제목은 종전 폭에서 멈추고, 좌우 바깥 여백은 본문 폭 표 기준을 따라 왼쪽 끝이 그대로다. CLI--chapter-fit, MCPchapter_fit.
실측(정부 양식 표) 기반 스타일. 개조식 외 공문서 프리셋에도 적용(셀 폰트만 개조식 전용).
- 열폭 내용 비례: 열별 최대 내용 실폭(text-metrics) 비례 배분 — 균등 1/n 아님. 최소 6%, 한 열 80% 캡. 표 전체 폭 = 본문 폭. 비례 몫이 최소폭 미달인 열은 minW 확정 후 잔여 폭 재배분(수렴 반복) — 열 많은 표에서도 음수·미달 폭 불가.
- 헤더행:
#E6E6E6음영(borderFill — 개조식 9, 그 외 3) + 가운데 정렬 + 쪽 분할 시 반복(repeatHeader). theme의 tableHeader 옵션은 공문서 표에 적용하지 않음(style 우선). - 정렬: 본문 셀이 전부 한 줄에 들어가는 열은 가운데, 긴 내용 열은 양쪽 정렬. 수직은 CENTER.
- 행 높이: 셀 줄바꿈 수 시뮬레이션으로 추정(다른 뷰어에서 안 잘리게).
- GFM 셀
<br>: kordoc 파서가 셀 내 개행을<br>로 방출하는 규약 — 생성 시 문단 분리로 복원(리터럴 노출 금지), 폭·행높이 측정과 정합. - GFM 셀 표시문자 측정: 링크는 표시문자만, 강조·취소선·첨자·밑줄은 인라인 파서가 방출하는 글자로 열폭·최장 어절·행높이·12→11→10pt 축소를 판단한다. 이스케이프한 문법 문자와 코드 안의 문자는 실제 표시 폭에 남긴다.
<br>별 표시문자와 실폭은 표 안에서 재사용해 줄높이를 다시 재지 않는다. - 비공문서 모드는 열폭 비례·
<br>문단 분리만 적용, 스타일(음영·정렬·반복)은 기존 유지.
- h1(첫 번째) → 표지(파랑 장식 바 + 제목 + 날짜 + 기관명).
cover: false로 끄거나{date, org}지정. 표지 소비 후 나머지 h1은 장 헤더로. - h2 → 로마숫자(Ⅰ Ⅱ… U+2160 정본) 장 헤더 표(1×3, 실측 기하). 선행 번호(
1.·Ⅱ.)는 자동 제거(이중 번호 방지). h2 목록으로 목차 자동 생성(toc: false로 끔). - h3 → □ 대항목. h3가 존재하는 문서는 리스트가 ○부터 시작(적응 시프트), 없으면 depth0→□.
- h4~h6 → ○ 중항목.
- 리스트 depth → □ ○ - ㆍ (시프트 반영).
※로 시작하는 문단/항목·blockquote → ※ 참고 스타일. - (v4.0.1) 소항목 부호는 하이픈
-— GT3 양식 저장값은 ―(U+2015)지만 실무자 QA 교정(2026-07-11)- 부처별 실측 양식 3종 중 2종(업무보고·보고서3)이 하이픈. 양식 1개의 저장값 < 실무 관행.
- (v4.0.1) 실측 폰트 세트를 보고서·계획서 프리셋으로 확장(
usesReportFonts): 본문 휴먼명조· 제목/□ HY헤드라인M(bold 치환 없음)·※ 한양중고딕·표 셀 맑은 고딕 12pt·제목박스 HY헤드라인M 22pt. charPr id 공간(11~25)·장평 variant 기점(26)은 개조식과 동일 배치. 기안문·통지·회의록은 함초롬 유지. - (v4.0.1) h2 말머리
h2Marker(비개조식): 보고서·계획서 기본box(□ + 문단 위 2×body + 부호폭 내어쓰기 — 실측 □ 대항목과 동일),number(1. 2. 재부여 — 공고문 관행),none. 선행 번호 제거 후 부여. - 쪽나눔: 표지→목차→본문 각각 새 페이지(
pageBreak="1").
- ○/―(본문 charPr 0~3)만 자동 장평(fit) 대상 — □(16pt)·※(13pt)·표(12pt)는 제외, 변형 charPr 시작 id는 24(
charVariantBase). - 목차에 쪽번호는 넣지 않는다(레이아웃 엔진 없이는 산출 불가 — 한컴에서 열어 채움).
- 장헤더·표지가 표로 렌더되므로 재파싱(parseHwpx) 시 표로 돌아옴(라운드트립 열화 허용).
한컴 실구현에서 이 속성은 이름과 반대로 동작한다. 어절 단위를 원하면 BREAK_WORD를 써야 한다.
| 속성 | KEEP_WORD |
BREAK_WORD |
|---|---|---|
breakLatinWord (영어) |
단어 유지 — 이름대로 | 글자 분리 |
breakNonLatinWord (한글) |
글자 분리 | 어절 유지 |
- 근거: 한글 COM(SaveAs PDF) 실렌더 A/B 매트릭스 — 동일 문서에서 속성 하나씩 토글.
KEEP_WORD는 정렬(JUSTIFY/LEFT) 무관 "실증되었/고," 식 어절 중간 분리,BREAK_WORD는 전 줄바꿈 어절 경계 + 영어 단어 통째 유지.snapToGrid·condense는 줄나눔 방식과 무관. - 정본 양식(2_보고서)의 본문이
KEEP_WORD/KEEP_WORD인 것은 한글 기본값(한글단위 '글자'/영어단위 '단어') 그대로 저장된 것. - 산출 정책: 범용·개조식(gaejosik)·보도자료 경로
breakNonLatinWord="BREAK_WORD"(어절)·breakLatinWord="KEEP_WORD"(단어). 줄폭보다 긴 단일 토큰(긴 URL·무공백·연쇄)만 강제 분해(한컴 동일). v5 엔진(기안문·보고서·계획서·통지·회의록·업무보고) 본문·요약박스도BREAK_WORD(어절)+JUSTIFY+외톨이줄 보호(2026-09-23, (k)장). 라운드 2(글자 단위)는 "동대/문"·"실/국"처럼 낱말을 쪼개 폐기. 라틴·숫자는 여전히 단어 유지.
정답지: 샘플양식1/2, 2_보고서 양식(SSOT), 추진계획 AI·API 2종, 국외연수 신청서,
바이오헬스 공고문 + 내부 실무문서 5종(성과관리계획서·만족도추진계획·발행계획안·공적요지·계약검토서).
전수 디코드는 scripts/style-digest.mjs. 괴리 목록: 골격 G01G20 / 표 TBL-0116 / 방법론 M1~M9.
<hp:pageNum pos="BOTTOM_CENTER" formatType="DIGIT" sideChar="-"/>— secPr과 같은 run- 표지·목차 페이지 첫 문단에
<hp:pageHiding … hidePageNum="1"/>(표지는 hideHeader="1"도) - 본문 첫 블록 run에
<hp:newNum num="1" numType="PAGE"/>— 표지·목차 카운트 제외 - secPr
startNum page="0"(이어서) 유지. 개조식 여백: 상하 15mm + header/footer 4251(15mm)
1×7 표, 열폭 [565,565,1414,13191,1414,565,565], h 3931@28pt(tocLabel 비례 스케일). 셀 채움 [네이비 #193AAA | 무 | 라벤더 #E0E5FA | 라벨 | 라벤더 | 무 | 네이비], 표 외곽 0.12mm. 라벨 GJ_CHAR_TOC_LABEL(28pt bold). ⚠ 배너·목차박스 호스트 문단은 저줄간격(GJ_PARA_BAR 70%) — 160% 호스트는 표 줄높이에 곱해져 배너와 박스가 페이지 분리된다 (실렌더 확인).
표지 표①과 동일 3×3 투톤 그리드, 행높이 600/3566/600(bodyTitle 22pt 비례), 제목 charPr 25 (HY헤드라인M 22pt). 목차 뒤 pageBreak 선두 배치 — 이 경우 본문 첫 블록의 pageBreak는 생략.
- 테두리 위계: 외곽 0.4mm / 내부 0.12mm / 헤더행 하변 DOUBLE_SLIM 0.5mm.
셀 위치(첫·끝 행/열, 병합 스팬 끝 기준)별 borderFill을 동적 발급(
gen-table-bf.ts, id 11+/4+) - 헤더행: #E6E6E6 채움 + bold + CENTER 130%(paraPr 18)
- 라벨열(2열 표, 1열 전행 ≤12자·한줄): #E7E7E7 + bold + CENTER
- 장문 열: LEFT 130%(paraPr 19) — JUSTIFY 금지
- 폭: 본문폭 −1800 축폭, 호스트 문단 RIGHT(paraPr 17). 짧은 열은 실폭+12% 고정 (측정은 함초롬 advance 기준이라 맑은 고딕 bold 실폭 여유 필요 — "4,673" 협착 실렌더 확인)
- 결재란: 직위 라벨행(h1100) + 서명 공란행(h4200), 칸폭 7085(25mm), 외곽 0.4mm, 호스트 RIGHT
- "끝.": 마지막 텍스트 블록이 /끝\s*.?$/가 아니면
끝.단독 문단 추가 (기안문 기본) - 제목박스: #0080C0 바(h382) + 제목(h2850) + gradient 바 — gradient는
<hc:gradation type="RADIAL" … #0080C0 → #3CBFFF>(GT6 원문)
한글은 OUTLINE 문단에 개요 번호("1.", "1.1.")를 강제 렌더 — outlineShapeIDRef=0,
paraHead numFormat=NONE 모두 무효 (COM 실렌더 A/B 실측). 공문서 모드는
명명 스타일 개요 1~4(style id 1~4, 헤딩 paraPr·charPr 참조)를 헤딩 문단 styleIDRef로 걸고,
파서(para-heading.ts)가 스타일명 /^개요 [1-6]$/로 헤딩을 복원한다 (왕복 보존).
코퍼스: 부처별 양식 3종(t1 업무보고·t2 SSOT·t3) + Downloads 실물 8종(바이오헬스 공고문·
추진계획·춘천AI·브라더·국외연수 등) + 서울 정보소통광장 실결재 기안문 60건.
괴리 전수표: .claude/plans/gap-table-v4.1.md (GAP-01~17, 처분 포함).
<hp:ctrl><hp:colPr id="" type="NEWSPAPER" layout="LEFT" colCount="1" sameSz="1" sameGap="0"/></hp:ctrl>
를 secPr 뒤 같은 run에 방출해야 한다. 없으면 한글이 컬럼 영역을 좌우 10mm(2835HU)씩
좁게 잡는다 — 본문은 우측 여백에 10mm 미달, 컬럼보다 넓은 treatAsChar 표(제목박스·데이터표·
목차박스)는 우측 여백 침범. COM 실렌더 → PDF 벡터 좌표 실측으로 확정(주입 실험 A/B).
표지·본문 제목박스(폭 48180)는 outMargin 좌우 0 — 283이면 진행폭(w+566)이 컬럼폭을 넘어
1mm 침범 (실물 t2도 48180 표 2개만 outMargin 0).
- 여백 지배값 t20/b15/l20/r15/머리꼬리 0 (41/60) → official 기본값 채택 (편람 공식
20/10/20/20은
margins로 지정) - 2단계 부호 ㅇ(이응) 134 : ○(원) 5 →
bullet2옵션, 통지·보도자료 기본 ㅇ - 본문 최빈 12pt(31/60, 굴림체·함초롬바탕) — 시스템 기본값 방치 가능성으로 15pt 유지(실무자 결정)
- 본문 2계열: 법정8단계형(1. 가. — 12pt 고딕) 15건 / 개조식형(□ HY견고딕17 + ㅇ 한컴돋움15 bold + - 휴먼명조14) 16건 — 개조식형 스타일은 GAP-14 보류
- 참고 표기
*가 ※보다 다수 → 실측 프리셋에서*마커 항목을 ※ 참고 스타일로 (GAP-15)
- 기안문(별지 제1호서식, hwpx-skill gonmun.py 실측 이식): 기관명 18pt bold CENTER / 수신·(경유)·제목 라벨 bold / 발신명의 22pt bold CENTER / 결문 9pt + ─×46 구분선 (기안자·검토자·결재권자 / 협조자 / 시행·접수 / 주소·홈페이지 / 전화·전송·이메일·공개구분)
- 업무보고 보고정보 행: 최상단 우측 12pt (실측 t3 휴먼명조 12 RIGHT / t1 굴림14 축소는 갈림)
- 공고문(바이오헬스 실측): 공고번호 본문크기 bold 좌 → 제목박스 → 본문(h2 아라비아 "1. 사업개요" 기본) → 날짜 RIGHT → 발신명의 bold RIGHT
- docframe charPr 9종은 variant·프로필 뒤 동적 id — 기능 미사용 시 미방출(기존 산출물 불변)
여백 15/15/20/20·머리꼬리 10mm, 본문 바탕(기본 폰트) 14pt 160%. 머리박스("보도자료" 20pt
bold + 보도시점/배포 10pt bold, 외곽 0.4mm) → 제목 25pt bold CENTER + 부제 - … - 15pt
bold → 본문 □→ㅇ→*(각주 12pt) → 담당 부서/담당자/연락처 표. 로고·부제 파랑은 미구현(단순화).
report 불릿 리스트도 개조식과 동일 실측 간격 □3000/○2000/-1200/ㆍ600 (t2 paraPr 저장값, body 1500 기준 비례 스케일) + □ keepWithNext.
기안문(official)·보고서(report)·계획서(plan)·통지(notice)·회의록(minutes)은 gen-gongmun.ts(v5)가 생성한다.
개조식(gaejosik, 중앙부처 표지·목차 양식)·보도자료(press)·범용 마크다운은 종전 gen-section.ts.
MdBlock[] ─outline.ts─▶ OutlineNode[](title/chapter/item(depth)/ref/sub/para/attach/summary/block)
─gongmun-scheme.ts─▶ 단계별 부호·글꼴·pt·bold·선행 타·줄간격 (서울 실측, reference 2.8)
─gen-gongmun.ts─▶ 문단 XML (StyleRegistry가 charPr/paraPr/글꼴 동적 발급, fit-line이 □·제목 한 줄 강제)
─gen-frame-seoul.ts─▶ 두문표·결문표·제목표·요약박스·결재선·표지
- 첫 h1 → 제목. h2 → 장(보고서
Ⅰ./통지1.; 기안문은 법정 1단계1.항목이 되고 아래 리스트는가.부터). - h3~h6 → 항목 depth level-3 (h3=□/1., h4=ㅇ/가.). 그 아래 리스트는 헤딩 depth+1부터.
- 문단·항목 선두의 명시 부호가 depth를 강제: □0 ㅇ○1 -2 ㆍ3 / 1.→0 가.→1 1)→2 …
개조식 문서 안의 법정 부호(
가. 기술인력)는 소제목(한컴돋움 13, 2타)로 보존. - ※·
*선두 → 참고(직전 항목 depth+1 들여쓰기). 붙임 → 붙임 블록(앞 한 줄, 선행 공백 보존). - 보고서: 제목 직후 인용문(
>) → 요약박스. 본문에 □/ㅇ 명시 부호가 있는 기안문은 개조식형 본문으로 자동 전환. - 리스트 사이 서술 문단은 법정 번호를 재시작(마크다운 의미), 헤딩에서 온 항목 아래 문단은 잇는다.
□·제목·장 제목: 장평 100→85(각 자간 0/-3/-5) → pt 1씩 축소(□ 하한 14, 제목 20) → 그래도 넘치면 마지막 조합 + warning
(MarkdownToHwpxOptions.warnings 싱크 → CLI stderr·MCP 응답). 폭 측정은 실글꼴 폭표(font-metrics.ts, (k)장), 표에 없는 글꼴만 근사 클래스.
표 셀은 12→11→10pt 자동 축소(requiredTableWidth) — 실측 셀 pt 분포와 일치.
docHead{org,slogan,to,via,title}→ 두문표 /docFoot{sender,drafter,reviewer,approver|approvers[],cooperator,recipients,docNum,receive,zip,address,site,phone,fax,email,disclosure}→ 결문표(수신 '내부결재'면 발신명의 생략)reportInfo→ 보고서 제목표 담당자 행(제목 없으면 우상단 12pt) / 기안문 우상단 12ptsummary·인용문 → 요약박스 ·cover{date,org,dept}+docInfo+approval→ 서울형 표지 ·approval단독 → 우상단 결재선표h2Markerband(보고서·계획서 기본)/roman/number/box/none ·bandColor/bandTextColor(띠 번호칸 #003366/#FFFFFF 기본, 교육청형 #DFE6F7/#000000) ·bullet2ㅇ(기본)/○ ·levels·fonts·bodyPt·lineSpacing→ 스킴 오버레이- 기안문 본문 기본 굴림체 12 160%(
bodyFontmyeongjo/gothic 지정 시 함초롬바탕/맑은 고딕), 보고서 15/180%, 여백 13/13/18/18 h13 f13.
출처:·자료:·근거:·참고:로 시작하는 항목·문단은 ※ 참고(한컴돋움 13pt)로 — 본문 ㅇ 항목과 확실히 구분(당구장표시).고아 줄 자간 축소(→ (k)장fitOrphanLine)fitParagraph(어절 조판 재현 + 비용 함수)로 대체. 사다리(자간 -1…-12 → 장평 97~88)는 그대로, 장평은autoFit.minRatio(기본 90) 아래로 내리지 않는다.줄바꿈은 어절 단위(BREAK_WORD)→ 라운드 2에서 글자 단위(KEEP_WORD)+양쪽정렬로 전환(아래).
-줄 어절 간격 벌어짐: 라운드 1의 어절유지+양쪽정렬은 실결재 개조식-문단의 1.2%뿐(reference 2.8 정렬·줄바꿈). 긴 어절 ("과학기술정보통신부장관에게")이 통째로 다음 줄로 밀리며 앞 줄이 늘어났다. 유저 결정으로 실측 76%인 JUSTIFY+KEEP_WORD(글자 단위) 로 전환 —gen-gongmun.ts항목·※·서술·장·붙임 문단 전부keepWord:false,fitOrphanLine·요약박스 줄 수 시뮬레이션도charAll. (2026-09-23 어절로 재전환: 벌어짐은 자간 조정으로 완화, (k)장) 라틴·숫자 토큰은breakLatinWord=KEEP_WORD그대로 단어 유지. 구 경로(범용·개조식·보도자료)는 어절 유지 불변.- 요약박스 글자가 테두리에 붙음: 실측 133건의 55%가 문단 좌우 여백 1000/1000(셀 여백은 141) —
buildSummaryBox문단left/right 1000(ParaSpec.right·paraPr right신설), 종전 선두 공백 2칸은 제거(실측 선두 공백 0 이 53%). 가용폭에서 2000 차감. - 표 열폭이 긴 글자 수 순: "단계|내용|근거"에서 근거가 가장 길어 최광열이 되고 내용이 두 줄로 꺾였다. 실측 462표: 내용류 열
중앙값 51%, 비고 21%(p75 26%), 마지막 열 26%.
gen-table.ts colRoles(headers)— 비고·비고사항·참고(사항)·출처·(관련/법적/추진)근거· 근거법령·담당(자/부서)·연락처 = remark(25% 상한, 단 최장 어절+패딩까지는 허용해 글자 세로 분해 금지),…내용/사항/실적/계획/방안/사유/ 개요/설명/임무/역할/현황/성과(12자 이하) = content(비례 가중 ×2, 본문 셀 LEFT — 한 줄에 들어가도 가운데 정렬하지 않음), 내용 열이 있는 3열+ 표의 역할 없는 마지막 열도 remark. 공문서 모드에서만 적용(범용 경로 바이트 불변). 역할 미지정 호출은 종전과 동일. - 법령 인용 뒤 법제처 MST·ID 코드
인공지능기본법(282791)→인공지능기본법, KOSISDT_1YL21161,(법정동코드 11215-10700),…, 통계 MCP 조회도구 언급 제거 (stripLawCodes— 출처는 기관·자료명만). - 요약박스는 여러 줄(제목 직후 인용문
>줄마다 문단) — 보고서는 요약 필수 — 부호 없이 한 문장(쉼표 허용) 3줄 이내 "…하고자 함"(보고 목적), 없거나 3줄 초과·두 문장 이상이면 warning(summaryWarnings— 문장 수는 줄을 이은 글에서 한글·닫는 괄호 뒤.?!다음에 글이 이어지는 경계 + 1, 날짜9. 23.은 숫자 뒤라 제외). 선두 부호는 벗기고 문장 꼬리 고아 줄은 자간 축소. 생성기는 요약을 쓰지 않는다(에이전트가 작성). - 개조식(gen-section)도 같은 요약 상자(2026-10-09): 표지 제목(h1) 바로 다음 블록이 인용문이면(또는
summary옵션) 본문 첫 쪽 제목 상자 아래·첫 장(Ⅰ) 앞에 1×1 상자 — #DFE6F7 음영·0.4mm 검정·한컴돋움 굵게 본문 크기(기본 15pt)·양쪽 160%, 좌우 여백 1000 은 개조식 정적 paraPr 를 늘리지 않게 칸 여백 (hasMargin="1"141+1000 — 한컴 저장본도 쓰는 꼴). 실측: 서울 실결재 553건 제목 아래 요약 상자 53개 전부 1×1, 3줄 이하 98%·2줄 75%·한 문단 84%, #DFE6F7 67%, 한컴돋움 15 굵게 72%. 요약 charPr·한컴돋움 글꼴은 요약이 있을 때만 levels 뒤 id 에 방출(그 밖의 산출물 바이트 불변). 표지가 없으면 첫 h1 이 장 헤더라 인용문은 종전대로 ※ 참고(summary옵션은 본문 맨 앞 — 목차만 있으면 목차 다음 쪽 첫머리 — 상자),summary옵션이 있으면 제목 뒤 인용문은 ※ 참고, 제목 뒤> ※ …도 요약 상자가 된다(v5 보고서와 같음). 문장 수는 인용문 줄을 이어 센다(한 문장을 두 줄로 나눠 쓴 요약은 한 문장, 상자 안 줄 경계는 보존). 목록 부호가.·나.는 문장 끝이 아니다.
재정경제부 「2차 업무보고 서면보고자료」(2026-07-15, A4 17쪽) PDF 를 PyMuPDF 로 글꼴·크기·색·도형(채움·선·좌표) 전수 덤프해
값을 확정했다. 서울 실결재 스킴과 달리 부호 단계의 글꼴·크기가 전부 같고
색으로 위계를 낸다 — 별개 스킴(ministryScheme)·별개 골격(gen-frame-ministry.ts).
| 요소 | 실측 | 마크다운 |
|---|---|---|
| 본문 □·ㅇ·- | 함초롬바탕 15 regular, 줄피치 21.7pt(≈145%), 문단 뒤 6~7pt, ㅇ 1타·- 3타 | □/ㅇ/- 명시 부호 또는 리스트(부호 없는 - 는 직전 ㅇ 아래) |
| (키워드) | □·❶ 뒤 함초롬바탕 Bold 15 #0000FF, ㅇ 뒤 Bold 검정 | 선두 (…)·[…] 24자 이내 |
| * 각주 | 맑은 고딕 12, 선두 3타, 130% | * … |
| 표 | 맑은 고딕 12 헤더 bold #DFE6F7, 본문 11.5, 선 0.36pt | GFM 표 |
| 표지 | 대외주의 빨강 박스(0.36pt, 74.7×22.4pt) 우상단 / 파란 바 #0C3DCA·#0A33A9 5.9pt 두 줄 / HY헤드라인M 32 / 날짜 24 | # 제목 + --cover-label 대외주의 --date |
| 목차 | "목 차" HY헤드라인M 24 #000080 / Ⅰ. 17 / 1. 15 (원본 박스는 그림 → 회색 0.7mm 테두리 표, 쪽 82% 높이) | 자동(h2 + h3) |
| Ⅰ. 장 | 띠 본문폭×26.5pt, 세로 그라데이션 #D6EAFE→흰, 상하 DOUBLE_SLIM #0000FF, HY헤드라인M 16, 장마다 새 쪽 | ## 장 |
| 절 | [숫자칸 29.7×23.4pt #3057B9 0.4mm 검정 테두리 흰 글자][제목 하변 0.5mm, 폭=글폭] HY헤드라인M 15 | ### 절 (장마다 1부터) |
| 소제목 | 채움 #203A7B 24.1pt·폭=글폭, HY헤드라인M 15 흰 "1. 민생경제 안정화" | #### 소제목 (절마다 1부터) |
| 항목 띠 | 전폭 23.5pt #E8F7FC 상하 0.4mm #00ACFF, ① + HY중고딕 15(원본 HaanYGodic24), 키워드·강조 파랑. 한 줄 요소라 넘치면 장평·자간으로 한 줄에 맞춘다(fitOneLine, 크기 유지) |
##### 항목 (소제목마다 ①부터) |
| 요약박스 | #FFF7CC 0.12mm 검정, ▪ 함초롬바탕 13(키워드 파랑 bold) / *·※ 줄 맑은 고딕 11 |
> ▪ … 인용문 — 위치 무관 전부 박스 |
| 별첨 | [별 첨 61.3×26.3pt #0066FF 흰 HY헤드라인M 16][5.9pt][제목 HY헤드라인M 16, 상·좌 0.12 / 하·우 0.4mm], 새 쪽 | ## 별첨 제목 |
| ❶ |
함초롬바탕 15, 글리프 보존(⇒·❶ 0단계, ↳ 1단계), [키워드] 파랑 bold |
선두에 그대로 |
| 쪽 | 여백 위·아래 10 + 머리말·꼬리말 10mm(본문 시작 20mm), 좌우 20 / "- 1 -" 하단 중앙, 표지·목차 숨김 | 기본 켜짐 |
구현 결정
- gradation 은 2색만:
colorNum="3"(#D6EAFE·흰·#D6EAFE) 은 한글 2024 COM 실렌더에서 셀이 검게 칠해진다(A/B 4종 실측).borderFillEntry가 색을 2개로 자르고type="LINEAR" angle="90" step="50"으로 방출. TableBfRegistry변 스펙에BorderSide직접 지정 허용(파랑 이중선·하늘색 0.4mm·빨강 0.12mm) — 이름 있는 위계(thin/thick/double/mid)와 공존.- 아웃라인 옵션
headingFrames(h3~h6 → heading 노드, 리스트 깊이 불간섭)·quoteBox(인용 어디서나 summary)·keepMarkers(❶⇒↳ 보존). 다른 프리셋은 옵션을 켜지 않아 바이트 불변. - 문체 검수: 줄마다 부호로 시작하는 인용문(성과 요약 박스)은 리드문 규칙(LEAD_ENDING·LEAD_LONG) 밖.
- 범위 밖: 원본 pg7 의 비전 박스(#FFF1E8, 상하 #FFB689, 가운데 파랑 HY헤드라인M 14·빨강 수치) — 1회성 장식이라 미구현(인용문 요약박스로 대체).
목차 쪽번호는 조판 전 산출 불가라 생략. 밑줄 강조(
<u>)는 기존 정책대로 평문화.
계기: 한글 2024(윈도)로 연 v5 보고서 PDF(「수도권 지자체 2026년 AI 계획 비교」 8쪽)에서 네 가지 결함. ① 항목 첫 줄 내용과 둘째 줄의 왼쪽이 안 맞음 ② 글자 단위 줄바꿈이 낱말을 쪼갬("동대/문", "실/국", "안/전") ③ 날짜가 줄 끝에서 갈라짐("2026. 1. / 22.") ④ 곧은따옴표가 휴먼명조에서 여닫음 없이 ’ 로 그려짐.
- 원인: 부호 뒤 일반 공백을 양쪽 정렬이 늘린다. 실결재 720건도 부호 뒤는 공백이 99%(ㅇ 1,571·- 1,292·□ 597문단)라 같은 어긋남이 있다. 압축(장평·자간)도 부호 폭을 줄여 첫 줄 내용이 왼쪽으로 당겨졌고, 내어쓰기는 함초롬 폭표로 재 ※ 는 3pt 어긋났다(한컴돋움 ※ 실폭 1.0em, 표 0.77em).
- 방식: 부호를 따로 된 run(부호 +
<hp:tab/>)으로 내고 문단 paraPr 는tabPrIDRef="1"(<hh:tabPr id="1" autoTabLeft="1"/>, 한글 기본 서식과 같은 정의). 한컴의 "내어쓰기용 자동 탭"은 탭 정지점을 내어쓰기 위치에 세운다. 근거: 법제처 국제출원서(licbyl 18194893) "(a)⇥" 문단 Arial Bold "(a)" 1,344 + 탭 1,132 = 2,476 ≈ intent 2,480(명시 탭 2,835·기본 간격 4,000 이 아닌 자동 정지점). 첫 줄 내용 시작 = 둘째 줄 시작이 폭 추정·양쪽 정렬·압축과 무관하게 구조적으로 같다. - 내어쓰기 = 부호 실폭 + 1타(0.5em,
gen-marker.ts markerLayout). 압축은 내용 run 에만 걸고 부호 run 은 형제 항목과 같은 모양. - 범위: v5 항목·※ 참고·소제목, 업무보고 요약박스 ▪, 개조식·보도자료(gen-section) 목록·□ 대항목·ㅇ 중항목·※·h2 부호. 부호 생략 항목은 탭 없음.
h2 두 자리 번호(
10.)는 내어쓰기(1.폭 기준)보다 넓어 탭이 기본 탭 칸(40pt)으로 튀므로 공백으로 잇는다. - 파싱: 부호 뒤 탭은 공백으로 읽힌다(
cleanParaText). 강조 span 추출도 탭·빈칸 컨트롤을 공백으로 받아 왕복 굵게 복원이 유지된다.
- v5 본문·요약박스·표 셀 모두
breakNonLatinWord="BREAK_WORD"(어절) + JUSTIFY +widowOrphan="1"(외톨이줄 보호: 쪽 머리에 "8. 28. 시행)" 한 줄만 넘어가던 것). - 라운드 2 가 걱정한 "긴 어절이 넘어가 앞 줄이 벌어짐"은
fit-line.ts fitParagraph가 맡는다. 무압축과 사다리(자간 -1…-12 → 장평 97~88)를 어절 조판으로 재현해 비용 = 벌어짐(공백이 두 배 넘게 늘어나는 줄의 초과분) + 고아 줄(마지막 줄 ≤ 22%, 1.5) + 압축량 × 10 이 가장 낮은 조합. 장평은autoFit.minRatio(기본 90) 아래로 내리지 않고,autoFit: false면 본문·항목·※ 참고 모두 압축하지 않는다. - 한 줄에 들어간다는 판단(fit 전부)은 가용폭 98%(여유 2%). 한컴 저장본 코퍼스 대조에서 실폭표 모델이 틀린 문단은 대부분 폭
±0.2
3% 보정으로 맞았고(한컴이 더 넓게 잡는 쪽 최대 +3%), 여유 0.60.7% 로 한 줄에 맞춘 압축 문단 2건이 한컴에서 넘쳤다. 자간 해석은 "글자폭 × %, 공백 포함"이 압축 문단 1,136개 중 845개로 가장 잘 맞는다(글자 크기 기준 654·공백 제외 723). - 짧은 꼬리 줄 올리기: 마지막 줄이 가용폭 절반 이하이고 압축 15% 이내로 줄 수가 하나 줄면 가장 적은 압축으로 줄인다. 줄인 결과에 벌어진 줄(공백 두 배 초과)이 생기면 안 한다(묶음 빈칸으로 묶은 긴 날짜가 밀려 앞 줄이 벌어지는 경우).
- 한 줄보다 긴 어절: 한컴은 어절 단위에서 그 어절을 다음 줄로 넘긴 뒤 쪼갠다(코퍼스 어절 단위 문단 400개: 넘긴 뒤 347·제자리
340 일치, 갈리는 13건은 넘긴 뒤가 맞음). 그런 문단은 글자 단위(KEEP_WORD)로 조판하되 모든 줄 끝이 공백이나 목록 구분자
(· , 、 /) 뒤에 오고, 폭 ±1% 에서도 같은 자리에서 끊기며, 벌어진 줄이 없는 가장 적은 압축(15% 이내)을 고른다(
fitCharBreaks). ±1% 인 까닭은 글자 단위에선 한 글자(줄폭의 약 3%)만 어긋나도 끊는 자리가 바뀌어 ±2% 면 후보가 거의 없어서다. 없으면 어절 단위. 고아 줄 하나 = 압축 15%, 공백 세 배로 벌어진 줄 하나 = 압축 10% 에 해당. 줄 수는 늘리지 않는다. - 참조 문서 재생성 결과(예측 조판): 고아 줄(≤20%) 5 → 2, 압축 문단 대부분 자간 -1~-4, 두 배 넘게 벌어진 줄 2(날짜가 붙은 긴 어절 "지정(2026. 8. 28." 이 넘어간 자리).
- 한컴오피스 번들 TTF(한컴돋움·HY견고딕·휴먼명조·HY헤드라인M·굴림체·굴림·맑은 고딕·함초롬돋움)의 hmtx 에서 ASCII 95자 + 전각과 다른 기호만 추출. 한글 음절·자모·원문자·도형은 글꼴 안에서 폭이 균일(전수 확인)해 cjk 한 값. 표에 없는 글리프는 한컴 대체 글꼴이라 cjk 폭.
- 검증: 이 표 + 공백 0.5em(useFontSpace=0) + ASCII 연속열 한 단어(
1.):가 한 덩어리) + 금칙으로 참조 PDF 본문 154줄의 줄바꿈 위치를 전부 재현. 실결재 linesegarray 대조에서 bold 는 폭이 같다(한컴돋움/b·휴먼명조/b 문단 100%). 종전 근사(·1.0em 과대 → 실폭 0.33em)는 고아 줄 압축을 과하게 했다. - 쓰는 곳: 생성 fit(
faceClassForGen→font:이름), 표 열폭(짧은 열 여유 12% → 3%), 요약박스 줄 수, 렌더 reflow·그리기(faceClassOf). - 확인 도구:
node bench/predict-layout.mjs 문서.hwpx --loose: 같은 모델로 생성 문서의 줄바꿈·벌어진 줄·고아 줄·압축을 한컴 없이 예측. - 렌더 reflow 는 글자마다 제 charPr 폭으로 재고 탭은 정지점 폭을 준다:
bench/verify-reflow.mjs평균 일치 97.76% → 99.07%(완전 일치 20 → 39문서). 탭 정지점은 왼쪽 여백 기준(첫 줄은 들여쓰기만큼 들어가서 잰다), 자동 탭 밖의 탭은 저장된hp:tab width(한컴 조판값)를 쓴다.hp:nbSpace는 공백으로 그리되 줄바꿈에선 U+00A0 이라 어절·글자 단위 모두 끊지 않는다.
- 날짜(2026. 9. 23. · 2026. 9. · 9. 23. · ’26. 9. 9.)·시각 범위(14:00 ~ 16:00)·금액의 "원" 앞(3억 원) 공백 → U+00A0 →
<hp:nbSpace/>(묶음 빈칸). 실결재도 날짜 안에 고정폭 빈칸을 넣는 관행(fwSpace 1,280곳)이 있고, 법제처 서식은 "1.hp:nbSpace/허가신청" 꼴을 쓴다. - 곧은따옴표 ' " → ‘ ’ “ ”(한글 자동 고침과 같음), 연도 약식 '26 → ’26. 인라인 코드·링크 URL 은 제외.
그 구간 바로 뒤 따옴표는 앞 구간 끝 글자로 판정(
'[링크](url)'의 닫는 따옴표), 태그>뒤는 여는 따옴표. - 적용: v5 아웃라인 노드·GFM 표 셀·제목·담당자 행·요약, 개조식·보도자료 블록(표지·목차·장 제목 포함). HTML 표 원문은 그대로.
XML 방출은 모두
escapeTextXml(U+00A0 →<hp:nbSpace/>), 문자 U+00A0 를 남기지 않는다. - 파서는
nbSpace를 공백으로 읽는다(종전 누락: "2026.9." 가 "2026.9." 로 붙었다).
condense(최소 공백): 격자 끈 문단에서 공백 수축으로 줄바꿈이 바뀌는 것은 확인(맑은 고딕 cond15 4/40 → 모델 반영 28/40)했지만 실결재 사용이 9문단뿐이라 쓰지 않는다. 벌어짐은 실무 관행인 자간 조정으로 푼다.
정보소통광장 시장·부시장급 결재 계획서 16건 중 편집형 5건을 정답지로 골라(bench/corpus-gen/seoul-bangchim/, git 밖) 정본
「청년취업사관학교 2.0」 추진계획(서울특별시장 제81호)을 전수 디코드했다. 5건 공통 하우스 스타일은 간이기안 표지(문서정보·결재선) →
사전 검토항목 점검표 → (목차) → 제목표·요약박스 → [Ⅰ] 장 상자이고, 본문 위계 글꼴·크기·굵기는 5건 모두 95~100% 같다.
| 요소 | 실측 | 마크다운 |
|---|---|---|
| 제목표 2×1 w48758 | 제목 HY헤드라인M 26 굵게 가운데 100%(상 0.4·하 0.15mm), 부제 HY헤드라인M 18 굵게 #0000FF, 담당 휴먼명조 12 균등배분 왼쪽 300 160%(상 0.15·하 0.4mm) | # 제목, 바로 뒤 - 부제 -, ☎ 가 든 줄 |
| 요약박스 1×1 | 셀 여백 566, 0.4mm #DFE6F7, 한컴돋움 15 굵게 균등배분 왼쪽 500 140% | 제목 뒤 > |
| 장 상자 1×3 h3014 | [번호 3223 0.5mm 네 변] [간격 1414 왼쪽 0.5mm] [제목 위아래 0.5mm HY견고딕 20, 폭 = 글폭+여유]. 번호는 작성자 것 — 상자 있는 15건 중 로마 숫자 8(HY견명조 굵게 7)·아라비아 숫자 6·가나다 1(숫자·가나다는 7건 중 6이 제목칸과 같은 글꼴·크기) | ## (Ⅰ부터), ## 1. …·## 가. … 는 그 번호 |
| 절 띠 1×3 h2551 | [숫자 3400 #437FC1 아래 0.1mm #CCCCCC, HY견고딕 16 흰] [565] [제목 #E5E5E5 HY견고딕 17] | ### (장마다 1부터) |
| 과제 소제목 | 한컴 PUA 원문자(→ ❶) 굵게 + HY견고딕 16 양쪽 200%, 번호는 장 안에서 절을 넘어 이어짐 | #### |
| 위계 | □ HY견고딕 17 보통 · ㅇ 한컴돋움 15 굵게 · - 휴먼명조 14 (셋 다 양쪽) · ▸ 한컴돋움 13 왼쪽 180% · ※ 한컴돋움 13 왼쪽, 줄간격 190% | □/ㅇ/-/▸/※ (부호 없는 - 는 직전 ㅇ 아래) |
| 숫자 위계 (16건 중 1) | 1. → 1) → ① → - 가 □ → ㅇ → - → - 와 같은 글꼴·크기(넷째 단계도 휴먼명조 14), 부호는 원고 그대로, 들여쓰기 0·1·2·4타 | □·ㅇ 없이 1.·1)·① 두 갈래 이상 |
| 캡션 | < … > 한컴돋움 13 굵게 가운데 · 【 … 】 HY헤드라인M 15 (작성자마다 달라 근거 약함) |
그 꼴의 한 줄 |
| 쪽 | 여백 13/13/18/18mm·머리꼬리 12.7mm (서울 보고서형과 같음) | — |
줄간격·정렬은 작성자가 쪽 맞춤으로 문단마다 바꾸는 값이라 문서 안에서도 역할 최빈값이 20~70% 뿐이고 문서마다 최빈값이 다르다
(정답지 5건: 180·200·175·190·205%). 기본값은 정답지가 아니라 같은 폴더 방침서 16건의 문서별 최빈값 표로 정했다 — 줄간격 190%
(□ 5건·ㅇ 4건·- 3건이 최빈값, 정본의 200% 는 □ 1건), ㅇ 양쪽(15건 중 11). 문서 하나에 맞추려면 lineSpacing 옵션.
재현율(node bench/gen-repro.mjs): 정답지 원문(kordoc 변환 *.orig.md)을 규약 마크다운으로 옮겨(mk-all.sh) 생성한 HWPX 를
style-digest 로 대조, 문단을 글 LCS 로 짝짓고 역할별로 글꼴·크기·굵기(결정적)·정렬·줄간격·문단 간격(손 조정)·색(강조)을 잰다.
손 조정은 정답지 자체 일관성(역할마다 한 값만 낼 때의 최대)을 상한으로 함께 낸다. 2026-09-29, 5건:
| 정답지 | 서식 일치 | 결정적 | 손 조정 (상한) |
|---|---|---|---|
| 청년취업사관학교 2.0 (정본) | 81.9% | 94.2% | 70.9% (78.7%) |
| 성장거점형 복합개발 | 86.4% | 95.5% | 77.5% (83.9%) |
| G3 서울플랜 | 78.1% | 95.1% | 64.3% (84.0%) |
| 제3차 청년정책 기본계획 (숫자 위계) | 77.1% | 84.3% | 68.0% (80.1%) |
| RISE 기본계획 (2장 구성, 절 상자) | 79.6% | 84.2% | 72.8% (79.2%) |
앞장(표지·점검표·목차, repro.json 에 정답지 표지 값·결재선 직위·점검표 표시·목차 여부를 옵션으로 줌)은 짝지은 문단 서식 일치 95.7~99.4%(RISE 95.7·정본 98.6·청년정책 97.9·성장거점형 99.4·G3 98.3). 결재자 이름·시민 칸·협조란(전자결재가 채움)과 목차 쪽번호는 만들지 않아 짝에서 빠진다.
남은 결정적 불일치는 작성자 개별 선택(RISE □ 16pt·각주 함초롬돋움 12, 청년정책 장마다 다른 ① 글꼴·■ 글머리)·프리셋에 없는 틀
(RISE 의 1×2 장 상자 + 1×3 절 상자, 청년정책의 1×2 과제 상자)·마스킹으로 부모가 지워진 항목·원고에 없는 굵게.
앞장(16건 모두 표지 → 점검표 → (목차 7건) → 제목표): cover 간이기안 표지는 방침서 실측 글꼴(문서정보 굴림체 10 굵게/9·결재선
굴림체 9·제목 띠 그라데이션 #3057B9→#A0B4E6 h663·날짜 HY견명조 21 굵게·기관 HY헤드라인M 26 굵게·부서 HY견명조 22, 16건 중 11~15건)로,
결재선은 직위 + 서명 칸 단순형(전자결재가 채우는 시민 칸·결재자 이름·협조란은 없음). checklist 사전 검토항목 점검표는 16건 모두 같은
고정 서식(19×5 w48518, 주황 괘선, 14문항 — 옛 판 2건 13문항)이라 문항 글·줄마다 맞춘 자간·장평·행 높이를 원본 그대로 옮겼고, 제목
배너 그림만 같은 색 그라데이션 칸 + 글로 대신한다. toc 목차는 정본 틀(3열 w47450, 제목칸 밑줄·쪽칸 괘선, 항목 사이 빈 행)이고 쪽 칸은
비운다(조판 전 산출 불가). 미구현: 강조색 표기법·결론 상자(점선 1×2)·목차 붙임 행.
원천: UpstageAI/korean-report-hwpx(MIT) — 정책브리핑 보도자료 HWPX 2,670건(52개 중앙행정기관) 전수 파싱 집계. 원본 문서는 없고
서식 수치만 있다. scripts/build-agency-styles.mjs <체크아웃> 이 src/hwpx/agency-styles.ts 를 만든다(손으로 고치지 않는다).
- 보고서형 값 = 보도자료 참고·붙임 구간(1,326건, 기관 42곳 — 표본 3건 미만 10곳은 공통값): □·ㅇ·- 글꼴·크기, ※ 글꼴·크기, 표 머리 글꼴·크기·음영, 2단계 부호(ㅇ 21·○ 13·◦ 6·❍ 2곳). 공통(기관 간 최빈) □·ㅇ·- 휴먼명조 15 · ※ 맑은 고딕 12 · 표 머리 맑은 고딕 12 #DFE6F7
- 보도자료 값 = 본문(52곳): 문단(기사체) 글꼴·크기, □·ㅇ·* 단계, 2단계 부호, 본문 방식(문단식 37곳·□식 15곳)
- 기관 색 = 참고·붙임 쪽 머리 표 라벨 칸 바탕(11,338건, 현행 기관 46곳 — 바탕 없음 3곳, 그 밖은 공통 #000080). kordoc 은 이 색을 장 띠 번호칸(
bandColor)에 쓴다 — 장 띠 자체의 실측은 아니다. 연한 바탕(교육부 #DFE6F7 등)은 글자를 검정으로 - 계층값 보정은 원 저장소 렌더러와 같다: 표본 5개 미만 계층의 크기는 공통값, 하위 계층 글자는 상위보다 크지 않게, 본문 계층에 섞인 제목 서체(HY헤드라인M·궁서 …)는 본문 서체로(보고서 □ 의 HY헤드라인M 은 유지), 주석·참고 13pt 초과는 12pt. 굵기는 원천에 없어 보통
배선(agency.ts — 명시 옵션이 늘 이긴다, 기관값은 빈자리만. fonts.heading 은 □, fonts.body·bodyFont 는 ㅇ·- 단계 글꼴도 정하고,
명시 bodyPt 면 단계·※·표 크기는 프리셋 비례에 맡긴다(각주 * 12pt 만 유지). levels 는 단계 안에서 속성별로 덮는다 — {0:{bold:true}} 는 기관 □ 글꼴·크기를 둔 채 굵게만):
| 프리셋 | 깔리는 옵션 |
|---|---|
| report·plan·ministry (v5) | levels 0~2 = □·ㅇ·-, fonts.body/ref/table, bullet2, bandColor/bandTextColor, 스킴 ※ 크기·표 크기·표 머리 음영 |
| gaejosik | levels 0 = □(전용 charPr) · ○·- 는 본문 크기와 다를 때만, fonts.body/ref/table, bullet2 |
| press | fonts.body·bodyPt = 문단, levels □·ㅇ 은 본문과 다를 때만 · 2 = *(각주), bullet2 |
본문 charPr 계열 단계(보도자료 □·ㅇ, 개조식 ○·-)를 levels 로 지정하면 장평 맞춤(autoFit) 대상에서 빠지므로 본문과 같으면 지정하지
않는다. 문단식 기관 보도자료에 □ 항목 원고가 오면 경고만 낸다(문체 변환은 엔진 범위 밖). 기안문·통지·회의록·서울 방침서는 받지 않는다.
보도자료 담당 표 press.contact.people: 담당 부서(행 병합) | 부서명 | 구분(책임자·담당자) | 직급 | 이름 | 전화, 사람마다 한 행 —
실물 보도자료 꼴, 칸 폭 비율은 원천의 담당 표 기본 폭. CLI --press-people '책임자/과장/이○○/044-000-0000;담당자/…'.
미채택: 계층 전환별 빈 줄 크기(□→ㅇ 8pt 등 — 기관 간 일치율 30% 안팎이고 kordoc 단계별 문단 간격과 겹친다), 내어쓰기 공식(kordoc 은 부호 실폭 + 1타 탭 정렬), 기관별 표지·보도시점 칸 기하·로고 자리, 줄 끝 자간 고르기(kordoc fitParagraph 가 이미 한다).