worldlabs
World Labs Marble APIを使用して、テキストプロンプトや参照画像からフォトリアルな3DワールドやGaussian Splatシーンを生成します。「3Dワールドを作って」「環境を生成して」「3Dシーンを作成して」などと指示されたときに使用します。事前に`WLT_API_KEY`環境変数の設定が必要です。
description の原文を見る
Generate photorealistic 3D worlds and environments with the World Labs Marble API — Gaussian Splat scenes from text prompts or reference images. Use when the user says "generate a 3D world", "create an environment", "make a 3D scene", or "use World Labs". Requires WLT_API_KEY environment variable.
SKILL.md 本文
World Labs — 3D ワールド/環境生成
World Labs Marble API を使用して、テキストプロンプトまたは画像から、フォトリアリスティックな3D環境を生成します。Three.js で SparkJS を使用してレンダリングされた Gaussian Splat シーン (SPZ) と、物理演算用のコライダーメッシュ (GLB) を出力します。
使用時期
- 環境/レベル生成 — テキストまたは参照画像から3Dワールド全体 (部屋、風景、建築物) を作成
- Meshy AI を補完 — Meshy は個別のモデル/キャラクターを生成し、World Labs はそれらが存在する環境を生成
- フォトリアリスティックなシーン — Gaussian Splat はメッシュベースの環境と比べてフォトリアリスティックな品質を提供
入力優先度
画像優先 — テキスト入力より常に画像入力を優先します:
- 画像モード (デフォルト) — ユーザーが参照画像、コンセプトアート、スクリーンショット、または写真を持っている場合は
--mode imageを使用します。AI が正確な視覚スタイル、レイアウト、照明、ムードを一致させることができるため、最も忠実な結果が得られます。 - テキストモード (フォールバック) — 参照画像が利用できない場合のみ
--mode textを使用します。API は短いプロンプトを自動的にリッチなシーン説明に展開しますが、結果は画像駆動型の生成ほど予測可能ではありません。
ゲームクリエーター パイプラインが実行される場合、最初にユーザーに参照画像を尋ねてください:
World Labs を使用してゲーム用のフォトリアリスティックな3D環境を生成できます。 環境の参照画像 (写真、コンセプトアート、スクリーンショット) はありますか?
- はい → ファイルパスまたは URL を提供
- いいえ → 代わりにテキスト説明から生成します
テックスタック
| コンポーネント | テクノロジー |
|---|---|
| API | World Labs Marble API (https://api.worldlabs.ai/marble/v1) |
| 認証 | WLT-Api-Key ヘッダー |
| 出力: ビジュアル | Gaussian Splat (.spz) — 100k、500k、フル解像度のティア |
| 出力: 物理 | コライダーメッシュ (.glb) — 衝突検出用 |
| 出力: スカイボックス | パノラマ画像 (.jpg/.png) |
| ブラウザレンダラー | SparkJS 2.x (@sparkjsdev/spark) — SparkRenderer + SplatMesh、Three.js 互換 |
| CLI スクリプト | scripts/worldlabs-generate.mjs (依存なし) |
環境変数
ユーザーにプロンプトする前に、キーが既に存在するかを確認してください:
test -f .env && grep -q '^WORLDLABS_API_KEY=.' .env && echo "found"
見つかった場合は、set -a; . .env; set +a でエクスポートし、プロンプトをスキップしてください。
設定されていない場合は、ユーザーに尋ねてください:
World Labs でフォトリアリスティックな3D環境を生成します。無料の API キーを取得できます:
- https://platform.worldlabs.ai でサインアップ
- API キーに移動
- 新しいキーを作成
以下のようにキーを貼り付けてください:
WORLDLABS_API_KEY=your-key-here(.env に保存され、この会話から自動的に削除されます。)または「skip」と入力して、代わりに基本的なジオメトリを使用してください。
CLI スクリプト使用方法
# テキストから3Dワールドへ
WORLDLABS_API_KEY=<key> node scripts/worldlabs-generate.mjs \
--mode text --prompt "a medieval tavern with wooden beams and a roaring fireplace" \
--output public/assets/worlds/ --slug tavern
# 画像から3Dワールドへ (ローカルファイルまたは URL)
WORLDLABS_API_KEY=<key> node scripts/worldlabs-generate.mjs \
--mode image --image ./reference-photo.jpg \
--output public/assets/worlds/ --slug my-world
# 生成ステータスを確認
WORLDLABS_API_KEY=<key> node scripts/worldlabs-generate.mjs \
--mode status --operation-id <op-id>
# 既存のワールドからアセットをダウンロード
WORLDLABS_API_KEY=<key> node scripts/worldlabs-generate.mjs \
--mode get --world-id <id> --output public/assets/worlds/ --slug my-world
# あなたのワールドを一覧表示
WORLDLABS_API_KEY=<key> node scripts/worldlabs-generate.mjs --mode list
出力ファイル
public/assets/worlds/
tavern.spz # Gaussian Splat (フル解像度)
tavern-500k.spz # Gaussian Splat (500k、中品質)
tavern-100k.spz # Gaussian Splat (100k、軽量/モバイル)
tavern-collider.glb # 物理演算用コライダーメッシュ (GLB)
tavern-pano.jpg # パノラマ画像 (スカイボックス)
tavern.meta.json # メタデータ: ワールド ID、プロンプト、タイムスタンプ、アセット URL
Three.js ゲームとの統合
テスト済み・動作確認済み — examples/worldlabs-arcade/ で完全に実行可能なデモを参照してください。
SparkJS 2.0 をインストール
npm install @sparkjsdev/spark@^2.0.0
パッケージ: @sparkjsdev/spark — Three.js 用の高性能 Gaussian Splat レンダラー。^2.0.0 にピン留めしてください。0.x ラインは異なる API (SparkRenderer なし) があり、以下のスニペットと一致しません。SPZ、PLY、SOGS、KSPLAT、SPLAT 形式をサポート (拡張子で自動検出)。
Three.js ピアバージョン: Spark 2.0 は three@^0.180.0 をピアの依存関係として宣言します。Three は 0.x マイナーをすべて潜在的に破壊的として扱うため、three@^0.181 以降は npm install 時にピアデップ エラー ERESOLVE をトリガーします。プロジェクトの package.json で three を ^0.180.0 にピン留めしてください。これは threejs-3d テンプレートと worldlabs-arcade サンプルの両方が使用しているものです。
バンドラーがない? npm の代わりに CDN importmap を使用してください:
<script type="importmap">{
"imports": {
"three": "https://cdnjs.cloudflare.com/ajax/libs/three.js/0.180.0/three.module.js",
"@sparkjsdev/spark": "https://sparkjs.dev/releases/spark/2.0.0/spark.module.js"
}
}</script>
WebGLRenderer 設定: antialias: false で作成してください。Splat シェーダーは独自のアンチエイリアシングを提供し、MSAA を有効にするとビジュアル向上なしに GPU を浪費します:
const renderer = new THREE.WebGLRenderer({ antialias: false });
Constants.js — ワールド設定
export const WORLD = {
splatPath: 'assets/worlds/tavern-500k.spz', // 500k はデスクトップの良いデフォルト
colliderPath: 'assets/worlds/tavern-collider.glb',
panoPath: 'assets/worlds/tavern-pano.png',
scale: 1,
position: { x: 0, y: 0, z: 0 },
};
WorldLoader.js — Gaussian Splat + コライダーをロード
Spark 2.0 は SparkRenderer を導入します。これはシーン レベルのオブジェクトで、Three.js のレンダー パイプラインにフックし、splat 品質、ソート、LOD を制御します。これを一度インスタンス化してシーンに追加し、通常の Three.js オブジェクトとして SplatMesh インスタンスを追加します。WebGLRenderer の render() 呼び出しはすべてを透過的に処理します。
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { SparkRenderer, SplatMesh } from '@sparkjsdev/spark';
import { WORLD } from '../core/Constants.js';
let _colliderMesh = null;
let _splatMesh = null;
export async function loadWorld(scene, renderer, camera) {
// 0. SparkRenderer — splat レンダリングの品質 + LOD コントロール。
// 任意の SplatMesh が追加される前にシーンに追加する必要があります。シーンごとに 1 つ。
const spark = new SparkRenderer({
renderer,
maxPixelRadius: 512, // より大きいmax → よりシャープなクローズアップ splat
sortRadial: true, // カメラ回転時の黒バーアーティファクトを排除
enableLod: true, // 距離で splat 数を自動削減
lodSplatScale: 1.0, // >1.0 = より多くの splat (より高品質)、<1.0 = より少ない
});
scene.add(spark);
const promises = [];
// 1. SparkJS 経由の Gaussian Splat — SplatMesh は通常の Three.js オブジェクトのように動作します。
// `splat.initialized` はファイルが解析され、GPU バッファがアップロードされると解決される Promise です
if (WORLD.splatPath) {
promises.push((async () => {
const splat = new SplatMesh({ url: WORLD.splatPath });
splat.scale.setScalar(WORLD.scale);
splat.position.set(WORLD.position.x, WORLD.position.y, WORLD.position.z);
scene.add(splat);
if (splat.initialized) await splat.initialized;
_splatMesh = splat;
})());
}
// 2. コライダーメッシュ (GLB) — 不可視、物理レイキャスティングのみ用
if (WORLD.colliderPath) {
promises.push((async () => {
const loader = new GLTFLoader();
const gltf = await loader.loadAsync(WORLD.colliderPath);
_colliderMesh = gltf.scene;
_colliderMesh.visible = false;
_colliderMesh.scale.setScalar(WORLD.scale);
_colliderMesh.position.set(WORLD.position.x, WORLD.position.y, WORLD.position.z);
_colliderMesh.traverse(c => { if (c.isMesh) c.material.side = THREE.DoubleSide; });
_colliderMesh.updateMatrixWorld(true); // 最初のレイキャスト前に必要
scene.add(_colliderMesh);
})());
}
// 3. パノラマを等方形スカイボックス + 環境照明として使用。
// 注意: World Labs splat シーンを使用する場合はこれをオフにしてください。パノラマは splat と同じ
// 環境を描写し、「世界の中の世界」の二重効果が得られます。Meshy キャラクター上の IBL では、
// `spark.renderEnvMap({ scene, worldCenter })` を使用して splat 自体から照明を行うことを推奨します。
if (WORLD.panoPath) {
promises.push((async () => {
const texLoader = new THREE.TextureLoader();
const panoTex = await texLoader.loadAsync(WORLD.panoPath);
panoTex.mapping = THREE.EquirectangularReflectionMapping;
panoTex.colorSpace = THREE.SRGBColorSpace;
scene.environment = panoTex; // 照明のみ — scene.background ではない
})());
}
await Promise.all(promises);
return { splat: _splatMesh, collider: _colliderMesh };
}
const _raycaster = new THREE.Raycaster();
const _downDir = new THREE.Vector3(0, -1, 0);
const _rayOrigin = new THREE.Vector3();
export function getGroundHeight(x, z, fallback = 0) {
if (!_colliderMesh) return fallback;
_rayOrigin.set(x, 50, z);
_raycaster.set(_rayOrigin, _downDir);
const hits = _raycaster.intersectObject(_colliderMesh, true);
return hits.length > 0 ? hits[0].point.y : fallback;
}
export function getCollider() { return _colliderMesh; }
Game.js — レンダリング ループ統合
SparkRenderer がシーンに入ると、splat レンダリングは透過的になります。SparkRenderer.autoUpdate はデフォルトで true なので、renderer.render(scene, camera) はシーン内のすべての SplatMesh に対してソート + 描画を処理します。追加の .render() または .update() 呼び出しは不要です。renderer.setAnimationLoop を使用してください (Spark 2.0 の推奨ループ形式で、WebXR 互換)。
import { loadWorld, getGroundHeight } from '../level/WorldLoader.js';
// init() 内:
await loadWorld(scene, renderer, camera);
// レンダリング ループ — 標準 Three.js、splat パス不要:
renderer.setAnimationLoop((time) => {
const delta = clock.getDelta();
player.update(delta, input, azimuth);
// プレイヤー Y をコライダー接地面にスナップ
const groundY = getGroundHeight(player.mesh.position.x, player.mesh.position.z, 0);
player.mesh.position.y = groundY;
// 単一の render 呼び出しはメッシュと splat の両方を処理
renderer.render(scene, camera);
});
解像度ティア
| ティア | ファイル | 品質 | ユースケース |
|---|---|---|---|
100k | {slug}-100k.spz | 低 | モバイル、高速読み込み、プレビュー |
500k | {slug}-500k.spz | 中 | デスクトップ ゲーム、良好なバランス |
full_res | {slug}.spz | 高 | ハイエンド、ヒーロー環境 |
ターゲット プラットフォームに基づいて選択してください。コライダー メッシュ (GLB) は splat 解像度に関係なく同じです。
Spark 2.0 品質チューニング
デフォルトの SparkRenderer({ renderer }) はほとんどのシーンで見栄えが良好です。そうでない場合、実際に数値を動かす 4 つのノブがあります。これらを SparkRenderer コンストラクターで渡してください:
| 症状 | ノブ | 方向 |
|---|---|---|
| クローズアップの splat がチャンキー/低解像度に見える | lodSplatScale | 2.0 に向かって上げる (2× の splat がレンダリング) |
| 遠距離で splat が明らかに出現/消滅 | lodRenderScale | 2.0 に向かって上げて、遠方の splat を画面上でより大きく保つ |
| カメラ回転時に黒バーまたはティアリング | sortRadial | true (デフォルト) のままにします。合成用に厳密な Z 深度が必要な場合のみ false に設定 |
| ロー エンド GPU/モバイル パフォーマンスが低い | lodSplatScale + maxPixelRadius | lodSplatScale を 0.5 に、maxPixelRadius を 256 に低下させる |
splat シーンからの IBL — Spark 2.0 は spark.renderEnvMap({ scene, worldCenter }) を追加します。これは splat シーンを THREE.Texture にレンダリングして、scene.environment または MeshStandardMaterial.envMap として使用可能にします。これは Meshy キャラクターが、その中に立つ World Labs 環境の照明をキャッチさせるための正しい方法です。完全なオプションについては SparkRenderer ドキュメントを参照してください。
パイプライン: World Labs + Meshy AI
完全な3Dゲームの場合、両方を組み合わせます:
- World Labs → 環境を生成 (部屋、風景、アリーナ)
- Meshy AI → キャラクターと小道具を生成 (プレイヤー、敵、アイテム)
- 統合 → キャラクターが World Labs コライダーメッシュを歩き、Gaussian Splat シーン内でレンダリング
┌─────────────────────────────────────────────────┐
│ 完全な3Dシーン │
├─────────────────────────────────────────────────┤
│ World Labs (環境) │
│ └─ Gaussian Splat (ビジュアル) │
│ └─ コライダーメッシュ (物理) │
│ └─ パノラマ (スカイボックス) │
│ │
│ Meshy AI (エンティティ) │
│ └─ プレイヤー キャラクター (リグ、アニメーション GLB) │
│ └─ 敵 (リグ、アニメーション GLB) │
│ └─ 小道具/アイテム (静的 GLB) │
│ │
│ Three.js (エンジン) │
│ └─ SparkJS が splat をレンダリング │
│ └─ GLTFLoader がキャラクター/小道具をレンダリング │
│ └─ レイキャスターがコライダーを接地/壁に使用 │
└─────────────────────────────────────────────────┘
リファレンス実装
examples/worldlabs-arcade/ を参照してください。完全なテスト済みデモ:
- World Labs Gaussian Splat 環境 (レトロ アーケード)
- アニメーション化された Soldier キャラクター (歩行/走行/アイドル)
- OrbitControls 三人称カメラ
- コライダーメッシュ接地レイキャスト
- パノラマ スカイボックス
トラブルシューティング
シーンが上下反転して見える (Y フリップ)
原因: World Labs SPZ ファイルは Three.js の規則と比較して Y 反転座標を使用しています。
修正: splat メッシュとコライダー メッシュの両方に rotation.x = Math.PI を適用します。その後、position.z を補正するために調整します:position.z += (minZ + maxZ)。親グループで scale.y = -1 を使用しないでください。SparkJS は負の親スケールで破損します。
レイキャストが床ではなく天井に当たる
原因: Y フリップ後、座標系が反転しています。下方向のレイキャストは、元々床だったもの (フリップ後は天井) に当たります。
修正: Y=-50 から上方向にレイキャスト (方向 (0, 1, 0)) して、ビジュアル床に最初に当たるようにします。床は反転後の最も低い表面です。
コライダーメッシュ レイキャストが ヒットを返さない
原因: コライダーメッシュのワールド マトリックスが、回転/位置設定後に更新されていません。特に最初のレンダリング フレームの前に。
修正: 回転と位置を設定した直後に _colliderMesh.updateMatrixWorld(true) を呼び出し、レイキャスト操作の前に実行します。
シーンが二重に表示される / 世界が世界の中に見える
原因: World Labs パノラマを scene.background として使用するか、3D シーンを囲む巨大な球として同じ環境を表示します。
修正: パノラマをシーン背景として使用しないでください。代わりに、単色 (scene.background = new THREE.Color(0x87CEEB)) またはカスタム スカイボックスを使用します。
生成がタイムアウトするか、時間がかかる
原因: World Labs 生成には通常 3 〜 8 分かかります。複雑なシーンやサーバーの負荷により、これが延長される可能性があります。
修正: 10 〜 15 秒ごとに操作ステータス エンドポイントをポーリングします。progress.status で "IN_PROGRESS" と "COMPLETE" を確認します。15 分以上停滞している場合は、新しい生成リクエストを作成してください。同じ操作を再試行しないでください。
Splat ファイルが読み込まれるが何もレンダリングされない (黒いシーン)
原因: Spark 2.0 では、SparkRenderer が実際に splat を描画するものです。SplatMesh を SparkRenderer なしでシーンに追加すると、出力が得られません。
修正: new SparkRenderer({ renderer }) をインスタンス化し、scene.add(spark) を、任意の SplatMesh が追加される前に実行します。シーンごとに 1 つの SparkRenderer で十分です。
Spark API が間違っている / メソッドが存在しない
原因: 0.x の代わりに 2.x をインストール。0.x ラインは SparkRenderer、LOD、sortRadial より前のものです。
修正: npm install @sparkjsdev/spark@^2.0.0 で 2.0 以降にピン留めしてください。node_modules/@sparkjsdev/spark/package.json で確認してください。
Splat がカメラ移動時に出現/消滅
原因: LOD システムがティアを交換しています。大規模なワールドでは問題ありませんが、小規模なものでは煩わしい場合があります。
修正: lodRenderScale を上げて遠方の splat をビジュアル的により大きく保つか、小規模なシーンの場合は enableLod: false に設定して、どこでもフル詳細度でレンダリングします。
キャラクターが無光状態に見える / splat 環境と一致しない
原因: Meshy (または他の GLB) キャラクターは環境マップなしで MeshStandardMaterial を使用し、フォトリアリスティック splat バックドロップに対してフラットにレンダリングされます。
修正: spark.renderEnvMap({ scene, worldCenter }) を使用して splat シーンを THREE.Texture にベイクしてそれを割り当てます:scene.environment = envMap。または、spark.recurseSetEnvMap(character, envMap) 経由でマテリアルごとに割り当てます。
メディア アップロードが 404 で失敗
原因: メディア アップロード準備に間違ったエンドポイントを使用しています。
修正: POST /media-assets:prepare_upload を使用してください (/media-assets ではなく)。これは PUT アップロード用の署名付き URL を返します。コロン構文は意図的です。リソース上のカスタム アクションです。
API が 401 Unauthorized を返す
原因: 間違った認証ヘッダー形式を使用しています。
修正: WLT-Api-Key: <your-key> ヘッダーを使用してください (Authorization: Bearer <your-key> ではなく)。World Labs API はカスタム ヘッダー形式を使用します。
チェックリスト
-
WORLDLABS_API_KEY環境変数が設定されている - ユーザーに最初に参照画像を要求する (画像から世界は推奨)
-
scripts/worldlabs-generate.mjsを実行してワールドを生成 (~3-8 分) - SPZ + コライダー GLB + パノラマが
public/assets/worlds/にダウンロード -
@sparkjsdev/spark@^2.0.0をインストール (0.x ではなく — API が異なる) -
WebGLRendererをantialias: falseで作成 -
WorldLoader.jsをsrc/level/に作成 (SparkRenderer + SplatMesh + GLTFLoader) -
SparkRendererをインスタンス化し、任意のSplatMeshの前にシーンに追加 -
await splat.initializedを使用して、splat が読み込まれると見なす前に -
Constants.jsをWORLD設定で更新 (splatPath、colliderPath、panoPath) -
Game.jsが init でloadWorld()を呼び出し、プレイヤー Y にgetGroundHeight()を使用 - 単一の
renderer.render(scene, camera)が splat とメッシュの両方を処理 — パス不要 - 物理は不可視のコライダーメッシュを接地/壁のレイキャストに使用
- テスト: キャラクターがコライダー表面を歩行、splat がそのまわりをレンダリング
- パフォーマンス: デスクトップに 500k SPZ、モバイルに 100k を使用。必要に応じて
lodSplatScaleをチューニング
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- opusgamelabs
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/opusgamelabs/game-creator / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。