mcpField
F
foundry-vtt-module-dev

foundry-vtt-module-dev

github.com/fcsouza開発2446 回インストール1 週間前に更新
リポジトリ

foundry-vtt-module-dev について

Foundry Virtual Tabletop v14以降のモジュール開発・保守を支援するスキルです。構成、ライフサイクル、データモデル、UI、スタイル、移行を扱います。

主な機能

  1. 01v14モジュール構成とマニフェスト
  2. 02初期化ライフサイクルの解説
  3. 03名前空間APIリファレンス
  4. 04ドキュメントモデルとサブタイプ
  5. 05ApplicationV2とCSSスタイル

活用シーン

  1. 01Foundry VTTモジュールの新規作成
  2. 02モジュールのv14 APIへの移行
  3. 03カスタムドキュメント型の追加
  4. 04テーマ対応モジュールUIの実装

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/fcsouza/agent-skills --skill foundry-vtt-module-dev

インストール後、Claude Code で/foundry-vtt-module-devを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

boilerplate/
actor-sheet.mjs
main.mjs
module.json
package.json
rollup.config.mjs
sheet.hbs
socket-handler.mjs
type-data-model.mjs
vite.config.mjs
references/
accessibility.md
active-effects-v2.md
adventure-documents.md
application-v2.md
audio-and-macros.md
build-pipeline.md
canvas-and-pixi.md
chat-and-ui.md
combat-and-tokens.md
document-model.md
handlebars-and-templates.md
hooks-and-settings.md
measured-templates.md
migration-guide.md
module-subtypes.md
permissions-and-ownership.md
regions-and-grid.md
scene-levels.md
sockets-rolls-packs.md
testing-with-quench.md
v14-migration.md

詳細

Foundry VTT モジュール開発

Foundry Virtual Tabletop(v14 以降)向けのモジュールを作成、拡張、保守します。このスキルでは、新しいモジュールのひな形作成から Foundry のバージョン間の移行まで、モジュールのライフサイクル全体を扱います。v13 から移行する場合は、最初に references/v14-migration.md をお読みください。

クイックスタート

モジュールの構成
my-module/
├── module.json          ← manifest (required)
├── scripts/
│   └── main.mjs         ← ES module entry point
├── templates/            ← Handlebars HTML templates
├── styles/               ← CSS stylesheets
├── packs/                ← compendium data
└── lang/
    └── en.json           ← localization strings

出発点として boilerplate/module.json と boilerplate/main.mjs を使用してください。

モジュールマニフェスト(module.json)

すべてのモジュールには、有効な module.json が必要です。v14 の重要なフィールドは次のとおりです。

{
  "id": "my-module",
  "title": "My Module",
  "description": "What this module does.",
  "version": "1.0.0",
  "compatibility": {
    "minimum": "14",
    "verified": "14"
  },
  "documentTypes": { "Actor": { "hero": {} } },
  "authors": [{ "name": "Your Name", "url": "https://github.com/you" }],
  "esmodules": ["scripts/main.mjs"],
  "styles": [{ "src": "styles/my-module.css", "layer": "modules" }],
  "languages": [{ "lang": "en", "name": "English", "path": "lang/en.json" }],
  "socket": true,
  "relationships": {
    "systems": [],
    "requires": [],
    "recommends": []
  }
}
フィールド用途
id一意の識別子。使用できる文字は [A-Za-z0-9_-] のみです。フォルダー名と一致させる必要があります
compatibilityminimum(このバージョン未満では読み込まれません)、verified(テスト済みのバージョン)を指定します。互換性がないことが確認されている場合を除き、maximum は省略してください
documentTypesモジュールが登録するカスタムの Actor/Item/ActiveEffect サブタイプを宣言します。キーは CONFIG.<Doc>.dataModels のキーと一致させる必要があります
esmodulesES モジュールのエントリーポイントです。従来の scripts より常にこちらを優先してください
styles{ src, layer? } オブジェクトの配列です。layer はシートを読み込む CSS カスケードレイヤーの名前です。通常の文字列も引き続き移行されますが、オブジェクトを記述してください
socketモジュールで game.socket.emit/on を有効にするには true に設定します
packsコンペンディウムパック定義の配列です。name は [A-Za-z0-9_-] に一致する必要があります。名前やパスが重複すると、読み込み時にエラーが発生します
relationships.requires他のモジュールやシステムへの必須依存関係です
libraryこのモジュールがユーザー向けではなく共有ライブラリである場合は true に設定します
quickstartv14 で追加されました。{ adventures: { "<id>": { uuid } }, postImport, world: { background, cover, description } } を指定すると、モジュールがクイックスタートとしてマークされ、セットアップ画面からワールドを作成してアドベンチャーをインポートします

v14 での変更点: システムでも template.json は非推奨になりました(v16 まで)。型は documentTypes と TypeDataModel で宣言してください。静的な .html ファイルは text/plain として配信されます。テンプレートは引き続きレンダリングされますが、ブラウザーで直接開くことはできません。

初期化ライフサイクル

モジュールは、順番に実行される 3 つのフックを通じて動作します。エントリーポイントでフックを登録してください。

// init — register settings, sheets, custom document types
// game.user is NOT available yet. Canvas is NOT ready.
Hooks.once("init", () => {
  console.log("my-module | Initializing");
  // Register settings, custom sheets, document types here
});

// setup — packages loaded, documents available, canvas not ready
Hooks.once("setup", () => {
  // Modify CONFIG, register additional features
});

// ready — everything available: game.actors, game.scenes, canvas
Hooks.once("ready", () => {
  console.log("my-module | Ready");
  // Safe to access game.actors, game.scenes, game.user
  // Run migrations, initialize socket listeners
});

CONFIG の追加(CONFIG.statusEffects、CONFIG.ActiveEffect.changeTypes、CONFIG.Canvas.layers)は init で登録してください。v14 以降、game.template はなくなりました。型のデフォルト値は game.model または TypeDataModel のスキーマから読み取ってください。

スタイル設定(CSS カスケードレイヤー)

Foundry は CSS カスケードレイヤー(@layer)を使用します。特異性の競合を避け、Foundry のライト/ダークテーマをサポートできるよう、モジュールの CSS をレイヤーに配置してください。コアでは、レイヤーが次の順序で宣言されています:reset, variables, elements, blocks, applications, compatibility, layouts, system, modules, exceptions。マニフェストで modules を指定すると、styles: [{ "src": "...", "layer": "modules" }]、ルールはコア独自のルールの後、exceptions の前に配置されます。

レイヤー名を独自に作らないでください。コアで宣言されていない名前は exceptions の後に配置され、コアの CSS をすべて上書きします。

modules の下で読み込まれるスタイルシート内にネストした @layer を置くと、そのレイヤー内にネストされます。そのため、@layer my-module { ... } は modules.my-module となり、レイヤー順序内の位置は変わりません。独自のルールをまとめるために使用し、マニフェストのフィールドの代わりにはしないでください。

@layer my-module {
  .my-module .window-content {
    --accent-color: var(--color-warm-2);
    padding: 0.5rem;
  }
}

テーマ設定では、シート上の body.theme-light/body.theme-dark と .themed.theme-<x> を使用します。@layer の名前とその仕組みは v13 から変更されていません。

CSS 変数(テーマ対応スタイル)

