Spycursion is now on Patreon!

We’d be honored to have your support on Patreon.

Just want to follow progress? You can join our mailing list here:

Designing a Video Game API

We’ve talked a bit about Spycursion and its open source model, but we haven’t really delved into how that will work from a practical standpoint. In this post I’ll talk about application programming interfaces, or API‘s, with the goal of helping you understand some of the decisions that go into designing an API for a multiplayer game like Spycursion. Please note, this information is intended for a more general audience, so many of the details have been simplified. This post is an introduction, not a reference manual!

What is an API?

An API is a set of rules and agreements, through which developers of various software components agree how those components will communicate. You can search the internet for API documents of all sorts to get a feel for what typically goes into those documents, but if you’ve never tried writing code for an API before (or writing code at all), you may get lost in the jargon.

Instead, let’s look at a simple real-world example…

Server: Hello, and welcome to Foodz R Us! Can I get you anything to drink?
You: Purple cow.
Server: Excuse me?
You: Purple cow.
Server: Err, I’m… sorry, we don’t have that on the menu. Would you like-

When a server at a restaurant asks if you’d like anything to drink, they are usually expecting you to name something on the drink menu, or perhaps to ask a question. Here, though, you violated their expectations and the server’s “API” returned an “error.” (I personally have never seen “purple cow” on any drink menu, but if you do, let me know!) In computer-speak, this example could be converted to something like…


{ "request": "drink_choice" }


{ "drink_choice": "purple_cow" }


  "error": "purple_cow not found",
  "drinks": [ "water", "tea", "milk", "juice", "beer" ]

{ "request": "drink_choice" }


{ "drink_choice": "purple_cow" }


  "error": "purple_cow not found",
  "drinks": [ "water", "tea", "milk", "juice", "beer" ]

{ "request": "drink_choice" }


{ "drink_choice": "purple_cow" }

Seasoned programmers will recognize that the messages above are in the popular JSON format. Certainly not all API’s use JSON (Spycursion’s does), but I will be using it throughout this post, for its simplicity and readability.


Just about every multiplayer video game will, at some point, involve you moving one or more characters from point A to point B on a game map. To keep things simple, let’s say our game map is a 2D grid made up of integer coordinates. (You know, the grids your high school Geometry teacher made you draw.) When you first start the game, you don’t necessarily know your character’s starting point, but the server should have that information, and so it lets your game client know:

{ "player_position": [ "x": 5, "y": -2 ] }

Now that the client and server are synced, you can move your character around the map. In a flat, boring world with no obstacles whatsoever, your client could just do something like this:

{ "move": [ "x": 3, "y": 1 ] }

But where’s the fun in that? In Spycursion, as in most other games, pathfinding may be required. Walking directly from A to B in a straight line might have you plowing through buildings or getting run over by a car! So the client, or the server, or both, will need to be able to navigate your character around obstacles. In practice, you would likely rely on the client for pathfinding, then convert that into API requests. If you as a player click the point (3,1), but there is an object in the way, the actual API requests might look like this:

{ "move": [ "x": 6, "y": -2 ] }
{ "move": [ "x": 6, "y": 1 ] }
{ "move": [ "x": 3, "y": 1 ] }

But what happens if a player hacks their client to just ignore those obstacles? What does the server do with a request that seems to defy the laws of physics? This is where collision detection comes into play, and any well-designed game server will include it. Basically, upon a player trying to run through a tree, the server sends a message to said player’s client…

{ "player_position": [ "x": 5, "y": -2 ] }

… as if to say, “Sorry, that thing is impermeable. You’re still at (5,-2).”



… Sorry, I should explain. REST stands for representational state transfer and is very often used in a sentence with “API.” Without getting into too many details, REST is an architectural style that is common among web API’s, and one of its more notable features is that the server does not store any client context between requests. In other words, every client request has all of the information that the server needs in order to process it. In a RESTful API, movement requests would look something like this:

  "from": [ "x": 5, "y": -2 ],
  "to": [ "x": 6, "y": -2 ]
  "from": [ "x": 6, "y": -2 ],
  "to": [ "x": 6, "y": 1 ]
  "from": [ "x": 6, "y": 1 ],
  "to": [ "x": 3, "y": 1 ]

A little verbose, but not terrible, right? Well, think about that little cheater with the hacked game client:

  "from": [ "x": 5, "y": -2 ],
  "to": [ "x": 3, "y": 1 ]
  "from": [ "x": 6, "y": -2 ],
  "to": [ "x": 4, "y": 7 ]
  "from": [ "x": 666, "y": 666 ],
  "to": [ "x": 666, "y": 666 ]

A stateless API would give the kid free reign to teleport around the game map! Naturally, this makes no sense for Spycursion, and you should treat any multiplayer game advertising a “REST API” with extreme skepticism.


I don’t believe we’ve talked about this, but here’s a new Spycursion tidbit for you — every player and NPC in the game has a vision cone. You can only see characters about 135 degrees in front of you (buildings and other stationary objects are always visible), so it matters which direction you’re facing. If you sneak up behind another player, they can’t see you without turning around. The API request to change where you’re facing is straightforward:

{ "look": 1.570795 }

