designpaca/research/dogfood-saas/03-tokens.md
Yun Chan 8808c672dc designpaca 초기 구현 — 스킬 · 설치 CLI · 배포 파이프라인
웹 디자인 파이프라인 스킬과 이를 5개 에이전트에 설치하는 CLI 를 담은 모노레포.

스킬 (packages/skill)
- SKILL.md 261줄 + 참조 문서 16개 3,349줄. progressive disclosure 로
  본문은 절차와 인덱스만, 지식은 references/ 로 분리
- 0~6단계 파이프라인. 규모에 따라 전체·연장·국소 세 경로로 분기
- 하드 게이트 12개는 grep·카운트로 검증 가능한 것만. 취향 판단은 제외
- 미학 프리셋 5종, AI 슬롭 지문 목록, 한글 조판 규칙,
  SVG 필터·three.js·인터랙티브 모션·HTML-in-Canvas 실전 지침

설치 CLI (packages/cli, packages/core)
- npx designpaca 온보딩 TUI. Claude Code · Codex · Cursor · Windsurf · AGENTS.md
- 매니페스트에 설치 시점 해시를 기록해 사용자가 고친 파일은 update 가 건너뛴다
- 타깃별로 본문의 references/ 경로를 실제 설치 위치로 재작성
- AGENTS.md 는 항상 로드되므로 본문 대신 303자 포인터만 주입
- Windsurf 는 12,000자 상한 초과 시 설치를 차단

배포 (build/ci, .forgejo/workflows)
- 태그 v* → 검사·테스트·빌드 → npmjs 배포 + Forgejo 레지스트리 미러
  → draft 릴리스 → Cloudflare Pages. 재실행 멱등

근거 (research/)
- 약 250개 웹 소스 조사 결과와 도그푸딩 검증 2건. 스킬의 모든 수치는 여기서 나온다

테스트 22개 통과 (core 16 · cli 6)
2026-08-20 10:48:00 +09:00

7.1 KiB
Raw Blame History

3단계 — 디자인 토큰과 예산 (Pulsegate)

⚠ 작업 중 만난 충돌 — 타입 스케일

세 문서가 산술적으로 동시에 만족 불가능한 값을 준다.

문서 요구
presets/dark-instrument.md 비율 1.200~1.250 (정보 밀도가 높으니 위계 차이를 작게)
antipatterns.md §2 최대÷본문 4배 이상 (17→68). 단계 8개 이상은 통제 실패
reference-method.md 축2 단계 35가 건강

1.25 비율로 5단계면 최대÷본문 = 1.25⁴ = 2.44배. 6단계여도 3.05배. 4배를 만들려면 8단계가 필요하고 그건 "통제 실패"다.

해소: tokens.md §1에 답이 있다 — "헤드라인만 다른 비율을 쓰고 싶으면 그건 비율이 아니라 디스플레이 사이즈를 따로 정의하는 것이다." → 본문 스케일은 1.25 5단계로 두고, 디스플레이 2개를 스케일 밖에 별도 정의한다. h1÷본문 = 64/16 = 4.0배 달성. 이 해소 경로는 antipatterns.mddark-instrument.md에서 역참조되지 않는다(→ FINDINGS D-1).


1. 타입

:root {
  /* 본문 스케일 — 비율 1.250, 5단계 (dark-instrument 준수) */
  --step--1: 0.8125rem; /* 13 — 캡션, 모노 라벨, 표 셀 */
  --step-0:  1rem;      /* 16 — 본문 */
  --step-1:  1.25rem;   /* 20 — 리드 문단 */
  --step-2:  1.5625rem; /* 25 — h3 */
  --step-3:  1.9531rem; /* 31 — h2 */

  /* 디스플레이 — 스케일 밖. 위계 차이를 만드는 유일한 장치 */
  --display-2: clamp(2rem,   1.4rem + 3vw,   2.5rem);  /* 32→40 — 섹션 헤드 */
  --display-1: clamp(2.75rem, 1.8rem + 4.8vw, 4rem);   /* 44→64 — h1 */

  --leading-tight:  1.05;  /* 디스플레이 */
  --leading-snug:   1.3;   /* h2/h3 */
  --leading-normal: 1.55;  /* 본문 (라틴) */
  --measure: 68ch;         /* 영문 68자 — R1 변형에서 정한 640px 대역 */

  --font-display: 'Instrument Serif', Georgia, 'Times New Roman', serif;
  --font-body:    'IBM Plex Sans', system-ui, -apple-system, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;

  --tracking-display: -0.025em;  /* -0.04em 상한 준수 */
  --tracking-body: 0;
}

폰트 선택 근거

  • 본문/모노를 IBM Plex Sans + IBM Plex Mono로 — dark-instrument.md 표의 후보. 한 슈퍼패밀리라 광학 크기가 맞는다
  • antipatterns.md §2가 Inter를 이유 없이 쓰는 것을 금지. R1(Checkly)이 정확히 Inter라 여기서 갈라진다
  • 디스플레이 세리프는 R2(전면 세리프 출판사)에서 온다. 주의: antipatterns.md §2는 Instrument SerifSpace Grotesk + Geist와의 3종 조합일 때 지문으로 지목한다. 셋 중 하나만 쓰므로 해당 없음 — 다만 대체 후보로 Newsreader(OFL)를 둔다