Foundry は、ライト/ダークテーマに対応する CSS カスタムプロパティを提供しています。ハードコードされた色よりも、常にこれらを優先してください。

@layer my-module {
  .my-module-panel {
    /* Text */
    color: var(--color-text-primary);
    border: 1px solid var(--color-border);

    /* Accent palette */
    --my-accent: var(--color-warm-2);
    --my-muted: var(--color-cool-4);

    /* Typography */
    font-family: var(--font-primary);
    font-size: var(--font-size-13);
  }
}

主な変数のカテゴリ:

カテゴリ変数
テキスト--color-text-primary, --color-text-secondary, --color-text-emphatic, --color-text-subtle, --color-text-dark-primary, --color-text-dark-secondary, --color-text-hyperlink, --color-text-selection
ボーダー--color-border, --color-border-dark, --color-border-light-1, --color-border-light-2
暖色系アクセント--color-warm-1, --color-warm-2, --color-warm-3
寒色系アクセント--color-cool-3, --color-cool-4, --color-cool-5
グレー--color-dark-1 … --color-dark-6, --color-light-1 … --color-light-6
フォント--font-primary, --font-body, --font-sans, --font-h1, --font-size-13 ~ --font-size-48
カーソル(v14 で追加)--cursor-default, --cursor-pointer, --cursor-grab, --cursor-text(および -down バリアント)
ローカル開発
  1. Foundry のデータパスにモジュールフォルダーを作成します:{userData}/Data/modules/my-module/
  2. またはシンボリックリンクを作成します:ln -s /path/to/your/dev/folder {userData}/Data/modules/my-module
  3. Foundry を起動し、アドオンモジュールに移動して、ワールド内でモジュールを有効にします
  4. ブラウザーのコンソール(F12)を開いて、ログとエラーを確認します

名前空間(foundry.*)

v13 以降、コア API のほぼすべてが foundry.* 名前空間に置かれています。レガシーなグローバル名も非推奨化用シムを通じて引き続き解決されますが、v15 で削除され(appv1 フレームワークは v16 で削除)、v14 ではすでに v12 時代のシムが削除されています。mergeObject、getProperty、Die、DiceTerm、Math.clamped、CONST.DOCUMENT_TYPES などの裸の名前は使えません。新しいファイルではすべて名前空間付きのパスを使用し、既存のファイルも編集する際に更新してください。

レガシーなグローバル名(v12 以前)名前空間付きのパス
Application, FormApplicationfoundry.appv1.api.Application (代わりに V2 を使用)
Dialogfoundry.appv1.api.Dialog (DialogV2 を使用)
ApplicationV2foundry.applications.api.ApplicationV2
HandlebarsApplicationMixinfoundry.applications.api.HandlebarsApplicationMixin
DialogV2foundry.applications.api.DialogV2
DocumentSheetV2foundry.applications.api.DocumentSheetV2
ActorSheetV2, ItemSheetV2foundry.applications.sheets.ActorSheetV2 / .ItemSheetV2
Hooksfoundry.helpers.Hooks (グローバルの Hooks も引き続きエイリアスとして使用可能)
Canvas, CanvasLayerfoundry.canvas.Canvas, foundry.canvas.layers.CanvasLayer
Token, Tile, Region(オブジェクト)foundry.canvas.placeables.*(MeasuredTemplate は v14 以降非推奨です。Region を使用してください)
Document, DataModel, TypeDataModelfoundry.abstract.Document, foundry.abstract.DataModel, foundry.abstract.TypeDataModel
fields.*(NumberField など)foundry.data.fields.*
Roll, DiceTerm, Diefoundry.dice.Roll, foundry.dice.terms.Die
Actors, Items(コレクション)foundry.documents.collections.Actors / .Items
loadTemplates, renderTemplatefoundry.applications.handlebars.loadTemplates / .renderTemplate
(レガシーなエイリアスなし)foundry.applications.fields.* — createFormGroup、createSelectInput、createCheckboxInput、createNumberInput、createTextInput、createTextareaInput、createMultiSelectInput、createEditorInput、setInputAttributes
(レガシーなエイリアスなし)foundry.applications.ux.* — Tabs、ContextMenu、DragDrop、Draggable、FormDataExtended、HTMLSecret、ProseMirrorEditor、SearchFilter、TextEditor
mergeObject, duplicate, debounce, isNewerVersionfoundry.utils.*(v14 で裸のグローバル名は削除されています。mergeObject、deepClone、expandObject、flattenObject、getProperty、setProperty、hasProperty、diffObject、equals(objectsEqual の代替)、getType、isEmpty、isNewerVersion、randomID、debounce、throttle、benchmark、parseUuid、buildUuid、buildRelativeUuid、escapeHTML、formatFileSize など)
(レガシーなエイリアスなし)foundry.data.operators.* — ForcedDeletion、ForcedReplacement(グローバルの _del、_replace)は、更新キー -= / == の代わりに使用します

更新する理由は? 残りのシムは v15 で削除される予定です(appv1 は v16)。名前空間付きのパスを使って書いたコードは将来も互換性がありますが、レガシーなグローバル名を使って書いたコードは、いつ使えなくなってもおかしくありません。

簡単な分割代入のパターン:

const { ApplicationV2, HandlebarsApplicationMixin, DialogV2 } = foundry.applications.api;
const { ActorSheetV2 } = foundry.applications.sheets;
const fields = foundry.data.fields;

各ファイルの先頭でこれらを使用すると、ファイルの残りの部分を自然に記述できます。


Document モデル

Foundry のデータレイヤーは、DataModel と Document を基盤としています。モジュールはこれを拡張して、カスタム Actor タイプや Item タイプを作成したり、構造化データを保存したりできます。

基本パターン: 型付きフィールドを含むスキーマを定義 → init 中に CONFIG に登録 → Foundry が永続化、検証、同期を処理します。

class HeroData extends foundry.abstract.TypeDataModel {
  static defineSchema() {
    const fields = foundry.data.fields;
    return {
      health: new fields.NumberField({ required: true, initial: 100, min: 0 }),
      class: new fields.StringField({ required: true, initial: "fighter" }),
      abilities: new fields.SchemaField({
        strength: new fields.NumberField({ initial: 10 }),
        dexterity: new fields.NumberField({ initial: 10 }),
      }),
      inventory: new fields.ArrayField(new fields.StringField()),
    };
  }

  prepareDerivedData() {
    this.maxHealth = this.health + this.abilities.strength * 2;
  }
}

// Register in init hook
Hooks.once("init", () => {
  CONFIG.Actor.dataModels.hero = HeroData;
});

フラグは、あらゆるドキュメントに付与できるモジュール名前空間付きのメタデータです。安全で、モジュールをアンインストールしても保持されます。

await actor.setFlag("my-module", "customData", { tracked: true });
const data = actor.getFlag("my-module", "customData");
await actor.unsetFlag("my-module", "customData");

v14 での変更 — 更新演算子。 "-=key": null および "==key": value の更新構文は非推奨です(v16 まで)。foundry.data.operators(グローバル変数 _del および _replace)を使用してください。

await actor.update({ "system.inventory": _del });                 // delete the key
await actor.update({ "system.abilities": _replace({ str: 12 }) }); // replace without merging

