Communitygithub.com

michaelburshtein/thought-to-motion

말하는 사람의 클립, 음성 녹음 또는 일반 텍스트를 내용에 맞춰 움직이는 모션 디자인이 적용된 세로(9:16) 또는 가로(16:9) 동영상으로 변환합니다. 단어 단위 자막(히브리어/영어), 키워드 카드, A/B 공개 효과, 아이콘, 엔딩 카드, 브랜드 테마, 무료 저작권 음악을 지원하며, 완전히 로컬에서 실행됩니다(Whisper/ivrit.ai + Remotion + ffmpeg). 두 번의 사람 승인 게이트를 거칩니다.

thought-to-motion란 무엇인가요?

이 스킬은 개인이 짧은 소셜 비디오, 음성 메모, 또는 텍스트를 전문가 수준의 모션 그래픽 동영상으로 제작할 수 있게 해주는 완전한 파이프라인입니다. 'thought-to-motion'은 녹음(말하는 사람 영상 또는 음성)을 받아 그 내용의 비트를 분석하고, 단어 단위 자막, 키워드 카드, 전환 효과, 아이콘, 종료 질문 등으로 동기를 부여합니다. 세 가지 모드(talking-head, voice, text), 두 가지 화면 비율(9:16, 16:9), 이중 언어 자막, 브랜드 테마(따뜻함, 영화, 기술), 저작권 없는 배경 음악을 지원합니다. 모든 처리는 로컬에서 이루어지며, 데이터가 외부로 전송되지 않습니다. 이 스킬의 핵심 워크플로는 설정 → 자료 준비 → 대본 검토 및 자막 작성 → 모션 계획 수립(게이트 1) → 스틸 렌더링(게이트 2) → 최종 동영상 렌더링으로 구성됩니다. 사용자는 각 게이트에서 승인을 해야 하며, 모든 콘텐츠(사실, 숫자, 인용문)는 대본에 근거해야 합니다. 주요 플랫폼은 Claude Code, Cursor와 같은 에이전트 시스템에서 원격 실행되며, 완전히 자체 호스팅됩니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/michaelburshtein/thought-to-motion-skill/tree/main/skills/thought-to-motion

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

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

문서

thought-to-motion은(는) 무엇을 하나요?

아이디어가 제품입니다. 그 외 모든 것은 레이어일 뿐입니다. 이 스킬은 녹음(말하는 사람 영상 또는 음성 메모)을 받아 그 내용의 비트를 찾고, 비트에 맞춰 모션을 디자인합니다: 말한 언어의 자막, 키워드 카드, 반전 공개 효과, 종료 질문.

세 가지 모드:

  • talking-head: 원본 영상을 유지하고, 카드, 자막, 확대 효과를 그 위에 배치합니다.
  • voice: 영상이 필요 없습니다(오디오 파일 또는 동영상에서 추출한 오디오). 브랜드 캔버스에 장면, 키네틱 자막, 라이브 파형을 전체 화면으로 표시합니다.
  • text: 녹음이 전혀 필요 없습니다. 일반 텍스트가 시간에 맞춰 키네틱 자막과 장면으로 브랜드 캔버스 위에 표시되며, 보통 배경 음악을 포함합니다.

두 가지 형식: 9:16(기본값; Reels, TikTok, Shorts) 및 16:9("aspect": "16:9"; YouTube, LinkedIn, 웹). 동일한 계획이 두 형식 모두에서 렌더링됩니다. 16:9의 경우 9:16 레이아웃을 넓은 무대 위에 배치합니다(talking-head: 화자는 오른쪽, 모션 디자인은 왼쪽).

모든 작업은 이 기기에서 실행됩니다. 어떤 영상, 오디오 또는 텍스트도 외부로 업로드되지 않습니다.

0. 설정(기기당 한 번)

스킬 폴더에서:

bash scripts/setup.sh          # venv + 고정 패키지 + lockfile 기반 engine/node_modules + 로컬 사운드 킷

필요 사항: ffmpeg, Node 18+, Python 3.10+. 첫 번째 전사 작업은 huggingface.co(및 해당 파일 CDN *.hf.co)에서 모델을 다운로드하여 .cache/hf에 저장합니다. 네트워크 접근이 허용 목록에 있는 경우 해당 호스트를 허용해야 합니다. Chrome/Chromium headless shell이 이미 존재하는 경우 BROWSER_EXECUTABLE=/path/to/headless_shell을 설정하세요. 그렇지 않으면 Remotion이 첫 번째 렌더링 시 engine/node_modules에 자체 headless shell을 다운로드합니다. Python 스크립트는 .venv/bin/python으로 실행하세요.

