feat(web): render bgm setups as a 3D table

Wire the tabletop library into the setup detail route: seed the store
from the setup, resolve the surface mount tree, and render world and HUD
surfaces. Add serializedToPackage to convert the vite-emitted package.
This commit is contained in:
2026-08-09 22:46:03 +08:00
parent cd08e6af04
commit f494a6f9be
6 changed files with 96 additions and 2 deletions
@@ -0,0 +1,49 @@
import { Suspense, useMemo } from 'react';
import type { SerializedPackage, Setup } from '@tts/bgm';
import {
SetupLoader,
WorldSurfaceView,
HudSurfaceView,
resolveMountTree,
serializedToPackage,
useTabletopStore,
} from '@tts/tabletop';
import Scene from '../viewers/Scene';
/**
* Render a bgm setup as an interactive 3D table.
*
* Seeds the tabletop store from the setup, resolves the surface mount tree,
* and renders each enabled surface — world surfaces in world space, HUD
* surfaces as an overlay — with their parts placed on routes. The store is
* seeded on every render so a setup change re-seeds it.
*/
export default function TabletopScene({
pkg,
setup,
}: {
pkg: SerializedPackage;
setup: Setup;
}) {
const packageData = useMemo(() => serializedToPackage(pkg), [pkg]);
const surfaces = useTabletopStore((s) => s.surfaces);
const tree = useMemo(
() => resolveMountTree(packageData.surfaces, new Set(Object.keys(surfaces))),
[packageData, surfaces],
);
return (
<Scene>
<SetupLoader pkg={packageData} setup={setup} />
<Suspense fallback={null}>
{tree.world.map((node) => (
<WorldSurfaceView key={node.id} pkg={packageData} node={node} />
))}
{tree.hud.map((node) => (
<HudSurfaceView key={node.id} pkg={packageData} node={node} />
))}
</Suspense>
</Scene>
);
}