本文へスキップ

FNFスプライトシートをGIFに · PNG+XML変換

Friday Night Funkin'のキャラクターは、PNG 1枚と「BF idle dance0000」のような名前が並ぶSparrow XMLでできています。2つを一緒にドロップすると、SubTextureがそれぞれフレームになり、名前の前半でアニメーションにまとまり、トリムのオフセットでキャラクターが跳ねないよう揃えたうえで、アニメーションごとにGIF・APNG・WebMで書き出せます。

Friday Night Funkin'(FNF)のキャラクターは、PNGとSparrow(Starling)形式のXMLアトラスでできています。SubTexture1つが1フレームで、名前の前半が同じフレーム(BF idle dance0000、…0001)が1つのアニメーションになります。2つのファイルを一緒にドロップすると、Nerulioが前半部分ごとにアニメーションをまとめ、トリムのオフセットを保ったまま、アニメーションごとにGIF(またはAPNG、WebM)を1つ書き出します。XMLにタイミングはないので、アニメーションごとにキャラクターのframeRate(キャラクターファイルになければ24 fps)を設定してください。GIFでは41.67 msが40 msになります。

スプライトシート、連番フレーム、GIF・APNG、.asepriteファイルをドロップ
空のStudioを開く
ブラウザ内で処理し、ファイルはアップロードされません。
Studio のスプライト作業画面:シートと一緒に開いたAseprite JSONアトラス。長さ付きの6フレームがひとつのアニメーションにまとまった画面
CC0アセット(OpenGameArt)を開いた実際のStudio画面です。
書き出し先
  • Starling / Sparrow XML検証済み· Phaser 4.2
  • GIF / APNGデコード確認· Pillow
  • Godot 4検証済み· Godot 4.7.2
  • Unity 6検証済み· Unity 6000.5.3f1
  • Phaser 3 / 4検証済み· Phaser 3.90 + 4.2
  • PixiJS 8検証済み· PixiJS 8.21
  • Aseprite JSON検証済み· Phaser load.aseprite · PixiJS 8.21
  • .aseprite検証済み· Aseprite 1.3.18
  • Spine / libGDX検証済み· spine-canvas 4.2
  • LÖVE検証済み· LÖVE 11.5
  • Defoldビルド確認· Defold bob.jar 1.13.1
  • GameMaker未検証
  • CSS sprites検証済み· Chromium

FNFがキャラクターのフレームを記述する方法

このXML形式はSparrowとStarlingフレームワークに由来します。各SubTextureはPNG上の矩形(x、y、width、height)を指します。トリムされたフレームにはframeX、frameY、frameWidth、frameHeightが加わります。元のフレームサイズと、その中での切り抜き矩形の位置で、負の数で書くのでframeX="-3"は左から3 pxという意味です。rotated="true"はその領域がシート上で時計回りに90°回されていることを示します。

ゲーム側はキャラクターごとにdata/charactersにJSONを置きます。renderTypeがsparrowならassetPathがPNGとXML(同名、拡張子なし)を指し、アニメーションごとにprefix(フレーム番号を除いたSubTexture名)、frameRate(既定24)、任意でframeIndices、looped、offsetsを持ちます。つまりタイミングはXMLにはありません。

Nerulioが読むのはPNGとXMLだけです。名前の末尾のフレーム番号を外してまとめ、全フレームをframeWidth × frameHeightの中の元の位置に置き、1フレーム100 msから始めます。キャラクターJSONは読まないので、速度、使うフレーム、ループ設定は自分で決めます。

SubTexture
1フレーム。名前とPNG上の矩形。
プレフィックス
ゲームが探すアニメーション名。SubTexture名から末尾のフレーム番号を除いた部分。
frameX / frameY
元のフレーム内での切り抜き矩形の位置を示す負のオフセット。
frameRate
キャラクターJSONにあるアニメーションの毎秒フレーム数。なければ24。

具体例:SubTexture 1つとタイミングの計算

<SubTexture name="BF idle dance0003" x="1024" y="0" width="402" height="390"
            frameX="-3" frameY="-2" frameWidth="408" frameHeight="394"/>

アニメーション "BF idle dance"、4番目のフレーム (0003)
領域          PNG の (1024, 0) から 402 × 390
元のフレーム  408 × 394、領域を (3, 2) に描く
タイミング    24 fps → 1000 / 24 = 41.67 ms / フレーム
GIF           41.67 ms → 4 /100 s = 40 ms
14フレーム    ゲーム 583 ms → GIF 560 ms (4 % 速い)、APNG は 42 ms → 588 ms

数値は説明用で、実際のキャラクターのXMLには固有の値があります。丸めの規則は固定です。GIFは1/100秒単位、APNGはミリ秒単位で保存します。

何がどこに対応するか

XML/キャラクターJSONではNerulioではGIFでは
SubTexture名のプレフィックスプレフィックスごとに1アニメーション、自然順アニメーションごとに1ファイル
x, y, width, heightPNG上のフレーム領域フレームのピクセル
frameX, frameY, frameWidth, frameHeight元のフレーム内のオフセットトリムされたフレームが元の位置に
pivotX, pivotY(あれば)フレームのピボット、なければ元フレームの下中央ピボットで揃える
rotated="true"回転したまま読み込み、書き出しは未検証(UNVERIFIED)—
frameRate(キャラクターJSON)読まない:1フレーム100 msから開始書き出し前にfpsで一括設定
frameIndices, looped, offsets(キャラクターJSON)読まない必要なフレームにタグを作り、ループしないものは繰り返し×1

できること

  • SubTexture名を前半でまとめる:「BF idle dance0000」「BF idle dance0001」…は自然順で「BF idle dance」というアニメーションに。
  • frameX・frameY・frameWidth・frameHeightを保持し、各フレームが本来のサイズの中の正しい位置に。
  • XMLには時間がないため100msから。「すべて fps で設定」でアニメーション全体を一度に変更。FNFのMODは24fps(約42ms)が多いですが、キャラクターファイルで確認を。
  • アニメーションごとにGIFを1本、フレームはピボットで揃え、透過は1ビット。柔らかい縁はAPNGならそのまま。
  • 同じフレームをStarling / Sparrow XML、Phaser、Godotなどの書き出し先にも。

使い方

  1. キャラクターのPNGと.xmlを一緒にドロップ。
  2. インポートパネルでフレーム数、名前のまとまり方、画像の外にあるフレームを確認。
  3. アニメーションごとにタグを選び、アニメーションパネルの「すべて fps で設定」か、フレームごとのmsを入力。
  4. Enterでプレビューし、オニオンスキン(F3)でオフセットが揃っているか確認。
  5. パック&書き出しでAnimated GIF(またはAPNG、WebM video)を選んで書き出すと、アニメーションごとに1ファイル。

出力されるファイル

ファイル用途
bf_gif.zip書き出し名がbfのときのダウンロード。中にbf_gif/フォルダがあります。
bf_gif/bf_BF_idle_dance.gifアニメーション1つ。ファイル名では英数字・ドット・ハイフン以外の文字が_になります。

ゲームのタイミングに合わせて書き出す

  1. data/characters/のキャラクターJSONを開き、アニメーションごとにprefix、frameRate(なければ24)、frameIndices、loopedを控えます。
  2. Nerulioでそのプレフィックスのタグを選び、frameRateの値でfps一括設定をします。24 fpsなら1フレーム41.67 msです。
  3. frameIndicesを使うアニメーションなら、そのフレームだけに新しいタグをドラッグで作り、loopedがfalseなら繰り返しを×1にします。
  4. Enterでプレビューします。オニオンスキン(F3)でトリムされたフレームが揃っているか確認できます。
  5. パック&書き出しでAnimated GIF(正確な色と柔らかい縁が要るならAPNG)を選んで書き出すと、アニメーションごとに1ファイルになります。

結果の確認

  • GIFのフレーム数は、そのプレフィックスを持つSubTextureの数、またはframeIndicesの長さと同じはずです。
  • 24 fpsの14フレームのアニメーションは、GIFでは約0.56秒ごとにループします(14 × 40 ms)。
  • ,と.で送ってみます。オフセットが正しく読めていればキャラクターの足元は動きません。

Sparrow XMLの属性とStudioでの扱い

XMLの属性Studioでの扱い
TextureAtlasのimagePathXMLとPNGを対応付け
SubTextureのnameフレーム名。末尾の数字より前がアニメーション名
x、y、width、heightシート上のフレーム範囲
frameX、frameYその範囲が本来のフレーム内で置かれる位置(XMLでは負の値)
frameWidth、frameHeight本来のフレームサイズ。全フレームが正しい位置を保つ
rotated="true"回った状態で読み込み、書き出しは未検証
pivotX、pivotYあればフレームのピボット
時間の属性なし設定するまでフレームあたり100ms

トラブルシューティング

症状考えられる原因確認方法対処
GIFの速度が違うSparrow XMLにはタイミングがなく、全フレームが100 msで始まりましたフレームパネルに100 msと出ますJSONのframeRate(既定24)でfps一括設定をしてください
2つのアニメーションが1つにまとまるプレフィックスが末尾の数字しか違いません。left20000はプレフィックスleft、フレーム20000と読まれますインポートパネル:名前のまとめ方タイムラインでタグをドラッグして手で分けてください
一部のフレームが横倒しになるSubTextureにrotated="true"があり、Studioはシート上の向きのまま保持しますXMLでrotatedを検索します作ったツールで回転なしにパックし直してください。回転フレームの書き出しは未検証です
フレームが足りない矩形がPNGの外にあります。多くは別バージョンのシートのXMLですインポートパネルが画像外のフレーム数を示しますこのXMLと対になるPNGを使ってください
色の帯やポスタリゼーションが出る高解像度のFNFの絵は255色をはるかに超え、GIFのパレットをディザなしのメディアンカットで減らしました「More than 255 colours」のメモAPNG(正確)かWebM動画で書き出してください

ほかの方法

方法こんなときに向いています
同じ書き出しのAPNG正確な色、柔らかい縁、ミリ秒のタイミング。24 fpsは1フレーム40 msではなく42 msになります。
Sparrow XMLとしてパックし直すプレビューの共有ではなく、ゲーム用にキャラクターを直したり詰め直したりしたいとき。
ゲーム画面を直接録画ゲーム内のオフセット、カメラ、音楽まで一緒に見せたいとき。

エンジン別の書き出しと検証方法

「検証済み」は、実際のCC0アセットから書き出したファイルを本物のエンジン・ツールで読み込み、元データと比較したという意味です。読み込んでいない形式はそのように表示します。

書き出し先ファイル検証
Godot 4.tres SpriteFrames · .tscn AnimatedSprite2D · .png.import検証済み Godot 4.7.2Godotで読み込み、全アニメーションフレームを描画して元ファイルと比較。シーンはNearestフィルターで、回転は使いません。
Unity 6.unity.json · Editor/NerulioSpriteImporter.cs · AnimationClip検証済み Unity 6000.5.3f1バッチモードでスプライト範囲・ピボット・ピクセル・クリップのキーと長さを確認。
Phaser 3 / 4atlas JSON (multiatlas) · .anims.json検証済み Phaser 3.90 + 4.2両バージョンでフレームとアニメーションを描画。
PixiJS 8spritesheet JSON · animations · anchor · meta.scale検証済み PixiJS 8.21回転・複数ページのアトラスも確認。
Aseprite JSONhash / array · frameTags · slices検証済み Phaser load.aseprite · PixiJS 8.21タグの方向と繰り返し回数を保持。
.asepritelayers · tags · durations · slices検証済み Aseprite 1.3.18Asepriteのコマンドラインで開いて描画。
Spine / libGDX.atlas検証済み spine-canvas 4.2Spineランタイムで回転・トリム領域をすべて描画。libGDX本体は未実行。
Starling / Sparrow XMLXML per page検証済み Phaser 4.2Phaser 3.90はトリムされたXMLフレームを誤って描画します(Phaser側の不具合)。「Sparrow XML (Phaser 3)」プリセットはトリムを切り、3.90・4.2とも合格。
LÖVELua quads · nerulio_atlas.lua · main.lua検証済み LÖVE 11.5同梱ヘルパーで全フレームを描画し、全アニメーションを再生。
Defold.atlas · .tilesourceビルド確認 Defold bob.jar 1.13.1Defoldのコマンドラインビルダーでビルドし、生成テクスチャのUVを読み戻して確認。
GameMakerspr_<name>_stripN.png · gamemaker.json未検証GameMakerでは読み込んでいません(ヘッドレス実行不可)。ストリップはGameMakerの取り込み方式どおりに切ります。
CSS sprites.css · preview .html検証済み Chromium同梱スタイルシートで全クラスを描画。
GIF / APNGone file per animationデコード確認 Pillow書き出し後に全フレームと遅延を再デコード。APNGは完全一致。

検証の根拠

GIFデコーダー:実在のGIF 29本で408/408フレームがPillowと一致、APNG 16本で132/132。.aseprite:コーパス231ファイルを読み込み・書き直し、Aseprite 1.3.18で開いてタグ・長さ・ピクセルが231/231一致。書き出し:実在のCC0アセットで実際のエンジンを49回実行し47回合格。失敗2回はPhaser 3.90のトリムXMLの不具合で、Phaser 3プリセットで回避できます。

制限

  • キャラクターJSON(frameRate、frameIndices、looped、offsets)は読みません。
  • Adobe Animateのテクスチャアトラス(animateatlas)とPackerのTXTシートは読まず、Sparrow XMLだけを読みます。
  • 実際のFNFキャラクターは記録された検証に含まれていません。
  • グリッド・島の推定は信頼度つきのプレビューで、「適用」を押すまで何も切りません。すべての選択に代替案があり、ワンクリックで切り替えられます。
  • レイヤーが正確に合成できない.asepriteファイル(グループの不透明度など)は統合して読み込み、理由を読み込みパネルに表示します。
  • 読み込んだアトラス内の回転フレームは回転したままで、その書き出しは未検証です。
  • 画像は一辺32,768px(2億6,800万ピクセル)まで。ブラウザのメモリにも依存します。

バージョンと出典

XMLの読み込みはStudio共通のアトラス取り込みで、実際のアセットをUIから読み込む検証(アトラスデータを含む)を経ています。実際のFNFキャラクターは記録された検証になく、回転フレームは未検証です。GIFの出力はPillowでデコードして確認しています。形式の説明はStarlingのドキュメント、キャラクターの項目はFNF公式のModdingドキュメントに基づきます。

参照した公式ドキュメント

よくある質問

GIFの速さがおかしいのはなぜ?

Sparrow XMLには時間がないため、全フレームが100msから始まります。MODに合わせた速さに変えてください。GIFは1/100秒単位なので24fps(1フレーム41.7ms)は4と書かれ、丸めた内容を表示します。APNGはmsで保存します。

一部のフレームが横倒しになります。

rotated="true"のSubTextureはシート上の向きのまま回った状態で読み込み、そのフレームの書き出しは未検証です。元のフレームがあるなら、回転なしでパックし直してください。

FNFのスプライトシートをPNGにできますか?

APNGならアニメーションごとに全ピクセルそのままの動くPNGを1本ずつ書き出し、パック&書き出しのどの書き出し先もデータファイルと一緒にパックし直したPNGシートを出力します。

無料ですか?アカウントは必要ですか?

このページの機能はすべて無料で、アカウントなしで使えます。透かしや制限された書き出しはありません。

スプライトはアップロードされますか?

いいえ。Studioはこのブラウザのタブ内でデコード・パック・書き出しを行います。プロジェクトはブラウザ(IndexedDB)に自動保存され、.nerulioファイルとして保存できます。

Asepriteやエンジンのプラグインは必要ですか?

いいえ。.asepriteファイルはブラウザで読み書きします。エンジン別のバンドルには必要なものが入っています(Godotはインポート設定とシーン、UnityとGodotのタイルセットは小さなエディタースクリプト)。