INKFINITE#
An infinite canvas whiteboard application for creative visual thinking and collaboration.
Overview#
Inkfinite is a web-based infinite canvas application.
Architecture#
Inkfinite is built with a reactive architecture and optimized canvas rendering. There are pan, zoom, and shape manipulation tools.
The project is organized as a pnpm monorepo with the following structure:
.
├── packages/
│ ├── core/ # Core logic and state management
│ └── renderer/ # Canvas rendering engine
└── apps/
├── web/ # SvelteKit web application
└── desktop/ # Tauri desktop wrapper
Desktop App: The desktop app shares the same codebase as the web app. The web app detects if it's running inside Tauri and uses file-based persistence instead of IndexedDB.
Packages#
packages/core
Modules#
-
Math (
math.ts) - Vector mathematics and geometric operationsVec2: 2D vector operations (add, subtract, scale, normalize, distance, etc.)Mat3: 3x3 transformation matrices for 2D transformsBox2: Axis-aligned bounding boxes
-
Camera (
camera.ts) - Viewport and coordinate system transforms- World ↔ screen coordinate conversions
- Pan and zoom operations
- Camera state management
-
Geometry (
geom.ts) - Shape hit testing and spatial queries- Point-in-shape testing
- Bounding box calculations
- Shape picking/selection
-
Reactivity (
reactivity.ts) - Observable state management- RxJS-based reactive store
- State subscription and updates
- Computed values and derived state
-
Model (
model.ts) - Data structures and types- Shape definitions (rect, ellipse, line, arrow, text)
- Editor state
- Page management
-
Actions (
actions.ts) - User input event system- Input event normalization
- Pointer, keyboard, and wheel events
- Coordinate space conversions
packages/renderer
High-performance canvas renderer with:
- Reactive Rendering: Subscribes to state changes and efficiently redraws
- Optimized Drawing: Uses requestAnimationFrame with dirty flag pattern
- HiDPI Support: Automatic pixel ratio scaling for crisp rendering
- Camera Transforms: Applies world-to-screen transformations
- Shape Rendering: Draws all shape types (rect, ellipse, line, arrow, text)
- Selection Visualization: Highlights selected shapes with dashed outlines
- Text Wrapping: Automatic text layout within bounded areas
apps/web
SvelteKit-based web application providing the user interface.
Tech Stack#
- Testing: Vitest with Playwright (browser tests) and Node (unit tests)
- Persistence: IndexedDB (Dexie) for web, filesystem for desktop
Development#
pnpm dev # Start development server
pnpm build # Build for production
pnpm test # Run tests
apps/desktop
Tauri desktop wrapper that loads the web app with native file system access.
Features#
- Native file dialogs (Open/Save)
- File-based document persistence (
.inkfinite.json) - Recent files tracking
- Same UI as web app with platform-specific persistence
Tech Stack#
- Framework: Tauri v2
- Frontend: Shared with web app (SvelteKit)
- Backend: Rust with Tauri plugins (dialog, fs, store)
Development#
cd apps/desktop
# Development mode (with hot reload)
pnpm tauri dev
# Build production app
pnpm tauri build
Note: The web app automatically detects when running in Tauri and switches from IndexedDB to file-based persistence.
Development#
Prerequisites#
Standard Setup:
- Node.js 18+
- pnpm 8+
Nix/NixOS Setup:
- Nix with flakes enabled
- For desktop app: Rust via rustup (not Nix)
Setup#
Standard
# Install dependencies
pnpm install
# Run tests
pnpm test
# Build all packages
pnpm build
# Start web app in development
cd apps/web
pnpm dev
Nix Shell
# Enter Nix development shell (provides Node.js & pnpm)
nix-shell
# Install dependencies
pnpm install
# For desktop app development, ensure Rust is installed via rustup:
# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh --no-modify-path -y
# Run web app
cd apps/web
pnpm dev
# Run desktop app (Tauri)
cd apps/desktop
pnpm tauri dev
- Node.js and pnpm are provided by Nix for consistency
- Rust must be installed via rustup to avoid macOS framework linking issues
- The shell automatically configures paths and SDK for Tauri development
Project#
Structure
.
├── packages/
│ ├── core/
│ │ ├── src/
│ │ │ ├── math.ts # Vector and matrix math
│ │ │ ├── camera.ts # Camera transforms
│ │ │ ├── geom.ts # Geometry utilities
│ │ │ ├── model.ts # Data structures
│ │ │ ├── reactivity.ts # State management
│ │ │ └── actions.ts # Input system
│ │ └── package.json
│ └── renderer/
│ ├── src/
│ │ └── index.ts # Canvas renderer
│ └── package.json
└── apps/
└── web/
├── src/
│ ├── routes/ # SvelteKit routes
│ └── lib/ # Svelte components
└── package.json
Design Principles
Code Organization#
- Namespace pattern - Types and operations co-located (e.g.,
Vec2type +Vec2.add()function) - Pure functions - Immutable operations, no side effects
- Type safety - Full TypeScript coverage with strict mode
Coordinate Systems#
- World space - Infinite 2D plane for shape coordinates
- Screen space - Viewport pixels, origin at top-left
- Camera - Mediates between world and screen coordinates
Theme
- Light: Nord color palette
- Dark: Iceberg.vim color palette
- Font: Open Sans