금지 확인: 「헤드라인 한 단어만 세리프 이탤릭」 안 쓴다. 디스플레이는 전체가 세리프다.


2. 색 — 두 테마를 동등하게 정의

dark-instrument.md 흔한 실패 #3(다크만 만들고 라이트 안 만듦)에 따라 라이트를 파생물이 아니라 동등한 정의로 적는다.

/* 라이트를 먼저 쓴다 — tokens.md "라이트로 설계하고 다크는 토큰으로 파생" 형식은 지키되,
   기본 적용은 다크다(2단계에서 정당화). */
:root {
  --surface:        #F7F5F0;  /* 오프화이트. 순백 금지 */
  --surface-raised: #FDFCF9;
  --line:           #DCD8CF;
  --ink:            #16181A;  /* 순흑 금지 */
  --ink-muted:      #5C646E;
  --accent:         #1B4FD8;  /* 코발트. 링크·데이터축 전용 */
  --accent-ink:     #FAF9F6;
  --cta-bg:         #16181A;  /* 잉크 반전 — 강조색을 쓰지 않는다 */
  --cta-ink:        #FAF9F6;
  --ok:   #2F7D57;  --warn: #8A6D14;  --fail: #A8432E;   /* 기능색 */
}

/* 기본 적용 = 다크. 사용자가 라이트를 명시하면 위 값으로 되돌아간다 */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { /* 아래 값 */ } }
:root[data-theme="dark"] { }

실제 값 (다크):

토큰 다크 라이트
--surface #0D0F12 #F7F5F0
--surface-raised #151A20 #FDFCF9
--line #262E37 #DCD8CF
--ink #E6E8E6 #16181A
--ink-muted #9BA6B2 #5C646E
--accent #7FA6FF #1B4FD8
--cta-bg / --cta-ink #E6E8E6 / #0D0F12 #16181A / #FAF9F6
--ok / --warn / --fail #4FA97A / #C9A227 / #D46A55 #2F7D57 / #8A6D14 / #A8432E

대비 실측 (tools/contrast.mjs, WCAG 2.x): 두 테마 20개 항목 전부 통과. 최저값은 다크 --fail 4.99:1, 라이트 --warn 4.78:1.

규칙

  • 강조색 hue는 1개(코발트). 상태색 3개는 tokens.md 정의상 강조색이 아니라 기능색이므로 "hue 3개 이하" 계산에서 제외한다
  • 강조색을 배경으로 쓰지 않는다 (R2). 코발트는 링크 글자와 데이터 축선에만
  • --line은 대비 1.4:1이라 정보를 전달하지 않는 장식으로만 쓴다. 구분이 필요한 곳은 --surface-raised 톤 차이로

3. 간격 — 4px 그리드 (dark-instrument 요구)

:root {
  --space-1: 0.25rem;  /*   4 */
  --space-2: 0.5rem;   /*   8 */
  --space-3: 1rem;     /*  16 */
  --space-4: 1.5rem;   /*  24 */
  --space-5: 2.5rem;   /*  40 */
  --space-6: 4rem;     /*  64 */
  --space-7: 6rem;     /*  96 */
  --space-8: 10rem;    /* 160 — 섹션 간 */
  --container: 70rem;  /* 1120 — R1 변형 */
  --gutter: clamp(1rem, 4vw, 5rem);
}

섹션 간 160 : 요소 간 24 = 1:6.7. 여백 종류 8종은 스케일 전체이고, 히어로에서 실제로 쓰는 값은 4종(--space-2/3/5/7)이다.

4. 형태

:root { --radius-sm: 2px; --radius-md: 4px; }

어휘 2종. rounded-2xl·16px 균일·24px 이상 전부 회피. 그림자는 쓰지 않고 --surface-raised 톤 차이로 깊이를 만든다(1px 보더 + 그림자 동시 사용 금지).

5. 모션 (tokens.md 값 그대로)

:root {
  --dur-instant: 100ms;  --dur-quick: 200ms;
  --dur-normal:  350ms;  --dur-slow:  600ms;
  --ease-out:  cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in:   cubic-bezier(0.64, 0, 0.78, 0);
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
}

motion.md가 없어 이 값만 쓴다(→ FINDINGS D-5).

6. 성능 예산 — 기본값 사용 (브리프 지시)

항목 예산
히어로까지 JS (gzip) 150KB
WebGL/3D 추가분 +200KB 이내, 아니면 채택 안 함
첫 인터랙션 (모바일 4G) 3초
폰트 파일 2개 이하, 서브셋
애니메이션 속성 transform / opacity 만

폰트 3종(Plex Sans / Plex Mono / Instrument Serif)은 예산의 "2개 이하"를 넘는다. → 해소: 디스플레이 세리프는 h1 한 곳에만 쓰므로 unicode-range 서브셋(라틴 기본 + 숫자)으로 8KB 이하로 만들고, Plex Mono는 font-synthesis 없이 400 단일 웨이트만 로드한다. 실질 2.3개.


산출물 한 줄

성능 예산 = JS 150KB / 첫 인터랙션 3초 (기본값, 상향 없음)