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

Why you should hire/befriend my wife Michelle

As part of a branding exercise, my wife Michelle asked me the following:

What would you say if you were trying to convince someone to work with me or to be my friend?

Michelle (colorized, February 2020)

Let me count the ways.

She will care about you more than you do.

Maybe it’s a commentary on self-love, but Michelle is genuinely the most thoughtful and caring person I have ever met.

At every moment of every day, she is evaluating what she can do, create, buy, or say to make everyone she loves happier.

Are you having a baby? She found this neat, handcrafted product on Etsy, thought of you, and shipped it to you with Grubhub gift card because you’ll need food those first few weeks and she knows it will be tough.

Did you start a new job? Instead of liking your status, she’ll call you and ask how it’s going. Having a tough time with the new coworkers? She’ll vow to slay them and their first borns if they ever hurt your feelings again.

Interested in anything at all? She’ll ask intelligent, engaging questions to allow you room to express your passion even if she doesn’t care about cryptocurrency flash minted tokens at all.

Did you mention off-hand that you enjoyed Bob’s Burgers? In eight months, you’ll be receiving a Bob’s Burgers recipe book for your birthday and handcrafted decorations that include Linda’s fucking face made of construction paper. You’re in her birthday calendar now, motherfucker!

She knows her shit.

It’s one thing to hire someone to complete a task for you.

It’s another to hire someone who will not only consider the larger picture that the task falls into, but also leverage that wider lens to advise on additional routes of attack.

Sure, she can assemble a go to market strategy for your product, but have you considered how this new products fits into your suite? Are you positioning it well for your current market? Have you considered how you could leverage it within your pitch decks? Are your sales teams prepped? Do they even know you’re about to roll it out?? Are you CRAZY?!

Sure, her wealth of experience is useful, but I argue that the mindset is far more valuable. Creative problem solving can extend itself to issues that have never come up. An average marketer can build you a textbook pitch deck based on experience; Michelle can build it for the business your business will become.

That’s the type of player you need on any squad.

She’s creative af.

It’s not enough that she’s smart and thoughtful, but she can take all that and package it up in a beautiful dress presentation.

Whether it be through sheer mastery of Powerpoint (no, like forreal mastery – not bullshit “put it on the resumé” mastery) or whipping up concept art in Indesign, she can take the info, make the words digestible for the audience, and then design the fuck out of it.

Honestly, it’s super annoying because I think I can pick out a decent Powerpoint theme and move things around and she puts me to utter shame like honestly it’s a real problem in our relationship.

Do it.

So, do you want a thoughtful, creative, intelligent, hella fine, masterful marketer to be your friend/contractor?

Make her tweet.

Why I’m glad my D&D character died (and yours, too)

Last week, I joined my first in-person D&D 5e session at a local gaming store that hosts organized play events every Sunday.

Much like the taverns most parties quest from, the room was full of adventurers of all ages and skill levels; some starting out with me at level 1 at the tier 1 table.

In fact, only three of us comprised the party assembled to quest through the first parts of Descent to Avernus.

For some of you, that sentence alone tells you everything you need to know about why we were TPK’d in the first dungeon. We only made it to level 2.

Accepting death leads to better gameplay

Death is weird. Whether it’s someone we know or the thought of dying ourselves, death is this looming inevitability that our brains try to hide from us lest we succumb to nihilism.

And so, sensibly, the death of a D&D character whose backstory and kit were carefully crafted over hours and days is something we want to avoid. Nobody plans for their PC to die; well, nobody new.

So, I’m glad I’m dead because it rips that bandaid off. Death is a part of the game (and life) and coming to terms with that outcome enables us to pull our own fears out from the character so we can better play them as they would be played. Instead of drawing from the personal attachment to life, I can inject realistic flaws and behaviors that my character would do that would get them killed, rather than an ever-present desire to flee to save their life at all costs.

I am not my character; if my character dies, it’s okay.

