Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
779246f
Add TaggedValue::TypeDefault to avoid baking placeholder Tables into …
Keavon May 7, 2026
a54de6a
Add TaggedValue::TypeDefault to avoid baking placeholder Tables into …
Keavon May 7, 2026
44c61c5
Migrate empty Vector/Raster/Graphic/Artboard placeholder values to Ty…
Keavon May 7, 2026
fd2cfe6
Re-save demo artwork
Keavon May 8, 2026
62ecdb4
Remove Graphic and Artboard placeholder containers from TaggedValue
Keavon May 8, 2026
7aa47c4
Remove Raster placeholder TaggedValue variant
Keavon May 8, 2026
aa07362
Simplify document migration
Keavon May 8, 2026
31325f9
Remove Vector placeholder TaggedValue variant
Keavon May 8, 2026
89751f6
Remove NodeIdTable from the TaggedValue
Keavon May 8, 2026
02f1c8b
Remove StringTable from the TaggedValue
Keavon May 8, 2026
f5d6070
Remove F64Table in place of F64Array in TaggedValue
Keavon May 8, 2026
394d7f9
Replace TaggedValue::Color(Table<Color>) with ::Color(Option<Color>)
Keavon May 8, 2026
8363c3b
Replace TaggedValue::GradientTable(Table<GradientStops>) with ::Gradi…
Keavon May 8, 2026
0d64937
Replace TaggedValue::BrushStrokeTable(Table<BrushStroke>) with ::Brus…
Keavon May 8, 2026
ff60a67
Make TaggedValue::DocumentNode runtime-only with TypeDefault placeholder
Keavon May 8, 2026
c8ea94a
Make TaggedValue::ContextFeatures runtime-only
Keavon May 8, 2026
b41d079
Remove Serialize/Deserialize from Table<T>
Keavon May 8, 2026
b33660c
Add a widget for TaggedValue::BrushStrokes to visualize strokes and s…
Keavon May 8, 2026
f759669
Define a reusable list of TaggedValue::TypeDefault types for its gene…
Keavon May 8, 2026
f94675e
Re-save demo artwork
Keavon May 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo-artwork/changing-seasons.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/isometric-fountain.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/marbled-mandelbrot.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/painted-dreams.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/parametric-dunescape.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/procedural-string-lights.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/red-dress.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/valley-of-spires.graphite

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::messages::tool::tool_messages::tool_prelude::Key;
use crate::messages::tool::utility_types::ToolType;
use crate::node_graph_executor::NodeGraphExecutor;
use glam::{DAffine2, DVec2};
use graph_craft::descriptor;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
use graphene_std::math::quad::Quad;
Expand Down Expand Up @@ -1760,12 +1761,7 @@ impl DocumentMessageHandler {
}

