mcpField
T
threejs-scene-setup

threejs-scene-setup

github.com/gamedev-skills開発5.4k6.2k 回インストール今日更新
リポジトリ

threejs-scene-setup について

three.jsアプリの基盤を構築するためのスキルです。シーンの初期設定や描画の問題を調べる開発者向けに、モジュール読み込みからOrbitControlsまでを扱います。

主な機能

  1. 01ESモジュール読み込みの設定
  2. 02シーン・カメラ・レンダラーの作成
  3. 03アニメーションループの設定
  4. 04キャンバスサイズ変更への対応
  5. 05OrbitControlsの追加

活用シーン

  1. 01three.jsシーンの初期構築
  2. 02空白または黒いキャンバスの修正
  3. 03ウィンドウ変更に応じた表示調整
  4. 04開発中のオービット操作追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill threejs-scene-setup

インストール後、Claude Code で/threejs-scene-setupを入力して読み込まれたか確認します。

同梱ファイルreferences/scene-graph.md

詳細

three.js シーンのセットアップ

three.js アプリの基盤を構築します。モジュールの読み込み、シーン/カメラ/レンダラーの組み合わせ、レンダーループ、レスポンシブなリサイズ、カメラコントロールを設定します。パターンは r186 を対象としています。既存のプロジェクトを変更する前に、インストール済みの three のバージョンを確認してください。例やアドオンはリリースごとに移動します。

使用する場面

  • three.js シーンの初期構築、真っ白/黒いキャンバスの修正、キャンバスのレスポンシブ化、アニメーションループの設定、OrbitControls の追加に使用します。
  • package.json が three に依存しており、コードで import * as THREE from 'three' を使用している場合に使用します。

使用しない場面: .gltf/.glb モデルの読み込みやスキンアニメーション → threejs-gltf-loading。マテリアル、ライト、シャドウ、環境マップ → threejs-materials-lighting。2D レンダリング → pixijs-rendering。

基本的なワークフロー

  1. インポートマップを使って three.js を ES モジュールとして読み込みます。 r147 以降、裸の指定子 'three' と 'three/addons/' はマッピングする必要があります(HTML 内、またはバンドラーで設定します)。アドオン(コントロール、ローダー)は three/addons/... の下にあります。
  2. 3要素を作成します。 グラフのルートとなる Scene、原点から後方に配置する PerspectiveCamera(fov, aspect, near, far)、そして domElement を DOM に配置する WebGLRenderer です。サイズと pixelRatio を設定します。
  3. メッシュを追加します。 new Mesh(geometry, material) を作成して scene.add(mesh) を呼び出します。ライトを使うマテリアルにはライトも必要です(threejs-materials-lighting を参照)。
  4. renderer.setAnimationLoop(fn) でレンダーループを動かします。 手動で実装する requestAnimationFrame に代わる、最新の WebXR/WebGPU に安全に対応した方法です。経過時間には Timer を使用します(Clock は r183 以降非推奨です)。
  5. リサイズに対応し、カメラのアスペクト比とレンダラーをキャンバスに合わせます。 camera.aspect を更新し、updateProjectionMatrix() と renderer.setSize(...) を呼び出します。
  6. 開発中の回転、パン、ズームには OrbitControls を追加します。 成功したと判断する前に、実際に何かが描画されること(ライトの当たった立方体や、反応するコントロール)を確認してください。

パターン

1. HTML のインポートマップ+モジュールエントリ(バンドラーなし)
<canvas id="c"></canvas>
<script type="importmap">
{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
    "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/"
  }
}
</script>
<script type="module" src="./main.js"></script>

バンドラー(Vite/webpack)を使う場合はインポートマップを省略し、npm i three を実行するだけで構いません。同じ import 文で解決されます。

2. シーン+カメラ+レンダラー
// main.js
import * as THREE from 'three';

const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // cap for perf
renderer.setSize(window.innerWidth, window.innerHeight);

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x101018);

const camera = new THREE.PerspectiveCamera(
  60,                                   // vertical field of view (degrees)
  window.innerWidth / window.innerHeight, // aspect
  0.1,                                  // near
  100                                   // far
);
camera.position.set(3, 2, 5);
camera.lookAt(0, 0, 0);

const cube = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshNormalMaterial()        // unlit; shows orientation without a light
);
scene.add(cube);
3. レンダーループ(setAnimationLoop+Timer)
const timer = new THREE.Timer();        // replaces the deprecated THREE.Clock (r183+)
timer.connect(document);                // optional: no huge delta after a hidden tab

renderer.setAnimationLoop((time) => {
  timer.update(time);                   // call once per frame, before getDelta()
  const dt = timer.getDelta();          // seconds since last frame
  cube.rotation.x += dt;                // frame-rate independent
  cube.rotation.y += dt * 0.7;
  renderer.render(scene, camera);
});
// renderer.setAnimationLoop(null); // stop the loop
4. レスポンシブなリサイズ
function onResize() {
  const w = window.innerWidth, h = window.innerHeight;
  camera.aspect = w / h;
  camera.updateProjectionMatrix();      // required after changing aspect
  renderer.setSize(w, h);
}
window.addEventListener('resize', onResize);
5. OrbitControls(回転/パン/ズーム)
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;          // inertial feel
controls.target.set(0, 0, 0);

renderer.setAnimationLoop(() => {
  controls.update();                    // needed every frame when damping is on
  renderer.render(scene, camera);
});

注意点

  • Failed to resolve module specifier "three" → インポートマップ(またはバンドラーの設定)がありません。"three" と "three/addons/" の両方をマッピングしてください。アドオンのパスは / で終わる必要があります。
  • エラーはないのにキャンバスが黒い → カメラが原点(オブジェクトの内部または背後)にあるか、ライトなしでライトが必要なマテリアル(MeshStandardMaterial)を使っています。カメラを後方に移動します。まず MeshNormalMaterial/MeshBasicMaterial を使ってジオメトリを確認してください。
  • アニメーションしない → ループ内で renderer.render を呼び出していないか、setAnimationLoop を呼び出しているものの、ループの外でレンダリングしています。
  • リサイズ後にビューが引き伸ばされる/つぶれる → レンダラーはリサイズしたものの、camera.aspect と updateProjectionMatrix() を更新していません。
  • HiDPI 画面でぼやける/ギザギザになる → renderer.setPixelRatio(...) を設定し、上限を設けてください(約2)。4K/Retina 画面でパフォーマンスが大きく低下するのを防げます。
  • OrbitControls が反応しない → enableDamping = true の場合、毎フレーム controls.update() を呼び出す必要があります。
  • 古いチュートリアルでは <script src="three.min.js"> を使用している → r147 以降、three.js は ES モジュールのみを提供しています。type="module" とインポートマップを使用してください。

参考資料

  • 座標規約、シーングラフ(Group、親子間の変換、Object3D の追加/削除)、2.5D 向けの OrthographicCamera、メモリリーク防止のためのジオメトリ/マテリアル/テクスチャの破棄については、references/scene-graph.md を参照してください。

関連スキル

  • threejs-materials-lighting — ライト、シャドウ、PBR を使って、サーフェスに光が当たった見た目を加えます。
  • threejs-gltf-loading — 3D モデルを読み込み、アニメーションを再生します。
  • pixijs-rendering — ブラウザーでの2Dレンダリング。
  • fps-shooter — three.js のスキルを組み合わせた、3Dジャンル向けのテンプレート。

コメント