- ZCode(~/.zcode/skills) 타깃 추가
- 중립 경로 agents(~/.agents/skills · .agents/skills) 타깃 추가
- gemini-cli(.gemini/skills)·copilot(~/.copilot/skills · .github/skills) 타깃 추가
- Cursor·Windsurf 를 네이티브 스킬 경로로 전환 — 규칙 파일 12,000자 상한 때문에
Windsurf 는 실제 스킬이 아예 설치되지 못했었다. 전역 설치도 가능해진다
- Antigravity 전역 경로를 공식 문서대로 ~/.gemini/antigravity-cli/skills 로 수정
실제로 한 페이지를 만들어 보고 드러난 것들이다.
0단계 인터뷰에 두 축을 더한다.
- 브랜드 색: 꽃집 작업에서 색을 묻지 않고 레퍼런스 실측 평균으로 정했다.
결과는 좋았지만 브랜드 색이 있었다면 그걸 무시한 작업이 된다.
"없다"는 답도 답이고, 그때는 피해야 할 색을 묻는다.
- 좁은 화면 내비: 항목 수는 0단계에 이미 정해져 있는데 구현에서 발견했다.
2~4개는 쌓고, 5~6개는 가로 스크롤, 7개 이상만 여는 메뉴다.
넷인데 햄버거를 쓰면 탭 한 번을 공짜로 뺏는 것이다.
4-0 이미지 조달 단계를 새로 만든다(references/images.md).
자리를 만들기 전에 무엇을 실을지 정한다. codex 설치와 auth_mode 를 확인해
생성 경로를 쓰고, 생성물이라는 사실을 design.md 에 남긴다.
래퍼 실패 대응을 기록했다 — codex-cli 0.147.0 은 base64 를 돌려주지 않고
~/.codex/generated_images/<session>/exec-<id>.png 로 저장한다. 공식 래퍼는
"image_gen 이 호출되지 않았다"며 실패하지만 파일은 멀쩡히 있다.
실측에서 이 메시지를 보고 두 번 다시 만들었고 두 번 다 이미 있었다.
싣기 전 최적화도 넣었다(실측 10.1MB → 603KB).
구현에서 넘어진 것 셋.
- images.md: <img width height> 를 적으면 그 height 가 계산된 높이가 되어
aspect-ratio 가 조용히 무시된다. computed 는 "3 / 4" 로 멀쩡히 보이고
실제 높이는 원본 1448px 이었다. height:auto 한 줄로 10.9 화면이 7 화면이 됐다.
- antipatterns.md: "컨트롤이 2줄로 접히나" 를 개별 높이로 재서 거짓 통과했다.
링크는 한 줄짜리였고 줄바꿈된 것은 컨테이너였다(top 46/77).
행 수는 높이가 아니라 top 값의 종류로 센다.
- typography.md: 세로쓰기에 가로쓰기 자간(0.14em)을 물리면 글자 사이 세로
간격이 되어 낱글자가 흩어진다. 한글은 자소가 모여 한 글자라 특히 심하다.
- layout.md: 그리드 구조를 바꾸면 미디어쿼리도 같이 다시 써야 한다.
넓은 화면은 멀쩡했고 390px 에서 헤드라인이 6줄이 됐다.
Antigravity 에서 스킬로 인식되지 않는다는 제보를 받고 확인했다.
설치 경로가 없었던 것이 원인이다.
공식 문서 기준 경로:
워크스페이스 <root>/.agents/skills/<이름>/
전역 ~/.gemini/config/skills/<이름>/
.agents/skills 는 특정 제품 경로가 아니라 중립 경로라, 같은 규약을 쓰는
다른 하네스도 함께 읽는다. SKILL.md 구조(프론트매터 + references/)가
Claude Code 와 같아서 변환 없이 그대로 복사하면 된다.
프론트매터 요구사항도 맞는 것을 확인했다 — description 필수, name 선택.
우리 SKILL.md 는 둘 다 갖고 있다.
- targets/antigravity.ts 추가, 설치 대상 5 → 6종
- 하위호환 경로(.agent/skills, 단수)는 감지에만 쓰고 설치는 복수형에만 한다.
두 곳에 깔면 스킬이 두 번 잡힌다
- 테스트 2개 추가: 범위별 경로, 변환 없이 싣는지 (테스트 25 → 27개)
- 소개 페이지 설치 대상 목록에 반영
세 가지를 고친다. 전부 실제 사용에서 드러난 것이다.
1) 0단계에서 가정으로 채우던 것을 인터뷰로 바꾼다
"꽃집 사이트 만들어보자"를 받고 업종 성격·목표 행동·톤·이름을 혼자 정했다.
물어보니 넷 중 넷이 달랐다(일상 구독 → 하이엔드 스튜디오, 문의 하나 → 넷 다,
톤 미정 → 에디토리얼, 이름 지어냄 → 목요일의 화원).
그대로 갔으면 레퍼런스 세 개를 전부 틀린 방향에서 골랐다.
SKILL.md 0단계에 질문 도구로 한 번에 묻는 절차를 넣었다. 무엇을 묻고
무엇을 묻지 않는지, 답이 모순될 때 어떻게 정리하는지까지 적었다.
2) 레퍼런스가 막히면 브라우저를 띄운다
Aesop(403) → Kinto(404) → Hasami(DNS) → MUJI(타임아웃)로 네 번 왕복하고
톤 레퍼런스를 하나도 못 얻었다. 좋은 레퍼런스일수록 봇을 막는다.
galleries.md 에 headed 브라우저로 직접 열어 스크린샷과 실측값을 받는
방법을 넣고, 접근 실패 2회면 바로 전환하도록 규칙을 세웠다.
Playwright 를 선택 의존성으로 잡았다(core/tools.ts).
- 온보딩 마지막에 설치 여부를 묻는다. 건너뛰어도 스킬은 동작한다
- `designpaca tools` 로 상태 확인, `--yes` 로 설치
- 수백 MB 라 --yes 없이는 상태만 보여준다
- MCP 서버는 설치만 하고 등록 명령은 안내만 한다(에이전트 설정을
대신 건드리지 않는다)
3) 온보딩 말투
"이제 브리프를 던져라", "설치해라", "건너뛴다" — 사용자를 향한 문구가
명령조였다. 스킬 문서의 단정한 반말은 의도지만 CLI UI 는 다르다.
전부 존댓말로 바꾸고, 각 단계가 왜 필요한지 설명을 붙였다.
명령조가 다시 섞이지 않도록 검사하는 테스트를 넣었다(테스트 22 → 25개).
진행도를 섹션 높이로 재고 있어서, 여섯 게이트를 다 돌리려면 정거장 목록 뒤에
화면 절반이 넘는 빈 공간(558px)이 필요했다. 콘텐츠가 아니라 스크롤 연료였고
화면에서는 그냥 큰 빈칸으로 보였다.
진행도를 목록이 화면을 지나는 구간으로 바꿨다.
start = 뷰포트 70% 지점에 목록 위쪽이 닿으면 0
end = 뷰포트 30% 지점을 목록 아래쪽이 빠져나가면 1
travel = 목록 높이 + (start - end)
뷰포트의 40% 가 구간으로 더해지므로, 목록 963px 이 1323px 구간이 되고
게이트당 220px 이다. 여백을 다 지우고도 과민 반응 기준(200px)을 넘긴다.
motion.md 에 "스크롤 구간이 모자라면 여백이 아니라 진행도 공식을 고쳐라" 를
기록했다.
데스크톱만 보고 고쳐서 좁은 화면의 위계가 사라져 있었다.
h1 만 vw 에 비례해 줄고 h2 는 고정 스케일이라 둘이 만난다.
1440px 65.4 / 33.2 = 1.97 배
1024px 52.5 / 33.2 = 1.58 배
390px 35.2 / 33.2 = 1.06 배 ← 사실상 같은 크기
하한을 3rem(48px, h2 의 1.45 배)으로 올려 전 구간을 확보했다.
320 / 390 / 768 / 1024 / 1440 에서 1.45 · 1.45 · 1.63 · 1.87 · 2.12 배.
tokens.md 에 "clamp 의 하한은 같이 변하지 않는 값을 기준으로 정한다" 와
최소·중간·최대 폭 세 곳에서 계산해 확인하라는 절차를 기록했다.
페이지에서 가장 중요한 섹션이 가장 짧았다(0.7 화면). 배분이 중요도와 반대다.
- min-height 72dvh → 88dvh. 100dvh 로 채우지는 않는다. 다음 섹션의 머리가
조금 보여야 스크롤할 것이 있다는 단서가 된다.
- h1 41.5px → 65.4px. 섹션 h2 가 33.2px 이라 8px 차이였고, 스케일상 한 단계
위일 뿐 화면에서는 같은 크기로 읽혔다. 처음에 --display(112px)를 썼다가
배경과 싸워 줄였는데 반대쪽 극단까지 갔다. 지금은 h2 의 1.97 배다.
- 저장소 링크를 헤더로 옮겼으므로 히어로에서는 뺐다. 같은 링크가 두 번 나갔다.
tokens.md 에 히어로 h1 은 섹션 h2 의 1.8~2.2 배라는 기준을 기록했다.
앞선 커밋에서 "backdrop-filter 체인에서 displacement 가 안 먹는다" 고 적고
데모를 뺐다. 틀렸다. svg-filters.md 에 이미 적혀 있던 두 규칙을 안 지킨 것이다.
- 변위 지도는 노이즈가 아니다. feTurbulence 로 만들면 값이 중립(128)으로
수렴해 scale 을 아무리 키워도 곱해지는 값이 0 이다.
- feImage 의 크기는 요소 크기와 같아야 한다. 자동으로 안 맞춰준다.
가장자리에서 안쪽으로 미는 그라디언트를 직접 그렸다. linearGradient 한 장으로는
R 과 G 를 따로 못 만들므로 지도를 두 장 놓고 displacement 를 두 번 건다.
쓰지 않는 축에는 128 고정인 B 채널을 물려 이동량을 0 으로 만든다.
실측: 평균 채널차 1.66(난류 지도) → 9.29(그린 지도), 최대 126.
배경에 격자를 깔아 확인했다 — 패널 가장자리에서 격자 셀이 눌린다.
svg-filters.md 에 지도 두 장 기법과 확인 방법을 기록했다.
푸터를 없애라는 지시가 반영돼 있지 않았다. .install-colophon 이 사실상
푸터였고, .install-grid 밖에 있어 padding-inline 을 못 받아 화면 왼쪽 끝에
붙어 있기까지 했다. 제거하고 저장소 링크는 헤더 nav 로 옮겼다.
재료 섹션은 "필터로 질감 만들기"(그레인/굴절/듀오톤)였고 화면에서 아무 말도
하지 않았다. 실무에서 손이 줄어드는 자리로 바꾼다.
- 글자 모양대로 생기는 스크림 — 흰 글자 대비 1.70:1 → 4.79:1 (AA 통과)
- 색각 이상 시뮬레이션 — 상태 배지 셋의 최소 색거리 82 → 2
- 구이(gooey) — 가로로 세어 덩어리 3개 → 1개
세 값 모두 화면을 캡처해 잰 것이다. 처음에는 데모보다 카피를 먼저 썼고,
그 결과 "2.1:1 → 12.4:1" 같은 재지 않은 숫자가 페이지에 실렸다. 전부 교체했다.
backdrop-filter 굴절 데모는 뺐다. feTurbulence 를 변위 지도로 써서 지도가
중립값(128)으로 수렴했고, scale 을 120 까지 올려도 채널차 2.96 이었다.
svg-filters.md 에 "변위 지도는 노이즈가 아니다" 라고 이미 적혀 있었는데
쓰기 전에 읽지 않았다.
섹션 끝의 note 도 삭제했다. color-interpolation-filters 를 명시했다는
문장은 방문자가 그것으로 할 수 있는 일이 없는 내부 자랑이었다.
스킬 내재화:
- svg-filters.md 실무 레시피 3종(스크림/색각/구이) + 구이가 붙는 문턱 계산
+ feTurbulence 변위 지도 실패 기록
- antipatterns.md 데모를 만들기 전에 카피부터 쓰지 마라
+ Playwright animations:'disabled' 가 끝 프레임을 찍는 함정
제목과 본문이 붙어 있던 문제를 고친다.
- h2{margin:0} + p{margin-top:0} 이라 제목 다음 간격이 0px 이었다.
섹션마다 각자 margin-top 을 붙여 어떤 곳은 0, 어떤 곳은 24px 로 갈려 있었다.
base.css 에서 한 번만 정하고 각 섹션의 margin-top 오버라이드를 걷어냈다.
- :where() 로 감싼 첫 시도는 특이도 0 이라 p 규칙에 져서 무효였다.
특이도를 갖추고 p 뒤로 옮겼다.
- 제목을 .head 로 감싼 수치 섹션은 인접 형제가 끊겨 혼자 0px 이었다.
.head 도 규칙에 포함했다.
파이프라인 정거장 간격이 224px 로 벌어져 목록이 흩어져 보이던 문제도 고친다.
- 읽기 간격과 sticky 스크롤 구간을 같은 값으로 맞추려던 것이 원인이다.
간격은 --stop-pad(space-5)로 되돌리고, 스크롤 구간은 .after 뒤 여백으로 옮겼다.
게이트당 237px 확보 — 과민 반응 기준(200px) 위다.
- 마커 원의 top 이 space-4, 패딩이 space-6 로 따로 적혀 있어 원이 제목보다
24px 위에 떠 있었다. 셋 다 --stop-pad 를 보게 했다.
3D 판 위 본문 대비는 실측 결과 최저 9.83:1 로 AAA 를 넘어 손대지 않았다.
스킬 내재화:
- tokens.md 제목 다음 간격 SSOT, :where() 특이도 함정, 리듬은 지역 토큰으로
- motion.md 읽기 간격과 스크롤 구간은 같은 손잡이가 아니다
- antipatterns.md 재는 도구가 거짓말하는 세 방식
(reveal 중 측정 / sharp stats 가 extract 를 무시 / 눈보다 숫자)
'backdrop-filter 에 SVG 를 얹으면 Chrome 이 선언 전체를 버린다' 고
적어두고 페이지 프리플라이트 로그에까지 실었다. 사실이 아니었다.
Chrome 151 에서 재측정
computed 값이 none 이 아니라 url(#id) 로 유지된다
대비 높은 배경 위에서 실제로 굴절된다(줄무늬가 가장자리에서 압축됨)
진짜 원인은 feImage 의 width/height 를 요소 크기와 맞추지 않은 것이었다.
backdrop-filter 는 필터 이미지를 자동으로 조정하지 않는다.
검색도 다시 했다. feTurbulence grain 에 갇혀 2019년 글만 보고 있었다.
liquid glass 계열 최신 자료를 보니 변위 지도는 노이즈가 아니라
물리 기반 사전계산 이미지였다 — R=X변위, G=Y변위, 128 이 중립,
감쇠는 Squircle 곡선. 캔버스로 즉석 생성하면 240x160 이 2.7KB 다.
스킬 svg-filters.md 에 '리퀴드 글래스' 절을 넣었다.
구조 · 변위 지도 만드는 법 · 함정 넷 · @supports 폴백.
오판 정정도 문서 첫 줄에 남겼다.
한 번 실패한 것을 '안 되는 것' 으로 적으면 그 문장이 다음 사람의
상한선이 된다. 페이지 로그 항목도 그 내용으로 바꿨다.
h2 '라틴 기준으로 만든 도구는 한글에서 멈춘다' 는 무엇이 어떻게 멈추는지
말하지 않았다. 그리고 데모가 그 주장을 증명하지 못했다.
데모가 실제로 실패하고 있었다
word-break: break-all 과 keep-all 을 나란히 두고 '차이는 한 줄뿐'이라고
적었는데, 재보니 줄 수 3 · 높이 87px 로 완전히 동일했다.
어절이 짧아 두 쪽이 같은 자리에서 끊긴 것이다. 차이가 0 인 비교는
증명이 아니라 주장의 반증이다.
개편
h2 -> '라틴 기본값은 한글에서 세 군데가 깨진다'
수치가 데모 개수와 정확히 대응한다
데모 -> 셋으로. 각각 실제로 갈린다
줄바꿈 break-all vs keep-all (긴 어절 + 15rem 고정폭)
행간 1.45 vs 1.75 (높이 74 vs 89)
크기 11px vs 15px (2줄 vs 3줄)
노트도 고쳤다. '로스팅프로파일이 갈린다'고 썼는데 실제로 갈린 건 다른
어절이었다 — 폭에 따라 바뀌므로 어절을 지목하지 않고 현상만 말한다.
스킬 antipatterns.md
'데모가 주장을 증명하는지 재라' 추가.
비교 데모의 높이·줄 수를 실제로 재는 코드와, 차이가 안 날 때의 대처.
지적 세 가지를 전부 확인했고 실제 결함도 하나 나왔다.
1. 재료 섹션 h2 가 아무것도 전달하지 않았다
'표면은 CSS 가 정하고, 공간은 GPU 가 맡는다'
금칙어도 없고 치환 테스트도 통과하는데 독자가 얻는 게 없다.
구현 이야기를 대구로 포장한 것이었다.
-> '텍스처 200KB 를 300바이트가 대신한다'
카피라이팅 방법론(so you can 테스트 / 6~12단어 / 검증 가능한 수치)을
찾아 적용했다. 우리 antipatterns 의 카피 절은 금지 목록뿐이라
이런 문장을 못 잡는다 — 작법 절을 새로 넣었다.
2. 필터 데모가 줄무늬였다
필터가 무엇을 하는지는 보이지만 왜 쓰는지는 안 보인다.
각 필터를 실제로 걸리는 자리로 옮겼다.
그레인 -> 매끈한 그라디언트 (없으면 밋밋하다는 대비)
굴절 -> 글자 (유리 뒤가 실제로 휘는 것)
듀오톤 -> 사진풍 면 (한 팔레트로 묶이는 것)
타일마다 '언제 쓰는가' 한 줄을 추가했다.
3. 그레인 필터가 아무 효과도 못 내고 있었다
feComposite in='SourceGraphic' in2='soft' operator='over' 는
원본을 노이즈 위에 올린다. 노이즈가 통째로 가려진다.
에러도 경고도 없이 조용히 죽는다.
feBlend overlay 로 바꾸고 baseFrequency 0.9 -> 0.62.
섹션 간 검은 띠도 고쳤다. 파이프라인 캔버스가 섹션 패딩(112px) 아래에서
시작해 히어로 배경이 끝난 자리와 사이에 200px 이 비었다.
스킬
antipatterns.md 카피 작법 — 금지 목록만으로는 못 잡는 실패
svg-filters.md 데모는 실무 소재에 · feComposite 입력 순서 함정
나스를 찾았다 — Tailscale 의 yunchan-nas (100.116.83.60 / LAN 192.168.0.39),
Synology DS420+. SSH 키(id_ed25519)로 이미 붙어서 비밀번호가 필요 없다.
Forgejo 구성
컨테이너 kd-forgejo (codeberg.org/forgejo/forgejo:11) + postgres:16-alpine
웹 3000 -> Cloudflare 프록시로 https://git.chanpaca.net
git SSH 2222 -> 컨테이너 내부 22
중요: git.chanpaca.net 은 Cloudflare 뒤라 22/2222 가 둘 다 막혀 있다.
오리진 IP 를 감추는 정상 구성이고, 그래서 git push 는 도메인이 아니라
Tailscale 주소로 해야 한다. remote 를 그렇게 걸었다.
SSH 키가 이미 Forgejo 에 등록돼 있다(encep-win, yunchan 계정).
push 에 토큰도 비밀번호도 필요 없다.
배포 전 검증
전체 빌드 통과 · 테스트 22개 통과
tarball 114.5KB / 22개 파일, 스킬 19개 포함
실제 npx 설치 왕복: install 19개 -> doctor 정상 -> 드리프트 감지 ->
update 가 수정 파일 보존 -> uninstall 후 잔여 0
배포 직전에 결함 하나를 잡았다. Windows 에서 작업해 스킬이 전부 CRLF 로
저장돼 있었고, 그대로 tarball 에 들어가면 SKILL.md 의 YAML 프론트매터를
파서에 따라 못 읽는다. 번들 스크립트에서 LF 로 정규화하고
.gitattributes 도 넣었다. 배포물은 어느 OS 에서 만들든 같아야 한다.
푸터 제거
출처가 사라지지 않게 설치 섹션 끝에 한 줄만 남겼다(저장소 · MIT).
회전 테두리
conic 의 각도를 @property 로 돌리면 매 프레임 배경을 다시 칠한다 —
컴포지터에서 못 돌고 메인 스레드가 페인트한다(하드 게이트 8).
정사각형 원뿔 레이어를 마스크 안에서 rotate 시켰다. transform 만 움직인다.
aspect-ratio: 1 이라야 회전 중 밝기가 일정하고,
width: 200% 라야 1178x52 헤더에서 모서리까지 닿는다. 주기 11초.
three.js 모바일
세로 화면에서 게이트가 통째로 안 보이고 있었다.
수직 시야는 화면 비율과 무관하지만 수평 시야는 aspect 에 비례한다.
데스크톱(2.5:1)에서 정한 판 폭 15 가 세로 화면(0.45:1)의 수평 시야
2.5 에 비해 여섯 배라, 첫 판이 화면을 완전히 덮었다.
fit() 에서 camera.aspect 를 갱신할 때 판의 scale.x 도 같이 잡는다.
저사양 판정도 고쳤다. hardwareConcurrency <= 4 만 보면 요즘 폰이 전부
고사양으로 잡힌다(8코어가 흔하다). innerWidth < 760 을 함께 본다.
DPR 1.5 -> 1.25, 캔버스 불투명도 0.7 -> 0.45(세로는 화면 전체를 덮는다).
스킬
svg-filters.md 테두리 광 회전은 각도가 아니라 정사각형 레이어 rotate
three.md 지오메트리를 화면 비율에 맞춰 다시 잡아라
저사양 판정에 화면 폭을 넣어라
헤더 헤어라인이 변마다 끊겨 보였다. conic-gradient 는 중심에서 각도로
도는데, 1180x54 처럼 납작한 형태에서는 각도가 급변해 긴 변에서 색이
거의 안 변하고 짧은 변에서 한꺼번에 바뀐다. 실제로 아래쪽만 절반 밝았다.
linear-gradient(100deg) 로 바꾸니 네 변이 같은 그라디언트를 공유해
테두리를 따라 이어진다. 마스크로 1px 만 남기는 구조는 그대로다.
얕은 글로우를 더했다 — 0 0 22px -8px 에 강조색 42%.
음수 spread 라 형태 밖으로 새지 않는다.
밝은 밴드에서는 흰빛 대신 그림자로 뒤집는다.
스킬 svg-filters.md 에 "유리 테두리를 그릴 때" 추가.
비율을 보고 conic/linear 를 고르라는 기준과 음수 spread 글로우.
게이트 씬을 파이프라인으로 옮기면서 히어로에도 남겨뒀더니 같은 그림이
페이지에 두 번 나왔다. 역할이 다르면 씬도 달라야 한다.
히어로 shader-plane 흐름 필드 노이즈를 두 번 접어 빛의 결을 만든다
공간을 만드는 재질. 아무것도 반응 안 한다
파이프라인 gate-scene 유리판 여섯 통과하면 그 단계가 켜진다. 주인공
재료 shader-plane 스테이지 필터 타일이 앉는 무대
히어로에는 무거운 씬을 임포트하지 않는다 — three.md §0 대로 셰이더 플레인 하나다.
lib/hero-scene.ts -> lib/gate-scene.ts 로 리네임했다. 이름이 용도와 다르면
다음 사람이 히어로 것인 줄 알고 고친다.
대비 실측: 캔버스 배경 최악 8.46:1(가장 밝은 중앙 여백), h1 자리 14.83:1.
readPixels 로 재려다 전부 0 이 나왔다 — preserveDrawingBuffer: false 면
버퍼가 비어 있다. 스크린샷 픽셀로 쟀고, 글자 없는 영역만 골랐다.
스킬 three.md
씬을 두 자리에 재사용하지 마라. 역할(주인공/재질/무대)로 나눠라
파일 이름을 용도와 맞춰라
WebGL 위 대비는 readPixels 가 아니라 스크린샷 픽셀로 잰다.
0 을 검정으로 착각하면 대비가 통과한 것처럼 보인다
"스크롤할 때 이미지가 고정되어 원경처럼 보이는 게 패럴랙스의 꽃"이라는
지적이 맞았다. 느리게 같이 움직이는 것으로는 그 인상이 안 나온다 —
속도만 다를 뿐 방향이 같기 때문이다.
고정 배경
background-attachment: fixed 는 iOS Safari 가 GPU 메모리 때문에
throttle 해서 스크롤 중 배경이 튄다. 쓰지 않았다.
섹션에 clip-path: inset(0) 을 걸어 position: fixed 의 컨테이닝 블록으로
만들었다. 배경이 화면에 멈춘 채 그 섹션 안에서만 보인다.
실측: 스크롤 1000px 구간에서 viewportTop 이 계속 0.
대가 둘을 받아들였다
조상에 transform/filter/mask 를 못 쓴다 — 페이드 마스크를 포기했다
prefers-reduced-motion 에서는 absolute 로 되돌린다
전부 고정하지는 않았다. 종이는 손에 닿는 거리라 원경으로 두면 거짓말이다
재료·설치·프리플라이트 fixed 원경
사례 drift 두 결과물이 흐르는 자리
조판 drift 종이는 가깝다
게이트 씬을 파이프라인으로
히어로에서는 의미를 판독기가 자막으로 설명해야 했다. 그림이 스스로
말하지 못한다는 뜻이다. 옆에 여섯 단계가 적힌 자리로 옮기니 자막이
필요 없어졌다 — 판을 통과하면 그 단계가 켜진다.
캔버스는 sticky, 진행도는 섹션에서 읽는다.
travel 을 섹션 높이로 잡았더니 캔버스가 사라진 뒤에도 진행이 남아
6단계 중 3단계에서 멈췄다. (섹션 높이 - 뷰포트 높이)로 고쳤다.
캔버스 위 텍스트 대비 14.2:1.
스킬
motion.md 패럴랙스의 원형은 고정 · clip-path 기법과 그 대가
sticky 캔버스의 진행도 계산
three.md 씬의 의미는 옆의 콘텐츠가 반응할 때 성립한다.
자막이 필요하면 배치를 의심해라
"티가 안 난다"는 지적이 맞았다. 세 가지를 동시에 잘못하고 있었다.
1. 이동량이 모자랐다
여유를 28% 잡아놓고 92px 만 움직였다. 스크롤 1800px 구간에서 5%다.
공식은 이미지를 컨테이너보다 크게 만들고 초과분 전체를 움직이는 것.
depth 0.45 -> 높이 145%, translateY(-31.03%). 같은 구간에서 374px.
translateY(%) 는 자기 크기 기준이라 컨테이너 높이를 몰라도 맞는다.
2. overflow: hidden 이 view() 타임라인을 죽이고 있었다
overflow: hidden 은 스크롤 컨테이너를 만들고, 그러면 자식의 view() 가
문서가 아니라 그 상자를 기준으로 잡힌다. 이미지는 상자 안에서 늘 같은
자리라 진행도가 고정된다. 콘솔 에러도 없고 computed 값도 정상이라
두 스크롤 위치에서 transform 을 재보고서야 이동 0px 인 것을 알았다.
잘라내는 일은 섹션의 overflow: clip 에 맡겼다.
3. opacity 로 눌러 이미지를 지웠다
어두운 광원 사진을 opacity 0.5 로 깔면 검정도 빛도 같이 죽는다.
mix-blend-mode: screen 으로 바꿨다 — 검정은 투명, 밝은 곳만 더해진다.
그래서 불투명도 0.85~1.0 을 써도 본문 대비가 안전하다.
생성 프롬프트도 같은 함정이었다. "어둡게"를 너무 강하게 넣어서
안전한 이미지가 아니라 없는 이미지를 만들었다.
격자 배경 제거
사진이 들어온 뒤로 배경이 두 겹이라 서로 경쟁했고 표로 읽혔다.
배경도 한 섹션에 하나다.
스킬 motion.md 에 넷 다 반영
이동량 공식 · overflow 함정 · screen 합성 · 배경은 한 겹
배경이 단색이면 패럴랙스는 성립하지 않는다. 앞의 것이 몇 px 어긋나도
비교할 대상이 없다. 히어로 말고는 기준면이 없어 시차가 안 보였다.
배경 이미지를 사 오는 대신 이 페이지가 이미 주장하는 것을 그렸다
.bg-grid 간격 눈금 격자. 셀이 --grid-cell = --space-6
파이프라인 · 수치. "모든 값이 토큰에서 나온다"가 배경에서도 성립
.bg-glow 광원 블롭. 섹션마다 --glow-x 로 자리를 옮긴다
재료 · 설치. 히어로의 빛이 마지막 CTA 에서 돌아온다
실측 3층 (스크롤 1000 -> 1600)
격자 +14.9px · 산출물 -14px · 단계명 0
한 층은 반드시 고정이다. 전부 움직이면 그냥 흔들리는 페이지다
그리드 wide 트랙을 좁은 화면에서 닫는다
고정 10rem 이라 모바일에서도 좌우 80px 이 살아남아, 390px 에서 본문이
x=112 부터 시작하고 폭이 278px 로 줄어 제목이 네 줄로 접혔다.
--wide-pad 를 clamp 로 바꿔 닫았다. 이제 전부 x=32 에서 시작하고 두 줄이다
파이프라인 정렬선을 하나로
제목 x=371 / 리드 x=435 / 스파인 x=143 이던 것을 전부 x=183 으로.
제목·리드·브리프를 스파인과 같은 컨테이너에 넣었다
히어로 높이를 콘텐츠에 맞춘다
모바일에서 콘텐츠 390px 에 736px 을 씌워 여백이 화면의 41% 였고
다음 섹션이 화면 밖으로 밀려 스크롤 단서까지 사라졌다.
모바일 min-height 제거(736 -> 554), 데스크톱 88dvh -> 78dvh
배경 마스크 62% -> 82% 로 늘려 하단의 죽은 띠를 없앴다
스킬 motion.md 에 "패럴랙스에는 기준면이 필요하다" 를 추가.
페이지가 주장하는 것을 배경으로 그리는 표와, 한 층은 고정이라는 규칙.
390px / 1440px 실렌더: 가로 스크롤 0, 대비 실패 0. 테스트 22개 통과
지적받은 것: 모바일 마진·패딩, 폰트 웨이트, 버튼 스타일 불일치, SSOT,
스크롤바, 모바일 메뉴, 그리고 3D 를 왜 상자에 넣었는지.
3D 의 역할을 잘못 잡았다
lusion.co 의 "3D 는 액자 안"은 3D 자체가 상품일 때의 규칙이다.
우리는 절차를 파는데 액자에 넣을 상품이 없어 "저 상자는 뭐냐"가 됐고,
의미를 게이트 판독기가 자막으로 설명하고 있었다.
이 씬의 역할은 재질이다. 배경으로 되돌리고 값을 전부 낮췄다 —
테두리 광 0.85->0.42, 알파 0.72->0.34, UV 경계 0.05->0.17, 이동 60%
ResizeObserver 로 캔버스를 따라가게 했다. window.resize 만 듣는 동안
히어로 높이 변화를 놓쳐 배경이 화면의 3분의 2만 덮었다
SSOT
웨이트 6종(400/500/560/600/620/660) -> 3종. 셋은 토큰에 없던 값이었다
.btn + btn-solid/btn-quiet. 두 버튼이 높이 36 vs 44, 패딩 16 vs 8,
테두리 1px vs 0, 웨이트 400 vs 500 이었다
--header-h. 간격을 clamp 로 바꾸자 관계가 끊겨 h1 이 헤더 뒤로 들어갔다
--space-5~8 과 --gutter 를 clamp 로. 고정이면 모바일 여백이 화면의 26%
scrollbar-color 지정
모바일
좌우 여백 24 -> 32px, 섹션 상하 112 -> 56px
헤더에 섹션 앵커 4개. 900px 미만은 details 기반 메뉴(JS 0바이트)
패럴랙스는 섹션마다 다른 말을 한다
히어로 글자 상승 / 배경 하강 — 반대 방향이라야 시차가 보인다
파이프라인 단계명 고정, 산출물만 지연 — 인과
재료 타일이 서로 다른 깊이 — 표면은 한 겹이 아니다
프리플라이트 뒤 항목일수록 늦게 — 로그는 흐른다
수치 없음. 의도적 정지 — 계기판의 바늘은 떨지 않는다
스킬
three.md §0-A 를 역할별로 갈랐다. "액자 안"만 적어둔 것이 잘못된
일반화였고 내가 거기 그대로 걸렸다. 재질일 때의 값 교정을 실측으로 남김
tokens.md 웨이트·컨트롤·헤더 높이·반응형 간격 — 토큰이 아예 없던 네 축
motion.md 섹션별 패럴랙스 배정표. 움직이지 않는 것도 결정이다
390px 실렌더: 가로 스크롤 0, 대비 실패 0, 웨이트 3종, radius 2종. 테스트 22개 통과
히어로를 고치면서 레퍼런스를 다시 보지 않았다. lusion 하나에서 얻은
원리만 들고 판 폭과 액자 비율을 네 번 고쳤다 — 전부 계산이지 근거가 아니었다.
국소 레퍼런스 실측
lusion.co 3D 가 첫 화면의 71%, h1 36px, 텍스트는 캔버스 위
basement.studio 3D 가 100%, h1 87px 은 캔버스 아래(y=916)
railway.com h1 54px 1줄, 미디어는 그 아래
우리(고치기 전) 3D 52% / 텍스트 43% — 둘 다 어중간
셋 다 3D 와 텍스트를 세로로 분리하고 3D 에 70% 이상을 준다.
CTA 가 첫 화면에 있어야 하므로 basement 형이 아닌 lusion 비율을 택했다.
현행 텍스트 24% / 액자 59%, 링크는 액자 캡션 줄로 내렸다.
3D 형태
판 15x6 으로 액자 비율과 일치시켰다. 좁으면 통과 내내 좌우 테두리가
남아 세로 기둥으로 보이고, 낮으면 액자 경계와 겹쳐 이중선이 된다
sway 를 0.16+0.05i 로 되돌렸다. 키우니 문이 아니라 쌓아둔 사각형이 됐다
모바일 액자 4/3 -> 1/1 (화면의 27% -> 36%)
스킬
SKILL.md 0단계: 연장·국소 경로에 1′(국소 레퍼런스 1개) 추가.
design.md 는 방향과 토큰까지만 답하고 형태를 답하지 않는다. 그 빈칸을
메우는 것이 기본값이고 기본값의 총합이 슬롭이다. galleries.md 의
국소 브리프 표에 진입점이 없던 것을 연결했다
방향을 글래스로 바꿀 때 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개 통과
'폰트 관련된 것도 스킬이 좀 잘 해줘야 하는데 그렇지 못한 것 같다'는 지적.
점검해보니 size-adjust, ascent-override, unicode-range, OpenType 기능,
FOUT/FOIT, 폰트 라이선스가 스킬 어디에도 없었다. font-display 와 서브셋은
tokens.md 에 한 줄씩뿐이었다.
references/typography.md 신설
- 고르는 절차: 개수를 먼저 정하고, 성격을 브리프에서 끌어내고,
x-height·대비·웨이트 범위·숫자 형태를 실제로 재서 검증한다
- 가변 폰트: 축, 표준 속성 우선, 가변 축 애니메이션이 왜 게이트 8 위반인지
- 로딩: font-display 값별 선택 기준, preload 조건, unicode-range
- 폴백 메트릭: size-adjust 와 override 3종. 재는 코드 포함
- OpenType: tabular-nums 등. font-variant-* 를 font-feature-settings 보다 먼저
- 한글: 동적 서브셋 원리, 웨이트가 라틴과 다르게 보이는 이유, 스택 순서
- 라이선스: 웹 임베딩 허용 여부가 상업 이용 허용과 다르다는 것
그리고 이 페이지가 그 규칙을 어기고 있었다
- 실측: 맑은 고딕이 Pretendard 보다 13.0% 넓다. 교체 순간 줄바꿈이 다시 잡힌다
- fonts.css 신설. OS 별로 폴백을 따로 정의하고 size-adjust 로 맞췄다
- 실측 차이 13.0% -> 0.0%
preflight.md 에 폰트 검사 6개를 추가했다. 지금까지 하나도 없었다.
designpaca 파이프라인 0~6단계를 실제로 돌려 만들었다. 근거는 research/site-brief.md,
결정 기록은 apps/site/design.md 에 있다.
한 문장 컨셉
- 이 페이지는 designpaca 를 거쳐 만들어졌고, 절차와 형태 수치를 한국어 기준으로 전부 공개한다
번호 없이 순서 표현 (C-07 회피)
- 파이프라인 6단계를 번호로 매기면 검출률 3위 슬롭 지문에 걸린다
- 시각: 스파인 위 위치가 순서를 만든다 / 내용: 같은 브리프가 단계마다 변한다
- 의미: <ol role="list"> — 화면에 번호 0개, 보조기술에는 "6개 중 n번째"
멀티링구얼
- / = 한국어, /en/ = 영어. 번역이 아니라 각 판을 따로 썼다
- 언어별 레이아웃이 자기 폰트만 로드한다 (판당 2개)
- 조판 섹션은 한국어판에서 주장이고 영어판에서 사례다
실측
- JS 314B (gzip, 예산 50KB) / CSS 3.0KB / HTML 4.4~4.8KB
- radius 2종 · backdrop-filter 0개 · 타입 5단계 · 강조색 1개
- 슬롭 지문 grep 9패턴 0건, 정적 하드 게이트 8개 전부 통과
감사에서 걸려 고친 것
- eyebrow 6개 → 상한 ceil(7/3)=3 위반 → 3개로
- clip-path 리빌 → 게이트 #8 위반 → transform 으로 교정
- 구분선 대비 1.30:1 → 입력 테두리용 별칭 분리 (WCAG 1.4.11)
- 본문 컬럼 960px → --measure 로. layout.md 예시 코드도 같이 수정
웹 디자인 파이프라인 스킬과 이를 5개 에이전트에 설치하는 CLI 를 담은 모노레포.
스킬 (packages/skill)
- SKILL.md 261줄 + 참조 문서 16개 3,349줄. progressive disclosure 로
본문은 절차와 인덱스만, 지식은 references/ 로 분리
- 0~6단계 파이프라인. 규모에 따라 전체·연장·국소 세 경로로 분기
- 하드 게이트 12개는 grep·카운트로 검증 가능한 것만. 취향 판단은 제외
- 미학 프리셋 5종, AI 슬롭 지문 목록, 한글 조판 규칙,
SVG 필터·three.js·인터랙티브 모션·HTML-in-Canvas 실전 지침
설치 CLI (packages/cli, packages/core)
- npx designpaca 온보딩 TUI. Claude Code · Codex · Cursor · Windsurf · AGENTS.md
- 매니페스트에 설치 시점 해시를 기록해 사용자가 고친 파일은 update 가 건너뛴다
- 타깃별로 본문의 references/ 경로를 실제 설치 위치로 재작성
- AGENTS.md 는 항상 로드되므로 본문 대신 303자 포인터만 주입
- Windsurf 는 12,000자 상한 초과 시 설치를 차단
배포 (build/ci, .forgejo/workflows)
- 태그 v* → 검사·테스트·빌드 → npmjs 배포 + Forgejo 레지스트리 미러
→ draft 릴리스 → Cloudflare Pages. 재실행 멱등
근거 (research/)
- 약 250개 웹 소스 조사 결과와 도그푸딩 검증 2건. 스킬의 모든 수치는 여기서 나온다
테스트 22개 통과 (core 16 · cli 6)