After several years of stagnation, I’ve released JotDown: a markdown editing suite on

Fullscreen and distraction free modes
Fullscreen and distraction free modes

Another markdown editor? Really?

While there’s certainly no shortage of markdown editors available, I wanted something more specific. Namely, a better way to organize markdown files.

Markdown files can be grouped together by category, directory, or tag, and that metadata is stored in an standard and portable way: as YAML at the beginning of the file, for example:

title: My Document Title
category: School
  - notes
  - todo

## My Heading

Lots of notes go here

I use JotDown for organizing and planning projects, campaign notes and ideas for tabletop games, and journaling for longer term projects.

Maybe it’ll be useful for somebody else as well.

It also supports all or most of the usual markdown editor features, but also includes:

  • Rendering of flow charts and sequence diagrams
  • Markdown preview including synced checkbox lists
  • Typewriter and distraction free modes Vlambeer-inspired powermode. Makes writing streaks more exciting

However, I haven’t spent any money on it yet, and that means that neither the Windows build, nor the (untested) Mac build have been code-signed. That means that your operating system is likely to either show you a warning when running this application, or may prevent you from running it entirely.

If there’s enough interest to warrant the cost, I’ll get one or both of those signed in the future.

Some time after it was discontinued, my Logitech G13 stopped working and I decided to design a replacement, which I’ve named Sherbet.

Final results first:

Sherbet keypad with joystick
Sherbet keypad with joystick

Printable files and assembly notes:


Like the G13, I wanted an analog thumb joystick, but also wanted to incorporate some ergonomic improvements from other keyboard designs, such as the Dactyl keyboard, Dactyl Manuform, Kinesis Advantage, and the Ergodox. Namely, column-staggered keys, height offsets, column curvature, and a more comfortable overall tilt.

I chose low-profile keyboard switches (linear Kailh Choc switches from NovelKeys) to reduce the overall required height, in part because my desk sits higher than a comfortable typing height, with a large tray below. I have about four inches of available space between the tray and the underside of the desk top for both the keyboard and my hand. If that space isn’t an issue, I’d strongly recommend a more compatible switch, as the keycap variety available for these ones are extremely limited. I’d also recommend starting with the Dactyl or Dactyl-Manuform above, since designing this took way more time and effort than I could have guessed.

I started by modeling the keys themselves based on Kailh’s specs for the switches before I’d received them, then tried to find a comfortable column curve, and printed some tests, then printed a few more to test column offsets. Here’s what I ended up with.

Testing column radiuses... radii
Testing column radiuses... radii
Testing layout and column height
Testing layout and column height
Key design, 3/4 view
Key design, 3/4 view
Top, showing column stagger
Top, showing column stagger
Front, showing column offsets
Front, showing column offsets

After deciding on a layout, I started by designing out the switch sockets that will make up the main support plate.

Model of key plate
Model of key plate
First 3D print, after removing and cleaning up the supports
First 3D print, after removing and cleaning up the supports
Print showing switches
Print showing switches
After adding key caps
After adding key caps

I tried a few different tenting angles, and settled on about 20 degrees. Again, this is partially to allow for clearance above the keyboard. I would have liked a steeper angle for comfort, but this is still an improvement over the (flat) G13, and my current ergonomic keyboard. The tent angle was originally parameter-driven in Fusion 360, allowing it to be changed while the rest of the design adjusted correctly around it. As the design became more complex, this parameter stopped really being configurable without breaking other features.

Previous plate with printed base to test tenting angles
Previous plate with printed base to test tenting angles

Wrist Rest

Next, I started on what would be the wrist rest. I wanted a comfortable rest well suited to my hand, and planned to make it molded and contoured. I built this in Sculpey very loosely, then used a photogrammetry package called Meshroom (and a bunch of photographs) to generate a 3d model, and scaled it up to match the original.

