게이트 씬을 파이프라인으로 옮기면서 히어로에도 남겨뒀더니 같은 그림이
페이지에 두 번 나왔다. 역할이 다르면 씬도 달라야 한다.
히어로 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 합성 · 배경은 한 겹
절대배치인데도 배경이 화면 가운데 561px 띠로만 깔렸다.
.section 은 subgrid 이고 `.section > * { grid-column: main }` 이 걸려 있는데,
절대배치 요소라도 그리드 영역이 잡히면 그 영역이 컨테이닝 블록이 된다.
position: absolute 는 그리드에서 배치를 면제해주지 않는다.
그리고 overflow: visible 이라 위아래 14% 여유분이 이웃 섹션으로 넘쳤다 —
조판 섹션의 종이가 프리플라이트 하단에 밝은 회색 띠로 나타났다.
.bg-photo { grid-column: full }
.has-bg { overflow: clip }
띠 폭 기준으로 잡았던 투명도도 다시 올렸다
사례 0.3 -> 0.5 · 프리플라이트 0.55 -> 0.8
재료 0.5 -> 0.6 · 설치 0.4 -> 0.55
1440px/390px 실렌더: 배경 5개 모두 전체 폭, 가로 스크롤 0.
화면 밖 섹션의 배경은 아직 로드되지 않는다 — lazy 가 의도대로 작동한다.
모션에 적용한 규칙("섹션마다 다른 말을 해야 한다")이 배경에서만 면제될
이유가 없다. 같은 그림을 전부에 깔면 그건 벽지다.
gpt-image-2 로 넉 장. 프롬프트마다 그 섹션의 주장을 그림으로 옮겼다
bg-refraction 겹친 유리판을 통과한 빛 재료·설치 표면은 한 겹이 아니다
bg-split 한 빔이 둘로 갈라진다 사례 같은 절차, 다른 결과
bg-align 정렬선 하나가 끊겨 있다 프리플라이트 자기 결과물을 남의 것처럼 본다
bg-paper 무광 인쇄용지, 섬유와 데클 조판 한글이 종이 위에 있어야 한다
넣지 않은 곳도 결정이다
파이프라인·수치 격자가 그 섹션의 주장이다
히어로 three.js 가 있다
규칙 목록은 담백해야 한다
프롬프트에는 매번 토큰 값을 그대로 넣었다. 광원은 #4FD6C4 와 #3D7BD6 둘뿐,
보라·마젠타·무지개·프리즘 분광 금지. "흰 본문 뒤에 깔리니 활자와 경쟁할
만큼 밝은 곳이 있으면 안 된다" 를 매번 반복했다.
BgPhoto 를 variant 로 확장. 소스 WebP 37/14/11/112KB,
빌드 12개 합계 276KB. 뷰포트에 맞는 하나씩만 lazy 로 받는다.
CSS 그라디언트 광원만으로는 패럴랙스의 기준면이 약했다. 굴절과 그레인이
실제로 들어 있는 이미지를 Codex CLI 내장 image_gen(gpt-image-2)으로 생성했다.
스톡이 아니라 이 페이지의 토큰 값을 프롬프트에 그대로 넣어 만든 것이다.
바탕 #0B0E12, 광원은 좌상단 딥 틸 #4FD6C4 와 우하단 파랑 #3D7BD6 둘뿐
보라·마젠타·무지개 금지 — 슬롭 지문이다
"흰 본문 뒤에 깔리니 활자와 경쟁할 만큼 밝은 곳이 있으면 안 된다.
중앙은 조용하게, 밝기는 모서리 쪽에"
사물·글자·사람·플레어·보케·비네트 전부 금지
components/BgPhoto.astro
CSS background-image 가 아니라 <Image loading="lazy"> 를 절대배치한다.
background-image 로 깔면 항상 받고 최적화도 안 된다
설치 섹션은 flip 으로 좌우 반전 — 같은 그림으로 읽히지 않게
섹션 경계에서 끊기지 않게 위아래를 마스크로 지운다
패럴랙스는 -46/+46px 로 가장 느리다
빌드 결과 WebP 26KB / 14KB / 7KB. 소스도 PNG 2MB 대신 WebP 37KB.
재료·설치 섹션 대비 실패 0건.
배경이 단색이면 패럴랙스는 성립하지 않는다. 앞의 것이 몇 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개를 추가했다. 지금까지 하나도 없었다.
'전체적인 레이아웃이나 카드가 너무 전형적이지 않나요'라는 지적.
정확했다. 유리라는 재질만 바뀌었을 뿐 구조는 카드 나열 그대로였다.
우리 규칙이 이미 그걸 금지하고 있었다.
layout.md: 벤토는 더 이상 차별화가 아니라 새 기본값이다
design-taste 4.4: 카드는 elevation 이 진짜 위계를 나를 때만
바꾼 것
- 수치: 벤토 카드 -> 조판. 큰 수치 둘이 왼쪽을 차지하고 나머지는
오른쪽 열에 목록으로 흐른다. 상자 없음
- 규칙: 2열 카드 -> 어긋난 목록. 홀수 항목은 근거가 한 칸 더 밀린다
- 프리플라이트: 카드 -> 로그. 세로선 하나가 형식을 만든다
- 설치 명령·재료 타일: 액자 제거
- 섹션 제목이 본문 정렬선보다 왼쪽으로 나온다. 같은 양을 전체에서 반복
유리 카드 29개 -> 5개. 정말 떠 있어야 하는 것에만 남겼다.
페이지의 수치와 프리플라이트 로그에도 그대로 적었다.
'3D 라고 그냥 큐브만 돌면 안 된다'는 지적에서 시작해 조사부터 했다.
research/three/06~08 에 사례 32건, GLB 소스 17곳, 방향 제안 3개가 있다.
조사 결론: 추상이다. GLB 는 쓰지 않는다.
- 구체 오브젝트의 성립 조건 3개(물리적으로 존재 / 각도가 정보 /
오브젝트가 하나로 정해짐)를 우리 브리프는 하나도 충족하지 않는다.
규칙 묶음은 돌려봐도 새 정보가 없다
- 실측: DamagedHelmet.glb 3,685KB 중 텍스처가 87%라 Draco 를 걸어도 -13%.
게다가 디코더만 200KB 로 예산의 67%를 먹는다
- Stripe Globe 는 모델 파일이 0바이트다. 6만 점을 코드로 생성한다.
지오메트리가 파일이 아니라 코드일 때 추상이 이긴다
- 2026 Awwwards Developer Award 수상작 중에는 3D 를 아예 안 쓴 것도 있다
채택안: 파이프라인 게이트
- 유리 판 여섯 장이 깊이 축에 정면으로 선다. 이 스킬의 여섯 단계다
- 스크롤하면 카메라가 문을 하나씩 통과하고 지나온 판은 뒤에 겹친다
- 판이 여섯인 이유가 생겼다. 아래 Pipeline 섹션과 같은 수다
- 순서는 이 제품의 본체다('순서를 바꾸지 마라'가 절대 규칙). 순서를
깊이로 옮기는 것은 은유가 아니라 직역이다
스크롤 연동은 이미 도는 렌더 루프에서 위치를 한 번 읽는다.
addEventListener('scroll') 을 쓰지 않는다(하드 게이트 10). 핀도 없다.
모션은 이유가 있어야 붙인다. 여기 넣은 것은 전부 '지금 이걸 보고 있다'
또는 '이건 눌린다'를 말한다. 장식 목적 애니메이션은 넣지 않았다.
- 유리 카드 29곳: 커서 아래에서 3px 떠오르고 그림자가 깊어진다
- 링크 2곳: 밑줄이 왼쪽에서 자란다
- 쇼케이스 판 2곳: 1.2% 다가온다
- 스파인 정거장: 마커가 커지고 인용선이 밝아진다
전부 transform 과 opacity 만 움직인다(하드 게이트 8).
prefers-reduced-motion 안에 넣어 모션을 줄이는 설정에서는 전부 사라진다.
헤더가 문서 흐름에 있어서 그 위 공간이 히어로 광원 밖으로 남았다.
화면에서 검은 띠로 보였다. 헤더를 띄우고 히어로가 최상단부터 차오르게 했다.
패럴랙스는 scroll-driven animation 으로만 만든다. scroll 리스너를 쓰지 않고
transform 만 움직이므로 미지원 브라우저에서는 제자리에 그대로 있다.
히어로 3D 는 배경을 렌더 타겟에 굽고 유리 판이 그 텍스처를 왜곡 샘플링한다.
transmission 재질이 매 프레임 씬을 재렌더하는 비용을 피한 구조다.
헤더에 배경이 왜 있냐는 지적에서 시작했다.
site-header 자체는 배경이 없었고, 안쪽 유리가 불투명 판으로
폴백된 것이었다. prefers-reduced-transparency 가 참이면
(윈도우 투명 효과 끄기 등) --surface-raised 단색이 깔린다.
투명도를 줄여달라는 요청은 "불투명한 판을 깔아라"가 아니다.
배경에 가까운 톤으로 낮추고 형태는 테두리와 그림자가 유지한다.
떠 있는 헤더는 더 가깝게 맞췄다.
three.js
- 공용 부트스트랩을 src/lib/shader-plane.ts 로 추출했다.
references/three.md 가 권하는 구조를 그대로 구현한 것이다.
지연 로드 · DPR 클램프 1.5 · 화면 밖이면 정지 · 실패 시 CSS 폴백
- 히어로: 광원 두 개가 흐르고 하나가 포인터를 느리게 따라온다
- 재료: 좌표를 노이즈로 밀어 유리 너머의 결을 만든다
- 두 셰이더가 같은 three 청크를 공유한다. 네트워크 요청 1건
--glow-2 를 토큰으로 승격해 셰이더의 하드코딩 색을 없앴다.
design-taste-frontend, high-end-visual-design, redesign-existing-projects 를
로드해 리디자인 모드로 진행했다. 이전 페이지는 디자인 스킬을 파는 자리가
문서처럼 생겼다는 지적을 받았다.
Design Read
- redesign-overhaul / 개발자 대상 / 정밀기기 언어
- DESIGN_VARIANCE 8 · MOTION_INTENSITY 6 · VISUAL_DENSITY 3
방향
- 다크 잉크 바탕에 three.js 셰이더 광원. 유리 패널이 그 위에 뜬다
- 리퀴드 글래스는 이 브리프에서 장식이 아니라 제품 시연이다.
SVG 필터와 three.js 의 결합 그 자체이기 때문이다
- 밝은 밴드는 조판 섹션 하나뿐. 한글이 종이 위에 있어야 하는 자리다
제품 증명
- 히어로 배경에 셰이더(초기 번들 밖, 첫 페인트 후 지연 로드)
- 재료 섹션에 SVG 필터 3종을 실제로 먹인 타일: 그레인, 굴절, 듀오톤
- 도그푸딩 산출물 2개를 실제 스크린샷으로. 가짜 목업이 아니다
감사에서 걸려 고친 것
- backdrop-filter 에 SVG 를 얹으면 Chrome 이 선언 전체를 버린다.
CSS.supports 는 참을 주면서 computed 는 none 이 된다
- main 에서 그리드 클래스가 빠져 subgrid 가 붕괴, 가로 444px 오버플로
- 진입 연출이 두 번 콘텐츠를 삼켰다. opacity 를 버리고 transform 만 남겼다
- eyebrow 4개, 제목 em-dash 2건
수치는 불리해진 것도 그대로 싣는다
- 반투명 패널 1개 -> 29개. 유리가 주제가 됐으므로
- three.js 185KB(gzip). 데모라서 JS 예산을 올렸고 그 사실을 페이지에 적었다
정적 검사로는 안 잡히고 320px 실렌더에서만 나온 것들이다.
발견 내용은 페이지의 프리플라이트 로그 섹션에 그대로 실었다.
1. 320px 가로 오버플로 13px
표를 overflow 컨테이너로 감쌌는데도 넘쳤다. grid item 의 기본
min-width 가 auto 라 콘텐츠가 부모를 밀어낸다. min-width:0 이
있어야 overflow-x 가 실제로 작동한다.
2. 다크 밴드 버튼 대비 2.88:1 (기준 4.5:1)
밴드가 --accent 만 반전시키고 --accent-ink 는 흰색으로 뒀다.
--accent-ink-inverse 토큰을 추가해 함께 반전시킨다. 6.21:1 로 회복.
3. 파이프라인 6단계 중 뒤 3개가 영영 opacity 0 ← 가장 심각
animation-range 의 cover 22% 에 페이지 하단 요소는 도달하지 못한다.
스크롤을 끝까지 내려도 이 페이지의 본체가 절반 사라진 상태였다.
이펙트를 끄면 보이지만 켜면 사라지는 것은 폴백이 있는 것과 다르다.
스크롤 진입 연출을 제거했다. 남은 모션은 호버·포커스뿐이다.
하드 게이트 12/12 전부 통과 (8개 정적 + 4개 실렌더).
실렌더 대비 최저 6.21:1, AA 미달 0건.
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)