Taylor

Made for Games

Taylor Monthly - January 2026

- 2,100 words
  Count
Releases 1
Commits 7
Contributors 2
Pull requests merged 6
Issues closed 0
Stars 123

At a Glance

Taylor v0.4.1 Released

It took me around 3~ months to get to the point where I felt another release was warranted. I’m going to try and do more frequent releases as I feel it helps make it obvious this is a maintained and active project.

You can checkout the release notes for Taylor v0.4.1 for more details about what’s changed, but at a rough glance:

Website Updates

CSS Changes

I’ve completed all my cascading style sheets (CSS) changes for my websites now. This means the Taylor website, the Taylor Playground, and my personal blog are now all based on simple.css. This also means they have both light and dark modes that change based on your preferences.

Documentation Update

I have redesigned the documentation page to have the more useful content towards the top of the page. It now also generates the library links from the gembox file, so it stays up to date with each new release.

Old Documentation Page

Taylor's old documentation page showing the sections in the
following order:

- Tutorials
- Migrations
- APIs

New Documentation Page

Taylor's new documentation page showing the sections in the
following order:

- Tutorials
- APIs
- Migrations

Switched to LocalCI

LocalCI is a Ruby gem I built for managing Continuous Integration (CI) workflows that can run locally. Using this has meant it’s significantly easier for contributors to be confident their pull requests will be accepted by running bundle exec rake ci.

A terminal showing the output of the command bundle exec rake ci.

The output is as follows.

Running flow 'Setup'
Step 'Clean' completed in 0.54s
flow completed in 0.60s

Running flow 'Documentation'
Step 'Test' completed in 0.23s
flow completed in 0.30s

Running flow 'Formatting - Setup'
Step 'Ephemeral Files' completed in 0.33s
flow completed in 0.40s

Running flow 'Formatting'
Step 'Standard' completed in 2.73s
Step 'Clang Format' completed in 0.78s
flow completed in 2.80s

Running flow 'Linting - Setup'
Step 'Ephemeral Files' completed in 0.36s
flow completed in 0.40s

Running flow 'Linting'
Step 'Chunk #1' completed in 43.83s
Step 'Chunk #2' completed in 42.29s
Step 'Chunk #3' completed in 45.58s
Step 'Chunk #4' completed in 43.79s
Step 'Chunk #5' completed in 51.17s
Step 'Chunk #6' completed in 50.70s
Step 'Chunk #7' completed in 58.61s
Step 'Chunk #8' completed in 34.53s
flow completed in 58.61s

Running flow 'Testing - Setup'
Step 'Build Taylor - Linux' completed in 8.41s
Step 'Build Taylor - Windows' completed in 13.54s
flow completed in 21.99s

Running flow 'Testing'
Step 'CLI Tests' completed in 0.71s
Step 'Linux Taylor Tests' completed in 0.20s
Step 'Windows Taylor Tests' completed in 2.23s
flow completed in 2.32s

Running flow 'Testing - Teardown'
Step 'Clean' completed in 0.50s
flow completed in 0.50s

Running flow 'Docker Images - Setup'
Step 'Build Base Image' completed in 56.79s
flow completed in 56.87s

Running flow 'Docker Images'
Step 'Build Android Image' completed in 1m 47s
Step 'Build Linux Image' completed in 1m 3s
Step 'Build OSX Image' completed in 1m 32s
Step 'Build Windows Image' completed in 1m 37s
Step 'Build Web Image' completed in 1m 45s
flow completed in 7m 46s

Running flow 'Export Test - Setup'
Step 'Export Test Suite' completed in 1m 54s
flow completed in 1m 54s

Running flow 'Export Test'
Step 'Linux' completed in 0.21s
Step 'Windows' completed in 1.70s
Step 'Web' completed in 4.36s
flow completed in 4.45s

You can check out the Pull Request if you want more details on how it works.

clang-format Update

Taylor is now formatted against clang-format 21. This change has come about due to me working on both Fedora and Debian and that seems to be the latest version available on Fedora.

I took this opportunity to change a couple of the rules that had been bothering me. I also distinctly remember someone commenting about the BreakAfterReturnType rule bothering them but I can’t find the comment anymore. Ever since then it has bothered me too and now I’ve finally changed that rule!

Before (TopLevel)

auto
mrb_Circle_initialize(mrb_state* mrb, mrb_value self) -> mrb_value
{
  // ...
}

After (Automatic)

auto mrb_Circle_initialize(mrb_state* mrb, mrb_value self) -> mrb_value
{
  // ...
}

I have also bumped the ColumnLimit to 100 as I found default of 80 made the code a bit too vertical and 100 is what I tend to use everywhere else.

This has been a long time coming, I just didn’t have the time to get deep into the .clang-format file and update it for what I wanted on top of upgrading clang-format itself.

Jumpy Alien Example

Jumpy Alien now has a complete gameplay loop! It’s incredibly bare bones and the game design is awful but it’s still a big milestone. I can now spend time refining the project and making it feel nicer.

The main menu is shown before going into play the game. Once playing the player gets a score of one before crashing into a pipe and seeing the end screen showing their high score of 1. They then retry and get a score of 0 being shown the end screen again showing their score of 0.

Began Redesigning taylor squash

I got the itch to redesign the squash command in Taylor because the current implementation leaves a lot to be desired.

The Way It Works Now

Given these three files.

# game.rb
require "lib/game"

Game.call()
# lib/game.rb
require "lib/player"

class Game
  def self.call
    puts "Run the game!"
  end
end
# lib/player.rb
class Player
  def self.call
    puts "Does player things"
  end
end

If we called taylor squash --stdout we would see the following code printed to standard output.

# Start game.rb
# Start ./lib/game.rb
# Start ./lib/player.rb
class Player
  def self.call
    puts "Does player things"
  end
end
# End ./lib/player.rb

class Game
  def self.call
    puts "Run the game!"
  end
end
# End ./lib/game.rb

Game.call()
# End game.rb

You can see that I’ve just replaced the require lines with the content from the files. This is actually very different to how require works under the hood and can lead to discrepancies between running in development and release builds. This is the big motivator behind redesigning taylor squash.

The Redesign

My plan is to distribute this as both a regular Ruby gem and an mruby mgem if I can get it to a point I’m happy with it.

The design I’m currently experimenting with is a bit more complicated but should lead to a more consistent operation between development and release. I would use lambdas to keep the namespaces clean and an overridden require method. I’ve put a functional example below to illustrate what the output could look like.

You can see this working in your browser.

#!/usr/bin/env ruby

SQUASHER_FILES = {
  "first_require" => -> {
    class First
      def self.call
        puts "First"
      end
    end
  },
  "second_require" => -> {
    class Second
      def self.call
        puts "Second"
      end
    end
  },
}

class Squasher
  def self.inject
    original_require = Kernel.method(:require)

    Kernel.define_method(:require) do |file|
      if Squasher.files.has_key?(file)
        Kernel.module_exec {
          Squasher.files[file].call
        }
      else
        original_require.call(file)
      end
    end
  end

  def self.files
    SQUASHER_FILES || {}
  end
end
Squasher.inject

require "first_require"

First.call

require "second_require"

Second.call

Running that will give you the following output.

First
Second

There’s definitely flaws with this but I think it’s a pretty promising start. I do also plan to squash files from gems into the output but would need to do something special for native gems.

I’ll probably be working on this for a while before releasing anything as it’s a very delicate process. I’m also worried about breaking people’s current builds in Taylor as this is a radical change.