What-If 릴 메이커은(는) 무엇을 하나요?
사용자가 한 줄(예: "달이 5초 동안 사라진다면?")을 입력합니다. 여러분은 나머지 모든 것을 처리하고 final.mp4(1080×1920, 30fps, 60초, 내레이션, 자막, 효과음 포함)와 Instagram용 caption.txt를 반환합니다. 아이디어가 불명확하지 않은 이상 질문하지 마세요. 합리적인 기본값을 선택하고 선택한 기본값을 명시하세요.
하우스 스타일은 코드(Three.js)로 제작된 로우폴리 3D 실제 위치입니다. 왼쪽 상단에 카운트다운 HUD, 이탤릭체 세리프 자막, 흰색 외곽선 검정 배경 "x-ray" 섹션, 큰 그림 장면(행성/우주/미시), 점진적인 여파, 그리고 팔로우 버튼이 있는 엔드 카드가 포함됩니다. 핸들: @the.whatif.studio.
0. 일회성 설정 (확인 후 누락된 것만 설치)
Node 18+, Python 3.10+ 및 PATH에 ffmpeg 필요(winget install ffmpeg / brew install ffmpeg).
프로젝트 루트: ~/whatif/ (없으면 생성). 공유 엔진 파일은 루트에 있으며, 각 동영상은 videos/<slug>/에 저장됩니다.
mkdir -p ~/whatif/models ~/whatif/videos && cd ~/whatif
npm init -y && npm i [email protected] playwright @fontsource/cormorant-garamond @fontsource/ibm-plex-mono
npx playwright install chromium
pip install kokoro-onnx soundfile scipy numpy
curl -L -o models/kokoro-v1.0.onnx https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/kokoro-v1.0.onnx
curl -L -o models/voices-v1.0.bin https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/voices-v1.0.bin
그런 다음 이 스킬의 engine/ 폴더에서 엔진 파일을 루트로 복사합니다(없는 경우, 섹션 9 참조). Windows에서는 python3 대신 python을 사용하세요.
1. 물리학 우선 (가장 중요)
댓글 작성자들은 과학을 확인합니다. 아무것도 작성하기 전에:
- 실제로 무슨 일이 일어나는지 파악하세요. 추론과 모든 숫자를
videos/<slug>/physics.md에 기록하고, 빠른 Python 계산으로 숫자를 검증하세요. - 직관에 반하는 트위스트를 찾으세요(예: 중력 차단: 처음에는 아무 일도 없는 것처럼 보이지만, 눌린 암석, 물, 공기가 바깥으로 튀어나오면서 그 밀어냄이 중력처럼 느껴짐). 트위스트가 훅입니다.
- 주요 주장은 웹 검색으로 확인하세요(가능할 경우). 불확실한 내용은 표현을 순화하고("몇 분 동안", "수 킬로미터") 정확한 수치를 절대 지어내지 마세요.
2. 스크립트 (videos/<slug>/script.json)
다음 60초 비트 템플릿을 따르세요(이야기에 따라 시간은 조정 가능):
| 시간 | 비트 | 시각 | HUD |
|---|---|---|---|
| 0–8 | 평범한 세계, 훅 | 위치를 천천히 돌리는 달리; 제목 0.2–3.9 | <이벤트>까지 카운트다운 8.00 S→0, 부제 = 위치 |
| 8.0 | 이벤트 발생 | 리플 + 크로마 펄스 | — |
| 8–28 | 이벤트 윈도우, 느리게 표시(예: 실제 5초를 4배속) | 처음은 일반 뷰, 이후 x-ray | <이벤트 종료>까지 5.00 S, 부제 4배속 느리게 · <실시간 통계> |
| 16–24 | 숨은 메커니즘 | 외곽선 모드 + 빛나는 입자 | 동일 |
| 24–28 | 큰 그림 | 별도 장면(행성/우주/세포), 흰색 플래시 인앤아웃 | 동일 |
| 28 | 복귀 | 플래시 + 붐 | <상태> / 복귀 |
| 28–52 | 여파 확대 | 흔들림, 균열, 파도, 파편 등 | 주요 통계(예: 176 KM/H) |
| ~46 | 결정타 | — | "그리고 네. <결과>." |
| 51.2–52 | 검은 화면으로 페이드 | ||
| 52–60 | 엔드 카드 | 사실 한 줄 + 더 많은 What-If를 위해 팔로우, ~57.3 버튼 누름 | — |
내레이션: 14–16줄, 초당 3단어 이하, 차분한 다큐멘터리 톤. 0.3초의 첫 줄은 제목 질문입니다. 엔드 카드에는 한 문장의 사실(~52.7)과 "더 많은 What-If를 위해 팔로우하세요."(~56.6) 두 줄이 있습니다. 자막은 내레이션 줄의 축약 버전입니다(2줄 이하, <br>로 구분).
{
"handle": "@the.whatif.studio",
"voice": "am_michael",
"title": "중력이 5초 동안 사라진다면?",
"titleEnd": 3.9,
"endTitle": "중력이 5초 동안 사라진다면?",
"endFact": "당신은 중력을 느끼지 않습니다. 당신은 땅이 밀어올리는 것을 느낍니다.",
"duration": 60, "endStart": 52, "press": 57.3,
"narration": [[0.3, "중력이 사라진다면... 5초 동안?"], [4.1, "지금 이 순간에도 중력은 이 공원의 모든 원자를 끌어당기고 있습니다."]],
"captions": [[4.1, 7.9, "지금 이 순간에도 중력은<br>이 공원의 모든 원자를 끌어당기고 있습니다."]]
}
3. 음성 먼저, 그다음 타이밍 수정
python3 gen.py <slug>를 실행하세요. videos/<slug>/audio/lNN.wav와 durs.json을 쓰고 각 줄의 길이를 출력합니다. 한 줄이 다음 줄이나 비트 변경과 겹치면 텍스트를 줄이거나 이동한 후 다시 실행하세요. 그런 다음 각 자막을 [start, start + duration + 0.35, text]로 설정합니다. 음성: am_michael(기본 남성), af_heart(최고 여성), bm_george(영국 남성).
4. 장면 빌드 (videos/<slug>/scene.js)
각 동영상마다 새 장면을 작성합니다. 반드시 build(h), update(t, h), hud(t)를 내보내야 합니다(템플릿은 섹션 9). 규칙:
- 결정론적: 빌드 시에만
h.rnd()/h.R(a,b)(시드 기반)를 사용합니다.update의 모든 것은t의 순수 함수여야 합니다.Math.random,Date또는performance.now를 절대 사용하지 마세요. - 슬로우 모션은 월드 타임으로:
w = t<8 ? t : t<28 ? 8+(t-8)/4 : 13+(t-28). 사람, 물, 구름을w로 애니메이션합니다. - 외관:
flatShading이 적용된 로우폴리 기본 도형. 실제 장소를 느슨하게 모델링합니다(부두, 공원, 거리, 해변). 건물은 상자(캔버스 창문 텍스처), 다양한 색상의 상자+구체 사람들, 인스턴스 트리, 흰색 구체가 있는 검은 가로등. 그라데이션 하늘 셰이더, 스프라이트 구름, 깊이감을 위한THREE.Fog, 그림자가 있는 태양DirectionalLight(그림자 카메라 ±45) +HemisphereLight를 추가합니다. - 카메라: 세로 FOV ~58, 눈높이 1.7–2.2m, 느린 달리와 부드러운 틸트. 여파에서는 합산 사인파로 흔들림을 추가합니다.
- X-RAY 단계:
outline: 0→1반환(~0.6초에 걸쳐 페이드). 적용되는 동안 건물 맵을null로 바꾸고 구름을 숨깁니다(노이즈가 많은 가장자리 방지). 선택적으로overScene반환: 선/입자를 위한 가산Points장면(depthTest false). - 큰 그림 장면: 두 번째 장면+카메라를 빌드하고 24–28초 동안
scene/camera로 반환합니다. - FX는
update에서 반환:flash(0–1 흰색),chroma,ripple+rp(링 반지름),fade(51.2–52에서 0→1). - 성능: 드로우 콜을 ~400 미만으로 유지하고(인스턴싱), 카메라 근처에 큰 투명 스프라이트를 많이 배치하지 마세요(오버드로우가 매우 느림).
- 하단 20%와 오른쪽 가장자리(Instagram UI)에는 텍스트를 배치하지 마세요. 자막은 y≈1240에 위치합니다.
5. 미리보기, 수정
node render.js preview <slug> 2,6,10,18,22,26,30,40,47,55를 실행하세요. JPEG를 videos/<slug>/prev/에 씁니다. 열어서 확인: 장소를 알아볼 수 있는지, 자막이 읽기 쉬운지, 외곽선 모드가 깔끔한지, 큰 그림 장면이 잘 구성되었는지, 여파가 드라마틱한지? 문제를 수정하고 다시 미리보기하세요. 스틸 이미지가 괜찮아 보일 때만 전체 동영상을 렌더링하세요.
6. 레이어 렌더링
장면(plate)과 텍스트(overlay)는 별도로 렌더링되므로 텍스트 수정 시 3D 재렌더링이 필요하지 않습니다.
# plate: 프로세스당 하나씩(CPU 코어 2개당), 각각 다른 PORT에서; 0..endStart까지만(나머지는 검정)
LAYER=plate PORT=8781 node render.js full <slug> plate1.mp4 0 26
LAYER=plate PORT=8782 node render.js full <slug> plate2.mp4 26 52
LAYER=overlay PORT=8783 node render.js full <slug> overlay.mov 0 60
이것들을 백그라운드에서 실행하고 로그를 폴링하세요. WebGL이 SwiftShader(느림, CPU)를 보고하면 HEADFUL=1을 시도하여 실제 GPU를 사용하세요.
7. 사운드 (videos/<slug>/mix.py)
섹션 9의 믹스 템플릿을 복사하고 EVENTS 블록을 비트에 맞게 편집하세요: 앰비언스, 카운트다운 틱, 이벤트 전 라이저, 이벤트 시 붐과 복귀, x-ray에서 샤머, 큰 그림 전 후샤, 럼블/크랙 또는 기타 여파 사운드, 엔드 패드와 버튼 팝. 내레이션을 자동으로 배치하고 음성 아래로 효과음을 덕킹합니다. 실행한 후 노멀라이즈:
python3 videos/<slug>/mix.py <slug>
ffmpeg -y -i videos/<slug>/mix.wav -af loudnorm=I=-14:TP=-1.5:LRA=11 -ar 48000 videos/<slug>/mix_norm.wav
8. 합성 및 전달
cd videos/<slug>
ffmpeg -y -i plate1.mp4 -i plate2.mp4 -f lavfi -t 8 -i "color=black:s=1080x1920:r=30" -i overlay.mov -i mix_norm.wav \
-filter_complex "[0:v][1:v][2:v]concat=n=3:v=1:a=0,format=yuv420p,setsar=1[b];[b][3:v]overlay=format=auto,format=yuv420p[v]" \
-map "[v]" -map 4:a -c:v libx264 -preset veryfast -crf 23 -c:a aac -b:a 192k -movflags +faststart -shortest final.mp4
(검정 클립 길이 = duration − endStart.) final.mp4에서 8–10 프레임을 추출하여 전달 전에 확인하세요. caption.txt를 작성하세요: 훅 한 줄, 실제 물리학에 관한 2–3 문장, "@the.whatif.studio를 팔로우하여 더 많은 what if를 확인하세요", 그리고 12–15개의 해시태그(#whatif #physics #science #3danimation …). 사용자에게 CapCut에서 15–20% 볼륨으로 조용한 음악을 추가할 수 있다고 알리세요.
9. 엔진 파일
재사용 가능한 엔진은 이 스킬의 engine/ 폴더에 있습니다. 파일을 복사하세요 — 다시 입력하지 마세요. 하나의 공유 엔진이 모든 동영상에서 재사용되며, 두 파일은 각 동영상별로 복사된 후 편집됩니다.
공유 엔진 (~/whatif/에 한 번 복사):
engine/index.html→~/whatif/index.htmlengine/main.js→~/whatif/main.jsengine/render.js→~/whatif/render.jsengine/gen.py→~/whatif/gen.py
동영상별 (각 새 동영상마다 복사한 후 편집):
engine/scene.template.js→videos/<slug>/scene.js— 각 동영상마다 장면을 다시 작성합니다(섹션 4 참조). 반드시build(h),update(t, h),hud(t)를 내보내야 합니다.engine/mix.py→videos/<slug>/mix.py— EVENTS 블록을 비트에 맞게 편집합니다(섹션 7 참조).
# SKILL_DIR = 이 스킬의 폴더; 프로젝트 루트(~ /whatif)에서 실행
cp "$SKILL_DIR"/engine/{index.html,main.js,render.js,gen.py} ~/whatif/
cp "$SKILL_DIR"/engine/scene.template.js videos/<slug>/scene.js
cp "$SKILL_DIR"/engine/mix.py videos/<slug>/mix.py
전달 전 품질 체크리스트
- 물리학 확인 및 숫자 계산 완료; 트위스트가 처음 15초 안에 명확히 드러납니다.
- 모든 내레이션 줄이 비트에 맞고 겹치지 않습니다; 자막이 내레이션과 일치합니다.
- 미리보기가 좋아 보였습니다; 최종 동영상이 8–10 프레임에서 점검되었습니다.
- 핸들 @the.whatif.studio가 표시됩니다; 엔드 카드가 작동하고 버튼 누름이 "더 많은 what if를 위해 팔로우하세요" 직후에 발생합니다.
- 음량은 약 −14 LUFS입니다; 음성이 효과음 위에 명확하게 들립니다.