Communitygithub.com

motion-video · 코드로 검증 가능한 애니메이션 만들기

코드로 인트로/모션/자막 애니메이션/데이터 시각화 모션/UI 데모/설명 영상/루핑 GIF를 제작하고 mp4/webm/gif/webp로 출력합니다. '화면이 실제로 움직이고 중간 상태가 누락되지 않았음'을 기계 검증을 통해 보장합니다.

motion-video · 코드로 검증 가능한 애니메이션 만들기란 무엇인가요?

이 스킬은 작은 모델(Flash, mini, turbo 등)이 CSS와 Canvas로 애니메이션을 작성할 때 발생하는 '작성은 했지만 실제로 움직이지 않는' 문제를 해결합니다. 중간 상태가 생략되고, 이징이 가짜이며, 키 요소가 다른 시점에 나타나고, 끝이 중간에서 멈추는 현상을 방지합니다. 접근 방식은 '더 예쁘게 쓰는 법'을 가르치는 것이 아니라 애니메이션을 기계적으로 판정 가능한 엔지니어링 결과물로 만드는 것입니다. 사양 먼저, 코드는 나중에; 모든 화면 상태는 seek(t)의 순수 함수여야 함; 수치는 스크립트로 계산; 결정론적 렌더러로 프레임별 출력; 기계 검증(수치 레이어 + 픽셀 레이어); 구조가 문제없다는 확인 후에야 사람이 구도 평가를 합니다. 이 스킬은 Claude Code, Cursor, Codex, Copilot 등 다양한 AI 에이전트 플랫폼에서 사용할 수 있으며, Workspace 내 기존 리소스를 우선 활용하고, 모든 시각 요소는 코드로만 생성합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/IFIAnder/motion-video-skill/tree/HEAD

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

motion-video · 코드로 검증 가능한 애니메이션 만들기은(는) 무엇을 하나요?

이 스킬은 매우 구체적인 문제를 해결합니다. 작은 모델(Flash / mini / turbo 등)이 CSS와 Canvas를 작성할 수는 있지만, 작성된 애니메이션이 종종 "작성은 했지만 실제로 움직이지 않는" 경우가 많습니다. 중간 상태가 생략되고, 이징은 가짜이며, 핵심 요소가 다른 시점에 나타나고, 끝이 중간에서 멈춥니다. 모델은 스스로 이를 알아차리지 못합니다. 눈이 없기 때문입니다.

따라서 여기서의 접근 방식은 "더 예쁘게 쓰는 법"을 가르치는 것이 아니라 애니메이션을 기계가 판정할 수 있는 엔지니어링 결과물로 만드는 것입니다:

  1. 사양 먼저, 코드는 나중에 — 미적 판단을 표의 숫자로 번역합니다.
  2. 화면은 반드시 t의 순수 함수여야 함 — 구조적으로 중간 상태를 작성하도록 강제합니다.
  3. 수치는 스크립트에 맡기고, 직접 계산 금지 — 베지어, 스프링, 지연(stagger) 간격, 대비 등은 모두 도구를 실행하고, 암산하지 않습니다.
  4. 결정론적 렌더러로 프레임별 출력 — 동일한 코드는 항상 동일한 프레임을 생성합니다.
  5. 기계 검증 — 수치 레이어를 먼저 검증하고, 픽셀 레이어를 다시 검증합니다.
  6. 기계가 "구조에 문제없음"이라고 말한 후에야 사람이 구도를 평가합니다.

격차는 하나의 주문으로 메워지지 않습니다. 이 여섯 가지 작업을 통해 "잘못 생각한 것"을 "발견 가능하고 수정 가능한 것"으로 바꿉니다. 격차가 어디서 오는지, 무엇을 메울 수 있고 무엇을 메울 수 없는지는 references/delta-vs-opus.md를 참조하세요.


품질 우선: 불필요한 오버헤드만 절약하고, 검증은 절약하지 않음

이 규칙은 아래의 불변 규칙보다 더 우선합니다. 이 스킬의 목표는 Opus 수준의 영상을 만드는 것이지, 가장 저렴한 영상을 만드는 것이 아닙니다. 따라서 "이 작업을 할까 말까"의 판단 기준은 빠르냐가 아니라 더 나아지느냐입니다.

절약해도 되는 오버헤드는 단 한 가지 유형뿐입니다: 반복적이고, 비효율적이며, 서로 리소스를 경쟁하는 것입니다. 검증 밀도, 렌더링 품질, 프레임 속도, 모션 블러 — 이러한 것들은 절대 절약하지 않습니다.

절약 허용 (낭비이며, 절약해도 점수에 영향 없음)