나의 브랜드(한 번)

brand.example.json을 brand.json으로 복사하여 작성하세요: 워드마크(이름 또는 브랜드), 시리즈 레이블, 핸들, 브랜드 라인, 테마(warm, cinematic 또는 tech, engine/src/lib/theme.js 참조; 거기서 자신만의 색상과 글꼴을 추가할 수 있습니다). 모든 계획의 brand, theme 및 bumpers 필드는 이 파일에서 가져옵니다. brand.json이 없으면 헤더, 인트로 또는 아웃트로가 표시되지 않습니다.

1. 인입(추론할 수 없는 것만 질문하세요)

  • 소스. 사람이 말하는 동영상 -> talking-head; 오디오 전용, 또는 음성만 중요한 동영상 -> voice(prep이 오디오를 추출함); 일반 텍스트 -> text 모드.
  • 형식: 9:16, 16:9 또는 둘 다(동일한 계획을 다른 aspect로 두 번 렌더링).
  • 음악: 켜기 또는 끄기. 내장된 생성 배경 음악만 포함됩니다(calm / warm / pulse, 저작권 없음, 클레임 대상 아님). 사용자가 특정 노래를 원하면 음악을 끄고; 사용자가 앱에서 추가합니다.
  • 자막 언어: 기본값 = 음성 언어. 두 번째 언어에 대한 두 가지 옵션: 이중 언어(동영상 하나에 음성 언어 위에 더 작은 번역을 아래에 표시: lang2 + text2) 또는 별도 렌더링.
  • 테마(warm 따뜻함 / cinematic 어두움 / tech 네이비, engine/src/lib/theme.js 참조), 브랜드 워드마크 + 시리즈 레이블(또는 없음), 그리고 종료 질문/CTA(있는 경우).
  • Voice 모드: 사용자가 사용할 사진이 있다면 해당 사진을 <job>/public/에 넣습니다.

2. 준비

텍스트 모드(녹음 없음):

.venv/bin/python scripts/prep_text.py <text.txt | "inline text"> <job> [--lang he|en] [--wpm 150] [--aspect 9:16|16:9]

텍스트를 구문 경계에서 자막 크기 줄로 나누고, 편안한 읽기 속도로 시간을 지정하여 plan.draft.json을 작성합니다(모드 "text", 음악 calm, 모션 calm). 사용자의 단어를 다시 쓰지 말고, 분할 및 시간 지정만 수행하세요. 그런 다음 voice 모드와 마찬가지로 장면을 디자인합니다(섹션 4). 섹션 4로 건너뛰세요.

동영상 또는 오디오:

.venv/bin/python scripts/prep.py <media> <job> [--mode voice] [--lang he|en|auto] [--no-cut]

1080x1920 30fps(또는 오디오)로 정규화하고, 0.45초 이상의 일시 정지를 자르고, 음성을 정리합니다(DeepFilterNet3 노이즈 제거 + EQ, 디에싱, 압축, -14 LUFS; 기본값 --clean gentle, 매우 시끄러운 야외 클립은 full, 스튜디오 녹음은 off), 사운드 킷을 복사하고, 잘린 타임라인을 단어 시간과 함께 전사합니다 -> <job>/transcript.json. 히브리어는 자동으로 ivrit.ai 모델을 사용합니다. 스크립트는 신뢰도가 낮은 단어를 출력하므로 먼저 확인하세요.

선택 사항: 배경 바꾸기(talking-head)

최상의 결과 - 깨끗한 플레이트를 촬영하세요. 자리에 앉기 전에 빈 방을 3-5초 동안 촬영한 다음 걸어 들어와 시작하세요. 삼각대에 휴대폰을 고정하고 노출과 초점을 잠급니다(iPhone: "AE/AF LOCK"이 나타날 때까지 화면을 길게 누름). 그래야 방이 들어갈 때 밝아지거나 어두워지지 않습니다. 카메라를 줌하거나 움직이지 마세요. prep.py는 빈 시작 부분을 자동으로 감지하여 정확한 배경 참조(work/clean_plate.png)로 저장하고, 해당 부분(및 걸어 들어오는 부분)을 동영상에서 잘라냅니다. 깨끗한 플레이트가 없으면 엔진이 머리와 몸통 뒤의 방을 추측해야 합니다. 빈 방은 별도의 클립일 수도 있습니다(같은 고정 휴대폰 위치에서 촬영, 대화 전 또는 후):

