しゃべったことばが、カードになって、目の前の机に立つ。
Google の AI + WebXR ライブラリ「XR Blocks」製の空間メモアプリ。
GDG イベント「Innovative Crosstalk Jamboree Geeks'26」(2026-08-02)のセッション「XRグラスにもWebブラウザが載ってくる」の登壇デモとして作成した。
| 操作 | 内容 |
|---|---|
| こえで書く | 話したことばがそのままカードになる(音声認識、ja-JP) |
| おまかせとキーボード | 音声が使えない環境(Quest Browser など)では、文例からの1タップ生成と XR 内バーチャルキーボードに切り替わる |
| 机に置く | カードが現実の机や床の上に、こちらを向いて直立する(平面検出) |
| 吸着 | カードを掴んで壁の近くで離すとポスターのように貼り付き、机の上で離すと立つ |
| ならべる | 散らかったカードを目の前のグリッドへ再整列する |
| 消す | カード右上の×で1枚ずつ、「全部消す」でまとめて消せる |
| 星エフェクト | サムズアップすると直近のカードに星が弾ける(ハンドトラッキング環境) |
| スピーカーブース | セッション情報、登壇者プロフィール、コミュニティ紹介のパネルが左手に常設で並ぶ |
カードもパネルも、レイとピンチで掴んで好きな場所に動かせる。
Quest 3 か Android XR、または ARCore 対応 Android の Chrome で本番 URL を開き、Enter XR を押す。
https://xrblocks-demo.nisshi.dev/
対応していない環境(デスクトップや iPhone)で開くと、ヘッドセットの代わりになるシミュレータが自動で起動する。
Vite+(vp コマンド)がセットアップ済みであることが前提。
vp installAI コーディングエージェントで開発する場合は、xrblocks 公式のエージェントスキルを入れておくと、API の使い方をエージェントが正しく参照できる。導入には gh CLI を使う。実行するとインストール先のエージェントを選択できる。
gh skill install google/xrblocks --all --scope projectインストール先(Claude Code なら .claude/skills)は .gitignore 済みなので、クローンごとにこのコマンドを実行する。
ワークフロー系スキル(xb-implement や xb-build-app など)はリリースタグ未収録で main にのみ存在する。必要なら commit SHA を指定して個別に追加する。
gh skill install google/xrblocks "skills/xb-implement@$(gh api repos/google/xrblocks/commits/main --jq .sha)" --scope projectデスクトップで開発するときは HTTP で起動して、シミュレータで確認する。
vp run dev:httphttp://localhost:5174/?formFactor=desktop を開くとシミュレータが自動起動する。WASD で移動、右ドラッグで視点回転、左クリックで選択。
実機(Quest 3 やスマホ)で開発版を確認するときは HTTPS で起動する。
vp run devLAN に公開されるので、実機のブラウザから https://<MacのIP>:5173 を開く。自己署名証明書なので警告を通過する必要がある。単に動くものを見たいだけなら本番 URL の方が確実で、開発版を実機で見る意味は後述のホットスワップにある。
デバッグと検証用のスイッチ。組み合わせて使える。
| パラメータ | 効果 |
|---|---|
?formFactor=desktop |
シミュレータを自動起動する |
?debug=1 |
window.xb と window.xbReady をコンソールへ公開する |
?voice=0 |
音声入力なし環境の UI(おまかせとキーボード)を強制する |
?hands=1 / ?hands=0 |
ハンドトラッキング要求の UA 判定を明示上書きする |
実機のブラウザで dev サーバーの URL を開いたまま、Mac でコードを編集する。
- src/features/ 配下の変更は、ページをリロードせず実行中のシーン内でスクリプトが差し替わる(HMR ホットスワップ)。XR セッションに入ったまま変更が反映されるので、Enter XR を押し直す必要がない
- それ以外のファイルの変更は通常のフルリロードになり、Enter XR の押し直しが必要
コンソールを見たいときは、USB 接続して PC の Chrome から chrome://inspect/#devices を開く(Quest は開発者モードの有効化が必要)。
「ボタンが出ない」「押しても反応しない」ときは、まず docs/research/xrblocks-xrsession.md を読む。XR Blocks は非対応や失敗を画面に出さない設計なので、原因の切り分け方をそこにまとめてある。
最短の変更ポイントを2つ。
- おまかせメモの文例: src/features/memo/sampleMemos.ts の配列に1行足すと、「メモをつくる(おまかせ)」の巡回に入る
- スライド画像: スピーカーブースのスライドビューアは
public/booth/slides/の画像を表示する。画像を置いてmanifest.jsonのslides配列をファイル名で更新する
UI の日本語文言を変えたときは、MSDF フォントアトラスの再生成が必要。
bash scripts/generate-jp-msdf.shuiblocks(パネル UI)の文字はソース中のグリフを集めたサブセットアトラスで描画しているため、新しい漢字を使うと再生成するまで表示されない。
npm パッケージ版の xrblocks を Vite で使う場合に踏んだ罠。XRSession まわりの詳しい調査は docs/research/xrblocks-xrsession.md に、uiblocks の調査は docs/research/uiblocks.md にある。
- xrblocks が動的 import する
troika-three-textとlitとthree-mesh-bvhは dependencies に含まれていないため、自分で追加する必要がある three-mesh-bvhを空モジュールでスタブするとMesh.prototype.raycastがundefinedで上書きされ、render ループが無言で止まる。スタブせず本物を入れる- 使わない任意依存(
@google/genaiなど)は vite.config.ts で空スタブに alias している - XR ボタン(
XRButton)は無スタイルの DOM を生成するだけなので、オーバーレイ CSS(src/style.cssに定義済み)が無いと画面外に消える enableHands()はhand-trackingを required feature にするため、非対応の手持ちスマホでは Enter XR を押しても無反応になる。このリポジトリでは UA を見て手持ち Android だけ hands を外しているplaceOnHorizontalSurfaceなどに渡す Temporal のタイムアウトは整数フィールドのみ受け付ける({seconds: 2.5}は RangeError)。ミリ秒の整数で渡す- uiblocks のドロップシャドウ層と掴み代マージンは不可視のままレイを奪い、背後のボタンが押せなくなる(対処は src/shared/uiblocksRaycast.ts)
TextButtonのfontSizeはTextViewと単位系が異なる(約7倍の値を渡す)- 日本語テキストの自動折り返しは使えないため、src/shared/wrapText.ts(BudouX の文節境界で折る)を通して
\nを明示する
