Spring Lisp Game Jam 2026

ibobev1 pts0 comments

Spring Lisp Game Jam 2026 · Andrey Listopadov

Spring Lisp Game Jam 2026

Sun, May 24, 2026

@programming @gamedev<br>tic80<br>fennel<br>~14 minutes read

This year I decided to participate in the Spring Lisp Game Jam.<br>It&rsquo;s an annual event, where you have to make a game in any kind of lisp in a limited time, usually a week.

I&rsquo;ve been putting this away for several years, because every time the jam started I wasn&rsquo;t ready to spend time on it, because of work or other duties I had at the time.<br>This year, however, I decided to take a vacation, and give it my all.<br>Life, of course, had other plans, but I managed to persevere.

This game jam doesn&rsquo;t have a particular theme, which is good, as I always wanted to make a particular kind of a game - a movement-oriented platformer.<br>I really enjoyed games like Metroid Fusion and Metroid Dread, which, to my taste, have great platforming, especially in Dread, so I wanted to make something akin to it.<br>On paper, this idea seemed doable.<br>In practice, well, you&rsquo;ll see.

I decided to make &ldquo;speed&rdquo; the main thing of my game, thinking that the core idea will be to maintain speed, and complete room-based obstacle courses.<br>My engine of choice was again TIC-80 as I had some experience with it already, and it&rsquo;s the most frictionless environment I know for making small games.<br>That&rsquo;s debatable, of course, given TIC&rsquo;s restrictions of resolution of 240x136 pixels and a 16-color-only palette.<br>But I like restrictions, they breed creativity, as we all know.

This is more of a postmortem post, as I&rsquo;m writing this after finishing the game - I simply had no capacity of writing this during the development.<br>So information below is more of how I remember this, and of notes I made along the way.

Day 1

First things first, I chose TIC-80, and it supports programming in lisp out of the box.<br>The language in question is Fennel, which is a nice lisp that compiles to Lua.<br>I needed a few things though.

TIC doesn&rsquo;t have any built-in functionality besides the essential things for drawing on the screen and reading user&rsquo;s input.<br>My game needs to deal with collisions, and while other game engines, like LOVE, include a library for that, TIC is certainly not.

A popular library for this is bump.lua, however, TIC doesn&rsquo;t allow filesystem interactions, so the library must be bundled inside the cart.<br>However, this is a Lua library, and I&rsquo;m making a game in Fennel.

Fennel has a way of inlining dependencies via the --require-as-include option that could be used, however, it only works when compiling Fennel code to Lua.<br>And I&rsquo;m not sure if this will pass for the game jam.<br>Plus, Fennel doesn&rsquo;t compile comments, so I couldn&rsquo;t just write the game cart in Fennel and then compile it to Lua, I&rsquo;d need to translate all of the cart metadata by hand.

Luckily, a few years ago I made a port of bump.lua to Fennel for cases like this.<br>I used it in the other game I was making at the time.<br>You can read my old dev-log here.<br>Anyhow, I needed to make an actual game, not just mess with libraries, so I picked a palette and began working.

First day was all about player controller.<br>I needed a solid foundation to build the game around, and none of my previous player controllers were adequate for this.<br>They were too stiff.

At the end of the day I ended up with this:

Your browser does not support the video tag.

This is a bit more than just a player controller - I have a camera system, level editor, placeholder graphics, and powerups already coded.

This is my camera system:

(local camera<br>{:x 96<br>:y 40<br>:update<br>(fn [self {: x : y}]<br>(doto self<br>(tset :x (* (// x 240) 240))<br>(tset :y (* (// y 136) 136))))<br>:draw<br>(fn [{: x : y} remap]<br>(map (// x 8) (// y 8) (+ (// x 8) 31) (+ (// y 8) 18) 0 0 0 1 remap))<br>:translate<br>(fn [{:x cam-x :y cam-y} x y]<br>(values (- x cam-x) (- y cam-y)))})

It&rsquo;s a simple object that has three main methods.

The update method is responsible for camera positioning.<br>It is called on each frame, and it simply clamps the x, y position into the one full screen range.<br>Thus, this is not a free camera, it is locked to the current screen.

I had dynamic cameras in the past, and while I like them, for this game I wanted something different.<br>Essentially, my vision was that each screen will be an obstacle course, although even at this point I already knew this would be a bit problematic.

The draw method simply draws the current visible range of tiles via the map command.<br>I have a remap callback ready in case I&rsquo;ll need to change some tiles dynamically.

The final method translate is an interesting one.<br>When I draw anything, like the player, or interactable objects, I need to do so in the camera space.<br>So I call (camera:translate obj.x obj.y) to get screen-space coordinates.<br>In other words, object&rsquo;s coordinates may be 1337,420, but in camera space they as well may be 42,27.

The camera draws the level from the...

rsquo game camera fennel lisp like

Related Articles