.venv/bin/python scripts/plate_from_clip.py <job> <empty_room_clip>

해당 클립의 정지된 빈 시작 부분만 사용하고(누군가 들어오면 중지), 대화 자체 배경에 정렬(ECC, 어파인)하고 채널별로 노출과 색상을 일치시킵니다. 처리하기 전에 work/plate_check.jpg(대화 | 플레이트 | 차이)와 출력된 일치 번호를 확인하세요.

.venv/bin/python scripts/background.py <job> <plate.jpg> --draft [--reveal SECONDS]   # 초안: 절반 해상도, 약 4배 빠름
.venv/bin/python scripts/background.py <job> <plate.jpg> [--reveal SECONDS]           # 최종: 전체 해상도
# 옵션: [--match 0.65] [--wrap 0.35] [--preview SECONDS]

로컬 인물 매팅(MODNet)과 깨끗한 방 차이 매트 결합: 정적 카메라의 경우 클립의 중앙값이 빈 방이며, 이와 다른 모든 것(빠른 손, 머리카락, 팔)은 사람으로 유지됩니다. 빈 방은 각 지점이 실제로 비어 있는 프레임에서만 학습되므로(먼저 사람이 마스킹됨), 머리 옆의 실제 벽이 사람으로 오인되지 않습니다. 반투명 가장자리(머리카락)는 빈 방을 기준으로 오염 제거되므로 이전 벽의 잔해가 보이지 않습니다. 데스크 라인(--desk auto: 턱 아래 약 1.2 얼굴 높이; 또는 0.9와 같은 분수; 서 있는 샷의 경우 off) 아래의 모든 것은 사람 앞에 있는 책상과 휴식 중인 팔뚝으로, 촬영된 그대로 유지되며 조명이 다시 맞춰집니다. 핸드헬드 영상에는 --moving-camera를 사용하세요(모델 전용). 화자 뒤의 일반 벽이나 녹색 벽이 가장 깨끗한 결과를 제공합니다. 그런 다음 사람의 밝기와 색상을 플레이트에 맞게 다시 조명하고, 플레이트의 빛이 가장자리를 감싸고, 하나의 비네트 + 그레인이 둘 모두에 적용되어 하나의 카메라로 촬영된 것처럼 보입니다. --reveal은 해당 순간까지 실제 방을 유지하다가 새 방으로 전환됩니다(화자가 카메라에서 요청할 때 좋음). 항상 1-2프레임에 대해 --preview를 실행하고 전체 클립을 처리하기 전에 사용자에게 보여주세요. 처리 후 scripts/bg_qa.py <job>을 실행하세요: 원본 동영상과 새 동영상을 프레임마다 비교하여 사람이 손실된 곳(빨간색) 또는 이전 방이 새어 나온 곳(노란색)을 초 단위로 보고하고, 최악의 프레임 시트(work/bg_qa_sheet.jpg)를 제공합니다. 사용자가 동영상을 보기 전에 모든 실패한 초를 수정하거나 표시하세요. 알려진 오탐: 깨끗한 플레이트와 촬영 사이에 움직인 물체(의자, 문)가 "사람"으로 계산됩니다. 해당 초에 대해 조치를 취하기 전에 시트를 확인하세요. 플레이트는 장면과 일치해야 합니다: 실내/실외, 시간대, 따뜻함/차가움 조명, 카메라 높이. public/source_bg.mp4를 작성합니다.

3. 대본 읽기, 수정, 자막 쓰기

  • 명백한 인식 오류(이름, 속어, 혼합 언어 단어)를 수정하세요. 모든 수정 사항을 사용자에게 나열하세요. 절대 조용히 의미를 변경하지 마세요. 무슨 말인지 확실하지 않으면 질문하세요.
  • 불필요한 말("음", "어")을 제거하세요. 자막: 하나의 큐에 하나의 아이디어, 최대 ~42자, 최대 2줄, 읽을 수 있는 속도(<= ~20자/초), 큐 시간은 단어 타임스탬프에서 가져옵니다.
  • 두 번째 언어: 큐를 직접 번역하되 화자의 목소리와 동일한 시간을 유지하세요(이중 언어 자막의 경우 text2로; 번역을 한 줄에 맞게 충분히 짧게 유지).
  • RTL 자막에서는 인용된 영어를 하나의 실행으로 유지하세요("כי אני זוכר Is that cheese") - 엔진이 이를 분리합니다.

