composites について
Decentraland シーンを作成・編集するエージェント向けの、composite 形式と編集方法のリファレンスです。Creator Hub MCP を優先するワークフロー、境界計算、検証項目を説明します。
主な機能
- 01Creator Hub MCP の利用判断
- 02区画データに基づくシーン境界計算
- 03GLB モデルの境界ボックス確認
- 04Composite 形式リファレンス
- 05新規作成と編集の検証項目
活用シーン
- 01Creator Hub でシーンのエンティティを編集
- 02ファイル編集で composite を作成
- 03モデルがシーン境界を超えるか確認
MCP 対応
エンティティ作成、コンポーネント変更、シーン設定には Creator Hub MCP ツールを使い、composite ファイルの手動編集より優先するよう案内します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ decentraland/ sdk-skills --skill compositesインストール後、Claude Code で/compositesを入力して読み込まれたか確認します。
同梱ファイルcomposite-reference.md
詳細
コンポジット
このスキルは、ほかのDecentralandスキル(create-scene、add-3d-models、sdk-scenes)で共有されるコンポジット形式のリファレンスです。
以下の必須ワークフローは、作成または編集するすべてのコンポジットに適用されます。まずCreator Hub MCPのゲートを確認し、シーンの境界を計算し(ステップ0)、エンティティの作成時にリファレンスの形式カタログを参照してから、終了前に最後の検証ゲートを実行します。
ゲート — ファイルを編集する代わりにCreator Hub MCPを使用する(最初に確認)
main.compositeの手動編集は、既定の方法ではなく、代替手段です。 Creator HubはMCPサーバー(スキル:creator-hub-mcp)を公開しています。このサーバーのツール(scene_state、create_entity、set_component、remove_entity、place_smart_item、attach_script、set_scene_settings、…)を使うと、開いているシーンをリアルタイムで変更できます。ビューポートが更新され、エディターがコンポジット自体を自動保存し、inspector::Nodesやエディター内のほかの管理情報も整合性が保たれ、変更はすべてユーザーが元に戻せます。一方、ファイルを編集すると、エディターの自動保存によってファイル全体が再生成され、作業内容が気づかないうちに消えるという典型的な問題が起こるおそれがあります。
ファイルに触れる前に、以下のうち最初に該当する項目を選んでください。
- セッションでCreator Hub MCPツールを利用できる(Claude Codeでは
mcp__creator-hub__*、Creator Hub内蔵のAIアシスタントではscene_state/create_entity)→main.composite、main.crdt、scene.jsonを手動で編集しないでください。エンティティ、コンポーネント、設定の変更にはすべてツールを使用してください。このスキルの形式カタログはコンポーネントの構造を確認するためのリファレンスです。set_componentには、コンポジットに保存されるものと同じJSONを渡します。また、ステップ0(境界の計算)も引き続き適用されます。 - Creator Hubは実行中だが、ツールが接続されていない → MCPを使うほうが安全であることと、接続方法(
{baseDir}/../creator-hub-mcp/reference/connect.md:Settings > AI > Expose AI assistant MCP serverを選択し、スニペットをコピー)をユーザーに伝えてください。ユーザーが断った場合に限り、Creator Hubでシーンを閉じた状態でファイル編集に切り替えてください。シーンが開いている(または開いている可能性がある)のにMCPが接続されていない場合は、停止して確認する必要があります。シーンを閉じる/MCPを接続する/コードで構築する、の選択肢を提示し、返答を待ってください。代わりにsrc/で静的エンティティを構築するかどうかはユーザーが決めることであり、あなたが決めてはいけません。グレーボックスとしてでも、セッションが非対話型だからという理由でも同様です(規範となるルール:sdk-scenes → Agent Behavioral Guidelines、項目5)。 - Creator Hubを使用していない(CLIのみのプロジェクト、CI、アプリが閉じており、ユーザーがその状態を希望している)→ 以下のファイルワークフローをすべて適用します。
ステップ0 — scene.jsonを読み込み、境界を計算する(必須)
エンティティの位置をひとつでも書き込む前に、scene.jsonを読み込み、シーンの境界を計算してください。 これは最初に行う必要があります。すべてのエンティティの位置がこの境界内に収まっていないと、描画されません。
境界の計算方法
scene.jsonを開き、scene.parcels("x,y"文字列の配列)とscene.baseを見つけます。- すべてのparcelを整数として解析します。すべてのparcelにおけるXとYの最小値と最大値を求めます。
- 次のように計算します。
parcelsWide = max(parcel_x) - min(parcel_x) + 1
parcelsDeep = max(parcel_y) - min(parcel_y) + 1
maxX = parcelsWide * 16
maxZ = parcelsDeep * 16
- 有効なエンティティの位置:**Xは[0, maxX]、Zは[0, maxZ]**です。負の値、およびmaxX/maxZを超える値はシーンの範囲外となり、描画されません。
Step 0b — 3Dモデルのバウンディングボックスを確認する(GLBモデルでは必須)
モデルのTransform.positionはローカル原点であり、見た目の範囲ではありません。 樹木や植生のモデルは、原点からいずれかの方向に6〜12 m以上伸びていることがよくあります。樹木をx=2に配置すると、x=–10に描画され、シーンの境界外に出ることがあります。
モデルのバウンディングボックスの調べ方 — GLBバイナリを解析し、ノードレベルの変換を適用します。生のアクセサーのmin/max値だけでは信頼できません。多くのGLBモデルでは、GLTFノード階層に大きなスケールや平行移動が組み込まれているためです(たとえば、アクセサー上では0.6 mでも、ノードのスケールが24倍で、実際の描画サイズが14 mになるモデルがあります)。
node -e "
const buf = require('fs').readFileSync('assets/Models/MyModel.glb');
const jsonLen = buf.readUInt32LE(12);
const json = JSON.parse(buf.slice(20, 20+jsonLen));
let minW=[Infinity,Infinity,Infinity], maxW=[-Infinity,-Infinity,-Infinity];
json.nodes?.forEach(n => {
if (n.mesh === undefined) return;
const s = n.scale || [1,1,1];
const t = n.translation || [0,0,0];
for (const prim of json.meshes[n.mesh].primitives) {
const acc = json.accessors[prim.attributes.POSITION];
if (!acc.min || !acc.max) continue;
for (let i = 0; i < 3; i++) {
const lo = acc.min[i]*s[i]+t[i], hi = acc.max[i]*s[i]+t[i];
minW[i] = Math.min(minW[i], lo, hi);
maxW[i] = Math.max(maxW[i], lo, hi);
}
}
});
const w=maxW[0]-minW[0], h=maxW[1]-minW[1], d=maxW[2]-minW[2];
console.log('Rendered size:', w.toFixed(2)+'m x', h.toFixed(2)+'m x', d.toFixed(2)+'m');
console.log('World min:', minW.map(v=>v.toFixed(2)), 'max:', maxW.map(v=>v.toFixed(2)));
"
モデルごとに計測し、推測やハードコードはしないでください。 範囲はモデルによって大きく異なります。たとえば、上記のスクリプトを一般的な樹木に実行すると、原点から水平方向の一方に約11 m伸びていることがわかる場合があります(原点のzは最低でも12)。一方、柱はすべての方向で1 m未満です。配置するGLBごとに、必ずバウンディングボックスを計算してください。
ルール: すべてのGLBモデルについて、次を計算します。
minSafeX = max(0, -bbox.minX) + margin (≥1 m)
minSafeZ = max(0, -bbox.minZ) + margin (≥1 m)
maxSafeX = maxX - (bbox.maxX + margin)
maxSafeZ = maxZ - (bbox.maxZ + margin)
Transformの位置が4つすべての境界条件を満たす場合にのみ、モデルを配置してください。
バウンディングボックスが不明な樹木/植生モデルの場合は、すべての境界から12 mの安全バッファーを確保してください。つまり、原点は[12, maxX-12] × [12, maxZ-12]の範囲に配置します。
建築物を配置する際は、現実の縮尺ではなく三人称視点の縮尺を考慮してください。 部屋が大きすぎると、フロアプランに必要な区画の面積が変わるため、境界を決める段階でサイズを調整してください。寸法については、add-3d-models → 「ルール:三人称カメラに合わせて室内を拡大する」を参照してください。
例
| scene.jsonの区画 | parcelsWide | parcelsDeep | 有効なX | 有効なZ |
|---|---|---|---|---|
["0,0"] | 1 | 1 | 0 – 16 | 0 – 16 |
["0,0","1,0"] | 2 | 1 | 0 – 32 | 0 – 16 |
["0,0","1,0","0,1","1,1"] | 2 | 2 | 0 – 32 | 0 – 32 |
明示的なユーザー指示なしにscene.jsonの区画数を変更しないでください
デザインに必要なスペースが区画の範囲を超える場合は、区画を追加するかユーザーに確認してください。 無断で追加したり、確認を避けるためにデザインを圧縮したりしないでください(部屋を縦に積み重ねる、三人称視点の縮尺より小さくするなど)。scene.jsonへの区画の追加は常に可能とは限らず、シーンの公開先によって異なります。Genesis Cityに公開する場合、区画はデプロイに使用するウォレットが所有または賃借している必要があります。Worldに公開する場合は、追加できる可能性があります。ユーザーが断った場合は、既存の区画の境界内で作業し、その範囲で可能な限り豊かなシーンを作成してください。
Composite形式カタログ(リファレンス)
{baseDir}/composite-reference.mdを読み、main.composite JSON形式の完全な仕様を確認してください。JSON構造とjsonSchemaのルール、エンティティIDの割り当て、コンポーネント形式のカタログ(core::Transform、core::GltfContainer、… core::NftShape)、コンポーネントのグループ化パターン、編集モードのルール(inspector::Nodes)、実行時のスポーン、TypeScriptからCompositeエンティティを取得するパターンが記載されています。
検証チェックリスト
Step 1 — モードを検出する。 Compositeからinspector::*、composite::root、またはasset-packs::ActionTypesを検索してください。いずれかが存在する場合は編集モードです。以下の編集モード用チェックリストを使用してください。それ以外の場合は、ゼロから作成する際のチェックリストを使用してください。
スクラッチから作成する際のチェックリスト
新しいコンポジットを作成する前に、次の項目を確認してください。
-
versionが1である -
inspector::*コンポーネントが一切含まれていない —inspector::Nodes、inspector::SceneMetadata(バージョンを問わず)、inspector::Selection、inspector::TransformConfig、inspector::UIStateは含めないでください。これらはすべて Creator Hub によって自動生成されます。新しいファイルに含めると、エンティティツリーが壊れたり、ビルドエラーが発生したりします。 -
composite::rootまたはasset-packs::ActionTypesが含まれていない — エンジンによって自動生成されます - すべてのユーザーエンティティ(512 以上)に
core::Transformとcore-schema::Nameがある - コンポジット内でエンティティ ID が重複していない
- 明示的な ID を指定してコードで作成されたエンティティと、エンティティ ID が重複していない
-
core::コンポーネントにjsonSchemaがない — これは必須要件です。core::コンポーネントに jsonSchema を含めると、Creator Hub がエンティティを正しく解析できなくなります - コア以外のコンポーネント(
asset-packs::*、core-schema::*)にはすべてjsonSchemaがある(カタログからコピー) - すべての
GltfContainer.srcパスがスラッグ化された名前の形式になっている:assets/asset-packs/<slug>/<filename> - 参照されているアセットファイルがすべてディスクにダウンロードされている(GLB、音声、画像)
-
GltfContainerにデフォルトの衝突マスクが設定されている(visibleMeshesCollisionMask: 0、invisibleMeshesCollisionMask: 3) - すべての位置が区画の境界内にある — 境界は Step 0 で実際の
scene.jsonの区画リストから算出済みです。すべてのエンティティの X は[0, maxX]、Z は[0, maxZ]の範囲内です。負の値や maxX/maxZ を超える値はレンダリングされません。ユーザーが「大きな」シーンを指定していても、区画数が変更されていない場合、すべてのエンティティは元の境界内に収まります。 -
GltfContainerエンティティごとに、GLB にアニメーションが含まれているか(ファイル内に埋め込まれたクリップ名)を確認済みです。含まれている場合、そのエンティティにcore::Animatorコンポーネントがあります。アニメーション付きモデルに Animator がないと、最初のクリップが制御手段なしでループ再生されます。 -
GltfContainerエンティティごとに、GLB に衝突メッシュが含まれているか(名前に文字列_colliderを含むメッシュがあるか)を確認済みです。含まれている場合、それらを有効にするためinvisibleMeshesCollisionMaskが3(CL_POINTER + CL_PHYSICS)に設定されています。組み込みコライダーがない場合は、モデルのおおまかな形状を覆うためにcore::MeshColliderのボックスまたは球が必要かどうかを判断済みです(歩行可能な面、壁、クリック可能なオブジェクトなど)。 - コンポジット内のどこかに
asset-packs::Actions、asset-packs::Triggers、またはasset-packs::Statesがある場合、エンティティ 0 にasset-packs::Counterが存在し、そのvalueが Actions/Triggers/States データ内で使用されている最も大きいidに設定されている(これらの ID のアロケーターです) -
{self}、{assetPath}、プレースホルダー文字列がなく、すべて具体的な値に置き換えられている - コンポーネント名に基本名を使用している(例:
asset-packs::Actions。asset-packs::Actions-v1ではありません)。-v3のようなバージョンサフィックスは使用しないでください。 - コアコンポーネントのみを使用するコンポジットには、追加のライブラリは不要です。
asset-packs::*コンポーネントを含む場合、古い SDK ではプロジェクト依存関係として@dcl/asset-packsが必要です。現在の SDK では、@dcl/inspectorに同梱されたコピーが代わりに使用されます
編集モードのチェックリスト(composite にはすでに inspector::* が含まれています)
- Creator Hub MCP は利用できません。 そのツールがセッション内にある場合は、ここで停止してください。以下の項目はすべて
create_entity/set_componentによって処理されます(このスキルの冒頭にあるゲートと creator-hub-mcp を参照)。 - Creator Hub でシーンが現在開かれていないことを、
main.compositeまたはscene.jsonに書き込む前に毎回(セッションごとに一度ではなく)再確認しました。 オーナーはいつでもシーンを再度開けます。Hub が開いている間に書き込んだ区画の変更は、Hub の自動保存によって元に戻されました(2026-10)。インスペクターはメモリー内のエンジンからmain.composite全体を自動保存で上書きし、エラーを出さずに外部の編集を破棄します。書き込む前にシーンを閉じるようユーザーに依頼し、その後、再度開くよう依頼してください。シーンが開いていて MCP を利用できない場合は、停止して確認してください。ユーザーが明示的に選択しない限り、代わりに静的エンティティをsrc/に移動してはいけません(sdk-scenes → Agent Behavioral Guidelines の項目 5 に、シーンが開いていることを示す兆候も記載されています)。
追加する各新規エンティティ <id> について、上記の新規作成時のルールに加えて(inspector::* などは削除せず保持するという緩和条件が適用されます):
-
<id>を、inspector::Nodes.data["0"].json.value内のエンティティ0のエントリーのchildren配列の末尾に追加しました。 - 新しいエントリー
{ "entity": <id>, "children": [...] }をinspector::Nodes.data["0"].jsonのvalue配列の末尾に追加しました(エンティティに子がなければ[]を使用します)。 -
<id>のTransform.parentが0以外の場合、<id>はルートではなく親エンティティのchildren配列に含まれています。 -
core-schema::Name.data["<id>"]に{ "json": { "value": "..." } }エントリーがあります。エンティティをエンティティツリーに正しく表示し、コードから検索できるようにするには、名前が必要です。 -
inspector::TransformConfig.data["<id>"]に{ "json": {} }エントリーがあります(空のオブジェクトで問題ありません)。 -
entity-names.tsは、新しい名前を含めるように更新する(EntityNames内)か、次回の保存時に Creator Hub が再生成できるよう変更せずに残しています。自動生成されたヘッダーを手動で編集してはいけません。 - 既存の
inspector::Nodes、inspector::SceneMetadata-*、inspector::Selection、inspector::TransformConfig、composite::root、asset-packs::ActionTypesを削除または取り除いていません。これらは Creator Hub が管理しており、そのまま残す必要があります。 -
scene.jsonの区画が変更されていない限り、inspector::SceneMetadata-*は変更されていません(変更された場合は、レイアウトブロックがscene.jsonと一致している必要があります)。 - 予約済みエンティティ
1(PlayerEntity)と2(CameraEntity)は、inspector::Nodes内にそれぞれ独立したトップレベルの{ "entity": 1, "children": [] }/{ "entity": 2, "children": [] }エントリーとして引き続き存在しています。これらは独立したツリールートです。エンティティ0のchildren配列(または他のchildren配列)に含めてはいけません。
確認コマンド(編集モード): 編集後、core::Transform.data に存在するすべてのエンティティ ID が、次の両方に現れることを確認してください。
inspector::Nodes.data["0"].json.valueにトップレベルの{ "entity": <id>, ... }エントリーとして存在する。- 同じ
valueリスト内のchildren配列のちょうど 1 つに存在する(親のchildren配列)。
エンティティ 0、1、2 はルートであり、どの children 配列にも現れないため、ルール 2 の例外です。
ここにエントリーがないことが、「エンティティは描画されるのに Creator Hub のエンティティツリーには表示されない」問題の根本原因です。
書き込み後の検証
コンポジットを書き込んだ後、SDK のビルドを実行して検証します。
npx sdk-commands build
ビルドはエラーなしで成功する必要があります。失敗した場合、そのコンポジットは無効です。よくあるエラーは次のとおりです。
Composite references undefined component "X". Ensure provider.schemas was registered pre-seal via setCompositeProvider().(古い SDK/リリース済み SDK では"X is not defined and there is no schema to define it"と表記されます)→ 非コアコンポーネントにjsonSchemaがない、または存在すべきでないinspector::*コンポーネントがある- TypeScript のエラー → 生成されたスクリプトを修正します
- 配布するつもりのないファイルを示すエラー(
Composite 'art/.../before.composite' can't be read、またはバックアップファイルに起因するスキーマエラー)→ ビルドはプロジェクト内のすべての*.compositeを対象にします(sdk-commandsのlogic/composite.ts)。バックアップは別の拡張子(before-composite.jsonなど)を付けるか、プロジェクトの外に保存し、ビルドのデバッグ出力にある.composite:の一覧を確認してください。デプロイの除外ルールでは、ビルド対象からファイルを除外できません。 - 追加した
inspector::*コンポーネントに関するスキーマエラー → inspector コンポーネントを独自に作成しないでください(inspector::TransformConfigはその一例です)。ファイル内にすでにエントリーがある inspector コンポーネントだけを書き、その形を正確にコピーしてください。