Pix3 is a browser-based editor for building rich HTML5 scenes that combine 2D and 3D layers.
Pix3 employs an operations-first architecture where all state mutations are handled by OperationService. Actions are initiated via CommandDispatcher, which wraps operations. Core functionalities are provided by injectable services (@injectable(), @inject()). UI and metadata are managed by Valtio reactive proxies (appState), while scene nodes are non-reactive and owned by SceneManager in SceneGraph objects. The rendering is handled by a single Three.js pipeline. UI components extend ComponentBase, defaulting to light DOM. A Property Schema System dynamically renders UI in the Inspector based on node schemas.
Scene creation commands use a shared CreateNodeBaseCommand in src/features/scene, while each concrete Create*Command keeps node-specific metadata/IDs for registry and menu integration.
See full specification in docs/pix3-specification.md. Additional agent guidelines: AGENTS.md.
A self-hosted Node.js server that enables real-time multiplayer editing and cloud project storage.
- Express — REST API for auth, projects, file storage, and admin
- better-sqlite3 — local SQLite database (users, projects, memberships)
- @hocuspocus/server — WebSocket CRDT sync via Yjs
- JWT (HttpOnly cookie) — session auth; token also returned in response body for WebSocket handshake
- bcrypt — password hashing
| Group | Endpoints |
|---|---|
| Auth | POST /api/auth/register, POST /api/auth/login, POST /api/auth/logout, GET /api/auth/me |
| Projects | GET /api/projects, POST /api/projects, POST /api/projects/:id/share, DELETE /api/projects/:id/share, DELETE /api/projects/:id |
| Storage | GET /api/projects/:id/manifest, GET /api/projects/:id/files/*, POST /api/projects/:id/files/*, DELETE /api/projects/:id/files/* |
| Admin | GET /api/admin/users, DELETE /api/admin/users/:id, GET /api/admin/projects |
| Sync | WebSocket on WS_PORT (default 4000) — room format project:{projectId} |
HTTP_PORT=4001
WS_PORT=4000
DB_PATH=./data/pix3.db
HOCUSPOCUS_DB_PATH=./data/crdt.db
PROJECTS_STORAGE_DIR=./data/projects
JWT_SECRET=change-me
PASSWORD_SALT_ROUNDS=10cd packages/pix3-collab-server
npm install
npm run dev # tsx watch src/server.tsAppState.auth—{ user, isAuthenticated, isLoading }— tracks sessionAuthService—restoreSession()called on shell init; also exposeslogin(),register(),logout()pix3-auth-screen— combined login/register Lit component shown before the welcome screen when unauthenticated- JWT
tokenis stored onappState.auth.user.tokenand passed to HocuspocusProvider for WebSocket auth
ApiClient.ts— typedfetchwrapper for all REST endpoints (credentials: 'include'for cookie auth)CloudProjectService— wraps project CRUD, exposessubscribe()for reactive UI updates- Welcome screen (
pix3-welcome) shows Cloud Projects alongside local recent projects
CollaborationService— connects to Hocuspocus; room name simplified toproject:{id}; auth token resolved fromappState.auth.user.tokenor atokenOverride(share token for guests)CollabSessionService— generates share tokens via API and embeds them in invite URLs (?token=)CollabJoinService— reads optional?token=from URL for guest access (no account needed)SceneCRDTBinding— unchanged;Y.Map('scene').get('snapshot')format is compatible with server persistence
LocalSyncService— opt-in sync between a cloud project and a local directory via File System Access API; uses SHA-256 manifest diffing to only transfer changed files
Pix3 supports project-level autoload scripts via pix3project.yaml.
- Manage entries in Project Settings > Autoload.
- Quick-create from Assets Browser > Create > Create autoload script.
- Generates
scripts/<SingletonName>.tsfrom template. - Rebuilds project scripts.
- Registers the singleton in project autoloads automatically.
- Generates
Pix3 includes a node-local signals engine and scene-level groups engine.
- Signals (
NodeBase):signal(name),connect(signal, target, method),emit(signal, ...args),disconnect(...)- Base
Script.onDetach()auto-cleans listeners viadisconnectAllFromTarget(this).
- Groups (
NodeBase+SceneManager):addToGroup(),removeFromGroup(),isInGroup()sceneManager.getNodesInGroup(group)sceneManager.callGroup(group, method, ...args)
- Groups are stored in scene YAML as
groups: [].
Recommended pattern for global events: create an Events autoload singleton and emit/connect signals through it.
- Node.js 18+
- npm (or yarn)
- Chromium-based browser
git clone <repository-url>
cd pix3
npm installcd pix3/packages/pix3-runtime && npm run yalc:publish
yalc update
The project uses multiple tsconfig files to manage different scopes:
tsconfig.json: Main editor and core library configuration.samples/tsconfig.json: configuration for standalone sample scripts to ensure they resolve@pix3/runtimecorrectly without being part of the main build.packages/pix3-runtime/tsconfig.json: configuration for the runtime package.
npm run devOpen the app at http://localhost:5173.
- Launch Chrome with remote debugging. The
.vscode/launch.jsonconfig uses these flags. - Start the MCP server from the workspace root:
npx chrome-devtools-mcp@0.12.1 --autoConnect --browserUrl=http://127.0.0.1:9222
npm run dev- Start Vite dev server with hot reloadnpm run build- Build production bundlenpm run test- Run Vitest unit testsnpm run lint- Check code style and errorsnpm run format- Format code with Prettiernpm run type-check- Validate TypeScript types
Use CSS custom properties for accent colors, defined in src/index.css:
--pix3-accent-color: #ffcf33(for hex values)--pix3-accent-rgb: 255, 207, 51(forrgba()functions with opacity)
Example: background: rgba(var(--pix3-accent-rgb), 0.8);
- Unit Tests: Vitest
- Linting: ESLint with TypeScript and Lit-specific rules
- Formatting: Prettier
- Type Safety: Strict TypeScript
- Accessibility: WCAG 2.1 AA compliance target
[Add your license information here]
Built with ❤️ for creators who blend pixels and polygons
