Game development services

We build our own game properly.
We'll build yours the same way.

Cat Splat Studios is a game studio in Toronto. Our flagship is Sentinels of Gleamwood, a Unity 6 action roguelite heading to Steam. It runs on data-driven state machines, a level generator that proves its own levels are walkable, 657 automated tests, and content validators wired in as build gates.

All of that is running today, and we are happy to walk you through any part of it.

By the numbers

72kLines of C# across 408 files
657Play-mode tests passing, zero failing
31Enumerated routes across 10 biomes
21Versioned builds through the Steam pipeline
5Modding tiers, plain text, no compiler
2Validators, one of which fails the build

What we do

The work we take on

Each of these is backed by something you can open and read in a working codebase, and we are happy to walk you through any of it.

Unity 2D action-game engineering

We build the parts of an action game that are painful to retrofit: a character controller with the feel already in it, combat with real hit windows and hitstop, enemies with readable tells, and a front end that works on a controller from the title screen down.

Proof Sentinels of Gleamwood, built in Unity 6 on 2D URP. A hand-rolled raycast character controller with one-way platform masks and an explicit commanded-versus-actual velocity contract, a custom URP sprite shader with flash and slice effects, a custom PlayerLoop tick system, and nine data-authored enemies.

Unreal Engine C++ gameplay and AI

The same work in the other engine. Player pawns and controllers, enemy AI that reads clearly to the player, and the director-level systems that decide what shows up and when.

Proof Codename: Shifter, Unreal Engine 4.27. Our own contributions there are the player pawn and its controller, a custom AI movement component, the AI controller on top of it, a combat director, and the encounter subsystem with its spawn points. Behaviour trees drive the enemies, with custom tasks, services and decorators, plus weight-based swarm evaluation and a shared target distributor. Shifter was built by a team, so this is the part of it we wrote.

Procedural generation you can prove is playable

The hard part is not generating a level. It is generating one that never strands a player behind a jump they cannot make. We build generators as pure functions of a seed so bugs reproduce, then verify the output against the real movement numbers instead of hoping.

Proof A level's layout is a pure function of seed and node, so a suspended run regenerates rather than serialising geometry, and the generator unit-tests with no scene loaded. The reachability auditor floods a state space of position, vertical velocity and dash cooldown, sweeping the shipped collider box and reading every constant from the live player settings asset rather than from code defaults. Two separate gates: every shipped room is proved traversable under that model, and a 200-seed sweep over a four-path layout built from the shipped room pool returns four distinct paths every seed, zero overlapping rooms, and a room count inside the designed 28–41 band on better than nine seeds in ten.

Systems your designers can tune without a programmer

If every balance change needs a build, your designers are queuing behind your engineers. We author behaviour as data and generate the editing surface from that data, so tuning is a slider or a text edit rather than a ticket.

Proof Every enemy is a state machine authored as ScriptableObject sub-assets. Six of nine shipped enemies needed no new code at all. The run web, all ten biomes and every boss live in one text file that imports with validation. A typo raises an error and leaves the field on the value it already had. Scene-view hitbox handles are drawn through the exact method the combat code scans with, so the preview cannot drift from the game.

Modding and player-authored content

Community content is a retention feature and a support liability at the same time. The difference between the two is whether the safety was engineered or hoped for.

Proof Five override tiers as plain text beside the executable. Levels authored as ASCII room files, with the engine deriving footprint, door sockets and reachability from the drawing, then auditing it on the player's machine where no editor exists. Clone-never-mutate at two levels. Save slots bound to a campaign at creation, so cross-campaign corruption is impossible rather than unlikely.

Steam release engineering and build automation

The last ten percent of shipping is depots, launch options, and being able to say which commit a build came from. We have that wired, and we've run it twenty-one times.

Proof A real SteamPipe pipeline: templated VDF and a PowerShell upload driver with a preview dry run. The build description is stamped with the git SHA so any upload traces back to a commit, and the executable name is pinned so a marketing rename can't break the launch option. In-editor build manager with semver bumping, git capture and build info baked into the player.

Tests, validators, and a handover you can use

We write tests for the parts that are expensive to be wrong about, and we make the build refuse to compile when the content is broken. When the contract ends you get documentation written for whoever arrives after us.

Proof 58 play-mode test files on their own assembly definition, covering the hard parts: state-machine golden sequences, kinematic physics, generator determinism, reachability, save isolation and mod loading. Two content validators, one of which throws a build exception, so an unreachable room or a broken run web cannot be built. Plus a multi-page wiki whose tool screenshots regenerate from the real editor.

Cat Splat Engine

We wrote our own engine, and we use it

Cat Splat Engine is a C++17 runtime on OpenGL 3.3, a dockable editor, a standalone player and a headless asset cooker. All four build from one CMake tree and share one output directory, so a scene saved in the editor runs in the player with no copy step.

It exists because some problems are much easier to understand once you have had to solve them yourself.

742GoogleTest cases
11Render passes
7Backends behind 3 interfaces
50kLines of C++
Engine call sites IPhysicsBackend JoltPhysXSimple
Engine call sites IScriptBackend LuaNull
Engine call sites IAudioBackend miniaudioNull
No library type crosses that line. Not one Jolt, PhysX, Lua or miniaudio type appears in an engine header, and the isolation is enforced at the CMake level with private static library links rather than by convention. A scene authored against Jolt loads under PhysX unchanged. This pattern is the reason the roadmap below is realistic.

