Communitygithub.com

lowpoly-shorts

30~60秒の縦型ローポリPS1スタイル3Dショート動画(ブロック状のCC0キャラクター、フラットなピクセルフェイス、ザラついたディザールック、ワードハイライト付きキャプション、同期された効果音、AI音声)を、Blenderでコードだけで、レンダリング費用0ドルで制作します。

lowpoly-shorts とは?

このスキルは、Claude Codeまたは類似のAIエージェントが、ユーザーのリクエストに応じて「ローポリPS1スタイル」の短編3Dアニメーション動画を完全にコードベースで生成するためのものです。ユーザーが「ローポリショート」「PS1スタイルの動画」「もしも…」といった3Dショート動画を依頼した場合や、このスキルを明示的に指定した場合に使用します。 主な特徴と利点は以下の通りです。 * **完全コードベース**: 動画生成AIは使わず、ClaudeがBlenderスクリプト(Python)を1本書き、ユーザーのマシン上でレンダリングします。 * **低コスト**: レンダリング費用は0ドル。キャラクターや効果音、音楽はCC0ライセンスのものを使用するか、コードで合成します。音声のみElevenLabsなどのTTSサービスを使用しますが、1ショートあたり約0.10ドルと低コストです。 * **反復的なプレビューループ**: プレビュー機能により、ブラウザ上で素早く低解像度のプレビューを確認し、タイムライン上にノートを追加できます。Claudeはそのノートに基づいて修正し、変更があったショットのみを再レンダリングするため、フィードバックサイクルが高速です。 * **PS1スタイルに特化**: 360x640のレンダリング解像度、フラットシェーディング、ポスト処理での15ビットカラー+ベイヤーディザ、x3ニアレスト補間など、PS1時代のビジュアルを再現するための明確なルールがあります。 * **一貫したパイプライン**: スクリプト執筆、音声収録、ワードタイミング、ショットリスト、シーン構築、プレビュー、レンダリング、サウンドミックス、ポストプロダクション、動画出力という明確な10ステップのパイプラインに従います。 * **テンプレートの存在**: `examples/lift-rocket/` がテンプレートとして機能し、新しいショート動画を作成する際の出発点となります。 このスキルは、PS1スタイルの美学に基づいたユニークでコスト効率の高い3Dアニメーション制作を、AIエージェントが自律的に行えるように設計されています。開発者やAIエージェントユーザーは、このスキルを用いて「もしエレベーターがロケットのように速かったら?」といったアイデアを、最小限の手間とコストで短い動画に変換できます。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mr-render/lowpoly-shorts/tree/HEAD

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

ローポリPS1ショート動画

全てはコードで実現:Claudeがショート動画ごとに1つのBlenderスクリプトを作成し、ユーザーのマシン上でレンダリング、フレームを確認して修正し、音声とキャプションを構築します。動画生成AIは使用しません。

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以上、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。

パイプライン(ショート動画ごとに1つのフォルダ、examples/lift-rocket/をコピーして開始)

#ステップファイル/コマンド完了条件
1脚本script.mdフックとなる質問 + 結果の連鎖(それぞれが前より悪く、より面白い) + 実際の数字 + ドライなオチ。30~40秒で60~110ワード。すべての数字は情報源で確認し、Factsリストに記載。
2音声vo/takeA.mp32テイク録音し、ワードタイミングがきれいな方を選択。落ち着いた声ではなく、エネルギッシュなクリエイターの声(落ち着いた声は「退屈」とフィードバックされたため)。
3ワードタイミングpython ../../scripts/words.py vo/takeA.mp3takeA_words.jsonに長さ0のワードがない。
4ショットリストscript.md内のテーブルナレーションのフレーズごとに1ショット、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.py効果音をピクチャーフレームに配置、上にナレーション、下にローファイBGM、ダッキング。mix_raw.wav + cues.jsonを出力。
9ポストpython post.pyPS1ディザ、エフェクト、ワードハイライトキャプション、統計数値の表示 -> 1080x1920でout/に出力。
10合成以下を参照short.mp4、その後測定と同期確認。

フレームルール(全般):24 fps、フレーム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 = ナレーションBGMが止まる場所、出力は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秒、1ショット変更13秒、変更なし12秒。フレームのレンダリング時間のほとんどは固定オーバーヘッドであるため、解像度を下げるよりもレンダリングするフレーム数を減らす方が効果的です。

キット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):アーマチュアを移動させる前に実行。kinds: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ビットカラー+ベイヤーディザ、x3ニアレスト補間。
  • フェイスは32x28ピクセルのフラットなデカールで、ハードカットで切り替えます。フェイスをスムーズにアニメーションさせないでください。
  • 力が加わったときの押しつぶし:アーマチュアのスケールをキー設定(zを縮小、xyを拡大)。コメディのビート:高速イン(2〜3フレーム)、ホールド。
  • キャプション:1〜3ワード、太めのサンセリフ、白色に黒のストローク、現在のワードは黄色、下3分の1(1920のy 1300)。
  • 統計数値の表示:赤い角丸ボックス、上3分の1、4フレームかけてポップイン、実在の数字ごとに1つ。

サウンドルール

  • すべての効果音は、そのピークがピクチャーフレームに重なるように配置します(at(name, frame, db, peak=...))。
  • 音声が最も重要:VOは0 dBFSにノーマライズ、効果音バスは-11 dB、音楽は-7 dB、さらに音声が話している間のサイドチェインダッキング(効果音-5 dB、音楽-9 dB)。リフトショートのv1では効果音が-3、音楽が0だったため「ナレーションが聞こえない」というフィードバックがありました。
  • 音楽は大きなストップビートで完全にカットし、その後戻します。無音がギャグを引き立てます。
  • マスター:loudnorm -15 LUFS、トゥルーピーク -1.5 dBTP。
  • 確認:earshotのtimelineをmp4とcues.jsonで(目標:すべてのキューが100ミリ秒以内)、measureでLUFSを確認。

すでに発生したバグ(繰り返さないこと)

  • パックメッシュはレンダリング非表示で出荷される:hide_render = False(キットが行う)。
  • ドアメッシュはすでに閉じた位置にある:オフセットのみをアニメーションさせる。そうしないと、0.7mの隙間ができて閉じる。
  • 天井が約2.75mより低いと、エレベーターサイズの車内のカメラから壁のディスプレイが見えなくなる。
  • まだ見せてはいけないキャラクター:彼のショットまでlocation.z = -50をキー設定する。
  • NLAのワンショットからホールドへの移行:クリップのblend_out = 0を設定する。そうしないと、1フレームだけポーズが飛ぶ。
  • 逆ショットは真っ黒になる(照明のない天井):フロントライトと天井に少しのエミッションを追加する。逆アングルは早めにレンダリングする。
  • mp3でのfaster-whisperはPyAVの不一致で壊れる可能性がある:words.pyは最初にffmpegでデコードする。
  • -0.04秒から始まるフレーズはアラインメントで空のスライスを生成する:max(0.0, ...)でクランプする(対応済み)。

コスト(リフトショート、RTX 3070 Tiラップトップ)

レンダリング820フレーム92秒、ポスト17秒、0ドル。キャラクター、効果音、音楽:0ドル(CC0+コードで合成)。音声:ElevenLabsで1テイクあたり約0.10ドル、ショート動画あたり2テイク。

引き渡す前に

  • スチルだけでなく、最終フレームのコンタクトシート(約2秒ごと)を確認する。
  • ラウドネスを測定し、同期を確認し、キャプションがナレーションテキストと一致しているか確認する(スペル修正はpost.pyのFIXで行う)。
  • 何を測定したか、何を人間が聴いていないかをユーザーに伝える。

関連スキル