threejs-webgl
Three.jsを使った3DウェブアプリケーションをWebGL/WebGPUで構築するための包括的なスキルです。インタラクティブな3Dシーン、製品コンフィギュレーター、3Dビジュアライゼーション、没入型ウェブ体験などを開発する際に使用します。Three.js、3Dレンダリング、シーン、カメラ、メッシュ、マテリアル、ライト、アニメーション、テクスチャに関わるタスクで自動的に適用されます。
description の原文を見る
Comprehensive skill for Three.js 3D web development. Use this skill when building interactive 3D scenes, WebGL/WebGPU applications, product configurators, 3D visualizations, or immersive web experiences. Triggers on tasks involving Three.js, 3D rendering, scenes, cameras, meshes, materials, lights, animations, textures, or WebGL/WebGPU rendering.
SKILL.md 本文
Three.js WebGL/WebGPU 開発
概要
Three.js は、WebGL と WebGPU を使用してウェブブラウザで 3D グラフィックスを作成するための業界標準の JavaScript ライブラリです。このスキルは、シーン、カメラ、レンダラー、ジオメトリ、マテリアル、ライト、テクスチャ、アニメーションを含む高性能で対話的な 3D エクスペリエンスの構築について、包括的なガイダンスを提供します。
コアコンセプト
シーングラフアーキテクチャ
Three.js は階層型のシーングラフを使用し、すべての 3D オブジェクトツリー構造で整理されます。
Scene
├── Camera
├── Lights
│ ├── AmbientLight
│ ├── DirectionalLight
│ └── PointLight
├── Meshes
│ ├── Mesh (Geometry + Material)
│ └── InstancedMesh
└── Groups
必須コンポーネント
すべての Three.js アプリケーションにはこれらのコア要素が必要です。
- Scene: すべての 3D オブジェクトのコンテナ
- Camera: ビューポイントを定義
- Renderer: シーンをキャンバスに描画(WebGL または WebGPU)
- Geometry: オブジェクトの形状を定義
- Material: 表面の外観を定義
- Mesh: ジオメトリとマテリアルを組み合わせ
クイックスタートパターン
基本的なシーンセットアップ
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Scene, Camera, Renderer
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x333333);
const camera = new THREE.PerspectiveCamera(
75, // FOV
window.innerWidth / window.innerHeight, // Aspect ratio
0.1, // Near clipping plane
1000 // Far clipping plane
);
camera.position.set(0, 2, 5);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 7.5);
directionalLight.castShadow = true;
scene.add(directionalLight);
// Controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Animation Loop
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// Handle Resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
WebGPU セットアップ(最新の代替案)
import * as THREE from 'three/webgpu';
const renderer = new THREE.WebGPURenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setAnimationLoop(animate);
renderer.toneMapping = THREE.LinearToneMapping;
renderer.toneMappingExposure = 1;
document.body.appendChild(renderer.domElement);
一般的なパターン
1. マテリアル付きメッシュの作成
// 基本的なメッシュ
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00,
roughness: 0.5,
metalness: 0.5
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// テクスチャ付きメッシュ
const loader = new THREE.TextureLoader();
const texture = loader.load('texture.jpg');
texture.colorSpace = THREE.SRGBColorSpace;
const texturedMaterial = new THREE.MeshStandardMaterial({
map: texture
});
const mesh = new THREE.Mesh(geometry, texturedMaterial);
scene.add(mesh);
2. ライティング戦略
// スリーポイントライティングセットアップ
function setupThreePointLight(scene) {
// キーライト(メイン)
const keyLight = new THREE.DirectionalLight(0xffffff, 3);
keyLight.position.set(5, 10, 7.5);
keyLight.castShadow = true;
scene.add(keyLight);
// フィルライト(影を柔らかくする)
const fillLight = new THREE.DirectionalLight(0xffffff, 1);
fillLight.position.set(-5, 5, -5);
scene.add(fillLight);
// リムライト(エッジ定義)
const rimLight = new THREE.DirectionalLight(0xffffff, 0.5);
rimLight.position.set(0, 5, -10);
scene.add(rimLight);
// アンビエント(基本照度)
const ambient = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambient);
}
// 物理ライト(リアリスティック)
const bulbLight = new THREE.PointLight(0xffee88, 1, 100, 2);
bulbLight.power = 1700; // ルーメン(100W 相当)
bulbLight.castShadow = true;
scene.add(bulbLight);
// ヘミスフィアライト(空 + 地面)
const hemiLight = new THREE.HemisphereLight(
0xddeeff, // 空の色
0x0f0e0d, // 地面の色
0.02
);
scene.add(hemiLight);
3. インスタンスド ジオメトリ(パフォーマンス)
// 数千個の同一オブジェクトを効率的にレンダリング
const geometry = new THREE.SphereGeometry(0.1, 16, 16);
const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const instancedMesh = new THREE.InstancedMesh(geometry, material, 1000);
const matrix = new THREE.Matrix4();
const color = new THREE.Color();
for (let i = 0; i < 1000; i++) {
matrix.setPosition(
Math.random() * 10 - 5,
Math.random() * 10 - 5,
Math.random() * 10 - 5
);
instancedMesh.setMatrixAt(i, matrix);
instancedMesh.setColorAt(i, color.setHex(Math.random() * 0xffffff));
}
instancedMesh.instanceMatrix.needsUpdate = true;
scene.add(instancedMesh);
4. 3D モデルの読み込み(glTF)
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
// ローダーのセットアップ
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('/draco/');
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
// モデルを読み込み
gltfLoader.load('model.glb', (gltf) => {
const model = gltf.scene;
// シャドウを有効化
model.traverse((child) => {
if (child.isMesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
scene.add(model);
// アニメーションを処理
if (gltf.animations.length > 0) {
const mixer = new THREE.AnimationMixer(model);
const action = mixer.clipAction(gltf.animations[0]);
action.play();
// アニメーションループで:
// mixer.update(deltaTime);
}
});
5. シャドウ設定
// レンダラーでシャドウを有効化
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // or VSMShadowMap
// ライトシャドウを設定
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 50;
directionalLight.shadow.camera.left = -10;
directionalLight.shadow.camera.right = 10;
directionalLight.shadow.camera.top = 10;
directionalLight.shadow.camera.bottom = -10;
directionalLight.shadow.radius = 4;
directionalLight.shadow.blurSamples = 8;
// オブジェクトシャドウ設定
mesh.castShadow = true;
mesh.receiveShadow = true;
6. レイキャスティング(インタラクション)
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
function onMouseClick(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
const object = intersects[0].object;
object.material.color.set(0xff0000);
}
}
window.addEventListener('click', onMouseClick);
インテグレーションパターン
GSAP でのアニメーション
import gsap from 'gsap';
// カメラをアニメーション
gsap.to(camera.position, {
x: 5,
y: 3,
z: 10,
duration: 2,
ease: "power2.inOut",
onUpdate: () => {
camera.lookAt(scene.position);
}
});
// メッシュプロパティをアニメーション
gsap.to(mesh.rotation, {
y: Math.PI * 2,
duration: 3,
repeat: -1,
ease: "none"
});
React 統合(react-three-fiber スキルを参照)
// Three.js は React Three Fiber と自然に統合
// React 統合パターンについては react-three-fiber スキルを使用
ポストプロセッシング
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // 強度
0.4, // 半径
0.85 // 閾値
);
composer.addPass(bloomPass);
// アニメーションループで:
composer.render();
パフォーマンス最適化
1. ジオメトリの再利用
// 悪い例: メッシュごとに新しいジオメトリを作成
for (let i = 0; i < 100; i++) {
const geometry = new THREE.BoxGeometry(1, 1, 1);
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
}
// 良い例: ジオメトリを再利用
const sharedGeometry = new THREE.BoxGeometry(1, 1, 1);
for (let i = 0; i < 100; i++) {
const mesh = new THREE.Mesh(sharedGeometry, material);
scene.add(mesh);
}
2. 反復的なオブジェクトに InstancedMesh を使用
数百/数千個の同一オブジェクトの場合は、InstancedMesh を使用します(上記のパターンを参照)。
3. テクスチャ最適化
// テクスチャを圧縮
texture.generateMipmaps = true;
texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter;
// 2 の乗数の寸法を使用(512, 1024, 2048)
// 複数の小さなテクスチャにはテクスチャアトラスを検討
4. 詳細度のレベル(LOD)
const lod = new THREE.LOD();
lod.addLevel(highDetailMesh, 0); // 0-50 ユニット
lod.addLevel(mediumDetailMesh, 50); // 50-100 ユニット
lod.addLevel(lowDetailMesh, 100); // 100+ ユニット
scene.add(lod);
5. フラスタム カリング
Three.js は自動的にカメラの視野外のオブジェクトを除外します。オブジェクトが正しいバウンディングスフィアを持つようにしてください。
mesh.geometry.computeBoundingSphere();
6. リソースの解放
function disposeScene() {
scene.traverse((object) => {
if (object.geometry) object.geometry.dispose();
if (object.material) {
if (Array.isArray(object.material)) {
object.material.forEach(material => material.dispose());
} else {
object.material.dispose();
}
}
});
renderer.dispose();
}
ベストプラクティス
1. 一貫したタイミングのためにアニメーション クロックを使用
const clock = new THREE.Clock();
function animate() {
const deltaTime = clock.getDelta();
const elapsedTime = clock.getElapsedTime();
// フレームレートに依存しないアニメーションに deltaTime を使用
mesh.rotation.y += deltaTime * Math.PI * 0.5; // 毎秒 90°
renderer.render(scene, camera);
}
2. カメラセットアップガイドライン
- FOV: ほとんどのアプリケーションで 45~75°
- Near プレーン: できるだけ遠く(z-fighting を回避)
- Far プレーン: できるだけ近く(精度)
- アスペクト比: 常にキャンバスの寸法と一致
3. マテリアル選択
- MeshBasicMaterial: ライトなし、平坦な色(デバッグ、UI)
- MeshLambertMaterial: 安価な拡散光(モバイル)
- MeshPhongMaterial: 鏡面反射ハイライト(旧標準)
- MeshStandardMaterial: PBR、リアリスティック(推奨)
- MeshPhysicalMaterial: 高度な PBR(クリアコート、透過)
4. 座標系
- Three.js は右手座標系を使用
- +Y は上、+Z はカメラに向かう方向、+X は右
- 回転はラジアンを使用(Math.PI = 180°)
5. シーン組織化
// 関連オブジェクトをグループ化
const building = new THREE.Group();
building.add(walls, roof, windows);
scene.add(building);
// 意味のある名前を使用
mesh.name = 'player-character';
const found = scene.getObjectByName('player-character');
よくある落とし穴
1. リサイズ時にアスペクト比を更新しない
ウィンドウがリサイズされるときは、常にカメラのアスペクト比と投影行列を更新してください。
2. アニメーションループで新しいオブジェクトを作成
// 悪い例: メモリリーク
function animate() {
const geometry = new THREE.BoxGeometry(); // 毎フレーム作成!
// ...
}
// 良い例: ループ外で一度作成
const geometry = new THREE.BoxGeometry();
function animate() {
// ジオメトリを再利用
}
3. シャドウを有効化するのを忘れる
レンダラー、ライト、オブジェクトでシャドウを有効化することを忘れずに。
4. Z-Fighting(フリッカリング)
- Near プレーンの距離を増やす
- Far プレーンの距離を減らす
- 同一平面上に重なるサーフェスを回避
material.polygonOffset = trueをmaterial.polygonOffsetFactorで使用
5. カラースペースの問題
// テクスチャには常にカラースペースを設定
texture.colorSpace = THREE.SRGBColorSpace;
// レンダラー出力エンコーディングを設定
renderer.outputColorSpace = THREE.SRGBColorSpace;
6. リソースを解放しない
不要になったジオメトリ、マテリアル、テクスチャ、レンダラーに対して常に .dispose() を呼び出してください。
リソース
このスキルには Three.js 開発を加速するためのバンドルリソースが含まれています。
references/
api_reference.md: コアクラス(Scene、Camera、Renderer など)のクイック API リファレンスmaterials_guide.md: マテリアルタイプとプロパティの包括的なガイドoptimization_checklist.md: パフォーマンス最適化戦略
scripts/
setup_scene.py: Three.js シーンセットアップボイラープレートコードを生成texture_optimizer.py: ウェブ用テクスチャをバッチ最適化(リサイズ、圧縮)gltf_validator.py: 使用前に glTF モデルを検証
assets/
starter_scene/: 完全な HTML/JS ボイラープレートプロジェクトshaders/: カスタム GLSL シェーダーサンプル(頂点、フラグメント)hdri/: PBR ライティング用環境マップdraco/: 圧縮モデル用 DRACO デコーダー
高度なトピック
カスタムシェーダー(GLSL)
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0.0 },
uColor: { value: new THREE.Color(0x00ff00) }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform float uTime;
uniform vec3 uColor;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(uColor * vUv.x, 1.0);
}
`
});
レンダーターゲット(テクスチャへのレンダリング)
const renderTarget = new THREE.WebGLRenderTarget(512, 512);
// シーンをテクスチャにレンダリング
renderer.setRenderTarget(renderTarget);
renderer.render(scene, camera);
renderer.setRenderTarget(null);
// テクスチャを使用
const material = new THREE.MeshBasicMaterial({
map: renderTarget.texture
});
GPU 計算(GPGPU)
パーティクルシミュレーション、クロス物理などに GPUComputationRenderer を使用します。
このスキルを使用する時期
以下の場合にこのスキルを使用してください。
- インタラクティブな 3D ウェブエクスペリエンスを構築
- プロダクトコンフィギュレーターまたはビジュアライザーを作成
- WebGL/WebGPU レンダリングを実装
- 3D モデル、シーン、またはアニメーションを操作
- Three.js パフォーマンスを最適化
- Three.js を他のライブラリ(GSAP、React など)と統合
- Three.js レンダリング問題をデバッグ
React 統合については、react-three-fiber スキルを使用してください。 アニメーションについては、gsap-scrolltrigger スキルと組み合わせてください。 UI アニメーションについては、motion-framer スキルを使用してください。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- freshtechbro
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/freshtechbro/claudedesignskills / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。