designpaca/research/three/08-proposal.md
Yun Chan 17d04ee2bb 히어로 3D 를 파이프라인 게이트로 — 형태에 이유를 준다
'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). 핀도 없다.
2026-08-20 12:32:09 +09:00

12 KiB
Raw Permalink Blame History

08 — designpaca 소개 페이지 3D 방향 제안

근거: 06-webgl-showcase.md(사례 32건), 07-glb-sources.md(실측 압축), 현재 코드 apps/site/src/lib/hero-scene.ts


0. 결론 먼저 — 추상이다. GLB는 쓰지 않는다.

06 §2에서 뽑은 추상 3D 성공 조건 3개를 브리프에 대입한 결과다.

조건 designpaca
형태가 데이터에 묶여 있다 가능. 페이지가 이미 파이프라인 6단계·토큰 값·자기 성능 수치를 텍스트로 공개하고 있다. 그 숫자를 형태로 옮기면 된다
은유가 카피에도 존재한다 가능. "게이트", "통과 조건", "예산" 은 이미 카피의 언어다
3D를 끄면 정보를 잃는다 ⚠️ 설계하기 나름. 아래 세 안은 전부 이 조건을 만족하도록 짰다

구체 오브젝트를 배제하는 이유06 §1의 공통 조건 3개 중 하나도 만족하지 않는다.

  1. 파는 것이 물리적으로 존재하지 않는다. 규칙 묶음이다
  2. 각도가 정보가 아니다. 규칙은 돌려봐도 새 정보가 없다
  3. 오브젝트가 하나로 정해지지 않는다 — 무엇을 놓아도 은유고, 은유가 카피에 없으면 장식이다

예산이 이 판단을 다시 확인해준다 (07 실측): PBR 텍스처 GLB는 3.7MB로 300KB 예산의 12배다. Draco는 텍스처를 못 줄여서 13%에 그치고, Draco 디코더 자체가 200KB(예산의 67%) 다. GLB를 쓰려면 무텍스처 저폴리(35~90KB) + meshopt(디코더 25KB)뿐인데, 그 급의 모델로는 의미를 나를 수 없다.


제안 A — 파이프라인 게이트 (권장)

무엇을 보여주나

현재 떠 있는 유리 판 여섯 장에 이름을 준다. Z축을 따라 순서대로 세우고, 각 판이 파이프라인 한 단계가 된다.

카메라 ──→ [0 브리프 게이트] [1 레퍼런스] [2 방향] [3 토큰] [4 구현] [5 프리플라이트] ──→ 페이지 본문
  • 스크롤하면 카메라가 판을 하나씩 통과한다. 통과한 판은 뒤에 남아 겹쳐 굴절된다
  • 각 판 위에는 그 단계의 통과 조건 한 줄이 DOM 텍스트로 겹쳐 있다 (WebGL 안에 텍스트를 넣지 않는다 — 검색·선택·스크린리더)
  • 아직 통과하지 않은 판은 흐리고, 통과한 판은 선명하다. 깊이 = 진행도

왜 이 브리프에 맞나

  1. 개수 문제가 이미 풀려 있다. 히어로는 지금도 판이 6장이고 Pipeline.astro는 정확히 6단계다. "왜 6장인가"에 답이 생긴다 — 지금은 답이 없다
  2. 순서가 이 제품의 본체다. SKILL.md의 절대 규칙이 "순서를 바꾸지 마라"다. 순서를 공간의 깊이로 만드는 것은 은유가 아니라 직역이다
  3. 06 §1의 Oryzo 교훈("스크롤이 2D 레이어가 아니라 진짜 Z축으로 카메라를 민다")과 Shopify Editions 교훈("각 섹션이 독립된 무대")을 동시에 쓴다
  4. 기존 코드를 버리지 않는다. 렌더타겟 굴절 기법, 예산 준수, 폴백이 그대로 산다. 판의 배치와 라벨만 바뀐다

GLB 필요 여부

불필요. PlaneGeometry 6장 + 기존 굴절 셰이더. 새 에셋 0개.

예산 추정

