マガジン

13作品のHTMLは何KBか:一つのファイルの重さ

遊びを見つける

執筆にClaudeを使用しています。

二つの小さなゲーム盤を糸でつないだ、オンライン対戦のイメージ。
記事のテーマをもとに制作したAI生成イメージ。実際のゲーム画面ではありません。

アソバースの公式作品13本は、どれも独立したHTMLで、外部通信なしに動きます。つまり1本のゲームが1つのファイルに収まっているということです。そこで、13本のファイルを重い順に並べる場面を考えてみます。いちばん重いのは、オンライン対戦のある作品でしょうか。それとも音を扱う作品でしょうか。あるいは、機能は多くないのに、思いがけない部分が容量を使っているかもしれません。 この記事は、その順位表を読者が自分で作るための分析の手順です。数値の結果は載せません。確かめるのは、次の2点です。 測る前に順位を予想し、測ったあとで外れた理由を探すと、ファイルサイズの数字が作品の設計を読む手がかりになります。自作ゲームを投稿する人にとっては、アップロード上限との距離を測る練習にもなります。

この記事の目次
  1. 「重さ」を三つに分けてから数える
  2. 測る前に順位を予想する
  3. 手元にHTMLを用意し、内訳を数える
  4. 記録表と結果の読み方
  5. 起こりやすい誤り
  6. 次の行動
  7. 参考資料

「重さ」を三つに分けてから数える

「HTMLの重さ」という言葉は、少なくとも三つの意味で使われます。最初に区別しておかないと、記録した数字が比べられなくなります。

  1. ファイルサイズ(展開後):ファイルをそのまま保存したときのバイト数です。この分析の主役です。
  2. 転送サイズ(圧縮後):ブラウザがネットワークから受け取ったバイト数です。サーバーが圧縮して送ると、ファイルサイズより小さくなることがあります。
  3. 読み込みの重さ:実際に開いて遊べるまでの待ち時間です。ファイルサイズだけでなく、端末の性能や処理の中身にも左右されるため、この記事では扱いません。

単位にも注意が必要です。1KBを1,000バイトとする場合と、1KiB(キビバイト)を1,024バイトとする場合があります。アソバースのアップロード上限は「20MiB以内」「1ファイル30MiB以内」のようにMiB(1,048,576バイト)で示されています。上限と比べたいなら、記録する側もKiBかMiBにそろえるのが安全です。この記事では、記録の単位をKiBに統一します。題名の「KB」は、日常的な呼び方に合わせたものです。

もう一つ、日本語を含むファイルの特性があります。UTF-8という一般的な文字コードでは、半角英数字は1文字1バイトですが、日本語の文字は多くの場合1文字3バイトを使います。13作品は日本語と英語の表示切り替えに対応しているため、両方の文言を持っていれば、その分がファイルサイズに入ります。この仕組みが実際の順位にどう効くかは、測って確かめる部分です。

測る前に順位を予想する

測る前に、13本を重いと思う順に並べて紙に書いてください。予想が外れたとき、どの思い込みが外れたかを見るための記録になります。

予想の手がかりには、確認済みの機能の違いが使えます。次のような観点です。

  • 判定エンジンを同梱している作品はあるか(灯りのチェスはchess.jsを同梱しています)。
  • 音を扱う作品はどれか(雨音のピアノ、こだまの森、WAVE / WAVE)。音が合成なのか、データとして埋め込まれているのかは、ここでは決めつけません。
  • 画面や段階の数が多い作品はどれか(8ステージ、6レシピ、3つの星系など)。
  • 保存機能を持つ作品はどれか(余白の庭、WAVE / WAVE、かたちのあいだ)。
  • オンライン対戦の画面を持つ作品はどれか(潮目のオセロ、灯りのチェス)。

ここで立てる予想は、仮説です。たとえば「機能が多い作品ほど重い」「音のある作品ほど重い」「判定エンジンを同梱した作品は突出して重い」といった形で書いてください。検証の方法は、次の節以降に示します。

予想には、順位だけでなく「いちばん大きな部分は何か」も添えておくと効果的です。「プログラムが大半だろう」「絵のデータだろう」といった一言で十分です。

手元にHTMLを用意し、内訳を数える

ファイルサイズを取り出す

作品はサイト上でsandbox付きのiframeの中で動いており、アップロードされたコードはメインサイトとは別のオリジンから配信されます。そのため、ページ全体を保存しても、測りたいゲームのHTMLではなく外側のページを保存してしまうことがあります。測る対象が本当にゲーム本体のHTMLか、必ず確認してください。

確実な方法は、ブラウザの開発者ツールのNetworkタブを使うことです。

  1. 作品のページを開く前に、開発者ツールを開いてNetworkタブを表示します。
  2. 「Disable cache」(キャッシュを使わない)にチェックを入れてから、作品を開きます。
  3. 読み込み一覧の中から、種類が「document」のリクエストのうち、作品本体と思われるものを探します。外側のページと作品のHTMLが両方並ぶことがあるため、配信元のドメインや名前を見て判断します。
  4. 「転送サイズ」と「リソースのサイズ」(展開後)の2列を、どちらも記録します。

この列の名前や、保存の操作の細かな呼び方は、ブラウザの種類やバージョンで異なります。見つからない場合は、使っているブラウザの開発者ツールの案内を確認してください。HTMLを手元に保存して調べるのは、個人の確認用にとどめ、再配布はしないでください。作品の権利の扱いは、サイトの現在の案内で確認します。

自分が投稿した作品なら、手元のファイルをそのまま測れます。その場合は、次の道具をそのまま使えます。

内訳を数える小さな道具

手元にHTMLファイルがあるとき、中身を「script」「style」「データURI」に分けて数える最小の道具です。次のコードを breakdown.html のような名前で保存し、ブラウザで開いて、測りたいHTMLを選んでください。外部通信はしません。

html
<!doctype html>
<meta charset="utf-8">
<title>HTMLの内訳</title>
<input type="file" id="f" accept=".html,.htm" multiple>
<pre id="out">HTMLファイルを選んでください</pre>
<script>
const enc = new TextEncoder();
const size = s => enc.encode(s).length;
const kib = n => (n / 1024).toFixed(1).padStart(8);
function total(text, re, pick) {
  let sum = 0;
  for (const m of text.matchAll(re)) sum += size(pick ? pick(m) : m[0]);
  return sum;
}
document.getElementById("f").addEventListener("change", async e => {
  const rows = ["名前 | 全体KiB | script | style | データURI | 非ASCII文字数"];
  for (const file of e.target.files) {
    const t = await file.text();
    rows.push([
      file.name, kib(file.size),
      kib(total(t, /<script[^>]*>([\s\S]*?)<\/script>/gi, m => m[1])),
      kib(total(t, /<style[^>]*>([\s\S]*?)<\/style>/gi, m => m[1])),
      kib(total(t, /data:[a-z]+\/[\w.+-]+;base64,[A-Za-z0-9+\/=]+/gi)),
      [...t].filter(c => c.charCodeAt(0) > 127).length
    ].join(" | "));
  }
  document.getElementById("out").textContent = rows.join("\n");
});
</script>

この道具は、正規表現で文字列を拾う近似です。HTMLを厳密に解析してはいません。「データURI」は、画像や音をテキストに変換してHTMLの中へ直接書き込む方式の部分を指します。画像や音を別ファイルとして置かず、1つのHTMLに収めるときによく使われる方法です。

記録表と結果の読み方

測った数字は、作品ごとに次の表の形で記録します。1作品につき1行、計測は同じ条件で最低2回行い、一致を確かめてください。

  • 展開後サイズ、記録の単位:KiB(小数1桁)、意味:ファイルそのものの重さ
  • 転送サイズ、記録の単位:KiB(小数1桁)、意味:圧縮の効き具合を見る
  • script、記録の単位:KiB、意味:プログラム部分
  • style、記録の単位:KiB、意味:見た目の指定
  • データURI、記録の単位:KiB、意味:埋め込まれた画像・音などの候補
  • 残り、記録の単位:KiB、意味:全体から上の3つを引いた値
  • 非ASCII文字数、記録の単位:文字、意味:日本語などの文言量の目安

「残り」は、マークアップ(画面の骨組み)と文言が中心になります。scriptの中にデータURIが書かれている場合は二重に数えられるので、合計が全体を超えることがあります。そのときは重複していると読んでください。

結果の読み方

表が埋まったら、次の順に読み比べます。

  • 展開後サイズの順位を、予想と照らす。 当たった作品より、大きく外れた作品に注目します。外れた理由が、設計の手がかりになります。
  • 最大の項目を見る。 scriptが最大なら、ロジックの量が重さを決めています。データURIが最大なら、埋め込んだ素材が重さを決めています。「残り」が最大なら、文言や画面の骨組みの量が効いています。
  • 灯りのチェスのscriptを読む。 chess.jsを同梱しているため、scriptの中に判定エンジンが含まれています。ほかの作品のscriptと比べて、その比率がどうなるかは、測ってから判断します。
  • 転送サイズと展開後サイズの差を見る。 差が大きい作品は、繰り返しの多い文字列が多く、圧縮が効いていると読めます。差がほとんどない作品は、すでに圧縮に近い形のデータ(画像など)が多いか、圧縮されずに配信されている可能性があります。どちらなのかは、データURIの列と合わせて判断します。
  • 非ASCII文字数を見る。 日本語と英語の両方の文言を持つ作品は、この数が増えます。ただし記号や絵文字も数に入るため、「文言の量」の目安にとどめてください。
  • 保存機能の有無と重さを並べる。 保存のある3作品(余白の庭、WAVE / WAVE、かたちのあいだ)が上位に偏るかを見ます。偏らなければ、保存機能はサイズを左右する主因ではないと読めます。

最後に、各作品のサイズをアップロード上限(20MiB=20,480KiB)と並べて、何分の一かを計算してみてください。投稿の目安にもなります。上限が、作品の大きさに対してどれだけ余裕のある数字なのかが、実感として分かります。

起こりやすい誤り

数字の集計では、次の誤りが起こりやすくなります。

  • KBとKiBが混ざる。 ブラウザの表示がkB(1,000単位)か、自作の道具がKiB(1,024単位)かを確かめ、1つの表では必ず片方にそろえます。
  • キャッシュの影響。 キャッシュが使われると、転送サイズが0や極端に小さく表示されます。Disable cacheを有効にして測り直してください。
  • 外側のページを測る。 iframeの外側のHTMLを測ると、ゲーム本体の数字になりません。対象が作品のHTMLであることを、毎回確認します。
  • 1回の計測で決める。 拡張機能や通信状況が影響することがあります。同じ条件で複数回測り、一致を確かめます。
  • 正規表現を過信する。 近似の道具なので、内訳の合計は全体と完全には一致しません。細かな差ではなく、どの項目が大きいかの傾向を読む用途に使います。
  • サイズを品質と結びつける。 軽いから良い作品、重いから悪い作品ではありません。素材を埋め込んでいるのか、判定を丁寧に作っているのかは、サイズだけでは判断できません。

次の行動

まず13本の予想順位を書き、1本でもよいので作品のHTMLの展開後サイズと転送サイズを測って、予想と照らしてみてください。投稿を考えている人は、自作のHTMLを上の道具に読み込ませ、最も大きな項目と上限との距離を確かめることをおすすめします。

参考資料

  • ブラウザ開発者ツール(Networkパネル)の公式ドキュメント
  • MDN Web Docs「データURL」「TextEncoder」