Working today

  • Cascaded shadow maps, four cascades at 2048, texel snapped so they hold still as the camera turns, with far cascades updated on a movement budget rather than every frame
  • Cook-Torrance PBR with split-sum image based lighting, baked from an HDR file or from a procedural sky
  • An eleven pass pipeline: shadows, forward opaque, skybox, sorted transparency, bloom, ACES tonemap, ink outline, colour grade, vignette, FXAA, UI
  • Up to 16 point and spot lights, selected by influence so an overflowing scene drops the least important light instead of an arbitrary one
  • EnTT ECS with 17 component types, versioned JSON scene serialization, play in editor with snapshot and restore, and undo and redo across play sessions
  • Physics, scripting and audio behind three interfaces carrying seven backends, selected by name at runtime
  • A game UI system with its own markup and stylesheet format, real CSS style specificity and combinators, two way data binding, and hot reload
  • A job system behind async asset loading, and a headless cooker that validates a project without opening a window

Not built yet

  • No skeletal or skinned animation. The renderer draws static meshes, and the vertex format has no bone data at all
  • No networking of any kind
  • Point and spot lights cast no shadows. Only the sun does
  • The asset cooker validates a project, it does not bake a binary format
  • No texture compression and no anisotropic filtering. Everything is RGBA8
  • Anti-aliasing is FXAA only. There is no MSAA and no TAA
  • Windows is the supported platform. The Linux tree compiles under gcc and clang, but runtime deployment is unfinished and has not been validated on real hardware
  • No game has shipped on it. It is a working engine with a working toolchain, and that is the entire claim

Where it goes next

None of the four below is built. They are the direction the engine is being taken in, and they are listed here because each one has a concrete reason to be achievable rather than being a wish. If you are hiring us for work today, hire us for the list above.

  1. Planned

    A modern renderer, with OpenGL kept as the fallback

    Vulkan first, behind a render interface in the same shape as the physics, scripting and audio seams. The graphics API currently reaches 26 of the engine's 155 source files, so the surface a second backend has to cover is already known and bounded. OpenGL 3.3 stays in the tree as the compatibility path for older hardware rather than being ripped out.

    Why it is realistic Three subsystems already sit behind interfaces with zero library types in engine headers. The renderer is the next one to go behind a seam, not the first.

  2. Planned, after Vulkan

    Ray traced lighting

    Hardware ray tracing needs the newer API underneath it, so this follows the Vulkan backend rather than running alongside it. Shadows and reflections are the first targets, since those are where the current pipeline works hardest: cascaded shadow maps and a screen space post stack both exist to approximate what tracing does directly.

    Why it is realistic The pipeline is already a list of passes with a shared context, so a traced pass slots into the same structure the existing eleven use.

  3. Planned

    Wider platform support, including mobile

    Linux is partly there. The whole tree compiles under gcc and clang with Jolt and the built in physics backend, and what remains is runtime linking and a validated end to end build. Mobile is a larger job: it needs a windowing and input layer beyond GLFW, a GLES or Vulkan path, and packaging after that. The aim is to cover as many targets as the codebase can honestly carry.

    Why it is realistic Platform specific dependencies are already isolated. PhysX is declared Windows only in the package manifest and simply drops out of a Linux build without touching engine code.

  4. Planned

    Peer to peer rollback netcode

    Rollback needs a simulation that produces the same result twice from the same inputs, which is a property you either design for early or retrofit painfully. One fixed step accumulator already drives gameplay and physics together in the main loop, so the two can never disagree about how many steps have elapsed. Jolt is the deterministic simulation the rollback would re-run against.

    Why it is realistic The hard precondition is in place already. There is currently no networking code at all, so this is greenfield on top of a fixed step loop rather than surgery on a variable one.

How we work

Four shapes, all fixed-scope

Every one ends with something you can run, plus the source.

Prototype or vertical slice

Four to ten weeks, one fixed goal, a playable build at the end. Good when you need to know whether the idea is fun before you fund it.

A named system

Combat, movement, procedural generation, saves, modding, front end, input. We take one subsystem, build it data-driven and tested, and hand it over documented. Good when your team is strong but short a specialist.

Tools and pipeline

Editor tooling your designers will actually open, runtime tuning panels that survive into builds, release automation, and a test harness for whatever keeps breaking. Good when the game is fine and the making of it isn't.

Audit and rescue

One week reading your codebase, then a written report covering what is load-bearing, what is going to hurt, and what to do first. Fixed price. Good when you have inherited something and need to know what you are holding.

We work in English on Toronto hours, and we're comfortable either being the only engineers on a small project or a specialist pair of hands inside a bigger team.

Straight answers

What we won't claim

Studios our size tend to round up. Here's where we round down.

Nothing of ours is out on Steam yet

The app, the depot and the upload pipeline are real and exercised, and twenty-one versioned builds have gone through them. The game has not launched. Our one previously published title is a mobile game, Rocket Recover, and it's archived.

Our tests aren't on CI

657 play-mode tests pass and the validators run as a build gate, but the suite runs locally and on demand. If you need a green badge on every pull request, that's something we'd build with you rather than bring.

The game you're looking at is greybox

The enemy art is finished and the level art is still greybox. We do systems, tools and engineering, so if the project needs art you will want to bring an artist alongside us.

We are three people

Two developers and Vader, who is a cat. That is worth knowing before you scope anything large with us, and it is also why we are careful about what we take on.

Our engine has never shipped a game

Cat Splat Engine is real, tested and actively developed, and it is not a product. It is there to show that low-level work does not scare us.

Tell us what you're building

Send a paragraph about the project, what stage it's at, and what's currently in your way. If it isn't a fit we'll say so in the reply, and if we know someone better suited we'll name them.

Toronto, Ontario. A person reads every one of these.