Communitygithub.com

lowpoly-shorts

30~60초 세로형 로우폴리 PS1 스타일 3D 단편 영상(블록형 CC0 캐릭터, 평면 픽셀 얼굴, 깔끔한 디더 룩, 단어 강조 자막, 동기화된 SFX, AI 음성)을 Blender로 코드만으로 $0 렌더 비용에 제작합니다.

lowpoly-shorts란 무엇인가요?

이 스킬은 Claude가 사용자의 로컬 머신에서 Blender를 실행하여 PS1 스타일의 3D 단편 영상을 완전히 코드로 제작하는 전문 도구입니다. 사용자가 '로우폴리 단편', 'PS1 스타일 영상', '만약...' 같은 3D 단편을 요청할 때 활성화되며, 비디오 생성기가 아닌 실제 Blender 렌더링을 기반으로 합니다. 지원 플랫폼은 Claude Code, Cursor, Codex 등이며, Blender 4.2+에서 검증되었습니다. `examples/lift-rocket/` 예제를 템플릿으로 삼아 스크립트 작성부터 음성, 자막, SFX, 포스트 프로세싱까지 전 과정을 자동화합니다. 24fps, 360x640 EEVEE 렌더링에 PS1 스타일 디더와 워드-하이라이트 캡션을 적용하며, 모든 자산은 CC0 라이선스로 비용이 들지 않습니다. 미리보기 루프를 통해 사용자가 타임라인에 노트를 남기면 Claude가 수정 후 변경된 샷만 재렌더링하여 효율성을 극대화합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mr-render/lowpoly-shorts/tree/HEAD

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

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

문서

로우폴리 PS1 단편 영상

모든 것은 코드로 이루어집니다: Claude가 단편당 하나의 Blender 스크립트를 작성하여 사용자의 머신에서 렌더링하고, 프레임을 확인한 후 수정한 다음, 사운드와 자막을 구축합니다. 비디오 생성기는 사용하지 않습니다.

examples/lift-rocket/ ("만약 엘리베이터가 로켓만큼 빠르다면?", 34초)에서 검증되었습니다. 새 단편을 작성하기 전에 해당 예제를 읽어보세요: 그것이 템플릿입니다.

요구 사항 (먼저 확인하고 누락된 것을 설치하세요)

  • Blender 4.2+ (5.3에서 테스트 완료). 찾기: PATH에 blender, 또는 C:\Program Files\Blender Foundation\<ver>\blender.exe / /Applications/Blender.app/Contents/MacOS/Blender.
  • Python 3.10+ with numpy pillow soundfile faster-whisper; PATH에 ffmpeg.
  • 캐릭터: Quaternius "Ultimate Modular Men" (CC0, 무료, quaternius.com). assets/quaternius-modular-men/에 압축 풀기 또는 LOWPOLY_PACK을 Individual Characters/Blends 폴더로 설정.
  • TTS 음성 (ElevenLabs 또는 사용자가 보유한 모든 도구). 선택 사항: 사운드를 확인할 earshot MCP.

파이프라인 (단편당 하나의 폴더, examples/lift-rocket/을 시작 템플릿으로 복사)

#단계파일 / 명령어완료 조건
1스크립트script.md후크 질문 + 결과의 연쇄(각각 더 나쁘고 재미있음) + 실제 숫자 + 건조 펀치라인. 3040초 기준 60110 단어. 모든 숫자는 출처 확인 후 Facts 목록에 작성.
2음성vo/takeA.mp32테이크 중 깨끗한 단어 타이밍이 있는 것을 선택. 활기찬 크리에이터 목소리(차분함 = "지루함" 피드백).
3단어 타이밍python ../../scripts/words.py vo/takeA.mp3takeA_words.json에 길이가 0인 단어 없음.
4샷 목록script.md의 표VO 구문당 하나의 샷, 1~3초마다 새로운 그림, 각 샷은 단어 시간에 연결.
5씬build.py (Blender)blender -b -P build.py -- frames --still 30,120,...으로 스틸 렌더링; 전체 렌더 전에 모든 스틸 확인.
6미리보기 + 노트python ../../scripts/preview.py . render 후 serve사용자가 열린 노트 없음 (미리보기 루프 참조).
7렌더blender -b -P build.py -- frames360x640 EEVEE PNG, f_0001.png...
8사운드python build_mix.pySFX를 그림 프레임에 배치, VO 위에, 로파이 배경음 아래, 덕킹. mix_raw.wav + cues.json 생성.
9포스트python post.pyPS1 디더, 효과, 단어 강조 자막, 통계 콜아웃 -> 1080x1920 out/ 폴더.
10먹싱아래 참조short.mp4, 측정 및 동기화 확인.

