브라우저의 재발견 · 스크롤 스크러빙

스크롤을 타임라인 스크러버로 쓰는 6가지 기법

손가락(스크롤)이 곧 재생 헤드다. 각 칸을 스크럽해 효과를 보고, 카드 오른쪽 ‘?’로 필요한 준비물·AI 지시문·핵심 코드를 확인하라. 빌드도 라이브러리도 없이 이 파일 하나로 돌아간다.

권장: Chrome / Edge. 1번 칸(순수 CSS scroll-timeline)은 최신 크로미엄에서만 동작한다.

04 패럴랙스 레이어 (시네마틱) translateY × 배속 · 6층
DEPTH 0%카메라 하강 · 6개 레이어
transform: translateY(scroll × rate)
↕ 길게 스크럽

패럴랙스 레이어

필요한 것

앞·중·뒤로 나눈 레이어들(PNG/SVG). 각 레이어에 ‘배속(rate)’ — 뒤는 느리게(0.1~0.3), 앞은 빠르게(1.0+). 속도 차이가 깊이감.

AI에게 이렇게

“배경·중경·전경 레이어를 스크롤에 따라 각각 다른 속도로 위로 올려줘. 전경이 제일 빠르게.”

핵심 코드
layer.style.transform = `translateY(${scroll * rate}px)`;
01 스크롤-구동 CSSJS 0줄
CSS ONLYscroll-timeline
scroll-timeline 미지원
Chrome/Edge에서 확인
animation-timeline: scroll();
↕ 스크럽

스크롤-구동 CSS

필요한 것

스크롤 컨테이너 1개 + @keyframes 하나. JS·라이브러리 없음. Chrome·Edge 전용(사파리·파이어폭스 아직).

AI에게 이렇게

“스크롤 컨테이너 안 요소를 animation-timeline: scroll()로 스크롤에 맞춰 부채처럼 펼쳐지게 해줘. JS 없이 CSS만.”

핵심 코드
.card{ animation: fan linear both; animation-timeline: scroll(); } @keyframes fan{ to{ transform: rotate(46deg) } }
02 진행률 매핑scroll + rAF
0%정규화 + 관성
p = scrollTop / (scrollH − clientH)
↕ 스크럽

진행률 매핑

필요한 것

아무것도 안 필요. 순수 JS 몇 줄. 모든 스크럽의 기본 엔진. 부드럽게 하려면 lerp(관성) 한 줄만 더.

AI에게 이렇게

“스크롤 진행률을 0~1로 계산해서 요소에 연결해줘. requestAnimationFrame + lerp 스무딩으로 부드럽게.”

핵심 코드
const p = el.scrollTop / (el.scrollHeight - el.clientHeight); cur += (p - cur) * 0.13; // 관성(lerp)
03 이미지 시퀀스Canvas · 임시
FRAME 00준비 중
drawImage(frames[p×N])
↕ 스크럽

이미지 시퀀스 스크러빙

필요한 것 (핵심!)

① 영상 1개 → ② 프레임 이미지로 쪼갠 파일들(60~120장, FFmpeg) → ③ 스크롤 전에 전부 preload. 프레임이 많을수록 부드럽고 용량↑.

준비 명령 (FFmpeg)
ffmpeg -i input.mp4 -vf fps=30 \ frames/f_%03d.jpg
AI에게 이렇게

“frames 폴더의 f_001~120.jpg를 전부 preload한 뒤, 스크롤 진행률로 프레임을 골라 canvas에 drawImage 해줘.”

핵심 코드
ctx.drawImage( frames[Math.floor(p * (N-1))], 0, 0);

※ 지금은 임시 비주얼 — 영상을 넣으면 실제 프레임으로 교체됩니다.

05 셀프-드로잉 SVGstroke-dashoffset
PATH 0%선이 그려짐
strokeDashoffset = len × (1 − p)
↕ 스크럽

셀프-드로잉 SVG

필요한 것

SVG path 하나(경로·그래프·서명). 전체 길이를 재서 점선(dasharray)으로 잡고, 오프셋을 스크롤로 줄이면 선이 그려진다. 아래 면적은 clip으로 함께 채운다.

AI에게 이렇게

“이 SVG 선을 스크롤에 따라 그려지게 하고, 선 아래 면적도 같이 채워지게 해줘.”

핵심 코드
const len = path.getTotalLength(); path.style.strokeDasharray = len; path.style.strokeDashoffset = len * (1 - p);
06 3D 파티클 글로브원근투영 · no three.js
0°수동 투영 · 340pt
k = fov / (fov + z)
↕ 스크럽