ActiveEffect は型付きドキュメントになりました(type + system。サブタイプは documentTypes.ActiveEffect 経由)。その changes は system.changes に格納されます。詳しくは Active Effects のセクションを参照してください。DataField#migrateSource は _migrate(value, options, _state) に変更され、migrateData はデータを返す必要があります。

フィールドタイプの全リファレンス、ライフサイクルフック(_preCreate、_onCreate、_preUpdate、_onUpdate、_preDelete、_onDelete)、埋め込みドキュメントの管理、複数ドキュメントへのアトミックな書き込みを行う foundry.documents.modifyBatch()、フラグとモデルフィールドの使い分けについては、references/document-model.md を参照してください。

モジュールのサブタイプ

モジュールは、あらゆるシステムで動作するあらゆるワールドに、カスタムの Actor、Item、JournalEntryPage、その他のドキュメントサブタイプを追加できます。v11 以降、公式にサポートされている拡張メカニズムです。

必要な要素は 3 つあります。module.json の documentTypes 内で宣言し(htmlFields と filePathFields を含めます)、自動付与されるプレフィックス付きキー(my-module.vehicle)で CONFIG.<Doc>.dataModels に TypeDataModel を登録し、プレフィックス付きタイプのシートを登録します。モジュールをアンインストールしてもユーザーが困らないよう、必ず変換手段を用意してください。

宣言の構文、無効化時の動作、変換マクロ、注意点については、references/module-subtypes.md を参照してください。


アプリケーションフレームワーク(v2)

すべての UI で ApplicationV2 を使用します。レガシーの Application クラスおよび FormApplication クラス(foundry.appv1)は非推奨で、v16 で削除される予定です。

標準的なパターン: テンプレートを使用するウィンドウには HandlebarsApplicationMixin(ApplicationV2) を継承します。アクターシート/アイテムシートには、foundry.applications.sheets の ActorSheetV2/ItemSheetV2 を使用します。これらは DocumentSheetV2 を継承し、ドキュメント固有のドラッグ&ドロップとトークン管理を追加します。

const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;

class MySheet extends HandlebarsApplicationMixin(ApplicationV2) {
  static DEFAULT_OPTIONS = {
    id: "my-sheet",
    classes: ["my-module"],
    window: { title: "My Sheet", resizable: true },
    position: { width: 500, height: 400 },
    actions: {
      rollDice: MySheet.#onRollDice,
    },
  };

  static PARTS = {
    main: { template: "modules/my-module/templates/sheet.hbs" },
  };

  async _prepareContext(options) {
    return { name: "Hello Foundry" };
  }

  static async #onRollDice(event, target) {
    const roll = new Roll("1d20");
    await roll.evaluate();
    await roll.toMessage({ flavor: "Ability Check" });
  }
}

v14 の新機能 — 分離ウィンドウ。 すべての ApplicationV2 には、デフォルトで「分離」/「再接続」のヘッダーコントロール(DEFAULT_OPTIONS.window.controls)が追加されます。app.detachWindow() はアプリを独立したブラウザーウィンドウに移動し、app.attachWindow() は元のウィンドウに戻します。app.renderChild(child) は同じウィンドウ内に別のアプリをレンダリングします。各切り替え時に openDetachedWindow(id, win)/closeDetachedWindow(id, win) フックが実行されます。ドキュメント間の移動後も維持する必要があるカスタム要素は、foundry.applications.elements.AdoptableHTMLElement を継承してください。

v14 の新機能 — レンダーフックとフレームボタン。 _preRender(context, options) は _prepareContext の後、フレームとパーツのレンダリング前に実行されます。クラスチェーン内の各クラスに対して preRender<ClassName> フックを呼び出します。_getFrameButtons(options) は追加のヘッダーボタン({ icon, label, action, visible? }。ヘッダーコントロールと同じ形式で、現在は label/visible/onClick を使用します。name/condition/callback は非推奨です)を返します。DialogV2.wait({ renderOptions }) は、ダイアログのレンダー呼び出しにオプションを渡します。

DocumentSheetV2、DialogV2、パーツシステム、アクションハンドラー、フォーム送信については、references/application-v2.md を参照してください。ドラッグ&ドロップの詳細、非同期処理/競合パターン、デバウンス戦略については、同じファイルの「Drag & Drop Deep Dive」および「Async Patterns」セクションを参照してください。

Foundry のカスタム Handlebars ヘルパー({{localize}}、{{selectOptions}}、{{formInput}}、{{formGroup}}、{{editor}} など。{{select}} と {{colorPicker}} は v14 で削除されました)、カスタム HTML 要素(<prose-mirror>、<file-picker>、<color-picker>、<string-tags>、および v14 の <formula-input> と <autocomplete-tags>)、それらをヘルパーより優先すべき場合、カスタムヘルパー/パーシャルの登録、テンプレートの事前読み込み、一般的なシートのパターンについては、references/handlebars-and-templates.md を参照してください。リッチテキストは ProseMirror のみです。TinyMCE と CONFIG.TinyMCE は廃止されました。

シートとダイアログは HTML です。ARIA ロール、キーボード操作、フォーカス管理、および prefers-reduced-motion への対応を加えてください。references/accessibility.md を参照してください。


フックと設定

フックは Foundry のイベントシステムです。設定には、ワールド単位またはクライアント単位のモジュール設定が保存されます。

// Document lifecycle hooks — fire for every Actor/Item/etc CRUD operation
Hooks.on("createActor", (actor, options, userId) => {
  console.log(`Actor ${actor.name} created by user ${userId}`);
});

Hooks.on("preUpdateItem", (item, changes, options, userId) => {
  // Return false to cancel the update
  if (changes.name === "forbidden") return false;
});

// Settings — register in init, use anywhere after
Hooks.once("init", () => {
  game.settings.register("my-module", "difficulty", {
    name: "Difficulty Level",
    hint: "Adjusts the challenge rating of encounters.",
    scope: "world",       // GM-set, all players see same value
    config: true,         // show in settings menu
    type: String,
    choices: { easy: "Easy", normal: "Normal", hard: "Hard" },
    default: "normal",
    onChange: (value) => console.log("Difficulty changed to", value),
  });
});

// Read a setting
const diff = game.settings.get("my-module", "difficulty");

v14 の新しいフック: preRender<App>(app, context, options)、openDetachedWindow/closeDetachedWindow(id, win)、Placeables サイドバータブ用の get<DocumentName>PlaceableContextOptions(app, menuItems)、dropItemSheetData(item, sheet, data)、planToken(document)。削除されたフックはありません。jQuery を使う renderChatMessage は引き続き非推奨で、代わりに renderChatMessageHTML(message, html, context) を使用してください。renderChatMessage は v15 で削除されます。

v14 で変更 — コア設定: core.rollMode は非推奨の互換用設定です。game.settings.get("core", "messageMode")(public | gm | blind | self | ic)を参照してください。core.gridTemplates と core.coneTemplateType は、MeasuredTemplates とともに非推奨になりました。

フックのライフサイクル全体、ドキュメントフックの命名規則、キャンバスフック、Hooks.callAll と Hooks.call の違い、設定サブメニュー、scope: "world" と scope: "client" の違いについては、references/hooks-and-settings.md を参照してください。


高度なパターン

ソケット(GM が権限を持つ方式)

非 GM クライアントは、ワールドドキュメントを直接変更できません。パターンは、クライアントがリクエストを送信し、GM クライアントがそれを受け取って変更を実行し、その結果をブロードキャストする、というものです。