낭비절약 방법
Chrome 4개를 동시에 실행하여 CPU 경쟁 유발직렬 실행 (실제로 동시 실행보다 빠름), render.mjs에 단일 인스턴스 잠금 내장
각 장(chapter)마다 20KB 사양 문서하나의 storyboard.md에 모두 작성
render --still을 반복 호출하여 매번 한 프레임씩 추출한 번에 6–8개 시점 추출
동일한素材(에셋)를 반복적으로 재분석한 번 분석하고 결과를 storyboard에 기록
프레임별 PNG를 디스크에 저장했다가 다시 읽기optimizeForSpeed 활성화; 대규모 프로젝트는 image2pipe 사용 (cinema-grade.md §9)
"안전을 위해" 동일한 작업을 세 번 검증두 번 검증(수치 + 픽셀)으로 충분, 세 번째는 정보를 추가하지 않음

절약 금지 (절약 = 품질 저하)

금지 사항이유
전체 audit, jump/flat 각각 처리 포함납품 전 마지막 관문, 건너뛰면 검증되지 않은 것임
verify --idempotent멱등성이 깨지면 이후 모든 검증을 신뢰할 수 없음
rigcheck (캐릭터나 포즈를 변경할 때마다)뼈대 오정렬은 숫자로만 잡을 수 있고, 눈으로는 잡을 수 없음
납품 버전에 모션 블러 적용 안 함셔터가 있는 것과 없는 것의 느낌은 한 단계 차이, 단순한 장식이 아님
빠른 움직임이 있을 때 60fps 사용 안 함30fps에서 빠른 팔다리는 끊겨 보임, 이는 결함이지 절충이 아님
프레임 추출하여 검토 (다중 시점 + 부분 확대)1장의 이미지로는 중간 문제를 알 수 없음; 최소 6프레임 + 핵심 부위 2–3배 확대
수정 후 재실행하지 않음 ("되었겠지"라고 생각)재실행하지 않으면 수정하지 않은 것과 같음

한 줄 기준

절약한 것이 대기 시간이라면 절약해도 되지만, 절약한 것이 '오류를 발견할 기회'라면 절대 안 됩니다.

렌더링 70분이 허용되지 않는 이유는 "70분이 너무 길어서"가 아니라, 그 70분 중 85%가 4개 프로세스가 서로 CPU를 경쟁하는 데 사용되었기 때문입니다 — 대기가 품질 향상으로 이어지지 않았습니다. 반면 180° 셔터를 위해 렌더링 시간을 4배 늘리는 것은 실질적인 시각적 향상을 가져옵니다 — 이 비용은 반드시 지불해야 합니다.

올바른 속도 향상 순서

  1. 먼저 낭비를 제거하십시오: 동시 실행을 직렬로, 중복 시작 병합, 중복 문서 삭제, 일괄 프레임 추출
  2. 그런 다음 구현을 최적화하십시오: 스크린샷 매개변수, 단일 프로세스 다중 탭, 디스크 저장 없이 직접 인코딩
  3. 마지막으로 검증 감소를 고려하십시오 — 이 단계는 기본적으로 발생해서는 안 됩니다; 발생했다면 앞의 두 단계를 제대로 수행하지 않은 것입니다.

불변 규칙

