From 17e2aa6cb5470c55002400e60770f2cd4366fc84 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Thu, 30 Apr 2026 18:29:51 +0300 Subject: [PATCH] perf(canvas): avoid scene recording during live edits --- packages/core/src/canvas/renderer.ts | 2 ++ packages/core/src/canvas/renderer/pipeline.ts | 30 ++++++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/core/src/canvas/renderer.ts b/packages/core/src/canvas/renderer.ts index a2ee1f222..c6024b1d1 100644 --- a/packages/core/src/canvas/renderer.ts +++ b/packages/core/src/canvas/renderer.ts @@ -77,6 +77,8 @@ export class SkiaRenderer { scenePicture: SkPicture | null = null scenePictureVersion = -1 scenePicturePageId: string | null = null + lastObservedSceneVersion = -1 + lastSceneVersionChangeAt = 0 nodePictureCache = new Map() readonly labelCache = new LabelCache() readonly profiler: RenderProfiler diff --git a/packages/core/src/canvas/renderer/pipeline.ts b/packages/core/src/canvas/renderer/pipeline.ts index 84a63d622..ff58ae4bd 100644 --- a/packages/core/src/canvas/renderer/pipeline.ts +++ b/packages/core/src/canvas/renderer/pipeline.ts @@ -24,6 +24,9 @@ export function renderSceneToCanvas( export type RenderLayer = 'full' | 'scene' | 'overlays' +const LIVE_SCENE_CHANGE_MS = 120 +const now = typeof performance !== 'undefined' ? () => performance.now() : () => Date.now() + export function renderFromEditorState( r: SkiaRenderer, state: EditorState, @@ -77,6 +80,28 @@ export function renderFromEditorState( ) } +function hasVolatileOverlay(overlays: RenderOverlays): boolean { + return ( + overlays.dropTargetId != null || + overlays.rotationPreview != null || + overlays.editingTextId != null || + overlays.nodeEditState != null + ) +} + +function hasLiveSceneChange(r: SkiaRenderer, sceneVersion: number, layer: RenderLayer): boolean { + if (layer === 'overlays' || sceneVersion < 0 || sceneVersion === r.lastObservedSceneVersion) { + return false + } + + const timestamp = now() + const live = + r.lastSceneVersionChangeAt > 0 && timestamp - r.lastSceneVersionChangeAt < LIVE_SCENE_CHANGE_MS + r.lastObservedSceneVersion = sceneVersion + r.lastSceneVersionChangeAt = timestamp + return live +} + export function render( r: SkiaRenderer, graph: SceneGraph, @@ -105,10 +130,7 @@ export function render( } const hasVolatileOverlays = - overlays.dropTargetId != null || - overlays.rotationPreview != null || - overlays.editingTextId != null || - overlays.nodeEditState != null + hasVolatileOverlay(overlays) || hasLiveSceneChange(r, sceneVersion, layer) const canUsePicture = !hasVolatileOverlays &&