edwin
cd ../writing
  • #kotlin
  • #android
  • #gamedev
  • #accessibility

Ons Klaverjas: A Card Game for the Kitchen Table

Edwin de Jong5 min read

Klaverjassen is the Dutch card game. Four players, two teams, 32 cards, and a scoresheet full of little marks. Every family plays it a bit differently, and every family is sure their way is the right one.

Most klaverjas apps look the same. Small cards, timers counting down, an ad after every round and a shop behind every button. Fine if you're twenty and on the train. Not fine for most of the people I'd actually want at my table.

So I built one. It's called Ons Klaverjas, it's free, and there are no ads in it.

Second Try

This isn't my first klaverjas game. In 2025 I wrote one in React with Socket.IO. Rotterdam rules only, private rooms with a code, and that was about it. It worked, but it was a weekend project and it looked like one.

In September 2026 I started over, this time properly. A native Android app, a real server, and the rules written down before any code. Within a day there was a playable offline table. Within a week there were online tables, lessons, friends, and the app was in the Play Store.

Same as the Godot client for Ugaris, AI agents did a big part of the typing. I wrote the specs, decided, reviewed and played. A lot.

Big Cards, No Rush

The rule for every screen: if it works for the people with the biggest hands and the smallest letters, it works for everyone.

So the cards are big and use the familiar Dutch deck. Every screen has one clear thing to do. Nothing has a timer. A ring around the portrait, a line of text and, if you want, a voice tell you whose turn it is. You tap a card and then confirm, so a shaky finger doesn't throw away your trump. There's a four-color deck for people who mix up hearts and diamonds, and the font is Atkinson Hyperlegible, which is made to stay readable with poor eyesight.

What turned out nice is that this is just better for everybody. Nobody has ever complained that the cards were too big.

Your Rules, Not Mine

Rotterdams or Amsterdams is the big split. Do you have to overtrump? Do you announce roem yourself or does the game count it? Pit, seinen, all of it.

Instead of picking one and annoying half the country, every rule is a setting. There are presets for Rotterdam, Amsterdam, Utrecht and the two federations, and a few short questions about how you play at home set the rest. If you join an online table with different rules, the game shows you what's different before you sit down.

One Engine Everywhere

The heart of it is a single game engine in Kotlin Multiplatform. Rules, variants, computer players, hints, lessons, challenges and tournament seating all live there. The exact same code runs in the Android app, on the Ktor server and in the browser.

That sounds like a nice architecture diagram, but it solves real problems. The app and the server can never disagree about whether a card was legal. A computer player on the server can't peek at your cards, because it gets the same limited view of the table a human does. And when I fix a rule, it's fixed everywhere at once.

The browser version is a React app around that same engine. There's no iOS app in the App Store, so on an iPhone or iPad you play in Safari, at the same tables as the Android players.

Computer Players That Play Fair

Playing against a bad computer is boring, and playing against one that cheats is worse. The computer players use the rules of thumb from a Dutch strategy guide: count the trumps, signal to your partner, know when to make trump. On the higher levels they also play out hundreds of possible deals of the cards they can't see before picking a card.

The interesting bit came later. Tuning a bot used to mean a new release. Now every computer player is a versioned profile, a list of named numbers I can change from the admin panel. Challenges pin the profile they were made with, so a board everyone plays stays fair even after I make the bots smarter.

Playing Together

Make a table, share a six-letter code on WhatsApp, and grandma on her tablet sits at the same table as the grandkids on an iPad in the browser. At a private table you can hear and see each other, with the video right in the portraits around the table. An empty seat gets a computer player.

Voice and video are WebRTC with a coturn server for the people behind annoying networks. That part took more work than I'd like to admit. Phones are very good at finding new ways to be silent.

There are also daily, weekly, monthly and yearly challenges where everyone gets exactly the same cards against the same computer players, so the leaderboard is about how you played, not your luck. And clubs and families can run an online klaverjasdrive, where the game seats the tables, starts the rounds and keeps the standings.

Nothing Gets Lost

Every online match is event-sourced. Each move is written to PostgreSQL before it goes out to the players. When I deploy a new server, the old one tells everyone it's doing maintenance, closes, and the new one rebuilds every running match from the database before it lets anyone back in. Players see a short "onderhoud" message and then just carry on.

The server runs on my homelab Kubernetes cluster through ArgoCD, the same setup as Ugaris. CI builds the image, and a rollout is a commit.

Not For Sale

No ads, no shop, no paid version, no third-party tracking. You don't need a password. You can link a Google account if you want your scores back on a new phone, and you can download or delete your data from inside the app. It's in Dutch first, and translated to English, German and French.

People can support it if they want. The game stays the same either way.

Try It

It's on Google Play and in the browser at onsklaverjas.nl/spelen. If your family plays with some weird house rule I haven't thought of yet, I want to hear about it.