어느 하나라도 위반하면 결과물은 검증 불가능하므로 다시 만들어야 합니다.

  1. 사양 없이 코드를 작성하지 마십시오. 먼저 샷 테이블과 타임라인 테이블을 생성하십시오 (STEP 1). 테이블의 각 요소는 반드시 enter / active / exit 세 가지 시간 구간을 가져야 합니다. 하나라도 누락되면 요소가 언제 존재하는지 명확히 파악하지 못했음을 의미합니다. 하지만 사용자가 한마디만 할 때 ("멋지게 만들어 줘", "네 능력을 보여줘", "최선을 다해")는 절대 인터뷰를 요청하지 마십시오 — 스스로 모티프/메타 서사/형식/등급 네 가지 슬롯을 채우고 storyboard.md에 작성한 후 바로 작업을 시작하십시오. references/wish-mode.md 참조.
  2. 모든 화면 상태는 seek(t)의 순수 함수여야 합니다. requestAnimationFrame, Date.now(), performance.now(), Math.random(), 자동 증가 카운터, 자체 실행 CSS @keyframes/transition을 금지합니다. 동일한 코드와 동일한 t는 항상 동일한 픽셀을 렌더링해야 합니다.
  3. 수치는 모두 스크립트를 실행하여 얻고, 암산을 금지합니다. 곡선 제어점, 스프링 매개변수, 지연(stagger) 간격, 좌표 변환, 대비 비율, linear() 문자열 등은 모두 ease.mjs에서 생성해야 합니다. 답변에 이러한 숫자가 나타나기 전에 먼저 도구 출력이 있어야 합니다. 아래 '숫자는 도구에, 판단은 너에게' 참조.
  4. 수정 후 반드시 verify와 render + audit을 실행하십시오. FAIL 상태로 납품하지 마십시오. WARN은 각각에 대해 "수정함" 또는 "설계 내 의도된 사항임, 이유는..."를 명시하십시오. verify를 건너뛰고 전체 영상을 렌더링하지 마십시오 — 8초를 더 써서 얻는 것은 "화면이 움직이지 않음"이라는 정확한 이유를 모르는 상태뿐입니다.
  5. 납품 세트: 완성 영상 (mp4/webm/gif) + 접촉 시트 (-sheet.png) + audit 결과.
  6. 미적 판단이 확실하지 않으면 후보를 제시하고, 추측하지 마십시오. 두 가지 색상, 두 가지 리듬을 사용자에게 선택하게 하십시오. 평범한 버전을 납품하는 것보다 낫습니다.
  7. 에셋을 기다리지 말고 직접 그리십시오. 납품 결과물에 '이미지 삽입 권장', '여기에 그림 배치', '에셋 준비되면 추가' 등의 내용을 금지합니다. 렌더링 파이프라인은 HTML/CSS/SVG/Canvas만 사용합니다 — 모든 시각적 요소는 코드로만 생성되어야 합니다. 광원/텍스처/그래픽/아이콘이 필요할 때는 먼저 references/asset-recipes.md를 참조하십시오 (20가지 기성 스니펫, 바로 붙여넣기 가능: 글로우, 라이트 스위프, 입자, 유리 카드, 네온, 그리드, 추상 일러스트, 입자, 와이어프레임 구, 차트, 도시 실루엣, 글리치, 스캔 라인, 아이콘 세트, 광선, 피사계 심도, 천 텍스처, 보케, 의사 3D). 없으면 직접 SVG 경로를 작성하십시오. 그래픽으로 이모지나 유니코드 기호를 사용하는 것을 금지합니다. 각 화면은 최소 세 개 레이어(배경 그라데이션/그리드 → 주제 → 분위기 입자/보케), 최소 2개의 자체 제작 시각 요소, 1개의 깊이 단서(그림자/그라데이션/색상 오버레이/입자)를 포함해야 합니다. 레이어가 하나뿐이고 텍스트와 색상 블록만 있는 화면 = 불합격.
  8. 기존 에셋을 우선 사용하고, 재구축을 금지합니다. 작업 공간에 이미 조립된 뼈대/명세/컴포넌트/디자인이 있다면, 반드시 전체를 그대로 사용해야 하며, 단 하나의 수치도 재추정해서는 안 됩니다. rigcheck.mjs --ref를 사용하여 원래 값을 사용하고 있음을 증명하십시오. 사고 기록: 한 번 재구축에서 head.pos를 [-6.8,-182.5]에서 [0,-248]로 (65.9px 차이), torso.pv를 [160,160]에서 [160,291]로 (131px 차이) 변경한 결과 머리가 몸체 왼쪽에 떠 있었고, "그림 검사"로는 발견되지 않았습니다 — 인간의 눈은 이를 "하나의 캐릭터"로 읽기 때문입니다. 이러한 오류는 반드시 숫자로 확인해야 합니다.
  9. 에셋 화이트리스트. storyboard.md에 명시적으로 나열된 에셋만 사용하십시오. 작업 공간의 다른 파일 (이전 버전 결과물, 관련 없는 캐릭터 이미지, 다른 프로젝트의 설정)은 절대 건드리지 마십시오, 사용 가능해 보여도 마찬가지입니다. 새 에셋이 필요하면 storyboard에 한 줄을 추가하고 용도를 설명한 후 찾으십시오.
  10. 검증을 타협하지 말고, 동시 렌더링도 금지합니다. audit이 WARN을 보고한다고 해서 "납품해도 된다"는 의미가 아닙니다: 하드 점프(jump)와 순색 프레임(flat)은 반드시 제거하거나 각각 설명해야 하며, 그렇지 않으면 다시 만들어야 합니다. verify/rigcheck에 FAIL이 있으면 절대 계속해서는 안 됩니다. 렌더링은 한 번에 하나의 render.mjs 프로세스만 실행하십시오 — 스크립트에는 단일 인스턴스 잠금이 있으며, 동시 실행은 CPU 경쟁만 유발합니다. 병렬 처리가 필요하면 단일 Chrome에서 여러 탭을 여십시오 (cinema-grade.md §9 참조), 여러 프로세스를 실행하지 마십시오.

