diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f12f5d..d69dd9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,13 +17,24 @@ paint, retained source assets, and opaque fallback content for unsupported visuals. - Native path geometry, rendering, hit testing, compound fills, and shared Rust/TypeScript fixtures. - Hierarchical vector editing with nested selection, world-space transforms, reparenting, direct - anchor and handle editing, and path topology operations. + anchor and handle editing, path topology operations, selection cycling, duplicate-and-connect, + shape conversion, and a searchable command palette. - Selection refinement with object, equal-gap, handle, and grid snapping guides, modifier-aware movement and drawing constraints, Alt-drag duplication, hover feedback, transformed handles, edge scrolling, zoom-to-selection, and persisted grid preferences. +- Deterministic align, distribute, stack, grid, tidy, tree, flow, and radial layout operations, + with locked anchors and preserved connector and relationship references. +- Editable cards, ordered presentation frames, reusable image assets with captions, masks, color + sampling, and native URL, file, and page references. +- Semantic names, roles, tags, descriptions, sources, structured metadata, and typed relationships + across the model, editor, CLI, conversion, layout, inspection, merge, and export paths. - Titled frames with child containment, move-with-contents behavior, nested selection, frame export, - binding-aware arrows, curved and elbow routing, bend controls, labels, automatic endpoint updates, - and binding-preserving copy and persistence. + binding-aware arrows, curved, elbow, and obstacle-aware routing, bend controls, labels, automatic + endpoint updates, and binding-preserving copy and persistence. +- Visual agent proposal review with object and relationship previews, partial acceptance, rejection, + stale-head handling, and distinct added, changed, moved, and removed states. +- A responsive, keyboard-accessible board browser with sorting, storage and save details, workspace + switching, duplication, guarded board changes, actionable errors, and user-focused inspection. - Excalidraw and Obsidian Canvas import/export, offline peer sync, and a bundled agent skill with file, proposal, and stale-head examples. diff --git a/README.md b/README.md index d0bb4b8..7ceccda 100644 --- a/README.md +++ b/README.md @@ -57,18 +57,19 @@ cargo build -p inkfinite-cli --bin inkfinite cargo xtask dist ``` -See the [CLI documentation](apps/web/src/content/docs/reference/cli.md) for +See the [CLI documentation](apps/web/src/content/docs/automation/cli.md) for installation paths and shell completion setup. ## Documentation -- [Getting started](apps/web/src/content/docs/getting-started.md) -- [Web editor](apps/web/src/content/docs/applications/web.md) -- [Desktop editor](apps/web/src/content/docs/applications/desktop.md) -- [Command-line interface](apps/web/src/content/docs/reference/cli.md) -- [Agent workflows](apps/web/src/content/docs/reference/agents.md) -- [File format](apps/web/src/content/docs/reference/file-format.md) -- [Internals and repository map](apps/web/src/content/docs/internals.md) +- [Quickstart](apps/web/src/content/docs/quickstart.md) +- [Editor guide](apps/web/src/content/docs/guide/editor.md) +- [Import and export](apps/web/src/content/docs/guide/import-and-export.md) +- [Web platform](apps/web/src/content/docs/platforms/web.md) +- [Desktop platform](apps/web/src/content/docs/platforms/desktop.md) +- [CLI](apps/web/src/content/docs/automation/cli.md) +- [Agent workflows](apps/web/src/content/docs/automation/agents.md) +- [Architecture](apps/web/src/content/docs/development/architecture.md) ## Credits diff --git a/ROADMAP.md b/ROADMAP.md index b5bfba8..1a1625c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -33,129 +33,6 @@ content and stable visual fallback where it does not. See [SVG import](apps/web/src/content/docs/internals/svg-import.md) and [native path geometry](apps/web/src/content/docs/internals/native-path-geometry.md). -### Canvas interaction quality - -Inkfinite supports duplicate-and-drag and duplicate-and-connect, selection -cycling for overlapping and nested objects, snapping and guides, keyboard nudging, -fit-to-drawing and fit-to-selection, grouping, nested selection, connector -labels and endpoint reassignment, and text and Markdown editing. A searchable -command palette exposes the selection and viewport actions. Connector routing -now uses deterministic obstacle-aware orthogonal paths in Rust and in TypeScript -previews. Rectangle and ellipse conversion is a native transaction exposed -through selection commands, preserving shared style, metadata, hierarchy, -transform, and identity. - -### Stronger content primitives - -Inkfinite has native containers and frames, Markdown blocks, image records backed -by separate assets, image paste and drop, non-destructive crop, reusable built-in -card stencils, image captions, and display masks. Image assets are content -addressed and can be reused from the TypeScript selection controls. Captions and -masks survive the native validation and SVG export paths. The editor can sample -an image palette, copy sampled colors, and arrange selections in a deterministic -grid. - -URL, file, and page references are native reference shapes with typed targets, -validation, SVG/canvas rendering, reference stencils, and selection controls. -Cards, frames, images, assets, and references use the same document projection, -transaction reconciliation, undo history, merge handling, inspection, and export -workflows. - -### Semantic objects and relationships - -The native model, CLI, and editor projection carry object names, roles, tags, -descriptions, provenance, user-defined sources, and structured metadata. The -selection controls expose those fields for ordinary objects, show provenance -for a single selection, and keep metadata through conversion, grouping, -duplication, and SVG export where the format has a representation. - -Bindings carry an optional relation type for semantic connections. Rust, the -CLI, and the editor projection preserve the type and shape references. Queries -can select typed bindings and filter their incoming or outgoing shape, while -visual routing validation remains separate from relationship-reference -validation. - -### Layout operations - -Align, distribute, stack, grid, and tidy use the shared transaction engine -across the editor and CLI. Selection layout orders shapes by world-space bounds, -works across layers and nested parents, translates nested shapes in their local -coordinate systems, and treats locked objects as fixed anchors. Grid and tidy -use deterministic row-major placement with spacing derived from the selection. - -Layout changes move ordinary shape records only. Connector endpoints and -semantic relationship bindings retain their shape references and attachment -metadata, and all layout operations use the normal transaction, undo, merge, -inspection, and stale-head workflows. - -#### Graph layout - -Use an Inkfinite-owned deterministic adapter rather than adding a Graphviz -runtime to native and browser builds. This keeps the layout behavior in the -shared document model and avoids separate native and WebAssembly engine -integrations. The document model, transaction engine, CLI, MCP, and editor -must depend only on the Inkfinite graph layout contract. - -Build a small internal layout graph from selected shapes, their measured -world-space bounds, and explicit structured connections. Nodes and edges must be -ordered deterministically before layout. Graph layout must not infer semantic -relationships from visual proximity or connector geometry. - -Support these layouts initially: - -- `flow`: layered placement with top-to-bottom and left-to-right directions. -- `tree`: layered placement with stable relationship ordering and tree-oriented - rank handling. -- `radial`: concentric placement after flow and tree behavior is stable. - -Use the layout adapter only to determine node placement. Connector routing, -rendering, graph storage, and SVG output remain Inkfinite concerns. After node -positions change, Inkfinite's obstacle-aware connector router continues to -produce native editable connector paths. - -The Inkfinite graph layout contract contains stable shape IDs, node dimensions, -structured edges, layout options, and returned positions. Normalize returned -coordinates into Inkfinite world coordinates and preserve a predictable -selection origin so applying layout does not unnecessarily move the selection -across the canvas. - -Native and browser adapters must use the same graph contract and produce -equivalent normalized layouts for the same fixtures. Do not add unsafe FFI or a -separate browser engine for the initial implementation. - -Graph layout results must become ordinary Inkfinite transactions. Applying a -layout must preserve object identity, hierarchy, semantic metadata, bindings, -connector attachment, undo/redo behavior, CRDT merge behavior, and stale-head -validation. - -Add deterministic fixtures covering chains, branching trees, multiple roots, -diamonds, cycles, disconnected components, different node dimensions, nested -shapes, and connection-heavy selections. Define behavior for locked shapes, -cycles in tree mode, relationships crossing the selected subgraph, and -unsupported graph structures. - -Treat force-directed, stress, circular, packing, and constraint-based layouts -as later extensions. They should reuse the Inkfinite graph layout contract and -transaction boundary rather than introducing engine-specific document concepts. - -### Agent proposal review - -Inkfinite stores proposals against known heads, summarizes operations, and -supports partial acceptance or rejection while clearing stale proposals. The -review surface now receives Rust-owned before/after records for every affected -object, including shapes, bindings, layers, pages, and assets. The canvas uses -those records and world bounds to preview additions, modifications, moves, and -removals; relationships are shown as labeled proposal connectors. - -The review panel lists object-level changes and changed metadata or relationship -fields alongside the operation summary. Additions, modifications, moves, and -removals use separate visual tokens and remain separate from ordinary -selection. Desktop session coverage now exercises partial acceptance, rejection, -and stale-head refresh, while browser review coverage checks the summary and -canvas ghost states. Accepted and rejected reviews clear the proposal and its -canvas preview. MCP may create proposals when local policy allows it, while the -desktop app remains the place for visual review. - ### Richer interoperability and embeds Inkfinite already imports and exports JSON Canvas nodes, groups, labeled edges, @@ -183,22 +60,6 @@ design, brainstorming, project planning, moodboards, research maps, and wireframes. They should be standard documents that users can inspect, edit, export, and repurpose, not substitutes for missing editor behavior. -### Board management - -The board browser creates, searches, opens, renames, inspects, and deletes -boards. It now identifies the active board, storage location, save state, and -last update, offers name/date sorting, and supports keyboard movement through -large lists. Browser storage, desktop workspaces, and recent files use the same -board-management interaction, with file timestamps supplied by desktop storage -when available. - -The browser is responsive and accessible on narrow viewports and coarse -pointers. Board actions duplicate boards through each platform's repository, -show busy and failure states in the browser, flush pending edits before a -switch, and recover the active canvas when its board is deleted. The inspector -leads with board name, dates, and location, then shows storage, schema, -document, and record diagnostics. - ### Editor polish The editor already separates drawing tools, application actions, contextual diff --git a/TODO.md b/TODO.md index dd7437b..1106f57 100644 --- a/TODO.md +++ b/TODO.md @@ -21,118 +21,6 @@ and rendered output where visual fidelity matters. - [ ] Verify opaque fallback content remains visually stable - [ ] Add deterministic round-trip fixtures for these workflows -## Canvas interaction quality - -Make common drawing and editing operations fast, predictable, and consistent -across mouse, touch, and keyboard input. - -### Selection and direct manipulation - -- [x] Add duplicate-and-connect alongside the existing duplicate-and-drag flow -- [x] Add selection cycling for overlapping and nested shapes -- [x] Add a searchable command palette for existing selection and viewport - commands - -### Connectors and conversion - -- [x] Implement deterministic obstacle-aware connector routing in Rust and use - it for TypeScript interaction previews -- [x] Implement shape conversion as a Rust transaction and expose it through - TypeScript selection commands without losing shared style or metadata -- [x] Cover duplicate-and-connect, selection cycling, command execution, and - automatic routing with Playwright integration tests - -## Stronger content primitives - -### Cards and frames - -- [x] Turn the existing TypeScript card stencil into editable card behavior - built from ordinary Rust container, content, and semantic records -- [x] Add card title, body, role, tags, source, link, and custom metadata to the - native model and generated bindings, then expose TypeScript controls -- [x] Convert cards to and from simpler content objects without losing content -- [x] Add persisted frame ordering and export behavior in Rust, with - presentation and navigation controls in TypeScript - -### Images, assets, and rich content - -- [x] Add image caption and mask properties, validation, and export in Rust, - with reusable-asset and editing controls in TypeScript -- [x] Add TypeScript color sampling controls for image selections; use the - shared grid layout operation for arrangement -- [x] Add native URL, file, and page-reference content with TypeScript editor - rendering and controls where practical -- [x] Verify new card, frame, and asset behavior through save/reopen, undo/redo, - merge, inspection, and export -- [x] Add end-to-end coverage for the new card, frame, and asset workflows - -## Semantic objects and relationships - -Keep semantics optional while making mature documents queryable by people, -the CLI, and agents. - -### Object metadata - -- [x] Project existing Rust names, roles, tags, descriptions, and provenance - into TypeScript editor selection controls -- [x] Add optional user-defined source and structured metadata to the Rust model - and generated bindings -- [x] Preserve semantic fields in the TypeScript editor projection and through - conversion, grouping, duplication, import, and export where supported - -### Semantic connections - -- [x] Add an optional relation type to Rust binding records and generated - bindings -- [x] Query incoming, outgoing, and typed relationships in Rust without - inferring them from coordinates -- [x] Validate dangling or invalid relationship references separately from - visual routing -- [x] Add model, CLI, and editor integration tests for typed relationships - -## Layout operations - -Treat layout as an operation that updates ordinary editable objects rather than -as a permanent graph constraint. - -### Selection layout - -- [x] Add deterministic Rust stack operations beside the existing shared align - and distribute commands, then expose them in TypeScript -- [x] Add Rust grid and tidy operations for mixed selections and TypeScript - controls and previews -- [x] Define deterministic spacing, ordering, nesting, and locked-object rules -- [x] Preserve connector attachment and semantic relationships after layout - -### Graph layout - -- [x] Add deterministic Rust tree and flow layouts using structured connections -- [x] Add Rust radial layout after tree and flow behavior is stable -- [x] Verify layout through undo/redo, save/reopen, merge, and stale-head - handling -- [x] Add integration tests for representative before/after layout operations - -## Agent proposal review - -Turn structured agent mutations into visual proposals that people can inspect -before committing them. - -### Richer canvas preview - -- [x] Derive object-specific modification, removal, and move previews in Rust - and render them in the TypeScript canvas -- [x] Include relationship and metadata changes in Rust preview data and the - TypeScript review UI -- [x] Define distinct visual tokens for proposed additions, modifications, and - removals - -### End-to-end review - -- [x] Add end-to-end tests for the existing proposal summary, partial accept, - reject, ghost preview, and stale-head flows -- [x] Verify accepted and rejected proposals leave no stale canvas or review - state - ## Richer interoperability and embeds - [ ] Extend the existing TypeScript JSON Canvas round-trip for new card, @@ -165,34 +53,6 @@ before committing them. - [ ] Verify every starter through open, edit, save, reopen, inspect, and export - [ ] Add end-to-end tests for opening and editing each starter -## Board management - -Bring board creation, discovery, switching, and maintenance up to the quality of -the canvas editor. - -### Browser and workspace - -- [x] Clarify the active board, storage location, save state, and last-updated - information in the TypeScript board-management UI -- [x] Add explicit sort controls and complete keyboard navigation for large - board lists -- [x] Unify browser storage, desktop workspaces, and recent files behind the - same board-management interaction where their capabilities overlap -- [x] Make the board browser responsive and accessible on narrow viewports and - coarse pointers - -### Board actions - -- [x] Add board duplication through the shared TypeScript repository interface - and the existing Rust desktop file/session services -- [x] Surface TypeScript UI busy and failure states instead of logging - board-action errors to the console -- [x] Protect board switches when pending editor changes cannot be flushed -- [x] Make the board inspector useful to users while retaining file, schema, and - document diagnostics for maintainers -- [x] Add end-to-end tests for the existing board actions plus duplication, - switching, workspace selection, and persistence across reloads - ## Editor polish - [ ] Standardize hover, pressed, selected, disabled, busy, and focus-visible @@ -287,4 +147,3 @@ the canvas editor. - [ ] Revisit skill organization after SVG and MCP workflows stabilize - [ ] Export SVG as copyable code - [ ] Export PNG to clipboard -- [x] Add a move handle to the layer pane diff --git a/apps/web/src/content/docs/applications/editor.md b/apps/web/src/content/docs/applications/editor.md deleted file mode 100644 index bf6e576..0000000 --- a/apps/web/src/content/docs/applications/editor.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: Canvas editor -description: Draw, arrange, navigate, and move content through Inkfinite's shared editor. -section: Applications -group: Applications -order: 4 ---- - -The web and desktop apps share the same canvas, tools, shortcuts, and document operations. The -desktop app adds native file handling and local CLI access; the web app stores boards in the -browser. - -## Navigating the canvas - -Pan with a trackpad, middle-button drag, or Space-drag. Pinch or hold Ctrl/Cmd while scrolling to -zoom. The controls in the lower-left corner set an exact zoom level, fit the drawing, or fit the -current selection. **Shift+1** fits the drawing and **Shift+2** fits the selection. - -The status bar reports the active tool, cursor and viewport coordinates, selection, save state, -and grid settings. Grid visibility, grid size, and snapping preferences persist between sessions. - -## Selecting and moving shapes - -Use **Select** for whole shapes and **Direct Select** for a path's anchors and handles. Double-click -a nested shape to move into its group or frame; use Escape to move back out. - -Dragging a selection can snap its edges, centers, corners, handles, and equal gaps to nearby -content. The canvas draws guides for each active snap. Hold Shift to constrain movement or drawing -to 15-degree angles. Hold Alt/Option while dragging to duplicate a selection. During resize, Shift -preserves the aspect ratio and Alt/Option resizes around the center. - -The **Layout** menu aligns and distributes selected shapes, stacks and grids them, lays out -connected graphs, changes their stacking order, groups or ungroups them, and controls locks. -Graph layouts use relation bindings and both endpoints of bound arrows; they do not infer edges -from nearby objects. The **Object metadata** section edits names, roles, tags, -descriptions, sources, links, and structured metadata for any selection. A single selected object -also shows its provenance. Right-click the canvas or a selection for commands relevant to that -location. - -## Draw and Connect - -The toolbar includes rectangles, ellipses, frames, lines, arrows, text, Markdown, and freehand -pen strokes. A frame contains ordered child shapes and carries them when it moves. Select a frame -to enter it or fit it to the viewport. The Card stencil creates a frame from ordinary text and -Markdown objects; its selection controls edit the title and body alongside the shared object -metadata fields. - -Arrows may be straight, curved, or elbow-routed. Drag an endpoint onto a shape to bind it; the -endpoint follows that shape when it moves. Arrow controls edit bends, endpoint heads, routing, and -labels. - -Select a shape to edit its fill, stroke, and opacity. Text, Markdown, and Card selections also -show font and size controls. New canvas text uses Instrument Sans. - -| Category | Bundled fonts | -| -------- | ------------------------------------------------------------------------------------- | -| Sans | Instrument Sans, Atkinson Hyperlegible Next, IBM Plex Sans, Google Sans, Playpen Sans | -| Serif | Source Serif 4, Newsreader, Fraunces | -| Mono | JetBrains Mono, Geist Mono, Azeret Mono | - -**Direct Select** exposes anchors and Bézier handles for native paths. Path commands can open or -close a path, split or join segments, and change segment geometry. - -## Clipboard and Import - -The editor preserves hierarchy, assets, and connections when copying and pasting native shapes. -It also accepts plain text, Markdown, SVG markup, SVG files, and images. Use paste in place when -you need the copied coordinates, or paste at the pointer to choose the destination. - -Drop an `.inkfinite`, SVG, Excalidraw, or image file onto the canvas to import it. Imported SVG -geometry remains editable when Inkfinite supports the element. Unsupported visual content may be -kept as opaque fallback content; review the import report before discarding the source file. - -Images support aspect-ratio resize, crop, opacity, and replacement. Copy a selection as SVG or PNG -when another application needs a presentation copy rather than editable Inkfinite records. - -## Layers and Shortcuts - -The Layers panel creates, activates, renames, reorders, hides, locks, and changes the opacity of -layers. Its arrow button collapses the panel when the canvas needs more room. - -Press **?** for the searchable shortcut list. Common commands include: - -- Cmd/Ctrl+C, X, and V for copy, cut, and paste -- Cmd/Ctrl+D to duplicate -- Cmd/Ctrl+G to group and Shift+Cmd/Ctrl+G to ungroup -- arrow keys to nudge, with Shift for 10-pixel steps -- Cmd/Ctrl+B to open the board browser -- Escape to clear a selection or close the current menu or dialog - -The editor reports failed saves, imports, exports, and clipboard operations in the interface. -In the desktop app, a draft remains separate from a named `.inkfinite` file until you choose -**Save As**. diff --git a/apps/web/src/content/docs/reference/agents.md b/apps/web/src/content/docs/automation/agents.md similarity index 94% rename from apps/web/src/content/docs/reference/agents.md rename to apps/web/src/content/docs/automation/agents.md index fca2bc6..6884ec8 100644 --- a/apps/web/src/content/docs/reference/agents.md +++ b/apps/web/src/content/docs/automation/agents.md @@ -1,9 +1,9 @@ --- title: Agent workflows description: 'Safe, reviewable Inkfinite document changes for coding agents.' -section: Reference -group: Reference -order: 9 +section: Automation +group: Automation +order: 12 --- Use Inkfinite's command-line tools to inspect, validate, and change documents. @@ -32,7 +32,7 @@ MCP interface when model-controlled changes require authorization or review. Shape and layer locks apply to every CLI transaction. Do not work around a lock by editing a child or bypassing the CLI. The direct CLI does not enforce `agent_editable` or hide records in invisible -layers; permissioned integrations can use that metadata as part of their own policy. +layers. Permissioned integrations can use that metadata as part of their own policy. Raw `app apply` validates and commits a prepared transaction. diff --git a/apps/web/src/content/docs/reference/cli.md b/apps/web/src/content/docs/automation/cli.md similarity index 95% rename from apps/web/src/content/docs/reference/cli.md rename to apps/web/src/content/docs/automation/cli.md index 4b15f35..c731512 100644 --- a/apps/web/src/content/docs/reference/cli.md +++ b/apps/web/src/content/docs/automation/cli.md @@ -1,9 +1,9 @@ --- -title: Command-line interface -description: Use the Inkfinite CLI with saved files and live desktop sessions. -section: Reference -group: Reference -order: 7 +title: CLI +description: Inspect, query, change, validate, and render files and live desktop sessions. +section: Automation +group: Automation +order: 11 --- Inspect, change, validate, and render Inkfinite documents from a terminal. @@ -113,18 +113,18 @@ inkfinite import svg architecture.inkfinite \ ``` `layout` supports `align`, `distribute`, `stack`, `grid`, `tidy`, and `graph`. Select -shapes with repeated `--shape` flags or one `--role` selector; stack accepts +shapes with repeated `--shape` flags or one `--role` selector. Stack accepts `--axis` and `--gap`, grid accepts `--columns`, `--column-gap`, and `--row-gap`, tidy accepts `--gap`, and graph accepts `--algorithm flow|tree|radial`, `--direction top-to-bottom|left-to-right`, `--node-gap`, and `--rank-gap`. Graph edges come from selected-to-selected relation bindings or the two endpoints -of a selected connector; proximity and unselected endpoints are ignored. +of a selected connector. Proximity and unselected endpoints are ignored. `import svg` creates the retained source asset, native group containers, and supported shapes in one validated transaction. Use `--page` or `--layer` to -choose a target; otherwise the first page and layer receive the import. +choose a target. Otherwise the first page and layer receive the import. -File commands never prompt. Close the desktop editor before changing its file; a lock or stale-head +File commands never prompt. Close the desktop editor before changing its file. A lock or stale-head error is a signal to inspect current state, not a reason to overwrite the file. To hand the edit to another process without changing the document, add diff --git a/apps/web/src/content/docs/concepts/documents.md b/apps/web/src/content/docs/concepts/document-model.md similarity index 98% rename from apps/web/src/content/docs/concepts/documents.md rename to apps/web/src/content/docs/concepts/document-model.md index 0c30e08..a474d12 100644 --- a/apps/web/src/content/docs/concepts/documents.md +++ b/apps/web/src/content/docs/concepts/document-model.md @@ -1,9 +1,9 @@ --- -title: Documents +title: Document model description: 'Pages, layers, shapes, bindings, and persistence in Inkfinite documents.' section: Concepts group: Concepts -order: 3 +order: 13 --- An Inkfinite document stores canvas content and the history needed to merge edits from different diff --git a/apps/web/src/content/docs/concepts/transactions-and-sync.md b/apps/web/src/content/docs/concepts/transactions-and-sync.md index a275fad..4266111 100644 --- a/apps/web/src/content/docs/concepts/transactions-and-sync.md +++ b/apps/web/src/content/docs/concepts/transactions-and-sync.md @@ -3,7 +3,7 @@ title: Transactions and sync description: 'How Inkfinite validates edits, records history, and merges peer changes.' section: Concepts group: Concepts -order: 4 +order: 14 --- Inkfinite groups related operations into transactions, validates them against the current document, @@ -23,13 +23,21 @@ file. Permissioned integrations can apply caller policy before submitting a vali ## Undo and redo -The editor records transactions in its history. Undo applies the inverse of an accepted local edit; -redo reapplies an edit that was undone. Because history belongs to the document model, both the web +The editor records transactions in its history. Undo applies the inverse of an accepted local edit. +Redo reapplies an edit that was undone. Because history belongs to the document model, both the web and desktop editors use the same behavior. An edit may become impossible to undo after later changes remove or replace the records it depended on. Inkfinite reports the conflict instead of reconstructing an uncertain result. +## Proposal review + +A desktop session can hold an agent transaction as a proposal against known document heads. The +review panel lists affected objects, metadata, and relationships, while the canvas previews added, +changed, moved, and removed content. Reviewers can accept all or part of a proposal or reject it. +Accepting and rejecting both clear the preview. Stale proposals must be refreshed against the +current document before acceptance. + ## Synchronization Automerge assigns document heads to the current causal state. Two peers can make changes from a @@ -41,4 +49,4 @@ heads, query the affected records again, and rebuild the intended change from cu The current local file and desktop proposal workflows provide this concurrency model without claiming a hosted synchronization service. A live desktop proposal can also become stale while it -waits for review; review the refreshed preview before accepting it. +waits for review. Review the refreshed preview before accepting it. diff --git a/apps/web/src/content/docs/internals.md b/apps/web/src/content/docs/development/architecture.md similarity index 87% rename from apps/web/src/content/docs/internals.md rename to apps/web/src/content/docs/development/architecture.md index 029af10..3730bf2 100644 --- a/apps/web/src/content/docs/internals.md +++ b/apps/web/src/content/docs/development/architecture.md @@ -1,12 +1,12 @@ --- -title: Internals +title: Architecture description: "How Inkfinite's Rust document engine, TypeScript editor, desktop bridge, renderer, and CLI fit together." -section: Internals -group: Internals -order: 10 +section: Development +group: Development +order: 18 --- -Inkfinite has one durable document model and a separate editor-facing projection. Rust owns the +Inkfinite has one canonical document model and a separate editor-facing projection. Rust owns the canonical document, transactions, Automerge state, native files, headless rendering, and desktop sessions. TypeScript owns interactive editor state, tools, browser input, and Canvas rendering. @@ -29,9 +29,9 @@ The current system includes: - CLI workflows for file and live-session inspection, queries, validation, structured mutations, dry runs, rendering, schemas, and machine-readable output -The linked pages in this section describe these components in detail. Start with [Documents](/docs/concepts/documents/) +The linked pages in this section describe these components in detail. Start with [Documents](/docs/concepts/document-model/) for the record model, [Transactions and sync](/docs/concepts/transactions-and-sync/) for commits and -merges, [SVG import](/docs/internals/svg-import/) for interchange, and [Native path geometry](/docs/internals/native-path-geometry/) +merges, [SVG import](/docs/development/svg-import/) for interchange, and [Native path geometry](/docs/development/native-path-geometry/) for vector editing. ## Architecture @@ -65,10 +65,10 @@ the same persistence adapter. The web editor persists its editor document in Ind editor projects the Rust-owned native document into editor state and sends completed document edits back through Tauri. -See [Web editor](/docs/applications/web/) and [Desktop editor](/docs/applications/desktop/) for the +See [Web editor](/docs/platforms/web/) and [Desktop editor](/docs/platforms/desktop/) for the application-specific behavior. -## Durable model and editor projection +## Document model and editor projection The most important internal distinction is between the Rust document contract and the TypeScript editor model. @@ -77,9 +77,9 @@ editor model. relation, a parent-relative transform, ordered container children, kind-specific properties, semantic metadata, common style, and a record version. Semantic metadata includes optional names, roles, descriptions, sources, links, tags, custom JSON fields, and provenance. Binding records can -also carry an optional relation type with source and target shape IDs; the query API filters those +also carry an optional relation type with source and target shape IDs. The query API filters those records by type and direction. -Pages own ordered layers; layers own ordered root shapes. +Pages own ordered layers. Layers own ordered root shapes. Containers can own nested shapes and optionally apply free, stack, or grid layout. `@inkfinite/core` is the interactive projection used by tools and Canvas rendering. It keeps the @@ -90,14 +90,14 @@ utilities. These are not two canonical file formats. The desktop and browser persistence adapters translate between the generated Rust contracts in `@inkfinite/bindings` and the editor projection returned by -Rust sessions. The frontend keeps the projected state for low-latency interaction; Rust remains +Rust sessions. The frontend keeps the projected state for low-latency interaction. Rust remains authoritative for the native session and `.inkfinite` file. -For the durable record structure, see [Documents](/docs/concepts/documents/). The [native path -geometry guide](/docs/internals/native-path-geometry/) documents the path representation used by -SVG interoperability and future vector editing. The [SVG import guide](/docs/internals/svg-import/) +For the record structure, see [Document model](/docs/concepts/document-model/). The [native path +geometry guide](/docs/development/native-path-geometry/) documents the path representation used by +SVG interoperability and vector editing. The [SVG import guide](/docs/development/svg-import/) documents the parser's native mappings, transform rules, styles, text behavior, and asset handling. -The [testing guide](/docs/internals/testing/) documents shared fixtures and focused verification. +The [testing guide](/docs/development/testing/) documents shared fixtures and focused verification. ## Edit flow @@ -146,7 +146,7 @@ Causal heads and record versions are used for optimistic concurrency. See | `crates/inkfinite-core` | Data model, transaction engine, Automerge integration, files, queries, sessions, sync, IPC, and headless rendering | | `crates/inkfinite-cli` | `inkfinite` command parsing, human/JSON output, file-mode operations, live desktop control, and binding/schema generation | | `apps/desktop/src-tauri` | Tauri command surface and native application integration around `inkfinite-core` | -| `packages/bindings` | Generated TypeScript contracts derived from Rust; do not edit these by hand | +| `packages/bindings` | Generated TypeScript contracts derived from Rust. Do not edit these by hand | | `packages/core` | Editor-facing model, geometry, actions, tools, stencils, interchange, and browser-side utilities | | `packages/editor` | DOM input normalization, interaction state, transaction drafts, and Canvas 2D rendering | | `packages/ui` | Shared Svelte editor, panels, controls, themes, and UI components | @@ -164,7 +164,7 @@ into world coordinates, culls shapes outside an expanded viewport, and keeps fix text and Markdown layout. Selection handles, binding previews, and snapping guides are rendered from editor-only state and are not native document records. -Headless rendering is separate. `inkfinite-core` renders the durable document directly to +Headless rendering is separate. `inkfinite-core` renders the canonical document directly to deterministic SVG for CLI output, fixtures, and inspection. This keeps headless output independent of the browser renderer. @@ -180,13 +180,13 @@ authenticated local IPC protocol exposed by the Tauri process rather than racing writer. The Rust protocol supports direct live commits and optional proposals. See -[Command-line interface](/docs/reference/cli/) and [Agent workflows](/docs/reference/agents/) for +[Command-line interface](/docs/automation/cli/) and [Agent workflows](/docs/automation/agents/) for the supported commands and review flow. ## Files and generated contracts Canonical desktop files are Automerge-backed `.inkfinite` documents. Rust owns native reads, -validation, file locking, recovery state, and atomic replacement. JSON is an inspection projection; +validation, file locking, recovery state, and atomic replacement. JSON is an inspection projection. SVG, PNG, Excalidraw, and Obsidian Canvas are interchange or presentation formats rather than alternate native documents. See [File format](/docs/reference/file-format/) for the user-facing format contract. diff --git a/apps/web/src/content/docs/development/building-from-source.md b/apps/web/src/content/docs/development/building-from-source.md new file mode 100644 index 0000000..964eee2 --- /dev/null +++ b/apps/web/src/content/docs/development/building-from-source.md @@ -0,0 +1,73 @@ +--- +title: Building from source +description: Set up Rust, WebAssembly, Svelte, and Tauri development for Inkfinite. +section: Development +group: Development +order: 19 +--- + +Inkfinite is a pnpm workspace with Rust crates, a WebAssembly document engine, a Svelte web app, +and a Tauri desktop shell. + +## Requirements + +Install Node.js 18 or newer, pnpm, and Rust 1.89. Desktop development also requires the +[Tauri 2 prerequisites](https://v2.tauri.app/start/prerequisites/) for your operating system. + +From the repository root, install JavaScript packages: + +```sh +pnpm install +``` + +Add the WebAssembly target and install the `wasm-bindgen` CLI version used by `Cargo.lock`: + +```sh +rustup target add wasm32-unknown-unknown +cargo install wasm-bindgen-cli --version 0.2.126 --locked +pnpm wasm:build +``` + +## Run the applications + +Start the documentation site and web editor: + +```sh +pnpm dev:web +``` + +Open the printed local URL for the site or its `/app` route for the editor. Start the desktop app +with: + +```sh +pnpm tauri dev +``` + +## Workspace commands + +Build the CLI with Cargo or create its installable release tree: + +```sh +cargo build -p inkfinite-cli +cargo xtask dist +``` + +Generate TypeScript bindings after changing shared Rust types: + +```sh +pnpm bindings:generate +``` + +Run the repository checks from the root: + +```sh +cargo fmt --all -- --check +cargo test --workspace --all-features +cargo clippy --workspace --all-targets --all-features -- -D warnings +pnpm format:check +pnpm test +pnpm check +pnpm lint +``` + +See [Testing](/docs/development/testing/) for focused package and Playwright commands. diff --git a/apps/web/src/content/docs/internals/native-path-geometry.md b/apps/web/src/content/docs/development/native-path-geometry.md similarity index 96% rename from apps/web/src/content/docs/internals/native-path-geometry.md rename to apps/web/src/content/docs/development/native-path-geometry.md index e5af296..dd3fbfb 100644 --- a/apps/web/src/content/docs/internals/native-path-geometry.md +++ b/apps/web/src/content/docs/development/native-path-geometry.md @@ -1,9 +1,9 @@ --- title: Native path geometry description: 'The path representation used by SVG interoperability and vector editing.' -section: Internals -group: Internals -order: 11 +section: Development +group: Development +order: 21 --- Inkfinite stores arbitrary vector geometry as native `path` shapes. SVG import and vector @@ -95,10 +95,10 @@ compare preview results with the canonical Rust operation for curve splitting, t and nested transforms. Direct selection uses Alt-click on a rendered segment to add an anchor. Delete removes selected -anchors; Q and C convert their incoming segments to quadratic and cubic curves, L converts them +anchors. Q and C convert their incoming segments to quadratic and cubic curves, L converts them to lines, O opens selected subpaths, Z closes them, and B breaks selected cubic handles. J joins two selected endpoints from separate open subpaths, or joins cubic handles for another selection. -These commands remain editor interactions; the resulting topology operations are committed through +These commands remain editor interactions. The resulting topology operations are committed through the Rust reconciliation API. A completed gesture submits one operation in one transaction through the Rust document session. Rust diff --git a/apps/web/src/content/docs/internals/origin-and-authorization.md b/apps/web/src/content/docs/development/origin-and-authorization.md similarity index 98% rename from apps/web/src/content/docs/internals/origin-and-authorization.md rename to apps/web/src/content/docs/development/origin-and-authorization.md index 28054e8..42ff5f8 100644 --- a/apps/web/src/content/docs/internals/origin-and-authorization.md +++ b/apps/web/src/content/docs/development/origin-and-authorization.md @@ -1,9 +1,9 @@ --- title: Origin and authorization description: How transaction provenance differs from document locks and integration permissions. -section: Internals -group: Internals -order: 13 +section: Development +group: Development +order: 22 --- Inkfinite records the source of each transaction separately from the rules that decide whether an @@ -26,7 +26,7 @@ from `origin: agent` to `origin: human` must never give the caller more capabili ## Validation and authorization The transaction engine applies document correctness rules to every origin. These include schema -validation, causal-head and record-version checks, atomic commit, durable document validation, and +validation, causal-head and record-version checks, atomic commit, document validation, and ordinary shape and layer locks. Authorization belongs at an interface that can identify the caller and its granted permissions. diff --git a/apps/web/src/content/docs/internals/svg-import.md b/apps/web/src/content/docs/development/svg-import.md similarity index 97% rename from apps/web/src/content/docs/internals/svg-import.md rename to apps/web/src/content/docs/development/svg-import.md index 63fe7b5..0773a6f 100644 --- a/apps/web/src/content/docs/internals/svg-import.md +++ b/apps/web/src/content/docs/development/svg-import.md @@ -1,9 +1,9 @@ --- title: SVG import description: 'How static SVG content is parsed into Inkfinite native shapes and assets.' -section: Internals -group: Internals -order: 12 +section: Development +group: Development +order: 20 --- Inkfinite parses the supported static SVG subset in Rust and maps it to native @@ -65,7 +65,7 @@ Negative coordinates are valid, and negative dimensions are rejected. ## Path normalization SVG path data is normalized to the native path representation described in the -[native path geometry guide](/docs/internals/native-path-geometry/): +[native path geometry guide](/docs/development/native-path-geometry/): - relative and absolute move, line, horizontal, and vertical commands become move and line segments @@ -144,8 +144,8 @@ Rust document session parses the bytes, builds the shared SVG transaction, commi one history entry, and returns the new canonical snapshot and editor projection. The browser caches that projection with the canonical IndexedDB bytes and uses it to hydrate the editor. File selection, drag-and-drop, and pasted markup use this -path. The web build runs `scripts/build-wasm.mjs` before Vite packages the worker; -it requires the matching `wasm-bindgen` CLI. The CLI accepts +path. The web build runs `scripts/build-wasm.mjs` before Vite packages the worker. +It requires the matching `wasm-bindgen` CLI. The CLI accepts `inkfinite import svg FILE --input ARTWORK.svg` and can validate the transaction with `--dry-run` before saving. @@ -160,7 +160,7 @@ input data for provenance and future re-import, not executable document content. `@inkfinite/wasm` exposes the Rust document session, importer, and deterministic SVG renderer. The browser loads the generated module once inside the shared worker. -Import requests transfer their byte buffer to the session; render requests send one +Import requests transfer their byte buffer to the session. Render requests send one canonical snapshot and one render-options object across the worker boundary. Rust response envelopes and renderer options use the generated types in `@inkfinite/bindings/wasm`. diff --git a/apps/web/src/content/docs/internals/testing.md b/apps/web/src/content/docs/development/testing.md similarity index 98% rename from apps/web/src/content/docs/internals/testing.md rename to apps/web/src/content/docs/development/testing.md index a5c1e31..7313424 100644 --- a/apps/web/src/content/docs/internals/testing.md +++ b/apps/web/src/content/docs/development/testing.md @@ -1,9 +1,9 @@ --- title: Testing description: 'How Inkfinite tests document behavior, editor workflows, and visual changes.' -section: Internals -group: Internals -order: 13 +section: Development +group: Development +order: 23 --- Inkfinite keeps fast correctness checks close to the code they protect. Rust and diff --git a/apps/web/src/content/docs/getting-started.md b/apps/web/src/content/docs/getting-started.md deleted file mode 100644 index 0a40f1f..0000000 --- a/apps/web/src/content/docs/getting-started.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Getting started -description: Install Inkfinite and create your first document. -section: Get started -group: Start here -order: 2 ---- - -Run Inkfinite from the repository, then choose the web or desktop editor based on where you want -to keep your documents. - -## Requirements - -You need Node.js 18 or newer, pnpm, and Rust 1.89. Building the desktop app also requires the -[Tauri 2 prerequisites](https://v2.tauri.app/start/prerequisites/) for your OS. - -Clone the repository, open a terminal in its root directory, and install the JavaScript packages: - -```sh -pnpm install -``` - -The web editor also needs the Rust WebAssembly target and the `wasm-bindgen` CLI version used by -`Cargo.lock`. Set them up and compile the browser document engine once after a fresh checkout: - -```sh -rustup target add wasm32-unknown-unknown -cargo install wasm-bindgen-cli --version 0.2.126 --locked -pnpm wasm:build -``` - -## Installation - -Start the web editor: - -```sh -pnpm dev:web -``` - -The command prints a local URL for the documentation site. Open its `/app` route to use the -editor. Documents created there stay in that browser profile. - -To run the desktop editor instead: - -```sh -pnpm tauri dev -``` - -The desktop app can open and save `.inkfinite` files on your computer. - -## Create a document - -Open the editor and use the file browser to create a board. Add shapes from the toolbar, then drag -on the canvas to place them. The editor saves web documents to IndexedDB; the desktop app keeps a -draft until you choose **Save As** and select a file. - -Use **Import** when you already have an Excalidraw or Obsidian Canvas file. Import creates a new -Inkfinite document and leaves the source file unchanged. - -## Next steps - -- Read [Documents](/docs/concepts/documents/) to understand pages, layers, and shapes. -- Read [Web editor](/docs/applications/web/) or [Desktop editor](/docs/applications/desktop/) for - storage details. -- Read [Command-line interface](/docs/reference/cli/) before changing a saved document from a - script or coding agent. diff --git a/apps/web/src/content/docs/guide/boards-and-files.md b/apps/web/src/content/docs/guide/boards-and-files.md new file mode 100644 index 0000000..a8057f1 --- /dev/null +++ b/apps/web/src/content/docs/guide/boards-and-files.md @@ -0,0 +1,45 @@ +--- +title: Boards and files +description: Manage browser boards, desktop drafts, native files, workspaces, and recovery. +section: Guide +group: Guide +order: 8 +--- + +A board is the document you open in the editor. Its storage depends on whether you use the web or +desktop app. + +## Board browser + +Press **Cmd/Ctrl+B** to open the board browser. You can create, search, sort, inspect, duplicate, +rename, and delete boards. The browser identifies the active board, storage location, save state, +and last update. + +Inkfinite flushes pending changes before switching boards. If a save or board action fails, the +browser keeps the current board open and reports the error. The list supports keyboard navigation +and narrow touch screens. + +## Browser storage + +The web app stores boards in IndexedDB for the current origin and browser profile. Another browser, +profile, or deployment origin has a separate database. Clearing site data or using private browsing +can remove access to those boards. + +Export important browser work. Use the desktop app when you need a native file that you can copy, +version, or inspect with the CLI. + +## Desktop files and drafts + +A new desktop board is a draft in the app's local data directory. Choose **Save As** to create a +named `.inkfinite` file. **Save** writes later changes to that file. Import and export paths remain +separate from the native document path. + +The desktop board browser also lists recent files and can work with a selected workspace directory. +Open documents through the desktop app so it can manage file locks, recovery data, and live CLI +sessions. + +## Recovery + +Canonical writes use a temporary file and atomic replacement. If recovery data is available after +an interrupted write, validate it and save it as a new native file rather than overwriting the last +known file blindly. Do not remove a sidecar lock while the desktop app or CLI owns it. diff --git a/apps/web/src/content/docs/guide/editor.md b/apps/web/src/content/docs/guide/editor.md new file mode 100644 index 0000000..4da1ca0 --- /dev/null +++ b/apps/web/src/content/docs/guide/editor.md @@ -0,0 +1,45 @@ +--- +title: Editor +description: Navigate the canvas, use drawing tools, select objects, and change their appearance. +section: Guide +group: Guide +order: 3 +--- + +The web and desktop apps share the same canvas, tools, shortcuts, and document operations. The +desktop app adds native file handling and local CLI access. + +## Canvas navigation + +Pan with a trackpad, middle-button drag, or Space-drag. Pinch or hold Ctrl/Cmd while scrolling to +zoom. The lower-left controls set an exact zoom level, fit the drawing, or fit the current +selection. **Shift+1** fits the drawing and **Shift+2** fits the selection. + +The status bar reports the active tool, cursor and viewport coordinates, selection, save state, +and grid settings. Grid visibility, size, and snapping preferences persist between sessions. + +## Tools and selection + +The toolbar contains Select, Direct Select, shapes, text, Markdown, and pen tools. Select works +with complete objects. Direct Select edits anchors and handles on native paths. + +Drag a selection to move it. Hold Shift to constrain movement or drawing to 15-degree angles. Hold +Alt/Option while dragging to duplicate. During resize, Shift preserves the aspect ratio and +Alt/Option resizes around the center. + +Double-click a nested object to enter its group or frame. Press Escape to return to its parent. +Right-click the canvas or a selection for commands that apply at that location. + +## Appearance + +Select an object to edit its fill, stroke, and opacity. Text, Markdown, and Card selections also +show font family and size controls. Arrow controls edit bends, endpoint heads, routing, and labels. + +The command palette searches selection and viewport commands. The Layers panel controls layer +order, visibility, locks, names, and opacity. See [Objects and structure](/docs/guide/objects-and-structure/) +for frames, groups, cards, and metadata. + +## Errors and recovery + +The editor reports failed saves, imports, exports, and clipboard operations in the interface. A +desktop draft remains separate from a named `.inkfinite` file until you choose **Save As**. diff --git a/apps/web/src/content/docs/guide/import-and-export.md b/apps/web/src/content/docs/guide/import-and-export.md new file mode 100644 index 0000000..e691d12 --- /dev/null +++ b/apps/web/src/content/docs/guide/import-and-export.md @@ -0,0 +1,46 @@ +--- +title: Import and export +description: Move editable boards and presentation copies between Inkfinite and other tools. +section: Guide +group: Guide +order: 7 +--- + +Use import when you want external content to become part of an Inkfinite board. Use export when you +want an editable interchange file or a presentation copy for another application. + +## Supported formats + +| Format | Import | Export | Result | +| ---------------------- | ----------- | ------ | ------------------------------------ | +| Inkfinite | Yes | Yes | Native document and history | +| SVG | Yes | Yes | Supported geometry stays editable | +| PNG and other images | As an image | PNG | Raster content | +| Excalidraw | Yes | Yes | Supported objects are mapped | +| Obsidian / JSON Canvas | Yes | Yes | Supported nodes and edges are mapped | + +The editor also accepts pasted plain text, Markdown, SVG markup, and images. Native clipboard copy +preserves hierarchy, assets, and connections. **Paste in place** keeps copied coordinates. Ordinary +paste places content near the pointer. + +## Import files + +Choose **Import**, paste content, or drop a supported file on the canvas. Importing an Excalidraw or +Obsidian Canvas file creates an Inkfinite document and leaves the source unchanged. SVG import maps +supported static elements to native shapes and assets. + +An import report lists omitted content, conversions, and fallback content. Keep the source until you +have checked the imported board. Unsupported SVG visuals may be retained as opaque fallback content +rather than editable geometry. + +## Export a board + +Export SVG for vector presentation output or PNG for the current viewport. SVG can include the +current selection or the current page. Excalidraw and Obsidian Canvas exports map supported editable +content and report content their formats cannot represent. + +Export does not change the current desktop document's native path or saved state. Continue saving +the `.inkfinite` file as the source when you need the complete board and its history. + +See [Interoperability](/docs/reference/interoperability/) for a concise capability matrix and known +format differences. diff --git a/apps/web/src/content/docs/guide/layout-and-connections.md b/apps/web/src/content/docs/guide/layout-and-connections.md new file mode 100644 index 0000000..015d44e --- /dev/null +++ b/apps/web/src/content/docs/guide/layout-and-connections.md @@ -0,0 +1,43 @@ +--- +title: Layout and connections +description: Align selections, arrange connected graphs, bind arrows, and use snapping guides. +section: Guide +group: Guide +order: 5 +--- + +Inkfinite can arrange a selection by geometry or by the relationships stored between objects. + +## Align and distribute + +Select two or more objects and open **Layout**. Alignment commands line up left, center, right, top, +middle, or bottom edges. Distribution makes horizontal or vertical spacing even. **Tidy** repairs +an uneven row or column, while stack and grid commands create a regular arrangement. + +Order commands move objects forward, backward, to the front, or to the back. The menu also groups, +ungroups, locks, and unlocks a selection. + +## Graph layout + +Tree, flow, and radial layouts arrange objects connected by relationship bindings. Tree and flow +layouts support horizontal and vertical directions. Radial layout places connected objects around +the graph. + +Graph layout reads relation bindings and both endpoints of bound arrows. It does not infer an edge +because two objects happen to be near each other. Select the connected objects you want to arrange, +then choose a graph layout from **Layout**. + +## Arrow bindings + +Create an arrow and drop an endpoint on a shape to bind it. A bound endpoint follows the shape when +it moves or resizes. Arrows can be straight, curved, or elbow-routed and can carry labels and +relationship metadata. + +Use arrow selection controls to change routing, bends, heads, and labels. A free endpoint remains at +its canvas position until you drag it onto an object. + +## Snapping + +When you move or resize a selection, Inkfinite can snap edges, centers, corners, handles, and equal +gaps to nearby content. The canvas draws a guide for each active snap. Change snapping and grid +preferences from the status bar. diff --git a/apps/web/src/content/docs/guide/objects-and-structure.md b/apps/web/src/content/docs/guide/objects-and-structure.md new file mode 100644 index 0000000..f853ad8 --- /dev/null +++ b/apps/web/src/content/docs/guide/objects-and-structure.md @@ -0,0 +1,44 @@ +--- +title: Objects and structure +description: Work with shapes, rich content, frames, groups, layers, metadata, and stencils. +section: Guide +group: Guide +order: 4 +--- + +Inkfinite combines drawing primitives with structured canvas objects. Every object has a stable ID, +a transform, properties for its kind, and optional metadata. + +## Drawing objects + +The shape tools create rectangles, ellipses, frames, lines, arrows, text, Markdown, and freehand +strokes. Images remain native assets and support crop, captions, display masks, opacity, +replacement, and color sampling. + +URL, file, and page-reference objects keep external or internal targets as editable content. The +Card stencil creates a frame with ordinary text and Markdown children. Select a card to edit its +title and body. + +## Frames and groups + +Frames and groups contain ordered child objects. Moving a container moves its children. Double-click +a nested object to enter its container, then press Escape to return to the parent. + +Frames provide a visible canvas region and can be fitted to the viewport. Groups collect objects +without adding a frame presentation. Container child order controls drawing order within the +container and the order used by SVG export. + +## Layers + +Each page contains ordered layers. The Layers panel creates, activates, renames, reorders, hides, +locks, and changes the opacity of layers. A shape lock prevents edits regardless of the source of +the transaction. + +## Metadata and stencils + +The object metadata controls edit names, roles, tags, descriptions, sources, links, and structured +metadata. A single selected object also shows read-only provenance: actor, origin, time, and source. +These fields let people and CLI queries find objects by meaning instead of canvas coordinates. + +Open **Insert** to add a stencil. Stencils can create a single object or a structured set of +objects, such as a Card frame with title and body children. diff --git a/apps/web/src/content/docs/guide/vector-editing.md b/apps/web/src/content/docs/guide/vector-editing.md new file mode 100644 index 0000000..83eb9d8 --- /dev/null +++ b/apps/web/src/content/docs/guide/vector-editing.md @@ -0,0 +1,37 @@ +--- +title: Vector editing +description: Edit native path anchors, Bézier handles, segments, and imported SVG geometry. +section: Guide +group: Guide +order: 6 +--- + +Inkfinite stores supported arbitrary vector geometry as native path shapes. You can edit paths drawn +in Inkfinite and paths created from supported SVG elements. + +## Direct Select + +Choose **Direct Select**, then select a path. Inkfinite displays anchors and the Bézier handles that +control curved segments. Drag an anchor to move it. Drag a handle to change the direction and +strength of a curve. + +Whole-object selection still controls the path's transform, bounds, fill, stroke, and opacity. Use +Direct Select only when you need to change the geometry inside those bounds. + +## Path topology + +Path commands open or close a subpath, split a segment, join compatible endpoints, and change a +segment's geometry. A path may contain more than one subpath and may mix line and Bézier segments. + +Closing a path adds a segment from its final anchor to its first anchor. Opening it removes the +closing segment. Split creates a new anchor on a segment. Join connects compatible open endpoints. + +## Imported SVG paths + +SVG paths and supported vector primitives become native Inkfinite geometry during import. Their +anchors and segments can then be edited with Direct Select. Unsupported visual content may remain +as opaque fallback content and cannot expose native anchors. + +Read [Import and export](/docs/guide/import-and-export/) for the supported workflow. Maintainers can +read [Native path geometry](/docs/development/native-path-geometry/) for the stored representation +and invariants. diff --git a/apps/web/src/content/docs/introduction.md b/apps/web/src/content/docs/introduction.md index f0a0a00..1d3d473 100644 --- a/apps/web/src/content/docs/introduction.md +++ b/apps/web/src/content/docs/introduction.md @@ -1,7 +1,7 @@ --- title: Introduction description: 'Learn what Inkfinite is, where documents live, and which guide to read next.' -section: Get started +section: Start here group: Start here order: 1 --- @@ -11,9 +11,9 @@ the browser and as a desktop app, with the same editor and document model in bot ## What you can make -Use shapes, arrows, text, Markdown, freehand strokes, layers, and stencils to sketch an idea or -build a structured diagram. The canvas supports direct manipulation, undo and redo, grouping, -reordering, panning, and zooming. +Use shapes, arrows, text, Markdown, cards, images, freehand strokes, layers, and stencils to sketch +an idea or build a structured diagram. Inkfinite also supports graph layout, native vector path +editing, and SVG, Excalidraw, and Obsidian Canvas interchange. ## Where documents live @@ -27,15 +27,15 @@ command-line tools use file locks, atomic replacement, and recovery data to prot ## Ways to work - Open the [web editor](/app) for a browser-based canvas, or read its - [storage guide](/docs/applications/web/). -- Use the [desktop editor](/docs/applications/desktop/) for native files and desktop menus. -- Use the [command-line interface](/docs/reference/cli/) to inspect, edit, validate, or render a + [storage guide](/docs/platforms/web/). +- Use the [desktop editor](/docs/platforms/desktop/) for native files and desktop menus. +- Use the [command-line interface](/docs/automation/cli/) to inspect, edit, validate, or render a document from a script. -- Use [agent workflows](/docs/reference/agents/) to inspect, validate, and apply scripted document changes. +- Use [agent workflows](/docs/automation/agents/) to inspect, validate, and apply scripted document changes. ## Where to go next -Follow [Getting started](/docs/getting-started/) to run an editor and create a document. +Follow the [Quickstart](/docs/quickstart/) to create and export a board. -Read [Documents](/docs/concepts/documents/) for the data model or -[Transactions and Sync](/docs/concepts/transactions-and-sync/) for editing, history, and convergence. +Read [Document model](/docs/concepts/document-model/) for the data model or +[Transactions and sync](/docs/concepts/transactions-and-sync/) for editing, history, and convergence. diff --git a/apps/web/src/content/docs/applications/desktop.md b/apps/web/src/content/docs/platforms/desktop.md similarity index 63% rename from apps/web/src/content/docs/applications/desktop.md rename to apps/web/src/content/docs/platforms/desktop.md index 46063a3..6944c57 100644 --- a/apps/web/src/content/docs/applications/desktop.md +++ b/apps/web/src/content/docs/platforms/desktop.md @@ -1,27 +1,15 @@ --- -title: Desktop editor -description: Build the Inkfinite desktop app and work safely with native files. -section: Applications -group: Applications -order: 6 +title: Desktop +description: Work with native files, drafts, workspaces, and live local CLI sessions. +section: Platforms +group: Platforms +order: 10 --- The desktop editor combines the shared canvas interface with native file handling and authenticated -local CLI access. See [Canvas editor](/docs/applications/editor/) for tools, gestures, clipboard -formats, layers, and shortcuts. - -## Run locally - -Install Node.js 18 or newer, pnpm, Rust 1.89, and the -[Tauri 2 prerequisites](https://v2.tauri.app/start/prerequisites/) for your operating system. From -the repository root, run: - -```sh -pnpm install -pnpm tauri dev -``` - -This starts the web frontend and native Tauri shell in development mode. +local CLI access. See the [Editor guide](/docs/guide/editor/) for tools, gestures, selection, and +styling. To run the desktop app from a checkout, follow +[Building from source](/docs/development/building-from-source/). ## Document sessions @@ -43,5 +31,5 @@ the view, or focus the window. Structured live mutations commit immediately after causal-head, record-version, validation, and lock checks. Reviewed model access belongs to the permissioned MCP interface. CLI discovery and authentication remain local to the current user account. See -[Agent workflows](/docs/reference/agents/) and -[Command-line interface](/docs/reference/cli/) for commands. +[Agent workflows](/docs/automation/agents/) and +[Command-line interface](/docs/automation/cli/) for commands. diff --git a/apps/web/src/content/docs/applications/web.md b/apps/web/src/content/docs/platforms/web.md similarity index 60% rename from apps/web/src/content/docs/applications/web.md rename to apps/web/src/content/docs/platforms/web.md index 64644a6..b0380ef 100644 --- a/apps/web/src/content/docs/applications/web.md +++ b/apps/web/src/content/docs/platforms/web.md @@ -1,29 +1,19 @@ --- -title: Web editor -description: Run the Inkfinite web editor and understand its browser storage. -section: Applications -group: Applications -order: 5 +title: Web +description: Use the browser editor and understand where it stores boards. +section: Platforms +group: Platforms +order: 9 --- The web editor provides the full canvas interface without access to native `.inkfinite` files. -See [Canvas editor](/docs/applications/editor/) for tools, gestures, clipboard formats, layers, and -shortcuts. +See the [Editor guide](/docs/guide/editor/) for tools, gestures, selection, and styling. ## Open the editor -The hosted editor lives at [`/app`](/app). To run it from source: - -```sh -pnpm install -rustup target add wasm32-unknown-unknown -cargo install wasm-bindgen-cli --version 0.2.126 --locked -pnpm wasm:build -pnpm dev:web -``` - -Open the local URL printed by Vite and add `/app` to its path. The site root contains this -documentation. +The hosted editor lives at [`/app`](/app). It loads the Rust document engine through WebAssembly +and stores boards for the current site in the browser. To run your own build, follow +[Building from source](/docs/development/building-from-source/). ## Storage and backups diff --git a/apps/web/src/content/docs/quickstart.md b/apps/web/src/content/docs/quickstart.md new file mode 100644 index 0000000..f60cf04 --- /dev/null +++ b/apps/web/src/content/docs/quickstart.md @@ -0,0 +1,45 @@ +--- +title: Quickstart +description: Create, connect, arrange, and save your first Inkfinite board. +section: Start here +group: Start here +order: 2 +--- + +Open the [web editor](/app) to start a board in your browser. Use the desktop app instead when you +want to save a native `.inkfinite` file on your computer. + +## Create a board + +Open the board browser and choose **New board**. The browser stores boards in IndexedDB. The desktop +app starts with a draft and asks for a file location when you choose **Save As**. + +Select a shape from the toolbar, then drag on the canvas to place it. Add text or Markdown with +their toolbar tools. Use the Select tool to move and resize objects. + +## Connect and arrange + +Choose the Arrow tool and drag between two shapes. Drop each endpoint on a shape to bind it. The +arrow follows its connected shapes when you move them. + +Select several objects and open **Layout** to align, distribute, stack, or tidy them. Drag a +selection near another object to see edge, center, and equal-gap snapping guides. + +## Navigate the canvas + +Pan with a trackpad, middle-button drag, or Space-drag. Pinch or hold Ctrl/Cmd while scrolling to +zoom. **Shift+1** fits the drawing in the viewport. **Shift+2** fits the current selection. + +Press **?** to open the searchable keyboard shortcut list. Press **Cmd/Ctrl+B** to return to the +board browser. + +## Save or export + +Browser boards save automatically to the current browser profile. In the desktop app, choose +**Save As** to turn a draft into a `.inkfinite` file. + +Use **Export** for SVG, PNG, Excalidraw, or Obsidian Canvas output. Keep the `.inkfinite` file when +you want to preserve the complete document and its history. + +Continue with the [Editor guide](/docs/guide/editor/) or read about +[boards and files](/docs/guide/boards-and-files/). diff --git a/apps/web/src/content/docs/reference/file-format.md b/apps/web/src/content/docs/reference/file-format.md index fa2bcc5..6f0212a 100644 --- a/apps/web/src/content/docs/reference/file-format.md +++ b/apps/web/src/content/docs/reference/file-format.md @@ -3,7 +3,7 @@ title: File format description: 'Inkfinite native files, document contract, safe writes, editable canvas interchange, compatibility limits, and lossless exports.' section: Reference group: Reference -order: 8 +order: 17 --- Inkfinite uses `.inkfinite` as its native document format. The editor can also import and export Excalidraw and Obsidian Canvas files when you need to move editable content between applications. @@ -28,21 +28,21 @@ pub struct DocumentSnapshot { } ``` -The `format` field is `"inkfinite.document"` and `format_version` is currently `2`. The document contains normalized pages, layers, shapes, bindings, and assets. Binding records may include a `relation_type` alongside their source and target shape IDs. Pages own ordered layers; layers own ordered root shapes; containers own their ordered child shapes. Container child order drives frame presentation and SVG export. Card fields are stored in the container's semantic metadata while title and body remain ordinary text and Markdown children. IDs remain stable across saves and replicas. +The `format` field is `"inkfinite.document"` and `format_version` is currently `2`. The document contains normalized pages, layers, shapes, bindings, and assets. Binding records may include a `relation_type` alongside their source and target shape IDs. Pages own ordered layers. Layers own ordered root shapes. Containers own their ordered child shapes. Container child order drives frame presentation and SVG export. Card fields are stored in the container's semantic metadata while title and body remain ordinary text and Markdown children. IDs remain stable across saves and replicas. -Text and Markdown shapes store their CSS font family as a string. Card titles and bodies use the font families on their text and Markdown child shapes, so changing a card's font does not require a document format migration. The web and desktop editors load their bundled fonts at runtime; a headless renderer needs the requested family supplied as a font asset or an available font family and otherwise reports a fallback warning. +Text and Markdown shapes store their CSS font family as a string. Card titles and bodies use the font families on their text and Markdown child shapes, so changing a card's font does not require a document format migration. The web and desktop editors load their bundled fonts at runtime. A headless renderer needs the requested family supplied as a font asset or an available font family and otherwise reports a fallback warning. The CLI can print a deterministic JSON projection for inspection and CI. That projection is not a second file format and cannot replace the Automerge history or causal heads stored in the canonical file. ## Safe writes -`DocumentFile` holds an advisory sidecar lock for the canonical path. Every transaction is validated before it is committed. A save writes a temporary same-directory replacement, flushes and syncs it, and then replaces the canonical file. An interrupted replacement leaves bounded recovery data that can be validated and saved as a new canonical baseline. +`DocumentFile` holds an advisory sidecar lock for the canonical path. Every transaction is validated before it is committed. A save writes a temporary same-directory replacement, flushes and syncs it, and then replaces the canonical file. An interrupted replacement leaves recovery data that can be validated and saved as a new canonical baseline. Invalid bytes, stale heads, missing references, and invalid record properties are rejected before the canonical file is changed. Recovery uses the same document validation and persistence path as a normal save. ## Versioning -`format_version` and protocol version fields are explicit so future releases can reject unsupported data safely. They describe the current serialized contract; they do not select between document models or file flows. +`format_version` and protocol version fields are explicit so future releases can reject unsupported data safely. They describe the current serialized contract. They do not select between document models or file flows. ## Editable interchange @@ -59,7 +59,7 @@ Inkfinite reads and writes Excalidraw v2 scene JSON. The converter handles recta | Excalidraw content | Inkfinite result | | -------------------------------- | ---------------------------------------------------- | | Rectangle, ellipse, text | Matching editable shape | -| Line or arrow | Matching line or arrow; extra line vertices are lost | +| Line or arrow | Matching line or arrow. Extra line vertices are lost | | Bound arrow and label | Arrow bindings and label | | Freedraw | Freehand stroke | | Group or frame | Flat Inkfinite group | @@ -80,7 +80,7 @@ Inkfinite implements the JSON Canvas 1.0 structure used by Obsidian `.canvas` fi | Text node | Markdown card | | File node | Markdown wiki link | | Link node | Markdown link | -| Group node | Flat Inkfinite group; label and background are lost | +| Group node | Flat Inkfinite group. Label and background are lost | | Edge between nodes | Bound Inkfinite arrow | JSON Canvas does not represent general drawing primitives, freehand strokes, layers, rotation, or free-floating arrows. When exporting, Inkfinite writes text and Markdown as cards, bound arrows as edges, and groups around supported cards. Other drawing shapes are omitted and listed in the conversion notes. Rotated cards use their axis-aligned bounds. diff --git a/apps/web/src/content/docs/reference/interoperability.md b/apps/web/src/content/docs/reference/interoperability.md new file mode 100644 index 0000000..7192587 --- /dev/null +++ b/apps/web/src/content/docs/reference/interoperability.md @@ -0,0 +1,36 @@ +--- +title: Interoperability +description: Check import, export, editability, and compatibility across supported canvas formats. +section: Reference +group: Reference +order: 16 +--- + +## Format matrix + +| Format | Import | Export | Editability | Main limits | +| -------------------------- | ----------- | ------ | ------------------------------------ | ------------------------------------------------------- | +| `.inkfinite` | Yes | Yes | Native | Use desktop or CLI for files | +| SVG | Yes | Yes | Supported geometry is native | Unsupported visuals may use fallback content | +| PNG | As an image | Yes | Raster | No individual vector objects | +| Excalidraw v2 | Yes | Yes | Supported objects are mapped | Rough styles, some shapes, and exact metrics differ | +| Obsidian / JSON Canvas 1.0 | Yes | Yes | Supported nodes and edges are mapped | General drawing shapes and rotation are not represented | + +## Round trips + +A native `.inkfinite` file preserves the document, causal heads, and Automerge history. Treat it as +the source when work will return to Inkfinite. + +Excalidraw conversion supports rectangles, ellipses, lines, arrows, text, freehand strokes, groups, +frames, bindings, and labels. Unsupported images, iframes, diamonds, style details, and some +arrowheads are reported during conversion. + +JSON Canvas conversion supports text, file, link, and group nodes plus edges between nodes. The +format cannot represent Inkfinite's general drawing primitives, freehand strokes, layers, rotation, +or free-floating arrows. + +SVG import maps the supported static subset to native shapes. SVG export produces vector output for +the current page or selection. PNG captures the current viewport. + +Read [Import and export](/docs/guide/import-and-export/) for the editor workflow and +[File format](/docs/reference/file-format/) for native storage details. diff --git a/apps/web/src/content/docs/reference/shortcuts.md b/apps/web/src/content/docs/reference/shortcuts.md new file mode 100644 index 0000000..8b533fc --- /dev/null +++ b/apps/web/src/content/docs/reference/shortcuts.md @@ -0,0 +1,47 @@ +--- +title: Keyboard shortcuts +description: Look up canvas navigation, selection, editing, and application shortcuts. +section: Reference +group: Reference +order: 15 +--- + +Press **?** in the editor to open the searchable shortcut panel. + +## Selection and editing + +| Action | Shortcut | +| ------------------------------------ | ------------------------------ | +| Select all | Cmd/Ctrl+A | +| Clear selection or leave a container | Escape | +| Copy, cut, paste | Cmd/Ctrl+C, X, V | +| Duplicate | Cmd/Ctrl+D | +| Duplicate and connect | Option+Cmd / Alt+Ctrl+D | +| Group | Cmd/Ctrl+G | +| Ungroup | Shift+Cmd/Ctrl+G | +| Lock selection | Shift+Cmd/Ctrl+L | +| Nudge | Arrow keys | +| Nudge 10 pixels | Shift+Arrow keys | +| Undo | Cmd/Ctrl+Z | +| Redo | Shift+Cmd/Ctrl+Z or Cmd/Ctrl+Y | + +## Order and canvas + +| Action | Shortcut | +| ----------------------------- | -------------------- | +| Bring forward / send backward | Cmd/Ctrl+] / [ | +| Bring to front / send to back | Shift+Cmd/Ctrl+] / [ | +| Pan | Space+drag | +| Zoom in / out | + / − | +| Fit drawing | Shift+1 | +| Fit selection | Shift+2 | + +## Application + +| Action | Shortcut | +| -------------------- | ---------- | +| Open boards | Cmd/Ctrl+B | +| Open command palette | Cmd/Ctrl+K | +| Show shortcuts | ? | + +Right-click the canvas or a selection to see commands for the current context. diff --git a/apps/web/src/lib/docs/DocsCopyMarkdown.svelte b/apps/web/src/lib/docs/DocsCopyMarkdown.svelte index 3fb9dac..821f152 100644 --- a/apps/web/src/lib/docs/DocsCopyMarkdown.svelte +++ b/apps/web/src/lib/docs/DocsCopyMarkdown.svelte @@ -44,6 +44,8 @@ font-size: 0.82rem; font-weight: 650; text-decoration: none; + white-space: nowrap; + flex: 0 0 auto; } .copy-markdown:hover { diff --git a/apps/web/src/lib/docs/DocsShell.svelte b/apps/web/src/lib/docs/DocsShell.svelte index 8d72151..56d36d6 100644 --- a/apps/web/src/lib/docs/DocsShell.svelte +++ b/apps/web/src/lib/docs/DocsShell.svelte @@ -112,8 +112,10 @@ } .doc-description { + min-width: 0; max-width: 42rem; margin: 1rem 0 0; + flex: 1 1 auto; color: var(--docs-text-muted); font-size: 1.12rem; line-height: 1.55; diff --git a/apps/web/src/lib/docs/SiteHeader.svelte b/apps/web/src/lib/docs/SiteHeader.svelte index c8d0db4..fc36591 100644 --- a/apps/web/src/lib/docs/SiteHeader.svelte +++ b/apps/web/src/lib/docs/SiteHeader.svelte @@ -9,14 +9,14 @@ let { docs, currentSlug = '' }: { docs: Doc[]; currentSlug?: string } = $props(); const primaryLinks = [ - { label: 'Start', href: '/docs/getting-started/', slug: 'getting-started' }, - { label: 'Concepts', href: '/docs/concepts/documents/', slug: 'concepts' }, - { label: 'Reference', href: '/docs/reference/cli/', slug: 'reference' } + { label: 'Start', href: '/docs/quickstart/', slug: 'quickstart' }, + { label: 'Guide', href: '/docs/guide/editor/', slug: 'guide' }, + { label: 'Automation', href: '/docs/automation/cli/', slug: 'automation' } ] as const; const githubUrl = 'https://github.com/stormlightlabs/inkfinite'; function isCurrent(slug: string): boolean { - if (slug === 'getting-started' && currentSlug === 'introduction') return true; + if (slug === 'quickstart' && currentSlug === 'introduction') return true; return currentSlug === slug || currentSlug.startsWith(`${slug}/`); } diff --git a/apps/web/src/lib/docs/content/types.ts b/apps/web/src/lib/docs/content/types.ts index d744a3d..1d7fb01 100644 --- a/apps/web/src/lib/docs/content/types.ts +++ b/apps/web/src/lib/docs/content/types.ts @@ -2,11 +2,13 @@ import type { Component } from 'svelte'; /** Sidebar sections used to organize the documentation. */ export const docSections = [ - 'Get started', + 'Start here', + 'Guide', + 'Platforms', + 'Automation', 'Concepts', - 'Applications', 'Reference', - 'Internals' + 'Development' ] as const; export type DocSection = (typeof docSections)[number]; diff --git a/apps/web/src/routes/+page.svelte b/apps/web/src/routes/+page.svelte index 527db12..c9a21d4 100644 --- a/apps/web/src/routes/+page.svelte +++ b/apps/web/src/routes/+page.svelte @@ -11,13 +11,13 @@ const docs = getDocs(); const landingDocSlugs = [ - 'introduction', - 'getting-started', - 'concepts/documents', - 'concepts/transactions-and-sync', - 'reference/cli', - 'reference/agents', - 'reference/file-format' + 'quickstart', + 'guide/editor', + 'guide/import-and-export', + 'platforms/desktop', + 'automation/cli', + 'automation/agents', + 'development/architecture' ] as const; const landingDocs = landingDocSlugs .map((slug) => docs.find((doc) => doc.slug === slug)) @@ -58,7 +58,7 @@ @@ -202,7 +202,7 @@ content, and export it again through one validated Rust pipeline.
- + How SVG import works