Weft는 긴 호흡의 설명형 영상을 위한 이중 트랙(dual-track) 워크플로우입니다. 입력은 사용자가 직접 쓴 산문 대본이고, 주제는 가리지 않습니다 — 역사, 과학, 문화 분석, 사고실험, 철학 비교 등 무엇이든 됩니다 (대본 작성 자체는 Weft 범위 밖).
다음 둘을 분리합니다:
- 나레이션 비트(narration beats): 대본, 자막, TTS 타이밍
- 비주얼 샷(visual shots): 생성 이미지, 텍스트 카드, 재사용, 몽타주, 모션
이렇게 하면 하나의 비주얼이 여러 나레이션 비트를 덮거나, 하나의 나레이션 비트가 여러 비주얼을 쓸 수 있습니다. 실질적 목표는 "문장마다 이미지 한 장" 식의 편집 노동을 줄이면서, ffmpeg로 완성 MP4를 기본 산출물로 뽑는 것입니다. NLE 편집이 필요할 때는 CapCut 드래프트나 FCPXML로 핸드오프합니다.
install.sh: 설치 스크립트 (venv 생성,weft명령 설치,.env시드)uninstall.sh: 제거 스크립트 (weft명령·venv 제거,.env는 보존)weft/: 파이썬 CLI와 핵심 파이프라인.claude/skills/script-to-conti/: 대본을 Weft 이중 트랙CONTI.md로 바꾸는 스킬.claude/skills/conti-qa/: 콘티 품질 검토(리듬·프롬프트·카드·사실/추측 lint) 스킬.claude/skills/visual-qa/: 생성 이미지 후보·최종 MP4를 비전으로 검수하는 스킬.claude/skills/animation-render/: remotion/hyperframe 샷을clip.mp4로 렌더하는 스킬.agents/skills/: Codex에서도 같은 스킬들을 쓰기 위한 미러weft/picker/: 로컬 이미지 후보 선택기(picker)STYLE_GUIDE.md: 이미지 스타일 커스터마이즈 가이드WORKFLOW.html: 시각적 워크플로우 개요example/CONTI.md,example/SCRIPT.md: 예시 입력
생성물(오디오·이미지·CapCut 드래프트)은 로컬에서 만들어지며 저장소에 커밋되지 않습니다.
저장소 안에서 한 번만 실행하세요:
./install.shinstall.sh는 venv를 만들고 패키지를 editable로 설치(weft 명령 생성)한 뒤 ~/.local/bin에 심볼릭 링크하고 .env.example로부터 .env를 시드합니다. 그다음부터 weft는 어느 디렉터리에서나 동작합니다.
설치 후 저장소의 .env에 본인 키를 채우세요:
- TTS용
TYPECAST_API_KEY,TYPECAST_VOICE - 이미지 생성용
OPENAI_API_KEY
editable 설치라서 weft는 어느 작업 디렉터리에서든 이 .env를 찾습니다. 현재 폴더에 둔 프로젝트별 .env도 인식됩니다.
설치(./install.sh)와 .env 키 입력만 끝났으면, 그다음부터는 명령어를 외울 필요가 없습니다.
cd ~/my-video # 대본·문서(.md 등)가 들어 있는 폴더
claude # 이 폴더에서 Claude Code 실행그리고 한마디 하세요:
이 폴더 대본으로 weft 영상 만들어줘
Claude Code가 weft whereisskill로 script-to-conti 스킬을 찾아 읽고 전체 파이프라인을 돕니다 — 대본을 콘티(CONTI.md)로 바꾸고, weft conti로 검증하고, conti-qa로 품질을 점검한 뒤, weft tts(나레이션) → weft images(이미지) → weft ffmpeg(렌더)로 EXPORTS/weft_render.mp4 를 만들어 줍니다. 중간중간 콘티·이미지를 함께 확인하며 진행합니다. (스킬은 전역 설치하지 않습니다 — weft --help가 AI에게 weft whereisskill을 안내하고, 스킬을 그때그때 읽어 옵니다.)
실제 산출물(나레이션·이미지)은
.env의OPENAI_API_KEY(이미지)·TYPECAST_API_KEY(TTS)가 있어야 나옵니다. 키가 없으면stub(플레이스홀더)로만 흐름을 확인합니다. 반복 캐릭터·스타일·BGM을 쓰려면 폴더에CHARACTER.png/STYLE.txt/BGM.json을 두라고 일러주면 됩니다.
명령을 직접 한 단계씩 돌리고 싶으면 아래 빠른 시작을 참고하세요.
스킬이 모든 Claude Code 세션에서 자동으로 뜨길 원하면(트레이드오프: weft와 무관한 작업에서도 로드됨) weft 저장소에서 한 번 전역 링크하세요.
uninstall.sh가 정리합니다.mkdir -p ~/.claude/skills && ln -sfn "$PWD"/.claude/skills/*/ ~/.claude/skills/
설치한 것을 깔끔히 되돌리려면 저장소 안에서:
./uninstall.shweft 명령(심볼릭 링크)·venv·빌드 산물을 지웁니다. 키가 든 .env는 보존됩니다(완전히 지우려면 안내대로 직접 삭제).
직접 쓴 산문 대본(SCRIPT.md 등)이 있으면 먼저 AI 어시스턴트에게 script-to-conti 스킬을 사용해서 Weft CONTI.md로 변환하라고 요청하세요. 이 스킬은 한 문장마다 이미지를 하나씩 만들지 않고, ▶ 새 그림·↓ 홀드·▦ 몽타주·↺ 재사용 같은 이중 트랙 지시를 넣어 이미지 수를 줄이는 콘티를 만듭니다.
- Claude용:
.claude/skills/script-to-conti/ - Codex용:
.agents/skills/script-to-conti/
터미널에서 스킬 파일 위치를 확인하려면:
weft whereisskill예시 요청:
이 대본을 script-to-conti 스킬로 Weft CONTI.md로 바꿔줘.
스킬 위치는 `weft whereisskill`로 확인해서 SKILL.md를 읽어줘.
검증은 weft conti까지 돌려서 validation_errors=0이 되게 해줘.
프로젝트는 CONTI.md가 들어 있는 폴더입니다. 그 폴더로 cd한 뒤, 현재 디렉터리를 대상으로 동작하는 하위 명령을 실행하세요(경로 인자 불필요):
cd my-video # CONTI.md가 있는 폴더
weft conti # ./CONTI.md -> ./generated_project/ (파싱 + 검증 + 컴파일)
weft tts # ./generated_project (Typecast 나레이션; API 비용)
weft images # ./generated_project (OpenAI/Gemini 이미지; API 비용)
weft animate # Remotion/HyperFrame shot spec 생성·렌더된 clip 확인
weft ffmpeg # ./generated_project -> EXPORTS/weft_render.mp4 (먼저 볼 MP4)
weft pick # 선택: 이미지 후보를 사람이 고름
weft capcut # 선택: 마음에 안 들 때 CapCut 드래프트 생성
weft fcpxml # 선택: FCPXML 핸드오프한 번에:
weft all # 사람용 빠른 자동 실행: conti -> tts -> images -> animate check -> ffmpeg
weft all --capcut # MP4에 더해 CapCut 드래프트도 생성
weft all --fcpxml # MP4에 더해 FCPXML도 생성CONTI.md가 있는 폴더 안에서 실행하세요:
weft conti # ./CONTI.md -> JSON 트랙·픽·SRT·렌더 플랜
weft parse # CONTI.md 파싱 결과 JSON을 출력만 (파일 생성 없음)
weft validate # CONTI.md 파싱+검증 결과만 출력 (파일 생성 없음)
weft tts # Typecast 나레이션 WAV
weft images # OpenAI 이미지 후보
weft pick # 로컬 브라우저 picker
weft animate # Remotion/HyperFrame animation shot 준비·검사
weft ffmpeg # ffmpeg MP4 렌더러 (자막 기본 burn-in)
weft capcut # 선택: CapCut 드래프트 빌더
weft fcpxml # 선택: Final Cut/Premiere/Resolve용 FCPXML 핸드오프
weft all # 사람용 빠른 자동 MP4 렌더
weft all --capcut # MP4 + CapCut
weft all --fcpxml # MP4 + FCPXML
weft settings # WEFT_SETTINGS.txt 생성/확인
weft whereisskill # AI에게 읽힐 script-to-conti 스킬 경로 출력별칭: weft dryrun은 weft conti와 같고, weft render는 weft ffmpeg와 같습니다.
weft upload(선택): 완성 MP4를 비공개로 YouTube에 업로드 — ./install.sh youtube-upload로 의존성을 설치한 뒤 자세한 설정은 manual4youtubeupload.md를 보세요.
conti의 입력은 기본값이 ./CONTI.md, 나머지 프로젝트 명령의 프로젝트 디렉터리는 기본값이 ./generated_project입니다. 파워 유저는 경로를 명시적으로 넘길 수도 있습니다.
weft capcut와 weft all --capcut은 --no-register로 CapCut 목록 등록을 건너뛸 수 있습니다(드래프트 파일만 생성).
weft conti 또는 weft all을 실행하면 프로젝트 폴더(CONTI.md 옆)에 WEFT_SETTINGS.txt가 없을 때 기본 파일을 만듭니다. VASP INCAR처럼 이 파일 하나를 다른 프로젝트에 복사하면 같은 렌더/provider 옵션을 재사용할 수 있습니다. CLI로 직접 준 옵션은 이 파일보다 우선합니다. 기본 빠른 산출물은 ffmpeg MP4이고, CapCut/FCPXML은 필요할 때 추가 실행합니다.
바로 쓸 수 있는 예시는 setting_examples/에 있습니다:
youtube_4k_high.WEFT_SETTINGS.txtyoutube_high.WEFT_SETTINGS.txtstandard.WEFT_SETTINGS.txtlow.WEFT_SETTINGS.txt
테스트 영상 용량을 줄이는 예:
EXPORT_FFMPEG=true
FFMPEG_ENCODER=libx264
FFMPEG_CRF=32
FFMPEG_PRESET=veryfast
FFMPEG_BITRATE=2M그 뒤:
weft settings로 현재 프로젝트 설정 파일을 만들거나 확인할 수도 있습니다.
weft allweft ffmpeg는 EXPORTS/render_plan.json, 선택 이미지, TTS WAV, 컴파일된 자막 이벤트를 바로 EXPORTS/weft_render.mp4로 렌더합니다. 자막은 기본으로 영상에 입혀지며(--no-subtitles로 비활성화), --encoder auto가 macOS의 h264_videotoolbox를 우선 시도하고 실패하면 libx264로 fallback합니다. 소프트웨어 인코딩 확인용은 --preset ultrafast, 더 작은/고화질 출력은 --crf 값 조정으로 맞추세요.
기본은 BGM 없음입니다. 유튜브 오디오 라이브러리처럼 라이선스가 확보된 음원 파일(mp3/wav/m4a, 서사 없는 배경음 권장)을 준비해 WEFT_SETTINGS.txt에 지정하면, weft ffmpeg가 BGM을 깔고 나레이션이 나오는 동안 자동으로 BGM을 낮춥니다(사이드체인 덕킹) — ⏸ 정적 구간과 문장 사이에서는 다시 올라옵니다. CapCut을 거칠 필요가 없습니다.
BGM_FILE=music/bgm.mp3 # CONTI.md 기준 상대 경로 또는 절대 경로 (전곡 1개, 짧으면 자동 반복)
#BGM_GAIN_DB=-16 # BGM 기본 음량(dB)
#BGM_DUCK_DB=-12 # 나레이션 중 추가로 낮추는 깊이(dB)
#BGM_FADE_SECONDS=2.0 # 곡(구간) 시작/끝 페이드(초)막(구간)별로 다른 곡을 쓰려면 CONTI.md 옆에 BGM.json을 만듭니다. BGM_FILE보다 우선하고, CARDS.json처럼 weft conti/weft all이 generated_project로 복사합니다:
[
{"file": "music/opening.mp3", "from": "0:00", "to": "1:30", "gain_db": -16},
{"file": "music/ending.mp3", "from": "1:30", "to": ""}
]to를 비우면 영상 끝까지이고, 마지막 곡은 영상 끝에서 페이드아웃됩니다. 설정해 두고 한 번만 끄려면 weft ffmpeg --no-bgm(또는 weft all --no-bgm). weft capcut 드래프트에는 BGM이 별도 오디오 트랙으로 단순 배치만 됩니다(덕킹·정밀 페이드는 CapCut에서 직접).
weft animate는 source_kind=remotion 또는 source_kind=hyperframe shot마다 SHOTS/<shot>/animation/SPEC.md를 만들고, AI가 렌더해야 할 출력 경로 SHOTS/<shot>/rendered/clip.mp4를 검사합니다. 렌더된 MP4는 일반 clip처럼 weft ffmpeg, weft capcut, weft fcpxml에 들어갑니다.
weft fcpxml은 같은 render_plan에서 편집 가능한 FCPXML을 만듭니다. 이미지/클립/애니메이션 클립은 비디오 레인, TTS는 오디오 레인, 자막은 타이틀 레인으로 들어갑니다.
provider는 .env에서 바꿀 수 있습니다:
IMAGE_PROVIDER=openai # openai | gemini | comfyui | stub
TTS_PROVIDER=typecast # typecast | stub
OPENAI_IMAGE_MODEL=gpt-image-2 # 기본(네이티브 16:9). 더 싸게는 gpt-image-1-mini(2026-12-01 종료)
GEMINI_API_KEY= # IMAGE_PROVIDER=gemini 일 때 (Google AI Studio 키)
GEMINI_IMAGE_MODEL=gemini-3.1-flash-image # 기본. 저가형 gemini-2.5-flash-image / 고품질 gemini-3-pro-image
IMAGE_ASPECT=16:9 # 16:9 | 9:16 | 1:1 | 3:2stub은 API 키 없이 로컬 테스트용 PNG/WAV를 만듭니다.
이미지 비율(IMAGE_ASPECT, 기본 16:9)은 provider가 어떤 크기를 반환하든 저장 시점에 센터 크롭으로 정확히 맞춰집니다. Gemini와 gpt-image-2는 16:9를 네이티브로 생성하고, gpt-image-1 계열은 1536x1024(3:2)로 요청한 뒤 1536x864로 크롭됩니다.
⚠ 기본 모델은 gpt-image-2입니다. 구모델을 선택했다면 종료 일정에 주의하세요: gpt-image-1은 2026-10-23, gpt-image-1-mini/gpt-image-1.5는 2026-12-01 서비스 종료. 모델/provider를 바꾸면 캐시 키가 달라져 weft images 재실행 시 이미지가 재생성(재과금)됩니다.
반복 캐릭터: CHARACTER.png를 CONTI.md 옆(또는 generated_project 안)에 두고 shot 프롬프트에 @char를 쓰면, OpenAI(images.edit)/Gemini(이미지 입력)에 캐릭터 시트가 레퍼런스로 전달되고 마커는 "the recurring channel character exactly as shown in the reference sheet"로 치환됩니다. 다른 경로는 CHARACTER_SHEET=로 지정하세요. 시트가 없거나 미지원 provider(comfyui/stub)면 마커만 제거되고 경고가 한 번 출력됩니다. weft pick 화면의 재생성 패널에서도 provider/모델을 골라 shot별로 다시 생성할 수 있습니다.
comfyui는 로컬 ComfyUI 서버(COMFYUI_URL, 기본 http://127.0.0.1:8188)로 이미지를 생성합니다.
COMFYUI_WORKFLOW에는 ComfyUI에서 **Save (API Format)**으로 내보낸 워크플로 JSON 경로를 지정하고(weft가 실행되는 이 PC 기준 경로),
JSON 안의 긍정 프롬프트(CLIPTextEncode 등) text 값을 __WEFT_PROMPT__로 바꿔 두면 shot 프롬프트로 치환됩니다.
(선택: __WEFT_SEED__를 넣으면 후보마다 다른 시드로 치환 — 없으면 "seed" 키를 자동으로 바꿔 후보가 서로 다른 변주가 됩니다.)
워크플로는 16:9에 가까운 해상도(예: 1344×768, 1920×1088)로 출력하게 두면 저장 시 크롭 손실이 없습니다. @char 캐릭터 시트는 comfyui에서 지원하지 않습니다(마커만 제거됨 — 워크플로에 IP-Adapter 등을 직접 구성).
원격 GPU의 ComfyUI (SSH) — 다른 머신에서 도는 ComfyUI를 쓰려면 SSH 포트 포워딩으로 로컬 포트에 연결하는 게 가장 안전합니다(ComfyUI는 인증이 없습니다). ComfyUI가 원격에서 기본값(127.0.0.1:8188)으로 떠 있으면, weft를 돌리는 PC에서 터널만 열어 두고 COMFYUI_URL은 기본값 그대로 둡니다:
ssh -N -L 8188:localhost:8188 homegpu # 이 PC의 8188 → 원격 8188 (켜둔 채 사용)IMAGE_PROVIDER=comfyui
COMFYUI_URL=http://127.0.0.1:8188 # 터널 끝점 — SSH 별칭(homegpu)을 URL에 직접 쓰지 말 것
COMFYUI_WORKFLOW=/path/to/workflow_api.json(SSH 별칭 homegpu는 ssh 명령만 아는 이름이라 HTTP URL에는 못 씁니다. 워크플로 JSON은 원격 ComfyUI를 브라우저로 열어 만든 뒤 이 PC에 저장하세요.)
AI 에이전트 주의: API 키가 __로 시작하거나 placeholder처럼 보여도 문자열 모양만으로 무효라고 판단하지 마세요. 키 유효성은 실제 실행 결과로 판단합니다. TYPECAST_API_KEY/TYPECAST_VOICE가 비어 있거나 TTS_PROVIDER=stub일 때만 stub/placeholder 운용으로 보고, 그 외에는 weft tts 실행 결과(Typecast HTTP 응답, 생성 WAV, sidecar의 provider=typecast)로 확인하세요. secret 값은 로그나 답변에 출력하지 마세요.
다른 프로젝트 폴더 사용 — 그냥 그 폴더로 cd하세요:
cd that-folder
weft all이미지 후보 개수 지정:
weft images --n 3AI 어시스턴트로 대본을 Weft CONTI.md로 변환할 때는 script-to-conti 스킬을 사용하세요. Claude에서는 .claude/skills/script-to-conti/, Codex에서는 .agents/skills/script-to-conti/가 같은 내용을 제공합니다. AI agent의 기본 작업 방식은 weft all이 아니라 단계별 CLI 실행입니다. 정적인 은유/삽화는 image, 숫자 변화·도표·수식 전개는 remotion 또는 hyperframe, 기존 영상은 clip으로 고르게 하세요.
AI agent가 CLI로 weft를 제어할 때의 권장 순서: weft conti가 0건으로 통과하면 먼저 conti-qa 스킬로 품질 검토를 한 차례 돌리고 나서 weft tts/weft images(API 과금)로 진행하세요 — 과금 전에 콘티를 고치는 것이 가장 쌉니다. 나레이션 칸의 TTS 발음 표기는 script-to-conti가 변환 시점에 적용합니다.
콘티 이후 단계에도 전용 스킬이 있습니다 (weft whereisskill로 경로 확인):
conti-qa:weft conti통과 후 콘티 품질 검토 — 리듬·이미지 프롬프트·텍스트카드·사실/추측 lintvisual-qa:weft images/weft ffmpeg후 후보 PNG와 최종 MP4를 비전으로 검수, 픽 수정·재생성 제안animation-render:weft animate가 만든 SPEC.md를 받아 remotion/hyperframe 샷을clip.mp4로 렌더
이 스킬의 출력:
- 나레이션 비트 행
- 비주얼 샷 지시자:
▶,↓,▦,↺,⏸,❝,⤴ - 샷 프롬프트
- 모션 메모
- 자막
그다음 프로젝트 폴더 안에서 실행:
weft conti모든 생성 이미지는 다음을 받습니다:
샷별 프롬프트 + 공유 Style 접미사
프로젝트 폴더(CONTI.md 옆)에 STYLE.txt 파일을 두면 공유 스타일을 덮어쓸 수 있습니다. 파일이 없으면 처음 이미지를 생성할 때 기본 3b1b 스타일 문장이 STYLE.txt로 자동 생성됩니다:
STYLE.txt(프로젝트 폴더,CONTI.md옆)- 또는
generated_project/STYLE.txt
기본값은 weft/assets.py의 DEFAULT_STYLE과 같은 문장입니다. 그다음 프로젝트 폴더 안에서 이미지를 다시 생성:
weft images템플릿과 예시는 STYLE_GUIDE.md를 참고하세요.
conti를 다시 실행하면generated_project가 새로 만들어지고 픽이 초기화됩니다.- picker로 고른 뒤에는, 프로젝트를 의도적으로 다시 만들 게 아니라면
capcut만 바로 실행하세요. weft capcut은 **CapCut이 바로 여는 드래프트(프로젝트)**를 만들어 CapCut 목록에 등록합니다. 등록은 CapCut의 프로젝트 목록 파일(root_meta_info.json)을 고치는데, CapCut이 켜져 있으면 종료할 때 그 파일을 자기 메모리로 덮어써 새 드래프트가 사라집니다. 그래서 빌드는 CapCut을 종료한 상태에서 하세요. (켜진 채 실행하면 등록을 건너뛰고 파일만 만들어 둡니다 — CapCut을 종료한 뒤weft capcut을 다시 실행하면 목록에 등록됩니다.)
MIT © 2026 Minwoo Park. LICENSE 참고.
Weft is a dual-track workflow for long-form explainer videos. The input is a prose script you write yourself, on any topic — history, science, cultural analysis, thought experiments, philosophical comparisons, and so on (writing the script is outside Weft's scope).
It separates:
- narration beats: script, subtitles, TTS timing
- visual shots: generated images, text cards, reuse, montage, motion
This lets one visual cover multiple narration beats, or one narration beat use several visuals. The practical goal is to reduce one-image-per-sentence editing work while producing a finished MP4 via ffmpeg as the default output; CapCut drafts and FCPXML are optional handoffs when NLE editing is needed.
install.sh: installer (creates venv, installs theweftcommand, seeds.env)uninstall.sh: uninstaller (removes theweftcommand and venv; keeps.env)weft/: Python CLI and core pipeline.claude/skills/script-to-conti/: skill for turning a script into a Weft dual-trackCONTI.md.claude/skills/conti-qa/: conti quality-review skill (rhythm, prompt, card, fact/speculation lint).claude/skills/visual-qa/: vision review skill for generated image candidates and the final MP4.claude/skills/animation-render/: skill that renders remotion/hyperframe shots intoclip.mp4.agents/skills/: Codex mirrors of the same skillsweft/picker/: local image candidate pickerSTYLE_GUIDE.md: image style customization guideWORKFLOW.html: visual workflow overviewexample/CONTI.md,example/SCRIPT.md: sample input
Generated media (audio, images, CapCut drafts) is produced locally and is not committed.
Run this once inside the repo:
./install.shinstall.sh creates a venv, editable-installs the package (creating the weft command), symlinks it into ~/.local/bin, and seeds .env from .env.example. After that, weft works from any directory.
Then fill the repo's .env with your own keys:
TYPECAST_API_KEY,TYPECAST_VOICEfor TTSOPENAI_API_KEYfor image generation
Because the install is editable, weft finds this .env from any working directory. A per-project .env in the current folder also works.
Once ./install.sh and your .env keys are done, you don't have to memorize commands.
cd ~/my-video # a folder containing your script/document (.md, etc.)
claude # start Claude Code in that folderThen just say:
make a weft video from the script in this folder
Claude Code finds the script-to-conti skill via weft whereisskill, reads it, and drives the whole pipeline: it turns the script into a CONTI.md, validates it with weft conti, reviews it with conti-qa, then runs weft tts (narration) → weft images → weft ffmpeg to produce EXPORTS/weft_render.mp4, checking the conti and images with you along the way. (Skills are not installed globally — weft --help points the AI to weft whereisskill, which loads them on demand.)
Real output (narration, images) needs
OPENAI_API_KEY(images) andTYPECAST_API_KEY(TTS) in.env; without them it runs instubmode for a dry walkthrough. For a recurring character, custom style, or BGM, just tell it to useCHARACTER.png/STYLE.txt/BGM.jsonin the folder.
Prefer driving each step yourself? See Quick Start below.
Want the skills to load automatically in every Claude Code session (trade-off: they load even for non-weft work)? Link them once from the weft repo;
uninstall.shcleans them up.mkdir -p ~/.claude/skills && ln -sfn "$PWD"/.claude/skills/*/ ~/.claude/skills/
To cleanly undo the install, run inside the repo:
./uninstall.shIt removes the weft command (symlink), the venv, and build artifacts. Your .env (with keys) is kept.
If you already have your own prose script (SCRIPT.md, etc.), first ask the AI assistant to use the script-to-conti skill and convert it into a Weft CONTI.md. The skill writes dual-track visual directives such as ▶ new image, ↓ hold, ▦ montage, and ↺ reuse, so the result does not default to one image per sentence.
- Claude:
.claude/skills/script-to-conti/ - Codex:
.agents/skills/script-to-conti/
To print the skill file paths from a terminal:
weft whereisskillExample prompt:
Use the script-to-conti skill to convert this script into a Weft CONTI.md.
Find the SKILL.md path with `weft whereisskill` and read it first.
Run weft conti and iterate until validation_errors=0.
A project is a folder containing CONTI.md. cd into it and run subcommands that operate on the current directory (no path args needed):
cd my-video # folder containing CONTI.md
weft conti # ./CONTI.md -> ./generated_project/ (parse + validate + compile)
weft tts # ./generated_project (Typecast narration; API cost)
weft images # ./generated_project (OpenAI/Gemini images; API cost)
weft animate # prepare/check Remotion/HyperFrame animation shot clips
weft ffmpeg # ./generated_project -> EXPORTS/weft_render.mp4 (first review MP4)
weft pick # optional: manual image candidate picking
weft capcut # optional: build CapCut draft if the MP4 needs editing
weft fcpxml # optional: FCPXML handoffOne shot:
weft all # human quick run: conti -> tts -> images -> animate check -> ffmpeg
weft all --capcut # also build a CapCut draft
weft all --fcpxml # also export FCPXMLRun these inside the folder that contains CONTI.md:
weft conti # ./CONTI.md -> JSON tracks, picks, SRT, render plan
weft parse # print parsed CONTI.md as JSON only (writes nothing)
weft validate # print parse+validation results only (writes nothing)
weft tts # Typecast narration WAVs
weft images # OpenAI image candidates
weft pick # local browser picker
weft animate # prepare/check Remotion/HyperFrame animation shot clips
weft ffmpeg # ffmpeg MP4 renderer (burns in subtitles by default)
weft capcut # optional CapCut draft builder
weft fcpxml # optional FCPXML handoff for Final Cut/Premiere/Resolve
weft all # human quick MP4 render
weft all --capcut # MP4 + CapCut
weft all --fcpxml # MP4 + FCPXML
weft settings # create/show WEFT_SETTINGS.txt
weft whereisskill # print script-to-conti skill paths for AI assistantsAliases: weft dryrun equals weft conti, and weft render equals weft ffmpeg.
weft upload (optional): upload the finished MP4 to YouTube as private — install deps with ./install.sh youtube-upload, then see manual4youtubeupload.md for setup.
conti's CONTI source defaults to ./CONTI.md; the other project commands default their project dir to ./generated_project. Power users can still pass paths explicitly.
weft capcut and weft all --capcut accept --no-register to skip registering the draft in CapCut's list (the draft files are still written).
weft conti or weft all creates a default WEFT_SETTINGS.txt next to CONTI.md when it is missing. Like VASP INCAR, copy this one file into another project to reuse the same render/provider options. Explicit CLI flags override this file for one-off runs. The default quick output is an ffmpeg MP4; CapCut/FCPXML are extra handoff commands when needed.
Ready-to-copy examples live in setting_examples/:
youtube_4k_high.WEFT_SETTINGS.txtyoutube_high.WEFT_SETTINGS.txtstandard.WEFT_SETTINGS.txtlow.WEFT_SETTINGS.txt
Smaller test-render example:
EXPORT_FFMPEG=true
FFMPEG_ENCODER=libx264
FFMPEG_CRF=32
FFMPEG_PRESET=veryfast
FFMPEG_BITRATE=2MThen:
weft settingsalso creates or shows the current project settings file.
weft allweft ffmpeg renders EXPORTS/render_plan.json, picked images, TTS WAVs, and compiled subtitle events directly into EXPORTS/weft_render.mp4. Subtitles are burned in by default (--no-subtitles disables them), and --encoder auto tries macOS h264_videotoolbox first before falling back to libx264. Use --preset ultrafast for faster software-encoding checks, or adjust --crf for size/quality.
The default is no BGM. Prepare a licensed music file yourself (mp3/wav/m4a, e.g. from the YouTube Audio Library; non-narrative background music works best) and point WEFT_SETTINGS.txt at it — weft ffmpeg lays the BGM under the video and automatically lowers it while narration plays (sidechain ducking), letting it rise back during ⏸ pauses and gaps. No CapCut round-trip required.
BGM_FILE=music/bgm.mp3 # relative to CONTI.md or absolute (one track; loops if shorter)
#BGM_GAIN_DB=-16 # base BGM level (dB)
#BGM_DUCK_DB=-12 # extra attenuation while narration plays (dB)
#BGM_FADE_SECONDS=2.0 # fade in/out per track segment (seconds)For different songs per act, create BGM.json next to CONTI.md. It takes priority over BGM_FILE and is copied into generated_project by weft conti/weft all (like CARDS.json):
[
{"file": "music/opening.mp3", "from": "0:00", "to": "1:30", "gain_db": -16},
{"file": "music/ending.mp3", "from": "1:30", "to": ""}
]An empty to means "until the end of the video", and the last track fades out at the video end. To skip BGM for one run, use weft ffmpeg --no-bgm (or weft all --no-bgm). The weft capcut draft only places the BGM segments on a separate audio track (do ducking/precise fades inside CapCut yourself).
weft animate creates SHOTS/<shot>/animation/SPEC.md for source_kind=remotion and source_kind=hyperframe shots, then checks for the expected rendered output SHOTS/<shot>/rendered/clip.mp4. Once rendered, these MP4s enter weft ffmpeg, weft capcut, and weft fcpxml like normal clips.
weft fcpxml exports the same render_plan as an editable FCPXML timeline: images/clips/animation clips on a video lane, TTS on an audio lane, and subtitles on a title lane.
Providers are selectable in .env:
IMAGE_PROVIDER=openai # openai | gemini | comfyui | stub
TTS_PROVIDER=typecast # typecast | stub
OPENAI_IMAGE_MODEL=gpt-image-2 # default (native 16:9). gpt-image-1-mini is cheaper (retires 2026-12-01)
GEMINI_API_KEY= # for IMAGE_PROVIDER=gemini (Google AI Studio key)
GEMINI_IMAGE_MODEL=gemini-3.1-flash-image # default. Budget: gemini-2.5-flash-image / hero: gemini-3-pro-image
IMAGE_ASPECT=16:9 # 16:9 | 9:16 | 1:1 | 3:2stub creates local PNG/WAV assets without API keys for tests and offline dry runs.
IMAGE_ASPECT (default 16:9) is enforced exactly at save time with a center crop, whatever size a provider returns. Gemini and gpt-image-2 generate 16:9 natively; the gpt-image-1 family is requested at 1536x1024 (3:2) and cropped to 1536x864.
⚠ The default model is gpt-image-2. If you pick an older model, mind the shutdowns: gpt-image-1 retires 2026-10-23, gpt-image-1-mini/gpt-image-1.5 on 2026-12-01. Changing the model/provider changes cache keys, so the next weft images run regenerates (re-bills) existing shots.
Recurring character: put a CHARACTER.png next to CONTI.md (or inside generated_project) and write @char in a shot prompt — the sheet is sent as a reference image (OpenAI images.edit / Gemini image input) and the marker becomes "the recurring channel character exactly as shown in the reference sheet". Use CHARACTER_SHEET= for a custom path. Without a sheet or on providers without reference support (comfyui/stub), the marker is stripped with a single warning. The weft pick UI's regeneration panel also offers per-shot provider/model dropdowns.
comfyui generates images on a local ComfyUI server (COMFYUI_URL, default http://127.0.0.1:8188).
Point COMFYUI_WORKFLOW at a workflow JSON exported from ComfyUI with Save (API Format) (a path on the machine running weft),
and put __WEFT_PROMPT__ where the positive prompt text goes — Weft substitutes the shot prompt there (JSON-escape safe).
(Optional: __WEFT_SEED__ gets a fresh seed per candidate; without it, "seed" keys are randomized so the N candidates are real variations.)
Have the workflow output a near-16:9 resolution (e.g. 1344×768, 1920×1088) to avoid crop loss. @char character sheets are not supported on comfyui (the marker is stripped — wire IP-Adapter into the workflow yourself).
Remote ComfyUI over SSH — for ComfyUI on another machine, an SSH port-forward to a local port is the safe option (ComfyUI has no auth). If it runs on the remote default (127.0.0.1:8188), open a tunnel from the machine running weft and keep COMFYUI_URL at the default:
ssh -N -L 8188:localhost:8188 homegpu # this PC's 8188 → remote 8188 (leave running)IMAGE_PROVIDER=comfyui
COMFYUI_URL=http://127.0.0.1:8188 # the tunnel endpoint — do not put the SSH alias in the URL
COMFYUI_WORKFLOW=/path/to/workflow_api.json(The SSH alias homegpu is known only to ssh, not to HTTP. Build the workflow via the remote ComfyUI in a browser, then save the JSON onto this PC.)
AI agent note: do not decide whether an API key is real from its string shape. A Typecast key may start with __ and still be valid. Treat TTS as stub/placeholder only when TYPECAST_API_KEY or TYPECAST_VOICE is empty, or when TTS_PROVIDER=stub is set. Otherwise verify by running weft tts and checking the Typecast HTTP result, generated WAVs, or sidecar metadata with provider=typecast. Never print secret values in logs or responses.
Use another project folder — just cd into it:
cd that-folder
weft allSet image candidate count:
weft images --n 3Use the script-to-conti skill when you want an AI assistant to convert a script into a Weft CONTI.md. Claude reads .claude/skills/script-to-conti/; Codex reads .agents/skills/script-to-conti/. AI agents should normally run the CLI step by step instead of using weft all: choose image for static illustration/metaphor shots, remotion or hyperframe for charts/equations/process animation, and clip for existing video.
Recommended order when an AI agent drives weft via the CLI: once weft conti passes with zero violations, run the conti-qa skill once before weft tts/weft images (which bill API usage) — fixing the conti before billing is the cheapest point. TTS-friendly pronunciation in the narration column is applied by script-to-conti at conversion time.
Dedicated skills also cover the stages after the conti (weft whereisskill prints the paths):
conti-qa: quality review afterweft contipasses — rhythm, image prompts, text cards, fact/speculation lintvisual-qa: vision review of candidate PNGs and the final MP4 afterweft images/weft ffmpeg, with pick fixes and regeneration suggestionsanimation-render: takes the SPEC.md fromweft animateand renders remotion/hyperframe shots intoclip.mp4
The skill outputs:
- narration beat rows
- visual shot directives:
▶,↓,▦,↺,⏸,❝,⤴ - shot prompts
- motion notes
- subtitles
Then, from inside the project folder, run:
weft contiEvery generated image receives:
shot-specific prompt + shared Style suffix
Override the shared style by placing a STYLE.txt file in the project folder (next to CONTI.md). If the file is missing, the first image-generation run materializes the default 3b1b-style sentence into STYLE.txt:
STYLE.txt(in the project folder, next toCONTI.md)- or
generated_project/STYLE.txt
The generated default matches DEFAULT_STYLE in weft/assets.py. Then, from inside the project folder, regenerate images:
weft imagesSee STYLE_GUIDE.md for templates and examples.
- Re-running
contirebuildsgenerated_projectand resets picks. - After using the picker, run
capcutdirectly unless you intentionally want to regenerate the project. weft capcutbuilds a CapCut-openable draft (project) and registers it in CapCut's project list. Registration edits CapCut's project-list file (root_meta_info.json), and if CapCut is running it overwrites that file from memory on quit, so a freshly registered draft disappears. Build with CapCut closed. (If it's running, registration is skipped and only the files are written — close CapCut and runweft capcutagain to register it in the project list.)
MIT © 2026 Minwoo Park. See LICENSE.