모든 곳의 프레임 규칙: 24fps, 프레임 1 = t 0, F = lambda t: int(round(t * 24)) + 1.

먹싱:

ffmpeg -y -framerate 24 -i out/f_%04d.png -i mix_raw.wav -c:v libx264 -crf 16 -pix_fmt yuv420p \
  -af "loudnorm=I=-15:TP=-1.5:LRA=11,aresample=48000" -c:a aac -b:a 192k -shortest short.mp4

그림을 재절단하지 않고 나중에 음성 교체: python ../../scripts/words.py vo/takeB.mp3 후 python ../../scripts/align.py vo/takeA_words.json vo/takeB.mp3 --end 34 (--end = VO 배경음이 멈추는 지점; 출력은 end + 2초 길이. 없으면: 마지막 단어 + 1.5초, 그림보다 짧은 파일 생성) -> takeB_aligned.wav + takeB_aligned_words.json. build_mix.py (VO 환경 변수)와 post.py가 이를 가리키도록 설정.

미리보기 루프 (전체 렌더 전)

브라우저에서 빠른 저해상도 미리보기, 사용자가 타임라인에 노트를 남기면 Claude가 수정 후 내용이 변경된 샷만 재렌더링. 샷 = build.py의 카메라 마커.

수행명령어 (단편 폴더에서)
미리보기 렌더python ../../scripts/preview.py . render (첫 실행: 모든 샷; 이후: 변경된 샷만)
노트 페이지 열기python ../../scripts/preview.py . serve -> http://127.0.0.1:8765
노트 읽기python ../../scripts/preview.py . notes (샷별로 그룹화, 프레임 번호 포함)
수정 후build.py 편집, render 재실행, python ../../scripts/preview.py . done 3 5 --reply "변경 사항"
샷 강제 렌더render --shots c_press,c_slam 또는 render --all
  • build.py는 --blend-only를 허용해야 함 (씬 빌드 후 저장, 렌더하지 않음). 예제 참조.
  • 변경 감지: 모든 미리보기 프레임은 지문(활성 카메라, 모든 보이는 오브젝트의 변환, 아마추어 포즈, 얼굴 교체, 재질, 조명, 메시 데이터)을 가집니다. 샷은 프레임 중 하나가 변경된 경우에만 재렌더링됩니다. 변경되지 않은 샷은 이전 프레임을 유지합니다.
  • preview.json의 설정 (선택 사항): scale 50 (%), step 2 (매 2번째 프레임), samples 1, audio (기본 mix_raw.wav, 또는 VO), final = 전체 파이프라인 명령어. 페이지의 "승인 및 최종 렌더" 버튼이 이를 실행합니다; notes는 사용자가 클릭하면 APPROVED를 출력합니다.
  • 노트를 하나씩 수정하고 각각에 답변한 후 재렌더링하고 사용자에게 새로고침할 필요가 없다고 알림: 페이지가 자동으로 비디오를 다시 로드합니다. 동일한 종류의 반복 노트는 이 파일에 규칙이 됩니다.
  • lift-rocket 기준 측정 (RTX 3070 Ti 노트북, 820프레임): 첫 미리보기 76초, 샷 하나 변경 13초, 변경 없음 12초. 대부분의 프레임 렌더 시간은 고정 오버헤드이므로 해상도 낮추는 것보다 프레임 수를 줄이는 것이 더 효과적입니다.

Kit API (scripts/lowpoly_kit.py, Blender 내부에서 임포트)

  • load_character(scn, "Suit") -> (armature, meshes, actions). 캐릭터: Adventurer, Beach, Casual_2, Casual_Hoodie, Farmer, King, Punk, Spacesuit, Suit, Swat, Worker.
  • 액션 (제자리, 24개): Death, HitRecieve, HitRecieve_2, Idle, Idle_Neutral, Interact, Kick_Left/Right, Punch_Left/Right, Roll, Run, Run_Back/Left/Right, Walk, Wave, Gun_Shoot, Idle_Gun*, Idle_Sword, Sword_Slash, Run_Shoot.
  • add_faces(scn, arm, head, tag, kinds, spec, drop) (아마추어 이동 전에 호출). 종류: neutral, blink, side, shock, grimace, squint, dazed, xeyes. drop은 팩의 3D 눈/눈썹을 삭제합니다.
  • show_faces(faces, [(frame, kind), ...]): 하드 컷, 각 얼굴은 다음까지 유지.
  • nla(arm, [(action, start, end, blend[, influence]), ...]): 이후 항목이 더 높은 트랙에 배치.
  • drive_root(arm, [(frame, x, y, yaw, ease), ...], last): yaw 0은 -Y 방향 (기본 카메라).
  • new_cam, aim, yaw_to, ps1_render_settings(scn, outdir).
  • 세트: scripts/set_lift_lobby.py (BUILD_ONLY=True로 실행하면 box, uv_world, mat 반환). 새 세트는 동일한 패턴을 따름: 픽셀 텍스처가 있는 상자 (interpolation = "Closest").