// Requires "socket": true in module.json
const SOCKET_NAME = "module.my-module";

// GM listens and executes
Hooks.once("ready", () => {
  game.socket.on(SOCKET_NAME, async (data) => {
    if (!game.user.isGM) return;
    if (data.type === "updateActor") {
      const actor = game.actors.get(data.actorId);
      await actor.update(data.changes);
    }
  });
});

// Any client requests
function requestActorUpdate(actorId, changes) {
  if (game.user.isGM) {
    return game.actors.get(actorId).update(changes);
  }
  game.socket.emit(SOCKET_NAME, { type: "updateActor", actorId, changes });
}
ダイスロール
const roll = new Roll("2d6 + @mod", { mod: 3 });
await roll.evaluate();       // ALWAYS await — roll() is only an async alias of evaluate()
await roll.toMessage({ flavor: "Damage Roll" });
console.log(roll.total);     // e.g. 11

// Visibility: pass a messageMode (a key of CONFIG.ChatMessage.modes)
await roll.toMessage({ flavor: "Secret" }, { messageMode: "gm" });
await roll.toMessage({ flavor: "Uses the chat dropdown" },
  { messageMode: game.settings.get("core", "messageMode") });

// Use getRollData() on actors to expose system data to roll formulas
const rollData = actor.getRollData(); // { abilities: { str: 16, ... }, health: 50, ... }
const abilityRoll = new Roll("1d20 + @abilities.str", rollData);

v14 で変更 — ロールモードはメッセージモードになりました。 Roll#toMessage、ChatMessage.create、RollTable#draw、Combat#rollInitiative の rollMode(publicroll、gmroll、blindroll、selfroll)は非推奨です。public | gm | blind | self | ic の messageMode を使用してください。CONFIG.Dice.rollModes は CONFIG.ChatMessage.modes に、ChatMessage#applyRollMode は applyMode に置き換えられました。古い値は Roll._mapLegacyRollMode(rollMode) で変換してください。チャットコマンドは ChatLog.CHAT_COMMANDS に登録します(MESSAGE_PATTERNS は非推奨です)。

コンペンディウムパック
const pack = game.packs.get("my-module.monsters");
const docs = await pack.getDocuments();
const dragon = await pack.getDocument("some-id");
await game.actors.importFromCompendium(pack, "some-id");
ローカライズ
// lang/en.json: { "MY_MODULE.greeting": "Hello, {name}!" }
game.i18n.localize("MY_MODULE.greeting");              // "Hello, {name}!"
game.i18n.format("MY_MODULE.greeting", { name: "GM" }); // "Hello, GM!"

v14 では game.i18n.localize にバインドされた _loc グローバルが追加され、localize(id, data) でプレースホルダーもフォーマットされるようになりました。game.i18n.localize は非推奨ではありません。_loc は省略形です。

ソケットのパターン、カスタム DiceTerm、Roll.RESOLVERS、コンペンディウムのクエリ、fromUuid()、ローカライズの設定について詳しくは、references/sockets-rolls-packs.md をお読みください。


キャンバス拡張

PIXI.js を使用してカスタムレイヤーや配置可能オブジェクトを追加し、Foundry キャンバスを拡張します。

const { CanvasLayer } = foundry.canvas.layers;

class MyLayer extends CanvasLayer {
  static get layerOptions() {
    return foundry.utils.mergeObject(super.layerOptions, { name: "myLayer" });
  }

  async _draw(options) {
    // Add PIXI children here
  }

  async _tearDown(options) {
    this.removeChildren().forEach(c => c.destroy());
  }
}

// Register in init
Hooks.once("init", () => {
  CONFIG.Canvas.layers.myLayer = { layerClass: MyLayer, group: "primary" };
});

レイヤークラスを差し替える場所は CONFIG.Canvas.layers のみです。v14 以降、CONFIG.<Doc>.layerClass(CONFIG.Token.layerClass など)は非推奨のプロキシです。代わりに CONFIG.Canvas.layers.tokens.layerClass = MyTokenLayer と記述してください。

Scene Levels(v14 で追加)。 Scene には Level ドキュメントの埋め込みコレクション(scene.levels、scene.initialLevel、表示中のレベルを示す canvas.level)が保持されます。背景、前景、フォグのテクスチャは Scene から Level に移動しました(level.background.src、level.foreground.src、level.elevation.{bottom,top})。scene.background、scene.foreground、scene.foregroundElevation、scene.backgroundColor は非推奨のゲッターです。配置可能な各ドキュメントには levels セットがあります。トークンには level と depth があります。非推奨の getDocuments() の代わりに、layer.viewedDocuments()(Level を考慮)を反復処理してください。references/scene-levels.md をお読みください。

テンプレートは Regions に置き換えられました。 MeasuredTemplateDocument、TemplateLayer、Scene#templates は非推奨です(v16 まで)。RegionDocument#shapes では、circle、cone、ellipse、emanation、grid、line、polygon、rectangle、ring、token の各シェイプを使用できます。インタラクティブな配置には canvas.regions.placeRegion(data, { create }) を使用し、canvas.regions.templateMode で切り替えます。

const region = await canvas.regions.placeRegion({
  name: "Fireball",
  shapes: [{ type: "circle", x: 0, y: 0, radius: canvas.dimensions.distancePixels * 20 }],
  levels: [canvas.level.id],
  displayMeasurements: true,
});

RegionDocument.createTokenEmanation(token, range, regionData) は、トークンに紐付いたオーラ(attachment.token)を作成します。region.spawnTokens() / region.teleportTokens() はトークンをリージョン内に移動します。references/measured-templates.md の「Templates with Regions」と、references/regions-and-grid.md をお読みください。

Placeables サイドバーとパレット。 v14 では Placeables サイドバータブ(ui.placeables、foundry.applications.sidebar.tabs.PlaceableDirectory)が追加されました。ドキュメントタイプごとにタブがあり(CONFIG.<Doc>.sidebar = { applicationClass, order })、フック get<DocumentName>PlaceableContextOptions を利用できます。Placeable の設定は foundry.applications.sheets.PlaceableConfig を拡張します。

VFX(実験的)。 foundry.canvas.vfx には VFXEffect とコンポーネントが含まれています。CONFIG.Canvas.vfx.enabled = true にするまで無効であり、API は今後変更される可能性があります。foundry.canvas.animation.ParticleGenerator は ParticleEffect / PrimaryParticleEffect に置き換わるものです(v16 まで非推奨)。CanvasShakeEffect は画面を揺らし、Scene#transition はシーンの遷移を制御します(CONFIG.Canvas.sceneTransitions)。

ほとんどのモジュールでキャンバス拡張は必要ありません。カスタムレイヤー、PlaceableObject のサブクラス、座標変換、CanvasAnimation.animate()、PIXI のパフォーマンスに関するヒントについては、references/canvas-and-pixi.md をお読みください。

バンドル済みの JS ライブラリ

Foundry には、以下のライブラリがあらかじめ読み込まれています。インストールもインポートも不要です。

