From d91da0270399e9f7fb223dba317a786295ad192c Mon Sep 17 00:00:00 2001 From: Owais Jamil Date: Sun, 02 Aug 2026 17:41:12 +0000 Subject: [PATCH] refactor: move routes around in web app --- README.md | 2 ++ apps/web/svelte.config.js | 2 +- apps/web/src/routes/+page.svelte | 529 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- apps/web/src/routes/+page.ts | 2 -- apps/web/src/lib/docs/DocsHeader.svelte | 10 ++++++---- apps/web/src/lib/docs/DocsShell.svelte | 4 ++-- apps/web/src/routes/app/+page.svelte | 30 ++++++++++++++++++++++++++++++ apps/web/src/routes/app/+page.ts | 2 ++ apps/web/src/routes/docs/+page.svelte | 519 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- apps/web/src/routes/docs/+page.ts | 5 +++++ packages/ui/src/lib/components/Dialog.svelte | 4 ++-- packages/ui/src/lib/editor/constants.ts | 2 +- apps/web/src/routes/docs/getting-started/+page.svx | 42 ++++++++++++++++++++++++++++++++++++------ apps/web/src/routes/docs/introduction/+page.svx | 3 ++- packages/ui/src/lib/editor/components/StatusBar.svelte | 10 +++++++++- packages/ui/src/lib/editor/components/StatusBar.svelte.test.ts | 6 +++--- apps/web/src/routes/docs/applications/desktop/+page.svx | 37 ++++++++++++++++++++++++++++++------- apps/web/src/routes/docs/applications/web/+page.svx | 30 ++++++++++++++++++++++++------ apps/web/src/routes/docs/concepts/documents/+page.svx | 34 ++++++++++++++++++++++++++++------ apps/web/src/routes/docs/concepts/transactions-and-sync/+page.svx | 34 ++++++++++++++++++++++++++++------ apps/web/src/routes/docs/reference/agents/+page.svx | 52 +++++++++++++++++++++++++++++++++++++++++++++------- apps/web/src/routes/docs/reference/cli/+page.svx | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 22 file(s) changed, 844 insertion(s)(+), 597 deletion(s)(-) diff --git a/README.md b/README.md --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ pnpm dev:web ``` +Open the printed local URL for the documentation site, or add `/app` to open the editor. + Start the desktop app: ```sh diff --git a/apps/web/svelte.config.js b/apps/web/svelte.config.js --- a/apps/web/svelte.config.js +++ b/apps/web/svelte.config.js @@ -7,7 +7,7 @@ extensions: ['.svelte', '.svx', '.md'], preprocess: [vitePreprocess(), mdsvex({ extensions: ['.svx', '.md'] })], kit: { - adapter: adapter({ fallback: 'index.html' }), + adapter: adapter(), prerender: { entries: ['*'] }, alias: { $editor: '../../packages/ui/src/lib/editor', diff --git a/apps/web/src/routes/+page.svelte b/apps/web/src/routes/+page.svelte --- a/apps/web/src/routes/+page.svelte +++ b/apps/web/src/routes/+page.svelte @@ -1,30 +1,525 @@ -
- -
+ + Inkfinite + + + + +
+
+
+

Documentation

+

Give your ideas

+

infinite room.

+

+ Inkfinite is an open canvas for people and coding agents to sketch, connect, + and refine ideas together. +

+ +
+ + +
+ +
+
+

One whiteboard, many ways in

+

Draw or automate.

+
+
+ {#each features as feature, index (feature.title)} + + + +

{feature.title}

+

{feature.description}

+ Read the guide +
+ + {/each} +
+
+ +
+
+

Start here

+

Open a canvas and make your first mark.

+
+ + Download + +
+
+
diff --git a/apps/web/src/routes/+page.ts b/apps/web/src/routes/+page.ts deleted file mode 100644 --- a/apps/web/src/routes/+page.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const ssr = false; -export const csr = true; diff --git a/apps/web/src/lib/docs/DocsHeader.svelte b/apps/web/src/lib/docs/DocsHeader.svelte --- a/apps/web/src/lib/docs/DocsHeader.svelte +++ b/apps/web/src/lib/docs/DocsHeader.svelte @@ -6,8 +6,8 @@ import DocsSearch from './DocsSearch.svelte'; - type Props = { sidebarOpen: boolean; toggleSidebar: () => void }; - let { sidebarOpen, toggleSidebar }: Props = $props(); + type Props = { sidebarOpen: boolean; toggleSidebar: () => void; landing?: boolean }; + let { sidebarOpen, toggleSidebar, landing = false }: Props = $props();
@@ -21,11 +21,13 @@ onclick={toggleSidebar}> - + Inkfinite - + {#if !landing} + + {/if}
diff --git a/apps/web/src/lib/docs/DocsShell.svelte b/apps/web/src/lib/docs/DocsShell.svelte --- a/apps/web/src/lib/docs/DocsShell.svelte +++ b/apps/web/src/lib/docs/DocsShell.svelte @@ -7,12 +7,12 @@ let { children }: { children: Snippet } = $props(); let sidebarOpen = $state(false); - let landing = $derived(page.url.pathname === '/docs' || page.url.pathname === '/docs/'); + let landing = $derived(page.url.pathname === '/');
- (sidebarOpen = !sidebarOpen)} /> + (sidebarOpen = !sidebarOpen)} /> {#if sidebarOpen}
- (infoOpen = false)} title="About Inkfinite"> + (infoOpen = false)} + title="About Inkfinite" + class="about-dialog">

About Inkfinite

@@ -384,6 +388,10 @@ .about { max-width: 480px; padding: var(--ink-space-5); + } + + :global(.about-dialog) { + --ink-dialog-radius: 1rem; } .about h1 { diff --git a/packages/ui/src/lib/editor/components/StatusBar.svelte.test.ts b/packages/ui/src/lib/editor/components/StatusBar.svelte.test.ts --- a/packages/ui/src/lib/editor/components/StatusBar.svelte.test.ts +++ b/packages/ui/src/lib/editor/components/StatusBar.svelte.test.ts @@ -84,8 +84,8 @@ expect(onOpenBrowser).toHaveBeenCalledOnce(); expect(onHistoryClick).toHaveBeenCalledOnce(); - await expect - .element(screen.getByRole('dialog', { name: 'About Inkfinite' })) - .toBeInTheDocument(); + const dialog = screen.getByRole('dialog', { name: 'About Inkfinite' }); + await expect.element(dialog).toBeInTheDocument(); + expect(window.getComputedStyle(dialog.element()).borderRadius).toBe('16px'); }); }); diff --git a/apps/web/src/routes/docs/applications/desktop/+page.svx b/apps/web/src/routes/docs/applications/desktop/+page.svx --- a/apps/web/src/routes/docs/applications/desktop/+page.svx +++ b/apps/web/src/routes/docs/applications/desktop/+page.svx @@ -1,20 +1,43 @@ Desktop editor · Inkfinite documentation - + # Desktop editor -Build and use Inkfinite as a native desktop application. +The desktop editor combines the shared canvas interface with native file handling and authenticated +local CLI access.

