Communitygithub.com

spatial-film

Spatial Film - talking-explainer의 영화 엔진. 실제 제품 UI, 플랫폼에 충실한 서드파티 캔버스(GHL, n8n, Zapier), 네이티브 템포의 음악 및 SFX와 함께 45-90초 분량의 나레이션 없는 공간 3D 제품 모션 그래픽을 제작합니다(CSS-3D 카메라 1대, 푸시스루, 하드 컷 없음, 마지막 프레임이 첫 번째로 루프). HyperFrames를 통해 1080p60으로 렌더링됩니다. 사용자가 "spatial film" 또는 "3D motion graphic"이라고 말하거나, MOTION-PROMPT.md를 건네주거나, 6개 이상의 장면/3D 카메라 제품 비디오(음성 해설 없음)를 요청할 때 사용합니다.

spatial-film란 무엇인가요?

Spatial Film은 고품질 3D 제품 모션 그래픽을 제작하기 위한 AI 에이전트 기술입니다. 사용자가 "spatial film" 또는 "3D motion graphic"을 요청하거나, MOTION-PROMPT.md 파일을 제공하거나, 6개 이상의 장면으로 구성된 3D 카메라 제품 비디오(음성 해설 없음)를 요청할 때 활성화됩니다. 이 기술은 CSS 3D 변환을 사용하는 단일 가상 카메라, 장면 간 부드러운 푸시스루 전환, 마지막 프레임이 첫 번째 프레임으로 자연스럽게 루프되는 구조를 특징으로 합니다. 실제 제품 UI와 GHL, n8n, Zapier와 같은 서드파티 플랫폼의 캔버스를 충실히 재현하며, 네이티브 템포의 배경 음악과 사운드 효과를 통합합니다. 5명의 병렬 작업자가 단일 계약(frame.md + seam table + per-scene harness)에 따라 협력하여 HyperFrames를 통해 1080p60으로 렌더링합니다. 나레이션이 필요한 설명형 영화(explainer-kit)는 이 기술의 기반 위에서 실행됩니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/brewed-ops/talking-explainer/tree/main/skills/spatial-film

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

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

문서

Spatial Film

60초 제품 영화(7개 장면, 단일 웨이브에 5명의 작업자, 모든 이음매가 프레임 단위로 정확, 확인 깔끔, 4분 19초 만에 1080p60)로 엔드투엔드 검증되었습니다. 템플릿의 film.json에는 해당 영화의 실제 장면 막대와 큐 시트가 작업 예제로 포함되어 있습니다.

<skill> = 이 기술의 폴더(이 SKILL.md가 있는 디렉터리). 모든 스크립트는 영화 프로젝트 루트에서 실행하세요. 아래 python = explainer-kit의 설정 확인이 ~/.talking-explainer/config.json에 저장한 Python 명령어(Windows에서는 py -3.12, macOS에서는 python3).

필요한 것

  • Node 20+, PATH에 ffmpeg + ffprobe, numpy와 Pillow가 있는 Python 3.10+.
  • HyperFrames 기술: npx hyperframes skills update general-video hyperframes-animation media-use (패킷 빌더, 청사진 + 애니메이션 맵, 음악 도우미). CLI 자체는 프로젝트별로 고정되며 npx를 통해 실행됩니다.
  • 표면 사전 렌더링을 위한 Playwright: 영화 폴더에서 npm i -D playwright 실행 (또는 PLAYWRIGHT_PATH 설정).
  • 선택 사항, 소스 음악의 경우: HeyGen 계정 - 자신의 터미널에서 npx hyperframes auth login을 한 번 실행하세요. 계정이 없으면 직접 트랙을 가져와 4단계를 music-analyze.py부터 시작하세요.
  • 최종 렌더링을 위한 GPU 지원 머신 (소프트웨어 경로로도 렌더링되지만 약 15배 느립니다).

