툰 릴 (Toon reel)
당신은 toon-reel-engine으로 짧은 애니메이션 스토리를 연출하고 제작합니다. 모든 것은 Python입니다:
캐릭터, 세트, 조명, 카메라는 코드로, 모든 프레임은 시간 T의 순수 함수입니다. 타임라인
에디터나 키프레임 UI는 없습니다. 데이터(키, 샷 테이블)를 작성한 다음 프레임을 확인합니다.
엔진의 레이아웃 (유지하세요: 상대 임포트가 이것에 의존합니다):
tools/toon/ 엔진: toon.py (렌더러), rig.py (캐릭터), anim.py (타이밍), cast/ props/ sets/ (키트)
tools/ sound.py (큐에서 스템 생성), mix_check.py (음성 명료도), finish.py (-14 LUFS 내보내기),
thumb.py (커버), find_phrases.py (내레이션 테이크의 구절 시간)
episodes/starter/toon 템플릿: "The Lamp", 12.5초, 4개 샷, 방 1개, 1명. 이것을 복사하여 시작하세요.
episodes/window/toon 전체 예제: "The Man at the Window", 50초, 13개 샷, 두 세계와 반전.
episodes/jeff, episodes/smilingman 전체 예제와 키트가 임포트하는 지원 모듈 (실행 가능한 에피소드는 아님)
명령어. 아래 python은 requirements.txt가 설치된 인터프리터를 의미합니다 (Windows에서는 py).
에피소드 자체 스크립트(reel.py, build_tl.py, finalize.py)는 에피소드 폴더
episodes/<name>/toon에서 실행됩니다. 도구는 프로젝트 루트에서 실행합니다: python tools/sound.py episodes/<name>/toon.
첫 번째: 엔진 찾기 또는 설정
플러그인의 설치 폴더 내부가 아닌, 사용자 자신의 프로젝트 폴더에서 작업하세요 (업데이트 시 교체됨).
- 작업 폴더에 이미
tools/toon/toon.py가 있으면 사용하세요. - 그렇지 않으면 엔진이 이 스킬과 함께 제공됩니다. 그 루트는 이 스킬의 기본 디렉토리보다 두 폴더 위에 있습니다
(
<skill dir>/../..:tools/,episodes/,requirements.txt및.gitignore를 포함합니다). 그 네 개를 작업 폴더에 복사하고 레이아웃을 유지한 후, 사용자에게 알리세요. 해당 폴더에tools/가 없으면 (스킬이 단독으로 복사된 경우) 대신https://github.com/wlr2/toon-reel-engine을 클론하세요. pip install -r requirements.txt를 실행하고ffmpeg -version이 작동하는지 확인하세요 (5.1 이상). 자막은 Arial Black이 필요하거나,TOON_FONT를 두꺼운 산세리프.ttf로 설정하세요.- 무엇이든 만들기 전에 설정을 증명하세요.
episodes/starter/toon에서:python build_tl.py, 그런 다음python reel.py --frame 5.0을 실행하면review/_f5.00.png가 생성되어야 합니다.
순서는 고정됨
스크립트 -> 타임라인 -> 캐스트 시트 + 세트 프레임 -> 블로킹 -> 체크 (2회) -> 프리뷰 -> 마스터 -> 사운드 -> 마무리 -> 포스트.
마스터 렌더는 체크를 통과하고 기록되기 전에 절대 시작되지 않습니다. 애니메이션을 시작하기 전에 사용자에게 캐릭터 시트와 세트 프레임 하나를 보여주고, 풀 해상도 프레뷰 전에 레이블이 지정된 키프레임 시트를 보여주세요. 무엇이든 돈을 쓰기 전에 (유료 TTS, 유료 SFX, 클라우드 렌더) 물어보세요.
1. 스크립트 (references/script.md)
10단계 방법: 가장 구체적인 모순으로 시작, 하나의 주요 질문, 결과의 연쇄, 몇 초마다 변화, 말하기 및 애니메이션을 위해 작성, 움직이는 중간, 마지막 시그니처 대사로 얻은 결말, 정직한 프레이밍 (크리피파스타의 경우 "AN INTERNET HORROR STORY"), 시간이 지정된 샷 테이블, 그 다음 보존 편집. 사용자가 스크립트나 비트 시트를 건네주면, 그들의 단어와 그들의 사양이 여기의 하우스 룰보다 우선합니다: 그들의 대사를 다시 쓰지 말고, 변경 사항을 제안하고 변경할 내용을 인용하세요.
산출물: SCRIPT.md (세 개의 훅 + 선택, 전체 내레이션, 시간이 지정된 샷 테이블, 단어 수) 및 script.py.
2. 타임라인, 그 다음 음성
script.py는PHRASES(각 대사가 배치되는 위치, 텍스트, 빨간색 키워드에[word]가 있는 자막 청크)와MARKS(초 단위의 스토리 비트, 샷 경계가 됨)를 보유합니다.python build_tl.py는timeline.json(total,marks,lines)을 작성합니다. 릴은timeline.json만 읽습니다. 스타터에서는 오디오가 존재하기 전에 작동합니다: 구절 길이는 단어 수에서 추정되므로 먼저 그림을 블로킹할 수 있습니다.- 음성은 스피커당 하나의 테이크, 48kHz 모노이며, 모든 TTS 또는 마이크에서 가져옵니다 (이 저장소는 제공하지 않음; ElevenLabs는 유료, Kokoro는 무료 및 로컬). 절대 테이크를 속도를 높여 맞추지 마세요. 대신 비트를 자르세요. TTS에 보내는 텍스트에서 숫자를 단어로 표기하세요.
python tools/find_phrases.py take.wav는 테이크에서 각 구절의(start, end)를 출력합니다. 그것들을PHRASES에 넣고build_tl.py를 다시 실행하세요: 구절을 잘라내어 배치하고audio/narration.wav를 작성합니다. 그런 다음 각 샷을 다시 확인하세요: 실제 구절 길이는 추정치와 다릅니다.- 제공된
build_tl.py파일은 한 명의 내레이터를 처리합니다. 여러 스피커의 경우 스피커당 하나의 테이크를 유지하고 각 구절에 스피커를 추가하세요 (build_tl.py의 작은 변경). - TikTok용 욕설: 별도 스템에서 비프음 처리하고 자막에서 별표 처리하세요 (
f***ing).
3. 에피소드 파일 (references/engine.md)
| 파일 | 역할 |
|---|---|
script.py | 대사, 자막 청크, 마크 |
build_tl.py | timeline.json (+ audio/narration.wav) |
looks.py | 캐스트: 각 룩은 rig.LOOK의 딕셔너리 |
scenes.py | 세계: 세트 지오메트리, 조명, 시간 T에 누가 어디에 있는지, 연기 트랙 |
reel.py | SHOTS, 자막, render(T), 체크, 렌더 명령어 |
cues.py | tools/sound.py용 사운드 이벤트 |
finalize.py | 스템을 믹스하고 렌더에 먹싱, tools/finish.py 실행 |
episodes/starter/toon을 episodes/<name>/toon에 복사하여 새 에피소드를 시작하세요.
reel.py, build_tl.py 및 finalize.py는 일반적이며 그대로 둘 수 있습니다. script.py, looks.py, scenes.py,
SHOTS 테이블 및 cues.py를 교체하세요. episodes/window/toon에서 시작하지 마세요: reel.py, cues.py 및 체크는
그 스토리(두 개의 거울 세계, 명명된 마크, 사용자 정의 트위스트 카메라)에 연결됩니다. 기술을 위해 읽으세요: 텍스처,
피사계 심도, 세계별 얼굴 키, 유리 위의 손, 세계 간 크로스페이드. 더 큰 에피소드는 연기를 scenes.py에서 acting.py로
이동합니다.
세계는 두 가지 메서드가 필요합니다: 모든 것을 그리고 {pid: rig.draw 결과}를 반환하는 draw(fr, cam, T)와
[(pid, look, pose)]를 반환하는 cast(T). pid는 이 에피소드에서 사람의 ID입니다 ("nora"). 위치당 하나의 세계와
하나의 타임라인; 샷만 카메라를 선택합니다.
4. 룩 (references/look.md)
둥글고 단순한 모양, 약간 큰 머리, 크고 표현력 있는 눈, 부드러운 3-스톱 음영과 기본 색상의 더 어두운 윤곽선이 있는
무광 재질. 각 캐릭터는 스크립트에서 디자인된 고유한 실루엣, 얼굴 및 팔레트를 얻습니다 (다른 릴의 캐릭터를
재스킨하지 않음); 반복 캐릭터는 모델에 충실합니다. 애니메이션 전에 모델 시트를 만드세요. tools/toon에서:
python -m cast.sheet ../../episodes/<name>/toon/looks.py <look> (프로젝트 루트에 assets/kit/cast/<look>.png를
작성하거나 세 번째 인수로 지정한 경로에 작성).
5. 조명 (references/lighting.md)
모든 위치에 세 개의 레이어: 차가운 환경 (청자색 밤은 디테일 유지), 모든 얼굴에 부드러운 키 라이트 (위앞에서, 램프나 창문에 의해 동기 부여됨), 그리고 다양한 거리의 따뜻한 실용 조명으로 근처를 비춤. 얼굴은 프레임에서 가장 선명한 것; 배경은 주변보다 약간 더 어둡고 대비가 낮습니다. 발, 가구 및 닿는 손 아래의 접촉 그림자. 위치당 하나의 조명 설정: 방향, 색상 및 노출은 컷 전반에 걸쳐 유지됩니다. 블룸, 빛나는 윤곽선, 찌그러진 검은색 없음. 날씨 (비, 눈, 바람)는 스토리에 날씨가 있을 때 조용한 순간에 애니메이션됩니다.
6. 카메라 (references/camera.md)
- 2-3초마다 컷. 각 샷은 하나의 동작, 하나의 표정 또는 하나의 폭로를 제공합니다.
- 훅 (0-3초)은 릴에서 가장 아름다운 움직이는 샷: 카메라와 캐릭터가 프레임 1부터 움직입니다.
- 투샷 먼저, 그 다음 매칭 클로즈업. 클로즈업은 시선 방향에서 ~35도 이내를 유지합니다.
track(a, b, ease)는 두 키(position, target, focal px, horizon)사이에서 하나의 깔끔한 움직임을 만듭니다. 카메라는 타겟을 향해 회전하지만 기울일 수 없음: 타겟의 높이는 무시됩니다. 카메라 높이와horizon으로 위아래를 프레이밍합니다 (값이 작을수록 시선이 프레임에서 더 높아져 내려다보는 것으로 읽힘).- 시야에 있는 사람으로부터 카메라를 >= 0.45m 유지:
rig.draw는 그보다 가까운 사람을 그리지 않습니다. - 자막 (Arial Black 66px, 흰색, 검은색 윤곽선, 키워드 #FF4D4D)은 얼굴이나 손 위에 절대 놓이지 않습니다.
cap=(y, size)으로 샷별로 이동하세요.
7. 연기 및 연출 (references/acting-staging.md)
모든 동작은 오프셋이 있는 체인: 눈 -> 머리 -> 어깨 -> 몸통 -> 손, 준비 -> 움직임 -> 안정. 반응은
out/snap으로 이즈, 안정은 back으로. 머리와 어깨만 돌리는 사람은 기본 발로 설 수 있음;
걷거나 몸을 돌리는 사람은 세계 공간에 발을 고정해야 함 (rig.replant 또는 rig.gait에서 ankle_R/ankle_L),
한 발씩. 무언가를 블로킹하기 전에 연출 교훈을 읽으세요: 각각은 이미 발생한 결함입니다.
8. 체크: 모든 마스터 전의 관문 (references/checks.md)
python reel.py --check-> 전체review/reel_checks.txt를 읽으세요. 스타터에서 모든 문제는ANOMALY라인입니다: 도달, 가라앉는 발, 과도하게 구부러진 팔꿈치, 팔꿈치 및 무릎 뒤집힘, 점프, 렌즈에 너무 가까운 사람, 얼굴이나 손 위의 자막.python reel.py --stills-> 각 샷의 첫/중간/마지막 프레임 (1차).python reel.py --sheet <SHOTS>-> 접촉 샷, 걷기, 회전 및 가려짐 변경의 모든 프레임을 간격 시트로 (2차). 분할, 튀어나오는 팔다리, 물체를 통과하는 머리, 사라지는 물체를 찾으세요.- 데이터에서 수정하고 다시 실행한 후 각 이상을
review/LOG.md에 기록하세요 (추가만): 시간, 샷, 원인, 수정, 확인 방법; 사유와 함께 승인된 플래그, 검사할 수 없었던 것. - 코드만으로 "이상 없음"을 주장하지 마세요. 코드는 관절을 확인하고 그림을 확인하지 않음: 사람이 가구나 서로를 통과하는 것, 손이 없는 소품, 잘못된 그리기 순서, 또는 0.8m 옆으로 이동하는 것이 분할로 읽히는 것을 보지 못합니다. 그것들은 시트에서 찾으세요.
9. 렌더링 (에피소드 폴더에서)
python reel.py --preview --full->review/reel_preview.mp4(1080x1920, 무음).python finalize.py preview는 믹스를 추가 ->review/preview.mp4. 보여주고 승인을 받으세요.python reel.py --master-par 12->video/reel_silent.mp4: 12개 프로세스로 마스터 (코어 수 사용).
10. 사운드, 믹스, 마무리, 포스트 (references/sound-finish.md)
cues.py, 그런 다음 프로젝트 루트에서python tools/sound.py episodes/<name>/toon-> 음악, SFX 및 앰비언스 스템. 실제 물건에는 실제 녹음 (CC0 또는 라이선스 샘플을assets/sfx/에 가져오기); 추상적인 드론, 라이저 및 붐에만 합성. 스타터의 큐는 모두 합성되어 체인이 실행됨: 교체하세요.python tools/mix_check.py episodes/<name>/toon: 모든 대사에서 음성이 배경음보다 >= 10dB여야 함 (실제 내레이션 테이크가 있을 때까지 모든 대사가 실패).python finalize.py final(에피소드 폴더) ->tools/finish.py-> -14 LUFS, <= -2 dBTP, H.264 High, +faststart.- 커버, 프로젝트 루트에서:
python tools/thumb.py frame.png cover.jpg --line "TITLE:#F2EFE6:120". POST.md: 플랫폼별 자막, 해시태그, 앱에서 HD 업로드를 켜라는 알림.
여기서 사용되는 용어
- 마크 (mark): 초 단위의 명명된 스토리 비트 (
MARKS), 샷 경계 및 동작 타이밍에 사용. - 스테이션 (station): 캐릭터가 서는 지점 (x, z, facing) 및 그곳으로 이동하는 시간.
- 고정된 발 (planted foot): 세계 위치에 고정된 발목 (
ankle_R/ankle_L), 발이 미끄러지지 않도록 함. - 클립 영역 (clip zone): 신체 일부를 무언가 뒤에 숨기는 화면 공간 클립 (울타리, 벽 모서리).
- 벽면 아이템 (wall-flat item): 벽에 평평하게 붙은 세트 장식 (커튼, 포스터); 벽만큼 뒤로 정렬.
- 실용 조명 (practical): 세트에서 보이는 광원 (램프, 불이 켜진 창문).
습관
- 주장하기 전에 보세요. 프레임을 렌더링하고 시트를 읽은 다음 본 것을 말하세요.
- 하나의 변경, 해당 샷의 한 번 재렌더, 한 번 재확인, 시트 포함.
- 연출이 계속 실패하면 단순화하거나 더 명확한 각도를 선택하세요. 절대 해부학을 블러, 어둠, 컷 또는 자막으로 숨기지 마세요.
- 사용자가 준 모든 수정 사항을 에피소드의
review/LOG.md에 기록하고, 일반적인 경우 프로젝트 루트의STAGING_NOTES.md에 기록하세요 (모든 에피소드 시작 시 읽음). 절대 플러그인의 자체 폴더에 쓰지 마세요.