戻る

リビングのアーケード

ブラウザで本当に遊べるレトロなカートリッジ・アーケード。コンソール、CRT モニター、コントローラーが並ぶ 3D デスクをぐるりと眺め、電源を入れてカートリッジ・ライブラリへ。Snake、Breakout、Blocks の 3 本のオリジナル・ミニゲームは、インストール不要、セーブデータなし。ある午後と「もう一回」だけがそこにある。

作者: Theodore
ライブで試す
リビングのアーケードライブで試す

このプロジェクトについて

Playroom はブラウザで動くリビングのアーケードです。ページを開くと 1989 年風のゲームデスク — CRT モニター、コンソール、コントローラー、そして差し込み済みの Snake カートリッジ — が現れ、ドラッグで回してじっくり眺められます。コンソールか POWER ON をクリックすると、カメラが画面へ寄っていき、ブラウン管を突き抜けて 3 本のカートリッジが並ぶライブラリに降り立ちます。

3 本のゲームはすべて Playroom のオリジナル。Snake はリズムよく連続で食べ続けるゲーム、Breakout は 3 ステージのブロック配置とパワーアップ、Blocks は着地ゴーストと 7 ピース 1 セットの袋で積み上げを読みやすくしています。アカウントも、アップデートも、セーブデータも不要 — ハイスコアはブラウザに残り、音楽と効果音はボタンひとつで切れます。

プロジェクト全体が依存するのは Three.js と Vite だけ。バックエンドも環境変数もなく、6 つの GLB ハードウェアモデルと Tripo フェイスマークのデカール 1 枚がアセットのすべてです。WebGL が使えないときはテキストメニューが引き継ぎ、ゲームはそのまま完全に遊べます。

体験ポイント

  1. ドラッグして CRT モニター、コンソール、コントローラー、カートリッジが並ぶリビングのセット全体をぐるりと眺め、コンソールか POWER ON をクリック。カメラが画面に向かって寄り、CRT を突き抜けてカートリッジ・ライブラリへ入っていきます。
  2. 3 本のカートリッジ、3 本のオリジナルゲーム。Snake は 5 秒以内の連続ヒットで 5 倍チェーン、金の果実は 50 点。Breakout は 3 ステージのブロック配置に、W(パドル拡大)と 3(トリプルボール)のパワーアップ。Blocks は 7 ピース 1 セットの袋、着地ゴースト、連続消しボーナス。
  3. デスクトップでは矢印キー / WASD とスペース、P で一時停止、ESC で終了。モバイルではタッチ操作。ハイスコアはあなたのブラウザの中にだけ残ります。
  4. 各ゲームに専用のチップチューン・ループと効果音があり、メニューでは CC BY 4.0 の楽曲「Trip Of Your Smile」が流れます。WebGL が使えない環境ではテキストボタンにフォールバックし、そのまま遊べます。

技術解説

  • 3D アセット · 実行時に再バインドされる 6 つの GLB ハードウェア

    CRT モニター、コンソール、コントローラー、3 本のカートリッジは 6 つの GLB ファイルとして同梱されています(Three.js の GLTFExporter で書き出した、1 つあたり 128〜384 三角形のローポリ)。GLTFLoader が並列で読み込み、各インスタンスはディープクローン。書き出し時のキャプチャ用センタリングのオフセットをゼロに戻し、マテリアルはインスタンスごとに複製、すべてのメッシュが影を落とし、受け取ります。カートリッジのラベル面は書き出し時のローカルオフセットから特定して cartridge-label と名付け、Canvas で描いたカバー・テクスチャに差し替え。ピクセルのマスコットは名前付きノード — mascot-body、両腕、アンテナ、Tripo のフェイスマークを載せたロゴ・デカール — からリグを組み、平面のデカールをくっきり保つためトーンマッピングとデプス書き込みを無効化しています。

    アセット層には差し替えスロットも用意されています。public/models/manifest.json の controller フィールドを任意の GLB に向けると、fitProp がバウンディングボックスから幅 2.54 単位にスケールし、床に接地・中央揃えして元のコントローラーの位置を引き継ぎます。独自の(たとえば Tripo で生成した)コントローラーを、コードを一行も触らずに差し込めます。

  • 画面とラベル · UI としての Canvas テクスチャ

    シーンは外部テクスチャを一枚も読み込みません。CRT の画面は 1024×700 の CanvasTexture で、待機画面(PLAYROOM SYSTEM / PLAYER ONE / PRESS START)を 2D コンテキストにフレームごとに描き、map と emissiveMap の両方に使ってブラウン管を発光させています。各カートリッジのカバーはそれぞれ 640×610 の Canvas で、カタログにあるそのゲームのカラー、インク色、番号、タグラインからピクセルアートとタイトル文字までその場で描画します。

    電源を入れると、スクリーン・ライフサイクル・コントローラーがマテリアルをデータストリームのテクスチャに切り替え、カメラは画面中心を軸にした球面軌道でブラウン管の正面へ回り込み、寄っていってガラスを抜ける瞬間にライブラリへカット。prefers-reduced-motion 環境ではこの一連の動きを省き、直接切り替わります。

  • インタラクション · ポインター・ジェスチャー、レイキャストによる選択、シネマティックな軌道

    デスク表示では、ひとつのポインター操作がオービットのドラッグでもありクリックでもあります。ジェスチャー・コントローラーは押した瞬間の theta / phi を記録し、閾値を超えた移動をドラッグ、それ以外をクリックとして扱います。ヒット判定は Raycaster で行い、デスクではセット全体が電源ボタンとして機能し、ライブラリでは親チェーンをたどって gameId を持つノードまで遡ります。指を離してもオービットはその場で固まらず、シネマティック・コントローラーが手動のオフセットをゆっくりとした自動の揺れへと溶け込ませます。

    カートリッジにホバーまたはフォーカスすると 0.24 浮き上がり、わずかにロールしながら前へ傾き、ピクセルのマスコットがそのゲーム専用のポーズに切り替わります。各カートリッジはそれぞれ異なる正弦波の位相で上下に揺れます。レンダーループ内のすべての補間はフレームレート非依存のイージング 1 − e^(−5·dt) を使うため、フレームが遅くなってもカクつきません。

  • ゲームと音 · 独立した 2D セッションと合成サウンド

    3 本のゲームは純粋なロジック・モジュール(create / step / input)で、セッション層がそれらを独立した 2D Canvas に描画します — Snake と Breakout は 480×480、Blocks は 300×540。requestAnimationFrame は実行中にだけスケジュールされるため、ポーズは文字どおりフレームを止め、1 ステップ 250 ms の上限でタブ切り替え後のすり抜けを防ぎます。ゲームイベント(食べる、ブロック破壊、ライン消去、パワーアップ、レベル)はパーティクル効果層に流れ込み、優先度に従ってひとつの効果音キューにまとめられます。

    サウンドはすべて Web Audio のオシレーターでリアルタイムに合成。ゲームごとに 16 ステップのチップチューン・メロディ(82〜120 BPM)と、周波数グライドとエンベロープを組み合わせた 20 種あまりのキューを、最大 64 ボイスで鳴らします。メニュー曲は CC BY 4.0 の録音で、ダウンロードに失敗すると合成ループにフォールバック。タブが隠れると音は止まり、オーディオ・コンテキストは最初のクリック後にだけ解放されます。ハイスコアは localStorage に保存し、ストレージが拒否されればメモリに退避 — 保存の失敗がゲームを中断することは決してありません。