ガイド

HTML5ゲームを自分のサイトで公開する方法:設置・埋め込み・対処

静的なゲームフォルダの実践ガイド。置く場所、開き方、ページへの埋め込み方、起動しないときの確認点をまとめました。

パンダのPolarzinhoが、サーバーからブラウザのウィンドウへ向かう光るチューブにゲームの箱を押し込んでいるイラスト。ウィンドウには空に浮かぶ島のゲームが映っている。

HTML5ゲームの公開方法を一文で言うと、game/フォルダの中身を静的ファイルを配信できる任意のWebホストにアップロードし、サブフォルダはそのまま保ち、そのフォルダのアドレスをブラウザで開く、ということです。当社マーケットプレイスの全エディションにあるホスト可能なgame/フォルダは、そのまま動きます。PHP、データベース、ビルド手順、アカウントは不要で、ホストはプレイヤーのブラウザにファイルを渡すだけで済みます。

すべてがうまくいけば、作業はそれだけです。このガイドが扱うのは、そうならない日のことです。空白の画面、404エラー、MIMEタイプのメッセージ、何も表示しないiframeなどです。当社はこれらのテンプレートを販売しているので、自社パッケージのための現場マニュアルとしてお読みください。使い捨てのローカルサーバーからGridsparkとVelvet Poolを配信し、Gridsparkをわざと何通りかの方法で壊してみて、他のエディションの公開マニュアルも読みました。記述がマニュアルに由来し、当社自身のテストによるものでない場合は、そのつど明記しています。

HTML5ゲームのホスティングで実際にすること

静的ホストは、ファイルを保存し、リクエストに応じてブラウザに渡します。ゲームを実行するのはホストではなく、プレイヤーのブラウザです。当社エディションの動作要件がこれほどシンプルなのはそのためで、最新のブラウザ、HTTPまたはHTTPSで静的ファイルを配信するホストがあればよく、遊ぶのにPHP、データベース、アカウントは不要です。game/フォルダはビルド済みなので、公開にnpmもビルド手順もいりません。

始める前に知っておきたい制限が2つあります。一部のエディションには、静的ではない任意の部品があります。ZabumとRicopopには、PHP 7.4以上と書き込み可能なフォルダが必要な任意のランキングがあり、TypeScriptのエディション(Beep Out、Pinloop、Trimora、Twirldrop、Riffvolt、Sunset Rally、Tenguin、Mochi Monsters、Deepforge、Barricade Z、Zabum)は、ソースを編集して再ビルドする場合にだけNode.jsが必要です。バージョンは各マニュアルに書かれています。Velvet Pool、Puttide、Ricopop、Gridsparkは素のJavaScriptで出荷されており、編集とアップロードするファイルの間にコンパイルの工程はありません。納品されたままのゲームを公開するだけなら、これらは一切不要です。また、ホスティング自体は購入に含まれません。ストアの利用条件では、ホスティングとお客様のサーバーへのインストールは、作業前に見積もりをお出しする別サービスとされています。サポートが対象とするのは、提供したファイルのインストールと使い方に関するご質問です。

アップロードするものと、手元に残すもの:

  • game/の中身をすべてアップロードします。index.html、スクリプト、スタイル、画像、音声、フォントです。
  • source/(編集用の開発者向けコピー)、documentation/(マニュアル)、ZIPファイルそのものは含めません。Zabumのマニュアルは、source/を誤ってアップロードすることを、main.tsxなどの404エラーの原因のひとつに挙げています。
  • パッケージに付属する第三者のライセンス表示は、利用条件に従って、ご自身の製品と一緒に保管してください。

Gridsparkを見る(例として使うエディション)

HTML5ゲームを公開する:ZIPから遊べるページまでの最短ルート

