Instance tables refactor part 7: Rename "ImageFrame" -> "RasterData", "ImageFrameTable" -> "RasterDataType", and "RasterFrame" -> "RasterDataType"

This commit is contained in:
Keavon Chambers
2025-06-15 16:54:40 -07:00
parent 2696abc6b3
commit 5cacab2e39
34 changed files with 285 additions and 281 deletions

View File

@@ -30,7 +30,7 @@ use glam::{DAffine2, DVec2, IVec2};
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
use graphene_core::raster::BlendMode;
use graphene_core::raster::image::ImageFrameTable;
use graphene_core::raster::image::RasterDataTable;
use graphene_core::vector::style::ViewMode;
use graphene_std::renderer::{ClickTarget, Quad};
use graphene_std::vector::{PointId, path_bool_lib};
@@ -864,7 +864,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
responses.add(DocumentMessage::AddTransaction);
let layer = graph_modification_utils::new_image_layer(ImageFrameTable::new(image), layer_node_id, self.new_layer_parent(true), responses);
let layer = graph_modification_utils::new_image_layer(RasterDataTable::new(image), layer_node_id, self.new_layer_parent(true), responses);
if let Some(name) = name {
responses.add(NodeGraphMessage::SetDisplayName {

View File

@@ -6,7 +6,7 @@ use bezier_rs::Subpath;
use glam::{DAffine2, DVec2, IVec2};
use graph_craft::document::NodeId;
use graphene_core::raster::BlendMode;
use graphene_core::raster::image::ImageFrameTable;
use graphene_core::raster::image::RasterDataTable;
use graphene_core::text::{Font, TypesettingConfig};
use graphene_core::vector::PointId;
use graphene_core::vector::VectorModificationType;
@@ -66,7 +66,7 @@ pub enum GraphOperationMessage {
},
NewBitmapLayer {
id: NodeId,
image_frame: ImageFrameTable<Color>,
image_frame: RasterDataTable<Color>,
parent: LayerNodeIdentifier,
insert_index: usize,
},

View File

@@ -9,7 +9,7 @@ use graph_craft::concrete;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput};
use graphene_core::raster::BlendMode;
use graphene_core::raster::image::ImageFrameTable;
use graphene_core::raster::image::RasterDataTable;
use graphene_core::text::{Font, TypesettingConfig};
use graphene_core::vector::brush_stroke::BrushStroke;
use graphene_core::vector::style::{Fill, Stroke};
@@ -209,11 +209,11 @@ impl<'a> ModifyInputsContext<'a> {
self.network_interface.move_node_to_chain_start(&stroke_id, layer, &[]);
}
pub fn insert_image_data(&mut self, image_frame: ImageFrameTable<Color>, layer: LayerNodeIdentifier) {
pub fn insert_image_data(&mut self, image_frame: RasterDataTable<Color>, layer: LayerNodeIdentifier) {
let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template();
let image = resolve_document_node_type("Image")
.expect("Image node does not exist")
.node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::ImageFrame(image_frame), false))]);
.node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::RasterData(image_frame), false))]);
let image_id = NodeId::new();
self.network_interface.insert_node(image_id, image, &[]);

View File

