새벽 세 시, 인트로를 2D 픽셀아트로 다시 그렸어요
3D로 만들던 인트로를 접고 캔버스 2D 픽셀아트로 다시 그렸습니다. 9초 동안 불이 켜지고, 누가 걸어 들어와, 노트북을 열면 그 화면이 진짜 사이트가 됩니다.
처음엔 three.js로 만들고 있었어요. 방을 세우고 조명을 놓고 캐릭터 glb를 불러오고… 그런데 로딩이 끝날 때까지 화면이 까맣고, 다 뜨고 나면 생각보다 안 예뻤어요. 무엇보다 9초짜리 연출 하나 때문에 라이브러리를 통째로 들고 다니는 게 아까웠습니다.
그래서 캔버스 2D + 픽셀 스프라이트로 다시 그렸어요. 지금 인트로는 이렇게 흘러갑니다.
- 암전 → 천장 전구가 몇 번 깜빡이며 켜지고
- 캐릭터가 화면 밖에서 걸어 들어오고 (8프레임 워크 사이클)
- 옆구리에 낀 노트북을 두 손으로 눕혀서
- 뚜껑을 열면, 그 화면 안에 진짜 사이트의 히어로가 떠 있어요
노트북 화면 안은 진짜 DOM이에요
화면칸만 그림이 아니라 DOM 오버레이입니다. 인트로가 끝나면 그 사각형이 화면 전체로 펼쳐지면서 사이트가 돼요. 히어로는 Hero.astro 하나를 인트로와 홈이 같이 씁니다. 같은 마크업, 같은 CSS를 쓰니까 넘어가는 순간 한 픽셀도 어긋나지 않아요.
노트북 스프라이트의 화면칸은 “꺼진 색”으로 칠해 뒀어요. 그 자리에 DOM 사각형을 덮는데, 스프라이트가 밝은 하늘색이면 1~2px만 어긋나도 그 틈으로 밝은 띠가 새어 나옵니다. 어두운 색끼리면 어긋나도 안 보여요.
걸음이 미끄러지지 않게 하는 규칙 셋
- 걷기 프레임은 시간이 아니라 이동 거리에 묶여 있어요 (프레임당 17.1px = 실측 보폭의 절반). 시간에 묶으면 속도가 바뀔 때마다 발이 바닥을 긁습니다.
- 프레임을 놓는 기준점은 그림 한가운데가 아니라 머리 중심이에요. 팔다리가 벌어지면 bbox 중심이 13px씩 흔들려서 몸이 앞뒤로 덜컥거립니다.
- 걷는 거리를 한 주기 단위로 올림해서, 마지막 걸음이 두 발 모은 프레임에서 끝나게 했어요.
걷다 서는 순간에도 팔이 제자리로 돌아오며 손이 13px 튀어요. 그 0.16초만 두 위치를 섞습니다.
그레인은 배경에만
화면에 고정된 잡티를 캐릭터와 노트북 위까지 깔면, 그것들이 움직일 때마다 다른 픽셀이 덮여요. 윤곽선과 평평한 면이 프레임마다 지글거립니다. 잡티는 배경에만 까세요.
한 번만 틀어요
인트로는 첫 방문에만 돕니다. sessionStorage에 봤다는 표시를 남기고, prefers-reduced-motion이면 아예 건너뛰어요. 다시 보고 싶으면 아래 아이콘 줄의 되감기 버튼(/?intro=1)을 누르면 됩니다.
재생 여부는 첫 페인트 전에 결정해야 해요. 렌더링 이후에 판단하면 사이트가 한 번 보였다가 인트로로 덮이는 깜빡임이 생깁니다. <head> 안 인라인 스크립트에서 <html>에 data-intro를 붙이고, CSS가 그걸 보고 본문을 잠급니다.