In fact, some characters should die with the right circumstances. Think to yourself, “what would my character die for?” when building them. To protect the innocent? To save a companion? To complete an evil ritual?

Plan for their death – even with your DM – and embrace it when it comes.

Besides, your PC’s twin sibling can always show up at the dungeon entrance with the same stats 🙂

Three Practical Tips for NOT Killing Your House Plants

Yep! I blog about tech and plants 🙂

So, you seem to “kill every plant you own,” huh?

Somehow, the magic balance between sunlight and water eludes you and you end up with toasted leaves or wilted stems.

Fear not, comrade! In just a few paragraphs you’ll have a better understanding of how to take care of your house plants.

Let’s dive right in.

Tip One: Drainage.

Most of the time, when people water their plants, they don’t have proper drainage.

This means that water will sit inside the pot and drown the plant when watered (instead of dispersing into the ground like in nature) and leads to overwatering which can cause rotting and other issues.

Check out these signs of bad drainage and overwatering:

  • Leaves dropping off the plant while green
  • Soft spots or rot on trunks & stems
  • Buds not opening

To be fair, most plants are sold in a piece of junk planter with no drainage. This immediately sets the new plant-parent up for failure.

Typically, you’ll want to have a planter with holes in the bottom along with a planter saucer beneath it to collect the drainage water. This allows you to remove waste water and lets the plant breath.

Photo by rawpixel.com from Pexels

This is the fundamental step to watering your plants because most plants should soak for a short time. The trick is being able to drain the plants after they are done soaking.

Without drainage in your planters (and a saucer to allow for water removal), you will not be able to properly water your plants and might be killing them.

Tip Two: Soaking.

The second trick to watering plants is to give them an appropriate amount of time to drink water. This comes in two steps.

First, check if the plant is dry. For some plants, this will be easy to tell with the top layer of soil. Other plants will need a bit more dryness, so you’ll need to check deeper. A good rule of thumb is probably “halfway deep is dry”. Over time, you’ll be able to better time this.

Pro tip: this timing changes during seasons as air becomes hot/cold and dry/humid.

Then, once you detect that the plant needs water, continue to water your plants until you see water fill up the drainage basin. Sometimes this occurs quickly – you’ll get the timing.

It’s important to note that during soaking the plant may consume that overflow water.

Over the next hour, check in on your plants to make sure that they continue to soak. This means refilling water if they have consumed their reservoir.

Once the hour is over, discard the waste water.

Tip Three: Sunlight.

Depending on your plant, it will require more or less sunlight. Be sure to look up the general needs of your plant for this information.

But, in general, more sunlight is not a bad thing.

Here are some common symptoms of a plant that needs more light:

  • Light/yellowing leaves from chlorophyll disuse
  • Wilting / weak stems from insufficient photosythentic energy
  • Intense leaning from plants searching for more natural light
  • Wide space between leaves as the stems grow longer for the search

For example, I have a Philodendron that doesn’t require a whole ton of light to survive. Typically, I house it in a north-facing room away from the window. This was fine in the summertime, but the winter lighting was impacting its health – leaves were dying off and the plant was looking very weak.

So, I pulled it out from the darker room to my bright east-facing window. This led to immediate response and results: tons of new growth and 100% perkier!

However, the extended light seems to be over-illuminating it now that the summer light has returned, so I might pull it slightly around the corner from the window to reduce direct sunlight or possibly back to the north room.

Try different positions with your plants over the next few weeks to see if more or less sunlight impacts their perkiness.

Good luck!

And that’s it! With good drainage, proper soaking, and enough sunlight, your plants will live thrive!

Most house plants will only require attention once or twice a week.

Get into the habit of feeling the soil’s dryness. This will be the key to ensuring proper water consumption.

Good luck!

Let me know how your plants are doing in the comments below!

How to change your password on every account you own

When I was a young warthog, I created my first Gmail account.

