SolidTV Renderer 2.0 Is Released: Same Work, 40% Faster
By Chris Lorenzo · Published October 15, 2026 · 7 min read
Eleven days ago I announced the SolidTV Renderer 2.0 alpha, a ground-up rewrite of the renderer with the same API. 2.0 is now officially released. 2.0.0 went out on October 7, it has been running in production for almost a week, and the numbers are impressive: 2.0 does the same work as 1.x, with the same result on screen, about 40% faster across devices.
The alpha's numbers came from stress scenes on test devices. These come from a production app, which is the test that counts.
Renderer work per frame
~40% faster in production, across devices
Garbage per steady frame
30–120 B against up to 74 kB on 1.10
Text layout
2–3.7× faster with identical output
Slow frames on a Xumo TV
6.25% → 2.4% after the frame-cap fix
What production shows
Every frame, the renderer works out what changed on screen, then draws it. 2.0 does exactly the job 1.x did, and the screen looks the same. It just gets that job done about 40% faster, across the devices the app ships to. (For the technical reader: that's the update and draw phase of each frame, against 1.10.)
That time goes back to your app. At 60 FPS a frame lasts 16.7 ms, and everything has to fit inside it: handling the key press, processing data, layout, and the renderer's own work. The less of each frame the renderer takes, the more is left for everything else, and the less likely a busy frame runs long and drops.
The other half is garbage. 2.0 keeps node state in typed arrays, so a steady frame allocates almost nothing: 30 to 120 bytes in the lab, against up to 74 kB on 1.10. Less garbage created means less to collect, and fewer collection pauses landing in the middle of a scroll. On TVs with little memory, those pauses are the stutters you can see.
What's new since the alpha
2.0 has had seven releases since the alpha, up to 2.0.6 today. Most of that work came from running it on real hardware, much of it on a Xumo TV. Xumo TVs run WPE WebKit, the browser engine common on RDK-based TVs and set-top boxes.
Smoother frames on WebKit TVs
- The 60 FPS cap no longer holds frames that are on time. On WPE WebKit, frame timestamps are whole milliseconds and wobble around the display's refresh. The cap read some on-time frames as early and held them for a whole refresh, turning a 16 ms frame into a 33 ms one. 1.10 had the same flaw. With the fix, slow frames on the Xumo TV fell from 6.25% to 2.4%, and animated FPS rose from 57.0 to 59.2.
- Uncapped by default.
targetFPSnow defaults to uncapped. Set it to 60 to keep 1.10's cap. - Frames drawn while idle reach the screen. On WPE WebKit, a frame drawn while the app was
otherwise idle, like an image swapped from a timer or a QR code set from a promise, could stay off screen
until the next key press. The new
presentOnIdlesetting nudges WebKit to show it, and the loop still sleeps when nothing changes.
Faster text, laid out before it's needed
- Text layout is 2 to 3.7 times faster, with output identical to the bit. A test compares 25,160 layouts against a verbatim copy of the old code, and all 79 text visual regression snapshots still pass. On the Xumo TV, text layout fell from 97–124 ms per test run to 70 ms in a first run.
- Layout moves to idle time. Text nodes that exist but aren't on screen yet now lay out
while the renderer is idle, and the new
renderer.measureText()lets an app lay out text it knows is coming, like the next row's titles. The frame that brings that text on screen just looks the layout up.
That second change came out of the most interesting bug of the week. On the Xumo TV, one title on the test page dropped a frame on every run: 17 to 18 ms for a 16-glyph title that takes microseconds to lay out. The layout wasn't slow. That title was the 86th layout of the session, the one that made JavaScriptCore decide the layout function was hot enough for its optimizing compiler. On this engine that compile runs on the main thread, inside the frame. On a laptop the same compile takes about 1 ms.
Splitting the function in two only split the compile into more stalls. Moving layout into idle time took that stall from 3 runs out of 3 to none. A laptop profiler will never show you a stall like this, which is why a performance audit starts on the devices you ship to.
Animations that start and move evenly
- Cheaper to start. A key press often starts several animations at once. Starting one is
now 1.4 to 1.6 times faster in microbenchmarks (about 2.6 times with a
cubic-beziereasing), and it allocates about half the memory. - The first step is one frame. An animation started during a busy frame used to take that frame's whole delta as its first step, key handler included. A 200 ms focus animation started after a 46 ms key handler opened 23% of the way in. Now its first step is at most one frame.
- Even motion, opt-in. The new
animationSnapRatesetting steps animations by whole display frames instead of raw frame timestamps. On a 2020 Samsung TV running Tizen 5.5, 25% to 35% of raw steps were off by a quarter of a frame or more. With snapping, 86% to 90% of steps are exactly one frame, at the same frame rate. It stays opt-in until it has run on the LG and Xumo TVs.
Both animation fixes came out of a frame-pacing report from a partner team running 2.0.
Faster first screens and steadier images
- Shaders compile while the app waits for data. Between booting and the app's first API response, the renderer usually sits idle for a second or two. 2.0 now compiles the first screen's shader programs in that window, one at a time, instead of inside the first frames.
- More images in flight. On the Xumo TV, 2.0's cold page load trailed 1.10's, because 2.0 allowed only 4 image loads in flight, network fetches included. The default is now 14, which brought visible images in about a second sooner on a slow network. Cold loads on that TV are still a little behind 1.10, and they're next on my list.
- Image swaps under memory pressure. With
doNotExceedCriticalThresholdon, a large image swapped near the memory limit could stay stuck on the old image. 2.0.1 fixed it: in a test of 77 swaps under memory pressure, the swaps that never showed went from 29 to none. - Fewer draw calls. Rounded boxes that use the border or shadow shaders, but show no border or shadow, now batch across different opacities. A row of cards fading at different alphas no longer splits into separate draws.
For framework authors
2.0 also adds the pieces @solidtv/solid needed: TextNode.measure() for flex
layouts sized by their text, Node.insertBefore so draw order follows Solid's child order, a text
layout cache whose lookups went from up to 0.8 µs and 1 kB of garbage to 0.017 µs and none, and
1.10's read-only clippingRect. In DevTools, every WebGL program now carries the name of the
shader it draws.
Upgrading
For apps built on @solidtv/solid, upgrading is a version bump. Install 2.0 with the matching
Solid release, which is on npm's next tag:
npm install @solidtv/renderer@^2.0.6 @solidtv/solid@next
Three things to check:
- Fonts. 2.0 draws text only with SDF fonts, so every font your app uses needs an SDF atlas. If you already use SDF fonts, there's nothing to change.
- Defaults. A few defaults changed from 1.10. If your app relied on one, set it explicitly.
- WPE WebKit devices. On Xumo and other WPE-based devices, turn on
presentOnIdle.
| Setting | 1.10 | 2.0 |
|---|---|---|
targetFPS |
60 | Uncapped |
bounds |
200 on every side | [100, 100, 450, 50] top, right, bottom, left |
image |
4 | 14, and it now caps network requests too |
texture |
10 ms | 25 ms |
The browser floor is still Chrome 38, so 2.0 reaches the same Tizen, webOS, Android TV, Fire TV and set-top box browsers as 1.x.
What's next
- Cold image loads on WebKit TVs, to close the remaining gap with 1.10.
animationSnapRateon the LG and Xumo TVs, to see whether it can be on by default.- Solid 2.0, the reason this rewrite started.
From the first design doc to the 2.0.0 release took eight days. A week of production later, the numbers say it was worth it, and I'm excited to keep pushing.
Upgrading a production app?
If you'd like help moving your app to 2.0, or want someone to look at frame pacing on your devices, get in touch.
- Renderer:
@solidtv/renderer - Framework:
@solidtv/solid - Docs: solid-tv.github.io/solid
- GitHub: github.com/solid-tv/solid