pub fn deserialize_document(serialized_content: &str) -> Result<Self, EditorError> {
// Walk the document JSON and rewrite any `TaggedValue` variants that have been removed since being released as `"None"` so the document still deserializes.
// `migrate_node` then drops the resulting orphan node inputs so the value never reaches graph execution.
let mut json_value: serde_json::Value = serde_json::from_str(serialized_content).map_err(|e| EditorError::DocumentDeserialization(e.to_string()))?;
graph_craft::document::value::TaggedValue::scrub_removed_variants_from_json(&mut json_value);

let document_message_handler = serde_json::from_value::<DocumentMessageHandler>(json_value.clone())
let document_message_handler = serde_json::from_str::<DocumentMessageHandler>(serialized_content)
.or_else(|e| {
log::warn!("Failed to directly load document with the following error: {e}. Trying old DocumentMessageHandler.");
// TODO: Eventually remove this document upgrade code
Expand Down Expand Up @@ -1804,7 +1800,7 @@ impl DocumentMessageHandler {
pub snapping_state: SnappingState,
}

serde_json::from_value::<OldDocumentMessageHandler>(json_value).map(|old_message_handler| DocumentMessageHandler {
serde_json::from_str::<OldDocumentMessageHandler>(serialized_content).map(|old_message_handler| DocumentMessageHandler {
network_interface: NodeNetworkInterface::from_old_network(old_message_handler.network),
collapsed: old_message_handler.collapsed,
commit_hash: old_message_handler.commit_hash,
Expand Down Expand Up @@ -3349,7 +3345,7 @@ impl DocumentMessageHandler {
/// Create a network interface with a single export
fn default_document_network_interface() -> NodeNetworkInterface {
let mut network_interface = NodeNetworkInterface::default();
network_interface.add_export(TaggedValue::Artboard(Default::default()), -1, "", &[]);
network_interface.add_export(TaggedValue::TypeDefault(descriptor!(graphene_std::table::Table<graphene_std::Artboard>)), -1, "", &[]);
network_interface
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ use crate::messages::portfolio::document::utility_types::nodes::CollapsedLayers;
use crate::messages::prelude::*;
use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode;
use glam::{DAffine2, DVec2, IVec2};
use graph_craft::document::value::TaggedValue;
use graph_craft::descriptor;
use graph_craft::document::{NodeId, NodeInput};
use graphene_std::Color;
use graphene_std::renderer::Quad;
use graphene_std::renderer::convert_usvg_path::convert_usvg_path;
use graphene_std::table::Table;
use graphene_std::text::{Font, TypesettingConfig};
use graphene_std::vector::style::{Fill, Gradient, GradientSpreadMethod, GradientStop, GradientStops, GradientType, PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
use graphene_std::{Artboard, Color};

#[derive(ExtractField)]
pub struct GraphOperationMessageContext<'a> {
Expand Down Expand Up @@ -170,15 +170,15 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
}

// Set the bottom input of the artboard back to artboard
let bottom_input = NodeInput::value(TaggedValue::Artboard(Table::new()), true);
let bottom_input = NodeInput::type_default(descriptor!(Table<Artboard>), true);
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 0), bottom_input, &[]);
} else {
// We have some non layers (e.g. just a rectangle node). We disconnect the bottom input and connect it to the left input.
network_interface.disconnect_input(&InputConnector::node(artboard_layer.to_node(), 0), &[]);
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 1), primary_input, &[]);

// Set the bottom input of the artboard back to artboard
let bottom_input = NodeInput::value(TaggedValue::Artboard(Table::new()), true);
let bottom_input = NodeInput::type_default(descriptor!(Table<Artboard>), true);
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 0), bottom_input, &[]);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::messages::prelude::*;
use glam::{DAffine2, DVec2};
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput};
use graph_craft::{ProtoNodeIdentifier, concrete};
use graph_craft::{ProtoNodeIdentifier, concrete, descriptor};
use graphene_std::brush::brush_stroke::BrushStroke;
use graphene_std::raster::BlendMode;
use graphene_std::raster_types::Image;
Expand All @@ -15,7 +15,7 @@ use graphene_std::table::Table;
use graphene_std::text::{Font, TypesettingConfig};
use graphene_std::vector::style::{Fill, GradientSpreadMethod, GradientType, Stroke};
use graphene_std::vector::{GradientStops, PointId, Vector, VectorModification, VectorModificationType};
use graphene_std::{Color, Graphic, NodeInputDecleration};
use graphene_std::{Artboard, Color, Graphic, NodeInputDecleration};

#[derive(PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
pub enum TransformIn {
Expand Down Expand Up @@ -132,11 +132,11 @@ impl<'a> ModifyInputsContext<'a> {
/// Creates an artboard as the primary export for the document network.
pub fn create_artboard(&mut self, new_id: NodeId, location: DVec2, dimensions: DVec2, background: Color, clip: bool) -> LayerNodeIdentifier {
let artboard_node_template = resolve_network_node_type("Artboard").expect("Node").node_template_input_override([
Some(NodeInput::value(TaggedValue::Artboard(Default::default()), true)),
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
Some(NodeInput::type_default(descriptor!(Table<Artboard>), true)),
Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)),
Some(NodeInput::value(TaggedValue::DVec2(location), false)),
Some(NodeInput::value(TaggedValue::DVec2(dimensions), false)),
Some(NodeInput::value(TaggedValue::Color(Table::new_from_element(background)), false)),
Some(NodeInput::value(TaggedValue::Color(Some(background)), false)),
Some(NodeInput::value(TaggedValue::Bool(clip), false)),
]);
self.network_interface.insert_node(new_id, artboard_node_template, &[]);
Expand All @@ -147,7 +147,7 @@ impl<'a> ModifyInputsContext<'a> {
let boolean = resolve_proto_node_type(graphene_std::path_bool_nodes::boolean_operation::IDENTIFIER)
.expect("Boolean node does not exist")
.node_template_input_override([
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)),
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
]);

Expand All @@ -157,10 +157,9 @@ impl<'a> ModifyInputsContext<'a> {
}

pub fn insert_blend_data(&mut self, layer: LayerNodeIdentifier, count: f64) -> NodeId {
let blend = resolve_network_node_type("Blend").expect("Blend node does not exist").node_template_input_override([
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
Some(NodeInput::value(TaggedValue::F64(count), false)),
]);
let blend = resolve_network_node_type("Blend")
.expect("Blend node does not exist")
.node_template_input_override([Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(count), false))]);

let blend_id = NodeId::new();
self.network_interface.insert_node(blend_id, blend, &[]);
Expand All @@ -172,10 +171,7 @@ impl<'a> ModifyInputsContext<'a> {
pub fn insert_morph_data(&mut self, layer: LayerNodeIdentifier) -> NodeId {
let morph = resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER)
.expect("Morph node does not exist")
.node_template_input_override([
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
Some(NodeInput::value(TaggedValue::F64(0.5), false)),
]);
.node_template_input_override([Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]);

let morph_id = NodeId::new();
self.network_interface.insert_node(morph_id, morph, &[]);
Expand Down Expand Up @@ -298,10 +294,7 @@ impl<'a> ModifyInputsContext<'a> {
pub fn insert_color_value(&mut self, color: Color, layer: LayerNodeIdentifier) {
let color_value = resolve_proto_node_type(graphene_std::math_nodes::color_value::IDENTIFIER)
.expect("Color Value node does not exist")
.node_template_input_override([
Some(NodeInput::value(TaggedValue::None, false)),
Some(NodeInput::value(TaggedValue::Color(Table::new_from_element(color)), false)),
]);
.node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::Color(Some(color)), false))]);

