It’s time for my annual self review. In last year’s review I said I wanted to spend time learning things for myself, and less time writing for other people. The main themes for 2025 were:
- playing with text (very broadly)
- playing with maps (specifically mapgen4)
- improving my web site
Outside of Red Blob Games work, I had two goals: improve my health and improve my quality of life. So how did the year go? I think it went well.
Since I have forgotten everything I did, I went through my Notion page[1] and my git logs:
for git in $(find . -name .git) do dir=$(dirname "$git") cd "$dir" echo ___ "$dir" git --no-pager log --since=2025-01-01 --pretty=format:"%as %s%d%n" cd - >/dev/null done
Interpreters/Compilers
The main theme for this year was text. I wanted to be very broad in applying this theme: interpreters/compilers, procedural generation, rendering, language models, text editors, search engines, and anything else related to text. Last year I bought and started reading munificent’s excellent book Crafting Interpreters[2], but it wasn’t until this year that I spent a lot of time on it. It creates a new language, Lox, and then teaches you how to write an interpreter and compiler for it.
- I implemented the first part, an interpreter. The code samples in the book are in Java, but I used Python instead. When I use the same language as the book/tutorial, I am more likely to copy code without fully understanding it. By using a different language, it forces me to understand the code so that I can reimplement it.
- I read but didn’t implement the second part, a compiler. I instead used what I learned with Web Assembly (wasm). I hand-compiled some simple code from Lox to wasm, but didn’t tackle the harder topics (closures and function calls). I also compiled some Javascript to wasm, and tried AssemblyScript. I used tools that compile wasm to C and wasm to x86 to understand better what the opcodes do. I wrote partial notes for myself.
- I’ve made LL(1) and LALR parsers before, and also an LL(1) parser generator which is now a Debian/Ubuntu package[3]. I’ve long been interested in Pratt Parsers[4], and Crafting Interpreters finally got me to try it. Pratt Parsers turn out to be really cool for the “expression” part of a grammar. Also see Oil Shell’s links to Pratt Parsing tutorials[5] and matklad’s blog post[6]. After implementing the lexer and parser, I compiled to wasm, loaded the wasm module at run time, and ran the code.
I also read lots more about interpreters and compilers. I made notes and bookmarks[7]. It’s an endlessly fascinating area to study.
Text
This year’s theme was text, and although intepreters/compilers were a large part of that, I also did other text-related projects.
- I had explored Signed Distance Field (SDF) font rendering in 2024 but this year I wanted to write a tutorial with a complete working example. Part of the motivation for this is that my blog posts are already showing up in search engines, and those blog posts are “what I tried” and not “what I recommend”. Knowing that my pages are showing up in the Google search results[8] makes me a bit embarassed by the page it’s returning, and I want to make a better one. I had hoped to finish this in 2025 but it’s still incomplete.
- I wrote a very simple search engine for my site, and wrote about it: Part 1 and Part 2. You can try it here.
- It seems like everyone’s talking about “AI”, especially Large Language Models (LLMs). Some people have very strong positive or negative feelings about them. I’ve had fairly negative feelings about them for the past ten years and am exhausted. As part of the text theme for this year, I decided I’d look into them a bit more.
- I wrote a blog post about creative things we might be able to do with them[9] if we could disassemble the chat interface into ingredients and then reassemble the ingredients into new uses.
- I wrote a blog post about the wrong information ChatGPT writes about Red Blob Games, and how I might be able to harness that.
- I tried using them occasionally for “side quests” like cropping images for my business cards, coming up with example code I can study, or reformatting/rewriting my code in a different style, but I just haven’t put enough effort to learn how to use them effectively for anything other than simple things.
- I made a text editor tool that lets me quickly tweak the SVG of a diagram. I used CodeMirror with a plugin and “attached” it to SVG diagrams on my page. I can then press Alt while dragging the mouse to tweak a number, and see the results. Once I have something I like, I can paste the updated SVG back into the source page. The goal here was that I want to preserve the formatting and comments from the SVG I had hand written, and only make minimal edits with the interactive tool.
- I started watching for and fixing my text editing annoyances while using Emacs. As a side effect, I’ve been also watching for and fixing annoyances with Linux, Mac, shell, and other tools I use regularly. My computing environment is getting better!
I wanted to work on procedural name generation for maps, which would’ve connected my text projects to my map projects, but didn’t get around to it. That’s ok. I always have more ideas than time.
Maps
Maps are such a rabbit hole for me that I tell myself not to work on map projects unless someone other than me wants me to work on maps. It turns out this year I had two companies approach me about map work, so I gave myself permission to work on my other map projects too.
- I had originally written mapgen2[10] to have the generation algorithms only, and I had the UI “demo” as a separate repository that I hadn’t shared. The idea was that you could use mapgen2 to generate a map and then attach it to your own game, which already has its own UI and rendering. But this year I decided to merge the two. It’s easier to start with a complete repository that works and remove some files you don’t need than to start with an incomplete repository and try to figure out how to make it work.
- I rewrote mapgen4’s renderer from using regl.js[11] to using WebGL directly. Regl is nice but there were WebGL 2 features I wanted to use. WebGL 2 has been widely available since 2022[12], and there are no plans to make Regl support it.
- I reimplemented mapgen4’s river renderer. I had been drawing river segments on the CPU, putting those segments into a texture, and then using that render on the GPU. The new renderer is a shader that runs on the GPU.
- Since I had just gone through the mapgen4 rendering code, I had lots of ideas for improvements, and I implemented many of them, and fixed some bugs along the way.
- I started writing a guide to procedural river generation. Some of my tutorials on terrain generation don’t include the rivers because rivers are tricky. I know how to make them work in mapgen2 and mapgen4 but I don’t know how to generate them in general. But I am only halfway through this.
- I updated my voronoi map tutorial to include biomes and rudimentary rivers.
- I de-optimized parts of Mapgen4 to make it easier to experiment with.
- I modified mapgen2’s renderer to work with mapgen4.
- I experimented with towns, roads, and trade routes.
- I played with noise functions.
- I tried increasing the paintability of mapgen4, allowing more elevations as well as a choice between plateaus and mountain peaks.
- Realm of the Mad God used my map generator for their 13 maps, but didn’t keep track of the seeds. I have long been curious if I could find the seeds from the map. I searched map seeds to match existing maps and found half of them.
- I tried a stylized hill/mountain image.
- I made a biome painter on top of mapgen1.
- I added more to my jittered grid page but I think it’s time to move it onto its own URL outside of /x/. I usually use /x/ for short-lived projects, and this page is slowly turning into a reference page.
It was good to play with mapgen4 again, and I started getting ideas of what might go into a mapgen5.
Site Management
This is the second year that I’m using my own home grown blogging software. I like it a lot better than what I was using before. But I didn’t blog as much this year as last year. Part of that was that I was spending a lot of time on my own projects (particularly learning interpreters/compilers) but also because I spent some time working with Jetbolt Games on Galactic Assault Squad[13] and another game studio on an unannounced project.
For the blog but also the rest of the site I’ve been wanting to add tags like “#hexagons”[14] along with browsing by topic. I have hundreds of pages so it’s going to take a while. I’ve made progress on this but want to label more of my site before I add browsing by topic.
My site is older than most any site out there, and most sites don’t last that long. I have around 5000 links from my site to others. A lot of the links I have on my site have broken over the years. I made some good progress on fixing broken links but there’s still more to do. It’s tricky because some links report as good (status 200) but are actually broken in the sense that the content I linked to is gone, replaced by some generic marketing or spam. And some links report as bad (404) but are actually good, with the server reporting 404 to my crawler but 200 to a regular browser. So there’s a lot of manual checking involved.
I continue to update my existing pages. For example this year I improved the conversions and spiral coordinates sections of the Hexagons Guide. I’ve also updated my pages using Flash applets to use Ruffle, and it’s been great to make those experiments available again.
I significantly sped up my web site build. It had been fast initially but as I’ve added more and more to the site (now 26,079 individual files) it’s gotten slower to process. I’ve been rewriting parts of it from using Bash to Python. If I need further optimizations I may use Rust or C++ in places. I’ve also switched my Python projects to use uv[15], which I’m enjoying very much.
I simplified my web site build by removing the Sass compiler. CSS has added the features I had been using from Sass. The build step is now faster, and the pages are slightly smaller.
Next year
I have some ideas for projects in 2026. I’ve been thinking about how to choose projects[16], and I ask myself:
- Is it that I want it done?
- Is it that I want to be doing it?
- Is it that I want to have done it?
There are often times I want to have done something, but when I sit down to do it, I don’t actually want to do it. That’s ok. And sometimes the problem is that I don’t know how to do it. That’s ok too. But I need to get better at understanding what’s stopping me, and not beating myself up about it. The better I can pick projects, the more likely I’ll succeed with them. For 2026 I have a list of possible projects, but not a theme:
- A specialized text transformation language, using what I learned about interpreters/compilers this year. I’d like to design something specific to make example code for my Hexagon guide. I currently use Haxe macros to generate hexagon code in C++, Python, C#, Haxe, Java, JavaScript, TypeScript, Lua, and Rust.
- My guide to SDF font rendering.
- My guide to procedural river generation.
- Version 2 of my A* page. I have some ideas[17] of how to improve this page. Last time I worked on it, I focusd on the diagrams, but the next round should be focusing on better explanations.
- Attempt 3 of explaining coordinate transforms. I’ve tried this twice before but didn’t like the results. I have some ideas of how to approach it differently this time.
- Using SQLite as an ECS (Entity Component System[18]). I’ve long thought of ECS as a rediscovery of the principles of relational databases. It might be interesting to use a relational database directly instead of an ECS as an intermediary.
- A “first pass” at all the topics ChatGPT falsely thinks I have written. I could spend my time complaining about its hallucinations, or I could instead consider it a list of ideas.
- A procedural name generator. I want to try something more interesting than Markov chains, and have lots of ideas.
Whichever ones I end up picking, I think they will be a lot of fun. Happy 2026 everyone!