# @blinksgg/canvas — Core Principles

These principles guide every design decision in the canvas library.
When in doubt, refer here. When principles conflict, earlier ones win.

## 1. Touch-first, mouse-compatible

Design for fingers and stylus first, then ensure mouse works well.
Every interaction has device-aware thresholds — 44px hit targets for
fingers, 3px drag thresholds for pencil, palm rejection when stylus
is active. Mouse is not the default; it is one of three equal input
sources.

> "Pencil draws, fingers navigate, mouse does both."
> — input-classifier.ts

## 2. Headless core, optional UI

All state lives in Jotai atoms with zero React dependency. The `core/`
layer is a pure state machine: atoms in, atoms out. Components in
`components/` are one possible UI — consumers can build entirely
custom UIs by importing only `@blinksgg/canvas/core` and
`@blinksgg/canvas/hooks`.

## 3. Local-first, sync-optional

Every operation (drag, resize, copy, paste, undo, redo) works without
a network connection. The clipboard is in-memory. Undo/redo uses
delta-based snapshots in local state. The database layer (`db/`) is
an optional add-on with an adapter interface — not a requirement.

## 4. Events are data, actions are configurable

Canvas interactions produce typed events (NodeDoubleClick,
BackgroundLongPress, etc.). What *happens* in response is a mapping
in a settings store, not hardcoded logic. Users remap actions via
presets or the SettingsPanel. This separates "what happened" from
"what to do about it."

## 5. Atoms over context

Prefer Jotai atoms over React context for shared state. Atoms are
composable, testable without React, and don't cause provider
waterfall re-renders. Use React context only for non-reactive
configuration (style themes, callback refs).

## 6. Fully controllable headless API

Every canvas operation must be executable from the `core/` layer
without React. If a hook can do it, an atom or pure function in
`core/` can do it too. The React hooks are convenience wrappers,
not the only path. External tools, tests, and non-React integrations
should have full control via `store.set(atom, value)`.

## 7. Performance by default

Virtualization is on by default (only render visible nodes).
The React Compiler handles memoization automatically. Edge paths
only recompute when their connected nodes move. Delta-based history
is O(1) for moves instead of O(N) full-graph snapshots.

## 8. Composition over configuration

Provide small, focused hooks (`useNodeDrag`, `useNodeResize`,
`useTapGesture`) that compose into complex behavior. The `Canvas`
component is a convenient composition — not the only way to use the
library. Advanced users compose hooks directly.

## 9. Backend-agnostic persistence

The `CanvasStorageAdapter` interface defines CRUD + subscriptions.
Implement it for any backend. The simplest path is callback props
(`onNodePersist`) with no adapter at all.