Run locally

-*todo* +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: -

Document Sessions

+```sh +pnpm install +pnpm tauri dev +``` -*todo* +This starts the web frontend and native Tauri shell in development mode. -

Local Control

+

Document sessions

-*todo* +Use **Open** to load a canonical `.inkfinite` file. New documents remain drafts in the app's local +data directory until you choose **Save As**. The app tracks the current native path separately from +imports and exports, so exporting a PNG, SVG, Excalidraw file, or Obsidian Canvas file does not mark +the native document as saved elsewhere. + +The desktop backend uses file locks, recovery data, and atomic replacement for canonical writes. +Do not edit the same file with a file-mode CLI command while it is open in the desktop app. Use the +live proposal workflow instead. + +

Local CLI access

+ +The desktop app exposes authenticated IPC to the local `inkfinite` CLI. Read-only commands can list +sessions, inspect the open document, query records, or focus the window. Mutation commands normally +create a proposal that appears as a ghost preview for human review. + +Direct live apply requires a one-time authorization token issued by the desktop UI. Discovery and +authentication remain local to the current user account. See [Agent workflows](/docs/reference/agents/) +for the review process and [Command-line interface](/docs/reference/cli/) for commands. diff --git a/apps/web/src/routes/docs/applications/web/+page.svx b/apps/web/src/routes/docs/applications/web/+page.svx --- a/apps/web/src/routes/docs/applications/web/+page.svx +++ b/apps/web/src/routes/docs/applications/web/+page.svx @@ -1,16 +1,34 @@ Web editor · Inkfinite documentation - + # Web editor -Run Inkfinite in the browser. +The web editor provides the full canvas interface without access to native `.inkfinite` files. -

Web App

+

Open the editor

-*todo* +The hosted editor lives at [`/app`](/app). To run it from a source checkout: -

Storage & Backups

+```sh +pnpm install +pnpm dev:web +``` -*todo* +Open the local URL printed by Vite and add `/app` to its path. The site root contains this +documentation. + +

Storage and backups

