- Project scaffolding (pyproject.toml, Makefile, CI workflows)
- Pre-commit hooks, ruff, ty configuration
- Documentation structure (Sphinx + shibuya)
- Domain models:
Canvas,Stroke,Shape,Text,Point,ElementStyle - Type enums:
ElementType,ShapeType - Storage layer:
StorageProtocol,InMemoryStorage - Service layer:
CanvasService - REST API: Canvas CRUD, Element CRUD
- Litestar plugin:
ScribblPlugin,ScribblConfig - Tests: 114 passing
- WebSocket handler for canvas sessions (
CanvasWebSocketHandler) - Connection manager for tracking users (
ConnectionManager) - Broadcast element changes to connected clients
- Cursor position sync
- Conflict resolution strategy (last-write-wins with version tracking)
- Message types: join, leave, element_add/update/delete, cursor_move
- Tests: 137 passing
- SQLAlchemy models (
CanvasModel,ElementModelwith JSON columns) - Alembic migrations (
001_initial_schema) -
DatabaseStorageimplementingStorageProtocol -
[db]optional extra (advanced-alchemy, alembic, asyncpg) - Lazy imports to avoid errors when db extra not installed
- Tests: 164 passing
- Element layers with z-index ordering (
z_indexfield on Element) - Z-ordering operations:
bring_to_front,send_to_back,move_forward,move_backward - Command pattern for undo/redo (
CommandHistory,CommandHistoryManager) - Command types: Add, Delete, Update, Move, Reorder, Group, Ungroup
- Element grouping with
Groupelement type andgroup_idfield - Group operations:
group_elements,ungroup_elements - Copy/paste elements with per-user clipboard
- Database migration for z_index and group_id (
002_add_z_index_and_group) - Tests: 207 passing
-
ExportServicefor canvas rendering to multiple formats - Export canvas as JSON (dict/string)
- Export canvas as SVG (strokes, shapes, text with full styling)
- Export canvas as PNG (via cairosvg, optional
[export]extra) - REST API endpoints:
/export/json,/export/svg,/export/png - Tests: 237 passing
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/canvases |
Create canvas |
| GET | /api/canvases |
List canvases |
| GET | /api/canvases/{id} |
Get canvas with elements |
| PATCH | /api/canvases/{id} |
Update canvas |
| DELETE | /api/canvases/{id} |
Delete canvas |
| GET | /api/canvases/{id}/elements |
List elements |
| POST | /api/canvases/{id}/elements/strokes |
Add stroke |
| POST | /api/canvases/{id}/elements/shapes |
Add shape |
| POST | /api/canvases/{id}/elements/texts |
Add text |
| DELETE | /api/canvases/{id}/elements/{eid} |
Delete element |
| GET | /api/canvases/{id}/export/json |
Export as JSON |
| GET | /api/canvases/{id}/export/svg |
Export as SVG |
| GET | /api/canvases/{id}/export/png |
Export as PNG |
| Endpoint | Description |
|---|---|
ws://.../ws/canvas/{id} |
Real-time canvas collaboration |
Message Types (Client -> Server):
join- Join canvas session with user_id/user_nameelement_add- Add stroke/shape/text elementelement_update- Update element propertieselement_delete- Delete an elementcursor_move- Update cursor position
Message Types (Server -> Client):
sync- Full canvas state on joinuser_joined/user_left- User presenceelement_added/element_updated/element_deleted- Element changescursor_moved- Other users' cursor positionserror- Error responses
- Docker deployment (Dockerfile + docker-compose.yml)
- SQLite storage backend for persistence
- Create SQLite storage implementation (
storage/db/auth_storage.py) - User, Session, UserStats models (
storage/db/auth_models.py) - Database setup and session factory (
storage/db/setup.py) - Wire up DATABASE_URL environment variable
- Create SQLite storage implementation (
- Wire up stats recording to game events
- TelemetryService with tracking for connections, games, rounds, guesses, drawings
- Room created/closed tracking
- Game started/ended tracking with winner
- Round started tracking with drawer
- Guess tracking (correct/wrong, time)
- Drawing completed tracking
- Player join/leave tracking
- Telemetry & Analytics
- Stats API endpoint (
/stats) - Optional Sentry integration (SENTRY_DSN env var)
- Optional PostHog integration (POSTHOG_API_KEY env var)
- Custom callback support for external integrations
- Stats API endpoint (
- Swap to Scalar default + Swagger OpenAPI plugin
- ScalarRenderPlugin at
/schema/(primary) - SwaggerRenderPlugin at
/schema/swagger(secondary) - Custom Scalar theme CSS (
frontend/dist/css/scalar-theme.css)
- ScalarRenderPlugin at
- Database CLI commands via advanced-alchemy SQLAlchemyPlugin
-
litestar database upgrade- Run migrations -
litestar database downgrade- Rollback migrations -
litestar database make-migrations- Autogenerate migrations from models -
litestar database show-current-revision- Check current state
-
- Custom query CLI commands (
litestar query)-
litestar query users- List users with search -
litestar query stats- Show user statistics -
litestar query sessions- List sessions (with --active flag) -
litestar query leaderboard- Show leaderboard (by wins/games/accuracy) -
litestar query tables- List all tables with row counts -
litestar query sql "SELECT ..."- Execute raw SELECT queries
-
- Environment configuration
-
.env.examplewith all environment variables documented - LITESTAR_APP for CLI discovery
- DATABASE_URL support in migrations
-
- Database migrations
-
001_initial_schema- Canvas and Element tables -
002_add_z_index_and_group- Z-index and grouping (SQLite batch mode) -
003_auth_tables- Users, UserStats, Sessions tables
-
- Request/response validation error handling
- Structured error responses with
ErrorResponsedataclass - Per-field validation error details
- Exception handlers for all custom exceptions
- HTTP exception handler with appropriate error codes
- Structured error responses with
- Health check endpoints (
/health,/ready)-
/health- Liveness probe with component health status -
/ready- Readiness probe checking dependencies - Database health check with latency measurement
-
- Structured logging with correlation IDs
-
CorrelationIdMiddlewarefor request tracking -
RequestLoggingMiddlewarefor request/response logging -
X-Correlation-IDheader propagation - Structlog integration with context variables
- JSON logging option for production
-
- Rate limiting
-
RateLimitConfigusing Litestar's built-in middleware - Configurable via environment variables (
RATE_LIMIT_*) - Default: 100 requests/minute, excludes health checks
- Returns
429 Too Many RequestswithRateLimit-*headers
-
- Task queue with Huey (SQLite backend)
-
SqliteHueyconfiguration with environment variables (TASK_QUEUE_*) - Periodic tasks: session cleanup, weekly stats reset, canvas cleanup, telemetry aggregation
- CLI commands:
litestar tasks run,litestar tasks status,litestar tasks list - Manual task runners:
cleanup-sessions,cleanup-canvases,reset-weekly -
[tasks]optional extra for Huey dependency
-
Free-form collaborative whiteboard where everyone draws simultaneously.
Features:
- All users can draw at same time
- Real-time cursor positions
- Layer management (visibility, lock, reorder, delete)
- Export to PNG/SVG
Advanced drawing tools and capabilities.
- Image Upload & Manipulation (upload, resize, rotate, crop, opacity)
- Advanced Shape Tools (polygon, star, arrows, speech bubbles, Bezier curves)
- Text Formatting (font selection, bold/italic/underline, alignment, text-along-path)
- Layer opacity sliders
- Blend modes for layers
- Infinite canvas with pan/zoom
New Canvas Clash variations.
- Speed Draw - Rapid-fire 15-30 second rounds
- Blind Contour - Can't see strokes until time's up
- Telephone Game - Alternating draw/guess, each sees only previous entry
- Multiplayer Canvas - Everyone draws simultaneously, layer per user, time-lapse export
Community and engagement features.
- User Profiles (public gallery, achievements, badges)
- Drawing Gallery (browse, like, comment, share community art)
- Drawing Challenges (daily/weekly prompts with voting)
- Following/followers system
- Sticky notes and annotations for collaborative mode
Monetization and physical products.
- Image to T-Shirt (print-on-demand integration: Printful, Printify)
- Sticker Sheets (print-ready PDF with cut lines)
- Canvas Prints (high-res export, standard print sizes)
- Design marketplace
- NFT Minting (optional blockchain integration)
Native applications.
- Progressive Web App (PWA) with offline support
- Native iOS app with Apple Pencil support
- Native Android app with stylus support
- Desktop apps (Electron or Tauri)
- Tablet-optimized interface
Third-party connectivity.
- Webhooks (canvas updates, game events, Discord/Slack integration)
- Public API with OAuth2 and rate limiting
- Embed Widget (customizable canvas for external sites)
- AI Assistance (auto-complete strokes, style transfer, background removal, upscaling)
- Video/voice chat integration
Production-grade deployment.
- Redis session storage for horizontal scaling
- WebSocket message broker (Redis Pub/Sub) for multi-instance
- CDN integration for static assets
- S3/GCS storage backend for large canvases
- Kubernetes Helm chart
- Terraform modules for cloud deployment
Pictionary-style drawing game - fully implemented with:
- Game lobby with room codes, public/private rooms
- Round system with drawer rotation, word selection, timer
- Drawing tools: pen, shapes, line, fill, eraser, 24 colors, brush sizes
- Chat system with guessing, close guess hints, correct guess celebrations
- Spectator mode, custom word lists, content moderation
- All UI components: lobby, game screen, word selection, round end, final scoreboard
- OAuth2 authentication (Google, Discord, GitHub)
- User profiles with avatars and stats
- Global leaderboards (wins, fastest, drawer, games played)
- Room permissions (kick, ban, transfer host)
- 38 auth + permissions tests passing
- WebSocket reconnection with exponential backoff
- Real-time stroke streaming (no delay until mouse release)
- All drawing tools working (shapes, text, eraser, fill)
- Undo/redo functionality
- PNG export with Pillow (no system dependencies)
Modern, interactive frontend using HTMX + Tailwind CSS + DaisyUI with Bun for build tooling.
- Create
frontend/directory structure:frontend/ ├── package.json # Bun package manifest ├── bunfig.toml # Bun configuration ├── tailwind.config.js # Tailwind + DaisyUI config ├── src/ │ ├── css/ │ │ └── main.css # Tailwind directives + custom styles │ └── js/ │ └── main.js # HTMX extensions, Alpine.js, custom JS └── dist/ # Built assets (gitignored) - Initialize Bun project:
bun init - Install dependencies:
bun add tailwindcss @tailwindcss/cli daisyui bun add -d bun-plugin-tailwind
- Configure
tailwind.config.jswith DaisyUI plugin and scribbl theme - Add build scripts to
package.json:bun run build- Production buildbun run dev- Watch mode for development
- Add
[ui]optional extra to pyproject.toml
- Install litestar-htmx:
uv add litestar-htmx - Configure
HTMXPluginin Litestar app - Set up Jinja2 template engine with
JinjaTemplateEngine - Configure static files router for built assets:
from litestar.static_files import create_static_files_router static_router = create_static_files_router( path="/static", directories=["frontend/dist"] )
- Create template directory:
src/scribbl/templates/ - Add
HTMXRequesttype for HTMX-aware request handling
- Create
base.htmltemplate with:- DaisyUI theme support (light/dark toggle)
- HTMX script include (
<script src="https://unpkg.com/htmx.org@2"></script>) - Alpine.js for client-side interactivity
- Tailwind CSS built stylesheet
- Navigation component with DaisyUI navbar
- Flash message/toast container for HTMX responses
- Create
partials/directory for HTMX partial templates - Implement DaisyUI theme switcher (localStorage persistence)
-
GET /- Dashboard/landing page- Recent canvases grid (DaisyUI cards)
- Create new canvas button
- Quick stats (total canvases, recent activity)
-
GET /canvases- Canvas list view- Responsive grid layout with DaisyUI cards
- Search/filter with HTMX (
hx-get,hx-trigger="keyup changed delay:300ms") - Pagination with HTMX (
hx-get,hx-target,hx-swap="outerHTML") - Delete canvas with confirmation modal
- Partial templates for HTMX responses:
partials/canvas_card.html- Single canvas cardpartials/canvas_list.html- Canvas list containerpartials/canvas_grid.html- Grid of canvas cards
-
GET /canvases/{id}/edit- Full canvas editor page - Canvas toolbar component (DaisyUI button groups):
- Tool selection (pen, shapes, text, eraser)
- Color picker
- Stroke width slider
- Undo/redo buttons
- Layer controls
- Canvas area with HTML5
<canvas>element - Side panel for:
- Element properties (HTMX updates)
- Layer list with drag-to-reorder
- Export options
- WebSocket connection indicator (DaisyUI badge)
- User presence indicators (avatars, cursor positions)
- Canvas CRUD with HTMX:
- Create:
hx-post="/api/canvases"with form - Update:
hx-patch="/api/canvases/{id}"inline editing - Delete:
hx-deletewithhx-confirmor DaisyUI modal
- Create:
- Element operations via HTMX:
- Add element: POST with
HTMXTemplateresponse - Update element: PATCH with partial swap
- Delete element: DELETE with
hx-swap="delete"
- Add element: POST with
- Use
litestar-htmxresponse classes:from litestar_htmx.response import HTMXTemplate, Reswap, Retarget, TriggerEvent @get("/canvases/{id}/elements") async def get_elements(id: UUID) -> Template: return HTMXTemplate( template_name="partials/element_list.html", context={"elements": elements}, trigger_event="elementsLoaded" )
- Implement
HXLocationfor client-side redirects without full reload - Use
TriggerEventfor toast notifications
- WebSocket connection management with reconnection
- HTMX WebSocket extension for real-time updates:
<div hx-ext="ws" ws-connect="/ws/canvas/{id}"> <div id="canvas-elements" hx-swap-oob="true"> <!-- Elements updated via WebSocket --> </div> </div>
- Cursor position broadcasting
- Live element updates from other users
- Connection status indicator with DaisyUI badge states
- Navigation:
navbar,menu,breadcrumbs - Canvas cards:
card,card-body,card-actions - Forms:
input,select,range,toggle - Buttons:
btn,btn-primary,btn-group - Feedback:
toast,alert,loading,progress - Modals:
modalfor confirmations, settings - Drawers:
drawerfor mobile navigation - Tooltips:
tooltipfor toolbar hints - Theme: Custom scribbl theme extending DaisyUI
- Create
UIControllerclass:from litestar import Controller, get from litestar_htmx import HTMXRequest from litestar.response import Template class UIController(Controller): path = "/ui" @get("/") async def index(self, request: HTMXRequest) -> Template: return Template("index.html", context={...}) @get("/canvases") async def canvas_list(self, request: HTMXRequest) -> Template: if request.htmx: return HTMXTemplate("partials/canvas_list.html", ...) return Template("canvas_list.html", ...)
- Route handlers for all UI pages
- HTMX-aware responses (full page vs partial)
- Makefile targets:
make frontend-install- Install frontend dependencies with Bunmake frontend-build- Build production assetsmake frontend-dev- Watch mode for developmentmake serve-dev- Run Litestar with frontend watch
- Hot reload setup for templates
- Browser-sync or similar for CSS changes
# pyproject.toml additions
[project.optional-dependencies]
ui = [
"litestar[jinja]",
"litestar-htmx>=0.4.0",
]// frontend/package.json
{
"dependencies": {
"tailwindcss": "^4.0",
"daisyui": "^5.0"
},
"devDependencies": {
"bun-plugin-tailwind": "^0.1"
}
}- litestar-workflows: Tailwind CDN + Alpine.js base template pattern
- litestar-pydotorg: DaisyUI theming, Lucide icons, theme persistence
- litestar-htmx:
HTMXPlugin,HTMXRequest,HTMXTemplateresponses
make dev # Install Python dependencies
make frontend-install # Install frontend dependencies (Bun)
make frontend-build # Build frontend assets
make serve # Run app at http://127.0.0.1:8000 (includes UI)
make serve-dev # Run with hot reload (run make frontend-dev in another terminal)
make serve-api # Run API only (no UI)
make lint # Run linters
make ci # Run all CI checks