The last time I wrote here about the layer based SVG engine (LBSE) was back in autumn 2021, when I published the technical design document. A lot has happened since then, but maybe not what you would expect after almost four years. The engine landed in WebKit and it works well, but it is still not the default. You have to switch it on by toggling a runtime setting (in MiniBrowser). Between autumn 2021 and late 2022 LBSE was bootstrapped upstream, patch after patch. We added support for all the individual building blocks that make up SVG: paths, shapes, text, polygons, etc. within the new LBSE design. After that first big push the work stalled for a few months and resumed in mid-2023, and lasted until April 2024, due to generous support by Wix. During that period most advanced painting features, such as clipping, masking, filters, non-solid paint servers (patterns, gradients), markers, etc. were all implemented, sharing the logic with HTML and CSS rather than running through the separate code paths, as the legacy SVG engine did. Then the work paused again. A project of this size needs sustained funding to move forward, and for a while that funding was not there.
LBSE is promising, but it still has to earn its place, and it is worth being precise about what that means, because the goal was never simply “make SVG faster”. The legacy SVG engine is an island: historically grown, it has its own painting code, its own handling of transforms, clipping, masking, etc. and it shares only a little of the code that renders HTML and CSS for historical reasons. Many improvements that went into WebKit, went into “the other engine”, the main part, the HTML/CSS rendering engine. GPU-accelerated transforms and animations, accelerated compositing, all the work that made HTML/CSS fast. SVG sat right next to it and got none of it. That is what LBSE is really about. Put SVG on the same machinery, and it inherits all of that at once, and it keeps inheriting whatever comes next, instead of someone having to build it a second time for SVG alone.
The catch is that shared machinery is general machinery, and generality is not free. The legacy engine has been hand tuned for exactly one job, with two decades of tuning behind it. LBSE, on the other hand, has to integrate surgically into the shared HTML/CSS rendering code, without regressing that code even a little. This is the hottest code in the engine and it renders every web page out there, so sprinkling SVG special cases through layout and painting until LBSE looks good is simply not an option. Whatever LBSE needs either fits the existing design, or it has to make the existing design better for HTML and CSS too.
There is a second kind of work hiding in there as well. Some things that are rare in HTML are everywhere in SVG. Transformations are the obvious example. A typical web page has a handful of transformed elements, while in SVG almost every single element can carry a transform, and deeply nested transforms are the norm rather than the exception. The shared code was written with HTML in mind, and it does its job perfectly well there. So parts of the shared machinery have to be reworked, and fast paths that nobody ever needed for HTML have to be invented from scratch, without making anything slower for HTML in the process.
So the bar is a double one. LBSE first has to be competitive with the legacy engine on the plain, everyday rendering that legacy is already good at, because nobody switches engines if a static icon that never moves suddenly takes longer to paint. The rest, the hardware acceleration and every future improvement to the HTML/CSS engine that SVG now gets for free, only counts as a win once that first bar is met.
Fast forward to early 2026: This year the status quo finally changed. Igalia made a one-off investment into a fresh round of LBSE development, to give the engine the chance to prove itself. We are hopeful to finally show the world that LBSE is performant, and to attract new partners who share our vision that a performant, hardware-accelerated SVG engine is the future for UIs on embedded devices. This is the first of two posts covering the first half of 2026, where we stand now and how the LBSE project evolved since the long break in 2024. The last six months were intense, and ended with the single most invasive change to LBSE since it was first written. This post covers that change, and the next one picks up the hard problem it left behind.
A quick reminder of where we were#
When we designed LBSE, the central idea was simple. Instead of keeping the old, separate SVG painting code, SVG should reuse the very same machinery that HTML and CSS already use, the RenderLayer tree. That is what unlocked hardware-accelerated transform animations, perspective transformations, z-index support - all the nice things SVG never had before in WebKit.
To get there quickly, we took a shortcut in the early days. Every single SVG renderer got its own RenderLayer. A <rect> , a <path> , a <g> , everything. The reason was convenience: if every element has a layer, then the existing layer tree already knows how to order children, apply transforms, clip and composite. We did not have to reinvent any of that. Furthermore, the intrinsic SVG paint order, which follows the DOM structure 1:1, is guaranteed automatically this way, while z-index support is still there to deviate from that order when desired. All of that just works out of the box once every renderer receives its own layer. RenderSVGModelObject::requiresLayer() simply returned true all the time, and the rest of WebCore did the heavy lifting.
We knew from the start that this approach would most likely never ship in this form, because it is simply too wasteful. But that was fine. It was never meant to be the final design. What it gave us was a way to finally try out the things SVG had been missing for years, all running through the same machinery as HTML and CSS. It also gave us the possibility to reimplement all SVG render tree classes, in a way that’s fully unified between HTML and SVG, so that e.g. an SVG <clipPath> applied to an SVG element or an HTML element would no longer run through different code paths, as it historically did in WebKit. Thus just maintaining a 1:1 correspondence between renderers and layers was the fastest path to seeing the idea actually work, and once we had, the real shape of the engine could follow.
... continue reading