+ +The web editor stores boards in IndexedDB for the current origin and browser profile. It does not +write canonical files to your filesystem, and another browser or deployment origin has a separate +database. + +Export work that you cannot afford to lose. Browser storage may disappear when you clear site data, +remove a profile, or use private browsing. Use the desktop app when you want a canonical +`.inkfinite` file that can be copied, versioned, or changed by the CLI. + +Excalidraw and Obsidian Canvas exports preserve supported editable content but may omit features +that the target format cannot represent. PNG and SVG exports are presentation copies. See +[File format](/docs/reference/file-format/) before relying on an export as a backup. diff --git a/apps/web/src/routes/docs/concepts/documents/+page.svx b/apps/web/src/routes/docs/concepts/documents/+page.svx --- a/apps/web/src/routes/docs/concepts/documents/+page.svx +++ b/apps/web/src/routes/docs/concepts/documents/+page.svx @@ -1,20 +1,42 @@ Documents · Inkfinite documentation - + # Documents -Learn how Inkfinite represents an infinite-canvas document. +An Inkfinite document stores canvas content and the history needed to merge edits from different +peers.

Document structure

-*todo* +A document contains pages. Each page has an ordered tree of layers and shapes, along with bindings +that connect related shapes. Stable IDs identify every record, so an edit can refer to one object +without relying on its current position or display name. -

Shapes and Layers

+Pages separate canvases within one document. The editor displays one selected page at a time, but +the native file preserves every page and its history. -*todo* +

Shapes and layers

+ +Shapes include rectangles, ellipses, lines, arrows, text, Markdown cards, and freehand strokes. +Each shape has a kind, transform, kind-specific properties, and metadata. A shape can also carry a +name, semantic role, and tags for reliable CLI queries. + +Layers control stacking and visibility. Container shapes can own other shapes, which lets a group +move as one unit. Bindings connect arrows to source and target shapes without making either shape +a child of the other. + +Locks prevent edits to a layer or shape. The `agent_editable` metadata flag creates a separate +boundary for agent-originated transactions, even when a human can still edit the object in the +canvas.

Persistence

-*todo* +The web editor stores documents in the browser's IndexedDB database. Clearing site data or using a +different browser profile can make those documents unavailable, so export important work. + +The desktop editor and CLI use canonical `.inkfinite` files. Each file contains Automerge state +and change history, not just the visible canvas snapshot. Writers use a lock, recovery data, and +atomic file replacement to avoid partial saves. See [File format](/docs/reference/file-format/) for +editable interchange and presentation exports. diff --git a/apps/web/src/routes/docs/concepts/transactions-and-sync/+page.svx b/apps/web/src/routes/docs/concepts/transactions-and-sync/+page.svx --- a/apps/web/src/routes/docs/concepts/transactions-and-sync/+page.svx +++ b/apps/web/src/routes/docs/concepts/transactions-and-sync/+page.svx @@ -1,20 +1,42 @@ Transactions and sync · Inkfinite documentation - + # Transactions and sync -Understand how Inkfinite applies durable edits and converges between peers. +Inkfinite groups related operations into transactions, validates them against the current document, +and records accepted changes in Automerge history.

Transactions

-*todo* +A transaction has an ID, an actor, optional preconditions, and one or more operations. Operations +create, patch, move, or delete records. Grouping a coherent edit in one transaction keeps +validation, history, and review tied to the user's request. + +Preconditions can require specific document heads or record versions. Inkfinite rejects the whole +transaction when those expectations are stale, when a selector is ambiguous, or when an operation +would cross a lock or agent-editability boundary. A rejected transaction does not partially modify +the canonical file.

Undo and redo

-*todo* +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. -

Syncing

+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. -*todo* +

Synchronization

+ +Automerge assigns document heads to the current causal state. Two peers can make changes from a +shared base and merge them without choosing one entire file over the other. + +The CLI includes the heads returned by `inspect` and `query` as transaction preconditions. If a +human or another agent edits the document first, the stale transaction fails. Inspect the new +heads, query the affected records again, and rebuild the intended change from current state. + +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. diff --git a/apps/web/src/routes/docs/reference/agents/+page.svx b/apps/web/src/routes/docs/reference/agents/+page.svx --- a/apps/web/src/routes/docs/reference/agents/+page.svx +++ b/apps/web/src/routes/docs/reference/agents/+page.svx @@ -1,28 +1,66 @@ Agent workflows · Inkfinite documentation - + -# Agentic Workflows +# Agent workflows Use Inkfinite's command-line and proposal tools to make reviewable document changes.

Workflow

-*todo* +For a saved file, follow the same sequence for every change: + +1. Run `inspect --json` and keep the returned heads. +2. Use `query --json` to read only the relevant records. +3. Build the smallest transaction that satisfies the request. +4. Run the mutation with `--dry-run --json`. +5. Apply it only after the dry run passes. +6. Validate the document and render the affected page, role, or selection. + +Prefer semantic roles, names, and tags over coordinates when they identify one record. If a selector +matches multiple shapes, narrow it with an exact ID. Do not guess which one the human meant.

Proposals

