最近、なかなか面白い小実験をやってみました。
二次元キャラクターのちょっとしたアニメーション効果を、それぞれ:
- WebGL
- Canvas 2D
- 純 DOM + CSS
の3つの方法で実装し直しました。
効果自体は複雑ではありません:
- まばたき
- 眉毛/下まぶたの連動
- 汗のゆらゆらした揺れ
- アホ毛の振り動き
でも本当に面白いのは、「作れた」こと自体ではなく:
同じものを、3つの技術スタックで実装したとき、どれくらい差が出るのか?
というところです。
本質的には「フロントエンドグラフィクス色の濃い」再現実験でした。
最初はただアホ毛アニメーションを再現したかった
インスピレーション元:https://tamanidamani.itch.io/nijikas-ahoge
当時のシンプルな思い:「自分だったらどう実装する?」
そしてやるほどに熱中してしまい、最終的にこうなりました:
じゃあ、WebGL、Canvas2D、DOM の3パターン全部作ってみよう。
そうしてリポジトリは今の形になりました:
同じ効果を3つのバージョンで実装しています。
まず結論
一言でまとめるなら:
WebGL が最強だけど、Canvas2D が一番書きやすくて、DOM がビジネス向け
1. WebGL バージョン:「本当のゲーム開発」に一番近い
このバージョンが一番手間がかかります。
なぜなら本質的には「フロントエンドアニメーション」ではなく:GPU グラフィクスプログラミング だからです。
どう実装しているのか?
コアとなる考え方は:
- 背景レイヤー1枚
- スプライトを重ねていく
- shader で描画制御
- JS でアニメーションパラメータを動かす
例えば:
- アホ毛の回転
- まばたきの切り抜き
- alpha ブレンド
これらはすべて GPU 側で処理されます。
だんだんとこういうものに触れるようになります:
- uniform
- texture
- shader
- UV
- 頂点座標
- テクスチャ座標
そして笑顔が消えていきます。
でも WebGL は本当に強い
要素が増えてくると、WebGL の「全然平気」という感覚が際立ちます。
特に:
- 高解像度
- マルチレイヤー
- shader エフェクト
- パーティクル
- ポストプロセス
こういう場面では、
Canvas2D は息を切らし始め、
DOM はカクカクになり始めます。
WebGL はまだ平然と:「もっと来い」と言わんばかりです。
でも開発体験は……
正直に言えば:かなりハードコアです。
「なぜテクスチャが反転してるの?」というだけでも30分調べることになります。
なぜなら:
- 座標系が違う
- UV の向きが違う
- テクスチャの原点が違う
さらには:shader の変数名を1つ間違えると画面が真っ暗になる。 コンソールには人間の読める言葉ひとつ出ません。
2. Canvas2D:一番書いていて気持ちいいバージョン
ここは:「複雑さがちょうどいい」 ところです。
drawImage は本当に神器
このバージョンのコアは基本的に: ctx.drawImage(...)
ひたすら描いて、重ねて、切り抜くだけ。
まばたきはどう実装する?
ここはかなり気に入っています。
単純にスケールするのではなく:ソース画像を上から下へ切り抜いていく。 そして下端を固定。
こうすることで、単なる画像圧縮ではなく、本当の「目を閉じる」ように見えます。
こういう小さなディテールが、見た目の印象を大きく変えます。
アホ毛はどうやる?
Canvas2D での回転は非常にオーソドックス:
save()
translate()
rotate()
drawImage()
restore()
左下の支点を中心に回転。
おしまい。 考え方が非常に直感的です。
なぜ Canvas2D がスイートスポットだと思うか
「効果も出せるし、髪も抜けない」 というバランス感覚があるからです。
WebGL のように:「アニメーションを作る前に shader に教えられる」こともありません。
でも DOM のように:「後半はブラウザのレイアウトシステムと格闘する」こともありません。
Canvas2D は基本的に:
- デバッグしやすい
- ブラウザ互換性が高い
- 思考の負担が小さい
- 十分な自由度がある
だからこそ、多くのインディーゲームが好んで使うのも納得です。
3. DOM バージョン:「グラフィクスプログラミング」らしくないバージョン
このバージョンは実は一番面白いです。
canvas に一切頼らず、純粋に:
- HTML
- CSS
- JS
だけで作っています。
パーツは全部 div
例えば:
- 目
- 眉毛
- 汗
これらはすべて <div> で、
- background-position
- background-size
を使ってアトラスから切り抜いています。
目を閉じる実装は UI テクニックっぽい
このアプローチは自分でもかなり気に入っています。
overflow: hidden; でマスクを作り、
中のスプライトを下に動かすことで「上から下へ目を閉じる」を実現しています。
DOM の最大のメリット
本当のウェブページ に適しています。
例えば:
- UI システム
- ボタン
- テキスト
- レスポンシブレイアウト
これらとシームレスに融合できます。
でも DOM は確実に重くなる
特に要素が増えると:
- layout
- repaint
- composite
ブラウザが猛烈に再計算を始めます。
気づけば:CSS でゲームエンジンの半分を作っている自分 がいます。
3つの方案、結局どう選ぶ?
「どれがどれを圧倒する」というものではありません。
あるのは:今のプロジェクトが何に近いか だけです。
もしあなたが:
- 複雑なビジュアルエフェクトを作りたい →
WebGL - インディーゲームを作りたい →
Canvas2D - ウェブページ上でインタラクティブなキャラクターを作りたい →
DOM
このプロジェクトで一番感じたこと
実は、異なる技術スタックの背景には、
まったく異なるレンダリングの思考法があります。
- WebGL は考える:
GPU がどう描くか - Canvas2D は考える:
このフレームをどう描くか - DOM は考える:
ブラウザがどうレイアウト・合成するか
これらは同じ世界観すら違います。
おわりに
このリポジトリの本質は「アニメーションを作る」ことではなく、
実は次のことを研究するものでした:
ブラウザは一体どうやってものを画面に描いているのか。
コードと一緒に読むのがおすすめです:https://github.com/iAJue/CanvasGame
前回こんな比較をしたのはもう前回の話です:《如何优雅的提交一个表单》