4. 모션 계획 -> 게이트 1 (승인)

먼저 references/motion-rules.md를 읽으세요. 그런 다음 references/prompts/의 스테이지 프롬프트를 순서대로 실행하세요. 이는 작업 단계를 위한 자료를 생성하며, 이를 게이트를 대체하지 않습니다:

  1. 스토리 및 후크 편집기 (1-story-hook-editor.md): 후크 후보, 열린 질문과 닫히는 지점, 아크, 컷 목록. 축어적 범위만 사용합니다. 텍스트 모드: 대신 6-text-to-video-writer.md를 사용하세요.
  2. 자막 디자이너 (3-caption-designer.md): 청킹, 읽기 속도, 강조 단어, RTL.
  3. 모션 디렉터 (2-motion-director.md): 비트당 하나의 요소, 해당 단어에 착지, 한 번에 하나의 초점, 교체보다는 변형.
  4. 사운드 디자이너 (4-sound-designer.md): 착지점에 드문드문 사운드, 음악 스타일, 하나의 침묵 비트.

비트 찾기(references/design-rules.md 참조): 후크, 명명된 참조(쇼, 사람, 장소, 제품), 핵심 개념, 대비 또는 선택, 목록, 화자가 실제로 말한 숫자, 반전/공개, 질문/CTA. 각 비트를 요소에 매핑합니다(references/plan-schema.md 참조). 사용자에게 표를 제시하세요:

| # | 시간 | 말한 내용 | 요소 | 이유 | 가르치는 것 | 확인 | |---|---|---|---|---|---|

또한 비디오 캐치프레이즈(비디오의 주요 아이디어, 화자가 실제로 말하는 약 2-3초 분량의 대사)를 오프너용으로 제안하세요. 또한 다음을 나열하세요: 자막 수정 사항, 추가한 화면상 사실(예: 쇼의 연도)과 출처, 테마, 사운드. 멈추고 승인을 기다리세요. 승인 전에는 아무것도 렌더링되지 않습니다.

5. 계획 작성 및 검증

<job>/plan.json을 작성하세요(스키마는 references/plan-schema.md, 예제는 examples/ 참조). 그런 다음:

.venv/bin/python scripts/validate_plan.py <job>/plan.json

모든 ERROR를 수정하세요. WARN을 읽고 중요한 것을 수정하세요. 스키마 외에도 모션 규칙을 검사합니다: 0.5초까지의 콘텐츠, 6초 이상 시각적 이벤트 없음, 최대 2개의 그래픽 동시 사용, 읽기 속도(최대 20자/초), 자막 지속 시간, 확대 제한, 빛 누출 안전, 사운드 효과 간격, 침묵 비트. 의도적으로 규칙을 위반하는 경우 게이트 2에서 그 이유를 명시하세요.

검증기는 안전 영역(x 60-900, y 220-1420: 앱 UI가 덮지 않는 프레임 부분)을 적용하고 모든 카드와 패널이 발표자의 얼굴에서 떨어지도록 합니다(faces.json에서 추적). 카드를 자동으로 이동하려면 --fix를 추가하세요. references/safe-zones.md 참조.

가상 카메라(talking-head, 자동)

.venv/bin/python scripts/shots.py <job> [--plan plan.json]

