# @blinksgg/canvas

> Multi-instance React canvas library for node-graph editors: infinite
> pan/zoom canvas, pluggable node types, views (grid/list/tile/map),
> gestures, command palette, event-action system. Current version:
> **7.0.5**.

This file orients LLM coding agents. Read it before generating code
that uses this library, then consult the linked docs for depth.

## Packages (all `@blinksgg` scope, Forgejo registry)

| Package | What it gives you |
|---|---|
| `@blinksgg/canvas` | The React component layer (`<Canvas />`, hooks, views). Most consumers need only this. |
| `@blinksgg/canvas-core` | Headless state: Jotai atoms, runtime factory, plugin/command/view/node-type registries |
| `@blinksgg/canvas-db` | Graphology graph store + Supabase adapter + React Query hooks |
| `@blinksgg/canvas-nodes` | Built-in node components (text/note/etc.) |
| `@blinksgg/canvas-views` | View implementations (grid/list/tile/map) |

Install: `pnpm add @blinksgg/canvas react react-dom jotai`
Peer deps: react >=18, jotai ^2.6.0. Node >=18.

## Critical rules for generated code

1. **Never import jotai subpaths** (`jotai/vanilla/store`). Import from
   the main `jotai` entry; for the `Store` type use
   `@blinksgg/canvas-core`'s re-export.
2. **One runtime per `<Canvas />` instance.** Stores, registries,
   commands, and event-actions are scoped per runtime since v6. Do NOT
   reach into module singletons from app code when hosting multiple
   canvases — use `createCanvasRuntime()` / scoped APIs.
3. **Strict nullish typing is enforced repo-wide**
   (`exactOptionalPropertyTypes`, `noUncheckedIndexedAccess`). Props
   typed `prop?: T` genuinely may be absent; pass `undefined`
   explicitly rather than omitting via spreads that write `undefined`.
4. **localStorage keys are public contract.** See the Persistence table
   in `docs/api-stability.md` before adding storage atoms; transient UI
   state must not persist.
5. **Module-singleton facades are permanent** default-runtime surface
   (`commandRegistry`, `registerView`, `registerNodeType`,
   `registerPlugin`, …) but are shared across all canvases on a page.

## Minimal usage

```tsx
import { Canvas } from '@blinksgg/canvas';

<Canvas
  renderNode={({ node }) => <div>{node.label}</div>}
  onGraphError={(e) => console.error(e)}
/>
```

Headless (no React): use `@blinksgg/canvas-core` runtime factory +
atoms; see docs/api-stability.md "Default-runtime facades".

## Documentation map

| Doc | Read when |
|---|---|
| `README.md` | Install, quick start, package split, architecture overview |
| `docs/api-stability.md` | What's Stable/Experimental/permanent facades, atom naming conventions, storage-key contract |
| `docs/migration-v6.md` | Upgrading 5.x → 6.x (multi-instance runtimes — BREAKING) |
| `docs/migration-v7.md` | Upgrading 6.x → 7.x (gestureContexts removal, exactOptionalPropertyTypes — BREAKING) |
| `CHANGELOG.md` | Version history, Keep-a-Changelog format |
| `docs/arch-gesture-system-v2.md` | Input classification → gesture resolution pipeline, palm rejection |
| `docs/consumers.md` | Known consumer apps and integration patterns |
| `TODO.md` | Roadmap status (post-7.0: soak, jotai v3 watch) |

Older migration guides (v1–v5) and plan documents describe historical
architecture; read only when archaeology is required.

## Versioning & release discipline

- Semver, Keep-a-Changelog. Every behavior change ships as its own
  versioned commit ("X.Y.Z: Title") with a CHANGELOG entry.
- Full gate before any publish: dual-level tsc, vitest suite (1580+
  tests incl. multi-canvas SSR smoke), build (14 targets), coverage
  floors, consumer-smoke script.
- Published to Forgejo npm: `registry.spaceoperator.org/api/packages/amir/npm/`.
