Game overview

I just released a new game!

Mosaic River is a mobile solitaire game. You’re an archaeologist, sailing down a river, collecting mosaic tiles, and placing them into a triangular grid to make melds (straights, flushes, etc). Tiles have bonuses randomly assigned at each game.

You can try it now: it’s free (ad-supported) on iOS and Android.

It’s perhaps easiest to explain by describing some of the influences.


The first is Uwe Rosenberg’s Patchwork, one of the finest board games ever created. In Patchwork, the acting player can choose any of the three tiles in front of a marker, and choosing a tile advances the marker to that position. This means sometimes you might want to take a suboptimal piece to skip over a piece that would be really good for your opponent. In Mosaic River, you draft by sailing across the river and choosing one of the next three tiles. Choosing a nearer tile will allow you to collect more tiles overall, but it has a cost. Choosing a further tile might mean that you skip tiles you want, but in return you gain more optionality later (or, at worst, a few extra points).

A screenshot of the game Mosaic River: the river

Another influence is Diffusion-limited aggregation (DLA). In DLA, particles move around randomly and then connect. You end up with these tree structures. This influenced the design of Mosaic River’s connectivity rules. Half of tiles are “center” tiles, which need to be next to two other tiles, and other half are “edge” tiles, which need to be next to only one. The idea is to create a similar bushy structure. But since you only end up taking a small subset (perhaps a third) of the available tiles, and because center tiles want to connect in multiple ways in a compact cluster, we need to give a little bonus to edge tiles to get the desired shape.

A screenshot of the game Mosaic River: the mosaic

Of course, Lost Cities is also an archaeology-themed card game with five suits, but it wasn’t consciously an influence. It’s just that every kid dreams of being Howard Carter or Indiana Jones. I’ve been listening to the History Of Egypt podcast too, although I think I am likely to give up, since there’s often proportionally more focus on the pagentry of Egyptian religious celebrations than on the narrative than I would prefer.


I’ve decided to try a different revenue model with Mosaic River than with Surfwords. I’m doing ads. This sucks, and I hate it, but since Surfwords isn’t selling, I’m going to try something different.

It was pretty easy to get AdMob working with Godot, but the plugin is a little dumb: it doesn’t seem to understand that you need different admob ids for Android and iOS but that you otherwise want (usually) the same codebase for each. (Actually, looking at the config, maybe it does understand this, and I’m just doing something wrong.)

I guess we’ll see how ads perform financially. My next game (see below) will try the freemium model and maybe that will do better.



As with Surfwords, getting graphical elements to scale nicely to different screen sizes is a hassle. I ended up having to adjust the dimensions of the mosaic to accommodate older (wider) iPhones. It looks like phone manufacturers are starting to standardize somewhat on very skinny ratios, roughly 2:1, but older iPhones and Android phones still exist in the world and must be usable. The long skinny shape is actually somewhat restrictive as a game developer — as a random example, on some modern phones, anything circular can take up at most 35% of the screen (for a 4:3 screen, it’s 58%).

As usual, Godot’s layout model is not as user-friendly as one would hope. It even makes me miss CSS, which is saying something.

Google’s Kafkaesque process

Google refused to approve my app, because it was crashing on startup. Weirdly, this didn’t occur during their pre-launch checks. During pre-launch, crashes are reported with logs. During approval, you can’t get logs. This makes no sense. I uploaded a new version with some random added logging, and of course the crash went away. But please let me know if you run into a crash, and, if you can, send me an adb logcat.

Godot-Admob bugs; Apple bugs


Of course, as soon as I released, someone pointed me to an issue that didn’t exist on any of the devices I tested on (and that Apple somehow totally failed to flag — so much for the supposed quality review). Then when I went to upload a hacked-together fix, I run into a random Apple bug that Apple, of course, doesn’t report on their system status page. It eventually fixed itself. Anyway, if you’re on certain Apple devices, wait for 1.0.1.

end edit

Art direction

It turns out that I do not enjoy art direction. This is about me: I don’t want to tell an artist that I don’t like their work, and that they have to do it over again. I think I would feel differently if an artist were a true partner in the project, instead of a hired gun.

I’m working with a designer on my next game (see below). This will, I hope, be a different experience, since instead of requesting spot art, I’m asking someone to work out the entire visual design of the game. It’s still a contractual relationship with me taking all of the risk, but it feels like a different story, since it’s not someone working to a specification, but rather someone creating their own visual story.

Shader performance

I used Material Maker to create the two main backgrounds of my game. This is a model that I really like: you plug some nodes together, maybe write some light math, and out comes an image at whatever scale you like. But it’s also somewhat opaque: when it performs badly, you have to go into a bunch of generated code to figure out what’s going on.

The marble-ish mosaic background ended up just baked into an image. Easy, and performant. The river background was way more complicated, since I wanted something animated and not obviously repeating. The problem is that phones have very crappy GPUs, so doing anything at all complicated blows the framerate budget out of the water. I didn’t really expect this, since the game does not have a ton of visual effects. So maybe I’m doing something wrong, or maybe Godot is. Or maybe GPUs are really good at slinging a lot of pixels around but not so good at generative stuff.

I definitely noticed that Material Maker does not have the ability to optimize one common case. And there was another missing feature too, which I just hacked around in the end.

Scoring and bonuses

I redesigned the scoring several times. While working on the code to compute straights, I noticed that a single tile could be part of multiple straights. This meant that the most optimal strategy was to ignore all other melds, and just try to maximize the number of straights. I fixed this by adjusting the scoring: I made straights score linearly rather than quadratically in length, and made them slightly lower scoring on average than flushes or n-of-a-kind.

Deciding which tiles got bonuses was also a little tricky too. Initially, I randomly allocated bonuses. But this didn’t work for “meld bonuses”. Meld bonuses are a kind of bonus which stick to the tiles. They are represented by scarabs, feathers, and eyes. If you have all three tiles with scarabs (say) directly adjacent, you get a lot of points. But you can’t do that if all three bonuses end up on edge tiles. So then I moved the bonuses so that they were just on center tiles. But you could still end up in a bad situation: if two identical meld bonuses end up directly across the river from each other: you can’t (except with another bonus which you might not have gotten yet) collect both. This felt unfair, and thus unfun.

I thought of a number of complicated ways to allocate bonuses to try to avoid this, but none of them seemed likely to work. So I decided to just reshuffle the deck until that situation was avoided.

Discovering America

While I was thinking about how to score intersecting straights, I considered a rule that a tile could only count for one meld. But then the melds would have be chosen carefully. There were three unpalatable choices:

  1. The player could choose the melds at the end of the game (creating a tedious task right when the user wants the reward of seeing their final score).

  2. The player could choose them during the game (interrupting flow and forcing them to make choices that they would likely regret).

  3. The game could consider all of the possbilities and choose the best (creating an opaque scoring system).

I decided to do none of these, and to just allow intersecting straights. But I realized that, on its own, the decision problem was actually interesting — it just didn’t fit with the vibe of Mosaic River. So my next game will be about deciding how tiles should be arranged into melds. I’ve tried it out, and I’m really, really excited about it. Watch this space for news!

Previous post: Response to some Hacker News comments on Stable Diffusion