@@ -15,7 +15,7 @@ use graph_craft::concrete;
use graph_craft::document::value::*;
use graph_craft::document::*;
use graphene_core::raster::brush_cache::BrushCache;
use graphene_core::raster::image::ImageFrameTable;
use graphene_core::raster::image::RasterDataTable;
use graphene_core::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha};
use graphene_core::text::{Font, TypesettingConfig};
use graphene_core::transform::Footprint;
@@ -608,8 +608,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
exports: vec![NodeInput::node(NodeId(3), 0)],
nodes: [
DocumentNode {
inputs: vec![NodeInput::network(concrete!(ImageFrameTable<Color>), 0)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, ImageFrameTable<SRGBA8>>")),
inputs: vec![NodeInput::network(concrete!(RasterDataTable<Color>), 0)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, RasterDataTable<SRGBA8>>")),
..Default::default()
},
DocumentNode {
@@ -636,7 +636,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true)],
inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
@@ -852,7 +852,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
nodes: [
DocumentNode {
inputs: vec![
NodeInput::network(concrete!(ImageFrameTable<Color>), 0),
NodeInput::network(concrete!(RasterDataTable<Color>), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Red), false),
],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
@@ -861,7 +861,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
},
DocumentNode {
inputs: vec![
NodeInput::network(concrete!(ImageFrameTable<Color>), 0),
NodeInput::network(concrete!(RasterDataTable<Color>), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Green), false),
],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
@@ -870,7 +870,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
},
DocumentNode {
inputs: vec![
NodeInput::network(concrete!(ImageFrameTable<Color>), 0),
NodeInput::network(concrete!(RasterDataTable<Color>), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Blue), false),
],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
@@ -879,7 +879,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
},
DocumentNode {
inputs: vec![
NodeInput::network(concrete!(ImageFrameTable<Color>), 0),
NodeInput::network(concrete!(RasterDataTable<Color>), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Alpha), false),
],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
@@ -893,7 +893,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true)],
inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
@@ -959,13 +959,13 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
exports: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(1), 0)],
nodes: [
DocumentNode {
inputs: vec![NodeInput::network(concrete!(ImageFrameTable<Color>), 0), NodeInput::value(TaggedValue::XY(XY::X), false)],
inputs: vec![NodeInput::network(concrete!(RasterDataTable<Color>), 0), NodeInput::value(TaggedValue::XY(XY::X), false)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::ExtractXyNode")),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::network(concrete!(ImageFrameTable<Color>), 0), NodeInput::value(TaggedValue::XY(XY::Y), false)],
inputs: vec![NodeInput::network(concrete!(RasterDataTable<Color>), 0), NodeInput::value(TaggedValue::XY(XY::Y), false)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::ExtractXyNode")),
manual_composition: Some(generic!(T)),
..Default::default()
@@ -978,7 +978,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true)],
inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
@@ -1029,7 +1029,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
exports: vec![NodeInput::node(NodeId(0), 0)],
nodes: vec![DocumentNode {
inputs: vec![
NodeInput::network(concrete!(ImageFrameTable<Color>), 0),
NodeInput::network(concrete!(RasterDataTable<Color>), 0),
NodeInput::network(concrete!(Vec<graphene_core::vector::brush_stroke::BrushStroke>), 1),
NodeInput::network(concrete!(BrushCache), 2),
],
@@ -1044,7 +1044,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true),
NodeInput::value(TaggedValue::BrushStrokes(Vec::new()), false),
NodeInput::value(TaggedValue::BrushCache(BrushCache::new_proto()), false),
],
@@ -1083,7 +1083,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
node_template: NodeTemplate {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_core::memo::MemoNode"),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true)],
inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)],
manual_composition: Some(concrete!(Context)),
..Default::default()
},
@@ -1102,7 +1102,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
node_template: NodeTemplate {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_core::memo::ImpureMemoNode"),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true)],
inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)],
manual_composition: Some(concrete!(Context)),
..Default::default()
},
@@ -1784,7 +1784,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::network(concrete!(ImageFrameTable<Color>), 0), NodeInput::node(NodeId(0), 0)],
inputs: vec![NodeInput::network(concrete!(RasterDataTable<Color>), 0), NodeInput::node(NodeId(0), 0)],
manual_composition: Some(generic!(T)),
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::UploadTextureNode")),
..Default::default()
@@ -1802,7 +1802,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true)],
inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
@@ -1882,7 +1882,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
// document_node: DocumentNode {
// implementation: DocumentNodeImplementation::proto("graphene_core::raster::CurvesNode"),
// inputs: vec![
// NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
// NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true),
// NodeInput::value(TaggedValue::Curve(Default::default()), false),
// ],
// ..Default::default()
@@ -2646,7 +2646,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
// exports: vec![NodeInput::node(NodeId(1), 0)],
// nodes: [
// DocumentNode {
// inputs: vec![NodeInput::network(concrete!(ImageFrameTable<Color>), 0)],
// inputs: vec![NodeInput::network(concrete!(RasterDataTable<Color>), 0)],
// implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"),
// manual_composition: Some(concrete!(Context)),
// skip_deduplication: true,
@@ -2684,7 +2684,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
// ..Default::default()
// }),
// inputs: vec![
// NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
// NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true),
// NodeInput::scope("editor-api"),
// NodeInput::value(TaggedValue::ImaginateController(Default::default()), false),
// NodeInput::value(TaggedValue::F64(0.), false), // Remember to keep index used in `ImaginateRandom` updated with this entry's index

View File

