diff --git a/demo-artwork/marbled-mandelbrot.graphite b/demo-artwork/marbled-mandelbrot.graphite
index 676c2c96..52765a62 100644
--- a/demo-artwork/marbled-mandelbrot.graphite
+++ b/demo-artwork/marbled-mandelbrot.graphite
@@ -1 +1 @@
-{"network_interface":{"network":{"exports":[{"Node":{"node_id":12241147352993594415,"output_index":0}}],"nodes":[[4388711862172196665,{"inputs":[],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_raster_nodes::std_nodes::MandelbrotNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"FOOTPRINT","inject":""}}],[3606681156406984991,{"inputs":[{"Node":{"node_id":6323350524796370485,"output_index":0}},{"Value":{"tagged_value":{"GradientStops":[[0.3237704918032787,{"red":1.0,"green":0.0,"blue":1.0,"alpha":0.1}],[0.5655737704918032,{"red":0.8901961,"green":0.8117647,"blue":0.39215687,"alpha":1.0}],[0.8155737704918032,{"red":0.0,"green":1.0,"blue":1.0,"alpha":0.5}]]},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_raster_nodes::gradient_map::GradientMapNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[6029481207635803402,{"inputs":[{"Node":{"node_id":4388711862172196665,"output_index":0}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1000.0,1000.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"call_argument":{"Generic":"T"},"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0}}],"nodes":[[0,{"inputs":[{"Import":{"import_type":{"Generic":"T"},"import_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true,"context_features":{"extract":"","inject":""}}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0}},{"Import":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Import":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Import":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Import":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[7624113397561636853,{"inputs":[{"Value":{"tagged_value":{"Graphic":{"element":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":3606681156406984991,"output_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0}}],"nodes":[[0,{"inputs":[{"Import":{"import_type":{"Generic":"T"},"import_index":0}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::ToGraphicNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[4,{"inputs":[{"Node":{"node_id":0,"output_index":0}},{"Node":{"node_id":3,"output_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::ExtendNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true,"context_features":{"extract":"","inject":""}}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0}},{"Reflection":"DocumentNodePath"}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::SourceNodeIdNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[1,{"inputs":[{"Import":{"import_type":{"Generic":"T"},"import_index":1}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::WrapGraphicNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[80924370013313595,{"inputs":[{"Node":{"node_id":6029481207635803402,"output_index":0}},{"Value":{"tagged_value":{"GradientStops":[[0.0,{"red":0.19607843,"green":0.0,"blue":0.21176471,"alpha":1.0}],[0.12704918032786883,{"red":0.0627451,"green":0.19215687,"blue":0.39607844,"alpha":1.0}],[0.5,{"red":0.8901961,"green":0.8117647,"blue":0.39215687,"alpha":1.0}],[1.0,{"red":0.58431375,"green":0.92941177,"blue":0.92941177,"alpha":0.01}]]},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_raster_nodes::gradient_map::GradientMapNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[6323350524796370485,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":35.0},"exposed":false}},{"Value":{"tagged_value":{"NoiseType":"OpenSimplex2"},"exposed":false}},{"Value":{"tagged_value":{"DomainWarpType":"OpenSimplex2"},"exposed":false}},{"Value":{"tagged_value":{"F64":100.0},"exposed":false}},{"Value":{"tagged_value":{"FractalType":"PingPong"},"exposed":false}},{"Value":{"tagged_value":{"U32":3},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.5},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"CellularDistanceFunction":"Hybrid"},"exposed":false}},{"Value":{"tagged_value":{"CellularReturnType":"CellValue"},"exposed":false}},{"Value":{"tagged_value":{"F64":1.0},"exposed":false}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_raster_nodes::std_nodes::NoisePatternNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[6565638614909771142,{"inputs":[{"Node":{"node_id":7624113397561636853,"output_index":0}},{"Node":{"node_id":80924370013313595,"output_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0}}],"nodes":[[0,{"inputs":[{"Import":{"import_type":{"Generic":"T"},"import_index":0}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::ToGraphicNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[4,{"inputs":[{"Node":{"node_id":0,"output_index":0}},{"Node":{"node_id":3,"output_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::ExtendNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true,"context_features":{"extract":"","inject":""}}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0}},{"Reflection":"DocumentNodePath"}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::SourceNodeIdNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[1,{"inputs":[{"Import":{"import_type":{"Generic":"T"},"import_index":1}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::WrapGraphicNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[12241147352993594415,{"inputs":[{"Value":{"tagged_value":{"Artboard":{"element":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":6565638614909771142,"output_index":0}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1000.0,1000.0]},"exposed":false}},{"Value":{"tagged_value":{"Color":{"element":[{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"call_argument":{"Generic":"T"},"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0}}],"nodes":[[0,{"inputs":[{"Import":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":1}},{"Value":{"tagged_value":{"String":"Artboard"},"exposed":false}},{"Import":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":2}},{"Import":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":3}},{"Import":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":4}},{"Import":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":5}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::artboard::CreateArtboardNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[3,{"inputs":[{"Import":{"import_type":{"Fn":[{"Concrete":{"name":"core::option::Option>","alias":null}},{"Concrete":{"name":"graphene_core::table::Table","alias":null}}]},"import_index":0}},{"Node":{"node_id":2,"output_index":0}},{"Reflection":"DocumentNodePath"}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::ExtendNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true,"context_features":{"extract":"","inject":""}}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0}},{"Reflection":"DocumentNodePath"}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::SourceNodeIdNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}]],"scope_injections":[]},"network_metadata":{"persistent_metadata":{"node_metadata":[[4388711862172196665,{"persistent_metadata":{"reference":"Mandelbrot","display_name":"Mandelbrot","input_metadata":[],"output_names":["Raster"],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6323350524796370485,{"persistent_metadata":{"reference":"Noise Pattern","display_name":"Noise Pattern","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Spacer","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Clip","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Seed","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_scale","input_name":"Scale","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_noise_type","input_name":"Noise Type","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_domain_warp_type","input_name":"Domain Warp Type","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_domain_warp_amplitude","input_name":"Domain Warp Amplitude","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_fractal_type","input_name":"Fractal Type","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_fractal_octaves","input_name":"Fractal Octaves","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_fractal_lacunarity","input_name":"Fractal Lacunarity","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_fractal_gain","input_name":"Fractal Gain","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_fractal_weighted_strength","input_name":"Fractal Weighted Strength","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_ping_pong_strength","input_name":"Fractal Ping Pong Strength","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_cellular_distance_function","input_name":"Cellular Distance Function","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_cellular_return_type","input_name":"Cellular Return Type","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_cellular_jitter","input_name":"Cellular Jitter","input_description":"TODO"}}],"output_names":["Image"],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12241147352993594415,{"persistent_metadata":{"reference":"Artboard","display_name":"Artboard","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Artboards","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"hidden","input_name":"Contents","input_description":"TODO"}},{"persistent_metadata":{"input_data":{"is_integer":true,"unit":" px","y":"Y","x":"X"},"widget_override":"vec2","input_name":"Location","input_description":"TODO"}},{"persistent_metadata":{"input_data":{"is_integer":true,"y":"H","x":"W","unit":" px"},"widget_override":"vec2","input_name":"Dimensions","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"artboard_background","input_name":"Background","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Clip","input_description":"TODO"}}],"output_names":["Out"],"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-8,3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Create Artboard","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-21,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Extend","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,-4]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Source Node ID","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6029481207635803402,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Value","input_description":"TODO"}},{"persistent_metadata":{"input_data":{"y":"Y","unit":" px","is_integer":false,"x":"X"},"widget_override":"vec2","input_name":"Translation","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"transform_rotation","input_name":"Rotation","input_description":"TODO"}},{"persistent_metadata":{"input_data":{"y":"H","x":"W","is_integer":false,"unit":"x"},"widget_override":"vec2","input_name":"Scale","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"transform_skew","input_name":"Skew","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"hidden","input_name":"Origin Offset","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":"hidden","input_name":"Scale Appearance","input_description":""}}],"output_names":["Data"],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7624113397561636853,{"persistent_metadata":{"reference":"Merge","display_name":"Swirly Noise","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Graphical Data","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Over","input_description":"TODO"}}],"output_names":["Out"],"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Wrap Graphic","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-21,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Source Node ID","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Extend","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Graphic","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-21,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3606681156406984991,{"persistent_metadata":{"reference":"Gradient Map","display_name":"Gradient Map","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Image","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Gradient","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Reverse","input_description":""}}],"output_names":["Image"],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6565638614909771142,{"persistent_metadata":{"reference":"Merge","display_name":"Mandelbrot Set","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Graphical Data","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Over","input_description":"TODO"}}],"output_names":["Out"],"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-16,6]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Extend","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Wrap Graphic","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-21,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Source Node ID","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Graphic","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-21,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[80924370013313595,{"persistent_metadata":{"reference":"Gradient Map","display_name":"Gradient Map","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Image","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Gradient","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Reverse","input_description":""}}],"output_names":["Image"],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[345.0,-187.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,1336.0,394.0],"node_graph_top_right":[1468.796875,0.0]},"selection_undo_history":[[12241147352993594415]],"selection_redo_history":[]}}},"collapsed":[],"commit_hash":"f6ffa45a8180183d70a67d3e41249934a8fcacc9","document_ptz":{"pan":[-339.3903349049215,-502.62390663267854],"tilt":0.0,"zoom":4.0,"flip":false},"document_mode":"DesignMode","render_mode":"Normal","overlays_visibility_settings":{"all":true,"artboard_name":true,"compass_rose":true,"quick_measurement":true,"transform_measurement":true,"transform_cage":true,"hover_outline":true,"selection_outline":true,"pivot":true,"origin":true,"path":true,"anchors":true,"handles":true},"rulers_visible":true,"snapping_state":{"snapping_enabled":true,"grid_snapping":false,"artboards":true,"tolerance":8.0,"bounding_box":{"center_point":true,"corner_point":true,"edge_midpoint":true,"align_with_edges":true,"distribute_evenly":true},"path":{"anchor_point":true,"line_midpoint":true,"along_path":true,"normal_to_path":true,"tangent_to_path":true,"path_intersection_point":true,"align_with_anchor_point":true,"perpendicular_from_endpoint":true},"grid":{"origin":[0.0,0.0],"grid_type":{"Rectangular":{"spacing":[1.0,1.0]}},"rectangular_spacing":[1.0,1.0],"isometric_y_spacing":1.0,"isometric_angle_a":30.0,"isometric_angle_b":30.0,"grid_color":{"red":0.6038274,"green":0.6038274,"blue":0.6038274,"alpha":1.0},"dot_display":false}},"graph_view_overlay_open":false,"graph_fade_artwork_percentage":80.0}
\ No newline at end of file
+{"network_interface":{"network":{"exports":[{"Node":{"node_id":12241147352993594415,"output_index":0}}],"nodes":[[4388711862172196665,{"inputs":[],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_raster_nodes::std_nodes::MandelbrotNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"FOOTPRINT","inject":""}}],[3606681156406984991,{"inputs":[{"Node":{"node_id":6323350524796370485,"output_index":0}},{"Value":{"tagged_value":{"GradientStops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.3237704918032787,{"red":0.23828125,"green":0.0,"blue":0.08377075,"alpha":1.0}],[0.5655737704918032,{"red":0.92578125,"green":0.8676921,"blue":0.5569153,"alpha":1.0}],[0.8155737704918032,{"red":0.17333984,"green":0.625,"blue":0.625,"alpha":1.0}],[1.0,{"red":0.106292725,"green":0.3359375,"blue":0.3359375,"alpha":1.0}]]},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_raster_nodes::gradient_map::GradientMapNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[6029481207635803402,{"inputs":[{"Node":{"node_id":4388711862172196665,"output_index":0}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1000.0,1000.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"call_argument":{"Generic":"T"},"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0}}],"nodes":[[0,{"inputs":[{"Import":{"import_type":{"Generic":"T"},"import_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true,"context_features":{"extract":"","inject":""}}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0}},{"Import":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Import":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Import":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Import":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[7624113397561636853,{"inputs":[{"Value":{"tagged_value":{"Graphic":{"element":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":3606681156406984991,"output_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0}}],"nodes":[[0,{"inputs":[{"Import":{"import_type":{"Generic":"T"},"import_index":0}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::ToGraphicNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[4,{"inputs":[{"Node":{"node_id":0,"output_index":0}},{"Node":{"node_id":3,"output_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::ExtendNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true,"context_features":{"extract":"","inject":""}}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0}},{"Reflection":"DocumentNodePath"}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::SourceNodeIdNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[1,{"inputs":[{"Import":{"import_type":{"Generic":"T"},"import_index":1}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::WrapGraphicNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[80924370013313595,{"inputs":[{"Node":{"node_id":6029481207635803402,"output_index":0}},{"Value":{"tagged_value":{"GradientStops":[[0.0,{"red":0.28211805,"green":0.0,"blue":0.3046875,"alpha":1.0}],[0.12704918032786883,{"red":0.13647461,"green":0.3989315,"blue":0.8125,"alpha":1.0}],[0.5,{"red":1.0,"green":0.9409449,"blue":0.625,"alpha":1.0}],[1.0,{"red":0.58431375,"green":0.92941177,"blue":0.92941177,"alpha":0.01}]]},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_raster_nodes::gradient_map::GradientMapNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[6323350524796370485,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":35.0},"exposed":false}},{"Value":{"tagged_value":{"NoiseType":"OpenSimplex2"},"exposed":false}},{"Value":{"tagged_value":{"DomainWarpType":"OpenSimplex2"},"exposed":false}},{"Value":{"tagged_value":{"F64":100.0},"exposed":false}},{"Value":{"tagged_value":{"FractalType":"PingPong"},"exposed":false}},{"Value":{"tagged_value":{"U32":3},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.5},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"CellularDistanceFunction":"Hybrid"},"exposed":false}},{"Value":{"tagged_value":{"CellularReturnType":"CellValue"},"exposed":false}},{"Value":{"tagged_value":{"F64":1.0},"exposed":false}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_raster_nodes::std_nodes::NoisePatternNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[6565638614909771142,{"inputs":[{"Node":{"node_id":7624113397561636853,"output_index":0}},{"Node":{"node_id":80924370013313595,"output_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0}}],"nodes":[[0,{"inputs":[{"Import":{"import_type":{"Generic":"T"},"import_index":0}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::ToGraphicNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[4,{"inputs":[{"Node":{"node_id":0,"output_index":0}},{"Node":{"node_id":3,"output_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::ExtendNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true,"context_features":{"extract":"","inject":""}}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0}},{"Reflection":"DocumentNodePath"}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::SourceNodeIdNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[1,{"inputs":[{"Import":{"import_type":{"Generic":"T"},"import_index":1}}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::WrapGraphicNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[12241147352993594415,{"inputs":[{"Value":{"tagged_value":{"Artboard":{"element":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":6565638614909771142,"output_index":0}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1000.0,1000.0]},"exposed":false}},{"Value":{"tagged_value":{"Color":{"element":[{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"call_argument":{"Generic":"T"},"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0}}],"nodes":[[0,{"inputs":[{"Import":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":1}},{"Value":{"tagged_value":{"String":"Artboard"},"exposed":false}},{"Import":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":2}},{"Import":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":3}},{"Import":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":4}},{"Import":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":5}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::artboard::CreateArtboardNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[3,{"inputs":[{"Import":{"import_type":{"Fn":[{"Concrete":{"name":"core::option::Option>","alias":null}},{"Concrete":{"name":"graphene_core::table::Table","alias":null}}]},"import_index":0}},{"Node":{"node_id":2,"output_index":0}},{"Reflection":"DocumentNodePath"}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::ExtendNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0}}],"call_argument":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true,"context_features":{"extract":"","inject":""}}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0}},{"Reflection":"DocumentNodePath"}],"call_argument":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic::SourceNodeIdNode"}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false,"context_features":{"extract":"","inject":""}}]],"scope_injections":[]},"network_metadata":{"persistent_metadata":{"node_metadata":[[4388711862172196665,{"persistent_metadata":{"reference":"Mandelbrot","display_name":"Mandelbrot","input_metadata":[],"output_names":["Raster"],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6029481207635803402,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Value","input_description":"TODO"}},{"persistent_metadata":{"input_data":{"x":"X","is_integer":false,"y":"Y","unit":" px"},"widget_override":"vec2","input_name":"Translation","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"transform_rotation","input_name":"Rotation","input_description":"TODO"}},{"persistent_metadata":{"input_data":{"unit":"x","y":"H","is_integer":false,"x":"W"},"widget_override":"vec2","input_name":"Scale","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"transform_skew","input_name":"Skew","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"hidden","input_name":"Origin Offset","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":"hidden","input_name":"Scale Appearance","input_description":""}}],"output_names":["Data"],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3606681156406984991,{"persistent_metadata":{"reference":"Gradient Map","display_name":"Gradient Map","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Image","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Gradient","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Reverse","input_description":""}}],"output_names":["Image"],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12241147352993594415,{"persistent_metadata":{"reference":"Artboard","display_name":"Artboard","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Artboards","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"hidden","input_name":"Contents","input_description":"TODO"}},{"persistent_metadata":{"input_data":{"is_integer":true,"unit":" px","y":"Y","x":"X"},"widget_override":"vec2","input_name":"Location","input_description":"TODO"}},{"persistent_metadata":{"input_data":{"unit":" px","x":"W","y":"H","is_integer":true},"widget_override":"vec2","input_name":"Dimensions","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"artboard_background","input_name":"Background","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Clip","input_description":"TODO"}}],"output_names":["Out"],"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-8,3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Extend","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,-4]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Source Node ID","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Create Artboard","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-21,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[80924370013313595,{"persistent_metadata":{"reference":"Gradient Map","display_name":"Gradient Map","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Image","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Gradient","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Reverse","input_description":""}}],"output_names":["Image"],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6565638614909771142,{"persistent_metadata":{"reference":"Merge","display_name":"Mandelbrot Set","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Graphical Data","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Over","input_description":"TODO"}}],"output_names":["Out"],"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-16,6]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Graphic","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-21,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Wrap Graphic","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-21,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Source Node ID","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Extend","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7624113397561636853,{"persistent_metadata":{"reference":"Merge","display_name":"Swirly Noise","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Graphical Data","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Over","input_description":"TODO"}}],"output_names":["Out"],"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Wrap Graphic","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-21,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Source Node ID","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Graphic","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-21,-3]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Extend","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"","input_description":""}}],"output_names":[],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6323350524796370485,{"persistent_metadata":{"reference":"Noise Pattern","display_name":"Noise Pattern","input_metadata":[{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Spacer","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Clip","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":null,"input_name":"Seed","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_scale","input_name":"Scale","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_noise_type","input_name":"Noise Type","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_domain_warp_type","input_name":"Domain Warp Type","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_domain_warp_amplitude","input_name":"Domain Warp Amplitude","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_fractal_type","input_name":"Fractal Type","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_fractal_octaves","input_name":"Fractal Octaves","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_fractal_lacunarity","input_name":"Fractal Lacunarity","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_fractal_gain","input_name":"Fractal Gain","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_fractal_weighted_strength","input_name":"Fractal Weighted Strength","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_ping_pong_strength","input_name":"Fractal Ping Pong Strength","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_cellular_distance_function","input_name":"Cellular Distance Function","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_cellular_return_type","input_name":"Cellular Return Type","input_description":"TODO"}},{"persistent_metadata":{"input_data":{},"widget_override":"noise_properties_cellular_jitter","input_name":"Cellular Jitter","input_description":"TODO"}}],"output_names":["Image"],"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[345.0,-187.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,1336.0,394.0],"node_graph_top_right":[1468.796875,0.0]},"selection_undo_history":[[6565638614909771142],[7624113397561636853],[6565638614909771142],[7624113397561636853],[6565638614909771142],[6565638614909771142]],"selection_redo_history":[]}}},"collapsed":[],"commit_hash":"f6ffa45a8180183d70a67d3e41249934a8fcacc9","document_ptz":{"pan":[-339.3903349049215,-502.62390663267854],"tilt":0.0,"zoom":4.0,"flip":false},"document_mode":"DesignMode","render_mode":"Normal","overlays_visibility_settings":{"all":true,"artboard_name":true,"compass_rose":true,"quick_measurement":true,"transform_measurement":true,"transform_cage":true,"hover_outline":true,"selection_outline":true,"pivot":true,"origin":true,"path":true,"anchors":true,"handles":true},"rulers_visible":true,"snapping_state":{"snapping_enabled":true,"grid_snapping":false,"artboards":true,"tolerance":8.0,"bounding_box":{"center_point":true,"corner_point":true,"edge_midpoint":true,"align_with_edges":true,"distribute_evenly":true},"path":{"anchor_point":true,"line_midpoint":true,"along_path":true,"normal_to_path":true,"tangent_to_path":true,"path_intersection_point":true,"align_with_anchor_point":true,"perpendicular_from_endpoint":true},"grid":{"origin":[0.0,0.0],"grid_type":{"Rectangular":{"spacing":[1.0,1.0]}},"rectangular_spacing":[1.0,1.0],"isometric_y_spacing":1.0,"isometric_angle_a":30.0,"isometric_angle_b":30.0,"grid_color":{"red":0.6038274,"green":0.6038274,"blue":0.6038274,"alpha":1.0},"dot_display":false}},"graph_view_overlay_open":false,"graph_fade_artwork_percentage":80.0}
\ No newline at end of file
diff --git a/website/content/_index.md b/website/content/_index.md
index b0af5f7e..cff512bb 100644
--- a/website/content/_index.md
+++ b/website/content/_index.md
@@ -25,7 +25,7 @@ meta_description = "Open source free software. A vector graphics creativity suit
Your procedural toolbox for 2D content creation
-Graphite is a free, open source vector and raster graphics editor, available now in alpha. Get creative with a fully nondestructive editing workflow that combines layer-based compositing with node-based generative design.
+Graphite is a free, open source vector graphics editor and animation engine, available now in alpha. Get creative with a fully nondestructive editing workflow that combines layer-based compositing with node-based generative design.
@@ -85,15 +85,15 @@ meta_description = "Open source free software. A vector graphics creativity suit
-
+
-
-
-
-
-
+
+
+
+
+
-
+
@@ -139,14 +139,14 @@ meta_description = "Open source free software. A vector graphics creativity suit
Design for a magazine spread, a preview of the upcoming focus on desktop publishing
- Isometric Fountain — All layer stacks are represented, under the hood, by a nondestructive node graph
+ Procedurally generated animation demonstrating Graphite's approach to creative coding with nodes
+
+
+ Procedurally generated animation demonstrating Graphite's approach to creative coding with nodes
Mandelbrot fractal filled with a noise pattern, procedurally generated and infinitely scalable
-
- Coming soon: this user interface mockup shows the raster image editing features planned for 2025
-
@@ -189,7 +189,7 @@ The latest major update is out now! See what the team has been cooking up recent
-Starting life as a vector editor, Graphite is evolving into a general-purpose, all-in-one graphics toolbox that is built more like a game engine than a conventional creative app. The editor's tools wrap its node graph core, providing user-friendly workflows for vector, raster, animation, and beyond.
+Starting life as a vector editor, Graphite is evolving into a general-purpose, all-in-one graphics toolbox that is built more like a game engine than a conventional creative app. The editor's tools wrap its node graph core, exposing user-friendly workflows for vector, raster, animation, and beyond.
Start creating
@@ -299,7 +299,7 @@ Presently, Graphite is a lightweight offline web app with features primarily ori
## Desktop-first and web-ready
-Where's the download? The web app is [currently live](https://editor.graphite.rs) and desktop apps for Windows, Mac, and Linux will be available in Q4 2025.
+Where's the download? The web app is [currently live](https://editor.graphite.rs) and desktop apps for Windows, Mac, and Linux will be released in December 2025.
Graphite is designed principally as a professional desktop application that is also accessible in a browser for quick access from anywhere. It's built for speed with (nearly) no JavaScript. And regardless of platform, it runs locally and privately on your own hardware— there is no server.
diff --git a/website/content/features.md b/website/content/features.md
index eb4cbb0d..5ac66b35 100644
--- a/website/content/features.md
+++ b/website/content/features.md
@@ -73,267 +73,327 @@ Marrying vector and raster under one roof enables both art forms to complement e
-
+
— Pre-Alpha —
-
+
Editor systems; basic vector art tools
-
+
— Alpha 1 —
-
+
Better tools; node graph prototyping
-
+
— Alpha 2 —
-
+
Node graph integration in documents
-
+
— Alpha 3 —
-
+
Procedural vector editing and usability
-
+
— Alpha 4 —
-
+
Parametric animation
-
-
Instancer repeat nodes
+
+
Instancer nodes for looped generation
-
-
Table-based graphical data
+
+
Enhanced Pen, Path, and Shape tools
+
+
+
+
Table-based graphical data format
+
+
+
+
Data panel for graphical introspection
+
+
+
+
Layer clipping masks
+
+
+
+
All-around performance optimizations
-
+
Desktop app (Windows, Mac, Linux)
-
+
GPU-accelerated raster rendering
-
-
Evolution of the graphical data format
+
+
Expanded imaging model data format
-
-
Robust vector mesh editing/rendering
-
-
-
+
Automatic image trace vectorization
-
-
Timeline panel for animation curves
+
+
Context menus throughout the editor
-
+
Simplified main properties panel
-
-
Custom attributes for table data
-
-
-
-
Signed distance field rendering
-
-
-
-
Local fonts access
-
-
-
-
Local file browser for saving/loading
-
-
-
+
Node version management
-
+
Stable document format
-
-
-
-
— Beta —
+
+
+
— Beta 1 —
-
-
Variable color swatches
+
+
Local fonts access
-
-
Command palette and context menus
+
+
Saving over local files (web version)
-
-
Physical units of measure
+
+
Timeline panel for animation curves
-
-
Brush tool rewrite
+
+
Nested documents as custom nodes
-
-
Stylus and touch interaction
+
+
Variables and color swatches
-
+
+
Custom attributes for table data
+
+
+
+
Physical measurement units
+
+
+
+
Text-on-path tool support
+
+
+
+
Per-glyph text style controls
+
+
+
+
Robust vector mesh editing/rendering
+
+
+
+
Nondestructive shape builder tool
+
+
+
Broader SVG support including filters
-
-
Shape builder tool
+
+
Parametric art standalone export
-
+
+
New and improved brush tool
+
+
+
+
Stylus and touch interaction
+
+
+
+
MIDI and audio-reactive visualization
+
+
+
+
— Beta 2 —
+
+
+
Dockable and multi-window panels
-
+
+
Command palette
+
+
+
+
Onion skinning mode for animation
+
+
+
+
Animatable deformation meshes/rigs
+
+
+
+
Simulation domains
+
+
+
+
Signed distance field rendering
+
+
+
+
Procedural PBR material generation
+
+
+
Code editor for custom nodes
-
-
Document history management
-
-
-
-
Offline edit resolution with CRDTs
-
-
-
-
History brush and clone stamp tools
-
-
-
+
Asset libraries and node marketplace
-
-
Automation and batch processing
+
+
Automation/batch processing tools
-
-
Standalone parametric documents
-
-
-
-
Raw photo processing
-
-
-
+
Select mode (marquee masking)
-
+
+
Raster adjustments, filters, and effects
+
+
+
Liquify and warp transforms
-
-
Advanced typography and typesetting
+
+
Raw photo processing
+
+
+
+
— LTS Releases —
-
+
+
Advanced typesetting features
+
+
+
PDF, EPS, AI, DXF, PSD, and TIFF
-
+
CMYK, spot color, and ICC profiles
-
+
HDR and WCG color handling
-
-
-
— 1.0 Release —
-
-
-
Internationalization and accessibility
-
-
-
+
Outliner panel (node graph tree view)
-
+
+
Document history management
+
+
+
+
Offline edit resolution with CRDTs
+
+
+
+
History brush and clone stamp tools
+
+
+
+
Internationalization and accessibility
+
+
+
AI nodes and tools (e.g. magic wand)
-
+
Procedural styling of paint brushes
-
+
Infinite generative vector patterns
-
-
CAD style constraint relationships
+
+
Geometric constraint system solver
-
-
Responsive design constraint solvers
+
+
Responsive design layout solver
-
+
Authoring animated SVGs, Lottie, etc.
-
+
Live video stream compositing
-
-
iPad app and keyboard-free controls
+
+
Tablet app and keyboard-free controls
-
-
Cloud document storage
+
+
Media collection manager/browser
-
+
+
Cloud document storage/device sync
+
+
+
Multiplayer collaborative editing
-
+
Predictive graph rendering/caching
-
-
Distributed graph rendering
+
+
Multi-device distributed rendering
-
-
Cloud rendering accelerator service
+
+
Hosted rendering accelerator service
-
+
…and that's all just the beginning…
@@ -341,3 +401,45 @@ Marrying vector and raster under one roof enables both art forms to complement e
+
+
+
+
+
+## Roadmap spotlight: keyframe animation
+
+Coming early 2026, Graphite will expand its animation toolset beyond parametrically-driven motion to include traditional keyframe animation. The Timeline panel pictured below will let animators drive parameters using keyframes and curves through a traditional dopesheet interface.
+
+Node parameters can be set to a constant value in the Properties panel, exposed to the graph for procedural animation, or exposed to a channel in the upcoming Timeline panel for hand-authored keyframing.
+
+The panel will enable users to scrub through time with the playhead and choose between timing with discrete frames or continuous seconds. A dedicated curves editing mode (not pictured) will enable fine-tuning parameters with a labeled Y-axis, while the dopesheet allows individual channels to be expanded to view and edit the shape and smoothness of curves inline.
+
+Work-in-progress design mockup:
+
+
+
+
+
+
+
+
+
+
+
+## Roadmap spotlight: raster image editing
+
+The vision since Graphite's inception has been to open up the traditional raster image editing workflow to the greater degree of flexibility found in node-based compositors, without one approach compromising the ergonomics of the other.
+
+As with Graphite's current vector toolset, raster editing will interpret the user's interactive edits as modifications to the construction of layers in the underlying node graph rather than destructive alterations to layer pixel data (as in other image editors). By containing only a description of the user's editing operations without the data, documents will remain ultra tiny when source assets are linked externally.
+
+Brushes, selection tools, masks, filters, effects, adjustment layers, and other tools used to manipulate raster layers will all be presented in a familiar form when Graphite's raster toolset nears maturity by the end of beta.
+
+Work-in-progress design mockup:
+
+
+
+
+
+
+
+
diff --git a/website/content/learn/_index.md b/website/content/learn/_index.md
index 5a191906..52771ba7 100644
--- a/website/content/learn/_index.md
+++ b/website/content/learn/_index.md
@@ -9,9 +9,7 @@ js = ["/js/youtube-embed.js"]
css = ["/component/youtube-embed.css"]
+++
-Welcome to the Graphite user manual. Keep reading to to learn how the software can help bring your 2D creative ideas to life.
-
-You may choose to read this sequentially and learn from the structured introduction and sample projects. Or you may jump to chapters of interest that also serve as quick reference.
+Welcome to the Graphite user manual. Keep reading to learn how the software can help bring your 2D creative ideas to life.
## More chapters on the way
diff --git a/website/content/learn/interface/_index.md b/website/content/learn/interface/_index.md
index 0148aae3..2fce2aed 100644
--- a/website/content/learn/interface/_index.md
+++ b/website/content/learn/interface/_index.md
@@ -23,12 +23,6 @@ On the left, the [**menu bar**](./menu-bar) provides quick access to many editor
-### Document title
-
-In the center, the **document title** displays the name of the active document. That name is given a `*` suffix if the file has unsaved changes. For example, *Painting.graphite** would be unsaved but *Painting.graphite* would have no changes following its last save.
-
-
-
### Window buttons
On the right, the **window buttons** provide platform-specific controls for the application.
@@ -37,7 +31,7 @@ On the right, the **window buttons** provide platform-specific controls for the
| | |
|-|-|
-| **Web** |
A button to enter fullscreen mode is displayed.
The label "*Go fullscreen to access all hotkeys*" indicates that some shortcut keys like Ctrl N (macOS: ⌘ N ) are reserved by the web browser and can only be used in fullscreen mode. (An alternative to going fullscreen: include Alt in the shortcut combinations for browser-reserved hotkeys.)
|
+| **Web** |
A button to enter fullscreen mode is displayed.
Some shortcut keys like Ctrl N (macOS: ⌘ N ) are reserved by the web browser and can only be used in fullscreen mode. (Alternative to going fullscreen: include Alt in the shortcut combinations for browser-reserved hotkeys.)
|
diff --git a/website/content/volunteer/guide/graphene/networks-and-nodes.md b/website/content/volunteer/guide/graphene/networks-and-nodes.md
index d3cf1624..aeb12cb9 100644
--- a/website/content/volunteer/guide/graphene/networks-and-nodes.md
+++ b/website/content/volunteer/guide/graphene/networks-and-nodes.md
@@ -13,7 +13,7 @@ Any (sub)graph can import/export data from/to the outside world. For example, a
In the Graphite editor UI, here is an example graph of artwork that imports no data but exports its content to the canvas:
-
+
The graph shown above represents the full artwork, meaning it's the root-level graph in its document. But there is nothing special about that graph compared to any subgraph. To avoid the confusion of calling it a graph or subgraph which comes with implications about user-facing concepts in the context of a document, we will use the less-ambiguous term **network** in the context of Graphene's internal concepts and codebase.
diff --git a/website/content/volunteer/guide/student-projects/_index.md b/website/content/volunteer/guide/student-projects/_index.md
index 7cac22d5..7ddce48c 100644
--- a/website/content/volunteer/guide/student-projects/_index.md
+++ b/website/content/volunteer/guide/student-projects/_index.md
@@ -95,12 +95,6 @@ Based on the experience and insight brought to the table by the student, the nat
-### Native development
-
-#### Graphite desktop app engineering
-
-*This is a newly added project pending a full written overview. Come ask on Discord for details.*
-
### Rendering and graphics
Several of these require a good understanding of computer graphics rendering techniques and algorithms. Experience in game development and writing your own rendering engines is a plus.
diff --git a/website/sass/component/carousel.scss b/website/sass/component/carousel.scss
index 78f18cba..8f042c80 100644
--- a/website/sass/component/carousel.scss
+++ b/website/sass/component/carousel.scss
@@ -8,7 +8,7 @@
touch-action: pan-y pinch-zoom;
cursor: grab;
- img {
+ :is(img, video) {
position: relative;
display: inline-block;
user-select: none;
@@ -33,7 +33,7 @@
}
}
- &:not(.dragging, .jostling) .carousel-slide img {
+ &:not(.dragging, .jostling) .carousel-slide :is(img, video) {
transition: transform 500ms;
}
@@ -141,11 +141,11 @@
}
}
- &.window-size-1 .carousel-slide img {
+ &.window-size-1 .carousel-slide :is(img, video) {
width: 100%;
}
- &.window-size-2 .carousel-slide img {
+ &.window-size-2 .carousel-slide :is(img, video) {
width: calc((100% / 2) - 10px);
padding: 0 10px;
@@ -158,7 +158,7 @@
}
}
- &.window-size-3 .carousel-slide img {
+ &.window-size-3 .carousel-slide :is(img, video) {
width: calc((100% / 3) - 10px * (4 / 3));
padding: 0 10px;
diff --git a/website/static/js/carousel.js b/website/static/js/carousel.js
index cb7263ff..2b2c7b2e 100644
--- a/website/static/js/carousel.js
+++ b/website/static/js/carousel.js
@@ -17,7 +17,8 @@ window.addEventListener("pointermove", dragMove);
* dragLastClientX: number | undefined,
* velocityDeltaWindow: Array<{ time: number, delta: number }>,
* jostleNoLongerNeeded: boolean,
- * requestAnimationFrameActive: boolean
+ * requestAnimationFrameActive: boolean,
+ * videoSyncInterval: ReturnType
| undefined,
* }} Carousel
*/
@@ -34,8 +35,8 @@ function initializeCarousel() {
if (!(insertInsideElement instanceof HTMLElement)) return;
slideImages.forEach((image) => {
const clonedImage = image.cloneNode(true);
- if (!(clonedImage instanceof HTMLImageElement)) return;
- clonedImage.alt = "";
+ if (!(clonedImage instanceof HTMLImageElement) && !(clonedImage instanceof HTMLVideoElement)) return;
+ if (clonedImage instanceof HTMLImageElement) clonedImage.alt = "";
insertInsideElement.insertAdjacentElement("beforeend", clonedImage);
});
});
@@ -61,6 +62,7 @@ function initializeCarousel() {
velocityDeltaWindow,
jostleNoLongerNeeded,
requestAnimationFrameActive: false,
+ videoSyncInterval: undefined,
};
carousels.push(carousel);
@@ -166,6 +168,160 @@ function slideTo(carousel, index, smooth) {
slideImages[clamp(offsetIndex + 2, 0, slideImages.length - 1)].removeAttribute("loading");
setCurrentTransform(carousel, index * -100, "%", smooth);
+
+ // Manage video preloading and playback
+ manageVideoPlayback(carousel, index);
+}
+
+/**
+ * Get all video elements for a given slide index (main + torn edge copies)
+ * @param {Carousel} carousel
+ * @param {number} index
+ */
+function getVideosForSlide(carousel, index) {
+ // Account for the first image being the faded-out last image
+ const offsetIndex = index + 1;
+ const slideImages = Array.from(carousel.carouselContainer.querySelectorAll("[data-carousel-slide] [data-carousel-image]"));
+ const tornLeftImages = Array.from(carousel.carouselContainer.querySelectorAll("[data-carousel-slide-torn-left] [data-carousel-image]"));
+ const tornRightImages = Array.from(carousel.carouselContainer.querySelectorAll("[data-carousel-slide-torn-right] [data-carousel-image]"));
+
+ const mainElement = slideImages[offsetIndex];
+ const tornLeftElement = tornLeftImages[offsetIndex];
+ const tornRightElement = tornRightImages[offsetIndex];
+
+ return {
+ main: mainElement instanceof HTMLVideoElement ? mainElement : null,
+ tornLeft: tornLeftElement instanceof HTMLVideoElement ? tornLeftElement : null,
+ tornRight: tornRightElement instanceof HTMLVideoElement ? tornRightElement : null,
+ };
+}
+
+/**
+ * Check if the carousel is currently in transition (dragging or animating)
+ * @param {Carousel} carousel
+ */
+function isCarouselInTransition(carousel) {
+ // Check if user is dragging
+ if (carousel.dragLastClientX !== undefined) return true;
+
+ // Check if carousel has the "dragging" class (set during drag)
+ if (carousel.carouselContainer.classList.contains("dragging")) return true;
+
+ // Check if any slide has a transition in progress by looking at the computed style
+ const firstImage = carousel.images[1];
+ if (firstImage instanceof HTMLElement) {
+ const style = window.getComputedStyle(firstImage);
+ // If transform is transitioning, we're in motion
+ if (style.transitionProperty.includes("transform") && style.transitionDuration !== "0s") {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Preload and manage playback of videos on current and adjacent slides
+ * @param {Carousel} carousel
+ * @param {number} currentIndex
+ */
+function manageVideoPlayback(carousel, currentIndex) {
+ const totalSlides = carousel.dots.length;
+
+ // Clear any existing sync interval
+ if (carousel.videoSyncInterval !== undefined) {
+ clearTimeout(carousel.videoSyncInterval);
+ carousel.videoSyncInterval = undefined;
+ }
+
+ // Stop all videos that aren't on current or adjacent slides
+ for (let i = 0; i < totalSlides; i++) {
+ if (Math.abs(i - currentIndex) > 1) {
+ const videos = getVideosForSlide(carousel, i);
+ [videos.main, videos.tornLeft, videos.tornRight].forEach((video) => {
+ if (video) {
+ video.pause();
+ video.currentTime = 0;
+ }
+ });
+ }
+ }
+
+ // Preload and potentially play videos on current and adjacent slides
+ const indicesToPreload = [currentIndex - 1, currentIndex, currentIndex + 1].filter((index) => index >= 0 && index < totalSlides);
+
+ indicesToPreload.forEach((index) => {
+ const videos = getVideosForSlide(carousel, index);
+
+ // Exit early if not a video slide
+ if (!videos.main) return;
+
+ // Preload the video
+ if (videos.main.readyState < 3) videos.main.load();
+
+ // If this is the current slide, play the main video when ready
+ if (index === currentIndex) {
+ const playWhenReady = () => {
+ if (videos.main && videos.main.readyState >= 3) {
+ // Start the main video
+ videos.main.currentTime = 0;
+ videos.main.play().catch(() => {});
+ } else if (videos.main) {
+ // Video not ready yet, check again
+ videos.main.addEventListener("canplaythrough", playWhenReady, { once: true });
+ }
+ };
+
+ playWhenReady();
+
+ // Monitor for transitions and sync torn videos when in motion
+ updateVideoSyncForTransitions(carousel, videos);
+ }
+ });
+}
+
+/**
+ * Set up monitoring to play/pause torn edge videos based on transition state
+ * @param {Carousel} carousel
+ * @param {{ main: HTMLVideoElement | null, tornLeft: HTMLVideoElement | null, tornRight: HTMLVideoElement | null }} videos
+ */
+function updateVideoSyncForTransitions(carousel, videos) {
+ if (!videos.main) return;
+
+ const syncTornVideos = () => {
+ const inTransition = isCarouselInTransition(carousel);
+
+ // During transition: sync and play all copies
+ if (inTransition && videos.main) {
+ const mainTime = videos.main.currentTime;
+ [videos.tornLeft, videos.tornRight].forEach((video) => {
+ if (!video) return;
+
+ if (video.paused) {
+ video.currentTime = mainTime;
+ video.play().catch(() => {
+ // Ignore autoplay errors
+ });
+ } else {
+ // Keep synced
+ const drift = Math.abs(video.currentTime - mainTime);
+ if (drift > 0.1) {
+ video.currentTime = mainTime;
+ }
+ }
+ });
+ }
+ // Not in transition: pause torn edge videos to save performance
+ else {
+ if (videos.tornLeft && !videos.tornLeft.paused) videos.tornLeft.pause();
+ if (videos.tornRight && !videos.tornRight.paused) videos.tornRight.pause();
+ }
+
+ // Continue checking while in transition, or check again soon in case transition starts
+ carousel.videoSyncInterval = setTimeout(syncTornVideos, 100);
+ };
+
+ syncTornVideos();
}
/**
diff --git a/website/templates/base.html b/website/templates/base.html
index 72436164..b7798fbe 100644
--- a/website/templates/base.html
+++ b/website/templates/base.html
@@ -140,7 +140,7 @@
Press
Contact
- Copyright © {{ now() | date(format = "%Y") }} Graphite Labs, LLC (an open source organization)
+ Copyright © {{ now() | date(format = "%Y") }} Graphite Labs, LLC (an open source community organization)