Files
Alonso Torres 217284b1e1 Improve path operations and edition (#10807)
*  Improve path operations and edition

* 🐛 Fix floating-point equality issues in path editing

Replace exact equality checks with tolerance-based comparisons
in path editing functions to handle floating-point rounding
differences after transforms, rotations, or curve fitting.

Changes:
- distribute-content: Round coordinates to 0.1 precision before
  grouping to ensure coincident nodes move together
- separate-node: Use gpt/close? instead of exact equality to
  find nodes with floating-point imprecision
- collision-step: Use mth/close? for tolerance-based comparison
  to detect paste collisions correctly
- resolve-edit-fills: Add cycle detection to prevent infinite
  loops with corrupted parent chains

Made collision-step, available-offset-step, and resolve-edit-fills
public for better testability.

Added comprehensive tests for all fixes covering both exact and
floating-point coordinate scenarios.

AI-assisted-by: qwen3.7-plus

* 🐛 Fix path editor code review findings

Fix issues identified during code review of path editor enhancements:

- Fix unused binding lint warning in distribute-content that blocked CI
- Fix collision-step floor comparison to use round instead of floor,
  correctly detecting collisions when coordinates drift slightly below
  integer boundaries
- Fix resolve-edit-fills to recurse through empty parent groups when
  searching for inherited fills in nested group hierarchies
- Fix expand-coincident-node-indices to use fuzzy comparison (gpt/close?)
  instead of exact equality, handling floating-point divergence after
  transforms or rotations
- Remove unreachable dead code in path-point* on-pointer-down handler
- Add tests for collision-step boundary cases, nested group fill
  inheritance, and coincident node alignment/flipping

AI-assisted-by: mimo-v2.5-pro

---------

Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-08-27 10:51:10 +02:00
..
2026-03-18 18:05:30 +01:00
2026-08-06 16:13:06 +02:00
2026-08-06 16:13:06 +02:00
2026-08-06 16:13:06 +02:00
2026-08-06 16:13:06 +02:00
2026-06-30 16:15:30 +02:00
2026-08-06 16:13:06 +02:00
2026-08-06 16:13:06 +02:00
2026-08-06 16:13:06 +02:00
2026-02-25 10:30:29 +01:00

Penpot WASM render

This is the canvas-based WebAssembly render engine for Penpot.

Rust & Emscripten

This project is a Rust crate that targets Emscripten (wasm32-unknown-emscripten).

We use wasm32-unknown-emscripten compilation target:

  • It compiles Rust code into WASM
  • It generates the JavaScript code (“glue”) to load and run the WASM code

How Rust, Emscripten, and WASM are connected

Skia

We use Skia, an Open Source 2D graphics library. In particular, the render engine uses Skia via custom binaries of the rust-skia crate.

How to build

With the Penpot Development Environment running, create a new tab in the tmux.

cd penpot/render-wasm
./build

You can also use ./watch to run the build on every change.

The build script will compile the project and copy the .js and .wasm files to their correct location within the frontend app.

Render targets

The same Rust source produces two artifacts, which differ only in compiler options:

Target Tuned for Cargo profile Consumed by
frontend speed release (-O3) frontend/resources/public/js
export size size (-Oz) exporter/resources/wasm
./build            # both targets, frontend first
./build frontend   # workspace / viewer renderer
./build export     # headless exporter renderer

./watch still follows a single target (frontend unless you pass one), since watching both would rebuild twice on every keystroke.

Each target keeps its own CARGO_TARGET_DIR (target/<target>), so switching between them does not invalidate the other's cache. Set BUILD_MODE=release (or NODE_ENV=production) for an optimized build; the default is debug.

Each target writes its own generated shared.js (the enum discriminants the CLJS side compiles against) next to the code that imports it — respectively frontend/src/app/render_wasm/api/shared.js and exporter/src/app/wasm/shared.js. Neither build writes to the other's paths.

Architecture overview

Edit your local frontend/resources/public/js/config.js to add the following flags:

  • enable-feature-render-wasm to enable this render engine.
  • enable-render-wasm-dpr (optional), to enable using the device pixel ratio.

How to test

We currently have two types of tests:

  • Unit tests
cd penpot/render-wasm
./test

Technical documentation