diff --git a/editor/src/node_graph_executor/runtime.rs b/editor/src/node_graph_executor/runtime.rs
index 227999143c..da92ad313b 100644
--- a/editor/src/node_graph_executor/runtime.rs
+++ b/editor/src/node_graph_executor/runtime.rs
@@ -328,6 +328,18 @@ impl NodeRuntime {
return;
}
+ // Skip thumbnails if the layer is too complex (for performance)
+ if graphic_element.render_complexity() > 1000 {
+ let old = thumbnail_renders.insert(parent_network_node_id, Vec::new());
+ if old.is_none_or(|v| !v.is_empty()) {
+ responses.push_back(FrontendMessage::UpdateNodeThumbnail {
+ id: parent_network_node_id,
+ value: "".to_string(),
+ });
+ }
+ return;
+ }
+
let bounds = graphic_element.bounding_box(DAffine2::IDENTITY, true);
// Render the thumbnail from a `GraphicElement` into an SVG string
diff --git a/node-graph/gcore/src/lib.rs b/node-graph/gcore/src/lib.rs
index 1333ec7433..4f1f0aaf0b 100644
--- a/node-graph/gcore/src/lib.rs
+++ b/node-graph/gcore/src/lib.rs
@@ -22,6 +22,7 @@ pub mod ops;
pub mod raster;
pub mod raster_types;
pub mod registry;
+pub mod render_complexity;
pub mod structural;
pub mod text;
pub mod transform;
diff --git a/node-graph/gcore/src/render_complexity.rs b/node-graph/gcore/src/render_complexity.rs
new file mode 100644
index 0000000000..3c137c87e8
--- /dev/null
+++ b/node-graph/gcore/src/render_complexity.rs
@@ -0,0 +1,61 @@
+use crate::instances::Instances;
+use crate::raster_types::{CPU, GPU, Raster};
+use crate::vector::VectorData;
+use crate::{Artboard, Color, GraphicElement};
+use glam::DVec2;
+
+pub trait RenderComplexity {
+ fn render_complexity(&self) -> usize {
+ 0
+ }
+}
+
+impl RenderComplexity for Instances {
+ fn render_complexity(&self) -> usize {
+ self.instance_ref_iter().map(|instance| instance.instance.render_complexity()).fold(0, usize::saturating_add)
+ }
+}
+
+impl RenderComplexity for Artboard {
+ fn render_complexity(&self) -> usize {
+ self.graphic_group.render_complexity()
+ }
+}
+
+impl RenderComplexity for GraphicElement {
+ fn render_complexity(&self) -> usize {
+ match self {
+ Self::GraphicGroup(instances) => instances.render_complexity(),
+ Self::VectorData(instances) => instances.render_complexity(),
+ Self::RasterDataCPU(instances) => instances.render_complexity(),
+ Self::RasterDataGPU(instances) => instances.render_complexity(),
+ }
+ }
+}
+
+impl RenderComplexity for VectorData {
+ fn render_complexity(&self) -> usize {
+ self.segment_domain.ids().len()
+ }
+}
+
+impl RenderComplexity for Raster {
+ fn render_complexity(&self) -> usize {
+ (self.width * self.height / 500) as usize
+ }
+}
+
+impl RenderComplexity for Raster {
+ fn render_complexity(&self) -> usize {
+ // GPU textures currently can't have a thumbnail
+ usize::MAX
+ }
+}
+
+impl RenderComplexity for String {}
+impl RenderComplexity for bool {}
+impl RenderComplexity for f32 {}
+impl RenderComplexity for f64 {}
+impl RenderComplexity for DVec2 {}
+impl RenderComplexity for Option {}
+impl RenderComplexity for Vec {}
diff --git a/node-graph/gsvg-renderer/src/renderer.rs b/node-graph/gsvg-renderer/src/renderer.rs
index 70f7c18206..a71cdf1b56 100644
--- a/node-graph/gsvg-renderer/src/renderer.rs
+++ b/node-graph/gsvg-renderer/src/renderer.rs
@@ -10,6 +10,7 @@ use graphene_core::instances::Instance;
use graphene_core::math::quad::Quad;
use graphene_core::raster::Image;
use graphene_core::raster_types::{CPU, GPU, RasterDataTable};
+use graphene_core::render_complexity::RenderComplexity;
use graphene_core::transform::{Footprint, Transform};
use graphene_core::uuid::{NodeId, generate_uuid};
use graphene_core::vector::VectorDataTable;
@@ -204,7 +205,7 @@ pub struct RenderMetadata {
}
// TODO: Rename to "Graphical"
-pub trait GraphicElementRendered: BoundingBox {
+pub trait GraphicElementRendered: BoundingBox + RenderComplexity {
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams);
#[cfg(feature = "vello")]
@@ -1151,7 +1152,7 @@ impl GraphicElementRendered for GraphicElement {
}
/// Used to stop rust complaining about upstream traits adding display implementations to `Option`. This would not be an issue as we control that crate.
-trait Primitive: std::fmt::Display + BoundingBox {}
+trait Primitive: std::fmt::Display + BoundingBox + RenderComplexity {}
impl Primitive for String {}
impl Primitive for bool {}
impl Primitive for f32 {}