@@ -12,7 +12,7 @@ use graph_craft::Type;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput};
use graphene_core::raster::curve::Curve;
use graphene_core::raster::image::ImageFrameTable;
use graphene_core::raster::image::RasterDataTable;
use graphene_core::raster::{
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute,
SelectiveColorChoice,
@@ -22,14 +22,14 @@ use graphene_core::vector::generator_nodes::grid;
use graphene_core::vector::misc::CentroidType;
use graphene_core::vector::style::{GradientType, LineCap, LineJoin};
use graphene_std::animation::RealTimeMode;
use graphene_std::application_io::TextureFrameTable;
use graphene_std::application_io::TextureDataTable;
use graphene_std::ops::XY;
use graphene_std::transform::{Footprint, ReferencePoint};
use graphene_std::vector::VectorDataTable;
use graphene_std::vector::misc::ArcType;
use graphene_std::vector::misc::{BooleanOperation, GridType};
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops};
use graphene_std::{GraphicGroupTable, NodeInputDecleration, RasterFrame};
use graphene_std::{GraphicGroupTable, NodeInputDecleration, RasterDataType};
pub(crate) fn string_properties(text: &str) -> Vec<LayoutGroup> {
let widget = TextLabel::new(text).widget_holder();
@@ -190,7 +190,7 @@ pub(crate) fn property_from_type(
// GRAPHICAL DATA TYPES
// ====================
Some(x) if x == TypeId::of::<VectorDataTable>() => vector_data_widget(default_info).into(),
Some(x) if x == TypeId::of::<RasterFrame>() || x == TypeId::of::<ImageFrameTable<Color>>() || x == TypeId::of::<TextureFrameTable>() => raster_widget(default_info).into(),
Some(x) if x == TypeId::of::<RasterDataType>() || x == TypeId::of::<RasterDataTable<Color>>() || x == TypeId::of::<TextureDataTable>() => raster_widget(default_info).into(),
Some(x) if x == TypeId::of::<GraphicGroupTable>() => group_widget(default_info).into(),
// ============
// STRUCT TYPES
@@ -198,7 +198,7 @@ pub(crate) fn property_from_type(
Some(x) if x == TypeId::of::<Color>() => color_widget(default_info, ColorInput::default().allow_none(false)),
Some(x) if x == TypeId::of::<Option<Color>>() => color_widget(default_info, ColorInput::default().allow_none(true)),
Some(x) if x == TypeId::of::<GradientStops>() => color_widget(default_info, ColorInput::default().allow_none(false)),
Some(x) if x == TypeId::of::<Font>() => font_widget(default_info).into(),
Some(x) if x == TypeId::of::<Font>() => font_widget(default_info),
Some(x) if x == TypeId::of::<Curve>() => curve_widget(default_info),
Some(x) if x == TypeId::of::<Footprint>() => footprint_widget(default_info, &mut extra_widgets),
// ===============================

View File

@@ -263,7 +263,7 @@
// // let transform = context
// // .executor
// // .introspect_node_in_network(context.network, &imaginate_node, |network| network.inputs.first().copied(), |frame: &ImageFrame<Color>| frame.transform)
// // .introspect_node_in_network(context.network, &imaginate_node, |network| network.inputs.first().copied(), |frame: &RasterData<Color>| frame.transform)
// // .unwrap_or_default();
// let image_size = context
// .executor
@@ -283,7 +283,7 @@
// .map(|(node_id, _)| node_id)
// .copied()
// },
// |frame: &IORecord<(), ImageFrame<Color>>| (frame.output.image.width, frame.output.image.height),
// |frame: &IORecord<(), RasterData<Color>>| (frame.output.image.width, frame.output.image.height),
// )
// .unwrap_or_default();

View File

@@ -17,7 +17,7 @@ pub enum FrontendGraphDataType {
impl FrontendGraphDataType {
fn with_type(input: &Type) -> Self {
match TaggedValue::from_type_or_none(input) {
TaggedValue::Image(_) | TaggedValue::ImageFrame(_) => Self::Raster,
TaggedValue::Image(_) | TaggedValue::RasterData(_) => Self::Raster,
TaggedValue::Subpaths(_) | TaggedValue::VectorData(_) => Self::VectorData,
TaggedValue::U32(_)
| TaggedValue::U64(_)

View File

@@ -485,7 +485,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
("graphene_core::raster::GradientMapNode", "graphene_core::raster::adjustments::GradientMapNode"),
("graphene_core::raster::HueSaturationNode", "graphene_core::raster::adjustments::HueSaturationNode"),
("graphene_core::raster::InvertNode", "graphene_core::raster::adjustments::InvertNode"),
// ("graphene_core::raster::IndexNode", "graphene_core::raster::adjustments::IndexNode"),
("graphene_core::raster::InvertRGBNode", "graphene_core::raster::adjustments::InvertNode"),
("graphene_core::raster::LevelsNode", "graphene_core::raster::adjustments::LevelsNode"),
("graphene_core::raster::LuminanceNode", "graphene_core::raster::adjustments::LuminanceNode"),

View File

@@ -7,8 +7,10 @@ use graphene_core::Context;
use graphene_core::GraphicGroupTable;
use graphene_core::instances::Instances;
use graphene_core::memo::IORecord;
use graphene_core::raster::Image;
use graphene_core::vector::{VectorData, VectorDataTable};
use graphene_core::{Artboard, ArtboardGroupTable, GraphicElement};
use graphene_std::Color;
use std::any::Any;
use std::sync::Arc;
@@ -154,7 +156,7 @@ impl InstanceLayout for GraphicElement {
match self {
Self::GraphicGroup(instances) => instances.identifier(),
Self::VectorData(instances) => instances.identifier(),
Self::RasterFrame(_) => "RasterFrame".to_string(),
Self::RasterDataType(_) => "RasterDataType".to_string(),
}
}
// Don't put a breadcrumb for GraphicElement
@@ -165,7 +167,7 @@ impl InstanceLayout for GraphicElement {
match self {
Self::GraphicGroup(instances) => instances.layout_with_breadcrumb(data),
Self::VectorData(instances) => instances.layout_with_breadcrumb(data),
Self::RasterFrame(_) => label("Raster frame not supported"),
Self::RasterDataType(_) => label("Raster frame not supported"),
}
}
}
@@ -225,6 +227,19 @@ impl InstanceLayout for VectorData {
}
}
impl InstanceLayout for Image<Color> {
fn type_name() -> &'static str {
"Image"
}
fn identifier(&self) -> String {
format!("Image (width={}, height={})", self.width, self.height)
}
fn compute_layout(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
let rows = vec![vec![TextLabel::new(format!("Image (width={}, height={})", self.width, self.height)).widget_holder()]];
vec![LayoutGroup::Table { rows }]
}
}
impl InstanceLayout for Artboard {
fn type_name() -> &'static str {
"Artboard"

View File

@@ -10,7 +10,7 @@ use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput};
use graphene_core::Color;
use graphene_core::raster::BlendMode;
use graphene_core::raster::image::ImageFrameTable;
use graphene_core::raster::image::RasterDataTable;
use graphene_core::text::{Font, TypesettingConfig};
use graphene_core::vector::style::Gradient;
use graphene_std::vector::{ManipulatorPointId, PointId, SegmentId, VectorModificationType};
@@ -207,7 +207,7 @@ pub fn new_vector_layer(subpaths: Vec<Subpath<PointId>>, id: NodeId, parent: Lay
}
/// Create a new bitmap layer.
pub fn new_image_layer(image_frame: ImageFrameTable<Color>, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
pub fn new_image_layer(image_frame: RasterDataTable<Color>, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
let insert_index = 0;
responses.add(GraphOperationMessage::NewBitmapLayer {
id,
@@ -424,12 +424,9 @@ impl<'a> NodeGraphLayer<'a> {
/// Check if a layer is a raster layer
pub fn is_raster_layer(layer: LayerNodeIdentifier, network_interface: &mut NodeNetworkInterface) -> bool {
let layer_input_type = network_interface.input_type(&InputConnector::node(layer.to_node(), 1), &[]).0.nested_type().clone();
if layer_input_type == concrete!(graphene_core::raster::image::ImageFrameTable<graphene_core::Color>)
|| layer_input_type == concrete!(graphene_core::application_io::TextureFrameTable)
|| layer_input_type == concrete!(graphene_std::RasterFrame)
{
return true;
}
false
layer_input_type == concrete!(graphene_std::RasterDataType)
|| layer_input_type == concrete!(graphene_core::raster::image::RasterDataTable<graphene_core::Color>)
|| layer_input_type == concrete!(graphene_core::application_io::TextureDataTable)
}
}

View File

@@ -383,7 +383,7 @@ impl NodeGraphExecutor {
TaggedValue::OptionalColor(render_object) => Self::debug_render(render_object, transform, responses),
TaggedValue::VectorData(render_object) => Self::debug_render(render_object, transform, responses),
TaggedValue::GraphicGroup(render_object) => Self::debug_render(render_object, transform, responses),
TaggedValue::ImageFrame(render_object) => Self::debug_render(render_object, transform, responses),
TaggedValue::RasterData(render_object) => Self::debug_render(render_object, transform, responses),
TaggedValue::Palette(render_object) => Self::debug_render(render_object, transform, responses),
_ => {
return Err(format!("Invalid node graph output type: {node_graph_output:#?}"));