designpaca/apps/site/design.md
Yun Chan 9648d1d82a 소개 페이지를 스킬 전체 경로로 다시 만들고, 배운 것을 스킬에 반영
방향을 글래스로 바꿀 때 2단계 재결정을 하고도 전체 경로로 올리지 않았다.
레퍼런스 없이 재질만 갈아끼운 결과가 스위스 미니멀 뼈대에 유리를 바른
페이지였고, design.md 는 초판 결정을 그대로 담고 있었다. 0단계부터 다시 돌았다.

1단계 — 레퍼런스 3개를 computed style 까지 실측
  R1 zed.dev      컨테이너 1120px 과 전체폭이 교대 · radius 2px 621회
  R2 lusion.co    3D 는 액자 안, 텍스트는 액자 밖 · 배경 흰색 · h1 36px
  R3 Codrops      DOM 이 구조를 소유하고 WebGL 은 uniform 만 만진다

2단계 — 프리셋 swiss-minimal → dark-instrument, 컨셉 "검사대 위의 물체"
        유리는 액자에만 남긴다(헤더 · 검사대 · 명령창)

4단계 — 히어로 재구성. 캔버스를 배경에서 빼 액자 안으로, 텍스트는 밖으로
        판독기가 통과한 게이트를 표시한다(값이 바뀔 때만 DOM 을 쓴다)
        파이프라인을 2열로 열어 625px → 1113px

5단계에서 실제로 걸린 것
  게이트 3  radius 4종 → 2종 (3px / 14px, pill 제거)
  게이트 1  base.css 토큰 밖 rgb() 7곳 → 토큰
  게이트 7  헤더 English 2.59:1 → ink 로 상향
  카운트    히어로 h1 4줄 → 2줄
  셰이더    판이 정면이라 프레넬이 구조적으로 0. 법선을 굽히고 UV 로 테두리
  셰이더    gl_FragCoord 를 렌더 타겟 크기로 나눠 UV 가 1 을 넘고 있었다
  수치      페이지가 실은 "타입 단계 5단계"가 실측 9종이었다. lang 속성이
            스케일을 재정의해 링크 하나가 16px 로 새고 있었다
  측정      대비 스크립트가 반투명 배경을 불투명으로 계산했다. 알파 합성으로 교정

스킬 반영
  three.md    §0-A 배치 원리(3D 는 액자 안) · 프레넬 0 함정 · gl_FragCoord 함정
  preflight.md 대비 측정 시 알파 합성. 검사 도구가 틀리면 통과도 의미가 없다

최종: 하드 게이트 12/12, 대비 실패 0, 320px 오버플로 0, 테스트 22개 통과
2026-08-20 13:33:28 +09:00

12 KiB

design.md — designpaca 소개 페이지

6단계 산출물. 다음 실행(사람이든 에이전트든)은 이 파일을 먼저 읽고 같은 결정을 이어간다.

개정 이력

날짜 무엇이 바뀌었나
2026-08-20 초판 swiss-minimal · three.js 미사용 · 라이트 기반
2026-08-20 2판(현행) dark-instrument · three.js 채택 · 전체 경로 재주행

초판이 거짓말이 됐던 경위를 남긴다. 사용자가 "글래스모피즘·리퀴드글래스·히어로에 힘"을 요청했을 때 그것은 2단계 방향 재결정이었고, 스킬은 그럴 때 전체 경로로 올려 1단계부터 다시 돌라고 씌어 있다. 그러지 않고 4단계 구현으로 바로 들어갔다. 레퍼런스 없이 재질만 갈아끼운 결과가 스위스 미니멀 뼈대에 유리를 바른 페이지였고, design.md 는 초판 상태로 남아 프리셋·이펙트·형태 수치가 전부 어긋났다. 2판은 0단계부터 다시 돌았다.


브리프 3줄

  • 무엇을: designpaca 소개 페이지. 파이프라인 스킬 + npx 설치 CLI 를 소개하는 단일 페이지, 한국어·영어 두 판
  • 누구에게: Claude Code · Codex · Cursor 를 쓰는 개발자. 이 페이지를 보고 npx designpaca 를 터미널에 치게 만드는 것이 목표
  • 제약: Astro 정적 → Cloudflare Pages. 이 페이지 자체가 스킬의 품질 증거물이다 — 스킬이 금지하는 것을 이 페이지가 하면 안 된다