3D 파티클 글로브

필요한 것

간단: 구 위의 점 좌표를 코드로 원근투영(이 데모). 본격: three.js + 3D 모델(.glb) — 제품 회전, 인체 모형 등.

AI에게 이렇게

“구 표면에 점들을 뿌리고, 스크롤 진행률만큼 Y축으로 회전시켜 원근투영으로 canvas에 그려줘. 뒤쪽 점은 어둡게.”

핵심 코드
const k = fov / (fov + z); // 원근 sx = cx + X * R * k; // three.js면: model.rotation.y = p * 2π

스크러빙 × 효과 결합

스크롤로 효과를 재생한다

앞의 호버·시그니처 효과를 스크롤에 물리면, 사용자가 스크롤한 만큼 효과가 진행된다. 요즘 사이트가 쓰는 스크롤-트리거 리빌이 바로 이 원리다.

C1스크롤 텍스트 리빌 스태거 × 스크롤
0/0글자 리빌
글자 임계값 = i / N
↕ 스크럽

스크롤 텍스트 스태거

필요한 것

글자별 span + 각 글자의 등장 임계값(i/N). 스크롤 진행률이 그 지점을 넘으면 글자가 올라온다. 스크롤 리빌의 대표.

AI에게 이렇게

“스크롤에 따라 제목 글자가 하나씩 순서대로 올라오며 나타나게 해줘.”

핵심 코드
const l = clamp((p - i/N) / 0.16, 0, 1); span.style.opacity = l; span.style.transform = `translateY(${(1-l)*24}px)`;
C2스크롤 디코드 스크램블 × 스크롤
0%디코드
DECODE
i < p×N ? 원문 : 랜덤
↕ 스크럽

스크롤 디코드 (스크램블)

필요한 것

스크롤 진행률만큼 왼쪽부터 원문을 확정하고 나머지는 랜덤 글자로. 스크램블 효과를 스크롤에 묶은 것.

AI에게 이렇게

“스크롤할수록 랜덤 글자가 원래 텍스트로 왼쪽부터 확정되게 해줘.”

핵심 코드
out += (i < p*N) ? final[i] : chars[Math.random()*chars.length|0];
C3스크롤 카운터 숫자 롤 × 스크롤
0스크롤 카운터
value = round(p × target)
↕ 스크럽

스크롤 카운터 (오도미터)

필요한 것

0~9 세로 릴 + overflow:hidden. 목표값 × 스크롤 진행률을 숫자로 굴린다. 통계·성과 섹션에 자주.

AI에게 이렇게

“스크롤하면 숫자가 0에서 목표값까지 굴러 올라가는 카운터 만들어줘.”

핵심 코드
const val = Math.round(p * target); reel.style.transform = `translateY(${-digit}em)`;
C4스크롤 비포/애프터 clip-path × 스크롤
0%before → after
AFTER
BEFORE
clip-path: inset(0 0 0 p%)
↕ 스크럽

스크롤 비포/애프터

필요한 것

겹친 두 이미지 + clip-path를 스크롤로 밀어 앞 레이어를 걷어낸다. 리모델링·보정 전후 비교에 딱.

AI에게 이렇게

“스크롤하면 앞 이미지가 옆으로 걷히며 뒤 이미지가 드러나는 전후 비교 만들어줘.”

핵심 코드
front.style.clipPath = `inset(0 0 0 ${p*100}%)`;
C5스크롤-속도 마퀴 velocity × 스크롤
0스크롤 속도 → 마퀴
SCROLLFASTERMARQUEESPEED SCROLLFASTERMARQUEESPEED
offset += 스크롤 속도
↕ 빠르게 스크럽

스크롤-속도 마퀴

필요한 것

스크롤 속도(velocity)를 매 프레임 계산해 마퀴 이동량에 더한다. 빠르게 굴리면 텍스트가 확 빨라지는 어워즈 단골 기법. 평소엔 천천히 흐른다.

AI에게 이렇게

“스크롤 속도에 따라 흐르는 텍스트(마퀴)가 빨라졌다 느려졌다 하게 해줘.”

핵심 코드
sc.onscroll = ()=> vel += (now - last) * 0.6; // 매 프레임: off -= (0.6 + vel); vel *= 0.92;
C6스크롤 컬러 필 background-clip × 스크롤
0%컬러 필
SCROLLSCROLL
background-clip:text + width p%
↕ 스크럽