let color_value_id = NodeId::new();
self.network_interface.insert_node(color_value_id, color_value, &[]);
Expand Down Expand Up @@ -427,15 +420,15 @@ impl<'a> ModifyInputsContext<'a> {
match &fill {
Fill::None => {
let input_connector = InputConnector::node(fill_node_id, backup_color_index);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(Table::new()), false), true);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(None), false), true);
}
Fill::Solid(color) => {
let input_connector = InputConnector::node(fill_node_id, backup_color_index);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(Table::new_from_element(*color)), false), true);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(Some(*color)), false), true);
}
Fill::Gradient(gradient) => {
let input_connector = InputConnector::node(fill_node_id, backup_gradient_index);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Gradient(gradient.clone()), false), true);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::FillGradient(gradient.clone()), false), true);
}
}
let input_connector = InputConnector::node(fill_node_id, fill_index);
Expand Down Expand Up @@ -502,8 +495,7 @@ impl<'a> ModifyInputsContext<'a> {
return;
};
let input_connector = InputConnector::node(gradient_node_id, graphene_std::math_nodes::gradient_value::GradientInput::INDEX);
let stops_table = Table::new_from_element(stops);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::GradientTable(stops_table), false), false);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Gradient(stops), false), false);
}

/// Update the gradient line so its endpoints are at `new_start` and `new_end`.
Expand Down Expand Up @@ -606,10 +598,8 @@ impl<'a> ModifyInputsContext<'a> {
return;
};

let stroke_color = if let Some(color) = stroke.color { Table::new_from_element(color) } else { Table::new() };

let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::ColorInput::INDEX);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(stroke_color), false), true);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(stroke.color), false), true);
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::WeightInput::INDEX);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.weight), false), true);
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::AlignInput::INDEX);
Expand All @@ -623,8 +613,7 @@ impl<'a> ModifyInputsContext<'a> {
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::PaintOrderInput::INDEX);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::PaintOrder(stroke.paint_order), false), false);
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashLengthsInput::<graphene_std::table::Table<f64>>::INDEX);
let dash_lengths_table = stroke.dash_lengths.into_iter().map(graphene_std::table::TableRow::new_from_element).collect();
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64Table(dash_lengths_table), false), true);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64Array(stroke.dash_lengths), false), true);
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashOffsetInput::INDEX);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.dash_offset), false), true);
}
Expand Down Expand Up @@ -726,8 +715,7 @@ impl<'a> ModifyInputsContext<'a> {
let Some(brush_node_id) = self.existing_proto_node_id(graphene_std::brush::brush::brush::IDENTIFIER, true) else {
return;
};
let strokes_table = strokes.into_iter().map(graphene_std::table::TableRow::new_from_element).collect();
self.set_input_with_refresh(InputConnector::node(brush_node_id, 1), NodeInput::value(TaggedValue::BrushStrokeTable(strokes_table), false), false);
self.set_input_with_refresh(InputConnector::node(brush_node_id, 1), NodeInput::value(TaggedValue::BrushStrokes(strokes), false), false);
}