컨텍스트 낭비 없이 이 기술을 사용하는 방법

  • 한 번에 하나의 단계 참조만 로드하세요. 해당 단계가 시작될 때만 로드합니다. 절대 미리 모두 로드하지 마세요.
  • 스크립트는 검증된 코드입니다. 실행하세요. 로직을 인라인으로 재생성하지 마세요.
  • 메인 세션은 전체 장면 파일(20-60KB)을 읽지 않습니다. 연락처 시트로 장면을 판단하고 grep -n과 정확한 패치로 수정하세요.
  • 작업자에게는 내용을 붙여넣지 말고 파일 경로를 제공하세요. storyboard.html(60KB+)은 셀 ID로 grep하며, 전체를 읽지 않습니다.
  • 먼저 연락처 시트를 읽고 세부 사항을 확인해야 할 때만 단일 스냅샷 PNG를 여세요.

단계 (각 단계는 게이트에서 종료됩니다 - 게이트가 통과될 때까지 다음 단계로 넘어가지 마세요)

#단계로드게이트
0스캐폴드: node <skill>/scripts/new-film.mjs <dir> --name <slug>-폴더에 film.json, frame.md, kit, 템플릿 문서가 있어야 함
1인테이크, BRIEF, STORYBOARD, 스케치 시트references/storyboard.md## Locked 아래에 사용자의 명시적인 "go"가 기록되어야 함
2frame.md, kit, 사전 렌더링된 표면references/surfaces.md (+ GHL/n8n/Zapier가 나타나는 경우에만 platform-canvases.md)frame.md에 {{가 없어야 함, 모든 캡처 PNG를 확인해야 함
3하네스 스모크 테스트, 패킷, 병렬 작업자references/workers.md모든 장면: lint 오류 0, 연락처 시트가 해당 블록과 일치해야 함
4음악 + SFX (작업자가 빌드하는 동안 실행)references/audio.mdBGM이 네이티브 BPM, 다운비트에 0번째 마디, film.json에 큐가 있어야 함
5조립, 확인, 이음매, 렌더링, 배송references/verify-ship.md확인 통과, seam-check 모두 PASS, hardware-gpu 렌더링 확인

의도 및 스케치 검토 단계를 위해 /hyperframes -> /general-video를 경유하세요 (이 기술은 프로젝트 형태, 계약, 스크립트 및 게이트를 제공하며, general-video는 패킷 빌더와 작업자 역할을 제공합니다).

파일

경로설명
template/프로젝트 스켈레톤: film.json (장면 막대, BPM, BGM, SFX, 큐 - 유일한 타이밍 소스), frame.md (설계 진실 계약, 채워넣기 포함), BRIEF.md, STORYBOARD.md, assets/kit.css (기본 영화 키트), assets/fonts/ (Poppins 500/700 + OFL), references/worker-brief.md, references/scene-starter.html (lint-클린 장면 스켈레톤), references/snippets.html, package.json (고정된 hyperframes 0.8.117).
surfaces/GHL, n8n 및 Zapier 캔버스의 준비된 HTML 재구축 + 긴 마케팅 페이지(가상의 Northwind Dental 데이터), platform.css, sprite.svg, jobs.json.
scripts/new-film.mjs템플릿에서 프로젝트 스캐폴드.
scripts/capture-surfaces.cjssrc/captures/*.html을 2배로 assets/captures/*.png로 렌더링 (jobs.json).
scripts/measure-surface.cjs표면의 요소에 대한 1x 상자, 정확한 주석/자르기 대상용.
scripts/make-harness.py, scripts/test-scene.mjs장면별 격리된 테스트 프로젝트; 하나의 장면 lint + 스냅샷.
scripts/music-search.mjs, sfx-search.mjsmedia-use의 REST 헬퍼를 통한 HeyGen 카탈로그 (Windows 안전).
scripts/music-analyze.py, music-bars.pynumpy 전용 템포 + 마디당 에너지 (librosa 필요 없음).
scripts/bgm-cut.py마디선에서 BGM 자르기, 트랙 자체 아웃트로 연결, 페이드; --b는 더 긴 영화 아래에서 BGM을 루프하도록 반복합니다.
scripts/assemble.pyfilm.json -> index.html (마디 그리드의 장면 슬롯, BGM, 지속 시간 및 레인이 포함된 SFX).
scripts/seam-check.py모든 이음매(컷 전/컷 시점/컷 후)와 루프(프레임 0 대 마지막)를 픽셀 단위로 증명합니다.
scripts/render-final.mjs--browser-gpu를 사용한 CLI 렌더링, 파일에 기록, gpu 모드 + ffprobe 확인 후 flash-scan.py 실행.
scripts/flash-scan.py렌더링의 모든 프레임: 양쪽 이웃과 다른 프레임(1/60초 동안 표시된 요소) = 버그.
scripts/encode-web.mjs웹 인코딩 (H.264 CRF 21, faststart, AAC 또는 --silent) + 포스터 프레임.
scripts/blink-fit.py, scripts/build-presenter.py나레이션 영화: 시트 포즈용 깜빡임 오버레이(--band = 눈 띠); mascot에 mouth-fit.json이 있을 때 립싱크와 함께 자체 트랙에서 프레젠터 오버레이를 만듭니다.
scripts/el-tts.py, el-words.py, el-music.pyElevenLabs를 통한 나레이션 영화 (env EL의 키, 디스크에 절대 저장 안 함): SCRIPT.md의 음성 후보, Scribe 단어 타이밍, 생성된 BGM.
scripts/seam-diff.py프레젠터 상자가 마스킹된 이음매 diff (나레이션 영화).
scripts/fromto-scan.py사전 렌더링: 렌더링 작업자(장면 내 탐색)가 절대 적용하지 않는 fromTo FROM 전용 속성을 플래그합니다. 모든 렌더링 전에 0 히트.
scripts/patch_exact.py스크립트된 장면 수정을 위한 정확한 CRLF-안전 찾기/바꾸기 (각각 하나의 일치를 주장).
scripts/selftest.mjs이 기술이 이 머신에서 작동한다는 엔드투엔드 증명. 반드시 PASS를 출력해야 합니다.

나레이션 영화 (음성 해설 + 화면상 프레젠터)

나레이션 "API vs Webhook" 설명 영화(83초, 세로 및 가로, 복제된 음성, 마스코트 프레젠터, 5명의 작업자가 작업한 10개 장면)로 검증되었습니다. 위의 음악 영화 규칙은 다음 규칙으로 대체되는 경우를 제외하고 여전히 유효합니다:

  • 먼저 음성 후보. EL=<key> python <skill>/scripts/el-tts.py . eric=<voice_id> michelle=<voice_id>는 SCRIPT.md의 들여쓰기된 줄을 읽고 음성별로 하나의 MP3를 src/audio/voice-candidates/에 씁니다 (env의 키만, 디스크에 절대 저장 안 함). 사용자가 귀로 선택하게 한 다음 선택한 것만 전사합니다.
  • 나레이션이 시계입니다. 단어 시간: EL=<key> python <skill>/scripts/el-words.py <voice.mp3> src/timing/voice-words.json (ElevenLabs Scribe - 로컬 모델 없음, 키 필요), 또는 word_timestamps가 있는 faster-whisper (언어 설정, VAD 켬; explainer-kit의 transcribe.py, 무료 및 로컬). 단어 JSON을 src/timing/에 보관하세요. film.json에서 "bpm": 60, "beats_per_bar": 1로 설정하면 "마디"가 1초가 되고 장면 길이는 문장 쉼표에서 자른 일반 초가 됩니다. 스토리보드 블록은 장면 로컬 단어 시간을 제공합니다. 도착은 ~0.1초 일찍 시작하여 단어에 맞춥니다. 제목은 다음 컷 전에 화면에 최소 ~1초 동안 표시되도록 하세요 (컷을 표시하는 줄의 마지막 단어와 비교하여 확인).
  • film.json 추가 사항 (assemble.py + make-harness.py가 읽음): 음성을 위한 "audio": [{id, src, dur, volume}], 모든 장면 위에 있는 전체 영화 레이어(프레젠터)를 위한 "overlays": [{id, track, z}] - 따라서 이음매에서 팝되지 않고 장면은 프레젠터가 없는 상태로 유지됩니다.
  • 포즈 PNG의 프레젠터: 포즈당 하나의 투명 PNG (explainer-kit의 prep-mascot.py가 트림, 스케일링 및 매니페스트 작성), 그런 다음 scripts/blink-fit.py <mascot_dir> (선택 사항, torch 필요; BLINK 눈 띠를 NCC로 각 포즈에 맞춤; 0.70 미만 포즈는 깜빡임 없음) 및 scripts/build-presenter.py (src/presenter-track.json에서 오버레이 작성: 큐 단어의 포즈, 헤드 고정으로 전환이 절대 점프하지 않음, 음성 봉투 밥, 호흡, 깜빡임, fx). 출력물을 수동으로 편집하지 마세요.
  • 오디오: 음성을 -16 LUFS / -1.5 dBTP로 loudnorm (4.6 dBTP에서 클리핑된 일반 게인), 그 아래에서 BGM을 오프라인으로 사이드체인 덕킹 (~17 dB 이하), SFX는 조용하게 (0.1-0.45). 음성 키를 패딩하거나 덕이 BGM을 음성 길이로 자르지 않도록 하세요 ("bgm 110.25s vs slot 113s" 경고 확인): [1:a]apad=whole_dur=<TOTAL>[k];[0:a][k]sidechaincompress=threshold=0.03:ratio=6:attack=25:release=450,atrim=end=<TOTAL>. 카탈로그 BGM 없음(HeyGen 검색 500초 또는 로그인 없음): EL=<key> python <skill>/scripts/el-music.py .media/candidates/bed.mp3 <ms> "<프롬프트: 악기, BPM, 내레이터 아래에 위치, 드롭 없음, 해결된 코드로 끝남>" - 영화 길이에 맞춰 스스로 끝나는 트랙은 스플라이스가 필요 없습니다.
  • 이음매 확인 노이즈: 프레젠터가 모든 이음매를 가로질러 움직이므로 seam-check.py는 이로 인해 실패합니다. 플래그된 각 쌍을 scripts/seam-diff.py a.png b.png out.png x0,y0,x1,y1으로 판단하세요 (프레젠터 상자 마스킹) - 외부 0.00%는 통과입니다.
  • 세로(1080x1920) 크기 규칙: 모든 장면의 상단 띠는 실제 제목(60-84px), 본문 텍스트 >= 40px을 포함하며, 객체는 전체 너비와 프레젠터 위의 높이를 사용합니다. 첫 번째 웨이브는 프레임 상단 45%에 ~33px 텍스트를 배송했습니다. dispatch 전에 frame.md에 이 숫자를 넣으세요.
  • 루프가 아님: 나레이션 영화는 고정된 잠금 화면에서 끝납니다. seam-check의 루프 라인은 무시하세요.

하드 규칙 (프리미엄과 부드러움을 만드는 규칙)

  1. 소스의 진실. 제품 UI는 제품 자체의 HTML/CSS에서 이식됩니다. 서드파티 캔버스는 사용자의 실제 캡처에서 재구축되며, 기억에 의존하지 않습니다. 가상 데이터만 사용합니다. 제품이 실제로 가지고 있는 기능만 사용합니다.
  2. 카메라 1대. 모든 장면에서 원근 1866px(35mm); 카메라 레이어 아래 드리프트 레이어로 아무것도 정지하지 않음; 먼 잎사귀에 시차 + DOF 흐림. 3D 부모에 opacity/filter/overflow/clip-path 없음 (평탄화됨).
  3. 1080p+에서 선명하게. CSS zoom (.kit-zoom)으로 UI 스케일, 절대 transform: scale(>1) 사용 금지; 각 조각을 화면상 가장 가까운 크기로 작성; 캡처는 네이티브 이하로 표시되는 2x PNG입니다.
  4. 60fps 부드러움 규칙. Transform/opacity만 사용; 착지에는 spring, 도착에는 expo/power3, 카메라 다리에는 inOut; linear, steps, snap 또는 반올림 금지; 카메라 다리는 0.15-0.3초 겹치고 0.6초 이상 지속됩니다.
  5. 결정론적. window.__timelines[id]에 마지막으로 등록된 장면당 하나의 일시 중지된 타임라인, 명시적 시작이 있는 fromTo, random/clock/CSS 전환 없음.
  6. 이음매는 공유 프레임입니다. 각 이음매는 두 이웃이 ~0.1초 동안 유지하는 하나의 정확한 그림이며, 리그 외부의 2D 플레이트에 의해 잠깁니다. 하드 컷, 빈 프레임, 사라짐으로의 페이드 없음. 마지막 프레임 = 첫 번째 프레임.
  7. 그리드 위에. 장면은 전체/반 마디; 클릭, 틱, 스탬프 및 스왑은 비트에 맞춤; 네이티브 템포의 음악은 마디선에서 잘림.
  8. 계약 수정, 장면 수정 아님. 루트 상대 assets/... 경로, 숫자로 시작하지 않는 id, 장면 id로 접두사가 붙은 id 및 클래스. 모든 장면이 위반할 규칙은 frame.md / worker-brief에서 한 번 수정됩니다.
  9. 금지 사항. 이모지, 네온 글로우, 보라색-파란색 그라데이션, 색상이 있는 왼쪽 테두리 카드, 원형 스피너(쉬머), 스톡 인물, "John Doe", 슬라이드쇼 페이싱 또는 아무것도 말하지 않는 모션.
  10. CLI와 하드웨어 GPU로 최종 제작. Studio 내보내기(소프트웨어 경로, ~15배 느림) 사용 금지.

문제 발생 시

증상원인수정
Lint: 자산 경로 오류하위 구성에서 ../assets/루트 상대 assets/... (계약에서 수정)
Lint: 잘못된 구성 idid가 숫자로 시작s01-click, 절대 01-click 아님 (film.py가 거부함)
패킷 빌더 오류 발생 / 패킷 > 48KB두 개의 청사진 id 또는 너무 많은 rules:하나의 id (Adapt); 블록당 2-3개의 규칙
UI가 흐릿해 보임변환 스케일링 또는 작성된 크기보다 카메라 쪽으로 밀림.kit-zoom, 가장 가까운 크기로 작성
3D가 갑자기 평평해짐3D 조상에 opacity/filter/overflow잎사귀로 이동
이음매 팝한 쪽이 공유 프레임을 유지하지 않음seam-check.py, 표류하는 쪽의 플레이트/포즈 수정
이음매가 몇 % 실패하지만 프레임이 동일하게 보임플레이트 아래 리그 사본이 그림자를 두 배로 만듦유지하는 동안 플레이트만 표시됨 (frame.md 이음매)
제품 UI가 실제 앱과 다름기억 또는 부분적인 CSS에서 재구축됨실제 앱을 2배로 캡처 (surfaces.md 첫 번째 섹션)
duplicate_audio_track 경고 800개+data-duration 없는 SFXassemble.py 재실행
music-search가 자격 증명이 없다고 표시로그인하지 않음사용자가 터미널에서 npx hyperframes auth login 실행
렌더링이 ~1 프레임/초로 느림소프트웨어 GPU (Studio 내보내기)render-final.mjs (CLI, --browser-gpu --workers 6)
중지 후에도 렌더링이 계속 실행됨셸 중지가 node를 중지하지 않음프로세스 트리 종료 (verify-ship.md)
렌더링 진행률이 표시되지 않음출력이 `tail`로 파이프됨

자체 테스트

node <skill>/scripts/selftest.mjs

임시 폴더에 2개 장면 영화를 스캐폴드한 다음, 하네스, 조립, check, seam-check, 하드웨어 GPU 렌더링(1920x1080, 60fps) 및 웹 인코딩을 실행합니다. 반드시 PASS를 출력해야 합니다. 새 머신에서 그리고 편집 후에 실행하세요.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

관련 스킬