pixijs-performance
PixiJS v8アプリのFPS改善・ドローコール削減・GPUメモリ最適化が必要なときに使用するスキルです。`cacheAsTexture(false)`や`releaseGlobalResources`などの破棄パターン、`GCSystem`/`TextureGCSystem`、`PrepareSystem`、オブジェクトプーリング、バッチング、動的テキスト向けの`BitmapText`、`Culler`によるカリング、解像度とアンチエイリアスのトレードオフを網羅します。FPSの低下・ジャンク・メモリリーク・ドローコール最適化などの場面でトリガーされます。
description の原文を見る
Use this skill when profiling or optimizing a PixiJS v8 app for FPS, draw calls, or GPU memory. Covers destroy patterns (cacheAsTexture(false), releaseGlobalResources), GCSystem and TextureGCSystem, PrepareSystem, object pooling, batching rules, BitmapText for dynamic text, culling (Culler, CullerPlugin, cullable, cullArea), resolution/antialias tradeoffs. Triggers on: FPS, jank, draw calls, batching, object pool, GCSystem, PrepareSystem, Culler, cacheAsTexture, memory leak, destroy patterns.
SKILL.md 本文
最適化する前にプロファイルしてください。PixiJS は多くのコンテンツをそのまま適切に処理できます。ブラウザの DevTools のパフォーマンス + GPU プロファイリングが最初の手段です。ボトルネックが見つかったら、以下のターゲットパターンを適用してください(destroy、pool、batch、cache、または cull)。
クイックスタート
container.cacheAsTexture(true);
container.updateCacheTexture();
container.cacheAsTexture(false);
container.destroy({ children: true });
import { CullerPlugin, extensions } from "pixi.js";
extensions.add(CullerPlugin);
offscreenContainer.cullable = true;
offscreenContainer.cullArea = new Rectangle(0, 0, 256, 256);
// GC を初期化オプション (ms) でチューニング。`textureGC.*` プロパティは
// 8.15.0 以降廃止されました — Application 初期化時にこれらを使用してください。
await app.init({ gcMaxUnusedTime: 60_000, gcFrequency: 30_000 });
関連スキル: pixijs-scene-container (destroy オプション), pixijs-scene-core-concepts (render groups, layers, culling), pixijs-scene-text (動的コンテンツ用 BitmapText), pixijs-assets (atlasing), pixijs-custom-rendering (カスタムバッチャー)。
コアパターン
適切なクリーンアップ付き destroy
import { Sprite, Assets } from "pixi.js";
const texture = await Assets.load("character.png");
const sprite = new Sprite(texture);
// sprite のみ destroy (再利用のためにテクスチャは保持)
sprite.destroy();
// sprite とそのテクスチャを destroy
sprite.destroy({ children: true, texture: true, textureSource: true });
読み込んだアセットが完全に終了したら:
Assets.unload("character.png");
これによってキャッシュから削除され、GPU リソースがアンロードされます。
Application destroy/recreate サイクル
import { Application } from "pixi.js";
// グローバルプールをクリーンアップする正しい destroy
app.destroy({ releaseGlobalResources: true });
const newApp = new Application();
await newApp.init({ width: 800, height: 600 });
releaseGlobalResources: true がない場合、古いアプリからのプール済みオブジェクト(バッチ、テクスチャ)が新しいアプリにリークし、フリッカーと破損を引き起こします。
テクスチャガベージコレクション
PixiJS は GCSystem を介して未使用のテクスチャと GPU リソースを自動的に回収します。デフォルト:30 秒ごとにチェック、60 秒間アイドル状態のリソースを削除します。これらは時間ベース(ミリ秒)です。
import { Application } from "pixi.js";
const app = new Application();
await app.init({
gcActive: true,
gcMaxUnusedTime: 120000, // クリーンアップ前のアイドル時間 (ms) (デフォルト: 60000)
gcFrequency: 60000, // チェック間隔 (ms) (デフォルト: 30000)
});
手動制御の場合:
texture.source.unload(); // 直ちに GPU メモリを解放
PrepareSystem による GPU アップロード
レンダリング前にテクスチャとグラフィクスを GPU にアップロードして、最初のフレームのカクつきを回避します:
import "pixi.js/prepare";
import { Application, Assets } from "pixi.js";
const app = new Application();
await app.init();
// アセットがアップロードされるまでレンダリングしない
app.stop();
const texture = await Assets.load("large-scene.png");
// 事前に GPU にアップロード
await app.renderer.prepare.upload(app.stage);
// これで最初のフレームでカクつかない
app.start();
prepare.upload() は Container(サブツリー内のすべてのテクスチャ、テキスト、グラフィクスをアップロード)または個別のリソースを受け入れます。
cacheAsTexture でパフォーマンス向上
cacheAsTexture() は container のサブツリーを単一のテクスチャにレンダリングし、複雑な静的コンテンツの draw call を削減します。内部的には render group を作成し、結果をキャッシュします。
使用タイミング:
- 多くの静的な子要素(UI パネル、装飾的な背景、複雑な Graphics)
- 高価なフィルタを持つ container(フィルタ結果をキャッシュ)
- めったに変わらない大規模なサブツリー
トレードオフ:
- キャッシュされたテクスチャの GPU メモリを使用(大きい container = より多くのメモリ)
- 最大テクスチャサイズは GPU に依存(通常 4096x4096;
renderer.texture.maxTextureSizeを確認) - 子要素を変更した後は
updateCacheTexture()を呼び出す必要がある - マスクとの組み合わせは不安定(マスキングスキルを参照)
import { Container, Sprite } from "pixi.js";
const panel = new Container();
// ... 多くの静的な子要素を追加 ...
panel.cacheAsTexture(true);
// オプション付き
panel.cacheAsTexture({ resolution: 2, antialias: true });
// 変更後に更新
panel.updateCacheTexture();
// destroy の前に必ず無効化(下記の Common Mistakes を参照)
panel.cacheAsTexture(false);
panel.destroy();
回避すること: 繰り返しのオン/オフ切り替え(絶え間ないキャッシュ更新は利点を相殺)、スパースな container のキャッシング(得られるものがほぼない)、4096x4096 より大きい container のキャッシング。
オブジェクトリサイクリング
destroy/recreate ではなく、プロパティを変更してオブジェクトを再利用します:
import { Sprite, Container, Texture } from "pixi.js";
class BulletPool {
private _pool: Sprite[] = [];
private _container: Container;
constructor(container: Container) {
this._container = container;
}
public get(texture: Texture): Sprite {
let bullet = this._pool.pop();
if (!bullet) {
bullet = new Sprite(texture);
this._container.addChild(bullet);
}
bullet.texture = texture;
bullet.position.set(0, 0);
bullet.rotation = 0;
bullet.scale.set(1);
bullet.alpha = 1;
bullet.tint = 0xffffff;
bullet.blendMode = "normal";
bullet.visible = true;
return bullet;
}
public release(bullet: Sprite): void {
bullet.visible = false;
this._pool.push(bullet);
}
}
destroy と recreate は visible の切り替えとプロパティの更新よりも大幅に高コストです。GPU リソースは割り当てられたままで、シーングラフの表示のみ変わります。
バッチング最適化
PixiJS は同様の連続したオブジェクトを単一の draw call にバッチします。バッチ破壊は以下で発生します:
- オブジェクトタイプの変更(Sprite vs Graphics)
- テクスチャソースの変更(バッチごとのテクスチャ制限を超える、通常 16)
- ブレンドモードの変更
- トポロジーの変更
draw order を最適化します:
import { Sprite, Graphics, Container } from "pixi.js";
// 4 つの draw call: タイプが交互
const bad = new Container();
bad.addChild(new Sprite(t1));
bad.addChild(new Graphics().rect(0, 0, 10, 10).fill(0xff0000));
bad.addChild(new Sprite(t2));
bad.addChild(new Graphics().rect(0, 0, 10, 10).fill(0x00ff00));
// 2 つの draw call: タイプがグループ化
const good = new Container();
good.addChild(new Sprite(t1));
good.addChild(new Sprite(t2));
good.addChild(new Graphics().rect(0, 0, 10, 10).fill(0xff0000));
good.addChild(new Graphics().rect(0, 0, 10, 10).fill(0x00ff00));
同じ原則がブレンドモードにも適用されます:screen/normal/screen/normal = 4 draw、screen/screen/normal/normal = 2 draw。
個別テクスチャ上のスプライトシート
import { Assets, Sprite } from "pixi.js";
// スプライトシート(単一テクスチャアトラス)を読み込み
const sheet = await Assets.load("game-atlas.json");
// すべてのフレームが 1 つの GPU テクスチャを共有; バッチングを有効化
const hero = new Sprite(sheet.textures["hero.png"]);
const enemy = new Sprite(sheet.textures["enemy.png"]);
const coin = new Sprite(sheet.textures["coin.png"]);
個別のテクスチャはそれぞれ独自の GPU アップロードを必要とし、バッチごとのテクスチャ制限を超えるとバッチ破壊が発生します。スプライトシートは多くのフレームを 1 つのアトラステクスチャに統合します。
半解像度シートでは @0.5x ファイル名サフィックスを使用して、PixiJS が自動的にスケーリングします。
テキストパフォーマンス
Text と HTMLText は変更のたびにキャンバスに再レンダリングし、GPU に再アップロードします。無条件にフレームごとに更新しないでください:
import { BitmapText, Text } from "pixi.js";
// 間違い:毎フレーム canvas を再レンダリング + GPU アップロード
app.ticker.add(() => {
scoreText.text = `Score: ${score}`;
});
// 正しい:頻繁に変わるコンテンツに BitmapText を使用
const scoreText = new BitmapText({
text: "Score: 0",
style: { fontFamily: "Arial", fontSize: 24, fill: 0xffffff },
});
app.ticker.add(() => {
scoreText.text = `Score: ${score}`;
});
BitmapText は事前生成されたグリフアトラスからレンダリングされます。更新は quad の再配置のみで、キャンバス再レンダリングや GPU アップロードはありません。スコア、タイマー、カウンター、および頻繁に変わるものに使用してください。
キャンバス Text を使用する必要がある場合、更新が実際に値が変わったときのみ発生するようにガードします:
app.ticker.add(() => {
const next = `Score: ${score}`;
if (scoreText.text !== next) {
scoreText.text = next;
}
});
テキスト resolution はデフォルトでレンダラー resolution と一致します。高 DPI ディスプレイで GPU メモリを削減するため、text.resolution = 1 を使用して独立して低下させます。
Graphics パフォーマンス
Graphics オブジェクトは、その形状が変わらないとき最も高速です(transforms、alpha、および tint は問題ありません)。小さい Graphics(~100 ポイント未満)は Sprite のようにバッチされます。数百の形状を持つ複雑な Graphics は遅く、代わりにテクスチャに変換します:
import { Graphics, Sprite } from "pixi.js";
const complex = new Graphics();
// ... 複雑な形状を描画 ...
// 1 回テクスチャにレンダリング、Sprite として使用
const texture = app.renderer.generateTexture(complex);
const sprite = new Sprite(texture);
カリング
PixiJS は cullable が設定されたとき、表示領域外のオブジェクトのレンダリングをスキップします。CPU コスト(境界チェック)を GPU 節約と引き替えにするため、デフォルトで無効です。カリングは CullerPlugin が登録されたときのみ実行されます:
import { extensions, CullerPlugin, Culler, Rectangle } from "pixi.js";
extensions.add(CullerPlugin); // Application.init の前
// 画面外にあるかもしれないオブジェクトで有効化
sprite.cullable = true;
// オプション:事前計算された cull rectangle はフレームごとの境界計算を回避します。
// cullArea がない場合、Culler はオブジェクトのグローバル境界を使用します。
sprite.cullArea = new Rectangle(0, 0, 800, 600);
// サブツリー全体のカリングをスキップ(静的 UI、常に表示)
uiRoot.cullableChildren = false;
// または、プラグインなしで手動でカリング:
Culler.shared.cull(app.stage, app.renderer.screen);
container の cullableChildren は culler がその子孫に再帰するのを停止します。多くの子を持つ静的 UI パネルの大きな利益です。Culler.shared.cull(container, rect) は同じロジックを手動でカスタムレンダーパイプラインに対して実行します。GPU バウンドのときカリングを使用し、CPU バウンドのときは避けてください。オブジェクトごとの境界チェックはオーバーヘッドを追加するためです。
Resolution と antialias トレードオフ
import { Application } from "pixi.js";
const app = new Application();
// モバイルフレンドリー:低解像度、antialias なし
await app.init({
resolution: 1,
antialias: false,
backgroundAlpha: 1, // 不透明な背景がより高速
});
resolution: 2 はピクセル数を 4 倍にします。モバイルでは、これはフレームレートを半分にすることができます。正しいバランスを見つけるためにプロファイルしてください。
大量のテクスチャ destruction をずらす
function staggerDestroy(textures: Texture[], perFrame: number = 5): void {
let index = 0;
const ticker = app.ticker;
const destroy = () => {
const end = Math.min(index + perFrame, textures.length);
for (let i = index; i < end; i++) {
textures[i].destroy(true);
}
index = end;
if (index >= textures.length) {
ticker.remove(destroy);
}
};
ticker.add(destroy);
}
1 フレームで多くのテクスチャを destroy するとフリーズが発生します。複数のフレーム間でコストを分散させます。
フィルタとマスクのコスト
- bounds がわかっているとき、
container.filterArea = new Rectangle(x, y, w, h)を設定します。なしで、PixiJS は毎フレーム境界を測定します。 - フィルタメモリを解放:
container.filters = null。 - マスクコスト(最も安価から最も高価):軸揃え矩形マスク(scissor rect)< Graphics マスク(stencil buffer)< Sprite/alpha マスク(フィルタパイプライン)。数百のマスクは、タイプに関係なく遅くなります;軸揃えされた境界のとき矩形マスクを推奨します。
- インタラクティブな子がない container では
interactiveChildren = falseを設定します。 - 大きい container では、再帰的な子 hit テスティングをスキップするため
hitAreaを設定します。
安全な destroy 順序
destroy する前にシーンから削除します:
parent.removeChild(sprite);
sprite.destroy();
レンダーパイプラインが参照を保持しているときに destroy すると、null ポインタクラッシュが発生します。フレーム途中で destruction が発生する必要がある場合は、延期します:
app.ticker.addOnce(() => {
parent.removeChild(sprite);
sprite.destroy();
});
よくある間違い
[CRITICAL] releaseGlobalResources なしの App destroy
間違い:
app.destroy();
const newApp = new Application();
正しい:
app.destroy({ releaseGlobalResources: true });
const newApp = new Application();
このフラグなしで、古いアプリからのスタイルプール済みバッチとテクスチャがグローバルプールに残存し、新しいアプリによって再利用され、フリッカーと視覚的な破損を引き起こします。
[HIGH] シーングラフでのオブジェクトタイプのインターリーブ
sprite / graphic / sprite / graphic = 4 draw call。
sprite / sprite / graphic / graphic = 2 draw call。
バッチ破壊を最小化するため、子要素の順序で同じオブジェクトタイプをグループ化します。同じことはブレンドモード順序にも適用されます。
[HIGH] destroy/recreate ではなく、destroy と recreate の代わりにリサイクリング
Destroy/recreate は高コスト:GPU リソースをディールロケート、ガベージコレクションをトリガー、新しい GPU アップロードが必要。texture、position、visible および他のプロパティを更新してオブジェクトを再利用します。頻繁にスポーン/デスポーンするエンティティにはオブジェクトプールパターンを使用します。
[HIGH] 個別テクスチャの代わりに多くのスプライトシートを読み込み
個別の各テクスチャはそれ自身の GPU メモリスロットを消費し、バッチごとのテクスチャ制限に達するとバッチングが破壊されます。スプライトシートはテクスチャをアトラスに統合します。また、いずれかの軸で 4096px を超えるテクスチャを回避します。いくつかのモバイル GPU で失敗するためです。
[HIGH] フレームごとに Text または HTMLText を更新
各更新は完全な文字列をキャンバスに再レンダリングし、GPU にアップロードします。60fps でこれは大きなオーバーヘッドを作成します。動的コンテンツ(スコア、タイマー、カウンター)に BitmapText を使用します。キャンバス Text が必要な場合、値が実際に変わったときのみ更新します。ソース: src/docs/concepts/performance-tips.md
[HIGH] 複雑な Graphics をテクスチャの代わりに使用
数百の複雑な Graphics オブジェクトはレンダリングが遅い。小さい Graphics(~100 ポイント未満)は Sprite のようにバッチできますが、複雑なものはできません。複雑な静的形状を renderer.generateTexture() でテクスチャにレンダリングし、Sprite として表示します。ソース: src/docs/concepts/performance-tips.md
[MEDIUM] 大量のテクスチャ destruction をずらしていない
1 つのフレームで数十のテクスチャを destroy すると、目に見えるフリーズが発生します。複数のフレーム間で destruction を分散させます(例:ticker コールバックで毎フレーム 5)。ソース: src/docs/concepts/garbage-collection.md
[MEDIUM] 大規模なシーンに PrepareSystem を使用していない
renderer.prepare.upload() がない場合、テクスチャは最初のレンダリング時に GPU にアップロードされ、フレームカクつきを引き起こします。読み込み画面またはシーン遷移の場合、表示する前にアップロードします。import 'pixi.js/prepare' が必要です(デフォルトバンドルにも含まれていません;常に明示的にインポートしてください)。ソース: src/prepare/PrepareSystem.ts
[MEDIUM] プロファイリングなしで高解像度または antialias を使用
resolution: 2 はピクセル数を 4 倍にします。antialias: true は GPU コストを追加します。両者ともモバイルデバイスでパフォーマンスを低下させます。有効化する前に、ターゲットハードウェアで常にプロファイルしてください。ソース: performance-tips.md
API リファレンス
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- pixijs
- リポジトリ
- pixijs/pixijs-skills
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/pixijs/pixijs-skills / ライセンス: 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を通じてオンチェーン取引とデータ照会を実現します。