룩 규칙

  • 렌더 360x640, filter_size 0, AgX Punchy, 플랫 쉐이딩; 포스트: 15비트 컬러 + Bayer 디더, x3 nearest.
  • 얼굴은 평평한 32x28 픽셀 데칼로 하드 컷으로 교체; 얼굴을 부드럽게 애니메이션하지 마십시오.
  • 힘을 받으면 아마추어 스케일 키프레임으로 찌그러짐 (z축 감소, xy축 증가). 코미디 비트: 빠르게 진입 (2~3프레임), 유지.
  • 자막: 1~3단어, 두꺼운 산세리프, 흰색에 검은색 테두리, 현재 단어는 노란색, 하단 1/3 (y 1300 of 1920).
  • 통계 콜아웃: 빨간색 둥근 상자, 상단 1/3, 4프레임에 걸쳐 팝인, 실제 숫자당 하나.

사운드 규칙

  • 모든 SFX는 피크가 그림 프레임에 오도록 배치 (at(name, frame, db, peak=...)).
  • 음성이 반드시 이겨야 함: VO는 0 dBFS로 정규화, SFX 버스 -11 dB, 음악 -7 dB, 음성이 말하는 동안 사이드체인 덕킹 (SFX -5 dB, 음악 -9 dB). lift 단편 v1에서는 SFX가 -3, 음악이 0이어서 "음성이 안 들려요" 피드백 발생.
  • 큰 멈춤 비트에서 음악을 완전히 자르고, 이후 다시 가져옴. 침묵이 개그를 판매합니다.
  • 마스터: loudnorm -15 LUFS, 트루 피크 -1.5 dBTP.
  • 확인: earshot timeline을 mp4와 cues.json에 대해 실행 (목표: 모든 큐가 100ms 이내), measure로 LUFS 확인.

이미 발생한 버그 (반복 금지)

  • 팩 메시는 렌더 숨김 상태로 제공됨: hide_render = False (kit에서 처리).
  • 문 메시는 이미 닫힌 위치에 있음: 오프셋만 애니메이션, 그렇지 않으면 0.7m 간격으로 닫힘.
  • 약 2.75m보다 낮은 천장은 엘리베이터 크기 차량 내부에서 카메라가 벽 디스플레이를 가림.
  • 아직 보여져서는 안 되는 캐릭터: 자신의 샷까지 location.z = -50 키프레임.
  • NLA 원샷에서 홀드로 전환: 클립의 blend_out = 0 설정, 그렇지 않으면 포즈가 한 프레임 동안 튐.
  • 역방향 샷이 검게 나옴 (조명 없는 천장): 전면 조명과 약간의 천장 방출 추가. 역방향 앵글은 일찍 렌더.
  • faster-whisper가 mp3에서 PyAV 불일치로 깨질 수 있음: words.py는 먼저 ffmpeg로 디코딩.
  • -0.04초에서 시작하는 구문은 정렬에서 빈 조각 생성: max(0.0, ...)으로 클램프 (처리 완료).

비용 (lift 단편, RTX 3070 Ti 노트북)

렌더 820프레임 92초, 포스트 17초, $0. 캐릭터, SFX, 음악: $0 (CC0 + 코드로 합성). 음성: ElevenLabs 테이크당 약 $0.10, 단편당 2테이크.

전달 전 확인사항

  • 최종 프레임의 컨택트 시트를 확인 (약 2초 간격), 스틸만 확인하지 말 것.
  • 음량 측정, 동기화 확인, 자막과 VO 텍스트 대조 (철자 수정은 post.py FIX에서 처리).
  • 무엇을 측정했는지, 무엇을 사람이 듣지 않았는지 사용자에게 알릴 것.

관련 스킬