레퍼런스 (전부 실측. computed style 추출까지 돌렸다)

슬롯 사이트 업종 실측값 가져온 원리 가져오지 않은
R1 · 구조 zed.dev 코드 에디터 컨테이너 1120px(68회) ↔ 전체폭 1425px(50회) 교대 · 본문 칼럼 512px · radius 2px 가 621회 · 모노 524회로 지배 폭의 교대, 각진 형태 어휘, 모노를 정체성으로 세리프 h1(우리는 한글) · 최대÷본문 3.0배(위계가 약하다) · 섹션 11개
R2 · 톤 lusion.co 3D 프로덕션 스튜디오 배경 흰색 · 텍스트 색 2단계(검정 135 / 흰 16) · 폰트 1개(Aeonik) · 강조색 rgb(0,22,236) 4회 · 캔버스는 radius 15px 액자 안 · h1 이 36px 3D 는 액자 안, 텍스트는 액자 밖. 3D 가 크면 타이포는 물러난다. 색은 캔버스 안에서만 소리친다 흰 배경 자체 · 파랑
R3 · 디테일 Codrops "Inside HAOQI.DESIGN" 축 5 전용 DOM 이 구조를 소유하고 WebGL 은 셰이더 uniform 만 만진다. 한 rAF 에서 스크롤을 공유하고 뷰포트 밖에서는 정지 R3F/Lenis 스택

