Korean Label Handling and Hangul Font Requirements in diagram-design: A Complete Guide
Korean (Hangul) labels in diagram-design are managed through a strict style guide that mandates specific font stacks, a 12 px minimum size floor, and per-character width budgeting using 1 em per full-width CJK character.
The cathrynlavery/diagram-design repository treats Korean text as a first-class label type with dedicated handling rules. This article breaks down the font requirements, sizing constraints, and rendering logic defined in /skills/diagram-design/references/style-guide.md and enforced by verify-treemap.py.
Primary Hangul Font Stack
The diagram templates load Noto Sans KR as the primary Korean typeface alongside the default Latin families. According to the style guide, the complete web-font stack includes:
GeistandGeist Mono(default Latin families)Instrument Serif(default serif)- Noto Sans KR and Noto Serif KR (Korean-specific Google Fonts)
This combination ensures Hangul glyphs render correctly whether the diagram is viewed online with live web fonts or offline with bundled fallbacks. The Google Fonts stylesheet is preloaded in skills/diagram-design/assets/template-full.html across all four diagram templates.
Element-Level Font Family Extensions
Because Geist contains no Hangul glyphs, any <text> element with Korean characters must explicitly extend its font-family declaration. The recommended stack from line 94 of the style guide:
<text font-family="'Geist', 'Noto Sans KR', 'Apple SD Gothic Neo', 'Malgun Gothic', sans-serif">
결제 서비스
</text>
The fallback chain covers all major platforms:
- Noto Sans KR — Primary web font (Google Fonts)
- Apple SD Gothic Neo — macOS system fallback
- Malgun Gothic — Windows system fallback
For mixed Latin/Korean titles using the serif family, the stack switches to 'Instrument Serif', 'Noto Serif KR', serif' so Korean portions fall back to the matching Korean serif face.
Per-Character Width Budgeting
Korean label handling includes precise width calculations for layout stability. The verify-treemap.py script enforces these rules during CI:
| Character Type | Advance Width |
|---|---|
| Full-width CJK (Hangul, Hanja, Kana) | 1.0 em |
| Latin (Geist default) | ~0.60 em |
| Monospace (Geist Mono) | ~0.62 em |
The total label width equals the sum of per-character advances multiplied by font size, plus padding, rounded up to the next multiple of 4. This prevents overflow in treemap cells and maintains the 4 px grid alignment used throughout the design system.
Three Mandatory Rules for Korean Labels
The style guide defines three non-negotiable rules for Hangul text at line 103:
1. Sublabels Stay Latin
Technical sub-labels (ports, protocols, URLs) must remain in Geist Mono at 9 px. Hangul is never rendered at this small mono size because readability collapses. If a Korean name includes technical metadata, the Korean portion separates to a larger non-mono line.
2. 12 px Minimum Size Floor
Hangul must never appear smaller than 12 px. When a Korean name would require a smaller font to fit, the name is truncated instead. This rule protects stroke clarity in complex Hangul syllables.
3. Arrow Labels Switch Register
Arrow labels, eyebrows, and legend text normally use 7–8 px uppercase Geist Mono. When Hangul appears in these slots, the rendering changes:
| Property | Latin Default | Hangul Override |
|---|---|---|
| Font family | Geist Mono |
Sans-serif stack with Noto Sans KR |
| Font size | 7–8 px | 12 px |
| Text transform | uppercase |
none |
| Mask rectangle height | 8 px | 16 px (rounded to multiple of 4) |
This register switch is documented at line 107 of the style guide.
Skill Manifest Integration
The Korean label requirements are discoverable at runtime through SKILL.md line 202, which points agents to the dedicated Korean-label section. This integration ensures that automated diagram generation follows the same constraints as manually authored content.
Practical Code Examples
Korean SVG Label with Proper Font Stack
<svg width="200" height="40" xmlns="http://www.w3.org/2000/svg">
<text x="10" y="30"
font-family="'Geist', 'Noto Sans KR', 'Apple SD Gothic Neo', 'Malgun Gothic', sans-serif"
font-size="12px">
결제 서비스
</text>
</svg>
Width Budget Calculation (verify-treemap.py Logic)
def label_width(text, font_size_px):
em_per_char = {
'wide': 1.0, # Hangul, CJK full-width
'latin': 0.60, # Geist default
'mono': 0.62 # Geist Mono default
}
width_em = 0
for ch in text:
if is_full_width(ch): # Hangul or other CJK
width_em += em_per_char['wide']
elif is_mono_context(): # technical sublabel
width_em += em_per_char['mono']
else:
width_em += em_per_char['latin']
# padding & rounding to next multiple of 4
raw_px = width_em * font_size_px
padded_px = raw_px + 8 # 4 px left + 4 px right
return ((padded_px + 3) // 4) * 4
Arrow Label Fallback for Hangul
<text font-family="'Geist Mono', 'Noto Sans KR', sans-serif"
font-size="12px"
text-transform="none"
letter-spacing="0">
인증
</text>
Key Source Files
| File | Role |
|---|---|
skills/diagram-design/references/style-guide.md |
Defines Korean font stack, width budgeting, and Hangul rendering rules |
SKILL.md |
Runtime agent reference pointing to Korean-label requirements |
scripts/verify-treemap.py |
CI enforcement of 1 em per full-width character rule |
skills/diagram-design/assets/template-full.html |
Template including Korean and Latin font preloads |
Summary
- Font requirement: Noto Sans KR (sans) and Noto Serif KR (serif) must load alongside Geist families
- Element rule: Korean
<text>elements extend font-family with platform fallbacks - Sizing rule: 12 px minimum for Hangul; truncate rather than shrink
- Width rule: 1 em per full-width CJK character, rounded to 4 px grid
- Register switch: Arrow labels and small elements switch from 7–8 px mono to 12 px sans when containing Korean
Frequently Asked Questions
What happens if a Korean label is too long for its container?
The name is truncated rather than rendered below 12 px. The style guide mandates this floor to preserve Hangul stroke clarity, and verify-treemap.py validates container fits during CI.
Can I use a different Korean font instead of Noto Sans KR?
The style guide specifies Noto Sans KR as the primary web font for consistency across diagrams. System fallbacks (Apple SD Gothic Neo, Malgun Gothic) are acceptable for offline scenarios, but the Google Fonts link must remain in templates.
Why do technical sub-labels stay in monospace even when the main label is Korean?
Readability of Hangul at 9 px monospace collapses due to dense stroke patterns. The mono size is reserved for Latin technical content (ports, URLs) that benefits from fixed-width alignment, while Korean names render at 12 px in proportional sans.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →