Claude CodeでBlenderを動かしてWebに載せるには、動きをPythonスクリプトで組ませてBlenderを画面なしで実行し、glbで書き出したファイルをthree.jsのGLTFLoaderで読み込んでAnimationMixerで再生します。Blenderで決めた動きが、タイミングもイージングもそのままブラウザで再生されます。
ClaudeとBlenderの連携というと、MCPで3Dのシーンを作らせてみた、という話が目立ちます。Web制作で困るのはその先です。書き出したglbに動きが入っていない、向きが90度ずれる、圧縮したら読み込めない、再生が終わると止まったまま動かない。どれも、作ってからページに載せるまでの間で起こります。
この記事では、筆者が個人サイトORECTICのファーストビューで、Blenderで作った渾天儀の組み上がる動きをthree.jsで再生するまでに使った手順を紹介します。仕様は2026年10月20日に公式ドキュメントで確認しました。手元の環境はBlender 5.2.2 LTSとthree.js 0.170で、記事のサンプルコードはこの環境で実際に動かしています。
ClaudeからBlenderを動かす3つの方法
ClaudeからBlenderを動かす方法は、公式のBlenderコネクタ、コミュニティ製のMCP for Blender、Blenderを画面なしで起動してスクリプトを実行する方法の3つです。前の2つはMCPで、開いているBlenderをClaudeが会話しながら操作します。3つ目はMCPを使わず、Claude Codeが書いたPythonをBlenderのコマンドで実行します。
| 公式Blenderコネクタ(Blender Lab) | MCP for Blender(旧blender-mcp) | 画面なしスクリプト | |
|---|---|---|---|
| 作っているところ | Blenderの開発者(Blender Lab) | 個人開発者(Blender財団とは無関係) | 自分(Claude Codeが書く) |
| Blenderの要件 | 5.1以上 | 3.0以上 | 制限なし(使うAPIによる) |
| Claudeとのつなぎ方 | Claude Desktopのコネクタ/MCPクライアント | MCPクライアント(uvxで起動) | Claude CodeがBashで実行 |
| 操作のしかた | 開いているBlenderを会話で操作 | 開いているBlenderを会話で操作 | 毎回起動して、終わったら閉じる |
| 同じ結果を作り直せるか | 会話の記録次第 | 会話の記録次第 | スクリプトを再実行すれば同じになる |
| 向く用途 | 試作・シーンの把握・動きを探る | 試作・シーンの把握・動きを探る | 本番に載せる素材を作る |
公式のコネクタは、Anthropicが2026年4月28日にClaude for Creative Workで発表しました。発表には「The Blender developers have created an MCP connector, which is now officially available for Claude」とあります。中身はBlender Labが公開しているBlender MCPで、v1.0.0が2026年4月27日、v1.0.3が9月11日に出ています。
MCP for Blenderは、コネクタが出る前から使われてきたコミュニティ製のMCPサーバーです。READMEには「This is a third-party integration and not made by Blender」と書かれています。ライセンスはMITで、PyPIの最新版は2026年10月20日公開の2.2.1です。更新が多いので、使う前にREADMEで最新の設定方法を確認してください。
Claude CodeにMCPを追加するコマンド
Claude CodeからMCP for Blenderを使う場合は、Blender側にアドオンを入れて接続を開始してから、次のコマンドでサーバーを追加します。Claude Codeでは、起動コマンドを--の後ろに書くのが公式の書式です。
claude mcp add blender -- uvx mcp-for-blender公式のコネクタはClaude DesktopのCustomize → Connectorsから追加します。Anthropicのチュートリアルによると、コネクタはBlenderと同じマシンで動く必要があるためClaude Desktopが必要で、Claude Codeなど他のMCPクライアントからも使えます。
Web制作の本番は画面なしスクリプトで作る理由
ページに載せる素材は、画面なしスクリプトで作るのが確実です。MCPは「この輪をもう少し早く寄せて」と会話しながら探るのに向いています。ただ、決まった動きを色違い・サイズ違いで作り直す、書き出しの設定を毎回同じにする、という本番の作業には、スクリプトに残す方式が合っています。
- 作り直せる:シーンも動きもコードなので、配色やフレーム数の定数を変えて再実行すれば同じ構成で出し直せる
- 書き出し設定が固定される:上方向の変換・Draco圧縮・アニメーションの書き出し方をスクリプトに書いておけば、書き出すたびに設定が変わることがない
- 実行するコードを先に読める:Claude Codeが書いたスクリプトを確認してから実行できる。MCPはAIが書いたコードをその場でBlenderに渡す
- 失敗を検知できる:
--python-exit-codeを付けると、スクリプトのエラーをコマンドの終了コードで受け取れる
筆者は、動きの方向を決めるまでは静止画を何枚も描かせて見比べ、決まったら同じスクリプトでglbを書き出す、という流れにしています。公式のBlender MCPにも、画面なしで起動したBlenderでPythonを実行するツール(execute_blender_code_for_cli)が入っているので、MCPから同じ方式を呼ぶこともできます。
Claude Codeに作らせる手順
手順は、シーンをPythonで組む、主要なフレームだけ描いて確かめる、動きの案を比べて決める、glbで書き出す、three.jsで再生する、の5段階です。Claude Codeには最初に「何を・どのくらいの長さで・どこに載せるか」を渡します。
- シーンをPythonで組む:形・マテリアル・キーフレームをすべてスクリプトに書かせる。動きの数値(フレーム数・イージング)は定数にまとめさせる
- 主要なフレームだけ低解像度で描く:
blender -b -P scene.py -- --frames 1,40,90のように数枚だけ描き、1枚に並べて形と構図を確認する - 動きの案を2〜3案作って比べる:静止画では動きの良し悪しが分からないので、低解像度の動画で並べて見て決める
- glbで書き出す:決まったスクリプトに書き出しの処理を足し、本番用のファイルを作る
- three.jsで再生する:GLTFLoaderで読み込み、AnimationMixerで再生する。ページの表示と合わせて最終確認する
Claude Codeへの頼み方
筆者は次のような条件を最初に渡しています。ポイントは、書き出し先と、Blenderの外で付ける要素(文字・光・回り続ける動き)を先に分けておくことです。
Blender 5.2をスクリプトで動かして、Webのファーストビューに載せる3Dの動きを作って。
- シーンは scene.py にすべてコードで組む(手作業の操作はしない)
- 30fps・96フレームで、部品が外側から集まって組み上がる。行き過ぎて揺れる動きは付けない
- 実行は blender -b -P scene.py -- <引数>。--frames で静止画、--glb で3Dデータを書き出す
- JSで差し替える部品と回す部品には名前を付ける(Core、Ring1〜3)
- 文字・ナビ・光の効果はBlenderに入れない(HTMLとthree.js側で付ける)
- 書き出しは +Y上・Draco圧縮・カメラとライトは含めないサンプル:動く立方体をglbで書き出す
最小の例です。立方体を下から上げながら1回転させ、glbで書き出します。Blender 5.2.2で実行し、アニメーションが入ったglbが出力されることを確認しました。
import sys
import bpy
# 「--」より後ろの引数だけを受け取る
argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
out = argv[0] if argv else "logo.glb"
# 空のシーンから始める
bpy.ops.wm.read_factory_settings(use_empty=True)
scene = bpy.context.scene
scene.render.fps = 30
scene.frame_start, scene.frame_end = 1, 60
# 立方体を置き、下から上がりながら1回転させる
bpy.ops.mesh.primitive_cube_add(size=1)
cube = bpy.context.active_object
cube.name = "Logo"
cube.location = (0, 0, -2)
cube.rotation_euler = (0, 0, 0)
cube.keyframe_insert("location", frame=1)
cube.keyframe_insert("rotation_euler", frame=1)
cube.location = (0, 0, 0)
cube.rotation_euler = (0, 0, 6.2832)
cube.keyframe_insert("location", frame=60)
cube.keyframe_insert("rotation_euler", frame=60)
# glbで書き出す(+Y上・Draco圧縮・シーン全体の動きを焼き込む)
bpy.ops.export_scene.gltf(
filepath=out,
export_format="GLB",
export_yup=True,
export_animation_mode="SCENE",
export_force_sampling=True,
export_cameras=False,
export_lights=False,
export_draco_mesh_compression_enable=True,
)
print("exported:", out)実行は次のコマンドです。--より後ろはBlenderが読まずにスクリプトへ渡すので、出力先などの引数はそこに書きます。
blender -b -P scene.py -- logo.glbBlenderのコマンドライン引数のマニュアルによると、-b(--background)は画面なしで起動するオプションで、引数は書いた順に実行されます。-bを-Pより前に書くのはこのためです。
サンプル:three.jsで再生する
書き出したglbを読み込んで再生するコードです。three.jsはimport mapで読み込み、Draco圧縮したglbを読むためにDRACOLoaderを渡しています。three.js 0.170で、クリップが読み込まれて再生されることを確認しました。
import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(40, innerWidth / innerHeight, 0.1, 100);
camera.position.set(0, 1, 6);
scene.add(new THREE.HemisphereLight(0xffffff, 0x444444, 3));
// Draco圧縮したglbを読むにはDRACOLoaderを渡す(1つ作って使い回す)
const draco = new DRACOLoader().setDecoderPath(
"https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/libs/draco/"
);
const loader = new GLTFLoader().setDRACOLoader(draco);
const clock = new THREE.Clock();
let mixer;
const gltf = await loader.loadAsync("logo.glb");
scene.add(gltf.scene);
// Blenderで付けた動きはgltf.animationsにクリップとして入っている
mixer = new THREE.AnimationMixer(gltf.scene);
gltf.animations.forEach((clip) => {
const action = mixer.clipAction(clip);
action.setLoop(THREE.LoopOnce, 1);
action.clampWhenFinished = true; // 最後のフレームで止める
action.play();
});
renderer.setAnimationLoop(() => {
mixer?.update(clock.getDelta()); // 経過秒数で進める
renderer.render(scene, camera);
});AnimationMixerは、シーン内のオブジェクトのアニメーションを再生するプレーヤーで、毎フレームupdate()に経過秒数を渡して進めます。three.jsの最新版はr186(2026年9月24日)なので、新しく作る場合はバージョンの番号を差し替えてください。
glb書き出しでつまずく5つの点
Blenderの動きをglbで持ち出すときにつまずくのは、APIの変更、書き出されないアクション、上方向の違い、Draco圧縮、再生後の停止の5点です。どれもエラーが出ずに「動かない」「向きが違う」という形で現れるので、先に知っておくと原因を探す時間が減ります。
1. Blender 5.0でキーフレームの読み方が変わった
Blender 5.0で、アクションから直接Fカーブを取るaction.fcurvesが削除されました(5.0のリリースノート)。Blender 4.x向けの記事やAIが書くコードにはobj.animation_data.action.fcurvesがよく出てきますが、5.x では動きません。Fカーブは、アクションのスロットに対応するchannelbagから取ります。
import bpy
from bpy_extras import anim_utils
obj = bpy.data.objects["Logo"]
ad = obj.animation_data
# Blender 5.x:アクションのFカーブはスロットごとのchannelbagにある
bag = anim_utils.action_get_channelbag_for_slot(ad.action, ad.action_slot)
for fc in bag.fcurves:
print(fc.data_path, fc.array_index, round(fc.evaluate(30), 3))このコードで、サンプルの立方体の30フレーム目の値(高さ-1.025、回転3.062ラジアン)が読み出せることを確認しました。Claude Codeに頼むときは「Blender 5.2のAPIで」とバージョンを明記すると、古い書き方を避けやすくなります。
2. 動きが書き出されないアクションがある
BlenderのglTF 2.0マニュアルによると、既定のActionsモードでは、オブジェクトに付いているアクションか、NLAにstashしたアクションだけが書き出されます。マニュアルには「If you have multiple actions you want to export, make sure they are stashed!」とあります。サンプルのようにexport_animation_mode="SCENE"にすると、シーン全体の動きをフレームごとに焼き込んで1本のクリップにできます。
書き出せる動きの種類にも範囲があります。マニュアルでは、glTFのアニメーションはオブジェクトとボーンの位置・回転・拡大と、シェイプキーの値を変えるもの、と説明されています。マテリアルの色やライトの強さを動かしたい場合は、three.js側で付けるほうが確実です。
3. Blenderはz軸が上、glTFはy軸が上
Blenderはz軸が上の座標系で、glTFはglTF 2.0の仕様で「+Y as up」と決まっています。three.jsも既定の上方向はy軸です。書き出しのexport_yupは既定でオンなので、glbとthree.jsの間では向きは揃います。
ずれるのは、Blenderの座標の数値をJSに書き写すときです。Blenderの (x, y, z) は、three.jsでは (x, z, -y) になります。カメラの位置や回転の中心をBlenderから持ってくるときは、この入れ替えを忘れないようにしてください。
4. Draco圧縮したglbはDRACOLoaderがないと読めない
Draco圧縮は書き出しの既定ではオフで、export_draco_mesh_compression_enable=Trueで有効になります。圧縮したglbを読むには、three.jsのGLTFLoaderにsetDRACOLoader()でDRACOLoaderを渡す必要があります。渡さずに読むとエラーになります。
Dracoはファイルを小さくする代わりに、表示する端末側でデコードする時間がかかります。DRACOLoaderのドキュメントにも「at the cost of additional decoding time on the client device」と書かれています。モデルが小さい場合は、圧縮あり・なしの両方で読み込みの速さを測ってから決めてください。
5. 再生し終えたアクションは止まったままになる
LoopOnceで1回だけ再生したアクションは、最後まで行くと止まった状態になります。clampWhenFinishedを付けると最後のフレームで止まり、付けないと最初の姿勢に戻ります。もう一度再生したり、特定の時刻を表示したりする前にはaction.reset().play()で再生できる状態に戻します。
実例:orecticdesign.comのファーストビュー
筆者の個人サイトORECTICのファーストビューでは、真鍮の渾天儀が外側から集まって組み上がり、組み上がった後は輪が回り続けます。形と組み上がる動きはBlenderで作り、glbでthree.jsに渡しています(実物はorecticdesign.comで動いています)。Blenderは、筆者が作ったClaude Codeのスキルから画面なしで動かしました。


Blenderとthree.jsの役割分担
| 担当 | Blender(glbに入れる) | three.js・HTML(ブラウザ側で付ける) |
|---|---|---|
| 形 | 輪・パネル・台座・芯の形とマテリアル | 中心の芯を、地図を貼った球に差し替え |
| 動き | 外側から集まって組み上がる96フレーム(30fpsで3.2秒) | 組み上がった後に輪を回し続ける |
| 光と空間 | 試し描き用のライトとカメラ(glbには含めない) | 環境光・電灯の影・光のにじみ・霧・床と壁 |
| 文字 | なし | ナビのラベルはHTML。地球儀の回転に合わせて動かす |
Blenderで付けたオブジェクトの名前は、glbの中にそのまま残ります。three.js側ではCoreという名前の芯を探して地図を貼った球に差し替え、名前がRingで始まる輪を回しています。差し替えや操作をしたい部品には、Blenderの段階で名前を付けておくと、ブラウザ側のコードが短くなります。
作ってみて分かったこと
- 動きは動く状態で見て決める:組み上がりは、行き過ぎて揺れる動きを付けず、ぴたりと止まる形にした。動きの良し悪しは静止画では判断できないので、低解像度の動画で見てから決めている
- ブラウザ側で付ける要素を先に決める:組み上がった後の回転をBlenderに入れると、ループの継ぎ目とファイルの重さが問題になりやすい。回り続ける動きはJSで1行足すほうが軽い
- ファイルは小さく収まる:Draco圧縮したglbは約300KBだった。部品が多くても、動きを焼き込んだ3.2秒ならこの大きさで収まる
- 動きを減らす設定にも対応する:OSで動きを減らす設定をしている人には、組み上がる動きを飛ばして完成形から表示している
書き出し先の選び方:3Dデータ・動画・CSS・SVG
Blenderで作った動きは、glb以外にも動画・CSS・SVGの線として書き出せます。何を動かすかで選びます。筆者は次の表で決めています。
| 動かすもの | 書き出し先 | 理由 |
|---|---|---|
| マウスやスクロールに反応させたい立体 | glb+three.js | カメラや部品をブラウザ側で動かせる |
| 質感・光・モーションブラーが主役の素材(商品・ロゴ・背景ループ) | 動画(mp4・webm) | レンダリングした見た目をそのまま出せる |
| 文字・ラベル・ボタンなど、情報としての要素 | HTML/CSS | 文字を読める・選べる状態のまま動かせる |
| 描かれる・伸びる線 | SVGの線 | 線の太さを保ったまま拡大縮小できる |
CSSで済む動きはどこまでか
位置・回転・拡大・透明度の変化だけなら、BlenderのFカーブの値をCSSのキーフレームに移せます。前の節のchannelbagからFカーブを読み、各フレームの値を書き出す流れです。ただ、文字やボタンを少し動かすだけなら、Blenderを通さずにClaudeにCSSを直接書かせるほうが早い場面も多くあります。その進め方はCSSアニメーションはAIに「コードを渡して」作るで、すぐ使える動きの例はCSSアニメーションのサンプル集で紹介しています。
透過動画はSafari向けに別の形式が要る
背景を透過させた動画を使う場合、webm(VP9)はSafariで透過が効きません。MDNのコーデックガイドにも「Safari does not support alpha transparency in this format」とあります。SafariはHEVCの透過動画に対応していますが、Blenderの動画書き出しではH.265/HEVCに透過を付けられないため、別のツールで変換する工程が必要です。透過させたい素材は、glbで持ち出せないかを先に検討する価値があります。
MCPを使う前に確認すること
どちらのMCPも、Claudeが書いたPythonを確認なしでBlenderの中で実行します。Blenderの中のPythonはファイルの読み書きもできるので、使う前に次の点を確認してください。
- 公式のBlender MCPのページには「The MCP server will execute LLM generated code in Blender without any guards in place」とあり、機密情報のない環境(仮想マシンなど)での利用が勧められている
- MCP for BlenderのREADMEは、Blenderのコードを実行するツールについて「ALWAYS save your work before using it」と注意している。作業中のファイルは先に保存しておく
- MCP for Blenderのアドオンが開く接続には認証も暗号化もないとREADMEに書かれている。同じネットワークの他の端末から届かない環境で使う
- MCP for Blenderは既定で匿名の利用状況を送る。止める場合はREADMEにある環境変数で無効にする
画面なしスクリプトの方式でも、実行するのはClaude Codeが書いたコードです。違いは、実行の前にファイルとして読めることです。Claude CodeのMCPの設定や使い分けはClaude CodeのMCP連携ガイド一覧に、同じ「公式コネクタとスクリプト」の比較をPhotoshopで試した例はClaudeでPhotoshopを操作する2つの方法にまとめています。
よくある質問
Q. ClaudeからBlenderを操作する公式の方法はありますか?
あります。Blenderの開発者によるBlender LabがBlender MCPを公開し、Anthropicが2026年4月28日にClaude向けの公式コネクタとして発表しました。Claude DesktopのCustomize → Connectorsから追加でき、Blender 5.1以上が必要です。
Q. Blender MCPとMCP for Blenderは何が違いますか?
Blender MCPはBlenderの開発者が作った公式のMCPサーバーで、MCP for Blender(旧blender-mcp)は個人開発者が作ったコミュニティ製のMCPサーバーです。どちらもClaudeから開いているBlenderを操作でき、AIが書いたPythonをBlenderの中で実行する点は同じです。
Q. MCPを使わずにClaude CodeからBlenderを動かせますか?
動かせます。Claude CodeにPythonスクリプトを書かせ、blender -b -P script.py で画面なしのBlenderに実行させます。シーンも動きもスクリプトに残るので、同じ素材を何度でも作り直せます。
Q. Blenderのアニメーションがglbに入らないのはなぜですか?
既定のActionsモードでは、オブジェクトに付いているアクションかNLAにstashしたアクションしか書き出されないためです。複数のアクションはstashしておくか、export_animation_mode=”SCENE” でシーン全体の動きを焼き込んで書き出します。
Q. three.jsで読み込んだglbの向きがずれるのはなぜですか?
Blenderはz軸が上で、glTFとthree.jsはy軸が上だからです。書き出しの export_yup が有効ならglbの向きは揃うので、ずれる場合はBlenderの座標の数値をJSに書き写した箇所を (x, z, -y) に直してください。
Q. Draco圧縮したglbが読み込めないときはどうすればいいですか?
GLTFLoaderにsetDRACOLoader()でDRACOLoaderを渡し、デコーダーの置き場所をsetDecoderPath()で指定してください。Draco圧縮したglbは、DRACOLoaderがないと読み込めません。