Very rough wrist rest made out of Sculpey
Very rough wrist rest made out of Sculpey
Take lots of photos
Take lots of photos
Wrist rest model with texture map from Meshroom
Wrist rest model with texture map from Meshroom
Wrist rest model imported into Fusion 360
Wrist rest model imported into Fusion 360

Next, I basically traced the main contours of the model to smooth it out and define the footprint I wanted

Scanned model with surface model overlayed
Scanned model with surface model overlayed
Sculpey model next to simplified, printed version
Sculpey model next to simplified, printed version

While this process was fun, and the result was comfortable, I found that the contours got in the way when my hand moved around while typing, so later designs are all plain and flat. Oh well.


I started working on the overall case next, which proved to be the most challenging part. I’ve still pretty new to CAD, and haven’t done anything this complex before. Trying to find ways to describe compound curves, and the way that two surfaces should meet was really challenging, and took the longest of any part of this project (so far).

Render of case, including arduino joystick and some thumb buttons
Render of case, including arduino joystick and some thumb buttons

I also found some better rendering environments and the renders improved a bit as well.

Re-render of case
Re-render of case
Render of case, 3/4 view
Render of case, 3/4 view

I printed out just the thumb area to test comfort and positioning. It’s fine as-is, but the joystick module is just too bulky to be able to position where it really needs to be ergonomically.

Printed thumb joystick and buttons
Printed thumb joystick and buttons

I picked up a (much smaller) third-party Switch joycon controller instead, which can sit much closer to the keys with room for wiring. This connects with a (much less convenient) 5-wire 0.5mm pitch flexible flat cable. I picked up a 6 pin ffc breakout board from Amazon, but they can be found much cheaper on eBay or AliExpress.

Comparison of joystick sizes
Comparison of joystick sizes
Joycon joystick with switches
Joycon joystick with switches
Redesigned case to use smaller joystick
Redesigned case to use smaller joystick

When the shell was done, I added supports for the electronic componenents that will live inside. For the joystick, I needed to make small cover plate that will screw into the side of the case, because I wouldn’t be able to reach the normal screw mounts for it. For the Teensy microcontroller, I just made a friction fit holder, and screw mounts for that. I added some ziptie spots, and larger 4mm holes to allow the wrist rest to fasten on.

I’m also using a micro USB breakout board for the main USB connector to avoid wear or damage to the microcontroller.

Render of case inside
Render of case inside

I think this whole design phase took about a month total. I won’t hazard a guess at the number of hours spent on it, but… “many”.


After so much time spent on design and testing, the final prints for this were relatively fast and uneventful.

Printed at 0.2mm on a Maker Select Plus. Took about 15 hours
Printed at 0.2mm on a Maker Select Plus. Took about 15 hours
Postprocessing: Removing supports and cleanup. Sustained only minor injuries
Postprocessing: Removing supports and cleanup. Sustained only minor injuries
Underside of printed case with electronics mounted
Underside of printed case with electronics mounted

I printed the case lid (also in white) without painting, and attached some adhesive cork to the bottom. I’ll be using m3 threaded heat set inserts to fix the cover to the base.

Lid/cover with non-slip cork attached
Lid/cover with non-slip cork attached


I tried a few color schemes in the modeling environment, and ended up with something like this. Color options are a bit limited, because the key caps only come in black and an off white I didn’t like for this.

Paint mock up with masked stripe
Paint mock up with masked stripe

To finish, I first sanded with 220 grit sandpaper to know down the layer lines and surface problems, and then sprayed with a filler primer.

After first coat of primer
After first coat of primer

After priming, I used Bondo glazing putty, sanded (220 and 600 grit), primer, then putty and sanding again.

After two passes of primer and glazing putty, and lots of sanding
After two passes of primer and glazing putty, and lots of sanding
Primed white again
Primed white again

I masked off a stripe using thin vinyl tape, and airbrushed with Testor’s airbrush pink.

Case, with the last of the paint
Case, with the last of the paint

After painting, I sprayed on 4 or 5 layers of gloss coat, then sanded a bunch of it back out with 1200 grit sandpaper to remove dust, fuzz, and bugs, then sprayed again.