숫자는 도구에, 판단은 너에게

이러한 유형의 모델(Flash / mini / turbo)은 공통된 경향이 있습니다: 도구를 사용하기보다 스스로 추정하는 것을 선호합니다. 암산의 비용이 0이고 도구는 기다려야 한다고 생각합니다. 이 비용 계산은 잘못되었으며, 먼저 숫자로 명확히 계산해 보겠습니다:

암산ease.mjs 실행
직접 소요 시간0초약 0.3–0.5초
한 번에 정확할 확률30–40% (베지어 제어점을 한 자리만 잘못 추정해도 곡선의 특성이 완전히 바뀜)100%
잘못되었을 때의 비용90프레임 렌더링 ≈ 8초 + 검토 시간, 그리고 오류를 발견하지 못할 가능성이 높음, 단지 "매끄럽지 않다"고 느낄 뿐0
예상 비용0 + 0.5 × (8 + 30) ≈ 19초, 품질은 조용히 저하됨0.5초

암산으로 절약한 0.5초는 가장 비싼 절약 방식입니다. 따라서 이것은 권장 사항이 아니라 엄격한 요구 사항입니다:

다음 숫자는 모두 도구 출력에서 비롯되어야 하며, 답변에 추정 값을 손으로 작성하는 것을 금지합니다:

필요한 것실행할 것
임의의 베지어 특성(오버슛, 플랫폼, 샘플 테이블)node scripts/ease.mjs cubic 0.22 1 0.36 1
스프링 매개변수(튕김 정도, 정지 시간, 중간에 멈추는지 여부)node scripts/ease.mjs spring 120 14 1 1.2
곡선을 CSS linear()로 압축node scripts/ease.mjs css-linear --preset silkIn
요소 그룹의 지연(stagger) 간격, 총 시간 초과 여부node scripts/ease.mjs stagger 7 2.4 0.5
텍스트 대비 기준 충족 여부node scripts/ease.mjs contrast "#0b0e14" "#6d8bbd"
배경색에서 읽을 수 있는 회색조 생성node scripts/ease.mjs ramp "#0b0e14" 5

자체 점검 세 가지 질문 (납품 전 스스로에게 질문하고, 답하지 못하면 위반입니다):

  1. 내 답변의 모든 곡선 매개변수가 이전 명령의 출력을 가리킬 수 있는가?
  2. "약 0.3 정도"와 같이 추정한 숫자를 어딘가에 작성했는가? 있다면 → 삭제하고 명령을 실행하십시오.
  3. "이 곡선은 매우 매끄럽다"고 말한 이유는 ease.mjs가 출력한 ASCII 그래프와 오버슛 백분율을 봤기 때문인가, 아니면 추측 때문인가?

모델도 스스로 검증하고 싶어하므로, 검산기를 사용하여 안심시키십시오: verify.mjs는 실제 계산된 스타일을 읽습니다. 추측이 아닙니다. 모델이 "확인하고 싶다"고 할 때 올바른 동작은 verify를 실행하는 것이지, 자신의 머릿속에서 시뮬레이션하는 것이 아닙니다.


환경

npm 의존성 제로. Chrome 또는 Edge (로컬에 이미 있음) + ffmpeg + ffprobe 필요.

ffprobe는 audit이 해상도/길이를 확인할 때만 사용됩니다. 없으면 조용히 통과하지 않습니다: --width/--height/--duration이 선언되면 FAIL, 선언되지 않으면 WARN 및 "해상도를 알 수 없음 (미확인)" 출력.

node scripts/render.mjs --check      # chrome / ffmpeg / node / WebSocket 기능 출력

출력에서 chrome이 NOT FOUND이면 --chrome <path>로 지정하거나 브라우저를 먼저 설치하십시오.

이미지 이해 기능이 없을 때 대처 방법

일부 모델(예: 순수 텍스트 추론 버전)은 read_image를 사용할 수 없습니다. 이 체인의 판정은 모두 숫자이며, 이미지가 아닙니다. 따라서 여전히 전체 프로세스를 진행할 수 있습니다: ease (매개변수) → verify (수치 궤적 + 멱등성) → audit (픽셀 통계, 결론은 숫자) → rigcheck (기하학적 단언).

  • 가능: 구조, 움직임, 기하학, 가독성
  • 불가능: 구성 품질, 색상 조화, 스타일 일관성, 시각적 관통(穿模)