항목 추가
three (이미 있음) ±0
판 배치·카메라 리그 코드 +2~3KB
스크롤 연동 +0KBscroll 리스너 대신 rAF에서 scrollY를 읽는다 (하드게이트 #10)
라벨 +0KB — DOM 오버레이
합계 +3KB 이내

실패 위험

위험 대응
스크롤 하이재킹. 게이트 통과를 강제하면 이탈한다 전체 스크롤 길이를 2뷰포트 이내로 묶고, 핀 고정을 쓰지 않는다. 스크롤을 멈춰도 페이지가 진행된다
판이 텍스트 가독성을 해친다 라벨은 판 에 두고 판 위에 겹치지 않는다. 대비는 별도 측정
여전히 "떠다니는 사각형"으로 읽힌다 판을 정면으로 세우고 정렬한다. 지금의 자유 부유를 버린다. 계기판은 정렬돼 있다
reduced-motion에서 의미가 사라진다 판 6장을 정지 상태로 한 장 렌더해서 순서가 보이게 한다. 현재처럼 아예 로드하지 않으면 정보를 잃는다 → 이 안은 폴백 정책을 바꿔야 한다

⚠️ 이 안의 유일한 구조적 대가: 3D가 정보를 나르게 되는 순간, "reduced-motion이면 아예 로드하지 않는다"는 현재 정책이 정보 손실이 된다. 해결: reduced-motion에서는 CSS만으로 6단계를 세로 목록으로 보여준다(이미 Pipeline.astro가 한다). 3D는 같은 정보의 다른 표현이 된다.


제안 B — 토큰 격자

무엇을 보여주나

페이지가 실제로 쓰는 토큰을 3차원 좌표계에 세운다. 축이 곧 토큰 종류다.

  • X축 = 간격 스케일 --space-1~--space-8 (8단계)
  • Y축 = 타입 스케일 (본문 단계 + 디스플레이)
  • Z축 = 색 역할 (--surface / --surface-raised / --ink / --ink-muted / --line / --accent)
  • 각 노드의 위치와 크기가 실제 CSS 변수 값에서 읽힌다. getComputedStyle로 뽑아 그대로 스케일에 넣는다
  • 다크/라이트를 토글하면 격자가 실제로 재배치된다 — 색 축의 좌표가 바뀌기 때문
  • 노드에 마우스를 올리면 그 토큰이 페이지 어디에 쓰였는지 DOM 요소가 하이라이트된다

왜 이 브리프에 맞나

  1. 페이지 컨셉이 "그 절차와 형태 수치를 전부 공개한다" 이다. 수치가 그대로 형태가 된다. 은유가 0단계다
  2. 06 §2의 Stripe Globe와 같은 논리 — 점 하나하나가 데이터고, 지오메트리가 파일이 아니라 코드
  3. 3D를 끄면 진짜로 정보를 잃는다. 세 축을 2D로 접으면 축 하나가 사라진다. 이 조건을 가장 확실히 만족하는 안이다
  4. 토큰이 바뀌면 격자가 따라 바뀐다 — 하드코딩이 불가능한 구조라 스킬의 "토큰은 계약이다" 원칙을 코드가 증명한다

GLB 필요 여부

불필요. InstancedMesh 노드 + LineSegments 축. Stripe가 6만 점을 모델 없이 만든 것과 같다.

예산 추정

항목 추가
InstancedMesh + 라인 축 +3KB
getComputedStyle 토큰 리더 +1KB
호버 하이라이트 연동 +2KB
합계 +6KB 이내

실패 위험

위험 대응
"도표를 왜 3D로?" — 가장 큰 위험. 2D 표가 더 읽기 쉬우면 3D는 진 것이다 축 세 개가 동시에 필요하다는 걸 보여줘야 한다. 축 하나를 접었을 때 잃는 것이 눈에 보여야 정당화된다
격자가 차갑고 예쁘지 않다 Ethereal Glass 미학과 충돌할 수 있다. 노드를 유리 재질로 하고 축을 시안 틸로 — 미학은 유지 가능
정보 과다 축당 표시 개수를 제한한다. 전부 보여주려 하지 마라
히어로에 두기엔 무겁다 히어로가 아니라 Metrics/Typography 섹션 옆에 두는 것이 맞을 수 있다. 히어로는 A안, 본문은 B안 조합이 가능하다

제안 C — 실측 계기판

무엇을 보여주나

페이지가 지금 이 순간의 자기 수치를 3D로 그린다. 값은 전부 실제 API에서 읽는다.

데이터 소스
번들 전송량 performance.getEntriesByType('resource')
LCP PerformanceObserver
드로우콜 / 삼각형 renderer.info.render
현재 DPR renderer.getPixelRatio()
프레임 시간 분포 rAF 델타 히스토그램
  • 막대그래프가 아니라 공간에 뜬 눈금과 축. 값이 예산선을 넘으면 그 축만 색이 바뀐다
  • 관찰자 효과를 숨기지 않는다: 3D를 켜면 드로우콜과 프레임 시간이 올라가고, 그게 화면에 그대로 보인다

왜 이 브리프에 맞나

  1. Metrics.astro가 이미 *"이 페이지의 수치"*를 텍스트로 공개하고 있다(JS 0.6%, three 추가분 185KB, 슬롭 지문 0건). 이 안은 그 섹션의 3D 판이다 — 새 컨셉이 아니라 기존 컨셉의 연장
  2. 스킬의 5단계가 "측정하지 않았으면 통과가 아니다" 라고 말한다. 페이지가 스스로를 측정하는 화면은 제품 주장의 증명이다
  3. 3D가 자기 비용을 스스로 고백하는 구조라, "3D를 왜 넣었나"는 질문에 페이지가 직접 답한다

GLB 필요 여부

불필요. 라인 + 인스턴스 + 텍스트는 DOM.

예산 추정

항목 추가
계측 코드 (PerformanceObserver 등) +2KB
축·눈금 지오메트리 +2KB
합계 +4KB 이내

실패 위험

위험 대응
수치가 나쁘면 자폭한다. 저사양 기기에서 프레임이 무너지면 그 화면이 증거로 남는다 이게 정직함이라 판단하면 그대로 두고, 아니면 이 안을 버려라. 어중간하게 감추면 최악
계기판 자체가 진부하다 antipatterns.md §4 「펄스 애니메이션 상태 점」에 인접하다. 값이 실제로 변할 때만 움직여야 한다
개발자 아닌 방문자에게 무의미하다 청중이 에이전트·개발자라 큰 문제는 아니지만, 히어로에 두면 첫인상이 좁아진다. 본문 섹션용
측정 자체가 프레임을 먹는다 샘플링 주기를 1초로. 매 프레임 계측하지 않는다

1. 조합 권장안

셋은 배타적이지 않다. A를 히어로에, C를 Metrics 섹션에 두는 조합이 가장 안전하다.

위치 이유
히어로 A 파이프라인 게이트 첫 화면에서 제품이 무엇인지(6단계 순서) 말한다. 기존 코드 재사용
Metrics 섹션 C 실측 계기판 이미 그 자리에 있는 텍스트 수치의 3D 판
(선택) Typography/Tokens 섹션 B 토큰 격자 여력이 있을 때만. 셋 다 넣으면 페이지가 3D 전시장이 된다

셋 다 하지 마라. 06 §1이 반복해서 말하는 것은 "어려운 아이디어 하나를 끝까지 판다" 다.


2. 하지 말아야 할 것 (진부해진 웹 3D)

금지
회전하는 큐브 / 토러스넛 three.js "hello world" 그 자체. 18줄 튜토리얼의 결과물이 그대로 프로덕션에 올라간 신호
이유 없는 파티클 구(sphere) 파티클이 데이터에 묶이지 않으면 스크린세이버다. 06 §2 조건 1 위반
마우스를 따라다니는 구체 / 커서 오브 인터랙션을 설계하지 않았다는 신호. 커서는 이미 커서다
Spline 기본 씬 임포트 800KB2MB. 예산의 37배. 게다가 Spline 특유의 매끄러운 블롭은 즉시 식별된다
떠다니는 3D 추상 블롭·기하 도형 antipatterns.md §7이 명시적으로 금지 — "콘텐츠 부재를 덮는 장식"
히어로 뒤 방사형 그라디언트 오브·헤일로 antipatterns.md §1 — "구성을 못 잡았을 때의 회피 수단"
네온 온 다크 발광 와이어프레임 antipatterns.md §1 「네온 온 다크」. 개발자 툴 브리프라도 관성이다
아무 데나 떠 있는 유리 판 지금 우리다. 형태에 근거가 없으면 유리도 블롭과 같다
3D 텍스트로 만든 로고 회전 텍스트는 DOM에 있어야 한다. 3D 로고는 검색·선택·스크린리더를 전부 잃고 얻는 게 없다
모든 섹션에 3D 스크롤할 때마다 캔버스가 뜨면 컨텍스트 상한(8~16)과 VRAM을 동시에 친다
로딩할 게 없는데 3D 프리로더 antipatterns.md §5 — 없는 대기를 만든다

3. 어느 안을 택하든 지켜야 할 것

  • 텍스트는 DOM에. 라벨·수치·통과 조건 전부. WebGL 안에 넣지 않는다
  • 판정 질문 하나: "3D를 끄면 무엇을 잃는가?" 답이 "분위기"면 그 안은 실패다
  • 형태의 개수에 근거가 있어야 한다. 6장인 이유, 8개인 이유를 한 줄로 못 대면 개수를 바꿔라
  • 예산: 세 안 모두 +6KB 이내다. 300KB 상한은 GLB를 전제한 값이고, 여기서는 쓸 일이 없다
  • 폴백 재설계: 3D가 정보를 나르게 되면 "reduced-motion이면 로드하지 않는다"가 정보 손실이 된다. 같은 정보를 CSS/DOM으로도 제공해야 한다