diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index b325bfd2ab..175540b05b 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -5,8 +5,7 @@ use graph_craft::document::value::{RenderOutput, TaggedValue}; use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput}; use graph_craft::proto::GraphErrors; use graph_craft::wasm_application_io::EditorPreferences; -use graphene_std::application_io::{NodeGraphUpdateMessage, RenderConfig}; -use graphene_std::application_io::{SurfaceFrame, TimingInformation}; +use graphene_std::application_io::{NodeGraphUpdateMessage, RenderConfig, TimingInformation}; use graphene_std::raster::{CPU, Raster}; use graphene_std::renderer::{RenderMetadata, format_transform_matrix}; use graphene_std::text::FontCache; @@ -56,7 +55,6 @@ pub struct NodeGraphExecutor { futures: VecDeque<(u64, ExecutionContext)>, node_graph_hash: u64, previous_node_to_inspect: Option, - last_svg_canvas: Option, } #[derive(Debug, Clone)] @@ -79,7 +77,6 @@ impl NodeGraphExecutor { node_graph_hash: 0, current_execution_id: 0, previous_node_to_inspect: None, - last_svg_canvas: None, }; (node_runtime, node_executor) } @@ -384,19 +381,14 @@ impl NodeGraphExecutor { // Send to frontend responses.add(FrontendMessage::UpdateImageData { image_data }); responses.add(FrontendMessage::UpdateDocumentArtwork { svg }); - self.last_svg_canvas = None; } - RenderOutputType::CanvasFrame(frame) => 'block: { - if self.last_svg_canvas == Some(frame) { - break 'block; - } + RenderOutputType::CanvasFrame(frame) => { let matrix = format_transform_matrix(frame.transform); let transform = if matrix.is_empty() { String::new() } else { format!(" transform=\"{matrix}\"") }; let svg = format!( r#"
"#, frame.resolution.x, frame.resolution.y, frame.surface_id.0, ); - self.last_svg_canvas = Some(frame); responses.add(FrontendMessage::UpdateDocumentArtwork { svg }); } RenderOutputType::Texture { .. } => {} diff --git a/frontend/src/components/panels/Document.svelte b/frontend/src/components/panels/Document.svelte index d8453997f8..41ba94ee6c 100644 --- a/frontend/src/components/panels/Document.svelte +++ b/frontend/src/components/panels/Document.svelte @@ -198,9 +198,13 @@ const logicalWidth = parseFloat(foreignObject.getAttribute("width") || "0"); const logicalHeight = parseFloat(foreignObject.getAttribute("height") || "0"); - // Clone canvas for repeated instances (layers that appear multiple times) - // Viewport canvas is marked with data-is-viewport and should never be cloned + // Viewport canvas is marked with data-is-viewport and should never be cloned. + // If it's already mounted in the viewport, skip the DOM replacement since it's already showing the rendered content. + // We check `canvas.isConnected` to ensure it's in the live DOM, not a detached tree from a destroyed component. const isViewport = placeholder.hasAttribute("data-is-viewport"); + if (isViewport && canvas.isConnected && canvas.parentElement?.closest("[data-viewport]")) return; + + // Clone canvas for repeated instances (layers that appear multiple times) if (!isViewport && canvas.parentElement) { const newCanvas = window.document.createElement("canvas"); const context = newCanvas.getContext("2d");