후자는 이미지를 볼 수 있는 사람이나 시각 모델에게 맡겨야 합니다. 하지만 마지막으로 미룰 수 있습니다: 먼저 숫자로 잡을 수 있는 모든 오류를 잡은 후, 한 번에 사람에게 6–8프레임을 보여줍니다 (--still 일괄 추출 + --guides 안전 영역 오버레이).


문서 인덱스 (필요할 때 읽고, 한 번에 모두 읽지 마십시오)

파일언제 읽을 것인가
references/wish-mode.md사용자가 한마디만 할 때 먼저 읽으십시오: 네 슬롯, 장(chapter) 유도, 기본값 표, 소원 모드에서 인터뷰 금지
references/spec-and-prompt.mdSTEP 1에서 사양 표를 작성할 때; 재사용 가능한 프롬프트 템플릿이 필요할 때; "도구 사용을 꺼리는" 모델을 다룰 때
references/code-patterns.mdSTEP 2에서 코드를 작성할 때: seek(t) 패러다임, 이징 라이브러리, keys() 키프레임 표, spring(f,z), SVG/Canvas, 20가지 현대 CSS 효과
references/asset-recipes.md화면에 뭔가 부족할 때 가장 먼저 찾아보십시오: 글로우, 라이트 스위프, 입자, 유리, 네온, 그리드, 일러스트, 입자, 와이어프레임 구, 차트, 아이콘 세트, 보케, 의사 3D
references/rig-characters.md화면에 움직이는 캐릭터가 있을 때: 부품 + 부모-자식 변환 체인 + 포즈 표 + 12가지 원칙을 필드에 적용하는 방법
references/cinema-grade.md최종 확정 전: 모션 블러, 인코딩 매개변수(밴딩 방지), 비네트, HUD 시스템, 카메라 스윙, 프레임 속도 선택, 장편 구성, 병렬 속도 향상
references/review-checklist.mdSTEP 5 사람 눈 샘플 검사 + 납품 전 하나씩 확인
references/failure-modes.mdaudit/verify 오류 발생 시 원인 파악
references/delta-vs-opus.md"이 시스템이 어디까지 보완할 수 있는지" 알고 싶을 때, 모델을 교체해야 하는지 판단해야 할 때

먼저 분류: 소원 모드인지 요구 사항 모드인지

입력 형태경로
크기/길이/내용/스타일 중 대부분이 주어짐; 또는 질문에 대한 답변 형태사양 모드: STEP 0 질문 → STEP 1 사양 표 → ...
한마디 + 위임 어조 ("멋지게 만들어 줘", "네 능력을 보여줘", "어떤 종류의 영상처럼", "최선을 다해")소원 모드: STEP 0 건너뛰기, 역질문 금지. 먼저 작업 공간을 스캔하여 모티프를 찾고, 스스로 네 슬롯을 채운 후 STEP 1부터 시작. wish-mode.md 참조

판단 기준은 간단합니다: 그가 명확히 말하지 않은 것이 "내가 물어볼 때까지 기다리라"는 것인가, 아니면 "네가 정하라"는 것인가? 어조에 "네가 알아서 해/최선을 다해/보여줘"가 포함되면 후자입니다. 소원 모드에서도 storyboard.md를 작성해야 합니다 — 차이점은 표를 당신이 작성한다는 것뿐, 질문을 통해 얻은 것이 아니라는 점입니다.

워크플로

STEP 0 · 세 가지 명확히 하기 (사양 모드에서만; 소원 모드는 건너뜀)

  • 용도: 프로젝션 인트로 / 소셜 숏폼 / 웹 히어로 모션 / 설명 삽입 영상 / 데이터 성장 모션 / GIF
  • 크기 및 길이: 아래 표의 기본값 참조, 사용자가 명확히 요청하지 않는 한
  • 분위기: 안정적 (기업/금융), 빠름 (기술/런칭), 부드러움 (라이프스타일/브랜드), 하드 (게임/스포츠)
용도크기길이프레임 속도형식
인트로 / 발표회1920x10803–6초30mp4
소셜 세로 화면1080x19205–15초30mp4
웹 히어로 / 배너1920x800 또는 1440x6002–4초, 반복 가능30webp / apng (투명 필요); webm은 먼저 알파 검증 필요
데이터 모션 / 차트1920x10803–8초30mp4
루핑 GIF800x800 / 1080x10801–3초, 끊김 없이 반복되어야 함15–20gif / webp
설명 삽입 영상1920x1080컷당 2–5초, 전체 영상은 편집30mp4

