# reference-method.md — 레퍼런스 해체와 합성 레퍼런스를 **원리로 분해**해서 **다른 결과물로 재조합**하는 절차다. **원칙 한 줄**: 레퍼런스를 언어로 설명했을 때 그 설명이 여러 결과물로 구현될 수 있으면 원리다. 하나로만 이어지면 표현이다. **원리만 가져간다.** | 가져간다 (원리) | 안 가져간다 (표현) | |---|---| | 그리드의 비대칭 관계 (관찰 예: 5:7) | 섹션 배치 그대로 | | 타입 단계의 관계 (관찰 예: 1.333) | 폰트 조합 그대로 | | 색의 역할 배분 (관찰 예: 60/30/10) | 색상값 | | 여백의 상대 리듬 (관찰 예: 섹션 120 / 요소 24) | 섹션 순서 | | 모션의 의도 (스크롤=시선 유도) | 애니메이션 시퀀스 | 표의 숫자는 특정 사례를 설명하는 관찰 예시일 뿐, 다른 프로젝트에 그대로 적용할 법칙이 아니다. 관계가 현재 콘텐츠·언어·과업·렌더에서도 작동하는지 확인한 뒤 값을 정한다. --- ## 1. 레퍼런스 슬롯으로 해체하기 R1·R2·R3은 구조·톤·디테일을 섞어 복제하지 않기 위한 **검토 슬롯**이다. 세 슬롯을 채웠다는 사실은 합성의 품질을 보장하지 않는다. 프로젝트에 필요한 슬롯만 채우고, 비운 슬롯은 이유와 대체 근거를 기록한다. | 슬롯 | 가져올 것 | 어디서 | |---|---|---| | **R1 · 구조** | 그리드, 섹션 순서, 정보 위계, 여백 리듬 | 같은 업종·같은 목적 | | **R2 · 톤** | 색 역할, 타입 페어링, 형태 언어, 질감 | 다른 업종 또는 웹 이외 매체를 우선 검토 | | **R3 · 디테일** | 모션 1개, 호버 1개, 전환 1개 | Codrops / Eyecandy / Design Spells | R2가 R1과 같은 업종이어도 브리프가 요구하는 브랜드·시장·제작 조건에 맞으면 가능하다. 같은 업종의 평균을 무비판적으로 복제하지 않도록, 가져오는 원칙·관찰·결정·검증을 분리해 기록한다. ### 목표 시장은 네 번째 레퍼런스가 아니라 경계 조건이다 목표 시장을 적지 않으면 검색 결과 상위의 서구 사례가 무의식적으로 기본값이 된다. 먼저 한 줄로 잠근다. ```md 시장: 국가/도시/생활권 · 주 사용 기기 · 단위/통화 · 문의/구매 관습 · 피해야 할 외래 문법 ``` - R1은 같은 업종·목적에 더해 **같은 목표 시장을 우선**한다. 구조에 단위·용어·연락 방식이 묻어 있기 때문이다. - R2는 다른 업종 또는 같은 문화권의 다른 매체를 먼저 검토하되, 같은 업종이 더 적합하면 그 조건과 이유를 기록한다. - 다른 문화권 R3는 기법만 가져온다. 카피·색·상징·사진 연출까지 번지면 경계 조건 위반이다. - 같은 시장 자료가 부족하면 빈칸을 숨기지 말고, 어떤 관습을 공식 문서·현지 서비스로 별도 검증했는지 적는다. 목표 시장 적합성은 국기·전통 문양 같은 표식이 아니다. 통화 단위, 면적 표기, 동네 탐색 축, 정보 순서, 촬영 조도, CTA 동사처럼 **사용자가 실제로 행동하는 문법**이다. **충돌 해결 순위** 1. 가독성·접근성이 언제나 이긴다. R2의 톤이 대비를 깨면 톤을 조정한다. 2. R1 구조가 R3 모션을 이긴다. 모션 때문에 구조를 바꾸지 않는다. 3. 브리프가 모든 레퍼런스를 이긴다. 충돌하면 레퍼런스를 버린다. 4. 한 축에 여러 출처가 영향을 주면 출처별 관찰과 최종 결정을 분리한다. 출처가 섞였다는 사실이 실패는 아니며, 근거 없이 절충한 경우만 다시 검토한다. --- ## 2. 6축 해체 프레임워크 각 레퍼런스를 6축으로 뜯는다. **형용사만으로 끝내지 않는다.** 실측값, 관찰 가능한 규칙, 적용 조건을 함께 적고 실제 렌더에서 결정이 맞는지 확인한다. 아래 숫자 범위는 보편 판정이 아니라 관찰을 시작할 때 쓸 수 있는 예시다. **R3 예외**: R3는 사이트가 아니라 기법이다. 축 5(모션 언어) 하나만 채우고 나머지는 비운다. 대신 R3에는 **구현 제약**(브라우저 지원, 성능 비용, 보간 조건)을 반드시 적는다. ### 축 1 — 레이아웃 그리드 컬럼 수·거터 / 콘텐츠 최대폭과 뷰포트 비 / 대칭·비대칭(비율) / 그리드를 깨는 요소 / 실제 본문 줄 길이와 읽기 맥락 → *"무엇을 정렬시키고 무엇을 일부러 어긋나게 했나?"* ### 축 2 — 타입 스케일 실제 사용된 크기 목록 / 그 사이 비율 / 단계 수 / 패밀리 수 / 굵기 대비 / line-height / letter-spacing → *"최대 글자와 본문의 비는 몇 배이고, 이 화면의 과업·언어·읽기 폭에서 위계가 보이는가?"* ### 축 3 — 컬러 역할 색상값이 아니라 **역할**로 적는다. surface 단계 수 / text 위계 / accent 면적과 역할 / border 존재 여부 / state 색 분리 여부 → *"강조색을 지워도 정보 위계와 조작 상태를 이해할 수 있는가?"* ### 축 4 — 여백 리듬 기본 단위 / 섹션 간 수직 여백 / 요소 간 : 섹션 간 비율 / 여백 값 종류 / 좌우 패딩 → *"가장 큰 빈 공간은 어디이고 왜 거기인가?"* ### 축 5 — 모션 언어 트리거(로드/스크롤/호버/커서) / duration / easing / 정보 전달인가 장식인가 / reduced-motion 대응 → *"모션을 전부 끄면 작동하는가?"* (작동해야 정상) **어떤 CSS 속성 또는 스크롤 로직을 쓰는지 반드시 적어라.** `transform`·`opacity`는 저비용 기본이지만 다른 선택은 금지가 아니다. `stroke-dashoffset`·`height`·`clip-path`·`filter` 같은 기법은 1단계부터 비용 측정, 입력 간섭, 감소 모션, 지원 범위와 예산을 함께 기록해 `motion.md`의 계약으로 검증한다. ### 축 6 — 시선 흐름 첫 진입점 / 2·3번째 / 비즈니스 우선순위와 일치 여부 / Z·F·수직 낙하 중 무엇인가 / CTA가 경로 위에 있나 **회색조 위계 서술** (에이전트용 squint test 대체) — 자기가 만들 화면에 대해 문장으로 쓴다: > 색을 전부 제거했을 때 가장 강한 덩어리는 ___, 두 번째는 ___, 세 번째는 ___. > 이 순서는 비즈니스 우선순위 [1위 ___ / 2위 ___ / 3위 ___]와 일치한다 / 하지 않는다. 일치하지 않으면 크기·굵기·대비·공간·순서를 검토한다. 색만으로 해결하지 않고, 필요한 경우 색 역할도 프로젝트 토큰 안에서 조정한다. --- ## 3. 실전 절차 체크리스트 - [ ] **1. 브리프를 한 문장으로 압축한다.** `[대상]이 [행동]하게. 느낌은 [형용사 2개].` 이 문장 없이 수집을 시작하지 않는다. - [ ] **1-b. 목표 시장 경계 조건을 쓴다.** 국가/생활권·기기·단위/통화·행동 관습·금지할 외래 문법. R1이 같은 시장인지 표시한다. - [ ] **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·본문 크기**를 본다. 본문이 **1KB 미만이면 파킹 도메인을 의심하라** — 전형적 파킹 페이지는 `/lander` 로 보내는 JS 한 줄뿐이다. - 후보들의 본문이 **바이트 단위로 동일**하면 공통 응답일 수 있다. 파킹이라고 단정하지 말고 제목·본문 정체성·소유자·정본 링크를 확인한다. - 정본 판정 근거는 **콘텐츠 안에서** 찾아라: 저장소 링크, 설치 명령에 적힌 패키지·스킬 이름, 소유자 계정, 문서 제목이 로컬 파일과 일치하는지. - [ ] **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. 결정한다.** 출처 ID → 원칙/조건 → 관찰 → 결정 → 검증 계획을 프로젝트 `design.md` 또는 evidence 기록에 남긴다. - [ ] **9. 필요한 변형과 이유를 적는다.** 변형 개수는 슬롯 수와 무관하다. - [ ] **10. antipatterns.md를 훑고 발견한 후보를 프로젝트 계약과 실제 렌더로 평가한다.** --- ## 4. WebFetch 프롬프트 템플릿 (그대로 복사해서 쓴다) ### 4-A. 원본 사이트 구조 분석 — 가장 자주 쓴다 > 이 페이지의 구조를 분석해줘. 다음을 순서대로 답해라. > 1. 상단부터 순서대로 섹션 목록. 각 섹션의 역할을 한 단어로 붙여라. > 2. h1의 정확한 문장, 그리고 h2 전체 목록. > 3. CTA 문구 전부와 각각이 페이지 어디에 있는지. > 4. 내비게이션 항목 목록. > 5. 이 페이지가 방문자에게 시키려는 우선 행동과, 있으면 보조 행동. 각각이 어디서 어떤 위계로 제시되는지. > 6. 카피의 톤 — 평균 문장 길이, 1인칭/2인칭 사용, 전문용어 밀도. > 7. 숫자나 지표가 사용된 위치와 그 값. > 추측하지 말고 페이지에 실제로 있는 것만 답해라. 없으면 "없음"이라고 써라. ### 4-B. 폰트 확인 (Typewolf 등) > 이 페이지에서 언급된 폰트 이름을 전부 나열해라. 각각에 대해 헤드라인용인지 본문용인지, 유료인지 무료인지, 제시된 무료 대체 폰트가 있으면 그 이름까지 적어라. 페이지에 없는 정보는 지어내지 마라. ### 4-C. 모션 기법 확인 (Eyecandy · Codrops) > 이 페이지에서 설명하는 애니메이션 기법의 이름, 그 기법이 시각적으로 무엇을 하는지, 구현에 쓰인 CSS 속성이나 JS 라이브러리를 나열해라. 코드 예시가 있으면 핵심 부분을 그대로 옮겨라. ### 4-D. 디자인 시스템 토큰 확보 (DesignSystems.one · 공개 시스템 문서) > 이 문서에서 다음을 추출해라. 값이 명시된 것만 적고 없으면 "미공개"라고 써라. > 1. 컬러 토큰 이름과 값 (전체 스케일) > 2. 타입 스케일 — 크기 목록, line-height, 굵기 > 3. 여백 스케일 — 기본 단위와 전체 단계 > 4. border-radius 값 목록 > 5. 그림자 정의 > 6. 모션 duration과 easing ### 4-E. 리디자인 — 현행 사이트 감사 > 이 페이지를 감사해줘. 다음을 답해라. > 1. 섹션 순서와 각 섹션이 실제로 전달하는 정보 > 2. 정보 위계상 가장 강조된 것과, 비즈니스적으로 가장 중요해 보이는 것 — 둘이 일치하는가 > 3. 카피에서 구체적 사실(숫자, 고유명사, 조건)이 들어간 문장과 그렇지 않은 문장의 비율 > 4. 내비게이션 구조와 항목 수 > 5. 페이지에서 명백히 불필요하거나 중복인 섹션 > 추측하지 말고 페이지에 있는 것만 답해라. --- ## 5. computed style 추출 (축 1·2·3·4를 얻는 유일한 방법) WebFetch는 마크다운으로 변환하면서 CSS를 버린다. **그리드·타입스케일·컬러·여백은 WebFetch로 절대 나오지 않는다.** 브라우저 도구(Chrome DevTools MCP / Playwright)로 원본 사이트를 열고 아래를 실행한다. ```js () => { const cs = (el, p) => getComputedStyle(el).getPropertyValue(p); const vis = el => { const r = el.getBoundingClientRect(); return r.width > 0 && r.height > 0; }; const all = [...document.querySelectorAll('body *')].filter(vis); const textEls = all.filter(el => [...el.childNodes].some(n => n.nodeType === 3 && n.textContent.trim().length > 1)); const tally = a => { const m={}; a.forEach(v=>{m[v]=(m[v]||0)+1;}); return Object.entries(m).sort((x,y)=>y[1]-x[1]).slice(0,12); }; const h1 = document.querySelector('h1'); const p = [...document.querySelectorAll('p')].filter(vis).find(el => el.innerText.trim().length > 200); return { // 반드시 첫 줄에 둔다. 페이지가 실행 중 이탈하면 엉뚱한 사이트의 값이 돌아온다. url: location.href, title: document.title, viewport: innerWidth + 'x' + innerHeight, heading: h1 && { size: cs(h1,'font-size'), lh: cs(h1,'line-height'), ls: cs(h1,'letter-spacing'), weight: cs(h1,'font-weight'), family: cs(h1,'font-family').split(',')[0] }, body: p && { size: cs(p,'font-size'), lh: cs(p,'line-height'), color: cs(p,'color'), family: cs(p,'font-family').split(',')[0], widthPx: Math.round(p.getBoundingClientRect().width) }, fontSizes: tally(textEls.map(el => cs(el,'font-size'))), families: tally(textEls.map(el => cs(el,'font-family').split(',')[0].replace(/["']/g,''))), textColors: tally(textEls.map(el => cs(el,'color'))), backgrounds:tally(all.map(el => cs(el,'background-color')).filter(c => c !== 'rgba(0, 0, 0, 0)')), radii: tally(all.map(el => cs(el,'border-radius')).filter(r => r !== '0px')), widths: tally(all.filter(el => el.getBoundingClientRect().width > 500) .map(el => Math.round(el.getBoundingClientRect().width) + 'px')), sectionPadding: [...new Set([...document.querySelectorAll('section, main > div')].filter(vis).slice(0,20) .map(el => cs(el,'padding-top') + ' / ' + cs(el,'padding-bottom')))] }; } ``` **결과 읽는 법** > **먼저 `url` 을 봐라. 열려고 한 사이트가 아니면 나머지 값은 전부 버려라.** > 페이지가 실행 중 이탈하거나 리다이렉트되면 스크립트는 **다른 사이트의 값을 조용히 반환한다.** > 실측에서 2회 연속 발생했다. 이건 실패가 아니라 **오염**이다 — 숫자가 6축 시트에 들어가고, > 3단계 토큰의 근거가 되고, `design.md` 또는 프로젝트 evidence 기록에 출처 ID → 원칙/조건 → 관찰 → 결정 → 검증으로 남는다. `evidence-ledger.md`는 기록 형식을 안내하는 정본이다. - `fontSizes` 상위 항목 = 타입 스케일 후보다. 실제 본문 요소와 화면 위계를 같이 확인한다. - `textColors` 상위 항목 = 텍스트 위계 후보다. 색 수가 아니라 역할·대비·실제 렌더를 본다. - `backgrounds` 최다값 = 지배 배경 후보다. 채도·등장 횟수만으로 강조 역할이나 면적을 단정하지 않는다. - `radii` 종류 수 = 형태 어휘를 살필 출발점이다. 수가 아니라 토큰 역할과 화면 밀도로 평가한다. - `widths` 최다값 = 컨테이너 폭. `body.widthPx` = 텍스트 컬럼 폭. 브라우저 도구를 못 쓰는 환경이면 **6축 중 4개가 빈칸이라는 사실을 산출물에 명시**하고 넘어간다. 채운 척하지 마라. --- ## 6. 하지 말아야 할 것 - **갤러리 홈페이지만 fetch하고 "레퍼런스를 봤다"고 말하기.** 갤러리 홈은 카드 이미지뿐이라 정보가 0이다. **반드시 원본 사이트를 연다.** - 레퍼런스 이름만 나열하고 넘어가기. 6축 수치가 없으면 참고한 게 아니다. - **WebFetch만 하고 6축을 채웠다고 하기.** WebFetch는 축 6과 카피 톤만 준다. 나머지는 §5가 필요하다. - 하위 페이지 URL의 slug를 추측하기. 인덱스에서 `href`를 뽑아라. - R1·R2·R3를 같은 갤러리에서 고르기. - 6축 시트에 "세련됐다", "깔끔하다" 같은 형용사 적기. --- ## 6. 산출물 형식 (필수) 레퍼런스 조사 단계는 **아래 블록을 출력하기 전까지 완료되지 않는다.** 다음 단계로 넘어가지 마라. ```markdown ## 브리프 [대상]이 [행동]하게. 느낌은 [형용사 2개]. ## 목표 시장 - 지역/생활권: - 기기/단위/통화: - 행동 관습: - 금지할 외래 문법: ## R1 · 구조 — <출처 ID> <이름> <원본 URL> - 가져올 축: 그리드, 여백 리듬 - 원칙/조건: - 관찰: - 결정: - 검증 계획: - 그리드: 관찰한 최대폭 / 비대칭 또는 대칭 관계 / 거터 - 여백: 관찰한 단위 / 섹션 간 / 요소 간 / 관계 - 6축 밖의 관측: (있으면) 카피 규범, 증거 제시 방식, 반복 노출 규칙 등 - 변형: 최대폭을 1120으로 축소 — 본문 한 줄이 국문 40자를 넘었기 때문 ## R2 · 톤 — <출처 ID> <이름> <원본 URL> [업종/매체 선택 조건:] - 가져올 축: 컬러 역할, 타입 스케일 - 원칙/조건: - 관찰: - 결정: - 검증 계획: - 컬러: 관찰한 역할 단계와 면적 관계 - 타입: 관찰한 서체 역할·단계 관계·최대/본문 비율 - 6축 밖의 관측: (있으면) 신뢰를 만드는 방식, 제품을 보여주는 방식 - 변형: 비율을 1.25로 조정 — 정보량이 많아 중간 단계가 필요 ## R3 · 디테일 — <출처 ID> <이름> <출처 URL> - 가져올 축: 모션 언어 (R3는 이 축만 채운다) - 원칙/조건: - 관찰: - 결정: - 검증 계획: - 모션: 스크롤 진입 시 8px 상승 + 페이드, 320ms, ease-out - 구현 제약: 브라우저 지원 / JS 비용 / 보간 조건 - 변형: 280ms로 단축 — 페이지가 길어 반복 노출이 잦음 ## 회색조 위계 가장 강한 덩어리는 ___, 두 번째 ___, 세 번째 ___. 비즈니스 우선순위 [1 ___ / 2 ___ / 3 ___]와 일치한다. ## 안 할 것 - (antipatterns.md에서 이 브리프에 특히 위험한 후보와 그 이유) ``` **검증 조건** — 사용한 슬롯마다 다음을 채운다. - 사용한 슬롯은 **원본 사이트 URL**이 있다 (갤러리 URL 아님) - 목표 시장 경계 조건이 있고 R1의 시장 일치 여부가 적혀 있다 - R2의 업종 또는 매체 선택 조건이 적혀 있다 - 각 슬롯에 **가져올 축**, 출처 ID → 원칙/조건 → 관찰 → 결정 → 검증 계획이 명시되어 있다 - 필요한 변형과 그 이유가 적혀 있다 - 6축은 실측값 또는 관찰 가능한 규칙으로 채웠고, §5를 못 실행했다면 어느 축이 빈칸인지 명시했다 - R3를 썼다면 **구현 제약**(지원 범위·JS 비용)이 적혀 있다 - 회색조 위계가 비즈니스 우선순위와 일치한다 > 근거: research/references/02-methodology.md (조사일 2026-08-20)