Commit graph

10 commits

Author SHA1 Message Date
Yun Chan
eb9f61e907 fix(site): 스파인 뒤 62dvh 여백을 없애고 게이트 진행도를 목록 기준으로 잰다
All checks were successful
ci / build (push) Successful in 26s
release / release (push) Successful in 50s
진행도를 섹션 높이로 재고 있어서, 여섯 게이트를 다 돌리려면 정거장 목록 뒤에
화면 절반이 넘는 빈 공간(558px)이 필요했다. 콘텐츠가 아니라 스크롤 연료였고
화면에서는 그냥 큰 빈칸으로 보였다.

진행도를 목록이 화면을 지나는 구간으로 바꿨다.
  start = 뷰포트 70% 지점에 목록 위쪽이 닿으면 0
  end   = 뷰포트 30% 지점을 목록 아래쪽이 빠져나가면 1
  travel = 목록 높이 + (start - end)

뷰포트의 40% 가 구간으로 더해지므로, 목록 963px 이 1323px 구간이 되고
게이트당 220px 이다. 여백을 다 지우고도 과민 반응 기준(200px)을 넘긴다.

motion.md 에 "스크롤 구간이 모자라면 여백이 아니라 진행도 공식을 고쳐라" 를
기록했다.
2026-08-21 01:20:35 +09:00
Yun Chan
8267905c0c 테두리 광을 회전시키고 three.js 모바일 대응을 고친다
회전 테두리
  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        지오메트리를 화면 비율에 맞춰 다시 잡아라
                  저사양 판정에 화면 폭을 넣어라
2026-08-20 16:37:49 +09:00
Yun Chan
91bb4ae9dc 히어로와 파이프라인이 같은 씬을 쓰던 것을 나눈다
게이트 씬을 파이프라인으로 옮기면서 히어로에도 남겨뒀더니 같은 그림이
페이지에 두 번 나왔다. 역할이 다르면 씬도 달라야 한다.

  히어로     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 을 검정으로 착각하면 대비가 통과한 것처럼 보인다
2026-08-20 16:11:53 +09:00
Yun Chan
af3a08397e 배경을 뷰포트에 고정하고, 게이트 씬을 파이프라인으로 옮긴다
"스크롤할 때 이미지가 고정되어 원경처럼 보이는 게 패럴랙스의 꽃"이라는
지적이 맞았다. 느리게 같이 움직이는 것으로는 그 인상이 안 나온다 —
속도만 다를 뿐 방향이 같기 때문이다.

고정 배경
  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   씬의 의미는 옆의 콘텐츠가 반응할 때 성립한다.
             자막이 필요하면 배치를 의심해라
2026-08-20 16:08:11 +09:00
Yun Chan
9c9ab2de7e 디자인 SSOT 를 세우고 3D 를 배경 재질로 되돌린다
지적받은 것: 모바일 마진·패딩, 폰트 웨이트, 버튼 스타일 불일치, 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개 통과
2026-08-20 14:15:30 +09:00
Yun Chan
4b853355e3 히어로를 국소 레퍼런스로 다시 잡고, 국소 경로에 1′ 단계를 넣는다
히어로를 고치면서 레퍼런스를 다시 보지 않았다. 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 의
  국소 브리프 표에 진입점이 없던 것을 연결했다
2026-08-20 13:44:29 +09:00
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
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
Yun Chan
85be000704 헤더 상단 검은 띠 제거 · 패럴랙스 · 히어로 3D 유리 씬
헤더가 문서 흐름에 있어서 그 위 공간이 히어로 광원 밖으로 남았다.
화면에서 검은 띠로 보였다. 헤더를 띄우고 히어로가 최상단부터 차오르게 했다.

패럴랙스는 scroll-driven animation 으로만 만든다. scroll 리스너를 쓰지 않고
transform 만 움직이므로 미지원 브라우저에서는 제자리에 그대로 있다.

히어로 3D 는 배경을 렌더 타겟에 굽고 유리 판이 그 텍스처를 왜곡 샘플링한다.
transmission 재질이 매 프레임 씬을 재렌더하는 비용을 피한 구조다.
2026-08-20 12:17:02 +09:00
Yun Chan
ed9463c3c2 헤더 배경 수정 + three.js 를 두 곳으로
헤더에 배경이 왜 있냐는 지적에서 시작했다.
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 를 토큰으로 승격해 셰이더의 하드코딩 색을 없앴다.
2026-08-20 11:52:45 +09:00