It was a time of AOL Instant Messenger, Koolaid Jammers, and learning how to bypass school internet blacklists with proxies to play flash games during comp sci.

As such, I did not create a timeless email address.

Instead, I opted for a juvenile one to befit my tremendously small ego: [email protected].

But that was my email address and slowly but surely I used it to create one account after another over more than 10 years.

Facebook, Amazon, MySpace, Soundcloud, Bank of America, WordPress, etc. The list goes on as you well know.

Some years later I wised up and created a sensible email address – only to slap on an email forwarder and continue to use my Gmail-of-youth.

I thought this blog post was about passwords?

Yeah, yeah, I’m getting there.

So, here I was using my old Gmail for all my accounts, when I started to pay attention to the news.

Yeah, data breaches made me fix my email address because, like 73% of people, I was using the same passwords across multiple accounts.

Let me reiterate: my email-password combo was the same for basically every account I own. So, if any of these accounts became compromised, the hacker would have my email-password for all of my accounts.

And I thought, well there are so many accounts out there, mine probably is safe. Nope.

I ran my amazing email address through the breach scanner (yes, it’s legit) and found I’d had my data exposed by Apollo, a company I had literally never heard of.

As the data breaches began to pile up, not only did I become more worried, but I learned quite how easy it is to access this breached data.

Literally, any Joe Schmoe can go and retrieve it from the published list – though, I’m not going to show you how to do that, sorry.

So, I freaked out and changed all my passwords

It’s understandable, really.

It would be foolish of me to continue to trust organizations to keep my data safe, so the least I can do is plan for them to lose it and mitigate the risk of my other accounts.

I resolved to take my security into my own hands by changing the passwords of every account that I owned to one that was unique and secure.

Now, I’m not a lunatic. I didn’t stay up for 48 hours straight trying to remember every account I owned and change its password.

Instead, I took one hour to do the following task list:

  1. Set up a password manager
  2. Change my password (and email) on the most important accounts I could think of.
  3. Set up two-factor authentication (2FA) when available

A password manager is absolutely key here.

Without one, you’d end up with a Google Sheet with all your accounts and passwords lined up – now that wouldn’t be very secure, would it?

Though you might be thinking “well then, wouldn’t all my passwords just be stored on the password manager’s servers and equally be at risk”, password managers have deep layers of security and encryption that hinge upon a master password – so even if the data breached, without the master password the information would be useless.

Protip: Master passwords should be long phrases that you can easily remember like “honestly, I still can’t believe it’s not butter” or “long live the flying spaghetti monster”.

Longer passphrases are far more effective than 0bscur3 pAsSw0rdZ! since it takes computers way longer to guess.

Personally, I use Last Password, but I hear excellent things about One Password as well.

Two factor is equally as important since it prevents unauthorized account access even if they have your password. Always choose to use an application like Authy or Google Authenticator, instead of SMS, when available. (SMS has been proven vulnerable, but it’s better than nothing).

Protip: *always* store your 2FA backup code within your password manager – if you lose your phone, you’ll be screwed without the backup code.

After that initial hour, I decided to just update the rest of my accounts as I went along.

In all honesty, I’m still in the process.

The end … of an era

Now, my key accounts

  • All have a unique, secure password stored safely (and handily) in my password manager
  • Have 2FA enabled with Authy (with backup codes also stored in my password manager)
  • No longer use my old Gmail address

On top of that, I added a forwarder from my old email to my new one and made sure to automatically label incoming emails from that account so I could be sure to address anything sent there.

I’ll never delete it though, it’s such a baller email address.

Why you should keep your WordPress site updated (obviously)

Have you ever logged into your WordPress site and seen those bright orange notifications in the sidebar?

“11 Updates!? I just updated this last month!”

How many times have you ignored those notifications, letting them pile up week after week until you finally say “screw it” and update them all in one shot?

