Collaborative Whiteboard
Build a collaborative whiteboard for iPhone and iPad in SwiftUI: several people draw on the same board, and each person's strokes appear on everyone else's screen almost instantly. Drawing always feels immediate because strokes are shown and saved locally with SwiftData first, then sent through a small WebSocket relay server; if the connection drops, you keep drawing, and your strokes are sent when it returns, without duplicates or lost work. Every stroke has a unique id and a consistent order, so every device ends up with the same picture, and undo only removes your own strokes. You'll learn drawing with SwiftUI Canvas and gestures, SwiftData, URLSessionWebSocketTask, offline queues, and making several devices converge on the same state.
- Estimate
- ~14.5h
- Steps
- 7
- Completed by
- 0
- Proposed by
- codeseed.app
SwiftUI · SwiftData · URLSessionWebSocketTask
Project roadmap
- 01
Design the sync model
~2.5hWrite DESIGN.md: a stroke has a UUID, an author device id, color, width, points and a timestamp; a board is a list of events (add stroke and remove stroke) applied in a fixed order (timestamp, then id), so every device ends up the same. Describe the relay server (it stores each board's events with a sequence number, broadcasts new ones, and sends missed events when a client reconnects), the local outbox of unsent events, and what happens on reconnect. Done when: DESIGN.md explains events, ordering and offline behavior.
- 02
Draw with SwiftUI
~2.5hBuild a drawing view with Canvas and a DragGesture: collect points while dragging, draw the current stroke live and smooth it with quadratic curves, and simplify long strokes to fewer points. Add a color and width picker and undo for your own last stroke. Support Apple Pencil pressure on iPad as an extra. Done when: drawing is smooth, and undo removes your last stroke.
- 03
Save strokes with SwiftData
~1.5hCreate SwiftData models for boards and stroke events (with the points encoded compactly), save each finished stroke immediately, and rebuild the board from its events when opened. Done when: drawings survive closing and reopening the app.
- 04
Build the relay server
~2hWrite a small WebSocket server (for example with Vapor in Swift, or Node.js) that keeps events per board with sequence numbers, ignores events it has already seen (by id), broadcasts new ones to everyone on the board, and sends events after a client's last sequence number when it connects. Limit event size and board size. Done when: two test clients on the same board exchange events and catch up after reconnecting.
- 05
Sync strokes
~2.5hConnect with URLSessionWebSocketTask, send events from a local outbox (stored in SwiftData alongside each stroke) and remove them once the server confirms, and apply incoming events from others, ignoring ones already stored. Reconnect with increasing waits, requesting events after the last sequence number received, and pause while the app is in the background. Done when: two devices drawing at the same time end up with identical boards.
- 06
Handle offline drawing
~1.5hShow the connection state and how many strokes are waiting to be sent. Test drawing on both devices while one is offline, then reconnecting: both must end up with the same strokes in the same order, with nothing lost or duplicated. Done when: offline drawing merges correctly on both devices.
- 07
Test it
~2hWrite unit tests for applying events and ordering (including duplicates and events arriving out of order) as pure functions, the outbox with an in-memory SwiftData container, and the sync client with a fake socket that drops and reconnects. Add a test simulating two devices with random events that checks both end up identical. Done when: all tests pass.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack