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:
@@ -58,12 +58,13 @@ tts-workshop/
|
||||
│ │ ├── package.json
|
||||
│ │ ├── tsconfig.json
|
||||
│ │ └── src/
|
||||
│ │ ├── index.ts # Hono app + @hono/node-server
|
||||
│ │ ├── routes/
|
||||
│ │ │ ├── search.ts # GET /search?q=...&page=1
|
||||
│ │ │ ├── items.ts # GET /items/:id, /items/:id/file
|
||||
│ │ │ └── health.ts # GET /health
|
||||
│ │ └── env.ts # zod env validation
|
||||
│ │ ├── index.ts # Hono app + @hono/node-server
|
||||
│ │ ├── routes/
|
||||
│ │ │ ├── search.ts # GET /search?q=...&page=1
|
||||
│ │ │ ├── items.ts # GET /items/:id, /items/:id/file
|
||||
│ │ │ ├── asset.ts # GET /asset?url=... (CORS-safe asset proxy)
|
||||
│ │ │ └── health.ts # GET /health
|
||||
│ │ └── env.ts # zod env validation
|
||||
│ └── web/
|
||||
│ ├── package.json
|
||||
│ ├── tsconfig.json
|
||||
@@ -81,6 +82,14 @@ tts-workshop/
|
||||
│ │ ├── SearchResults.tsx
|
||||
│ │ ├── ObjectTree.tsx # containment-tree sidebar
|
||||
│ │ ├── viewers.tsx # viewer registry + default viewer
|
||||
│ │ ├── viewers/ # 3D viewers (r3f/drei/postprocessing)
|
||||
│ │ │ ├── register.ts # registers per-class 3D viewers (lazy)
|
||||
│ │ │ ├── Scene.tsx # shared Canvas: lights, controls, post
|
||||
│ │ │ ├── TileViewer.tsx
|
||||
│ │ │ ├── TokenViewer.tsx
|
||||
│ │ │ ├── CardViewer.tsx
|
||||
│ │ │ ├── CustomModelViewer.tsx
|
||||
│ │ │ └── assetUrl.ts # route asset URLs through the proxy
|
||||
│ │ ├── objectIcons.tsx # class → icon mapping
|
||||
│ │ ├── objectIconsData.ts # generated icon subset (do not edit)
|
||||
│ │ └── objectIcons.test.ts
|
||||
@@ -188,6 +197,11 @@ Hono server exposing search + fetch.
|
||||
otherwise resolves via the Steam API.
|
||||
- `GET /items/:id/file` — raw save bytes, filename from `getFileName`. Also
|
||||
accepts `fileUrl`.
|
||||
- `routes/asset.ts`
|
||||
- `GET /asset?url=...` — fetch an external asset (texture, model) and stream
|
||||
it back with a `Content-Type` header. Workshop hosts often omit CORS
|
||||
headers, which would block three.js loaders in the browser; routing through
|
||||
the proxy makes those assets loadable. Only `http(s)` URLs are allowed.
|
||||
- `routes/health.ts`
|
||||
- `GET /health` — liveness.
|
||||
- `env.ts` — zod validation of `STEAM_API_KEY`, `PORT`.
|
||||
@@ -212,6 +226,16 @@ proxy API and `packages/extract` directly for analysis.
|
||||
- `components/viewers.tsx` — viewer registry (`registerViewer` /
|
||||
`resolveViewer`) plus a `DefaultViewer` that renders an object's fields;
|
||||
custom per-class viewers can be registered later.
|
||||
- `components/viewers/` — 3D viewers built on `@react-three/fiber`,
|
||||
`@react-three/drei`, and `@react-three/postprocessing`. `register.ts`
|
||||
registers lazy-loaded viewers for `Tile`/`Custom_Tile` (flat box),
|
||||
`Custom_Token` (cylinder), `Card`/`Deck`/`Custom_Deck` (thin box with
|
||||
face/back textures), and `Custom_Model`/`Custom_Model_Bag`/
|
||||
`Custom_Model_Infinite_Bag` (GLTF/OBJ/FBX from `CustomMesh.MeshURL`).
|
||||
`Scene.tsx` is a shared canvas with lighting, orbit controls, contact
|
||||
shadows, and subtle bloom/vignette. `assetUrl.ts` routes asset URLs through
|
||||
the proxy for CORS-safe loading. The viewers are lazy-loaded so the three.js
|
||||
stack is code-split out of the main bundle.
|
||||
- `components/objectIcons.tsx` — maps TTS object classes to one or more
|
||||
Iconify icons (`iconsForObject`); unknown classes fall back to a help icon.
|
||||
Icons may come from multiple sets (mdi, material-symbols, file-icons, ...);
|
||||
@@ -234,6 +258,7 @@ proxy API and `packages/extract` directly for analysis.
|
||||
| GET | `/search?q=&page=` | Scrape Workshop browse, return item list | — |
|
||||
| GET | `/items/:id` | Full parsed `TTSMod` (`?fileUrl=` skips key) | key* |
|
||||
| GET | `/items/:id/file` | Raw save bytes, filename from header | key* |
|
||||
| GET | `/asset?url=` | CORS-safe proxy for external assets | — |
|
||||
|
||||
\* `STEAM_API_KEY` is optional; `/items/*` works without it when a `fileUrl`
|
||||
query param is supplied.
|
||||
@@ -259,6 +284,8 @@ packages/extract → flatten objects / extract refs / download assets
|
||||
- `cheerio` — Workshop browse page scraping (backend only).
|
||||
- `zod` — validation.
|
||||
- `react`, `react-dom`, `react-router-dom`, `zustand` — frontend.
|
||||
- `three`, `@react-three/fiber`, `@react-three/drei`,
|
||||
`@react-three/postprocessing` — 3D object viewers.
|
||||
- `@iconify/react`, `@iconify-json/mdi`, `@iconify/utils` — iconify icons for
|
||||
object class tags (subset bundled via `scripts/generate-object-icons.mjs`).
|
||||
- `vite`, `@vitejs/plugin-react`, `tailwindcss`, `@tailwindcss/vite` — frontend tooling.
|
||||
|
||||
Reference in New Issue
Block a user