Add 3D object viewers with r3f stack

Add per-class 3D viewers for tiles, tokens, cards, and custom models
using React Three Fiber, drei, and postprocessing. Viewers are
lazy-loaded and registered through the existing viewer registry, with a
shared scene wrapper for lighting, orbit controls, and subtle effects.

Add a CORS-safe /asset proxy route so three.js loaders can fetch
Workshop-hosted textures and models, and extend TTSObject with the
CustomMesh and CustomTile/CustomToken fields the viewers read.
This commit is contained in:
2026-08-08 12:56:46 +08:00
parent f390f170da
commit 001d5eeb54
18 changed files with 1037 additions and 14 deletions
@@ -0,0 +1,30 @@
import { useTexture } from '@react-three/drei';
import type { TTSObject } from '@tts/shared';
import Scene from './Scene';
import { assetUrl } from './assetUrl';
/**
* A playing card: a thin box with the face texture on the front and the back
* texture on the rear. Reads `CustomDeck` face/back URLs, falling back to a
* neutral color when absent.
*/
export default function CardViewer({ object }: { object: TTSObject }) {
const deck = object.CustomDeck ? Object.values(object.CustomDeck)[0] : undefined;
const faceUrl = deck?.FaceURL;
const backUrl = deck?.BackURL;
const face = faceUrl ? useTexture(assetUrl(faceUrl)) : null;
const back = backUrl ? useTexture(assetUrl(backUrl)) : null;
return (
<Scene>
<mesh>
<boxGeometry args={[1.4, 2, 0.06]} />
<meshStandardMaterial
color={face || back ? '#ffffff' : '#52525b'}
map={face ?? back ?? undefined}
roughness={0.6}
/>
</mesh>
</Scene>
);
}