Development tools 2019

Here is a list of development tools I’m using at the moment.


  • iMac retina 27″ 2015, 32GB RAM
  • iPhone SE
  • iPad Mini 4
  • XBox wireless controller




  • Recent versions of Photoshop have been not so great. Pixelmator development has almost ceased. Considering switching to Affinity Photo.
  • Starting to use Blender for 2D vector graphics as well (icons etc).

Previous installments


Git activity graph

Number of commits is not a good metric for productivity, project health or anything else really. But let’s pretend! It may be OK as a simple activity indicator…

Here’s a Python script I made that graphs daily commit counts on a git repository by year.

Download the script here. Requires Python 3 and PIL/Pillow.


pip3 install pillow
python3 /path/to/imgui imgui



Example output for imgui:

D2 log 015 – Load time improvements

As I keep adding assets to the game, the load time keeps increasing. Who would have thought? A 5 second startup may not sound like much but it quickly adds up during development.

One way to fix it would be to load assets on demand. This might cause stuttering, but that’s OK for development. However, improving the load time would benefit the final game as well. Let’s do that!

I added a job system that allows the preload to happen on multiple threads. Load time: 1.5 seconds. Nice! Now that I’ve “jobified” the tasks that need to run, further improvements can be made with relatively little effort.



D2 log 014 – Video player

The main menu of the game is going to have an animated background. Currently I’m thinking it could be the end of the original trailer put on loop:

As a temporary playback solution I used a series of JPEG files. Not very efficient. When looking for a decent video playback library, I found this one:

A brand new “single-header” library for decoding MPEG1 video, by Dominic Szablewski. Simple API, easy to integrate. It’s great!

In fact, I spent more time looking for my .blend source file than writing code to use the library. In Blender, I switched render output from image to video and set the codec to MPEG1. It all worked the first time I ran the game.

D2 log 012 – Blender pipeline

The new Blender 2.8 is great. Unfortunately it broke my batch render script.

Fixing the script and the rendering setup were quite a challenge due to the major UI changes in 2.8, but eventually I figured it out. Even learned a few new tricks along the way. How did I manage to write the original script without the built-in scripting console? So helpful!

My Blender export pipeline looks like this:

  1. master.blend file with fixed camera & lighting setup
  2. extra .blend file for each asset
  3. link assets into master
  4. for each asset, render object & shadow into separate PNG

First draft of the new script for 2.8:

import bpy
import os
import subprocess

# Requires Blender 2.8
# /Applications/ -b -P
# Notes:
# Node setup: see master.blend -> Compositing
# Render menu -> Film -> transparent
# Shadow catcher plane -> Object menu -> Visibility -> Shadow catcher
# Adding more objects: File -> Link... -> "Collection" from ext. file -> Move to Assets collection in master

basepath = os.path.normpath(os.path.dirname(os.path.abspath(__file__)))
master_blend = "blender28-batch-render-test-master.blend"

src = os.path.join(basepath, master_blend)


bpy.context.scene.render.resolution_percentage = 50
bpy.context.scene.render.resolution_x = 1280
bpy.context.scene.render.resolution_y = 960
bpy.context.scene.cycles.samples = 20

assets_name = "Assets" # name of collection in master.blend
assets_collection = None

for collection in
	if == assets_name:
		assets_collection = collection

if assets_collection is None:
	print( "Error: %s collection not found in master" % assets_name )

# Save original filenames for output nodes
output_nodes = []
for node in bpy.context.scene.node_tree.nodes:
	if ( node.type == "OUTPUT_FILE" ):
		output_nodes.append( ( node, node.file_slots[0].path ) )

for target in assets_collection.objects:
	# Show only the current object
	for obj in assets_collection.objects:
		obj.hide_render = !=

	# Set output filename
	for node, path in output_nodes:
		node.file_slots[0].path = + "_" + path


Master & test .blend files here:

Example output:




Additionally, I created a simple pipeline for rendering weapon silhouettes for the HUD. With a single click, it pulls in each weapon model, renders it from a side-view, then uses just the alpha to write a single-color transparent PNG.

And similar setup for pickup icons, with a subtle “glow” pass.


The latest annoying update from Dropbox made me look around for an alternative.

iCloud, Google Drive and OneDrive might seem like the obvious candidates but I’d rather avoid them. Why? They are too much like Dropbox. Sooner or later they are going to introduce a similarly annoying UI blunder, crippling limitation or an unfriendly plan.

So I decided to try Syncthing instead. Simple, free, self-hosted, with Linux, Mac and Windows clients. Sounds good…

You deleted 9094 files from Dropbox
Yep. Do I want them back? Nah, I’m good.

From a business standpoint it probably makes sense that Dropbox doesn’t offer a pay-for-what-you-use plan but that is exactly what I want. With Syncthing, it’s no problem.

I set up a simple DigitalOcean VPS as a “master” node that’s always online and adding extra storage space is super easy and cheap.

I’ve been using Syncthing for about two weeks now and it seems to be working really well. It is solid software, complete and functional with no extra fluff. Filesystem changes are picked up and synced quickly.

★★★★★ / ★★★★★

Syncthing web UI
The device management & overview of sync status.

D2 log 010 – IMGUI

After experimenting with Cocoa-based editors, I’ve gone back to IMGUI. The panels I had built with Cocoa were beautiful (and I love native Mac apps), but it was too much work.

Building functional interfaces is a lot faster with IMGUI.

Luckily enough I get to use IMGUI at my day job now and I’ve learned a lot since my last attempt to integrate it into the game.

Turns out the problem of IMGUI and my own UI elements fighting for input events can be solved quite easily. I just need to process things in the right order and honor the “IMGUI wants focus” flags.

Superforce temporarily removed from App Store

I just got a notice from Apple that Superforce has been removed from the App Store. Oh no!

Luckily, it was not due to violation of any of the intricate compatibility or privacy rules… it just had not been updated for a while. Not fresh enough!

I’m going to prepare a new build, test it on as many recent devices as I can get my hands on and submit it for review. Superforce is coming back to the App Store soon.