Commit Graph
80 Commits
Author SHA1 Message Date
Keavon Chambers 1c88592fa4 Fix clipping masks, click targets, and bounds when rendering Vector[] and flattened graphic wrappers (#4429)
* Honor clipping masks when rendering Vector[] lists, not just Graphic[] groups

* Keep per-layer click targets when a Vector[] round-trips through a Graphic[] wrapper

* Skip the rebuild and the merged-layers snapshot when flattening a lone anonymous graphic wrapper

* Fix a group's bounds excluding its raster children and stretching to the origin

* Fix SVG clipping masks landing in the wrong space when sibling layers differ in transform
2026-09-15 14:40:35 +02:00
Keavon Chambers 29540adc8f New node: 'Gradient to Colors' for unwrapping a gradient ramp into its colors (#4425)
* New node: 'Gradient to Colors' for unwrapping a gradient ramp into its colors

* Update 'Gradient Midpoints' wording
2026-09-15 14:40:23 +02:00
Keavon Chambers be42a0aada Add the "Perceptual" and "Classic" families of gradient spaces with OkLab as the new default (#4415)
* Add an OkLab gradient interpolation space and make it the new default

* Fix the Properties panel fill row resetting the gradient interpolation space to the default

* Add OkLch, Lab, LCh, and HSL gradient interpolation spaces

* Add a hue direction attribute and picker choice for polar gradient interpolation spaces

* Add an HSV gradient interpolation space

* Rename the sRGB Linear and sRGB Gamma gradient spaces to RGB Linear and RGB Gamma

* Divide the gradient interpolation dropdown between absolute and relative color spaces

* Rename the OkLch gradient interpolation space to OkLCh for channel-notation capitalization

* Shorten the color picker popover's hue direction row label to Arc

* Call the Gradient Interpolation node's parameter Space and extend the picker tooltip title to match

* Rename the gradient interpolation attribute and type family to gradient space

* Rename the gradient tool's gradient space transform to gradient to viewport transform

* Add serde aliases and a node replacement covering the gradient space renames

* Give the gradient space choices artist-facing labels and reorder the dropdown sections

* Add a Gradient Hue Direction node and its attribute read node

* Say interpolate instead of blend for gradient stop color traversal in docs and tooltips

* Label the polar perceptual gradient spaces as Perceptual Hue and group the dropdown sections by geometry

* Add a migration alias covering the gradient space attribute reader rename

* Carry the gradient hue direction attribute through boolean operations

* Register GradientHueDirection wire types in the node registry
2026-09-15 14:39:44 +02:00
Keavon Chambers b9a8065eb8 Rename gradient type to gradient form (#4405)
* Rename gradient type to gradient form

* Update the demo art for the gradient form rename

* Say form not type in the Gradient Form node's doc comment
2026-09-15 14:39:04 +02:00
Keavon Chambers d5e31c23bb Rename spread method to gradient spread so it matches the other gradient attribute names (#4404)
* Rename spread method to gradient spread so it matches the other gradient attribute names

* Keep the legacy gradient struct's spread method field name matching its on-disk key
2026-09-15 14:38:59 +02:00
Keavon Chambers 8d4f1346a1 Move the gradient-focused nodes from the Color category to a new Gradient category (#4403) 2026-09-15 14:38:53 +02:00
Keavon Chambers f6b4ce71e6 Rework Gradient into a newtype of List<Color> with optional position and midpoint attributes (#4397)
* Rework Gradient into a newtype of List<Color> with optional position and midpoint attributes

* Fix Vello stopless-gradient fallback coverage, empty legacy gradient tables, the node docs gradient swatch, NaN position elision, and wired setter input overwrites
2026-09-15 14:38:29 +02:00
Keavon Chambers 4f49c000e8 Rename the nodes 'Length' -> 'Magnitude', 'Flatten Path' -> 'Combine Paths', 'Vec2 Value' -> 'Combine Vec2', and add a new 'Vec2 Value' node (#4349)
* Rename the node 'Length' -> 'Magnitude'

* Rename the node 'Flatten Path' -> 'Combine Paths'

* Replace the node 'Vec2 Value' with 'Combine Vec2' and add a new 'Vec2 Value' that's actually a vec2

* Update demo artwork
2026-09-15 14:35:48 +02:00
Keavon ChambersandDennis Kobert 20eb5ccb8a New nodes: Sum, Average, Minimum, Maximum, Any, All (#4344)
Co-authored-by: Dennis Kobert <dennis@kobert.dev>
2026-09-15 14:35:27 +02:00
Keavon ChambersandDennis Kobert 04d6c0d5cf Convert the node catalog to rank-polymorphic kernels, materialize stored values as ranked wires, and display wire rank in the graph
Co-authored-by:    Dennis Kobert <dennis@kobert.dev>
2026-09-15 14:35:20 +02:00
Keavon Chambers 83cfd0225a Reshape the node catalog: rename the list access nodes, split Text to Vector, reinstate Upload Texture as a proto node, and delete the vestigial debug nodes 2026-09-15 14:35:15 +02:00
Keavon Chambers 9dd1e2bdf9 Rename GradientStops to Gradient and the legacy Gradient/Fill structs to LegacyGradient/LegacyFill 2026-09-15 14:34:59 +02:00
Dennis Kobert 149e1fc4e0 Carry eight dropped columns through flatten_graphic 2026-09-15 14:34:54 +02:00
Dennis Kobert d4dc2e9e6b Adopt map_element in the mirror kernels 2026-09-15 14:34:30 +02:00
Dennis Kobert c1704df0b3 Elide the arena lifetimes that the signatures do not need 2026-09-15 14:34:02 +02:00
Dennis KobertandClaude Fable 5 0a4288eca6 Read a named attribute at each value type it can hold
One read node per value type, mirroring master's read family. A name
means one value type, so there is no coercion between them: master's
number read silently widened integers, and these refuse instead, which
is the same rule the write side already enforces.

Each takes any record wire through the opaque reading input and serves
the name's own default where the attribute is absent, so the value
carries the declared type either way.

The gradient enums join the value-type rows now that a family exists to
read them at.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-09 12:36:00 +00:00
Dennis KobertandClaude Fable 5 5baeb8fd46 Accept any record wire on an input read only for its attributes
An element generic declared on a reading input, absent from the output
and from every other input, has nowhere to go and nothing to be: the
node reads its declared attributes and never the element. That is an
attr-to-element map, so it accepts any upstream record wire.

The blessing is inferred rather than marked, since the signature already
says it. The two substrate pieces were both in place: the element rides
as the byte-carried token, so the registry takes one generic row instead
of a row per element type, and the reads resolve against the input's own
layout as they always have. Only the passthrough rule stood in the way,
in the three places that enforced it.

A generic the output carries, or one on an input with no reads, is
unchanged and still owes an implementations list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-09 12:15:40 +00:00
Dennis KobertandClaude Fable 5 f04d439b33 Name the attribute read for the type it reads
The read is a number read, not a read of whatever the name holds: our
model has no coercion, so a name written at another value type is a graph
error rather than a conversion. The name says so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-09 11:35:38 +00:00
Dennis KobertandClaude Fable 5 5eb80721dd Resolve a named read's offset when the graph compiles
The fold already holds the name and the read input's finished layout, so
the offset falls out there rather than at construction: `RecordLayout`
carries the resolved numbers and `set_layout` copies them into the read
slots. Constructors are untouched, and census-marker reads keep their
current installation.

A read meets the value type the name was written at, so a disagreement
between a read here and a write upstream is the same graph error as two
writes disagreeing; the one-name-one-type check now spans reads and
writes together. An absent attribute stays absent and the read serves
the forced default rather than reporting it.

`read_attribute` is the catalog's get half, typed and never `Option` at
the kernel boundary, with the name declared exactly as the write side
declares it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-09 10:50:08 +00:00
Dennis KobertandClaude Fable 5 fc94487d0b Keep the name placeholder out of the kernel entirely
A name input declares where a placeholder's name is wired and nothing
more. The name is spent resolving the layout when the graph compiles, so
the kernel neither declares it nor is passed it; the return type's
`Named<X, V>` is the only tie between the write slot and the folded name.

The wire is untouched: the input keeps its declared position and crosses
as constant text, so a document's input order is unchanged. The
placeholder stays a concrete token, so it adds no generic for the node
to carry and none to go unconstrained.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-09 10:20:22 +00:00
Dennis KobertandClaude Fable 5 9b92edc0e9 Write an attribute under a name the graph supplies
`Named<X>` in parameter position declares where a placeholder's name is
wired, and the macro gives that input constant text; `Attr<Named<X, V>>`
in the return writes under it. The kernel is handed the bare placeholder,
since the name is spent resolving the layout and a folded offset is all
the write needs, so the hot path matches a marker node's exactly.

A name-generic write names its value type through the wired generic,
which only an implementations row resolves, so those nodes emit their
layout meta per row rather than sharing one across rows.

`write_attribute` is the catalog's set half, restoring the identifier
master's documents carry with its input positions. Its name input is a
constant, so those documents resolve without migration, and the reset
marker that stood in for the missing node retires with it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-09 09:26:17 +00:00
Dennis Kobert 9f0e0ebc96 Clear the remaining clippy warnings on the diff surface 2026-09-06 16:25:17 +00:00
Dennis Kobert fbdba0e545 Drop narration and internal asides from comments 2026-09-06 15:59:41 +00:00
Dennis Kobert 9d3abe385f Sweep the data-flow wire and edge wording to input and source 2026-09-06 15:14:55 +00:00
Dennis Kobert 38d479bdfa Key the paint list park sites so a group-free paint moves 2026-09-05 13:12:17 +00:00
Dennis Kobert 30573e6eb6 Condense the narrative comments to their constraints 2026-09-05 13:12:17 +00:00
Dennis Kobert a955d6b458 Run cargo fmt 2026-08-29 18:40:02 +00:00
Dennis Kobert e5b910f840 Adopt serving lifetimes and the safe record surfaces in the node crates 2026-08-28 13:30:06 +00:00
Dennis Kobert e8aea0728a Build native groups at the legacy conversion seams 2026-08-27 20:22:24 +00:00
Dennis Kobert 68a2fb2be3 Render root levels natively and remove the unconstructed stack form 2026-08-27 14:44:19 +00:00
Dennis Kobert eb11eec5bb Store paint attributes in the paint markers' owned optional form 2026-08-26 14:02:01 +00:00
Dennis Kobert ff99f3605c Drop unread index bounds from fold kernels and mark re-addressing nodes ModifyIndex 2026-08-25 11:05:38 +00:00
Dennis Kobert 9aef511891 Cargo fmt 2026-08-24 23:15:10 +02:00
Dennis Kobert 027218f16c Declare which index levels a node reads and nullify the rest 2026-08-24 17:06:07 +00:00
Dennis Kobert dcc9059041 Give To Graphic a unit row so an unconnected content input renders as nothing 2026-08-24 12:02:46 +00:00
Dennis Kobert d70eae205d Quiet the clippy type-complexity and closure lints on the record kernels 2026-08-24 11:07:14 +00:00
Dennis Kobert ed6922d7eb Read the layer path in its owned form and retarget the introspection tests 2026-08-24 10:26:24 +00:00
Dennis Kobert aba941e81d Collapse typed levels in To Graphic like the pre-flip list conversion 2026-08-24 01:35:32 +00:00
Dennis Kobert 8c67ad508f Restore pre-flip color parity: rng replay, typed wrap, boolean marker paints 2026-08-24 00:43:44 +00:00
Dennis Kobert c0eb2ee4ff Remove the runtime-named attribute family and its type-erased bridges 2026-08-23 19:05:26 +00:00
Dennis Kobert 3fb8b10f80 Cache materialized spans per context and size emitter extents from the subject query 2026-08-23 00:57:37 +00:00
Dennis Kobert c33f8ae75b Convert mirror to a fold emitter and bridge levels into the erased list 2026-08-22 22:15:03 +00:00
Dennis Kobert f2b0f7c533 Defer an empty side's inner extent in extend 2026-08-22 19:11:48 +00:00
Dennis Kobert 4bceae26f2 Add the leveled fill rows and the graphic coercion entries 2026-08-22 16:13:01 +00:00
Dennis Kobert fb71ea426d Bridge legacy seams and convert the transform family 2026-08-22 14:25:31 +00:00
Dennis Kobert 887dbaca2c Re-home the layer-path stamp and switch the node path to its plain value form 2026-08-22 12:35:48 +00:00
Dennis Kobert 56c772de4c Swap the map and index family nodes to their leveled forms in place 2026-08-22 12:27:53 +00:00
Dennis Kobert 93e34d00e5 Swap the graphic structural nodes to their leveled forms in place 2026-08-22 12:24:02 +00:00
Dennis Kobert e4adf16eba Move the paint and merged-layer markers to graphic-types as optional references 2026-08-22 10:23:02 +00:00
Dennis Kobert 81a319430b Cut over to the graphene execution model 2026-07-31 23:19:42 +02:00