release: v0.11.0
This commit is contained in:
parent
3c39a1731d
commit
45ba92ea82
45 changed files with 1459 additions and 1887 deletions
|
|
@ -1,5 +1,11 @@
|
|||
# designpaca
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 40개 근거의 종류·적용 범위·한계를 분리한 ledger와 불확실성 라우팅, 구도·타입·이미지·스타일 가이드, 규범 적합성과 취향·과업 평가의 구분, 적용 가능한 게이트 계약을 번들에 반영했다.
|
||||
|
||||
## 0.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "designpaca",
|
||||
"version": "0.10.0",
|
||||
"version": "0.11.0",
|
||||
"description": "웹 디자인 파이프라인 스킬 — Claude Code · Codex · Cursor 에 한 줄로 설치한다",
|
||||
"keywords": [
|
||||
"design",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
# @designpaca/core
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 40개 근거의 종류·적용 범위·한계를 분리한 ledger와 불확실성 라우팅, 구도·타입·이미지·스타일 가이드, 규범 적합성과 취향·과업 평가의 구분, 적용 가능한 게이트 계약을 동기화했다.
|
||||
|
||||
## 0.10.0
|
||||
|
||||
## 0.9.2
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@designpaca/core",
|
||||
"version": "0.10.0",
|
||||
"version": "0.11.0",
|
||||
"private": true,
|
||||
"description": "designpaca 설치 엔진 — 타깃 어댑터, 매니페스트, 드리프트 감지",
|
||||
"type": "module",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,15 @@
|
|||
# CHANGELOG
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 40개 근거의 종류·적용 범위·한계를 분리한 ledger와, 판단이 애매할 때 불확실성에 맞춰 참조 문서를 여는 라우팅을 추가했다. 구도·타입·이미지·스타일 가이드, 규범 적합성과 취향·과업 평가의 구분, 적용 가능한 게이트 계약도 정비했다.
|
||||
|
||||
- 초광폭을 별도 레이아웃 상태로 취급하도록 1920·2560px 실렌더 매트릭스, 읽는 `--measure`와 넓은 정보 표면의 분리, 컨트롤·입력·표 셀의 실제 인셋/겹침 검사를 추가했다. 8 CSS px 인셋은 WCAG 수치가 아니라 프로젝트 품질 기본값으로 명시했다.
|
||||
- CSS Color 4 `color(srgb …)`·알파 합성과 sr-only/aria-hidden/overlay의 가시 텍스트 판정을 감사 하니스 규칙으로 승격했다. UI가 아니라 측정기가 틀린 경우도 RED fixture에서 먼저 재현하도록 한다.
|
||||
- 근거는 W3C WCAG, W3C Tables Tutorial, Apple HIG Layout/Text Fields, Nielsen Norman Group의 폼 여백 연구를 반영했다.
|
||||
|
||||
## 0.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@ description: "웹 디자인 전 과정을 끌고 가는 파이프라인 스킬.
|
|||
|
||||
1. **레퍼런스 없이 시작하지 않는다.** 전체 경로에서 1단계를 건너뛴 디자인은 5단계에서 실패 처리한다. 연장·국소 경로는 `design.md` 가 그 자리를 대신한다 — 그것도 없이 건너뛰면 실패다.
|
||||
2. **모든 시각적 결정에는 브리프로 소급되는 이유가 있어야 한다.** "보통 이렇게 한다"는 이유가 아니다.
|
||||
3. **화려함은 4순위다.** Awwwards 배점이 Design 40 / Usability 30 / Creativity 20 / Content 10이다. 3D를 얹는 것보다 타입 스케일을 정돈하는 게 결과에 두 배 유효하다.
|
||||
4. **대담함은 한 곳에만.** 리스크는 하나다. 나머지는 조용히 받쳐준다. 두 곳에서 소리치면 둘 다 죽는다.
|
||||
3. **화려함만으로 통과하지 않는다.** Awwwards의 공개 평가 비중은 Design 40 / Usability 30 / Creativity 20 / Content 10이다. 이 비중은 해당 어워드의 심사 틀일 뿐, 제품 성과나 특정 기법의 효과를 보장하지 않는다. 출처와 적용 조건은 `references/evidence-ledger.md`에 남긴다.
|
||||
4. **대담함은 의도와 검증을 같이 가진다.** 강한 선택을 채택하면 어떤 사용 과업·브랜드 목표를 돕는지, 어느 화면에서 어떻게 확인할지 적는다. 리스크의 개수는 보편 규칙이 아니라 브리프·표면 밀도·렌더 결과로 판단한다.
|
||||
5. **성능 예산을 넘기면 그 이펙트는 채택하지 않는다.** 예산은 3단계에서 정하고 5단계에서 검증한다. 데모·포트폴리오 브리프면 예산을 올려도 되지만 **올렸다고 말해야 한다**.
|
||||
6. **완료의 정의는 게이트 통과다(자율 검증 폐쇄 루프).** 5단계에서 `tools/design-gate.mjs` 를 프로젝트에 심어 돌리고, 실패 항목이 있으면 4단계로 돌아가 고치고 **전체를 재실행**한다. 게이트 없이 6단계로 넘어가지 않는다. 사용자를 QA 로 쓰지 않는다 — 검증은 기본 내장, 사용자 피드백은 보조다. 상세는 `references/audit-gate.md`. **게이트는 계측이고 계측엔 공백이 있다**(왼쪽 인셋·시각적 무게는 오버플로 검사를 통과한다). 사용자 보고가 오면 방어하지 말라 — 스크린샷을 픽셀 판정으로 해부해 원인을 수치화하고, 그 검사를 게이트에 추가해 재발을 막는다(하니스 규칙 15~17).
|
||||
6. **완료는 기능·프로젝트 계약·렌더 시각 평가가 함께 확인된 상태다(자율 검증 폐쇄 루프).** 5단계에서 변경 영향 범위에 맞는 자동 검사와 실제 렌더 평가를 수행한다. 실패 항목이 있으면 4단계로 돌아가 고치고, 고친 영역과 그에 연결된 회귀 위험을 다시 검사한다. 사용자를 QA 로 쓰지 않는다 — 검증은 기본 내장, 사용자 피드백은 보조다. 상세는 `references/audit-gate.md`. **게이트는 계측이고 계측엔 공백이 있다**(왼쪽 인셋·시각적 무게는 오버플로 검사를 통과한다). 사용자 보고가 오면 방어하지 말라 — 스크린샷을 픽셀 판정으로 해부해 원인을 수치화하고, 그 검사를 게이트에 추가해 재발을 막는다(하니스 규칙 15~17).
|
||||
7. **OS·플랫폼 관습은 조사 없이 바꾸지 않는다.** 내비 구조·뒤로가기·시트·safe area·터치 타깃 같은 관습은 사용자가 이미 OS 전체에서 배운 것이다. "웹에서는 그랬다"를 폰에 옮기면 백 키가 앱을 종료하는 웹앱이 된다(실측 사고). 바꾸기 전에 HIG·M3·NN/g 에서 근거를 찾고, 모바일 앱 수준 브리프면 `references/mobile-app-ux.md` 를 구현 전에 읽는다.
|
||||
8. **언어와 문화권은 컴퓨터 로케일을 기본값으로 삼는다.** 새로 쓰는 UI 카피·메타데이터·빈 상태·오류 문구·장식 텍스트·이미지 안의 글자는 OS 로케일의 언어로 만든다. 영어는 기술 용어·국제 브랜드·짧은 보조 표기처럼 필요한 범위에서만 허용한다. 그 밖의 언어·문자(한국어 로케일에서는 한자·중국어·일본어 포함)와 이를 흉내 낸 인장·세로쓰기·서예·동아시아 이국화 장식은 사용자가 명시적으로 요청하거나 원본 브랜드 자산으로 제공하지 않는 한 만들지 않는다. 원본에 있는 고유명사·인용문은 임의로 고치지 않되, 에이전트가 새 레이블로 증식시키지 않는다.
|
||||
|
||||
**접근성은 예외다. 이것만은 협상하지 않는다.** 키보드·포커스·대비·`prefers-reduced-motion`은 어떤 이펙트보다, 어떤 브리프보다 우선한다. 픽셀은 왜곡해도 DOM은 살린다.
|
||||
**판정 위계를 섞지 않는다.** (1) WCAG·키보드·포커스·대비·감소 모션·진실성처럼 규범 또는 기능에 근거한 항목은 하드 게이트다. (2) 프로젝트의 브리프·`design.md`·토큰·성능 예산은 그 프로젝트의 계약이다. (3) 색·radius·정렬·레이아웃 반복·마퀴·제목 줄 수 같은 스타일 휴리스틱은 관찰 후보일 뿐이다. 후보는 맥락 적합성과 실제 렌더를 보고 채택·수정·유지한다. 픽셀은 왜곡해도 DOM은 살린다.
|
||||
|
||||
## 파이프라인
|
||||
|
||||
|
|
@ -48,11 +48,25 @@ description: "웹 디자인 전 과정을 끌고 가는 파이프라인 스킬.
|
|||
|
||||
참조 문서는 **해당 단계에 들어갈 때 읽는다.** 처음부터 전부 읽지 마라 — 컨텍스트 낭비다.
|
||||
|
||||
### 불확실성 라우팅
|
||||
|
||||
결정이 애매할 때는 감으로 규칙을 더 만들지 말고, 아래에서 **필요한 문서만** 연다. 읽은 근거는 프로젝트의 `design.md` 또는 evidence 기록에 `질문 → 근거/적용 범위 → 결정 → 렌더·과업 검증`으로 남긴다.
|
||||
|
||||
| 판단 질문 | 읽을 문서 | 꺼내 쓸 항목 / 남길 결정 |
|
||||
|---|---|---|
|
||||
| 무엇을 먼저 보이게 하고, 어떤 구도·이미지·크롭이 과업을 돕는가? | `references/art-direction.md` | 콘텐츠 우선순위, 시선·여백·이미지 역할, 크롭 비교와 선택 이유 |
|
||||
| 이 원칙이 보편 규범인가, 특정 사례·실무 지침인가? | `references/design-foundations.md` + `references/evidence-ledger.md` | 주장 종류(원론·규범·실무·사례·전망·서지), 출처의 조건과 적용 여부 |
|
||||
| 이 브리프에 맞는 시각 언어와 피해야 할 관습은 무엇인가? | `references/style-playbook.md` | 스타일의 표현 수단·주의점, 브리프에 맞춘 변형 |
|
||||
| 실제 언어·글꼴·숫자에서 읽히는가? | `references/typography.md` | 실제 카피 proof sheet, 폰트·폭·행간·폴백 결정 |
|
||||
| 무엇을 어떤 범위까지 검사하고 완료라 할 수 있는가? | `references/preflight.md` + `references/audit-gate.md` | 기능·접근성 검사, 같은 조건의 렌더 평가, 영향 범위 |
|
||||
|
||||
자료가 부족하거나 오래됐거나 출처끼리 충돌하면, 권위 있는 원문·공식 규범·해당 분야의 사례를 필요한 범위에서 추가 조사한다. 출처를 많이 모으는 대신 **주장, 적용 범위, 반대 근거, 검증 방법**을 기록한다. 출처와 프로젝트 계약이 충돌하면 기존 우선순위(`사용자 지시 → design.md → 기존 토큰·코드 → 기본값`)를 적용하고, 규범·기능 요구의 적용 수준과 예외를 확인한다. 기능·접근성 요구와 계약이 충돌하면 양쪽을 충족할 대안을 먼저 찾고, 해소되지 않으면 충돌을 명시한다. 취향 휴리스틱으로 필수 요구를 덮지 않는다. 이 과정은 현재 프로젝트의 결정에 쓰는 것이며, 설치된 스킬 자체를 매번 고치는 지시는 아니다.
|
||||
|
||||
---
|
||||
|
||||
### 0단계 — 브리프 게이트
|
||||
|
||||
**먼저 프로젝트 루트에 `design.md` 가 있는지 확인한다.** (프로젝트 루트 = 패키지 매니저 설정 파일이 있는 디렉터리. 모노레포면 **작업 대상 패키지의 루트**를 쓰고, 저장소 루트에도 있으면 둘 다 읽되 가까운 쪽이 이긴다) 있으면 읽고, 그 결정을 이 스킬의 기본값보다 우선한다. 같은 프로젝트를 두 번째로 작업할 때 지난번과 다른 디자인이 나오면 그건 실패다.
|
||||
**먼저 프로젝트 루트에 `design.md` 가 있는지 확인한다.** (프로젝트 루트 = 패키지 매니저 설정 파일이 있는 디렉터리. 모노레포면 **작업 대상 패키지의 루트**를 쓰고, 저장소 루트에도 있으면 둘 다 읽되 가까운 쪽이 이긴다) 있으면 읽고, 그 결정을 이 스킬의 기본값보다 우선한다. 같은 프로젝트는 기존 계약과 사용자의 기대를 유지한다. 다만 사용자가 명시적으로 리디자인을 요청했거나 감사 결과가 방향 변경을 뒷받침하면, 바꾸는 이유·보존할 자산·검증 조건을 기록하고 새 방향으로 진행한다.
|
||||
|
||||
브리프를 세 줄로 압축한다. 세 줄을 못 쓰면 아직 작업을 시작할 수 없다.
|
||||
|
||||
|
|
@ -129,46 +143,35 @@ description: "웹 디자인 전 과정을 끌고 가는 파이프라인 스킬.
|
|||
결과를 크게 바꾸는 축을 골라 **선택지와 함께** 한 화면에 낸다. 각 선택지에는
|
||||
"이걸 고르면 무엇이 달라지는지"를 적어라. 고르는 사람이 결과를 예상할 수 있어야 한다.
|
||||
|
||||
거의 모든 브리프에서 다음이 결과를 가장 크게 바꾼다. **위 넷은 거의 항상 묻는다.**
|
||||
브리프·기존 코드·브랜드 자산에서 답을 확인할 수 없고 결과를 크게 바꿀 때만 아래 항목을 묻는다. 이미 알려진 사실을 다시 묻지 않는다.
|
||||
|
||||
| 축 | 무엇이 달라지는가 | 안 물으면 |
|
||||
|---|---|---|
|
||||
| **업종·성격** | 정보 구조 전체. 같은 "꽃집"도 구독형과 하이엔드 스튜디오는 다른 사이트다 | 카테고리 평균이 나온다 |
|
||||
| **목표 행동** | CTA 의 수와 위치, 어떤 섹션이 필요하고 어떤 게 군더더기인지 | CTA 가 넷이 되고 페이지가 무너진다 |
|
||||
| **톤** | 2단계 프리셋과 감수할 리스크가 여기서 결정된다 | 내 기본 미학이 나온다 |
|
||||
| **고유명사·실제 값** | 이름·지역·가격·연락처 | 지어내면 하드 게이트 11 |
|
||||
| **고유명사·실제 값** | 이름·지역·가격·연락처 | 지어내면 규범·기능 하드 게이트 실패 |
|
||||
| **기존 브랜드 색·로고** | 있으면 3단계 팔레트가 **거기서 시작한다** | 있는 자산을 무시하고 새로 만든다 |
|
||||
| **좁은 화면의 내비** | 항목 5개 이상이면 구조가 달라진다 | 넓은 화면 메뉴를 그대로 접어 두 줄이 된다 |
|
||||
| **좁은 화면의 내비** | 라벨 길이·번역·확대·폭·우선순위·깊이가 구조를 바꾼다 | 넓은 화면 메뉴를 그대로 접어 두 줄이 된다 |
|
||||
|
||||
### 색은 반드시 확인한다 — 없다는 답도 답이다
|
||||
### 색은 이미 알려진 자산부터 확인한다
|
||||
|
||||
**"브랜드 색이 있나요"** 는 결과를 되돌릴 수 없게 바꾸는 질문이다.
|
||||
이미 로고·간판·패키지에 색이 있는데 사이트만 다른 색이면, 잘 만들어도 **틀린 것**이다.
|
||||
로고·간판·패키지·기존 토큰에 브랜드 색이 있으면 그것부터 확인한다. 없는지 또는 피할 색이 필요한지 이미 브리프·자산에서 알 수 있으면 재질문하지 않는다. 정보가 없고 색 선택이 브랜드 정합성을 크게 바꾸는 경우에만 한 번에 묻는다.
|
||||
|
||||
- **있다** → 3단계에서 그 색이 강조색이고, 레퍼런스는 그 색과 어울리는 곳으로 고른다
|
||||
- **없다·상관없다** → 레퍼런스 실측에서 뽑는다. 이때도 **어떤 색을 피해야 하는지**는 물어라
|
||||
(경쟁사가 쓰는 색, 대표가 싫어하는 색은 사용자만 안다)
|
||||
- **기존 색이 있다** → 역할·대비·면적을 검토해 토큰에 반영한다. 반드시 강조색일 필요는 없다.
|
||||
- **없다·상관없다** → 레퍼런스와 과업에서 색 역할을 정한다. 피할 색이 결과를 좌우하고 확인할 근거가 없을 때만 묻는다.
|
||||
|
||||
> 실측 사례: 꽃집 작업에서 색을 묻지 않고 레퍼런스 세 곳의 배경 평균(`#F8F6F0`)으로 정했다.
|
||||
> 결과는 좋았지만 **운이 좋았던 것**이다. 브랜드 색이 있었다면 그걸 무시한 작업이 된다.
|
||||
|
||||
### 좁은 화면의 내비를 미리 정한다
|
||||
|
||||
내비 항목 수는 0단계에서 이미 정해진다(= 섹션 수). **구현 단계에서 발견하면 늦다.**
|
||||
내비 구조는 항목 수만으로 정하지 않는다. 실제 라벨과 번역 길이, 글꼴 확대, 최소 화면 폭, 가장 중요한 이동 경로, 메뉴 깊이, 키보드 포커스 순서를 함께 본다. 한 줄·가로 스크롤·하단 바·여는 메뉴 중에서 그 조건에서 과업을 가장 덜 방해하는 방식을 고르고, 실제 좁은 화면과 확대 상태에서 검사한다.
|
||||
|
||||
| 항목 수 | 좁은 화면 처리 | 비용 |
|
||||
|---|---|---|
|
||||
| 2~4개 | 그대로 한 줄. 자간을 줄이고 `justify-content: space-between` | 0 |
|
||||
| 5~6개 | 가로 스크롤 줄 또는 하단 고정 바 | 낮음 |
|
||||
| 7개 이상 | **여는 메뉴**(햄버거) | `<details>` 로 JS 0바이트 |
|
||||
|
||||
**햄버거를 기본값으로 삼지 마라.** 항목이 넷인데 햄버거를 쓰면 한 번의 탭을 공짜로 뺏는 것이다.
|
||||
반대로 여섯 개를 한 줄에 욱여넣으면 접힌다 — 실측에서 링크가 두 줄(top 46/77)에 걸렸다.
|
||||
|
||||
여는 메뉴가 필요하다고 판단되면 `references/layout.md` 의 **모바일 내비** 절을 본다.
|
||||
여는 메뉴가 필요하다고 판단되면 `references/layout.md` 의 **모바일 내비** 절을 본다. 항목이 적어도 긴 번역·깊은 계층이면 여는 메뉴가 맞을 수 있고, 항목이 많아도 우선순위가 뚜렷하면 일부를 분리할 수 있다.
|
||||
|
||||
넷을 `multiSelect` 로 낼지 단일 선택으로 낼지 구분해라 — **목표 행동은 대개 복수**고,
|
||||
톤과 성격은 하나여야 한다. 둘 다 고르면 방향이 서지 않는다.
|
||||
톤과 성격에는 주된 방향을 두되, 브리프가 요구하면 서로 보완하는 속성을 함께 쓸 수 있다. 어떤 속성이 위계를 이끄는지 기록한다.
|
||||
|
||||
**물어도 되는 것과 물으면 안 되는 것**
|
||||
|
||||
|
|
@ -192,15 +195,17 @@ description: "웹 디자인 전 과정을 끌고 가는 파이프라인 스킬.
|
|||
|
||||
이 단계가 designpaca의 심장이다. 머릿속 기본값이 아니라 **실제로 존재하는 사이트**에서 시작한다. 연장·국소 경로는 0단계에서 이미 이 단계를 건너뛰기로 정했고, 그 근거는 `design.md` 다.
|
||||
|
||||
레퍼런스 **3개**를 서로 **다른 층위**에서 고른다:
|
||||
전체 경로에서는 `references/design-foundations.md`를 읽어 이론을 브리프의 사용 과업·제약으로 번역하고, `references/evidence-ledger.md`에서 출처 ID와 기록 형식을 확인한다. 조사 결과는 패키지 문서에 쓰지 말고 프로젝트의 `design.md` 또는 프로젝트 evidence 기록에 남긴다.
|
||||
|
||||
레퍼런스 슬롯은 구조·톤·디테일을 **분리해 검토하는 장치**다. 새 화면에는 보통 아래 세 슬롯을 채우되, 세 개를 찾았다는 사실이 좋은 합성이나 결과를 보증하지 않는다. 브리프에 맞지 않는 슬롯은 비워 둔 이유와 대체 근거를 남긴다:
|
||||
|
||||
| 슬롯 | 무엇 | 규칙 |
|
||||
|---|---|---|
|
||||
| **R1 — 구조** | 같은 업종/목적의 사이트 | 정보 구조와 흐름을 가져온다 |
|
||||
| **R2 — 톤** | **반드시 다른 업종** | 분위기·재질·타이포 감각을 가져온다 |
|
||||
| **R2 — 톤** | 다른 업종 또는 매체를 우선 검토 | 분위기·재질·타이포 감각을 가져온다 |
|
||||
| **R3 — 디테일** | 어디서든 | 하나의 구체적 기법(모션·타입·인터랙션) |
|
||||
|
||||
R1과 R2를 같은 업종에서 고르면 결과는 그 업종의 평균이 된다. SaaS 구조 + SaaS 톤 = 또 하나의 SaaS 슬롭이다.
|
||||
R1과 R2의 업종이 같아도 평균을 무비판적으로 복제하지 말고, 가져올 원칙·적용 조건·실제 렌더 검증을 분리해 기록한다.
|
||||
|
||||
**목표 시장이 다른 레퍼런스는 자동으로 중립이 되지 않는다.** 단위·용어·문의 방식·사진 조도·신뢰 표지는 문화권의 일부다. 시장 적합성이 중요한 브리프는 R1을 같은 목표 시장에서 우선 찾고, R2는 **같은 문화권의 다른 업종**을 우선한다. 다른 문화권의 R3는 구현 기법 하나만 가져온다. 상세 계약은 `reference-method.md`와, 가상·AI·규제 쇼케이스면 `trustworthy-showcases.md`를 따른다.
|
||||
|
||||
|
|
@ -209,23 +214,24 @@ R1과 R2를 같은 업종에서 고르면 결과는 그 업종의 평균이 된
|
|||
|
||||
**갤러리 목록 페이지가 아니라 원본 사이트를 열어라.** 이미지를 볼 수 없어도 구조는 읽을 수 있다.
|
||||
|
||||
**403·404·타임아웃을 두 번 만나면 텍스트 페처를 버리고 브라우저를 띄워라.**
|
||||
좋은 레퍼런스일수록 봇을 막는다. 대체 갤러리를 찾아 헤매는 것은 시간 낭비이고,
|
||||
찾아낸 대체 소스는 애초에 보려던 것보다 나쁘다. `designpaca tools` 로 설치된
|
||||
**403·404·타임아웃을 두 번 만나면 텍스트 페처만 반복하지 말고 브라우저 또는 다른 정본 출처를 검토한다.**
|
||||
대체 출처는 처음 후보보다 자동으로 열등하지 않다. 출처가 제공하는 관찰 범위·신뢰성·브리프 적합성을 비교해 고른다. `designpaca tools` 로 설치된
|
||||
headed 브라우저가 있으면 스크린샷과 실측값을 바로 받는다 — 방법은 `galleries.md` §5.
|
||||
|
||||
> 통과 조건: R1/R2/R3 각각의 URL과, 그것에서 **무엇을 가져올지** 한 줄씩. 형식은 `reference-method.md` 참조.
|
||||
> 통과 조건: 사용한 슬롯마다 URL·출처 ID·원칙/조건·관찰·결정·검증 계획이 있다. 형식은 `reference-method.md`와 `evidence-ledger.md`를 따른다.
|
||||
|
||||
---
|
||||
|
||||
### 2단계 — 방향 결정
|
||||
|
||||
레퍼런스 3개를 하나의 방향으로 합성한다. 베끼지 않는다. **축을 정하고 그 축 위에서 결정한다.**
|
||||
사용한 레퍼런스 슬롯을 하나의 방향으로 번역한다. 베끼지 않는다. **축을 정하고 그 축 위에서 결정한다.**
|
||||
|
||||
이 단계에서 `references/style-playbook.md`를 읽어 선택한 스타일의 표현 수단·주의점·적용 조건을 검토한다. 이론이나 스타일 이름은 결론이 아니므로, `design.md` 또는 프로젝트 evidence 기록에 출처 ID → 원칙/조건 → 관찰 → 결정 → 검증 계획을 남긴다.
|
||||
|
||||
정해야 할 것:
|
||||
- **한 문장 컨셉** — 이 사이트가 주는 인상을 한 문장으로. ("고급 잡지의 여백", "계기판처럼 정확한", "밤의 스튜디오")
|
||||
- **미학 프리셋** — 아래에서 고르거나, 브리프가 요구하면 새로 정의한다
|
||||
- **감수할 리스크 하나** — 정당화할 수 있는 과감한 선택 하나. 없으면 그 디자인은 안전하고 잊힌다
|
||||
- **표현 리스크** — 과감한 선택을 쓴다면 왜 이 과업에 맞는지와 실제 렌더 검증 방법. 리스크가 없다는 결정도 허용하되 이유를 기록한다
|
||||
- **표면 다이얼** — 랜딩·관리자·가맹처럼 과업이 다른 화면이 함께 있으면 각 표면의 표현성·정보 밀도·모션·증거 노출을 0~3으로 따로 적는다. 공통 토큰은 공유하되 과업 밀도까지 같게 만들지 않는다
|
||||
|
||||
| 프리셋 | 한 줄 | 언제 |
|
||||
|
|
@ -238,7 +244,7 @@ headed 브라우저가 있으면 스크린샷과 실측값을 바로 받는다
|
|||
|
||||
고른 프리셋 파일 **하나만** 읽어라. 다섯 다 읽지 마라. 고르는 기준은 `references/presets/README.md`.
|
||||
|
||||
> 통과 조건: 한 문장 컨셉 + 프리셋 + 리스크 하나가 적혔다.
|
||||
> 통과 조건: 한 문장 컨셉 + 프리셋 + 표현 리스크의 채택/비채택 근거가 적혔다.
|
||||
> **연장 경로는 이 단계를 돌지 않는다.** `design.md` 의 컨셉·프리셋·리스크를 그대로 이어받는다. 바꾸고 싶으면 전체 경로로 올린다.
|
||||
|
||||
---
|
||||
|
|
@ -253,7 +259,7 @@ headed 브라우저가 있으면 스크린샷과 실측값을 바로 받는다
|
|||
|
||||
**성능 예산도 여기서 정한다.** 나중에 정하면 이미 늦는다. 전체 표는 `references/tokens.md` §5 하나뿐이다 — 다른 문서에 예산 표를 만들지 마라.
|
||||
|
||||
기본선: 히어로까지 JS **150KB(gzip)** / 첫 인터랙션 **3초** / 애니메이션은 `transform`·`opacity` 만.
|
||||
기본선: 히어로까지 JS **150KB(gzip)** / 첫 인터랙션 **3초**. `transform`·`opacity`는 저비용 기본 선택이다. 다른 속성 또는 스크롤 기반 로직은 자동 금지가 아니라, 측정한 비용·입력 간섭·감소 모션 경로·프로젝트 예산을 기록하고 실제 기기/브라우저에서 검증한다.
|
||||
브리프가 데모·포트폴리오라면 예산을 올려도 된다. **올린다는 사실과 이유를 명시해라.**
|
||||
|
||||
> 통과 조건: 토큰이 실제 값으로 적혔고, 성능 예산이 숫자로 정해졌다.
|
||||
|
|
@ -266,9 +272,9 @@ headed 브라우저가 있으면 스크린샷과 실측값을 바로 받는다
|
|||
|
||||
**4-0. 이미지 조달** → `references/images.md`
|
||||
자리를 만들기 전에 **무엇을 실을지** 정한다. 나중에 채우면 비율이 안 맞아 레이아웃을 다시 짠다.
|
||||
사용자가 준 사진이 있으면 무조건 그것이고, 없으면 **codex 가 설치돼 있는지 확인해 생성**한다.
|
||||
생성했으면 `design.md` 에 생성물이라고 적는다 — 나중에 실제 사진으로 바꿀 사람이 알아야 한다.
|
||||
히어로·증거 컷·모바일 히어로를 각각 슬롯으로 적은 **이미지 바이블**을 먼저 만든다. 데스크톱 크롭에서 핵심 피사체가 폴드 아래로 밀리면 모바일은 별도 원본을 만든다.
|
||||
사용자가 준 사진·기존 브랜드 자산·직접 제작·라이선스 가능한 자료·생성물 중에서, 이미지 슬롯의 역할과 품질·권리·진실성에 맞는 것을 고른다. 자산이 없다는 사실만으로 자동 생성하지 않는다.
|
||||
생성물을 쓰면 `design.md` 에 생성물과 용도를 적는다 — 나중에 실제 사진으로 바꿀 사람이 알아야 한다.
|
||||
히어로·증거 컷·모바일 히어로를 각각 슬롯으로 적은 **이미지 바이블**을 먼저 만든다. 슬롯별 실제 크롭에서 핵심 피사체와 맥락이 보존되는지 확인하고, 같은 원본의 초점 조정으로 해결되지 않을 때만 별도 자산을 고른다.
|
||||
싣기 전에 반드시 줄인다(실측: 10.1MB → 603KB).
|
||||
|
||||
**4-1. 레이아웃과 타이포그래피** → `references/layout.md` (+ 폰트 적용은 `references/typography.md` §5, §6)
|
||||
|
|
@ -285,7 +291,7 @@ headed 브라우저가 있으면 스크린샷과 실측값을 바로 받는다
|
|||
|
||||
**4-5. 서류로서의 완성** — 프리셋이 서류·원장·콘솔 계열(장부, 시간표, 관리 화면)일 때만 도는 단계다.
|
||||
그 앱이 종이에서 하던 일을 화면이 이어받아야 프로덕션이다. 셋을 검토한다:
|
||||
- **인쇄** — `@media print`. 앱 크롬(내비·툴바·버튼)은 물러나고 활성 화면이 서류가 된다. 모달이 열려 있으면 그 서류만(`body:has(dialog[open])` 로 앱을 숨긴다). 상태색은 `print-color-adjust: exact` 로 보존. 인쇄 버튼을 크롬에 더했다면 **그 줄의 최소폭 합**을 가장 좁은 폭에서 다시 잰다(하드 게이트 5)
|
||||
- **인쇄** — `@media print`. 앱 크롬(내비·툴바·버튼)은 물러나고 활성 화면이 서류가 된다. 모달이 열려 있으면 그 서류만(`body:has(dialog[open])` 로 앱을 숨긴다). 상태색은 `print-color-adjust: exact` 로 보존. 인쇄 버튼을 크롬에 더했다면 프로젝트의 최소 지원 폭에서 실제 조작 가능성을 다시 잰다
|
||||
- **키보드 단축키** — 콘솔의 손가락 문법. 숫자키 뷰 전환, `/` 검색 포커스. `kbd` 물리 키 칩으로 안내하고, 입력 요소에 포커스가 있을 때는 무력화한다
|
||||
- **본연의 도메인 동작** — 학적부는 기록, 시간표는 격자, 주문은 원장. 그 도메인이 종이에서 하던 핵심 동작 하나가 빠져 있으면 그게 곧 '데모 티'다
|
||||
|
||||
|
|
@ -306,54 +312,52 @@ HTML-in-Canvas(`drawElementImage`)는 **폴백을 완성한 뒤에만** 얹는
|
|||
→ `references/preflight.md` (전체 체크리스트)
|
||||
→ `references/antipatterns.md` (슬롭 지문 목록 + grep 검출 + 자가 채점표)
|
||||
|
||||
특히 다음 다섯은 기계적으로 검사할 수 있다. **반드시 돌려라**:
|
||||
다음 항목을 변경 영향과 프로젝트 검증 계약에 맞춰 확인한다. 자동 검사와 렌더 평가는 구분한다:
|
||||
|
||||
1. **슬롭 지문 grep** — 보라 CTA(`#6366f1`·`#8b5cf6` 계열), 전체 대문자 헤드라인, 번호 매긴 1·2·3 단계. 실측 검출률 상위 항목이다
|
||||
1. **스타일 후보 grep** — 보라 CTA, 전체 대문자 헤드라인, 번호 매긴 단계처럼 반복되는 기본값을 찾아 근거 없이 남아 있는지 검토한다. 검출 자체는 실패가 아니며 `antipatterns.md`의 맥락 질문과 실제 렌더로 판정한다
|
||||
2. **카피 경쟁사 치환 테스트** — 제품명을 경쟁사 이름으로 바꿔도 문장이 성립하면, 그 카피는 아무것도 말하지 않았다
|
||||
3. **이펙트 전부 끄기** — CSS 필터·WebGL·애니메이션을 끈 상태에서 페이지가 여전히 읽히는가
|
||||
4. **게이트 실행(폐쇄 루프)** — `tools/design-gate.mjs --init` 으로 설정을 만들고 돌린다. 오버플로·h1·수축·대비·SEO/meta·죽은 선택자·토큰 위생·스케일×폭까지 전 뷰 × 전 폭. L1(단위)·L5(탐색)·L6(시나리오 E2E)는 프로젝트 `tools/` 에 보강해 `npm run verify` 체인으로. **게이트 통과 없이 완료 선언 금지.**
|
||||
4. **게이트 실행(폐쇄 루프)** — `tools/design-gate.mjs --init` 으로 설정을 만들고, 변경 영향과 프로젝트 계약에 맞춘 뷰·폭·상태에서 실행한다. 오버플로·제목 존재/가시성·수축·대비·SEO/meta·죽은 선택자·토큰 위생·스케일×폭을 해당 범위에서 검사한다. 명시한 양의 `h1MaxLines` 계약이 있을 때만 줄 수를 검사한다. L1(단위)·L5(탐색)·L6(시나리오 E2E)는 프로젝트에 필요한 경우 `tools/` 에 보강해 `npm run verify` 체인으로. 자동 검사 결과와 실제 렌더 평가를 함께 기록한다.
|
||||
5. **상태 완결성 스윕** — 입력·파괴·열림이 있는 화면은 실제로 조작해 본다: 수치 입력에 범위 밖 값을 넣고, 파괴적 행동을 되돌려보고, 열린 메뉴를 Esc 로 닫는다. 기준은 `references/preflight.md` §4-1. 통과 못 하면 4단계로
|
||||
6. **상태별 시각 E2E** — URL별 390·1440 기본 화면과 결과·오류·모달 같은 핵심 상태를 캡처한다. 하니스는 개수·규격·0바이트·중복 해시를 단언하고, 캡처를 실제로 열어 목표 시장 적합성·시선 위계·이미지 크롭·반복을 눈으로 판정한다. 구조 PASS를 시각 PASS로 바꾸어 말하지 않는다
|
||||
|
||||
> 게이트가 잡은 실제 사고 목록과 7계층 설계 근거는 `references/audit-gate.md` 다. 자기 검사 스크립트를 매번 새로 쓰지 마라 — 이 게이트를 심고 확장해라.
|
||||
|
||||
#### 하드 게이트 — 전부 "아니오"여야 한다
|
||||
#### 규범·기능 하드 게이트 — 전부 충족해야 한다
|
||||
|
||||
취향이 아니라 **버그**다. 여기엔 오버라이드가 없다. 체크박스가 아니라 질문이니 실제로 검사해라.
|
||||
아래는 취향이 아니라 적용 WCAG·플랫폼 접근성·사용자에게 약속한 기능의 실패다. 프로젝트 계약과 스타일 판단은 다음 절에서 별도 검토한다.
|
||||
|
||||
1. 토큰 밖에 인라인 hex/rgb/oklch 색상값이나 인라인 `font-family` 가 있는가?
|
||||
2. 상태색(성공·경고·오류)을 제외하고, 한 페이지에서 강조색이 2개 이상인가?
|
||||
3. `border-radius` 값이 토큰 밖에 있거나, 서로 다른 값이 3종 이상인가?
|
||||
4. 페이지 중간에 테마(라이트/다크)가 뒤집히는데, 그 반전이 3단계 토큰에 규칙으로 정의돼 있지 않은가?
|
||||
(리듬으로 의도한 반전은 통과다. 정의 없이 섹션마다 다른 것이 실패다)
|
||||
5. 320~1920px 사이 어느 폭에서든 가로 스크롤이 생기는가?
|
||||
6. 버튼 라벨·내비 링크가 2줄로 접히는 폭이 있는가?
|
||||
7. 버튼 텍스트와 배경의 대비가 4.5:1 미만인가?
|
||||
8. `transform`/`opacity` 외의 속성을 애니메이션하는가?
|
||||
9. 풀하이트 섹션에 `100vh` 를 썼는가? (모바일 주소창 때문에 `100dvh` 여야 한다)
|
||||
10. `window.addEventListener('scroll')` 을 썼는가? (`IntersectionObserver` 또는 scroll-driven animation 을 써라)
|
||||
11. **사용자가 주지 않은 수치**(지표·통계·후기·고객 수)가 페이지에 **그럴듯한 값으로** 들어가 있는가?
|
||||
1. 키보드만으로 모든 인터랙티브 요소에 도달하고, 보이는 포커스와 논리적 순서를 유지하는가?
|
||||
2. 텍스트·UI·상태가 적용 WCAG 대비 기준을 충족하고, 의미 있는 이미지·폼·제목 구조·언어가 접근 가능한가?
|
||||
3. 감소 모션 환경에서 움직임 민감도를 낮추면서 콘텐츠·상태·조작을 보존하는가?
|
||||
4. 지원 범위의 뷰포트·글자 확대·입력 방식에서 의도하지 않은 가로 스크롤, 겹침, 조작 불능이 없는가?
|
||||
5. 입력·파괴·열림 상태가 실제로 검증되고, 오류·되돌림·Esc·포커스 복귀가 필요한 곳에서 작동하는가?
|
||||
6. 애니메이션 또는 스크롤 로직이 입력을 방해하지 않고, 정한 성능 예산과 지원 범위를 실제로 검증했는가?
|
||||
7. **사용자가 주지 않은 수치**(지표·통계·후기·고객 수)가 페이지에 **그럴듯한 값으로** 들어가 있지 않은가?
|
||||
걸렸으면 셋 중 하나다: (a) `{{SETUP_TIME}}` 같은 **명시적 placeholder** 로 바꾸고 6단계 `design.md` 미확정 목록에 올린다, (b) 사용자에게 실제 값을 묻고 멈춘다, (c) 그 섹션 자체를 다른 구조로 바꾼다.
|
||||
**placeholder 는 통과다.** 숫자 모양의 구멍은 정직하고, 지어낸 숫자는 슬롭이다.
|
||||
12. `<div>` 로 만든 가짜 스크린샷·가짜 브라우저바·가짜 폰 프레임이 있는가?
|
||||
13. **토큰 체계·프리셋을 바꿨는데 브랜드 표면(theme-color 메타·파비콘·og:image)이 옛 값을 그대로 쓰고 있는가?** 실측 사고: 프리셋 전환 11버전 뒤에 종이 시대 파비콘·theme-color 가 살아 있었다. 토큰 마이그레이션은 이 셋을 갱신하기 전까지 끝난 게 아니다. `theme-color` 는 실제 배경색과 같아야 한다(게이트가 비교한다)
|
||||
14. **HTML·JS 에서 사라진 컴포넌트의 CSS 규칙·JS 함수가 남아 있는가?** 제거는 HTML·CSS·JS 삼위일체다. 게이트의 죽은 선택자 검사가 클래스 사용률을 대조한다
|
||||
15. **현재 로케일 기본값·명시 브리프와 무관한 제3언어 또는 문화권 클리셰를 에이전트가 새로 넣었는가?** 화면·메타·ARIA·예제 데이터·생성 이미지와 세로쓰기·인장·서예성 장식까지 실제 렌더에서 확인한다. 한국어 로케일에서는 한자·중국어·일본어의 신규 사용이 이에 해당한다. 영어와 사용자가 제공한 원문은 예외다.
|
||||
8. 실제 증거로 오인될 수 있는 가짜 스크린샷·브라우저바·폰 프레임을 라벨 없이 만들지 않았는가?
|
||||
|
||||
#### 카운트 규칙
|
||||
#### 프로젝트 계약 — `design.md`와 구현에서 대조한다
|
||||
|
||||
세어봐라. 넘으면 고친다.
|
||||
- 토큰·테마 반전·브랜드 표면(theme-color·파비콘·og:image)·남은 코드가 프로젝트 결정을 반영하는가?
|
||||
- 로케일·문화권·실제 수치·진실 라벨이 브리프와 제공 자산의 범위를 지키는가?
|
||||
- 지원 viewport·성능 예산·상태별 시각 E2E는 프로젝트가 정한 매트릭스와 도구 한계 안에서 보고됐는가? 자동 도구가 측정하지 못한 항목은 통과로 추정하지 말고 수동 평가로 남긴다.
|
||||
|
||||
#### 스타일 휴리스틱 — 계수는 시작점이지 판정이 아니다
|
||||
|
||||
세어보고, 반복이 정보·브랜드·사용성에 맞는지 실제 렌더에서 평가한다. 아래 수치를 넘겼다는 사실만으로 고치거나 통과시키지 않는다.
|
||||
|
||||
- 작은 대문자 라벨(eyebrow) 개수 ≤ `ceil(섹션수 / 3)`
|
||||
- 같은 이미지+텍스트 스플릿 레이아웃 연속 ≤ 2회
|
||||
- 마퀴 ≤ 1개
|
||||
- 마퀴: 반복·자동재생·정지 수단·감소 모션 경로를 검토한다
|
||||
- 섹션이 6개 이상이면 서로 다른 레이아웃 패밀리가 최소 3개
|
||||
- 히어로: 헤드라인 ≤ 2줄, 서브텍스트 ≤ 20단어, 텍스트 요소 ≤ 4개
|
||||
- 히어로: 제목 줄 수·서브텍스트 길이·텍스트 밀도가 목표 행동과 읽기 폭에 맞는지 확인한다. 줄 수를 맞추려고 글자 크기를 줄이지 않는다
|
||||
|
||||
**국소 경로는 카운트를 페이지 전체로 다시 세지 않는다.** 내가 손댄 부분이 기존 카운트를 넘기게 만드는지만 본다.
|
||||
**하드 게이트 15개는 경로와 무관하게 전부 돈다.**
|
||||
**규범·기능 하드 게이트는 경로와 무관하게 전부 돈다.**
|
||||
|
||||
> 통과 조건: 하드 게이트 15개 전부 "아니오", 카운트 규칙 통과, `preflight.md` 체크리스트 통과. 실패 항목이 있으면 4단계로 돌아간다.
|
||||
> 통과 조건: 규범·기능 하드 게이트 충족, 프로젝트 계약 대조 완료. 기능·접근성 자동 검사와 시각 평가(위계·브랜드·타입·구도·이미지·리듬)를 별도 보고하고, 스타일 휴리스틱의 보류·채택·수정 근거를 남긴다. 실패 항목이 있으면 4단계로 돌아간다.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -363,8 +367,9 @@ HTML-in-Canvas(`drawElementImage`)는 **폴백을 완성한 뒤에만** 얹는
|
|||
|
||||
```markdown
|
||||
# design.md
|
||||
브리프 3줄 / 레퍼런스 R1·R2·R3 URL / 한 문장 컨셉 / 프리셋 / 감수한 리스크 하나
|
||||
브리프 3줄 / 레퍼런스 슬롯과 출처 ID / 한 문장 컨셉 / 프리셋 / 표현 리스크의 채택·비채택 근거
|
||||
토큰 전체(타입·색·간격·모션) / 성능 예산과 실측치 / 채택한 이펙트와 그 폴백
|
||||
출처 ID → 원칙·조건 → 관찰 → 결정 → 검증 결과를 프로젝트 evidence 기록에 연결 / 기능·접근성 자동 검사와 시각 평가의 별도 결과
|
||||
의도적으로 하지 않은 것과 그 이유
|
||||
```
|
||||
|
||||
|
|
@ -382,6 +387,9 @@ HTML-in-Canvas(`drawElementImage`)는 **폴백을 완성한 뒤에만** 얹는
|
|||
|---|---|
|
||||
| `references/galleries.md` | 1단계 — 어느 갤러리를 볼지 정할 때 / **1′ — 국소 브리프 표** |
|
||||
| `references/reference-method.md` | 1단계 — 레퍼런스를 뜯어볼 때 |
|
||||
| `references/design-foundations.md` | **1·2단계 — 이론을 프로젝트 조건으로 번역할 때** |
|
||||
| `references/style-playbook.md` | **2·4단계 — 선택한 스타일의 표현 수단과 금기를 검토할 때** |
|
||||
| `references/evidence-ledger.md` | **0·1·2·5·6단계 — 출처와 관찰·결정·검증을 추적할 때** |
|
||||
| `references/presets/README.md` | 2단계 — 미학 방향을 고를 때 (고른 프리셋 하나만 추가로 읽는다) |
|
||||
| `references/tokens.md` | 3단계 — 토큰을 정할 때 |
|
||||
| `references/typography.md` | 3단계 — 폰트를 고를 때 / 4-1 — 적용할 때 |
|
||||
|
|
@ -396,7 +404,7 @@ HTML-in-Canvas(`drawElementImage`)는 **폴백을 완성한 뒤에만** 얹는
|
|||
| `references/preflight.md` | 5단계 — 감사 |
|
||||
| `references/antipatterns.md` | 3·5단계 — 한글 조판 / 슬롭 검출 |
|
||||
| `references/audit-gate.md` | **5단계 — 게이트(폐쇄 루프) 설계·설치·하니스 규칙** |
|
||||
| `tools/design-gate.mjs` | **5단계 — 범용 게이트 실행기(SEO/meta·대비·수축·페이지별 h1 최대 줄 계약·시각·WebKit 옵션)** |
|
||||
| `tools/design-gate.mjs` | **5단계 — 범용 게이트 실행기(SEO/meta·대비·수축·명시한 양의 h1 줄 수 계약·시각·WebKit 옵션)** |
|
||||
|
||||
## 작업 중 지켜야 할 것
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@designpaca/skill",
|
||||
"version": "0.10.0",
|
||||
"version": "0.11.0",
|
||||
"private": true,
|
||||
"description": "designpaca 스킬 원본 — SKILL.md 와 참조 문서",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -1,47 +1,43 @@
|
|||
# antipatterns.md — 금지 목록
|
||||
# antipatterns.md — 점검 후보
|
||||
|
||||
AI가 만든 티는 **못 만들어서** 나는 게 아니라 **결정을 안 해서** 난다.
|
||||
보라 그라디언트, Inter, 3열 아이콘 카드, `rounded-2xl shadow-lg`, "Get Started"는 전부 **미결정의 기본값**이다.
|
||||
AI가 만든 티는 **못 만들어서** 나는 게 아니라 결정을 설명·검증하지 않을 때 난다.
|
||||
보라 그라디언트, Inter, 3열 아이콘 카드, `rounded-2xl shadow-lg`, "Get Started"는 반복될 수 있는 출발점이다. 존재만으로 미결정이라고 단정하지 않고, 브리프·프로젝트 계약·실제 렌더로 판단한다.
|
||||
|
||||
프리플라이트에서 이 문서를 훑고 걸린 항목을 전부 해소한다. **4개 이상 걸리면 폐기하고 다시 시작한다.**
|
||||
프리플라이트에서 이 문서를 훑어 후보를 찾는다. 검출은 실패가 아니다. 브리프·프로젝트 계약·실제 렌더를 대조해 유지·수정·제거를 결정하고 그 근거를 남긴다.
|
||||
|
||||
---
|
||||
|
||||
## 0. 최우선 — 측정된 상위 지문
|
||||
## 0. 먼저 보는 반복 후보
|
||||
|
||||
Show HN 랜딩 1,590개 실측에서 검출률이 가장 높았던 셋이다. **이 셋부터 확인하라.**
|
||||
원자료와 재현 가능한 표본이 없는 빈도 수치는 규칙의 근거가 될 수 없다. 아래 항목은 흔한 기본값을 찾는 검색 후보이며, 색·대문자·번호가 존재한다는 사실만으로 실패가 아니다.
|
||||
|
||||
| 순위 | 지문 | 검출률 | 왜 문제 | 대신 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | **CTA 버튼이 보라·인디고 계열** (`bg-indigo-600`, `#6366f1`, `#8b5cf6`) | **10.7%** | Tailwind 기본 팔레트 = "색을 안 골랐다"는 신호 | 브랜드 색. 없으면 중립 대비가 가장 강한 색(잉크 위 화이트 반전) |
|
||||
| 2 | **헤드라인·섹션 라벨이 전체 대문자** (`FEATURES`, `HOW IT WORKS`) | **10.5%** | 얻지 않은 권위를 빌리는 장치. 가독성도 낮음 | 라벨을 없애고 헤드라인만으로 섹션을 구분 |
|
||||
| 3 | **번호 매긴 1·2·3 단계 섹션** | **9.4%** | 실제 순서가 아닌데 순서인 척 | 단계가 진짜 순서일 때만. 그 경우에도 번호보다 화면 캡처 3장이 낫다 |
|
||||
|
||||
전체 표본의 22%가 4개 이상 지문을 가진 "heavy slop"이었다.
|
||||
| 후보 | 확인할 질문 |
|
||||
|---|---|
|
||||
| 보라·인디고 CTA | 브랜드 팔레트·상태 구분·대비·목표 행동을 설명하는가? |
|
||||
| 전체 대문자 라벨 | 언어·가독성·정보 위계에 맞는가? |
|
||||
| 번호 매긴 단계 | 사용자가 실제 순서로 수행하는 과업인가? |
|
||||
|
||||
---
|
||||
|
||||
## 1. 컬러
|
||||
|
||||
> **다크가 슬롭이 아니라 기본값이 슬롭이다.**
|
||||
> bun.sh는 다크 배경인데도 이 절의 항목을 거의 전부 회피한다 — 순흑이 아닌 `#0D0A0C`, 텍스트 3단계, 보라 대신 마젠타 `#FF2E97`, radius 어휘 3종.
|
||||
> A-01은 "다크를 쓰지 마라"가 아니라 **"고르지 않은 채로 다크에 떨어지지 마라"**는 뜻이다. 아래 전부 동일하다.
|
||||
다크·그라디언트·강한 색은 그 자체로 실패가 아니다. 화면 역할, 브랜드, 대비, 실제 기기 렌더에서 이유를 설명할 수 있는지 점검한다.
|
||||
|
||||
| 지문 | 왜 문제 | 대신 |
|
||||
|---|---|---|
|
||||
| **다크 모드를 브리프 근거 없이 기본값으로** (`bg-slate-900`, `#0B0B0F`) | 생성 도구의 반사 반응. 단일 시그니처 검출 빈도 1위 | 라이트로 설계하고 다크는 토큰으로 파생. 사용자 82%가 다크를 쓴다는 데이터는 "지원하라"이지 "기본값으로 하라"가 아니다 |
|
||||
| **보라→파랑 그라디언트 히어로** (`from-purple-600 to-blue-500`, `#6366f1→#a855f7`) | 수십만 튜토리얼의 기본값 | 브랜드 색 1개 + 중립. 그라디언트를 쓸 거면 같은 hue 내 명도 변화 (`#1B4332→#2D6A4F`) |
|
||||
| **라벤더 퍼플이 어디에나** (`#a78bfa`, `#c4b5fd`) | 텍스트→랜딩 생성기의 출력 지문 | 보라를 쓰지 마라. 꼭 필요하면 채도를 낮추고 온도를 틀어라 (`#6B5B95`) |
|
||||
| **네온 온 다크** — 시안(`#22d3ee`)·바이올렛이 검정 위에서 발광 | 게이밍·개발자 툴 브리프가 아닌데 나오면 즉시 티가 남 | 저채도 액센트 1개. 발광 대신 명도 차이로 위계 |
|
||||
| **컬러 글로우** (`box-shadow: 0 0 80px rgba(139,92,246,.5)`) | 광원 논리 없이 깊이를 색으로 위조 | 중립 그림자 2단 (`0 1px 2px rgba(0,0,0,.06)`, `0 8px 24px rgba(0,0,0,.08)`) |
|
||||
| **히어로 뒤 방사형 그라디언트 오브·헤일로** | 구성을 못 잡았을 때의 회피 수단 | 배경을 비우거나 실제 콘텐츠(제품 스크린샷, 타입)로 채워라 |
|
||||
| **순백 `#ffffff` / 순흑 `#000000`** 을 배경·텍스트로 | 아무 결정도 하지 않았다는 뜻. 눈부심·번짐 유발 | 오프화이트 `#FAFAF7`, 잉크 `#111014`. 브랜드 hue를 2~4% 섞으면 더 좋다 |
|
||||
| **Tailwind 기본 토큰 그대로** (`slate-900`, `gray-500`, `emerald-500`) | 누구나 알아본다 | `tailwind.config`의 색을 **교체**한다(확장 아님). `ink-900`, `ember-600` 같은 고유 이름 |
|
||||
| **다크 모드를 브리프 근거 없이 기본값으로** (`bg-slate-900`, `#0B0B0F`) | 대상 환경·브랜드·콘텐츠에 맞는지 설명하지 못하면 선택이 기본값처럼 보일 수 있다 | 라이트·다크의 역할 토큰, 실제 기기 대비, 사용자 설정·테마 전환 필요성을 비교한다 |
|
||||
| **보라→파랑 그라디언트 히어로** (`from-purple-600 to-blue-500`, `#6366f1→#a855f7`) | 제품·브랜드·정보 역할과 무관하면 배경 장식만 남을 수 있다 | 단색·동일 hue 변화·다중 hue를 같은 콘텐츠에서 비교하고, 텍스트 대비와 행동 위계를 확인한다 |
|
||||
| **라벤더 퍼플이 어디에나** (`#a78bfa`, `#c4b5fd`) | 맥락 없는 반복은 기본값처럼 보일 수 있음 | 브랜드·접근성·표면 역할을 설명하고 실제 렌더에서 위계를 확인 |
|
||||
| **네온 온 다크** — 시안(`#22d3ee`)·바이올렛이 검정 위에서 발광 | 색의 의미·대비·주변광에서의 읽기 비용을 확인해야 한다 | 상태·행동·콘텐츠 역할과 연결하고, 저채도/고채도·명도 대비를 실제 기기에서 비교한다 |
|
||||
| **컬러 글로우** (`box-shadow: 0 0 80px rgba(139,92,246,.5)`) | 깊이·계층·상태를 글로우만으로 표현하면 의미가 모호해질 수 있다 | 그림자·경계·여백·글로우 후보 중 실제 계층과 성능을 가장 잘 드러내는 것을 선택한다 |
|
||||
| **히어로 뒤 방사형 그라디언트 오브·헤일로** | 메시지·제품 증거·구도보다 장식이 먼저 읽히는지 점검한다 | 배경·제품 화면·타입 중심 구도를 같은 콘텐츠로 비교한다 |
|
||||
| **순백 `#ffffff` / 순흑 `#000000`** 을 배경·텍스트로 | 극단값이 브랜드·매체·환경에 맞는지 점검한다 | 대상 기기·주변광·텍스트 대비와 실제 렌더의 눈부심을 확인한다. 색 자체를 실패로 취급하지 않는다. 출처: [WCAG 2.2 Contrast](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html)와 프로젝트 브리프 |
|
||||
| **Tailwind 기본 토큰 그대로** (`slate-900`, `gray-500`, `emerald-500`) | 역할·브랜드·상태가 토큰 이름과 값에서 드러나는지 점검한다 | 기본 토큰을 유지·확장·교체할 수 있다. 의미 역할과 실제 렌더 근거를 기록한다 |
|
||||
| **코드에서 색 이름을 직접 호출** (`purple-500`) | 색이 역할을 못 가짐 | 의미 토큰: `--color-action-primary`, `--color-surface-elevated`, `--color-text-secondary` |
|
||||
| **그라디언트 텍스트** (`background-clip: text`) | 스캔성을 깎고 정보는 0. OG 이미지에서 깨짐 | 단색. 강조는 크기·굵기·여백으로 |
|
||||
| **그라디언트 텍스트** (`background-clip: text`) | 작은 크기·이미지 배경·공유 이미지에서 읽기와 fallback을 점검한다 | 단색·그라디언트·다른 위계 수단을 비교하고, 실제 export와 대비를 확인한다 |
|
||||
| **크림/베이지(`#FDF8F3`)를 "고급"의 기본값으로** | 보라를 대체한 신종 슬롭 | 크림을 쓸 거면 왜 크림인지 브리프와 연결하고 텍스트·액센트를 그에 맞춰 재설계 |
|
||||
| **hue 4개 이상** | 결정 못 한 상태 | hue 3개 이하. 면적 60(지배)/30(중립)/10(강조) |
|
||||
| **다크에서 본문 대비 미달** (`#0f172a` 위 `#94a3b8`) | 기능적 결함 | 본문 4.5:1 또는 APCA Lc ≥ 75. 다크의 본문은 순백 대신 `#E8E6E3` |
|
||||
| **여러 hue가 경쟁함** | 행동·상태·정보의 우선순위가 색 때문에 흐려질 수 있다 | 색 역할과 화면 면적을 실제 상태에서 비교한다. hue 수·60/30/10은 출발 가설일 뿐 통과 기준이 아니다 |
|
||||
| **다크에서 본문 대비 미달** | 적용 WCAG 성공 기준을 실제 배경 합성값으로 충족하는지 점검한다 | `#0f172a` 위 `#94a3b8`의 WCAG 대비는 약 **6.96:1**이므로 미달 사례가 아니다. WCAG 2.2 AA 본문 판정에는 contrast ratio를 사용하며 APCA는 이를 대체하지 않는다. 반투명·이미지 배경은 실제 렌더에서 계산한다. 출처: [WCAG 2.2 Contrast](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html) |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -49,18 +45,17 @@ Show HN 랜딩 1,590개 실측에서 검출률이 가장 높았던 셋이다. **
|
|||
|
||||
| 지문 | 왜 문제 | 대신 |
|
||||
|---|---|---|
|
||||
| **Inter를 이유 없이 기본값으로** (특히 중앙 정렬 히어로) | AI 인터페이스의 기본 서체 | Satoshi / Switzer / DM Sans / Work Sans. Inter는 초고밀도 다국어 UI 같은 명확한 이유가 있을 때만 |
|
||||
| **Space Grotesk + Instrument Serif + Geist 조합** | 이 셋의 **반복 조합**이 생성 지문으로 특정됨 | 셋 중 **하나만** 쓰는 것은 허용. 둘 이상 함께 쓰면 실패. 파운드리를 바꾸면 더 낫다 (Fontshare, Velvetyne) |
|
||||
| **헤드라인 한 단어만 세리프 이탤릭** (`Build <em>better</em> products`) | 가장 널리 퍼진 "성의 표시" 관용구. 이제는 성의가 아니라 지문 | 강조는 줄바꿈·크기·색·여백으로 |
|
||||
| **페이지 전체에 폰트 패밀리 1개** | 위계를 크기로만 만들게 되어 밋밋 | 디스플레이 1 + 본문 1. 성격 차이를 크게 |
|
||||
| **타입 스케일이 평평함** (16/18/20/24, 비율 1.15 미만) | 모든 게 똑같이 중요해 보임 | 비율 1.25 또는 1.333. **최대/본문 4배 이상** (17→68). 비율만으로 4배가 안 나오면(1.25 5단계 = 2.44배) **디스플레이 사이즈를 스케일 밖에 따로 정의한다**(`tokens.md` §1). **단계 수를 늘려서 맞추지 마라** — 그건 아래 행에 걸린다 |
|
||||
| **타입 스케일 단계 8개 이상** | 통제 실패 | 3~5단계로 제한하고 각 단계에 역할 이름 부여 |
|
||||
| **히어로 = pill 배지 + 거대 헤드라인** (`✨ Now in beta` + H1) | 가장 알아보기 쉬운 구조 지문 | 배지를 지워라. 정말 필요하면 문장 안이나 내비 옆으로 |
|
||||
| **Inter 선택** (특히 중앙 정렬 히어로) | 서체가 언어·정보 밀도·브랜드 톤에 맞는지 점검한다 | 후보 서체와 숫자·한글·긴 제목을 같은 viewport에서 비교하고, 라이선스·fallback metric을 기록한다. Inter 자체를 실패로 취급하지 않는다. 출처: `references/typography.md`와 프로젝트 브리프 |
|
||||
| **Space Grotesk + Instrument Serif + Geist 조합** | 조합이 실제 위계와 브랜드 톤을 만드는지 점검한다 | 서체 수가 아니라 역할·fallback·가독성을 실제 렌더에서 비교한다. 조합의 구성원 수만으로 실패시키지 않는다. 출처: `references/typography.md` |
|
||||
| **헤드라인 한 단어만 세리프 이탤릭** (`Build <em>better</em> products`) | 강조가 브랜드 언어·문장 의미·읽기 순서를 실제로 돕는지 점검한다 | 이탤릭·줄바꿈·크기·색·여백을 같은 문구에서 비교하고 선택 이유를 기록한다 |
|
||||
| **페이지 전체에 폰트 패밀리 1개** | 서체 수와 무관하게 제목·본문·데이터의 위계가 읽히는지 점검한다 | 한 패밀리 또는 여러 패밀리를 같은 콘텐츠·viewport·확대 상태에서 비교하고, 역할과 fallback을 기록한다. 출처: `references/typography.md` |
|
||||
| **타입 스케일이 평평해 보임** | 최대/본문 배율이 아니라 실제 과업의 위계·읽기 폭·언어 적합성을 점검한다 | 제목·본문·보조 정보의 역할과 렌더된 우선순위를 비교한다. 배율·단계 수는 관찰값으로 기록하되 최대/본문 4배나 특정 비율을 보편 통과 조건으로 쓰지 않는다. 출처: `references/design-foundations.md`, `references/typography.md` |
|
||||
| **타입 스케일 단계가 많음** | 같은 역할에 여러 크기가 섞이면 읽기 순서가 흐려질 수 있다 | 각 단계에 역할을 이름 붙이고, 대표 폭·확대 상태에서 실제 위계를 확인한다. 단계 수 자체로 실패시키지 않는다 |
|
||||
| **히어로 = pill 배지 + 거대 헤드라인** (`✨ Now in beta` + H1) | 배지가 실제 상태·시간성·제약을 설명하는지 점검한다 | 배지·문장 안 상태·내비 상태·생략을 비교하고, 첫 행동에 필요한 경우만 남긴다 |
|
||||
| **`_01_ _02_ _03_` 장식 번호 라벨** | 에디토리얼 흉내인데 구조는 없음 | 번호가 순서를 의미할 때만 |
|
||||
| **본문 letter-spacing 0.05em 이상** | 단어 인식이 느려짐 | 본문 0. 소형 대문자 라벨에만 +0.08em |
|
||||
| **대형 헤드라인 음수 자간 -0.06em 이상** | 글자가 서로 먹힘 | -0.02em ~ -0.04em |
|
||||
| **본문 line-height 1.3 미만 / 본문 12px 이하** | 가독성·접근성 실패 | 라틴 본문 line-height 1.5–1.7, 크기 16–18px 권장. **예외**: 고밀도 라틴 UI(대시보드·개발자 도구)에서 13–14px는 의도된 선택일 수 있다 — bun.sh 본문 최다 크기가 13.5px다. 단 **한글에는 이 예외를 적용하지 마라.** 한글은 같은 px에서 라틴보다 작아 보여 16px가 하한이다 |
|
||||
| **모노스페이스를 장식으로** (코드 아닌 라벨에 `font-mono`) | "테크 느낌"의 저비용 흉내 | 모노는 코드·데이터·식별자에만 |
|
||||
| **본문/헤드라인 자간이 읽기를 방해함** | 글꼴·언어·크기·폭에 따라 글리프 충돌, 단어 인식, 줄바꿈이 달라진다 | 0, 양수, 음수 자간을 대표 문구·지원 viewport·200% 확대에서 비교한다. 단일 `em` 수치를 보편 기준으로 쓰지 않는다 |
|
||||
| **본문 크기·행간이 과업에 맞지 않음** | 작은 글자나 촘촘한 행간은 읽기·확대·오류 복구 비용을 높일 수 있다 | 글꼴·언어·콘텐츠 밀도별 후보를 실제 기기·200% 확대·긴 문단에서 검증한다. 16px이나 고정 line-height를 보편 하한으로 선언하지 않는다 |
|
||||
| **모노스페이스를 장식으로 사용** | 코드·데이터 외 용도에서도 의미·가독성·브랜드 톤을 돕는지 점검한다 | 대상 언어·크기·대비·긴 문자열을 실제 렌더에서 비교한다. 모노스페이스 자체나 용도만으로 실패시키지 않는다. 출처: `references/typography.md` |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -69,17 +64,14 @@ Show HN 랜딩 1,590개 실측에서 검출률이 가장 높았던 셋이다. **
|
|||
| 지문 | 왜 문제 | 대신 |
|
||||
|---|---|---|
|
||||
| **표준 골격**: 히어로 → 3열 피처 → 로고월 → 요금제 → FAQ → 푸터 | shadcn/ui 예제·Tailwind UI·Vercel 템플릿의 순서 그대로 | 섹션 순서를 브리프의 설득 논리로 재배열. 예: 문제 제시 → 실제 사용 화면 → 반론 처리 → 가격 |
|
||||
| **중앙 정렬 히어로** (텍스트 가운데 + CTA 2개 + 아래 스크린샷) | 가장 안전해서 가장 흔함 | 비대칭 그리드(5:7, 7:5), 좌측 정렬 대형 타입, 또는 텍스트를 화면 하단 1/3로 |
|
||||
| **정확히 3열, 균등 폭 피처 카드** | 콘텐츠가 3개여서가 아니라 3이 예쁘게 떨어져서 3인 것 | 항목 수를 콘텐츠가 정하게. 폭도 중요도에 따라 다르게 |
|
||||
| **아이콘이 카드 상단 중앙**에 있는 피처 카드 (아이콘 타일 + 제목 + 2문장) | 가장 확실한 단일 지문 | 아이콘을 없애고 숫자·스크린샷·실제 UI 조각으로. 쓸 거면 좌측 인라인 |
|
||||
| **카드 좌측 3–4px 컬러 스트립** (`border-l-4 border-purple-500`) | em-dash에 맞먹는 신뢰도의 지문 | 삭제. 구분이 필요하면 배경 톤 차이나 여백 |
|
||||
| **카드 안의 카드 안의 카드** | 시각적 소음. 깊이가 정보와 무관 | 중첩 최대 1단계. 안쪽은 구분선이나 여백으로 |
|
||||
| **근거 없는 지표 배너** (`10,000+ users · 99.9% uptime · 4.9★`) | 검증 불가한 숫자 나열은 신뢰를 깎는다 | 숫자 1개만, 출처와 함께. 없으면 섹션 삭제 |
|
||||
| **모든 여백이 같은 값** (전부 `p-6`, 전부 `gap-4`) | 리듬이 없어 강약이 사라짐 | 8pt 그리드 위 4~6종. 섹션 간 : 요소 간 ≈ 1:5 |
|
||||
| **섹션마다 동일한 상하 패딩** (`py-20` 반복) | 어디가 중요한지 알 수 없음 | 중요한 섹션에 더 많은 여백. 여백이 강조다 |
|
||||
| **벤토 그리드를 기본 선택지로** | 2026년 기준 표준이라 차별화가 아니다. "고민 안 했음"의 새 신호 | 타일 크기 차이가 정보 위계를 반영할 때만. 아니면 단순 리스트 |
|
||||
| **콘텐츠가 뷰포트 가장자리에 붙음** | 모바일에서 특히 조악 | 모바일 16–24px, 데스크톱 24–80px 좌우 패딩 |
|
||||
| **본문 컬럼이 화면 전체 폭** | 한 줄이 100자를 넘어 읽기가 무너짐 | 영문 `max-width: 65ch`. 국문은 25–40자 폭 |
|
||||
| **중앙 정렬 히어로** (텍스트 가운데 + CTA 2개 + 아래 스크린샷) | 목표 행동·읽기 폭·브랜드의 구도를 돕는지 점검한다 | 중앙·비대칭·좌측 정렬 후보를 같은 콘텐츠와 viewport에서 비교하고, 선택 근거를 기록한다. 중앙 정렬 자체를 실패로 취급하지 않는다. 출처: `references/design-foundations.md`, 프로젝트 브리프 |
|
||||
| **균등 카드 grid** | 항목 중요도·비교 과업·작은 폭 재배치가 균등 구조와 맞는지 점검한다 | 3열/비대칭/목록을 콘텐츠와 대표 과업에서 비교한다 |
|
||||
| **아이콘 중심 피처 카드** | 아이콘이 실제 기능 이해를 돕는지, 이미지·수치·UI 증거가 더 나은지 점검한다 | 아이콘 위치·라벨·실제 제품 조각을 비교하고, 전체 카드 hitbox와 접근 가능한 이름을 확인한다 |
|
||||
| **컬러 스트립·중첩 카드** | 경계와 깊이가 실제 정보 묶음을 나타내는지 점검한다 | 여백·선·표면·중첩을 비교한다. 중첩 횟수와 border 폭은 통과 기준이 아니다 |
|
||||
| **근거 없는 지표 배너** (`10,000+ users · 99.9% uptime · 4.9★`) | 검증할 수 없는 수치는 사실처럼 제시하면 안 된다 | 출처·측정 조건·기간이 있는 수치만 쓰고, 수가 여러 개여도 목적에 맞는 묶음과 출처를 제시한다 |
|
||||
| **여백 리듬이 정보 관계를 가림** | 같은/다른 간격이 관련성과 우선순위를 드러내지 못할 수 있다 | 토큰 수·비율을 고정하지 말고, 실제 콘텐츠와 회색조 렌더에서 그룹·섹션 관계를 확인한다 |
|
||||
| **벤토 그리드를 기본 선택지로** | 타일 크기 차이가 정보 위계나 과업을 설명하지 못할 수 있다 | 벤토·단순 목록·비교 grid를 콘텐츠와 작은 폭 재배치에서 비교한다. 연도별 트렌드 주장은 근거가 아니다 |
|
||||
| **콘텐츠 여백·본문 폭이 읽기를 방해함** | viewport·글꼴·언어·확대에 따라 줄 길이와 행동 영역이 달라진다 | gutter와 measure 후보를 320px·200% 확대·넓은 폭에서 렌더해 검증한다. 고정 px·ch 범위는 출발값일 뿐이다 |
|
||||
| **푸터가 링크 4열 + 소셜 아이콘 + 카피라이트뿐** | AI가 가장 성의 없이 만드는 곳 | 실제 정보(연락처, 주소, 사업자 정보)를 넣어라. 링크가 4개뿐이면 4열로 만들지 마라 |
|
||||
|
||||
---
|
||||
|
|
@ -88,19 +80,15 @@ Show HN 랜딩 1,590개 실측에서 검출률이 가장 높았던 셋이다. **
|
|||
|
||||
| 지문 | 왜 문제 | 대신 |
|
||||
|---|---|---|
|
||||
| **`rounded-2xl shadow-lg p-6` 를 손대지 않고 사용** | shadcn/ui 기본값. AI가 복붙하도록 설계된 값 | radius를 프로젝트 고유값으로(4px 또는 12px). 큰 그림자 대신 1px 보더 + 배경 톤 차이 |
|
||||
| **모든 요소 border-radius 16px 균일 / 24px 이상 과대** | radius가 결정이 아니라 기본값임을 드러냄. 24px+ 는 블롭처럼 보임 | radius 어휘 2개 (컨테이너 12px, 인터랙티브 8px). 또는 0으로 통일 |
|
||||
| **1px 회색 보더 + 넓게 퍼진 그림자 동시 사용** | 두 깊이 표현을 겹친 것. 광원 논리 없음 | 하나만 선택 |
|
||||
| **글래스모피즘 전면 사용** (`backdrop-blur` 카드 다수) | 실기기 FPS 15~30% 하락 | 내비 바·모달로 제한. 카드에는 쓰지 마라 |
|
||||
| **이모지를 아이콘 대신** (🚀 ⚡ 🎯 ✨) | 즉각적인 아마추어 신호 | 아이콘 세트 하나 고정 (Lucide, Phosphor, Radix). 이모지는 카피 안에서만 |
|
||||
| **버튼이 항상 2개 나란히** (`Get started` + `Learn more`) | 주 행동을 정하지 못했다는 뜻 | 주 CTA 1개. 보조는 텍스트 링크로 격하 |
|
||||
| **회색조 로고 6~8개 일렬 로고월** | 대부분 무관하거나 검증 불가 | 실제 고객이면 한 곳의 사례를 문장으로. 없으면 섹션 삭제 |
|
||||
| **이니셜 원형 아바타 + 텍스트 후기 3개** | 검증 불가한 후기는 신뢰를 깎는다 | 실명 + 직함 + 원문 링크. 없으면 넣지 마라 |
|
||||
| **가상 질문으로 채운 FAQ 6개** (`How does it work?`) | 실제로 받은 질문이 아님 | 실제 문의 3개. 답변에 구체적 숫자·조건 |
|
||||
| **요금제 3열 카드 + 가운데 "Most popular" 배지** | 가장 재현율 높은 SaaS 템플릿 | 비교 표, 단일 가격, 또는 계산기 |
|
||||
| **기본 radius·shadow·padding 조합을 그대로 사용** | 컴포넌트 역할·밀도·브랜드 표면이 토큰과 맞는지 점검한다 | radius·선·그림자·여백 후보를 실제 상태에서 비교하고, 역할 토큰으로 기록한다 |
|
||||
| **여러 깊이 표현을 겹침** | 경계·그림자·표면 차이가 같은 계층을 중복 설명하는지 점검한다 | 하나 또는 여러 단서를 쓸 수 있다. 포커스·상태·인접 표면에서 계층이 읽히는지 검증한다 |
|
||||
| **글래스모피즘 전면 사용** (`backdrop-blur` 카드 다수) | backdrop filter의 성능·대비·reduced-transparency 대안이 필요할 수 있다 | 대상 기기의 performance, fallback 표면, 텍스트 대비를 측정하고 역할이 있을 때만 채택한다 |
|
||||
| **이모지를 아이콘 대신** (🚀 ⚡ 🎯 ✨) | 의미·locale·플랫폼 렌더링·접근 가능한 이름이 역할을 돕는지 점검한다 | 이모지·아이콘 세트·텍스트를 실제 대상과 보조기술에서 비교한다 |
|
||||
| **여러 CTA가 같은 무게로 경쟁함** | 사용자가 다음 행동을 선택하기 어려울 수 있다 | 행동 우선순위·위험·되돌림에 맞춰 주/보조 CTA와 배치를 정하고 과업 테스트한다 |
|
||||
| **로고월·후기·FAQ·요금제 템플릿** | 사실·질문·가격 구조가 현재 제품의 증거인지 점검한다 | 검증 가능한 출처와 실제 고객 질문·요금 조건을 사용한다. 개수·열 수·배지 존재로 실패시키지 않는다 |
|
||||
| **펄스 애니메이션 상태 점** (초록 원 깜빡임 + "All systems operational") | 정적 정보에 장식 애니메이션 | 상태가 실제로 바뀔 때만 |
|
||||
| **자동 스크롤 마퀴** (로고·후기·태그가 끝없이 흐름) | 읽기를 방해하고 주의를 강탈 | 정적 그리드. 많으면 페이지네이션 |
|
||||
| **hover가 아무 반응 없거나 전 요소가 동일하게 `scale(1.02)`** | 인터랙션을 설계하지 않았다는 신호 | 요소마다 다른 반응(링크는 밑줄, 카드는 배경 톤, 버튼은 명도). **hover는 가장 먼저 설계한다** |
|
||||
| **자동 스크롤 마퀴** (로고·후기·태그가 끝없이 흐름) | 읽기·움직임 민감도·입력과 충돌할 수 있음 | 목적·정지 수단·감소 모션·성능을 검증하고, 정적 그리드 또는 페이지네이션과 비교 |
|
||||
| **hover 상태가 과업을 돕지 않음** | 포인터 반응이 행동 가능성·현재 상태·위험을 설명하지 못할 수 있다 | 링크·카드·버튼의 상태를 역할별로 설계하고, touch/keyboard에서도 같은 핵심 단서를 제공한다 |
|
||||
| **편집 불가 히어로 카피 뒤 깜빡이는 커서 `|`** | 타이핑 흉내. 정보 없음 | 삭제 |
|
||||
|
||||
---
|
||||
|
|
@ -109,14 +97,11 @@ Show HN 랜딩 1,590개 실측에서 검출률이 가장 높았던 셋이다. **
|
|||
|
||||
| 지문 | 왜 문제 | 대신 |
|
||||
|---|---|---|
|
||||
| **모든 요소에 동일한 fade-in-up** (`opacity 0→1`, `translateY 20px`, 같은 delay) | 모션 언어가 없다는 뜻. 페이지가 계속 떠오르기만 함 | 중요한 것에만. 순차 등장이 필요하면 stagger 40–60ms |
|
||||
| **인터페이스에 bounce / elastic 이징** | 2010년대 감성. 즉시 촌스러움 | `ease-out` 또는 `cubic-bezier(0.2, 0, 0, 1)` |
|
||||
| **이미지 hover 시 `scale` 또는 `rotate`** | 생성 UI의 반복 지문 | 이미지는 두고 캡션·오버레이·보더를 변화시켜라 |
|
||||
| **duration이 전부 300ms** | 마이크로와 연출을 구분 못 함 | 마이크로 100–200 / 트랜지션 200–400 / 연출 600–1200ms |
|
||||
| **같은 모션을 모든 요소에 적용** | 모션이 상태·관계·우선순위를 설명하지 못하고 읽기를 방해할 수 있다 | 중요한 변화에만 모션을 연결하고, duration/easing은 과업·거리·reduced-motion에서 검증한다. 고정 ms 범위는 출발값이다 |
|
||||
| **bounce·elastic·scale·rotate 모션** | 장면의 물성·피드백 의미·멀미·성능과 맞는지 점검한다 | 이징과 속성은 실제 상호작용·reduced-motion·저사양 기기에서 비교한다 |
|
||||
| **스크롤 reveal 실패 시 콘텐츠가 `opacity: 0`으로 남음** | JS 실패 시 빈 페이지가 됨 | 기본을 visible로 두고 JS가 숨긴 뒤 보여주는 방식. 또는 CSS scroll-driven animation |
|
||||
| **`prefers-reduced-motion` 미대응** | 접근성 실패 | 모션 제거 경로를 반드시 제공 |
|
||||
| **전 섹션 패럴랙스** | 스크롤 감각이 어긋나고 성능 저하 | 한 섹션만, 이동량 10–20px |
|
||||
| **히어로에 3D/Spline 씬을 이유 없이** | JS 런타임 800KB~2MB. 모바일 4G에서 Core Web Vitals 실패 | 브리프가 요구할 때만. 아니면 정적 렌더 이미지 + 미세 모션 |
|
||||
| **`prefers-reduced-motion` 미대응** | 사용자 모션 선호를 무시하면 중요한 상태를 이용하기 어려울 수 있다 | `prefers-reduced-motion`에서 비동작 대체 신호와 핵심 과업을 실제로 검증한다 (`evidence-ledger.md`의 `W3C-REDUCED`) |
|
||||
| **전 섹션 패럴랙스·3D/Spline 씬** | 콘텐츠보다 연출이 우선되거나 저사양·느린 망에서 핵심 경로를 막을 수 있다 | 목적·성능 예산·정적 fallback·정지 제어를 정하고 local proxy와 field data를 구분해 측정한다 |
|
||||
| **로딩할 게 없는데 프리로더 카운터** | 없는 대기를 만듦 | 삭제 |
|
||||
|
||||
---
|
||||
|
|
@ -158,7 +143,7 @@ Show HN 랜딩 1,590개 실측에서 검출률이 가장 높았던 셋이다. **
|
|||
|---|---|---|
|
||||
| 표면은 CSS 가 정하고, 공간은 GPU 가 맡는다 | **텍스처 200KB 를 300바이트가 대신한다** | 구현 → 이득. 수치가 검증 가능 |
|
||||
| Powerful Features | 엑셀 없이 정산이 끝난다 | 명사구 → 주장 |
|
||||
| 빠르고 안정적인 배포 | 배포 실패가 롤백까지 90초 | 형용사 → 측정치 |
|
||||
| 빠르고 안정적인 배포 | 실제 배포·롤백 결과와 조건 | 형용사 → 측정치. 예: 검증된 `p95 롤백 시간`, 기간, 환경 |
|
||||
|
||||
### 데모가 주장을 증명하는지 재라
|
||||
|
||||
|
|
@ -189,7 +174,7 @@ B 라면, 반응형에서 매번 바뀌는 것을 지목한 것이다. 지목하
|
|||
|
||||
| 지문 | 왜 문제 | 대신 |
|
||||
|---|---|---|
|
||||
| **`It's not X, it's Y` / `단순한 X가 아니라 Y입니다`** | ChatGPT 최대 지문. 400단어에 3번씩 나옴 | 그냥 Y를 말해라. 대조가 필요하면 비교 대상을 실명으로 |
|
||||
| **`It's not X, it's Y` / `단순한 X가 아니라 Y입니다`** | 대조가 실제 차이·조건을 설명하지 못하면 문장이 비어 보일 수 있다 | Y를 직접 말하거나, 필요할 때 비교 대상과 검증 조건을 명시한다 |
|
||||
| **스타카토 3연타** (`No fluff. No filler. No BS.` / `빠르게. 정확하게. 간단하게.`) | 리듬으로 내용 없음을 감춤 | 한 문장으로 구체적으로 |
|
||||
| **em-dash(—) 한 문단에 2회 이상** | AI 문장 리듬의 대표 지문 | 마침표로 끊거나 쉼표로. 한국어에서 특히 부자연스럽다 |
|
||||
| **`In today's fast-paced digital landscape...`** 도입 | 아무 말도 하지 않는 문단 | 첫 문장부터 본론. 도입 문단 삭제 |
|
||||
|
|
@ -201,9 +186,9 @@ B 라면, 반응형에서 매번 바뀌는 것을 지목한 것이다. 지목하
|
|||
| `Streamline / Empower / Supercharge / Unlock / Leverage / Seamless / Elevate` | 아무 제품에나 붙는 동사. 정보량 0 | 제품이 실제로 하는 동작 동사 (`정산한다`, `병합한다`, `4일을 6시간으로 줄인다`) |
|
||||
| `world-class / cutting-edge / enterprise-grade / best-in-class` | 자기 평가 형용사는 증거가 아니다 | 인증명, 벤치마크 수치, 고객사 실명 |
|
||||
| `Build the future of X` / `Your all-in-one platform` / `Scale without limits` | 경쟁사 이름으로 바꿔도 성립 | 치환 테스트를 통과하는 문장 (예: "Financial infrastructure for the internet") |
|
||||
| 헤지 표현 (`may help you`, `~할 수 있습니다`) | 확신 없음 = 신뢰 없음 | 단정하거나 조건을 명시 (`10명 이하 팀에서는`) |
|
||||
| 헤지 표현 (`may help you`, `~할 수 있습니다`) | 불확실성의 범위가 숨겨지면 독자가 주장 강도를 판단하기 어렵다 | 검증된 내용은 명확히 쓰고, 불확실하면 조건·근거·한계를 명시한다 |
|
||||
| CTA가 `Get Started` / `Learn More` / `시작하기` | 무엇이 시작되는지 알 수 없음 | 결과를 말하는 CTA (`무료로 30일 써보기`, `가격표 보기`) |
|
||||
| 모든 숫자가 어림수 (`10,000+`, `99.9%`, `50% faster`) | 검증 불가 | 정확한 수치와 측정 조건 (`p95 응답 240ms, 2026-07 기준`) |
|
||||
| 출처·조건 없는 숫자 (`10,000+`, `99.9%`, `50% faster`) | 사실처럼 보이는 주장의 검증 경로가 없다 | 정확/범위 수치 모두 출처·측정 조건·기간을 붙인다. 조건 없는 수치는 제거하거나 예시임을 라벨링한다 |
|
||||
| 모든 헤딩이 명사구 (`Powerful Features`, `Simple Pricing`) | 헤딩이 정보를 전달하지 않음 | 헤딩에 주장을 담아라 (`엑셀 없이 정산이 끝난다`) |
|
||||
| 레이블·서브레이블·헬퍼가 같은 말 3번 (`이메일` / `이메일 주소` / `이메일 주소를 입력하세요`) | 화면 소음 | 하나만 남긴다 |
|
||||
| 이모지로 시작하는 불릿 (`✅ 빠른 속도`) | 정보 위계를 이모지로 대체 | 일반 불릿 또는 문장으로 |
|
||||
|
|
@ -214,10 +199,7 @@ B 라면, 반응형에서 매번 바뀌는 것을 지목한 것이다. 지목하
|
|||
|
||||
| 지문 | 왜 문제 | 대신 |
|
||||
|---|---|---|
|
||||
| **랩탑 앞에서 웃는 다국적 팀 스톡 사진** | 방문자는 스톡을 알아보고 **신뢰도가 실제로 하락**한다 | 실제 팀 사진, 실제 작업 공간, 또는 사진 없이 타입으로 |
|
||||
| **떠 있는 3D 추상 블롭·기하 도형** | 콘텐츠 부재를 덮는 장식 | 제품 실제 화면, 데이터 시각화, 또는 여백 |
|
||||
| **AI 생성 일러스트** (지나치게 매끄럽고 대칭적) | 결함이 없어도 톤에서 티가 남 | 일러스트 시스템을 직접 정의하거나 아예 쓰지 않는다 |
|
||||
| **일반 SVG 도형을 조합한 히어로 그래픽** | 플레이스홀더 클립아트처럼 읽힘 | 제품 UI 조각을 실제로 렌더 |
|
||||
| **스톡 사진·추상 3D·AI 일러스트·일반 SVG 그래픽** | 이미지가 제품 증거·브랜드·정보 이해 대신 빈 자리를 메우는지 점검한다 | 실제 사진·제품 UI·데이터·일러스트·여백 중 과업을 가장 잘 설명하는 것을 선택하고, 출처·라이선스·alt·크롭을 검증한다 |
|
||||
| **아이콘 세트가 섞임** (라인·필·이모지 혼재) | 시스템이 없다는 증거 | 세트 하나 고정. 굵기·크기·광학 정렬 통일 |
|
||||
| **`src`가 비었거나 깨진 이미지 태그** | 검증 없이 배포된 흔적 | 배포 전 이미지 로드 전수 확인 |
|
||||
| **모든 이미지가 같은 비율의 둥근 사각형** | 그리드를 이미지에 강제 | 콘텐츠에 맞는 비율. 풀블리드 1장을 섞으면 리듬이 생긴다 |
|
||||
|
|
@ -226,25 +208,19 @@ B 라면, 반응형에서 매번 바뀌는 것을 지목한 것이다. 지목하
|
|||
|
||||
## 8. 한글 조판 (한국어 프로젝트 필수)
|
||||
|
||||
서구 갤러리에는 없는 규칙이다. **영문 기준을 그대로 쓰면 전부 깨진다.**
|
||||
한국어는 글꼴·줄바꿈·fallback·문장 리듬을 실제 콘텐츠와 지원 기기에서 별도로 검증한다. 영문 출발값을 그대로 복사하지 않는다.
|
||||
|
||||
| 규칙 | 값 | 이유 |
|
||||
|---|---|---|
|
||||
| **한글 폰트 미지정 금지** | `Pretendard` 또는 `본고딕` 명시 | 지정하지 않으면 시스템 기본(맑은 고딕 / Apple SD 산돌고딕)으로 떨어지고, 그 자체가 완성도 미달 신호다 |
|
||||
| **line-height를 영문보다 높게** | 본문 **1.6–1.8** | 한글은 글자 밀도가 높아 1.5로는 답답하다 |
|
||||
| **음수 자간 금지** | 본문 0, 대형 헤드라인만 -0.01 ~ -0.02em | 한글은 고정폭에 가까워 음수 자간이 즉시 뭉개진다 |
|
||||
| **`word-break: keep-all`** | `overflow-wrap: break-word`와 함께 | 기본값은 단어 중간에서 줄바꿈되어 어색하다 |
|
||||
| **한 줄 25–40자** | 영문 45–75자 기준을 쓰면 너무 길다 | 컨테이너 폭을 좁혀라 |
|
||||
| **라틴 폰트를 폴백 앞에** | `font-family: 'Satoshi', 'Pretendard', sans-serif` | 한글 폰트를 앞에 두면 라틴 문자까지 그 폰트로 그려진다 |
|
||||
| **번역투 금지** | `~를 통해`, `~에 대한`, `~에 있어서` | 영문 AI 카피를 기계 번역한 티가 난다. `~로`, `~의`, `~에서`로 |
|
||||
| **한글 글꼴과 fallback 미확인** | 한국어 glyph coverage·줄바꿈·숫자·운영체제 fallback이 과업에 맞는지 점검한다 | 시스템 한글 폰트를 포함해 실제 지원 기기에서 긴 제목·본문·숫자를 렌더하고, 선택·라이선스·fallback metric을 기록한다. 시스템 폰트 사용만으로 완성도 미달로 취급하지 않는다. 출처: `references/typography.md`, 프로젝트 브리프 |
|
||||
| **한글 line-height 후보** | 글꼴·크기·문단 길이·화면 폭에 따라 읽기 리듬이 달라진다 | 1.6–1.8을 포함한 후보를 실제 본문·확대 상태에서 비교한다. 특정 값이 보편 기준은 아니다 |
|
||||
| **한글 음수 자간** | 글리프 충돌·단어 인식·확대 상태에서의 읽기성을 점검한다 | 본문·대형 제목·지원 viewport·200% 확대에서 실제 렌더를 비교한다. 음수 자간의 존재만으로 실패시키지 않고, 충돌이나 읽기 저하가 확인되면 조정한다. 출처: `references/typography.md`, 프로젝트 렌더 검증 |
|
||||
| **줄바꿈·measure·fallback 순서** | 단어 단위 줄바꿈, 라틴/한글 숫자 렌더, 폭은 글꼴과 콘텐츠에 따라 달라진다 | `word-break`, `overflow-wrap`, measure, fallback 순서를 대표 문단·긴 단어·숫자·지원 기기에서 비교한다. 고정 글자 수나 순서를 규범으로 쓰지 않는다 |
|
||||
| **번역투 가능성** | 문맥·대상 독자와 맞지 않는 직역은 의미를 흐릴 수 있다 | 실제 독자와 용어 체계에 맞춰 문장을 다듬고, 제시 표현을 기계적 치환 규칙으로 쓰지 않는다 |
|
||||
|
||||
**한글 폰트 선택**
|
||||
- 기본값: **Pretendard** (SIL OFL, Thin~Black 9단계, 가변). CDN: `https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/variable/pretendardvariable.min.css`
|
||||
- 명조·에디토리얼: **마루 부리** (세리프 부활 트렌드의 한글 대응)
|
||||
- 수치 많은 UI: **Spoqa Han Sans Neo**
|
||||
- 다국어 안정성: **본고딕 / Noto Sans KR**
|
||||
- 캠페인 헤드라인: 배민 도현체·여기어때 잘난체 — **B2C 한정. B2B에 쓰면 즉시 아마추어**
|
||||
- 나눔고딕은 너무 흔하다. 폴백으로만.
|
||||
**한글 폰트 후보**
|
||||
- Pretendard, 마루 부리, Spoqa Han Sans Neo, 본고딕/Noto Sans KR 등은 목적·glyph coverage·라이선스·fallback·전송량을 비교할 후보다.
|
||||
- 캠페인 display 폰트도 업종 자체로 배제하지 않는다. 실제 문구·브랜드·작은 크기·지원 기기에서 읽기와 인상을 검증한다.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -281,11 +257,11 @@ It's not .* it's
|
|||
**한글 프로젝트 추가 검사**
|
||||
|
||||
```
|
||||
# 있어야 하는 것 — 없으면 실패
|
||||
# 확인 후보 — 프로젝트 계약과 실제 렌더로 평가
|
||||
word-break:\s*keep-all
|
||||
Pretendard|Noto Sans KR|본고딕|마루부리
|
||||
|
||||
# 없어야 하는 것
|
||||
# 세밀하게 확인할 후보 — 프로젝트 계약과 실제 렌더로 평가
|
||||
letter-spacing:\s*-0\.0[3-9] (한글 본문)
|
||||
~를 통해|~에 대한|에 있어서
|
||||
```
|
||||
|
|
@ -306,10 +282,10 @@ letter-spacing:\s*-0\.0[3-9] (한글 본문)
|
|||
|
||||
```js
|
||||
await page.evaluate(() => el.scrollIntoView({ block: 'center' }));
|
||||
await page.waitForTimeout(1600); // 반드시 애니메이션이 끝난 뒤에 잰다
|
||||
await page.waitForTimeout(1600); // 프로젝트의 모션 종료 조건을 확인한 뒤 잰다
|
||||
```
|
||||
|
||||
**② `sharp(...).extract(...).stats()` 는 잘라내기를 무시하고 원본 전체를 잰다.**
|
||||
**② `sharp(...).extract(...).stats()` 사용 결과가 의도한 crop 통계를 반영하는지 확인한다.**
|
||||
영역을 여섯 군데 잘라 밝기를 쟀는데 여섯 개가 **소수점까지 똑같이** 나왔다.
|
||||
전부 원본 전체 평균이었기 때문이다. 값이 수상하게 균일하면 도구를 먼저 의심해라.
|
||||
|
||||
|
|
@ -324,12 +300,10 @@ const s = await sharp(buf).stats(); // 잘라낸 버퍼를 다시 물려야
|
|||
겹쳐 있어서 "필터가 안 붙는다" 는 잘못된 결론이 나왔다. 멈춘 프레임을 그대로
|
||||
찍으려면 그 옵션을 **빼야** 한다.
|
||||
|
||||
> 여기서 더 중요한 결론이 나왔다 — **움직임으로 증명하려 들지 마라.**
|
||||
> 지나가는 프레임은 방문자도 놓치고 측정도 매번 다른 값을 준다.
|
||||
> 정지된 before/after 두 장이 더 정확하게 말한다.
|
||||
> 움직임이 핵심 주장을 전달한다면 정지 상태의 대체 증거와 함께 검증한다. 지나가는 프레임은 캡처 시점에 따라 달라질 수 있으므로, before/after 정지 캡처가 비교에 적합한 경우가 많다.
|
||||
|
||||
**④ 개별 요소의 높이로는 "여러 줄에 걸친 것" 을 못 잡는다.**
|
||||
"컨트롤이 2줄로 접히는가"(하드 게이트 6)를 이렇게 쟀다.
|
||||
"컨트롤 행이 지원 폭에서 읽거나 조작할 수 없게 되는가"를 이렇게 쟀다.
|
||||
|
||||
```js
|
||||
// 틀렸다 — 이 검사는 "접힘 0" 이라고 답한다
|
||||
|
|
@ -348,16 +322,15 @@ new Set([...document.querySelectorAll('.nav a')]
|
|||
```
|
||||
|
||||
같은 함정이 갤러리·태그 목록·버튼 그룹 어디에나 있다.
|
||||
**"몇 줄인가" 를 물을 때는 높이가 아니라 위치를 세라.**
|
||||
**"몇 줄인가"를 물을 때는 컨테이너의 위치 분포와 요소 높이를 함께 본다.**
|
||||
|
||||
**⑤ 눈으로 의심한 것이 실측에서 뒤집힐 수 있다.**
|
||||
WebGL 판이 본문 뒤를 지나가는 화면을 보고 "대비가 죽었다" 고 판단해 캔버스를
|
||||
어둡게 만들려 했다. 스크린샷에서 글자 사이 빈 띠의 배경 휘도를 재보니
|
||||
최악 지점이 **9.83:1** — AAA(7:1)를 넘었다. 고칠 필요가 없었다.
|
||||
밝은 것과 대비가 낮은 것은 다르다. **화려한 배경 위의 대비는 인상이 아니라 숫자로 판정해라.**
|
||||
밝은 것과 대비가 낮은 것은 다르다. 화려한 배경 위 텍스트는 실제 배경 합성 상태의 contrast ratio와 읽기 관찰을 함께 확인한다.
|
||||
|
||||
> 캔버스 위에서는 `readPixels` 가 안 통한다(three.md 참고). 스크린샷을 찍어
|
||||
> **글자를 피한 빈 띠**의 평균 휘도를 재는 것이 유일하게 맞는 방법이다.
|
||||
> 캔버스 접근 가능성은 렌더링 구성에 따라 다르다. 스크린샷 기반 측정은 한 방법이며, 텍스트와 배경의 실제 합성 상태를 대표하는 표본을 골라 계산한다.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -371,8 +344,7 @@ sticky 캔버스가 끝까지 돌려면 목록 뒤에 스크롤 구간이 필요
|
|||
문장 자체는 틀리지 않았다. 다만 **읽는 사람이 그 자리에서 기대하는 말이 아니다.**
|
||||
사용자가 처음 한 말이 "이건 왜 있는 거예요" 였다.
|
||||
|
||||
레이아웃이 필요해서 쓴 문장은 예외 없이 겉돈다. 여백이 필요하면
|
||||
`padding` 을 주고, 그 자리에 놓을 말이 정말 있을 때만 문장을 쓴다.
|
||||
레이아웃을 위해 추가한 문장이 콘텐츠 역할을 하지 않으면 겉돌 수 있다. 여백과 문장 중 어느 것이 목적을 더 잘 충족하는지 검토한다.
|
||||
|
||||
> 자가 진단: 이 문장을 지우면 **레이아웃이 깨지는가, 뜻이 빠지는가?**
|
||||
> 레이아웃만 깨진다면 그 문장은 여백의 대역이고, 여백으로 바꿔야 한다.
|
||||
|
|
@ -393,7 +365,7 @@ sticky 캔버스가 끝까지 돌려면 목록 뒤에 스크롤 구간이 필요
|
|||
**곁가지 하나가 본론의 1.3 배, 첫인상이 가장 짧다.** 분량 배분이 중요도와 정반대다.
|
||||
사용자 표현으로는 "정신이 없어 보인다".
|
||||
|
||||
부분 수정을 몇 번 하고 나면 반드시 전체를 다시 재라.
|
||||
부분 수정이 누적되면 전체 비율·읽기 순서·핵심 과업을 다시 측정한다.
|
||||
|
||||
```js
|
||||
// 섹션별 화면 수 — 배분이 우선순위와 맞는지 한 번에 보인다
|
||||
|
|
@ -453,26 +425,22 @@ sticky 캔버스가 끝까지 돌려면 목록 뒤에 스크롤 구간이 필요
|
|||
| 7 이미지 | | |
|
||||
| 8 한글 조판 | | |
|
||||
|
||||
**통과 조건 — 전부 예여야 한다**
|
||||
- [ ] 최우선 3종(보라 CTA / 전체 대문자 / 1·2·3 단계) 중 걸린 것이 없다
|
||||
- [ ] grep 검사에서 나온 항목을 전부 해소했다
|
||||
**검토 조건 — 근거와 결과를 남긴다**
|
||||
- [ ] 반복 후보(보라 CTA / 전체 대문자 / 1·2·3 단계)를 발견했으면 프로젝트 계약·브리프·실제 렌더 근거로 유지·수정·제거를 결정했다
|
||||
- [ ] grep 검사에서 나온 항목은 자동 실패로 취급하지 않고, 출처·관찰·결정·검증을 기록했다
|
||||
- [ ] 카피가 경쟁사 치환 테스트를 통과한다
|
||||
- [ ] 모션을 전부 끄고도 페이지가 작동한다
|
||||
- [ ] 강조색을 지워도 페이지가 읽힌다
|
||||
- [ ] 색을 회색조로 바꿔도 위계 순서가 비즈니스 우선순위와 일치한다
|
||||
- [ ] 키보드만으로 전 인터랙션이 가능하고 포커스 링이 보인다
|
||||
- [ ] (한국어) 한글 폰트가 명시되어 있고 `word-break: keep-all`이 있다
|
||||
- [ ] 모든 섹션에서 제목→본문 간격이 **같은 값**이다 (0px 인 섹션이 하나도 없다)
|
||||
- [ ] (한국어) 글꼴·fallback·줄바꿈 규칙이 실제 지원 기기와 긴 제목·본문·숫자에서 읽히는지 검증하고, 프로젝트 계약에 선택 근거를 남겼다
|
||||
- [ ] 제목→본문 간격이 각 섹션의 정보 관계를 설명하고, 의도하지 않은 0px·겹침·불균형이 없는지 실제 렌더에서 확인했다
|
||||
- [ ] 화면에 적은 수치는 **전부 그 화면을 캡처해 잰 값**이다 (추정치·기대치가 섞여 있지 않다)
|
||||
- [ ] 이미지 높이를 실제로 쟀다 — 원본 픽셀 높이가 그대로 나오면 `aspect-ratio` 가 죽은 것이다
|
||||
- [ ] 이미지의 실제 표시 비율·크롭·해상도가 의도한 콘텐츠 역할과 화면 폭에 맞는지 측정했다. 원본 픽셀과의 일치만으로 `aspect-ratio` 동작을 판정하지 않는다
|
||||
- [ ] 내비·버튼 그룹의 **행 수를 `top` 값으로** 셌다 (개별 높이로는 못 잡는다)
|
||||
|
||||
**판정**
|
||||
|
||||
| 걸린 개수 | 판정 |
|
||||
|---|---|
|
||||
| 0–1 | 통과 |
|
||||
| 2–3 | 해당 항목 수정 후 재검 |
|
||||
| **4 이상** | **폐기. reference-method.md §3부터 다시** |
|
||||
후보 수를 점수나 자동 통과 기준으로 쓰지 않는다. 각 후보마다 `프로젝트 계약`, `출처 ID`, `적용 조건`, `실제 렌더 관찰`, `유지·수정·제거 결정`, `검증 결과`를 남긴다. WCAG 성공 기준 또는 실제 기능 실패가 있으면 그 항목은 해결 전 통과로 선언하지 않는다. 그 밖의 스타일 후보는 과업·브랜드·위계·성능의 증거로 판정한다.
|
||||
|
||||
> 근거: research/references/04-ai-slop-signatures.md, 03-trends-2026.md (조사일 2026-08-20)
|
||||
> 근거와 한계: `references/evidence-ledger.md`, `references/design-foundations.md`, 프로젝트 브리프와 렌더 검증
|
||||
|
|
|
|||
149
packages/skill/references/art-direction.md
Normal file
149
packages/skill/references/art-direction.md
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
# art direction — 화면에서 판단할 수 있게 방향을 정하는 법
|
||||
|
||||
2단계에서 방향을 고르고, 3단계 토큰과 4단계 구현 전에 읽는다. 아트디렉션은 스타일 이름이나 색 견본을 고르는 일이 아니라, 실제 카피·자산·과업을 어떤 화면 질서로 보일지 결정하는 일이다.
|
||||
이 문서는 원전을 그대로 옮긴 규칙도, 특정 효과의 실험적 성과 주장도 아니다. 아래 출처와 프로젝트 렌더를 바탕으로 합성한 작업 절차다.
|
||||
|
||||
| 이 문서를 여는 때 | 여기서 얻는 결정 | 답이 부족할 때 필요한 추가 근거 |
|
||||
|---|---|---|
|
||||
| 첫 화면의 정보 순서·이미지 역할·섹션 리듬이 아직 불명확할 때 | 방문자 질문, 주장, 증거, 다음 행동과 그것의 화면 비중 | 실제 사용자 과업, 콘텐츠 소유자 확인, 브랜드 자산·권리·사실성, 지원 기기·상태별 렌더 |
|
||||
| 같은 스타일 안에서 구도·크롭·타입·밀도를 정해야 할 때 | 초점, 정렬선, 여백 역할, 원본·배포 크롭, proof sheet의 채택 근거 | 원본 자산, 실제 카피·수치·상태, 이미지 설명·접근성 요구, 배포 비율과 실제 viewport |
|
||||
| 한 선택의 품질이나 과업 적합성을 판정할 때 | 동일 조건에서 비교할 관찰·원인 후보·한 가지 수정 | 프로젝트 계약, 사용성·접근성 규범, 기능·성능 측정, 필요하면 해당 분야의 1차 출처 또는 현장 검증 |
|
||||
|
||||
출처가 현재 질문을 직접 지지하지 않으면 이 문서의 예시를 규칙으로 확대하지 않는다. 필요한 과업·자산·규범의 1차 근거를 새로 확인하고, 그 범위와 한계를 프로젝트 기록에 남긴다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 대안을 언제 비교할지 먼저 정한다
|
||||
|
||||
큰 불확실성이 있는 디자인 결정에서만 구조가 다른 대안을 작게 비교한다. 예를 들어 첫 화면이 공간의 분위기를 먼저 보여야 하는지, 예약 가능한 시간과 위치를 먼저 보여야 하는지처럼 정보 순서가 바뀌는 결정이다.
|
||||
이때의 대안은 색·서체·사진만 바꾼 변형이 아니라, 질문에 답하는 순서와 화면 골격이 달라야 한다.
|
||||
|
||||
| 상황 | 할 일 | 하지 않을 일 |
|
||||
|---|---|---|
|
||||
| 브랜드·과업·정보 우선순위가 아직 불확실함 | 서로 다른 구조를 가진 소수 안을 같은 콘텐츠로 비교 | 시안 수를 의무화하거나 장식만 바꾼 안을 세기 |
|
||||
| 브랜드 방향과 핵심 구조가 확정됨 | 기존 방향 안에서 카피·크롭·밀도 후보를 고름 | 확정된 정체성을 매 화면마다 다시 경쟁시킴 |
|
||||
| 국소 컴포넌트나 상태를 다듬음 | 그 화면의 과업과 상태를 기준으로 후보를 비교 | 전체 랜딩의 AIDA나 히어로 구도를 복사 |
|
||||
|
||||
결정마다 `무엇이 불확실한가 / 구조 차이는 무엇인가 / 같은 조건은 무엇인가 / 채택 이유는 무엇인가`를 `design.md`에 남긴다. 대안 탐색은 좁은 문제를 확인하는 절차이며, 더 많은 안이 더 좋은 결과를 보장하지 않는다.
|
||||
|
||||
## 2. 콘텐츠 편집표로 화면의 일을 정한다
|
||||
|
||||
레이아웃 전에 각 화면 또는 섹션이 답해야 할 질문을 적는다. 마케팅 서사에 유용한 순서가 있어도 기능 화면·운영 화면에 AIDA를 강요하지 않는다.
|
||||
|
||||
| 방문자 질문 | 핵심 주장 | 실증 콘텐츠 | 행동 또는 다음 정보 | 화면 비중 |
|
||||
|---|---|---|---|---|
|
||||
| 여기는 무엇이며 나에게 왜 중요한가 | 한 문장 가치 | 실제 결과, 공간, 사례, 수치의 출처 | 더 보기, 예약, 시작 | 첫 화면에서 가장 크게 |
|
||||
| 이 주장을 믿을 근거가 있는가 | 구체적 차이 | 과정, 비교, 고객 맥락, 검증 가능한 정보 | 세부 근거로 이동 | 주장 다음에 충분히 |
|
||||
| 지금 무엇을 해야 하는가 | 다음 행동의 비용과 결과 | 가격, 일정, 준비물, 현재 상태 | 실행, 저장, 문의 | 행동 직전에 읽히게 |
|
||||
| 일이 진행 중인 운영 화면인가 | 지금의 상태와 예외 | 목록, 필터, 경고, 최근 변경 | 처리, 검토, 복구 | 빈도·위험도에 비례 |
|
||||
|
||||
행마다 실제 문장, 실제 데이터, 실제 자산을 붙인다. 주장이 있는데 실증 콘텐츠가 없으면 장식으로 덮지 말고 주장 범위를 줄이거나 근거를 확보한다.
|
||||
행동이 없으면 CTA를 억지로 추가하지 말고 다음에 필요한 정보를 우선한다.
|
||||
|
||||
## 3. 실제 재료로 구도 축을 고른다
|
||||
|
||||
빈 로렘입숨과 회색 상자로 구도를 확정하지 않는다. 실제 한글·영문 카피, 제목 길이, 숫자, 사진·도표·상태를 넣고 아래 축 중 필요한 것을 고른다.
|
||||
|
||||
| 구도 축 | 질문 | 렌더에서 확인할 것 |
|
||||
|---|---|---|
|
||||
| 초점 | 처음 시선이 닿아야 하는 것은 무엇인가 | 제목·행동·증거 중 하나가 경쟁 없이 먼저 읽히는가 |
|
||||
| 정렬선 | 무엇이 같은 관계로 묶이는가 | 제목, 수치, 표, 행동의 시작선이 의미를 드러내는가 |
|
||||
| 큰 면과 작은 정보 | 무엇이 면적을 가져야 하는가 | 큰 사진·제목이 보조 정보의 읽기를 막지 않는가 |
|
||||
| 여백의 역할 | 비어 있는 면이 무엇을 돕는가 | 분리, 대기, 방향, 강조 중 이유 없이 빈 곳은 없는가 |
|
||||
| 이미지와 텍스트 관계 | 둘은 같은 주장인가 다른 역할인가 | 텍스트가 사진 속 사실을 과장하거나 반복하지 않는가 |
|
||||
|
||||
색만 바꾼 안은 별도 구조안이 아니다. 사진 위 텍스트는 대비만 보지 말고, 피사체·캡션·행동이 같은 의미를 말하는지 확인한다.
|
||||
수치·상태·가격·주소처럼 수정 가능하고 사실 검증이 필요한 정보는 이미지 안에 굽지 않는다.
|
||||
|
||||
## 4. 이미지는 원본과 배포 크롭을 함께 검토한다
|
||||
|
||||
이미지의 품질은 원본 파일만으로 판정하지 않는다. 원본, 데스크톱 배포 크롭, 모바일 배포 크롭을 나란히 놓고 슬롯별로 아래를 기록한다.
|
||||
|
||||
| 기록 항목 | 확인 질문 |
|
||||
|---|---|
|
||||
| 주피사체 | 이 화면에서 반드시 남아야 하는 사람·제품·공간·행동은 무엇인가 |
|
||||
| 시선 방향 | 인물·물체·선이 카피나 다음 행동으로 시선을 보내는가 |
|
||||
| 사라지는 맥락 | 크롭 뒤에 장소·관계·사용 장면의 뜻이 사라지지 않는가 |
|
||||
| 데스크톱 초점 | 넓은 비율에서도 핵심이 안전 영역에 남는가 |
|
||||
| 모바일 초점 | 좁은 비율에서 핵심이 폴드 아래·텍스트 뒤로 밀리지 않는가 |
|
||||
| `object-position` | 같은 원본을 쓸 때 각 비율에서 의도한 초점 좌표가 명시됐는가 |
|
||||
|
||||
한 장의 원본을 모든 슬롯에 억지로 쓰지 않는다. 반대로 비교를 위해 여러 이미지를 인위적으로 생성할 필요도 없다. 필요한 슬롯에 실제로 다른 구도가 필요할 때만 별도 자산을 고른다.
|
||||
이미지 조달·진실 라벨·대체 텍스트의 세부는 [images.md](images.md)와 `trustworthy-showcases.md`를 따른다.
|
||||
|
||||
## 5. 타입은 proof sheet에서 결정한다
|
||||
|
||||
폰트 이름, 문자 견본, 한 줄 영문만으로 위계를 확정하지 않는다. 새 서체·타입 계층을 고르거나 변경이 줄바꿈·밀도·상태 인지에 영향을 줄 때만, 같은 폭과 크기에서 실제 콘텐츠를 넣은 proof sheet를 만든다.
|
||||
|
||||
- 프로젝트에서 쓰는 언어의 본문과 긴 제목
|
||||
- 표시하는 가격·날짜·비율·음수·증감 같은 숫자
|
||||
- 실제로 쓰는 선택됨, 오류, 비활성, 처리 중 같은 상태 텍스트
|
||||
- 변경 범위에 있는 버튼 라벨, 표 머리글, 카드 보조 정보
|
||||
|
||||
그 뒤 줄바꿈, 숫자 폭, 밀도, 상태의 구분, 확대 상태에서의 읽기를 비교한다. 서체 선택·로딩·폴백 메트릭·라이선스와 한글 조판의 정본은 [typography.md](typography.md)다.
|
||||
proof sheet는 멋의 순위를 매기는 카드가 아니라, 이 프로젝트의 실제 글자가 어떤 구도를 요구하는지 확인하는 증거다.
|
||||
|
||||
## 6. 전체 스크롤의 리듬을 편집한다
|
||||
|
||||
반복은 나쁜 것이 아니다. 같은 데이터·행동·비교 규칙을 읽게 하는 반복은 보존한다. 문제는 역할이 다른 섹션이 같은 제목·카드·장식만 반복해서 스크롤이 정보를 더하지 않을 때다.
|
||||
|
||||
1. 각 섹션의 의미 단위와 다음 행동을 목록화한다.
|
||||
2. 같은 의미 단위는 같은 리듬을 유지한다.
|
||||
3. 정보 관계가 달라지면 필요한 순서·밀도·배치를 조정한다.
|
||||
4. 장식만 변주해 다른 섹션처럼 보이게 하지 않는다.
|
||||
5. 긴 페이지는 폴드마다 무엇이 새로 이해되거나 진행되는지 실제 스크롤에서 확인한다.
|
||||
|
||||
리듬을 바꾸는 이유는 새 배경색이나 카드 모양이 아니라 독자의 질문과 과업이 바뀌었기 때문이다.
|
||||
|
||||
## 7. 실제 화면에서 한 번에 하나씩 비평한다
|
||||
|
||||
소스 코드나 모형을 보고 완성도를 선언하지 않는다. 같은 viewport, 상태, 카피, 자산에서 전후 렌더를 비교한다.
|
||||
|
||||
1. **관찰**: 무엇이 먼저 읽히는지, 어디에서 시선·행동·관계가 끊기는지 적는다.
|
||||
2. **원인 후보**: 구도, 카피 길이, 크롭, 위계, 상태 밀도 중 가능한 원인을 좁힌다.
|
||||
3. **한 가지 수정**: 한 번에는 한 원인 가설만 바꾼다.
|
||||
4. **동일 조건 비교**: 같은 폭·상태·콘텐츠에서 전후를 보고 유지·되돌림·다음 수정을 결정한다.
|
||||
|
||||
비평은 아래 세 관점에서 따로 적는다.
|
||||
|
||||
| 관점 | 확인 질문 | 주장하지 말 것 |
|
||||
|---|---|---|
|
||||
| 독창성 | 이 브랜드·과업·자산에서만 나올 이유가 보이는가 | 낯선 효과 하나가 고유성을 증명한다 |
|
||||
| 완성도 | 정렬, 타입, 크롭, 여백, 상태가 같은 규칙으로 끝까지 유지되는가 | 자동 심미 점수가 품질을 증명한다 |
|
||||
| 과업 | 사용자가 다음 정보와 행동을 예측·완료·복구할 수 있는가 | 시각 점수만으로 성공률이나 전환 인과를 증명한다 |
|
||||
|
||||
완료 판정은 세 갈래로 분리한다: 사용성·접근성 규범, 프로젝트의 기능·성능 계약, 시각 평가.
|
||||
한 갈래의 통과가 다른 갈래의 통과를 대신하지 않는다.
|
||||
|
||||
## 8. 같은 규칙도 화면에 따라 다르게 쓴다
|
||||
|
||||
### 공간 포트폴리오
|
||||
|
||||
방문자 질문은 “이 장소의 분위기와 작업 범위가 내 프로젝트에 맞는가”다.
|
||||
첫 화면은 실제 공간의 주피사체와 짧은 주장으로 관계를 만들고, 다음 섹션은 재료·과정·완성 공간의 증거로 이어진다.
|
||||
카피가 길지 않다면 큰 이미지 면과 넓은 여백이 장소의 규모·빛·질감을 읽게 할 수 있다.
|
||||
모바일 크롭에서 창, 사람의 행동, 재료 중 무엇이 사라지면 장소의 뜻이 바뀌는지 기록한다.
|
||||
문의 행동은 검증 가능한 범위·일정 정보 다음에 둔다.
|
||||
|
||||
### 밀집 운영 화면
|
||||
|
||||
방문자 질문은 “지금 무엇이 막혔고 어떤 항목부터 처리해야 하는가”다.
|
||||
첫 화면은 분위기 사진보다 상태, 위험, 우선순위, 가능한 행동을 먼저 둔다.
|
||||
같은 종류의 행·필터·수치는 반복 구조를 유지해야 비교가 빠르며, 여백은 장식보다 군집과 오류 복구를 돕는다.
|
||||
큰 영문 타이틀이나 풀블리드 이미지를 공간 포트폴리오처럼 복사하면 상태 정보와 행동이 밀릴 수 있다.
|
||||
타입 proof sheet에는 긴 한국어 상태, 숫자 열, 비활성·오류 라벨을 넣어 밀도에서 실제로 비교한다.
|
||||
|
||||
두 화면 모두 실제 콘텐츠, 구도 축, 원본과 크롭, 동일 조건 비평을 쓴다.
|
||||
다만 질문과 실증 콘텐츠가 다르므로 면적·정렬선·리듬·행동 순서를 같게 만들 이유는 없다.
|
||||
|
||||
## 근거와 적용 경계
|
||||
|
||||
| ID | 출처와 역할 | 이 문서에서의 사용 한계 |
|
||||
|---|---|---|
|
||||
| DC-DIAMOND | [Design Council, Double Diamond](https://www.designcouncil.org.uk/resources/the-double-diamond/) · practice | 불확실한 문제에서 소규모 대안 탐색과 검증의 절차 참고이며, 시안 수나 성과의 근거가 아니다 |
|
||||
| VA-MOFFAT | [V&A, Curtis Moffat: Working Methods](https://www.vam.ac.uk/articles/curtis-moffat-working-methods) · case · 2025-09-24 | contact print와 crop을 한 작업 사례로 참고하며, 모든 프로젝트의 이미지 절차로 일반화하지 않는다 |
|
||||
| CH-DESCRIPTION | [Cooper Hewitt image description guidelines](https://www.cooperhewitt.org/cooper-hewitt-guidelines-for-image-description/) · practice | 중요한 정보부터, 공간 관계를 따라 설명하는 방식을 참고한다. alt 단어 수를 고정하지 않는다 |
|
||||
| LUPTON-POSTERS | [How Posters Work](https://www.cooperhewitt.org/publications/how-posters-work/) · bibliography | 책의 소개·서지 확인만 한다. 원문을 읽었거나 개념을 인용했다는 주장이 아니다 |
|
||||
| GOV-IMAGES | [GOV.UK Design System: images](https://design-system.service.gov.uk/styles/images/) · practice | 정부 서비스 범위에서 과업 정보·맥락·alt를 다루는 지침이다. 감성 사진 금지를 상업 브랜드에 일반화하지 않는다 |
|
||||
|
||||
출처의 상세 기록 형식과 사용성·접근성·성능 검증은 [evidence-ledger.md](evidence-ledger.md), [design-foundations.md](design-foundations.md), 프로젝트의 `design.md`를 함께 따른다.
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
5단계(감사)를 **완료 선언의 게이트**로 만드는 문서다. 핵심 원칙은 하나다:
|
||||
|
||||
> **완료의 정의는 게이트 통과다. 사용자를 QA 로 쓰지 않는다.**
|
||||
> **완료는 기능·프로젝트 계약·렌더 시각 평가가 함께 확인된 상태다. 사용자를 QA 로 쓰지 않는다.**
|
||||
|
||||
"고쳤다"는 말의 근거는 검증 리포트의 수치다. 게이트가 실패 항목을 내면 4단계로 돌아가 고치고 **다시 전체를 돌린다** — 고친 것만 재검하지 않는다. 이 루프(구현 → 게이트 → 실패 → 수정 → 재게이트)가 designpaca의 기본 동작이며, 게이트 없이 6단계로 넘어가는 것은 경로 무관 금지다.
|
||||
"고쳤다"는 말의 근거는 검증 리포트의 수치와 실제 렌더 평가다. 게이트가 실패 항목을 내면 4단계로 돌아가 고치고, 변경한 영역과 연결된 회귀 위험을 다시 검사한다. 프로젝트가 정한 전체 검증 계약은 그대로 수행한다. 이 루프(구현 → 게이트 → 실패 → 수정 → 재게이트)가 designpaca의 기본 동작이며, 기능·접근성 자동 검사와 시각 평가(위계·브랜드·타입·구도·이미지·리듬)는 별도 결과로 보고한다.
|
||||
|
||||
## 왜 필요한가 — 실제 사고 목록
|
||||
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
| 브랜드가 모바일에서 1글자 폭으로 수축, 세로로 쌓임 | 수축 탐지(짧은 라벨 n줄 이상) + 브랜드 1줄 |
|
||||
| 기기 글꼴 확대(안드로이드 큰 글꼴 1.3×)에서 제목 부서짐 | 스케일×폭 h1 행렬 |
|
||||
| 본문 보조색이 배경 대비 4.4:1 (AA 미달) | 전 요소 대비 스캔(블렌드 계산) |
|
||||
| CSS `color-mix()`의 computed `color(srgb …)`를 0~255 rgb로 오독해 정상 대비를 1:1로 거짓 실패 | CSS Color 4 `color(srgb 0~1)` 파싱 + 알파 합성 RED fixture |
|
||||
| `.sr-only`·`aria-hidden` 장식·빈 overlay의 범위를 보이는 셀/버튼 글자로 합산해 0px 여백 거짓 실패 | text node 단위 실측 + 비가시 조상 제외. 화면에 보이는 글자만 인셋 판정 |
|
||||
| 조사만 하고 안 고친 영역(관심 과목 등) | 전 뷰 순회 — 검사는 '내가 고친 것'이 아니라 전체 표면 |
|
||||
| 대시보드 26명 ↔ 명단 12명 숫자 모순 | 콘텐츠 정합(요약 = 재계산 비교) |
|
||||
| aria-label 을 div/ul 에 오용(보조기술 무시) | html-validate + axe |
|
||||
|
|
@ -29,12 +31,14 @@
|
|||
| 같은 명시도의 숨김 규칙이 기본 규칙보다 앞에 있어 짐 — 모바일에서 숨기려던 kbd 안내가 렌더됨(6% 시각 diff) | 시각 회귀 + 규칙: **숨김 오버라이드는 기본 규칙보다 파일 뒤쪽에** 두거나 컴포넌트 규칙 근처의 미디어쿼리로 |
|
||||
| 탐색 차터가 결과를 단언하지 않아 "9288점" 입력이 조용히 통과(값을 덧붙인 타이핑) | 하니스 규칙 8(검사는 단언)·9(number 입력 조작) |
|
||||
| 모바일 라운드 — 중앙 모달이 썸존 밖, 백 키가 앱을 통째로 종료, safe area 무시, 입력 확대 | L6 시나리오(백·시트·터치타깃 스윕) + `references/mobile-app-ux.md` 표준 — **OS 관습은 조사 없이 바꾸지 않는다** |
|
||||
| 전역 `* { margin: 0 }`가 native dialog의 UA 중앙 여백을 지워 좌상단에 고정, 짧은 화면의 패널은 고정 크롬에 눌려 내부 scroll이 0px | dialog의 `fixed/inset/margin:auto`를 명시하고 390·1440·2560 중심 오차, viewport rect, `html` scroll lock, short-height scroll owner를 hard fail로 측정. 모달 행동은 [WAI-ARIA APG](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/)를 따른다 |
|
||||
| 2560px 분할 히어로에서 사진이 1400px 이상으로 팽창하고 카피 열은 200px 안팎으로 붕괴 | hero·copy·media·후속 정보 레일의 rect 계약. stage/media/copy/workbench 토큰을 분리하고 media 상한·copy 최소폭·정렬을 hard fail로 측정 |
|
||||
| 탭 전환 스크롤 잔류 — 짧은 뷰에서 클램프되어 헤더 반쯤 잘림, 뷰마다 크롬 위치 제각각 | 뷰 전환 `scrollTo(0,0)` 단언(M5) + mobile-app-ux.md |
|
||||
| 크럼을 헤더로 내보내 빈약한 헤더 — 계측 전부 통과했지만 사용자에게 '깨져 보인다' | 헤더 sticky·브랜드+액션 구조 단언 + **시각 무게 평가(눈)** — mobile-app-ux.md |
|
||||
| 왼쪽 인셋 리듬 불일치(제목 16 vs 앱바·카드 24) — 오버플로 검사는 오른쪽만 보므로 통과 | M6 왼쪽 인셋 스위트(텍스트 시작점 ≥12px·같은 축 ±10px) + preflight §0-E |
|
||||
| 모바일에서 절대 배치 지도 자식의 부모를 `position: static`으로 바꿈 — offsetParent가 BODY가 되어 격자·핀이 히어로 전체를 덮음. 기하 게이트 8/8 통과 | **상태별 실제 캡처를 열어 보는 시각 E2E** + absolute/fixed 자식의 containing block 단언(하니스 규칙 19) |
|
||||
| 새 관리자·가맹 서브페이지가 생겼지만 `public/work/*/index.html`만 검사 — 새 HTML 오류 8건이 검증 밖 | 정적 입력을 `public/work/**/*.html`·`**/*.css`로 재귀화 + 검사 대상 파일 수 단언(하니스 규칙 20) |
|
||||
| 마케팅 h1의 의도적 2줄 때문에 범용 1줄 규칙을 꺼 버릴 위험 | 기본 1줄 유지 + 페이지별 `h1MaxLines` 계약. 375·390 × 글꼴 확대 매트릭스도 같은 상한 적용 |
|
||||
| 마케팅 h1의 의도적 2줄 때문에 범용 줄 수 규칙을 강제할 위험 | 페이지별 읽기 폭·문구·글꼴 확대의 계약을 기록하고 375·390 × 글꼴 확대에서 실제 줄 수와 가독성을 판정. 줄 수를 맞추려고 글자 크기를 축소하지 않음 |
|
||||
|
||||
## 7계층
|
||||
|
||||
|
|
@ -44,7 +48,7 @@
|
|||
|---|---|---|
|
||||
| L0 정적 | stylelint + html-validate | 문법·구문 위반을 브라우저 켜기 전에 |
|
||||
| L1 단위 | 순수 계산 로직 추출(calc.js) + 경계값 테스트 | 프로젝트별 작성 — 0명/만석/초과/빈배열. **입력 검증·신청 가능 같은 '판정'(가능/불가+사유)도 여기 둔다** — UI 는 판정을 문장으로 번역만 |
|
||||
| L2 불변식 | `design-gate.mjs` — 오버플로·h1·수축·대비·SEO/meta·죽은 선택자·토큰 위생·theme-color 정합 | 전 뷰 × 전 폭 |
|
||||
| L2 불변식 | `design-gate.mjs` — 오버플로·제목 존재/가시성·수축·대비·SEO/meta·죽은 선택자·토큰 위생·theme-color 정합. 명시한 양의 `h1MaxLines`만 줄 수 계약으로 검사 | 전 뷰 × 전 폭 |
|
||||
| L3 시각 회귀 | 기준 화면 pixelmatch diff (≥0.1% 실패) + 핵심 상태 캡처 | 갱신은 검증된 배포 후 `--update-baseline`. 캡처 존재와 사람의 시각 판정은 별개다 |
|
||||
| L4 WebKit | Playwright webkit | 사파리 엔진 렌더 차이 |
|
||||
| L5 탐색 | 키보드 완전 통과 + 사용자 여정 차터 | 프로젝트별 작성 — 마우스 금지 |
|
||||
|
|
@ -70,7 +74,7 @@ L1·L5 는 프로젝트 안에 `tools/unit/*.test.mjs`, `tools/exploratory.mjs`
|
|||
|
||||
- **Windows**: 스크롤바가 오버레이가 아니다 — `overflow-x:auto` 짝에는 `overflow-y:hidden` + `scrollbar-width` 검토. 스크롤바 자체가 레이아웃을 민다.
|
||||
- **iOS/Safari(WebKit)**: `100vh` 주소창 문제(`100dvh`), 텍스트 인플레이션(`-webkit-text-size-adjust:100%`), WebKit 만의 flex/행높이 차이 → L4 로 재검.
|
||||
- **안드로이드**: 시스템 글꼴 확대(1.15~1.3× 흔함) — rem 전면 확대로 제목 칸 수축 → 스케일×폭 행렬으로 재현·검증.
|
||||
- **안드로이드**: 시스템 글꼴 확대는 제목·컨트롤을 수축시킬 수 있다. gate의 `fontScales`와 computed root 스케일은 회귀 신호일 뿐, px 고정 서체의 실제 OS 확대를 보장하지 않는다. 실제 접근성 확대와 WCAG 200% zoom은 별도 브라우저·기기 검증으로 보고한다.
|
||||
- **폰트 스왑**: `font-display: swap` 의 CLS — 폴백 메트릭 보정(typography.md §4) 없이 검사 통과를 선언하지 않는다.
|
||||
|
||||
## 하니스 규칙 (테스트를 만드는 테스트)
|
||||
|
|
@ -103,12 +107,18 @@ L1·L5 는 프로젝트 안에 `tools/unit/*.test.mjs`, `tools/exploratory.mjs`
|
|||
26. **진실 라벨은 개수가 아니라 의미 범위를 단언한다** — 같은 상태·출처·행동 가능성을 공유하는 자식은 제목과 경계가 분명한 가장 가까운 공통 부모가 한 번 소유하고 프로그램적으로 연결한다. 상태가 다른 자식만 예외 라벨을 둔다. 같은 공개 문구가 한 그룹의 모든 자식에 복제되면 범위 설계를 다시 본다.
|
||||
27. **보이는 입력과 판정 의존성을 같은 SSOT로 잠근다** — 폼의 사용자 조건 이름 집합과 순수 판정 함수가 참조하는 사용자 조건 집합을 비교한다. 숨은 기본값을 사용자 선호로 세지 않고, 보이는 입력을 무시하지 않으며, 분석 전 완료 결과가 없고 복합 비용 일부로 적합을 확정하지 않는지 단언한다.
|
||||
28. **공개와 관리 콘텐츠 소유권을 테스트한다** — 공개 DOM에는 내부 ID·원문 출처 원장·규제 채널 상수·감사 로그를 복제하지 않는다. 대신 사용자 행동을 막거나 바꾸는 제한과 해석 가능한 이유는 남긴다. 관리자는 그 요약을 재현하는 출처·검증 이벤트·판정 기록을 가진다.
|
||||
29. **색·가시성 측정기는 새 CSS 문법과 보이는 텍스트를 구분한다** — computed color가 CSS Color 4 `color(srgb r g b / a)`이면 0~1 채널을 0~255으로 변환하고, 반투명 배경은 자식에서 부모 방향으로 올바르게 합성한다. `Range.selectNodeContents()`로 sr-only·`aria-hidden` 장식·빈 overlay까지 합산하지 말고 실제 보이는 text node의 rect만 잰다. 두 경우 모두 UI를 고치기 전에 RED fixture → 파서 수정 → 같은 fixture GREEN 순서로 검사기 자체를 검증한다.
|
||||
30. **native dialog의 위치를 UA 스타일에 맡기지 마라** — 전역 reset은 dialog의 기본 margin을 지울 수 있다. open 상태에서 `(left + width/2, top + height/2)`와 viewport 중심의 오차, 화면 안 rect, `html` overflow, Escape 뒤 복귀를 390·1440·2560에서 측정한다. 내용이 길면 dialog 또는 내부 본문 하나만 scroll owner여야 한다.
|
||||
31. **초광폭 히어로는 비율 계약을 잰다** — 2560 같은 실제 wide viewport에서 hero 폭/정렬, copy 최소 폭, media 최대 폭, 다음 정보 레일 폭을 함께 단언한다. media만 넓고 카피가 가늘어지는 상태를 `overflow=0`으로 통과시키지 않는다. 절대 수치는 페이지별 토큰이 소유하며, 풀블리드 편집 사진 예외는 이유를 기록한다.
|
||||
32. **캐시 무효화도 사용자 화면에서 단언한다** — static CSS/JS를 덮어쓴 뒤 HTML만 새 URL이면 브라우저는 이전 stylesheet를 계속 쓴다. stylesheet와 `@import` 의 버전을 같이 바꾸고, 공개 URL에서 실제 href·새 토큰/핵심 computed value를 검사한다. HTTP 200과 새 HTML만으로 배포 성공을 선언하지 않는다.
|
||||
33. **썸네일은 안정한 프레임만 저장한다** — 캡처 전 local HTTP 경로에서 `document.fonts.ready`·모든 이미지 `decode()`·bounded settle을 기다리고, `prefers-reduced-motion: reduce`를 적용한다. 그 뒤 video/audio·CSS/WAAPI·rAF canvas를 멈추고, local 4xx·pageerror·깨진 이미지가 하나라도 있으면 실패시킨다. 원리는 `animation:none`으로 초기 상태를 재현하는 것이 아니라 **완성된 한 프레임을 고정**하는 것이다. 카드·OG·핵심 상태가 같은 계약을 공유하는지 파일 치수·0바이트·시각 검수까지 단언한다.
|
||||
34. **초광폭 text-media split은 가족별로 잰다** — hero가 통과했다고 과정·추천·가맹 분할이 통과한 것이 아니다. 서로 다른 DOM/여백 규칙을 가진 각 split root에서 1920·2560의 rail, copy/media rect, heading의 실제 내용 폭과 줄 수를 hard fail로 기록한다. wide override는 양쪽 logical padding을 명시하고, 상위 container의 `max-width`가 specificity 때문에 named stage를 다시 줄이지 않는지 단언한다. grid 바깥 rect가 정상이어도 text content가 한 글자 열로 수축하면 실패다.
|
||||
|
||||
## 리포트 양식
|
||||
|
||||
```
|
||||
게이트: 전 계층 통과 — 배포 가능 · 총 Ns
|
||||
| 계층 | 결과 | 항목 | 소요 |
|
||||
게이트: 기능·접근성 자동 검사 / 시각 평가를 별도 보고 · 총 Ns
|
||||
| 범주 | 결과 | 항목 | 소요 | 근거 |
|
||||
```
|
||||
|
||||
실패 상세는 원문 테일 포함. 리포트 파일(gate-report.md / verify-report.md)은 커밋 대상이다.
|
||||
실패 상세는 원문 테일 포함. 시각 평가는 같은 viewport·상태·자산을 전후로 보존해 위계·브랜드·타입·구도·이미지·리듬을 기록한다. 사용자 성과의 인과나 취향 우승을 검증 없이 주장하지 않는다. 리포트 파일(gate-report.md / verify-report.md)은 커밋 대상이다.
|
||||
|
|
|
|||
67
packages/skill/references/design-foundations.md
Normal file
67
packages/skill/references/design-foundations.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# design foundations — 근거를 결정으로 바꾸는 법
|
||||
|
||||
교과서 요약집이 아니다. 각 원칙은 실제 과업에서 무엇을 확인할지 정하는 도구다. 출처의 상세 범위는 [evidence ledger](evidence-ledger.md)를 따른다.
|
||||
|
||||
## 1. 먼저 성공 과업을 한 문장으로 적는다
|
||||
|
||||
`누가 / 어떤 맥락에서 / 무엇을 / 어떤 위험 없이 끝내야 하는가`를 쓴다. 시각 방향은 그 뒤에 고른다. 첫 화면의 주장은 이름, 가치, 다음 행동을 모두 억지로 넣는 공식이 아니라 이 과업의 다음 결정을 충분히 설명하는지로 판정한다.
|
||||
|
||||
| 원칙 | 지지 주장 | 적용 조건 | 잘못된 일반화 | 구체 검증 | 예시 결정 |
|
||||
|---|---|---|---|---|---|
|
||||
| 관련성 | 불필요한 정보는 관련 정보의 가시성과 경쟁한다 [NNG-HEUR] | 첫 선택과 오류 복구가 중요한 화면 | 요소 수가 적을수록 좋다 | 대표 과업에서 필요한 정보가 같은 화면에 있는지 본다 | 가입 전 가격 세부는 요약+상세 링크로 분리 |
|
||||
| 위계 | 크기·명도·위치·여백은 함께 작동해 시선을 만든다 [NNG-VISUAL] | 스캔이 필요한 랜딩·목록 | h1:h2 비율 하나로 판정 가능 | 회색조 캡처를 짧게 보고 제목·주요 행동·본문의 읽는 순서를 기록한다 | CTA만 색 대비, 섹션 제목은 공간 대비 |
|
||||
| 근접성·유사성·공통 영역 | 가까움, 공통 외곽, 유사한 표식은 관계를 읽히게 할 수 있다 [GESTALT] | 반복 모듈과 복잡한 정보 | 모든 영역이 12열 중앙 정렬이거나 카드여야 한다 | 카드·표·CTA의 묶음·분리·선택 상태를 회색조와 실제 과업에서 본다 | 사양과 가격은 한 group, 관련 도움말은 다음 group |
|
||||
| 정렬과 그리드 | 일관된 column·gutter·breakpoint는 제품 UI의 정렬 기준을 제공한다 [IBM-GRID] | 여러 화면의 반복 표면 | Carbon 격자나 특정 열 수가 보편 정답이다 | 콘텐츠 폭, 정렬선, 작은 폭의 재배치를 검증한다 | 읽는 surface와 비교 surface에 다른 폭 토큰을 둔다 |
|
||||
| 직접 조작 | 멀수록 작을수록 조준이 느리고 오류가 늘 수 있다 [FITTS] | 빈번한 포인터 행동 | 모든 버튼을 크게 만들면 해결된다 | 실제 hitbox, 거리, 인접 오탭을 관찰한다 | 아이콘만 누르게 하지 않고 라벨까지 클릭 가능하게 |
|
||||
| 단서와 선택 설계 | 행동 단서는 지각 가능해야 하고, 선택 비용은 선택지 수만 아니라 구분·라벨·목표에 좌우된다 [NORMAN-SIGN, HICK, KRUG] | 내비·필터·설정 | 7±2로 메뉴 수를 제한한다 | 사용자가 목표 항목을 찾는 시간·오류를 본다 | 9개 항목을 사용자 과업별 3개 묶음으로 재분류 |
|
||||
| 기억보다 인지 | 화면의 상태·다음 행동·되돌림을 드러내면 기억 부담을 낮춘다 [NNG-HEUR, MILLER] | 다단계·파괴적 행동 | 모든 것을 항상 보여야 한다 | 뒤로가기·오류·재진입에서 상태가 복구되는지 시험한다 | 업로드 후 파일명·교체·삭제를 같은 표면에 노출 |
|
||||
| 인지 부하 | 과업에 필요 없는 기억·변환·탐색 단계를 줄이면 문제 해결 부담을 낮출 수 있다 [COGNITIVE-LOAD] | 낯선 절차·설정·비교 | 모든 정보를 숨기거나 단계를 줄이면 더 쉽다 | 첫 사용자 과업의 오류·되돌림·완료 시간을 비교한다 | 설정 값을 군집화하고 선택 결과를 바로 옆에 보인다 |
|
||||
|
||||
## 2. 접근성은 시각 스타일과 독립된 통과선이다
|
||||
|
||||
WCAG는 A·AA·AAA의 테스트 가능한 성공 기준이다. 제품의 목표 수준과 적용 법규·계약을 먼저 정하고, 장식적 선택이 그 기준을 넘어서는지 확인한다. AA는 일반적인 목표가 될 수 있지만, 이것만으로 모두에게 적합하다는 보증은 아니다 [WCAG-22].
|
||||
|
||||
- 텍스트 대비, 200% 확대, 320 CSS px reflow, 사용자 text-spacing, 포인터 target, 자동 움직임을 핵심 화면·상태별로 시험한다 [WCAG-READ, WCAG-TARGET, WCAG-MOTION].
|
||||
- 모션 감소 선호에서는 움직임을 줄이되, 로딩·선택·오류 같은 상태 신호를 다른 방식으로 남긴다 [W3C-REDUCED].
|
||||
- 스크린샷은 이 기준을 증명하지 못한다. 키보드·줌·사용자 스타일·보조기술 테스트를 별도 기록한다.
|
||||
|
||||
## 3. 성능 수치의 이름을 바르게 쓴다
|
||||
|
||||
Core Web Vitals 적합성은 실제 사용자의 field data에서 모바일·데스크톱별 75th percentile로 판단한다. 로컬 Lighthouse/DevTools/테스트 장비 수치는 개발 회귀를 잡는 lab proxy이며 field 판정이 아니다 [CWV, CWV-METHOD].
|
||||
|
||||
| 주장 | 필요한 증거 |
|
||||
|---|---|
|
||||
| “개발 빌드가 이전보다 가벼워졌다” | 같은 환경·시나리오의 bundle/전송량 또는 lab 결과 |
|
||||
| “CWV good” | RUM 또는 CrUX의 LCP·INP·CLS p75, 기간·트래픽 분리 |
|
||||
| “사용자가 더 빨리 끝낸다” | 실제 과업 시간·성공률·오류/중단의 전후 비교 |
|
||||
| “이 디자인이 더 아름답다” | 동일 브리프에서의 렌더 비교와 근거 있는 리뷰; 자동 점수로 단정하지 않음 |
|
||||
|
||||
## 4. 비교는 같은 조건에서 한다
|
||||
|
||||
브랜드 고유성, 시각 위계, 구도·리듬, 이미지 품질은 실제 렌더에서 비교한다. 평가자는 같은 브리프·폭·상태·콘텐츠에서 다음을 적는다: 무엇이 첫 번째로 읽히는가, 어떤 근거가 이 브랜드에만 맞는가, 반복이 정보 구조를 드러내는가, 이미지의 크롭·해상도·대체 텍스트가 목적을 지지하는가. 심미성 자동점수, 상 수상, 단일 클릭 수로 전환 인과를 주장하지 않는다 [AWWWARDS, WEBBY].
|
||||
|
||||
## 5. 필요할 때: 평가의 네 증거선을 분리한다
|
||||
|
||||
예쁘다는 평가와 실제 과업 결과가 엇갈리거나, 변경이 개선 효과를 냈다고 주장하려 할 때 이 절을 연다. 평가 종류가 답하는 질문은 다르다. 첫인상·취향, 실제 과업 행동, 접근성 적합성, 전문가의 시각 검토를 한 PASS로 합치지 않는다. 보기 좋은 표면이 사용성 평가를 좋게 느끼게 할 수 있으므로, 호감과 과업 결과도 따로 적는다 [NNG-AESTHETIC].
|
||||
|
||||
| 증거선 | 답하는 질문 | 최소 기록 | 다른 증거로 대체할 수 없는 것 |
|
||||
|---|---|---|---|
|
||||
| 첫인상·취향 | 무엇이 먼저 읽히고 어떤 인상을 주는가 | 같은 렌더 조건, 관찰, 해석 | 실제 과업 성공·접근성 적합성 |
|
||||
| 실제 과업 행동 | 사람이 목표를 달성하며 어디에서 멈추거나 오류를 내는가 | 현실적인 중립 과업, 행동·발화·막힌 지점 | 표준 적합성·전문가 미감 판정 |
|
||||
| 접근성 적합성 | 정한 WCAG 수준과 제품 계약을 충족하는가 | 기준, 상태, 키보드·확대·보조기술 결과 | 사용자 경험 전체 |
|
||||
| 전문가 시각 검토 | 위계·타입·구도·이미지·리듬이 브리프와 맞는가 | 같은 조건의 전후 렌더, 관찰, 변경 근거 | 실제 사용자 연구 |
|
||||
|
||||
불확실하거나 영향이 큰 과업이면 실제 또는 예상 사용자가 현실적인 목표를 중립적 과제로 수행하게 하고, 답을 암시하지 않은 채 행동을 관찰한다 [GOV-TEST]. 실제 사용자 검증이 없으면 그 한계를 결과에 적고, 과업 효과를 확정적으로 주장하지 않는다. 사용자 평가는 표준 적합성 평가를 보완하며 대체하지 않는다 [W3C-USER-EVAL]. 일반적인 구현에 사용자 모집을 필수 게이트로 만들지 않는다. 에이전트 walkthrough는 정해진 시나리오의 회귀 점검일 뿐 실제 사용자 연구가 아니다.
|
||||
|
||||
수정은 `관찰 → 원인 가설 → 한 가지 변경 → 같은 조건의 재비교`로 남긴다. 필요하면 여러 구조적 대안을 탐색하고 작은 범위에서 시험해 버리거나 다듬는다는 Double Diamond의 프레임을 참고한다 [DC-DIAMOND]. 이 절차는 출처가 보장한 단일 방법이 아니라, 위 근거를 스킬 작업에 맞게 합성한 절차다. 고정된 관찰 시간·참여자 수·성공률 하나를 보편 통과선으로 쓰지 않는다.
|
||||
|
||||
## 6. 결정 기록 템플릿
|
||||
|
||||
```markdown
|
||||
- 출처 ID: WCAG-TARGET
|
||||
- 지지 주장: 포인터 대상의 AA 최소 크기는 24×24 CSS px이다.
|
||||
- 적용 조건: 모바일에서 빈번한 아이콘 행동.
|
||||
- 잘못된 일반화: 모든 컨트롤에 44px가 법적 필수라는 말.
|
||||
- 구체 검증: 390px에서 실제 클릭 영역과 인접 대상 간격을 측정한다.
|
||||
- 예시 결정: 삭제 아이콘의 보이는 glyph는 16px, 클릭 영역은 28px로 둔다.
|
||||
```
|
||||
58
packages/skill/references/evidence-ledger.md
Normal file
58
packages/skill/references/evidence-ledger.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# evidence ledger — 판단의 출처와 한계
|
||||
|
||||
조사일: 2026-09-12. 이 목록은 읽을거리 순위가 아니라, 디자인 결정에 쓸 수 있는 근거의 범위다. `normative`는 적합성 조건, `research`는 특정 인간-컴퓨터 상호작용의 경향, `practice`는 설계 절차, `case`는 한 사례 또는 심사 체계, `forecast`는 전망, `bibliography`는 서지 확인만 뜻한다. 사례·전망·서지는 효과나 인과를 증명하지 않는다.
|
||||
|
||||
| ID | 출처·날짜 | 종류 | 실제로 지지하는 주장 | 적용 조건 / 잘못된 일반화 | 구체 검증 |
|
||||
|---|---|---|---|---|---|
|
||||
| WCAG-22 | [WCAG 2.2](https://www.w3.org/TR/WCAG22/) · 2023-10-05 | normative | A·AA·AAA는 서로 다른 적합성 수준이며 AAA만으로 모두에게 접근 가능해지지는 않는다 | 법·계약 목표는 별도로 확인한다. AA를 자동 법적 보장이라 부르지 않는다 | 요구 수준과 전 과정의 SC를 매핑한다 |
|
||||
| WCAG-READ | [contrast](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html) · [resize](https://www.w3.org/WAI/WCAG22/Understanding/resize-text.html) · [reflow](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html) · [text spacing](https://www.w3.org/WAI/WCAG22/Understanding/text-spacing.html) · 2023 | normative | 일반 텍스트 AA 4.5:1/큰 텍스트 AA 3:1, 200% 확대, 320 CSS px 재배치, 사용자 지정 간격에서의 내용·기능 보존을 각각 요구한다 | 로고·비활성·2차원 배치 같은 예외가 있으며, 이는 단일 ‘좋은 조판’ 수치를 만들지 않는다 | 실제 상태에서 대비, 200% 확대, 320px/400%, W3C text-spacing 주입을 함께 검사한다 |
|
||||
| WCAG-TARGET | [SC 2.5.8](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html) · 2023 | normative | 포인터 입력 대상은 최소 24×24 CSS px(예외 포함)인 AA 기준이 있다 | 44px를 모든 대상의 WCAG AA 요건으로 말하지 않는다 | 실제 clickable box와 인접 대상 간격을 측정한다 |
|
||||
| WCAG-MOTION | [SC 2.2.2](https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html) · 2023 | normative | 자동으로 시작해 5초 넘게 병행되는 움직임은 멈춤·숨김·일시정지 제어가 필요할 수 있다 | 모든 모션 금지가 아니다 | 자동 콘텐츠마다 제어와 키보드 접근을 시험한다 |
|
||||
| W3C-REDUCED | [Media Queries 5](https://www.w3.org/TR/mediaqueries-5/#prefers-reduced-motion) · 확인 2026-09-12 | practice | CSS Media Queries 명세는 `prefers-reduced-motion` 질의를 정의한다 | WCAG 성공 기준이나 모든 모션 정책의 적합성 선언이 아니다 | 시스템 설정에서 핵심 상태 피드백이 남는지 확인한다 |
|
||||
| W3C-FONT | [CSS Fonts 4](https://www.w3.org/TR/css-fonts-4/#font-display-desc) · 확인 2026-09-12 | practice | CSS Fonts 명세는 `font-display`의 로딩 기간 표시 전략을 정의한다 | WCAG 적합성 요건이 아니며, `swap`이 항상 최선이거나 CLS를 반드시 만든다고 단정하지 않는다 | 느린 네트워크에서 FOUT/FOIT·레이아웃을 캡처한다 |
|
||||
| W3C-SIZE | [CSS Fonts 5](https://www.w3.org/TR/css-fonts-5/#size-adjust-desc) · 확인 2026-09-12 | practice | CSS Fonts Level 5 명세는 `size-adjust` descriptor를 정의한다 | 문서 상태·브라우저 지원을 별도 확인하며, 임의 백분율을 보편 처방으로 복사하지 않는다 | 대상 문자열·실제 폴백으로 줄바꿈과 높이를 비교한다 |
|
||||
| NNG-HEUR | [10 usability heuristics](https://www.nngroup.com/articles/ten-usability-heuristics/) · 마지막 검토 2024-01-30 | practice | 최소성은 관련 없는 정보가 관련 정보의 가시성을 경쟁시킨다는 휴리스틱이다 | ‘미니멀=요소 삭제’나 전환 효과의 증명이 아니다 | 핵심 과업별 정보·피드백·복구 가능성을 리뷰한다 |
|
||||
| NNG-VISUAL | [Principles of visual design](https://www.nngroup.com/articles/principles-visual-design/) · 확인 2026-09-12 | practice | scale, visual hierarchy, balance, contrast, Gestalt principles를 시각 디자인의 검토 차원으로 설명한다 | 특정 크기 비율·색 수·자동 심미성 점수를 처방하지 않는다 | 회색조와 실제 콘텐츠에서 우선순위·묶음·대비를 비교한다 |
|
||||
| NORMAN-SIGN | [Signifiers, not affordances](https://jnd.org/signifiers-not-affordances/) · 2008 | practice | 사용자가 어디서 어떻게 행동할지 알게 하는 지각 가능한 단서는 signifier로 설명할 수 있다 | 시각적으로 버튼처럼 보이면 이해·접근성이 자동 보장된다는 뜻이 아니다 | 첫 사용자가 라벨·상태·피드백으로 행동을 예측하는지 관찰한다 |
|
||||
| KRUG | [Don’t Make Me Think Revisited sample](https://sensible.com/downloads/DMMT-Revisited-sample-chapter.pdf) · 확인 2026-09-12 | bibliography | 공개 샘플은 Krug의 저작과 ‘명확한 선택지’라는 교육적 관점을 확인하는 범위다 | 메뉴 수 고정 규칙이나 실험적 성과 증거가 아니다 | 애매한 라벨을 대표 사용자의 과업 탐색으로 시험한다 |
|
||||
| FITTS | [Fitts’s law](https://doi.org/10.1037/h0055392) · 1954 | research | 목표까지 거리와 이동축의 폭은 조준 시간에 관계한다 | 메뉴 개수 공식이나 모바일 타깃 크기 법규가 아니다 | 자주 쓰는 행동의 실제 거리·hitbox·오입력을 관찰한다 |
|
||||
| HICK | [Hick](https://doi.org/10.1080/17470215208416600) · 1952 | research | 선택 신호의 정보량과 반응 시간 관계를 실험했다 | ‘7개 이상 메뉴 금지’로 변환하지 않는다 | 사용자 목표별 선택지의 분류·라벨·성공 시간을 테스트한다 |
|
||||
| MILLER | [Miller](https://doi.org/10.1037/h0043158) · 1956 | research | 단기 기억의 절대적 한계가 아니라 chunking과 과제 맥락을 논의했다 | 7±2를 내비게이션 항목 수 규칙으로 쓰지 않는다 | 회상 대신 과업 완료·오류·도움 요청을 관찰한다 |
|
||||
| GESTALT | [Wagemans et al.](https://doi.org/10.1037/a0029333) · 2012 | research | 근접성·유사성·공통 영역 같은 grouping 원리와 figure-ground를 현대적으로 검토한다 | 정렬·카드·색 하나만으로 이해·전환이 보장된다는 뜻이 아니다 | 관련 항목의 묶음과 분리, 선택 상태를 회색조·키보드·실제 과업에서 확인한다 |
|
||||
| COGNITIVE-LOAD | [Sweller](https://onlinelibrary.wiley.com/doi/10.1207/s15516709cog1202_4) · 1988 | research | 문제 해결에서 작업 기억과 문제 구조의 상호작용을 다룬다 | 정보량을 무조건 줄이거나 단일 요소 수 규칙으로 환원하지 않는다 | 처음 하는 과업에서 단계·용어·기억해야 할 상태를 줄이고 오류·완료 시간을 관찰한다 |
|
||||
| AWWWARDS | [Evaluation system](https://www.awwwards.com/about-evaluation/) · 확인 2026-09-12 | case | 해당 심사는 Design 40 / Usability 30 / Creativity 20 / Content 10으로 채점한다 | 배점 비율이 두 요소의 효과 크기나 사업 성과를 뜻하지 않는다 | 제출 목적일 때 네 차원을 별도 체크한다 |
|
||||
| WEBBY | [Judging criteria](https://www.webbyawards.com/judging-criteria/) · 확인 2026-09-12 | case | Webby는 콘텐츠·구조/내비게이션·시각 디자인·기능성·상호작용·전반 경험을 심사한다 | 수상은 특정 패턴의 보편적 효율 증거가 아니다 | 사례를 해체하되 과업·접근성·성능을 별도 검증한다 |
|
||||
| DROPBOX | [Dropbox brand](https://brand.dropbox.com/) · 확인 2026-09-12 | case | 브랜드 사이트가 공개한 자산·원칙의 사례다 | 브랜드의 자체 설명을 사용자 효과로 해석하지 않는다 | 사용할 요소를 렌더·접근성·브리프 적합성으로 다시 판정한다 |
|
||||
| AREA17 | [AREA 17 × Pentagram](https://area17.com/ideas/area-17-pentagram) · 확인 2026-09-12 | case | 제작사가 프로젝트 접근을 설명하는 사례다 | 제작사 주장은 독립 성과 검증이 아니다 | 구조와 시스템 선택만 참고하고 결과는 직접 비교한다 |
|
||||
| UNSEEN | [Unseen 2025 wrapped](https://2025.unseen.co/) · 확인 2026-09-12 | case | 시간·문화 맥락이 강한 실험적 웹 표면의 사례다 | 사이트 자체만으로 사용성·전환 효과를 주장하지 않는다 | 모션 off·키보드·모바일에서 핵심 메시지를 검증한다 |
|
||||
| CSSDA-UNSEEN | [CSS Design Awards listing](https://www.cssdesignawards.com/sites/unseen-studio-2025-wrapped/48957/) · 2026-03-09 | case | CSSDA가 해당 작품을 WOTD로 기록한 사례다 | 단일 수상을 스타일 효과의 일반 증거로 쓰지 않는다 | 작품의 제약과 대상이 현재 브리프와 맞는지 비교한다 |
|
||||
| CWV | [Web Vitals](https://web.dev/articles/vitals) · 2024-10-31 | practice | CWV의 good 기준은 LCP ≤2.5s, INP ≤200ms, CLS ≤0.1이며 field 75th percentile로 판정한다 | Lighthouse 한 번이나 개발 로컬 측정을 field 적합성이라 부르지 않는다 | RUM/CrUX와 모바일·데스크톱 p75를 기록하고, 로컬은 회귀 proxy로 표기한다 |
|
||||
| CWV-METHOD | [Threshold methodology](https://web.dev/articles/defining-core-web-vitals-thresholds) · 2025-05-07 | practice | CWV 임계값은 단일 인간 지각값이 아니라 연구·실사용 데이터·달성 가능성을 함께 고려한다 | 한 임계값을 모든 과업의 만족도 원인으로 단정하지 않는다 | 성능 수치와 과업 관찰을 분리 보고한다 |
|
||||
| IBM-GRID | [Carbon 2x Grid](https://carbondesignsystem.com/elements/2x-grid/usage/) · 확인 2026-09-12 | practice | 제품 UI에서 그리드·gutter·breakpoint를 일관되게 적용하는 방법의 예다 | 모든 브랜드가 Carbon 격자를 써야 한다는 규범이 아니다 | 콘텐츠 폭, 정렬선, 작은 폭의 재배치를 검증한다 |
|
||||
| IBM-DATA | [IBM data visualization basics](https://www.ibm.com/design/language/data-visualization/design/basics/) · 확인 2026-09-12 | practice | 데이터 표현은 목적·비교·맥락에 맞춰 선택해야 한다 | 장식적 차트나 색만으로 의미가 생긴다고 보지 않는다 | 질문-표현-축/라벨-대체 접근을 연결해 검토한다 |
|
||||
| IFD-TREND | [iF Design Trend Report 2025](https://ifdesign.com/en/if-magazine/newsroom/if-design-trend-report-2025) · 2025 | forecast | 기관의 거시 디자인 전망이다 | 웹 UI의 검증된 성과나 필수 스타일 목록이 아니다 | 브리프·사용자 조사와 맞을 때만 가설로 쓴다 |
|
||||
| DC-DIAMOND | [Design Council Double Diamond](https://www.designcouncil.org.uk/resources/the-double-diamond/) · 확인 2026-09-12 | practice | 발견·정의·개발·전달을 오가며 다양한 답을 탐색하고 작은 시험으로 버리거나 개선하는 프레임을 소개한다 | 고정 단계 수나 모든 프로젝트의 의무 절차로 쓰지 않는다 | 불확실성이 큰 결정의 대안·시험·폐기 근거를 기록한다 |
|
||||
| VA-MOFFAT | [Curtis Moffat: working methods](https://www.vam.ac.uk/articles/curtis-moffat-working-methods) · 2025-09-24 | case | contact sheet, 크롭, 비중심 배치가 작가 작업에서 어떻게 쓰였는지 보여 주는 사례다 | 웹 성과나 보편 구도 규칙의 증거가 아니다 | 이미지 선택·크롭의 목적과 전후 렌더를 비교한다 |
|
||||
| CH-DESCRIPTION | [Cooper Hewitt image-description guidelines](https://www.cooperhewitt.org/cooper-hewitt-guidelines-for-image-description/) · 확인 2026-09-12 | practice | 중요한 내용을 먼저 두고 공간 순서와 맥락에 맞춰 이미지를 설명하는 방법을 제시한다 | 박물관의 단어 수를 보편 alt 길이 규칙으로 바꾸지 않는다 | 정보성 이미지에서 목적·핵심 내용·대체 설명을 함께 검토한다 |
|
||||
| LUPTON-POSTERS | [How Posters Work](https://www.cooperhewitt.org/publications/how-posters-work/) · 확인 2026-09-12 | bibliography | Lupton의 책과 포스터를 분석 대상으로 삼는 출판 맥락을 확인하는 출발점이다 | 이 항목은 책 본문을 정독했거나 특정 구성 규칙을 인용했다는 뜻이 아니다 | 판본과 페이지를 확보한 뒤 적용할 개념과 한계를 기록한다 |
|
||||
| GOV-IMAGES | [GOV.UK Design System: images](https://design-system.service.gov.uk/styles/images/) · 확인 2026-09-12 | practice | 정부 서비스에서 목적에 맞는 사진·도식·대체 설명을 선택하는 지침이다 | 상업 브랜드에 무드 이미지를 금지하는 일반 규칙으로 확대하지 않는다 | 이미지가 과업 정보·맥락·접근성에 기여하는지 확인한다 |
|
||||
| GOV-TEST | [GOV.UK moderated usability testing](https://www.gov.uk/service-manual/user-research/using-moderated-usability-testing) · 확인 2026-09-12 | practice | 현실적인 중립 과업으로 실제 또는 예상 사용자의 행동과 어려움을 관찰하는 방법을 설명한다 | 특정 참여자 수·시간·성공률을 보편 통과선으로 만들지 않는다 | 과업 문구, 사용 환경, 행동·오류·중단 관찰을 분리 기록한다 |
|
||||
| NNG-AESTHETIC | [Aesthetic-usability effect](https://www.nngroup.com/articles/aesthetic-usability-effect/) · 2024-02-03, 검토 2026-09-01 | practice | 시각적 호감이 사용성에 대한 지각을 높일 수 있어 실제 과업 결과와 구분해 볼 필요를 해설한다 | 원 논문 전문을 읽었거나 호감이 실제 사용성을 보장한다고 주장하지 않는다 | 취향·첫인상과 과업 행동·오류를 별도 결과로 남긴다 |
|
||||
| W3C-USER-EVAL | [Involving users in evaluating web accessibility](https://www.w3.org/WAI/test-evaluate/involving-users/) · 2024-04-30 | practice | 사용자 평가는 표준 기반 적합성 평가를 보완하며 둘을 함께 써야 한다고 설명한다 | 적은 표본이나 한 번의 평가를 모든 사용자에게 일반화하지 않는다 | WCAG 평가와 사용자 관찰의 질문·결과를 분리해 기록한다 |
|
||||
| SWISS-NB | [The International Style 1950–1970](https://www.nb.admin.ch/en/the-international-style-1950-1970) · 확인 2026-09-12 | bibliography | 스위스/국제 타이포그래피의 역사·소장 맥락을 소개한다 | 역사 양식을 기능·전환의 보편 처방으로 바꾸지 않는다 | 그리드·타입 선택의 문화적 근거만 명시한다 |
|
||||
| BRINGHURST | [The Elements of Typographic Style](https://hartleyandmarks.com/Hartley-%26-Marks-Publishers) · 확인 2026-09-12 | bibliography | Bringhurst 4.0의 서지·출판 정보를 확인하는 출발점이다 | 이 ledger는 책 본문을 읽거나 특정 규칙을 인용했다는 뜻이 아니다 | 판본을 확보한 뒤 페이지 단위로 별도 기록한다 |
|
||||
| LUPTON | [Thinking with Type, 3rd ed.](https://www.chroniclebooks.com/products/thinking-with-type-1) · 2024 | bibliography | Lupton 저작의 3판 출판 정보를 확인하는 출발점이다 | 이 ledger는 본문 요약이나 보편 수치 근거가 아니다 | 판본을 확보한 뒤 개념·예시 페이지를 별도 기록한다 |
|
||||
| MULLER-BROCKMANN | [Grid systems in graphic design](https://niggli.ch/en/products/rastersysteme-fur-die-visuelle-gestaltung) · 확인 2026-09-12 | bibliography | Müller-Brockmann 저작의 출판사 서지 정보를 확인하는 출발점이다 | 그리드를 모든 과업의 정답으로 만들지 않는다 | 판본을 확보한 뒤 grid 선택의 목적·예외·검증을 분리 기록한다 |
|
||||
|
||||
## 사용할 때
|
||||
|
||||
결정마다 `출처 ID / 지지 주장 / 적용 조건 / 잘못된 일반화 / 구체 검증 / 예시 결정`을 남긴다. 예: `WCAG-TARGET / 24×24 AA 최소 / 포인터 대상 / 44px 의무라고 확대하지 않음 / 실제 버튼 box 측정 / 작은 아이콘을 24px 이상 hit area로 확장`.
|
||||
|
||||
## 교과서 입문·정독 범위
|
||||
|
||||
다음은 **서지 확인된 읽기 경로**다. 이 목록은 본문을 읽었다거나 특정 페이지의 규칙을 채택했다는 주장이 아니다. 입문에서는 편집·그리드·글자 형태의 어휘를 얻고, 실제 프로젝트에 인용할 때는 확보한 판본과 페이지를 다시 기록한다.
|
||||
|
||||
1. Bringhurst, *The Elements of Typographic Style* — 조판 어휘와 본문 리듬의 정독 출발점 [BRINGHURST].
|
||||
2. Lupton, *Thinking with Type*, 3rd ed. — 타입을 구성·위계·이미지와 연결하는 입문 [LUPTON].
|
||||
3. Müller-Brockmann, *Grid Systems in Graphic Design* — grid의 역사적·실무적 어휘 [MULLER-BROCKMANN].
|
||||
4. Meggs 계열의 그래픽 디자인 역사 저작은 별도 판본 서지와 페이지 근거를 확보한 뒤 역사 맥락용으로 추가한다. 이 ledger에서는 미확인 판본의 내용을 인용하지 않는다.
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
## 1. 브리프 → 갤러리 라우팅
|
||||
|
||||
`R1`은 구조, `R2`는 톤, `R3`는 디테일을 가져올 소스다. R2는 **반드시 R1과 다른 업종**에서 고른다.
|
||||
`R1`은 구조, `R2`는 톤, `R3`는 디테일을 검토할 슬롯이다. R2는 다른 업종 또는 매체를 우선 검토하되, 같은 업종이 브리프·시장·제작 조건에 맞으면 그 이유를 기록한다.
|
||||
|
||||
> **두 행에 동시에 걸리면 청중을 기준으로 고른다.** "개발자용 API 모니터링 SaaS"는
|
||||
> `SaaS · B2B` 와 `개발자 도구` 양쪽에 해당한다. 보는 사람이 엔지니어면 개발자 도구 행이다.
|
||||
|
|
@ -49,10 +49,7 @@
|
|||
|
||||
## 2. 경고 — 갤러리마다 편향이 있다
|
||||
|
||||
**Awwwards 구조를 SaaS에 이식하지 마라.**
|
||||
2026 Q1 SOTD 47건의 업종 분포는 럭셔리 패션 28% · 자동차 22% · 건축 18% · 문화기관 14%, **테크/SaaS는 5% 미만**이다.
|
||||
수상작의 전면 3D·풀스크린 인트로·스크롤 서사는 "제품을 팔지 않는 사이트"의 문법이다.
|
||||
Awwwards는 **타이포 완성도와 야심의 상한선**으로만 쓰고, 섹션 구조는 Land-book·Refero에서 가져온다.
|
||||
**Awwwards 사례를 제품 구조의 보편 답으로 쓰지 마라.** 어워드 사례는 심사 맥락·예산·제작 환경이 다르다. 전면 3D·풀스크린 인트로·스크롤 서사는 목적·성능 예산·사용 과업에 맞을 때만 선택한다. 각 사례에서 가져올 원칙과 적용 조건을 기록하고, 정보 구조는 목표 사용자·과업·프로젝트 계약으로 다시 검증한다.
|
||||
|
||||
그 밖의 편향:
|
||||
|
||||
|
|
@ -96,7 +93,7 @@ Awwwards는 **타이포 완성도와 야심의 상한선**으로만 쓰고, 섹
|
|||
라우팅 표에서 못 찾았을 때만 본다.
|
||||
|
||||
**종합 어워드**
|
||||
- Awwwards https://www.awwwards.com — SOTD 아카이브. 상한선용
|
||||
- Awwwards https://www.awwwards.com — SOTD 아카이브. 심사 맥락과 적용 조건을 함께 검토
|
||||
- The FWA https://thefwa.com — 인터랙티브·기술 실험
|
||||
- Godly https://godly.website — 주당 3~5개만 등록. 신호 대 잡음비 최고
|
||||
|
||||
|
|
|
|||
|
|
@ -8,22 +8,28 @@
|
|||
|
||||
---
|
||||
|
||||
## 1. 조달 경로 — 위에서부터 확인한다
|
||||
## 1. 조달 경로 — 기본 탐색 순서로 확인한다
|
||||
|
||||
| 순위 | 경로 | 언제 |
|
||||
|---|---|---|
|
||||
| 1 | **사용자가 준 사진** | 있으면 무조건 이것. 실제 작업물을 이길 생성물은 없다 |
|
||||
| 2 | **생성**(codex `image_gen`) | 콘셉트 확인용, 톤이 정확히 지정된 추상·분위기 컷 |
|
||||
| 1 | **사용자가 준 사진** | 자산 용도·품질·권리·진실성에 맞을 때. 실제 작업물은 그 근거가 필요한 화면에서 강하다 |
|
||||
| 2 | **생성**(codex `image_gen`) | 필요한 슬롯에 콘셉트 확인용 또는 톤이 정확히 지정된 추상·분위기 컷이 맞을 때 |
|
||||
| 3 | **스톡** | 라이선스가 명확한 곳만. 출처를 `design.md` 에 적는다 |
|
||||
| 4 | 없이 간다 | 타이포·색·여백만으로 만든다. 약한 사진보다 낫다 |
|
||||
|
||||
**0단계에서 물어라**: "쓸 수 있는 사진이 있나요?"
|
||||
없다고 하면 2번으로 가되, **생성물이라는 사실을 `design.md` 에 적는다.**
|
||||
나중에 실제 사진으로 바꿀 때 레이아웃을 다시 짜지 않도록 비율을 미리 고정해 둔다.
|
||||
이 순위는 기본 탐색 순서일 뿐이다. 자산 용도·품질·권리·진실성 판단보다 앞서지 않는다.
|
||||
|
||||
사용자가 이미 자산을 제공했거나 사용 가능한 사진이 없다고 명시했거나, `design.md`·저장소에서 확인할 수 있으면 다시 묻지 않는다. 기존 정보로 확인할 수 없고 자산 유무가 결정에 필요할 때만 **0단계에서 묻는다**: "쓸 수 있는 사진이 있나요?"
|
||||
없다는 답만으로 생성 경로를 자동 선택하지 않는다. 슬롯별 자산 용도·품질·권리·진실성을 비교해 경로를 고르고, 생성물을 쓰면 **생성물이라는 사실을 `design.md` 에 적는다.**
|
||||
나중에 실제 사진으로 바꿀 가능성이 있으면 레이아웃을 다시 짜지 않도록 비율을 미리 고정해 둔다. 구도·크롭·타이포 검토는 [art-direction.md](art-direction.md)를 따른다.
|
||||
|
||||
### 제품을 고르는 화면의 추가 원칙
|
||||
|
||||
사용자가 제품 자체를 비교·선택하는 카드라면 CSS 도형이나 레이어 쌓기로 제품을 대신 그리지 않는다. 실제·라이선스 사진이 없을 때만 비율을 정한 생성 사진을 쓰고, 사진과 같은 시각 그룹에 `생성 이미지`처럼 가까운 출처 라벨을 둔다. DOM 도식은 재료 비교, 과정 설명, 수치처럼 **그림보다 읽히는 정보**에만 쓴다.
|
||||
|
||||
---
|
||||
|
||||
## 2. codex 가 있으면 생성한다
|
||||
## 2. 생성이 적합할 때 사용할 경로
|
||||
|
||||
설치 여부를 먼저 확인한다. 없으면 조용히 3번으로 내려간다.
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
**`main` 폭에 고정값을 쓰지 마라.** `--measure` 는 3단계에서 언어와 폰트에 맞춰 정한 값이다.
|
||||
여기에 60rem 같은 숫자를 넣으면 본문이 measure 를 넘어가 이 문서의 통과 조건을 스스로 어긴다.
|
||||
한글은 보통 라틴보다 좁다(35ch ≈ 561px vs 640px).
|
||||
`ch`는 선택한 글꼴의 메트릭에 의존한다. 한글과 라틴의 실제 줄 길이는 글꼴·언어·내용으로 달라지므로, 예시 폭을 보편 수치로 쓰지 말고 대표 문단을 렌더해 확인한다.
|
||||
|
||||
이 한 번의 정의로 **본문 폭 · 넓은 블록 · 전체 폭**이 전부 정렬된다. 섹션마다 `max-width` 와 `padding` 을 다시 쓰면 반드시 어긋난다.
|
||||
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
### 벤토 그리드 주의
|
||||
|
||||
벤토(크기가 다른 카드들의 격자)는 **더 이상 차별화가 아니라 새 기본값**이다. 효과는 있지만(스크롤 깊이 증가) 표준화가 끝나서 "고민 안 했음"의 신호로 읽힌다. 쓰려면 최소한 다음 중 하나는 해라:
|
||||
벤토(크기가 다른 카드들의 격자)는 정보를 묶거나 우선순위를 드러낼 때 쓸 수 있다. 카드 크기 변화만으로 고유성·스크롤 깊이·이탈을 예측할 수는 없다. 아래 장치는 선택지이며, 구조가 필요로 할 때만 쓴다:
|
||||
- 카드 경계를 없애고 여백만으로 구획
|
||||
- 그리드에서 한 칸을 의도적으로 비우기
|
||||
- 카드 하나만 규칙을 깨고 밖으로 나가기
|
||||
|
|
@ -50,10 +50,10 @@
|
|||
|
||||
사람은 페이지를 읽지 않고 **훑는다.** 훑는 경로를 설계하는 것이 레이아웃의 본체다.
|
||||
|
||||
1. **첫 화면에서 세 가지만** — 무엇인지 / 왜 좋은지 / 다음 행동. 넷 이상이면 아무것도 안 읽힌다
|
||||
2. **위계는 크기가 아니라 대비로 만든다** — 크기·굵기·색·여백 중 **둘 이상을 동시에** 바꿔야 위계가 보인다. 크기만 조금 키우는 것은 위계가 아니다
|
||||
1. 첫 화면이 대표 과업에 필요한 정체성·가치·다음 행동을 충분히 설명하는지 확인한다. 세 요소는 흔한 점검 틀이지 모든 화면의 최대 항목 수가 아니다
|
||||
2. 위계는 크기·굵기·색·여백·위치의 조합으로 만든다. 어떤 두 변수를 반드시 바꿔야 한다는 공식보다, 회색조와 실제 콘텐츠에서 우선순위가 읽히는지를 본다
|
||||
3. **시선을 한 번은 멈춰라** — 전부 같은 리듬으로 흐르면 아무것도 강조되지 않는다. 섹션 하나는 리듬을 깨야 한다
|
||||
4. **스크롤은 보상이어야 한다** — 다음 화면에 무언가 새로운 것이 있어야 한다. 같은 카드 그리드가 세 번 반복되면 거기서 이탈한다
|
||||
4. 스크롤 뒤에도 새 정보나 과업 진전이 있는지 확인한다. 반복 카드가 이탈을 만든다는 보편 증거는 없으므로, 실제 콘텐츠와 사용자 행동으로 판단한다
|
||||
|
||||
### 의미가 다르면 섹션 토폴로지도 달라야 한다
|
||||
|
||||
|
|
@ -75,10 +75,10 @@
|
|||
|
||||
한 액션 묶음의 **같은 행에 놓인 직접 자식**인 채운 버튼과 텍스트 링크는 `align-items:center`만으로 시각 중심이 맞지 않을 수 있다. 중첩된 아이콘·배지까지 한꺼번에 비교하거나, 모바일에서 세로로 쌓인 액션에 이 규칙을 적용하면 오탐이다.
|
||||
|
||||
- 두 액션 모두 `inline-flex; align-items:center; min-height:44px`의 실제 hitbox를 가진다
|
||||
- 두 액션의 실제 hitbox와 정렬을 함께 측정한다. 44px은 편안한 시작값일 수 있지만, WCAG 2.2 AA의 포인터 target 최소 기준은 예외를 포함해 24×24 CSS px다 (`evidence-ledger.md`의 `WCAG-TARGET`)
|
||||
- `getBoundingClientRect()`의 중심 y 차이가 브라우저 CSS 픽셀 기준 2px 이하여야 한다
|
||||
- 텍스트 baseline이 아니라 클릭 가능한 박스 전체를 비교한다
|
||||
- 보조 링크를 44px로 키우면서 빈 padding이 과해지면 액션을 세로로 쌓는다
|
||||
- 보조 링크의 hitbox를 키운 결과 밀도가 나빠지면, 행동 중요도·오입력·레이아웃을 보고 세로 배치나 다른 구조를 검토한다
|
||||
|
||||
### 패널을 숨기면 그리드 트랙도 회수한다
|
||||
|
||||
|
|
@ -104,7 +104,7 @@
|
|||
|
||||
### 본문이 주인공이다
|
||||
헤드라인은 눈에 띄기 쉽다. **본문이 읽히는지**가 실력이다.
|
||||
- 한 줄 길이(`--measure`)를 반드시 적용해라. 전체 폭 본문은 읽을 수 없다
|
||||
- 한 줄 길이(`--measure`)를 본문 역할에 적용하고, 실제 언어·글꼴·확대 상태에서 읽기 리듬을 검토한다. 전체 폭이 항상 실패인 것은 아니지만 긴 산문에 무심코 적용하지 않는다
|
||||
- 문단 간격은 줄간격의 1.5배 이상. 들여쓰기와 문단 간격을 동시에 쓰지 마라
|
||||
- 링크는 색만으로 구분하지 마라(밑줄 또는 다른 신호 병행)
|
||||
|
||||
|
|
@ -112,7 +112,7 @@
|
|||
`references/antipatterns.md` 의 한글 조판 섹션을 읽어라. 요약:
|
||||
- `word-break: keep-all` — 없으면 단어가 아무 데서나 잘린다
|
||||
- line-height 1.6~1.8 (라틴보다 넉넉하게)
|
||||
- 음수 자간 금지
|
||||
- 자간은 글꼴·크기·스크립트별로 실제 렌더를 보고 조정한다. 한글 음수 자간은 기본 처방으로 쓰지 않으며, 적용했다면 작은 크기·확대·줄바꿈에서 검증한다
|
||||
- 한 줄 25~40자
|
||||
- 라틴 폰트를 폴백 스택 **앞**에 둔다 (숫자·영문이 한글 폰트로 렌더되면 조악해진다)
|
||||
- **한글 폰트를 지정하지 않는 것 자체가 완성도 미달 신호다**
|
||||
|
|
@ -131,31 +131,28 @@
|
|||
.cards { grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); }
|
||||
```
|
||||
|
||||
`auto-fit` + `minmax` 로 해결되는 것을 미디어쿼리로 만들지 마라. 미디어쿼리는 **레이아웃 구조 자체가 바뀔 때만** 쓴다.
|
||||
`auto-fit` + `minmax`는 유동 반복 grid에 유용하다. 미디어쿼리와 container query는 구조·밀도·행동이 바뀌는 실제 실패 지점에서 선택한다.
|
||||
|
||||
### 모바일에서 먼저 확인해라
|
||||
데스크톱에서 아름다운 것이 모바일에서 무너지는 것이 기본이고, 그 반대는 드물다. 특히:
|
||||
- 큰 타이포는 모바일에서 반드시 줄여라 (`clamp` 의 최소값)
|
||||
- 큰 타이포는 모바일에서 줄 수·가려짐·다음 행동의 가시성을 보고 크기·폭·문구·구도를 함께 조정한다. 단순 축소가 유일한 해법은 아니다
|
||||
- 가로 스크롤이 생기는 요소를 찾아라 (`overflow-x: hidden` 으로 덮지 말고 원인을 고쳐라)
|
||||
- 터치 타깃 44×44px 이상
|
||||
- 터치 타깃은 과업 빈도·오입력 위험과 WCAG 2.2 AA의 24×24 CSS px 최소 기준(예외 포함)을 함께 검토한다
|
||||
- 호버로만 접근되는 기능을 만들지 마라
|
||||
|
||||
---
|
||||
|
||||
## 4-b. 모바일 내비 — 햄버거를 기본값으로 삼지 마라
|
||||
|
||||
내비 항목 수는 0단계에서 이미 정해져 있다(= 섹션 수). 구현하다 발견하면 늦다.
|
||||
내비 구조는 섹션 수가 아니라 대표 과업, 라벨 길이, 우선순위, locale, 화면 폭을 함께 보고 0단계에서 정한다. Hick의 연구를 항목 수 공식으로 쓰지 않는다.
|
||||
|
||||
| 항목 수 | 처리 | 비용 |
|
||||
| 관찰한 조건 | 검토할 구조 | 검증 |
|
||||
|---|---|---|
|
||||
| **2~4개** | 한 줄 유지. 자간을 줄이고 `space-between` 으로 편다 | 0 |
|
||||
| **5~6개** | 가로 스크롤 줄, 또는 하단 고정 바 | 낮음 |
|
||||
| **7개 이상** | 여는 메뉴 | `<details>` 로 JS 0바이트 |
|
||||
| 모든 우선 행동이 한 줄에서 읽히고 hitbox가 확보됨 | 직접 노출된 내비 | 작은 폭·키보드에서 라벨 접힘과 순서를 본다 |
|
||||
| 라벨이 길거나 행동 우선순위가 갈림 | 일부 노출 + 추가 메뉴 또는 하단 행동 | 자주 쓰는 행동의 탐색 시간·오입력을 본다 |
|
||||
| 문맥별 명령이 많음 | 컨텍스트 메뉴·검색·계층적 IA | 메뉴 열기/닫기·포커스·Esc·현재 위치를 시험한다 |
|
||||
|
||||
**넷인데 햄버거를 쓰면 탭 한 번을 공짜로 뺏는 것이다.** 반대로 여섯을 한 줄에
|
||||
욱여넣으면 접힌다 — 실측에서 링크가 두 줄(top 46/77)에 걸렸고, 워드마크까지 3줄이 됐다.
|
||||
|
||||
### 2~4개 — 쌓는 것이 접히는 것보다 낫다
|
||||
### 항목 수 대신 실제 라벨·과업으로 결정한다
|
||||
|
||||
워드마크와 내비를 한 줄에 두면 둘 다 접힌다. 좁은 화면에서는 **위아래로 쌓아라.**
|
||||
|
||||
|
|
@ -169,10 +166,9 @@
|
|||
라벨 자간(`0.14em`)이 좁은 화면에서 폭을 크게 먹는다. **자간부터 줄여라** —
|
||||
폰트 크기를 줄이는 것보다 읽기에 덜 해롭다.
|
||||
|
||||
### 7개 이상 — `<details>` 면 JS 가 필요 없다
|
||||
### 단순 공개/접기에는 `<details>`를 검토한다
|
||||
|
||||
키보드 조작·`Esc`·포커스 이동이 브라우저 기본으로 온다.
|
||||
직접 만든 토글은 그걸 전부 다시 구현해야 하고, 대개 빠뜨린다.
|
||||
`<details>`는 간단한 공개/접기에는 유용하지만, 복잡한 메뉴의 포커스 이동·Esc·모달 동작을 자동으로 완성하지 않는다. 실제 키보드와 보조기술에서 목표 행동을 시험하고, 필요한 패턴을 선택한다.
|
||||
|
||||
```html
|
||||
<details class="nav-mobile">
|
||||
|
|
@ -215,6 +211,47 @@ new Set([...document.querySelectorAll('.nav a')]
|
|||
|
||||
---
|
||||
|
||||
## 4-d. 초광폭은 여백이 아니라 별도 레이아웃 상태다
|
||||
|
||||
1440px에서 멀쩡한 페이지가 1920·2560px에서 깨지는 방식은 반대다. 모바일처럼 넘치지는 않지만, 본문은 끝없이 늘어나고 고정 폭 헤드라인은 빈 여백에 밀려나며 표는 너무 좁아진다. **컨테이너 하나를 무조건 풀거나 조이지 마라.** 읽는 표면과 비교·명세 표면의 요구가 다르다.
|
||||
|
||||
```css
|
||||
:root { --measure: 42rem; --container-wide: 74rem; }
|
||||
.prose { max-width: var(--measure); }
|
||||
.specification { width: min(100% - 2 * var(--pad-inline), var(--container-wide)); }
|
||||
|
||||
@media (min-width: 120rem) {
|
||||
.specification { --container-wide: 86rem; } /* 데이터 표면만 확장 */
|
||||
}
|
||||
```
|
||||
|
||||
- 본문·설명·폼은 `--measure`를 지켜 행 길이와 label-입력 관계를 읽을 수 있게 둔다
|
||||
- 표·도면·비교 작업대는 더 넓어도 되지만, 어떤 surface가 넓어지는지 이름으로 구분한다. 전역 `max-width` 해제는 해결이 아니다
|
||||
- 1920과 2560에서 h1 폭·히어로 칼럼·table/flex 셀의 실제 rect를 재고, 빈 공간이 필요한지와 내용 폭이 부족한지를 별도로 판정한다
|
||||
|
||||
Apple도 다양한 화면 크기에서 적응형 레이아웃과 읽기 좋은 텍스트 폭의 제한을 권한다. 여기의 정확한 수치는 제품 토큰으로 정하고, 넓은 폭을 시험하지 않은 상태를 통과로 부르지 않는다. [Apple HIG Layout](https://developer.apple.com/design/human-interface-guidelines/layout)
|
||||
|
||||
### 4-e. 분할 히어로의 사진에는 상한이 있고, 카피에는 최소 폭이 있다
|
||||
|
||||
초광폭에서 `1fr 1fr`을 그대로 두면 사진은 창과 함께 계속 커지는데 카피는 상대적으로 가늘어져, 화면의 절반을 차지한 이미지와 읽을 수 없는 작은 설명이 공존한다. 풀블리드 편집 사진이 **의도적으로** 화면을 점유하는 경우가 아니라면, 분할 히어로를 wide surface처럼 별도 계약으로 둔다.
|
||||
|
||||
```css
|
||||
@media (min-width: 120rem) {
|
||||
.hero { width: min(100%, var(--stage-wide)); margin-inline: auto; }
|
||||
.hero-copy { width: min(100%, var(--copy-wide)); justify-self: end; }
|
||||
.hero-media { width: min(100%, var(--media-wide)); justify-self: end; }
|
||||
}
|
||||
```
|
||||
|
||||
- `--stage-wide`, `--copy-wide`, `--media-wide`, 후속 `--workbench-wide`를 따로 이름 짓는다. 한 `--wrap`을 무한히 키우지 않는다
|
||||
- 1920·2560에서 hero·copy·media·다음 정보 레일의 실제 rect를 기록한다. media의 상한, copy의 최소 폭, hero의 중앙/의도된 정렬을 **그 페이지의 계약**으로 단언한다
|
||||
- 이미지가 넓어질 자격은 이미지 자체의 편집적 역할에 있다. 정보·주문·비교가 뒤따르는 제품 화면에서는 후속 레일도 같은 밀도로 확장해, 첫 장면만 거대하고 본문은 점처럼 보이는 단절을 만들지 않는다
|
||||
- 이 계약은 hero만의 면허가 아니다. 과정·추천·가맹 같은 별도 text-media split은 각각 원래의 padding/`max-width` 규칙을 가진다. wide에서 새 stage를 넣을 때는 inherited `padding-inline`의 **양쪽 값**과 상위 container selector의 specificity를 함께 확인한다. 한쪽에 `calc((100vw - --wrap) / 2)`가 남으면 grid rect는 멀쩡해도 실제 텍스트 폭이 한 글자까지 붕괴할 수 있다. 각 split마다 heading의 실제 폭·줄 수와 copy/media rect를 별도로 측정한다.
|
||||
|
||||
이 규칙은 읽기 폭을 지키는 기존 wide-surface 원칙의 구체형이다. 사람의 시선은 이미지 크기보다 이미지·카피·행동의 비례에서 우선순위를 읽는다.
|
||||
|
||||
---
|
||||
|
||||
## 5. 이 단계의 통과 조건
|
||||
|
||||
- [ ] CSS/HTML만으로 페이지가 완성됐다. JS를 꺼도 읽힌다
|
||||
|
|
@ -224,7 +261,7 @@ new Set([...document.querySelectorAll('.nav a')]
|
|||
- [ ] 본문에 `--measure` 가 적용됐다
|
||||
- [ ] 모바일 폭 **320px**(iPhone SE 세로)에서 가로 스크롤이 없다
|
||||
- [ ] 키보드 Tab 만으로 모든 인터랙티브 요소에 도달한다. 포커스 링이 보인다
|
||||
- [ ] 같은 행 액션 묶음의 직접 자식 hitbox가 44px 이상이고 중심 y 차이가 CSS 픽셀 2px 이하다
|
||||
- [ ] 같은 행 액션 묶음의 직접 자식 hitbox가 과업·WCAG target 기준에 맞고, 중심 y 차이를 실제 CSS 픽셀로 기록했다
|
||||
- [ ] 데스크톱 분할 패널을 숨긴 상태에서 빈 그리드 트랙이 남지 않고 주 표면이 전체 폭을 회수한다. 모바일 시트는 닫힘·배경·포커스 복원을 따로 검증한다
|
||||
- [ ] 한글이 있다면 조판 규칙이 적용됐다
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
|---|---|
|
||||
| 애니메이션 때문에 콘텐츠가 **읽히기까지 지연**됨 | 첫 화면은 모션 없이 즉시 표시. 리빌은 스크롤 이후 |
|
||||
| 스크롤 리빌이 위아래로 오갈 때 **매번 재생** | `both` / `once` / `unobserve()` |
|
||||
| 애니메이션 중 **레이아웃 시프트** | 게이트 #8. `transform`/`opacity`만 |
|
||||
| 애니메이션 중 **레이아웃 시프트** | 레이아웃·입력·CLS를 실제로 측정하고 프로젝트 예산과 비교 |
|
||||
| **동시에 3개 이상** 독립 애니메이션 | 시선이 분산된다. 순차화하거나 통합 |
|
||||
| 400ms 넘게 **사용자를 막는** 전환, 인터럽트 불가 | 줄이고, 애니메이션 중에도 입력을 받아라 |
|
||||
| 무한 반복되는 **큰 면적** 움직임 | 전정기관 자극. 정지 수단을 주거나 제거 |
|
||||
|
|
@ -79,9 +79,9 @@
|
|||
|
||||
---
|
||||
|
||||
## 2. 하드 게이트 #8을 지키면서 하고 싶은 걸 다 하는 법
|
||||
## 2. 저비용 기본 선택으로 만들기
|
||||
|
||||
**`transform`/`opacity` 외의 속성을 애니메이션하면 실패다. 오버라이드 없다.** 그런데 거의 모든 요구는 우회할 수 있다.
|
||||
**`transform`/`opacity`는 저비용 기본 선택이다.** 다른 속성의 애니메이션은 자동 실패가 아니다. 다만 비용·CLS·입력 간섭·감소 모션·지원 범위를 측정해 프로젝트 예산과 비교하고, 목적이 더 단순한 정적 상태로 충족되는지도 먼저 검토한다.
|
||||
|
||||
| 하고 싶은 것 | 하지 마라 | 대신 |
|
||||
|---|---|---|
|
||||
|
|
@ -203,7 +203,7 @@
|
|||
### 코드 C — 스크롤 진입 리빌 (IntersectionObserver)
|
||||
|
||||
> 언제: Firefox 지원이 **요구사항**일 때, 또는 진입 시점에 **DOM을 바꿔야** 할 때(카운트업 시작, 지연 로드, 3D 씬 기동). CSS는 스타일만 바꾼다.
|
||||
> `window.addEventListener('scroll')`은 **게이트 #10**이다. 절대 쓰지 마라.
|
||||
> `window.addEventListener('scroll')`은 자동 금지가 아니다. 필요한 경우 passive 처리·throttle 또는 rAF 일정화·입력 지연·프레임 시간·감소 모션 경로를 측정하고, `IntersectionObserver` 또는 scroll-driven animation이 더 맞는지 비교한다.
|
||||
|
||||
```css
|
||||
/* .js가 붙기 전에는 그냥 보인다 — JS가 실패해도 콘텐츠가 사라지지 않는다 */
|
||||
|
|
@ -732,9 +732,9 @@ const progress = clamp01((start - rect.top) / travel);
|
|||
**하나라도 실패하면 4-4 복귀다.**
|
||||
|
||||
**게이트 직결**
|
||||
- [ ] `transition`·`@keyframes`를 전부 grep했다. 애니메이션되는 속성이 `opacity`·`transform`·`translate`·`rotate`·`scale`뿐이다 (**#8**)
|
||||
- [ ] `background-color`·`box-shadow`·`filter`·`height`·`width`·`top`·`left`·`color`를 전환하는 곳이 없다. 있으면 §2 우회표로
|
||||
- [ ] `addEventListener('scroll'`이 소스에 없다 (**#10**)
|
||||
- [ ] `transition`·`@keyframes`를 전부 grep하고, 각 속성의 목적·비용 측정·입력 간섭·감소 모션 경로를 기록했다. `opacity`·`transform`·`translate`·`rotate`·`scale` 이외 속성은 프로젝트 예산과 실제 렌더 결과로 정당화했다
|
||||
- [ ] `background-color`·`box-shadow`·`filter`·`height`·`width`·`top`·`left`·`color`를 전환한다면 §2의 저비용 대안과 비교하고, 유지 이유와 측정 결과를 기록했다
|
||||
- [ ] `addEventListener('scroll'`을 썼다면 passive 처리와 일정화, 프레임 시간·입력 지연 측정, 감소 모션 경로를 기록했다
|
||||
- [ ] duration·이징이 전부 `var(--dur-*)`·`var(--ease-*)`다. 인라인 ms 값이 없다
|
||||
- [ ] 이펙트를 전부 끈 상태에서 페이지가 완성돼 있다
|
||||
- [ ] **등장 모션이 감사 도구의 대기시간보다 짧다** — 시각 회귀가 뷰 전환 뒤 N ms 에 스크린샷을 찍는다면 등장 애니메이션은 그보다 짧게(관례: ≤70ms). 아니면 회귀가 매번 다른 프레임을 찍어 흔들린다. 자세한 규칙은 `audit-gate.md` 하니스 10
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ canvas { display: none !important; }
|
|||
```
|
||||
이 상태에서 **페이지가 여전히 읽히고 구조가 살아 있어야 한다.** 무너지면 이펙트가 구조를 대신하고 있는 것이다. 4-1로 돌아가라.
|
||||
|
||||
### B. 슬롭 지문 grep
|
||||
`references/antipatterns.md` 의 grep 목록을 소스에 돌린다. 검출률 상위 항목(보라 CTA, 전체 대문자 헤드라인, 번호 매긴 1·2·3 단계)부터.
|
||||
### B. 스타일 후보 grep
|
||||
`references/antipatterns.md`의 grep 목록을 소스에 돌려 보라 CTA, 전체 대문자 헤드라인, 번호 매긴 단계 같은 반복 후보를 찾는다. 검출은 실패가 아니다. 프로젝트 계약·브리프·실제 렌더를 대조해 결정을 기록한다.
|
||||
|
||||
### C. 카피 경쟁사 치환
|
||||
제품명을 경쟁사 이름으로 바꿔 읽는다. **문장이 그대로 성립하면 그 카피는 아무것도 말하지 않았다.** 히어로 문구부터 검사한다.
|
||||
|
|
@ -110,34 +110,43 @@ canvas { display: none !important; }
|
|||
|
||||
### 폰트 (`typography.md` §8 이 전체 목록)
|
||||
|
||||
- [ ] **폴백 메트릭을 보정했거나 `font-display: optional` 을 골랐다.** 둘 다 안 했으면 폰트가 교체되는 순간 레이아웃이 튄다
|
||||
- [ ] preload 한 파일이 첫 화면에 실제로 쓰인다. `crossorigin` 이 있다
|
||||
- [ ] 수치를 나열하는 곳에 `tabular-nums` 가 있다
|
||||
- [ ] 한글 폰트를 명시했고 서브셋을 쓴다
|
||||
- [ ] 웹폰트 임베딩 라이선스를 확인해 `design.md` 에 적었다
|
||||
- [ ] **폰트를 못 받은 상태로 열어봤다.** 그 상태로도 읽힌다
|
||||
- [ ] 웹폰트를 쓰면 실제 교체 시점의 레이아웃을 측정하고, 폴백 메트릭·`font-display` 전략을 선택했다. 특정 전략만으로 CLS 유무를 단정하지 않는다
|
||||
- [ ] 폰트를 preload했다면 첫 화면에서 실제로 쓰이고 요청에 맞는 `crossorigin`이 있다
|
||||
- [ ] 수치 비교가 필요한 곳의 숫자 정렬을 확인했다. `tabular-nums`는 해당 서체의 지원과 과업에 맞춰 선택한다
|
||||
- [ ] 한글 글꼴과 시스템 폴백을 실제로 확인했다. 웹폰트를 전송하는 경우 서브셋·전송량·글리프 범위를 검토했다
|
||||
- [ ] 웹폰트를 임베딩하면 라이선스를 확인해 `design.md`에 적었다
|
||||
- [ ] 웹폰트를 쓰면 **폰트를 못 받은 상태로 열어봤다.** 그 상태로도 읽힌다
|
||||
|
||||
### 자주 걸리는 것
|
||||
- 폰트 서브셋 안 함 (한글 전체 폰트는 수 MB)
|
||||
- 전송하는 폰트의 크기·글리프 범위 미측정. 한글 웹폰트는 필요한 범위와 라이선스에 맞춰 서브셋을 검토한다
|
||||
- 첫 화면 밖 이미지에 `loading="lazy"` 누락
|
||||
- 3D/WebGL을 초기 번들에 포함 (뷰포트 진입 시 동적 import 해야 한다)
|
||||
- 애니메이션이 `top`/`left`/`width` 를 건드림 → `transform` 으로 바꿔라
|
||||
- 애니메이션이 `top`/`left`/`width` 를 건드림 → `transform`·`opacity`로 가능한지 먼저 검토하고, 유지한다면 비용·CLS·입력 간섭·감소 모션을 측정해 예산과 대조한다
|
||||
- `will-change` 남발 → 레이어가 늘어 오히려 느려진다
|
||||
|
||||
---
|
||||
|
||||
## 3. 반응형
|
||||
|
||||
- [ ] **320px** 폭에서 가로 스크롤 없음 (하드 게이트 #5 는 320~1920px 전 구간을 요구한다. 375px 만 보면 그 아래가 뚫린다)
|
||||
- [ ] 프로젝트가 채택한 회귀 매트릭스에서 가로 스크롤 없음. 이 저장소의 기본 매트릭스는 **320·390·768·1440·1920·2560px**이며, 지원 기기·브리프가 다르면 그 계약을 바꾸고 이유를 기록한다
|
||||
- [ ] **크롬(탑바·앱바·툴바)에 컨트롤을 더했다면 그 줄의 최소폭 합을 가장 좁은 폭에서 다시 잰다** — 버튼 하나가 320px를 뚫는 사고가 반복된다(실측: 인쇄 버튼 1개로 +18px). 줄이 넘으면 감싸기(2행 랩)가 기본 수습이다
|
||||
- [ ] 1920px 이상에서 콘텐츠가 늘어지지 않음(최대 폭 제한)
|
||||
- [ ] 프로젝트 회귀 매트릭스의 각 폭에서 실제 브라우저 렌더를 잰다. 기본 매트릭스(320·390·768·1440·1920·2560px)는 저장소의 회귀 범위이며 WCAG의 보편 폭 기준은 아니다. 최소 폭의 오버플로와 wide 화면의 카피 측정폭·제목 칼럼을 함께 확인한다
|
||||
- [ ] WCAG 200% 확대 또는 운영체제의 실제 글꼴 확대가 지원 범위라면 실제 브라우저·기기에서 별도 검증한다. gate의 font-scale 행렬은 회귀 신호이며 px 고정 폰트의 OS 확대를 대체하지 않는다
|
||||
- [ ] 1920px 이상에서는 본문 측정폭을 유지하고, 표·도면·작업대처럼 정보 밀도가 필요한 표면만 별도의 `--container-wide`로 넓힌다. 같은 `max-width`를 전부 풀어 넓은 화면을 빈 종이로 만들지 않는다
|
||||
- [ ] 분할 히어로는 1920·2560에서 `hero / copy / media / 다음 정보 레일` rect를 기록했다. 사진의 최대 폭과 카피의 최소 폭을 페이지 토큰으로 정하고, 단지 viewport를 반으로 나눈 `1fr 1fr`가 사진을 무제한 키우지 않는지 확인한다
|
||||
- [ ] hero 검증만으로 text-media 분할 검증을 끝내지 않는다. 과정·추천·가맹처럼 DOM/여백 규칙이 다른 모든 분할 표면에서 rail·copy·media·제목의 실제 rect와 줄 수를 기록한다. wide override가 있다면 기존 `padding-left/right: calc(100vw …)`를 **양쪽 모두** 재설정했는지, 상위 `max-width`의 선택자 우선순위가 named stage를 다시 줄이지 않는지 확인한다
|
||||
- [ ] 중간 뷰포트(768~1024px)에서 레이아웃이 깨지지 않음 — **가장 자주 빠뜨리는 구간**
|
||||
- [ ] 터치 타깃: **버튼·아이콘·카드 등 독립 컨트롤은 44×44px 이상**(Apple/Google 권고)
|
||||
- [ ] 터치 타깃: **본문 안 인라인 텍스트 링크는 24×24px 이상**(WCAG 2.5.8 AA). 여기에 44 를 요구하면 정상적인 내비 링크가 오탐된다
|
||||
- [ ] **컨트롤의 내용 여백**: 버튼 라벨·입력값·select 표시·표 셀의 실제 렌더 글자가 테두리에 닿지 않는다. 이 저장소의 실렌더 기본값은 좌우 **8 CSS px** 이상이다. 이는 WCAG 적합성 수치가 아니라 검증 가능한 시각 품질 기본값이며, 아이콘 전용·체크박스·의도적인 데이터 정렬은 별도 근거를 적는다
|
||||
- [ ] **폼 기하**: 연결된 label/name/autocomplete를 확인한 뒤 실제 렌더 rect로 입력끼리 겹치지 않는지 잰다. 좁은 폭에서는 필드를 세로로 쌓고, label·입력·오류 문장이 서로의 클릭/읽기 영역을 침범하지 않게 한다
|
||||
- [ ] **표와 표처럼 보이는 flex/grid**: 데이터 관계에는 `th`/`td`와 `scope`를 쓰고, 모든 가시 셀에 좌우 읽기 여백을 둔다. 좁은 폭에서 스크롤·카드화로 형식이 바뀌어도 헤더-값 관계가 남아야 한다
|
||||
- [ ] 호버로만 접근되는 기능 없음
|
||||
- [ ] 긴 단어/URL이 넘치지 않음 (`overflow-wrap: anywhere`)
|
||||
- [ ] 가로 모드에서 첫 화면이 잠기지 않음
|
||||
|
||||
> 근거: [W3C WCAG 2.5.8 Target Size](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum) (최소 24 CSS px/간격 예외), [Apple HIG Layout](https://developer.apple.com/design/human-interface-guidelines/layout) (읽기 폭·음의 공간·다양한 화면 크기), [Apple HIG Text Fields](https://developer.apple.com/design/human-interface-guidelines/text-fields?changes=_7) (일관된 필드 폭·간격·세로 배치), [W3C Tables Tutorial](https://www.w3.org/WAI/tutorials/tables/tips/) (반응형에서도 데이터 관계 보존), [NN/g Form White Space](https://www.nngroup.com/articles/form-design-white-space/) (인접 요소의 간격이 관계를 전달함). 조사일 2026-08-30.
|
||||
|
||||
---
|
||||
|
||||
## 4. 콘텐츠
|
||||
|
|
@ -159,6 +168,7 @@ canvas { display: none !important; }
|
|||
- [ ] **판정은 순수 함수다** — 가능/불가+사유의 판정 로직은 UI 핸들러에 두지 않고 `calc.js` 같은 모듈로 추출해 단위 테스트(L1)가 같은 판정을 공유하게 한다. UI 는 판정 결과를 문장으로 번역만 한다. 실행취소의 재심사도 같은 함수를 쓴다
|
||||
- [ ] **파괴적 행동에는 되돌림이 있다** — 삭제·취소는 실행취소 또는 확인. 되돌리기가 확인보다 낫다(흐름이 끊기지 않는다). 재신청·복원은 원래 판정 함수로 다시 심사한다 — 사이에 끼어든 다른 변화가 있으면 정당하게 막혀야 한다
|
||||
- [ ] **열리는 것은 Esc 로 닫힌다** — 모달만이 아니다. 드롭다운·팝오버·알림 메뉴도. 닫힐 때 포커스는 연 요소로 돌아간다
|
||||
- [ ] native `<dialog>` 또는 동등 모달은 전역 reset 뒤에도 `position: fixed; inset: 0; margin: auto`와 viewport 상한/내부 scroll owner를 가진다. 390·1440·2560에서 중심점, 화면 안 rect, 배경 scroll lock을 실제로 단언한다. W3C의 modal dialog 키보드·포커스·닫기 계약을 따른다: [WAI-ARIA APG](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/), [MDN dialog](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dialog)
|
||||
- [ ] **로딩 상태는 실제 비동기에만** — 동기 인라인 데이터에 스켈레톤을 붙이는 건 저장을 흉내내는 것이다. 없는 지연을 만들지 마라
|
||||
|
||||
---
|
||||
|
|
@ -178,17 +188,30 @@ canvas { display: none !important; }
|
|||
- [ ] 생성 이미지는 가격·주소·점수의 증거로 쓰이지 않으며, 모바일 390×844에서 핵심 피사체가 첫 화면의 의도와 맞는다
|
||||
- [ ] URL별 390·1440 기본 화면과 핵심 입력/오류/모달 상태 캡처를 실제로 열어 보고 시각 PASS/RED를 따로 기록했다
|
||||
|
||||
## 4-3. 썸네일·OG 캡처 — 움직이는 화면을 대표하지 않는다
|
||||
|
||||
썸네일은 '페이지가 열렸다'는 증거가 아니라 사람들이 처음 보는 **정지된 브랜드 표면**이다. 로딩 중인 폰트, 이미지 디코드 전 프레임, 입장 모션 중간, 다음 WebGL 프레임을 파일로 남기면 정상 사이트도 카드에서 망가져 보인다.
|
||||
|
||||
- [ ] `file://` 즉시 캡처 대신 실제 배포와 같은 상대 URL을 해석하는 로컬 HTTP 서버에서 고정 viewport로 연다. 로컬 4xx, runtime error, `naturalWidth === 0` 이미지는 캡처 성공이 아니라 실패다
|
||||
- [ ] `document.fonts.ready`와 모든 가시 이미지의 `decode()`를 기다린 뒤, 페이지별로 정한 **bounded settle 시간**을 지난다. `document.fonts.ready`는 사용 중인 폰트의 로드와 레이아웃 작업이 끝날 때 이행한다
|
||||
- [ ] 캡처 환경은 `prefers-reduced-motion: reduce`를 에뮬레이션하고, 영상·오디오는 정지하며 CSS/WAAPI 애니메이션과 rAF 기반 canvas를 **정착한 한 프레임**에 멈춘다. `animation: none`으로 초기 상태를 되돌려 빈 화면을 만들지 말고, 실제로 완성된 프레임을 pause/finish 한다
|
||||
- [ ] 기본 컷·모달/결과 컷·OG 모두 같은 계약으로 찍고, 파일의 규격·0바이트·해시 중복을 검사한 뒤 적어도 움직임이 있던 대표 컷을 눈으로 연다. 생성 이미지가 있으면 기존 진실 라벨 계약도 그대로 보존한다
|
||||
|
||||
> 근거: [MDN `Document.fonts`](https://developer.mozilla.org/en-US/docs/Web/API/Document/fonts) (`ready`는 사용 중인 폰트의 로드와 레이아웃 완료 뒤 이행), [MDN `HTMLImageElement.decode()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode), [MDN `prefers-reduced-motion`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) (불필요한 모션을 줄이거나 대체하는 사용자 선호). 조사일 2026-08-30.
|
||||
|
||||
---
|
||||
|
||||
## 5. 디자인 자체
|
||||
|
||||
기계로 못 잡는 부분이다. **정직하게 답해라.**
|
||||
|
||||
첫인상·실제 과업 행동·접근성 적합성·전문가 시각 검토가 필요한 경우, [design foundations의 평가 절차](design-foundations.md)를 읽고 각 결과를 분리해 기록한다.
|
||||
|
||||
1. **이 사이트를 다른 회사의 것으로 바꿔도 그대로 쓸 수 있는가?** → 그렇다면 브리프에 맞춘 것이 없다
|
||||
2. **2단계에서 정한 한 문장 컨셉이 화면에서 보이는가?** → 안 보이면 컨셉이 문서에만 있는 것이다
|
||||
3. **감수하기로 한 리스크가 실제로 들어갔는가?** → 구현 중에 안전한 쪽으로 후퇴하지 않았는지
|
||||
4. **1단계 레퍼런스 R2(다른 업종의 톤)의 흔적이 있는가?** → 없으면 결국 R1을 베낀 것이다
|
||||
5. **강조색이 하나인가?**
|
||||
4. **사용한 레퍼런스의 원칙이 브리프와 렌더 결과에 맞게 번역됐는가?** → 슬롯 수나 업종 차이 자체로 판단하지 않는다
|
||||
5. **강조색·radius·정렬·반복이 프로젝트 토큰과 과업에 맞는가?**
|
||||
6. **여백이 의도적인가, 남은 것인가?**
|
||||
|
||||
---
|
||||
|
|
@ -204,8 +227,9 @@ canvas { display: none !important; }
|
|||
- [ ] 콘텐츠 체크리스트 통과
|
||||
- [ ] 상태 완결성(§4-1) — 입력 검증·되돌림·Esc 를 실제 조작으로 확인
|
||||
- [ ] 해당하면 진실 완결성(§4-2) — 예시·AI·규제·생성 이미지의 오해 경로를 실제 상태로 확인
|
||||
- [ ] 5장 여섯 질문에 정직하게 답했고, 실패 항목을 고쳤다
|
||||
- [ ] `antipatterns.md` 자가 채점표 통과
|
||||
- [ ] 정적 CSS/JS의 stable URL을 바꿨다면 HTML 링크와 `@import` 의 버전을 함께 올렸고, 공개 CDN에서 실제 내려온 stylesheet URL과 새 토큰/규칙을 확인했다. HTML만 cache-bust하고 CSS가 이전 버전이면 배포 성공이 아니다
|
||||
- [ ] 기능·접근성 자동 검사의 결과와 시각 평가(위계·브랜드·타입·구도·이미지·리듬)의 결과를 별도로 기록했다. 한쪽 PASS를 다른 쪽 PASS로 바꾸어 말하지 않았다
|
||||
- [ ] 5장 여섯 질문과 `antipatterns.md` 검토를 프로젝트 계약·실제 렌더 근거로 기록했다
|
||||
|
||||
**하나라도 실패하면 출시가 아니라 4단계 복귀다.**
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
2단계에서 읽는다. **하나를 고르고, 왜 그것인지 한 줄로 적는다.**
|
||||
|
||||
프리셋은 템플릿이 아니라 **결정의 출발점**이다. 그대로 쓰면 그 프리셋의 평균이 나온다.
|
||||
프리셋은 템플릿이 아니라 **결정의 출발점**이다. 값·폰트·효과 목록은 가설이며, 브리프·콘텐츠·실제 렌더 검증으로 조정한다. 단 각 프리셋이 정한 정체성 계약(예: editorial의 세리프 주역, dense 화면의 비교 가능성)은 바꾸려면 다른 프리셋 또는 새 방향을 정의한다.
|
||||
1단계 레퍼런스 R2(다른 업종의 톤)를 여기에 섞어야 이 브리프만의 것이 된다.
|
||||
|
||||
| 프리셋 | 한 줄 | 언제 |
|
||||
|
|
@ -14,4 +14,4 @@
|
|||
| [quiet-commerce](quiet-commerce.md) | 읽히는 커머스 | 전환이 목적인 B2C. 상품 수가 적고 사양이 설득의 주체 |
|
||||
|
||||
**어느 것도 맞지 않으면 새로 정의해라.** 브리프가 프리셋보다 우선한다.
|
||||
새로 정의할 때도 이 문서들의 항목 구조(타이포/색/간격/재질/모션/실패)는 그대로 채워야 한다.
|
||||
새로 정의할 때도 이 문서들의 항목 구조(타이포/색/간격/재질/모션/실패/검증)는 채운다. 실제 적용 조건과 검증은 `../style-playbook.md`를 따른다.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
> 한 문장: **기억되는 것이 목적일 때.** 규칙을 알고 나서 깬다.
|
||||
|
||||
벤토 그리드가 표준화되자 그 반작용으로 부상한 방향이다. 2026년 현재 **실제로 작동하는 차별화 수단**이다.
|
||||
규칙적 격자에 비대칭·겹침·예상 밖의 리듬을 의도적으로 더하는 방향이다. 이것이 2026년에 보편적으로 더 효과적이라는 실증 주장은 하지 않는다.
|
||||
|
||||
## 언제 고르나
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
## 결정
|
||||
|
||||
### 타이포그래피
|
||||
- 산세 + **모노스페이스 병용**. 수치·ID·코드는 반드시 모노
|
||||
- 산세를 본문 출발점으로 두고, 정렬이 중요한 수치·ID·코드에는 tabular figure 또는 모노를 검토한다. 모든 수치·ID에 모노가 필수인 것은 아니다.
|
||||
- 비율 1.200~1.250. 정보 밀도가 높으므로 위계 차이를 작게
|
||||
- 숫자는 **tabular-nums** 를 켜라 (`font-variant-numeric: tabular-nums`). 수치가 흔들리면 계기판이 아니다
|
||||
|
||||
|
|
@ -26,8 +26,7 @@
|
|||
| 수치·코드 | JetBrains Mono, IBM Plex Mono | + Pretendard |
|
||||
|
||||
### 색
|
||||
- **순수 검정을 쓰지 마라.** `#0d0d0f`~`#14130f` 대역. 순흑은 대비가 과해 눈이 아프다
|
||||
- 텍스트도 순백 금지. `#e8e4dc`~`#e6e6e9`
|
||||
- 순수 검정/흰색과 근접색을 모두 후보로 두고, 실제 기기·주변광·장시간 읽기에서 대비와 눈부심을 확인한다. `#0d0d0f`~`#14130f`, `#e8e4dc`~`#e6e6e9`는 출발값 예시다.
|
||||
- 표면 단계를 3개로: `--surface`(가장 어두움) / `--surface-raised` / `--line`
|
||||
- 강조색은 **밝고 채도 높게, 아주 좁게.** 어두운 배경에서는 작은 면적으로도 충분히 강하다
|
||||
- 상태색(성공/경고/오류)을 강조색과 구분해서 정의해라. 여기서는 기능이 우선이다
|
||||
|
|
@ -49,9 +48,9 @@
|
|||
|
||||
## 흔한 실패
|
||||
|
||||
1. **순수 검정 + 순수 흰색** → 눈이 아프고 아마추어
|
||||
1. **배경·텍스트 대비를 기기에서 확인하지 않음** → 순수색과 근접색 모두 조건에 따라 눈부심·번짐·브랜드 인상을 만들 수 있다
|
||||
2. **네온 보라/파랑 강조** → 슬롭 지문. 어두운 배경일수록 이 함정에 빠지기 쉽다
|
||||
3. **다크만 만들고 라이트를 안 만듦** → 토큰으로 짰으면 라이트도 나온다. 다크 전용은 사용자 선택권을 뺏는 것
|
||||
3. **테마 결정을 설명하지 않음** → 다크 전용일 수 있지만 대상 환경·브랜드·접근성·운영 이유를 기록하고, 지원하는 테마는 역할 토큰과 실제 상태를 완성한다
|
||||
4. **수치에 가변폭 폰트** → 숫자가 흔들려 읽기 어렵다
|
||||
5. **대비 미달** → 어두운 배경에서 `--ink-muted` 가 4.5:1 아래로 떨어지기 쉽다. 반드시 측정해라
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
## 결정
|
||||
|
||||
### 타이포그래피
|
||||
- **세리프를 주역으로.** 디스플레이와 본문 중 최소 하나는 세리프
|
||||
- 세리프 또는 고대비 산세를 주역 후보로 둔다. 대상 언어의 glyph·작은 크기·긴 읽기에서 더 잘 작동하는 쪽을 선택한다.
|
||||
- 비율 **1.333~1.618** — 헤드라인과 본문의 차이를 크게 벌린다
|
||||
- 본문 `--measure` 를 반드시 좁게. 라틴 60~68자, 한글 25~35자
|
||||
- 본문 `--measure`는 상대적으로 좁은 값에서 시작하고, 라틴 60~68자·한글 25~35자는 후보 범위로만 쓴다. 글꼴·언어·확대 상태의 실제 문단으로 확정한다.
|
||||
- 웨이트는 2개면 충분(Regular + 하나). 굵기로 소리치지 않는다
|
||||
|
||||
| 슬롯 | 무료 | 유료 | 한글 |
|
||||
|
|
@ -22,9 +22,9 @@
|
|||
| 본문 | Spectral, Lora | Söhne, Tiempos | 마루 부리 / 리디바탕 |
|
||||
|
||||
### 색
|
||||
- 배경은 **순백이 아니다.** 종이 쪽으로 살짝 따뜻하게 (`#fbfaf8`, `#f7f5f0`)
|
||||
- 잉크도 순흑이 아니다 (`#1a1917`, `#211f1c`)
|
||||
- 강조색은 **하나, 작게.** 링크·인용부호·페이지 번호 정도. 면적을 넓히면 잡지가 아니라 전단지가 된다
|
||||
- 종이 같은 따뜻한 배경과 순백 모두를 콘텐츠·이미지·브랜드 대비로 비교한다. `#fbfaf8`, `#f7f5f0`은 출발값 후보일 뿐이다.
|
||||
- 잉크는 순흑과 근접색을 실제 대비·주변 이미지·긴 읽기에서 비교한다.
|
||||
- 강조 역할이 필요하면 **한 색을 작게** 쓴다. 강조색이 없어도 되며, 링크·인용·페이지 번호의 구분은 대비·밑줄·위치로도 만들 수 있다.
|
||||
|
||||
### 간격
|
||||
- **여백이 콘텐츠다.** 섹션 간격을 본문 간격의 5~6배까지 벌려도 된다
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
- 이미지는 본문 폭을 넘어가게(`wide`/`full`) 두어 리듬을 만든다
|
||||
|
||||
### 재질 (`svg-filters.md`)
|
||||
- **필름 그레인**이 이 프리셋의 기본 재질. `feTurbulence fractalNoise` 를 아주 약하게(opacity 0.03~0.06)
|
||||
- 필름 그레인은 인쇄·사진 재질이 브리프에 맞을 때만 후보로 둔다. 효과 없이도 editorial 리듬이 성립해야 한다.
|
||||
- 인쇄물의 질감: 이미지에 미세한 듀오톤 또는 그라디언트 맵
|
||||
- 유리·네온·글로우는 이 프리셋에 어울리지 않는다
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
### 타이포그래피
|
||||
- 디스플레이 **세리프 1** + 본문 **산세리프 1**. 세리프가 톤을, 산세리프가 가독성을 맡는다
|
||||
- 비율 **1.333**, 최대÷본문 **4배 이상**. 비율만으로 안 나오면 디스플레이를 스케일 밖에 따로 정의한다(`tokens.md` §1)
|
||||
- 비율 1.333과 강한 display 대비에서 시작하고, 문구 길이·제품 증거·모바일 줄 수로 확정한다. 최대÷본문 4배 같은 고정 비율은 요구사항이 아니다.
|
||||
- 단계 **4~5개**. 커머스 레퍼런스는 흔히 10단계인데 그대로 베끼면 "통제 실패"에 걸린다
|
||||
- 웨이트 2개
|
||||
|
||||
|
|
@ -33,12 +33,12 @@
|
|||
### 색
|
||||
- 배경은 순백이 아니라 **오프화이트**. 단 **크림·베이지는 피해라** — "크림 = 고급"은 보라를 대체한 신종 슬롭이다. 크림을 쓰려면 브리프와 연결할 근거를 대라
|
||||
- 잉크도 순흑이 아니다
|
||||
- **강조색 하나, 면적 5% 미만.** 좋은 커머스 레퍼런스는 강조색을 CTA 한 곳과 링크에만 쓴다
|
||||
- 강조 역할이 필요하면 한 색으로 시작하고, 실제 상태색·링크·CTA를 포함한 화면에서 경쟁 여부를 검증한다. 5% 면적 같은 값은 보편 품질 기준이 아니다.
|
||||
- hue 2개 (중립 + 강조)
|
||||
|
||||
### 간격
|
||||
- 8px 그리드, 여백 값 5종
|
||||
- **섹션 간 : 요소 간 = 1:5.** 커머스는 섹션이 많아 간격이 좁으면 즉시 뭉개진다
|
||||
- 섹션과 요소 간격의 차이가 정보 묶음을 읽히게 하는지 본다. 1:5는 예시 가설이며, 상품 수·콘텐츠 길이·화면 폭에서 조정한다.
|
||||
- 비대칭을 쓴다 — 본문을 그리드 왼쪽에 두고 오른쪽 여백에 사양·수치를 흘린다
|
||||
- `--measure` 는 좁게. 한글 25~35자
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
## 결정
|
||||
|
||||
### 타이포그래피
|
||||
- **그로테스크 산세 하나로 끝낸다.** 두 번째 폰트를 넣고 싶으면 모노스페이스(라벨·코드용)까지만
|
||||
- 그로테스크 산세 하나에서 시작하고, 필요한 경우 라벨·코드 역할에 모노를 추가한다. 언어 범위나 실제 위계가 추가 패밀리를 요구하면 전송량과 렌더 근거를 남긴다.
|
||||
- 비율 **1.200~1.250** — 위계 차이를 작게. 대신 웨이트와 색으로 구분
|
||||
- 정렬은 왼쪽. 가운데 정렬은 히어로 한 곳까지만
|
||||
- **Inter 를 기본값으로 쓰지 마라.** Switzer, Satoshi, DM Sans 가 거의 언제나 낫다
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
| 라벨·코드 | JetBrains Mono, IBM Plex Mono | — | Pretendard + JetBrains Mono |
|
||||
|
||||
### 색
|
||||
- 무채색 90% + 강조색 하나
|
||||
- 무채색 비중이 큰 팔레트에서 시작하고, 강조 역할이 필요하면 한 색으로 시작해 실제 상태색·링크·CTA의 경쟁을 검증한다
|
||||
- 배경/카드/경계선의 명도 차이를 **아주 작게**. 그림자 대신 1px 경계선
|
||||
- 강조색은 채도를 낮춰라. 형광에 가까운 색은 이 프리셋에서 즉시 싸구려가 된다
|
||||
- **보라~파랑 그라디언트 절대 금지** (검출률 1위 슬롭 지문)
|
||||
|
|
@ -30,12 +30,12 @@
|
|||
### 간격
|
||||
- 4/8 배수 그리드를 **엄격하게** 지킨다. 여기서만큼은 예외를 만들지 마라
|
||||
- 정렬선이 전부 맞아야 한다. 이 프리셋의 품질은 정렬에서 나온다
|
||||
- 섹션 간격은 본문의 4배
|
||||
- 섹션과 본문의 간격 대비는 시작값으로 크게 두되, 콘텐츠 그룹과 좁은 폭에서 실제 리듬을 보고 확정한다.
|
||||
|
||||
### 재질 (`svg-filters.md`)
|
||||
- **재질을 거의 쓰지 않는다.** 이 프리셋의 표면은 평평한 종이다
|
||||
- 굳이 쓴다면 아주 약한 그레인 하나까지
|
||||
- 글래스모피즘 금지 — 실기기에서 FPS 15~30% 하락하고, 이 프리셋의 정직함과 어긋난다
|
||||
- 유리 효과는 이 프리셋의 평면적 언어와 충돌하기 쉽다. 채택하려면 계층상 이유와 저사양 기기의 성능·대비·reduced-transparency 대안을 검증한다. 고정 FPS 하락 수치를 일반화하지 않는다.
|
||||
|
||||
### 모션 (`motion.md`)
|
||||
- 상태 변화 위주(`--dur-instant`, `--dur-quick`). 등장 애니메이션은 최소화
|
||||
|
|
|
|||
|
|
@ -6,27 +6,27 @@
|
|||
|
||||
| 가져간다 (원리) | 안 가져간다 (표현) |
|
||||
|---|---|
|
||||
| 그리드 비율 (5:7 비대칭) | 섹션 배치 그대로 |
|
||||
| 타입 스케일 비율 (1.333) | 폰트 조합 그대로 |
|
||||
| 색의 역할 배분 (60/30/10) | 색상값 |
|
||||
| 여백 리듬 (섹션 120 / 요소 24) | 섹션 순서 |
|
||||
| 그리드의 비대칭 관계 (관찰 예: 5:7) | 섹션 배치 그대로 |
|
||||
| 타입 단계의 관계 (관찰 예: 1.333) | 폰트 조합 그대로 |
|
||||
| 색의 역할 배분 (관찰 예: 60/30/10) | 색상값 |
|
||||
| 여백의 상대 리듬 (관찰 예: 섹션 120 / 요소 24) | 섹션 순서 |
|
||||
| 모션의 의도 (스크롤=시선 유도) | 애니메이션 시퀀스 |
|
||||
|
||||
표의 숫자는 특정 사례를 설명하는 관찰 예시일 뿐, 다른 프로젝트에 그대로 적용할 법칙이 아니다. 관계가 현재 콘텐츠·언어·과업·렌더에서도 작동하는지 확인한 뒤 값을 정한다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 3-소스 합성 규칙
|
||||
## 1. 레퍼런스 슬롯으로 해체하기
|
||||
|
||||
레퍼런스 1개는 모방, 2개는 절충, **3개부터 합성**이다. 단 **층위를 나눠서** 고른다.
|
||||
R1·R2·R3은 구조·톤·디테일을 섞어 복제하지 않기 위한 **검토 슬롯**이다. 세 슬롯을 채웠다는 사실은 합성의 품질을 보장하지 않는다. 프로젝트에 필요한 슬롯만 채우고, 비운 슬롯은 이유와 대체 근거를 기록한다.
|
||||
|
||||
| 슬롯 | 가져올 것 | 어디서 |
|
||||
|---|---|---|
|
||||
| **R1 · 구조** | 그리드, 섹션 순서, 정보 위계, 여백 리듬 | 같은 업종·같은 목적 |
|
||||
| **R2 · 톤** | 색 역할, 타입 페어링, 형태 언어, 질감 | **반드시 다른 업종** (또는 웹이 아닌 것) |
|
||||
| **R2 · 톤** | 색 역할, 타입 페어링, 형태 언어, 질감 | 다른 업종 또는 웹 이외 매체를 우선 검토 |
|
||||
| **R3 · 디테일** | 모션 1개, 호버 1개, 전환 1개 | Codrops / Eyecandy / Design Spells |
|
||||
|
||||
**R2가 R1과 같은 업종이면 합성이 아니다.**
|
||||
SaaS 구조 + SaaS 톤 = 또 하나의 SaaS 슬롭.
|
||||
SaaS 구조 + 독립 출판사 톤 = 차별화.
|
||||
R2가 R1과 같은 업종이어도 브리프가 요구하는 브랜드·시장·제작 조건에 맞으면 가능하다. 같은 업종의 평균을 무비판적으로 복제하지 않도록, 가져오는 원칙·관찰·결정·검증을 분리해 기록한다.
|
||||
|
||||
### 목표 시장은 네 번째 레퍼런스가 아니라 경계 조건이다
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ SaaS 구조 + 독립 출판사 톤 = 차별화.
|
|||
```
|
||||
|
||||
- R1은 같은 업종·목적에 더해 **같은 목표 시장을 우선**한다. 구조에 단위·용어·연락 방식이 묻어 있기 때문이다.
|
||||
- R2의 `다른 업종` 규칙은 유지한다. 목표 시장 감각이 중요하면 **같은 문화권의 다른 업종**을 먼저 찾는다.
|
||||
- R2는 다른 업종 또는 같은 문화권의 다른 매체를 먼저 검토하되, 같은 업종이 더 적합하면 그 조건과 이유를 기록한다.
|
||||
- 다른 문화권 R3는 기법만 가져온다. 카피·색·상징·사진 연출까지 번지면 경계 조건 위반이다.
|
||||
- 같은 시장 자료가 부족하면 빈칸을 숨기지 말고, 어떤 관습을 공식 문서·현지 서비스로 별도 검증했는지 적는다.
|
||||
|
||||
|
|
@ -47,41 +47,38 @@ SaaS 구조 + 독립 출판사 톤 = 차별화.
|
|||
1. 가독성·접근성이 언제나 이긴다. R2의 톤이 대비를 깨면 톤을 조정한다.
|
||||
2. R1 구조가 R3 모션을 이긴다. 모션 때문에 구조를 바꾸지 않는다.
|
||||
3. 브리프가 모든 레퍼런스를 이긴다. 충돌하면 레퍼런스를 버린다.
|
||||
4. **한 축은 한 소스에서만.** 그리드는 R1에서만, 팔레트는 R2에서만. 섞으면 이유 없는 절충이 된다.
|
||||
4. 한 축에 여러 출처가 영향을 주면 출처별 관찰과 최종 결정을 분리한다. 출처가 섞였다는 사실이 실패는 아니며, 근거 없이 절충한 경우만 다시 검토한다.
|
||||
|
||||
---
|
||||
|
||||
## 2. 6축 해체 프레임워크
|
||||
|
||||
각 레퍼런스를 6축으로 뜯는다. **형용사는 기록이 아니다. 숫자나 규칙으로 적는다.**
|
||||
각 레퍼런스를 6축으로 뜯는다. **형용사만으로 끝내지 않는다.** 실측값, 관찰 가능한 규칙, 적용 조건을 함께 적고 실제 렌더에서 결정이 맞는지 확인한다. 아래 숫자 범위는 보편 판정이 아니라 관찰을 시작할 때 쓸 수 있는 예시다.
|
||||
|
||||
**R3 예외**: R3는 사이트가 아니라 기법이다. 축 5(모션 언어) 하나만 채우고 나머지는 비운다.
|
||||
대신 R3에는 **구현 제약**(브라우저 지원, 성능 비용, 보간 조건)을 반드시 적는다.
|
||||
|
||||
### 축 1 — 레이아웃 그리드
|
||||
컬럼 수·거터 / 콘텐츠 최대폭과 뷰포트 비 / 대칭·비대칭(비율) / 그리드를 깨는 요소 / 본문 한 줄 글자 수(영문 45–75, 국문 25–40)
|
||||
컬럼 수·거터 / 콘텐츠 최대폭과 뷰포트 비 / 대칭·비대칭(비율) / 그리드를 깨는 요소 / 실제 본문 줄 길이와 읽기 맥락
|
||||
→ *"무엇을 정렬시키고 무엇을 일부러 어긋나게 했나?"*
|
||||
|
||||
### 축 2 — 타입 스케일
|
||||
실제 사용된 크기 목록 / 그 사이 비율(1.25 또는 1.333이 표준) / 단계 수(3–5가 건강, 8+ 는 통제 실패) / 패밀리 수(2개 표준) / 굵기 대비 / line-height / letter-spacing
|
||||
→ *"최대 글자와 본문의 비는 몇 배인가?"* (4배 미만이면 위계 약함)
|
||||
실제 사용된 크기 목록 / 그 사이 비율 / 단계 수 / 패밀리 수 / 굵기 대비 / line-height / letter-spacing
|
||||
→ *"최대 글자와 본문의 비는 몇 배이고, 이 화면의 과업·언어·읽기 폭에서 위계가 보이는가?"*
|
||||
|
||||
### 축 3 — 컬러 역할
|
||||
색상값이 아니라 **역할**로 적는다. surface 단계 수 / text 3단계 유무 / accent 면적 %(10% 이하가 정상) / border 존재 여부 / state 색 분리 여부
|
||||
→ *"강조색을 지우면 여전히 읽히는가?"* (읽혀야 정상)
|
||||
색상값이 아니라 **역할**로 적는다. surface 단계 수 / text 위계 / accent 면적과 역할 / border 존재 여부 / state 색 분리 여부
|
||||
→ *"강조색을 지워도 정보 위계와 조작 상태를 이해할 수 있는가?"*
|
||||
|
||||
### 축 4 — 여백 리듬
|
||||
기본 단위(4 또는 8px) / 섹션 간 수직 여백(80–160px) / 요소 간 : 섹션 간 비율(1:4~1:6) / 여백 값 종류 수(4–6종이 건강) / 좌우 패딩
|
||||
기본 단위 / 섹션 간 수직 여백 / 요소 간 : 섹션 간 비율 / 여백 값 종류 / 좌우 패딩
|
||||
→ *"가장 큰 빈 공간은 어디이고 왜 거기인가?"*
|
||||
|
||||
### 축 5 — 모션 언어
|
||||
트리거(로드/스크롤/호버/커서) / duration / easing / 정보 전달인가 장식인가 / reduced-motion 대응
|
||||
→ *"모션을 전부 끄면 작동하는가?"* (작동해야 정상)
|
||||
|
||||
**어떤 CSS 속성을 애니메이션하는지 반드시 적어라.** 하드 게이트 #8은 `transform`·`opacity` 만 허용한다.
|
||||
`stroke-dashoffset`·`height`·`clip-path`·`filter` 로 만든 기법을 R3로 골라놓고 4단계에서 발견하면
|
||||
그때는 이미 늦다. **1단계에서 걸러라.** 그 기법이 좋다면 `motion.md` 의 우회법 표에서
|
||||
같은 인상을 `transform`/`opacity` 로 내는 방법을 찾은 뒤에 채택해라.
|
||||
**어떤 CSS 속성 또는 스크롤 로직을 쓰는지 반드시 적어라.** `transform`·`opacity`는 저비용 기본이지만 다른 선택은 금지가 아니다. `stroke-dashoffset`·`height`·`clip-path`·`filter` 같은 기법은 1단계부터 비용 측정, 입력 간섭, 감소 모션, 지원 범위와 예산을 함께 기록해 `motion.md`의 계약으로 검증한다.
|
||||
|
||||
### 축 6 — 시선 흐름
|
||||
첫 진입점 / 2·3번째 / 비즈니스 우선순위와 일치 여부 / Z·F·수직 낙하 중 무엇인가 / CTA가 경로 위에 있나
|
||||
|
|
@ -90,7 +87,7 @@ SaaS 구조 + 독립 출판사 톤 = 차별화.
|
|||
> 색을 전부 제거했을 때 가장 강한 덩어리는 ___, 두 번째는 ___, 세 번째는 ___.
|
||||
> 이 순서는 비즈니스 우선순위 [1위 ___ / 2위 ___ / 3위 ___]와 일치한다 / 하지 않는다.
|
||||
|
||||
일치하지 않으면 크기·굵기·대비를 조정한다. **색으로 해결하지 마라.**
|
||||
일치하지 않으면 크기·굵기·대비·공간·순서를 검토한다. 색만으로 해결하지 않고, 필요한 경우 색 역할도 프로젝트 토큰 안에서 조정한다.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -98,19 +95,19 @@ SaaS 구조 + 독립 출판사 톤 = 차별화.
|
|||
|
||||
- [ ] **1. 브리프를 한 문장으로 압축한다.** `[대상]이 [행동]하게. 느낌은 [형용사 2개].` 이 문장 없이 수집을 시작하지 않는다.
|
||||
- [ ] **1-b. 목표 시장 경계 조건을 쓴다.** 국가/생활권·기기·단위/통화·행동 관습·금지할 외래 문법. R1이 같은 시장인지 표시한다.
|
||||
- [ ] **2. galleries.md 라우팅 표에서 R1/R2/R3 갤러리를 정한다.** R2가 R1과 다른 업종인지 확인한다.
|
||||
- [ ] **3. 각 갤러리에서 원본 사이트 URL을 1개씩 확보한다.** 하위 페이지가 필요하면 **인덱스에서 `href`를 뽑아라. slug를 추측하지 마라** — 추측한 URL은 404가 난다.
|
||||
- [ ] **2. galleries.md 라우팅 표에서 필요한 레퍼런스 슬롯을 정한다.** R2의 업종·매체 선택 조건을 기록한다.
|
||||
- [ ] **3. 사용한 각 슬롯에서 원본 사이트 URL을 확보한다.** 하위 페이지가 필요하면 **인덱스에서 `href`를 뽑아라. slug를 추측하지 마라** — 추측한 URL은 404가 난다.
|
||||
- [ ] **3-b. 그 URL이 정본인지 검증한다.** 사용자가 특정 제품·브랜드를 지목했고 후보 도메인이 여럿이면 필수다. **HTTP 200은 살아있다는 뜻이 아니다.**
|
||||
- `curl -sS -o /dev/null -w "%{url_effective} %{http_code} %{size_download}\n" -L <url>` 로 **최종 URL·본문 크기**를 본다. 본문이 **1KB 미만이면 파킹 도메인을 의심하라** — 전형적 파킹 페이지는 `/lander` 로 보내는 JS 한 줄뿐이다.
|
||||
- 후보들의 본문이 **바이트 단위로 동일**하면 전부 같은 파킹 서비스다.
|
||||
- 후보들의 본문이 **바이트 단위로 동일**하면 공통 응답일 수 있다. 파킹이라고 단정하지 말고 제목·본문 정체성·소유자·정본 링크를 확인한다.
|
||||
- 정본 판정 근거는 **콘텐츠 안에서** 찾아라: 저장소 링크, 설치 명령에 적힌 패키지·스킬 이름, 소유자 계정, 문서 제목이 로컬 파일과 일치하는지.
|
||||
- [ ] **4. 원본 사이트 3개를 §4 템플릿으로 WebFetch 한다.** 갤러리 페이지가 아니라 원본이다. → 축 6·정보 위계·카피 톤을 얻는다.
|
||||
- [ ] **4. 사용한 원본 사이트를 §4 템플릿으로 WebFetch 한다.** 갤러리 페이지가 아니라 원본이다. → 축 6·정보 위계·카피 톤을 얻는다.
|
||||
- [ ] **5. §5로 computed style을 추출한다.** → 축 1·2·3·4를 얻는다. **이 단계를 건너뛰면 6축의 4개가 빈칸으로 남는다.**
|
||||
- [ ] **6. 텍스트 소스로 폰트 이름·무료 대체를 확정한다.** (Typewolf / Happy Hues / Eyecandy — galleries.md §3)
|
||||
- [ ] **7. 6축 해체 시트를 작성한다.** 숫자로. 6축에 안 들어가는 관측은 `6축 밖의 관측`에 적는다.
|
||||
- [ ] **8. 합성한다.** 축마다 어느 소스에서 가져왔는지 명시.
|
||||
- [ ] **9. 의도적 변형을 각 레퍼런스마다 1개씩 넣고 이유를 적는다.**
|
||||
- [ ] **10. antipatterns.md를 훑고 걸린 항목이 없는지 확인한다.**
|
||||
- [ ] **7. 6축 해체 시트를 작성한다.** 실측값 또는 관찰 가능한 규칙과 적용 조건을 쓴다. 6축에 안 들어가는 관측은 `6축 밖의 관측`에 적는다.
|
||||
- [ ] **8. 결정한다.** 출처 ID → 원칙/조건 → 관찰 → 결정 → 검증 계획을 프로젝트 `design.md` 또는 evidence 기록에 남긴다.
|
||||
- [ ] **9. 필요한 변형과 이유를 적는다.** 변형 개수는 슬롯 수와 무관하다.
|
||||
- [ ] **10. antipatterns.md를 훑고 발견한 후보를 프로젝트 계약과 실제 렌더로 평가한다.**
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -123,7 +120,7 @@ SaaS 구조 + 독립 출판사 톤 = 차별화.
|
|||
> 2. h1의 정확한 문장, 그리고 h2 전체 목록.
|
||||
> 3. CTA 문구 전부와 각각이 페이지 어디에 있는지.
|
||||
> 4. 내비게이션 항목 목록.
|
||||
> 5. 이 페이지가 방문자에게 시키려는 단 하나의 행동.
|
||||
> 5. 이 페이지가 방문자에게 시키려는 우선 행동과, 있으면 보조 행동. 각각이 어디서 어떤 위계로 제시되는지.
|
||||
> 6. 카피의 톤 — 평균 문장 길이, 1인칭/2인칭 사용, 전문용어 밀도.
|
||||
> 7. 숫자나 지표가 사용된 위치와 그 값.
|
||||
> 추측하지 말고 페이지에 실제로 있는 것만 답해라. 없으면 "없음"이라고 써라.
|
||||
|
|
@ -199,12 +196,12 @@ WebFetch는 마크다운으로 변환하면서 CSS를 버린다. **그리드·
|
|||
> **먼저 `url` 을 봐라. 열려고 한 사이트가 아니면 나머지 값은 전부 버려라.**
|
||||
> 페이지가 실행 중 이탈하거나 리다이렉트되면 스크립트는 **다른 사이트의 값을 조용히 반환한다.**
|
||||
> 실측에서 2회 연속 발생했다. 이건 실패가 아니라 **오염**이다 — 숫자가 6축 시트에 들어가고,
|
||||
> 3단계 토큰의 근거가 되고, `design.md` 에 남고, 어디서도 검출되지 않는다.
|
||||
> 3단계 토큰의 근거가 되고, `design.md` 또는 프로젝트 evidence 기록에 출처 ID → 원칙/조건 → 관찰 → 결정 → 검증으로 남는다. `evidence-ledger.md`는 기록 형식을 안내하는 정본이다.
|
||||
|
||||
- `fontSizes` 상위 항목 = 타입 스케일. 최다 크기가 본문이다. 최대÷본문이 **4배 미만이면 위계가 약한 레퍼런스**다.
|
||||
- `textColors` 상위 3~4개 = 텍스트 위계 단계. 3단계 이상이면 잘 설계된 것.
|
||||
- `backgrounds` 최다값 = 지배 배경. 등장 횟수가 적은 채도 높은 색이 **강조색**이고, 그 횟수가 곧 면적 감각이다.
|
||||
- `radii` 종류 수 = 형태 어휘. 1~3개면 통제된 것, 그 이상이면 우연히 결정된 것.
|
||||
- `fontSizes` 상위 항목 = 타입 스케일 후보다. 실제 본문 요소와 화면 위계를 같이 확인한다.
|
||||
- `textColors` 상위 항목 = 텍스트 위계 후보다. 색 수가 아니라 역할·대비·실제 렌더를 본다.
|
||||
- `backgrounds` 최다값 = 지배 배경 후보다. 채도·등장 횟수만으로 강조 역할이나 면적을 단정하지 않는다.
|
||||
- `radii` 종류 수 = 형태 어휘를 살필 출발점이다. 수가 아니라 토큰 역할과 화면 밀도로 평가한다.
|
||||
- `widths` 최다값 = 컨테이너 폭. `body.widthPx` = 텍스트 컬럼 폭.
|
||||
|
||||
브라우저 도구를 못 쓰는 환경이면 **6축 중 4개가 빈칸이라는 사실을 산출물에 명시**하고 넘어간다. 채운 척하지 마라.
|
||||
|
|
@ -236,22 +233,34 @@ WebFetch는 마크다운으로 변환하면서 CSS를 버린다. **그리드·
|
|||
- 행동 관습:
|
||||
- 금지할 외래 문법:
|
||||
|
||||
## R1 · 구조 — <이름> <원본 URL>
|
||||
## R1 · 구조 — <출처 ID> <이름> <원본 URL>
|
||||
- 가져올 축: 그리드, 여백 리듬
|
||||
- 그리드: 최대폭 1200 / 비대칭 7:5 / 거터 32
|
||||
- 여백: 8px 단위 / 섹션 간 120 / 요소 간 24 (1:5)
|
||||
- 원칙/조건:
|
||||
- 관찰:
|
||||
- 결정:
|
||||
- 검증 계획:
|
||||
- 그리드: 관찰한 최대폭 / 비대칭 또는 대칭 관계 / 거터
|
||||
- 여백: 관찰한 단위 / 섹션 간 / 요소 간 / 관계
|
||||
- 6축 밖의 관측: (있으면) 카피 규범, 증거 제시 방식, 반복 노출 규칙 등
|
||||
- 변형: 최대폭을 1120으로 축소 — 본문 한 줄이 국문 40자를 넘었기 때문
|
||||
|
||||
## R2 · 톤 — <이름> <원본 URL> [업종: R1과 다름 ✓]
|
||||
## R2 · 톤 — <출처 ID> <이름> <원본 URL> [업종/매체 선택 조건:]
|
||||
- 가져올 축: 컬러 역할, 타입 스케일
|
||||
- 컬러: 배경 1단계 / 텍스트 3단계 / 강조 1색 면적 6%
|
||||
- 타입: 세리프 디스플레이 + 그로테스크 본문, 비율 1.333, 최대/본문 4.2배
|
||||
- 원칙/조건:
|
||||
- 관찰:
|
||||
- 결정:
|
||||
- 검증 계획:
|
||||
- 컬러: 관찰한 역할 단계와 면적 관계
|
||||
- 타입: 관찰한 서체 역할·단계 관계·최대/본문 비율
|
||||
- 6축 밖의 관측: (있으면) 신뢰를 만드는 방식, 제품을 보여주는 방식
|
||||
- 변형: 비율을 1.25로 조정 — 정보량이 많아 중간 단계가 필요
|
||||
|
||||
## R3 · 디테일 — <이름> <출처 URL>
|
||||
## R3 · 디테일 — <출처 ID> <이름> <출처 URL>
|
||||
- 가져올 축: 모션 언어 (R3는 이 축만 채운다)
|
||||
- 원칙/조건:
|
||||
- 관찰:
|
||||
- 결정:
|
||||
- 검증 계획:
|
||||
- 모션: 스크롤 진입 시 8px 상승 + 페이드, 320ms, ease-out
|
||||
- 구현 제약: 브라우저 지원 / JS 비용 / 보간 조건
|
||||
- 변형: 280ms로 단축 — 페이지가 길어 반복 노출이 잦음
|
||||
|
|
@ -261,17 +270,17 @@ WebFetch는 마크다운으로 변환하면서 CSS를 버린다. **그리드·
|
|||
비즈니스 우선순위 [1 ___ / 2 ___ / 3 ___]와 일치한다.
|
||||
|
||||
## 안 할 것
|
||||
- (antipatterns.md에서 이 브리프에 특히 위험한 항목 3개 이상 명시)
|
||||
- (antipatterns.md에서 이 브리프에 특히 위험한 후보와 그 이유)
|
||||
```
|
||||
|
||||
**검증 조건** — 하나라도 빠지면 되돌아간다.
|
||||
- R1/R2/R3 각각 **원본 사이트 URL**이 있다 (갤러리 URL 아님)
|
||||
**검증 조건** — 사용한 슬롯마다 다음을 채운다.
|
||||
- 사용한 슬롯은 **원본 사이트 URL**이 있다 (갤러리 URL 아님)
|
||||
- 목표 시장 경계 조건이 있고 R1의 시장 일치 여부가 적혀 있다
|
||||
- R2의 업종이 R1과 다르다
|
||||
- 각 슬롯에 **가져올 축**이 명시되어 있다
|
||||
- 각 슬롯에 **변형 1개와 그 이유**가 있다
|
||||
- 6축 값에 숫자가 들어 있다 — **§5를 실행했거나, 못 했다면 어느 축이 빈칸인지 명시했다**
|
||||
- R3에 **구현 제약**(지원 범위·JS 비용)이 적혀 있다
|
||||
- R2의 업종 또는 매체 선택 조건이 적혀 있다
|
||||
- 각 슬롯에 **가져올 축**, 출처 ID → 원칙/조건 → 관찰 → 결정 → 검증 계획이 명시되어 있다
|
||||
- 필요한 변형과 그 이유가 적혀 있다
|
||||
- 6축은 실측값 또는 관찰 가능한 규칙으로 채웠고, §5를 못 실행했다면 어느 축이 빈칸인지 명시했다
|
||||
- R3를 썼다면 **구현 제약**(지원 범위·JS 비용)이 적혀 있다
|
||||
- 회색조 위계가 비즈니스 우선순위와 일치한다
|
||||
|
||||
> 근거: research/references/02-methodology.md (조사일 2026-08-20)
|
||||
|
|
|
|||
56
packages/skill/references/style-playbook.md
Normal file
56
packages/skill/references/style-playbook.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# style playbook — 과업에 맞는 시각 언어
|
||||
|
||||
스타일은 성격 테스트가 아니라 과업·콘텐츠·운영 조건의 출발점이다. 아래 항목을 고른 뒤에도 [design foundations](design-foundations.md)의 접근성·성능·과업 검증을 통과해야 한다. 수치나 금지 목록을 복사하지 말고, 실제 렌더에서 결정의 이유를 확인한다.
|
||||
|
||||
| 계열 | 목표·정보 구조 | 타입·색·이미지 | 모션 | 적합 조건 | 실패 | 검증 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Swiss / editorial | 복잡한 정보 또는 긴 읽기를 정돈한다. Swiss는 명확한 grid·비교, editorial은 본문·캡션·wide media의 읽기 리듬을 쓴다 | Swiss는 산세·제한된 역할색·도표/제품 증거. Editorial은 읽기 가능한 세리프 또는 산세·선택적 종이감·고품질 사진 | 상태 피드백 우선, 읽기 흐름을 빼앗지 않음 | 문서·B2B·문화·포트폴리오처럼 구조 또는 콘텐츠가 설득할 때 | 빈 여백으로 정보·근거를 숨김; editorial에서 라틴 전용 폰트가 한글을 망침 | 320px·200% 확대에서 measure·caption·표가 읽히고, 회색조에서 위계가 보이는지 |
|
||||
| Expressive | 기억할 장면 하나를 만들되 내용의 읽기 순서를 유지한다. 비대칭·겹침·강한 타입은 한 개의 중심 개념에 복무한다 | 개성 강한 display와 안정 본문을 구분; 높은 대비 색·질감은 근거 있는 한정 영역에 | reduced motion에서 같은 의미를 정지 상태로 전달 | 캠페인·문화·에이전시처럼 독자적 인상이 과업일 때 | 장치를 여러 개 겹쳐 메시지·포커스·대비를 잃음 | 효과 off, keyboard, 390px에서 메시지·행동이 먼저 남는지 |
|
||||
| Luxury | 희소성·재료·제작 맥락을 느리게 보여 준다. 선택지는 적고 증거는 깊다 | 절제된 팔레트, 정교한 type, 원본 수준 사진·재질; 장식보다 크롭과 상세에 투자 | 느린 전환도 사용자가 기다리는 흐름에서만 | 고관여 제품·공간·문화재처럼 신뢰와 감상이 함께 필요할 때 | 베이지·세리프·그레인을 고급의 자동 신호처럼 반복; 가짜 희소성/후기 | 이미지 출처·해상도·alt, 가격/조건의 명확성, 모션 off에서의 설득 |
|
||||
| Playful | 탐색과 학습의 긴장을 낮춘다. 핵심 행동은 여전히 예측 가능해야 한다 | 밝은 색은 의미 역할을 분리하고, 일러스트/캐릭터는 과업 단서를 보강 | 작은 보상·피드백은 가능하나 중지 가능성과 오류 회복을 제공 | 교육·커뮤니티·가벼운 소비 경험에서 놀이가 목표를 돕는 경우 | 재미가 상태·가격·위험 신호를 가림 | 처음 방문자가 다음 행동·오류 복구를 설명할 수 있는지, reduced motion |
|
||||
| Immersive | 공간·시간·감각적 몰입을 우선하되 대체 경로를 제공한다. 하나의 장면에서 깊이를 만든다 | 큰 원본 미디어, 제한된 overlay text, 읽을 수 있는 대비와 대체 콘텐츠 | WebGL/스크롤 연출은 progressive enhancement; pause·fallback 필수 | 전시·게임·영화·브랜드 스토리처럼 경험 자체가 가치일 때 | 로딩·멀미·배터리 비용을 감추고, 마우스/고성능 기기만 지원 | 저사양/느린 망/키보드/reduced motion에서 동일 핵심 정보와 행동 가능 여부 |
|
||||
| Dense | 빈번한 비교·감시·편집을 빠르게 한다. 요약→필터→상세의 정보 계층을 명시한다 | 가독성 높은 본문·tabular 수치·기능색·표/차트의 명확한 라벨 | 값 변화는 위치 이동보다 상태 표식; 빠른 피드백 | 운영 도구·분석·거래처럼 반복 과업과 숙련 사용자가 있을 때 | 미니멀이라는 이유로 필터·단위·오류 맥락을 숨김; 색만으로 상태 전달 | 대표 과업 시간, 200% 확대, keyboard, 좁은 폭의 우선순위/대체 경로 |
|
||||
|
||||
## 계열별 빠른 선택 예와 오용
|
||||
|
||||
### Swiss / editorial
|
||||
|
||||
- **구도**: Swiss는 같은 시작선의 명세·비교 레일을, editorial은 본문 폭·wide 이미지·여백 주석의 리듬을 선택한다.
|
||||
- **밀도·타입**: Swiss는 짧은 산세 본문과 촘촘한 비교를, editorial은 세리프 또는 산세 중 언어별 읽기 테스트를 통과한 본문과 캡션 계층을 쓴다.
|
||||
- **오용**: Swiss의 빈 공간으로 필수 사양을 숨기거나, editorial의 종이색·그레인을 콘텐츠 근거 없이 고급 신호로 반복하지 않는다.
|
||||
|
||||
### Expressive
|
||||
|
||||
- **구도**: 한 장면만 비대칭·중첩·대형 타입으로 만들고, 이후 정보는 안정된 grid로 회수한다.
|
||||
- **밀도·타입**: display의 개성과 본문의 읽기 역할을 분리하며, 강조색·질감·변형은 하나의 중심 아이디어에만 쓴다.
|
||||
- **오용**: 회전·세로쓰기·대문자·왜곡을 함께 쌓아 포커스 순서와 메시지를 잃지 않는다.
|
||||
|
||||
### Luxury
|
||||
|
||||
- **구도**: 여백 속 하나의 제품/재료 detail과 근거·조건이 이어지는 느린 순서를 쓴다.
|
||||
- **밀도·타입**: 큰 원본 사진은 크롭 품질을 우선하고, 가격·제작 방식·규격은 작은 글자로 숨기지 않는다.
|
||||
- **오용**: 베이지, 세리프, grain을 자동 고급 장치로 쓰거나 검증되지 않은 희소성·후기를 만들지 않는다.
|
||||
|
||||
### Playful
|
||||
|
||||
- **구도**: 다음 행동과 진행 상태를 고정하고, 그 주변에서 색·캐릭터·보상 피드백을 쓴다.
|
||||
- **밀도·타입**: 행동에는 명확한 라벨과 충분한 hitbox를 두며, 일러스트는 과업 단서를 설명할 때만 쓴다.
|
||||
- **오용**: 게임 같은 보상이 오류·가격·동의·파괴적 행동의 위험 신호를 가리지 않게 한다.
|
||||
|
||||
### Immersive
|
||||
|
||||
- **구도**: 한 장면의 미디어와 짧은 overlay를 중심으로 두고, 동일 내용을 읽을 수 있는 문서 흐름을 제공한다.
|
||||
- **밀도·타입**: 크고 원본 품질의 미디어를 쓸 때 contrast·caption·대체 텍스트를 표면의 일부로 설계한다.
|
||||
- **오용**: WebGL·스크롤 연출을 핵심 정보의 유일한 전달 경로나 고성능 기기 전용 상호작용으로 만들지 않는다.
|
||||
|
||||
### Dense
|
||||
|
||||
- **구도**: 요약→필터→상세와 비교 가능한 표·차트를 같은 정보 모델로 연결한다.
|
||||
- **밀도·타입**: tabular figure, 단위·기간 라벨, 기능색, 안정된 행 높이로 반복 과업의 속도를 돕는다.
|
||||
- **오용**: ‘깔끔함’을 이유로 필터·오류·데이터 출처·단위를 감추거나 색만으로 상태를 전달하지 않는다.
|
||||
|
||||
## 사례와 트렌드의 사용법
|
||||
|
||||
수상 사례는 완성된 화면을 베끼는 재료가 아니라 제약·구도·사용자 경로를 분해할 표본이다. Awwwards의 40/30/20/10은 그 심사 시스템의 배점일 뿐 효과 크기가 아니다 [AWWWARDS]. Webby와 CSSDA 사례도 심사/제작사 기록으로만 사용한다 [WEBBY, CSSDA-UNSEEN, AREA17, DROPBOX]. iF trend report는 가설 목록이며 웹 제품의 성과 증거가 아니다 [IFD-TREND].
|
||||
|
||||
사례를 채택하기 전에는 다음 다섯 가지를 한 줄씩 기록한다: `원래 대상과 과업`, `가져올 구조 또는 재질`, `현재 브리프에 맞는 이유`, `접근성·성능 비용`, `동일 조건 렌더 검증`. 이 기록이 없으면 사례는 장식 참조로만 남긴다.
|
||||
|
|
@ -383,7 +383,7 @@ SVG 필터는 장식이 아니라 재질을 만드는 도구다. "예뻐 보이
|
|||
|
||||
### 필터를 애니메이션하지 마라
|
||||
|
||||
필터 값이 바뀌면 매 프레임 전체가 재계산된다. **SKILL.md 하드 게이트 8(`transform`/`opacity` 외 애니메이션 금지)에도 걸린다.** 필터는 정적으로 쓴다.
|
||||
필터 값이 바뀌면 매 프레임 전체가 재계산될 수 있다. `transform`·`opacity`가 저비용 기본 선택이므로 필터는 정적 사용을 먼저 검토한다. 필터 애니메이션을 채택하면 프레임 시간·입력 간섭·감소 모션·프로젝트 예산을 실제 렌더에서 측정하고 기록한다.
|
||||
|
||||
| 하고 싶은 것 | 대신 할 것 |
|
||||
|---|---|
|
||||
|
|
@ -438,7 +438,7 @@ if (reduceEffects()) document.documentElement.classList.add('reduce-effects');
|
|||
- [ ] 필터 영역이 최소 크기이고, 잘리는 곳이 없다. `numOctaves` ≤ 4
|
||||
- [ ] 그레인 opacity ≤ 0.15 (anti-grid 제외)
|
||||
- [ ] `feImage`를 썼다면 data URI다
|
||||
- [ ] **애니메이션되는 필터가 없다**(하드 게이트 8). `will-change: filter`도 없다
|
||||
- [ ] 애니메이션되는 필터가 있다면 프레임 시간·입력 간섭·감소 모션·프로젝트 예산을 실제 렌더에서 측정했다. `will-change: filter`의 불필요한 사용은 없다
|
||||
- [ ] `backdrop-filter`가 뷰포트 전체를 덮지 않는다
|
||||
- [ ] 필터를 전부 끈 상태에서 페이지가 완성돼 있다
|
||||
- [ ] 필터 건 요소 안에 본문 텍스트나 `position: fixed` 자손이 없다
|
||||
|
|
@ -485,7 +485,7 @@ if (reduceEffects()) document.documentElement.classList.add('reduce-effects');
|
|||
|
||||
`conic-gradient(from var(--angle), …)` 를 `@property` 로 애니메이션하는 방법이 흔히 보이는데,
|
||||
**그건 매 프레임 배경을 다시 칠한다.** 컴포지터에서 못 돌고 메인 스레드가 페인트한다.
|
||||
`transform`·`opacity` 만 애니메이션하라는 규칙에 걸린다.
|
||||
저비용 기본 선택에서 벗어나는 사례다. 목적과 성능 측정, 감소 모션 경로를 프로젝트 계약에 기록한다.
|
||||
|
||||
**정사각형 원뿔 레이어를 마스크 안에서 회전시켜라.** 움직이는 것은 `rotate` 뿐이다.
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
| Perfect Fourth | 1.333 | 또렷한 위계 | 랜딩 페이지, 제품 소개 |
|
||||
| Golden | 1.618 | 극적 | 포트폴리오, 에디토리얼. 중간 단계가 비어 본문이 외로워진다 |
|
||||
|
||||
**한 페이지에 비율은 하나다.** 헤드라인만 다른 비율을 쓰고 싶으면 그건 비율이 아니라 **디스플레이 사이즈를 따로 정의**하는 것이다.
|
||||
본문 scale은 하나의 비율에서 시작하면 관리하기 쉽다. display가 다른 비율이나 별도 크기를 요구할 수 있으므로, 토큰 이름·역할·대표 폭에서의 위계 검증을 함께 기록한다.
|
||||
|
||||
### 실제 값으로 적는다
|
||||
|
||||
|
|
@ -34,12 +34,12 @@
|
|||
}
|
||||
```
|
||||
|
||||
### 반응형은 clamp 로, 미디어쿼리로 하지 마라
|
||||
### 유동 크기와 구조 전환을 구분한다
|
||||
|
||||
```css
|
||||
--step-4: clamp(2.25rem, 1.5rem + 3.75vw, 3.157rem);
|
||||
```
|
||||
`clamp(최소, 기준+vw, 최대)`. 최소값은 **모바일에서 읽히는 크기**, 최대값은 데스크톱 기준. 중간이 매끄럽게 이어져 중간 뷰포트에서 깨지지 않는다.
|
||||
`clamp(최소, 기준+vw, 최대)`는 연속적으로 변해야 하는 값에 유용하다. 최소·최대는 대표 콘텐츠로 확인한다. grid 열, 내비, 작업대처럼 구조가 바뀌는 지점에는 미디어쿼리나 container query를 쓰고, 임의 기기 폭이 아니라 실제 실패 지점에서 정한다.
|
||||
|
||||
### 함께 정해야 하는 것
|
||||
|
||||
|
|
@ -48,9 +48,9 @@
|
|||
| `--leading-tight` | 1.1~1.2 — 디스플레이/헤드라인 |
|
||||
| `--leading-normal` | 1.5~1.6 — 본문 (라틴) / **1.6~1.8 (한글)** |
|
||||
| `--measure` | 한 줄 길이. 라틴 60~75자, **한글 25~40자** |
|
||||
| 자간 | 큰 글자에만 음수(`-0.02em` 정도). **한글에는 음수 자간 금지** |
|
||||
| 자간 | 큰 라틴 디스플레이에서만 작은 음수 자간을 후보로 두고 실제 렌더로 확인. 한글은 글꼴·크기·문맥별로 시험하며, 음수값을 기본 처방이나 절대 금지로 두지 않는다 |
|
||||
|
||||
**폰트는 최대 2종**(+ 코드용 모노 1). 세 번째 텍스트 폰트를 넣고 싶다면 위계를 웨이트로 못 만들고 있다는 신호다.
|
||||
폰트 수는 전송량·언어 범위·위계·라이선스를 함께 보고 예산으로 정한다. 두 텍스트 패밀리와 필요 시 모노는 흔한 시작점이지만, 세 번째 패밀리가 무조건 실패라는 뜻은 아니다.
|
||||
|
||||
> **어떤 폰트를 어떻게 고르고 싣는지는 `typography.md` 가 정본이다.** 여기서는 스케일 값만 정한다.
|
||||
> 로딩 전략, 폴백 메트릭 보정, OpenType 기능, 한글 서브셋, 라이선스 확인이 그 문서에 있다.
|
||||
|
|
@ -70,16 +70,16 @@
|
|||
--ink: /* 본문 텍스트 */
|
||||
--ink-muted: /* 보조 텍스트 — 대비 4.5:1 유지 */
|
||||
--line: /* 경계선 */
|
||||
--accent: /* 강조 — 페이지당 하나 */
|
||||
--accent: /* 강조 역할이 필요할 때의 기본 토큰 */
|
||||
--accent-ink: /* 강조 위에 올라가는 글자색 */
|
||||
}
|
||||
```
|
||||
|
||||
### 규칙
|
||||
|
||||
1. **강조색은 하나다.** 두 개가 필요하다고 느끼면 위계 설계가 실패한 것이다. 예외: 상태색(성공/경고/오류)은 강조색이 아니라 기능색이다
|
||||
1. 강조 역할은 한 색에서 시작해 경쟁 여부를 검증한다. 여러 강조 역할이 필요할 수 있으며, 그때는 행동·상태·정보 목적을 역할 토큰으로 구분한다. 수만으로 위계 실패를 판정하지 않는다
|
||||
2. **채도가 높은 색은 면적을 좁게.** 넓은 면적에 쓰면 눈이 피로하고 싸구려로 보인다
|
||||
3. **중성색도 색이다.** 순수 회색(`#808080`) 대신 강조색 쪽으로 약간 기운 중성색을 쓰면 화면 전체가 하나로 묶인다
|
||||
3. **중성색도 색이다.** 순수 회색과 색조를 띤 중성색을 모두 후보로 두고, 표면·브랜드·상태색과의 관계를 비교한다
|
||||
4. **대비를 측정해라.** 본문 4.5:1, 큰 글자 3:1. 눈으로 판단하지 마라
|
||||
|
||||
### 다크 모드
|
||||
|
|
@ -88,9 +88,9 @@
|
|||
|
||||
다크를 기본으로 하려면 **근거를 한 줄로 대라.** 정당화되는 이유의 목록은 `presets/dark-instrument.md` 에 있다(야간 운영 환경, 밝은 데이터 시각화의 대비, 제품 자체가 어두움). 댈 수 없으면 라이트로 간다.
|
||||
|
||||
어느 쪽을 기본으로 하든 **두 테마를 동등하게 정의한다.** 다크만 만들고 라이트를 빼는 것은 사용자 선택권을 뺏는 것이다.
|
||||
라이트/다크 모두를 지원하기로 한 제품은 역할 토큰을 각각 정의하고 실제 상태를 검증한다. 제품이 한 테마만 제공할 수는 있지만, 사용자 환경·브리프·운영 맥락과 접근성 영향을 명시한다.
|
||||
|
||||
지원할 때는 색을 뒤집는 게 아니라 **역할별로 다시 정의**한다. 다크에서 순수 검정(`#000`)은 대비가 너무 세서 눈이 아프고, 순수 흰색 텍스트도 마찬가지다.
|
||||
지원할 때는 색을 뒤집는 게 아니라 **역할별로 다시 정의**한다. 순수 검정·흰색과 근접한 색은 제품·디스플레이·주변광에 따라 읽기 경험이 다르므로, 대비·눈부심·브랜드 표면을 실제 기기에서 확인한다.
|
||||
|
||||
```css
|
||||
:root { --surface: #fbfaf8; --ink: #1a1917; }
|
||||
|
|
@ -123,10 +123,10 @@
|
|||
### 여백이 위계를 만든다
|
||||
|
||||
- 관련 있는 것끼리는 **가깝게**, 다른 그룹과는 **확실히 멀게**. 애매한 중간 간격이 가장 나쁘다
|
||||
- 섹션 간격은 **본문 간격의 4배 이상**. 좁으면 페이지가 뭉개진다
|
||||
- 섹션·그룹·요소 간 간격 차이가 관계를 읽히게 하는지 실제 화면에서 본다. 4배 같은 고정 비율은 시작 가설일 뿐, 콘텐츠와 폭에 따라 조절한다.
|
||||
- 요소를 정렬할 때 **간격이 아니라 정렬선**을 먼저 맞춰라
|
||||
|
||||
### h1 이 h2 보다 한 단계만 크면 위계가 아니다
|
||||
### 제목 역할이 실제로 구분되는지 확인한다
|
||||
|
||||
히어로 제목을 줄이다가 실측에서 이렇게 됐다.
|
||||
|
||||
|
|
@ -142,10 +142,9 @@
|
|||
배경 그래픽과 싸워서 줄였는데, 줄이다가 h2 와 붙는 데까지 왔다.
|
||||
**한 극단에서 도망치다 반대쪽 극단에 도착한 것이다.**
|
||||
|
||||
기준: **넓은 화면에서 히어로 h1 은 섹션 h2 의 2 배 안팎.** 그 아래면 위계가 없고,
|
||||
그 위는 배경·여백과 싸우기 시작한다.
|
||||
넓은 화면에서 히어로와 섹션 제목이 같은 위계로 읽히지 않는지 비교한다. 2배 안팎은 한 프로젝트의 관찰값일 뿐 기준선이 아니다. 문구 길이, 구도, 여백, 브랜드 타입에 따라 같은 크기 차도 다르게 보인다.
|
||||
|
||||
### clamp 의 하한은 h2 를 기준으로 정한다
|
||||
### clamp 값을 역할 관계와 함께 확인한다
|
||||
|
||||
여기서 한 번 더 틀렸다. 데스크톱만 보고 고쳤더니 이렇게 됐다.
|
||||
|
||||
|
|
@ -162,7 +161,7 @@
|
|||
**h1 만 `vw` 에 비례해 줄고 h2 는 고정이라, 좁아질수록 둘이 만난다.**
|
||||
데스크톱에서 고친 위계가 모바일에서 그대로 사라진다.
|
||||
|
||||
하한을 h2 의 1.4 배 이상으로 잡으면 전 구간이 유지된다.
|
||||
모바일에서 h1과 h2가 거의 같은 크기로 수렴하지 않는지 확인한다. 아래 값은 해당 조합의 예시이며 모든 제목에 적용하는 비율 규칙이 아니다.
|
||||
|
||||
```css
|
||||
/* 하한 3rem = 48px = h2(33.2px)의 1.45 배 */
|
||||
|
|
@ -174,7 +173,7 @@
|
|||
| 비율 | 1.45 | 1.45 | 1.63 | 1.87 | 2.12 |
|
||||
|
||||
좁은 화면에서 2 배를 고집할 필요는 없다 — 폭이 좁으면 큰 글자가 줄만 늘린다.
|
||||
**1.4 배가 하한, 2 배 안팎이 상한**이고 그 사이를 `vw` 가 잇는다.
|
||||
최소·중간·최대 폭에서 제목 역할이 구분되는지 확인하고, 필요한 경우 h1과 h2를 함께 유동화하거나 문구·레이아웃을 조정한다.
|
||||
|
||||
> 확인법: 한 화면 폭에서만 재지 마라. `clamp` 를 쓴 값은 **최소 폭·중간 폭·최대 폭
|
||||
> 세 곳에서 계산해 보고**, 같이 변하지 않는 값(고정 스케일의 h2 등)과의 비율을 봐라.
|
||||
|
|
@ -291,12 +290,12 @@ h3 + *,
|
|||
### 버튼처럼 생긴 것은 전부 같은 치수를 쓴다
|
||||
|
||||
```css
|
||||
--control-h: 2.75rem; /* 44px — 터치 타깃 */
|
||||
--control-h: 2.75rem; /* 프로젝트의 편안한 기본 높이 예시 */
|
||||
--control-h-sm: 2.25rem; /* 36px — 헤더 등 조밀한 자리 */
|
||||
--control-pad-x: var(--space-3);
|
||||
```
|
||||
|
||||
컴포넌트마다 높이와 패딩을 다시 정하면 그때부터 SSOT 가 아니다.
|
||||
같은 역할의 컴포넌트는 치수 토큰을 공유한다. 다른 밀도나 위험도는 별도 역할 토큰으로 설명한다. WCAG 2.2 AA의 포인터 target 최소 기준은 예외를 포함해 24×24 CSS px이며, 44px는 많은 터치 UI에서 쓰는 편안한 시작값이지 보편 적합성 수치는 아니다 (`evidence-ledger.md`의 `WCAG-TARGET`).
|
||||
실측 사례: 같은 페이지의 두 버튼이 높이 36 vs 44, 패딩 16 vs 8, 테두리 1px vs 0,
|
||||
웨이트 400 vs 500 이었다. 규칙이 없으니 전부 달랐다.
|
||||
반대로 R1 의 두 버튼은 `h36 · pad-x10 · r4 · w400 · 14px` 로 **픽셀 단위까지 같았다.**
|
||||
|
|
@ -314,7 +313,7 @@ h3 + *,
|
|||
|
||||
### 큰 간격은 화면에 반응해야 한다
|
||||
|
||||
작은 값(4~24px)은 고정, 큰 값만 `clamp()`.
|
||||
작은 값은 고정값부터, 큰 공간은 `clamp()`부터 검토할 수 있다. 어느 쪽이든 콘텐츠·확대·컨테이너 조건에서 관계가 유지되는지 확인한다.
|
||||
|
||||
```css
|
||||
--space-6: clamp(2.5rem, 1.6rem + 2.6vw, 4rem);
|
||||
|
|
@ -339,16 +338,16 @@ h3 + *,
|
|||
| WebGL/3D 추가분 | +200KB | +600KB | 측정 |
|
||||
| 총 전송량 (첫 화면) | 1MB | 2MB | 측정 |
|
||||
| 첫 인터랙션 (모바일 4G) | 3초 | 5초 | 측정 |
|
||||
| LCP | 2.5초 | 3.5초 | 측정 |
|
||||
| CLS | 0.1 | 0.1 | 측정 |
|
||||
| 폰트 **패밀리** | 2개 이하 | 3개 | 개수 확인 |
|
||||
| LCP | field p75 2.5초 이하를 목표로 검토 | 브리프에 명시 | RUM/CrUX 또는 local proxy 표기 |
|
||||
| CLS | field p75 0.1 이하를 목표로 검토 | 브리프에 명시 | RUM/CrUX 또는 local proxy 표기 |
|
||||
| 폰트 **패밀리** | 프로젝트별 전송량·언어 범위 예산 | 브리프에 명시 | 실제 요청·전송량 확인 |
|
||||
| 폰트 전송량(첫 화면) | 100KB | 200KB | 측정 |
|
||||
| 애니메이션 속성 | transform/opacity 만 | 동일 (타협 없음) | grep |
|
||||
| 애니메이션 속성 | compositing 친화 속성을 우선 검토 | 브리프에 명시 | 성능·reduced-motion·상태 피드백 확인 |
|
||||
|
||||
예산을 올렸다면 **올렸다는 사실과 이유를 명시**해라. 조용히 넘기는 것이 가장 나쁘다.
|
||||
|
||||
> **폰트는 파일 개수가 아니라 패밀리 수와 전송량으로 센다.** 한글 웹폰트를 유니코드 범위별로
|
||||
> 수십 개 파일로 쪼개는 것은 **올바른 최적화**다(Pretendard `dynamic-subset` 은 14개 이상).
|
||||
> 수십 개 파일로 쪼개는 방식은 실제 사용 문자 범위·캐시·전송 waterfall에 따라 유효할 수 있다. 파일 개수 자체로 최적화를 판정하지 않는다.
|
||||
> 브라우저는 페이지에 실제로 쓰인 글자 범위만 받는다. 파일 개수를 줄이라고 요구하면
|
||||
> 한글 프로젝트를 단일 대용량 파일이라는 잘못된 방향으로 몬다.
|
||||
|
||||
|
|
@ -372,8 +371,7 @@ new PerformanceObserver((l) => {
|
|||
</script>
|
||||
```
|
||||
|
||||
**프로덕션 빌드에 돌려라.** 개발 서버는 번들이 다르고 HMR 스크립트가 섞여 값이 의미 없다.
|
||||
Lighthouse 를 쓸 수 있으면 그쪽이 더 정확하다 — 단 모바일 프로파일로.
|
||||
프로덕션 빌드에서 재는 편이 개발 서버보다 배포 조건에 가깝다. 다만 PerformanceObserver·Lighthouse 한 번은 **lab proxy**다. CWV의 적합성 주장은 실제 사용자의 field data에서 모바일·데스크톱별 75th percentile로 판단한다. local 값은 회귀 탐지에 쓰고 field 수치와 혼동하지 않는다 (`evidence-ledger.md`의 `CWV`, `CWV-METHOD`).
|
||||
|
||||
### 예산을 지키는 기본 수단
|
||||
|
||||
|
|
|
|||
|
|
@ -22,9 +22,7 @@
|
|||
|
||||
### 1-1. 먼저 개수를 정한다
|
||||
|
||||
**두 벌이면 충분하다.** 디스플레이 하나, 본문 하나. 코드나 수치가 있으면 모노 하나를 더한다.
|
||||
|
||||
세 번째 텍스트 폰트를 넣고 싶다면 **위계를 웨이트로 못 만들고 있다는 신호다.** 가변 폰트 한 벌의 300~700 구간이 서로 다른 폰트 두 벌보다 넓은 표현을 준다.
|
||||
디스플레이 하나와 본문 하나, 필요할 때 모노 하나는 관리하기 쉬운 시작점이다. 추가 패밀리는 언어 범위·역할·전송량·라이선스와 실제 위계 효과를 근거로 제한한다. 가변 폰트가 정적 파일보다 항상 작거나 모든 필요한 축을 제공하는 것은 아니므로 실제 subset과 로딩 결과를 비교한다.
|
||||
|
||||
### 1-2. 성격을 브리프에서 끌어낸다
|
||||
|
||||
|
|
@ -35,13 +33,13 @@
|
|||
| 정확함, 계기, 데이터 | 좁은 폭, 낮은 대비, 열린 카운터, 모노와 잘 붙는 것 |
|
||||
| 편집, 읽는 시간, 권위 | 세리프 또는 고대비 산세, 넉넉한 x-height |
|
||||
| 도구, 중립, 신뢰 | 그로테스크. 성격은 웨이트와 여백이 만든다 |
|
||||
| 인상, 기억 | 디스플레이 전용 서체. **본문에는 절대 쓰지 않는다** |
|
||||
| 인상, 기억 | 디스플레이 전용 서체를 우선 검토한다. 본문 사용은 긴 읽기·언어 범위·확대 상태에서 검증한 경우에만 채택한다 |
|
||||
|
||||
### 1-3. 후보를 실제 값으로 검증한다
|
||||
|
||||
이름과 인상으로 고르지 마라. 다음 넷을 본다.
|
||||
|
||||
- **x-height 비율** — 소문자 높이 ÷ 대문자 높이. 0.52 미만이면 작은 크기에서 흐려진다
|
||||
- **x-height 비율** — 소문자 높이와 본문 크기의 관계. 단일 임계값으로 가독성을 판정하지 말고 실제 크기·언어·렌더링에서 확인한다
|
||||
- **대비** — 획 굵기 차이. 큰 크기에서만 살아나는 폰트가 있다
|
||||
- **웨이트 범위** — 필요한 웨이트가 실제로 있는가. 없는 웨이트를 브라우저가 합성하면 뭉개진다
|
||||
- **숫자 형태** — 라이닝인가 올드스타일인가, tabular 가 있는가
|
||||
|
|
@ -66,7 +64,7 @@ document.fonts.check('16px "Pretendard Variable"');
|
|||
|
||||
## 2. 가변 폰트
|
||||
|
||||
웨이트를 **두 개 이상** 쓰면 거의 항상 가변이 유리하다. 정적 폰트 두 벌보다 가변 한 벌이 작고, 중간 웨이트를 공짜로 얻는다.
|
||||
여러 웨이트가 필요하면 가변 폰트를 후보로 둔다. 필요한 glyph·축·subset·캐시 조건에 따라 정적 파일 묶음이 더 작거나 호환성이 나을 수 있으므로 전송량과 실제 렌더를 비교한다.
|
||||
|
||||
### 축
|
||||
|
||||
|
|
@ -144,13 +142,13 @@ h1 { font-optical-sizing: auto; }
|
|||
| 셀프 호스팅 | 요청 도메인 하나, 캐시 통제, 서드파티 장애 무관 | 업데이트를 직접 한다 |
|
||||
| CDN | 설치가 한 줄 | 도메인이 늘고(각각 DNS+TLS), 그 서비스가 죽으면 글자가 죽는다 |
|
||||
|
||||
CDN 을 쓴다면 `preconnect` 를 반드시 건다. 셋 이상의 폰트 도메인은 그 자체가 결함이다.
|
||||
CDN을 쓸 때 `preconnect`는 실제 첫 화면 요청·연결 비용을 측정한 뒤 선택한다. 도메인 수만으로 결함을 판정하지 말고, 권한·캐시·장애 경로·전송 waterfall을 함께 검토한다.
|
||||
|
||||
---
|
||||
|
||||
## 4. 폴백 메트릭 — 가장 자주 빠뜨리는 곳
|
||||
|
||||
폰트가 늦게 오면 브라우저는 폴백으로 먼저 그리고 나중에 교체한다. 두 폰트의 **행 높이와 글자 폭이 다르면 그 순간 레이아웃이 튄다.** 이것이 CLS 의 흔한 원인이고, `font-display: swap` 을 쓰는 한 반드시 일어난다.
|
||||
폰트가 늦게 오면 표시 전략에 따라 폴백과 웹폰트가 교체될 수 있다. 두 폰트의 행 높이·폭이 다르면 레이아웃 이동의 원인이 될 수 있지만, `swap`이 반드시 CLS를 만든다고 단정하지 않는다. 실제 네트워크 조건에서 측정한다.
|
||||
|
||||
해결은 **폴백 폰트를 실제 폰트의 치수에 맞추는 것**이다.
|
||||
|
||||
|
|
@ -196,7 +194,7 @@ const measure = (family) => {
|
|||
|
||||
`ascent-override` / `descent-override` 는 실제 폰트의 `hhea` 또는 `OS/2` 값을 `unitsPerEm` 으로 나눈 백분율이다. 도구가 없으면 **행 높이가 눈에 띄게 튀지 않을 때까지 조정**하고 그 값을 `design.md` 에 적어라.
|
||||
|
||||
> `font-display: optional` 을 쓰면 이 문제가 사라진다. 대신 첫 방문자가 브랜드 서체를 못 볼 수 있다. **둘 중 하나는 골라야 한다.** 아무것도 안 하는 것이 최악이다.
|
||||
> `font-display: optional`은 교체 가능성을 줄이는 한 선택지다. 폴백 메트릭 보정, 표시 전략, preload 여부는 실제 첫 방문·재방문·느린 망에서 조합해 검증한다.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -240,7 +238,7 @@ body { font-kerning: normal; }
|
|||
|
||||
### 6-1. 서브셋은 선택이 아니다
|
||||
|
||||
한글 완성형은 11,172자다. 전체 폰트는 수 MB 다. 반드시 쪼갠다.
|
||||
한글 완성형은 11,172자다. 전체 폰트가 클 수 있으므로 subset 전략을 검토한다. 모든 프로젝트가 글자 빈도 기반의 동적 subset을 반드시 써야 하는 것은 아니며, 콘텐츠 범위·cache·운영 복잡도와 실제 전송량으로 결정한다.
|
||||
|
||||
**쪼개는 단위가 라틴과 다르다.** 라틴은 `unicode-range` 로 블록을 나누면 되지만, 한글은 자주 쓰는 글자가 블록에 흩어져 있다. 그래서 **글자 빈도로 나눈 수십 개 조각**을 만들고 각각에 `unicode-range` 를 건다. 브라우저가 페이지에 실제로 쓰인 조각만 받는다.
|
||||
|
||||
|
|
@ -313,13 +311,13 @@ font-family: "Switzer", "Pretendard Variable", system-ui, sans-serif;
|
|||
|
||||
## 8. 배포 전 체크리스트
|
||||
|
||||
- [ ] 폰트 패밀리 수가 예산 안이다(`tokens.md` §5). 텍스트 두 벌 + 모노 하나가 상한
|
||||
- [ ] 폰트 패밀리 수와 실제 첫 화면 전송량이 프로젝트 예산 안이다(`tokens.md` §5)
|
||||
- [ ] **"왜 이 폰트인가"에 한 문장으로 답할 수 있다**
|
||||
- [ ] 웨이트를 두 개 이상 쓰는데 정적 폰트를 여러 벌 받고 있지 않다
|
||||
- [ ] 필요한 웨이트의 가변/정적 후보를 실제 subset 전송량·지원 범위로 비교했다
|
||||
- [ ] 없는 웨이트를 브라우저가 합성하고 있지 않다(`font-synthesis-weight: none` 으로 확인)
|
||||
- [ ] `font-display` 를 의식적으로 골랐다
|
||||
- [ ] preload 한 파일이 첫 화면에 실제로 쓰인다. `crossorigin` 이 있다
|
||||
- [ ] **폴백 메트릭을 보정했거나, `optional` 을 골랐다.** 둘 중 하나는 했다
|
||||
- [ ] 실제 첫 방문·재방문·느린 망에서 폴백 메트릭과 `font-display` 선택이 의도한 줄바꿈·레이아웃을 유지한다
|
||||
- [ ] 수치를 나열하는 곳에 `tabular-nums` 가 있다
|
||||
- [ ] 한글이 있으면 서브셋을 쓴다. 파일 개수가 아니라 전송량으로 쟀다
|
||||
- [ ] 라틴 폰트가 폴백 스택 앞에 있다
|
||||
|
|
|
|||
72
packages/skill/tools/design-gate-contract.test.mjs
Normal file
72
packages/skill/tools/design-gate-contract.test.mjs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import assert from "node:assert/strict";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import url from "node:url";
|
||||
|
||||
const repo = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)), "../../..");
|
||||
const gate = path.join(repo, "apps/site/tools/design-gate.mjs");
|
||||
const work = fs.mkdtempSync(path.join(os.tmpdir(), "design-gate-contract-"));
|
||||
|
||||
const configFor = (page, extra = {}) => ({
|
||||
pages: [{ name: "fixture", path: page, h1: "h1", ...extra }],
|
||||
widths: [375, 390],
|
||||
fontScales: [1, 1.3],
|
||||
checks: {
|
||||
meta: false,
|
||||
contrast: false,
|
||||
stack: false,
|
||||
rhythm: false,
|
||||
scaleMatrix: true,
|
||||
tapTargets: false,
|
||||
leftInset: false,
|
||||
deadCss: false,
|
||||
cssHygiene: false,
|
||||
},
|
||||
});
|
||||
|
||||
const run = (name, html, extra = {}) => {
|
||||
const page = path.join(work, `${name}.html`);
|
||||
const config = path.join(work, `${name}.json`);
|
||||
fs.writeFileSync(page, html.replace("<!doctype html>", "<!doctype html><style>html { overflow-x: clip; } body { margin: 0; }</style>"));
|
||||
fs.writeFileSync(config, JSON.stringify(configFor(page, extra)));
|
||||
return spawnSync(process.execPath, [gate, `--config=${config}`], { cwd: work, encoding: "utf8" });
|
||||
};
|
||||
|
||||
const outputOf = (result) => result.stdout + result.stderr;
|
||||
|
||||
try {
|
||||
const flexible = run("flexible", `<!doctype html><style>h1 { width: 9ch; font-size: 2rem; }</style><h1>A flexible display heading</h1>`);
|
||||
assert.equal(flexible.status, 0, outputOf(flexible));
|
||||
assert.match(outputOf(flexible), /h1 보임 — [2-9]줄\(줄수 계약 없음\)/);
|
||||
|
||||
const capped = run("capped", `<!doctype html><style>h1 { width: 100px; font-size: 2rem; }</style><h1>Heading that must wrap</h1>`, { h1MaxLines: 1 });
|
||||
assert.equal(capped.status, 1, outputOf(capped));
|
||||
assert.match(outputOf(capped), /h1 — \d+줄\(최대 1줄\)/);
|
||||
|
||||
const expanded = run("expanded", `<!doctype html><style>h1 { width: 260px; font-size: 1.5rem; }</style><h1>Scale tolerant design</h1>`, { h1MaxLines: 1 });
|
||||
assert.equal(expanded.status, 0, outputOf(expanded));
|
||||
assert.match(outputOf(expanded), /375@1x:1줄/);
|
||||
assert.match(outputOf(expanded), /375@1\.3x:[2-9]줄/);
|
||||
|
||||
const clipped = run("clipped", `<!doctype html><style>.clip { width: 150px; overflow: hidden; } h1 { white-space: nowrap; font-size: 1.5rem; }</style><div class="clip"><h1>Heading that is clipped when enlarged</h1></div>`);
|
||||
assert.equal(clipped.status, 1, outputOf(clipped));
|
||||
assert.match(outputOf(clipped), /제목 텍스트 클리핑/);
|
||||
|
||||
const verticallyClipped = run("vertically-clipped", `<!doctype html><style>.clip { width: 300px; height: 32px; overflow-y: hidden; } h1 { margin: 0; font-size: 1.5rem; }</style><div class="clip"><h1>Title that becomes vertically clipped</h1></div>`);
|
||||
assert.equal(verticallyClipped.status, 1, outputOf(verticallyClipped));
|
||||
assert.match(outputOf(verticallyClipped), /제목 텍스트 클리핑 .+\(y\)/);
|
||||
|
||||
const missing = run("missing", `<!doctype html><h1>Existing heading</h1>`, { h1: ".missing" });
|
||||
assert.equal(missing.status, 1, outputOf(missing));
|
||||
assert.match(outputOf(missing), /h1 선택자 없음 \(\.missing\)/);
|
||||
|
||||
const empty = run("empty", `<!doctype html><h1></h1>`);
|
||||
assert.equal(empty.status, 1, outputOf(empty));
|
||||
assert.match(outputOf(empty), /h1 — 텍스트 없음/);
|
||||
|
||||
console.log("design-gate-contract: 7 passed");
|
||||
} finally {
|
||||
fs.rmSync(work, { recursive: true, force: true });
|
||||
}
|
||||
|
|
@ -26,7 +26,6 @@ const DEFAULT_CFG = {
|
|||
viewAttribute: "data-view",
|
||||
views: ["main"],
|
||||
h1: "h1",
|
||||
h1MaxLines: 1,
|
||||
brand: ".brand",
|
||||
},
|
||||
],
|
||||
|
|
@ -233,6 +232,53 @@ const UTILS = `
|
|||
const text = [...el.childNodes].find((node) => node.nodeType === 3 && node.textContent.trim());
|
||||
return window.__lines(text || el);
|
||||
};
|
||||
window.__heading = (sel) => {
|
||||
let el;
|
||||
try { el = document.querySelector(sel); }
|
||||
catch { return { state: "invalid" }; }
|
||||
if (!el) return { state: "missing" };
|
||||
if (!el.textContent.trim()) return { state: "empty" };
|
||||
const box = el.getBoundingClientRect();
|
||||
const hiddenAncestor = (() => {
|
||||
for (let node = el; node && node !== document.documentElement; node = node.parentElement) {
|
||||
const style = getComputedStyle(node);
|
||||
if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse" || style.contentVisibility === "hidden" || parseFloat(style.opacity) <= 0) return true;
|
||||
}
|
||||
return false;
|
||||
})();
|
||||
if (hiddenAncestor || box.width <= 0 || box.height <= 0) {
|
||||
return { state: "hidden" };
|
||||
}
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(el);
|
||||
const rects = [...range.getClientRects()].filter((r) => r.width > 1 && r.height > 4);
|
||||
const tops = rects.map((r) => r.top).sort((a, b) => a - b);
|
||||
const lines = [];
|
||||
for (const top of tops) if (!lines.length || top - lines[lines.length - 1] > 5) lines.push(top);
|
||||
return { state: "visible", lines: lines.length, rects: rects.map((r) => ({ left: r.left, right: r.right, top: r.top, bottom: r.bottom })) };
|
||||
};
|
||||
window.__headingScaleAudit = (sel) => {
|
||||
const heading = window.__heading(sel);
|
||||
if (heading.state !== "visible") return heading;
|
||||
const el = document.querySelector(sel);
|
||||
const clipping = [];
|
||||
const viewportWidth = document.documentElement.clientWidth;
|
||||
for (const rect of heading.rects) {
|
||||
if (rect.left < -1 || rect.right > viewportWidth + 1) clipping.push("viewport");
|
||||
}
|
||||
for (let ancestor = el; ancestor && ancestor !== document.documentElement; ancestor = ancestor.parentElement) {
|
||||
const cs = getComputedStyle(ancestor);
|
||||
const box = ancestor.getBoundingClientRect();
|
||||
const name = ancestor.className ? "." + String(ancestor.className).trim().split(/\\s+/)[0] : ancestor.tagName.toLowerCase();
|
||||
if (/^(hidden|clip|auto|scroll)$/.test(cs.overflowX) && heading.rects.some((rect) => rect.left < box.left - 1 || rect.right > box.right + 1)) clipping.push(name + "(x)");
|
||||
if (/^(hidden|clip|auto|scroll)$/.test(cs.overflowY) && heading.rects.some((rect) => rect.top < box.top - 1 || rect.bottom > box.bottom + 1)) clipping.push(name + "(y)");
|
||||
}
|
||||
return {
|
||||
...heading,
|
||||
documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth,
|
||||
clipping: [...new Set(clipping)],
|
||||
};
|
||||
};
|
||||
`;
|
||||
|
||||
const browser = await puppeteer.default.launch({ executablePath: CHROME, headless: "new", args: ["--force-device-scale-factor=1"] });
|
||||
|
|
@ -326,14 +372,19 @@ for (const p of CFG.pages) {
|
|||
}
|
||||
overs.length ? fail(`${p.name}/${v} 오버플로`, overs.join(" ")) : pass(`${p.name}/${v} 오버플로`, CFG.widths.join("/"));
|
||||
|
||||
// h1 줄 수 — 앱 화면은 기본 1줄, 마케팅 헤드라인은 페이지별로 최대 2줄까지 명시할 수 있다.
|
||||
// 제목은 항상 존재·가시성을 확인하고, 줄 수는 페이지가 명시한 계약일 때만 검사한다.
|
||||
await page.setViewport({ width: 1440, height: 900 });
|
||||
const h1l = await page.evaluate(`__lines(${JSON.stringify(p.h1 || "h1")})`);
|
||||
const h1MaxLines = Number.isInteger(p.h1MaxLines) && p.h1MaxLines > 0 ? p.h1MaxLines : 1;
|
||||
const h1Rule = h1MaxLines === 1 ? "h1 1줄" : `h1 최대 ${h1MaxLines}줄`;
|
||||
h1l >= 1 && h1l <= h1MaxLines
|
||||
? pass(`${p.name}/${v} ${h1Rule}`)
|
||||
: (h1l > h1MaxLines ? fail(`${p.name}/${v} h1 ${h1l}줄(최대 ${h1MaxLines}줄)`) : skip(`${p.name}/${v} h1`, "요소 없음"));
|
||||
const h1Selector = p.h1 || "h1";
|
||||
const h1 = await page.evaluate((sel) => window.__heading(sel), h1Selector);
|
||||
const h1MaxLines = Number.isInteger(p.h1MaxLines) && p.h1MaxLines > 0 ? p.h1MaxLines : null;
|
||||
if (h1.state === "missing") fail(`${p.name}/${v} h1`, `선택자 없음 (${h1Selector})`);
|
||||
else if (h1.state === "empty") fail(`${p.name}/${v} h1`, "텍스트 없음");
|
||||
else if (h1.state === "hidden") fail(`${p.name}/${v} h1`, `선택자가 숨김 (${h1Selector})`);
|
||||
else if (h1.state === "invalid") fail(`${p.name}/${v} h1`, `잘못된 선택자 (${h1Selector})`);
|
||||
else if (h1.lines < 1) fail(`${p.name}/${v} h1`, "텍스트 없음");
|
||||
else if (h1MaxLines !== null && h1.lines > h1MaxLines) fail(`${p.name}/${v} h1`, `${h1.lines}줄(최대 ${h1MaxLines}줄)`);
|
||||
else if (h1MaxLines !== null) pass(`${p.name}/${v} h1 최대 ${h1MaxLines}줄`, `${h1.lines}줄`);
|
||||
else pass(`${p.name}/${v} h1 보임`, `${h1.lines}줄(줄수 계약 없음)`);
|
||||
|
||||
// 세로 쌓임(수축) — 짧은 라벨 3줄 이상
|
||||
if (CFG.checks.stack) {
|
||||
|
|
@ -430,21 +481,34 @@ for (const p of CFG.pages) {
|
|||
}
|
||||
}
|
||||
|
||||
// ── 스케일×폭 h1 행렬 (안드로이드 글꼴 확대 재현) ──
|
||||
// ── 스케일×폭 제목 행렬 (글꼴 확대에서 줄 수 증가와 잘림을 분리한다) ──
|
||||
if (CFG.checks.scaleMatrix) {
|
||||
const bad = [];
|
||||
const h1MaxLines = Number.isInteger(p.h1MaxLines) && p.h1MaxLines > 0 ? p.h1MaxLines : 1;
|
||||
const measurements = [];
|
||||
for (const w of [375, 390]) {
|
||||
for (const s of CFG.fontScales) {
|
||||
await page.setViewport({ width: w, height: 800, isMobile: true, hasTouch: true });
|
||||
await page.goto(href, { waitUntil: "networkidle0" });
|
||||
await page.evaluate(UTILS);
|
||||
await page.addStyleTag({ content: `html { font-size: ${16 * s}px !important; }` });
|
||||
const l = await page.evaluate(`__lines(${JSON.stringify(p.h1 || "h1")})`);
|
||||
if (l > h1MaxLines) bad.push(`${w}@${s}x:${l}줄(최대 ${h1MaxLines}줄)`);
|
||||
const baseRootSize = await page.evaluate(() => parseFloat(getComputedStyle(document.documentElement).fontSize));
|
||||
if (!Number.isFinite(baseRootSize) || baseRootSize <= 0) {
|
||||
bad.push(`${w}@${s}x:root font-size 측정 실패`);
|
||||
continue;
|
||||
}
|
||||
await page.addStyleTag({ content: `html { font-size: ${baseRootSize * s}px !important; }` });
|
||||
const h1 = await page.evaluate((sel) => window.__headingScaleAudit(sel), p.h1 || "h1");
|
||||
const point = `${w}@${s}x`;
|
||||
if (h1.state === "missing") { bad.push(`${point}:h1 선택자 없음 (${p.h1 || "h1"})`); continue; }
|
||||
if (h1.state === "empty") { bad.push(`${point}:h1 텍스트 없음`); continue; }
|
||||
if (h1.state === "hidden") { bad.push(`${point}:h1 선택자가 숨김 (${p.h1 || "h1"})`); continue; }
|
||||
if (h1.state === "invalid") { bad.push(`${point}:h1 잘못된 선택자 (${p.h1 || "h1"})`); continue; }
|
||||
if (h1.lines < 1) { bad.push(`${point}:h1 텍스트 없음`); continue; }
|
||||
measurements.push(`${point}:${h1.lines}줄`);
|
||||
if (s > 1 && h1.documentOverflow > 1) bad.push(`${point}:문서 가로오버플로 +${h1.documentOverflow}px`);
|
||||
if (s > 1 && h1.clipping.length) bad.push(`${point}:제목 텍스트 클리핑 ${h1.clipping.join(",")}`);
|
||||
}
|
||||
}
|
||||
bad.length ? fail(`${p.name} 스케일×폭 h1`, bad.join(",")) : pass(`${p.name} 스케일×폭 h1`, `최대 ${h1MaxLines}줄 · scales ${CFG.fontScales.join("/")}`);
|
||||
bad.length ? fail(`${p.name} 스케일×폭 h1`, bad.join(",")) : pass(`${p.name} 스케일×폭 h1`, `줄수 정보 ${measurements.join(", ")}`);
|
||||
// 브랜드 1줄
|
||||
await page.setViewport({ width: 390, height: 844, isMobile: true, hasTouch: true });
|
||||
await page.goto(href, { waitUntil: "networkidle0" });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue