[JavaScript] 3D ROOM制作 5日目 VRヒント・バナー画像・Import/Export

[JavaScript] 3D ROOM制作 5日目 VRヒント・バナー画像・Import/Export

本日の作業

WIRED ROOM 制作5日目です。今日は VR の UI改善、広場のビジュアル強化、そしてデータ管理機能を一気に実装しました。

前回の記事:[3D ROOM制作 4日目 プログレスバー・ポータル改修・広場実装]

リポジトリ:[github.com/fixtan/WIRED_ROOM]

1. クレジットボード修正

エディタの表記を調整しました。

  • ラベルを「Credit List」→「Message」に変更
  • プレースホルダーを「お知らせ、備考、クレジットなど自由入力」に
  • テキストエリアの行数を 4 → 6 に拡大
  • ボード上の「── Credits ──」ヘッダーを削除

クレジット専用ではなく、自由にメッセージを書ける汎用ボードとして再定義しました。Canvas の高さは行数に応じて動的に伸びるので、長文でも問題ありません。

[JavaScript] 3D ROOM制作 5日目 クレジットボード修正

2. VR ポータル近接ヒント(vr-ui.js)

PC では、ポータルに近づくと [E] global のようなテキストが画面に表示されます。しかし VR ではこの HTML オーバーレイはヘッドセットの中から見えません。

そこで、VR 専用の 3D ヒントスプライトを実装しました。

新規ファイル: js/vr-ui.js

汎用的な VR ヒント表示モジュールです。Canvas テクスチャで [A] ENTER のようなテキストを描画し、Sprite として 3D 空間上に配置します。

// API
initVRHint(scene)              // シーンに初期化
showVRHint(pos, text, offset?) // 表示(テキスト変更時のみテクスチャ再生成)
hideVRHint()                   // 非表示
disposeVRHint()                // 破棄

controls.jscheckPortalProximity 内で isVRActive() を判定し、VR 時は HTML ではなく 3D スプライトを表示するようにしました。

ポイントは、ポータル専用ではなく汎用モジュールとして設計したことです。今後、他のオブジェクトとのインタラクション表示にもそのまま使えます。


3. 広場バナー画像

広場のポータル上に表示されるラベルが、テキストだけでは味気なかったので、バナー画像の表示機能を追加しました。

[JavaScript] 3D ROOM制作 5日目  広場バナー画像 [JavaScript] 3D ROOM制作 5日目  広場バナー画像 [JavaScript] 3D ROOM制作 5日目  広場バナー画像 [JavaScript] 3D ROOM制作 5日目  広場バナー画像 [JavaScript] 3D ROOM制作 5日目  広場バナー画像 [JavaScript] 3D ROOM制作 5日目  広場バナー画像 [JavaScript] 3D ROOM制作 5日目  広場バナー画像 [JavaScript] 3D ROOM制作 5日目  広場バナー画像

仕組みs

portal_list.jsonimage フィールドを追加。画像 URL が指定されていれば TextureLoader で非同期に読み込み、テキストラベルをバナースプライトに差し替えます。読み込み失敗時はテキストラベルのままフォールバックします。

{
  "name": "lain's room",
  "url": "https://lain-lab.com/room/",
  "image": "https://lain-lab.com/room/banner.webp",
  "description": "メインルーム"
}

バナー画像の仕様

  • 推奨サイズ: 480 × 120 px(4:1)
  • 形式: WebP または PNG、30KB以下推奨
  • CORS が通らないサーバーの画像は自動的にテキストにフォールバック

CORS 対応

クロスオリジンでバナーを読み込むため、Netlify の場合は public/_headers に以下を追加します。

/room/*
  Access-Control-Allow-Origin: *

Netlify、GitHub Pages、Vercel、Cloudflare Pages はデフォルトで CORS ヘッダーが付くので、多くの場合は追加設定不要です。

Base64 埋め込みの検討と却下

CORS 問題を完全に回避するため、バナーを Base64 で portal_list.json に直接埋め込む案も試しました。480×120 WebP で約 15KB。1 サイトなら問題ありませんが、20 サイト登録されると 300KB になり、portal_list.json が肥大化して現実的ではありません。

結論として、外部 URL + フォールバックが最もバランスの良い方式です。

結果

全ルームにバナーを作成して並べたところ、広場の印象が一変しました。テキストラベルだけの時とは別物です。


4. Import ZIP / Clear All Data

WIRED ROOM のデータはブラウザの localStorage と IndexedDB に保存されています。これまで Export ZIP でデータを書き出すことはできましたが、復元する手段がありませんでした。

[JavaScript] 3D ROOM制作 5日目  広場バナー画像

Import ZIP

エクスポートした ZIP ファイルを読み込んで、ルームを完全に復元します。

処理の流れ:

  1. ZIP を読み込み、public/manifest.json をパース
  2. 警告ダイアログ(既存データの上書き確認)
  3. 既存データを全クリア(IndexedDB + localStorage)
  4. room.glb → IndexedDB に保存
  5. 画像 → Base64 data URL に変換して IndexedDB に保存
  6. 動画 → ArrayBuffer のまま IndexedDB に保存
  7. VRM フィギュア + ポーズ → IndexedDB に保存
  8. クレジットデータ → roomMeta に復元
  9. room_config + room_media → localStorage に書き込み
  10. リロード → 完全復元

Clear All Data

localStorage と IndexedDB の全データを削除します。2 段階の確認ダイアログで誤操作を防止。削除後はセットアップウィザードが再表示されます。

ルーム切り替えワークフロー

この 2 つの機能を組み合わせることで、複数のルームを自由に切り替えられるようになりました。

  1. 現在のルームを Export ZIP でバックアップ
  2. Clear All Data で初期化
  3. 別の ZIP を Import ZIP で復元

ビルドツールもサーバーも不要で、ZIP ファイルだけでルームがポータブルになります。


今日の成果まとめ

項目内容
クレジットボードラベル・ヘッダー修正、汎用メッセージボード化
vr-ui.jsVR 近接ヒント表示(汎用 3D スプライト)
バナー画像corridor.js 拡張、CORS 対応、全 5 ルーム分作成
Import ZIPエクスポート ZIP からの完全復元
Clear All DataIndexedDB + localStorage 全消去
README.mdVR 操作、バナー仕様、Backup/Restore セクション追加

所感

今日の作業で WIRED ROOM が「ポータブルな 3D ポートフォリオ空間」として形になってきた実感があります。

Export → Clear → Import のラウンドトリップが一発で通ったのは、エクスポートの ZIP 構造がきちんと設計されていたおかげです。インポートは逆変換するだけで済みました。

バナー画像を全ルームに並べた時の見た目のインパクトも大きかったです。テキストラベルだけの広場とは別物でした。

過去に作ったゲームや作品の紹介ルームを個別に作って、ポータルで繋げれば、個人の作品群が一つの世界になります。そういう使い方ができるプラットフォームは今のところ他にないと思います。


リポジトリ: github.com/fixtan/WIRED_ROOM