R3 구현 제약: 셰이더 uniform 만 갱신하므로 transform/opacity 외의 CSS 를 애니메이션하지 않는다(게이트 #8 안전). 뷰포트 밖 렌더 정지가 필수 조건이다.

접근 실패 기록iglooinc.com 은 hugedomains 파킹으로 302, lasvit.com 은 403. reference-method.md §3-b 가 경고한 그대로였다. 왕복 세 번에서 끊고 우회했다.

한 문장 컨셉

검사대 위의 물체. 액자가 게이트고, 안에 든 것이 검사 중인 디자인이고, 밖의 글자가 판정 기록이다.

프리셋 — dark-instrument

초판의 swiss-minimal 에서 바꿨다. 페이지가 이미 어둡고 제품이 CLI 다. 초판에는 이 재질을 정당화하는 프리셋이 아예 없었다 — 그것이 "유리를 발랐는데 유리일 이유가 없다"의 원인이다.

프리셋은 "글래스모피즘은 내비게이션 바 정도까지"라고 반대한다. 사용자의 명시적 지시가 프리셋보다 위이므로 없애지 않고 의미가 생기는 자리로 옮겼다: 유리는 액자에만 쓴다 — 헤더 · 검사대 프레임 · 명령창. 콘텐츠 카드(브리프, 조판 데모)에서는 뺐다. 유리는 무언가를 담을 때만 의미가 있다.

감수한 리스크 — 하나

히어로에서 거대 타이포를 버리고 힘을 3D 액자로 넘긴다. 초판 히어로의 --display 는 최대 112px 로 화면 높이의 절반을 먹었고, 그 아래 캔버스가 깔려 있었다. R2 의 h1 은 36px 인데 히어로가 압도적이다 — 힘이 타이포가 아니라 물체에서 나오기 때문이다. 현행 히어로 h1 은 clamp(var(--step-2), 1.1rem + 2.4vw, var(--step-4)), 최대 41.5px 다. 페이지에서 가장 큰 글자(96px)는 히어로가 아니라 수치 섹션에 있다 — R2 도 그렇다.

토큰

src/styles/tokens.css 전문. 초판에서 바뀐 것만 적는다.

  • radius 2종: --radius-sm: 3px(요소) · --radius-frame: 14px(액자). 근거는 R1 의 2px(621회)과 R2 의 15px. 999px pill 3곳을 없앴다 — 계기판에 알약은 없다
  • --glow-2: #6E7BFF#3D7BD6. 앞의 값은 R 이 높아 보라-파랑으로 읽힌다. antipatterns.md 의 슬롭 지문이자 dark-instrument 가 "어두운 배경일수록 빠지기 쉬운 함정"으로 지목한 색이다
  • 유리 색값을 전부 토큰으로: --glass-sheen · --glass-rim · --core-hi. base.css 에 흩어져 있던 rgb(255 255 255 / …) 7곳이 하드 게이트 #1 위반이었다
  • 이중 베젤(.shell/.core) 폐기 → 단일 .frame. 껍데기와 속의 radius 가 서로 달라 그것만으로 형태 어휘가 두 종 늘어난다
  • --step--1: 0.8125rem 추가. 게이트 판독기가 스케일 밖 13px 을 쓰고 있었다
  • 강조색은 여전히 딥 틸 하나. 라이트/다크 쌍(--accent / --accent-inverse)은 규칙으로 정의된 반전이라 1종으로 센다

타입 스케일 실측: step--1 ~ step-46단계, --display(96px)는 스케일 밖, 모노는 본문의 0.9375배 파생. 최대÷본문 = 5.6배. 초판 페이지는 "5단계"라고 실었는데 실측은 9종이었다 — 아래 8·9번 참조.

성능 — 예산과 실측

예산을 올렸고, 올렸다고 말한다. 초판 예산은 히어로까지 JS 50KB 였다. 이 페이지는 three.js 를 파는 제품의 데모이므로 그 판단을 검증할 수 있어야 한다.

예산 숫자 자체를 한 번 고쳤다. 처음 three.js 예산을 160KB 로 적었는데 실측이 184KB 였다. three.js 크기는 미리 알 수 있는 값이므로 이건 예산 설정 실패다. 190KB 로 고쳤고, 사후 조정이라는 사실을 남긴다. 실측을 보고 예산을 맞추는 것은 예산이 아니다 — 다음 실행은 여기서부터 시작해야 한다.

항목 예산 실측 판정
히어로까지 JS, 초기 (gzip) 50KB 복사 버튼 314B + 씬 부트 통과
three.js, 지연 로드 (gzip) 190KB 184KB (동적 import(), IntersectionObserver 로 화면에 들어올 때만) 통과
첫 인터랙션 2초 미측정 배포 후 Lighthouse
LCP / CLS 2.5초 / 0.1 미측정 배포 후

WebGL 게이트: prefers-reduced-motion 이면 아예 시작하지 않는다. DPR 1.5 클램프. hardwareConcurrency <= 4 면 판을 6장에서 3장으로 줄인다. 탭이 숨거나 화면 밖이면 그리지 않는다.

채택한 이펙트와 폴백

이펙트 구현 폴백
검사대 3D 유리판 6장이 깊이 축에 서고 카메라가 스크롤로 통과. 굴절은 렌더 타겟 1장 샘플링(transmission 재질보다 훨씬 싸다) 캔버스 아래 CSS 그라디언트가 폴백이 아니라 결과물이다. 액자·판독기·캡션은 그대로 남는다
게이트 판독기 통과한 판이 바뀔 때만 DOM 을 쓴다. 프레임마다 쓰지 않는다 JS 없으면 게이트 01 / 06 정적 표시
복사 버튼 인라인 314B 클립보드 실패 시 텍스트를 선택 상태로 만든다

5단계에서 실제로 걸린 것

정적 검사와 실렌더를 둘 다 돌렸다. 걸린 것을 전부 적는다 — 유리한 것만 고르면 리스크가 자기 홍보가 된다.

  1. 하드 게이트 #3 위반 — radius 4종(sm/md/shell/999px). 2종으로 정리
  2. 하드 게이트 #1 위반base.css 에 토큰 밖 rgb() 7곳. 토큰으로 올림
  3. 하드 게이트 #7 위반 — 헤더 "English" 버튼 2.59:1. --ink-muted--ink 로 올려 통과
  4. 카운트 규칙 위반 — 히어로 h1 이 4줄이었다(상한 2줄). 폰트 크기를 낮춰 2줄
  5. 셰이더 결함 — 판이 정면으로 서 있어 dot(n, view) ≈ 1, 프레넬이 구조적으로 0이었다. 유리로 읽히게 하는 유일한 신호가 죽어 있었고 그것이 "그냥 흐릿한 사각형"의 원인이다. 법선을 미세하게 굽히고 UV 경계로 테두리 광을 따로 만들어 해결
  6. 셰이더 UV 오류gl_FragCoord 를 렌더 타겟 크기(캔버스의 0.6배)로 나누고 있었다. UV 가 1 을 넘어 텍스처가 잘렸다. getDrawingBufferSize() 로 교정
  7. 폭 리듬 부재 — 9개 섹션 중 파이프라인이 1440px 중 625px(43%) 만 쓰면서 높이는 1637px 로 가장 길었다. 페이지의 본체가 가장 좁았다. 2열로 열어 1113px
  8. 페이지가 실은 수치가 틀렸다 — "타입 단계 5단계" 라고 실었는데 실측 9종이었다. 이 페이지의 리스크가 "자기 수치를 공개한다" 인데 공개한 값이 틀리면 리스크가 아니라 허위다
  9. lang 속성이 타입 스케일을 새게 했다 — 언어 전환 링크에 lang="en" 이 붙어 있고(스크린리더가 "English" 를 영어로 읽어야 하므로 옳다) [lang] 셀렉터가 스케일을 통째로 재정의해 그 링크만 16px 이 됐다. 접근성 표시가 조용히 디자인 토큰을 바꾸고 있었다. 크기는 헤더에서 확정하고 링크는 상속만 받게 고쳤다

측정 스크립트 자체의 오류도 한 번 있었다. 대비 계산에서 반투명 배경을 불투명으로 취급해 "English 1.15:1" 이라는 틀린 값이 나왔다. 알파를 합성하도록 고친 뒤 실패 0건. 검사 도구가 틀리면 통과도 실패도 의미가 없다.

최종 판정 (1440px · 320px 실렌더)

  • 하드 게이트 12개 전부 "아니오"
  • 대비: 본문·링크·버튼 전 요소 AA 이상, 실패 0건
  • 320px: 가로 스크롤 없음(문서 폭 305px), 뷰포트 초과 요소 0, 버튼 줄바꿈 0
  • 카운트: 섹션 9 / eyebrow 3(상한 ceil(9/3)=3) / 마퀴 0 / 히어로 헤드라인 2줄 / radius 어휘 2종 / 반투명 패널 2개
  • 슬롭 지문 grep: 0건

의도적으로 하지 않은 것과 그 이유

  • "Anti-Slop" 이라는 명명 — tasteskill 이 쓰는 말이다. 같은 단어를 쓰면 즉시 아류로 읽힌다
  • 경쟁 제품의 실측치를 페이지에 싣기 — 남의 수치는 반박 가능하다. 우리 수치만 쓴다
  • GitHub 스타 등 인기 지표 — 우리는 숫자가 0이다. 인기 대신 규율을 증거로 쓴다
  • 3D 위에 본문 얹기 — R2 가 준 원리의 핵심이다. 액자 위에 얹는 글자는 판독기 하나뿐이고, 그것도 바탕을 깔았다
  • GLB 모델 — 조사 결과 추상 지오메트리가 이 브리프에서 더 낫다. 모델 하나가 수 MB 이고, 우리가 파는 것은 모델이 아니라 절차다
  • 다크를 "멋있어서" 고르기 — 프리셋이 다크 기본값을 슬롭 시그니처 1위로 지목한다. 제품이 터미널이라는 근거로 고른다
  • 언어 자동 리다이렉트 / 국기 아이콘 — 사용자를 놀라게 하고, 언어는 국가가 아니다
  • 두 판을 번역으로 만들기 — 각 언어판을 따로 썼다

다음 실행이 해야 할 일

  1. 배포 후 Lighthouse 로 첫 인터랙션·LCP·CLS 를 재고 "미측정" 을 채운다. 채우기 전까지 비워둔다
  2. 폰트를 CDN 의존에서 자체 호스팅으로 옮길지 판단한다 (현재 jsDelivr · Fontshare · Google Fonts 3곳)
  3. OG 이미지가 없다
  4. 섹션이 9개, 총 높이 11,197px 이다. 스크롤 보상이 충분한지 재검토할 여지가 있다

2026-08-20 · 2판. 0~6단계 전체 경로 재주행.