From 8bd3ef717c08f8f9bb762c42cff4767d99eb746d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Wed, 14 Jan 2026 18:13:56 +0100 Subject: [PATCH 1/7] :tada: Apply blur to canvas when switching pages --- frontend/src/app/main/ui/workspace.cljs | 6 ++++- .../main/ui/workspace/sidebar/sitemap.cljs | 26 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs index 53a1dc2621..10c25578a4 100644 --- a/frontend/src/app/main/ui/workspace.cljs +++ b/frontend/src/app/main/ui/workspace.cljs @@ -275,7 +275,11 @@ :wglobal wglobal :layout layout}]) (when (or (not (and file-loaded? page-id)) - (and wasm-renderer-enabled? (not @first-frame-rendered?))) + ;; in wasm renderer, extend the pixel loader until the first frame is rendered + ;; but do not apply it when switching pages + (and wasm-renderer-enabled? + (not file-loaded?) + (not @first-frame-rendered?))) [:> workspace-loader*])]]]]]])) (mf/defc workspace-page* diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs index 28fe1cee38..040b1055b4 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs @@ -13,6 +13,7 @@ [app.main.data.helpers :as dsh] [app.main.data.modal :as modal] [app.main.data.workspace :as dw] + [app.main.features :as features] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.title-bar :refer [title-bar*]] @@ -25,6 +26,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] + [app.util.timers :as timers] [cuerdas.core :as str] [okulary.core :as l] [rumext.v2 :as mf])) @@ -52,6 +54,13 @@ refs/workspace-data =)) +(defn- apply-canvas-blur + "Apply blur filter to the viewport canvas element immediately. + This is used to provide visual feedback during page navigation." + [] + (when-let [canvas (dom/get-element "render")] + (dom/set-style! canvas "filter" "blur(8px)"))) + ;; --- Page Item (mf/defc page-item @@ -63,6 +72,21 @@ navigate-fn (mf/use-fn (mf/deps id) #(st/emit! :interrupt (dcm/go-to-workspace :page-id id))) read-only? (mf/use-ctx ctx/workspace-read-only?) + on-click + (mf/use-fn + (mf/deps id) + (fn [] + ;; when using the wasm renderer, apply a blur effect to the viewport canvas + (if (features/active-feature? @st/state "render-wasm/v1") + (do + (apply-canvas-blur) + ;; NOTE: it seems we need double RAF so the blur is actually applied and visible + ;; in the canvas :( + (timers/raf + (fn [] + (timers/raf navigate-fn)))) + (navigate-fn)))) + on-delete (mf/use-fn (mf/deps id) @@ -155,7 +179,7 @@ :selected selected?) :data-testid (dm/str "page-" id) :tab-index "0" - :on-click navigate-fn + :on-click on-click :on-double-click on-double-click :on-context-menu on-context-menu} [:div {:class (stl/css :page-icon)} From 43d1d127dc622e1817965b8e10af970d7d384a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Thu, 15 Jan 2026 14:23:20 +0100 Subject: [PATCH 2/7] :tada: Apply blur effect to previous canvas pixels while setting wasm objects --- .../main/ui/workspace/sidebar/sitemap.cljs | 13 +- .../app/main/ui/workspace/viewport_wasm.cljs | 6 + frontend/src/app/render_wasm/api.cljs | 41 ++--- frontend/src/app/render_wasm/api/webgl.cljs | 166 ++++++++++++++++++ frontend/src/app/render_wasm/wasm.cljs | 3 + 5 files changed, 194 insertions(+), 35 deletions(-) create mode 100644 frontend/src/app/render_wasm/api/webgl.cljs diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs index 040b1055b4..d578ccfbc5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs @@ -23,6 +23,7 @@ [app.main.ui.hooks :as hooks] [app.main.ui.icons :as deprecated-icon] [app.main.ui.notifications.badge :refer [badge-notification]] + [app.render-wasm.api :as wasm.api] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] @@ -54,12 +55,7 @@ refs/workspace-data =)) -(defn- apply-canvas-blur - "Apply blur filter to the viewport canvas element immediately. - This is used to provide visual feedback during page navigation." - [] - (when-let [canvas (dom/get-element "render")] - (dom/set-style! canvas "filter" "blur(8px)"))) + ;; --- Page Item @@ -79,8 +75,9 @@ ;; when using the wasm renderer, apply a blur effect to the viewport canvas (if (features/active-feature? @st/state "render-wasm/v1") (do - (apply-canvas-blur) - ;; NOTE: it seems we need double RAF so the blur is actually applied and visible + (wasm.api/capture-canvas-pixels) + (wasm.api/apply-canvas-blur) + ;; NOTE: it seems we need two RAF so the blur is actually applied and visible ;; in the canvas :( (timers/raf (fn [] diff --git a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs index 645cba9b15..0530b21a06 100644 --- a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs +++ b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs @@ -312,6 +312,11 @@ (js/console.error "Error initializing canvas context:" e) false))] (reset! canvas-init? init?) + (when init? + ;; Restore previous canvas pixels immediately after context initialization + ;; This happens before initialize-viewport is called + (wasm.api/apply-canvas-blur) + (wasm.api/restore-previous-canvas-pixels)) (when-not init? (js/alert "WebGL not supported") (st/emit! (dcm/go-to-dashboard-recent)))))))) @@ -340,6 +345,7 @@ (mf/with-effect [@canvas-init? zoom vbox background] (when (and @canvas-init? (not @initialized?)) + (wasm.api/clear-canvas-pixels) (wasm.api/initialize-viewport base-objects zoom vbox background) (reset! initialized? true))) diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 3059462cd6..13b74427f7 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -29,6 +29,7 @@ [app.main.worker :as mw] [app.render-wasm.api.fonts :as f] [app.render-wasm.api.texts :as t] + [app.render-wasm.api.webgl :as webgl] [app.render-wasm.deserializers :as dr] [app.render-wasm.helpers :as h] [app.render-wasm.mem :as mem] @@ -37,7 +38,6 @@ [app.render-wasm.serializers :as sr] [app.render-wasm.serializers.color :as sr-clr] [app.render-wasm.svg-filters :as svg-filters] - ;; FIXME: rename; confunsing name [app.render-wasm.wasm :as wasm] [app.util.debug :as dbg] [app.util.dom :as dom] @@ -279,30 +279,6 @@ [string] (+ (count string) 1)) -(defn- create-webgl-texture-from-image - "Creates a WebGL texture from an HTMLImageElement or ImageBitmap and returns the texture object" - [gl image-element] - (let [texture (.createTexture ^js gl)] - (.bindTexture ^js gl (.-TEXTURE_2D ^js gl) texture) - (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_WRAP_S ^js gl) (.-CLAMP_TO_EDGE ^js gl)) - (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_WRAP_T ^js gl) (.-CLAMP_TO_EDGE ^js gl)) - (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_MIN_FILTER ^js gl) (.-LINEAR ^js gl)) - (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_MAG_FILTER ^js gl) (.-LINEAR ^js gl)) - (.texImage2D ^js gl (.-TEXTURE_2D ^js gl) 0 (.-RGBA ^js gl) (.-RGBA ^js gl) (.-UNSIGNED_BYTE ^js gl) image-element) - (.bindTexture ^js gl (.-TEXTURE_2D ^js gl) nil) - texture)) - -(defn- get-webgl-context - "Gets the WebGL context from the WASM module" - [] - (when wasm/context-initialized? - (let [gl-obj (unchecked-get wasm/internal-module "GL")] - (when gl-obj - ;; Get the current WebGL context from Emscripten - ;; The GL object has a currentContext property that contains the context handle - (let [current-ctx (.-currentContext ^js gl-obj)] - (when current-ctx - (.-GLctx ^js current-ctx))))))) (defn- get-texture-id-for-gl-object "Registers a WebGL texture with Emscripten's GL object system and returns its ID" @@ -332,8 +308,8 @@ (->> (retrieve-image url) (rx/map (fn [img] - (when-let [gl (get-webgl-context)] - (let [texture (create-webgl-texture-from-image gl img) + (when-let [gl (webgl/get-webgl-context)] + (let [texture (webgl/create-webgl-texture-from-image gl img) texture-id (get-texture-id-for-gl-object texture) width (.-width ^js img) height (.-height ^js img) @@ -1448,6 +1424,12 @@ result))) +(defn apply-canvas-blur + [] + (when wasm/canvas + (dom/set-style! wasm/canvas "filter" "blur(4px)"))) + + (defn init-wasm-module [module] (let [default-fn (unchecked-get module "default") @@ -1469,3 +1451,8 @@ (js/console.error cause) (p/resolved false))))) (p/resolved false)))) + +;; Re-export public WebGL functions +(def capture-canvas-pixels webgl/capture-canvas-pixels) +(def restore-previous-canvas-pixels webgl/restore-previous-canvas-pixels) +(def clear-canvas-pixels webgl/clear-canvas-pixels) diff --git a/frontend/src/app/render_wasm/api/webgl.cljs b/frontend/src/app/render_wasm/api/webgl.cljs new file mode 100644 index 0000000000..764da6dfa4 --- /dev/null +++ b/frontend/src/app/render_wasm/api/webgl.cljs @@ -0,0 +1,166 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.render-wasm.api.webgl + "WebGL utilities for pixel capture and rendering" + (:require + [app.common.logging :as log] + [app.render-wasm.wasm :as wasm] + [app.util.dom :as dom])) + +(defn get-webgl-context + "Gets the WebGL context from the WASM module" + [] + (when wasm/context-initialized? + (let [gl-obj (unchecked-get wasm/internal-module "GL")] + (when gl-obj + ;; Get the current WebGL context from Emscripten + ;; The GL object has a currentContext property that contains the context handle + (let [current-ctx (.-currentContext ^js gl-obj)] + (when current-ctx + (.-GLctx ^js current-ctx))))))) + +(defn create-webgl-texture-from-image + "Creates a WebGL texture from an HTMLImageElement or ImageBitmap and returns the texture object" + [gl image-element] + (let [texture (.createTexture ^js gl)] + (.bindTexture ^js gl (.-TEXTURE_2D ^js gl) texture) + (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_WRAP_S ^js gl) (.-CLAMP_TO_EDGE ^js gl)) + (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_WRAP_T ^js gl) (.-CLAMP_TO_EDGE ^js gl)) + (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_MIN_FILTER ^js gl) (.-LINEAR ^js gl)) + (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_MAG_FILTER ^js gl) (.-LINEAR ^js gl)) + (.texImage2D ^js gl (.-TEXTURE_2D ^js gl) 0 (.-RGBA ^js gl) (.-RGBA ^js gl) (.-UNSIGNED_BYTE ^js gl) image-element) + (.bindTexture ^js gl (.-TEXTURE_2D ^js gl) nil) + texture)) + +;; FIXME: temporary function until we are able to keep the same across pages. +(defn- draw-imagedata-to-webgl + "Draws ImageData to a WebGL2 context by creating a texture" + [gl image-data] + (let [width (.-width ^js image-data) + height (.-height ^js image-data) + texture (.createTexture ^js gl)] + ;; Bind texture and set parameters + (.bindTexture ^js gl (.-TEXTURE_2D ^js gl) texture) + (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_WRAP_S ^js gl) (.-CLAMP_TO_EDGE ^js gl)) + (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_WRAP_T ^js gl) (.-CLAMP_TO_EDGE ^js gl)) + (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_MIN_FILTER ^js gl) (.-LINEAR ^js gl)) + (.texParameteri ^js gl (.-TEXTURE_2D ^js gl) (.-TEXTURE_MAG_FILTER ^js gl) (.-LINEAR ^js gl)) + (.texImage2D ^js gl (.-TEXTURE_2D ^js gl) 0 (.-RGBA ^js gl) (.-RGBA ^js gl) (.-UNSIGNED_BYTE ^js gl) image-data) + + ;; Set up viewport + (.viewport ^js gl 0 0 width height) + + ;; Vertex & Fragment shaders + ;; Since we are only calling this function once (on page switch), we don't need + ;; to cache the compiled shaders somewhere else (cannot be reused in a differen context). + (let [vertex-shader-source "#version 300 es +in vec2 a_position; +in vec2 a_texCoord; +out vec2 v_texCoord; +void main() { + gl_Position = vec4(a_position, 0.0, 1.0); + v_texCoord = a_texCoord; +}" + fragment-shader-source "#version 300 es +precision highp float; +in vec2 v_texCoord; +uniform sampler2D u_texture; +out vec4 fragColor; +void main() { + fragColor = texture(u_texture, v_texCoord); +}" + vertex-shader (.createShader ^js gl (.-VERTEX_SHADER ^js gl)) + fragment-shader (.createShader ^js gl (.-FRAGMENT_SHADER ^js gl)) + program (.createProgram ^js gl)] + (.shaderSource ^js gl vertex-shader vertex-shader-source) + (.compileShader ^js gl vertex-shader) + (when-not (.getShaderParameter ^js gl vertex-shader (.-COMPILE_STATUS ^js gl)) + (log/error :hint "Vertex shader compilation failed" + :log (.getShaderInfoLog ^js gl vertex-shader))) + + (.shaderSource ^js gl fragment-shader fragment-shader-source) + (.compileShader ^js gl fragment-shader) + (when-not (.getShaderParameter ^js gl fragment-shader (.-COMPILE_STATUS ^js gl)) + (log/error :hint "Fragment shader compilation failed" + :log (.getShaderInfoLog ^js gl fragment-shader))) + + (.attachShader ^js gl program vertex-shader) + (.attachShader ^js gl program fragment-shader) + (.linkProgram ^js gl program) + + (if (.getProgramParameter ^js gl program (.-LINK_STATUS ^js gl)) + (do + (.useProgram ^js gl program) + + ;; Create full-screen quad vertices (normalized device coordinates) + (let [position-location (.getAttribLocation ^js gl program "a_position") + texcoord-location (.getAttribLocation ^js gl program "a_texCoord") + position-buffer (.createBuffer ^js gl) + texcoord-buffer (.createBuffer ^js gl) + positions #js [-1.0 -1.0 1.0 -1.0 -1.0 1.0 -1.0 1.0 1.0 -1.0 1.0 1.0] + texcoords #js [0.0 0.0 1.0 0.0 0.0 1.0 0.0 1.0 1.0 0.0 1.0 1.0]] + ;; Set up position buffer + (.bindBuffer ^js gl (.-ARRAY_BUFFER ^js gl) position-buffer) + (.bufferData ^js gl (.-ARRAY_BUFFER ^js gl) (js/Float32Array. positions) (.-STATIC_DRAW ^js gl)) + (.enableVertexAttribArray ^js gl position-location) + (.vertexAttribPointer ^js gl position-location 2 (.-FLOAT ^js gl) false 0 0) + ;; Set up texcoord buffer + (.bindBuffer ^js gl (.-ARRAY_BUFFER ^js gl) texcoord-buffer) + (.bufferData ^js gl (.-ARRAY_BUFFER ^js gl) (js/Float32Array. texcoords) (.-STATIC_DRAW ^js gl)) + (.enableVertexAttribArray ^js gl texcoord-location) + (.vertexAttribPointer ^js gl texcoord-location 2 (.-FLOAT ^js gl) false 0 0) + ;; Set texture uniform + (.activeTexture ^js gl (.-TEXTURE0 ^js gl)) + (.bindTexture ^js gl (.-TEXTURE_2D ^js gl) texture) + (let [texture-location (.getUniformLocation ^js gl program "u_texture")] + (.uniform1i ^js gl texture-location 0)) + + ;; draw + (.drawArrays ^js gl (.-TRIANGLES ^js gl) 0 6) + + ;; cleanup + (.deleteBuffer ^js gl position-buffer) + (.deleteBuffer ^js gl texcoord-buffer) + (.deleteShader ^js gl vertex-shader) + (.deleteShader ^js gl fragment-shader) + (.deleteProgram ^js gl program))) + (log/error :hint "Program linking failed" + :log (.getProgramInfoLog ^js gl program))) + + (.bindTexture ^js gl (.-TEXTURE_2D ^js gl) nil) + (.deleteTexture ^js gl texture)))) + +(defn restore-previous-canvas-pixels + "Restores previous canvas pixels into the new canvas" + [] + (when-let [previous-canvas-pixels wasm/canvas-pixels] + (when-let [gl wasm/gl-context] + (draw-imagedata-to-webgl gl previous-canvas-pixels) + (set! wasm/canvas-pixels nil)))) + +(defn clear-canvas-pixels + [] + (when wasm/canvas + (let [context wasm/gl-context] + (.clearColor ^js context 0 0 0 0.0) + (.clear ^js context (.-COLOR_BUFFER_BIT ^js context)) + (.clear ^js context (.-DEPTH_BUFFER_BIT ^js context)) + (.clear ^js context (.-STENCIL_BUFFER_BIT ^js context))) + (dom/set-style! wasm/canvas "filter" "none") + (set! wasm/canvas-pixels nil))) + +(defn capture-canvas-pixels + "Captures the pixels of the viewport canvas" + [] + (when wasm/canvas + (let [context wasm/gl-context + width (.-width wasm/canvas) + height (.-height wasm/canvas) + buffer (js/Uint8ClampedArray. (* width height 4)) + _ (.readPixels ^js context 0 0 width height (.-RGBA ^js context) (.-UNSIGNED_BYTE ^js context) buffer) + image-data (js/ImageData. buffer width height)] + (set! wasm/canvas-pixels image-data)))) diff --git a/frontend/src/app/render_wasm/wasm.cljs b/frontend/src/app/render_wasm/wasm.cljs index 0f6a0f6c5f..6547d27b9a 100644 --- a/frontend/src/app/render_wasm/wasm.cljs +++ b/frontend/src/app/render_wasm/wasm.cljs @@ -12,6 +12,8 @@ ;; Reference to the HTML canvas element. (defonce canvas nil) +;; Reference to the captured pixels of the canvas (for page switching effect) +(defonce canvas-pixels nil) ;; Reference to the Emscripten GL context wrapper. (defonce gl-context-handle nil) @@ -56,3 +58,4 @@ :stroke-linecap shared/RawStrokeLineCap :stroke-linejoin shared/RawStrokeLineJoin :fill-rule shared/RawFillRule}) + From 89f40dcda231cc50af032f3862279e5ef4261eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Torr=C3=B3?= Date: Mon, 19 Jan 2026 11:24:19 +0100 Subject: [PATCH 3/7] :wrench: Move WebGL context error message to 'errors' namespace (#8117) --- frontend/src/app/main/ui/static.cljs | 4 ++-- frontend/translations/en.po | 12 ++++++------ frontend/translations/es.po | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/main/ui/static.cljs b/frontend/src/app/main/ui/static.cljs index 96ec92fd8b..668fe8dae0 100644 --- a/frontend/src/app/main/ui/static.cljs +++ b/frontend/src/app/main/ui/static.cljs @@ -312,8 +312,8 @@ [] (let [on-reload (mf/use-fn #(js/location.reload))] [:> error-container* {} - [:div {:class (stl/css :main-message)} (tr "labels.webgl-context-lost.main-message")] - [:div {:class (stl/css :desc-message)} (tr "labels.webgl-context-lost.desc-message")] + [:div {:class (stl/css :main-message)} (tr "errors.webgl-context-lost.main-message")] + [:div {:class (stl/css :desc-message)} (tr "errors.webgl-context-lost.desc-message")] [:div {:class (stl/css :buttons-container)} [:> button* {:variant "primary" :on-click on-reload} (tr "labels.reload-page")]]])) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 8524ffd135..840a85a8d4 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -1559,6 +1559,12 @@ msgstr "Old password is incorrect" msgid "feedback.description" msgstr "Description" +msgid "errors.webgl-context-lost.main-message" +msgstr "Oops! The canvas context was lost" + +msgid "errors.webgl-context-lost.desc-message" +msgstr "WebGL has stopped working. Please reload the page to reset it" + #: src/app/main/ui/settings/feedback.cljs:122 msgid "feedback.description-placeholder" msgstr "Please describe the reason of your feedback" @@ -8478,12 +8484,6 @@ msgstr "Recent" msgid "labels.deleted" msgstr "Deleted" -msgid "labels.webgl-context-lost.main-message" -msgstr "Oops! The canvas context was lost" - -msgid "labels.webgl-context-lost.desc-message" -msgstr "WebGL has stopped working. Please reload the page to reset it" - msgid "dashboard.restore-all-deleted-button" msgstr "Restore All" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index ff4edb86de..18867cf814 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -1552,6 +1552,12 @@ msgstr "El email o la contraseña son incorrectos." msgid "errors.wrong-old-password" msgstr "La contraseña anterior no es correcta" +msgid "errors.webgl-context-lost.main-message" +msgstr "Ups! Se ha perdido el contexto del canvas" + +msgid "errors.webgl-context-lost.desc-message" +msgstr "WebGL ha dejado de funcionar. Por favor, recarga la página para restaurarlo" + #: src/app/main/ui/settings/feedback.cljs:120 msgid "feedback.description" msgstr "Descripción" @@ -8331,12 +8337,6 @@ msgstr "Recientes" msgid "labels.deleted" msgstr "Eliminados" -msgid "labels.webgl-context-lost.main-message" -msgstr "Ups! Se ha perdido el contexto del canvas" - -msgid "labels.webgl-context-lost.desc-message" -msgstr "WebGL ha dejado de funcionar. Por favor, recarga la página para restaurarlo" - msgid "dashboard.restore-all-deleted-button" msgstr "Restaurar todo" From 498b0b30fe690fa921f7f6e968a6963d3c909d95 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 19 Jan 2026 12:17:58 +0100 Subject: [PATCH 4/7] :bug: Fix problems with layout --- frontend/src/app/render_wasm/api.cljs | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 13b74427f7..21229896ba 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -955,6 +955,7 @@ (set-shape-grow-type grow-type)) (set-shape-layout shape) + (set-layout-data shape) (set-shape-selrect selrect) (let [pending_thumbnails (into [] (concat From 2c1cc89f539a850df53652ba401abdd76d42bda9 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 19 Jan 2026 12:54:15 +0100 Subject: [PATCH 5/7] :bug: Fix problem with thumbnail generation --- frontend/src/app/render_wasm/api.cljs | 5 +++-- frontend/src/app/worker/thumbnails.cljs | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 13b74427f7..3b555e419c 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -1031,8 +1031,9 @@ (perf/end-measure "set-objects") (process-pending shapes thumbnails full noop-fn (fn [] - (when render-callback (render-callback)) - (render-finish) + (if render-callback + (render-callback) + (render-finish)) (ug/dispatch! (ug/event "penpot:wasm:set-objects"))))))) (defn clear-focus-mode diff --git a/frontend/src/app/worker/thumbnails.cljs b/frontend/src/app/worker/thumbnails.cljs index 9f757f037d..70d8216d14 100644 --- a/frontend/src/app/worker/thumbnails.cljs +++ b/frontend/src/app/worker/thumbnails.cljs @@ -179,6 +179,7 @@ (->> (render-canvas-blob canvas width height bgcolor) (p/fnly (fn [data cause] + (wasm.api/clear-canvas) (if cause (rx/error! subs cause) (rx/push! subs From f42ff27f3d1bde44a7567332c112afbe530acda1 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 19 Jan 2026 16:44:57 +0100 Subject: [PATCH 6/7] :bug: Fix problem with bools --- frontend/src/app/render_wasm/api.cljs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 13b74427f7..585ce73a70 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -1360,8 +1360,9 @@ all-children (->> ids (mapcat #(cfh/get-children-with-self objects %)))] + (h/call wasm/internal-module "_init_shapes_pool" (count all-children)) - (run! (partial set-object objects) all-children) + (run! set-object all-children) (let [content (-> (calculate-bool* bool-type ids) (path.impl/path-data))] From 324d54ad285b3be12f7415561e090436b69ec4cc Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Fri, 16 Jan 2026 12:36:50 +0100 Subject: [PATCH 7/7] :bug: Fix set all rounded corners to 0 --- render-wasm/src/shapes.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/render-wasm/src/shapes.rs b/render-wasm/src/shapes.rs index 59e2c2fc18..7c757a4e5e 100644 --- a/render-wasm/src/shapes.rs +++ b/render-wasm/src/shapes.rs @@ -90,6 +90,18 @@ impl Type { } } + pub fn clear_corners(&mut self) { + match self { + Type::Rect(data) => { + data.corners = None; + } + Type::Frame(data) => { + data.corners = None; + } + _ => {} + } + } + pub fn path(&self) -> Option<&Path> { match self { Type::Path(path) => Some(path), @@ -694,9 +706,11 @@ impl Shape { pub fn set_corners(&mut self, raw_corners: (f32, f32, f32, f32)) { if let Some(corners) = make_corners(raw_corners) { self.shape_type.set_corners(corners); - self.invalidate_bounds(); - self.invalidate_extrect(); + } else { + self.shape_type.clear_corners(); } + self.invalidate_bounds(); + self.invalidate_extrect(); } pub fn set_svg(&mut self, svg: skia::svg::Dom) { @@ -1590,6 +1604,13 @@ mod tests { } else { unreachable!(); } + + shape.set_corners((0.0, 0.0, 0.0, 0.0)); + if let Type::Rect(Rect { corners, .. }) = shape.shape_type { + assert_eq!(corners, None); + } else { + unreachable!(); + } } #[test]