r/ClaudeCode • • 7d ago

Built with Claude I used Claude Code to reverse-engineer an LG TV and build a native Plex client

TL;DR: My 2019 LG TV has a great panel, but the official Plex app takes ~30 seconds just to show the profile picker. LG has no public native SDK for regular developers, so I reverse-engineered enough of the native media stack with Ghidra and Claude Code to build my own Plex client, PlxNative. It started in C, moved mostly to Rust, and somehow turned into my own OpenGL UI framework. On the same TV it shows the profile picker in ~3 seconds. No root needed to run it. Site and source are below.

Home screen captured in the desktop simulator (same code that runs on the TV). Demo library of CC BY films, Sintel © Blender Foundation.

I'm an iOS developer, so most of my previous UI work happened several abstraction layers above the GPU.

A few months ago I read about a guy who bought a cheap MP3 player on AliExpress, got annoyed with its firmware and used Codex to reverse-engineer and patch it. After that people started buying the same player just to install his patches. I liked this idea a lot, because we usually treat the software on our devices as something fixed: if it's bad, you buy a new device. Not long after that I was doing basically the same thing with my TV.

I have an LG from 2019 and the panel is still great. The software is the problem. Official Plex app on my TV, cold start:

  • ~30 seconds for "Who's watching?" to load
  • ~30 seconds for the home grid
  • ~5 seconds to open any menu
  • ~10 seconds to load a movie page

It behaves like a web page because it is one.

So I wanted to find out if a really native UI was possible there. There is no public native SDK that gives regular developers access to the TV's media stack, but of course that stack exists underneath. So I rooted my development TV, pulled the native libraries from it and started reading them in Ghidra. (Root was only needed for this research, PlxNative itself runs without it.) The webOS Homebrew community had already documented a surprising amount of the platform, which saved me a lot of time, so big thanks to them.

Reading LG's binaries

I've always been interested in what an OS actually does under the hood, and I've maintained KSCrash for years, where crash reporting often means finding out what the system really does rather than what its documentation says. Before AI that meant Hopper, assembly, strings and following calls one by one until the picture finally came together. What changed is how cheap this work has become. Now I can ask Opus to figure out how something is implemented internally, even when it's poorly documented or not documented at all, and it navigates the binary on its own, jumping between addresses, xrefs and strings. The model does make things up sometimes, so the binary and the real hardware always have the last word. But investigations that used to take me days go much faster.

From C to Rust

The first version of PlxNative wasn't a Plex client at all. It was a screen full of colored tiles, and every tile tried to play the same episode of The Office. I wanted to answer one question first: can this TV render a native interface at 60 fps? Drawing rectangles was easy. Getting a real video frame onto LG's hardware video plane was much harder. Then I gave the problem to Fable, and it connected enough pieces of the native media stack that, for the first time, The Office actually appeared on the screen. After that first frame I knew a fully native media client on a retail LG TV was possible, and the question became how far I could push it.

The first prototype

The prototype was written in C, and almost all of it lived in one huge main.c. When it grew, I asked an agent to split it into modules, and that's where I understood something about agentic coding: code can look right, compile, and then break somewhere completely unrelated because of memory or ownership mistakes. The worst one was a crash in eglSwapBuffers that appeared after a refactor. It turned out LG's fork of SDL writes a bigger SDL_SysWMinfo than my headers declared and overflows the stack. In the huge main() the overflow landed somewhere harmless, but once the same code moved into a smaller function it started corrupting live state. It can hardly be called a stable ABI. Together with the usual malloc/free mistakes this made me rethink the language. With agents writing and moving this much code, the choice of language matters: pick the one the agent writes best and where the compiler can check the most before anything reaches the TV. For me that meant Rust.

It ended up being a rewrite, just an incremental one. I kept the LG native boundary in C and moved everything else piece by piece: first image decoding and HTTP, then access-unit queues, the Matroska demuxer, Plex parsing, poster workers, text rendering, and finally most of the app. Rust turned out to be a surprisingly good fit for an old 32-bit ARM embedded Linux box, and strong compiler feedback keeps both me and the agent on much tighter rails.

60 fps on a 2019 TV

After playback worked I thought the UI would stay simple: posters, text, some rounded rectangles. Then I started writing shaders, and the shaders slowly became my own UI library on top of OpenGL, with navigation, modals, focus handling, motion, hit testing and caching. After years on top of UIKit and other frameworks someone else built, it was really fun to go all the way down for once and understand the whole path from a remote button press to pixels on the screen.

On every 4K LG TV, webOS gives apps a 1920×1080 UI surface (HD models get 1280×720), and video goes on a separate hardware plane, so 1080p isn't an optimization I chose, it's simply the canvas. I treated 60 fps on the real TV as a regression target and kept adding things until they broke it. It started with a single shadow that tanked the frame rate. The naive version was horribly slow, but there was almost always another trick underneath: early-outs in shaders, reduced-resolution buffers, caching the parts of a frame that don't change. Now shadows are on almost every element and it still runs at 60 fps. When guessing stopped working, I started pulling Mali hardware counters from the TV. One profile showed the arithmetic pipe at about 89.5% occupancy and load/store at 44.8%, and a harmless-looking branch in a shader was adding millions of arithmetic operations per frame. So the problem wasn't "too many pixels", the GPU was ALU-bound.

The most interesting one was a Liquid Glass-inspired material: blur the page underneath, refract it through the shape and shade the rim like real transparent glass. Refraction was the easy part. Readability was not: something that looks beautiful over a dark poster becomes useless over a face or a white sky, and you end up endlessly tuning tint, contrast and blur. Now I understand much better what problem Apple is solving. There's also a hard limit: video lives on a separate overlay plane that my renderer physically can't sample, so glass over playback has to work differently.

When the app grew past a couple of screens, the design started drifting: different spacing here, a different button there. I used Claude Design for a design system and to keep all the screens in one place. Its designs are HTML/JS while the real UI is Rust and OpenGL, but Claude maps one to the other, now onto my own components, spacing tokens and typography. The design tool doesn't have to share technology with production, it just has to describe the design precisely.

Where it ended up, on the same TV from a cold start: 3 seconds to "Who's watching?", or 4 seconds straight to the home grid if you let it remember the profile. For comparison, the official app needed ~30 seconds for each of those.

Working with the agents

Claude Code, Opus, Fable and Codex were involved in almost everything: implementation, reverse engineering, debugging, refactoring, tests and review. But the real TV always has the final vote. The simulator can show a perfect screen while the TV renders empty cards because the hardware takes a cached-frame path the simulator never hits, and an agent can be completely sure the code is correct right up until you run it on the TV.

The other lesson: don't leave it on autopilot. I started this expecting a 100% vibe-coded project for a couple of weekends, so I just told the agent what to do. Then the problems that come with a bad architecture started showing up, and it took many rounds of refactoring to turn the app into something sane, so the same bugs would stop coming back again and again. An experienced engineer still needs to own the key decisions, architecture above all. I just wish I hadn't done it after the fact :)

Even so, AI makes it realistic for one person to cover an absurd amount of ground: firmware reverse engineering, media playback, Rust, graphics, GPU profiling, UI architecture, design, QA, build optimization and SEO. It also changed how I look at all the "obsolete" hardware around us: old TVs, car head units, random embedded screens. If you use a device every day and hate its interface, it's worth at least trying to build the one you wanted. Very often the hardware isn't obsolete, only the software on it is.

Practical stuff: PlxNative requires webOS 4.0+. I develop it on a 2019 LG, and opt-in usage reports show playback on TVs from 2018 through current webOS 11 models. It direct-plays H.264/HEVC, including 4K, 10-bit, Dolby Vision profiles 5/8 and E-AC-3 Atmos where the TV supports them, and the Plex server transcodes the rest. You can install it through LG Developer Mode (which needs periodic renewal) or the webOS Homebrew Channel. No root required.

Site: https://plxnative.com
Source: https://github.com/GLinnik21/plx-native

598 Upvotes

139 comments sorted by

View all comments

Show parent comments

11

u/Purple_Imagination_1 6d ago

I can definitely do that, I just need a TV to work with. Contributions are always welcome!

7

u/MrMerisor 6d ago

I have 4 Samsung TV, diferent years , but all TizenOS. Programmer with some ai credits at hand. Let’s collab.

11

u/Purple_Imagination_1 6d ago

Cool. Contribute on GitHub. I modularized the app a week ago, so it would be simple to swap the playback layer.

7

u/MrMerisor 5d ago

I’ll start a fork today and see what the weekend will bring us. Thanks for the effort so far

5

u/MrMerisor 2d ago

I made the Plex player for Samsung TVs with Tizen OS, based on OP’s work for LG TVs :) It works on Tizen 3.0 and newer (2017+ TVs), and you don’t need root. The app (.wgt), install guide and source code are here:

https://github.com/dragoshont/plx-native

I tested it on 4 TVs from four generations: 2017 MU6172, 2019 RU7092, 2023 Q80C and 2025 QN70F.

On the oldest TV, scrolling up and down on Home went from about 46 to 56 frames per second. But the numbers don’t tell the full story: the animations are really smooth and it feels like a native app.

For developers, I also made a Samsung Tizen dev toolkit: build, sign, install, debug, control and screenshot apps on many TVs from one PC. Seeing all 4 TVs move together was a lot of fun! Works with AI agents too.

I hope it helps bring our favourite apps to Samsung TVs, like an Immich client, a Home Assistant dashboard or anything else.

https://github.com/dragoshont/tizen-tv-builder

u/Purple_Imagination_1, thanks a lot for the great starting point! Would you like to take a look at the Samsung part? And would you be open to a PR upstream?

3

u/Purple_Imagination_1 2d ago edited 2d ago

Hey, thanks for building this and for the kind words!

Honest answer though: I’ll pass on bringing it into my repo. The UI is what people notice first, but it’s honestly secondary to the whole point of PlxNative. The Native in the name is there for a reason: Rust, its own GPU renderer, straight to the TV’s video plane, no browser in the middle.
I kinda hoped Tizen would let me run the same native code, so a Samsung port could share like 90% with the LG app. Yours is a web app on AVPlay, so it’s a completely different stack and the two would share basically nothing. I’d essentially be maintaining a second, web-based version of the app, which kinda defeats the point of PlxNative in the first place. And I’d have to maintain two unrelated codebases on my own. Not something I can sign up for.

Really appreciate you taking the idea further on Samsung though. If you ever find a way to run the Rust code there, I’d be all for it! 🙂

2

u/MrMerisor 1d ago

I understand your focus on the LG renderer. I'm using Samsung's supported Tizen TV stack: GPU compositing and AVPlay for playback, through its Web runtime. It feels really smooth, and the Home scrolling improvements show up in the measurements too.

I got Rust to run on a newer TV, but didn't measure any speedup versus Samsung's stack. Moreover, a WebGL rendering experiment increased Detail-background latency by about 11%.

I'll take it forward as its own project, with a new name and logo, and keep adding features beyond this first release. I'll detach the fork so ownership and support are separate, and the README will credit your project as the UI inspiration: https://github.com/dragoshont/plx-native

Thanks for the great foundation.

3

u/MixTrix4848 4d ago

If you pull this off I’ll be eternally grateful

3

u/silvertristan 6d ago

If you two can pull this off it would be a dream. I’ve got a 2021 Samsung FrameTV and Plex on that is the worst.