threejs-scene-setup について
three.jsアプリの基盤を構築するためのスキルです。シーンの初期設定や描画の問題を調べる開発者向けに、モジュール読み込みからOrbitControlsまでを扱います。
主な機能
- 01ESモジュール読み込みの設定
- 02シーン・カメラ・レンダラーの作成
- 03アニメーションループの設定
- 04キャンバスサイズ変更への対応
- 05OrbitControlsの追加
活用シーン
- 01three.jsシーンの初期構築
- 02空白または黒いキャンバスの修正
- 03ウィンドウ変更に応じた表示調整
- 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。
基本的なワークフロー
- インポートマップを使って three.js を ES モジュールとして読み込みます。 r147 以降、裸の指定子
'three'と'three/addons/'はマッピングする必要があります(HTML 内、またはバンドラーで設定します)。アドオン(コントロール、ローダー)はthree/addons/...の下にあります。 - 3要素を作成します。 グラフのルートとなる
Scene、原点から後方に配置するPerspectiveCamera(fov, aspect, near, far)、そしてdomElementを DOM に配置するWebGLRendererです。サイズとpixelRatioを設定します。 - メッシュを追加します。
new Mesh(geometry, material)を作成してscene.add(mesh)を呼び出します。ライトを使うマテリアルにはライトも必要です(threejs-materials-lightingを参照)。 renderer.setAnimationLoop(fn)でレンダーループを動かします。 手動で実装するrequestAnimationFrameに代わる、最新の WebXR/WebGPU に安全に対応した方法です。経過時間にはTimerを使用します(Clockは r183 以降非推奨です)。- リサイズに対応し、カメラのアスペクト比とレンダラーをキャンバスに合わせます。
camera.aspectを更新し、updateProjectionMatrix()とrenderer.setSize(...)を呼び出します。 - 開発中の回転、パン、ズームには
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ジャンル向けのテンプレート。
コメント
Markdown 対応