하나의 고정 샷을 멀티 카메라 편집처럼 보이게 합니다: 카메라 A(와이드, 원본 프레이밍), B(미디엄, ~1.2배), C(클로즈, ~1.4배; 16:9에서는 최대 1.7배), 동일한 프레임에서 잘라내고 추적된 얼굴에 고정합니다. 카메라 변경은 prep이 만든 일시 정지 컷(점프 숨기기)에 착지하고, 그 외에는 문장 끝에; 샷은 3-8초 동안 지속됩니다. 같은 카메라를 두 번 사용하지 않습니다. 카드가 공간을 필요로 할 때는 와이드, 확대 및 공개 시에는 클로즈업. 각 확대 샷은 약 1.5% 안쪽으로 푸시됩니다(calm). 모든 카메라는 카드 및 자막에 대해 테스트되어 얼굴이 선명하게 유지됩니다. 클로즈업 셀카(얼굴이 프레임의 1/3보다 큼)는 9:16에서 가상 카메라를 얻지 못합니다. 더 가까이 갈 공간이 없습니다. AI 생성 각도 없음: 영상은 실제로 로컬 상태를 유지합니다. 게이트 1 테이블에 "카메라" 열(A/B/C)을 추가하세요.

6. 스틸 -> 게이트 2 (승인)

.venv/bin/python scripts/render.py stills <job>        # 주요 순간 -> <job>/stills/sheet.jpg

시트는 가이드를 보여줍니다: 안전하지 않은 영역은 빨간색, 추적된 얼굴은 녹색. 먼저 직접 확인하세요: 모든 것이 안전 영역 내에 있고, 얼굴/입을 덮는 것이 없으며, 히브리어/영어 순서가 올바르고, 글꼴이 로드되었으며(Times 유사 대체 글꼴 없음), 겹침이 없습니다. 그런 다음 독립 검토자(references/prompts/5-reviewer.md)를 별도의 에이전트로 실행하세요. 이 에이전트는 사용자의 추론을 보지 못한 상태여야 합니다. 스틸, plan.json 및 대본만 제공하세요. 차단 요인을 수정하고, 판정을 스틸과 함께 사용자에게 보여주세요. 멈추고 승인을 기다리세요. 검토자는 사용자를 대신하여 승인하지 않습니다.

7. 렌더링, 확인, 전달

.venv/bin/python scripts/render.py video <job> --name <NAME>            # 검토용 540x960 초안(기본값, 빠름)
.venv/bin/python scripts/render.py video <job> --name <NAME> --final    # 전체 1080x1920, 최고 품질

모든 검토 렌더링은 절반 해상도 초안(540x960) 입니다. 승인된 최종 버전에 대해서만 --final을 렌더링하세요. 자막 언어당 하나의 렌더링(계획에서 lang + captions 변경). 렌더링 후 확인: 지속 시간 일치, 오디오 존재, 몇 프레임이 올바르게 보이는지. MP4(1080x1920 또는 1920x1080 H.264 high profile, faststart; Reels, TikTok, Shorts, YouTube, LinkedIn에 적합)와 옆에 작성된 .srt 자막 파일(자막 언어당 하나)을 전달하세요. 계획에 "music"이 있으면 배경 음악이 렌더링 시 혼합되어 음성 아래에서 자동으로 낮아집니다. 렌더링은 2 CPU에서 동영상 1분당 몇 분이 소요됩니다.

--final은 <NAME>_social.mp4도 작성합니다: 약 10Mbps의 동일한 영상(스케줄러 API에 충분히 작음, 예: Instagram의 약 300MB 제한)이며, 최종 파일에서 오디오가 -14 LUFS / -1 dBTP로 다시 측정되고 정규화됩니다. 게시용으로 해당 복사본을 전달하고 높은 비트레이트 마스터를 보관하세요. 전달된 파일을 측정하고(ffmpeg -i <file> -af ebur128=peak=true -f null -) 음량을 보고하세요. 동영상은 마지막 말 이후 약 0.8초 후에 종료됩니다(prep이 해당 꼬리를 유지하므로 마지막 단어가 잘리지 않음). 계획에 "bumpers"가 있으면 render.py는 오프너 -> 인트로 -> 비디오 -> 아웃트로를 결합하고(scripts/bumpers.py), .srt 파일을 오프너 + 인트로 길이만큼 이동시키며, 사운드와 영상이 동기화되지 않으면 중지합니다(오프너, 인트로 및 아웃트로 참조).

규칙(협상 불가)

  • 사실, 숫자, 인용문 또는 이야기를 절대 지어내지 마세요. 대본 외의 화면상 사실(날짜, 제목)은 확인되어 게이트 1에서 사용자에게 표시되어야 합니다.
  • 인식 가능한 캐릭터, 로고 또는 저작권이 있는 아트워크를 그리지 마세요. 유형과 내장된 일반 아이콘을 사용하세요. 예외: logo 요소...

관련 스킬