-*todo* +For a document open in the desktop app, use `app propose` instead of changing its file. The app +shows created, changed, and deleted records as a ghost preview. The human can accept all operations, +accept selected operations, or reject the proposal. + +Partial acceptance creates a transaction from the approved operations and validates it again. A +stale proposal may need a refreshed preview after another edit changes the document. Review the +refresh rather than accepting an outdated result.

Permissions

-*todo* +Locks and `agent_editable` metadata are document boundaries. An agent must not work around a locked +layer, locked shape, or record marked `agent_editable: false` by editing a child or bypassing the +CLI. Report the boundary and ask the human to make or authorize the change. + +Direct `app apply` requires a one-time token issued by the desktop UI. The token authorizes a single +live action; it is not a reusable credential and never belongs in a transaction file.

Conflicts

-*todo* +Document heads are preconditions. If a file mutation exits with code `5`, inspect the current heads, +query the affected records again, and rebuild the transaction from that state. Do not remove lock +files, copy an older document over the current file, or silently drop intervening edits. + +Record-version preconditions protect individual objects in the same way. A failed version check +means the object changed after the agent inspected it.

Skills

-*todo* +The repository includes an installable agent skill at `skills/inkfinite`. It documents the safe +workflow and includes runnable examples for file edits, proposal review, partial acceptance, and +stale-head recovery. + +After building the CLI, verify the examples from the repository root: + +```sh +INKFINITE_CLI="$PWD/target/debug/inkfinite" \ + bash skills/inkfinite/scripts/verify-examples.sh +``` + +The fixture server used by those examples tests the protocol. It does not replace a real desktop +session or authorize direct apply. diff --git a/apps/web/src/routes/docs/reference/cli/+page.svx b/apps/web/src/routes/docs/reference/cli/+page.svx --- a/apps/web/src/routes/docs/reference/cli/+page.svx +++ b/apps/web/src/routes/docs/reference/cli/+page.svx @@ -1,6 +1,6 @@ Command-line interface · Inkfinite documentation - + # Command-line interface @@ -9,16 +9,86 @@

Command overview

-*todo* +Run `inkfinite --help` or `inkfinite --help` for the complete option reference. The main +commands are: + +| Command | Purpose | +| --- | --- | +| `new` | Create a blank canonical document | +| `inspect` | Print a document summary or materialized snapshot | +| `query` | Find records by semantic, structural, kind, or bounds filters | +| `validate` | Load and validate a canonical document | +| `shape`, `connect`, `layout` | Build and apply structured transactions | +| `apply` | Validate and apply a transaction draft from JSON | +| `render` | Write a deterministic SVG of a document or filtered view | +| `app` | Inspect or work with a running desktop session | +| `schema`, `capabilities` | Print machine-readable contracts for integrations | + +During development, build the binary with: + +```sh +cargo build -p inkfinite-cli --bin inkfinite +```

File mode

-*todo* +File-mode commands operate on a closed `.inkfinite` file. Start by inspecting its heads and querying +only the records you need: + +```sh +inkfinite inspect architecture.inkfinite --json +inkfinite query architecture.inkfinite --role architecture.service --json +``` + +Prefer `shape create`, `shape patch`, `shape delete`, `connect`, and `layout` when one of them +expresses the edit. Use `apply` for a transaction with operations that the structured commands do +not cover. Test mutations with `--dry-run` before saving: + +```sh +inkfinite shape patch architecture.inkfinite \ + --role architecture.service \ + --patch '@service-patch.json' \ + --dry-run --json + +inkfinite apply architecture.inkfinite \ + --transaction transaction.json \ + --dry-run --json +``` + +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.

Live mode

-*todo* +With the desktop app running, use `app status`, `app inspect`, and `app query` for read-only access. +`app propose` sends a transaction to the canvas as a reviewable ghost preview: -

Output Format

+```sh +inkfinite app status --json +inkfinite app query --role architecture.service --json +inkfinite app propose --transaction transaction.json --json +``` -*todo* +The human can accept the whole proposal or selected operations, or reject it without changing the +document. `app apply` bypasses proposal review only when the desktop UI has issued a one-time +authorization token for that action. Do not store that token in a document or script. + +

Output format

+ +Pass `--json` for deterministic machine-readable output. Successful mutations report the previous +and current heads, transaction ID, created, updated, and deleted records, repairs, and warnings. +Diagnostics go to standard error so standard output remains safe to pipe into another program. + +`capabilities --json` reports supported commands and stable exit codes. Current exit codes are: + +| Code | Meaning | +| ---: | --- | +| `0` | Success | +| `2` | Invalid command usage | +| `3` | File or input error | +| `4` | Invalid document or data | +| `5` | Existing file, lock, or state conflict | + +Use `schema document`, `schema transaction`, and `schema protocol` instead of inferring JSON shapes +from examples. Global `--json` and `--non-interactive` options may appear before or after a +subcommand. -- tangled.sh