From fc1f50001958aa869dceb3ab38202b249a51ab66 Mon Sep 17 00:00:00 2001 From: Kartios Date: Tue, 11 Aug 2026 20:29:06 -0700 Subject: [PATCH] perf: lazy load authenticated office peers --- src/interiors/officeScene.ts | 21 +++++++++++++++------ src/main.ts | 7 ++++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/interiors/officeScene.ts b/src/interiors/officeScene.ts index 22d783b..72e64e0 100644 --- a/src/interiors/officeScene.ts +++ b/src/interiors/officeScene.ts @@ -99,13 +99,17 @@ import { type RobotSpec, type RobotView, } from "./robots.ts"; -import { - createScenePeers, - type ScenePeersOptions, +import type { + ScenePeers, + ScenePeersOptions, } from "../realtime/scenePeers.ts"; import type { EntityPoseSnapshot } from "../realtime/types.ts"; -export type OfficeRealtimePeersOptions = Omit; +export type CreateOfficeScenePeers = (options: ScenePeersOptions) => ScenePeers; +export type OfficeRealtimePeersOptions = Omit & { + /** Injected by an authenticated caller so anonymous offices never download peer assets. */ + create: CreateOfficeScenePeers; +}; /** Shared empty, so a pack with no robots does not allocate one per call. */ const NO_ROBOTS: readonly RobotView[] = []; @@ -526,8 +530,8 @@ export function createOfficeScene(office: Office, options: OfficeSceneOptions): // Geographic callbacks are required by the generic adapter but harmless here: // an office subscription sends validated local poses in metre coordinates. const realtimePeers = depth === "full" && options.realtimePeers - ? createScenePeers({ - ...options.realtimePeers, + ? options.realtimePeers.create({ + ...withoutPeerFactory(options.realtimePeers), project: () => [0, 0], groundAt: () => 0, localSceneUnitsPerMetre: options.realtimePeers.localSceneUnitsPerMetre ?? 1, @@ -918,6 +922,11 @@ export function createOfficeScene(office: Office, options: OfficeSceneOptions): }; } +function withoutPeerFactory(options: OfficeRealtimePeersOptions): Omit { + const { create: _create, ...peerOptions } = options; + return peerOptions; +} + /** * The fixed interior rig: a soft high sun, a strong hemisphere for the bounce a * real room has and a real-time renderer does not, no sky and no fog. diff --git a/src/main.ts b/src/main.ts index 0b0f28a..e462d85 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1180,6 +1180,11 @@ async function enterOffice() { if (!built || !city) return; const { createOfficeScene, createOfficeMinimap, pack, materials } = built; const depth = access.can.officeDepth; + // Keep the remote-avatar renderer behind the authenticated boundary. The + // public Office door can build its full local scene without downloading it. + const createOfficePeers = access.subject !== null + ? (await import("./realtime/scenePeers.ts")).createScenePeers + : null; /** * The building's own sky, built before the scene because the scene wants the @@ -1252,7 +1257,7 @@ async function enterOffice() { ...(depth === "full" ? { onPresencePick: (p) => showDetail(p ? p.label : null) } : { onPlacePick: (place) => showDetail(place ? place.label : null) }), - ...(access.subject !== null ? { realtimePeers: {} } : {}), + ...(createOfficePeers ? { realtimePeers: { create: createOfficePeers } } : {}), }); office.onViewChange(() => renderLegend()); officePlan = buildOfficePlan(createOfficeMinimap, office);