ライブラリグローバル用途参照先
HandlebarsHandlebarsシート/ダイアログ/チャット向けの HTML テンプレートreferences/handlebars-and-templates.md
PixiJSPIXIWebGL キャンバスの描画。トークン、ライティング、シーンを支えるエンジンです(7.4.3 に固定)references/canvas-and-pixi.md
anime.js(v14 で追加)animejsトゥイーン/タイムラインアニメーションライブラリ。animejs ^4.3.6 は globalThis.animejs として公開されています—
GSAP (GreenSock)gsapCSS や CanvasAnimation では実現できない、協調的な UI/キャンバスアニメーションreferences/canvas-and-pixi.md の「GSAP」セクション
jQuery$, jQueryアプリ v1 と旧式の renderChatMessage フック用に引き続きバンドルされています(^3.7.1)。旧式のため、ネイティブ DOM API を使用してくださいreferences/migration-guide.md

適している場合はこれらを使用し、対応できない場合にのみ npm 依存関係を導入してください。


開発ツールとエコシステム

公式 CLI(@foundryvtt/foundryvtt-cli)
npm install -g @foundryvtt/foundryvtt-cli

公式 CLI(fvtt コマンド)は、コンペンディウムの管理に使用します。LevelDB パックを個別の JSON/YAML ファイルに展開し、再パッケージ化できます。コンペンディウムのコンテンツをバージョン管理するうえで不可欠です。

fvtt package workon my-module          # set active package context
fvtt package extract --type Module     # extract compendium to JSON files
fvtt package pack --type Module        # repackage JSON back to LevelDB
TypeScript(@league-of-foundry-developers/foundry-vtt-types)

Foundry VTT API 全体を対象とした、コミュニティ保守の型定義です。型付けされた game、CONFIG、Hooks、およびすべてのコアクラスを提供します。

npm add -D fvtt-types@github:League-of-Foundry-Developers/foundry-vtt-types#main
// tsconfig.json
{
  "compilerOptions": {
    "types": ["fvtt-types"],
    "target": "esnext",
    "moduleResolution": "bundler",
    "strict": true
  }
}

型定義を利用する前に、リポジトリで v14 対応状況を確認してください。v14 のスキーマ変更(ActiveEffect の system.changes、Scene Levels、Regions の構造、messageMode)への対応が、コアに追いついていない可能性があります。型定義がない場合は、型アサーションを使って先に進んでください。

ランタイム:Node 24

v14 サーバーには Node >=24.13.1 <25.0.0 が必要です(v13 では Node 20~22 が必要で、両者に互換性はありません)。ローカル開発、CI、Foundry ホストの環境を一致させるため、ビルドツールにも同じ Node を使用してください。

ビルドツール(Vite/Rollup)

Foundry モジュールは標準的なウェブアプリです。TypeScript のコンパイル、SCSS、npm 依存関係、バンドルには、Vite(推奨)または Rollup を使用してください。ソースは src/ に配置し、出力先は dist/ とします。dist/ は Foundry の Data/modules/<id>/ にシンボリックリンクします。

Foundry 固有の制約は 1 つだけです。アセットのハッシュ化は使用できません。Foundry は module.json に指定された固定パスでファイルを参照するため、出力ファイル名に [hash] を含めるとマニフェストが機能しなくなります。JS、CSS、コピーしたアセットのハッシュ化を無効にしてください。

boilerplate/ には、Foundry 向けに設定済みですぐ使える vite.config.mjs、rollup.config.mjs、package.json が含まれています。開発用のポート 30000 へのプロキシ、固定名での出力、テンプレート/言語ファイル/マニフェスト用のコピープラグイン、ソースマップ、ウォッチモードが設定されています。

(プロジェクト構成、開発ループ、flags.hotReload との連携、本番ビルド、ビルド前のマニフェスト注入、注意点を含む)完全なガイドについては、references/build-pipeline.md を参照してください。

リアクティブフレームワーク(Svelte/Lit)

ApplicationV2 では、Handlebars の代わりにリアクティブフレームワークを簡単にマウントできます。複雑なモジュール UI では、仮想 DOM によるオーバーヘッドがないため、コミュニティでは Svelte が好まれています。_renderHTML() をオーバーライドしてフレームワークをマウントし、_onClose() をオーバーライドして破棄してください。

モジュールテンプレート

League of Foundry Developers は、Vite、TypeScript、ESM をあらかじめ設定したスターターテンプレートを管理しています。GitHub で League-of-Foundry-Developers/FoundryVTT-Module-Template を参照してください。

Foundry への公開

https://foundryvtt.com/packages/submit からモジュールを提出してください。GitHub Releases を使用する場合、マニフェスト URL とダウンロード URL は次のパターンに従う必要があります。

manifest:  https://github.com/you/my-module/releases/latest/download/module.json
download:  https://github.com/you/my-module/releases/download/v1.0.0/module.zip

manifest URL は常に latest を指し、Foundry が更新を自動検出できるようにします。download URL はバージョン指定で、Foundry はこれを使用して特定のリリースをインストールします。

リリースを自動化するための最小限の GitHub Actions ワークフロー:

name: Release
on:
  push:
    tags: ["v*"]
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: zip -r module.zip module.json scripts/ templates/ styles/ lang/ packs/
      - uses: softprops/action-gh-release@v2
        with:
          files: module.zip
          generate_release_notes: true

git tag v1.0.0 && git push --tags でリリースにタグを付けると、ワークフローが実行されます。タグを付ける前に module.json のバージョンを更新してください。

Tours API

UI 要素を強調表示し、機能を順を追って案内する、対話型のガイド付きツアーです。ツアーは JSON ファイルで定義し、game.tours.register() を介して登録します。

modules/my-module/tours/welcome.json にツアー JSON ファイルを作成します。

{
  "title": "MY_MODULE.Tour.welcome.title",
  "description": "MY_MODULE.Tour.welcome.description",
  "canBeResumed": false,
  "display": true,
  "steps": [
    {
      "id": "step1",
      "title": "MY_MODULE.Tour.welcome.step1",
      "content": "MY_MODULE.Tour.welcome.step1Content",
      "selector": ".my-module-panel .header"
    },
    {
      "id": "step2",
      "title": "MY_MODULE.Tour.welcome.step2",
      "content": "MY_MODULE.Tour.welcome.step2Content",
      "selector": ".my-module-panel button[data-action='roll']"
    },
    {
      "id": "step3",
      "title": "MY_MODULE.Tour.welcome.step3",
      "content": "MY_MODULE.Tour.welcome.step3Content",
      "selector": ".my-module-panel .inventory"
    }
  ]
}

setup フックで登録します。

Hooks.once("setup", async () => {
  game.tours.register(
    "my-module",
    "welcome",
    await foundry.nue.Tour.fromJSON("/modules/my-module/tours/welcome.json")
  );
});

// Start programmatically (e.g., on first module load)
Hooks.once("ready", async () => {
  if (!game.settings.get("my-module", "tourCompleted")) {
    await game.tours.get("my-module.welcome").start();
    await game.settings.set("my-module", "tourCompleted", true);
  }
});

各ステップでは、selector を介して DOM 要素を強調表示します。sidebarTab フィールド(任意)を指定すると、ステップの前にサイドバーのタブが自動的に切り替わります。ステップでは、ツールチップの配置を指定する tooltipDirection(UP、DOWN、LEFT、RIGHT)を定義できます。

テスト(@ethaks/fvtt-quench)

