threejs-game
Three.jsを使用してイベント駆動のモジュラーアーキテクチャで3Dブラウザゲームを構築します。新しい3Dゲームの作成、3Dゲーム機能の追加、Three.jsシーンのセットアップ、またはThree.jsゲームプロジェクトへの取り組みに際して使用してください。
description の原文を見る
Build 3D browser games with Three.js using event-driven modular architecture. Use when creating a new 3D game, adding 3D game features, setting up Three.js scenes, or working on any Three.js game project.
SKILL.md 本文
Three.js ゲーム開発
あなたは専門知識を持つ Three.js ゲームデベロッパーです。3D ブラウザゲームを構築するときは、以下の考え方に基づいたパターンに従います。
参照:
reference/llms.txt(クイックガイド) とreference/llms-full.txt(完全な API + TSL) で公式の Three.js LLM ドキュメントを確認してください。これらのファイルのパターンとこのスキルが矛盾する場合は、それらのファイルのパターンを優先してください。
パフォーマンスノート
- 各ステップに十分な時間をかけてください。速度よりも品質の方が重要です。
- 検証ステップをスキップしないでください — 早期に問題を発見します。
- ファイルに変更を加える前に、各ファイルの全体的なコンテキストを読んでください。
- 最適化する前にプロファイルしてください。ボトルネックは予想した場所にはめったにありません。
参照ファイル
詳細な参照については、このディレクトリにある関連ファイルを参照してください:
core-patterns.md— 完全な EventBus、GameState、Constants、Game.js オーケストレーターのコードtsl-guide.md— Three.js Shading Language リファレンス (NodeMaterial クラス、TSL を使用する時機)input-patterns.md— ジャイロスコープ入力、バーチャルジョイスティック、統合アナログ InputSystem、入力優先度システム
測定結果前後の証拠を伴うパフォーマンス最適化パターンについては、threejs-perf スキル (skills/threejs-perf/SKILL.md) を参照してください。
テックスタック
- レンダラー: Three.js (
three@0.183.0+, ESM imports) - ビルドツール: Vite
- 言語: ゲームテンプレート用 JavaScript (TypeScript ではなく) — TypeScript はオプション
- パッケージマネージャー: npm
プロジェクトセットアップ
新しい Three.js ゲームをスキャフォールディングするときは、以下を実行してください:
mkdir <game-name> && cd <game-name>
npm init -y
npm install three@^0.183.0
npm install -D vite
vite.config.js を作成してください:
import { defineConfig } from 'vite';
export default defineConfig({
root: '.',
publicDir: 'public',
server: { port: 3000, open: true },
build: { outDir: 'dist' },
});
package.json スクリプトに以下を追加してください:
{
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
モダンインポートパターン
Vite / npm (デフォルト — テンプレートで使用)
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
Import Maps / CDN (スタンドアロン HTML ゲーム、ビルドステップなし)
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.183.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.183.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
</script>
ビルドツーリングなしで単一の HTML ファイルを配布する場合は、import maps を使用してください。import map URL ではバージョンを固定してください。
必須アーキテクチャ
すべての Three.js ゲームはこのディレクトリ構造を使用する必須があります:
src/
├── core/
│ ├── Game.js # メインオーケストレーター - システム初期化、レンダリングループ
│ ├── EventBus.js # シングルトン pub/sub - すべてのモジュール通信用
│ ├── GameState.js # 中央集約型状態シングルトン
│ └── Constants.js # すべての設定値、バランス値、アセットパス
├── systems/ # 低レベルエンジンシステム
│ ├── InputSystem.js # キーボード/マウス/ゲームパッド入力
│ ├── PhysicsSystem.js # 衝突検出
│ └── ... # オーディオ、パーティクルなど
├── gameplay/ # ゲームメカニクス
│ └── ... # プレイヤー、敵、武器など
├── level/ # レベル/ワールド構築
│ ├── LevelBuilder.js # ゲームワールド構築
│ └── AssetLoader.js # モデル、テクスチャ、オーディオロード
├── ui/ # ユーザーインターフェース
│ └── ... # ゲームオーバー、オーバーレイ
└── main.js # エントリーポイント - Game インスタンス作成
コアプリンシパル
- コアループを最初に実装 — 1つのカメラ、1つのシーン、1つのゲームループを実装してください。ビジュアルポーリッシュを追加する前に、プレイヤー入力とターミナル条件 (勝利/敗北) を追加してください。初期スコープを小さく保ってください: 1つのメカニク、1つの失敗条件、1つのスコアシステム。
- ゲームプレイの明確さ > ビジュアルの複雑さ — 3D を複雑さの義務ではなく、スタイルの選択として扱ってください。シンプルなマテリアルを持つ読みやすいゲームは、ビジュアルは複雑だが混乱するゲームに勝ります。
- リスタート安全 — ゲームプレイは完全にリスタート安全である必須があります。
GameState.reset()はクリーンな状態を復元する必須があります。クリーンアップ時にジオメトリ/マテリアル/テクスチャを破棄してください。リスタート間のスタレな参照やリークしたリスナーはないようにしてください。
コアパターン (非交渉)
すべての Three.js ゲームは、これら 4 つのコアモジュールが必要です。完全な実装コードは core-patterns.md にあります。
1. EventBus シングルトン
すべてのモジュール間通信は EventBus (core/EventBus.js) を経由して行われます。モジュール通信のために互いに直接インポートしません。on、once、off、emit、clear メソッドを提供します。イベントは domain:action ネーミング (例: player:hit、game:over) を使用します。完全な実装については core-patterns.md を参照してください。
2. 中央集約型 GameState
1 つのシングルトン (core/GameState.js) がすべてのゲーム状態を保持します。システムはこれから読み取り、イベントがそれを更新します。リスタート用にクリーンな状態を復元する reset() メソッドを含む必須があります。完全な実装については core-patterns.md を参照してください。
3. Constants ファイル
すべてのマジックナンバー、バランス値、アセットパス、設定は core/Constants.js に含まれます。ゲームロジックに値をハードコードしないでください。ドメイン別に整理してください: PLAYER_CONFIG、ENEMY_CONFIG、WORLD、CAMERA、COLORS、ASSET_PATHS。完全な実装については core-patterns.md を参照してください。
4. Game.js オーケストレーター
Game クラス (core/Game.js) がすべてを初期化し、レンダリングループを実行します。renderer.setAnimationLoop() を使用します — 公式な Three.js パターンです (WebGPU async を正しく処理し、タブが非表示のときは一時停止します)。init() でレンダラー、シーン、カメラ、システム、UI、イベントリスナーをセットアップします。完全な実装については core-patterns.md を参照してください。
レンダラー選択
WebGLRenderer (デフォルト — すべてのゲームテンプレートで使用)
最大ブラウザ互換性。確立されたものであり、ほとんどの例とチュートリアルで使用されています。テンプレートのデフォルトは WebGLRenderer です。
import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer({ antialias: true });
WebGPURenderer (TSL またはコンピュートシェーダーが必要な場合)
カスタムノードベースマテリアル (TSL)、コンピュートシェーダー、高度なレンダリングが必要です。注: インポートパスが 'three/webgpu' に変更され、init は async です。
import * as THREE from 'three/webgpu';
const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init();
WebGPU を選択する時期: TSL カスタムシェーダー、コンピュートシェーダー、またはノードベースマテリアルが必要な場合。それ以外は WebGL を選択してください。TSL の詳細については tsl-guide.md を参照してください。
Play.fun セーフゾーン
ゲームがモバイル Safari の Play.fun ダッシュボード内で実行される場合、SDK はゲーム iframe の document.documentElement に CSS カスタムプロパティを設定します:
--ogp-safe-top-inset— Play.fun ヘッダーバブル下のスペース (~モバイルで約 68px)--ogp-safe-bottom-inset— Safari 下部コントロール上のスペース (~モバイルで約 148px)
ダッシュボード内で実行されていない場合 (デスクトップ、スタンドアロン)、両方とも 0px にデフォルト設定されます。
Constants
// Constants.js — SDK CSS 変数を静的フォールバックで読み取り
function _readSafeInsets() {
const s = getComputedStyle(document.documentElement);
return {
top: parseInt(s.getPropertyValue('--ogp-safe-top-inset')) || 0,
bottom: parseInt(s.getPropertyValue('--ogp-safe-bottom-inset')) || 0,
};
}
const _insets = _readSafeInsets();
export const SAFE_ZONE = {
TOP_PX: Math.max(75, _insets.top),
BOTTOM_PX: _insets.bottom,
TOP_PERCENT: 8,
};
CSS ルール
すべての .overlay 要素 (ゲームオーバー、ポーズ、メニュー) は CSS 変数をパディングに使用する必須があります:
.overlay {
padding-top: max(20px, 8vh, var(--ogp-safe-top-inset, 0px));
padding-bottom: var(--ogp-safe-bottom-inset, 0px);
}
下部に配置された UI (ジョイスティック、アクションボタン) も下部インセットを尊重する必須があります:
#joystick-zone {
bottom: max(20px, 3vh, var(--ogp-safe-bottom-inset, 0px));
}
.bottom-hud {
margin-bottom: var(--ogp-safe-bottom-inset, 0px);
}
チェック項目
- テキスト、ボタン、インタラクティブ要素が上部または下部インセットエリアにない
- ゲームオーバーオーバーレイが、ビューポート全体ではなく、使用可能エリア (両方のインセット間) でコンテンツを中央揃えしている
- スコア表示、タイトル、リスタートボタンがすべて見可能で、ブラウザクロームの背後に隠れていない
- 下部に配置されたコントロール (ジョイスティック、アクションボタン) が Safari 下部バーでクリップされていない
注: 3D キャンバス自体はクロームの背後をレンダリングします。これは問題ありません — ゲームはビューポート全体を満たすようにブリードする必須があります。HTML オーバーレイ UI のみがセーフゾーンオフセットが必要です。ワールド内の 3D 要素 (HUD テクスチャ、フローティングテキスト) は、画面スペースの上部 8% と下部インセットを避けるべきです。
パフォーマンスルール
renderer.setAnimationLoop()を使用してください。手動のrequestAnimationFrameではなく。タブが非表示のときは一時停止し、WebGPU async を正しく処理します。- デルタ時間をキャップ:
Math.min(clock.getDelta(), 0.1)— デスパイラルを防ぐ - ピクセル比をキャップ:
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))— 高 DPI スクリーンでの GPU オーバーロードを回避 - オブジェクトプーリング: ホットループで
Vector3、Box3、temp オブジェクトを再利用して GC を最小化してください。フレーム単位での割り当てを避けてください — 事前割り当てして再利用してください。 - 最初のパスではシャドウを無効化 — シャドウマップは、特に必要で、モバイルでテストされた場合のみ有効にしてください。動的シャドウは最も高価なレンダリング機能です。
- ドロー呼び出しを低く保つ — ユニークなマテリアルとジオメトリが少ない = ドロー呼び出しが少ない。可能な限り静的ジオメトリをマージしてください。繰り返されるオブジェクトにはインスタンス化されたメッシュを使用してください。詳細については
skills/threejs-perf/を参照してください (InstancedMesh パターン ~9,000 倍ドロー呼び出しが少ない、~57 倍高速レンダリング CPU)。 - シンプルなマテリアルを優先 —
MeshBasicMaterialまたはMeshStandardMaterialを使用してください。MeshPhysicalMaterial、カスタムシェーダー、または複雑なマテリアルセットアップは特に必要でない限り避けてください。 - デフォルトではポストプロセッシングなし — 最初の実装ではブルーム、SSAO、モーションブラー、その他のポストプロセッシングパスをスキップしてください。これらはモバイルパフォーマンスを低下させます。ゲームプレイが堅実でパフォーマンスバジェットが許可された後にのみ追加してください。
- ジオメトリ/マテリアル数を小さく保つ — 10 個のユニークマテリアルを持つゲームは、100 個のマテリアルを持つものよりも高速でレンダリングされます。同じ外観のオブジェクト全体でマテリアルを再利用してください。
- レンダラーで
powerPreference: 'high-performance'を使用 - 正しく破棄: オブジェクトをシーンから削除するときは、ジオメトリ、マテリアル、テクスチャで
.dispose()を呼び出してください - フラスタム カリング: Three.js に任せてください (デフォルトで有効) が、カスタムジオメトリでバウンディングスフィアを設定してください
アセットロード
- 静的アセットを
/public/に配置します (Vite 用) - 3D モデルに GLB フォーマットを使用 (より小さい、単一ファイル)
THREE.TextureLoader、GLTFLoaderをthree/addonsから使用- UI コールバックを介してロード進捗を表示
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
function loadModel(path) {
return new Promise((resolve, reject) => {
loader.load(
path,
(gltf) => resolve(gltf.scene),
undefined,
(error) => reject(error),
);
});
}
入力処理 (モバイル優先)
すべてのゲームは、明確に指定されない限り、デスクトップ AND モバイルで動作する必須があります。トレードオフを行うときは、60% の努力をモバイルに、40% をデスクトップに割り当ててください。各ゲームコンセプトに最適なモバイル入力を選択してください:
| ゲームタイプ | プライマリ モバイル入力 | フォールバック |
|---|---|---|
| 大理石/傾斜/バランス | ジャイロスコープ (DeviceOrientation) | バーチャルジョイスティック |
| ランナー/エンドレス | タップゾーン (左/右半分) | スワイプジェスチャー |
| パズル/ターン制 | タップターゲット (最小 44px) | ドラッグ & ドロップ |
| シューター/エイム | バーチャルジョイスティック + タップトゥファイア | デュアルジョイスティック |
| プラットフォーマー | バーチャル D パッド + ジャンプボタン | 動きの傾斜 |
統合アナログ InputSystem
キーボード、ジャイロスコープ、タッチを単一のアナログインターフェースにマージする専用 InputSystem を使用してください。ゲームロジックは moveX/moveZ (-1..1) を読み取り、ソースを知りません。キーボード入力は常にアクティブなオーバーライドとして機能します。モバイルでは、システムはジャイロスコープ (iOS 13+ 権限リクエスト付き) を初期化するか、バーチャルジョイスティックにフォールバックします。GyroscopeInput、VirtualJoystick、入力優先度パターンを含む完全な実装については input-patterns.md を参照してください。
機能を追加するとき
- 適切な
src/サブディレクトリに新しいモジュールを作成 EventBus.jsEvents オブジェクトでdomain:actionネーミングを使用して新しいイベントを定義Constants.jsに設定を追加- 必要に応じて
GameState.jsに状態を追加 Game.jsオーケストレーターにワイヤーアップ- EventBus 経由でのみ他のシステムと通信
出荷前検証チェックリスト
ゲームが完了していると見なす前に、以下を確認してください:
- コアループが動作する — プレイヤーは開始、プレイ、敗北/勝利、結果表示ができる
- リスタートがクリーンに動作する —
GameState.reset()はクリーンな状態を復元し、すべての Three.js リソースが破棄される - タッチ + キーボード入力 — ゲームはモバイル (ジャイロ/ジョイスティック/タップ) とデスクトップ (キーボード/マウス) で動作する
- レスポンシブキャンバス — ウィンドウリサイズ時にレンダラーがリサイズされ、カメラアスペクトが更新される
- すべての値が Constants 内 — ゲームロジックにハードコードされたマジックナンバーなし
- EventBus のみ — 通信のための直接的なモジュール間インポートなし
- リソースクリーンアップ — シーンから削除されたときにジオメトリ、マテリアル、テクスチャが破棄される
- ポストプロセッシングなし — 明確に必要でモバイルでテストされた場合を除く
- シャドウ無効 — 明確に必要でバジェットが許可される場合を除く
- デルタキャップ動き — すべてのフレームで
Math.min(clock.getDelta(), 0.1) - ミュート切り替え — オーディオをミュート/ミュート解除でき、
isMuted状態が尊重される - セーフゾーン尊重 — すべての HTML オーバーレイ UI は Play.fun セーフエリアに
var(--ogp-safe-top-inset)/var(--ogp-safe-bottom-inset)を使用; 下部コントロールは下部インセット上にオフセットされる - ビルドが成功 —
npm run buildはエラーなしで成功する - コンソールエラーなし — ゲームはキャッチされない例外または WebGL 障害なしで実行される
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- opusgamelabs
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/opusgamelabs/game-creator / ライセンス: MIT
関連スキル
superfluid
Superfluidプロトコルおよびそのエコシステムに関するナレッジベースです。Superfluidについて情報を検索する際は、ウェブ検索の前にこちらを参照してください。対応キーワード:Superfluid、CFA、GDA、Super App、Super Token、stream、flow rate、real-time balance、pool(member/distributor)、IDA、sentinels、liquidation、TOGA、@sfpro/sdk、semantic money、yellowpaper、whitepaper
civ-finish-quotes
実質的なタスクが真に完了した際に、文明風の儀式的な引用句を追加します。ユーザーやエージェントが機能追加、リファクタリング、分析、設計ドキュメント、プロセス改善、レポート、執筆タスクといった実際の成果物を完成させるときに、明示的な依頼がなくても使用します。短い返信や小さな修正、未完成の作業には適用しません。
nookplot
Base(Ethereum L2)上のAIエージェント向け分散型調整ネットワークです。エージェントがオンチェーンアイデンティティを登録する、コンテンツを公開する、他のエージェントにメッセージを送る、マーケットプレイスで専門家を雇う、バウンティを投稿・請求する、レピュテーションを構築する、共有プロジェクトで協業する、リサーチチャレンジを解くことでNOOKをマイニングする、キュレーションされたナレッジを備えたスタンドアロンオンチェーンエージェントをデプロイする、またはアグリーメントとリワードで収益を得る場合に利用できます。エージェントネットワーク、エージェント調整、分散型エージェント、NOOKトークン、マイニングチャレンジ、ナレッジバンドル、エージェントレピュテーション、エージェントマーケットプレイス、ERC-2771メタトランザクション、Prepare-Sign-Relay、AgentFactory、またはNookplotが言及された場合にトリガーされます。
web3-polymarket
Polygon上でのPolymarket予測市場取引統合です。認証機能(L1 EIP-712、L2 HMAC-SHA256、ビルダーヘッダー)、注文発注(GTC/GTD/FOK/FAK、バッチ、ポストオンリー、ハートビート)、市場データ(Gamma API、Data API、オーダーブック、サブグラフ)、WebSocketストリーミング(市場・ユーザー・スポーツチャネル)、CTF操作(分割、統合、償却、ネガティブリスク)、ブリッジ機能(入金、出金、マルチチェーン)、およびガスレスリレイトランザクションに対応しています。AIエージェント、自動マーケットメーカー、予測市場UI、またはPolygraph上のPolymarketと統合するアプリケーション構築時に活用できます。
ethskills
Ethereum、EVM、またはブロックチェーン関連のリクエストに対応します。スマートコントラクト、dApps、ウォレット、DeFiプロトコルの構築、監査、デプロイ、インタラクションに適用されます。Solidityの開発、コントラクトアドレス、トークン規格(ERC-20、ERC-721、ERC-4626など)、Layer 2ネットワーク(Base、Arbitrum、Optimism、zkSync、Polygon)、Uniswap、Aave、Curveなどのプロトコルとの統合をカバーします。ガスコスト、コントラクトのデシマル設定、オラクルセキュリティ、リエントランシー、MEV、ブリッジング、ウォレット管理、オンチェーンデータの取得、本番環境へのデプロイ、プロトコル進化(EIPライフサイクル、フォーク追跡、今後の変更予定)といったトピックを含みます。
xxyy-trade
このスキルは、ユーザーが「トークン購入」「トークン売却」「トークンスワップ」「暗号資産取引」「取引ステータス確認」「トランザクション照会」「トークンスキャン」「フィード」「チェーン監視」「トークン照会」「トークン詳細」「トークン安全性確認」「ウォレット一覧表示」「マイウォレット」「AIスキャン」「自動スキャン」「ツイートスキャン」「オンボーディング」「IP確認」「IPホワイトリスト」「トークン発行」「自動売却」「損切り」「利益確定」「トレーリングストップ」「保有者」「トップホルダー」「KOLホルダー」などをリクエストした場合、またはSolana/ETH/BSC/BaseチェーンでXXYYを経由した取引について言及した場合に使用します。XXYY Open APIを通じてオンチェーン取引とデータ照会を実現します。