From 14ac770b06071f6bf60e733a4e357fd650e3a478 Mon Sep 17 00:00:00 2001 From: Owais Jamil Date: Mon, 24 Aug 2026 22:48:50 -0500 Subject: [PATCH] chore: update changelog * improve illustrations --- CHANGELOG.md | 14 +- ROADMAP.md | 161 +++------------- TODO.md | 178 ------------------ .../tests/svg_import_fixtures.rs | 6 + .../tests/svg_import_fixtures.rs | 4 + fixtures/svg-import/README.md | 11 +- fixtures/svg-import/compound-paths/ring.svg | 4 +- .../gradients/gradient-inheritance.svg | 11 +- .../svg-import/illustrations/night-garden.svg | 16 ++ .../svg-import/unsupported/feature-matrix.svg | 27 ++- 10 files changed, 105 insertions(+), 327 deletions(-) create mode 100644 fixtures/svg-import/illustrations/night-garden.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index 33e7e26..db8be4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,14 @@ TypeScript contracts and a common editor projection. - Native shapes, paths, groups, frames, cards, images, layers, assets, semantic metadata, relationships, built-in stencils, and deterministic layout operations. -- Canvas editing with snapping, constraints, nested selection, path anchors and handles, connection - routing, duplicate-and-connect, typography controls, and a searchable command palette. -- Static SVG import and export with native geometry, hierarchy, transforms, compound fills, - embedded images, retained source assets, and warnings for omitted features. +- Canvas editing with snapping, constraints, nested selection, path anchors and handles, + duplicate-and-connect, typography controls, and a searchable command palette. +- Shared path metrics and straight, curved, and orthogonal connectors with tangent-aware + arrowheads, path-relative labels, hit testing, and deterministic export. +- Boolean paths, gradient paints, clips, masks, filters, variable-width strokes, and text on path, + with editor controls and SVG round-trip coverage. +- SVG import and export with editable native geometry, hierarchy, transforms, compound fills, + gradients, effects, text paths, embedded images, sanitized fallbacks, and deterministic workflows. - Excalidraw and Obsidian Canvas import and export, plus deterministic SVG and PNG rendering. - CLI workflows for inspection, queries, validation, structured mutations, dry runs, rendering, schemas, live desktop sessions, and machine-readable output. @@ -28,6 +32,8 @@ - Consolidated the web and desktop editors into shared UI, runtime, DOM input, renderer, and core packages. +- Unified creation styles across editor, CLI, MCP, stencils, and starter documents, with neutral + defaults resolved against light and dark canvases. - Moved canonical browser state and committed geometry operations to Rust while keeping interaction previews in TypeScript. - Unified SVG parsing, transactions, and rendering across desktop, web, CLI, and MCP. diff --git a/ROADMAP.md b/ROADMAP.md index 39529b7..c651bfc 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -10,150 +10,40 @@ primitives should support diagramming, sketching, spatial thinking, visual collection, and agent-assisted editing without separate internal systems for each workflow. -The roadmap prioritizes stronger primitives, interoperability, correctness, -editor usability, and performance before large libraries of templates or -format-specific content. +The roadmap prioritizes interoperability, editor usability, distribution, and +performance before large libraries of templates or format-specific content. -## Current: reliable core editor - -### Visual defaults and editor polish - -A new document should look intentional without requiring immediate styling. - -Centralize creation defaults shared by the editor primitives and remove -hard-coded styling from individual tools. Use restrained neutral styling for -ordinary geometry and reserve Inkfinite's accent for interaction, emphasis, -and relationships. - -The editor should have coherent defaults for shapes, frames, connectors, pen -strokes, text, Markdown, and cards across light and dark appearances. Visual -regression fixtures should make accidental changes to those defaults visible. - -### Connector geometry - -Treat arrows as semantic relationships whose resolved visual geometry uses the -same native path representation as other Inkfinite vectors. - -Straight, curved, and orthogonal routing should resolve bindings, waypoints, -and routing parameters into ordinary path geometry. Rendering, SVG export, -bounds, hit testing, labels, and arrowheads should consume that resolved path -rather than maintaining separate connector approximations. - -Curved arrows should retain compact editable routing state such as bend and -waypoint information rather than persisting sampled polylines. Arrowheads -should follow the tangent of the resolved path, and labels should be positioned -by distance and normal offset along it. - -Shared path metrics should provide length, point and tangent at distance, -nearest-point queries, flattening, and trimming. Keep the canonical geometry -implementation in Rust and expose it through the existing editor bindings so -interactive rendering and headless export cannot diverge. - -This path-aware connector work should also provide the geometry foundation for -text on path and other future features that attach content or markers to vector -paths. - -### SVG round-trip - -Inkfinite has one validated Rust SVG pipeline across desktop, web, CLI, and -MCP. It maps supported geometry and embedded images into native shapes, -preserves hierarchy, transforms, and compound fills, retains source assets, -and reports unsupported content. - -Imported descendants are ordinary document records available to editor, CLI, -and MCP operations. Native and fallback fixtures cover save/reopen, -edit/export, undo/redo, CRDT merge, active-document import, and explicit -creation of a new document from SVG. - -Interchange uses deterministic native representation where Inkfinite -understands the content and sanitized static fallback content where it does -not. - -See [SVG import](apps/web/src/content/docs/development/svg-import.md) and -[native path geometry](apps/web/src/content/docs/development/native-path-geometry.md). - -### Richer interoperability +## Current: richer interoperability JSON Canvas support should continue to map external data onto ordinary -Inkfinite objects, relationships, frames, cards, and assets rather than -creating a parallel document system. +Inkfinite objects, relationships, frames, cards, and assets. Mixed-document +fixtures should exercise native geometry, imported SVG, raster assets, links, +cards, frames, and relationships together. -Mixed-document fixtures should exercise native geometry, imported SVG, raster -assets, links, cards, frames, and relationships together. - -Mermaid and D2 are candidates for structured import only if their graphs map -cleanly onto Inkfinite's native objects and relationships. Avoid a separate -format-specific rendering architecture. - -## Next: stronger vector primitives - -Once native SVG round-trip and ordinary editing workflows are dependable, -expand the vector model itself. - -### Boolean geometry - -Union, intersection, difference, and exclusion operate on selected native paths -as one undoable editor command. Rust resolves transformed path geometry through -one boolean pipeline, stores the result as ordinary native line segments, and -keeps the first path's transform, paint, metadata, and fill rule. Generated -geometry survives SVG export and import. - -### Rich paint - -Linear and radial gradients extend flat colors. Gradient stops, opacity, -coordinate units, transforms, and spread behavior live in the canonical -document representation and work through rendering, serialization, SVG -interoperability, editing, CLI inspection, and export. - -### Clipping, masks, and effects - -Inkfinite supports editable path clipping, alpha and luminance masks composed -from path subpaths, and an initial SVG filter subset: blur, colour adjustments, -opacity, and drop shadows. The editor, canvas renderer, deterministic SVG -exporter, and canonical document projection use the same effect properties. -Unsupported SVG effect primitives remain available as sanitized static fallback -content rather than being discarded. - -### Expressive strokes - -Freehand strokes store optional hardware pressure samples and editable width -profiles along normalized path distance. Direct selection exposes width handles -separately from the sampled path points, while outline rendering uses document -units so zoom changes do not change the result. SVG export writes the rendered -outline as a filled path when a variable profile is present. - -### Text on path - -Text shapes can reference native path shapes without copying their geometry. -The attachment stores a local distance, alignment, side, and forward or reverse -direction, then uses the shared path metrics for glyph placement, bounds, hit -testing, and offset handles. Editing the path updates the attached text while -preserving the text record; the selection controls can attach, detach, and -change its layout settings. - -The SVG pipeline imports `textPath` references, including paths declared in -`defs`, and exports native references with the supported alignment, side, -offset, and reversal settings. +Mermaid and D2 are candidates for structured import where their graphs map +cleanly onto Inkfinite's native objects and relationships. Imported nodes, +edges, labels, groups, and supported styles should remain editable and use the +shared graph-layout pipeline. Unsupported constructs need clear warnings and a +predictable fallback rather than a separate format-specific renderer. ## Next: web installation and export workflows ### Clipboard interoperability -Treat the clipboard as another interchange surface. - -Selections and documents should be copyable as canonical SVG markup. Raster -exports should be copyable as PNG when platform clipboard APIs permit it, with -predictable browser fallbacks. +Treat the clipboard as another interchange surface. Selections and documents +should be copyable as canonical SVG markup. Raster exports should be copyable +as PNG when platform clipboard APIs permit it, with predictable browser +fallbacks. ### PWA and offline operation Make the existing local-first web editor installable rather than creating a separate offline product. -The PWA should cache the application shell, WASM runtime, and required static -assets while continuing to use Inkfinite's normal local document repository. -Creating, editing, reopening, and exporting local documents should continue to -work without a network connection. +The PWA should cache the application shell, WebAssembly runtime, and required +static assets while continuing to use Inkfinite's normal local document +repository. Creating, editing, reopening, and exporting local documents should +continue to work without a network connection. Application updates must be explicit enough that cached application code does not become an invisible second deployment state. @@ -168,19 +58,18 @@ platform matrix, and CLI/MCP binary distribution. Keep a documented manual release checklist and small reproducible build scripts. GitHub Releases should eventually contain desktop, CLI, and MCP artifacts with -checksums. Publish the intended Rust packages to crates.io. - -Automation can be introduced where manual repetition becomes expensive; it is -not a prerequisite for the first useful release candidate. +checksums. Publish the intended Rust packages to crates.io. Add automation where +manual repetition becomes expensive rather than making it a prerequisite for +the first useful release candidate. ## Later: reusable content ### User libraries Built-in stencils already demonstrate reusable ordinary Inkfinite objects. -Later library work should let users save, find, insert, update, and remove -their own selections while retaining nested content, assets, relationships, -and semantics. +Later library work should let users save, find, insert, update, and remove their +own selections while retaining nested content, assets, relationships, and +semantics. Libraries remain ordinary document fragments validated by the shared native document APIs. diff --git a/TODO.md b/TODO.md index 8b5d917..42df817 100644 --- a/TODO.md +++ b/TODO.md @@ -1,48 +1,5 @@ # Inkfinite TODO -## Editor defaults - -Make newly created content look deliberate before the user changes any styling. - -- [x] Move creation-time visual defaults into a shared style policy instead of - hard-coding colors independently in editor tools and UI controls -- [x] Define defaults for rectangles, ellipses, frames, lines, arrows, pen - strokes, text, Markdown, and cards -- [x] Use neutral shape styling by default and reserve the Inkfinite accent for - selection, arrows, emphasis, and interactive state -- [x] Increase the default rectangle corner radius and define distinct frame - styling so frames do not look like ordinary shapes -- [x] Remove light-canvas assumptions from text and Markdown defaults -- [x] Resolve automatic creation colors against the document/page canvas at creation time - and persist the resulting explicit colors; keep application theme colors out of - canonical document rendering -- [x] Ensure creation through the editor, CLI, MCP, stencils, and starter - documents uses the same default style policy where appropriate -- [x] Add light- and dark-canvas visual fixtures covering every built-in - primitive -- [x] Add screenshot regression coverage for a representative mixed document - -## SVG round-trip - -Run representative native and fallback SVG fixtures through each complete -document workflow. Compare normalized structure where representation matters -and rendered output where visual fidelity matters. - -- [x] Offer creation of a new document from SVG as a separate editor action -- [x] Verify and fix TypeScript editor traversal of imported root containers so - existing child records can be selected, edited, reparented, and deleted - independently -- [x] Test import through save/reopen, edit/export, undo/redo, and CRDT merge -- [x] Test active-document import and explicit new-document creation end to end -- [x] Test imported child shapes through editor selection and targeted CLI - query and mutation -- [x] Verify native vectors export without rasterization -- [x] Verify nested transforms export deterministically -- [x] Verify compound fill rules survive import and export -- [x] Add sanitized static fallback content for unsupported visuals and verify - that it remains visually stable -- [x] Add deterministic round-trip fixtures for these workflows - ## Richer interoperability and embeds - [ ] Extend the existing TypeScript JSON Canvas round-trip for new card, @@ -61,136 +18,6 @@ and rendered output where visual fidelity matters. - [ ] Add end-to-end import, edit, and export comparisons for representative mixed-format documents -## Connector geometry - -Make arrows semantic connectors backed by the same geometry operations used -for native paths. Avoid separate approximations for rendering, export, -selection, labels, and arrowheads. - -### Shared resolved geometry - -- [x] Define a resolved arrow geometry representation backed by native - `PathGeometry` -- [x] Resolve bound endpoints, explicit waypoints, and routing configuration - before rendering or interaction code consumes the arrow -- [x] Make straight arrows resolve to ordinary line path segments without - changing existing document behavior -- [x] Move canonical arrow geometry resolution into Rust and expose it through - the existing editor/WASM bindings -- [x] Use the same resolved geometry for interactive rendering and headless SVG - export -- [x] Replace arrow bounds derived only from stored points with bounds from the - resolved path, including Bézier extrema -- [x] Add deterministic fixtures comparing interactive and exported geometry - for free, bound, transformed, and multi-point arrows - -### Path metrics - -- [x] Add shared path flattening with a geometric tolerance rather than fixed - samples per curve -- [x] Add path length and point-at-distance queries -- [x] Add tangent-at-distance queries for line, quadratic, and cubic segments -- [x] Add nearest-point and distance-along-path queries for hit testing and - snapping -- [x] Add path trimming by start and end distance -- [x] Reuse the shared path metrics for native path and arrow hit testing - instead of maintaining separate curve-sampling implementations -- [x] Add deterministic tests for lines, quadratic curves, cubic curves, - transformed paths, and degenerate segments - -### Curved arrows - -- [x] Add persistent curved-arrow bend state without storing sampled curve - points -- [x] Resolve two-point curved arrows to native quadratic Bézier geometry -- [x] Add a direct-manipulation bend handle with a well-defined straight-arrow - zero state -- [x] Preserve bound endpoints while the bend handle is edited -- [x] Define multi-point curved-arrow behavior as rounded waypoint routes - rather than an unconstrained spline -- [x] Render native quadratic and cubic path segments directly instead of - drawing sampled curves with `lineTo` -- [x] Add undo/redo and save/reopen coverage for curved-arrow edits -- [x] Add visual fixtures for positive, negative, zero, short, long, bound, and - multi-point curves - -### Path-aware arrowheads and labels - -- [x] Orient start and end arrowheads from the tangent of the resolved path - rather than the first or last sampled line segment -- [x] Define arrowhead geometry independently from shaft geometry so additional - head styles can be added without changing routing -- [x] Trim the visible shaft where required so filled arrowheads do not overlap - the path beneath them -- [x] Position arrow labels by distance along the resolved path -- [x] Apply label offset along the local path normal rather than a global axis -- [x] Keep label placement stable when bindings, bend, or orthogonal routing - change -- [x] Add hit-test and visual coverage for arrowheads and labels on straight, - curved, and orthogonal routes - -## Advanced vector editing - -### Boolean paths - -- [x] Define union, intersection, difference, and exclusion operations over - Inkfinite's native path representation -- [x] Preserve transforms and fill rules when combining selected paths -- [x] Expose boolean operations through editor commands and selection controls -- [x] Make each boolean operation one undoable document transaction -- [x] Verify generated geometry through SVG import/export round trips -- [x] Add deterministic fixtures for overlapping, nested, compound, and - self-intersecting paths - -### Gradient fills and strokes - -- [x] Extend the paint representation beyond flat colors with linear and radial - gradients -- [x] Represent gradient stops, positions, transforms, spread behavior, and - opacity in canonical document data -- [x] Render gradients consistently in the interactive renderer and exports -- [x] Import and export supported SVG gradients without flattening them -- [x] Add gradient controls for stop creation, deletion, position, color, and - opacity -- [x] Add fixtures covering transformed gradients and gradient inheritance - -### Clips, masks, and filters - -- [x] Define which SVG clip, mask, and filter constructs Inkfinite can represent - natively -- [x] Preserve unsupported constructs as sanitized fallback content instead of - silently discarding them -- [x] Add native clip-path editing before exposing more general mask editing -- [x] Add basic mask composition once clip-path behavior is stable -- [x] Define the initial editable filter subset rather than attempting the full - SVG filter graph at once -- [x] Verify deterministic import, editing, save/reopen, and SVG export - -### Variable-width strokes - -- [x] Extend stroke data with a width or pressure profile along the path -- [x] Capture pointer pressure where available without making pressure input - mandatory -- [x] Add editing for width points independently of ordinary path nodes -- [x] Render width profiles consistently at different zoom levels -- [x] Define SVG export behavior, including conversion to outlined paths when - required -- [x] Add pen, edit, undo/redo, and export fixtures - -### Text on path - -Build text-on-path behavior on the shared path metrics introduced for -path-aware connectors rather than creating a second path-placement system. - -- [x] Define the relationship between a text object and its supporting path -- [x] Represent text position as an offset along the supporting path -- [x] Reuse shared path length, point, tangent, and normal queries for layout -- [x] Support direction, alignment, side, and path reversal -- [x] Keep the path independently editable without destroying attached text -- [x] Add direct manipulation for text offset along the path -- [x] Import and export representative SVG `textPath` content -- [x] Add undo/redo and round-trip fixtures - ## Clipboard and export workflows ### SVG as code @@ -227,9 +54,6 @@ path-aware connectors rather than creating a second path-placement system. ## Release and distribution -Keep releases understandable and reproducible before investing in extensive -automation. - - [ ] Decide which Rust crates are public API and which remain workspace-only - [ ] Define crates.io package metadata and publication order for publishable crates @@ -247,8 +71,6 @@ automation. ## Agent skills -Revisit skills after the CLI and MCP surfaces have stabilized. - - [ ] Inventory existing skills and the commands or workflows each depends on - [ ] Remove duplicated instructions that are better represented by CLI or MCP capabilities diff --git a/crates/inkfinite-core/tests/svg_import_fixtures.rs b/crates/inkfinite-core/tests/svg_import_fixtures.rs index 300a3fe..fd18332 100644 --- a/crates/inkfinite-core/tests/svg_import_fixtures.rs +++ b/crates/inkfinite-core/tests/svg_import_fixtures.rs @@ -44,6 +44,12 @@ const VALID_FIXTURES: &[(&str, &str, usize, usize)] = &[ 0, 1, ), + ( + "night garden illustration", + include_str!("../../../fixtures/svg-import/illustrations/night-garden.svg"), + 2, + 10, + ), ]; fn node_counts(group: &inkfinite_core::svg_import::SvgGroup) -> (usize, usize) { diff --git a/crates/inkfinite-wasm/tests/svg_import_fixtures.rs b/crates/inkfinite-wasm/tests/svg_import_fixtures.rs index 7845376..633905b 100644 --- a/crates/inkfinite-wasm/tests/svg_import_fixtures.rs +++ b/crates/inkfinite-wasm/tests/svg_import_fixtures.rs @@ -14,6 +14,10 @@ const FIXTURES: &[(&str, &str)] = &[ "compound path", include_str!("../../../fixtures/svg-import/compound-paths/ring.svg"), ), + ( + "night garden illustration", + include_str!("../../../fixtures/svg-import/illustrations/night-garden.svg"), + ), ( "unsupported features", include_str!("../../../fixtures/svg-import/unsupported/feature-matrix.svg"), diff --git a/fixtures/svg-import/README.md b/fixtures/svg-import/README.md index 753abed..fb32e39 100644 --- a/fixtures/svg-import/README.md +++ b/fixtures/svg-import/README.md @@ -7,9 +7,14 @@ - `nested-groups/` checks group-local transforms, inherited paint, and opacity. - `compound-paths/` checks repeated subpaths, elliptical arcs, and even-odd fill rules. -- `gradients/` checks transformed linear gradients, radial gradients, inherited - stops, spread behavior, and stop opacity. -- `unsupported/` checks warnings for omitted features and active content. +- `gradients/` uses a layered twilight landscape to check transformed linear + gradients, radial gradients, inherited stops, spread behavior, and stop + opacity in a complete composition. +- `illustrations/` combines ordinary geometry, curves, inherited group styles, + local transforms, and opacity in an asset that is useful beyond a single + syntax regression. +- `unsupported/` uses a presentable supported fallback while checking warnings + for omitted features and active content. - `malformed/` checks that invalid XML, numbers, paths, and transforms fail before a partial import is returned. diff --git a/fixtures/svg-import/compound-paths/ring.svg b/fixtures/svg-import/compound-paths/ring.svg index c0f821b..fd2af55 100644 --- a/fixtures/svg-import/compound-paths/ring.svg +++ b/fixtures/svg-import/compound-paths/ring.svg @@ -1 +1,3 @@ - + + + diff --git a/fixtures/svg-import/gradients/gradient-inheritance.svg b/fixtures/svg-import/gradients/gradient-inheritance.svg index 143b9eb..fe90fe3 100644 --- a/fixtures/svg-import/gradients/gradient-inheritance.svg +++ b/fixtures/svg-import/gradients/gradient-inheritance.svg @@ -1,4 +1,4 @@ - + @@ -6,11 +6,14 @@ - + - - + + + + + diff --git a/fixtures/svg-import/illustrations/night-garden.svg b/fixtures/svg-import/illustrations/night-garden.svg new file mode 100644 index 0000000..17040be --- /dev/null +++ b/fixtures/svg-import/illustrations/night-garden.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/fixtures/svg-import/unsupported/feature-matrix.svg b/fixtures/svg-import/unsupported/feature-matrix.svg index 2696ceb..9f3efbe 100644 --- a/fixtures/svg-import/unsupported/feature-matrix.svg +++ b/fixtures/svg-import/unsupported/feature-matrix.svg @@ -1 +1,26 @@ -Static import warning fixture
unsupported
+ + Static import warning fixture + + + + + + + + + + + + + + + + + + + + + +
unsupported
+ +
-- 2.51.2