손그림 애니메이션 영상
전체 워크플로우: 모든 프레임은 t(초)의 순수 함수이며, 브러시로 그려집니다(먹선, 평면 채색, 수채화 번짐, 해칭). 무헤드 Chrome이 프레임을 병렬로 이미지로 렌더링하고, ffmpeg가 MP4로 합성합니다. 예외는 유체 및 모래 애니메이션입니다. 이들은 프레임 간 시뮬레이션 상태가 존재하므로 처음부터 순차적으로 렌더링해야 합니다. 화면 속 어떤 이미지도 AI 생성 이미지가 아니며, 모두 코드로 그려집니다.
여덟 가지 엔진:
| 화풍 | 엔진 | 시작점 |
|---|---|---|
| 수채화·수묵화 (해칭으로 국소적 판화 느낌 가능) | p5.js + p5.brush, 속도는 카메라 움직임의 복잡도에 따라 크게 변동 | ClaudeAnimationBase (MIT) |
| 크레용·그림책·연속 그림 | 순수 2D canvas, 프레임당 10–50ms | 본 저장소의 crayon-kit/, crayon.md 참조 |
| 그림자극·실루엣·무대 | 순수 2D canvas, 프레임당 2–10ms, 꽹과리는 코드 합성 | 본 저장소의 piying-kit/, piying.md 참조 |
| 채색 수묵 격투 (무산오행풍) | 순수 2D canvas, 프레임당 20–100ms | 본 저장소의 inkfight-kit/, wushan.md 참조 |
| 과학 설명 영상 (도해·자막·더빙) | 순수 2D canvas, 프레임당 60–130ms, 효과음 코드 합성, 나레이션 edge-tts | 본 저장소의 explainer-kit/, explainer.md 참조 |
| 판화 시리즈 (공판·동판·청사진·스크린톤 등) | SVG, 프레임당 약 1초, 다중 경로 병렬 렌더링; 배경음악은 Tone.js + 실제 악기 샘플 사용 | 본 저장소의 prints-kit/, prints.md, music.md 참조 |
| 유체 채색 MV (음표 구동·추상) | WebGL2 안정 유체, 프레임당 약 65ms, 순차 렌더링만 가능 | 본 저장소의 fluid-kit/, fluid.md 참조 |
| 모래 그림 (조명 박스 투과·한 그림을 다음 그림으로 변환) | WebGL2 높이장, 프레임당 약 90ms 이상, 순차 렌더링만 가능 | 본 저장소의 sand-kit/, sand.md 참조 |
| 공책 낙서 (볼펜·색연필·촬영한 종이) | 순수 2D canvas, 전체 페이지를 미리 텍스처로 렌더링, 프레임당 2–10ms | 본 저장소의 doodle-kit/, doodle.md 참조 |
| 공점 몽타주 (화풍 릴레이) | Node + @napi-rs/canvas로 직접 프레임 생성, 브라우저 사용 안 함 | 본 저장소의 montage-kit/, montage.md 참조 |
참고 작품: PDoomVideo – 2분 30초짜리 MV로, Claude가 Claude Code에서 생성했습니다. 해당 저장소는 라이선스가 없으므로 학습만 가능하고 코드를 배포할 수 없습니다. ClaudeAnimationBase는 동일 작성자가 나중에 정리한 MIT 기반 코드입니다.
환경
- 이 skill은 paint-video-skill 저장소에서 가져왔습니다. 문서의
crayon-kit/,piying-kit/,inkfight-kit/,explainer-kit/,prints-kit/,fluid-kit/,sand-kit/,doodle-kit/,montage-kit/,examples/,tools/는 모두 그 저장소에 있으며, skill 디렉토리 안에 있지 않습니다. 로컬에서 찾을 수 없으면 사용자에게 저장소 클론 위치를 묻거나 새로 클론하세요. - Node 22.12 이상, Chrome 또는 Chromium (찾을 수 없으면
render.mjs에--chrome=<경로>전달, 또는CHROME_PATH설정), ffmpeg가 PATH에 있어야 합니다. - 자막 도구는 Python 3와 numpy, Pillow가 필요합니다.
npm install은 타사 코드를 다운로드하여 실행하므로, 설치 전에 사용자에게 물어보세요. 새 프로젝트를 시작할 때는 이미 설치된 템플릿 디렉토리를node_modules와 함께 통째로 복사하면 매번 다시 설치할 필요가 없습니다.
작업 시작 단계 (수채화 / 수묵화)
- 베이스 복사: 새 프로젝트 디렉토리로 복사하되
out,docs,.git은 제외합니다. Windows에서는robocopy <베이스> <새 디렉토리> /E /XD out docs .git /XJ를 사용하며, 종료 코드 1은 복사 성공을 의미합니다. - 먼저 새 디렉토리의
ANIMATION_GUIDE.md를 전체 읽기: 여기에 완전한 규칙과 API(paint(),inkLine(), 카메라, 장면 전환,clawd()의 모든 매개변수)가 있습니다. 여기서는 반복하지 않습니다. - 먼저
STORYBOARD.md작성 후 사용자에게 검토 받고, 그 다음 코드 작성: 가이드의 형식을 따릅니다: 한 줄 개요, 세계관과 색상, 관통 모티브, 감정 호, 컷별 '포인트' 시간표. 작성 전 같은 디렉토리의directing.md(연출 매뉴얼: 숏 사이즈, 액시스, 편집점, 리듬, 구도, 연기)를 읽고, 그 형식에 맞춰 컷별 표를 작성한 후 끝에 있는 체크리스트로 검토합니다. src/config.js의 길이와 bpm을 수정합니다. 씬은 새 파일src/scenes/<이름>.js로 작성하고, IIFE로 감싼 후 마지막에shots([...])를 호출합니다.studio.html에서demo.js행을 이 파일로 교체합니다.- 컷 하나씩 작업하고, 각 컷이 완료될 때마다 아래의 검사 루프로 확인합니다.
- 영상 출력:
node render.mjs --clip --out=out/video.mp4. 길이가 긴 경우--frames --workers=4로 병렬 렌더링한 후--encode로 합성합니다.
본 저장소 examples/brush/에는 완전히 실행 가능한 두 개의 씬이 있습니다: stars.js(《별을 줍다》, 14.5초, bpm 90)와 ink.js(《낙관》, 수묵화, 16.8초, bpm 80). src/scenes/에 넣고, studio.html에서 demo.js를 교체한 후 config.js의 길이와 bpm을 위 괄호 안의 값으로 변경합니다. 작성법만 참고하고 이야기는 그대로 따라 하지 마세요.
베이스에 적용된 두 개의 패치 (render.mjs의 ffmpeg 매개변수 두 곳과 Chrome 매개변수 한 곳):
- 출력을 표준 tv range로 변경:
'-pix_fmt', 'yuv420p'를'-vf', 'scale=out_range=tv,format=yuv420p', '-color_range', 'tv'로 교체합니다. 그렇지 않으면 일부 플레이어에서 완전히 검게 표시됩니다. - Windows 듀얼 그래픽 노트북에
--force_high_performance_gpu추가: 그렇지 않으면 Chrome이 내장 그래픽에서 실행되어 점점 느려집니다.crayon-kit/render.mjs에는 이미 이 두 패치가 적용되어 있습니다.
가장 중요한 규칙
모든 화풍에 공통
모델이 애니메이션을 만들 때 가장 자주 실수하는 부분:
- 프레임은 t의 순수 함수: 프레임이 순서 없이 병렬로 렌더링될 수 있으므로 프레임 간 상태가 있으면 안 되고,
Math.random()을 사용할 수 없습니다. 모든 난수는 시간과 요소 번호로 계산해야 합니다. - 순수 2D, 3D 투영 사용 안 함: 깊이는 가림, 크기, 난색/한색으로 표현합니다.
- 글자 쓰지 않음: 화면에 레이블, 간판, 글자가 있는 말풍선을 넣지 마세요. 표현하고 싶은 것은 그림으로 그리고, 이모트(
!,?, 땀방울, 전구)를 사용하세요. MV 가사 자막은 예외로, 별도 레이어로 겹쳐 올리며 방법은mv-workflow.md의 자막 섹션을 참조하세요. - 각 컷은 한 가지 사건을 담아야 함: 한 번에 한 가지만 보여주고, 먼저 원인이 있고 그다음 반응이 있어야 합니다.
- 시간 감각이 가장 자주 실패하는 부분: 관객은 한 번만 봅니다. 각 '포인트'에 찾고, 이해하고, 잠시 멈출 시간을 주세요. 빠른 것은 액션, 느린 것은 의미입니다. 첫 번째 버전은 거의 항상 너무 빠릅니다.
- 모든 이음매에는 장면 전환이 필요: 시작과 끝을 포함하여, 갑작스러운 시작이나 중단이 없어야 합니다. 장면 전환은 이야기와 관련되어야 하며, 매번 같은 방식을 사용하지 마세요. 격투 장면은 예외: 컷 간에 장식적인 전환 없이 액션 중간에 직접 전환합니다.
wushan.md참조. - 캐릭터는 크게: 1080p 화면에서 중간 숏은 캐릭터가 화면 높이의 약 1/3–1/2, 클로즈업 얼굴은 화면 높이의 절반 이상을 차지해야 합니다. 1/10 미만은 롱숏(원경)에만 사용합니다. 각 엔진의 크기 매개변수 의미가 다르므로 값을 혼용하면 안 됩니다.
p5.brush 전용 (수채화 / 수묵화)
베이스의 ANIMATION_GUIDE.md 출처:
- 고정 난수는
hash(i), 선 떨림은jit()을 사용합니다. 각 독립 요소 시작 시boilSeed(key)를 한 번 호출해야 합니다. 그렇지 않으면 움직이는 요소가 뒤따르는 모든 정적 요소를 함께 떨리게 만듭니다. - 모두 브러시로 그리기:
paint()와inkLine()만 사용하고, p5 기본rect,ellipse,fill()은 사용하지 마세요. 그렇게 하면 2000년대 플래시처럼 보입니다. - 방향 전환은 미리 그려진 몇 가지 키 포즈 뷰를 전환하여 수행합니다(
turn()). clawd()의u: 중간 숏 20–28, 클로즈업 40–70, 12 미만은 롱숏에만 사용합니다.
크레용 엔진의 API, 난수 및 캐릭터 크기는 다른 시스템이며, crayon.md를 참조하세요.
기본 미학
사용자가 스타일을 지정하지 않은 경우 다음을 따릅니다. 이 기준은 '종이와 먹'에 가깝습니다: 낮은 채도의 따뜻한 색상, 수공예 흔적, 절제된 동작. 사용자가 자신의 스타일 설명을 제공하면 그것을 우선합니다.
색상: 씬 파일 시작 부분에서 팔레트를 재정의합니다. 베이스의 기본 팔레트는 채도가 높은 편입니다(하늘색, 보라색, 장미색):
Object.assign(PAL, {
paper: '#f7f2e6', cream: '#faf7f0', ink: '#2e2a24',
clay: '#bb5f3c', clayDk: '#8f4428', clayLt: '#d98a6c', // 진흙 색; Clawd의 몸체가 이 색을 사용함
sky: '#a9bfc4', sap: '#8a9a6a', ochre: '#c9a25a', teal: '#6f9590',
rose: '#c98a8a', indigo: '#4a5670', night: '#262a38', violet: '#7d6f8f'
});
각 영상에서 3–5가지 색상을 골라 사용하면 충분하며, 모두 사용할 필요는 없습니다. 색상은 이야기 전개에 따라 변화하는 아크를 가져야 합니다. 예를 들어 차갑고 어두운 시작에서 따뜻하고 밝은 끝으로.
질감: 베이스에는 종이 질감과 입자가 기본 포함되어 있으므로 유지합니다. 해칭(hatch)은 판화 느낌에 적합하지만, 그림자와 국소적 부분에만 사용하고 화면 전체에 깔지 마세요.
풍부함 ≠ 싸구려:
- 화려할 수 있음: 한 컷 안에 많은 것들이 움직일 수 있습니다. 이것은 '연기형' 화면입니다.
- 싸구려가 되어서는 안 됨: 화려함을 위해 색종이, 별, 불꽃을 채우는 용도로 사용하지 마세요. 특수 효과는 이야기의 일부여야 합니다. 예를 들어 별이 떨어지거나, 불이 켜지는 것처럼.
- 자가 진단 방법: 이 요소를 제거하면 화면이 의미가 없어지는가? 단지 화려함만 줄어든다면 삭제하세요.
- 절제 ≠ 공허함: 여백은 계층이 있어야 합니다. 화면에는 환경, 전중후경, 질감이 있어야 하며, 종이 색상 위에 몇 개의 물체만 덩그러니 놓여 있어서는 안 됩니다. 한 컷은 한 가지만 보지만, 그 한 가지는 생활감 있는 세상 속에 배치되어야 합니다.
붓 터치는 손으로 그린 것처럼: 캐릭터는 가이드에 따라 평면 채색에 먹선을 사용해도 괜찮지만, 먹선이 영상 전체에서 동일한 굵기가 되어서는 안 됩니다: inkLine(pts, sw, colour, brush)의 sw는 거리와 주종에 따라 변화시키고, 디테일은 'inkfine', 'dry' 브러시로 변경합니다. 배경과 환경은 수채화 fill, wash로 건습 레이어를 만듭니다. 모든 것이 동일한 굵은 검은 선에 평면 채색이면 오려내기 그림처럼 보입니다.
변하지 않는 하나의 제약: 각 영상은 먼저 영상 전체를 관통하는 하나의 불변 요소를 정합니다. 예를 들어 동일한 구도 위치, 동일한 형태, 동일한 캐릭터 포즈 등을 정하고, 장면 전환과 매치 컷을 모두 이에 맞춰 수행하며, 끝은 시작을 반영합니다.
음악과 리듬: 베이스의 모든 것은 bpm에 맞춰져 있습니다. 배경음악이 없으면 bpm을 느리게(80–100) 가져가고, 리듬은 차분하게.
테스트 영상에서 배운 점
《별을 줍다》 (examples/brush/stars.js)
Clawd가 빈 항아리를 들고 떨어지는 별을 받으며, 항아리의 별빛이 밤을 조금씩 따뜻하게 만듭니다.
- 이모트는 수동으로 꺼야 함: 베이스의 excited, proud 표정은 머리 주위에 자동으로
spark불꽃을 생성하는데, 이는 싸구려 장식입니다.emotions(t, [[0, 'excited', { emote: null }], ...])로 끄세요.!,?, 하트 같은 의미 있는 반응은 유지해도 됩니다. - '따뜻해짐'을 하늘 전체를 따뜻한 색으로 바꾸는 것으로 표현하지 마세요: 밤하늘의 바탕색을 직접 갈색-노란색으로 혼합하면 전체 화면이 흙색으로 변해 더러워집니다. 하늘은 여전히 밤색으로 유지하고, 차가운 색만 약화시켜(
#4b4356쪽으로 혼합) 따뜻함은 지평선의 번짐과 빛나는 물체에만 둡니다. - 소품은 한눈에 알아볼 수 있어야 함: 어두운 배경 위의 유리 항아리를 처음에 회색으로 그리면 쓰레기통처럼 보입니다. 차가운 계열의 밝은 유리로 바꾸고 하이라이트를 추가해야 알아볼 수 있습니다.
- 조리개 마무리는 세 단계로: 먼저 주체에 맞추고, 잠시 멈춘 후, 닫습니다. 한 번에 0으로 가면 갑자기 화면이 꺼진 것처럼 보입니다.
- Clawd의 팔은 매우 짧아 머리 위의 물건에 닿지 않으며, 들어 올리는 동작은 마치 머리에 얹은 것처럼 보입니다. '받들다' 동작은 직접 그려야 합니다.
- 실제 속도 측정: 14.5초, 348프레임, 4개 프로세스 병렬 약 6분, 프레임당 약 1초(RTX 4060 노트북), ffmpeg 인코딩 10초. 연락표는 프레임당 0.1–1.7초로 매우 저렴하므로 여러 번 확인하세요.
《이슬을 빌리다》 (반면교사)
달팽이가 이슬을 지고 시든 묘목을 구하러 갑니다. 모든 규칙을 지켰지만(글자 없음, 불꽃 없음, 색상표 맞음, 캐릭터 변형 없음), 영상은 여전히 재미가 없었습니다:
- 이야기의 상태 변화는 한눈에 알 수 있을 정도로 과장되어야 함: 묘목이 처음부터 끝까지 거의 비슷하게 보여 '수분 부족으로 고개 숙임 → 물 마시고 활짝 핌'의 대비가 드러나지 않아 영상 전체의 인과 관계가 사라졌습니다. 중요한 상태의 전후 두 프레임을 나란히 놓았을 때 비전문가도 차이를 바로 알 수 없을 정도면 충분하지 않은 것이므로, 과장되게 수정해야 합니다.
- 이야기를 진행시키는 소품은 적어도 캐릭터 머리 크기만큼 커야 함: 이슬방울이 달팽이 눈보다 작고 색도 엷어 등껍질에 떨어지면 보이지 않았습니다. 소품이 작으면 카메라를 당기거나, 밝게 하거나, 윤곽선을 추가하세요.
- 스토리보드에 움직임이라고 쓰여 있으면 화면이 실제로 움직여야 함: 스토리보드에는 달팽이가 물을 지고 뿌리로 간다고 쓰여 있었지만, 실제 변위는 매우 작아 대부분 정지 화면처럼 보였습니다. 스토리보드와 대조하여 '누가 어디서 어디로'를 항목별로 확인하세요.
- 화면이 너무 비어 있음: 영상 전체에 묘목 하나, 달팽이 하나, 잎사귀 하나만 있었습니다. 위의 '절제 ≠ 공허함'을 참조하세요.
- 장면 전환에는 이유가 있어야 함: 이야기와 무관한 초록색 띠가 화면을 휩쓰는 것은 단지 형태만 바뀐 하드 컷에 불과했습니다.
작성 후 자가 점검: 각 컷의 첫 프레임과 마지막 프레임을 나란히 놓고, 이 컷에서 무슨 변화가 일어났는지 말할 수 없다면 재미없는 것이므로 사건을 더 부풀리세요.
《낙관》, 수묵화 (examples/brush/ink.js)
- 화풍을 바꾸려면 팔레트와 화법만 바꾸면 되고, 베이스는 건드릴 필요 없음: 영상 전체에 먹의 세 가지 농담과 Clawd의 주홍색만 사용했습니다. '만 먹 속의 한 점 붉은색'은 수묵화의 고전적인 기법이며, Clawd가 바로 그 붉은 점입니다.
- 먹이 번짐: 형태의 각 점이 찍힌 지점에서 시작하여 거리 순서대로 퍼져 나갑니다(
bloom()). '전체 형태가 서서히 나타나는 것(페이드인)'보다 훨씬 더 종이 위에서 먹이 번지는 것처럼 보입니다. - 수묵화의 레이어: 먼저 엷은 바탕색을 깔고, 산꼭대기에 진한 먹을 덧칠하여 아래로 희미해지게 하고, 산기슭에는 종이 색상의 안개를 누르고, 먼 산은 시차를 두고 더 느리게 움직이게 합니다.
- 세계가 캐릭터와 함께 한 획 한 획 자라남: 캐릭터가 가는 곳마다 갈대, 강, 돌이 그려지며, 사건 자체가 그림을 그리는 행위입니다. 이 방식은 각 컷의 시작과 끝 프레임에 명확한 변화를 보장합니다.
- 구도 제약도 끝 지점을 고려해야 함: 캐릭터가 앞길을 볼 수 있으려면 진행 방향의 뒤쪽에 서 있어야 하며, 끝까지 가면 자연스럽게 화면의 해당 쪽 모서리에 위치하게 됩니다.
두 번째 화풍: 크레용 그림책
사용자가 동심, 그림책, 크레용, 연속 그림을 원하거나 더 이상 수채화를 원하지 않을 경우, 같은 디렉토리의 crayon.md를 읽으세요. 이 시스템은 p5.brush를 사용하지 않으며, 자체 작성 2D canvas 크레용 엔진(crayon-kit/)으로 수채화보다 한 자릿수 빠릅니다. 내용: 엔진 원리와 API, 캐릭터 매개변수, 변신 개그와 분할/깨짐 프레임 방법, 크레용 자막, 프로브를 사용한 자막과 인물 회피.
세 번째 화풍: 그림자극
사용자가 그림자극, 실루엣, 무대를 원하거나 노래 없이 꽹과리만으로 짧은 영상을 만들고자 할 경우, 같은 디렉토리의 piying.md를 읽으세요. 엔진은 piying-kit/에 있습니다: 각 조각을 따로 새겨서 구멍을 뚫은 후 빛이 투과하는 막에 곱하고, 캐릭터는 조종 막대가 달린 관절 인형이며, 꽹과리 리듬은 numpy로 합성합니다. 내용: 엔진 원리와 API, 캐릭터 매개변수, 액션을 꽹과리 리듬에 맞추는 방법, 무대 뒤 카메라 위치의 미러링과 실루엣 윤곽광, 합성기.
네 번째 화풍: 채색 격투 (무산오행풍)
사용자가 격투, 무협, 액션을 원하거나 무산오행, 채색 수묵을 지정한 경우, 같은 디렉토리의 wushan.md를 읽으세요. 엔진은 inkfight-kit/에 있습니다: 인물은 붓으로 선을 그리고 평면 채색과 어두운 면을 추가하며, 동작은 키 프레임을 통과하는 부드러운 곡선을 따르고, 발은 별도로 찍는 지점에 따라 움직이며, 충격 프레임은 반전과 주홍색을 사용하고, 마지막으로 불과 먹이 화면을 가득 채웁니다. 내용: 엔진과 인체의 API, 격투 장면 구성 방법(먼저 접촉점을 정한 후 역으로 위치를 추정, probe.mjs로 숫자 쌍을 얻음), 카메라 배치, 겪은 문제점.
다섯 번째: 과학 설명 영상
사용자가 과학 영상, 특정 발견이나 원리를 설명하는 것을 원할 경우, 같은 디렉토리의 explainer.md를 읽으세요. 베이스는 explainer-kit/입니다. (《빛으로, 뇌를 열다》, 2026 노벨상 광유전학, 3:05). 각 장면마다 하나의 화풍을 사용하며, 자막, 챕터, 도해 주석을 허용합니다. 화면, 효과음, 나레이션은 하나의 timeline.js를 공유합니다. 나레이션이 화면보다 길게 읽힐 경우, 문장 길이에 따라 해당 화면 부분을 늘립니다.
여섯 번째: 판화 시리즈 단편
사용자가 질감 있는, 평면적이지 않은 스타일의 시리즈 화면을 원하거나 판화, 공판, 동판, 청사진, 스크린톤을 지정한 경우, 같은 디렉토리의 prints.md를 읽으세요. 베이스는 prints-kit/입니다. (《먼 빛》, 93초, 민들레 씨앗의 6단계 여정). 내용:
- 지평선과 광원은 6단계 동안 고정, 기법은 단계마다 변경;
- 6가지 기법 각각의 SVG 구현 방법;
- 고정 난수로 프레임이 새로 그려질 때 깜빡임 방지;
- 화면이 '이야기'하도록 하는 세 가지 요소: 주인공과 동료, 하루의 시간, 연필 라벨;
- 다섯 가지 장면 전환 인쇄법;
- 다중 경로 병렬 렌더링 (각 경로 약 2–3GB 메모리 사용, 기본 4경로).
일곱 번째: 유체 채색 MV (음표 구동)
화면이 계속 움직이고, 구체적인 이야기 없이 음악에 맞춰 변하는 MV를 원할 경우, 같은 디렉토리의 fluid.md를 읽으세요. 베이스는 fluid-kit/입니다. (《한 방울의 먹》, 91초, 클래식 + 록). WebGL2 안정 유체, 안료는 흡광도에 따라 색이 겹쳐집니다. 악보에서 음표 목록을 내보내고, 각 악기는 고정된 화법을 가집니다. (바이올린은 붓, 베이스 드럼은 충격, 심벌즈는 꽃). 각 섹션은 하나의 '물성'입니다. 클라이막스의 꽃은 7가지 폭발 방식이 번갈아 나타납니다. 사람을 그리지 않고, 카메라가 없으며, 프레임은 순차적으로만 렌더링할 수 있습니다.
여덟 번째: 모래 그림 (조명 박스 투과, 한 그림을 다음 그림으로 변환)
작은 이야기를 하고 싶지만 사람을 그리고 싶지 않고, 화면이 계속 변하면서 동적 PPT처럼 보이지 않도록 하고 싶을 경우, 같은 디렉토리의 sand.md를 읽으세요. 베이스는 sand-kit/입니다. (《모래시계》, 75초, 한 톨의 모래가 본 1년, 아홉 장면이 시작과 끝이 연결됨). WebGL 높이장으로 모래를 시뮬레이션합니다: 뿌리기, 손가락으로 긋기, 손바닥으로 밀기, 안식각, 모래 커튼, 누르기, 삼각형 닦아내기, 달 열기. 배경광은 세 채널을 각각 투과시키며, 얇은 부분은 한 톨씩 보입니다. 규칙은 빛이 주인공이고, 장면 전환은 형태가 이어지도록 하며, 여백을 둡니다. 화면을 먼저 정하고 그 다음에 음악을 작곡하며, 60bpm, 1박 = 1초입니다. 프레임은 순차적으로만 렌더링할 수 있습니다.
아홉 번째: 공책 낙서 (볼펜 + 색연필 + 촬영한 종이)
'종이', '공책', '수업 중 낙서' 느낌을 원하고, 주인공이 살아난 낙서 캐릭터일 경우, 같은 디렉토리의 doodle.md를 읽으세요. 베이스는 doodle-kit/입니다. (《페이지 마진》, 38초, 페이지 여백의 작은 공이 펜이 없는 틈을 타 한 바퀴 돌아옴). 볼펜 선은 끊기고, 색연필은 비스듬한 해칱에 종이 톱니 입자가 있으며, 전체 페이지는 촬영 광택이 있습니다. 그림자가 있는 실제 펜이 사진 느낌을 살려줍니다. 살아있는 것은 선이 떨리고, 멈추면 종이로 돌아갑니다. 원테이크(one shot)이며, 음악은 동작에 맞춰 씁니다. 후반부에는 이 화풍으로 노래 전체의 스토리 MV를 촬영한 경험도 기록되어 있습니다. 사람을 그리지 않고, 두 개의 펜과 미끄러지는 공책으로 두 사람을 연기하는 방법.
열 번째: 공점 몽타주 (동일한 형태가 동일한 점에 위치)
서로 관련 없는 장면들을 빠르게 컷하고 마지막에 급정지하며, 매 컷마다 동일한 형태가 화면의 동일한 점에 위치하도록 할 경우, 같은 디렉토리의 montage.md를 읽으세요. 베이스는 montage-kit/입니다. (《한 입》, 25.8초): 도넛이 화면을 가득 채우고, 구멍 안에서 카우보이가 말을 타고 질주하며, 매 박자마다 구멍 안의 화풍이 바뀌고, 바깥쪽 원은 한 박자 늦게 이어받으며, 24가지 화풍이 릴레이로 이어지고, 마지막에 한 입 베어 냅니다. 연속 애니메이션은 해부학적 수준의 공유 골격에 의존하며, 각 화풍은 그리는 방법만 관리합니다. 또 다른 방식인 '한 컷 한 세계'도 함께 기록되어 있습니다.
직접 배경음악 작곡
기존 노래가 없고 영상을 위한 배경음악을 작곡해야 할 경우, 같은 디렉토리의 music.md를 읽으세요. Tone.js와 실제 악기 샘플을 사용하며, 합성 음색은 사용하지 않습니다. 내용: 편곡 규칙, 기계음 제거 방법, VSCO2 오케스트라 샘플과 옥타브 표기의 함정, 음원 변경 후 음량 정렬 방법, 로컬 샘플 캐시, 무헤드 Chrome 오프라인 내보내기와 2회 음량 표준화, 그리고 '박'을 사용하여 화면과 음악을 정렬하는 방법. 클래식과 록을 결합한 곡에 대한 별도 섹션: 다중 강도 교체의 실제 드럼(DRSKit), 디스토션 기타, 트랙별 내보내기, 그리고 자체 작성 Python 믹싱 데스크(이퀄라이저, 압축, 새추레이션, 컨볼루션 리버브, 구간별 음량 정렬, 리미터).
검사 루프 (각 컷마다 수행, 생략 금지)
코드만 읽어서는 애니메이션 효과를 알 수 없습니다. 반드시 렌더링하여 확인해야 합니다:
node render.mjs --sheet=0.1,0.8,1.6,2.4 --cols=4 --w=480 --out=out/check/sheet.jpg # 연락표: 각 컷의 첫, 중간, 마지막 프레임
node render.mjs --strip=2.1:2.6 --cols=6 --w=320 --out=out/check/strip.jpg # 연속 프레임: 방향 전환, 점프, 장면 전환
node render.mjs --sheet=2.3 --crop=760,420,500,400 --w=500 --out=out/check/face.jpg # 부분 확대: 표정, 손, 접촉점
연락표의 ms/frame이 모두 0이면 페이지가 아무것도 그리지 않은 것입니다. (대부분 씬 파일에 문법 오류가 있는 경우). 먼저 터미널의 [page error]를 확인하세요.
이미지 뷰어로 열어서 항목별로 확인:
- 사건을 읽을 수 있는지, 캐릭터가 충분히 큰지, 배경과 분리되는지;
- 순간 이동, 돌변하는 프레임이 있는지;
- 신체와 지지물: 앉기, 서기, 물체에 기대기 – 다리 들기, 무릎 굽히기, 앉는 과도기가 있어야 하며, 신체가 물체에 평행하게 붙어 이동하거나 겹쳐서는 안 됨;
- 사지 길이 일정: 손을 뻗어 물건을 잡을 때 팔이 늘어나면 안 되고, 닿지 않으면 캐릭터가 다가가거나 허리를 굽혀야 함;
- 휘두르거나 뒤집는 소품이 장면의 물체를 통과하면 안 됨;
- 동작에 준비와 후속 동작이 있는지, 좌우 대칭으로 동시에 움직이고 있지 않은지;
- 이음매에 장면 전환이 있는지;
- 글자가 있는지;
- 색상이 더럽지 않은지 (노란색이 파란색 위에 겹치면 녹색이 됨, 발광은
glow()를 사용해야 함); - 색상 구성이 정해진 색조를 지키고 있는지.
성능 및 알려진 문제점 (p5.brush)
- 이어서 렌더링할 때는 프레임 파일의 존재 여부만 확인: 코드를 변경한 후
--frames를 실행하면 이미 존재하는 프레임은 그대로 유지되어 완성 영상에 이전 화면이 섞이게 되며, 오류도 발생하지 않습니다. 베이스의render.mjs가 그렇습니다. 코드를 변경한 후에는 먼저out/frames를 이동(삭제하지 말고)시킨 후 렌더링하세요.crayon-kit의render.mjs는 프레임에 코드 서명을 기록하여 코드가 변경되면 중단하고--force(이전 프레임을out/frames_old_*로 이동) 또는--keep-frames(이미 수동으로 이동한 수정된 컷)를 선택하게 합니다. - 페이지 오류:
crayon-kit의render.mjs는 페이지 오류 발생 시 실패와 함께 종료됩니다. 베이스는[page error]한 줄만 출력하고 그대로 이미지를 생성하므로 직접 주의해야 합니다. - 연락표는 프레임당 소요 시간을 출력하며, 목표 ≤1.5초/프레임입니다. 수채화
fill이 가장 비쌉니다: 넓은 면적의 형상은wash를 사용하고,fill은 적게 사용하며 변의 수를 줄이세요. - 전용 그래픽 카드가 있는 경우 프레임당 약 1초입니다. 눈에 띄게 느려지면
node gpu_probe.mjs <chrome 경로>로 Chrome이 어떤 GPU에서 실행되고 있는지 확인하세요. studio.html은 Google Fonts에서 Permanent Marker 폰트를 로드하며,letter()에서만 사용됩니다. 글자를 쓰지 않는 영상은 해당<link>행을 바로 삭제하여 네트워크가 불통일 때 로딩에 막히는 것을 방지하세요.- 점 좌표에 NaN이 발생하면 오류 메시지는
Failed to construct 'OffscreenCanvas'이며, 스택은 장면 코드 대신 이 오류를 가리키므로, 기하학 계산을 다시 확인해야 합니다. - 카메라가 2배 이상 확대되면 원점에서 매우 먼 긴 선이 한 점으로 붕괴될 수 있습니다. 매우 긴 가장자리는
inkLine으로 분할하여 그리세요. - 가끔
WebGL: INVALID_OPERATION경고 5개가 나타나는 것은 무해하며, 다른 페이지 오류는 실제 오류입니다. - 큰 형상을
fill만으로 그리면 거의 투명: 먼 산, 수면 등 수천 픽셀 너비의 형상을fill만으로 그리면 너무 연하게 보입니다. 먼저wash(washOp: 255, 색상을 연하게)로 바탕을 깔고, 그 위에fill을 한 겹 더하여 번짐과 가장자리를 만드세요. inkLine에 점 두 개만 주면 아무것도 그리지 않고 오류도 발생하지 않음: 직선도 최소 3개 이상의 점을 주어야 하며, 약간의 요철을 넣으면 손으로 그린 것처럼 보입니다. 잔물결, 물자국, 땅의 짧은 선에서 특히 자주 발생합니다.- 동일한 형상을 분할하여 그리지 마세요: 산꼭대기의 어두운 부분을 여러 조각으로 나누어 그리면 겹치는 부분에 세로 방향 이음새가 나타납니다. 한 번에 전체를 그리고, 가장자리의 요철은
hash(i)를 사용하세요. inkLine분할 시 마지막 부분의 점 수 확인: 슬라이스 끝에 점이 1개만 남을 수 있으며, 이 경우spline() requires at least 2 points오류가 직접 발생합니다.
장편 또는 MV
먼저 같은 디렉토리의 mv-workflow.md를 읽으세요: 음악 분석, 박자표 기반 컷별 표, 부품 라이브러리, 배치 작업, 분할 렌더링, 부분 수정, 완성 영상 색보정, 가사 자막.
또 다른 방법: 메인 에이전트가 스토리보드와 스타일 설명을 작성하고, 챕터별로 여러 하위 에이전트에게 나누어 각자 챕터 파일을 수정하게 합니다. 사용자가 요구하지 않으면 한 사람이 처음부터 끝까지 작업하여 영상 전체의 일관성을 높입니다.
가사 싱크 및 오디오 비트 분석에는 paint-mv-skills (MIT, 중국어)도 참고할 수 있습니다.
인도물
- 인도물은
out/video.mp4이며, 연락표 스크린샷을 함께 첨부합니다. - 보고 시 세 가지를 명확히 해야 함: 총 길이, 프레임당 평균 소요 시간, 자체 점검 중 발견하여 수정한 사항. 확인하지 않은 부분은 명시적으로 확인하지 않았다고 말합니다.