You might recognize that number — yes, here are those Geometry nightmares again — as half of pi, telling the server that your character is now looking at pi/2 radians, or 180 degrees, which in this case just means “due south.” When you turn around, you might discover another player trying to sneak up on you, about which the server now sends a warning:

  "player_id": 66666,
  "player_position": [ "x": 5, "y": -3" ],
  "player_looking": 0

In reality, you wouldn’t be sent the opposing player’s actual ID (see below), but instead a lot of information about their appearance, and perhaps an indication that you’d encountered them before. Again, we’re keeping things simple here.


Another MMO trope: Interacting with other characters. (I know, it’s awful.) In most games, if you wanted to converse with and/or hit on another character, your client might send a request like this:

  "action": "talk",
  "player_id": 66666,
  "message": "Hey, stop sneaking up on me."

And that’s all well and good, if your client has the player’s ID, which it probably does, as it was probably already sent by the server. Spycursion, though, is a bit different. We can’t tell you a given player’s actual ID or username, because of the possibility of disguises. (This is a spy game, after all!) If you knew that little Johnny’s player ID was 66666, and this fact was always shared by the server, then little Johnny could never truly fool you. Instead, we have to assign a temporary ID for every character who enters your vision cone. This is shared between client and server, until enough time has passed, or you leave the map, at which point you “forget what they looked like.”

If another player starts a conversation with you, your client gets a message like this:

  "player_id": 1234,
  "says": "I heard there was a new Spycursion blog post today!"

Other spy-like requests look similar, except of course the server doesn’t notify your client that someone has just planted a bug on you. 😉


This post wouldn’t be complete without me talking about the API details behind what happens on your character’s computer screen. That said… there actually isn’t much to talk about! Spycursion’s in-game internet will offer many services which can essentially be divided into two types — “hackable” and “unhackable.” The “unhackable” services will have their own API specifications, while the “hackable” services will consist of in-game programs written in Slang. All of the Slang programs follow one simple API request:

  "command": "rm",
  "args": [ "-rf", "/" ],
  "target": "0123:4567:89ab:cdef:0123:4567:89ab:cdef",
  "session_key": "0123456789abcdef"

The target and session key are just for verification that you are logged into a remote host, and for allowing you to have multiple terminals running at once. That request includes every (non-client-specific) command you’ll run from the terminal, including network tools, the Slang compiler, and your programs themselves.

We haven’t fully decided which services will fall under which categories. Transparently, we would love every service to fall under the “hackable” category, but it’s just a question of feasibility and what we actually want players mucking around with.


Spycursion’s API documents aren’t yet ready for public release (and even if they were, the server isn’t ready for public release, so you wouldn’t be able to do much with them). In the meantime, hopefully this post has taught you a few things about video game API’s, and maybe even motivated you to design your own!

Anomaly Report #73 (CASSI 001)

From: Burdinjaun

Subject: [TS//SCI] United States Armed Forces, Cyber Directorate — Possible Security Breach
Status: Investigation in Progress
Interviewer:                         , Military Investigator

Verifying… [100%]

Deciphering… [100%]



Interviewer: Please verbally express your consent to record this interview.

Tomás Lednura, PhD: I consent.

Interviewer: Can you summarize the facts of what happened on Oct. 24th, in the Annex B Conference Room 109, at 13:34?

Lednura: OK, as I recall it… Hmm, 17 people were summoned to the room due to an urgent security breach. 13 were there when the meeting started and the doors were closed. Four were high ranking officers, six were cybersecurity experts. The rest were CASSI developers.

Interviewer: For the record, CASSI is the Computer-Assisted Security Surveillance Intelligence. Do you recall all the names?

Lednura: You should have them in the written report I sent… (trails off) Jack from cyber security, my boss, called the meeting. I made the discovery of the information leak, and he restated what I had told him. At 13:01, one of the servers hosting CASSI started extracting data from the other servers and sending it to external sources. There were no known intrusions at the time, as verified by extensive malware checks. The data transfer processes were not spawned from a cron job or any other server configurations, and resisted all attempts to kill them. After getting everybody up to date on the situation, an engineer from the AI development team gave an assessment… (pause) Lisa, I think. Anyhow, she said that CASSI was only capable of monitoring communications and looking for possible national security threats. Any alarms would be relayed to a GUI in a room where some analyst would continue the work, and the system had no volition or any I/O capable of moving files or sending messages to the outside. I guess she could give you a better summary.

Interviewer: Sadly, we can’t ask her, nor anyone else. After the events of that day, one by one everyone in that room has died or disappeared. Except you, Dr. Lednura.

Lednura: What? How is that possible? I talked to Glenn a week ago!

Interviewer: Please stay on topic. We’ll talk about Mr. Lewis’ disappearance later. We need all the facts first.

Lednura: (sighs) I think those are all the facts any of us had prior to the meeting. During the meeting, we found that large amounts of data were being transferred. There was no rhyme or reason as far as security classification, but most of it was generated by CASSI processes. Like I said, every time we killed one of those processes a new one replaced it, and no other countermeasures worked, either. Gen. Miller asked for a summary; we told him what we knew and showed some evidence illustrating what was happening. That’s when I suggested taking the server offline, but there was a lot of debate about that. The CASSI guys were adamant that there was no way it could be responsible for the situation.

Interviewer: Was it?

Lednura: The evidence was inconclusive, but it was strong enough to suggest that turning off the server could stop the leak. I explained that, and Gen. Miller gave the OK to shut it down, even with the devs protesting about its state being corrupted, losing generations and all of that. As soon as he gave that order, the alarm went off, and the monitors showed the activation of something called Protocol Z14. I didn’t even know what Protocol Z14 was, I still don’t. But I distinctly remember hearing the big doors locking.

Interviewer: The big doors?

Lednura: That’s internal jargon for a complete lockdown, basically. Gen. Miller gave us this confused look and said that Protocol Z14 could not be activated without his OK. But we were all locked out of our systems.

Interviewer: Aside from that, did he reveal anything about the nature of the Z14 protocol?

Lednura: No, we’re all trained to avoid asking too many questions. But a voice recording sounding with the alarm said we had five minutes before the whole floor was incinerated, so we were frantically trying to override the security systems preventing us from getting out, or at least the ignition systems about to burn us alive. (sigh) But it was useless. After a few minutes we gave up and accepted our fate.

Interviewer: Just like that?

Lednura: What else could we do? We were in a concrete basement, with two-meter reinforced walls, a single exit sealed by a solid steel door, no working overrides, and a (expletive) incendiary bomb about to go off!

Interviewer: OK, and-

Lednura: Gen. Miller was starting to say something when the alarms ceased, and a green notification on the monitors signaled that Protocol Z14 had been suspended. Everybody was cheering, but the general just had that same confused or worried look on his face.

Interviewer: I can tell you this much: Protocol Z14 was designed to not be stopped, paused or suspended in any way. Once initiated, there is no way to stop it, by design.

Lednura: I guess that’s why he asked right afterward who had stopped it. We were all as puzzled as he was. Then a bunch of code appeared on my screen-

Interviewer: That’s enough, thank you. Now let’s talk about Mr. Lewis’ disappearance.


(click sound; end of recording)

Spycursion and the News

I’d originally planned to pick a relevant news story and tie it to Spycursion somehow — “Hey look, you can steal Bitcoin too, here’s how you might do that,” etc., etc. But it turns out there were so many news stories that I couldn’t just choose one; that’s also why this month’s post is late. (That’s my excuse, and I’m stickin’ to it.) The plethora of cyberespionage-related news stories inspired another idea, which I’ll get to in a minute. As for the Spycursion update… I decided to go meta.

If you live in the United States, you’re probably aware of the allegations by the intelligence community against Russia for attempting to interfere in our 2016 (and 2018) elections. To the best of our knowledge, Russia didn’t do this by hacking voting machines — instead, they hacked our minds. They spread disinformation targeting both ends of the political spectrum in an attempt to divide Americans and sow chaos.

Consider where you get your news. If you’re like most people, you probably get a significant chunk of your news online, and a significant chunk of that from social media; the other largest news source, especially for older people, is TV.

Now, if you’re a disinformation specialist and you want to spread some salacious-but-obviously-false rumor, where do you go? The New York Times has over 130 million monthly readers, but that would be difficult to get into… pesky fact-checkers and all that. No, if your story is actually fake, no reputable news source would publish it (we hope) — you have to get in through a backdoor. One of those backdoors is social media. So you, being the sleazy fake news artist that you are, make a troll post on 4chan. Some legit-sounding but conveniently anonymous users “verify” it, and then some Twitter bots pick it up. From there, it spreads, with trolls fanning the flames and useful idiots spreading it around, and you’re off to the races.

There’s another backdoor, though, one that’s arguably even more insidious. This backdoor is mostly effective with stories that are half-true, or true, but with a particular spin on them… but it doesn’t have to be limited to those stories. The NYT alone has about 1300 employees. Let’s say you identify a shy young election reporter who made the rookie mistake of saving sexytime videos on her old, unpatched iPhone. Insta-blackmail! Now, her editors might catch anything too egregious you try to publish, but go up a couple of steps in the chain of command, and you could virtually guarantee the publishing of any semi-legitimate story that you want. And that’s not all! News organizations don’t just stick with their own stories, of course; they source from others. What gets published in the NYT also goes to Reuters, CNN, the gossipy lady down the street, etc. Congratulations! You’ve effectively blackmailed the entire media industry.

I don’t believe we’ve discussed it much, but we’ve designed a media system into Spycursion. It will be basic at first, like publishing stories about major hacks that players do, and other random events. The ability to blackmail journalists may come later. In order for that to be useful, you’d first need a good reason to do it — elections, stock market, laws, etc. All more advanced and ambitious features… but all incredibly awesome. 😉 You may even have the ability to play as a journalist, working for a news organization, deciding what stories to publish or not to publish… and being targeted by disinformation specialists.

Spycursion News Network

Now, for that other inspired idea: The Spycursion News Network! We will be sharing out real-world news stories about cybersecurity, espionage, and related topics, through this Twitter account. (The way things are going… we’ll probably post multiple times every day.) And yes, as the game and the media system progress, we’ll share some fake stories from within the world of Spycursion, too. For now, it’s all real, though. If you’re interested in these topics, give that account a follow!

Project Update for June 2019

Common Lisp: How deep does the rabbit hole go?

Being that both Scott and I had to go back to getting jobs to put bread in the table things are going slower than when we were both 100% dedicated to the project. In the last update Scott mentioned some ideas we had around re-structuring the client, as you may imagine we can manage to keep the server side purely in Common Lisp, but the client side is a bit different, we need to create UI elements, and 3D graphics, as well as adding assets. We talked about moving away from Qt, not because Qtools are not capable, but mainly because in it’s current state UI elements cannot be rendered in the OpenGL window, which creates a disjointed experience for the user.

So we started an internal discussion to evaluate the future of Spycursion’s development, things that we wanted, things that we needed contrasted to what we have and what we need to implement, and how home grown that implementation needs to be, of course we want to use existing solutions where it makes sense, but we have our own philosophy around development.

Quick story, we considered going down the path of using Godot, using gdnative to be able to program all of the game logic in Common Lisp while using the game engine capabilities to import assets, create the world, apply physics, etc. I even started the task of creating the bindings1 using CFFI. All of this seemed like a good contribution to the lisp game developers community, and there are plenty of Godot tutorials on line. So asides from having to redo everything in Godot, what stopped us?, it is not Lisp far enough down.

If we make it so we can program Godot’s game logic in Common Lisp we are only layering a coat of usability on top of an otherwise C++ stack. Lisp Hackers could only contribute to the engine through plug ins or functions that work with the API, but if they want to go deeper they have to switch languages. So the fair question now is, how far down we can go in our current stack before we have to switch languages?, after all a lot of what we do in game development is done through FFI. The answer is, arguably, farther down than if we just wrap Godot, of course with some trade-offs. So what will Godot do for us, here is a non comprehensive list:

  • Asset management, sounds, music, sprites/models.
  • A visual environment to create levels and assign properties to in-game objects (walls, ground, etc).
  • A physics engine.
  • Custom Shaders (with their own language).
  • GUI which can be layered on top of the game.
  • A simple scripting language for the logic.

What we have now with our prototype client:

  • Asset management, mostly 3D models only, character animations are rendered correctly, 2D sprites can be imported as planes with texture.
  • A non visual environment to create complex scenes.
  • Custom Shaders using the excellent CEPL library created by Chris Bagley (akaBaggers), shaders are written in Vari which is very Lispy.
  • The complete Common Lisp language for the logic.

The Missig parts

Asset management

We have not added any sound to our game yet, so we haven’t dealt with importing and managing sound including music, however there are several options out there like Pavel Korolev’s (aka Borodust) bodge-openal, or Nicholas Haffner’s (aka Shinmera) harmony, and some others. So we have native options we can integrate in our client with relative ease.

Scene management

Although I listed the “non visual environment” I guess I should mention two things. First, in our current work flow I was able to create a scene in Blender directly, and then import the elements one by one in the SC client replicating the placement from blender automatically. So in a way we have a visual environment to create the scene. I think however, that using CEPL it should be simple enough to create a solution where you move and rotate things around as needed. So far we haven’t got a need for that.


We are working currently working on integrating bodge-ui (suggested by our good friend Borodust), which will allow us to layer UI elements on top of the game, this is what will substitute Qtools, I’ve made some basic testing and the UI renders well in Linux and Windows, I can’t check Mac but we will get around to testing more thoroughly once we integrate things in the Spycursion client. We also talked about having the users be able to create “web pages”, the solution in Godot seems to be using a combination of bbcode and the GUI, which got us thinking, we don’t really need a full blown HTML render in game, in fact is safer to use something like bbcode but with the addition of forms.

Is there need for a Common-Lisp game engine?

We have been constructing a game, not a game engine, using loose parts created by great programmers, by programming the code to be modular and reusable we get a similar effect to having a full blown engine, as an example. if we need to add another scene we just create a scene file, place the assets in a convenient place, and declare things and we have a scene ready to be rendered. I talked about Shinmera’s harmony, and Borodust’s bodge-ui, these wonderful programmers are already giving us the building blocks, so you can make your own mix and match, or you can choose to use their full solutions i.e. Radiance, CL-Bodge, etc. We even thought about going 2D with Dave O’Toole’s (aka dto) Xelf.

Ongoing work

There is a lot going, very slowly but going, we are refactoring the client to make the code modular an easy to reuse, some manual steps are being moved to CLOS methods (before, after and around), some hard coded values are being moved to special variables, etc. The code has to be easy to maintain, and our initial approach needed some refining. I’ve been working mainly on the client, and Scott more on the server, and a lot of what we have been doing is “invisible”, but we are doing what must be done. Hopefully as we add/refine the visual aspects of the game we will be able show the progress instead of just telling you about it.


We want to publicly say thanks to our Patreon supporters, although we cannot live from their contribution some of the game expenses will be alleviated, and it shows us that there is still interest on having this game become a reality.


1. Borodust already did Godot’s bindings

Spycursion Update (May 1, 2019)

It’s been about a month since our Kickstarter campaign ended and we launched our Patreon page. As people who have watched exciting projects rise and fall — often without even saying goodbye — the last thing we want is to leave Spycursion dormant for months while our fans wonder what happened to it and if we will ever return. (If Spycursion ever does fall into the bit bucket of history, it won’t be because we ghosted you — it will be because we went out in a blaze of glory.) To that end, our goal is to share a progress update roughly once every month, even in months where not a whole lot has happened…

… like this one! As I hinted in the last post, both Mauricio and I have had to “take some time off” to focus on useless trivialities like, say, paying the electric bill. Aside from that, we’ve been zooming out a bit to discuss the Spycursion architecture and how to tackle a development roadmap in our new post-Kickstarter world.

Ooh, Shiny!

Can I be honest? You know all those parts of the game that you’ve probably seen from our trailer? Those are my least favorite parts. The parts of Spycursion that I enjoy talking about and sharing the most are, well… the parts you can’t see. There are good reasons for that. Spycursion was never meant to be a graphics-first game, and in fact, I hadn’t even planned on making it 3D! My original vision of Spycursion was as a 2D isometric world. It evolved into 3D throughout the process of development and commissioning assets, as we decided that 3D would allow for greater flexibility in terms of feature additions and look-and-feel modifications.

But really, we should go back even further. In July 2018, we published this post containing the very first public Spycursion screenshots (with the exception of this very, very early device UI screenshot, in Nov. 2017). At that point, the game had been in development for nearly a year. We hadn’t shared screenshots because we weren’t focused on anything that could be screenshotted. Then, we read pieces from some wise(?) internet denizens who told us that, in order to have a successful Kickstarter campaign, we would have to make shiny things and show them off and generally become glued to social media. (Anyone who’s ever worked on an indie game knows where this is going.)

Hence, our focus shifted from server to client, and more or less remained there until the Kickstarter launch. I don’t know whether this was ultimately the right decision, but I do know that not focusing on the client certainly wouldn’t have helped that campaign. In any event, I personally feel that the visuals in Spycursion’s trailer turned out well, but not as well as they could have. There was a degree of crunch in the weeks and months leading up to February, and as a result I didn’t feel we were able to give the client the polish it deserves. That’s why one of our first post-Kickstarter discussions was about…

(Shiny) Client Architecture

If you’ve followed our blog, you know that the Spycursion client relies heavily on a couple of Common Lisp frameworks — CEPL and QTools. What you might not realize is that, within our code base, these two frameworks never even touch each other. It’s almost as if we have two separate clients that just happen to have the same name. That makes some sense, of course, because they have very different purposes. But let’s say that we want to display a device UI (a Qt QMDIArea, if you’re fancy) partially overlaid on top of that 3D world, rather than in a completely separate window. I’m not sure there’s a good solution to that. (QtOpenGL comes the closest, but we dismissed that because it would be difficult to use with CEPL or other GL frameworks, plus it had some problems on OS X.) Qt also adds some bloat that we’d rather not have.

Though we’ve discussed it before, without the time pressure of Kickstarter, we’ve decided to begin replacing QTools now. And that replacement will be… Nuklear! Why Nuklear? Well, for starters, look at these two screenshots and tell me which one fits better in a game about cyberespionage. (Yeah, I thought so.) In seriousness, what’s attractive about Nuklear is that it’s simple and embeddable, and doesn’t try to take over your entire application.

Now, the astute and tech-savvy reader may be thinking, “Wait, Nuklear is written in C, not Lisp… does it have any Lisp bindings?” Well, yes, yes it does! We’ve decided to give cl-bodge a shot, specifically the UI module, and see if we can make a workable device UI out of it. Another potential benefit here is that we could get away from traditional desktop UI paradigms of the sort enforced by Qt, and design something more unique. It’s too early to know what that might look like, but I’m excited about the possibility.

If cl-bodge works well for us on the UI, we may also use other modules of it for other purposes. It is possible that we will eventually replace CEPL, but I think the more likely outcome is that we blend the two, taking advantage of cl-bodge where it makes sense and working with CEPL as a friendlier alternative to raw OpenGL (cl-opengl).

More Shiny?

Between paying the bills and replacing QTools (not to mention me having a strong desire to hide back in my server code), it may be awhile before we can share more screenshots of any quality. It will definitely be awhile before we share more videos. When we do, we’ll try to include some upgrades to the 3D world, as well. We picked up a fair amount of technical debt during pre-Kickstarter crunch time, so performance improvements are definitely in order. With performance improvements, we can add more “bling bling” (to use the words of an influencer who didn’t want to share Spycursion because it didn’t have enough of that). And if we get enough funds through Patreon, we could add new 3D art as well.

What Kind of Shiny Would You Like to See?

As always, we invite our Patrons and followers to help shape not only Spycursion itself, but how we share it with you. What do you think about the technical changes outlined above? What do you want to read about in future updates? What would you like to see on our Patreon page?

Let us know!

Out With the Old, In With the New

The Launch

On Feb. 26, we launched our Kickstarter campaign in the hopes of funding the rest of Spycursion’s development. Our spirits were high (even if our energy levels weren’t), we hit 2% funding within a few hours, but most of all, we were just excited for our studio to move into a new phase of its life. We had lined up PR contacts and were running a really clever — perhaps too clever — marketing campaign. At that point, all we had to do is wait for the inevitable surge in backers.

Early Bird

Admittedly, we should have seen the signs. By Day 3 I was beginning to, but to be completely honest, I spent most of the first three days of our campaign so exhausted from the preparation of it that I could do little else but refresh social media feeds and ask Mauricio why more backers weren’t coming in. The press weren’t responding to us in nearly enough volume, our ad campaign was a total flop, and our mailing list on its own wasn’t large enough to drive the early traffic we needed. We had focused all of our energy on that 72-hour period, and it netted us a whopping 4% funding. I was about to call a pow-wow with Mauricio and Dan to figure out how we could save this floundering campaign. Until…


Did you hear that? That was the sound of my wife breaking her wrist (in a very complicated and interesting fashion, she says). So, yes, I spent much of the next week focusing on her rather than our Kickstarter campaign.

The Doldrums

By the time I got back into things, our campaign hadn’t advanced much further and we all agreed that it was more or less doomed. That’s when we made the decision to move to Patreon and shared this update on the Kickstarter page. Since that update, Mauricio and I have been working on said Patreon page, discussing our new development plans… and looking for jobs. C’est la vie.

The Future!

As you may have already gathered, development on Spycursion will continue! It will be at a slower pace, no doubt. We almost certainly won’t be able to hit the Q4 2020 goal that were aiming for with the Kickstarter campaign. On the upside, if we can get our sustainable funding situation worked out, then you’ll have happier, less stressed-out devs working on the game — which means greater productivity and fewer bugs!

For now, we’ve launched a Patreon page to serve as both a funding boost and a barometer of how our fans are feeling about the game. Right now, our membership tiers are very simple: For every month that you back us, for an amount of your choice (more on that in a minute), you get one month of Spycursion gameplay after it’s released. We will certainly add more tiers, and possibly raise the minimum price tier, as time goes on. For now, we’d just like to know what our supporters want in terms of rewards. Let us know if you have reward ideas or other thoughts on our Patreon page!

In diagnosing the non-success of our Kickstarter campaign, one of the conclusions we reached is that the pricing and value we offered didn’t line up. Our pricing was based on a fuller, more polished version of Spycursion that we had in our heads — rather than reflecting the presentation that we were able to showcase at this stage of development. People don’t see what’s in our heads, they only see what we can show them, and what we could show them didn’t justify the price points. (And yet, it clearly did, for those who backed us. A friend pointed out that some backers were willing to pledge over $200 for a game that’s 18+ months away! That’s certainly not nothing!)

This is why the “pay what you want” model we’ve adopted on Patreon is key. We’d like our supporters to think carefully about what they see, what we’ve shared, and our own capabilities, to decide what a month of Spycursion is worth to them… and then tell us! At this point, we’re expecting a lot of $1/month backers, and that’s perfectly fine. Over time, we hope to earn more supporters and more trust. The nice thing about Patreon is that we don’t have to get everything right at the beginning; our fans can help us over a longer time period in molding Spycursion into what they’d like it to be. We hope you will join us on this journey!

The basics of game programming in Common Lisp.

Common lisp is a wonderful language, a lot of people tend to think it is a functional programming language, and while that is not a bad thing, Lisp is not a functional programming language, it is a multi-paradigm programming language. While it is not considered good Lisp style, you can program in an imperative way; Why am I telling you all this? well, because people always object that being functional makes it difficult to program games, which is not completely true either, but Common Lisp will work with you and not force you to work around it.

While I am in the theme of fallacies, another false misconception about Lisp is that it does not have libraries, it does have more than a descent amount of native libraries, Common Lisp implementations also have FFIs which has allowed to create bindings to very useful C libraries, and since bindings are commonly not “Lispy” some times we have great adventurers creating wrappers that made them feel like they were written for Common Lisp.

So, What do you need to program a game?, in the simplest terms you need:

  • Output: A place to show text, graphics, lights, sound or whatever your game uses for interaction with the user.
  • Input: Devices to interact with the game (i.e, move the character, move icons, write text, etc).
  • Assets: Different types of things that go into your game (images, models, sounds, maps, music).
  • Constraints: A set of rules that physically or logically constraint the actions that you as a player can do (i.e. physic engines)
  • Logic: A set of rules that affect how the user interacts with elements in the world. (i.e. open a chest, a door, use a computer etc)

    You might argue there are more things, but to me this five make the core of what you need. So lets break this down for Spycursion, which is our game, I will intentionally leave out the socket magic happening between the client and server, which is necessary in any MMO.

    There are two types of interaction in our game, the Computer GUI and Terminals and the 3D world.

    Spycursion Computers


    The computers in Spycursion are meant to look like real computers, once you start using a computer you will either see a GUI environment or a Terminal, so what we need here is a GUI library, we could (and actually thought about) write one from scratch, but with so many solutions in existence out there we decided to use one with the characteristics we needed, and the winner was Qt, one of it’s redeeming qualities being portability, which is important when you are writing a game that runs in Linux, Mac and Windows. To write our Qt in a lispy way we use the fantastic Qtools library written by Nicholas Hafner (a.k.a Shinmera).


Qt provides the necessary tools to import icons, images, play sounds, and even render html, so it is relatively easy to get a full screen application that looks like a computer desktop.


Constraining a GUI is very easy, you just provide the programs that you want people to be able to use, and what those programs are capable of doing. Constraining a terminal is even easier, you just decide what commands exist and how they interact with others (piping, I/O). In both cases you can restrict user rights, so it ends up being a bit like real life system administration, but with more control.


Implementing Logic in Qt is very straight forward, you can decide what happens when you press a button, hit enter, change text, etc.

I won’t provide examples because there are plenty on the Internet.

Spycursion 3D World


Since we are shooting for a 3D world the safest bet is to use OpenGL, Lisp has the cl-opengl library, but that is too verbose, the good news is that Chris Bagley (a.k.a Baggers) created CEPL, which has as a design goal, and I cite “… making the user feel that GPU programming has always been part of the languages standard.”, asides from that promise, Baggers has spend hours doing great videos which he has shared on Youtube.
To run OpenGL you need what is called a surface, which is basically a graphic container, when we started doing this the only stable option for CEPL was SDL2, so we to use cl-sdl2 too. The library, in this setup, is used only to have a display window, but it is capable of a lot more, as an example you can look at sketch, which you could use to create 2D games.


A lot of the things we care about were also concerns to Baggers, and he has a whole ecosystem of related stuff, some of which even come installed with CEPL or are part of it, for Input his contribution is called skitter, which allows us to detect mouse movement, position, clicks, keyboard presses and all that jazz, it can even handle game controllers. While we use it with CEPL it is independent of it.


So far we have been worried more about showing a 3D world, some menus and text, so I will talk only about those aspects, of course there are options to import and play sound, but I will focus on 3D models. You should be able to use a 3D modeling program to create your assets, save files, and get the data from those files imported into your program, that is the job of the great assimp library, and of course we have classimp which is classier ;-), with that library you can import several 3D model file formats, so you can use a variety of programs to create your model, including free options like Blender, or you can buy them in a format you can use. Of course this only creates a data structure, so you have to do all the wiring yourselves, but you will be able to import models including the animations which you need for your game.


All constrains and logic are programmed in Lisp, with some help from stenciling, this is one of the few instances where we used cl-opengl directly instead of using the CEPL scaffolding. In general Common Lisp is a very potent programming language, so writing logic in it is very straightforward and flexible. We are currently not using physics engines but there are libraries for that too.

Some final thoughts

There are many wonderful tools you can use to make your game, we are just talking about the ones we used, you could use Xelf for 2D games, or Trial for 3D and 2D, there are libraries for text rendering both in 2D and 3D, libraries to do text based games (i.e. cl-ncurses), tools for importing and playing sound. There have been games written in Common Lisp in recent years, and there are Common Lisp game jams (the next one starts on April 18th, 2019), the fact is that writing games has been improving the ecosystem.

If you ask for it, we could expand in some of these themes, but the basics are the same, choose the type of game you want and the look for it, choose the adequate input and output libraries, add suitable libraries for importing assets, use some libraries for collision detection and physics if necessary, add your own logic, mix everything with tons of creativity, and you’ll have a game.

The Spirit of Kickstarter

Kickstarter has changed a lot over the years. Observe this video game project from 2012… and then observe this one from 2018.

Go on. I’ll wait.

In 2012, a tiny independent game studio could launch a campaign without so much as a video trailer and net $150,000 in funding. Meanwhile, in 2018, established studios learned they could repackage their old releases, toss them onto Kickstarter with some collectors’ items, and fund a successful campaign literally overnight.

Don’t get me wrong, I loved the Myst games. But I can’t help but feel that’s not really what Kickstarter is for, ya know?

Some people have told me that we shouldn’t be launching a Kickstarter campaign. “You aren’t a big studio with an established audience.” “Your graphics aren’t very good yet.” “You don’t have gobs of marketing dollars.” All of those things are true. I certainly wish inspiration had struck back in 2012, when those weren’t necessities — we might have surged past our funding goal a long time ago.

But instead of looking at the cards we weren’t dealt, let’s look at the ones we were:

  • An innovative concept in an underserved niche. I truly believe that enough people exist who would be excited enough about Spycursion to back it, as long as we are able to find that audience. (Not always an easy task!) When and where we have found that audience, we’ve received a lot of praise. (And a handful of naysayers, usually related to one of the “cards we weren’t dealt” above.)
  • Secret alien technology. We haven’t played up Lisp too much as an advantage, partly because it’s still largely uncharted territory for game development. But both Mauricio and I have often been surprised by how easy it makes certain things. If When Spycursion happens, I won’t say it was only because of our choice of programming language… but I will say that that choice probably helped.
  • A small, but enthusiastic, fan base. That’s you! And, it turns out, you may be the most important part of this whole equation…

It’s important to realize that indie studios like us are no longer competing against the likes of Starlight Inception for visibility on Kickstarter. We’re competing against Myst, and if we try to compete on traditional grounds, we’ll get creamed every time. We’ve done our best so far to put those first two advantages above to good use, but the third one is mostly out of our hands. That’s where you come in.

And yes, this is the part of the blog post where we shamelessly ask you to share Spycursion with all of your family, friends, enemies, acquaintances, ex-lovers, and every random person with whom you make eye contact but don’t click the Back button yet because there are good reasons why you should do so!

If you’ve spent any amount of time browsing Kickstarter, you’ve probably seen those projects from very non-startup companies with high-budget videos and suspiciously low funding goals. You know, the ones using spammy crowdfunding agencies, the ones that make you think to yourself: “This entire campaign is solely for publicity, isn’t it?”

Well, we’re the antithesis of that. We’re just a couple of people with some ideas and skills who came together to bring a game to life. As a brand new, zero-budget studio, we’re using Kickstarter for its original intended purpose — to “kickstart” a creative project! Kickstarter is, and always has been, our Plan A. (There are contingency plans — all of which have significant downsides — but those are better off in another post.) Sadly, that also means we’re facing some headwinds that we arguably shouldn’t have to face. That’s why your support (financial and/or social) is crucial to our success.

Do you love the concept of Spycursion and the long-term vision we have for it? Splendid! Share. This. Game.

Do you love the concept of Spycursion but hate how the graphics look right now? Excellent! Share. This. Game. With the support of you and all your family/friends/enemies/etc., we can afford some better art and all of the graphical bling-bling you can handle.

Do you love the concept of Spycursion but are skeptical that we can actually pull it off? Glad to hear it! Share. This. Game. With the enough support, we will pull it off, and if for some reason we don’t, we’ll be open-sourcing the whole shebang for you to try pulling it off yourself. (See the “Risks and Challenges” section of our Kickstarter page.)

Do you hate the concept of Spycursion altogether? Cool beans! Share. This. Game. You never know who else might enjoy it in your stead.

Did you come from /r/lisp or Hacker News and you just want a Lisp game to point to when people trash your favorite language? Superb! Share. This. Game.

Share our Kickstarter page. Share our trailer. Share this blog post. Share it on Facebook. Share it on Twitter. Share it on Reddit, or Mastodon, or Pinterest, or whatever your favorite social networks are. Share it on 4chan just kidding please don’t do that. Share it on your blog. Share it on a postcard. Share it at parties. Share it especially with people you know who happen to be in media and/or very rich. Share. This. Game.

With enough sharing (and broken records), we can bring Spycursion to life. That, in my opinion, is what the spirit of Kickstarter is all about. Thank you for your support!

Some things we’ve learned developing a 3D game for Lisp.

Hi, Mauricio Here,

This blog post is kind of a developers blog, as I said in my only previous post I’ve been dealing with the MS Windows side of things, I also made some 3D models using Blender, and use the abstractions Scott had created to create a a new scene for the game (a bedroom), but of course my job has not been limited to that. We’ve learned some stuff that we would like to share, so that is what I am doing.

Classimp on Windows.

One of the earlier lessons we learned was related to Assimp, for one thing downloading the binaries and moving the dll to your project directory does not work, in recent Assimp versions the name of the dll isn’t even one of the names searched by Classimp, and renaming or making the code match the dll name does not do the trick. In order to make classimp work we had to compile with gcc instead of visual c, using mingw,, this produces a libassimp.dll which is what classimp looks for and that DLL works fine. The latest Assimp library supported by Classimp is 3.3.1, so if you want to compile it yourself download that version and then follow the instructions here.

When you compile with MingGW using the instructions in the link the DLL will be in the “assimp-3.3.1\build\tools\assimp_cmd” directory, and asides from that you get an assimp.exe executable that is very useful for asset conversion. Currently we are consuming fbx files, so when I created models in Blender I exported them as fbx files, and that caused problems in some cases, so we adopted a different  workflow which so far guarantees a model that loads correctly in CEPL, we use assimp.exe in the command line to convert the .blend to .dae which is the extension for Collada, an open exchange format, and then use Autodesk FBX Converter to convert the .dae to .fbx. This workflow gives you better control over the way that the files are converted.

Why not reading the .blend files directly?, Well for one thing we had some pre-made assets and those were fbx, and we want to be uniform., another reason is that sometimes the file would not be read correctly by classimp, but assimp.exe tries several stuff and is able to export it, as long as you remove any lamps form the scene (I also remove the cameras for good measure). And a third reason, is that sometimes we want to pre-transform the vertices  specially with several objects in the same file, and doing this during the export simplifies the code to read the file. So we do use this:

assimp export file.blend  file.dae -ptv

In the command line, where -ptv stands for pre-transform vertices, and assimp guesses the output file format from the extension of the second file. Assimp does not export fbx , that is why we export to ,dae and then convert. Classimp can read .dae files correctly, but fbx files are smaller, and the difference in load time is negligible for our purposes, and as I said we want to keep uniformity.

Another good tip is to use the assimp viewer to open an asset, and then look at the log file, this will warn you of possible problems when importing with classimp.

Multiple Textures in one Mesh.

We ran into a problem with a model of an avatar we were using in the game, the textures were not imported correctly, the head texture was applied to the body, so the model looked like it had no pants, and it had some weird things in the skin (actually stretched head features). The problem is that when you run (classimp:import-into-lisp) each mesh object contains only one texture. however the model had a mesh with two textures.

Luckily Blender allows you to select the portion of the mesh that is assigned to a particular texture and separate it. So we separated the head from the body, re exported, re-sorted the textures and voila, problem solved.

How do you know the order of the meshes? Well, the first thing is to name things right in Blender, then the structure you get when you import into lisp has a tree and that gives you the clue.

SPYCURSION-CLIENT> (ai:import-into-lisp (car *char8-data*))
SPYCURSION-CLIENT> (ai:root-node *)
#<CLASSIMP:NODE {1004FA9443}>
SPYCURSION-CLIENT> (ai:children *)
#(#<CLASSIMP:NODE {1004FA8663}> #<CLASSIMP:NODE {1004FA8903}>
  #<CLASSIMP:NODE {1004FA8B93}> #<CLASSIMP:NODE {1004FA8E33}>
  #<CLASSIMP:NODE {1004FA90D3}> #<CLASSIMP:NODE {1004FA9373}>)
SPYCURSION-CLIENT> (loop for x across * collect (ai:name x))
("Head" "Gadget" "Bag" "Body" "Jacket" "Hair")

So the first mesh is the head, the second the Gadget, and so on. The pre existing textures worked well because I just separated and saved again so the UV coordinates remain intact,  now each mesh reads from the right image, and maps the right coordinates.


One of the models I was making was a full room, to do it I used Archimesh, the room was simple, a rectangular room with a window and a door,  and some cabinets, this worked out perfectly in Blender, but not so much when I imported the models in CEPL. The thing is that boolean operators produce weird geometry, and the holes in the walls for the door and window are produced by boolean subtraction. In other models the sub surface modifiers looked like crap when imported,

So I decided to re-make the room the old fashioned way, loop-cuts and face deletion, replace the old room, and apply all of the modifiers to other objects before exporting, that way the look was predictable.

The other thing I learned is that you need to either use the a processing flag in classimp or export the model with pre-transformed vertices, otherwise the objects in the scene were not placed in the right position. I used Blender to lay out the room furniture, and then exported each element separately, that made it easier to place and remove things, and handle the textures.

I also spend some time baking textures, and exporting the UVs, the UVs exported from Blender are immediately usable, and you can use DIRT to import the texture, so asides from the tedious process of UV wrapping the objects, assigning the image, and baking the textures into it, the process is very painless.

Final Thoughts

After ironing out the exporting problems saving models so they can be used with CEPL turns out to be a straight away process, there are some things in our code we are optimizing to make the process of maintaining the software and adding stuff more straight forward, but we have a working skeleton,  we can create rooms and cities, place avatars, animate them,  etc.

Of course there is still work to do, and Spycursion is curious in that it has two environments, the OS and the 3D world, but even when we some times hit ourselves against a wall, there is always a door a couple of steps away, as we learn more is like turning the lights on, we now where the walls doors, windows and other stuff is, and that allows us to move freely.