pixijs-html-source について
DOM 要素や不変スナップショットを PixiJS v8 のテクスチャソースとして扱うスキルです。PixiJS 内でブラウザー要素を描画する開発者向けに、ライブ更新とスナップショットのライフサイクルを説明します。
主な機能
- 01DOM 要素をテクスチャソース化
- 02HTMLSource によるライブ更新
- 03不変の ElementImageSource スナップショット
- 04Sprite、Texture、Mesh で利用可能
- 05ブラウザー対応確認とリソース解放
活用シーン
- 01PixiJS シーン内に操作可能な DOM 要素を表示
- 02変化する要素を必要に応じてテクスチャへ再描画
- 03トランジションやトレイル用の静的スナップショットを保持
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ pixijs/ pixijs-skills --skill pixijs-html-sourceインストール後、Claude Code で/pixijs-html-sourceを入力して読み込まれたか確認します。
詳細
HTMLSource と ElementImageSource は、DOM 要素を TextureSource に変換します。変換後は、Sprite、Texture フレーム、Mesh へのマッピングなど、通常のテクスチャが使える場所ならどこでも使用できます。HTMLSource はライブ要素のピクセルを GPU に反映します(要素はブラウザー内で引き続き編集やクリックが可能です)。ElementImageSource は再描画されない不変のスナップショットをラップします。どちらも pixi.js/html-source にあり、このパスからインポートすると拡張機能が登録されます。
これらのソースは、実験段階の HTML-in-Canvas ブラウザープロポーザルに依存しており、PixiJS v8 では EXPERIMENTAL としてマークされています。ブラウザー API を有効にする必要があります。有効になっていない場合、初回レンダリング時にテクスチャアップローダーがエラーをスローします。この機能に依存する前に、
canvas.requestPaintで機能を検出してください。この API はマイナーリリース間で変更される可能性があります。
pixijs-scene-sprite とテクスチャに関する知識を前提としています。これらはテクスチャ ソース であり、表示オブジェクトではありません。画面に表示するには、Sprite(または Texture/Mesh)でラップしてください。Web Workers では使用できません。ワーカーにはキャプチャ対象の DOM がないためです。
クイックスタート
import { Application, Sprite } from "pixi.js";
import { HTMLSource } from "pixi.js/html-source";
const app = new Application();
await app.init({ resizeTo: window });
document.body.appendChild(app.canvas);
// The element must be a direct child of the Pixi canvas.
const form = document.createElement("form");
form.innerHTML = '<input value="still editable" />';
app.canvas.appendChild(form);
// Render the live form as a sprite. It stays interactive in the browser.
const source = new HTMLSource({ resource: form });
const sprite = Sprite.from(source);
sprite.anchor.set(0.5);
sprite.position.set(app.screen.width / 2, app.screen.height / 2);
app.stage.addChild(sprite);
関連スキル: pixijs-scene-sprite(テクスチャを表示)、pixijs-scene-mesh(ジオメトリにマッピング、PerspectiveMesh)、pixijs-scene-dom-container(逆の用途:GPU パイプラインの外側で、キャンバスの 上に HTML を重ねて表示)、pixijs-assets(テクスチャソースとローダー/キャッシュ)、pixijs-environments(Web Workers では DOM を利用できません)。
コンストラクターのオプション
どちらのソースも TextureSource を拡張しているため、すべての TextureSourceOptions(resolution、scaleMode、addressMode、label など)が有効です。それぞれで resource が必須です。
HTMLSourceOptions(ライブ要素):
| オプション | 型 | デフォルト | 説明 |
|---|---|---|---|
resource | Element | — | 必須です。描画するライブ DOM 要素です。所有するキャンバスの直接の子である必要があります。そうでない場合、コンストラクターは例外をスローします。 |
canvas | HTMLSourceCanvas | — | 要素のレイアウトサブツリーを所有するキャンバスです。要素がキャンバスの直接の子である場合は resource.parentElement から推測されます。推測できない場合は指定してください。 |
autoLayout | boolean | true | 所有するキャンバスに layoutsubtree 属性を設定します。この属性がある場合に限り、ブラウザーはキャンバスの子要素をレイアウトして描画します。自分で <canvas layoutsubtree> を記述する場合は false に設定してください。 |
autoUpdate | boolean | true | キャンバスの paint イベントを監視し、要素の再描画時に再アップロードします。一度だけキャプチャする静的なテクスチャの場合は false に設定してください。 |
autoRequestPaint | boolean | true | 構築後に初回の描画を一度リクエストします。継続的なアニメーションの場合は false に設定し、フレームごとに自分で source.requestPaint() を呼び出してください。 |
ElementImageSourceOptions(不変のスナップショット):
| オプション | 型 | デフォルト | 説明 |
|---|---|---|---|
resource | ElementImage | — | 必須です。canvas.captureElementImage(element) によるスナップショットです。 |
autoClose | boolean | false | ソースの破棄時に snapshot.close() を呼び出します。スナップショットをほかのソースと共有する場合は false のままにしてください。そうしないと、解放後のリソースを使用することになります。 |
静的な HTMLSource.defaultOptions オブジェクトを使って、すべての HTMLSource のデフォルトを変更できます。たとえば、HTMLSource.defaultOptions.autoUpdate = false のように設定します。
基本パターン
セットアップと副作用のあるインポート
import "pixi.js/html-source";
import { HTMLSource, ElementImageSource } from "pixi.js/html-source";
pixi.js/html-source は extensions.add(...) を呼び出して、HTMLSource、ElementImageSource およびそれらの WebGL/WebGPU アップローダーを登録します。これがないと、レンダラーには 'html' アップローダーがなく、これらのソースは描画されません。クラスは pixi.js ではなく pixi.js/html-source からエクスポートされます。
pixi.js/html-source から名前付きエクスポートをインポートすると、副作用も実行されます。そのため、このパスからほかにインポートするものがない場合に限り、単独の import 'pixi.js/html-source' が必要です。
機能検出とブラウザーのサポート
HTML-in-Canvas API はブラウザーフラグで制御されています。この API に依存する前に、機能を検出してください。
import type { HTMLSourceCanvas } from "pixi.js/html-source";
const canvas = app.canvas as HTMLSourceCanvas;
if (canvas.requestPaint) {
// HTML-in-Canvas is available.
}
型付きの requestPaint および captureElementImage メンバーを使うには、app.canvas を HTMLSourceCanvas にキャストしてください。ブラウザーが API に対応していない場合、source.requestPaint() は false を返します。API が無効な場合、テクスチャアップローダーは初回の描画時に例外をスローします。
API がない場合、初回のアップロード時に、WebGL では [HTMLSource] WebGLRenderingContext.texElementImage2D is not available...、WebGPU では [HTMLSource] GPUQueue.copyElementImageToTexture is not available... がスローされます。
HTMLSource を使用したライブ要素
const form = document.createElement("form");
app.canvas.appendChild(form); // direct child of the canvas
const source = new HTMLSource({ resource: form });
const sprite = Sprite.from(source);
要素はレンダラーの <canvas> の直接の子である必要があります。ソースは resource.parentElement から所有するキャンバスを推定します(または canvas を渡します)。デフォルトでは、キャンバスに layoutsubtree を設定し、キャンバスの paint イベントを監視して、初回の描画を一度リクエストします。最初の描画が行われるまで、source.isReady は false です。その後は true になります。autoUpdate が false の場合は、直ちに true になります。resourceWidth/resourceHeight は、要素の実ピクセルサイズ(offsetWidth/offsetHeight)を返します。
requestPaint を使用した連続アニメーション
const source = new HTMLSource({ resource: clock, autoRequestPaint: false });
const sprite = Sprite.from(source);
app.ticker.add(() => {
clock.textContent = new Date().toLocaleTimeString();
source.requestPaint(); // re-snapshot the DOM this frame
});
ブラウザーは、要求があった場合にのみキャンバスの子要素を再描画します。フレームごとに内容が変わる要素では、autoRequestPaint: false を設定し、独自のティッカー内で source.requestPaint() を呼び出して、任意のタイミングで再描画を実行します。
ElementImageSource を使用した不変スナップショット
import { ElementImageSource } from "pixi.js/html-source";
import type { HTMLSourceCanvas } from "pixi.js/html-source";
const canvas = app.canvas as HTMLSourceCanvas;
const snapshot = canvas.captureElementImage!(element);
const source = new ElementImageSource({ resource: snapshot, autoClose: true });
const sprite = Sprite.from(source);
captureElementImage() は、要素の現在のピクセルを不変の ElementImage に固定します。所有するキャンバスも paint リスナーも再描画のライフサイクルもないため、ソースは構築した時点ですぐに使用可能です。要素の破棄後も保持する必要がある場合や、スナップショットを他の場所に渡す場合(トランジション、「粉砕」効果、トレイル効果など)に使用します。使用後は snapshot.close() でスナップショットを解放するか、autoClose: true を渡して、destroy() 時にソースが閉じるようにします。
スプライト、テクスチャ、メッシュでソースを使用する
どちらのソースも通常の TextureSource です。Sprite.from(source)/Texture.from(source) でラップして、フレーム分割またはスライスしてサブテクスチャを作成するか、メッシュにマッピングします。
import { Rectangle, Texture } from "pixi.js";
// A 64x64 slice of the rendered element.
const chunk = new Texture({
source,
frame: new Rectangle(0, 0, 64, 64),
});
// Mapped onto geometry (e.g. a perspective warp).
const mesh = new PerspectiveMesh({ texture: Texture.from(source) /* ... */ });
自動検出と優先順位
// Resolves to an HTMLSource (element) or ElementImageSource (snapshot) only as a last resort.
const sprite = Sprite.from(elementAlreadyInTheCanvas);
Texture.from/Sprite.from に渡された汎用 HTML 要素または ElementImage は、テクスチャソースの優先順位が最も低い(-10)これらのソースに解決されるため、他の組み込みソースが処理できないリソースだけを受け取ります。画像、動画、キャンバスの各要素は意図的に対象外です。これらには、専用のより高速なソースがあります。オプション(autoUpdate、autoClose)が必要な場合や、SVG などの HTML 以外の要素を使用する場合は、ソースを明示的に構築してください。
よくある間違い
[HIGH] pixi.js からインポートして pixi.js/html-source からインポートしない
誤り:
import { HTMLSource } from "pixi.js"; // not exported from the core entry
正しい例:
import { HTMLSource } from "pixi.js/html-source";
HTMLSource、ElementImageSource、および 'html' アップローダーは pixi.js/html-source にのみ存在します。このパスから何かをインポートすると拡張機能が登録されます。このモジュールには副作用があると指定されているため、クラスだけをインポートした場合も、バンドラーは登録処理を保持します。
[HIGH] ブラウザー API が有効だと思い込む
HTML-in-Canvas 提案は、デフォルトでは提供されていません。API が無効の場合、アップローダーは初回のレンダリング時にエラーをスローします。まず機能を検出してください。
const canvas = app.canvas as HTMLSourceCanvas;
if (!canvas.requestPaint) {
// Fall back to a static image, DOMContainer overlay, or a message.
}
[MEDIUM] 要素がキャンバスの直接の子ではない
document.body.appendChild(form); // wrong parent
const source = new HTMLSource({ resource: form }); // throws
HTMLSource は、要素が所有するキャンバスの直接の子(app.canvas.appendChild(form))であることを必要とし、そうでない場合はエラーをスローします。ソースを構築する前に要素をキャンバスに追加するか、canvas オプションを渡してください。
[MEDIUM] requestPaint を呼び出さずにライブ要素が更新されると思い込む
アニメーションしない要素は、ブラウザーの paint イベント時に自動更新されます(autoUpdate: true)。フレームごとに変わる内容は、描画を発生させる何かがない限り再アップロードされません。source.requestPaint() を毎フレーム呼び出して更新してください(autoRequestPaint: false を設定します)。
[MEDIUM] 使用中の ElementImage を閉じる
const source = new ElementImageSource({ resource: snapshot, autoClose: true });
const other = new ElementImageSource({ resource: snapshot }); // shares the snapshot
source.destroy(); // closes the snapshot — `other` is now a use-after-free
ソースがスナップショットを排他的に所有する場合にのみ、autoClose: true を設定してください。スナップショットを共有する場合は autoClose を無効のままにし、最後のソースが破棄された後に一度だけ snapshot.close() を呼び出してください。
クリーンアップ
source.destroy();
HTMLSource.destroy() は、キャンバスの paint リスナーを切り離し、キャンバスへの参照を null にします。ElementImageSource.destroy() は、autoClose が設定されている場合にスナップショットを閉じます。設定されていない場合は、メモリを解放するために自分で snapshot.close() を呼び出してください。