Real-Time Collaborative Code Editor β Where ideas blossom together
Lattice is a Google Docs-style collaborative code editor that enables multiple users to write code together in real-time. Built with a focus on seamless collaboration, Lattice ensures that conflicts are mathematically impossible through the use of CRDTs (Conflict-free Replicated Data Types).
- CodeMirror 6 with syntax highlighting for 15+ languages
- Custom cherry blossom theme
- Code folding, bracket matching, auto-close
- Keyboard shortcuts (undo, redo, find, comment)
- Real-time sync via Yjs CRDTs
- Remote cursor awareness with colored cursors
- User presence bar with avatars
- "Who's typing" indicator
- WebSocket hub with room-based broadcasting
- SQLite persistence for document recovery
- Rate limiting for API endpoints
- Graceful shutdown with cleanup
- Docker multi-stage builds
- Docker Compose orchestration
- Nginx reverse proxy with WebSocket support
- Health checks for all services
| Layer | Technology |
|---|---|
| Frontend | React 18, TypeScript 5, Vite 5 |
| Editor | CodeMirror 6, y-codemirror.next |
| CRDT | Yjs, lib0 |
| Backend | Go 1.21, Gorilla WebSocket |
| Database | SQLite (modernc.org/sqlite) |
| Transport | WebSocket (custom sync protocol) |
| Styling | CSS Modules, CSS Variables |
| Testing | Vitest, Playwright, Go testing |
| Deployment | Docker, Docker Compose, Nginx |
- Go 1.21 or higher
- Node.js 18 or higher
- npm (or pnpm/yarn)
- Docker & Docker Compose (optional, for containerized deployment)
git clone https://github.com/manpreetbhatti/lattice.git
cd latticeBackend:
cd backend
go mod tidyFrontend:
cd frontend
npm installUsing Make:
make dev # Starts both backend and frontend concurrentlyOr start services individually:
Backend (runs on http://localhost:8080):
cd backend
go run cmd/server/main.goFrontend (runs on http://localhost:3000):
cd frontend
npm run devQuick Start:
make build # Build Docker images
make up # Start all servicesOr using docker-compose directly:
docker-compose build
docker-compose up -dProduction Mode (with Nginx reverse proxy):
make prod
# Or: docker-compose --profile production up -dDocker Commands:
make logs # View logs
make down # Stop services
make clean # Remove containers and volumes
make status # Check container status and health| Mode | Frontend | Backend |
|---|---|---|
| Development | http://localhost:3000 | http://localhost:8080 |
| Docker | http://localhost:3000 | http://localhost:8080 |
| Production | http://localhost | (proxied through Nginx) |
make test-all # Runs backend, frontend, and E2E testsmake test-backend # With coverage and verbose output
# Or manually:
cd backend
go test ./... # Run all tests
go test ./... -v # Verbose output
go test ./... -cover # With coverage
go test -run TestConcurrent ./... # Run specific testsmake test-frontend # Run unit tests
# Or manually:
cd frontend
npm test # Run once
npm run test:watch # Watch modeNote: E2E tests require the backend and frontend servers to be running.
make test-e2e # Run E2E tests
make test-e2e-ui # Interactive UI mode
# Or manually:
cd frontend
npm run test:e2e # Run all E2E tests
npm run test:e2e:ui # Interactive mode
npx playwright test --project=chromium # Specific browser| Layer | Framework | Tests |
|---|---|---|
| Backend DB | Go testing | Room CRUD, Updates, Snapshots |
| Backend Hub | Go testing | Broadcast, Client registration |
| Backend API | Go testing | REST endpoints, Pagination |
| Frontend CRDT | Vitest | Y.Doc integration, Awareness |
| Frontend Hooks | Vitest | useLattice hook |
| E2E Collaboration | Playwright | Multi-user sync, Presence |
make help # Show all available commands
make dev # Start both backend and frontend
make dev-backend # Start backend only
make dev-frontend # Start frontend only
make test # Run backend + frontend unit tests
make lint # Run linters (go vet + eslint)
make db-reset # Reset the SQLite databasesequenceDiagram
participant A as Client A<br/>(CodeMirror + Yjs)
participant S as Go Server<br/>(Hub + SQLite)
participant B as Client B<br/>(CodeMirror + Yjs)
A->>S: Connect (WebSocket)
B->>S: Connect (WebSocket)
S->>B: Sync existing state
A->>S: Document update (CRDT)
S->>B: Broadcast update
B->>S: Document update (CRDT)
S->>A: Broadcast update
How CRDTs Work:
When two users type at the same position simultaneously:
- Traditional editors: One change wins, the other is lost (conflict!)
- Lattice: Both changes merge deterministically using Yjs's YATA algorithm β no data loss, ever.
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check |
/api/stats |
GET | Server statistics |
/api/rooms |
GET | List all rooms |
/api/rooms |
POST | Create a room |
/api/rooms/{id} |
GET | Get room details |
/api/rooms/{id} |
DELETE | Delete a room |
| Action | Windows/Linux | Mac |
|---|---|---|
| Undo | Ctrl+Z |
β+Z |
| Redo | Ctrl+Shift+Z |
β+Shift+Z |
| Find | Ctrl+F |
β+F |
| Toggle comment | Ctrl+/ |
β+/ |
| Indent | Tab |
Tab |
| Outdent | Shift+Tab |
Shift+Tab |
| Select next occurrence | Ctrl+D |
β+D |
| Select all occurrences | Ctrl+Shift+L |
β+Shift+L |
| Go to line | Ctrl+G |
β+G |
| Duplicate line | Ctrl+Shift+D |
β+Shift+D |
| Language | Extension | Language | Extension |
|---|---|---|---|
| JavaScript | .js |
Python | .py |
| TypeScript | .ts |
Go | .go |
| JSX | .jsx |
Rust | .rs |
| TSX | .tsx |
C/C++ | .c, .cpp |
| HTML | .html |
Java | .java |
| CSS | .css |
SQL | .sql |
| JSON | .json |
Markdown | .md |