画像を1枚も使わずに世界を描く — Canvasだけの落書きグラフィック

公開: 2026年10月25日 ・ 筆者: Toshi(開発者)

バズ走には画像ファイルが1枚もありません。東京タワーも、ピラミッドも、月も太陽も、棒人間も、すべて Canvas 2D API の円弧・直線・ベジェ曲線で描いています。「素材を持たない」という制約から生まれた描き方と、その結果として手に入った軽さについて書きます。

なぜ画像を使わないのか

最初の目的は読み込み時間をゼロに近づけることでした。画像を1枚でも読み込むと、回線によっては表示までに1〜2秒かかり、その間に離脱されます。全部コードで描けば、HTMLが届いた瞬間に描画が始まります。

やってみて分かった副次的な利点が2つあります。1つは統一感。線の太さ・色・ゆらぎをコードで共通化しているので、どのステージも同じ「落書き帳」の世界に見えます。もう1つは追加コストの低さ。新しい都市を足すのに素材を探す必要がなく、数十行の描画関数を書くだけで済みます。

手描きらしく見せる「ずらして重ねる」

完全な円を1本描くと、どうしてもCGらしい硬さが出ます。太陽は「中心をわずかにずらした円弧を3本重ねる」だけで、手でぐるぐる描いたような質感になりました。この考え方は他の要素にも応用しています。

重要なのは、ゆらぎを Math.random() で毎フレーム変えないことです。毎フレーム変えると線がチラついて「ノイズ」になります。ゆらぎは描画位置から決まる固定値にして、同じ場所は常に同じ形に描いています。

配色は3色+1色だけ

用途色
背景(紙)#f4f2ec クリーム色
線画・地面・棒人間#111111 ほぼ黒
アクセント(鉢巻・★・強調)#d32f2f 赤
遠景の建物#8f8b80 灰色

色数を絞ると、ステージが変わっても世界観が崩れません。赤は「主人公の鉢巻」「三段ジャンプの★」「自己ベスト更新中」など、プレイヤーが注目すべきものだけに使う、というルールにしています。宇宙ステージでも背景は黒ではなく同じクリーム色で、星や惑星を線で描くことで「夜空の落書き」として表現しました。

ランドマークの描き方

全22ステージには、それぞれ一目でどこか分かる建造物を置いています。描画はすべて「基準点(x, y)とスケール」を受け取る関数で、ステージ切り替え時に遠景として描かれます。

どれも「描き込まない」のがコツです。情報量を減らすほど、見る側が記憶の中の形で補完してくれます。

棒人間とアニメーション

主人公は drawPlayer 関数が描いています。頭は塗りのない円、体と手足は線幅一定・端が丸い線。走りは「脚の角度を距離に応じて周期的に振る」だけですが、鉢巻を速度に応じて後ろへ長くなびかせることでスピード感を出しています。三段ジャンプでは胴体ごと回転させ、何段目かを見た目で分かるようにしました。ジャンプの軌跡や着地の土煙は drawFx が担当し、こちらも円弧と短い線だけです。

縦画面ではカメラを引く

スマートフォンの縦画面では、横長のパソコン画面に比べて前方の視認距離が短く、障害物が見えた瞬間には避けられません。解決策はゲーム内部の座標はそのままに、描画だけ縮小することでした。画面幅が狭いときは全体を約1.7倍引いて描き、見える範囲を広げます。物理計算には一切手を入れていないので、端末による有利不利はほぼありません。

実装は、画面幅に応じて決めた倍率(900px以上で1.0、600px以上で0.8、それ未満で0.62)を描画座標に掛けるだけです。ただし文字やUIまで縮むと読めなくなるので、UIはCanvasの外にHTMLで重ねています。ゲーム画面はCanvas、ボタンや文字はHTML、という分担が結果的に多言語対応でも役に立ちました。

毎秒60回描いても重くならない工夫

この結果、ゲーム本体のHTMLは約100KBに収まりました。画像ゼロなので、通信が細い環境でもタップした次の瞬間に走り始められます。

次の記事:サーバーを1台も持たずに5人対戦 — Durable Objectsの使い方と落とし穴

⚽ いますぐ走る