10초 초과 또는 3컷 초과: 여러 장면 파일로 분할하고, 각각 별도 렌더링 및 검증 후 ffmpeg로 연결하십시오. 하나의 seek()가 30초를 관리하도록 하지 마십시오 — 그러면 아무도 자체 점검할 수 없습니다.

STEP 1 · 사양 작성 (유일하게 자유로운 창작 단계)

storyboard.md를 생성하십시오. 두 가지가 모두 필요합니다:

① 샷(컷) 테이블

#시간화면이 하는 일주요 움직임종료 상태
10.00–1.10초제목이 한 글자씩 떠오름y: +96→0, 각 글자 75ms 지연제목 배치 완료
21.10–2.40초진행 바가 채워지고 세 점이 튀어나옴scaleX: 0→1 (ease-in-out)바가 끝까지, 점 정렬

② 요소 타임라인 테이블 (요소당 한 행, 이후 코드의 유일한 근거)

요소enteractiveexit속성곡선
#title span0.15 + i*0.075영상 끝까지—translateY 96→0, opacity 0→1easeOutCubic
#bar b0.300.30–2.40—scaleX 0→1easeInOutCubic
.dots i1.50 + i*0.15영상 끝까지—scale 0→1easeOutBack

이 테이블을 작성할 수 없다면 = 아직 명확히 파악하지 못한 것입니다. 테이블을 건너뛰고 코드를 작성하지 마십시오. 작성해 봐야 "시작 프레임과 끝 프레임만" 있을 것입니다.

'곡선' 열은 단지 이름만 적고 끝내는 것이 아닙니다. 이름을 정한 후 즉시 도구를 한 번 실행하여 "이 곡선이 해당 길이에서 어떻게 동작할지"를 확정하고, 이 행을 숫자 값이 포함된 형식으로 보완하십시오:

node scripts/ease.mjs cubic 0.33 1 0.68 1     # easeOutCubic → 플랫폼 구간/오버슛 확인
node scripts/ease.mjs stagger 6 2.4 0.7       # 2.4초 내 6개 제목 글자, 각각 0.7초 → 간격 및 오버플로우

그러면 테이블의 두 행은 다음과 같이 변합니다:

요소enteractiveexit속성곡선 (도구 확인)
#title span0.15 + i*0.075영상 끝까지—translateY 96→0, opacity 0→1cubic-bezier(0.33,1,0.68,1), 오버슛 0%, 0.75 후 플랫폼 구간 → 길이를 0.7초 내로 압축
.dots i1.50 + i*0.15영상 끝까지—scale 0→1spring(120,14) 오버슛 7.1%, 0.67초 안정화 → 구간 길이 0.75초로 지정

좋은 곡선의 판단 기준 (도구가 직접 알려줍니다): 오버슛 ≤ 15%, 중간 플랫폼 없음, 스프링 안정화 시간이 구간 길이를 초과하지 않음. 하나라도 충족되지 않으면 매개변수를 변경하여 다시 실행하고, "일단 이렇게 쓰고 렌더링해 보자"고 하지 마십시오.

템플릿 및 더 많은 패러다임: references/spec-and-prompt.md

STEP 2 · 구현

뼈대부터 시작하고, 한 번에 전체 장면을 작성하지 마십시오. 뼈대 = 배경 + 움직이는 요소 하나 + seek 계약 준수.

window.scene = {
  duration: 3.0, fps: 30, width: 1920, height: 1080, ready: true,
  seek(t) {
    // 각 요소: '타임라인 테이블의 해당 행'을 그대로 3줄의 코드로 번역
    // k = curve(seg(t, enter, enter + duration)) → k로 속성 보간
  },
};

CSS와 JS는 반드시 인라인해야 합니다. 외부 CDN을 참조하지 마십시오 (렌더링 시 네트워크 단절처럼 실패함). 글꼴은 시스템 글꼴을 사용하십시오 ("Segoe UI", "Microsoft YaHei", Arial).

사용 가능한 패러다임 (DOM/CSS/SVG/Canvas/GSAP/Web Animations, 이징 라이브러리, 다중 구간 편성, 텍스트 한 글자씩, 경로 스트로크, 숫자 롤링, 마스크 전환, CSS linear(), filter/blend-mode/mask 사용법): references/code-patterns.md

무언가를 그려야 할 때 (광원, 텍스처, 그래픽, 아이콘, 차트, 일러스트, 의사 3D)는 먼저 references/asset-recipes.md를 찾아보십시오. 20가지 무의존성 스니펫이 있으며, 모두 단일 파일 HTML에 바로 붙여넣고 seek(t)로 구동할 수 있습니다. 감으로 처음부터 만들거나 에셋을 기다리지 마십시오.

