A visualization platform for the ongoing work of aaajiao. This repository serves as the technical foundation for the Symbiosis project, providing a space where 3D scans, point clouds, and rich-media annotations converge to document the intersection of labor, material production, and global trade.
poly.cam.work is more than a 3D viewer. It is a digital archive and research platform designed to bridge the gap between physical labor and digital representation. By integrating high-fidelity LiDAR scans with contextual media, it allows for a multi-layered exploration of the Symbiosis project—a decade-long engagement with industrial production, youth precarity, and the shifting landscapes of global trade.
The platform serves as:
- A Research Hub: Centralizing data visualizations, field recordings, and 3D documentation.
- An Artistic Interface: Providing a spatial narrative for the Symbiosis project's core concepts of Absorption and Trance.
- A Technical Foundation: Offering a robust workflow for publishing and managing 3D scenes with rich-media annotations.
For deeper context on the artwork and its evolving research, see the Symbiosis Project Background or read the Project Manifesto.
- 1bit Game — A roamable digital ruin generated from the wreckage of manufacturing collapse.
- Two Rituals (Video) — A video work documenting the two states of Absorption and Trance.
- WorldLabs 3D — A 3D world built with WorldLabs.
- GLB + PLY scene rendering with React Three Fiber
- Annotation system with image/video/link content
- Local-first draft workflow (edits persist in browser before publish)
- Publish/release workflow on Vercel with rollback + version management
- Media upload to Vercel Blob at publish time via client upload tokens
- Smoke and browser-level test coverage
- Vite 7 + React 19 + TypeScript 7 (strict), with TypeScript 6 for compiler API compatibility
- Three.js + @react-three/fiber + @react-three/drei
- zustand + shadcn/ui + Tailwind CSS v4
- Vercel Functions (
api/) + Vercel Blob
src/ Frontend app code
api/ Vercel Functions (auth/draft/media/publish/release/rollback)
public/ Static assets (source model files live in public/models)
e2e/ Playwright smoke tests
docs/ Planning and implementation docs
- Bun 1.3+
- Node.js 22.x on Vercel
- Node.js 22.12 locally via
.node-version/.nvmrc - Modern browsers (Safari 16+, Chrome/Edge 107+, Firefox 104+)
- (Optional) Vercel CLI for
vercel dev
Create a local env file from .env.example and set:
POLYCAM_BLOB_READ_WRITE_TOKEN: preferred Vercel Blob read/write token nameADMIN_PASSWORD: editor login passwordAUTH_SECRET: cookie signing secret (32+ chars)- Legacy fallback:
BLOB_READ_WRITE_TOKENis still accepted if already configured
Install dependencies:
bun installnode_modules is not portable across operating systems. This project runs on both macOS and Linux, but native Rollup and TypeScript 7 packages are installed per platform, so after moving the repo between machines you should rerun bun install locally. If a copied node_modules/ directory still causes a mismatch, remove it and reinstall on the current machine.
bun run typecheck and bun run build use TypeScript 7's native tsc, installed under the @typescript/native alias. The typescript dependency aliases @typescript/typescript6, which supplies the TypeScript 6 JavaScript API required by typescript-eslint and a separate tsc6 executable. Keep both aliases when updating dependencies; replacing typescript with TypeScript 7 directly would remove the API used by lint. This follows the official side-by-side setup.
Run frontend dev server:
bun run devRun API routes locally (recommended, no Vercel login required):
bun run dev:apiAlternative API runtime using Vercel CLI:
vercel devbun run typecheck
bun run lint
bun run dev:api
bun run test:vitest
bun run test:e2e
bun run test:all
bun run buildSee docs/TESTING.md for the repo's test-layer rules, command selection, and Playwright hang troubleshooting.
bun run test:vitest:browseris the main path for browser-based UI interaction coverage.bun run test:e2eis the Playwright smoke suite for app-shell and critical runtime checks.bun run test:e2e:uiis a debugging mode and stays interactive until you stop it.
Authenticated editor flow:
- Login via
POST /api/auth/login - Session restore check via
GET /api/auth/session - Local edits stay in browser storage until publish
- Publish via
POST /api/publish/:sceneId(uploads local images, saves draft, creates release) - Manage releases via
GET /api/publish/:sceneId(list) andDELETE /api/publish/:sceneId(delete version) - Public clients read latest release via
GET /api/release/:sceneId - Roll back via
POST /api/rollback/:sceneId
Official scenes are repository-first. Maintainers add model assets to the codebase, then sync them to the cloud catalog.
- Add Assets: Place GLB and PLY pairs in
public/models/(e.g.,my-scan.glbandmy-scan.ply). - Refresh: In the File Manager, click Refresh to discover new local models.
- Sync: Click the Cloud icon next to a discovered scene to upload its assets to Vercel Blob and register it in the cloud catalog.
- Author: Once synced, the scene is available for annotation and publishing like any other cloud scene.
Import: load a local draft JSON file into the current sceneExport: download current local draft JSONPublish: push local draft (including local images) to cloud release (scene content only)Sync: upload official model assets (GLB/PLY) to cloud catalogDiscovered: local official scene found inpublic/modelsCloud: official scene whose assets are synced to Vercel BlobSession: temporary scene uploaded via UI (not persisted in catalog)saved/unsaved: local draft publish state for current scenelive: currently served release version tag
- Source model assets are maintained in
public/models dist/is generated build output and should not be treated as a source of truth.vercelignoreexcludesdistand other non-deploy source folders from upload
v0.4.0