스크롤 그라디언트 텍스트 필

필요한 것

같은 글자 두 겹 — 회색 바탕 위에 그라디언트 글자(background-clip:text)를 얹고, 위 레이어를 감싼 상자의 width를 스크롤로 늘려 색이 왼쪽부터 채워진다.

AI에게 이렇게

“스크롤하면 제목 글자에 그라디언트 색이 왼쪽부터 차오르게 해줘.”

핵심 코드
/* 위 레이어: background-clip:text (그라디언트 글자) */ fillWrap.style.width = p*100 + "%"; // overflow:hidden
C7가로 스크롤 갤러리 세로→가로 × 스크롤
0%필름스트립
01
02
03
04
05
06
translateX(−p × (rowW − viewW))
↕ 스크럽

가로 스크롤 갤러리

필요한 것

가로로 긴 카드 줄 + 바깥 overflow:hidden. 세로 스크롤 진행률을 가로 이동으로 바꾼다. 요즘 포트폴리오·제품 소개의 단골.

AI에게 이렇게

“세로로 스크롤하면 카드 줄이 가로로 넘어가는 가로 스크롤 섹션 만들어줘.”

핵심 코드
const move = rowW - viewW; row.style.transform = `translateX(${-p*move}px)`;
C83D 카드 플립 rotateY × 스크롤
0°앞 → 뒤
FRONT
BACK
rotateY(p × 180deg)
↕ 스크럽

3D 카드 플립

필요한 것

앞·뒷면 두 장 + transform-style:preserve-3d, backface-visibility:hidden. 스크롤 진행률을 회전 각도로. 뒷면은 미리 180° 돌려둔다.

AI에게 이렇게

“스크롤하면 카드가 3D로 뒤집히며 앞면에서 뒷면으로 넘어가게 해줘.”

핵심 코드
inner.style.transform = `rotateY(${p*180}deg)`; /* 뒷면: transform: rotateY(180deg) */
C9프로그레스 링 원형 dashoffset × 스크롤
0%읽기 진행률
0%
strokeDashoffset = C × (1 − p)
↕ 스크럽

프로그레스 링 (읽기 진행률)

필요한 것

SVG 원(circle) 하나. 둘레(C=2πr)를 dasharray로 잡고 offset을 스크롤로 줄인다. 페이지 상단 읽기 진행 표시기에 쓴다.

AI에게 이렇게

“스크롤 진행률을 원형 링으로 보여주는 읽기 진행 표시기 만들어줘.”

핵심 코드
const C = 2 * Math.PI * r; ring.style.strokeDasharray = C; ring.style.strokeDashoffset = C * (1 - p);
C10스크롤 줌 (돌리) scale × 스크롤
1.0×파고들기
ZOOM
scale(1 + p × 4)
↕ 스크럽

스크롤 줌 (돌리 인)

필요한 것

요소를 scale로 크게 키우며(+페이드) ‘화면 속으로 빨려드는’ 전환. 히어로에서 다음 섹션으로 넘기는 연출에 강렬하다.

AI에게 이렇게

“스크롤하면 요소가 화면을 뚫고 들어가듯 확대되며 사라지게 해줘.”

핵심 코드
el.style.transform = `scale(${1 + p*4})`; el.style.opacity = 1 - p*0.8;
C11블러 → 포커스 filter blur × 스크롤
BLUR선명해짐
FOCUS
filter: blur((1 − p) × 12px)
↕ 스크럽

블러 → 포커스 (focus-in)

필요한 것

filter: blur() 값을 스크롤로 0까지 줄인다(+살짝 축소·페이드인). 흐릿하게 들어와 또렷해지는 등장 연출.

AI에게 이렇게

“요소가 흐릿하게 나타났다가 스크롤할수록 선명해지게 해줘.”

핵심 코드
el.style.filter = `blur(${(1-p)*12}px)`; el.style.opacity = 0.3 + 0.7*p;
C12배경 색 전환 gradient shift × 스크롤
0%그라디언트 이동
GRADIENT
background-position: p × 100%
↕ 스크럽

배경 그라디언트 시프트

필요한 것

큰 그라디언트 배경(background-size 300%)의 background-position을 스크롤로 이동. 섹션이 바뀌며 분위기(색)가 바뀌는 연출.

AI에게 이렇게

“스크롤하면 배경 그라디언트 색이 서서히 다른 색으로 흐르게 해줘.”

핵심 코드
el.style.backgroundPosition = `${p*100}% 50%`; /* background-size: 300% 300% */