Foundry 環境内で実行される、Mocha/Chai を使用したゲーム内テストフレームワークです。Foundry の API には初期化済みのゲーム状態が必要なため、テストにはこのフレームワークが必要です。quenchReady フックでテストバッチを登録します。Quench が有効な場合にのみテストファイルを遅延インポートし、本番バンドルが肥大化しないようにします。バッチ登録のパターン、ドキュメント/シート/フック/ロールのテストレシピ、Quench(手動)と純粋なヘルパーの単体テスト(GitHub Actions の Vitest)を分ける CI 戦略については、references/testing-with-quench.md を参照してください。

コミュニティライブラリ
ライブラリ用途使用する場面
libWrapperFoundry コアメソッドを安全にモンキーパッチするコアの動作を変更するとき(例:Token.prototype.draw)。モジュール間の競合を防ぎます
socketlibクライアント間の通信を簡素化する生の game.socket を使うより簡単な方法です。プレイヤークライアントから GM の応答を await できます
Developer Modeモジュールごとに統一されたデバッグフラグを設定するUI からモジュールごとに切り替えられる構造化ログ
モジュール API パターン

他のモジュールが連携できるように、公開 API を提供します。

Hooks.once("init", () => {
  game.modules.get("my-module").api = {
    getHeroData: (actorId) => game.actors.get(actorId)?.system,
    rollAbility: async (actorId, ability) => { /* ... */ },
  };
});

他のモジュールからは、game.modules.get("my-module")?.api?.getHeroData(id) を介してアクセスできます。

デバッグ
  • ブラウザーの DevTools(F12) — 主なデバッグツール
  • CONFIG.debug.hooks = true — すべてのフック呼び出しをコンソールに記録します
  • ui.notifications.info/warn/error() — テスト用のゲーム内フィードバック
  • Developer Mode モジュール — モジュールごとのデバッグフラグの切り替え

アクティブエフェクト

ActiveEffect は、ドキュメントデータを一時的に変更するための Foundry のシステムです。バフ、デバフ、状態、ステータス効果などが該当します。Actor と Item に埋め込みドキュメントとして保存されます。

v14 での変更 — ActiveEffect V2。 ActiveEffect は型付きドキュメントです。変更内容はルートの changes 配列から system.changes に移され、foundry.data.ActiveEffectTypeDataModel で定義されます。各変更内容は { key, type, value, phase, priority } です。

await actor.createEmbeddedDocuments("ActiveEffect", [{
  name: "Blessed",
  img: "icons/svg/angel.svg",
  type: "base",
  system: {
    changes: [{ key: "system.abilities.str", type: "add", value: 2, phase: "initial" }]
  },
  duration: { value: 10, units: "rounds", expiry: "turnStart" }
}]);

// Toggle an effect
const effect = Array.from(actor.allApplicableEffects()).find(e => e.name === "Blessed");
await effect.update({ disabled: !effect.disabled });
フィールドv13v14
変更内容ルートの changes: [...]system.changes: [...]
変更操作数値の mode(CONST.ACTIVE_EFFECT_MODES)文字列の type(CONST.ACTIVE_EFFECT_CHANGE_TYPES)
アイコンiconimg
持続時間{ rounds, turns, seconds, startTime, startRound }{ value, units, expiry, expired } と、別個の start スキーマ
OriginStringFieldDocumentUUIDField({ relative: true })
アイコン表示overlay ブール値showIcon(CONST.ACTIVE_EFFECT_SHOW_ICON.NEVER | CONDITIONAL | ALWAYS)

migrateData は読み込み時に古いドキュメントを変換するため、v13 のデータも引き続き使用できます。ただし、新しい形式で書き込んでください。

変更タイプ(CONST.ACTIVE_EFFECT_CHANGE_TYPES。既定の優先度とともに記載):custom(0)、multiply(10)、add(20)、subtract(20)、downgrade(30)、upgrade(40)、override(50)。add と subtract は文字列の連結や、配列および Set への追加・削除にも対応します。パッケージは CONFIG.ActiveEffect.changeTypes({ label, defaultPriority, handler, render })に独自のタイプを登録でき、任意の type 文字列も使用できます。認識されないタイプは無視されます。

フェーズ。 CONST.ACTIVE_EFFECT_CHANGE_PHASES は ["initial", "final"] です。コアは派生データの前に actor.applyActiveEffects("initial") を、後に applyActiveEffects("final") を呼び出します。追加のフェーズは CONFIG.ActiveEffect.phases に登録し、自分で applyActiveEffects("myPhase") を呼び出してください。それ以外の処理は行われません。

持続時間と期限切れ。 duration.units は CONST.ACTIVE_EFFECT_DURATION_UNITS(years、months、days、hours、minutes、seconds、rounds、turns)のいずれかです。duration.expiry は CONST.ACTIVE_EFFECT_EXPIRY_EVENTS(combatStart、roundStart、turnStart、combatEnd、roundEnd、turnEnd)のいずれか、または CONFIG.ActiveEffect.expiryEvents に追加したキーです。ActiveEffect.registry は期限切れ待ちの効果を追跡します。CONFIG.ActiveEffect.expiryAction(既定値は "update")によって、期限切れ時に duration.expired を設定するか、効果を削除するかが決まります。カスタムの期限切れイベントは ActiveEffect.registry.refresh() を通じて発火します。

変更タイプの適用方法を変えるには、ActiveEffect サブクラスの静的メソッド _applyChangeUnguided、_applyChangeAdd、_applyChangeSubtract、_applyChangeMultiply、_applyChangeOverride、_applyChangeUpgrade、_applyChangeCustom をオーバーライドしてください。古いインスタンスメソッド(apply、_applyAdd など)は v16 まで非推奨です。

CONFIG.ActiveEffect.legacyTransferral は廃止されました。アイテムの効果は常にアイテム上に保存され、allApplicableEffects() を通じて読み取られます。

サブタイプ、レジストリ、コンペンディウムに保存された効果、変更処理パイプライン全体については、references/active-effects-v2.md を参照してください。

グローバルステータス効果

CONFIG.statusEffects はステータス ID をキーとする Proxy です。ID を指定して割り当てます。

Hooks.once("init", () => {
  CONFIG.statusEffects["my-module.burning"] = {
    id: "my-module.burning",
    name: "MY_MODULE.Effect.burning",
    img: "modules/my-module/icons/burning.svg",
    system: {
      changes: [{ key: "system.abilities.dex", type: "subtract", value: 2 }]
    }
  };
});

push() も引き続き使用できますが、ID を指定して割り当ててください。既存の項目が適切に置き換えられます。パレット全体を置き換えるシステムでは、引き続き配列を割り当てることもできます。

すべての効果を取得する

actor.effects に含まれるのは、Actor に直接設定された効果のみです。Item から転送された効果を取得するには、allApplicableEffects() が必要です。

for (const effect of actor.allApplicableEffects()) {
  console.log(effect.name, effect.disabled, effect.isTemporary);
}

// Categorize for sheet display
function prepareActiveEffectCategories(effects) {
  const categories = {
    temporary: { label: "Temporary", effects: [] },
    passive:   { label: "Passive", effects: [] },
    inactive:  { label: "Inactive", effects: [] }
  };
  for (const e of effects) {
    if (e.disabled) categories.inactive.effects.push(e);
    else if (e.isTemporary) categories.temporary.effects.push(e);
    else categories.passive.effects.push(e);
  }
  return categories;
}

// Usage in _prepareContext
context.effects = prepareActiveEffectCategories(actor.allApplicableEffects());

