mirror of
https://github.com/penpot/penpot.git
synced 2026-11-10 03:50:33 +00:00
120 lines
4.4 KiB
Markdown
120 lines
4.4 KiB
Markdown
# Penpot WASM render
|
|
|
|
This is the canvas-based WebAssembly render engine for Penpot.
|
|
|
|
## Rust & Emscripten
|
|
|
|
This project is a Rust crate that targets [Emscripten](https://emscripten.org/) (`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
|
|
|
|

|
|
|
|
### Skia
|
|
|
|
We use Skia, an Open Source 2D graphics library. In particular, the render engine uses Skia via [custom binaries](https://github.com/penpot/skia-binaries/releases/) of the [rust-skia crate](https://github.com/rust-skia/rust-skia).
|
|
|
|
## How to build
|
|
|
|
With the [Penpot Development Environment](https://help.penpot.app/technical-guide/developer/devenv/) running, create a new tab in the tmux.
|
|
|
|
```sh
|
|
cd penpot/render-wasm
|
|
./build
|
|
```
|
|
|
|
You can also use `./watch` to run the build on every change.
|
|
|
|
The build script compiles the project and copies the `.js` and `.wasm` files to the app that uses each target.
|
|
|
|
### 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` |
|
|
|
|
```sh
|
|
./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`.
|
|
|
|
Set `PENPOT_WASM_PREPARED=1` when the pinned Rust toolchain is selected, its
|
|
Emscripten target is installed, and this package's Node dependencies are
|
|
installed. `./build` and `./test` then skip `rustup` setup and `pnpm install`.
|
|
Benchmark preparation sets this flag for each retained build.
|
|
|
|
### Serialize builds in one checkout
|
|
|
|
All targets in one checkout share one `flock` lock stored at
|
|
`render-wasm/.render-wasm-build.lock`. The lock covers dependency setup, the
|
|
Cargo build, artifact copy, and target cleanup. If another build or cleanup
|
|
already holds the lock, the new process prints a waiting message and starts
|
|
only after the first process exits.
|
|
|
|
The watch command takes the lock for each build, then releases it while it
|
|
waits for source changes. The lock file stays in the checkout after a build,
|
|
but the operating system releases its lock when the process exits, including
|
|
after an error or signal.
|
|
|
|
The lock applies to one checkout and only to commands that use these scripts.
|
|
A manual Cargo build can still write to the same target without taking the
|
|
lock. Set `RENDER_WASM_LOCK_FILE` to the same path in each process when you
|
|
make different checkouts share a `CARGO_TARGET_DIR`. The supported Linux build
|
|
environment must provide `flock` from util-linux; `flock --version` checks this
|
|
dependency.
|
|
|
|
Use the target cleanup commands instead of running `cargo clean` on the shared
|
|
`target/` directory:
|
|
|
|
```sh
|
|
./clean frontend # remove target/frontend only
|
|
./clean export # remove target/export only
|
|
```
|
|
|
|
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.
|
|
|
|

|
|
|
|
|
|
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
|
|
|
|
```sh
|
|
cd penpot/render-wasm
|
|
./test
|
|
```
|
|
|
|
- [Visual Regression Test](./docs/visual_regression_tests.md)
|
|
|
|
## Technical documentation
|
|
|
|
- [Rendering Architecture (Live vs Vector/PDF)](./docs/rendering_architecture.md)
|
|
- [Serialization](./docs/serialization.md)
|
|
- [Tile Rendering](./docs/tile_rendering.md)
|
|
- [Texts](./docs/texts.md)
|