Has that ever backfired on you? Some plugin update breaks your site and you’re now scrambling for 6 hours trying to fix it.

Has that caused you to avoid updating altogether?

You’re not alone.

Almost 40% of WordPress sites are not running the latest version (aka 10% of the internet) – let alone the countless plugins and themes that are also out of date.

The problem is that this is an incredibly bad idea.

When you leave WordPress out of date, you’re practically inviting hackers to enter your site.

This is because the vulnerabilities of older versions are published and available to the community as soon as the new version goes live (and often times soon).

So, that little orange icon should say something like “hackers literally know how to abuse your old plugins now”.

Scary? It should be.

What’s crazy is that this is completely common.

In fact, WP White Security found that 73% of the 40,000 most popular websites that use the WordPress software are vulnerable to attack.

So, what’s the worst that could happen?

Most likely, your website is an integral part of your business. Whether you’re using Ecommerce or simply blogging, your website is practically the face of your business and probably has access to sensitive customer data.

Leaving your site out of date leaves your site vulnerable for someone to take advantage of you and really hurt your business.

Extortion

This tactic can be attached to basically any of the following issues. Hackers will takedown or defame your site until you cough up some money for release.

And, unless you solve the problem, you’re vulnerable for them to extort you over and over again.

Compromised Customer Data

If you are collecting customer information like emails and phone numbers (or potentially payment information), you’re now dealing with a true crisis that leaves you exposed to customer retaliation and a PR nightmare.

Heard of Experian? Yeah.

Blacklisting

Typically, hackers will publish thousands of garbage posts and pages using your site that all backlink to some scam.

Or maybe they’ll inject malware directly onto your site to try and compromise customers.

When Google finds these pages on your site, it will Blacklist you from Search Results.

In fact, Google blacklists around 20,000 websites for malware, and around 50,000 for phishing each week.

That’s right – no more search rankings or traffic.

Oh, and it’s damn hard to undo, too.

Use in Botnets

Ever hear about “Russian botnets” or “DDoS”?

Hackers will basically put sleeper code onto your server and use it to attack other servers.

Defamation

After gaining access, hackers could take over the design of your site and post some pretty horrific content in its place.

Say goodbye to customers at least.

Takedowns

This is by far the nicest of punishments – taking your site completely offline. No site = no business.

All that, just from outdated stuff?

Yeah, it’s real life.

The simple act of updating WordPress, plugins, and themes protects you from most attacks (and that’s over 90,978 attacks happening per minute).

Naturally, there are other methods of entry, so you should be employing a security plugin as well, but just updating keeps you on a good level.

Even if you just use a secure password, you’ll be protected against 8% of WordPress security breaches.

Ok, I’ll do better to keep my plugins updated from now on.

Well, there’s another problem: plugin updates can crash your site.

Yeah I know, right? Can’t catch a break.

Plugin conflicts are no stranger to anyone who’s worked with WordPress for long, but only the dedicated few really know how to resolve these quickly.

Maybe the plugin you just installed doesn’t outright break your site, but it could still be a problem like the thousands of WordPress websites that were infected with malware disguised as a search engine optimization plugin.

And if it’s a severe break, do you have a backup of your site available? Know how to restore it?

Are you ready to call the amazing tech support at your server host when things go wrong?

To recap, if you plan to do this yourself, you’ll be responsible for:

  • Updating WordPress core, plugins, and themes daily
  • Checking if updates break your site
  • Checking that new plugins are ok to install
  • Resolving plugin breaks
  • Protecting your site against other vulnerabilities
  • Auditing your existing site for malware
  • Keeping an eye on your passwords
  • Backing up your site properly
  • Restoring your site if it goes down
  • Talking with tech support
  • Oh, and the rest of your business

How much are those hours worth to you? You should be doing bigger and better things.

Let me do it for you.

With plans starting at $100/mo, you’ll have a dedicated WordPress expert managing your site for you.