penpot/render-wasm
Alonso Torres f993f203bd
🐛 Fix problems with plugins API (#10412)
*  Adds static dispatch safe stubs in tests

* 🐛 Fix shapesColors metadata key to match ColorShapeInfo

* 🐛 Fix CommentThread.remove rejecting the owner's own threads

* 🐛 Fix page.removeCommentThread throwing on a spurious Promise

*  Implement ShapeBase.swapComponent in the plugin API

*  Expose File.revn in the plugin API

* 🐛 Fix FileVersion.createdAt calling Luxon method on a js/Date

* 🐛 Fix plugin font/typography application to text and ranges

* 🐛 Default plugin overlay interaction position for non-manual types

* 🐛 Fix plugin interaction setters passing an id-only shape

* 🐛 Fix grid addColumnAtIndex rejecting valid track types

* 🐛 Expose libraryId on library color/typography/component proxies

*  Implement LibraryTypography.setFont in the plugin API

* 🐛 Fix typography.applyToTextRange reading unexposed range bounds

* 🐛 Fix utils.geometry.center argument mismatch

* 🐛 Fix localStorage.removeItem calling getItem

* 🐛 Fix shape backgroundBlur proxy key casing

* 🐛 Report boolean shape type as 'boolean' in the plugin API

* 🐛 Return the resulting paths from plugin flatten

* 🐛 Make plugin z-order methods act on the target shape

* 🐛 Make is-variant-container? return a boolean

*  Implement Group.isMask in the plugin API

* 🐛 Return a shape proxy from TextRange.shape

* 🐛 Return the duplicated set from TokenSet.duplicate

* 🐛 Fix theme addSet/removeSet reading set name with a keyword

* 🐛 Accept string fontFamilies token value in the plugin API

* 🐛 Fix combineAsVariants ignoring the passed component ids

* 🐛 Fix board removeRulerGuide ignoring its argument

* 🐛 Fix board guides setter schema and parser

* 🐛 Avoid 0-byte allocation when syncing empty grid tracks

* 🐛 Validate grid track indices in the plugin API

* 🐛 Return null for empty input in group() and centerShapes()

* 🐛 Return TokenTypographyValue[] from a typography token's resolvedValue

* 🐛 Return TokenShadowValue[] from a shadow token's resolvedValue

* 🐛 Return string[] from a fontFamilies token's resolvedValue

* 🐛 Clear mutually-exclusive reps when setting LibraryColor gradient/image

* 🐛 Add readonly tags to types, deprecate Image type

* 📚 Update plugins changelog
2026-06-29 17:32:15 +02:00
..
2026-03-18 18:05:30 +01:00
2026-06-29 17:32:15 +02:00
2026-06-02 09:38:52 +02:00
2026-02-25 10:30:29 +01:00
2026-02-25 10:30:29 +01:00
2026-02-18 09:57:25 +01: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.

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