STEP 3 · 수치 검증 (먼저 숫자를 확인하고, 성급하게 렌더링하지 마십시오)

이 단계는 "다중 검증" 중 가장 먼저 실행되는 단계입니다: 초 단위, 코딩 불필요, 요소를 특정할 수 있습니다.

# 각 요소의 실제 궤적 확인: 누가 움직이는지, 어디로 움직이는지, 어디서 멈추는지
node scripts/verify.mjs --html scene.html --select "#bar b,#title span" --props transform,opacity --steps 31

# "화면이 오직 t에 의해서만 결정되는지" 검증 (동일한 t에 대한 두 번의 호출은 완전히 동일해야 함)
node scripts/verify.mjs --html scene.html --select ".item" --idempotent

이 명령은 다음과 같은 종류의 답을 직접 알려줍니다:

  • ⚠ #b[0] — sx · 중간에 0–2초 동안 멈췄다가 다시 변화함 → 보간이 중단되거나 누락됨
  • ℹ #card[0] — (전체) — 이 요소는 전체 구간 동안 전혀 변화 없음 → 선택자가 일치하지 않거나 style이 DOM에 기록되지 않음
  • ✖ seek이 멱등하지 않음: 동일한 t에 대해 13번의 두 호출 결과가 다름 → seek에서 누적 상태가 사용됨

수치 레이어가 통과한 후에 다음 단계로 진행하십시오. 수치에 문제가 있을 때 전체 영상을 렌더링하지 마십시오 — 그러면 모호한 "화면이 움직이지 않는 것 같다"는 결과만 얻고, 픽셀에서 원인을 역추적해야 합니다. 먼저 숫자가 말하게 하십시오.

STEP 4 · 렌더링 + 픽셀 검수

먼저 키프레임만 추출하십시오. 빠르고, 구도가 올바른지 판단하기에 충분합니다:

node scripts/render.mjs --html scene.html --still 0.2,1.0,2.2 --out out/stills

이 이미지들을 검토하십시오 (read_image로 직접 확인하고 건너뛰지 마십시오). 구도가 확인되면 전체 영상을 렌더링하십시오:

node scripts/render.mjs --html scene.html --out out/v.mp4 --fps 30 --sheet
node scripts/audit.mjs --video out/v.mp4 --fps 30 --duration 3 --width 1920 --height 1080

audit은 다음을 제공합니다: 변화하는 픽셀 곡선, 리듬 바, 등급별 결론. 결론에 따라 수정하고, 한 번에 지목된 한 곳만 수정한 후 즉시 audit을 재실행하십시오. 최대 5회; 5회차에도 FAIL이면 STEP 1로 돌아가 사양을 수정하십시오 (사양 자체가 잘못된 것입니다).

일반적인 오류 메시지는 references/failure-modes.md에서 확인하십시오.

STEP 5 · 사람 눈 샘플 검사

기계는 "구조가 옳다"는 것만 보장합니다. 다음 항목은 직접 이미지를 보고 확인해야 합니다:

  • 텍스트가 화면을 넘어가거나 / 잘리거나 / 배경색과 충돌하지 않는지
  • 시각적 중심이 예상 위치에 있는지 (3분할 법칙 / 중앙 / 요소 그룹의 무게 중심)
  • 대비가 충분한지 (어두운 배경에 40% 투명도의 회색 텍스트는 보이지 않음)
  • 진입/퇴장이 깔끔한지 (화면 밖에서 움직이기 시작하거나 화면 안에서 갑자기 사라지는 요소가 없는지)

체크리스트: references/review-checklist.md

STEP 6 · 납품

# 필요한 형식이 있으면 추가 명령 실행
node scripts/render.mjs --html scene.html --out out/v.webm --format webm
node scripts/render.mjs --html scene.html --out out/v.gif --format gif --fps 15

납품 시 포함할 내용: 완성 영상 경로, 접촉 시트, audit의 verdict 행, storyboard.md. audit에 WARN이 있지만 설계 내 의도된 것이라고 판단되면, 어느 항목인지와 이유를 명시하십시오.

최종 확정 버전은 반드시 모션 블러를 켜고 다시 렌더링해야 합니다.

node scripts/render.mjs --html scene.html --out out/final.mp4 --fps 30 --motion-blur 180

이것이 "부드러워 보이는 것"과 "화면 캡처처럼 보이는 것"의 경계입니다. 반복 단계에서는 시간 절약을 위해 일시적으로 끌 수 있지만, 납품 버전에는 셔터가 없어서는 안 됩니다 — 이것을 절약하는 것은 품질을 낮추는 것입니다. 모션 블러를 켠 후 audit을 한 번 더 실행하여 길이와 프레임 수가 변경되지 않았는지 확인하십시오. 빠른 움직임이 있는 경우 (캐릭터 동작, 카메라 스윙, 입자) 동시에 --fps 60을 적용하십시오.


