I Finally Built a Desktop App

Over the past six weeks, I’ve dug in deep on building a desktop app to scratch my own itch in running Dungeons and Dragons games.

While the product itself may not be relatable to those outside of that gaming circle, the process of building it might be.

Quick video of the current state (and download):

quick screencap of Guidance before I add words later. probablyp.s. download and check it out! github.com/wpmonty/guid…

Owlbear Inc. (@owlbearinc.bsky.social) 2025-08-13T04:11:14.608Z

Features

The Guidance app’s main job is to help a dungeon master run combat encounters with as little frill as possible. This task can be cumbersome and requires coordination by all players. This app automates and centralizes that flow.

Here’s the basics:

ElectronJS

Electron is a javascript based desktop building framework that essentially compiles down to Mac, Windows, Linux, and extendable to other distros as well.

Personally, I’ve included typescript and tailwind to keep it all clean, and though I started with Vite, I had to migrate to Webpack for better compatibility. Jest for basic testing. Eslint & prettier, obviously.

Campaign Creation

Each game group is it’s own collection of characters called a campaign.

The app handles multiple campaigns and so, we have Campaign CRUD.

Character Creation

Each campaign has any number of characters, each with their own stats.

So, we have Character CRUD.

Initiative Order

During gameplay, we organize turn order by initiative. Each character has their own modifier to a base dice roll.

Not only do we need to roll, modify, and order those characters, but we also need to allow for ephemeral adversaries to be added into that order, as well as track ephemeral statuses and health/damage.

This effectively is Initiative CRUD. Behind the scenes we actually just duplicate the Character db entries and delete the whole Initiative store when we’re done.

In addition, the players typically don’t get to see the total health of the adversaries, so a separate window is needed in order to stream that intel properly.

Dice Math

Perhaps the best known trope of the game, we use dice very commonly.

I not only have a dice rolling page with full notation support & quick rollers, but I also added inline math for easy damage calculations. Editing hp is so much easier!

Persistence

We want the app to load in all the data we created last time! While IndexDB is available in Electron, it’s a pain and not guaranteed to be permanent (never trust a browser).

The data gets passed through IPC (Electron’s frontend-backend handshake service) and stashed in a json file. The data is small enough that even the most robust transforms and loops are fast, so we really have no need for a “real” db.

State

While most of the above is stored via IPC filesystem, it’s stashed in a Redux state for easy reference when we initialize & any data changes.

Shout out to thunks and slices.

App Releases

This is where the deep dark fun begins. I want to share the built app files with the world, but don’t want to reveal the source code. I also need to account for (as I learn) app signing for Apple and Windows.

This is where the brilliant Electron Forge package comes in handy (absolute game changer). It handles packaging and signing the app into any of Electron’s supported operating systems.

I pair Forge with a Github action in a private repo that builds, packages, and signs the app before creating a new Release on the public repo. I include the latest.yml file in each build for automated updates.

Updates

I want to put this in the hands of my non-technical friends. They need auto update.

Electron Forge includes an auto update feature. I point the version lookup function to a nifty auto redirect that grabs the most recent release’s latest.yml version file.

Voila! Free update server.

Now, every time I release a new version, every app will see there is a new version and note that the user.

Licenses

I kept pulling on the thread and decided it would be cool to sell licenses and make a little cash if people liked this product.

The easy part was rolling my own license generator. It’s a Nextjs api endpoint with a password and a free Vercel postgres DB.

The hard part is tying that up to payments in a way that’s satisfying. I have Stripe, Patreon, and Gumroad webhook branches in flight right now to test the requirements definitions. Each has their own schema and I need to make sure to pair redirects in a way that ensures the proper license key is shown.

And then it begs the question of a user account. TBD.

For now, I can issue new license keys DIY and the app will do a high-trust query against the Nextjs api and cache the resultant pass/fail boolean in the local json store for use in unlocking features. Multi-campaign is the only thing locked for now.

Future Features

I’ve had to physically stop myself and delete branches and features to get this release out. From voice commands to discord integrations, I really want to push the boundaries of my abilities.

  • Discord integration; audio moments, player connectedness, dice posting
  • Voice commands: “roll x dice, roll initiative, add a monster, apply damage”
  • Import creatures from open sources
  • Creature CRUD
  • NPC CRUD
  • Encounter analyzer (combat balancing is really challenging!)
  • Player client?!

So much to do!

Main and Sidecar screens

TL;DR

So, we have persistent multi-parent data CRUD via IPC and filestorage.

That data is brokered with Redux and used throughout the app.

The app is releasable for public use, especially in combination with a hand rolled license server, and should be available for Mac, Windows, and Linux without ever needing those machines.

Automated updates are handled for free by Github release trickery and the only cost to me is Github actions throughput and a yearly tithe to Apple and Windows so they won’t mark my app as malware.

Not to mention, the app is very useful to me! Now that the framework is settled, I’m looking forward to pumping out more features for myself and a growing audience.

The end

It’s been a delight to accomplish this vision: my first desktop app!

As a web developer, I’ve seen my creations in browsers and installed as mobile apps. The desktop frontier is something that has always felt out of reach, but now I’ve got it pinned. Hell yeah, me!

Additionally, I hope that as our web grows darker, we might find more use in Desktop apps going forward. What could be more decentralized than old-school, desktop-only apps?

Until next time!

Best,
James

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.