Implementing Whiteboard (Collaborative Board) in Mobile Applications
Collaborative whiteboard — infinite canvas with objects: lines, shapes, stickers, images, text. Multiple users draw simultaneously, see each other's actions in real time. On mobile adds: finger input, pinch-to-zoom, Apple Pencil / Stylus with pressure sensitivity.
Most complex part here — not network level but canvas rendering and gesture handling under load.
Data Architecture: Object Model of Canvas
Each board object — distributed state document. Good fit: Y.Map where key is object UUID, value is its properties (type, coordinates, size, color, z-index). For composite objects (path from points) — Y.Array of points inside object.
const yobjects = ydoc.getMap('objects');
// Add arrow
yobjects.set(uuid(), {
type: 'arrow',
x1: 100, y1: 200,
x2: 400, y2: 350,
strokeColor: '#1a1a2e',
strokeWidth: 2
});
Concurrent move of one object by two users: Last-Write-Wins — acceptable for coordinates. Concurrent delete by one and change by other — standard CRDT problem: change operation applies to already deleted object and gets lost. Need tombstone logic or temporary "ghost" object storage.
Freehand Drawing: Stream Points
Free drawing generates 60–120 points per second (on 60Hz display). Sending each point via WebSocket — excessive. Optimization:
- Buffering — send batch points every 50ms.
- Simplification algorithm — Douglas-Peucker or Ramer-Douglas-Peucker removes redundant points with configurable epsilon. Curve from 500 points compresses to 30–50 without visible quality loss.
-
Stroke prediction — on iOS with Apple Pencil
UITouch.predictedTouchespredict next points before actual arrival, reducing perceived latency.
Stroke as CRDT object: start with temporary Y.Array points in Awareness (not in document — don't need full history of every point). On completion (touchEnd / pointerUp) — fix simplified path in document as single object.
Canvas Rendering on Mobile
React Native: react-native-skia (Skia graphics engine) — best option for performant 2D rendering. @shopify/react-native-skia supports Path, Paint, Text, Image. Render on GPU via RN's new architecture. react-native-svg — simpler but slower for animated objects.
Flutter: CustomPainter with Canvas API — native path. flutter_drawing_board — ready package with basic tools. For production: custom CustomPainter with dirty-region optimization (redraw only changed region via Canvas.clipRect).
iOS Native: Metal + MetalKit for max performance, UIBezierPath + CALayer for medium complexity. Apple PencilKit — ready component with Pencil support but limited customization.
Android Native: Canvas API with Path for simple cases, OpenGL ES / Vulkan via GLSurfaceView for complex.
Infinite Canvas Virtualization
With 1000+ objects, rendering entire canvas each frame — problem. Need spatial index (R-tree or simple grid-based) to find objects in current viewport. Render only visible objects + small buffer beyond viewport edges.
rbush — JavaScript R-tree library, works in React Native. On panZoom determine new viewport, query objects in that bounding box, render only them.
Sync: What to Send and When
Cursor/viewport awareness (user position on canvas) — via Y.js Awareness, not document, 10fps sufficient.
Objects in creation — two modes:
- Temporary preview via Awareness (others see unfixed object).
- Only final object after
touchEnd(simpler but no real-time drawing preview).
First mode gives better UX, second — less traffic and complexity.
Assessment
Basic whiteboard (shapes, text, arrows, sync) on Flutter or React Native — 10–16 weeks. With brush drawing, pressure sensitivity, smart path simplification and large canvas virtualization — 20–32 weeks.