主なプロパティ:e.disabled(非アクティブ)、e.isTemporary(duration.expiry が設定されている場合、または duration.value が有限の場合に true。v14 で対象が拡大されました)、e.showIcon(トークン上のアイコン表示)。


アドベンチャードキュメント

Adventure は、キャンペーンモジュール、ワンショット、エンカウントパックなどの既製コンテンツを配布するための、Foundry 公式のドキュメントタイプです。1つのアドベンチャーに、シーン、アクター、アイテム、ジャーナル、テーブル、マクロ、プレイリスト、カード、およびそれらを整理するフォルダー階層をまとめられます。ユーザーはすべてをワンクリックでインポートできます。

// Programmatic import (selective)
const pack = game.packs.get("my-module.starter-adventure");
const adventure = await pack.getDocument("adventureDocId");

// Preview before committing
const data = await adventure.prepareImport();

// Import — all collections by default, opt out per collection
await adventure.import({ scenes: false });

module.json で type: "Adventure" としてパックを宣言します。ワールド内でコンテンツを作成し、fvtt package pack でビルドして、packs/ に格納します。再インポート時に正しく更新されるよう、すべての場所で安定した ID を使用してください。

作成の流れ、プログラムからのインポート、バージョン更新、preImportAdventure フック、注意点(ID の重複、シーンのサムネイル、マクロの権限、プレイリストのパス)については、references/adventure-documents.md をお読みください。


権限と所有権

Foundry の権限モデルには、独立した2つの要素があります。ユーザーのロール(ゲーム全体の権限。USER_ROLES.PLAYER から GAMEMASTER まで)と、ドキュメントの所有権(ドキュメントごとのアクセス権。OWNERSHIP_LEVELS.NONE から OWNER まで)です。変更が許可されるのは、両方のチェックに合格した場合のみです。

// UI-level check (gate a button)
if (actor.canUserModify(game.user, "update")) { /* show edit UI */ }
if (actor.testUserPermission(game.user, "OBSERVER")) { /* show sheet */ }

// Granular permission (GM-configurable thresholds per role)
if (game.user.hasPermission("ACTOR_CREATE")) { /* show "New" button */ }

// Set ownership programmatically
await actor.update({ "ownership.default": 2, [`ownership.${player.id}`]: 3 });

埋め込みドキュメントのデフォルトは ownership: { default: -1 }(親から継承)です。プレイヤーは、自分が所有していないワールドドキュメントを変更できません。プレイヤーが開始した変更には、GM が権限を持つソケットパターンを使用してください。クライアント側のチェックは UX のためのものであり、サーバー側でも独立して検証されます。

ロールの階層、詳細な USER_PERMISSIONS、所有権の継承、GM が権限を持つパターン、コンペンディウムパックの所有権、エラーが通知されずに失敗する場合の注意点については、references/permissions-and-ownership.md をお読みください。


移行とメンテナンス

Foundry のバージョンをまたいでモジュールを更新する場合や、データスキーマを変更する場合は、ワールドの読み込み時に移行を実行してください。

const MIGRATIONS = [
  { version: 1, fn: migrateV1 },
  { version: 2, fn: migrateV2 },
];

Hooks.once("ready", async () => {
  if (!game.user.isGM) return;
  const current = game.settings.get("my-module", "schemaVersion") ?? 0;
  const target = MIGRATIONS[MIGRATIONS.length - 1].version;
  if (current >= target) return;

  for (const { version, fn } of MIGRATIONS) {
    if (current < version) await fn();
  }
  await game.settings.set("my-module", "schemaVersion", target);
  ui.notifications.info("my-module | Migration complete.");
});

v13 モジュールを v14 に移行しますか? まず references/v14-migration.md をご確認ください。ここには、すべての破壊的変更、置き換え方法と削除バージョンを含む各非推奨項目、およびチェックリストが記載されています。主な変更点は、ActiveEffect の変更が文字列型を使用する system.changes に移動したこと、MeasuredTemplate が Regions になったこと、Scene の背景/前景が Level ドキュメントに移動したこと、rollMode が messageMode になったこと、-=/== 更新キーが _del/_replace になったこと、そして v12 のグローバルシムが削除されたことです。

以前のバージョン間の移行(Application から ApplicationV2 への移行、同期ロールの削除)、データ移行のパターン、互換性フラグ、migrateWorld を使用した一括移行、移行レジストリーの全体的なパターンについては、references/migration-guide.md をお読みください。


ボイラープレートファイル

新しいモジュールを作成する際の出発点として、以下をコピーしてください。

ファイル用途
boilerplate/module.json有効な v14 マニフェスト — compatibility 14、styles オブジェクト、documentTypes
boilerplate/main.mjsinit/setup/ready、設定、シート登録を含む ES モジュールのエントリーポイント
boilerplate/type-data-model.mjsTypeDataModel と defineSchema を使用したカスタム Actor タイプ
boilerplate/actor-sheet.mjsActorSheetV2 + HandlebarsApplicationMixin
boilerplate/sheet.hbsキャラクター情報、能力、所持品を含む Handlebars テンプレート
boilerplate/socket-handler.mjsGM が権限を持つソケットパターン
boilerplate/vite.config.mjsVite の設定 — 開発用プロキシ、固定名の出力、静的ファイルコピー用プラグイン
boilerplate/rollup.config.mjsRollup の代替設定 — node-resolve、commonjs、postcss、copy、terser
boilerplate/package.jsonスクリプト(dev、build、link)、devDependencies、Node 24 の engines 固定

よくある落とし穴

  1. 非推奨の v1 クラスを使用する — Application、FormApplication、ActorSheet、ItemSheet は foundry.appv1 の下にあり、v16 で削除されます。ApplicationV2、DocumentSheetV2 を使用してください。
  2. ロールを await し忘れる — roll.roll() は evaluate() の非同期エイリアスにすぎません。必ず await roll.evaluate() を使用してください。Roll.evaluateSync() は決定的なロール(maximize/minimize)でのみ使用できます。
  3. ソケットのプレフィックスがない — ソケットイベントには "module.my-module" 形式を使用する必要があります。module. プレフィックスがないと、メッセージはルーティングされません。
  4. init で game.user にアクセスする — init 中は game.user が設定されていません。ユーザーに依存するロジックには ready フックを使用してください。
  5. GM 以外がワールドドキュメントを変更する — ワールドレベルのドキュメントを変更できるのは GM クライアントだけです。更新は成功したように返されますが、変更は保存されません。試行する前に document.canUserModify(user, "update") を使用し、プレイヤーが開始した変更は GM が権限を持つソケットパターンを通じて処理してください。references/permissions-and-ownership.md を参照してください。
  6. esmodules の代わりに scripts を使用する — scripts フィールドはファイルを従来のスクリプトとして読み込みます(モジュールスコープはありません)。適切な ES モジュールのサポートには、必ず esmodules を使用してください。独立した worldScripts フィールドはありません。この概念はコミュニティで誤って広まった呼び名です。すべてのモジュールスクリプトは、マニフェストの esmodules/scripts を介してクライアント側で実行されます。フック(init、setup、ready)と条件チェックを使って、コードを実行するタイミングと場所を制御してください。
  7. 内部設定で config: false を指定し忘れる — config: true の設定は、モジュール設定メニューに表示されます。スキーマのバージョンなど、プログラムからのみ使用する値には config: false を使用してください。
  8. 英語文字列をハードコードする — ユーザーに表示されるテキストには、英語のみをサポートする場合でも game.i18n.localize() を使用してください。将来のローカライズが簡単になります。
  9. フックのクリーンアップをしない — Hooks.on() のフック ID を保存し、アプリケーションを閉じるときに Hooks.off() を呼び出してください。フックのリークはメモリの問題や動作の重複を引き起こします。
  10. compatibility.maximum を厳しく設定しすぎる — ユーザーが新しい Foundry バージョンでモジュールを実行できなくなります。互換性を損なう問題を確認した場合にのみ設定してください。
  11. ライフサイクルフックで、すべてのクライアント上で副作用を実行する — _onCreate、_onUpdate、_onDelete は接続中のすべてのクライアントで発火します。if (game.userId !== userId) return; でガードし、発生元のクライアントでのみ副作用を実行してください。
  12. libWrapper を使わずにコアメソッドをパッチする — 直接モンキーパッチを行うと、複数のモジュールが同じメソッドを変更した際に問題が発生します。Foundry のコア関数を安全に、競合なくパッチするには libWrapper を使用してください。
  13. カスタム Actor タイプに getRollData() がない — getRollData() を実装しないと、@abilities.str のようなロール式が解決されません。ロールに必要なシステムデータを返してください。
  14. jQuery を使用する — jQuery は appv1 と従来の renderChatMessage フック用に引き続きバンドルされていますが、フックと _onRender にはネイティブの HTMLElement が渡されます。$() の代わりに querySelector、addEventListener、classList を使用してください。
  15. @layer を使わない CSS、または独自に作ったレイヤーの CSS — Foundry は CSS カスケードレイヤーを使用します。マニフェストで modules を指定してください:styles: [{ "src": "...", "layer": "modules" }]。コアが宣言していないレイヤー名は exceptions の後に並び、すべてのコア CSS を上書きします。
  16. rollMode を渡す(v14) — toMessage、ChatMessage.create、RollTable#draw、rollInitiative における rollMode は非推奨です。messageMode(public | gm | blind | self | ic)を渡すか、何も渡さないでください。toMessage は自動的に core.messageMode 設定を使用します。
  17. 数値の ActiveEffect 変更モード(v14) — CONST.ACTIVE_EFFECT_MODES とルートの changes 配列は非推奨です。文字列の type 値(add、subtract、multiply、override、upgrade、downgrade、custom)を使って system.changes を記述してください。
  18. -= と == の更新キー(v14) — v16 まで非推奨です。foundry.data.operators の _del と _replace(value)、または mergeObject(..., { applyOperators: true }) を使用してください。
  19. MeasuredTemplates の作成(v14) — MeasuredTemplateDocument、TemplateLayer、Scene#templates は非推奨です。代わりに canvas.regions.placeRegion({ shapes: [...] }) で Region を配置してください。references/measured-templates.md を参照してください。
  20. scene.background の読み取り(v14) — 背景、前景、およびそれらの高さは Level ドキュメントに移動しました。canvas.level/scene.levels を読み取ってください。Scene のゲッターは非推奨の互換用シムです。references/scene-levels.md を参照してください。
  21. CONFIG.<Doc>.layerClass の設定(v14) — これは非推奨のプロキシです。代わりに CONFIG.Canvas.layers.<name>.layerClass を割り当ててください。
  22. バンドルされた .html ファイルをブラウザーで開く(14.361 以降) — 静的な .html は text/plain として配信されます。Handlebars テンプレートは引き続き Foundry 経由でレンダリングされます。直接ブラウザーで開く場合のみ動作しなくなりました。
  23. template.json を同梱する(v14) — v16 まで非推奨です。マニフェストの documentTypes と TypeDataModel で型を宣言してください。game.template は削除されました。game.model を読み取ってください。

リファレンスファイル

API の詳細については、必要に応じて読み込まれる以下のファイルを参照してください。

ファイル読むタイミング
references/v14-migration.mdモジュールを v13 から v14 に移行する場合は、まずここを読んでください — 破壊的変更、削除予定バージョンを含む非推奨項目、チェックリスト
references/document-model.mdカスタム Actor/Item タイプ、TypeDataModel、defineSchema、フラグ、ライフサイクルフック、Journal ページ、Folder API の構築
references/application-v2.mdシート、ウィンドウ、ダイアログの構築 — ApplicationV2、DocumentSheetV2、HandlebarsApplicationMixin、ドラッグ&ドロップ
references/hooks-and-settings.mdフックのライフサイクル、ドキュメントフック、キャンバスフック、設定 API、サブメニュー、キーバインド、DataModel 設定
references/chat-and-ui.mdチャットコマンド、メッセージのレンダリング、コンテキストメニュー、enrichHTML、FilePicker、セキュリティ/認可、ProseMirror エディター
references/sockets-rolls-packs.mdソケット通信、ダイス/Roll 拡張、コンペンディウムパック、ローカライズ
references/canvas-and-pixi.mdカスタムキャンバスレイヤー、PlaceableObject、PIXI.js の統合、座標変換
references/combat-and-tokens.md戦闘トラッカー、イニシアチブ、Token HUD、シーンコントロール、プロトタイプトークンの設定
references/regions-and-grid.mdシーンリージョン API、RegionDocument、RegionBehavior、グリッドの計測、座標変換、グリッドのハイライト表示
references/scene-levels.mdレベルドキュメント、canvas.level、レベルごとの背景とフォグ、レベル対応の配置オブジェクト
references/active-effects-v2.mdActiveEffect V2 — system.changes、変更タイプとフェーズ、持続時間と期限切れ、レジストリ、効果のサブタイプ
references/vision-and-lighting.mdVisionMode、検出モード、ライティングシステム、AmbientLight、戦場の霧
references/measured-templates.mdリージョンを使ったテンプレート — 効果範囲の形状、placeRegion、トークンの放射、MeasuredTemplate からの移行
references/audio-and-macros.mdAudioHelper、プレイリスト、効果音、Macro の作成、ホットバーとの統合
references/module-subtypes.mdモジュールが提供する Actor/Item/JournalEntryPage サブタイプ、htmlFields/filePathFields、無効化時の動作
references/accessibility.mdARIA ロール、キーボードナビゲーション、フォーカス管理、色のコントラスト、prefers-reduced-motion
references/testing-with-quench.mdQuench(Mocha/Chai)を使ったゲーム内テストの作成、テストパターン、CI 戦略
references/build-pipeline.mdVite と Rollup の設定、開発用プロキシ、ホットリロード、アセットパス、ビルド前のマニフェスト注入
references/handlebars-and-templates.mdFoundry ヘルパーの一覧、カスタム HTML 要素、フォームヘルパー、カスタムヘルパー/パーシャル、テンプレートの事前読み込み、シートのパターン
references/adventure-documents.mdAdventure ドキュメント、シーン/アクター/アイテム/ジャーナルのパッキング、プログラムによるインポート、バージョン更新
references/permissions-and-ownership.mdユーザーロールとドキュメントの所有権、testUserPermission、canUserModify、USER_PERMISSIONS、GM 権限を基準とするパターン
references/migration-guide.md古いバージョンからの移行(v11→v12→v13)、非推奨 API の検出、データ移行スクリプト

コメント