명령어 빠른 참조

# 환경 점검
node scripts/render.mjs --check

# 계산 (곡선 / 스프링 / 지연 / 대비) — 이러한 것은 암산 금지
node scripts/ease.mjs cubic 0.22 1 0.36 1
node scripts/ease.mjs spring 120 14 1 1.2
node scripts/ease.mjs css-linear --preset silkIn
node scripts/ease.mjs stagger 7 2.4 0.5
node scripts/ease.mjs contrast "#0b0e14" "#6d8bbd"
node scripts/ease.mjs ramp "#0b0e14" 5
node scripts/ease.mjs presets

# 뼈대 기하학 점검 (캐릭터가 있을 때 필수 실행; 기존 rig이 있으면 반드시 --ref로 정렬)
node scripts/rigcheck.mjs --rig rig/ander.rig.json
node scripts/rigcheck.mjs --rig lib/rig.json --ref rig/ander.rig.json
node scripts/rigcheck.mjs --rig rig.json --pose '{"head":{"rot":0.2}}' --assert

# SKILL.md frontmatter 점검 (skill 수정 후 한 번 실행, "skill 전체를 불러올 수 없음" 방지)
node scripts/lint-skill.mjs

# 수치 검증 (초 단위, 요소 특정 가능)
node scripts/verify.mjs --html scene.html --select "#bar b" --props transform,opacity --steps 31
node scripts/verify.mjs --html scene.html --select ".item" --idempotent
node scripts/verify.mjs --html scene.html --all --json

# 키프레임 (검토용, 가장 빠름)
node scripts/render.mjs --html scene.html --still 0,0.5,1.5,2.9 --out out/stills

# 키프레임 + 구성 가이드라인 (100px 그리드 / 80px 안전 영역 / 3분할선 / 중앙 십자)
node scripts/render.mjs --html scene.html --still 1.6 --guides --out out/guides

# 전체 영상 + 접촉 시트
node scripts/render.mjs --html scene.html --out out/v.mp4 --fps 30 --sheet

# 최종 납품 버전에 모션 블러 적용 (180° 셔터 = 영화 표준; 렌더링 시간 4배, 최종 확정 시에만 사용)
node scripts/render.mjs --html scene.html --out out/final.mp4 --fps 30 --motion-blur 180

# 빠른 움직임이 있을 때만 (캐릭터 동작, 카메라 스윙, 입자) 60fps 적용
node scripts/render.mjs --html scene.html --out out/final.mp4 --fps 60 --motion-blur 180

# 2x 슈퍼샘플링 (더 선명함, 3–4배 느림)
node scripts/render.mjs --html scene.html --out out/v.mp4 --scale 2

# 투명 배경: webp / apng / png 신뢰 가능
node scripts/render.mjs --html scene.html --out out/v.webp --format webp --alpha
node scripts/render.mjs --html scene.html --out out/v.apng --format apng --alpha

# webm의 알파는 ffmpeg 빌드에 따라 다름. 로컬 테스트 결과 VP8/VP9 모두 알파 없이 다운그레이드됨.
# 스크립트는 인코딩 후 첫 번째 프레임을 다시 읽어 검증 — 투명 픽셀이 없으면 오류를 보고하고 어떤 형식으로 전환해야 하는지 알려줌
node scripts/render.mjs --html scene.html --out out/v.webm --format webm --alpha

# 루핑 애니메이션 GIF
node scripts/render.mjs --html scene.html --out out/v.gif --format gif --fps 15

# 픽셀 검수
node scripts/audit.mjs --video out/v.mp4 --fps 30 --duration 3 --width 1920 --height 1080
node scripts/audit.mjs --video out/v.gif --loop           # 루핑 이음새 검사
node scripts/audit.mjs --video out/v.mp4 --json out/audit.json

render.mjs 매개변수: --html --out --fps --duration --width --height --scale --format(mp4|webm|gif|webp|apng|png) --still --sheet --alpha --file --keep-frames --chrome --check --quiet verify.mjs 매개변수: --html --select --props --steps --idempotent --all --json audit.mjs 매개변수: --video --fps --duration --width --height --loop --json --frame-sample rigcheck.mjs 매개변수: --rig --ref --pose --assert --all ease.mjs 매개변수: cubic, spring, stagger, contrast, ramp, css-linear, presets

관련 스킬