「バーで見知らぬ人と話す」という体験をブラウザ上で再現できないか、ふと思い立ってしまった。インストール不要で、URLを送るだけで誰でも入れる3D交流空間を作りたかった。そんな衝動から始まったのが Avatar SNS というプロジェクトだ。
実際に動くものを公開しているので、まずは触ってみてほしい。
できること
- ユーザー名を入れるだけでログイン(登録不要)
- アバターを作ってバーに入店
- WASD / 矢印キーで移動、スペースでジャンプ
- リアルタイムチャット(他のプレイヤーと会話)
- バーテンダーに注文してドリンクを受け取る
- 椅子に着席
- ジュークボックスでBGMを変更(全員に同期)
- スマホ対応(バーチャルD-pad付き)
技術スタック
フロントエンド: Three.js r160(ES modules + importmap)
リアルタイム通信: Socket.io 4.7
サーバー: Express.js + Node.js
セッション管理: express-session + lowdb
インフラ: さくらVPS(Rocky Linux)+ Nginx + PM2 + Let's Encrypt
外部UIフレームワークは一切使っていない。バーの内装・アバター・エフェクトはすべて Three.js のプリミティブと Canvas API で生成している。
アーキテクチャの概要
Browser (Three.js)
↕ WebSocket (Socket.io)
Express Server
├── /api/auth セッション発行
├── /api/me ログイン状態確認
└── Socket.io 位置同期・チャット・ジュークボックス
lowdb (db.json) アバターデータ永続化
プレイヤーの位置は50msごとにサーバーへ送信し、サーバーが全員にブロードキャストする。O(n²) の構造なので、快適な同時接続はPC15人・スマホ8人程度が現実的な上限だ。
実装のポイント
アバターはすべてCanvas生成
3Dモデルファイルを一切使っていない。球体ジオメトリに Canvas で描画した顔テクスチャを貼ることで、ダウンロード0バイトのアバターを実現している。色・目のスタイルはユーザーが選択でき、サーバー経由で他プレイヤーに同期される。
バーの内装もすべてプリミティブ
床・壁・カウンター・椅子・ランプ・植物・絵画フレームまで、BoxGeometry / CylinderGeometry / ConeGeometry の組み合わせだけで作っている。GLTFモデルを使わないことでロードが速く、スマホでも動く。
スマホ対応
タッチデバイスを検出してバーチャルD-padを表示し、touchstart / touchend で keys オブジェクトを直接操作する。PCのキーボード処理をそのまま使えるので、ゲームループのコードを変更せずに対応できた。
const isMobile = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
function bindMoveBtn(id, code) {
const el = document.getElementById(id);
el.addEventListener('touchstart', e => { e.preventDefault(); keys[code] = true; }, { passive: false });
el.addEventListener('touchend', e => { e.preventDefault(); keys[code] = false; }, { passive: false });
}
bindMoveBtn('mb-up', 'KeyW');
bindMoveBtn('mb-down', 'KeyS');
モバイルでは PixelRatio を1倍固定・PointLight省略・シャドウ無効化してパフォーマンスを確保している。
セッション管理のハマりどころ
Nginx リバースプロキシ越しで動かす場合、app.set(‘trust proxy’, 1) を忘れると Android Chrome でセッションクッキーが正しく扱われない。また sameSite: ‘lax’ の明示と req.session.save() の明示的な呼び出しも必要だった。
app.set('trust proxy', 1);
const sessionMiddleware = session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { maxAge: 7 * 24 * 60 * 60 * 1000, httpOnly: true, sameSite: 'lax', secure: false }
});
req.session.save((err) => {
if (err) return res.status(500).json({ ok: false });
res.json({ ok: true });
});
今後の展望
3Dはブラウザで動かすには端末負荷が高く、コンテンツの拡張も手間がかかる。次は 2Dピクセルアート × Canvas 2D API で交流型ゲーム空間を作り直す予定だ。インタラクションの豊かさという点では、Habbo Hotel や Club Penguin のような2Dの方が作りやすく、スマホでも快適に動く。
ぜひ avatarsns.site で遊んでみてください。