Dents whose boundary turns backward by no more than the angle are
flattened by the hull; deeper dents keep their original boundary. At the
maximum of 360 degrees the node produces the fully convex hull as before,
and at 0 degrees every dent survives. Bridges between separate subpaths
always apply, so disjoint islands stay connected and interior geometry
(such as holes) never survives at any setting.
The partial hull reuses the convex pipeline, keeping collinear hull
vertices so pockets (the boundary stretch each bridge spans, located by
gap matching along the subpath) can attach to them. Each pocket is
processed by a canonical deletion sweep that repeatedly removes the
cheapest reflex sample vertex whose bypassing chord stays on the empty
side of the boundary and within the angle budget, which handles nested
dents inherently and can never cut into material bumps. Surviving chords
are polished to exact tangencies with the same closed-form solves used
for hull bridges, and kept stretches are emitted as exact cuts of the
original segments.
Replaces the WIP node crate, which depended on a convex_hull crate that
only existed outside the repository, with a self-contained implementation:
- The curved hull algorithm lives in vector-types' algorithms module. It
splits curves at inflections and cusps into curvature-monotone arcs,
discovers the boundary structure from a sampled polygonal hull, refines
every transition to an exact tangency with closed-form quartic
tangent-through-point solves, then emits the boundary as cuts of the
original segments joined by straight bridge lines.
- The node moves into vector-nodes alongside the other 'Vector: Modifier'
nodes, ported to the List/attributes model. It accepts Graphic[] or
Vector[], wraps every subpath (open or closed) and free-floating anchor
point across all items, and outputs a single world-space hull path.
- The boolean-union pre-pass is dropped as unnecessary: the hull of all
segments equals the hull of their union, and the polyline connector it
relied on lost floating points and mishandled open paths.
* Allow using any graphics type for fill
* Adapt gradient/fill property panels and tools to handle List<T>
* Make the initial gradient transform covers the target's bounding box
* Introduce AnyGraphicListDyn to avoid combinatorial explosion
* Allow using any graphics type for stroke paint
* Add FIll node migration
* Add `for_each_vector_list_mut` instead of `set_paint_attribute`
* Adapt paint flow to read and write attributes instead of legacy Fill/Stroke.color
* Fix responsibilities of paint related node input setters
* Fix Morph by storing List<Graphic> for attributes rather than the concrete types
Store fill/stroke paints as List<Graphic> so Color/Gradient transitions
do not hit set_attribute_value_dyn's type-mismatch fallback to default paint.
* Preserve paint attributes in vector editing ops
* Enhance the clarity between direct and chained fill gradients
* Update demo arts
* Consolidate Fill node gradient appearance inputs
* Fix after the cubic review
* Revert "Consolidate Fill node gradient appearance inputs"
This reverts commit 9622feb20196e2c4da99e98ca95dcc2e34c2c98e.
* Replace AnyGraphicListDyn with generic paint connectors on the Fill and Stroke nodes
* Canonicalize paint attribute storage to List<Graphic> with a single write helper
* Fix Solidify Stroke missing fills stored in the legacy style
* Fix Solidify Stroke producing invisible strokes for legacy-only stroke colors
* Fix the initial gradient transform ignoring the bounding box's vertical extent
* Step paint at the morph midpoint instead of dropping it for unmixable pairings
* Remove migration-stage comments
* Clarify the initial gradient transform helper's doc and name
* Correct the bake_paint_transforms doc and prune dead tolerance arms
* Delete the unused Gradient::lerp
* Fix a comment typo
* Thread network paths through the legacy gradient bake so nested fills migrate
* Restore the legacy fill fallback in Expand Fill and Stroke
* Read gradient stops from the node's own input in the Fill properties panel
* Use the transform input constant instead of a hardcoded index
* Remove the unreachable wired color fallback in the Fill properties solid branch
* Narrow the fill overlay redraw check to actual fill inputs
* Coalesce the fill setter's graph runs into a single dispatch
* Position the Gradient Value node inserted for gradient stops
* Bake backup gradient placement during migration
* Persist pending gradient bakes so unfinished migrations retry on reopen
* Migrate the backup gradient's type and spread method
* Harden the gradient-migration pass against document switches and stale bakes
* Keep the Fill properties UI for layerless and nested Fill nodes
* Leave a wired gradient transform input connected instead of overwriting it
* Refuse to start a gradient chain ahead of existing layer content
* Decode a Fill node's gradient through one shared reader
* Nudge a degenerate bounding box so the Fill gradient transform stays invertible
* Broadcast Fill and Stroke paint with a single attribute-column pass
* Fix Morph stepping the target's stroke in near the source instead of the target
* Tidy conventions: clippy get_first, comment periods, sentence-case test messages
* Reattach the gradient orientation doc to its function
* Re-save demo artwork
---------
Co-authored-by: Keavon Chambers <keavon@keavon.com>
* Revamp the syntax to #[hard(a..b)] and #[soft(a..b)] bounds on node definitions
* Address review feedback: error on empty bounds ranges and remove redundant count clamps
* Fix NaN transform from Repeat Array with a count of 1
* Remove redundant manual clamps already enforced by #[hard(...)] bounds
* feat: Render List<String> as raw paths in SVG and Vell mode
* chore: code review
* chore: change the hardcoded layout bounds to parley's
* chore: code review
* feat: Split text node to text_layer and text_to_vector node
* fix: CI fail because of difference in nature of Mac and github action
* chore: fix
* chore: replace FontStack as it got removed in parley 0.9
* chore: fmt
* chore: migrate the rendering as of new resource architechture
* chore: add text_layer node to text tool for testing
* code review
* Make boolean ops support the Text type
* chore: Move fallback_font_resource authority from editor to text node
* Fix 'Text Layer' node missing font dropdown
* Change node doc comments from Vec<T> to T[]
* Add migrations from the old Text node to Text -> Text to Vector
* Consolidate
* Rename the text attributes and reorder tilt to come before max_width/height
* Detect legacy Text nodes in the split migration by their trailing separate_glyphs input
* Code review
* Frame Text layer thumbnails by laying out their text for bounds
* Give Text layers click targets and selection outlines via collect_metadata
* Route Text tool through Text to Vector with fill, fixing editing-preview placement
---------
Co-authored-by: Keavon Chambers <keavon@keavon.com>
* Replace the 'Vec2 to Point' node with an 'As Vector' node and automatic conversion
* Accept a Vec2 as content for the Wrap Graphic node
* Rename the type-assertion nodes from 'To' to 'As'
* Fix the Transform node reversing a Vec2 input's direction
* Fix text migration bug
* Add conversion from Fill to Table<Graphic>
* Refactor Vector vello renderer for Gradient / Color
* Refactor Vector SVG renderer for Gradient / Color
* Fix conflicts
* Add basic clipping-based fill for SVG rendering
* Use Cow to avoid cloning graphic list for fill
* Cleanup for Cow usage
* format code
* Use `<pattern>` instead of `<clipPath>` for clip
This simplifies the future implementation of clipping-based rendering
for strokes, as the stroke does not support the use of a clip path but
rather paint sources from a paint server.
* Move svg pattern rendering function to RenderExt
* Fix comment
* Fix empty fill list rendering as default black
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* Move opaque check function to Graphic impl
* Add color converter and debug node to use graphic
* WIP: Use List<Graphic> to render Color & Gradient
* Use `Arc<List<Vector>>` for vector_data metadata
This exposes List's attributes to message handlers, enabling them to
access the necessary attribute data such as ATTR_STROKE_PAINT_GRAPHIC
as `Fill` and `Stroke` will not have paint information in the future.
* Recurse opacity checks on nested `Graphic`
Also extracts `fill_graphic_list_at` /
`stroke_paint_graphic_list_at` to share the row-attribute
lookup across the existing call sites.
* Fix fill and stroke visibility check degradation
* Fix clipping based stroke paint positioning
* Refactor vello renderer for stroke to use graphic
* Reduce `Fill` / `Stroke.color` to `List<Graphic>` allocations
* Revert "Use `Arc<List<Vector>>` for vector_data metadata"
This reverts commit 4285243a5d
* Expose paint row attributes as dedicated metadata for vectors
Add `fill_attributes` / `stroke_paint_attributes` to `DocumentMetadata`
so the `ExpandFillStrokeOnSelectedLayers` handler can read row paint
visibility without exposing entire `List<Vector>`.
* Fix transparency check to consider fill opacity
* Fix consistency of gradient placement for SVG stroke
* Rename `stroke_paint_..` to `stroke_..`
* Remove debug nodes
* Allow to use any graphic type without casting
* Rename `fill_graphic` / `stroke_graphic` to `fill` / `stroke`
* Fix SVG pattern placement when stroke transform differs from item transform
* Fix click target fill check for empty list in graphic
* Fix blank fill/stroke attribute masking legacy style
* Fix SVG's paint order trick for vector/raster fills
* Add zero-division guard for pattern wraparound prevention
* Code review
---------
Co-authored-by: Keavon Chambers <keavon@keavon.com>
* Stop pushing duplicate layer entries when re-clicking an already-selected layer
* Make Text node generate per-glyph bounding box click targets
* Show source-geometry outlines and aggregate all rows for layer click targets
* Strip 'editor:click_target' override on Path node so direct edits restore precise hit testing
* Fix inverting a zero-determinate transform
* Rename "editor:layer" to "editor:layer_path" and centralize it in a const
* Centralize "editor:merged_layers" in a const
* Centralize all other attributes in consts
* Rename consts with ATTR_ prefix
* Format
* Improve the Data panel with more type-specific detail pages
* Add network_path to SetDisplayName so renames target any network depth
* Track nested layers via full editor:layer paths and rename parent_layer to path_of_subgraph
* Polish the data panel NodeId leaf page with an editable name field
* Make lock and visibility toggles work for layers in nested subgraphs
* Fix formatting
* Fix connected_to_output running in the wrong network for nested-layer toggles
* Move Vec<String> to Table<String>
* Remove old VecDVec2
* Move Vec<u8> to Table<u8>
* Move Vec<f64> to Table<f64>
* Move [f64; 4] to Table<f64>
* Move Vec<NodeId> to Table<NodeId>
* Tidy up the TaggedValue variants
* Move Vec<BrushStroke> to Table<BrushStroke>
* Add missing type implementations
* Fix tests
---------
* Fix click target propagation with the Rasterize node
* Add the 'Write Attribute' node
* Remove tag_layer in favor of the new Write Attribute node, prune redundant attribute writes
* Replace the Vector<Upstream> type argument with the "editor:merged_layers" attribute
* Feature-gate serde derives behind cfg_attr in all runtime node graph type crates
* Refactor Table to move its hard-coded fields into an attributes field
* Encapsulate TableRow/TableRowRef/TableRowMut attribute fields behind accessor methods
* Remove TaggedValue::GraphicUnused
* Refactor Table<T> to use dynamic attributes instead fixed names
* Fix code review soundness concerns
* Add todo work
* Replace row-oriented Table<T> API with column-oriented access
* Fix attribute propagation bugs
---------
* Fix Morph node transform interpolation and preservation in the table
* Fix click target positions for Morph's nested layers by pre-compensating upstream_data transforms
* Redesign Morph node (v3) with control path input and uniformly spaced progression, and fix Stroke::lerp interpolation weights
* Add migration from Morph node v2 to v3
* Redesign the 'Blend Shapes' node behavior and subgraph definition
* Add the Layer > Blend menu entry to easily set up a blend
* Optimize the Morph node
* Refactor the Morph node to remove the roundtrip through BezPath
* Fine-tune Morph node Bezier order promotion and handle interpolation
* Add the Layer > Morph menu bar entry
* Fix NaN and guard against other potential NaN bugs breaking the editor
* Add InterpolationDistribution parameter to Morph with weighted progression, swap parameter orders, and rename shear to skew
* Add the Reverse parameter to the Morph node
* Update the order of the inputs to Blend Shapes for consistency with Morph
* Make Layer > Morph create the Morph Path control layer
* Fix migrations
* Move 10 to a constant
* Avoid division by 0 in the Blend Shapes node internals
* Rename nodes 'Blend' -> 'Mix' and 'Blend Shapes' to 'Blend'
* Fix a crash encountered while testing
* Final code review
* Make domain push dupe checks debug-only and use push_unchecked in the Morph node
* Pre-allocate for pushes to the vector domains
* Add fast path at t=0
* Inline reserve()
* Set up the control path layer above not below, and starting collapsed
* Review fixes
---------
Co-authored-by: Timon <me@timon.zip>
* Fix NaN points produced by Sample Polylines on 0-scaled input
* Fix Jitter Points inverse transform for zero-scale axes and stop resetting stroke transform
* Remove a couple confusing Debug nodes
* Fix edge case
* Update demo art
* Fix order change in Jitter Points causing different results from earlier
* Fix bug in bisect tool
* Break out functionality into helper functions
* Refactor transform decomposition API with skew support, add Decompose Skew node, and fix stroke transform interpolation
* Fix bug in master with skew changing Area node calculated value
* Code review simplification
* More code review fixes
* Rename cases where "shear" terminology was used in place of "skew"
* New node: Decimate
* Use preallocated stack to reduce number of allocations and fix double endpoints on closed paths
* Use Kurbo implementation of path-to-polyline sampling
* Add the 'Simplify' node
* Migrate Specta to Tsify to auto-generate messages.ts, working except colors and widgets
* Adopt the generated FillColor/Color/GradientStops
* Fix widget typing
* Separate WidgetGroup enum variants into wrapper structs
* Small rename
* Simplify widgets further
* Clean up message type references
* Switch type imports to the auto-generated file
* Remove lowercase serde rename
* Fix FillChoice deserialization
* Fix small regression from #3837
* Improve type safety
* Make WidgetSpan type-safe
* More cleanup and type safety
* More type safety
* More type safety
* Get the rest to type-check without errors; improve widget builder macro to have optional icons; improve Svelte 5 configs
* Cargo fmt
* Fix imports
* Update outdated readme info
* Fix lint command rename references
* Fix typos
* One more typos fix
* Remove unnecessary dep: prefix from the edited Cargo.toml files
* Remove excess parts from Cargo.toml
* Fix compiling on desktop
* Revert "Remove excess parts from Cargo.toml"
This reverts commit 6b711117b3a5d5d8a3ee20f36a43bc74930b7c82.
* Update dev docs with simpler, more accurate instructions