|
| 1 | +<style> |
| 2 | + img { |
| 3 | + transition: transform 0.25s ease; |
| 4 | + } |
| 5 | + |
| 6 | + img:hover { |
| 7 | + -webkit-transform: scale(1.8); |
| 8 | + transform: scale(1.8); |
| 9 | + position: relative; |
| 10 | + z-index: 5; |
| 11 | + } |
| 12 | +</style> |
| 13 | + |
| 14 | +# Boosting LightningJS Performance by 50% |
| 15 | + |
| 16 | +LightningJS has earned its reputation as a fast and capable framework for building TV applications. When Lightning 2.0 emerged, it set a new bar for what was possible on constrained TV hardware, offering a WebGL-based renderer that was lightweight, approachable for web developers, and performant enough to run smoothly even on most TV devices. For many teams, it became the de facto standard, and for good reason. |
| 17 | + |
| 18 | +That legacy matters. LightningJS is a solid idea, built on a strong architectural foundation. Using WebGL for TV UIs is a smart choice, and the renderer exists thanks to a tremendous amount of thoughtful engineering. Credit is due to the people who carried Lightning this far; shout out to Frank and Jeffrey for building something that has enabled an entire ecosystem of TV applications. |
| 19 | + |
| 20 | +Lightning 3.0 was introduced with the promise of moving that success forward. In some areas, it does. Node creation is faster, the internal structure is more modern, and the ambition to evolve the framework is clear. The potential is absolutely there. But in practice, especially on real TV hardware, Lightning 3 has not yet delivered the performance improvements many of us were hoping for. |
| 21 | + |
| 22 | +This article is not a critique for its own sake. It is a call to the community and to the LightningJS team to focus together on what made Lightning successful in the first place: real, measurable performance on real devices. |
| 23 | + |
| 24 | +--- |
| 25 | + |
| 26 | +## Building on Lightning 3 in the Real World |
| 27 | + |
| 28 | +Over the last year, I built a SolidJS integration on top of the Lightning 3 renderer with a clear goal: to provide a highly performant, developer-friendly way to build production-grade TV apps. |
| 29 | + |
| 30 | +From a developer experience perspective, the results were encouraging. SolidJS proved to be an excellent match: fine-grained reactivity, predictable updates, and access to a large, healthy open-source ecosystem. Teams enjoyed building with it, iteration was fast, and initial page loads were snappy. |
| 31 | + |
| 32 | +However, once these applications reached real TV hardware, the experience changed. While startup performance was good, and pages loaded quickly, interaction performance was inconsistent. Animations felt heavier than expected. Basic navigation, something TV UIs must excel at, often fails to meet the smoothness bar users intuitively expect. |
| 33 | + |
| 34 | +After extensive profiling and testing, one thing became clear: SolidJS was not the limiting factor. The bottleneck was the Lightning JS Renderer itself. |
| 35 | + |
| 36 | +--- |
| 37 | + |
| 38 | +## From Assumptions to Evidence |
| 39 | + |
| 40 | +Initially, it was reasonable to assume hardware limitations were the cause. TV devices are underpowered, and pushing pixels is expensive. Maybe 30 fps was the best that could be achieved? Maybe the latest beta of Lightning 3 Renderer will improve performance… |
| 41 | + |
| 42 | +Instead, nearly a year after Lightning 3’s release, progress has centered around a prolonged beta with breaking changes but little measurable performance improvement. Text rendering has improved a bit. But these changes don’t help the render loop. |
| 43 | + |
| 44 | +The original authors of Lightning 2 and Lightning 3 are no longer involved. With that transition, some of the hard-won institutional knowledge around renderer performance appears to have faded. |
| 45 | + |
| 46 | +At the same time, there is a prevailing sense that the renderer is already well-optimized and continuing to improve. Unfortunately, extensive profiling and real-device testing do not support that conclusion. This disconnect creates a real risk: without deep familiarity with the renderer’s internals, performance issues can be underestimated, misdiagnosed, or deprioritized. |
| 47 | + |
| 48 | +At this stage, meaningful gains will not come from surface-level changes, but from deliberate, informed work in the renderer’s hot paths. This is precisely the moment for renewed focus, not complacency. If LightningJS is to regain its performance leadership, rebuilding that depth of understanding must be treated as a priority. |
| 49 | + |
| 50 | +--- |
| 51 | + |
| 52 | +## A Breaking Point: When “Good Enough” Wasn’t |
| 53 | + |
| 54 | +One client project made the situation impossible to ignore. The UI was intentionally simple: a hero section at the top, followed by horizontally scrolling rows of content tiles. This is a common, well-understood TV layout, and it was aggressively optimized at the application level. |
| 55 | + |
| 56 | +The feedback from the boss: |
| 57 | + |
| 58 | +> “Scrolling between rows feels a bit slow on the box. Can we make it smoother?” |
| 59 | +
|
| 60 | +At that point, there was nothing left to optimize in the application code. The framework layer had been pushed as far as it reasonably could. The remaining bottleneck was the renderer. |
| 61 | + |
| 62 | +So I started examining the renderer itself. |
| 63 | + |
| 64 | +--- |
| 65 | + |
| 66 | +## Understanding the Renderer |
| 67 | + |
| 68 | +Over the course of a month, I profiled the renderer deeply: the update loop, node lifecycle, shader switching, draw calls, garbage generation, and how state changes propagate frame to frame. This meant digging into WebGL internals and understanding exactly where time and memory were being spent. |
| 69 | + |
| 70 | +WebGL is powerful, but it does not make performance problems disappear. At the end of the day, this is still JavaScript running tight loops on constrained hardware. Every allocation matters. Every unnecessary branch matters. Every redundant calculation matters. And in its current form, the renderer was simply doing too much work per frame. |
| 71 | + |
| 72 | +--- |
| 73 | + |
| 74 | +## Fixing What Was Already There |
| 75 | + |
| 76 | +One of the first discoveries was the number of subtle but impactful bugs in the renderer. These were not failures that caused crashes, but inefficiencies that quietly compounded over time. The update loop, in particular, was performing significant unnecessary work each frame, amplifying performance costs on constrained hardware. |
| 77 | + |
| 78 | +I attempted to address these issues upstream by opening numerous pull requests. While some small fixes were ultimately accepted as bug corrections, discussion around performance implications was nonexistent, and to make an impactful performance difference would require a large refactor of the core. |
| 79 | + |
| 80 | +This experience highlighted a broader challenge. Despite being positioned as a community-driven open-source project, there is limited transparency into current priorities, performance goals, or the renderer roadmap. Without clear signals around what is being optimized, why certain changes matter, or how contributors can meaningfully engage, collaboration is impossible. |
| 81 | + |
| 82 | +This lack of clarity is also visible in long-standing feature requests with clear user impact. Right-to-left text support, for example, has been requested since January 2025, yet there is still no visible roadmap or guidance on when or how it will be addressed. This effectively excludes entire regions and languages from fully adopting LightningJS, not because of technical limitations, but because of prioritization. |
| 83 | + |
| 84 | +Similarly, magic mouse support was started but never completed. After waiting without clarity on timelines or ownership, I ultimately implemented full support directly within the SolidJS integration in order to ship production applications over a year ago. |
| 85 | + |
| 86 | +These are not edge cases. They illustrate a broader pattern: when priorities are opaque and follow-through is uncertain, contributors are forced to work around the platform rather than build alongside it. |
| 87 | + |
| 88 | +--- |
| 89 | + |
| 90 | +## Garbage Collection: A Silent Performance Killer |
| 91 | + |
| 92 | +Garbage collection proved to be another major factor. |
| 93 | + |
| 94 | +On TV hardware, GC is unforgiving. Allocations inside high-frequency loops, temporary arrays, short-lived objects, and implicit allocations inevitably lead to unpredictable stutters when the collector runs. |
| 95 | + |
| 96 | +The renderer was generating garbage continuously during the render loop. By restructuring this logic to reduce allocations as much as possible, the impact was immediate. GC pauses became rarer and shorter, and animations stopped hitching unpredictably. |
| 97 | + |
| 98 | +This is not about clever tricks or clean code; it’s about respecting the realities of constrained devices. Reducing garbage pressure is critical to overall application performance. |
| 99 | + |
| 100 | +--- |
| 101 | + |
| 102 | +## Doing Less Work Per Frame |
| 103 | + |
| 104 | +A third major area of improvement was caching. |
| 105 | + |
| 106 | +A surprising amount of work was being recomputed every frame, even when nothing had changed. By aggressively caching results and skipping unchanged states, the renderer simply did less work per frame. I still have a bunch of additional ideas to pursue in this area. |
| 107 | + |
| 108 | +--- |
| 109 | + |
| 110 | +## Real-World Results |
| 111 | + |
| 112 | +After fixing bugs in the update loop, eliminating garbage in hot paths, and caching work, the forked renderer consistently outperforms the upstream LightningJS renderer by approximately 50% in real-world scenarios. |
| 113 | + |
| 114 | +Testing was done on a Raspberry Pi 3, a constrained device that closely mirrors the performance characteristics of low-end TV hardware. Using Lightning 3 beta v20, the upstream renderer averaged around 30 FPS in a representative TV UI. With the forked changes applied, the same application on the same device consistently exceeded 45 FPS. |
| 115 | + |
| 116 | +These numbers come from real hardware, not desktop simulations, and the difference is immediately visible to end users. |
| 117 | + |
| 118 | +Watch the video for yourself: |
| 119 | +[Youtube](https://www.youtube.com/watch?v=byM5IzrLKJE) |
| 120 | + |
| 121 | +--- |
| 122 | + |
| 123 | +## Looking Forward |
| 124 | + |
| 125 | +At this point, continuing to upstream these changes no longer feels productive. The performance issues have been clearly identified, fixes have been proposed, and ample time has passed for review and discussion. That process has not resulted in meaningful action. |
| 126 | + |
| 127 | +At the same time, this work represents a significant investment of time, expertise, and real-world validation. It would be irresponsible to discard it or indefinitely delay its use while teams shipping production applications continue to struggle with performance constraints. |
| 128 | + |
| 129 | +For that reason, I am choosing a different path. The renderer improvements will be shared directly with the clients I work with, ensuring they can deliver the level of performance their products require. In parallel, I am exploring whether there is broader interest in accessing these updates and what a fair valuation for that work might be. |
| 130 | + |
| 131 | +This is not an attempt to fragment the ecosystem, but to acknowledge reality. Historically, competition has been one of the most reliable drivers of innovation in open-source and platform ecosystems. When progress stalls, alternative implementations often serve as the catalyst for renewed focus, clearer priorities, and better outcomes for everyone involved. |
| 132 | + |
| 133 | +--- |
| 134 | + |
| 135 | +To learn more and get involved: |
| 136 | + |
| 137 | +- **Official Website**: [lightningtv.dev](https://lightningtv.dev) |
| 138 | +- **GitHub Repository**: [github.com/lightning-tv/solid](https://github.com/lightning-tv/solid) |
| 139 | +- **Community Discord**: [Discord](https://discord.gg/HEqckxcB) |
| 140 | +- **Connect with Me**: [Chris Lorenzo on LinkedIn](https://www.linkedin.com/in/chris-lorenzo/) |
0 commit comments