스톱모션 비디오
이 스킬로 만든 비디오는 음악에 맞춰 촬영된 스톱모션처럼 움직입니다. 각 포즈는 8분음표 하나 동안 유지되다가, 모든 것이 함께 바뀝니다. 페이지는 마디 첫 박에 등장합니다. 모든 클릭은 드럼 히트에 맞춰 울리며, 큰 변화는 강한 킥 위에 떨어집니다. 프레임 속도는 의도적으로 낮게 유지됩니다. 움직임이 거칠어 보이면 포즈 간격을 더 잘 배치합니다. 비트가 부드럽게 사라지지 않도록 합니다.
이 규칙들은 169.825 BPM의 드럼 앤 베이스 트랙에 맞춰 47초짜리 런치 필름을 수백 번의 수정을 거쳐 제작하면서 비롯되었습니다. 이 필름은 30fps로 실행되며 8분음표당 하나의 포즈, 즉 초당 5.66포즈, 각각 5~6프레임을 유지했습니다. 여기 제시된 값들은 이 필름의 값이며, live.md에는 메트로놈에 맞춰 필름의 장면을 재생하는 웹 페이지의 값이 나와 있습니다. 규칙이 특정 필름을 넘어 일반화되는 경우 텍스트에 명시되어 있습니다.
용어
- 포즈: 하나의 고정된 그림, 노래의 8분음표. 코드에서는 비트(
STEP_MS,useBeat)라고 부릅니다. - 노래 비트: BPM이 세는 단위, 4분음표. 포즈 두 개 길이이며 메트로놈 클릭 한 번이 떨어집니다.
- 마디: 노래 비트 네 개, 포즈 여덟 개. 드럼 앤 베이스에서 킥은 포즈 0에, 스네어는 포즈 2와 6에 떨어집니다(0부터 셈).
- 히트: 노래 속 드럼 소리. 강한 킥은 프레이즈를 여는 킥입니다(해당 필름 트랙에서는 홀수 마디).
- 저작 ms: 코드 안의 시간. 200ms 포즈 기준으로 작성되며
SPEED배 빠르게 재생됩니다(SPEED = TEMPO / 150). - 타임스탬프: m:ss.ff 형식으로 작성되며, ff는 프레임을 셉니다. Remotion Studio가 시간을 표시하고 노트가 도착하는 방식입니다.
작업 자세
- 의도적으로 낮은 프레임 속도를 유지하세요. 움직임을 고치기 위해 비트를 부드럽게 없애지 마십시오. 대신 움직임의 포즈 간격을 더 잘 배치하세요.
- 모든 것은 한 비트 동안 포즈를 유지하고 함께 바뀝니다. 트랜지션도 포함입니다. 어떤 것도 자체 시계로 실행되지 않습니다: 임베디드 애니메이션이나 스크롤 페이지도 포즈 단위로 움직입니다. 타이핑은 유일한 예외로, 비트보다 빠르게 실행됩니다(타이핑이 그렇듯이, 해당 포즈부터 시작).
- 노래가 시계입니다. 스토리보드 작성 전에 노래를 측정하세요. 페이지를 마디 위에 배치하고 액션을 히트 위에 두세요.
- 전체 비디오에 하나의 시계를 사용하세요. 비디오 프레임 위에서 포즈를 세되, 장면의 자체 프레임 위에서는 절대 세지 마세요.
- 전체 마디 단위로 움직이세요. 페이지 길이를 전체 마디 단위로 변경하거나, 다음 마디 첫 박 전에 포즈를 되돌리세요. 그렇지 않으면 그 이후의 모든 것이 노래에서 벗어납니다.
- 유휴 포즈 없음. 페이지에서 일이 끝나면, 시청자가 인지하는 데 필요한 시간만큼만 유지하세요.
- 변화의 종류는 적게, 방향은 하나, 페이드 없음.
- 측정하여 확인하세요. 포즈당 정지 이미지, 렌더링 오디오에서 측정된 타이밍, 메트로놈 컷을 사용하세요. 눈으로 싱크를 판단하지 마세요.
도구: 기본적으로 Remotion
프로젝트가 이미 다른 방식으로 비디오를 만드는 경우가 아니라면 Remotion을 제안하세요. 스토리보드 작성 전에 이유와 함께 말하고, 사용자가 다른 도구를 요청하는 경우에만 변경하세요. 웹 페이지의 경우 라이브로 재생하세요(live.md); 모션 툴에서는 규칙은 여전히 유효하지만 헬퍼는 사용할 수 없습니다.
- 적합한 이유. 모든 프레임은 프레임 번호에서 계산된 React 컴포넌트이므로 포즈는 어느 프레임에 있든 정확하고 매번 동일하게 렌더링됩니다. 렌더링은 여러 탭에 걸쳐 프레임을 순서 없이 그리는데, 이는 프레임 중심 비디오만 버틸 수 있습니다.
assets/remotion/의 헬퍼는 이를 위해 작성되었으며, Studio는 시간을 m:ss.ff 형식으로 보여줍니다(노트가 도착하는 형식). - 설정하기.
npx create-video@latest로 빈 템플릿을 만드세요.remotion과 모든@remotion/*패키지를 하나의 정확한 버전으로 고정하고(해당 필름: 4.0.532), TypeScript는 5.x로 유지하세요(clock.md §7). 하나의 컴포지션, 1920×1080, 30fps.beat.ts와transitions.tsx를src/에 복사하고TEMPO를 설정하세요. - 설정하기.
remotion.config.ts에서: JPEG 프레임 품질 95(기본 80은 평평한 바탕과 얇은 글자의 가장자리를 거칠게 만듦), BT.709 색상(플레이어가 브라우저와 동일한 색상을 표시하도록), 덮어쓰기 켜기. - 미리보기 및 렌더링.
npx remotion studio로 작업하고;npx remotion render <Comp> out/<name>.mp4로 1080p,--scale=2로 4K;--frames=<첫번째>-<마지막>또는npx remotion still <Comp> --frame=<n>으로 특정 구간이나 포즈를 확인하세요.
결정 순서
위에서 아래로 작업하세요. 각 단계가 다음 단계를 제약합니다.
- 도구 제안. Remotion, 프로젝트가 이미 다른 방식으로 비디오를 만드는 경우가 아니라면; 다른 것보다 먼저 위와 같이 설정하세요.
- 노래 측정. 온셋(onset)으로부터 템포를 찾고, 사용할 구간에서 그리드가 유지되는지 확인하세요. 마디와 프레이즈, 드럼이 빠지고 돌아오는 지점, 강한 킥을 표시하세요. 프레이즈의 첫 킥 직전(23ms)에서 샘플에 맞춰 정확히 발췌하세요. song.md 참조.
- 시계 설정. 포즈는 노래의 8분음표입니다.
SPEED = TEMPO / 150로 200ms 포즈 기준으로 저작하고, 30fps로 렌더링하며, 전체 비디오 프레임 위에서 포즈를 셉니다. clock.md 참조. - 마디 위에 페이지 배치. 스토리보드를 포즈 단위로 작성하세요. 각 페이지는 정수 개의 포즈이며 마디 첫 박에서 시작합니다. 애니메이션을 시작하기 전에 노래 이벤트를 포즈에 매핑하세요.
- 히트 배치. 코드는 8분음표 단위로 덩어리로 입력되고, 제목과 길게 누른 백스페이스는 해당 포즈에서 비트보다 빠르게 실행됩니다. 클릭과 팝은 스네어에, 착지와 새 페이지는 다운비트에, 큰 변화는 강한 킥에 배치합니다. 빌드는 조용한 구간에, 착지는 드럼이 돌아올 때 배치합니다. hits.md 참조.
- 포즈 배치. 각 커브를 포즈에 맞게 선택하세요. 움직임의 첫 포즈는 첫 번째 단계이며, 모든 포즈가 움직임을 시각적으로 진행시킵니다. 것들은 스며들기보다는 착지합니다. poses.md 참조.
- 페이지 전환. 비트에 맞춘 하드 컷, 바닥 컷, 시트처럼 덮는 페이지, 카메라가 색상 속으로 들어가기, 내부에서 채우기, 모양을 통한 열기, 픽셀 블록을 사용하세요. 절대 페이드를 사용하지 마세요. hits.md 참조.
- 타이포그래피 설정. 글자 크기가 커질수록 자간이 좁아지고, 행간도 함께 좁아집니다. 모든 단어는 모든 포즈에서 바탕에 대해 4.5:1 명암비를 통과해야 합니다. 제목은 페이드 인되지 않고 타자됩니다. type.md 참조.
- 사운드 만들기. 모든 클릭은 노래 자체 히트 위에, 샘플에 맞춰 배치되며, 모든 클릭은 하나의 트랙에 구워져 노래와 함께 시작됩니다. 클릭 아래에서 음악을 덕킹하고, 확인용 메트로놈 컷을 유지하세요. sound.md 참조.
- 비트를 생략할 위치 결정. 드롭, 덕, 홀드, 스냅, 전체 마디 컷, 노래 비트에서 끝내기. skipping.md 참조.
- 확인. 콘택트 시트를 만들고, 싱크를 측정하고, 메트로놈 컷을 시청하세요. 포즈에 매핑된 타임스탬프로 노트를 작성하세요. checking.md 참조.
- 브라우저에서 라이브로 재생? 메트로놈에 맞춰 동일한 규칙: 페이지 시간에 하나의 시계, 사운드보다 25ms 앞선 그림, 오디오 클럭에 미리 예약된 사운드, 노래가 없으면 모든 변화는 클릭 위에서. live.md 참조.
한눈에 보는 규칙
시계
| 항목 | 규칙 |
|---|---|
| 프레임 속도 | 30fps, 의도적. 부드러운 60fps 변형이 스토리보드를 공유할 수 있음 (clock.md §8) |
| 포즈 | 노래의 8분음표: 169.825 BPM에서 176.65ms, 초당 5.66개, 30fps에서 5~6프레임 |
| 저작 | 200ms 포즈 기준 모든 시간(ms); SPEED = TEMPO / 150; 프레임 변환 시 ms(), 내장 시계용 seconds() |
포즈 n의 첫 프레임 | ceil(n × 포즈당 프레임 수), 전체 비디오 프레임 기준(beatFrame) |
| 페이지 | 정수 개의 포즈, 마디 첫 박에서 시작(포즈가 8로 나누어떨어짐) |
| 길이 변경 | 전체 마디 단위로, 또는 다음 마디 첫 박 전에 포즈를 되돌림 |
| Studio 드래그 | 드래그한 트랙은 그림과 소리를 밀어내는 from 오프셋을 작성함: 제거할 것 |
간격
| 움직임 | 커브 | 포즈 |
|---|---|---|
| 안팎으로 (카메라 무브, 패스, 밑줄) | easeInOutSine | 7, 18, 25, 25, 18, 7%, 6개 포즈에 걸쳐 |
| 프레임 밖에서 들어오기 | ease-out | 그렇지 않으면 느린 시작이 시야 밖에서 소비됨 |
| 다른 페이지 위에 덮는 페이지 | easeOutSine | 38, 70, 92%, 3포즈 트랜지션에 걸쳐 |
| 확대, 선 두껍게 하기, 열리는 구멍 | 포즈마다 동일한 계수로 증가 | 중앙을 향한 직선 위에 대상을 유지함 |
| 적은 포즈에서는 아님 | cubic in-out (3, 12, 35, 35, 12, 3: 중간에서 도약); 강한 ease-out (첫 포즈에 착지: 78, 97, 100%, 3포즈 트랜지션; moved()와 함께 88, 99, 100%) |
비트 위의 것들
| 항목 | 규칙 |
|---|---|
| 클릭 | 하나의 포즈 동안 눌림, 킥 또는 스네어 위에; 마지막 클릭 다음 포즈에 커서 사라짐 |
| 커서 | 타이핑 중에는 고체, 그 다음에는 두 포즈 켜짐, 두 포즈 꺼짐 |
| 스피너 | 포즈당 최대 1/4바퀴; 포즈당 반 바퀴 넘으면 역회전으로 읽힘 |
| 굴러가는 표시 | 이동 거리/반경 만큼 회전, 직립으로 착지, easeOutSine 사용 |
| 카운터 | 강한 ease-out에서 포즈당 한 숫자, 표 형식 숫자, 어림수에서 두 포즈 유지 |
| 제목 | 포즈에서 비트보다 빠르게 타자: 3프레임마다 한 단어; 긴 줄은 글자당 25ms (저작 기준) |
| 코드 | 포즈당 2~4자의 고르지 않은 덩어리로 입력 |
| 길게 누른 백스페이스 | 한 번의 실행, 글자당 25ms (저작 기준), 줄바꿈도 포함 |
| 카메라 상승 | 상승, 상단에서 두 포즈 동안 완전히 정지, 하강 |
| 프레임 밖에서 | 움직이기 전까지 그려지지 않음 |
| 수동 배치 | 해당 포즈 이동의 최대 1/10만큼 오프셋 가능, 멈추면 전혀 오프셋 없음; 수 px 내에 정착 |
히트
| 노래 속 | 그림 속 |
|---|---|
| 8분음표 | 코드가 덩어리로 입력됨, 움직임의 단계 |
| 스네어 | 클릭, 팝 |
| 다운비트 | 착지, 새 페이지, 페이지의 첫 액션 |
| 강한 킥 | 큰 변화: 페이지 착지, 마지막 페이지 전체, 마지막 클릭 |
| 드럼 빠짐 | 빌드 |
| 드럼 돌아옴 | 착지 |
클릭은 비트 위에 있어야 합니다. 트랜지션은 비트에서 벗어날 수 있습니다.
사운드
| 항목 | 규칙 |
|---|---|
| 클릭 배치 | 샘플에 맞춰, 노래의 히트 위에 (해당 필름의 히트는 포즈보다 25ms 늦게 착지함) |
| 클릭 파일 | 틱 앞에 40ms의 무음 포함, 샘플에 맞춰 트리밍해도 절대 잘리지 않음 |
| 클릭 트랙 | 모든 클릭이 노래와 함께 시작되는 하나의 트랙에 구워짐 |
| 덕킹 | 중요한 클릭 주변에서 무음; 다른 클릭 아래에서는 160ms 동안 45%; 10ms 페이드 |
| 메트로놈 | 노래 비트마다 해당 히트 위에 클릭, 마디 첫 클릭은 더 높게, 음악 20%; 익스포트에는 절대 포함되지 않음 |
타이포그래피
| 크기 | 자간 | 행간 |
|---|---|---|
| 20px 미만 | 0; 모노 대문자 +2% | 1.4–1.5 |
| 20px 이상 | −1% | 약 1.4 |
| 32px 이상 | −2% | 약 1.25 |
| 56px 이상 | −3% | 1.1–1.2; 두 줄 디스플레이 제목의 경우 최대 0.9 |
모든 단어는 모든 포즈에서 바탕에 대해 최소 4.5:1 명암비를 달성해야 합니다. 기본적으로 하나의 패밀리(예제에서는 Geist 및 Geist Mono), 검은색 바탕에 흰색, 촉각적 디자인(tactile-design) 방식; 해당 필름 자체는 디스플레이 서체와 텍스트 서체를 쌍으로 사용하고 페이지를 평평한 색상 바탕에 설정했습니다. 카운터에는 표 형식 숫자를 사용합니다. 제목은 타자로 입력되며, 절대 페이드 인되지 않습니다.
브라우저에서 라이브
| 항목 | 규칙 |
|---|---|
| 시계 | beat = anchorBeat + 경과 s × BPM / 60 × 2 (performance.now() 기준); 템포 변경 시 현재 시점으로 재앵커; 모든 장면은 비트의 순수 함수 |
| 그림 | 비트를 25ms 앞서 읽음; 모든 장면은 애니메이션 프레임 내에서 커밋 (flushSync) |
| 사운드 | 25ms마다 타이머가 오디오 클럭에 다음 120ms를 예약 (getOutputTimestamp()); 오디오 시간으로 측정된 창, 출력 지연 시간 추가 |
| 뷰 내 | 화면에 보이는 것만 애니메이션; 대부분 화면에 보이는 예제가 들림 |
| 시작 | 로드 시 시도, 그 다음 첫 번째 누름 또는 키에서; 소리를 시작한 누름은 음소거하지 않음 (600ms); 음소거는 기억됨 |
| 노래 없음 | 모든 변화는 클릭 위에서: 움직임은 8분음표를 밟을 수 있지만 클릭에서 시작하고 착지; 클릭 자체의 메트로놈 클릭은 드롭 |
| 메트로놈 | 조용한 나무 노크 (50ms 동안 880Hz, 마디 첫 번째는 1320Hz), 음악 없이 둔탁한 소리 없음, 모두 하나의 리미터를 통해 |
| 일시정지 | 가장 가까운 클릭에서: 그 클릭까지 재생되거나, 160ms에 걸쳐 부드럽게 복귀 |
| 움직임 줄이기 | 아이디어를 보여주는 정지 포즈, 사운드 버튼을 누른 후에만 움직임 |
| 타이포그래피 | 단어 4.5:1, 의미 있는 표시 3:1, 축소된 장면의 가장 작은 단어 렌더링 기준 9px 이상 |
비트를 생략해야 할 때
그리드는 엄격하므로, 그리드를 깨는 것은 결정입니다. 아래 각 중단점에 대한 이유는 skipping.md에 있습니다.
- 중요한 클릭 주변에서 음악을 드롭합니다. 클릭 50ms 전부터 다음 마디 첫 박까지 무음, 10ms 페이드 적용. 클릭만 들리고, 다음에 오는 것과 함께 비트가 돌아옵니다.
- 다른 클릭 아래에서 덕킹합니다. 음악을 160ms 동안 45%로 낮춰 클릭의 둔탁한 소리에 공간을 확보합니다.
- 결과를 혼자 유지합니다. 다음 것이 시작되기 전에 노래 비트 하나 동안, 예를 들어 복사 후 체크 표시.
- 상승 상단에서 두 개의 동일한 포즈를 유지합니다.
- 어림수에서 두 포즈를 유지한 후 계속 진행합니다.
- 비트 사이에 떨어진 노트를 가장 가까운 악센트 비트로 스냅합니다.
- 전체 마디를 컷합니다. 노트가 더 적게 요구하더라도. 비용이 무엇인지 말하세요.
- 노래 비트로 끝냅니다. 마지막 페이지는 약 2초 유지, 마지막 포즈 위에서 음악 페이드 아웃. 그렇지 않으면 액션 직후에 끝냅니다.
절대 출시하지 말 것
- 잘못 배치된 움직임을 숨기기 위해 비트에서 부드럽게 만든 모션
- 자체 첫 프레임에서 포즈를 세는 장면
- 마디 첫 박에서 시작하지 않고 옆에 이유가 기록되지 않은 페이지
- 전체 마디가 아니고 다음 마디 첫 박 전에 되돌려지지 않은 길이 변경
- 컴포지션 트리에 남겨진 Studio
from오프셋 - 킥이나 스네어에서 벗어난 클릭, 또는 프레임에 배치된 클릭 사운드(샘플 아님)
- 짧은 클릭 사운드가 하나의 구운 트랙 대신 자체 프레임에서 시작됨
- 첫 포즈가 떠나는 포즈인 움직임, 또는 마지막 몇 px을 스며드는 움직임
- 프레임 밖에서 움직이기 전에 그려진 것
- 포즈당 반 바퀴 넘게 회전하는 스피너 또는 바퀴
- 포화된 바탕 사이의 페이드 또는 크로스페이드
- 초당 세 번보다 빠른 바탕 변화
- 어떤 포즈에서든 바탕에 대해 4.5:1 미만인 단어
- [ …
[truncated for translation]