pub fn resize_artboard(&mut self, location: DVec2, dimensions: DVec2) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use crate::messages::prelude::Message;
use crate::node_graph_executor::NodeGraphExecutor;
use glam::DVec2;
use graph_craft::ProtoNodeIdentifier;
use graph_craft::concrete;
use graph_craft::document::value::*;
use graph_craft::document::*;
use graph_craft::{concrete, descriptor};
use graphene_std::extract_xy::XY;
use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha};
use graphene_std::raster_types::{CPU, Raster};
Expand Down Expand Up @@ -205,10 +205,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
.collect(),
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::Graphic(Default::default()), true),
NodeInput::value(TaggedValue::Graphic(Default::default()), true),
],
inputs: vec![NodeInput::type_default(descriptor!(Table<Graphic>), true), NodeInput::type_default(descriptor!(Table<Graphic>), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
Expand Down Expand Up @@ -342,11 +339,11 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::Artboard(Default::default()), true),
NodeInput::value(TaggedValue::Graphic(Default::default()), true),
NodeInput::type_default(descriptor!(Table<Artboard>), true),
NodeInput::type_default(descriptor!(Table<Graphic>), true),
NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false),
NodeInput::value(TaggedValue::DVec2(DVec2::new(1920., 1080.)), false),
NodeInput::value(TaggedValue::Color(Table::new_from_element(Color::WHITE)), false),
NodeInput::value(TaggedValue::Color(Some(Color::WHITE)), false),
NodeInput::value(TaggedValue::Bool(true), false),
],
..Default::default()
Expand Down Expand Up @@ -576,11 +573,11 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::Vector(Default::default()), true),
NodeInput::type_default(descriptor!(Table<Vector>), true),
NodeInput::value(TaggedValue::F64(10.), false),
NodeInput::value(TaggedValue::Bool(Default::default()), false),
NodeInput::value(TaggedValue::InterpolationDistribution(Default::default()), false),
NodeInput::value(TaggedValue::Vector(Default::default()), false),
NodeInput::type_default(descriptor!(Table<Vector>), false),
],
..Default::default()
},
Expand Down Expand Up @@ -827,7 +824,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::value(TaggedValue::Vector(Default::default()), true)],
inputs: vec![NodeInput::type_default(descriptor!(Table<Vector>), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
Expand Down Expand Up @@ -1012,7 +1009,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::Vector(Default::default()), true),
NodeInput::type_default(descriptor!(Table<Vector>), true),
NodeInput::value(
TaggedValue::Footprint(Footprint {
transform: DAffine2::from_scale_angle_translation(DVec2::new(1000., 1000.), 0., DVec2::new(0., 0.)),
Expand Down Expand Up @@ -1123,7 +1120,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::value(TaggedValue::Raster(Default::default()), true)],
inputs: vec![NodeInput::type_default(descriptor!(Table<Raster<CPU>>), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
Expand Down Expand Up @@ -1278,7 +1275,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::value(TaggedValue::Raster(Default::default()), true)],
inputs: vec![NodeInput::type_default(descriptor!(Table<Raster<CPU>>), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
Expand Down Expand Up @@ -1328,7 +1325,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
node_template: NodeTemplate {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::Extract,
inputs: vec![NodeInput::value(TaggedValue::DocumentNode(DocumentNode::default()), true)],
inputs: vec![NodeInput::type_default(descriptor!(DocumentNode), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
Expand Down Expand Up @@ -1480,7 +1477,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::Vector(Default::default()), true),
NodeInput::type_default(descriptor!(Table<Vector>), true),
NodeInput::value(TaggedValue::VectorModification(Default::default()), false),
],
..Default::default()
Expand Down
Loading
Loading