# 3d Viewer

> Full project workflow for the three.ws platform. Use when: developing features, debugging, modifying UI, understanding architecture, running dev server, or making code changes anywhere in the repo (viewer, agent runtime, API, contracts).

- Skill: `nirholas/3d-viewer` (Agent Skill)
- Install (CLI): `npx skillmds@latest add nirholas/3d-viewer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nirholas/3d-viewer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: nirholas (https://skillmd.com/u/nirholas)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/nirholas/3d-viewer

---


# three.ws — Project Workflow

## Overview

**three.ws** started as a glTF 2.0 / GLB viewer and grew into a full embodied-agent platform. Live at [three.ws](https://three.ws/). Read [/CLAUDE.md](../../../CLAUDE.md) first — this skill is an index; the CLAUDE.md files are the source of truth.

## Two halves

- **Viewer half** — pure three.js. GLB loading, lighting, animations, validation, dat.gui.
- **Agent half** — persona (`agent-identity.js`), memory (`agent-memory.js`), skills (`agent-skills.js`), avatar emotion (`agent-avatar.js`), LLM runtime (`runtime/`), wallet identity (`erc8004/`), protocol bus (`agent-protocol.js`).

The viewer never imports the agent half. The agent layer wraps the viewer through `runtime/scene.js` (`SceneController`).

## Where code lives

| Area                         | Path         | Scoped doc                                          |
| ---------------------------- | ------------ | --------------------------------------------------- |
| Browser app (viewer + agent) | `src/`       | [src/CLAUDE.md](../../../src/CLAUDE.md)             |
| Vercel serverless API        | `api/`       | [api/CLAUDE.md](../../../api/CLAUDE.md)             |
| ERC-8004 Solidity registries | `contracts/` | [contracts/CLAUDE.md](../../../contracts/CLAUDE.md) |
| Format specs                 | `specs/`     | —                                                   |
| Priority-stack build prompts | `prompts/`   | [prompts/INDEX.md](../../../prompts/INDEX.md)       |
| User-facing docs             | `docs/`      | —                                                   |
| Static pages / assets        | `public/`    | —                                                   |
| SDK package                  | `sdk/`       | —                                                   |

Top-level HTML entries: `index.html`, `features.html`, `embed.html`, `agent-home.html`, `agent-embed.html`. Additional routes are rewritten by the `vercel-rewrites` middleware in [vite.config.js](../../../vite.config.js) and mirrored in [vercel.json](../../../vercel.json).

## Tech stack

- **three.js** r176 — WebGL2 rendering + `GLTFLoader`, `DRACOLoader`, `KTX2Loader`, `MeshoptDecoder`, `OrbitControls`
- **dat.gui** + **tweakpane** — control panels
- **simple-dropzone** — file drops
- **vhtml** — JSX → HTML string rendering (no virtual DOM)
- **gltf-validator** — KhronosGroup validation
- **Vite 7** — dev server + build (two targets: `app` and `lib`)
- **vite-plugin-pwa** — service worker + manifest
- **ethers v6**, **viem**, **@privy-io/js-sdk-core** — wallet + on-chain
- **Neon Postgres**, **Upstash Redis**, **Cloudflare R2**, **Vercel** — backend
- **Foundry** + **OpenZeppelin** (contracts)

## Commands

```bash
npm install
npm run dev         # app dev server on :3000
npm run dev:lib     # library build watch
npm run build       # app → dist/
npm run build:lib   # web component → dist-lib/
npm run build:all   # both
npm run deploy      # build + vercel --prod
npx prettier --write <file>
node --check <file.js>
```

No automated test suite (`npm test` exits 0). Verify with `node --check`, `npm run build`, and manual smoke at `localhost:3000`.

## Conventions

- ESM only (no CommonJS in `src/` or `api/`)
- Prettier: **tabs**, 4-wide, single quotes, 100-col print width
- No TypeScript in the main app (JSDoc for public APIs); `sdk/` may use TS
- Components are **vhtml JSX**, not React — `.jsx` files, `jsxFactory: 'vhtml'`
- URL hash params live in `src/app.js`: `model`, `widget`, `agent`, `kiosk`, `brain`, `proxyURL`, `preset`, `cameraPosition`, `register`
- Tool result shape: `{ ok: true, ... }` or `{ ok: false, error: 'msg' }`
- Naming: CamelCase classes, camelCase methods, UPPER_CASE constants, `_underscore` private

## Priority stack — before you start

The order of work is fixed in [prompts/INDEX.md](../../../prompts/INDEX.md):

1. Wallet auth (SIWE / Privy)
2. Selfie → agent
3. Edit avatars
4. View + embed
5. Portable embed (Claude.ai / LobeHub)
6. On-chain deployment (ERC-8004)

If a task isn't in a band, ask first. Side lanes (`pretext/`, `scalability/`, `widget-studio/` polish, CLI, AR, screenshot export) are explicitly deprioritized.

## Where to change what

- Rendering / GUI / display toggles → `src/viewer.js` and `src/viewer/*.js` (see [3d-features](../3d-features/SKILL.md))
- Validation → `src/validator.js` + `src/components/validator-*.jsx` (see [model-validation](../model-validation/SKILL.md))
- Build / deploy / Vercel routes → see [build-deploy](../build-deploy/SKILL.md)
- Agent persona / memory / skills → `src/agent-*.js`, `src/runtime/`, `src/skills/`, `src/memory/` — read [src/CLAUDE.md](../../../src/CLAUDE.md)
- Auth / avatars / OAuth / MCP / rate-limit / R2 → `api/` — read [api/CLAUDE.md](../../../api/CLAUDE.md)
- ERC-8004 registries → `contracts/` — read [contracts/CLAUDE.md](../../../contracts/CLAUDE.md)
- Top-level routing / URL hash params → `src/app.js` (don't create a new routing layer)

## Ground rules

- One task, one PR. Note unrelated bugs in the report — don't fix them inline.
- Edit existing files before creating new ones. No new top-level `.md` files unless asked.
- No new runtime deps without approval.
- `node --check` every modified JS. `npm run build` before reporting done. Report both outputs.
- Respect `Files off-limits` in prompt files — parallel work may touch them.
- Never `forge script --broadcast` without explicit user approval. Deployed contract addresses are immutable.
- Report what changed, what you skipped, what broke, and any surprises.