Looks nice, but there’s a lot of orange peel, and speckling from oversprayed clear coat. I did a very light scuff sand with 1200 grit in the worst areas, then buffed with rubbing compound followed by polishing compound.

Case: After clearcoat, after sanding, after polishing
Case: After clearcoat, after sanding, after polishing


I added homing bumps by embedding 1.5mm ceramic bearings in the key caps. Shown in the picture is one hole, drilled slightly too large, and one a bit too small, with the bearing forced in (but no glue. Not sure whether the larger size would be better with glue, vs deforming the plastic somewhat to accomodate the bearing.

Key cap with embedded bearing
Key cap with embedded bearing

Once I’d run out of tasks to procrastinate with, I started on wiring, beginning with the key rows and columns.

I couldn’t find any thinner gauge wire locally, and the only solid core wire I had was 22awg, which was just too hard to bend around the column offsets in the case, and to fit into small spaces between the case walls and the switch pins. Instead, I used 28awg stranded wire from a roll of ribbon cable, stripped it in sections with self-adjusting wire strippers, and then made and tinned small loops in the stripped sections. Thinner, solid wire would have been faster and less cumbersome.

Key switches with columns and rows soldered up
Key switches with columns and rows soldered up
Rows and columns connected to ribbon cable
Rows and columns connected to ribbon cable
Wired rows, columns, joystick, and usb breakout to microcontroller
Wired rows, columns, joystick, and usb breakout to microcontroller

I designed the wrist rest to use two m4 screws, with heat-set inserts in the rest. These ended up slightly misaligned when I inserted them, so I can’t attach it yet. I’m planning to reprint the rest with a slot cut through the bottom to hold an m4 nut instead, which should be easier to align.

In practice, an attached rest, or a way to mount the keyboard firmly to the desk, is required. Even with the cork bottom, and adding extra weight, the keypad shifts during use when pushing/pulling on the joystick, parallel to the desk.

I redesigned and reprinted the wrist rest so that it uses two captive m4 nuts, instead of heat-set inserts, and that seems to work fine.


Completed case and temporary wrist rest
Completed case and temporary wrist rest
Case underside
Case underside


I had initially planned to use QMK as the keyboard firmware, using an as-yet unmerged pull request designed to add joystick support. However, newer ARM Teensy controllers (>=Teensy 3.2, Teensy LC) are not well supported by QMK. Though there are two example (single-key) keyboards which support ARM Teensys, only one is currently working. Additionally, the incoming patch does not yet support ARM controllers.

When and if that patch is merged, and ARM support is implemented, I’ll finish and release the QMK setup. In the mean time, I put together an Arduino sketch instead, starting from somebody else’s work here.

It has two modes, one with a standard QWERTY layout plus the joystick and a single joystick button, and the other where all of the keys are mapped to joystick buttons. This allows enough buttons to configure Steam’s controller configurator, allowing the controller to be used as an XInput device with broader game support.

I’ve been using Slic3r with my 3d printer, but wanted to be able to easily restore old configuration values, compare changes and so forth.

Slic3r helpfully stores it’s configuration in INI files in the %appdata% directory, so the below batch script launches slic3r, and periodically git commits the configuration directory.

While the batch is running, launching the batch again will start a new instance of Slic3r and then exit.


  • Git must be installed, and available in the path.


echo off

set "slic3rpath=C:\path\to\Slic3r.exe"
set "configpath=%appdata%\Slic3r"
set "batchpath=%~dp0"
set "lockpath=%batchpath%slic3r.lock"

start "" "%slic3rpath%"

if exist "%lockpath%" (
  exit /b 1

copy NUL "%lockpath%"

timeout /t 120 /nobreak

tasklist /FI "IMAGENAME eq slic3r.exe" 2>NUL | find /I /N "slic3r.exe">NUL
if "%ERRORLEVEL%"=="0" (
  git -C "%configpath%" commit -a -m "Scheduled update"
  goto loop

DEL "%lockpath%"

I run this minimized (not completely hidden) by creating a shortcut to it, and setting the “Run” value to “Minimized” in the shortcut’s properties.

I had a system crash which caused Tabletop Simulator to write an incomplete/corrupted autosave file, and lost about an hour of progress in a board game.

Here’s a powershell script to rotate multiple copies of TTS’s TS_AutoSave.json. I now just run this via scheduled tasks every few minutes (TTS autosaves every 5 minutes if autosave is enabled).

# Keep a series of backups of Tabletop Simulator's
# autosave files in a subdirectory

# The most recent five will keep the .json file extenion,
# older ones will use .bak, so that Tabletop Simulator 
# will not try to process them.

# Update with the path to your save directory
$sourceDir = "C:\Path\To\Documents\My Games\Tabletop Simulator\Saves"
$destinationDir = $sourceDir + "\Autosave"

# The total number of rotated backups to keep.
# Tabletop simulator saves every 5 minutes, 
# so 15 files allows you to roll back to a save 75 minutes old
$maxFiles = 15

$source = $sourceDir + "\TS_AutoSave.json"
$destination = $destinationDir + "\00.json"

if (!(Test-Path $destination) -or ((Get-Item $source).LastWriteTime -gt (Get-Item $destination).LastWriteTime)) {
  $files = Get-ChildItem -Path $destinationDir\* -include *.json, *.bak

  for ($counter=$files.count - 1; $counter -ge 0; $counter--) {
    $filepath = $files[$counter].FullName

    if ($maxFiles -gt 0 -and $counter -gt ($maxFiles - 2)) {
      Remove-Item -Path $filepath
    } else {
      $newName = "$destinationDir\$(($counter + 1).ToString('00')).json"
      if ($counter -gt 3) {
        $newName += ".bak"
      Rename-Item -Path $filepath -NewName $newName

  Copy-Item $source $destination

If you’re running linux or linux-like, logrotate will do a better job, but the Windows implementations are incomplete.

I’ve been using the Logitech G13 for a while, and like a lot of people, did not care for the tiny, pointy, thumbstick.

There are a lot of ways to fix this (like replacing the thumbstick with one from a more comfortable gamepad), but here’s what I settled on.

Originally, I didn’t want to make any permanent modifications, so I packed a joystick cover full of sugru, and smooshed it on top of the existing joystick, and let it cure for a day.

Because of the shape of the joystick cone, it couldn’t fit completely inside the cover, and rather than having sugru completely wrapping around the joystick top, it was only adhered to the top.

Despite that, it lasted about 7 months under heavy use (enough to wear down the nubs on the cover) before falling off yesterday.

Worn joystick cap Upside-down joystick cap

Since I was out of sugru (and didn’t want to wait another 24 hours for it to cure anyway), I decided to use thermoplastic (instamorph, polymorph, etc.) instead.

To allow it to fit in the cover and to adhere better, I removed the rubber tip from the G13. There doesn’t appear to be a good (read: reversible) way to do this, as mine was both glued, and too inflexible to pull off of plastic shaft without damage, so I just removed it with a craft knife.

Like the sugru, I filled a new cover with thermoplastic, pushed it onto the joystick, and used a small pokey tool ensure that the thermoplastic wrapped around the top of the joystick (now flat), and let it cool.

New joystick cover

Here’s the thermoplastic, having been molded to the inside of the cover. New joystick cap without cover

I have sometimes wanted to run git bisect on all of the files in a single commit to determine which file caused a given issue. While this isn’t supported by git (for good reason), it’s easy enough to fake.

This happened recently when I made a global typography change in a rails project, causing a feature spec (which depended on a specific string format) to fail.

# Create a new branch, based on a working commit
git checkout -b bisect-debugging <working-commit>
# Apply the changes from the broken commit
git cherry-pick <broken-commit> --no-commit
# Unstage the changes from the commit
git reset
# Loop through modified files, adding and committing each
# To include new files, you could also use `git ls-files -om --exclude-standard` 
for file in $(git ls-files -m); do
  git add $file
  git commit -m $file
# Begin bisecting for your new commits
git bisect start <working-commit> HEAD
# Use the failing spec to determine whether this commit is good or bad
git bisect run bundle exec rspec spec/failing_test.rb:123

I’ve released Wheeler, an Open Broadcaster overlay.

Wheeler overlay showing pedal, steering and shift inputs

Wheeler is designed to replace pedal cams (sock cams) in racing games for streamers. It displays configurable racing wheel, pedal, shift and handbrake input and plays nicely with multiple input devices.

Wheeler is priced at pay-what-you-want, but all support is appreciated.

Additional details and setup instructions can be found at Wheeler’s page

After some trial and error (and error, and error, and error), I’ve managed to get DiRT Rally telemetry data to display on a TM1638 display module, and have released both the arduino sketch I’m using and the python script used for communication here:

The python script is also available as an all-in-one exe. You can download here.

Here it is in use:

I started with X-Sim and this guide, but ran into a few problems. X-sim required Dirt’s extradata option to be set to 1, and didn’t seem to be aware of each cars rev limit. In the linked guide, the rev limit has been hardcoded to 9,500, which is pretty far off of some of DiRT Rally’s cars. The Use automatic maximum adjustment setting partially resolves this, but it won’t know what the maximum rpm until you reach it at least once.

X-Sim is extremely flexible and powerful, but is very configuration-heavy and felt like overkill for this project. If you’re already using X-Sim to drive your sim rig/gauges, I’d recommend sticking with it.

Additionally, if you’re interested in using this LED module for other games, including Assetto Corsa, iRacing, Project Cars and rFactor, check out instead.


You are going to need a few things:

  • The TM1638 module: $8.34
  • An arduino. I’m using this one: $7.84 but I believe this one will work and is a bit cheaper as well: $4.99
  • (optionally) Some jumper wires: $2.96.
    I just soldered wires directly to the arduino pins, but if you plan to reuse your nano for something else in the future, this may be a better solution.

Hardware setup

Connect the Arduino to your machine. You may need to install these drivers to recognize the USB serial device:

Install the Arduino software. Here is a helpful getting started guide: Download the TM1638 library and extract the TM1638 directory to your Arduino library folder (ex: C:\Program Files\Arduino\libraries).

Verify that you can upload sketches by uploading the blinky light Arduino example (see guide link).

You will need to connect arduino pins to the LED module. One for ground, one for power, and 3 to control it. If you plan to daisy chain multiple modules, you’ll be using additional pins.

Both the Arduino and the LED module pins are labeled on the PCB. Connect the Arduino 5v to the VCC input pin on the Arduino, connect ground to ground. I’ve wired Strobe 0, Clock and data to D3, D4 and D5 respectively.

Figure displaying wiring arduino to TM1638 module
Wiring example from Prodigy in the x-sim forums.

If the TM1638 library was installed correctly, you should have a TM1638 menu in the Arduino app under File > Examples. Upload the tm1638_one_module_example sketch to verify that you can communicate with the led module. You may need to update the data, clock and strobe pins used, depending on how you wired them together.

Software setup

In your DiRT hardware configuration, <Documents>\My Games\DiRT Rally\hardwaresettings\hardware_settings_config.xml, set the motion_platform udp enabled attribute to true and extradata to 3

  <udp enabled="true" extradata="3" ip="" port="20777" delay="1" /> 

Install this sketch on your Arduino. You may need to change the data, clock and strobe pin numbers, again depending on how you wired the led module up.

Download the pygauge app, which will be responsible for passing telemetry data from DiRT Rally to the Arduino.

Edit the included config.yml file, setting the host and port of DiRT Rally (likely and 20777 if you’ve left everything default), and the COM port that your Arduino is connected to.

Launch the gauge app (either run the exe, or python path/to/ You should see the Arduino reset.

That’s about it. Load up DiRT Rally, and you should see the LED module react once your stage starts.

Finishing up

  • You may want to put the LED module in a project box of some kind. This will probably entail desoldering the ribbon cable connectors on the front of the module which stick out a fair bit.
  • Carbon fiber everything
  • Install fancy racing button box buttons for the LED module.
  • Add new features and submit a pull request!


  1. Install Arduino sketch:
  2. Set DiRT’s extradata to 3
  3. Grab latest from
  4. Update config.yml with your COM port, and dirt’s IP address and port.
  5. Run gauge.exe
  6. Start game.

I’ve released finalver, the versioning specification you’re probably already using.

Finalver is most appropriate for assets that change hands and update regularly, codifying and standardizing one of the most popular1 versioning systems in active use today.

It’s currently at version, and moving toward version soon.

  1. Citation needed 

This is the obiligatory “I’ve update my blog, and I’m serious about adding regular content, guys. From here on, things will be different,” post.

This site now sports the Minimal Mistakes jekyll theme and with it, better responsive support.

Additionally, the site has a new vanity domain, a real and appropriate moniker (“Fail Fast”), more room for large images, and a marginally less grumpy author avatar.

I still need to add a nice banner image and favicon, but it’s not pressing.

I’m looking forward to the content I’ve been meaning to write. Fingers crossed.

Ran into an issue this weekend with httparty, and an API (mapquest) that was sensitive to query parameter order. Specifically, when batch geocoding locations, mapquest expects a query string like: ?location=foo&location=bar&location=baz, and will return geocode results in the order received.

I noticed the issue when an api call for a US city returned a result in Ireland.

Httparty has two methods of encoding query parameters. The default, rails-friendly, way converts

:param => ['bar','baz']



This can be disabled by calling disable_rails_query_string_format, which replaces the default query string normalizer with this proc

  Array(query).map do |key, value|
    if value.nil?
    elsif value.is_a?(Array) {|v| "#{key}=#{URI.encode(v.to_s,"[^#{URI::PATTERN::UNRESERVED}]"))}"}
      HashConversions.to_params(key => value)

Different version of ruby (even different 1.8.7 versions) will sort the result of

Array({:key => :value})

differently. A sort was added at the end of the normalizer proc to ensure that the query string is consistent across versions, likely for testing. This works, but has the side effect of also shuffling the order of array value elements.


  • Presort query parameters to avoid surprises,
  • use an alternate proc for query normalization (I just removed the sort entirely in my app),
  • submit request as json (or other format)
  • or wait until it’s fixed upstream.

Httparty pull request can be found here:

Received 3 Raspberry Pi cases as gifts recently, and my wife was kind enough to supply me with these excellent boxes.

Three paper raspberry pi cases

Box template can be found here

Show the most recent git commit hash, and copy it to the clipboard:


git rev-parse HEAD | tee xclip -selection c

Windows (mingw/cygwin)

git rev-parse HEAD | tee /dev/clipboard


git rev-parse HEAD | tee pbcopy

Recently discovered Chocolatey, which I’ll be using for basic software installation on new machines.

Chocolatey both suffers and benefits from its community-driven packages. While there are a large number of packages available, especially compared to similar windows tools, several packages I tried are were not functioning and seem abandoned.

My current install script and package lists can be found here.

When running the setup_github_pages task, the ampersand in &hellip; can be escaped with a caret symbol.


@@ -345,7 +345,7 @@ task :setup_github_pages, :repo do |t, args|
   mkdir deploy_dir
   cd "#{deploy_dir}" do
     system "git init"
-    system "echo 'My Octopress Page is coming soon &hellip;' > index.html"
+    system "echo 'My Octopress Page is coming soon ^&hellip;' > index.html"
     system "git add ."
     system "git commit -m \"Octopress init\""
     system "git branch -m gh-pages" unless branch == 'master'