結晶洞窟

ケーススタディ

音を使わずに、手応えを作る

聴覚障害のある制作者が、音をいっさい使わない放置ゲームを作りました。何を制約として引き受け、どこで判断したかの記録です。

作ったもの
ブラウザで動く放置ゲーム(HTML 1ファイル、約8,000行)
使った技術
HTML / CSS / JavaScript / Canvas 2D。フレームワークもビルドツールも使っていません
外部への依存
Webフォント1つだけ。サーバーもデータベースもAPIもありません
対応言語
日本語・English・简体中文・한국어・Español の5言語
期間
2026年9月(設計と実装)

前提にあった3つの制約

作りはじめる前に、動かせない条件が3つありました。どれも後から足せるものではなく、最初の設計に効いてくるものです。

1. 音を使えない

私は聴覚障害があります。音で手応えを返すゲームは、私自身が楽しめません。効果音を付けて「自分には聞こえないけど、たぶんいい感じだろう」と想像しながら作るのは、作り手として誠実ではないと思いました。

だから最初から音を使わないと決めました。消極的な除外ではなく、「視覚だけで手応えを成立させる」という設計課題として引き受けました。

2. メンテナンスを最小限にしたい

私はプログラミング未経験です。作ったものが壊れたとき、自分で原因を突き止めて直せる保証がありません。加えて求職中で収入の見込みがないため、月額のかかるサーバーも借りられません。

この2つを合わせると、答えはひとつでした。そもそも壊れる箇所を作らない。

サーバーを一切使わないと決めました。ログインもなし、データベースもなし、外部APIもなし。セーブはブラウザの中だけ。読み込むものはWebフォント1つだけ。

この判断は、単に楽をするためのものではありません。技術的に何かあっても、自分の手に負える範囲に収まるようにするためです。サーバーがなければサーバーは落ちませんし、外部サービスを使っていなければ、その仕様変更に振り回されることもありません。公開したあと放っておいても、数年後に開いてたぶん同じように動きます。

3. 自分が使えるものにする

アクセシビリティを「余裕があれば足す機能」にしたくありませんでした。自分が当事者なので、後回しにすると自分が困ります。最初から組み込みました。


判断1:音の代わりに何を返すか

タップしたときの手応えは、ふつう音が担います。音を抜くと、そこに穴が空きます。何で埋めるかを考えました。

結論は「ひとつの動作に、性質の違う反応を3つ重ねる」でした。タップすると次の3つが同時に起きます。

  • 結晶が一瞬ふくらむ — 押した対象そのものが反応する(触った感触の代わり)
  • 粒子が弾ける — 押した位置から放射状に飛ぶ(力が加わった証拠)
  • 数字が浮かび上がる — 「+120」が上に流れて消える(結果の確認)

3つとも視覚ですが、担当している意味が違います。ひとつ消しても他の2つが残るので、どこかを見落としても手応えが途切れません。

浮かぶ数字には縁取りを入れました。背景の色は鉱脈ごとに変わるので、縁取りがないと条件によって数字が読めなくなるからです。

判断2:色だけで情報を伝えない

「買える設備」を緑、「買えない設備」を灰色にする——よくある表現ですが、色覚特性によっては区別できません。

買える設備には値段の前に「▸」を付けました。枠線も変わり、明度も変わります。色が見えなくても、記号と形で分かります。

同じ考えで、選択中の設定項目にはチェックマークが入ります。一時停止中は画面全体が暗くなり、なおかつ「一時停止中」という文字が出ます。状態を色だけで示している箇所は、最終的にひとつも残りませんでした。

判断3:文字サイズは全体を動かす

文字を大きくする機能はよくありますが、本文だけが大きくなって数字やボタンが小さいまま、ということがあります。

このゲームでは、CSSのカスタムプロパティひとつで画面全体の文字が拡大します。

--fs という倍率を用意し、すべての文字サイズを calc(14px * var(--fs)) のように定義しました。4段階のボタンはこの倍率を 0.92 / 1 / 1.14 / 1.32 に切り替えるだけです。

Canvasに描いている浮かぶ数字も、同じ倍率を読んで描画サイズを変えます。HTMLとCanvasという別々の仕組みが、ひとつの値で揃います。

判断4:コントラストを後から測って直した

最初に作った配色は、見た目は良かったのですが、薄いグレーの文字が背景に溶けていました。実際に測ると、コントラスト比が2.8:1しかない箇所がありました。WCAGの基準は4.5:1です。

すべての文字色を測り直し、基準を下回っていたものを明るくしました。さらに純黒×純白の「高コントラスト」配色を2つ追加しました。見た目を優先した配色と、読みやすさを最大にした配色の両方を用意して、選べるようにするという解決です。

判断5:セーブコードを312文字から47文字へ

別の端末に移すためのセーブコードは、最初はゲームの状態をJSONにしてBase64で変換していました。これが312文字ありました。手で扱うには長すぎます。

中身を見ると、ほとんどが {"crystals": のような繰り返しのラベルでした。値の順番さえ決めておけば、ラベルは要りません。

そこで、19個の数値を36進数(0〜9とa〜z)に変換して、ハイフンでつないだだけの形式に変えました。末尾2文字はチェックサムで、打ち間違いを弾きます。

CC2-16j8-247h-qglk-c-y-2-14-p-e-6-2-0-0-8o-1-7-0-tlqv01-0i

312文字が47〜60文字になりました。約6分の1です。古い形式のコードも読めるようにしてあるので、すでに控えを取っていた人が困ることはありません。

判断6:5言語を、後から足さなかった

多言語対応を後から足すと、文章がコードのあちこちに散らばっていて、全部拾い出す作業になります。それを避けるため、表示される文字をすべて1か所の翻訳テーブルに集めました。

翻訳したのはUIだけではありません。設備の名前と説明、鉱脈の名前、イベントの名前、遊び方の全文、共有用の文章まで含みます。

数字の単位も、はじめは言語ごとに変えていました。日本語は万・億・兆、英語は K・M・B。「1万」を英語話者に見せても伝わらないからです。

ところが実際に並べてみると、別の問題が見えました。どの単位も、読む人がその約束ごとを知っていることを前提にしているのです。日本語話者が「10K」で一瞬つまずくのと同じことが、英語話者の「1万」でも起きます。数字を読み違えるゲームで、数字が読み違えられては話になりません。

最終的に単位をやめ、桁をそのまま出すことにしました。「600,000,000」は長いけれど、どの言語の読者にとっても同じ意味です。長さのほうは、桁数に応じて文字を小さくし、収まらない箇所は折り返すことで解決しました。区切り記号だけは各言語の標準に合わせています。


途中で見つけた2つのバグ

整数の末尾のゼロが消えていた

「3000億」が「3億」と表示されていました。原因は数字を整形する関数です。

小数点以下の余分なゼロを消すために replace(/\.?0+$/, '') という処理を入れていたのですが、これが整数の末尾のゼロまで消していました。「3000」が「3」に、「1200万」が「12万」になっていたのです。

初版から入っていた不具合で、小さい数字では表に出ないため気づきにくいものでした。小数点を含む場合だけ処理するよう直しました。

HTMLのタグを1文字閉じ忘れていた

鉱脈到達や再結晶の演出が出なくなっていました。調べると、> を1文字書き忘れていて、続く3行がタグの属性として吸い込まれていました。

ブラウザはエラーを出さずに解釈するので、画面上は何も壊れて見えません。JavaScriptから要素を探したときに初めて null が返り、そこで処理が止まっていました。

さらに厄介だったのは、この停止が同じ関数の後半の処理も巻き込んでいたことです。「周回数が増えない」という別のバグに見えていたものが、実は同じ原因でした。表に出た症状と原因が離れている例です。


数字で見る

項目
HTMLファイル1個(約8,000行)
外部から読み込むものWebフォント1つだけ
対応言語5
配色5(うち高コントラスト2)
文字サイズ4段階
鉱脈12
セーブコードの長さ47〜60文字
サーバー費用0円

作ってみて

音を使わないという制約は、最初は「できないこと」でした。作り終えてみると、「視覚だけで手応えを作る」という具体的な設計課題に変わっていました。制約があったから、タップの反応を3つ重ねるという解き方にたどり着けたのだと思います。

アクセシビリティも同じです。自分が当事者だったので後回しにできず、結果として最初から組み込まれました。後から足すより、ずっと安く付きました。

サーバーを使わないという判断も、維持費のためだけではありませんでした。外部に依存しないので、公開したあと放っておいても壊れません。数年後に開いても、たぶん同じように動きます。

このゲームはこのサイトのトップページでそのまま遊べます。登録は不要です。気づいたことがあればお問い合わせからお知らせください。