
When I first started messing around with this, there wasn’t some magical “FFXIV Overlay Development for Dummies” guide waiting for me. No proper API. No documentation. No neat little tutorial video from a bloke on YouTube saying “just click this button and it all works”. There was just me, a game client, and the stubborn determination that I wanted a clean overlay showing DPS on another monitor while I played Final Fantasy XIV.
Most of it ended up being less “elite hacker cinema” and more sitting there like a confused archaeologist, poking at packets and watching what changed whenever I did something stupid in game. Hit a mob. See what updates. Change zones. See what updates. Cast Fire IV fifty times because apparently my version of software development is turning a Black Mage rotation into a debugging tool.
So why even bother with an overlay in the first place?
Honestly, because I missed Ember Overlay. It used to do exactly what I wanted, but after it stopped behaving properly with IIACT, I figured I’d either spend hours fixing someone else’s work or spend hours making my own broken version. Naturally, I chose the second option because that’s apparently how programmers entertain themselves.
The idea itself was dead simple. Full screen overlay on a second monitor. DPS numbers. A few useful bits of information. Nothing ridiculous. I didn’t want some RGB nightmare screaming statistics at me like the dashboard of a fighter jet. I wanted something lightweight that could quietly sit there while I played without eating performance or making my PC sound like it was preparing for take-off.
The first challenge was finding where the information actually lived.
Since there wasn’t a nice public API sitting there waiting for me, I started watching how the game and companion tools communicated locally. Loads of desktop apps do this. Overlays, launchers, helper tools, they all end up chatting away in the background somehow. Eventually I spotted what looked suspiciously like a local WebSocket stream constantly firing small updates around the machine.
At that point the process became pure trial and error. Do one action in game. Watch the traffic. Repeat until your sanity starts leaking out of your ears.
- Move zones? New frame appears.
- Take damage? Different frame.
- Target something? Another update.
After enough repetition the patterns started becoming obvious. It’s a bit like learning enemy attack patterns in an old Final Fantasy VII boss fight. At first it looks chaotic, then eventually you realise “oh, that packet always appears when this happens”.
Some of the frames were easy enough to understand because they were plain JSON. Others looked like somebody had compressed pure misery into binary form. That’s where things became less “web development” and more “digital caveman discovers hex editor”.
The approach stayed the same though:
- Observe.
- Guess.
- Test.
- Repeat.
I avoided trying to decode everything at once because that’s how you end up staring at random bytes at 3am questioning your life choices. Instead I built small correlations. One game action linked to one message shape. Slowly the puzzle pieces started fitting together.
For the binary payloads, I started looking for repeating offsets and markers. For textual ones, I checked keys and values for obvious meaning. HP values are usually pretty easy to spot when your character suddenly loses half their health standing in AoEs like an absolute champion.
Once I had enough mapped out, I threw together a tiny test harness to confirm assumptions properly. Trigger known events. Log frames. Compare results. Break things accidentally. Fix them again. Standard development cycle really.
The actual overlay itself is hilariously simple.
index.htmlhandles the basic structure.overlay.csskeeps things looking decent without turning the browser into a furnace.overlay.jsdoes the heavy lifting by reading the stream and updating the UI.
That separation turned out to be massively useful because the protocol changed constantly during testing. Having parsing logic separate from rendering meant I could alter how frames were interpreted without rewriting the entire overlay every five minutes.
Performance mattered from the start too because real time overlays can become bloated disasters very quickly. Nobody wants their DPS tracker causing more damage to FPS than an alliance raid full of summoners.
So I kept things lightweight:
- Simple DOM updates.
- Minimal animations.
- Debounced rapid events.
requestAnimationFramefor rendering.
No ridiculous frontend framework deciding it needs twelve million dependencies just to update a number on screen.
The technical side ended up looking roughly like this:
Messages generally fell into a few obvious categories:
zonefor area changes.playerStatefor HP, MP, targets and positions.abilityfor skill usage.combatantfor party and enemy updates.
Some messages were standard JSON like:
{ "type": "ability", "abilityName": "Fire IV", "damage": 4200}
Others were compact binary frames needing ArrayBuffer and DataView parsing. Which is developer speak for “guessing offsets until numbers stop looking cursed”.
Useful fields ended up being things like:
hpmaxHpmptargetIdzoneNamebuffs
and positional values like x, y, z.
Nothing particularly magical once you identify what you’re looking at.
One thing I learned very quickly is that reverse engineering anything requires humility because protocols change constantly. Something working perfectly today can completely explode tomorrow after an update. So the overlay was designed to fail quietly. Missing data hides widgets instead of throwing errors everywhere like a toddler having a tantrum.
And yes, before somebody starts dramatically clutching pearls in the comments, there are ethical considerations with this sort of thing. I kept everything strictly local. No interference with servers. No modifying the game. No injecting nonsense into packets. Just observing information already exposed locally and displaying it differently. Basically the software equivalent of peeking through your own curtains.
The biggest lessons from all of this?
- Keep your assumptions small.
- Test constantly.
- Don’t overcomplicate overlays.
And never underestimate how much time you can waste staring at hexadecimal values while telling yourself “I’m close now”.
In the end though, that was the fun of it. No documentation. No roadmap. Just slowly figuring things out piece by piece until eventually the overlay worked exactly how I wanted. Quiet. Lightweight. Functional.
Which, honestly, is more than I can say for half the software people release these days.
Repository: View Project on GitHub

Join the Discussion
Ever reverse engineered a game overlay because the original one stopped working and you refused to let that defeat you?