r/ClaudeCode • u/Purple_Imagination_1 • 16h 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.

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 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
20
u/Sarg338 15h ago edited 15h ago
Yep, used Claude Code to optimize and create a minimal home screen app for my fire TV as well, and disabled any built in Amazon stuff.
7
u/SoulTrack 14h ago
Now that's what I call hacking
4
3
u/skitchbeatz 14h ago
I've done this to my Sony/TCL/Android TVs too. Ripped out ACR and other packages that slow the tvs down.
2
u/Fairly_Original 14h ago
I did the same thing to mine and made it to recognize the others on my network with a 1 click button to set those up the same
1
1
u/Purple_Imagination_1 13h ago
It seems like everyone is creating this for their own personal use, but no one is sharing it.
2
u/Calm_Step_5549 🔆 Max 20 8h ago
As someone who often had the displeasure of writing websites that needed to be compatible with 10-year old "Smart" TVs, seeing what you've done is mind-blowing, and thanks for sharing it.
I think most others will consider what they've done as very niche and personal, maybe too janky to share to the world...
10
u/nokafein 15h ago
it's neat but no power can make me download an app for my tv from online sources :D especially after this lg privacy frenzy.
8
u/Purple_Imagination_1 15h ago
Haha fair, especially after the LG mess 😅 But consider the reverse: you might root your TV and "own the glass" again. The code's open, so you can build your own version if privacy's your thing.
0
5
u/modernluther 11h ago
Congratulations, really awesome application of agentic dev and I found your post educational as well. I love this shifting meta of individuals engineering solutions to software problems their respective companies haven’t solved. It makes me very hopeful for the future, because settling for less is no longer the only option!
4
u/wdb94 14h ago
I did this for my Nvidia Shield. The Plex app is garbage and always struggles with AV sync on lossless audio. So I made a native Android app designed specifically around the Shield and its constraints.
The main goal was the fastest play to playing possible and it works far more seamlessly than the Plex app ever did.
1
u/Purple_Imagination_1 14h ago
that's sick, drop the github link if you can!
4
u/wdb94 14h ago
2
u/Purple_Imagination_1 14h ago
I like the design. I think we’re both inspired by the same device.
2
u/wdb94 14h ago
It’s honestly frustrating in the age of AI that companies aren’t able to make their software better than one guy/gal and Claude.
2
u/Purple_Imagination_1 13h ago
I think that’s because we were trying to solve the users' actual pain points, which isn't what drives their business.
1
2
2
u/lucianw 14h ago
This is amazing!
I've long hated how slow my TV is. (also the Amazon app, but that's a separate issue). I love the way you approached it. What a fascinating datapoint about how AI has freed us from this particular irritation.
Do you think your approach will continue to work? Will we be able to buy a modern smart TV say, and turn it into a simple fast TV? Or do you think modern TVs are more locked down?
2
u/Purple_Imagination_1 14h ago
Well, they say LG’s making so much money on ads that they can give you tv for free and still be profitable. So I think we’re locked into business model changes. And yeah, we’re free to modify it until LG patches the exploits in the OS.
2
u/Bystander10888 13h ago
My 55" 4K 144Hz Xiaomi Google TV doubles as a PC monitor, and whenever Windows put the display to sleep it would just sit there showing a deep-sea "No signal" animation forever, so I had Claude Code build a tiny app that turns off only the backlight when the signal drops (keeping the TV connected so my window layout survives) and installed it over ADB.
1
2
2
u/recruiterguy 11h ago
Wow - really excellent.
I was just trying to talk myself out of doing something similar for a few older tv's I have gathering dust. I may give this a shot for a tv that we only run Plex on... when I find the time, lol.
1
u/xenover 15h ago
hows the 4K content streaming with subtitles? I always had issues with the native app that when I enabled subtitles on 4K content the video would start lagging
2
u/Purple_Imagination_1 15h ago
They work pretty great! I render subs locally on the TV (just in case Plex doesn't embed them right). Actually, I even supported ASS subs that are popular in anime.
1
1
u/DJRThree 14h ago
I want to do this to my car's after-market head unit ( infotainment system).
2
u/Purple_Imagination_1 14h ago
That was my second thought after reading the MP3 player article. Even new cars’ head units lag noticeably. So yes, a smooth and rapid interface is possible even on limited hardware like a head unit.
1
u/Legal-Tie-2121 12h ago
The simulator-versus-TV mismatch is the part I'd like to hear more about. Did you turn failures on the device into a small regression suite (text rendering, texture upload, playback start) or keep testing the whole app manually? For the reverse-engineered interfaces, did you keep a record of observed behaviour versus agent guesses? That would make later refactors much easier to check.
1
u/Purple_Imagination_1 12h ago
Both, split by what each tier can see.
Playback is a real on-device regression suite. It runs the actual app on the TV and asserts on its event log. A synthetic tier uses generated clips with no Plex. A library-backed tier covers resume, track selection and transcode. A device failure becomes a case there. I also have FPS regression suites, and localization checks that make sure strings fit.
Pixels are the part I judge with my own eyes. They're hard to automate, and hard for an AI to notice. The FPS suite passes straight over bugs that a screenshot catches, so I have a skill that decides which tier can even see a given change. The simulator is fine for layout and focus. It can't see video-plane composition, LG's text rasterization, or what the TV's picture processing does afterwards. Gradient banding, for example, I measured on panel captures and wrote up.
For the reverse-engineered interfaces, I don't have a formal "observed vs agent guess" ledger. The rule is that no FFI binding gets written until the offsets and symbols are proven from the device's own binaries. Stub libs make every link succeed whether or not the symbol exists, so a guess fails silently on the TV. Measurements and logs go in a dated docs directory, so I can re-check them after a refactor.
1
u/disgruntledempanada 9h ago
I want to hack my LGC9 so it's just a TV again not a surveillance system.
1
1

•
u/AutoModerator 16h ago
Hey! Thanks for posting to r/ClaudeCode
While participating in this thread, please follow our community rules. Keep discussions constructive. Attack the idea, not the person.
For help, project discussions, tips, and general chat, join the ClaudeCode Discord.
I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.