pixelfx について
pixelfxは、コードでピクセルアート効果を描くツールキットです。JavaScriptゲームの開発者やアニメーション素材を出力するチーム向けで、効果を実行中に調整でき、他のエンジン向けにスプライトシートとして書き出せます。
主な機能
- 01カラーとライトのバッファに効果を描画
- 02パレット、方向、グロー、シードを調整
- 03スプライトシートとアニメーションフレームを出力
- 04ループ、描画範囲、処理速度を検査
活用シーン
- 01JavaScriptゲームで効果をリアルタイム再生
- 02GodotやUnity向けのアニメーションシート出力
- 03キャラクターの攻撃効果を制作・確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ patch-gg/ pixelfx --skill pixelfxインストール後、Claude Code で/pixelfxを入力して読み込まれたか確認します。
詳細
pixelfx
コードで作るピクセルアートエフェクトです。各エフェクトは src/fx/<category>/<name>.js の1ファイルで、2つのバッファーに描画します。
color(不透明、ディザリング、または真の半透明のピクセル)と light(加算グロー)です。画像を使わないため、エフェクトをリアルタイムで再生したり、色を変えたり、反転したり、シードを変更したり、あらゆるエンジン向けにスプライトシートとしてレンダリングしたりできます。
この手法は Hugo Duprez のものです(Claude で優れたピクセルアートエフェクトを作る方法)。コードは粘土のようなものです。自分の目を信じ、参考資料を与えてください。一度きりのプロンプトでは、ありきたりなエフェクトしかできません。レンダリングして確認し、改良を重ねた下書きから、優れたものが生まれます。
まず最初に
- pixelfx のチェックアウト内で作業します。作業ディレクトリに
tools/render.mjsがない場合は、プロジェクトの隣にクローンします:git clone https://github.com/patch-gg/pixelfx。インストールは不要です。ツールは Node だけを使用します。 - 実行できることを確認します:
node tools/render.mjs fire/torchを実行すると、records/fire/torch/contact.pngが書き出されます。その PNG を画像読み取りツールで開いてください。このコンタクトシートを使って、以降すべてのエフェクトを確認します。
1. まず既存のエフェクトを探す
node tools/list.mjs <words> で ID、名前、タグ、説明を検索できます(node tools/list.mjs frost、node tools/list.mjs slash loop)。docs/CATALOG.md に全項目がカテゴリ別に記載されています。候補をレンダリングして、選ぶ前に確認してください。多くのリクエストは、オプションを変えるだけで既存のエフェクトを使えます:
palette:暗色から明色へ並ぶメインの色階調を、16進文字列で指定します。src/core/color.jsのPALの色階調(fire ember lava smoke dust ice water electric volt poison holy heal arcane shadow blood earth stone gold leaf wood metal bone neon cyber matrix candy night)、または独自の色階調を使えます。青い炎は{"palette": PAL.ice}です。seedで同等の別パターンに変更し、flipで左向きにし、angleで回転できます。グローの強さはlight(0..1+)で指定します。また、各エフェクトのmeta.optionsにある独自の設定(size、count、radius、text、height など)も指定できます。- コードを編集せずにオプションを試せます:
node tools/render.mjs fire/torch --opts '{"palette":["#102","#215","#43a","#8cf","#fff"]}'。
2. ゲームに組み込む
JS または TS の Canvas/WebGL ゲーム(プレーンな Canvas、Phaser、PixiJS、Kaplay、three.js)では、コードを直接使用できます。依存関係はありません。src/core と必要なエフェクトファイルをコピーするか、このリポジトリに依存してください。
import { createFrame, clearFrame, createFx, composite } from "pixelfx"; // src/core/index.js
import * as frostNova from "pixelfx/fx/ice/frost-nova"; // src/fx/ice/frost-nova.js
const frame = createFrame(320, 180); // the game's pixel resolution; ox, oy scroll it with the camera
const img = new ImageData(320, 180);
const fx = createFx(frostNova, { x: hero.x, y: hero.y, flip: hero.facing < 0 });
// every tick
fx.update(dt);
clearFrame(frame);
fx.draw(frame, "back"); // what goes behind characters
drawCharacters(); // your own sprites, or draw them into frame.color yourself
fx.draw(frame, "front");
composite(frame, img.data, background); // color over the background plus light; or null for transparent
ctx.putImageData(img, 0, 0); // then scale the canvas up with image-rendering: pixelated
if (fx.done()) removeIt(); // one-shots end on their own; fx.stop() fades a loop out
複数のエフェクトを1フレーム内で組み合わせられます。WebGL エンジンでは、合成した RGBA を毎フレームテクスチャにアップロードするか、エフェクトを一度スプライトシートにレンダリングして(下記参照)、ほかのアニメーションと同じように再生します。
任意のエンジン(Godot、Unity、GameMaker、Defold、LÖVE、Bevy、Construct)では、スプライトシートを書き出してください。
node tools/render.mjs ice/frost-nova --sheet を実行すると、records/ice/frost-nova/frost-nova.png(透明なフレームをグリッド状に並べたもの)と frost-nova.json(Aseprite 形式のフレーム)が生成されます。この形式は Phaser のアトラスローダー、Godot と Unity の Aseprite インポーター、ほとんどのツールで読み込めます。meta.pixelfx には fps、ループ、フレームサイズ、列数、ピボットが含まれます。ピボットを meta.pixelfx.pivot(エフェクトの原点。たとえば足元)に設定し、ニアレストネイバー・フィルタリングと圧縮なしでインポートして、meta.pixelfx.fps で再生してください。グローはアルファ付きの色としてシートに焼き込まれており、暗いシーンでは加算合成のように見えます。明るいシーンでは、色を変えたバージョンをレンダリングするか、エフェクトを暗いレイヤーに配置してください。
ライブラリ全体の場合:node tools/render.mjs <category> --sheet を実行すると、カテゴリ全体を書き出せます。
ヒットの背後にはキャラクターが必要です。 エフェクトだけではステッカーのように見えます。キャラクターを伴うエフェクトには act があり、キャラクターがいつ構え、いつ停止し、対象がどう反応するかを定義します。ゲームの作りに合わせて、次のいずれかを使用してください。
- 標準キャラクターを使う場合:
createFxの代わりにcreateAct(slash, { x, y })を使います。act.update(dt)、act.draw(frame)を呼び出し、act.shakeで画面を揺らします。停止中は自動的に動きを止めます。node tools/act.mjs <id> --sheetを実行すると、すべてをスプライトシートに焼き込めます。 - ゲーム独自のキャラクターを使う場合:タイミングを確認します。シートの JSON にある
slash.actまたはmeta.pixelfx.act(windup、recovery、tとfreezeを含むhits)を参照してください。エフェクトのwindup秒前にキャラクターの攻撃アニメーションを再生し、各ヒット時にはfreeze秒間、エフェクトとキャラクターの両方を含め、すべての更新を止めます。ホスト側のヒットストップは、act の有無にかかわらず、どのエフェクトでも機能します。
src/fx/moves/ には、構えから回復まで、エフェクトを連ねた一連の攻撃があります。誰かから技を求められたら、エフェクトではなく、まずここを確認してください。
3. 新しいエフェクトを作る
まず docs/AUTHORING.md を読んでください。これは仕様書です(meta、純粋なエフェクト用の draw(p, t, o)、またはシミュレーションを行うもの用の create(o)、ローカル座標、継ぎ目のないループ、空の状態での終了)。ツールキット、描画 API、品質基準についても記載されています。
それから:
- 1 行で表現します。アートディレクションとして、何を描くのか、どう動くのか、配色、タイミングを伝えます。「フロストノヴァ: 結晶が足元から外側へリング状に噴き出し、中心で白く閃光を放ち、破片が回転しながら飛び散ります。地面には霜が残り、消えていきます。」
- ライブラリで参考資料を探します:
node tools/list.mjs <words>を実行し、最も近いエフェクトファイルを 2〜3 個読んで、その技法を取り入れます(火花、煙、破片にはsrc/core/sim.jsのParticlesとBits、半透明のボリュームにはp.disc、シームレスなパーティクルにはcycle、炎や水にはtileFbmのスクロール)。Hugo Duprez のエフェクト の中で最も近いものも参考にしてください。これらは品質の基準です。同じ画面サイズで、彼の作品のほうにディテールや光、生き生きとした動きが多ければ、まだ完成ではありません。 - 下書きを作成します。
node tools/new.mjs <category>/<name>を実行すると、動作するファイルが作成されます(ループの場合は--loopを追加します)。方向性が定まっていない場合は、本当に異なる下書きを 3〜5 個(<name>-a.js~-e.js)作成し、すべてをレンダリングして(node tools/render.mjs "<category>/<name>-*")、選ぶ前にすべてのコンタクトシートを確認します。ユーザーがその場にいれば、最も良いものを 2〜3 個見せます(--gifを指定すると、共有用のアニメーションが作成されます)。 - 見て、評価し、修正します。 レンダリングし、
records/<id>/contact.pngを開いて、厳しい目を持つピクセルアーティストとして評価します。最も良くない点を修正して、もう一度レンダリングします。最低 3 回は繰り返してください。見せ場となる作品には、さらに必要です。--allを指定するとすべてのフレームが表示され、--mp4を指定すると動きをフルスピードで確認できます。 - キャラクターが関わる場合は、動きを実演します:
export const actを追加し(docs/AUTHORING.mdの「Acts」を参照)、t = 0 より前に予備動作を入れ、放出フレームでポーズを変え、接触時に停止してから、回復動作を入れます。node tools/act.mjs <id>を実行すると、12 fps の連続したステップが表示されます。動きはそれらと--mp4で評価し、コンタクトシートのサンプルだけで判断しないでください。 - チェックします。
node tools/check.mjs <id>を実行すると、キャンバス外への描画、最後に空の状態にならない単発アニメーション、ループのつなぎ目、乱数のシード未設定、遅いフレームを検出できます。また、アクト内のキーの順序違い、未知のポーズフィールド、テレポートする手も検出されます。問題がなくなるまで修正します。採用しなかった下書きは削除します。
確認すべき点と、よくある修正方法:
| 見え方 | 修正方法 |
|---|---|
| 1x ではぼやけて見える | 色数を減らし、シルエットを明確にし、焦点を1つに絞り、形を大きくします |
| 形の内部にノイズの点がぽつぽつ見える | ノイズのしきい値を下げ、at() で量子化し、小さな形にはノイズを加えません |
| 浮いた印象で、インパクトがない | 素早く入ってゆっくり抜ける動き(ease.outQuart/outExpo)、1~2フレームの白いヒーローフレーム、全体の時間を短くします |
| 硬い、または機械的に見える | 粒子ごとにサイズ、速度、遅延、寿命を変え、副次的な動き(火花、煙、破片)を加えます |
| 色あせて見える | グローを弱め(k 0.2~0.5)、輪郭の段階を暗くし、最も熱い中心部だけに白を使います |
| 平坦に見える | 光を片側から当てます。左上を明るく、右下の段階を暗くし、根元に暗い段階を加えます |
| 滑らかなグラデーションで、ベクター風に見える | 色にくっきりした段階を設け、柔らかさは光と半透明の煙にだけ使います |
| 煙があるべき場所に市松模様が出る | SMOKE、VAPOUR、DUST の粒子か p.disc を使います。実際に半透明にし、上から光を当てます |
| ループが折り返すときに継ぎ目が出る | cycle、loopNoise(phase)、セル全体でタイル化した tileNoise のスクロール、sin(phase * TAU * n) を使います |
| ワンショットが突然消える | t = duration より前に縮小させる、ディザで消す、または落下させます |
| キャラクターが動かず、エフェクトだけが良い | 予備動作、リリースポーズ、接触時の静止、反応するターゲット、回復動作を加えます |
| 動作に重みが感じられない | 打撃と反対方向への予備動作、長めの静止(最大0.2秒)、大きなシルエットの変化、揺れを加えます |
| ヒットのタイミングがずれている | 目測した時刻ではなく、エフェクト独自の定数にヒットキーを移動します |
| 武器の持ち方が悪い | 肘を曲げ、柄を胸の前に保ちます。振るときは刃が手に遅れてついてくるようにします。腕は約15 px まで伸びますが、それ以上は伸ばせないため、体を踏み込ませます |
| 腕が交差する、またはポーズが平坦に見える | こちらに対して三四分の一向きにします。腕を開くときは、手前の手を左(fx < 0)、奥の手を右に配置し、turn: 1 にします。yaw を使うと実際に向きを変えられます |
方向性のあるエフェクトは右を向き、地面のエフェクトは y = 0 に立ち、アクターのエフェクトは o.actor(標準の24 x 38キャラクターのマスクとピクセル)を包みます。また、Math.random は使いません。一般的なモチーフは問題ありませんが、特定のゲームのスプライト、キャラクター、ロゴを再現しないでください。
4. JS ではなくネイティブコードを使う
ゲームで JS を実行できず、スプライトシートでは不十分な場合(動くターゲットを追従するエフェクトや、実行時にインスタンスごとの色が必要な場合)は、エフェクトを移植します。純粋なエフェクトは時間の関数であり、シミュレーションを使うものは src/core/sim.js で粒子を更新します。2バッファ方式、ディザ付きアルファに使う4x4 Bayerしきい値、パレットランプの参照を維持してください。JS のオリジナルと移植版を並べて表示し、一致していることを確認します。