Skema is a modern, collaborative online whiteboard application that enables teams to sketch, brainstorm, and diagram ideas together in real-time. Built with a clean, minimal UI and powered by modern web technologies, it provides an infinite canvas for creative collaboration.
- Freehand Drawing: Natural pencil tool with pressure sensitivity
- Shapes: Rectangles, ellipses, rhombuses, lines, and arrows
- Text Tools: Multiple font families and styling options
- Image Support: Upload and manipulate images on canvas
- Eraser Tool: Clean removal of drawing elements
- Live Cursors: See teammates' cursor positions in real-time
- Instant Sync: All drawing actions synchronized across connected users
- User Presence: Know who's online and actively working
- Room-based Sessions: Create and join collaborative drawing rooms
- Infinite Canvas: Unlimited drawing space with smooth pan and zoom
- Layer Management: Organize drawings with intelligent layering
- Undo/Redo: Full history tracking with undo/redo functionality
- Performance Optimized: Smooth rendering even with thousands of elements
- Multiple Auth Providers: GitHub, Google, and Discord OAuth integration
- Secure Sessions: JWT-based authentication with NextAuth.js
- Room Access Control: Admin-controlled room permissions
- Theme Support: Light and dark mode with system preference detection
- Stroke Customization: Width, style, and color options
- Background Options: Multiple canvas background choices
- Shape Properties: Fill, stroke, and style customization
Skema is built as a modern monorepo using Turborepo with a microservices architecture:
skema/
βββ apps/
β βββ skema-web/ # Next.js frontend application
β βββ ws-server/ # WebSocket server for real-time features
βββ packages/
β βββ db/ # Prisma database schema and client
β βββ ui/ # Shared React components
β βββ eslint-config/ # Shared ESLint configurations
β βββ typescript-config/ # Shared TypeScript configurations
βββ docker-compose.yml # Production deployment configuration
Frontend (skema-web)
- Next.js 15.4.2 - React framework with App Router
- React 19 - UI library with concurrent features
- TailwindCSS 4.1 - Utility-first CSS framework
- Motion - Animation library for smooth interactions
- RoughJS - Hand-drawn style graphics rendering
- Zustand - Lightweight state management
- NextAuth.js - Authentication framework
Backend Services
- WebSocket Server - Real-time communication with Bun runtime
- Prisma ORM - Type-safe database access
- PostgreSQL - Primary database
- JWT - Secure token-based authentication
Development & Deployment
- Turborepo - Monorepo build system
- TypeScript - Type safety across the stack
- Docker - Containerized deployment
- Nginx - Reverse proxy and load balancing
- Bun - Fast JavaScript runtime and package manager
- Node.js 18+
- Bun 1.2.16+ (recommended) or npm/yarn
- PostgreSQL database
- Docker (for production deployment)
-
Clone the repository
git clone https://github.com/whoisasx/Canvora.git cd skema -
Install dependencies
bun install
-
Set up environment variables
Create
.envfiles in both applications:apps/skema-web/.env.local
# Database DATABASE_URL="postgresql://username:password@localhost:5432/skema" # Authentication NEXTAUTH_URL="http://localhost:3000" NEXTAUTH_SECRET="your-secret-key" AUTH_SECRET="your-auth-secret" JWT_SECRET="your-jwt-secret" # OAuth Providers AUTH_GITHUB_ID="your-github-client-id" AUTH_GITHUB_SECRET="your-github-client-secret" AUTH_GOOGLE_ID="your-google-client-id" AUTH_GOOGLE_SECRET="your-google-client-secret" # WebSocket WS_URL="ws://localhost:8080" NEXT_PUBLIC_WS_URL="ws://localhost:8080" BASE_URL="http://localhost:3000" AUTH_TRUST_HOST=true
apps/ws-server/.env
BASE_URL="http://localhost:3000"
-
Set up the database
cd packages/db bunx prisma migrate dev bunx prisma generate cd ../..
-
Start development servers
# Start all services bun dev # Or start individually bun dev --filter=@repo/web # Frontend only bun dev --filter=ws-server # WebSocket server only
-
Access the application
- Frontend: http://localhost:3000
- WebSocket Server: ws://localhost:8080
Using Docker Compose (Recommended)
-
Configure environment
cp .env.example .env # Edit .env with production values -
Deploy with Docker
docker-compose up -d
The application will be available at http://localhost with Nginx handling routing and SSL termination.
- Visit the homepage and authenticate using GitHub, Google, or Discord
- Create a new room or join an existing one using a room code
- Start drawing using the toolbar on the left
- Invite collaborators by sharing the room URL
- Select Tool (V): Select and manipulate existing elements
- Pencil (P): Freehand drawing with customizable stroke
- Rectangle (R): Create rectangular shapes
- Ellipse (O): Draw circles and ellipses
- Arrow (A): Create directional arrows
- Line (L): Draw straight lines
- Text (T): Add text annotations
- Image (I): Upload and place images
- Eraser (E): Remove elements from canvas
V- Select toolP- Pencil toolR- Rectangle toolO- Ellipse toolA- Arrow toolL- Line toolT- Text toolE- Eraser toolCtrl/Cmd + Z- UndoCtrl/Cmd + Y- RedoCtrl/Cmd + +/-- Zoom in/outSpace + Drag- Pan canvas
apps/skema-web/
βββ app/ # Next.js App Router
β βββ (auth)/ # Authentication pages
β βββ api/ # API routes
β βββ canvas/ # Canvas collaboration pages
β βββ dashboard/ # User dashboard
β βββ draw/ # Drawing engine and utilities
β βββ freehand/ # Offline drawing mode
βββ components/ # React components
βββ lib/ # Utility libraries
βββ types/ # TypeScript type definitions
βββ utils/ # Helper functions and stores
apps/ws-server/
βββ index.ts # Server entry point
βββ server.ts # WebSocket server implementation
βββ messageHandlers.ts # WebSocket message handlers
βββ types.ts # WebSocket message types
packages/
βββ db/ # Database schema and migrations
βββ ui/ # Shared UI components
βββ eslint-config/ # Linting configurations
βββ typescript-config/ # TypeScript configurations
- Fork the repository
- Create a feature branch
git checkout -b feature/amazing-feature
- Make your changes
- Run tests and linting
bun lint bun check-types
- Commit your changes
git commit -m 'Add amazing feature' - Push to the branch
git push origin feature/amazing-feature
- Open a Pull Request
# Development
bun dev # Start all development servers
bun dev --filter=web # Start frontend only
bun dev --filter=ws-server # Start WebSocket server only
# Building
bun build # Build all applications
bun build --filter=web # Build frontend only
# Code Quality
bun lint # Run ESLint on all packages
bun check-types # Run TypeScript checks
bun format # Format code with Prettier
# Database
cd packages/db
bunx prisma migrate dev # Run database migrations
bunx prisma generate # Generate Prisma client
bunx prisma studio # Open Prisma StudioThe application uses PostgreSQL with Prisma ORM. Key models include:
- User: Authentication and user profile data
- Room: Drawing session metadata
- Chat: Real-time drawing message storage
- Account: OAuth provider account linking
The real-time system handles various message types:
join-room/leave-room- Room membershipdraw-message- Drawing operationscursor/cursors-batch- Cursor trackingundo/redo- History operationssync-all- Full canvas synchronization
Configure OAuth providers in your environment:
- GitHub: Create OAuth app at https://github.com/settings/developers
- Google: Configure OAuth at https://console.cloud.google.com/
- Discord: Set up application at https://discord.com/developers/applications
Skema is optimized for performance with:
- Canvas Virtualization: Only renders visible elements
- Message Throttling: Prevents spam and reduces network load
- Efficient Serialization: Optimized data structures for WebSocket communication
- IndexedDB Caching: Offline storage for drawing data
- Layer Management: Smart rendering order for complex drawings
GET /api/rooms- List user's roomsPOST /api/rooms- Create new roomGET /api/rooms/[id]- Get room detailsPOST /api/create-chat- Store drawing messagePATCH /api/update-chat- Update drawing messageDELETE /api/delete-chat- Remove drawing message
Connect to ws://localhost:8080 and send JSON messages with the following structure:
interface MessageData {
type: "join-room" | "draw-message" | "cursor" | "undo" | "redo";
roomId?: string;
clientId?: string;
message?: any;
// ... additional fields based on message type
}- JWT-based authentication with secure token rotation
- CORS protection for API endpoints
- Input validation and sanitization
- Rate limiting on WebSocket connections
- Secure OAuth integration with major providers
This project is licensed under the MIT License - see the LICENSE file for details.
- Documentation: Check out our Wiki
- Issues: Report bugs on GitHub Issues
- Discussions: Join the conversation in GitHub Discussions
- Inspired by Excalidraw for the drawing experience
- Built with RoughJS for hand-drawn style graphics
- Uses Prisma for type-safe database access
- Powered by Next.js and React
Made with β€οΈ by the Canvora team