feat(skill): refine brand-claim copy diagnosis and impact-based render checks
Limit competitor substitution to brand-differentiation claims, add impact-scoped render measurement guidance to audit-gate, and correct motion, Range, and font-check wording found during review.
This commit is contained in:
parent
2a7017717b
commit
79e79c120b
8 changed files with 114 additions and 26 deletions
|
|
@ -106,13 +106,16 @@ AI가 만든 티는 **못 만들어서** 나는 게 아니라 결정을 설명·
|
|||
|
||||
---
|
||||
|
||||
## 6. 카피 — 경쟁사 치환 테스트
|
||||
## 6. 카피 — 브랜드 차별성 치환 진단
|
||||
|
||||
**AI 티는 시각보다 문장에서 먼저 난다.**
|
||||
|
||||
### 테스트
|
||||
카피에서 제품·회사 이름을 **경쟁사 이름으로 바꿔 읽는다.**
|
||||
**여전히 자연스러우면 그 카피는 아무것도 말하지 않은 것이다. 다시 써라.**
|
||||
### 진단 범위
|
||||
브랜드가 특별하다고 주장하는 헤드라인·브랜드 약속에만 제품·회사 이름을 **경쟁사 이름으로 바꿔 읽는다.** 다른 업체에도 그대로 성립하면 차별성의 근거와 구체성을 다시 본다.
|
||||
|
||||
수업·가격·대상·위치·FAQ·CTA 등은 이 치환만으로 실패시키지 않는다. 독자가 실제로 묻는 질문에 구체적으로 답하고, 검증 가능한 사실과 자연스러운 업종 표현을 우선한다. 예를 들어 `그림을 시작하는 각자의 자리`는 시적 브랜딩으로 쓸 수 있고, 사용자가 수업 내용을 찾는 안내 제목에서는 `수업 안내`가 더 직접적일 수 있다. 전자를 전면 금지하는 규칙은 아니다.
|
||||
|
||||
낯선 업종이나 추상 표현의 용법이 불확실할 때는 공식 실제 사례를 소규모로 조사해 용어를 참고한다. 사례의 주장·실적·후기를 가져오거나 현재 프로젝트의 사실처럼 쓰지 않는다.
|
||||
|
||||
### 작법 — 금지 목록만으로는 못 잡는다
|
||||
|
||||
|
|
@ -125,7 +128,7 @@ AI가 만든 티는 **못 만들어서** 나는 게 아니라 결정을 설명·
|
|||
|
||||
**세 가지로 거른다.**
|
||||
|
||||
**1. `so you can…` 테스트** — 문장 뒤에 이어 붙여 완성해봐라.
|
||||
**1. `so you can…` 테스트** — 브랜드 차별성 주장의 문장 뒤에 이어 붙여 완성해봐라.
|
||||
|
||||
```
|
||||
"feTurbulence 로 노이즈를 만든다" so you can → 200KB 텍스처를 300바이트로 줄인다 ✅
|
||||
|
|
@ -134,10 +137,9 @@ AI가 만든 티는 **못 만들어서** 나는 게 아니라 결정을 설명·
|
|||
|
||||
완성되지 않으면 기능만 쓴 것이다. **완성된 뒷부분을 헤드라인으로 올려라.**
|
||||
|
||||
**2. 6~12단어** — 2초 안에 훑히면서 가치를 전달하는 폭이다.
|
||||
한국어는 어절 기준으로 6~12, 글자 수로는 12~28자.
|
||||
**2. 실제 독자가 한 번에 이해하는 길이** — 같은 의미를 짧게 쓸 수 있는지 보되, 업종·언어·화면 폭과 질문의 복잡도를 무시한 보편 단어 수를 기준으로 삼지 않는다.
|
||||
|
||||
**3. 헤딩에 검증 가능한 것을 넣어라** — 숫자·조건·비교 대상 중 하나.
|
||||
**3. 차별성 주장에는 검증 가능한 근거를 넣어라** — 숫자·조건·비교 대상 중 하나가 있으면 좋지만, 없는 안내 제목에 억지로 넣지 않는다.
|
||||
|
||||
| 고치기 전 | 고친 뒤 | 무엇이 달라졌나 |
|
||||
|---|---|---|
|
||||
|
|
@ -185,7 +187,7 @@ 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") |
|
||||
| `Build the future of X` / `Your all-in-one platform` / `Scale without limits` | 근거 없는 브랜드 차별성 주장으로는 경쟁사 이름으로 바꿔도 성립 | 검증 가능한 차별점, 또는 독자의 질문에 직접 답하는 안내 문장 |
|
||||
| 헤지 표현 (`may help you`, `~할 수 있습니다`) | 불확실성의 범위가 숨겨지면 독자가 주장 강도를 판단하기 어렵다 | 검증된 내용은 명확히 쓰고, 불확실하면 조건·근거·한계를 명시한다 |
|
||||
| CTA가 `Get Started` / `Learn More` / `시작하기` | 무엇이 시작되는지 알 수 없음 | 결과를 말하는 CTA (`무료로 30일 써보기`, `가격표 보기`) |
|
||||
| 출처·조건 없는 숫자 (`10,000+`, `99.9%`, `50% faster`) | 사실처럼 보이는 주장의 검증 경로가 없다 | 정확/범위 수치 모두 출처·측정 조건·기간을 붙인다. 조건 없는 수치는 제거하거나 예시임을 라벨링한다 |
|
||||
|
|
@ -280,10 +282,7 @@ letter-spacing:\s*-0\.0[3-9] (한글 본문)
|
|||
**측정 시점**이었다. 제목과 본문이 나란히 애니메이션되면 같이 움직여 상쇄되지만,
|
||||
한쪽만 `.reveal` 이면 상쇄되지 않는다.
|
||||
|
||||
```js
|
||||
await page.evaluate(() => el.scrollIntoView({ block: 'center' }));
|
||||
await page.waitForTimeout(1600); // 프로젝트의 모션 종료 조건을 확인한 뒤 잰다
|
||||
```
|
||||
검사 대상의 실제 locator를 정하고 스크롤해 등장시킨다. 그 뒤 실제 스크롤과 전환이 끝난 조건을 확인하고 잰다. 프로젝트가 정한 상한 시간은 그 조건을 기다리는 고정 대기가 아니라 **상한을 넘기면 실패시키는 시간**이다. [렌더 측정 계약](audit-gate.md)에서 대상별 완료 조건과 clipping 측정 방법을 정한다.
|
||||
|
||||
**② `sharp(...).extract(...).stats()` 사용 결과가 의도한 crop 통계를 반영하는지 확인한다.**
|
||||
영역을 여섯 군데 잘라 밝기를 쟀는데 여섯 개가 **소수점까지 똑같이** 나왔다.
|
||||
|
|
@ -428,8 +427,8 @@ sticky 캔버스가 끝까지 돌려면 목록 뒤에 스크롤 구간이 필요
|
|||
**검토 조건 — 근거와 결과를 남긴다**
|
||||
- [ ] 반복 후보(보라 CTA / 전체 대문자 / 1·2·3 단계)를 발견했으면 프로젝트 계약·브리프·실제 렌더 근거로 유지·수정·제거를 결정했다
|
||||
- [ ] grep 검사에서 나온 항목은 자동 실패로 취급하지 않고, 출처·관찰·결정·검증을 기록했다
|
||||
- [ ] 카피가 경쟁사 치환 테스트를 통과한다
|
||||
- [ ] 모션을 전부 끄고도 페이지가 작동한다
|
||||
- [ ] 브랜드 차별성 주장은 경쟁사 치환 진단으로 근거·구체성을 검토했고, 안내 카피는 실제 질문·검증 가능한 사실·업종 표현으로 검토했다
|
||||
- [ ] 이펙트가 없어도 정보와 핵심 과업이 남고, 감소 모션에서도 상태와 조작이 유지된다
|
||||
- [ ] 강조색을 지워도 페이지가 읽힌다
|
||||
- [ ] 색을 회색조로 바꿔도 위계 순서가 비즈니스 우선순위와 일치한다
|
||||
- [ ] 키보드만으로 전 인터랙션이 가능하고 포커스 링이 보인다
|
||||
|
|
|
|||
|
|
@ -54,6 +54,43 @@
|
|||
| L5 탐색 | 키보드 완전 통과 + 사용자 여정 차터 | 프로젝트별 작성 — 마우스 금지 |
|
||||
| L6 시나리오 E2E | 실사용자 여정 재현 — 페르소나의 하루·장기 과업 포함 | 프로젝트별 작성. **기대값 단언 필수**(하니스 규칙 8), 백 키·시트·양방향 흐름은 `mobile-app-ux.md` 패턴 기준. 실측: RED 1,742 단언 중 318 실패가 신규 기능에 정확히 집중 — 시나리오를 먼저 쓰면 미구현이 수치로 드러난다 |
|
||||
|
||||
## 렌더 측정 계약
|
||||
|
||||
자동 측정은 실제 장면을 재현할 때만 의미가 있다. 새 범용 JS 엔진을 만들라는 뜻이 아니다. 프로젝트의 기존 E2E·시각 회귀 도구에 아래 계약을 적고, 페이지와 기능의 위험에 맞는 단언만 구현한다.
|
||||
|
||||
### 1. 장면과 레이아웃
|
||||
|
||||
각 artifact에는 빌드·revision 식별자, URL, viewport의 너비·높이·종횡비·zoom, 스크롤 위치, UI 상태, 로드한 폰트·이미지·영상 자산을 함께 남긴다. 폭만 적어서는 같은 폭에서 높이가 달라진 크롭, 짧은 화면의 고정 크롬, 확대에 따른 줄바꿈을 재현할 수 없다. 짧은 가로·긴 세로·확대가 결과에 영향을 주면 대표 장면에 포함한다. 배경 위치, 분기 종횡비, 헤더 높이, viewport 단위 선택은 프로젝트 계약으로 정한다.
|
||||
|
||||
화면 맞춤 hero는 헤더가 overlay인지, 문서 흐름에서 높이를 차지하는지 먼저 구분한다. 그 역할을 포함해 첫 화면의 남은 높이를 재고, 내용이 고정 높이보다 커지면 자연스럽게 확장되어야 한다. 모든 페이지 섹션에 `100vh`를 강요하지 않는다. 컨테이너의 `overflow=0`만으로 피사체·카피·행동의 안전 영역이 보존됐다고 판정하지 말고, 실제 크롭과 인접 콘텐츠의 겹침을 화면에서 확인한다.
|
||||
|
||||
### 2. 모션과 상태
|
||||
|
||||
reveal·전환은 실제 UI 스크롤·클릭·키보드 이벤트로 장면을 먼저 활성화한다. 그 장면에 필요한 폰트·이미지가 준비된 뒤 대상과 전환에 관여하는 조상 요소의 유한 전환 완료를 관측하고, 프로젝트가 의도한 최종 가시성·색·대비·위치에 도달했는지 확인한다. 최종 가시성은 `opacity: 1`을 일괄 요구하는 값이 아니다. 의도한 반투명 텍스트도 조상 opacity 합성을 포함한 실제 대비와 상태 계약으로 판정한다. 정한 상한 시간 안에 끝나지 않으면 실패 또는 미검증으로 기록하고 원인을 남긴다.
|
||||
|
||||
계속 움직이는 배경·카운터·캔버스는 별도 상태 계약으로 관측한다. 모든 페이지 애니메이션이 끝날 때까지 기다리는 검사는 만들지 않는다. 정지 상태의 대비, 일반 설정에서 trigger와 완료가 실제로 작동하는지, `prefers-reduced-motion` 경로를 각각 보고한다. 안정한 정상 상태의 대비가 영구 애니메이션의 저대비나 발화 실패까지 통과시키지 않는다.
|
||||
|
||||
고정 sleep, 검사 중 `opacity: 1` 강제, `animation: none` 주입으로 제품 모션 검사를 GREEN으로 만들지 않는다. 썸네일·OG용 정지 프레임은 별도 산출물이다. 그 경우에는 완성된 프레임을 고정하고 축소 모션을 적용할 수 있지만, 실제 동작 검수의 대체가 아니다.
|
||||
|
||||
### 3. 텍스트·클리핑·폰트
|
||||
|
||||
`Range.getClientRects()`는 선택 범위의 요소 box와 텍스트 font metric에 따른 사각형이며 글리프 잉크 경계가 아니다. heading·line box 밖 rect만으로 실제 잘림을 확정하지 않는다. viewport 밖 rect는 가시성 후보로 계속 검사하되, viewport와 실제 `overflow` clipping 조상을 함께 추적한다. `clip-path`·mask·transform처럼 rect만으로 설명하기 어려운 경계는 실제 렌더를 열어 수동 판정한다. 텍스트 후보가 보이면 인접 콘텐츠와 겹치거나 읽기 영역을 침범하는지도 함께 확인한다. [CSSOM View의 `Range.getClientRects()` 편집 초안](https://drafts.csswg.org/cssom-view/#dom-range-getclientrects)을 2026-09-20에 확인했다.
|
||||
|
||||
`document.fonts.ready`와 FontFaceSet 상태는 로드 준비의 근거일 뿐, 모든 화면 문자가 의도한 폰트로 그려졌다는 증명은 아니다. 필요한 문자·언어·숫자·기호와 웨이트를 실제 카피로 렌더하고, 브라우저가 제공하는 rendered-font 확인 또는 필요한 글리프 검증과 화면 관찰을 결합한다. 폰트 선택·subset·fallback의 세부 절차는 [typography.md](typography.md)를 따른다.
|
||||
|
||||
### 4. 실패와 증거
|
||||
|
||||
실패는 제품 결함, 측정기 오류, 계약 변경으로 분류한다. 실패 artifact와 원문 결과는 보존한다. 의도 변경 근거와 전후 렌더 증거 없이 기대값을 고치거나 assertion을 완화해 통과시키지 않는다. 측정기가 틀렸다면 UI를 먼저 고치지 말고 RED 재현을 남겨 측정기를 고친 뒤 같은 사례를 GREEN으로 확인한다.
|
||||
|
||||
artifact 한 건에는 빌드·revision, viewport·zoom·스크롤·상태, 기대값과 관측값, 자동 결과, 실제 화면의 시각 판정을 같이 남긴다. 수치와 스크린샷이 서로 다른 장면이면 증거가 아니다.
|
||||
|
||||
| 작은 재현 예제 | 재현 조건 | 정상 기대 | 오판 / 금지되는 처리 |
|
||||
|---|---|---|---|
|
||||
| reveal 진행 중 / 완료 뒤 저대비 | 실제 스크롤로 reveal을 시작한 직후와 유한 전환 종료 뒤를 각각 캡처한다 | 진행 중 프레임은 완료 판정에서 제외하고, 종료 뒤에는 의도한 색·합성 대비와 가시성을 확인한다 | sleep 한 번 뒤 진행 프레임을 PASS로 쓰거나, 종료했지만 실제 색 대비가 부족한 텍스트를 통과시킨다 |
|
||||
| line box 넘침 / 실제 hidden 조상 clip | 같은 긴 문장의 실제 잉크가 heading·line box 밖으로 나가게 두고, 한쪽은 `overflow: visible`, 다른 쪽은 잉크가 경계를 넘는 `overflow: hidden` 조상 안에 둔다 | 전자는 실제 잉크와 인접 영역을 보고 보존 여부를 판정하며, 후자는 실제 clip을 화면에서 확인한다 | Range rect 하나로 두 사례를 모두 잘림 또는 모두 정상으로 확정한다 |
|
||||
| 같은 폭, 다른 높이의 피사체 크롭 | 같은 폭의 이미지 장면을 짧은 viewport와 긴 viewport에서 header 역할·스크롤 위치를 같게 맞춘다 | 피사체와 행동의 안전 영역이 두 높이에서 의도대로 남는지 비교한다 | 폭만 기록해 짧은 화면에서 잘린 얼굴·문구를 놓친다 |
|
||||
| 의도 변경 없는 낡은 expected 값 | 렌더가 달라졌지만 디자인 의도 변경 기록이 없는 시각 회귀를 만든다 | 기존 기대값을 유지하고 제품 결함 또는 측정기 오류를 분류한다 | diff를 없애려고 expected·baseline만 무단 갱신한다 |
|
||||
|
||||
## 설치 (프로젝트에 게이트 심기)
|
||||
|
||||
```
|
||||
|
|
@ -81,19 +118,19 @@ L1·L5 는 프로젝트 안에 `tools/unit/*.test.mjs`, `tools/exploratory.mjs`
|
|||
|
||||
1. **선택자는 스코프필수** — 같은 data-* 가 다른 뷰에 있으면 숨은 요소를 잡는다(`#as-table [data-assign]` 처럼).
|
||||
2. **page.evaluate 클로저 금지** — Node 스코프 함수를 페이지 안에서 부르지 않는다. 측정 코드는 문자열로 주입.
|
||||
3. **줄 수 측정의 오탐 두 종류** — 폰트 메트릭 top 차이(±5px 허용오차), 인라인 아이콘과 텍스트의 top 차이(텍스트 노드만 분리 측정).
|
||||
3. **줄 수 측정의 오탐 두 종류** — 폰트 메트릭 top 차이(±5px 허용오차), 인라인 아이콘과 텍스트의 top 차이(텍스트 노드만 분리 측정). line box와 실제 글리프 잘림의 구분은 [렌더 측정 계약](#렌더-측정-계약)을 따른다.
|
||||
4. **CSS 수정 직후 검증은 캐시 차단**(`setCacheEnabled(false)`) + 실제 로드된 `?v=` 확인.
|
||||
5. **비전(모델) 검수는 '여부'가 아니라 '지점 평가'에만** — 여부는 계측으로.
|
||||
6. **모달 닫힘 직후 포커스 강탈** — 뷰 전환+타깃 포커스는 한 evaluate 로, settle 후 유실 재포커스.
|
||||
7. **게이트를 통과해도 리포트에 수치를 남긴다** — "ALL PASS"가 아니라 "무엇을 몇으로 확인했나".
|
||||
8. **검사는 단언한다** — `pass("차터", st)` 처럼 상태를 상세로만 찍는 건 검사가 아니다. 실측 사고: 점수 입력에 "88"을 `type()` 하면 기존 값에 **덧붙어** "9288"이 되었고, 차터는 상태 텍스트만 인쇄해 통과했다. 기대값과 비교해 pass/fail 을 내라.
|
||||
9. **number 입력은 선택-덮어쓰기가 안 된다** — 트리플 클릭 선택이 무시된다. 값을 비우고 타이핑하거나 `el.value = x; dispatchEvent(new Event("input"))` 로 설정한다.
|
||||
10. **등장 모션 지속시간 ≤ 감사 도구 대기시간** — 시각 회귀가 뷰 전환 100ms 뒤에 스크린샷을 찍는다면 등장 애니메이션은 그보다 짧게(≤70ms). 아니면 매번 다른 프레임이 찍혀 회귀가 흔들린다.
|
||||
10. **등장 모션과 캡처 상태를 맞춘다** — 모션 지속시간은 사용자 경험의 목적·입력 반응·감소 모션 계약으로 정한다. 시각 회귀는 그 값을 줄이라고 요구하지 않고, 실제 완료를 관측한 뒤 캡처한다. 임의 sleep으로 진행 프레임을 통과시키지 않으며 실제 모션 검수는 [렌더 측정 계약](#렌더-측정-계약)을 따른다.
|
||||
11. **같은 diff 수치가 반복되면 패치가 적용되지 않은 것** — 수정하고도 시각 diff %가 소수점까지 동일하면 수정이 렌더에 닿지 않았다(캐시·캐스케이드 순서·잘못된 파일). 고치기를 반복하지 말고 적용 자체를 의심해라.
|
||||
12. **페이지→노드 직렬화는 NaN 방어** — `getComputedStyle(el).fontSize` 등을 문자열 보간하면 "16px"이 NaN이 되고, 하니스는 NaN을 `null`로 받아 `"////px"` 같은 고장난 상세를 리포트한다. 수치는 항상 `parseFloat(x) || 0` 로 감싼다.
|
||||
13. **`position: fixed` 요소의 보임 판정은 offsetParent 로 하지 마라** — fixed 는 offsetParent 가 `null`이다. display 계산값·높이로 판정한다.
|
||||
14. **실기기(에뮬레이터) 검증은 텍스트 근거로** — `uiautomator dump` 의 `text="…"`에서 화면 제목·활성 탭을 읽어 단언한다. 스크린샷+비전은 "백 직후 전환 중 프레임"을 잡는 타이밍 오탐이 있다(실측 사고). 물리 폰이 붙어 있으면 `adb -s <emulator>` 로 대상을 한정한다.
|
||||
15. **시각 기준 갱신은 의도 변경 리뷰를 동반한다** — "달라졌으니 갱신"으로 결함이 기준에 박힌다(실측: 왼쪽 인셋 결함 화면이 기준 갱신으로 '정상'이 되어 재발을 숨겼다). 갱신 전에 무엇이 의도적으로 바뀌었는지 한 줄씩 나열하고, 사용자 보고가 있던 화면은 수리 후 재촬영한다.
|
||||
15. **시각 기준 갱신은 의도 변경 리뷰를 동반한다** — "달라졌으니 갱신"으로 결함이 기준에 박힌다(실측: 왼쪽 인셋 결함 화면이 기준 갱신으로 '정상'이 되어 재발을 숨겼다). 갱신 전에 무엇이 의도적으로 바뀌었는지 한 줄씩 나열하고, 사용자 보고가 있던 화면은 수리 후 재촬영한다. 증거 보존과 실패 분류는 [렌더 측정 계약](#렌더-측정-계약)을 따른다.
|
||||
16. **사용자 보고 스크린샷은 비전 요약이 아니라 픽셀 판정으로 해부한다** — 비전 모델의 픽셀 추정("~0px", "~16px")은 부정확하다. pngjs 등으로 화면을 가로 밴드로 나눠 각 밴드의 텍스트 시작 x를 직접 재면(보임 행만, 왼쪽 테두리 아티팩트 제외) "무엇이 어디서 어긋났는지"가 수치로 나온다. 실측: '제목이 가장자리에 붙는다'는 보고가 앱바 24px·제목 16px의 리듬 불일치로 확정됐다.
|
||||
17. **새 검사는 수정 전 코드로 RED 재현 후 GREEN** — 검사 자체의 측정 하자(오탐)도 이렇게 잡는다. 실측: 왼쪽 인셋 검사 초안이 ①`display:none` 요소의 rect=0, ②전폭 컨테이너의 보더박스(텍스트가 아님)로 38개 오탐 — RED 단계에서 발견해 교정했다.
|
||||
18. **시각 E2E는 기본 화면만 찍지 않는다** — URL별 390·1440 기본 화면에 더해 결과가 바뀐 입력, 오류/검토, 모달/차단 상태를 찍는다. 하니스는 파일 개수·가로세로·0바이트·해시 중복을 단언하고, 에이전트는 파일을 실제로 열어 시장 적합성·위계·크롭·반복을 판정한다. 스크린샷을 저장했다는 사실만으로 PASS하지 않는다.
|
||||
|
|
@ -111,7 +148,7 @@ L1·L5 는 프로젝트 안에 `tools/unit/*.test.mjs`, `tools/exploratory.mjs`
|
|||
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바이트·시각 검수까지 단언한다.
|
||||
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가 한 글자 열로 수축하면 실패다.
|
||||
|
||||
## 리포트 양식
|
||||
|
|
|
|||
|
|
@ -139,6 +139,8 @@
|
|||
- 터치 타깃은 과업 빈도·오입력 위험과 WCAG 2.2 AA의 24×24 CSS px 최소 기준(예외 포함)을 함께 검토한다
|
||||
- 호버로만 접근되는 기능을 만들지 마라
|
||||
|
||||
반응형 장면은 폭만 기록하지 않는다. 높이·종횡비·zoom·스크롤·상태가 짧은 화면, 긴 화면, 확대에서 결과를 바꾸는지 먼저 보고 대표 viewport를 고른다. 프로젝트의 특정 수치를 공통 규칙으로 만들지 않으며, 실제 측정 artifact와 실패 처리는 [audit-gate.md](audit-gate.md)의 렌더 측정 계약을 따른다.
|
||||
|
||||
---
|
||||
|
||||
## 4-b. 모바일 내비 — 햄버거를 기본값으로 삼지 마라
|
||||
|
|
@ -244,6 +246,7 @@ Apple도 다양한 화면 크기에서 적응형 레이아웃과 읽기 좋은
|
|||
|
||||
- `--stage-wide`, `--copy-wide`, `--media-wide`, 후속 `--workbench-wide`를 따로 이름 짓는다. 한 `--wrap`을 무한히 키우지 않는다
|
||||
- 1920·2560에서 hero·copy·media·다음 정보 레일의 실제 rect를 기록한다. media의 상한, copy의 최소 폭, hero의 중앙/의도된 정렬을 **그 페이지의 계약**으로 단언한다
|
||||
- 화면 맞춤 hero는 헤더가 overlay인지 문서 흐름에서 높이를 차지하는지 구분해 남은 높이를 계산한다. 카피·행동이 고정 높이보다 커지면 자연 확장하고, 모든 섹션에 `100vh`를 강요하지 않는다. 피사체·텍스트 안전 영역은 `overflow=0`만으로 통과시키지 말고 짧고 긴 viewport의 실제 크롭과 인접 영역 겹침을 확인한다
|
||||
- 이미지가 넓어질 자격은 이미지 자체의 편집적 역할에 있다. 정보·주문·비교가 뒤따르는 제품 화면에서는 후속 레일도 같은 밀도로 확장해, 첫 장면만 거대하고 본문은 점처럼 보이는 단절을 만들지 않는다
|
||||
- 이 계약은 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를 별도로 측정한다.
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@ canvas { display: none !important; }
|
|||
`references/antipatterns.md`의 grep 목록을 소스에 돌려 보라 CTA, 전체 대문자 헤드라인, 번호 매긴 단계 같은 반복 후보를 찾는다. 검출은 실패가 아니다. 프로젝트 계약·브리프·실제 렌더를 대조해 결정을 기록한다.
|
||||
|
||||
### C. 카피 경쟁사 치환
|
||||
제품명을 경쟁사 이름으로 바꿔 읽는다. **문장이 그대로 성립하면 그 카피는 아무것도 말하지 않았다.** 히어로 문구부터 검사한다.
|
||||
브랜드가 특별하다고 주장하는 문구에만 제품·회사 이름을 경쟁사 이름으로 바꿔 읽는 **진단 질문**을 쓴다. 다른 업체에도 그대로 성립하면 근거와 구체성을 재검토한다. 수업·가격·대상·위치·FAQ·CTA 같은 안내는 치환만으로 실패시키지 않는다. 독자의 실제 질문에 대한 구체적 답, 검증 가능한 사실, 자연스러운 업종 표현을 먼저 확인한다.
|
||||
|
||||
낯선 업종이나 추상 표현의 용법이 불확실할 때만 공식 실제 사례를 소규모로 조사해 용어를 참고한다. 그 사례의 주장·실적·후기를 가져오지 않으며, 현재 프로젝트의 사실로 바꾸어 말하지 않는다.
|
||||
|
||||
### D. 죽은 코드·토큰 위생 (design-gate 내장 검사)
|
||||
- CSS 클래스가 HTML·JS 어디에도 등장하지 않으면 죽은 것이다. 컴포넌트를 없앨 때 HTML·CSS·JS 를 **삼위일체로** 지웠는지 대조한다(동적 클래스 `is-${type}`·`seg-${n}` 처럼 조립되는 접두사는 게이트 설정의 `deadCssIgnore` 로 제외한다)
|
||||
|
|
@ -129,6 +131,7 @@ canvas { display: none !important; }
|
|||
## 3. 반응형
|
||||
|
||||
- [ ] 프로젝트가 채택한 회귀 매트릭스에서 가로 스크롤 없음. 이 저장소의 기본 매트릭스는 **320·390·768·1440·1920·2560px**이며, 지원 기기·브리프가 다르면 그 계약을 바꾸고 이유를 기록한다
|
||||
- [ ] 변경 영향에 따라 프로젝트가 채택한 뷰의 너비×높이, 짧은 화면, 긴 세로 흐름, 뷰포트 종횡비·피사체 보존·실제 clipping, 글자 확대를 추가로 검사한다. 크롬·모달·긴 폼·고정 CTA는 짧은 화면의 가시 영역과 scroll owner를, 목록·본문·이미지는 긴 세로 흐름과 피사체 보존을, 글꼴·카피·컨트롤은 지원 확대 상태를 잰다. 모션 상태와 clipping의 상세 계약은 [렌더 측정 계약](audit-gate.md)을 따른다
|
||||
- [ ] **크롬(탑바·앱바·툴바)에 컨트롤을 더했다면 그 줄의 최소폭 합을 가장 좁은 폭에서 다시 잰다** — 버튼 하나가 320px를 뚫는 사고가 반복된다(실측: 인쇄 버튼 1개로 +18px). 줄이 넘으면 감싸기(2행 랩)가 기본 수습이다
|
||||
- [ ] 프로젝트 회귀 매트릭스의 각 폭에서 실제 브라우저 렌더를 잰다. 기본 매트릭스(320·390·768·1440·1920·2560px)는 저장소의 회귀 범위이며 WCAG의 보편 폭 기준은 아니다. 최소 폭의 오버플로와 wide 화면의 카피 측정폭·제목 칼럼을 함께 확인한다
|
||||
- [ ] WCAG 200% 확대 또는 운영체제의 실제 글꼴 확대가 지원 범위라면 실제 브라우저·기기에서 별도 검증한다. gate의 font-scale 행렬은 회귀 신호이며 px 고정 폰트의 OS 확대를 대체하지 않는다
|
||||
|
|
@ -185,7 +188,7 @@ canvas { display: none !important; }
|
|||
- [ ] 민감 입력과 파생값의 영속 저장·쿠키·분석 이벤트 포함·네트워크 전송 경계를 E2E로 검증했다
|
||||
- [ ] 공개 화면은 사용자 해석·제한·다음 행동을, 관리자는 내부 원장·검증 이벤트·채널 판정·감사 로그를 소유한다. 사용자 행동에 영향을 주는 제한을 관리자에만 숨기지 않았다
|
||||
- [ ] 지도·차트·도식의 같은 정보가 DOM 목록·표·설명으로도 제공되고 데이터 원천이 하나다
|
||||
- [ ] 생성 이미지는 가격·주소·점수의 증거로 쓰이지 않으며, 모바일 390×844에서 핵심 피사체가 첫 화면의 의도와 맞는다
|
||||
- [ ] 생성 이미지는 가격·주소·점수의 증거로 쓰이지 않으며, 프로젝트가 채택한 모바일 뷰와 종횡비에서 핵심 피사체가 첫 화면의 의도와 맞는다
|
||||
- [ ] URL별 390·1440 기본 화면과 핵심 입력/오류/모달 상태 캡처를 실제로 열어 보고 시각 PASS/RED를 따로 기록했다
|
||||
|
||||
## 4-3. 썸네일·OG 캡처 — 움직이는 화면을 대표하지 않는다
|
||||
|
|
|
|||
|
|
@ -49,11 +49,13 @@
|
|||
브라우저에서 재는 법:
|
||||
|
||||
```js
|
||||
// 실제 렌더된 폰트가 무엇인지부터 확인한다. 폴백으로 떨어졌는데 모르는 경우가 많다
|
||||
document.fonts.check('16px "Pretendard Variable"');
|
||||
// 미로딩 매칭 폰트를 사용해야 하는지 점검한다
|
||||
document.fonts.check('16px "Pretendard Variable"', '가나다ABC0123');
|
||||
[...document.fonts].map(f => `${f.family} ${f.weight} ${f.status}`);
|
||||
```
|
||||
|
||||
`true`는 특정 폰트의 존재·실제 사용·개별 글리프 지원을 보증하지 않는다. [MDN `FontFaceSet.check()`](https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/check)을 2026-09-20에 확인했다. 화면에 필요한 문자·언어·숫자·기호와 웨이트를 실제 카피로 확인하고, 가능한 브라우저의 rendered-font 확인 또는 필요한 글리프 검증과 실렌더 관찰을 결합한다. heading·line box 밖 rect만으로 글리프 잘림을 확정하지 않는 절차와 artifact 조건은 [audit-gate.md](audit-gate.md)의 렌더 측정 계약을 따른다.
|
||||
|
||||
### 1-4. 기본값을 피한다
|
||||
|
||||
`Inter` 는 금지가 아니라 **기본값 금지**다. 다국어 UI나 초고밀도 대시보드처럼 이유가 있으면 쓴다. 이유 없이 쓰면 그건 고른 게 아니다.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue