CSSスプライト作成 · くっきりしたスプライトシートとクラス
Webゲームやサイト向け:何十もの画像リクエストを1つに。フレームごとに背景位置とサイズを持つCSSクラスになり、プレビューページですべてをくっきり確認できます。
CSSスプライトは、多数のアイコンやフレームをまとめた1枚の画像です。要素を1つの断片とちょうど同じ大きさにし、background-positionを断片の位置のマイナスにしてシートをずらすと、その断片だけが見えます。Nerulioは画像を1枚のPNGにパックし、画像ごとに1つのクラスを持つ.cssとプレビュー用の.htmlを書き出します。要素の枠ではトリムのオフセットを戻せず、回転した断片も戻せないので、トリムと回転はオフにします。image-rendering: pixelatedで拡大してもドット絵がくっきりします。全クラスをChromiumで描いて比較しました。

- CSS sprites検証済み· Chromium
- 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
- Starling / Sparrow XML検証済み· Phaser 4.2
- LÖVE検証済み· LÖVE 11.5
- Defoldビルド確認· Defold bob.jar 1.13.1
- GameMaker未検証
- GIF / APNGデコード確認· Pillow
CSSスプライトが1つの断片を見せる仕組み
要素は1つの断片とちょうど同じ大きさで、シートはその背景です。断片が枠の中に来るように、シートを左上へずらします。x = 42、y = 31にある断片ならbackground-position: -42px -31pxです。シートの残りは枠の外にあり、描かれません。
枠が見える範囲のすべてなので、トリムした断片は透明な余白を失ってずれ、回転した断片は背景のプロパティだけでは戻せません。そのためCSSプリセットは元の大きさの正立した画像をパックし、拡大しても隣に届かないよう2pxの間隔を空けます。
大きく描くには、すべての数値(幅、高さ、background-size、background-position)を同じ倍率で掛けるか、プレビューページのようにzoom: 4で要素ごと拡大します。image-rendering: pixelatedは、滑らかに補間せず最近傍で整数倍に拡大するようブラウザに伝えます。
- background-position
- 要素内でシートをずらす量。断片の位置のマイナス。
- background-size
- CSSピクセルでのシートの大きさ。ページごとに書かれているので拡大の結果が予測できる。
- image-rendering: pixelated
- ドット絵向けの最近傍拡大。背景画像にも効く。
例:40 × 29のフレーム6枚をCSSクラスに
run.png 82 × 91(40 × 29のフレーム6枚、トリムなし、間隔2)
.sprite{display:inline-block;background-repeat:no-repeat;image-rendering:pixelated;}
.sprite-page-0{background-image:url("run.png");background-size:82px 91px;}
.sprite-run_3{width:40px;height:29px;background-position:-42px -31px;}
HTML element: class="sprite sprite-page-0 sprite-run_3"
zoomなしで同じフレームを2倍に:
width 80px height 58px background-size 164px 182px background-position -84px -62pxrun_3は左から42px(run_2の40px+間隔2px)、上から31px(1行目の29px+間隔2px)の位置にあるので、そのマイナスがオフセットになります。
できること
- スプライトシートPNGと、フレームごとに1クラスの.css。
- 同梱スタイルシートで全クラスを描くプレビュー.html。
- どの倍率でもドット絵をくっきり保つimage-rendering: pixelated。
- CSSではトリムと回転をオフ(要素ボックスはトリムのオフセットを持てないため)。Chromiumでクラスごとに確認。
使い方
- 画像やフレームをドロップ。
- パック&書き出しでCSS spritesを選ぶ。
- プレビューページで全クラスを確認。
- .cssを読み込み、要素にクラスを付ける。
Webページで使う
run.pngとrun.cssをサイトにコピーし、ページのheadでstylesheetのlink要素からrun.cssを読み込みます。- 要素ごとにクラスを3つ付けます。
sprite、sprite-page-0のようなページのクラス、sprite-run_3のような画像のクラスです。 - フレームアニメーションは、JavaScriptのタイマーでフレームごとに画像のクラスを切り替えます。
- スプライトがボタンのアイコンなら、ボタンにアクセシブルなラベルを付けてください。スプライトの要素自体には文字がありません。
結果の確認
- 書き出した
run.htmlを開きます。全クラスが4倍で、下に名前付きで描かれます。 - ブラウザを拡大します。
image-rendering: pixelatedなら縁は四角いままです。縁に隣の断片が少し見えるなら、位置を変えずにbackground-sizeだけを変えたか、間隔を0にしています。
トラブルシューティング
| 症状 | 考えられる原因 | 確認方法 | 対処 |
|---|---|---|---|
| 断片に隣の断片の一部が見える | 要素が断片より大きい、または位置を変えずにbackground-sizeだけ変えた | 要素の幅と高さをクラスと比べる | すべての数値を同じ倍率で変えるか、zoomやtransformで要素を拡大 |
| ドット絵がぼやける | 要素にspriteクラスがなく、image-renderingが効いていない | 開発者ツールで計算済みのimage-renderingを見る | spriteクラスを付ける |
| 何も表示されない | 画像のパスが違う:url("run.png")はCSSファイルからの相対パス | ネットワークパネルでrun.pngが404 | PNGをCSSの隣に置くか、urlを直す |
| フレームに別のフレームの断片が見える | 要素がsprite-page-0なのに、そのフレームはページ1にある | プレビューのHTMLでそのフレームに使われているページのクラス | プレビューがそのフレームに付けているページのクラスを使う |
ほかの方法
エンジン別の書き出しと検証方法
「検証済み」は、実際の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 / 4 | atlas JSON (multiatlas) · .anims.json | 検証済み Phaser 3.90 + 4.2両バージョンでフレームとアニメーションを描画。 |
| PixiJS 8 | spritesheet JSON · animations · anchor · meta.scale | 検証済み PixiJS 8.21回転・複数ページのアトラスも確認。 |
| Aseprite JSON | hash / array · frameTags · slices | 検証済み Phaser load.aseprite · PixiJS 8.21タグの方向と繰り返し回数を保持。 |
| .aseprite | layers · tags · durations · slices | 検証済み Aseprite 1.3.18Asepriteのコマンドラインで開いて描画。 |
| Spine / libGDX | .atlas | 検証済み spine-canvas 4.2Spineランタイムで回転・トリム領域をすべて描画。libGDX本体は未実行。 |
| Starling / Sparrow XML | XML per page | 検証済み Phaser 4.2Phaser 3.90はトリムされたXMLフレームを誤って描画します(Phaser側の不具合)。「Sparrow XML (Phaser 3)」プリセットはトリムを切り、3.90・4.2とも合格。 |
| LÖVE | Lua quads · nerulio_atlas.lua · main.lua | 検証済み LÖVE 11.5同梱ヘルパーで全フレームを描画し、全アニメーションを再生。 |
| Defold | .atlas · .tilesource | ビルド確認 Defold bob.jar 1.13.1Defoldのコマンドラインビルダーでビルドし、生成テクスチャのUVを読み戻して確認。 |
| GameMaker | spr_<name>_stripN.png · gamemaker.json | 未検証GameMakerでは読み込んでいません(ヘッドレス実行不可)。ストリップはGameMakerの取り込み方式どおりに切ります。 |
| CSS sprites | .css · preview .html | 検証済み Chromium同梱スタイルシートで全クラスを描画。 |
| GIF / APNG | one file per animation | デコード確認 Pillow書き出し後に全フレームと遅延を再デコード。APNGは完全一致。 |
検証の根拠
書き出し:実在のCC0アセットで実際のエンジンを49回実行し47回合格。失敗2回はPhaser 3.90のトリムXMLの不具合で、Phaser 3プリセットで回避。実在の5フレームセットでパッカー比較(CodeAndWeb無料Webパッカー、GAPTools、free-tex-packer):回転ありで5つすべて最小、回転なしで5つ中4つ。全フレームがピクセル単位で復元できます。
制限
- ポリゴン(メッシュ)パッキングはありません。検証したエンジンのどれも、書き出しデータからメッシュアトラスを描画しないためです。
- GameMakerのストリップはGameMaker本体では未検証です。
- 拡大縮小バリエーション(@0.5x〜@4x)はニアレストネイバーのみです。
- トリムしたStarling XMLはPhaser 3.90で正しく描画されないため、「Sparrow XML (Phaser 3)」プリセットを使ってください。
バージョンと出典
Chromium(Playwright)で書き出したスタイルシートをそのままリンクし、.sprite-…のルールごとに要素を1つ描いて、スクリーンショットを元画像と比較しました。ほかのブラウザはこの実行に含まれていません。image-renderingとbackground-positionの動作はMDNの説明に従います。
参照した公式ドキュメント
よくある質問
トリムがオフなのはなぜ?
CSSの要素ボックスはトリムのオフセットを持てず、トリムしたフレームがずれます。そのためCSSは常にフレーム全体を保ちます。
どのブラウザで確認しましたか?
同梱スタイルシートでChromiumで全クラスを描画し、スクリーンショットと比較しました。
無料ですか?アカウントは必要ですか?
このページの機能はすべて無料で、アカウントなしで使えます。透かしや制限された書き出しはありません。
スプライトはアップロードされますか?
いいえ。Studioはこのブラウザのタブ内でデコード・パック・書き出しを行います。プロジェクトはブラウザ(IndexedDB)に自動保存され、.nerulioファイルとして保存できます。
Asepriteやエンジンのプラグインは必要ですか?
いいえ。.asepriteファイルはブラウザで読み書きします。エンジン別のバンドルには必要なものが入っています(Godotはインポート設定とシーン、UnityとGodotのタイルセットは小さなエディタースクリプト)。