diff --git a/apps/site/src/components/Typography.astro b/apps/site/src/components/Typography.astro
index f73d68a..3a0063d 100644
--- a/apps/site/src/components/Typography.astro
+++ b/apps/site/src/components/Typography.astro
@@ -13,18 +13,34 @@ const { c } = Astro.props;
{c.eyebrow}
{c.h2}
{c.lead}
- {c.body}
- {/* 주장을 글로 하지 않고 실물로 보여준다. 두 문단의 차이는 word-break 한 줄뿐이다 */}
-
-
-
{c.demoLabels[0]}
-
{c.demoText}
-
-
-
{c.demoLabels[1]}
-
{c.demoText}
-
+ {/*
+ 주장을 글로 하지 않고 실물로 보여준다.
+
+ 한때 word-break 하나만 두 칼럼으로 비교했는데, 어절이 짧아 두 쪽이
+ 같은 자리에서 끊겼다 — 줄 수도 높이도 똑같았다. 차이가 0 인 비교는
+ 증명이 아니라 주장의 반증이다. 셋으로 늘리고, 잘리는 긴 어절을 넣고,
+ 폭을 좁혀 실제로 갈리게 만들었다.
+ */}
+
+ {
+ c.demos.map((d) => (
+
+ {d.title}
+
+
+
{d.badLabel}
+
{c.sample}
+
+
+
{d.goodLabel}
+
{c.sample}
+
+
+ {d.note}
+
+ ))
+ }
@@ -33,41 +49,81 @@ const { c } = Astro.props;
diff --git a/apps/site/src/i18n/content.ts b/apps/site/src/i18n/content.ts
index 8f59b13..a8a1eec 100644
--- a/apps/site/src/i18n/content.ts
+++ b/apps/site/src/i18n/content.ts
@@ -74,9 +74,14 @@ export interface Content {
eyebrow: string;
h2: string;
lead: string;
- body: string;
- demoLabels: [string, string];
- demoText: string;
+ sample: string;
+ demos: {
+ id: "break" | "leading" | "size";
+ title: string;
+ badLabel: string;
+ goodLabel: string;
+ note: string;
+ }[];
rules: string[];
};
rules: { h2: string; lead: string; items: Rule[] };
@@ -337,13 +342,33 @@ export const ko: Content = {
},
typography: {
eyebrow: "한글 조판",
- h2: "라틴 기준으로 만든 도구는 한글에서 멈춘다",
+ h2: "라틴 기본값은 한글에서 세 군데가 깨진다",
lead:
- "영어권 디자인 도구는 한글 조판 규칙을 갖고 있지 않다. 9에서 11px 텍스트는 라틴에서 라벨이지만 한글에서는 읽을 수 없다. line-height 1.5는 라틴에서 표준이지만 한글에서는 답답하다.",
- body:
- "가장 자주 깨지는 것은 줄바꿈이다. 기본값은 단어 중간에서 줄을 끊는다. 아래 두 문단은 같은 글자, 같은 폭, 같은 폰트다. 차이는 word-break 한 줄뿐이다.",
- demoLabels: ["기본값", "keep-all"],
- demoText: "원두의 산미와 바디를 구분하는 사람에게 필요한 것은 형용사가 아니라 수치다.",
+ "영어권 디자인 도구에는 한글 조판 규칙이 없다. 그래서 기본값을 그대로 쓰면 아래 셋이 동시에 무너진다. 왼쪽이 기본값, 오른쪽이 이 스킬이 정한 값이다. 글자도 폭도 폰트도 같다.",
+ sample: "스페셜티커피의 로스팅프로파일을 구분하려면 산미와 바디를 수치로 봐야 한다.",
+ demos: [
+ {
+ id: "break",
+ title: "줄바꿈",
+ badLabel: "기본값",
+ goodLabel: "word-break: keep-all",
+ note: "기본값은 어절 한가운데를 끊는다. 왼쪽 마지막 줄을 보라 — 한 단어가 두 줄에 걸쳐 있다.",
+ },
+ {
+ id: "leading",
+ title: "행간",
+ badLabel: "line-height 1.45",
+ goodLabel: "line-height 1.75",
+ note: "라틴 표준 1.4~1.5 는 받침이 있는 글자에 좁다. 줄이 서로 붙어 보인다.",
+ },
+ {
+ id: "size",
+ title: "크기",
+ badLabel: "11px",
+ goodLabel: "15px",
+ note: "라틴에서 11px 은 라벨로 쓴다. 한글은 획이 많아 같은 크기에서 뭉갠다.",
+ },
+ ],
rules: [
"word-break: keep-all 없으면 단어가 아무 데서나 잘린다",
"line-height 1.6에서 1.8 사이. 라틴보다 넉넉하게",
@@ -572,19 +597,39 @@ export const en: Content = {
},
typography: {
eyebrow: "Your language is probably not Latin",
- h2: "Tools built on Latin assumptions stop at the script boundary",
+ h2: "Latin defaults break Korean in three places",
lead:
- "Design tooling written in English carries no rules for other scripts. 9 to 11px text is a label in Latin and unreadable in Korean. A line-height of 1.5 is standard in Latin and cramped in Korean.",
- body:
- "Line breaking fails first. The default breaks Korean mid-word, the equivalent of breaking English mid-syllable in the middle of a sentence. Both paragraphs below use the same text, width and font. The only difference is one line of word-break.",
- demoLabels: ["default", "keep-all"],
- demoText: "원두의 산미와 바디를 구분하는 사람에게 필요한 것은 형용사가 아니라 수치다.",
+ "Western design tools carry no Korean typesetting rules. Leave the defaults in place and all three of these fail at once. Left is the default, right is what this skill sets. Same text, same width, same font.",
+ sample: "스페셜티커피의 로스팅프로파일을 구분하려면 산미와 바디를 수치로 봐야 한다.",
+ demos: [
+ {
+ id: "break",
+ title: "Line breaking",
+ badLabel: "default",
+ goodLabel: "word-break: keep-all",
+ note: "The default breaks mid-word. Look at the last line on the left — one word straddles two lines.",
+ },
+ {
+ id: "leading",
+ title: "Leading",
+ badLabel: "line-height 1.45",
+ goodLabel: "line-height 1.75",
+ note: "The Latin standard of 1.4-1.5 is tight for syllable blocks with a final consonant.",
+ },
+ {
+ id: "size",
+ title: "Size",
+ badLabel: "11px",
+ goodLabel: "15px",
+ note: "11px is a label size in Latin. Korean glyphs carry more strokes and smear at it.",
+ },
+ ],
rules: [
- "word-break: keep-all, or words break at arbitrary points",
- "line-height between 1.6 and 1.8, more generous than Latin needs",
- "no negative letter-spacing. Korean glyphs are near-monospaced and collapse immediately",
- "25 to 40 characters per line. Latin's 65 is far too long",
- "not specifying a Korean font is itself a sign of unfinished work",
+ "Without word-break: keep-all, words break at arbitrary points",
+ "line-height between 1.6 and 1.8 — looser than Latin",
+ "Never use negative tracking. Korean is already near-monospaced",
+ "25 to 40 characters per line. The Latin 65 is far too long",
+ "Shipping without a Korean font stack is itself a tell",
],
},
rules: {
diff --git a/packages/skill/references/antipatterns.md b/packages/skill/references/antipatterns.md
index 53ae782..524c7ab 100644
--- a/packages/skill/references/antipatterns.md
+++ b/packages/skill/references/antipatterns.md
@@ -160,6 +160,28 @@ Show HN 랜딩 1,590개 실측에서 검출률이 가장 높았던 셋이다. **
| Powerful Features | 엑셀 없이 정산이 끝난다 | 명사구 → 주장 |
| 빠르고 안정적인 배포 | 배포 실패가 롤백까지 90초 | 형용사 → 측정치 |
+### 데모가 주장을 증명하는지 재라
+
+주장을 화면으로 보여주는 섹션이라면, **그 화면이 정말 다른지 숫자로 확인해라.**
+"차이는 이 한 줄뿐이다"라고 써놓고 두 쪽이 똑같으면, 그건 증명이 아니라 주장의 반증이다.
+
+> 실측 사례: `word-break: break-all` 과 `keep-all` 을 나란히 두고
+> "차이는 한 줄뿐"이라고 적었다. 재보니 **줄 수 3, 높이 87px 로 완전히 동일**했다.
+> 어절이 짧아 두 쪽이 같은 자리에서 끊긴 것이다. 반년을 그대로 뒀어도 몰랐을 것이다.
+
+```js
+// 비교 데모는 이렇게 검증한다
+const m = sel => { const e = document.querySelector(sel), r = e.getBoundingClientRect();
+ return { h: Math.round(r.height), lines: Math.round(r.height / parseFloat(getComputedStyle(e).lineHeight)) }; };
+// m('.bad') 와 m('.good') 이 같으면 그 데모는 아무것도 보여주지 않는다
+```
+
+**차이가 안 나면 조건을 극단으로 밀어라** — 폭을 좁히고, 잘리기 쉬운 긴 어절을 넣고,
+값 차이를 벌린다. 그래도 안 나면 그 비교는 애초에 보여줄 것이 없는 것이다.
+
+그리고 **설명 문장이 화면과 일치하는지 확인해라.** "A 가 갈린다"고 썼는데 실제로 갈린 건
+B 라면, 반응형에서 매번 바뀌는 것을 지목한 것이다. 지목하지 말고 현상만 말해라.
+
**대구·대조·리듬은 마지막에 얹는 것이다.** 먼저 말할 내용을 정하고,
그것이 정해진 뒤에도 대구가 성립하면 그때 써라. 대구부터 잡으면 내용이 비어도 모른다.