以下の手順は、Velvet Pool、Puttide、Gridspark、Sunset Rallyのマニュアルのインストール章に沿い、テストで追加した確認を加えたものです。例にGridsparkを使うのは、当社が最も多く配信し、最も多く壊したエディションだからです。

  1. パソコンでパッケージを展開します。game/(公開するフォルダ)、source/(編集用のコピー)、documentation/(マニュアル)が入っています。
  2. 任意ですが手軽です。ローカルでテストします。game/の中でターミナルを開き、python -m http.server 8765を実行して、http://localhost:8765/ を開きます。そこで遊べるなら、ファイルは問題なく、あとで起きる問題はホスト側にあります。
  3. 最終的なアドレスを今のうちに決めます。たとえばhttps://your-site.example/games/gridspark/です。ゲーム内のパスは相対パスなので、サブフォルダでも動きます。Gridsparkのマニュアルはpublic_html/games/gridspark/を例にしています。
  4. ホストのファイルマネージャーまたはFTPクライアントで、game/の中身をそのフォルダにアップロードします。サブフォルダはすべてそのまま保ちます。index.htmlは、フォルダの直下に置かれる必要があり、1階層深くなってはいけません。
  5. フォルダのアドレスを、末尾のスラッシュつきでhttpsで開きます。Gridsparkでは、スタート画面をタップして(ブラウザは、音声を許可する前にタッチかクリックを待ちます)、Playを押します。
  6. 一手指して、ページを再読み込みし、メニューにContinueが出ることを確認します。これで、ブラウザがそのアドレスで進行状況を保存していることが分かります。
  7. サイトからそのフォルダにリンクするか、ページに埋め込みます(下のiframeの節を参照)。

完成したGridsparkのフォルダには、index.html、style.css、gridspark.config.js、src/、assets/が並んで入っており、マニュアルはそれらを一緒に保つよう求めています。他のエディションは構成が少し違います(Velvet Poolにはスタイルシート1つではなく、css/とassets/があります)が、ルールは同じです。フォルダは届いたままアップロードしてください。

index.htmlをダブルクリックすると、空白のページになる理由

開いてみたエディションは、コードをESモジュールとして読み込みますが、ブラウザはfile://のアドレスからモジュールを読み込むことを拒否します。Gridsparkをディスクから直接Chromiumで開くと、暗い空の画面になりました。コンソールには、スクリプトがCORSポリシーによってブロックされ、理由は「Cross origin requests are only supported for protocol schemes」(httpやhttpsなど)だと出ました。同じフォルダをローカルのWebサーバーから配信すると、スタート画面がすぐに表示されました。Velvet Pool、Puttide、Sunset Rally、Gridsparkのマニュアルはどれも同じことを述べています。ゲームをfile://から開かないでください。

  • 動かない例:file:///C:/Users/you/games/gridspark/index.html
  • 動く例:ローカルのテストサーバーのhttp://localhost:8765/、またはホスト上のhttps://your-site.example/games/gridspark/。

テストしたのはChromiumだけです。マニュアルはこのブロックを一般的なブラウザが行うものとして説明しているので、どこでも起こると考えて準備してください。

iframeでゲームをページに埋め込む

すでにあるページの中にゲームを表示するには、iframeでアップロードしたフォルダを指定します。テストしたタグは次のとおりです。

<iframe src="https://your-site.example/games/gridspark/" title="Gridspark" allow="fullscreen; autoplay" width="960" height="540" style="border:0"></iframe>

  • src:フォルダの完全なアドレス。httpsで、末尾のスラッシュつきです。
  • title:短い名前。スクリーンリーダーがフレームを説明するのに使います。
  • allow="fullscreen; autoplay":マニュアルは、iframeで必要な場合はフルスクリーンと自動再生を許可するよう述べています。テストでは、これがない別アドレスのフレームではフルスクリーンが無効になり、Gridsparkはフルスクリーンボタンを非表示にしました。古いallowfullscreen属性でも、allowと同じ結果でした。ページと同じアドレスのフレームでは、どちらでもフルスクリーンが使えます。
  • sandbox属性は付けません。sandbox="allow-scripts"だけだと、Gridsparkは起動しませんでした。フレームのオリジンがnullになり、ブラウザがゲーム自身のスクリプトをブロックし、ローカルストレージがセキュリティエラーを投げました。allow-same-originを加えると動きますが、MDNは、同一オリジンのフレームでこの組み合わせを使うと保護がなくなると警告しています。そのため、ご自身でホストするゲームでは、sandboxは使わないでください。

スマートフォン向けのサイズにする

固定の16:9の枠は、デスクトップでは正しく見えますが、スマートフォンでは合いません。幅390pxでは、aspect-ratio 16/9のiframeは高さがわずか219pxで、Gridsparkのメニューは「Daily challenge」ボタンの下で切れてしまいました。フレームの高さを75svh、つまり画面の高さの4分の3にすると、メニュー全体が表示されました。ご自身のページにも、viewportのmetaタグが必要です。開いた6つのパッケージはどれも、自身のindex.htmlにそれを含んでいるので、直接開いたときにゲームが拡縮されます。

2つのスマートフォン画面を並べたもの。どちらもiframeの中にGridsparkのスタートメニューが表示されたページで、左は16:9の低いフレームでメニューが切れており、右は高いフレームでメニュー全体が見えている。
同じゲーム、同じスマートフォンの幅。左:16:9のiframe。右:高さ75svhのフレーム。

ゲームは、周囲にページがなくても自分のアドレスで動くので、そのアドレスを開くただのリンクは、いつでも有効な代替手段です。

Velvet Poolを見る(同じ方法で埋め込める3Dのエディション)

WordPressなどのサイトビルダー

フォルダをホストすることと、ページに表示することは別の作業で、WordPressでは2つの異なるツールを使います。以下はすべて、WordPressのドキュメントと開発者向けリファレンスに基づいており、当社自身がWordPressを動かして確かめたものではありません。

  1. ホストのファイルマネージャーまたはFTPで、フォルダをサイトのフォルダツリーにアップロードします(たとえば、WordPressのフォルダの隣にgames/フォルダを作ります)。メディアライブラリからではありません。WordPressのコードは、ユーザーにunfiltered_html権限がない限り、許可されるアップロード形式から.htmlと.jsを外すためです。
  2. ページに触る前に、フォルダのアドレスを単独で開きます。WordPressが文書化しているApacheの標準ルールは、一致するファイルやフォルダが存在しない場合にだけリクエストをindex.phpに送ります(!-fと!-dの条件がそれを調べています)。そのため、アップロードしたフォルダはそのまま配信されます。
  3. iframeは「カスタムHTML」ブロックに追加します。WordPressは、unfiltered_html権限のないユーザー(たとえば寄稿者)の場合、投稿の保存時にiframeタグが取り除かれると説明しています。保存後にフレームが消えたら、誰がそのページを編集したかを確認してください。

その他のサイトビルダーやCMSについては、テストしておらず、どれについても何も主張しません。ゲームに必要なのはどこでも同じ2つ、アップロードしたフォルダの置き場所と、iframeを受け付ける埋め込み要素です。ビルダーがどちらも提供しないなら、静的ファイルを配信できる場所にフォルダをホストし、そのアドレスにリンクしてください。

起動しないとき:トラブルシューティングの一覧

何かを変更する前に、ブラウザの開発者ツール(ほとんどのデスクトップブラウザではF12)を開き、「Console」と「Network」のタブを見てください。以下のどの失敗も、そこに赤い行を残し、その中のファイル名が原因を示すことが多いです。

空白の画面

次の順に確認します。アドレスがhttp://またはhttps://で始まっているか。Consoleに赤い行がないか。ファイル名の大文字と小文字が正確に保たれているか。3Dのエディションでは、WebGL2が使えるか(Velvet Poolのマニュアルは、ハードウェアアクセラレーションを有効にするよう述べています)。Linuxのホストは、Game.jsとgame.jsを別のファイルとして扱いますが、Windowsは同じとみなします。そのため、パソコンで動いたフォルダが、アップロード後に壊れることがあります。Velvet PoolとZabumのマニュアルは、どちらも大文字小文字について警告しています。

src/main.js、フォント、画像の404

フォルダの一部が届かなかったか、1階層深く届いています。index.html、style.css、設定ファイルだけをアップロードして再現しました。画面は空白のままで、Networkタブにはsrc/main.jsとすべてのフォントの404が並びました。足りないフォルダをアップロードするか、index.htmlが開くアドレスの位置に来るよう、中身を1つ上に移してください。画像や音声が足りない、または壊れている場合、Zabumのマニュアルは、FTPをバイナリまたは自動モードにするか、ZIPをアップロードしてホストのファイルマネージャーで展開することを勧めています。404はファイルがないということで、MIMEの問題ではありません。

スタイルが適用されず、巨大なアイコンが出る

リライトやクリーンURLの設定により、末尾のスラッシュなしでフォルダが配信されると、相対パスが1階層上で解決されます。リダイレクトせずにフォルダのページを返すテストサーバーで再現しました。ブラウザは、/games/gridspark/内のファイルではなく、/games/style.cssと/games/src/main.jsを要求して404になり、メニューは素のボタンと大きすぎるアイコンで描画されました。フォルダには末尾のスラッシュつきでリンクするか、index.htmlを直接指定してください。

ブラウザのウィンドウに、スタイルのない灰色のボタンと大きすぎる黒いアイコンが並ぶ白いページが表示されている。スタイルシートが読み込まれていないGridsparkのメニュー。
末尾のスラッシュなしのアドレスで開いたGridspark(リダイレクトしないサーバー上):スタイルシートもスクリプトも読み込まれない。

モジュールスクリプトのMIMEタイプエラー

テストでは、コンソールに次のように出ました。Failed to load module script: Expected a JavaScript-or-Wasm module script but the server responded with a MIME type of "text/plain". ブラウザはモジュールスクリプトに厳格です。マニュアルによれば、サーバーは.jsファイルをJavaScriptのMIMEタイプで、.wasmをapplication/wasmで送る必要があり、Sunset Rallyのマニュアルは.mjsも挙げています。各ファイルのContent-Typeは、Networkタブで確認できます。開いたビルドでは、モジュールは.jsファイルです。ご自身で.mjsファイルを追加し、古いApacheの設定がそれを割り当てていない場合は、.htaccessの一行で直せます。当社のサイトが使っているものと同じです。

AddType text/javascript .mjs

テストマシンのApache 2.4.62のタイプ表では、jsとmjsはすでにtext/javascript、wasmはapplication/wasmに割り当てられていたので、標準のインストールならこの行は不要です。ほかのサーバーはそれぞれ独自の表を持っているので、運用している方にお尋ねください。

CORSポリシーによるブロック

別のアドレスから読み込むモジュールスクリプトやフォントには、そのアドレスからのAccess-Control-Allow-Originヘッダーが必要です。テストでは、あるポートのページは、2つ目のサーバーがそのヘッダーを送るまで、別のポートのモジュールスクリプトを読み込めませんでした。実際の対処は地味で、ゲームのファイルを1つのアドレスの1つのフォルダにまとめておくことです。パッケージはそのように作られています。別のサイトのiframeにゲームを埋め込むのにCORSは不要です。iframeはゲームのアドレスを読み込むだけだからです。埋め込みの中でCORSエラーが出るなら、たいていは、上で説明したsandbox属性が原因です。

httpsページでの混在コンテンツ

httpsで配信されるページは、httpでスクリプトやiframeを読み込めません。ブラウザはどちらもブロックし、MDNはフォントとfetchリクエストもブロック対象の種類に挙げています。iframeのsrcにも、入力した完全なアドレスにも、https://を使ってください。ゲーム自身のファイルは相対パスを使うので、開いたアドレスのスキームに従います。httpsのアドレスがまったく開かない場合は、先にホストの管理画面で証明書を有効にしてください。

iframeに「refused to connect」と出る

テストでは、Chromiumが次の行を記録しました。最初の引用符の中に、ブロックされたフレームのアドレスがあります。Refused to display 'https://game-host.example/' in a frame because it set 'X-Frame-Options' to 'sameorigin'. ゲームをホストしているサーバーがそのヘッダーを送っていました。SAMEORIGINは同じアドレスからの埋め込みだけを許可し、DENYはいかなる埋め込みも許可しません。Content-Security-Policyヘッダーのframe-ancestorsルールも、同様の働きをします。ゲームのフォルダのヘッダーを変更するか、ページとゲームを1つのアドレスから配信してください。

最初は音が出ない

ブラウザは、最初のタップやクリックまで音声をブロックします。Gridsparkがタップでスタートする画面から始まるのはそのためです。一度タップし、音量とブラウザの権限を確認してください。

Puttideを見る(ホスト可能なビルド付きのゴルフのエディション)

古いバージョンが混ざらないようにゲームを更新する

ブラウザはスクリプトをキャッシュするため、アップロード後も、ご自身やプレイヤーが古いゲームを見ていることがあります。Gridsparkのマニュアルは次のルールを示しています。編集内容をバックアップし、遊べるファイルをひとまとめに置き換え、テストし、ホストが古いモジュールをキャッシュしている場合は強制再読み込みをします。古いモジュールと新しいモジュールを混ぜないでください。互いにインポートし合う小さなファイルでできたゲームを、途中まで更新するのは間違いです。

サービスワーカーのあるエディションは、独自のキャッシュを持ちます。ZabumはPWAで、更新後は強制再読み込み(CtrlまたはCmdにShiftとRを加えたもの)をしてください。音声ファイルを置き換えた場合は、sw.js内のキャッシュ名を変更して(マニュアルの例ではzabum-v5からzabum-v6へ)、そのファイルをアップロードします。サイトがCDNの背後にあるなら、そのキャッシュもパージしてください。読んだマニュアルのうち、PWAなのはZabumだけです。Velvet PoolとPuttideのマニュアルは、インストール可能なオフラインアプリではないと明記しています。

ファイルを置き換える前に変更履歴を読み、編集したものはコピーを残しておいてください。セーブデータは、アップロードするフォルダではなく、各プレイヤーのブラウザにあるため、ファイルを置き換えても消えません。

Zabumを見る(任意のPHPランキングを備えたPWAのエディション)

進行状況の保存場所と、ブラウザのデータを消した場合

これらのエディションにはアカウントもサーバー側のデータベースもありません。設定、言語、現在のプレイ、自己ベストはブラウザのローカルストレージにあり、Polar Gamesには何も送られません。Gridsparkのマニュアルはキーをgridspark.standalone.v1.*と記載しており、一手指したあと、gridspark.standalone.v1.bestとgridspark.standalone.v1.saveが確認できました。

Gridsparkのメインメニュー。Continueボタン、New gameのリンク、Daily challengeのボタン、保存されたベストスコア3,257が表示されている。
再訪すると、メニューにContinueと保存されたベストスコアが出ます。どちらもブラウザから読み込まれています。

ストレージは、フォルダではなく、アドレス(プロトコル、ホスト、ポート)に紐づきます。3通りで確認しました。同じアドレスの別フォルダにあるGridsparkのコピーは、同じ保存値を読み込みました。同じゲームを127.0.0.1ではなくlocalhostで開くと空の状態から始まり、同じアドレスでポートが違う場合も同様でした。Zabumのマニュアルは、httpとhttps、wwwとwwwなし、サブドメインが、それぞれ別のストレージを持つと付け加えています。

  • サイトデータやCookieを消すと、保存したゲームと記録が消えます。プライベートウィンドウでは、進行状況がそのセッションの間しか残らないことがあります。ストレージがブロックされていても、ゲームは動き続けます。
  • 別のブラウザや別のデバイスでは、ゼロから始まります。同期はなく、サインインするアカウントもありません。
  • アドレスを変えると、全員がリセットされます。httpからhttps、wwwからwwwなし、新しいドメインへの移行などです。
  • 同じアドレスの別フォルダにゲームを移しても、セーブは残ります。Gridsparkのテストで確認したとおりです。

リンクを共有する前のテストチェックリスト

  1. 最終的なアドレスを、プレイヤーが使うブラウザで開きます。Chromium系(ChromeまたはEdge)、Firefox、Safariです。当社自身のテストはChromiumだけだったので、このリストはお客様が実行するためのものです。
  2. 実際のスマートフォンで開きます。まずゲーム自身のアドレスで、次にご自身のページの中で、縦横の両方の向きで確認します。
  3. 開発者ツールで回線を絞り、最初の読み込みを観察します。Gridsparkは、当社のローカルサーバーから圧縮なしで配信すると、スタート画面に到達するまで約0.5MBと26リクエストでした。Chromiumを1.6Mbit/s、遅延150msに絞ると、画面が出るまで約3秒でした。game/フォルダ全体は、当社のコピーで約3.4MBで、Velvet Poolは約7.3MB、Puttideは約15MBです。古いスマートフォンで厳しい場合、Zabumのマニュアルは、ホストがgzipまたはbrotliでファイルを圧縮しているかを確認するよう勧めています。
  4. 一手指して再読み込みし、Continueとベストスコアがあることを確認します。
  5. 一度タップして、音が出ることを確認します。最初のタップの前に音が出ないのは普通です。
  6. プライベートウィンドウを開きます。閉じたときに進行状況を忘れるとしても、ゲームは動くはずです。
  7. 最初の読み込みで、ConsoleとNetworkのタブを読みます。赤い行も404もないことを確認します。
  8. 埋め込みでは、フルスクリーンボタンが出ること、スマートフォンでフレームが十分な高さであることを確認します。

FAQ

HTML5ゲームのホストに、PHP、データベース、特別なサーバーは必要ですか

納品されたままの当社エディションには不要です。静的なので、game/フォルダをHTTPまたはHTTPSでファイルを配信するホストにアップロードして開くだけです。ZabumとRicopopの任意のランキングには、PHP 7.4以上と書き込み可能なフォルダが必要です。

index.htmlをダブルクリックして開くだけではだめですか

だめです。ブラウザはfile://でゲームのモジュールをブロックし、ページは空白のままです。ホスト、またはpython -m http.server 8765のようなローカルのテストサーバーを使い、httpまたはhttpsのアドレスでゲームを開いてください。

HTTPSは必要ですか

マニュアルは、公開のホスティングにはHTTPSを使うよう述べています。Zabumのマニュアルは、「ホーム画面に追加」にはHTTPSが必要だと述べており、httpsのページは、混在コンテンツとしてブラウザがブロックするため、httpのiframeを埋め込めません。

WordPressのページにゲームを追加するには、どうしますか

ホストのファイルマネージャーまたはFTPでフォルダをアップロードし、そのアドレスを開いて遊べることを確認してから、「カスタムHTML」ブロックにiframeを追加します。unfiltered_html権限のないユーザーはiframeが取り除かれるので、ページを編集する人の権限を確認してください。

進行状況はどこに保存され、プレイヤーがブラウザのデータを消したらどうなりますか

ブラウザのローカルストレージに、アドレスごとに保存されます。サイトデータを消すと消え、別のブラウザやデバイスは空の状態から始まり、ドメインを変えたりhttpとhttpsを切り替えたりするとリセットされます。アカウントはなく、当社には何も送られません。

Polar Gamesがゲームをホストしてくれますか

いいえ。ストアが販売するのはファイルです。サポートが対象とするのは、インストールと使い方に関するご質問です。ホスティングとお客様のサーバーへのインストールは別サービスで、作業前に見積もりをお出しします。

次のステップ

自分のサイト用のHTML5ゲームをまだ選んでいる最中なら、各商品ページに動作要件の一覧、マニュアルへのリンク、支払い前に遊べるデモがあります。まずマニュアルのインストール章を読んでください。このガイドの作業で使うのは、そのページです。

HTML5ゲームテンプレートを見る