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)
This commit is contained in:
Yun Chan 2026-08-20 10:48:00 +09:00
commit 8808c672dc
135 changed files with 38838 additions and 0 deletions

827
research/site-brief.md Normal file
View file

@ -0,0 +1,827 @@
# designpaca 소개 페이지 — 1·2·3단계 산출물
> **2026-08-20 갱신 (4차).** **3단계(디자인 토큰과 예산)**를 추가했다 — §J가 4단계의 입력이다.
> 2단계는 사용자 결정 *"위에 모두 다 한다. 멀티링구얼하게 한다"* 에 따라 세 컨셉을 하나의 문장으로 통합한 것이다(§A).
> 6축과 대비값은 전부 실측·실계산이다. 추정값 없음.
>
> **읽는 순서**: §1 브리프 → **§J 토큰(3단계, 복사해 쓰는 곳)** → 근거가 필요하면 2단계(§A~§I) → 1단계(§2~§11).
---
## 1. 브리프
```
무엇을: designpaca 소개 페이지. 웹 디자인 파이프라인 스킬 + npx 설치 CLI 를 소개하는 단일 페이지
누구에게: Claude Code · Codex · Cursor 를 쓰는 개발자. `npx designpaca` 를 터미널에 치게 만드는 것이 목표
제약: Astro 정적 → Cloudflare Pages / 한국어 우선 / 히어로까지 JS 150KB gzip, 첫 인터랙션 3초
이 페이지 자체가 스킬의 품질 증거물이다
```
**한 문장 브리프**: 회의적인 개발자가 이 페이지를 읽고 `npx designpaca` 를 친다. 느껴야 할 것은 **절제**와 **근거**.
사용자 결정: **세 컨셉을 전부 담고, 한국어·영어 양쪽을 만든다.**
---
# 2단계 — 방향 결정
## A. 한 문장 컨셉
> **이 페이지는 designpaca를 거쳐 만들어졌고, 그 절차와 형태 수치를 한국어 기준으로 전부 공개한다.**
세 컨셉이 이 한 문장 안에서 각자의 자리를 갖는다.
| 컨셉 | 문장 속 위치 | 하는 일 |
|---|---|---|
| 3. 파이프라인을 판다 | **"designpaca를 거쳐 … 그 절차"** | 페이지의 뼈대 |
| 1. 형태까지 간다 | **"형태 수치"** | 주장의 증거 |
| 2. 한국어로 푼다 | **"한국어 기준으로"** | 차별화의 근거 |
| — 통합축 | **"전부 공개한다"** | 셋을 하나로 묶는 것 |
**통합축은 "자기 증명"이다.** 셋을 나열해 붙인 게 아니라, *이 페이지 자신이 첫 사례라는 사실* 하나로 묶인다.
파이프라인은 이 페이지가 실제로 거친 과정이고, 형태 수치는 그 과정이 남긴 흔적이고, 한국어는 그 흔적이 라틴 기준 도구로는 나올 수 없었다는 증거다.
---
## B. 미학 프리셋 — `swiss-minimal`
→ 3단계에서 `references/presets/swiss-minimal.md` **하나만** 읽는다. 넷 다 읽지 않는다.
하나만 고른다. 섞지 않는다.
**선택 근거**
1. 자기 증명의 핵심 장치가 **수치 공개**다. 수치는 격자와 표로 읽힌다.
2. **멀티링구얼이 결정적이었다.** `editorial`의 세리프 산문은 한국어에서 마루 부리, 영어에서 Spectral로 갈리며 두 판의 톤이 벌어진다. `swiss-minimal`의 그로테스크는 Pretendard / Switzer로 양쪽이 같은 성격을 유지한다.
3. `anti-grid`는 브리프 형용사(**절제**, **근거**)와 정면 충돌한다.
**나머지에서 빌릴 것 — 딱 이것만**
| 프리셋 | 빌릴 것 | 빌리지 않을 것 |
|---|---|---|
| `editorial` | 각 규칙 옆에 **근거 1문장**을 붙이는 Klim식 어법 | 세리프 본문, 산문 중심 레이아웃 |
| `anti-grid` | 파이프라인 섹션 **한 곳에서만** 그리드를 의도적으로 어긋내 진행감을 만든다 | 페이지 전반의 깨진 레이아웃, 모노스페이스 남용 |
---
## C. 감수할 리스크 — 하나
> **이 페이지 자신의 형태 수치를 페이지에 공개한다.**
> radius 어휘 수, `backdrop-filter` 개수, 타입 스케일 단계 수, 폰트 패밀리 수, 히어로까지의 JS gzip 크기, 프리플라이트 통과 항목.
**왜 이게 대담한가**: 공개한 순간 검증 가능해진다. 나중에 하나라도 어기면 페이지 전체의 주장이 무너진다. 되돌릴 수 없는 약속이다.
**왜 이걸 골랐나**: 컨셉의 심장이기 때문이다. "형태까지 간다"를 말로만 하면 그것도 자기 평가 형용사다. 수치를 걸어야 주장이 된다.
**단 이 수치는 5단계 실측 전까지 지어내지 않는다.** SKILL.md 하드 게이트 11에 정면으로 걸린다.
4단계에서는 `{{RADIUS_COUNT}}` `{{GLASS_COUNT}}` `{{TYPE_STEPS}}` `{{JS_GZIP_KB}}` 같은 **명시적 placeholder**로 두고,
5단계 프리플라이트에서 실제로 측정한 값으로 채운다. 숫자 모양의 구멍은 정직하고, 그럴듯한 숫자는 슬롭이다.
**나머지 두 위험은 리스크가 아니라 설계로 처리한다** — 대담함은 한 곳에만 둔다.
- 번호 없는 파이프라인 → §E에서 3중 장치로 해결
- 한국어판이 원본 → §F에서 영어판을 번역이 아닌 별도 집필로 해결
---
## D. 저격 회피 — 팀 리드 제안에서 한 걸음 더
리드 제안은 "수치를 익명으로 쓰되 우리 것을 나란히 공개"였다. **더 나은 방법이 있다.**
**남의 수치를 아예 쓰지 않는다. 우리 수치만 쓴다.**
| 이유 | 설명 |
|---|---|
| 익명화가 작동하지 않는다 | 안티슬롭 도구는 손에 꼽는다. "실측한 어떤 도구"라고 써도 누군지 다 안다. 익명화는 저격을 예의 바르게 만들 뿐이다 |
| 남의 수치는 반박 가능하다 | "그 40개는 대부분 nav야", "16px는 의도야" — 논쟁이 시작되는 순간 제품 이야기가 사라진다 |
| 자기 수치는 반박 대상이 아니다 | 우리가 우리 페이지에 대해 말하는 건 논쟁거리가 아니라 사실이다 |
**대신 이렇게 프레이밍한다**: *"카피만 고치면 남는 것"* 을 **우리 자신의 프리플라이트 로그**로 제시한다.
이 페이지를 만들면서 실제로 걸린 항목과 고친 값을 그대로 싣는다. 남을 검사한 결과가 아니라 **자신을 검사한 결과**다.
지목 대상은 제품이 아니라 **방법론**이다 — "카피 레이어만 다루는 접근". 이건 특정 제품이 아니라 안티슬롭 도구 전반의 공통 한계이므로 저격이 성립하지 않는다.
tasteskill.dev의 실측치(radius 8종 / 글래스 40 / 타입 12단계)는 **1단계 조사 문서에만 남기고 페이지에는 싣지 않는다.**
---
## E. C-07 해법 — 번호 없이 순서 표현하기
**결론: 풀렸다. 컨셉 3을 유지한다.**
### 3중 장치
**① 시각 — 연속선 위의 위치 (Harry Beck, 1933)**
Beck의 런던 지하철 노선도는 "topology trumped topography" 원칙으로 만들어졌다.
역을 실제 거리가 아니라 **등간격으로 선 위에 재배치**했고, 순서는 번호가 아니라 **선 위의 위치**가 만든다.
90년 넘게 세계 표준으로 남아 있으므로 가독성은 검증된 셈이다.
→ 세로 **스파인(연속선)** 이 파이프라인 섹션을 관통한다. 6단계는 그 선 위의 위치로 순서를 갖는다. 번호를 쓰지 않는다.
**② 내용 — 같은 대상의 상태 변화 (IKEA)**
IKEA 조립 설명서는 페이지당 한 동작만 보여주고, 화살표가 방향을, 하이라이트가 연결점을 나타낸다.
순서는 번호가 아니라 **"한 화면 = 한 동작"이라는 분절**과 **대상의 변화**가 만든다.
IKEA가 이렇게 하는 동기는 **언어 독립성**이다 — 한 벌로 전 세계에 나간다.
→ 각 단계마다 **같은 브리프 문장 하나**가 어떻게 변해 가는지 보여준다.
브리프 → 레퍼런스 3개 → 6축 수치 → 토큰 → 마크업 → 프리플라이트 결과.
**변화 자체가 순서를 증명하므로 번호가 필요 없다.**
**③ 의미 — `<ol role="list">` (Scott O'Hara)**
Safari/VoiceOver는 `list-style: none`이 적용되면 리스트 의미를 보조기술에 노출하지 않는다.
Scott O'Hara가 제시한 해법은 요소에 **`role="list"` 를 명시**해 의미를 복원하는 것이다.
```html
<ol role="list" class="pipeline"> <!-- list-style: none -->
<li></li>
</ol>
```
→ **시각적으로는 번호 0개, 보조기술에는 "6개 중 1번째"로 전달된다.**
C-07을 회피하면서 접근성은 오히려 좋아진다.
### 왜 서사형(narrative)은 안 썼나
문단 서술로 순서를 표현하는 방식(narrative recipe)도 검토했다.
조리 과정처럼 초기 중국·인도·유럽 레시피가 전부 문단 서술형이었다. 하지만 **복잡하지 않은 절차에만 적합하고 따라가기 어렵다**는 한계가 문헌에서 반복 지적된다.
6단계 파이프라인에는 부적합하다. 채택하지 않는다.
### 멀티링구얼 보너스
스파인과 상태 변화는 **번역이 필요 없다.** IKEA가 언어 독립성을 위해 택한 방식과 같은 이유로,
한국어판과 영어판이 **같은 시각 구조를 공유하고 텍스트만 갈린다.** 난제 1의 해법이 난제 3을 함께 줄인다.
---
## F. 멀티링구얼 설계
리드가 정한 기본값 4개는 **전부 타당하다. 뒤집을 근거 없음.** 그 위에 실행 값을 정한다.
| 항목 | 결정 |
|---|---|
| 경로 | `/` = 한국어(원본) · `/en/` = 영어. 같은 페이지 내 병기 안 함 |
| 전환 | 헤더에 하나. 자동 리다이렉트 없음. `<link rel="alternate" hreflang="ko|en|x-default">` |
| 집필 | 번역이 아니라 **각 언어판 별도 집필** |
| **국기 아이콘** | **쓰지 않는다.** 언어는 국가가 아니다. `한국어 / English` 텍스트로만 |
### 언어별로 갈리는 값
한글은 같은 px에서 라틴보다 작아 보이고 줄바꿈 규칙이 다르다. **두 판이 같은 값을 쓰면 한쪽이 깨진다.**
| 값 | 한국어판 `/` | 영어판 `/en/` |
|---|---|---|
| UI·본문 폰트 | **Pretendard** (단일) | **Switzer** |
| 코드·설치 명령 | JetBrains Mono | JetBrains Mono (공통) |
| 본문 크기 | **17px** | 16px |
| 본문 line-height | **1.7** | 1.55 |
| letter-spacing (본문) | **0** (음수 금지) | 0 |
| 텍스트 컬럼 폭 | **약 560px** (국문 2540자) | 약 640px (65ch) |
| 줄바꿈 | `word-break: keep-all` + `overflow-wrap: break-word` | 기본값 |
| 최소 텍스트 크기 | **16px** (예외 없음) | 14px |
두 판이 공유하는 것: 그리드, 여백 리듬, 컬러 토큰, radius 어휘, 모션, 스파인 구조.
---
## G. 섹션 구조
스파인(§E-①)이 §2부터 §4까지를 관통한다.
| # | 섹션 | 살아나는 컨셉 | 한국어판 | 영어판 |
|---|---|---|---|---|
| 1 | **히어로** — h1 `designpaca` / 한 문장 / 설치 명령 + 복사 버튼 / 보조 링크 2개 | — | 동일 구조 | 동일 구조 |
| 2 | **파이프라인** — 스파인 위 6단계. 번호 없음. 같은 브리프 문장이 단계마다 변한다 | **컨셉 3** | 동일 시각 구조 | 동일 시각 구조 |
| 3 | **이 페이지의 수치** — radius 어휘 수 / 글래스 개수 / 타입 단계 / 패밀리 수 / JS gzip | **컨셉 1** (+ 리스크 §C) | 동일 (언어 무관) | 동일 |
| 4 | **프리플라이트 로그** — 이 페이지를 만들며 실제로 걸린 항목과 고친 값 | **컨셉 1** (§D 프레이밍) | 동일 | 동일 |
| 5 | **조판** — 왜 라틴 기준 도구로는 안 되는가. 실제 대비 예시 | **컨셉 2** | *"한글 조판"* — 우리 주장의 핵심. `keep-all` 유무 대비를 실물로 | *"Your language is not Latin"* — 한글을 **사례**로 쓰고 주장을 일반화 |
| 6 | **규칙** — 상위 항목 + 각 규칙 옆 근거 1문장 | 컨셉 1 (`editorial`에서 빌림) | 동일 | 동일 |
| 7 | **설치 반복 + 에이전트 호환 목록** | — | 동일 | 동일 |
| 8 | 푸터 | — | 동일 | 동일 |
**§5가 두 판의 유일한 실질적 차이다.** 한국어판에서는 주장이고, 영어판에서는 사례다.
영어판에서 한글을 사례로 쓰는 편이 오히려 강하다 — 읽는 사람이 겪어보지 않은 문제를 구체적으로 보여주기 때문이다.
**설치 명령 노출 3회**: 히어로(§1) / 파이프라인 끝(§2) / 하단(§7). tasteskill과 Bun 양쪽에서 확인된 배치다.
---
## H. 하지 않을 것 (6단계 `design.md`에 그대로 들어간다)
### tasteskill.dev에서 가져오지 않는 것
| 항목 | 그들의 실측치 | 우리 값 |
|---|---|---|
| border-radius 어휘 | **8종** (최다 16px) | **2종** |
| `backdrop-filter` | **40개 요소** | **0개** |
| 타입 스케일 단계 | **12단계 이상** (911px 텍스트 43회) | **5단계**, 하한 16px |
| 폰트 패밀리 | 3개 (Playfair Display 7회) | **2개** + 코드용 모노 1개 |
| transition 최빈값 | **0.5s** | **200320ms** |
| 스폰서·후원자 벽 | 페이지의 **28%** | **0%** — 섹션 자체를 만들지 않는다 |
| 클릭 요소 | **77개** | 설치라는 단일 목표를 흐리지 않는 수준으로 |
| GitHub 스타를 최상단 지표로 | 78,216 | **쓰지 않는다.** 우리는 숫자가 없다. 인기 대신 **규율**을 증거로 쓴다 |
| h1 = 제품명 하나 | `Taste Skill` | 제품명 + 한 문장. 무명 제품이 이름만 두면 정보가 0인 히어로가 된다 |
| **"Anti-Slop" 명명** | 제목·설명 전반 | **이 단어를 쓰지 않는다.** 같은 말을 쓰면 즉시 아류로 읽힌다 |
| 장식 번호 | `01 Codex 02 Claude Code` | 번호 자체를 쓰지 않는다 (§E) |
### antipatterns.md에서 특히 경계할 것
`C-07`(번호 단계, 검출률 9.4%) · `D-01`/`D-02`(radius 16px 기본값) · `D-05`(글래스) · `B-06`/`H-13`(타입 단계·911px) · `B-04`(3번째 패밀리) · `C-08`(근거 없는 지표) · `D-06`(이모지 아이콘) · `B-14`(한글 폰트 미지정) · `D-09`(로고월·스폰서 벽)
---
## I. SKILL.md 하드 게이트 정합성
이 방향이 5단계에서 걸릴 수 있는 지점을 미리 처리한다. **지금 정해두지 않으면 4단계에서 반드시 위반한다.**
| 게이트 | 이 방향에서의 위험 | 지금 내리는 결정 |
|---|---|---|
| **#3** radius 3종 이상 | — | **2종**으로 확정. 토큰 밖 radius 금지 |
| **#4** 정의 없는 테마 반전 | **오프화이트 그라운드 + 다크 밴드 리듬**이 정확히 이 게이트를 건드린다 | 반전을 **토큰 규칙으로 정의**한다 — `--surface` / `--surface-inverse` 쌍을 3단계에서 만들고, **다크 밴드는 히어로와 설치 섹션 두 곳에만** 쓴다는 규칙을 함께 적는다. 섹션마다 기분대로 뒤집으면 실패다 |
| **#11** 지어낸 수치 | §C의 자기 수치 공개가 정면으로 걸린다 | 4단계까지 `{{RADIUS_COUNT}}`**placeholder**. 5단계 실측으로만 채운다 |
| **#12** 가짜 프레임 | 파이프라인 섹션에서 `<div>`**가짜 터미널·에디터 창**을 만들고 싶어진다 | **만들지 않는다.** 상태 변화는 실제 텍스트와 실제 코드 블록으로 보여준다. 크롬 장식 없음 |
| **카운트** 레이아웃 패밀리 3개 이상 (섹션 8개) | 전부 같은 세로 스택이 되기 쉽다 | 패밀리 3개 확보 — ① 중앙 정렬 히어로(§1) ② **스파인 + 좌우 교차 배치**(§2) ③ 표·격자(§3·§4·§6) |
| **카운트** eyebrow ≤ `ceil(8/3)` = 3개 | 섹션마다 작은 대문자 라벨을 붙이기 쉽다 | eyebrow **3개 이하**. 나머지 섹션은 헤드라인만으로 구분 |
| **카운트** 히어로 텍스트 요소 ≤ 4개 | 제품명 + 한 문장 + 설치 + 보조 링크 2개 = 5개가 된다 | 보조 링크 2개를 **하나의 그룹**으로 묶어 4개로 유지 |
| **preflight §1** `prefers-reduced-motion` | "전부 끄기"는 오답이다 | wipe(위치 이동)만 죽이고 **페이드와 상태 변화는 남긴다.** 덮개를 `display: none` 하고 opacity 전환은 유지 (구현은 §J-0) |
| **preflight §5-4** R2의 흔적 | Klim이 흔적 없이 사라지기 쉽다 | R2의 흔적이 남는 곳을 못박는다 — **radius 2종(1종에 가깝게)**, **타입 5단계**, **강조색 면적 극소**, **규칙 옆 근거 1문장 어법** |
---
# 3단계 — 디자인 토큰과 예산
## J. 토큰 (4단계에서 그대로 복사해 쓴다)
### J-0. 먼저 — 2단계 §E의 R3 기법을 교정한다
**게이트 #8**(`transform`/`opacity` 외의 속성을 애니메이션하는가)과 2단계에서 정한 `clip-path` wipe가 충돌한다.
**교정**: `clip-path` 대신 **덮개 요소를 `transform: translateX()` 로 밀어낸다.**
시각 효과는 동일한 좌→우 리빌이고, 게이트를 통과하며, 컴포지터 처리가 보장된다.
Codrops가 경고한 clip-path 보간 제약(같은 도형 함수·같은 점 개수)도 함께 사라진다.
```css
.reveal > .reveal__cover { /* 대상을 덮는 단색 판 */
transform: translateX(0);
animation: wipe linear both;
animation-timeline: view();
animation-range: entry 10% entry 55%; /* 2단계에서 정한 짧은 범위 */
}
@keyframes wipe { to { transform: translateX(100%); } }
@supports not (animation-timeline: view()) { .reveal__cover { display: none; } }
@media (prefers-reduced-motion: reduce) {
.reveal__cover { display: none; } /* 위치 이동만 죽인다. 페이드·상태 변화는 유지 */
}
```
---
### J-1. 타입 스케일 — 비율 **1.25**, 디스플레이는 스케일 밖
비율 1.25로 5단계를 쌓으면 최대÷본문이 **2.44배**에 그쳐 `antipatterns.md` B-05(4배 이상)를 만족할 수 없다.
**단계를 늘려 맞추지 않는다.** `tokens.md` §1대로 **디스플레이 사이즈를 스케일 밖에 따로 정의**한다.
| | 한국어판 `/` | 영어판 `/en/` |
|---|---|---|
| 본문 | 17px | 16px |
| 스케일 5단계 | 17 / 21.3 / 26.6 / 33.2 / 41.5 | 16 / 20 / 25 / 31.3 / 39 |
| **디스플레이 (스케일 밖)** | **68px** | **64px** |
| **최대÷본문** | **4.0배** ✓ | **4.0배** ✓ |
**하위 단계(캡션·라벨)를 만들지 않는다.** 한글 하한 16px을 지키면 본문 아래 단계가 설 자리가 없고,
`swiss-minimal`이 요구하는 "위계 차이를 작게, 대신 웨이트와 색으로 구분"과도 맞는다.
eyebrow는 **본문 크기 + 자간 + `--ink-muted`** 로 만든다. 두 판의 구조가 동일하게 유지되는 이득도 있다.
---
### J-2. CSS — 그대로 복사한다
```css
/* ============================================================
designpaca 소개 페이지 — 디자인 토큰
프리셋: swiss-minimal / 비율 1.25 / 강조색 1개 / radius 2종
============================================================ */
:root {
/* ---- 폰트 패밀리 ---------------------------------------- */
--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
--mono-size: 0.9375em; /* 부모 대비. 새 스케일 단계를 만들지 않는다 */
/* ---- 색: 라이트 (기본) ----------------------------------- */
--surface: #FAF9F6; /* 웜 오프화이트. 순백 아님 (A-07) */
--surface-raised: #F2F0EA;
--surface-inverse: #14161A; /* 다크 밴드. 순흑 아님 */
--ink: #16181C; /* 대비 16.88:1 */
--ink-muted: #5A5F66; /* 대비 6.11:1 */
--ink-inverse: #E9E7E2; /* 밴드 위 14.66:1 */
--ink-muted-inverse: #9AA0A6; /* 밴드 위 6.86:1 */
--line: #DFDCD4; /* 1.30:1 — 장식 구분선 전용 */
--line-inverse: #2A2E34; /* 1.33:1 — 장식 구분선 전용 */
--line-strong: var(--ink-muted); /* 입력·컨트롤 테두리. WCAG 1.4.11 (3:1) */
--accent: #0E6B63; /* 딥 틸. 대비 6.04:1 */
--accent-ink: #FFFFFF; /* 강조 위 글자. 6.36:1 */
--accent-inverse: #3FA89D; /* 밴드 위 강조. 6.30:1 */
/* ---- 형태: radius 2종 (게이트 #3) ------------------------ */
--radius-sm: 3px; /* 버튼·입력·배지 */
--radius-md: 6px; /* 카드·코드 블록 */
/* ---- 간격 ------------------------------------------------ */
--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: 8rem; /* 128 — 다크 밴드 상하. 본문 간격의 8배 */
/* ---- 모션 ------------------------------------------------ */
--dur-instant: 100ms; /* 호버·포커스 */
--dur-quick: 200ms; /* 작은 등장·퇴장 */
--dur-normal: 320ms; /* 패널·전환. 2단계 상한 */
--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);
/* bounce·elastic 없음 (E-02) */
}
/* ---- 색: 다크 테마 — 라이트와 동등하게 정의 ------------------ */
@media (prefers-color-scheme: dark) {
:root {
--surface: #14161A;
--surface-raised: #1C1F24;
--surface-inverse: #FAF9F6; /* 다크에서는 밴드가 밝아진다 */
--ink: #E9E7E2;
--ink-muted: #9AA0A6;
--ink-inverse: #16181C;
--ink-muted-inverse: #5A5F66;
--line: #2A2E34;
--line-inverse: #DFDCD4;
--line-strong: var(--ink-muted);
--accent: #3FA89D; /* 6.30:1 */
--accent-ink: #0B1A18; /* 6.21:1 */
--accent-inverse: #0E6B63;
}
}
/* ---- 타입: 한국어판 --------------------------------------- */
[lang="ko"] {
--font-sans: "Pretendard Variable", Pretendard, system-ui, sans-serif;
--step-0: 1.0625rem; /* 17 — 본문 · eyebrow · 코드 */
--step-1: 1.328rem; /* 21.3 — 리드 */
--step-2: 1.660rem; /* 26.6 — h3 */
--step-3: 2.076rem; /* 33.2 — h2 */
--step-4: 2.595rem; /* 41.5 — h1 */
--display: clamp(2.595rem, 1.6rem + 4.2vw, 4.25rem); /* → 68 */
--leading-tight: 1.15;
--leading-normal: 1.7; /* 한글은 넉넉하게 */
--measure: 33em; /* ≈ 561px. 한글 글자폭 ≈ 1em */
--tracking-display: -0.01em; /* 한글은 음수 자간을 크게 주지 않는다 */
--tracking-body: 0; /* 한글 본문 음수 자간 금지 */
--tracking-label: 0.08em;
word-break: keep-all;
overflow-wrap: break-word;
}
/* ---- 타입: 영어판 ------------------------------------------ */
[lang="en"] {
--font-sans: "Switzer", system-ui, -apple-system, sans-serif;
--step-0: 1rem; /* 16 */
--step-1: 1.25rem; /* 20 */
--step-2: 1.5625rem; /* 25 */
--step-3: 1.953rem; /* 31.3 */
--step-4: 2.441rem; /* 39 */
--display: clamp(2.441rem, 1.5rem + 4vw, 4rem); /* → 64 */
--leading-tight: 1.1;
--leading-normal: 1.55;
--measure: 65ch; /* ≈ 640px */
--tracking-display: -0.025em;
--tracking-body: 0;
--tracking-label: 0.08em;
}
/* ---- 다크 밴드: 게이트 #4가 요구하는 "규칙으로 정의된 반전" ---- */
/* 사용처는 히어로와 설치 섹션 두 곳뿐이다. 그 외 사용 금지. */
.band-inverse {
--surface: var(--surface-inverse);
--ink: var(--ink-inverse);
--ink-muted: var(--ink-muted-inverse);
--line: var(--line-inverse);
--accent: var(--accent-inverse);
background: var(--surface);
color: var(--ink);
padding-block: var(--space-8);
}
```
---
### J-3. 다크 밴드 규칙 (게이트 #4)
| 규칙 | 값 |
|---|---|
| 반전 수단 | `.band-inverse` 클래스 **하나**. 인라인 색 금지 |
| 사용 섹션 | **정확히 2곳** — 히어로(§G-1), 설치 반복(§G-7) |
| 밴드 상하 여백 | `--space-8` (128px). 일반 섹션은 `--space-7` (96px) |
| 밴드 전용 여백 토큰 | **만들지 않는다.** 기존 스케일 안에서 해결한다 (`tokens.md` §3 중간값 금지) |
---
### J-4. 성능 예산 — 이 프로젝트 확정값
기본값보다 **전 항목을 조인다.** Astro 정적 사이트이고 이미지가 거의 없으며 인터랙션이 복사 버튼과 언어 전환뿐이다.
| 항목 | 기본 | **이 프로젝트** | 근거 |
|---|---|---|---|
| 히어로까지 JS (gzip) | 150KB | **50KB** | Astro 아일랜드 최소. 복사 버튼 하나 |
| WebGL/3D 추가분 | +200KB | **0KB — three.js 를 쓰지 않는다** | 브리프에 3D 요구가 없다. R3는 CSS scroll-driven이라 JS가 0이다. `three.md`는 읽지 않는다 |
| 총 전송량 (첫 화면) | 1MB | **500KB** | 사진 없음. 폰트가 대부분 |
| 첫 인터랙션 (모바일 4G) | 3초 | **2초** | |
| LCP | 2.5초 | **2.0초** | LCP 요소는 히어로 텍스트다 |
| CLS | 0.1 | **0.05** | 유일한 위험이 폰트 스왑이다 |
| 폰트 파일 | 2개 이하 | **판당 2개** | 본문 1 + 모노 1 |
| 애니메이션 속성 | transform/opacity | **transform/opacity 만** | J-0에서 `clip-path` 를 제거해 확보했다 |
### 폰트 로딩 전략 — 최대 변수
**두 벌을 한 페이지에 로드하지 않는다.** 경로가 갈려 있으므로 Astro 레이아웃을 언어별로 나눈다.
| | 한국어판 `/` | 영어판 `/en/` |
|---|---|---|
| 본문 | Pretendard Variable — **동적 서브셋** (`unicode-range` 분할 CSS) | Switzer 가변 (라틴만) |
| 코드 | JetBrains Mono 400 (라틴 서브셋) | 동일 |
| preload | 본문 폰트 **1개만**. 모노는 코드 블록에만 쓰이므로 preload 하지 않는다 | 동일 |
| `font-display` | `swap` | `swap` |
- **한글 서브셋은 필수다.** 전체 한글 폰트는 MB 단위다. 동적 서브셋은 실제로 등장하는 유니코드 범위만 내려받는다.
- 영어판에 Pretendard를 **로드하지 않는다.** 한국어판에 Switzer를 **로드하지 않는다.**
- 실제 KB는 5단계에서 측정한다 (J-5).
---
### J-5. 자기 수치 공개 — 항목과 측정 방법 (지금 못 박는다)
**이 9개를 고정한다. 5단계에서 이 목록대로 재고, 결과가 나쁘게 나와도 그대로 싣는다.**
나중에 유리한 것만 골라 싣는 순간 §C의 리스크가 자기 홍보로 바뀐다.
| # | 공개 항목 | placeholder | 측정 방법 |
|---|---|---|---|
| 1 | radius 어휘 수 | `{{RADIUS_COUNT}}` | 빌드 결과에 `reference-method.md` §5 스크립트 → `radii` distinct 개수 |
| 2 | `backdrop-filter` 요소 수 | `{{GLASS_COUNT}}` | 같은 스크립트 `blurCount` |
| 3 | 타입 스케일 단계 수 | `{{TYPE_STEPS}}` | 같은 스크립트 `fontSizes` distinct 개수 |
| 4 | 폰트 패밀리 수 | `{{FONT_FAMILIES}}` | 같은 스크립트 `families` |
| 5 | 강조색 개수 | `{{ACCENT_COUNT}}` | 토큰 파일 grep + computed 색 tally |
| 6 | 히어로까지 JS (gzip) | `{{JS_GZIP_KB}}` | `list_network_requests` / 빌드 산출물 gzip |
| 7 | 첫 인터랙션 (모바일 4G) | `{{TTI_S}}` | Lighthouse 또는 performance trace |
| 8 | 하드 게이트 통과 | `{{GATES_PASSED}}/12` | `preflight.md` 실행 결과 |
| 9 | 슬롭 지문 grep 검출 | `{{SLOP_HITS}}` | `antipatterns.md` §9 grep 목록 |
**측정 대상은 프로덕션 빌드다** (`preflight.md` §0 — 소스만 보면 렌더된 DOM이 없어 잴 수 없다).
---
### J-6. 3단계 통과 확인
> **성능 예산 = JS 50KB(gzip) / 첫 인터랙션 2초 / three.js 미사용**
| 검사 | 결과 |
|---|---|
| 비율 하나인가 | ✓ 1.25. 디스플레이는 스케일 밖 별도 정의 |
| 최대÷본문 4배 이상 (B-05) | ✓ 두 판 모두 정확히 4.0배 |
| 폰트 2종 이하 (tokens.md §1) | ✓ 판당 본문 1 + 모노 1 |
| 강조색 하나 (게이트 #2) | ✓ `--accent` 하나. `--accent-inverse` 는 같은 색의 밴드용 변형이지 두 번째 강조가 아니다 |
| radius 3종 미만 (게이트 #3) | ✓ 2종 |
| 테마 반전이 규칙으로 정의 (게이트 #4) | ✓ `.band-inverse`, 사용처 2곳 못박음 (J-3) |
| 두 테마 동등 정의 (tokens.md §2) | ✓ 라이트·다크 전 역할 정의 |
| 대비 본문 4.5:1 / 버튼 4.5:1 (게이트 #7) | ✓ 14개 조합 전부 계산해 검증. **최저 6.04:1**, 최고 16.88:1 |
| 비텍스트 대비 3:1 (WCAG 1.4.11) | ✓ `--line`(1.30:1)은 **장식 구분선 전용**이다. 입력·컨트롤 테두리에는 `--line-strong`(= `--ink-muted`, 6.11:1)을 쓴다. 이 구분을 안 하면 4단계에서 폼 테두리가 그대로 실패한다 |
| transform/opacity 만 (게이트 #8) | ✓ J-0에서 `clip-path` 제거 |
| 한글 조판 (B-14) | ✓ `keep-all`, lh 1.7, 음수 자간 0, 하한 17px |
**4단계 인계 주의 — `layout.md`의 그리드를 그대로 복사하지 마라.**
`layout.md` §1의 예시 그리드는 `main` 컬럼이 `minmax(0, 60rem)` = **960px**인데, 여기서 정한 `--measure`
한국어 **33em(≈561px)** · 영어 **65ch(≈640px)**다. 그리드를 그대로 쓰면 본문이 measure를 훌쩍 넘겨
`layout.md` 자신의 통과 조건("본문에 `--measure`가 적용됐다")에 걸린다.
`main``minmax(0, var(--measure))` 로 바꾸고, 넓은 블록(표·코드·밴드)만 `wide`/`full` 로 내보낸다.
---
# 1단계 — 레퍼런스 조사 (아래 §2~§11)
---
## 2. 정본 도메인 확인
세 도메인을 리다이렉트 체인과 응답 본문으로 비교했다.
| 도메인 | 최종 URL | 상태 | 본문 크기 | 판정 |
|---|---|---|---|---|
| `tasteskill.com` | `tasteskill.com/` | 200 | **114 bytes** | **도메인 파킹** |
| `design-taste.com` | `design-taste.com/` | 200 | **114 bytes** | **도메인 파킹** |
| `tasteskill.dev` | `www.tasteskill.dev/` (308) | 200 | **253,145 bytes** | **정본** |
`tasteskill.com``design-taste.com` 은 **본문이 바이트 단위까지 동일**하다:
```html
<!DOCTYPE html><html><head><script>window.onload=function(){window.location.href="/lander"}</script></head></html>
```
`/lander` 로 보내는 JS 리다이렉트 한 줄뿐이다. 전형적인 파킹 도메인 랜더 패턴이며 콘텐츠가 없다.
**"HTTP 200" 은 살아있다는 뜻이 아니었다.** 상태 코드만 보고 판단했으면 엉뚱한 사이트를 참고할 뻔했다.
**정본: `https://www.tasteskill.dev/`** (Vercel 호스팅)
### 소유권 확인 근거
로컬 `design-taste-frontend/SKILL.md` 에는 어느 도메인도 적혀 있지 않아 파일만으로는 확정할 수 없다. 사이트 쪽에서 확인했다.
- 사이트의 설치 명령: `npx skills add https://github.com/Leonxlnx/taste-skill --skill "design-taste-frontend"`
**로컬 스킬의 `name:` 값(`design-taste-frontend`)을 정확히 지정한다.** 이게 결정적 근거다.
- 저장소: `github.com/Leonxlnx/taste-skill` (내비에 스타 78,216 노출)
- 후원 링크: `github.com/sponsors/Leonxlnx` — 동일 소유자
- 로컬 SKILL.md 본문 제목 `# tasteskill: Anti-Slop Frontend Skill` 과 사이트 제목 `Taste Skill | The Anti-Slop Frontend Framework for AI Agents` 일치
---
## 3. R1 · 구조 — Taste Skill — https://www.tasteskill.dev/
**업종**: AI 에이전트용 프론트엔드 스킬 — **우리와 같은 문제를 이미 푼 사이트**
**가져올 축**: 히어로 구조, 여백 리듬, 시선 흐름
### 6축 실측 (viewport 1814×851, scrollHeight 8865px)
| 축 | 관측값 | 가져갈 것 |
|---|---|---|
| **그리드** | 컨테이너 1216px / 1280px · 텍스트 컬럼 512612px · 풀블리드 1810px | 텍스트 컬럼 **512px** (본문 16px 기준 영문 약 62자) |
| **타입스케일** | 14(38회) / 12(21) / 11(19) / 15(17) / 10(16) / 12.5(13) / 16(12) / 9(8) / 72(6) / 128(5) / 18(4) / 60(4) → **12단계 이상**. 최대÷본문 = 128÷16 = 8배. h1 72px, lh 68.4px(0.95), ls 1.8px(0.025em), weight 600. 패밀리 **3개** — Manrope(104) + IBM Plex Mono(62) + Playfair Display(7) | h1 lh 0.95 / ls 0.025em 만. **단계 수와 패밀리 수는 안 가져감** |
| **컬러 역할** | 그라운드 **`#F5F4F2` 웜 오프화이트** (블록 6개, 합계 약 7,700px) · 히어로 밴드 **`#0E1011`** · 강조 **`#FF6B00` 오렌지**(배경 3회) / `#CC5400`(텍스트 4회) · 텍스트 4단계 `#0A0A0A`→lab27(≈#3C3C3C)→lab34.9(≈#4F4F4F)→lab66(≈#9E9E9E) | **오프화이트 그라운드 + 다크 밴드 리듬**, 텍스트 4단계, 강조 면적 극소 |
| **여백 리듬** | 섹션 패딩 `64/64`, `80/80`, `96/96`, `112/112`**4단계 리듬** | 그대로 채택 |
| **모션 언어** | transition-duration 0.5s(92회) / 0.3s(65) / 0.6s(42) / 0.7s(10) / 0.2s(10) / 0.15s(2) / 1s(2). **0.5s가 최다** | 안 가져감 (§5 R3에서 대체) |
| **시선 흐름** | h1 "Taste Skill"(72px, top 260) → 설명 1문단 → **설치 명령 + COPY 버튼(top 575)** → 보조 링크 2개(top 643) → 스폰서 | **설치 명령을 첫 화면 안에** 두는 배치 |
### 6축 밖의 관측 — 카피 규율 (이 사이트의 진짜 성취)
전체 본문을 정규식으로 훑은 결과다.
| 검사 | 결과 |
|---|---|
| 자기 평가 형용사 (`world-class`, `cutting-edge`, `powerful`, `stunning`, `seamless` …) | **0건** |
| 슬롭 동사 (`streamline`, `empower`, `supercharge`, `unlock`, `leverage`, `elevate`) | **0건** |
| `It's not X, it's Y` 구문 | **0건** |
| em-dash | **0개** |
| 근거 없는 지표 배너 (`10,000+`, `99.9%` 류) | **0건** |
- h1이 **제품명 하나(`Taste Skill`)**다. 헤드라인 문장으로 허세 부리지 않는다.
- h2가 전부 **짧은 평서문 + 마침표**: `Works with every agent.` `Current skills.` `What is new in v2.` `Projects built with Taste Skill.`
- 지표를 쓰되 **검증 가능한 외부 지표**만 쓴다 — 내비의 GitHub 스타 `78,216`. 자기가 만든 숫자가 아니다.
- `Projects built with Taste Skill` 섹션에 실사용 사례(Floria, Collective OS)를 붙인다.
**이 사이트는 안티슬롭을 "언어의 문제"로 풀었다.** 카피 레이어는 거의 완벽하다.
### 문제 — 형태 레이어는 풀지 않았다
같은 실측에서 나온 값들이다.
| 항목 | 관측값 | 걸리는 규칙 |
|---|---|---|
| border-radius 어휘 | **8종** — 16px(65회) / pill(42) / 18px(20) / 8px(13) / 12px(4) / 6px(2) / 24px(1) / 4px(1). **최다값이 16px** | D-01·D-02 (shadcn 기본값 영역) |
| `backdrop-filter` 적용 요소 | **40개** | D-05 글래스모피즘 전면 사용 — 실기기 FPS 1530% 하락 |
| 그라디언트 요소 | 25개 | A-02 인접 |
| 폰트 크기 단계 | **12단계 이상**, 그중 911px 텍스트가 **43회** | B-06 통제 실패 / H-13 경계 |
| 폰트 패밀리 | 3개. Playfair Display는 **7회만** 쓰임 | B-04 (2개 표준) |
| transition 최빈값 | **0.5s** (92회) | E-04 — 마이크로 인터랙션에 500ms는 느리다 |
| 스폰서·후원 영역 | top 9312649 + 80918865 ≈ **2,490px / 8,865px = 28%** | D-09 로고월과 동형 |
| 클릭 가능 요소 | **77개** (대부분 스폰서·후원자 링크) | 주의 분산 |
| 장식 번호 | `01 Codex` `02 Claude Code` `03 Cursor` `04 OpenCode` | B-09 |
**결론: 카피에서는 이겼고 형태에서는 기본값에 졌다.** 이 간극이 designpaca의 자리다.
**변형**: 폰트 크기를 **5단계**로 줄이고 하한을 **16px**로 올린다.
이유: 한국어가 주 언어다. 911px 텍스트 43회는 한글에서 성립하지 않는다(B-14·H-13). 12단계는 통제 실패이며, 우리 페이지는 tasteskill보다 정보량이 적어 5단계로 충분하다.
---
## 4. R1 판정 — tasteskill.dev vs Bun
사용자 지시가 우선순위 1위이고 도메인 동일성도 압도적이므로 **R1은 tasteskill.dev**다. 다만 축별로 어느 쪽이 우리 브리프에 맞는지는 갈린다.
| 축 | Bun | tasteskill.dev | 채택 |
|---|---|---|---|
| 문제 동일성 | JS 런타임 | **안티슬롭 스킬 = 우리와 동일** | tasteskill |
| 히어로 + 설치 배치 | h1 문장 + 설치 3회 노출 | h1 제품명 + 설치 복사버튼(첫 화면) | **tasteskill** |
| 여백 리듬 | 112128px 2단계 | **64/80/96/112 4단계** | tasteskill |
| 타입 통제 | 6단계 | 12+단계 | **Bun 방식** (단계 수만) |
| radius 통제 | 3종 | 8종 | **Bun 방식** (어휘 수만) |
| 카피 규율 | 좋음 (숫자에 조건 명시) | **완벽 (자기 평가 0)** | tasteskill |
| 증거 제시 | 벤치마크 + 측정 조건 | GitHub 스타 + 사용 사례 | **Bun 방식** |
| 성능 | 글래스 0 | 글래스 40 | **Bun 방식** |
**"참고하라"는 지시는 "베끼라"가 아니다.** 구조·여백·카피 규율은 tasteskill에서 가져오고,
**타입 단계 수·radius 어휘 수·글래스 사용은 명백히 나쁘므로 가져오지 않는다.**
Bun은 R1에서 내려 §10 부록에 남기고, 위 표의 "Bun 방식" 항목은 R1의 **변형 근거**로만 쓴다 (한 축은 한 소스에서만 — `reference-method.md` §1-4).
---
## 5. R2 · 톤 — Klim Type Foundry — https://klim.co.nz/blog/soehne-design-information/
**유지한다.** 재검토 결과 오히려 근거가 강해졌다.
**업종**: 타입 파운드리 — R1(AI 개발 도구)과 다름 ✓
**가져올 축**: 컬러 역할, 형태 언어
| 축 | 관측값 | 가져갈 것 |
|---|---|---|
| **타입스케일** | 14 / 16 / 22 / 36 / 100 → **5단계**. 최대÷본문 6.25배. h1 100px, lh 98px(0.98), ls 2px(0.02em), w700. **Söhne(그로테스크) + Martina Plantijn(세리프)** 2패밀리 | **5단계 + 2패밀리** — tasteskill의 12단계/3패밀리를 교정하는 값 |
| **컬러 역할** | 흰 `#FFFFFF`(41회) ↔ 검정 `#000000`(11회)·`#1C1C1C` 교대 / 텍스트 회색 4단계 / 강조 `#E1162B` 빨강 **5회만** | 강조 면적 극소 |
| **형태 언어** | **border-radius `2px` 단 하나** (122회) | **radius 어휘 1개** — tasteskill의 8종을 교정하는 값 |
| **시선 흐름** | h1 100px → 세리프 리드 36px → 본문 16px | 채택 |
**유지 근거**: tasteskill의 약점 3개(radius 8종, 타입 12단계, 글래스 40개)에 대해 Klim이 **정확한 반대값**을 갖고 있다 — radius 1종, 타입 5단계, 글래스 0.
R2를 바꾸면 이 교정축을 잃는다.
**6축 밖의 관측**: 홈에 h1이 없다. 로고와 견본으로 시작한다. 블로그 66편 대부분이 `Söhne design information` 같은 **설계 근거 문서**다. 제품 설명이 아니라 **왜 이렇게 만들었는지의 기록**으로 판다. 자기 평가 형용사가 없다.
**변형**: 본문 링크에 **밑줄을 되살린다**.
이유: 회색 색상차만으로 링크를 구분하는 건 색 단독 구분이라 접근성 문제이고, 개발자 대상 문서에서 식별이 약하다. D-15가 요구하는 호버 설계와도 맞물린다.
### 폰트 결정 (무료 대체)
| 원본 | 대체 | 출처 |
|---|---|---|
| Söhne (그로테스크) | **Switzer** | Fontshare, 무료 상업 |
| Martina Plantijn (세리프) | **Spectral** | Google Fonts |
| 코드·설치 명령 | **JetBrains Mono** | 기능 한정 |
| 한글 UI | **Pretendard** | SIL OFL |
| 한글 세리프 본문 | **마루 부리** | SIL OFL |
표현 패밀리 2개 + 기능 패밀리 1개(코드 한정). B-04·B-15 준수.
tasteskill의 Manrope / Playfair Display는 **가져오지 않는다** — Playfair는 가장 흔한 구글폰트 세리프다.
---
## 6. R3 · 디테일 — scroll-driven wipe
> **3단계에서 교정됨.** 아래 `clip-path` 방식은 SKILL.md 하드 게이트 #8(`transform`/`opacity` 외 애니메이션 금지)에 걸린다.
> 최종 구현은 **덮개 요소를 `transform: translateX()` 로 미는 방식**이다 → **§J-0** 참조. 시각 효과는 동일하다.
> 아래는 1단계 조사 기록으로 보존한다.
**유지한다.** tasteskill 실측이 변형 근거를 강화했다.
**출처**: Codrops `clip-path` 레퍼런스 + CSS scroll-driven animation 사양
**가져올 축**: 모션 언어 (R3는 이 축만)
| 항목 | 값 |
|---|---|
| 기법 | `animation-timeline: view()` + `clip-path: inset()` 키프레임 |
| 키프레임 | `inset(0% 60% 0% 0%)``inset(0% 0% 0% 0%)` |
| JS 비용 | **0KB** — 컴포지터 스레드 |
| 지원 | Chrome/Edge 115+, Firefox 132+, Safari 18+. 전역 약 84% (2026 중반) |
| 점진적 향상 | `@supports (animation-timeline: scroll())` |
| **보간 제약** | 초기·최종이 **같은 도형 함수 + 같은 점 개수**여야 한다. `inset()``inset()` 가능, `polygon()``inset()` 불가 |
**변형**: `animation-range`**`entry 10% entry 55%`** 로 단축하고 duration 계열을 **200320ms** 대역으로 고정.
이유: tasteskill의 transition 최빈값이 **0.5s(92회)**인데, 이 정도면 마이크로 인터랙션에서 굼뜨게 느껴진다(E-04). 우리는 그 절반 이하로 간다. 범위도 짧게 끝내 "계속 뭔가 움직이는" 인상을 피한다.
**추가 제약**: `prefers-reduced-motion: reduce` 에서 `clip-path: inset(0)` 고정 (E-06).
**글래스모피즘 0개** — tasteskill의 `backdrop-filter` 40개를 그대로 따라가면 성능 예산(첫 인터랙션 3초)이 깨진다.
---
## 7. 회색조 위계
색을 전부 제거했을 때 가장 강한 덩어리는 **h1(제품명)**, 두 번째는 **설치 명령 블록**, 세 번째는 **검사 결과 표**.
비즈니스 우선순위 [1 `npx designpaca` 실행 / 2 신뢰 획득 / 3 규칙 열람]와 **일치한다**
tasteskill이 설치 명령을 첫 화면(top 575) 안에 둔 배치를 채택했기 때문이다.
---
## 8. 안 할 것
### antipatterns.md 항목
| ID | 항목 | 이 페이지에서 왜 특히 위험한가 |
|---|---|---|
| **C-07 / B-09** | 번호 1·2·3 단계 | 파이프라인이 실제로 6단계라 가장 걸리기 쉽다. tasteskill도 `01 Codex 02 Claude Code`로 걸려 있다. **검출률 9.4%** |
| **C-08** | 근거 없는 지표 | "101개 규칙 / 250개 검증 URL"을 조건 없이 나열하면 걸린다 |
| **D-01·D-02** | radius 16px 기본값 | **tasteskill의 최다 radius가 정확히 16px다.** 참고하다 그대로 옮겨붙기 가장 쉬운 값 |
| **D-05** | 글래스모피즘 | tasteskill이 40개 요소에 쓴다. 따라가면 성능 예산이 깨진다 |
| **B-06 / H-13** | 타입 12단계, 911px | tasteskill의 43회. 한글에서는 성립 불가 |
| **B-04** | 3번째 패밀리 | tasteskill의 Playfair Display 7회. 어정쩡한 액센트 폰트 |
| **D-06** | 이모지 아이콘 | 개발자 README 관습이 넘어오기 쉽다 |
| **B-14** | 한글 폰트 미지정 | 한국어 우선 페이지의 즉시 실패 조건 |
### tasteskill 고유 — 따라 하면 아류가 되는 지점
| 항목 | 왜 우리는 안 하나 |
|---|---|
| **스폰서·후원자 벽 (페이지의 28%)** | 우리는 스폰서가 없다. 있어도 이건 제품 설명이 아니라 자금 조달 장치다. 로고월(D-09)과 같은 문제를 갖는다 |
| **GitHub 스타를 최상단 지표로** | 스타 78,216은 tasteskill의 자산이지 우리 것이 아니다. 숫자 0인 상태로 같은 자리에 두면 역효과다. **인기 대신 규율을 증거로 써야 한다** |
| **클릭 요소 77개** | 설치라는 단일 목표를 흐린다 |
| **h1 = 제품명 하나** | 이건 이름이 이미 알려진 제품의 특권이다. 무명 제품이 따라 하면 그냥 정보가 없는 히어로가 된다 |
| **"Anti-Slop" 이라는 명명 자체** | 같은 단어를 쓰면 즉시 아류로 읽힌다. 다른 언어로 같은 것을 말해야 한다 |
---
## 9. 컨셉 후보 (→ 2단계 §A에서 셋 다 통합됨)
> 사용자가 셋 중 고르는 대신 **전부 채택**했다. 아래는 통합 전 원본이며, 각 컨셉이 어느 섹션에서 살아나는지는 **2단계 §G**를 보라.
기존 A(설계 근거)·B(증거 먼저)는 tasteskill이 **이미 부분적으로 실행한 영역**이라 그대로 두면 아류가 된다. 재구성했다.
기존 C(같은 마크업 대조)는 여전히 유효하지만 단독 컨셉으로는 위험이 커서 §9-1의 한 섹션으로 흡수한다.
### 컨셉 1 — 형태까지 간다
> **"카피만 고쳐서는 슬롭이 안 없어진다. radius 8종, 글래스 40개, 폰트 12단계가 남는다."**
tasteskill이 언어 레이어에서 푼 문제를 **형태 레이어까지** 밀고 간다.
페이지 자체가 증거다 — radius 어휘 2종, 글래스 0, 타입 5단계, 폰트 2패밀리.
- **프리셋**: `editorial`
- **tasteskill과 같은 것**: 설치 명령을 첫 화면 안에 복사 버튼과 함께 / h2는 짧은 평서문 + 마침표 / 자기 평가 형용사 0 / 오프화이트 그라운드 + 다크 밴드 리듬
- **tasteskill과 다른 것**: 형태 레이어를 제품의 주장으로 삼는다. tasteskill은 형태를 말하지 않는다 — radius도 글래스도 타입 단계도 다루지 않는다. 우리는 **그 값들을 페이지에 숫자로 노출**한다
- **리스크**: 경쟁 제품의 약점을 지목하는 구조라 **저격으로 읽힐 수 있다.** 오픈소스 커뮤니티에서 반발을 산다. 대상을 명시하지 않고 "일반적인 안티슬롭 도구"로 추상화해야 하는데, 그러면 주장이 흐려진다. 이 균형이 이 컨셉의 전부다
### 컨셉 2 — 한국어로 푼다
> **"한글은 같은 px에서 더 작다. word-break 없이는 단어가 아무 데서나 잘린다. 이걸 아는 스킬이 없다."**
tasteskill을 포함해 기존 안티슬롭 도구는 전부 영어권이다. 한글 조판 규칙은 어디에도 없다.
911px 텍스트 43회는 라틴에서는 라벨이지만 **한글에서는 읽을 수 없다.** 이 사실 하나가 존재 이유가 된다.
- **프리셋**: `swiss-minimal`
- **tasteskill과 같은 것**: npx 한 줄 설치 / 에이전트 호환 목록 / 증거 중심 카피
- **tasteskill과 다른 것**: 대상 언어가 다르다. 경쟁이 아니라 **공백**이다. tasteskill을 깎을 필요 없이 "그 위에 얹는 것"으로 포지셔닝할 수 있다
- **리스크**: 시장이 작다. "한국어 전용"으로 좁혀 보이면 영어권 사용자를 잃는다. **영어 병기가 필수인데, 한국어 우선 페이지에서 영어를 병기하면 타이포 위계가 두 배로 복잡해진다** — 브리프의 "영어 병기 검토"가 여기서 결정 사항이 된다
### 컨셉 3 — 파이프라인을 판다
> **"designpaca는 규칙 목록이 아니다. 0단계부터 5단계까지 순서다."**
tasteskill은 **규칙 파일**을 판다. designpaca는 **절차**를 판다 — 브리프 게이트 → 레퍼런스 조사 → 방향 결정 → 토큰 → 구현 → 프리플라이트.
이 페이지가 그 절차를 실제로 거쳐 만들어졌다는 기록을 함께 싣는다 (이 문서가 그 1단계 산출물이다).
- **프리셋**: `anti-grid`
- **tasteskill과 같은 것**: 오픈소스 / npx 설치 / 에이전트 대상
- **tasteskill과 다른 것**: 파는 물건의 종류가 다르다. 규칙은 정적이고 절차는 시간축이 있다. 페이지 구조가 **선형 진행**을 갖는다는 점에서 레이아웃부터 갈린다
- **리스크**: 6단계를 시각화하려는 순간 **C-07(번호 매긴 1·2·3 섹션, 검출률 9.4%)에 정면으로 걸린다.** 이 컨셉은 자기 금지 목록과 가장 크게 충돌한다. 번호 없이 순서를 표현하는 방법을 먼저 찾지 못하면 착수하면 안 된다
### 추천
**컨셉 2를 뼈대로, 컨셉 1을 근거로 얹는 조합.**
컨셉 2는 tasteskill과 경쟁하지 않고 공백을 메우므로 저격 리스크가 없다. 컨셉 1의 형태 레이어 주장은 "왜 한글 조판만이 아니라 전반이 다른가"의 답으로 자연스럽게 들어간다.
컨셉 3은 C-07 문제를 푼 뒤에 재검토한다.
---
## 10. 부록 — 기존 조사 (R1 = Bun, 2026-08-20 1차)
R1에서 내렸지만 §4의 판정 근거이므로 수치를 보존한다.
### Bun — https://bun.sh/ 6축 실측 (viewport 1814×851)
| 축 | 관측값 |
|---|---|
| 그리드 | 컨테이너 1136px (뷰포트의 63%) / 텍스트 컬럼 750798px / 벤치마크 블록 1216px |
| 타입스케일 | 13.5 / 14 / 15 / 16 / 68 / 76 → **6단계**. 최대÷본문 5.0배. h1 68px, lh 62.56px(0.92), ls 1.36px(0.02em), w800. 패밀리 2개 (Archivo + Martian Mono) |
| 컬러 역할 | 배경 `#0D0A0C` / 표면 `rgba(234,234,232,.06)` / 텍스트 3단계 `#EAEAE8`·`#A8A8A5`·`#80807E` / 강조 `#FF2E97` 마젠타 |
| 여백 리듬 | 섹션 패딩 `112/112`, `64/112`, `0/128` |
| 모션 언어 | 미관측 |
| 시선 흐름 | h1 → 설치 명령 → 벤치마크. 설치 명령 **3회** 노출 |
| radius | **3종** — 9999px(116회) / 3px(68) / 4px(19) |
**6축 밖의 관측**: h2가 전부 시나리오 문장(`Bundling 10 copies of three.js`, `Try it on the repo you have open right now.`). 모든 숫자에 비교 대상과 조건이 붙는다(269ms vs 495ms vs 572ms / `171,127 lines / 2,104 files`).
**이 조사가 만든 결론**: 다크 배경인데도 슬롭 항목을 거의 전부 회피한다 → **"다크가 슬롭이 아니라 기본값이 슬롭이다."** 이 문장은 `antipatterns.md` §1 도입부에 반영됐다.
### 폐기한 컨셉 A / B / C
| 컨셉 | 폐기 사유 |
|---|---|
| A. 설계 근거를 파는 페이지 | tasteskill이 이미 카피 규율로 부분 실행. 그대로 가면 아류 → 컨셉 1로 재구성 |
| B. 증거 먼저 | tasteskill의 GitHub 스타 + 사용 사례가 같은 자리. 우리는 숫자 0이라 역효과 → 컨셉 1의 "형태 수치 노출"로 대체 |
| C. 같은 마크업, 다른 판단 | 단독 컨셉으로는 before를 잘 만들면 설득 실패 / 못 만들면 스트로맨. 컨셉 1의 한 섹션으로 흡수 |
---
## 11. `reference-method.md` 실사용 피드백 (2차)
1차에서 고친 4건(경로 C 승격 / 6축 밖의 관측 / slug 추측 금지 / R3 예외)은 이번 실행에서 **전부 실제로 쓰였다.**
특히 "경로 C를 안 거치면 4축이 빈칸"이 다시 확인됐다 — radius 8종, 글래스 40개, 폰트 12단계는 WebFetch로는 절대 안 나온다. 이 세 값이 이번 판정의 핵심 근거였다.
**이번에 발견한 새 결함 1건**
| 문제 | 조치 |
|---|---|
| **§3 절차가 "원본 사이트 URL을 확보한다"까지만 규정하고, 그 URL이 진짜 정본인지 검증하는 단계가 없다.** `tasteskill.com`은 HTTP 200이지만 114바이트 파킹 페이지였다. 상태 코드만 보고 갔으면 조사 전체가 어긋났다 | **수정함** — §3에 정본 검증 단계 추가 |
> 근거: research/references/02-methodology.md, 04-ai-slop-signatures.md (조사일 2026-08-20)
> 실측: www.tasteskill.dev, klim.co.nz, bun.sh computed style 추출 (2026-08-20)