My App
BoardKitFrontend

Frontend Overview

Overview of the @hfu.digital/boardkit-react package

The @hfu.digital/boardkit-react package provides a complete React frontend for collaborative whiteboards, including a canvas rendering engine, input pipeline, hooks, and pre-built components.

What's Included

CategoryExports
ContextBoardKitProvider, useBoardKit
HooksuseBoard, useCollaboration, useTool, useViewport, useHistory, usePageNavigation, usePresence, useGrid, useFollowMode, useImageImport, useExport, useErrorRecovery, useKeyboardShortcuts
ComponentsBoardCanvas, Toolbar, PageNavigator, SelectionHandles, TextEditor, ParticipantList, CursorOverlay, ShareDialog, ExportDialog, Minimap, DropZone
EngineCanvas2DRenderer, InputPipeline, viewport utilities, element renderers
GesturesGestureRecognizer, MouseHandler, TouchHandler, PenHandler
StoreBoardStore (mutable store with slice-based pub/sub)

Peer Dependencies

{
    "react": "^18.0.0 || ^19.0.0",
    "react-dom": "^18.0.0 || ^19.0.0"
}

Quick Start

import {
    BoardKitProvider,
    BoardCanvas,
    Toolbar,
    useBoard,
    useCollaboration,
    useTool,
    useKeyboardShortcuts,
} from '@hfu.digital/boardkit-react';

function App() {
    return (
        <BoardKitProvider config={{ apiUrl: '/api', wsUrl: 'ws://localhost:3000/board' }}>
            <Whiteboard />
        </BoardKitProvider>
    );
}

function Whiteboard() {
    const { board, loading } = useBoard('my-board-id');
    const { connectionState } = useCollaboration('my-board-id');
    const { activeTool, setTool } = useTool();
    useKeyboardShortcuts();

    if (loading) return <p>Loading...</p>;

    return (
        <div style={{ width: '100vw', height: '100vh' }}>
            <Toolbar activeTool={activeTool} onToolChange={setTool} />
            <BoardCanvas />
        </div>
    );
}

Architecture

The frontend follows a mutable-store-outside-React architecture:

  1. BoardStore lives outside React state. It holds all board data, scene state, viewport, tool state, and collaboration data.
  2. Hooks bridge the store into React via useSyncExternalStore and slice-based subscriptions.
  3. Canvas2DRenderer renders directly to two stacked <canvas> elements — no React reconciliation for drawing.
  4. InputPipeline translates DOM pointer events into normalized InputEvents that feed into the active tool.

This architecture avoids React re-renders during rapid drawing operations.

On this page