3Dなのにドット絵、売上で進む年表、ゲームオーバーに聞こえた効果音。「Web屋一代記」の作り方・技術編
Claudeと作ったブラウザゲーム「Web屋一代記」の中身を解説します。HTML1枚の組み立て方、値段と年の計算式、three.jsでドット絵に見せる設定、時代ごとのBGMの切り替え、そしてAIが音を聴けずに「ゲームオーバーの音」を選んでしまった話まで。

この記事の結論
- Claudeと作ったゲーム「Web屋一代記」の、中身の作りを解説する
- カギは計算と見た目を分けたこと。だから途中で2Dから3Dに作り替えても、ゲームの計算は一行も変えずに済んだ
- 最後に、AIが音を聴けないまま「ゲームオーバーの音」を選んでしまった話と、どう直したかも書く
- Claudeと作ったゲーム「Web屋一代記」の、中身の作りを解説する
- カギは計算と見た目を分けたこと。だから途中で2Dから3Dに作り替えても、ゲームの計算は一行も変えずに済んだ
- 最後に、AIが音を聴けないまま「ゲームオーバーの音」を選んでしまった話と、どう直したかも書く
前回の制作記録では、企画書1枚と「BGMうるさいね???」のような一言で作っていった流れを書いた。今回はその中身、どういう仕組みで動いているかを書く。

HTML1枚の中の組み立て
ゲームはindex.html 1枚で、中で役割ごとに分けている。
| 部品 | 役目 |
|---|---|
| DATA | 施設、強化、実績、時代、できごと35件。配列に1行足せば増える |
| state | お金や社員の数など、セーブされる中身のすべて |
| Game | 売上の計算、購入、会社の売却、留守中の報酬 |
| History | 今が何年かの計算、できごとの解放、クイズ |
| Auto | 自動で雇う・自動で強化する判断 |
| World3D / World2D | オフィスの描画。3Dが動かないときは2D |
| Sound | BGMと効果音 |
大事なのは、描画の部品は state を読むだけで、書き換えないという決まりだ。見た目をどう変えても、お金の計算には影響しない。途中で「three.jsで3Dにして」と頼んだときも、作り替えたのは描画の部品だけだった。
もう一つ、売上は「前回から何秒たったか × 毎秒の売上」で足している。画面のなめらかさやタブの切り替えに左右されず、閉じていた時間の報酬(上限24時間、効率50%)も同じ考え方で出せる。
数字の設計
値段は1.15倍ずつ上がる
施設の値段は「基本の値段 × 1.15の所持数乗」(評判の強化で1.14にもなる)。同じ人を雇うほど高くなるので、自然とほかの施設にも目が向く。放置ゲームでよく使われる上がり方だ。
年は売上の「桁」で進む
今が何年かは、これまでの売上の合計の桁数で決まる。
- 売上の合計が1,000円で1980年
- 1,000兆円で2026年
- その間は、桁が1つ増えるごとに約3.8年進む(12桁で46年)
桁で進めると、序盤はどんどん年が進み、後半はじっくり進む。売上が増えるペースと、時代が変わるペースがちょうど合う。
日本式の単位で、無量大数まで
お金は「万・億・兆・京・垓」と日本式で表示し、上は無量大数まで用意した。設定で「1.23e45」のような指数表記にも切り替えられる。
自動で雇うときの判断
放置しても進むように、ゲームが自動で人を雇う。どれを雇うかは、「値段 ÷ 雇ったら増える毎秒の売上」が一番小さいもの、つまり元が一番早く取れるものを選んでいる。人が考えても同じ答えになる、素直なルールだ。
ドット絵は「文字の地図」
画像ファイルは使っていない。社員のドット絵は、こんなふうに文字で書いた地図としてプログラムの中にある。
const BODY = [
'...hhhh...', // h = 髪
'..hhhhhh..',
'.hhhhhhhh.',
'.hssssssh.', // s = 肌
'.ssksskss.', // k = 目
];文字ごとに色を決めておき、職種ごとに髪や服の色、ヘッドホンやネクタイ、ヘルメットのような小物を差し替える。これで、インターン生からAI開発部まで10種類の施設の人たちを量産した。
モニターに映る画面も同じ作りで、24×16ドットの絵を2コマ用意してパラパラと動かしている。1980年代は黒地に緑の文字、90年代後半は虹色の文字とアクセスカウンター、2020年代はコードエディタとAIチャットだ。
three.jsで、3Dなのにドット絵に見せる
3Dにすると、どうしても線がなめらかになって「ドット絵らしさ」が消える。そこで、次の設定を組み合わせた。
| やりたいこと | 設定 |
|---|---|
| 斜め上から見下ろす | 遠近感のないカメラ(OrthographicCamera)を、方向 (1, 0.8165, 1) から向ける |
| ふちをギザギザのままに | なめらかにする処理(antialias)を切り、解像度を上げない(setPixelRatio(1)) |
| 模様をにじませない | 床などの模様は、拡大しても補間しない設定(NearestFilter) |
| 影もドットらしく | ぼかさない影(BasicShadowMap) |
| 社員はドット絵のまま | いつもカメラを向く板(スプライト)に、2Dの絵を貼る |
カメラの向き (1, 0.8165, 1) は、真横から30°見下ろす角度になる。この角度だと、床の正方形が横2:縦1のひし形に見える。昔からドット絵のクォータービューで定番の比率だ。
three.jsが読めなくても遊べる
three.jsはネットから読み込む。読めなかったときは、2Dの描画に切り替える。
try {
T = await import('https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js');
World = World3D; // 3Dで描く
} catch (e) {
World = World2D; // 読めなければ2Dで描く
}計算と描画を分けてあるので、どちらで描いてもゲームはそのまま進む。
音:合成音から、時代ごとの曲へ
制作中は、ブラウザのWeb Audio APIでその場で音を合成していた。音のファイルが要らない反面、「BGMと効果音も単調」という感想が出た。そこで公開にあわせて、CC0(権利を放棄した素材)の曲と効果音に差し替えた。
| 時代 | 曲の雰囲気 |
|---|---|
| 1980〜1990年 | チップチューン |
| 1991〜1994年 | FM音源風 |
| 1995〜1999年 | 明るいエレクトロ |
| 2000〜2009年 | チルアウト |
| 2010〜2019年 | ポップ |
| 2020〜2026年 | ローファイ |
仕組みはこうだ。
- 1秒ごとに「今流すべき曲」を調べる。タイトル画面ならタイトル曲、ゲーム中なら今の年が属する時代の曲。違っていたら、音量を0からゆっくり上げながら切り替える
- 曲は audio 要素で再生し、Web Audio APIの音量つまみにつないでいる。スマホでも音量の設定が効くようにするためだ
- 効果音は最初に読み込んで音のデータに変換しておき、鳴らすたびにすぐ再生する。作業のクリック音のように何度も鳴る音でも遅れない
- ファイルが読めないときは、元の合成音で鳴る。HTMLを直接開いたときも音が出る
- タブを裏に回したら、BGMは止める
AIは音を聴けない。「ゲームオーバーの音」事件
公開してすぐ、こう言われた。
モーダル表示の時のSEがゲームオーバーみたいなSEだね??
その通りだった。歴史の解説画面を開くときに鳴らしていたジングルは、ファ→ミ→レ#→レと半音ずつ下がる音だった。昔のゲームで、やられたときに鳴るあの下がり方だ。
原因は単純で、AIは音を聴けない。素材は配布ページの名前や説明で選んでいて、中身の音の動きまでは確かめていなかった。
聴けないなら、測る
そこで、候補のジングル17個の音の高さの動きを、プログラムで調べた。短く区切って一番強い周波数を出し、音名に直していく。
| ジングル | 音の動き | 聞こえ方 |
|---|---|---|
| これまでの音 | ファ→ミ→レ#→レ | 下がる。ゲームオーバー |
| 実績の音(新) | レ→ミ→ファ#→ソ | 上がる。達成した感じ |
| 解説の音(新) | レ#→ラ# | 短く上がる。「ピコン」 |
ユーザーの希望は「ピコンとかでいいのでは」だったので、解説画面には短く上がる2音を割り当てた。同じジングルを使っていた実績の音も、上がる音に替えた。ほかの効果音も調べ、下がる音はクイズ不正解の「ざんねん!」だけで、これはそのままで合っていた。
AIに任せられることは多い。でも、聴く・遊ぶ・気持ちよさを感じるところは、やはり人の一言がいちばん頼りになる。そしてAIの側は、確かめられないものを、確かめられる形に置き換える。今回でいえば「聴く」を「音の高さを測る」に置き換えた。
まとめ
- 計算と描画を分ける。描画は state を読むだけ。だから2Dから3Dへの作り替えも、計算に手を入れずに済んだ
- 値段は1.15倍ずつ、年は売上の桁で進める。序盤は速く、後半はじっくり
- 3Dでドット絵に見せるには、遠近感のないカメラ・30°の見下ろし・補間しない模様・ぼかさない影
- 音は時代ごとに曲を切り替え、読めないときは合成音に戻す
- AIが確かめられないものは、測れる形に置き換える。それでも最後は人の耳
出典
- three.js ドキュメント「OrthographicCamera」(遠近感のないカメラ)
- MDN「import()」(読み込みに失敗したら2Dに切り替える仕組み)
- MDN「AudioContext: createMediaElementSource()」(BGMを音量つまみにつなぐ)
- MDN「BaseAudioContext: decodeAudioData()」(効果音を先に変換しておく)
- Kenney「Music Jingles」(実績と解説の音。CC0)
- OpenGameArt.org(時代ごとのBGM。CC0)
本記事はゲームのプログラムと制作時のやり取りに基づく。数値は2026年10月26日時点の公開版のもの。
新しい記事が出たら、ブラウザの通知でお知らせします。
メールアドレスの登録は要りません。いつでも止められます。
関連記事
RELATED
企画書1枚と「BGMうるさいね?」の一言で。Claudeと作ったWeb業界の歴史ゲーム「Web屋一代記」を公開します
Web制作会社を1980年代から2026年まで育てる放置系ゲーム「Web屋一代記」を、Claude Codeと一緒に作り…
1件を引く処理と、全件を数える処理は別物。図にした
同じ表でも、1行を引く処理と全行を集計する処理では最適な形が違います。インデックスが効かない場面がある理由を図で整理しま…
「2カ月で10万行」は資産か、それとも借金か。AIで書いたコードの“その後”を考える
GMOの熊谷正寿代表が、Claude Codeで2カ月に約10万行のコードを書いたと語っています。トップ自らが使う姿勢は…