It's time for Penpot to (almost) move away from the DOM

This will yield massive improvements on performance while respecting interoperability.

As Open Source fans and product builders, we have always believed in the idea of standing on the shoulders of giants and being completely transparent about how we’re building Penpot and why.

When we started building our open source design & prototyping tool a few years ago, we made a very smart decision: we offloaded all the visual rendering hard work to the browser. This allowed us to focus on the Penpot internals and innovate on end-user facing features at light speed. There are many examples of this but CSS Flex and Grid layouts immediately come to mind.

Betting on browsers (our giants in the above metaphor) for the visual output of the Penpot canvas gave us a lot in exchange for a very small price to pay: using the browser’s DOM rendering mechanism. In very simple terms, the browser DOM is an API that interprets HTML/CSS and javascript and “draws” for you; it’s how 99% of the web operates and you can do pretty cool things with that.

We then asked ourselves what a “natural” format would look like to represent DOM-friendly vector graphics. SVG, an open standard, came out as a clear winner and so we started implementing a lossless SVG translation from our internal data representation. For a while all was bliss in the Penpot world, but we recently started to see the cracks in that approach.

At Penpot we’re not afraid of changing our minds if there’s new evidence or a new context. It’s vital that we are able to pivot around core tech decisions. In this particular case, not addressing the way we render our vector graphics could pose a risk to our continued success beyond 2025, so we need to act now.

The cracks

You can skip this section and jump right to the conclusion but I’d be happy if you stay with me to read about three distinct problems.

  • Browsers are still using SVG v1.1 spec from 2011 and haven’t really worked on seriously adopting 2.0, even if the first draft is from 2018 and an almost final version was published last year. This is quite disappointing, to be honest.

  • Browser management of the DOM struggles with an SVG-based infinite canvas. The performance is simply not there. The simplicity of the DOM (eventually) becomes its Achilles’s’ heel as the browser blindly tries to render every single element of the SVG regardless of the zoom level or the effective panning crop.

  • With recent Penpot innovations around declarative design and better collaborative features for designers and developers, we were starting to abuse the SVG format a bit too much. Even simpler things like multi-stroke support– which is absent on SVG 1.1 but which we introduced in Penpot 1.13 two years ago– required some nice hacks.

In isolation, none of these are deal-breakers. Combined, however, they start to wear on our capabilities. The Penpot community is trusting us to build the best design and prototyping tool, not just an OK-ish alternative to proprietary software. And our community demands that because, honestly, we always said that was our ambition.

We strongly believe the real issue is the DOM treatment of all major browsers, while the SVG is really just the canary in the mine. That said, once you make the decision to move away from the DOM (at least for the rendering responsibility), why not also ask yourself: what about SVG?

A serendipitous opportunity

Our own vision of what Penpot could achieve for the broader design and code community has evolved over the past couple of years. We are now looking at both declarative and imperative design paradigms, and this requires to have a more agnostic view on how we represent visual artifacts on a canvas. Which one is better? Imperative, like SVG, or declarative, like CSS? Well, it depends.

This “it depends” opens up a wormhole that can lead us to a new and exciting unexplored part of the software universe; an open format that can express interactive UI design directly as code.

I’m aware that this is a bigger topic and I wanted to keep this post short, but this is something that, if done right, could have profound repercussions on how we address the dual (visual and code) nature of UI.

For the moment, it’s fine if we just “move stuff around super fast.” If we won’t be leveraging the browser’s DOM free SVG rendering anymore, we are free to come up with our own ways of drawing pixels.

The conclusion

The work around a new Penpot rendering engine has already started. We will publish all the details as soon as there’s something juicy to discuss, and not any moment later.

Being a refactor-type adjustment, the vast majority of users will never get to learn about all this, because 1) it won’t affect the Penpot’s UI, 2) it’s going to be quite transparent in terms of functionality and 3) you will still be able to export your work as SVG (like now).

Actually, this is the type of technical decision that most of the companies never feel the need to share. But for us it would feel extremely awkward not to be absolutely transparent with every important decision we make as we continue to build the absolute best design and prototyping tool for designers and developers.

PS: If you feel like you could give us some tips around do’s and don’ts, feel free to reply to this thread or reach out to us via pablo.ruiz@penpot.app, where you can produce more structured suggestions. The team will make sure to give credit to all contributors!

33 Likes

Thank you for this! :clap: :clap: :clap:

1 Like

That’s why we love you (well…not only for this)!

4 Likes

The main issue I encountered with Penpot is that the exported SVGs don’t match how they appear in the tool. This is why I switched back to Figma. Are there any plans to add SVG editing tools like union, subtract, intersect, etc.

5 Likes

I would be interested following along the development, are there any public design documents / ideas described more in-depth we can read? I am not an expert on this area but have an academic interest.

1 Like

Absolutely, we will be sharing bits of the process. We’re still making decisions about how exactly to move forward in terms of technical decisions and architecture but, as a I say in my post, we’ll be communicating all of this once the real work has started.

1 Like

Whatever we add to Penpot (like union, subtract or intersect of paths/shapes) won’t necessary be in relationship with a particular format, like SVG. So the answer could be “yes” and “no” at the same time. We want to improve vectorial editing capabilities and make sure we can export really good SVG but these are separate tasks, I hope this made sense! :rofl:

1 Like

Have you thought about using <canvas> instead of SVG? I have used this for massive data visualization with scroll and zoom and a lot of other crazy quick interaction, like drawing items etc. It seems like this is what Figma is using . You can still create the SVGs using the same techniques to get identical SVG exports. I’m happy to share more about this approach if you are interested.

1 Like

Would canvas be way more performant? That’s the main issue here.

Yes, much more performant. One reason is that you no longer need the DOM but rather draw an image. Another reason is that it’s easier to filter which objects are drawn etc. I have used this to draw candle charts with hundreds of thousands of candle bars with interactivity.

Seems like I can’t upload a video. I can share the video over email, got any way to reach you directly?

Hi, let me share some engineering updates regarding the phasing away of the current, SVG-based render engine.

About the ongoing debate in this thread, @ohenrik is right in that a canvas-based engine would be much more performant. We just finished a proof of concept of a WebAssembly canvas-based render engine and this is the approach we will be taking.

We believe there are big potential gains we can reap with this. I cannot give you a specific date for when this work will be finished, but rest assured this is one of our top priorities.

It will also be fun to code, I’m not going to lie! :stuck_out_tongue: We’ll keep the community updated, of course.

Cheers!

10 Likes

That’s great to hear! Looking forward to seeing the new engine. Would love to learn more about the WebAssembly part of this, as I have not attempted that myself. Looking forward to seeing the code once it’s public (in a public branch).

Awesome news! Do you plan to make your progress as a public repo before a public release?

Best

Hi again! The code will live along the rest of Penpot, in the usual repo GitHub - penpot/penpot: Penpot: The open-source design tool for design and code collaboration This feature will be disabled by default via flags until it is ready to ship, of course, but you will be able to peek the develop branch as usual. And don’t forget you can also take a look at our backlog in Taiga :wink:

6 Likes

This looks really promising!

Haven’t used penpot in a self hosted way yet, is there a guide/documentation page that explains how to set flags?

1 Like

@ericwaetke In the technical guide there’s a config page, I hope that helps! 2. Penpot Configuration

Very ambitious plan !

From Penpot repo, it seems like you are going to use skia wasm. I’d be curious to know why you expect to be faster than the browser which is already using native skia ? Maybe using / contributing to Vello could lead to better performance.

I don’t want to sound too negative, I am super happy this project exists, but here is my humble opinion :

In Penpot, we are drawing UI. Any UI mockup will always be of reasonable complexity to target the web DOM (we’re drawing apps & website, not video games with million of entities).

So if mockups are slow to draw in Penpot then it is an issue with Penpot, not with the DOM.

Penpot is slow to scroll even an empty page, but my browser can render the most complex website with thousands of glyphs, shapes, images, blur effects, animations, etc. at 144fps in 4k. So I wouldn’t conclude that the issue is the DOM vs. canvas, the issue is Penpot.

I can also export a Penpot mockup to SVG, reopen it in the same browser and suddenly scrolling & zooming goes from 5fps to 144fps at 4k. Once again I think the issue is with Penpot, not with the DOM/SVG.

  • One improvement could be to switch Penpot from SVG to actual DOM. On Firefox for e.g, AFAIK the DOM is fully GPU accelerated with WebRender, while SVG is not (it is drawn on CPU with skia I believe). Since Penpot abstracts the design language anyway, you could keep the same user-facing abstractions but switch to the DOM (so a Penpot “rectangle” becomes a div, a “circle” becomes a div with border radius 100%, etc.). Then you make an exception for curves (which have to be svg). This would solve a lot of problems, no more hack for text-in-svg, native flexbox and grid layout, native backdrop-filter blur, etc.

  • Another issue could be that, when unzoomed, dislaying all boards at once represent a lot to draw. Here you could snapshot the board and show an image or use LOD (for e.g replace text with small rect like in VSCode’s minimap), etc. I think there are lots of techniques to make this viable.

Given how smooth even the most complex website render in browsers, I pretty convinced the DOM is not the issue, but in any case, I’m looking forward to see Penpot grow whatever technical direction you take !

@hahmi
My understanding is that penpot already tries to render raster thumbnails and show them instead of full rendering when a top-level frame is not selected: penpot/frontend/src/app/worker/thumbnails.cljs at develop · penpot/penpot · GitHub

That does seem to lead to subtle bugs reported on this forum, where the thumbnail is out of date, and the performance is still not on par with Figma’s renderer even then. Not dismissing your points but specifically for thumbnailing, that seem to already be implemented.

1 Like

Hi @hahmi , there are many things that affect performance, the render engine / mechanism used to display the user design is one of them (but an important one!). Take into account that Penpot is an app, and a lot of the logic done at the server for validation, calculating layouts, etc. is also done at the client to increase responsitivity.

Relying in the DOM (performance issues of having a huge DOM to deal with aside) has the problem of being browser-dependent. We would also need to rewrite a lot of rendering code to handle exporting to an SVG or PDF, for instance.

The suggestion of using thumbnails is good, but we’re already doing it (and as other user mentioned, there are subtle bugs related to using this technique) and has only gotten us this far.

Using the canvas is not the first idea that came to our mind. We also analyzed what other UI design apps are doing (tl;dr: <canvas> + Wasm), built PoCs… We truly think this is the right approach.

3 Likes