Doodle: a crazy drawing & guessing game

โœ๏ธ Introducing Doodle, a crazy drawing & guessing chain game. Think Pictionary meets Telephone. Better played with your friends over a video call!

doodle brainstorming

๐Ÿ  Doodle is a little side project I made during covid-19 confinement to play with friends while we cannot meet face to face. Initially, I thought the crisis would end before I finished it, which would make me lose interest. Little did I know! Not only did I finish it, Doodle has already lightened up the mood in a few remote evenings.

๐Ÿ’ป The game is entirely written in Typescript, which I had never used before. I’ve had lots of fun building it, getting feedback and playing with friends. I hope to soon post a more detailed post-mortem on the whole process. Maybe even a couple of articles about things I learned.

๐Ÿค“ In the meantime, you can check out the source code on Github.

๐Ÿ™Œ Give it a try and be sure to let me know any thoughts or feedback!

Plague: a Godot Wild Jam 18 game postmortem


A few weeks ago, Jay Cano and I took part in the week-long Godot Wild Jam 18 and submitted Plague. Here are some of my personal thoughts on how we did and maybe some lessons for the future!

๐Ÿ“ˆ Results

Out of 43 submissions, we ranked 6th overall. That is the top 13th percentile. More importantly, we ranked 3th for fun or top 6th percentile. For the sake of comparison, Onederful Wizard, which we submitted to the GMTK 2019, ranked 294 out of 2617 entries (top 11th percentile).

Even though both games received positive feedback, Plague ranked high for fun. We’re very happy about that!


๐Ÿ‘ What went well

โœ… Splitting tasks

During the previous jam, Jay and I rushed to implement features like crazy. Despite, Godot being very source control friendly, we ended up having to manually resolve too many merge conflicts.

This time we were much better organised and split tasks in a more consistent way.

  • ๐Ÿ‘‹ David: player movement, enemy behaviour, individual game systems, menus and effects.
  • ๐Ÿ‘‹ Jay: procedural level generation, level section design, enemy/item spawning and putting it all together.

Additionally, we both had separate “playground” scenes to test our work. We barely faced any merge conflicts!

โœ… Platforming

We got pretty good feedback for tight controls. Our player movement is not too complex. For maximum control, we use a KinematicBody rather than a RigidBody. We did a direct implementation of the formulas explained in the Building a Better Jump GDC talk.

The proposal of the video is simple. The variables designers tweak to control character movement should not be gravity, acceleration, etc. They should be jump_height, jump_distance, time_to_jump_peak, time_to_max_speed, etc. It’s much easier to reason about the distance a player can jump to build a level than the combination of gravity and other physics variables.

Additionally, we implemented a very simple Coyote Time. This gives players a grace period to jump even if the character has left a platform. Tiny thing, but it makes the experience a lot more responsive.

โœ… Procedural level generation

The game is a procedurally-generated infinite side-scroller. However, we do not procedurally place tiles. We have 8 hand crafted chunks. Then, the InfiniteLevelManager script is responsible for randomly selecting the next chunk as the player approaches the end of the current chunk. Finally, it populates the chunk with enemies and ammo pickups.

level chunk

This gave us an infinite scroller with a very simple procedural generation algorithm and super tight control over the end result. We even managed to progressively increase difficulty by spawning more and tougher enemies.

With more time, we would have increased the variation and potentially procedurally place decoration on top of the blocks instead of having it built-in.

โœ… Re-using assets

Jay and I are both engineers and not very good at art. It was a wise decision to leverage multiple asset packs. This led to good feedback on both audio and visuals.

There are so many super high quality free assets, it’s insane. If your jam allows it and you have a similar skillset to ours, go for it!

โœ… Time for polish

We dedicated a big chunk of the last day for polish and juiciness, which massively increased the game’s perceived quality.

  • ๐ŸŽฅ Camera shake for damage and bullet impacts.
  • ๐Ÿฆ˜ Coyote time for jumps.
  • ๐ŸŽฎ Gamepad controls. The game detects Xbox/PS4 controller or keyboard and shows different instructions in the main menu.
  • โ›ˆ๏ธ Weather effects. We added rain, lightning and thunder that start at random intervals.
  • ๐ŸŒŸ Particles and SFX for everything that happens in the game.

โœ… Automatic deployment

Right before the jam, I implemented a Continuous Delivery pipeline that exports the game and publishes to on every push to master. This completely removed the panic that typically happens when something goes wrong with game export right before the deadline.

You can also go back in time and see how the game looked at any point in time during development.

๐Ÿ‘Ž What went wrong

โŒ Poor use of theme

Due to some issues with the organisation, the theme announcement was delayed by half a day. Knowing that we weren’t going to have much time to work on the game during the week, we started right away without a theme.

Unfortunately, we failed to go back to the theme and really incorporate it into the game. In the end, you can interpret that the monsters are the “plague”. Other games like Harvestor-3000 and Ceefax made a much better use of the theme.

By the way, this is not a complaint about the organisation at all. We really appreciate their efforts to keep the jam going!

โŒ Lack of end goal

The infinite platformer concept made people feel a lack of purpose. We didn’t save top scores, so there was obvious sense of improvement nor progression.

An alternative may have been to introduce a final boss and an end-game after a fixed number of chunks. Lack of time!

โŒ Yet another platformer

The game is a simple platformer and the procedural generation was not enough to make it fresh. That is why we scored the lowest in originality, ranking 28th or 65th percentile.

In future jams, we should prioritize a differentiating feature and really go with it. Hopefully, foundational things like getting movement right will take less time going forward.

โœŒ๏ธ Thanks!

I had a blast participating in the jam. Thank you for reading this postmortem and thanks to everyone who played the game and gave us feedback.

Continuous Delivery pipeline for Godot and

During the recent Godot Wild Jam 18, I implemented a full Continuous Delivery system to automatically publish Plague, our entry, on The pipeline relies on Github Actions, the same mechanism I use to build and deploy this very blog.

Setting up your own is easy peasy and possibly free!

โš’๏ธ Pipeline overview

  1. Someone pushes to the master branch on the remote repo.
  2. The game is exported for all available platforms. In this case: Windows, Linux, MacOS and HTML5.
  3. A new Github release is created with attached files, one per platform.
  4. The release artifacts are pushed as new versions of the game to


๐Ÿค– Configure Godot exports

First, you need to setup the export settings in your Godot project. The official exporting guide explains it perfectly. The thing to keep in mind here is that the preset name will determine the name of the published artifact. For example, a preset called plague-mac will result in a release with an attached file called

In the case of our jam entry, we targeted MacOS, Windows, Linux and HTML5.


๐Ÿ“ฆ Export the game

Create a .github/workflows/export_game.yaml file in your repo. We will tell our new action to run on every push to master. We don’t want new releases on commits that do not actually change the game. Our Godot project lives in the game folder, so we tell the action to only run if there are changes in that folder.

      - master
      - 'game/**'

For the actual export step, we will leverage the Godot Export Github action. The explains its usage very well.

For the action to work, you need to create a personal access token, which will give the export action write access to create a new release. First, create a new token. Then go to<org>/<repo>/settings/secrets/new, paste the key and name the secret EXPORT_GITHUB_TOKEN.

Here’s our config in case it helps you. We setup the base version to be published, the links to download the Godot headless executable as well as the templates and tell it our project is located in the game folder in the repo.

    runs-on: ubuntu-latest
    name: Export game
    - name: checkout
      uses: actions/checkout@v2.0.0
    - name: export
      uses: firebelley/godot-export@v1.1.0
        base_version: 0.1.0
        godot_template_version: 3.2.stable
        relative_project_path: ./game
        GITHUB_TOKEN: ${{ secrets.EXPORT_GITHUB_TOKEN }}

Whenever you push these changes to your repo, you should already start seeing jobs being triggered and releases being published.


๐Ÿšข Ship the game

Butler is the CLI, which lets you upload builds of your game. Our publish Github action will need to talk to using a valid API key. In order to get one, install butler and generate a key via butler login. Refer to the docs for the details.

Then, copy your Butler API key and go to and create a BUTLER_CREDENTIALS entry with the contents of the key.

Now create a .github/workflows/publish_game.yaml file in your repo. This action will run every time a new release is created or edited.

    types: [created, edited]

Our workflow needs to contain a job per platform we want to publish. Each job will leverage the Fetch GH Release Asset and Butler Push actions. We first download the latest release artifact for the platform we want to export and then we call the butler action to push the build to When pushing multiple times to the windows channel, each will be considered a new version of the same “product.

Here you can use the secrets.GITHUB_TOKEN, which is automatically populated.

    runs-on: ubuntu-latest
      - name: download widows
        uses: dsaltares/fetch-gh-release-asset@master
          GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
      - name: release windows
        uses: josephbmanley/butler-publish-itchio-action@master
          CHANNEL: windows
          ITCH_GAME: plague
          ITCH_USER: dsaltares

That’s it! Once you push the publish workflow and make a change to the game, Github will export, create a new release and update your game on


On your game page, you should see something like:


One last thing to remember is that you need to manually tag your HTML build as browser playable from the website as specified in the Butler docs.. You will only need to do this once as long as future HTML builds have the same channel.

โœ… Advantages

  • โณ Automated. Do not waste time exporting your game regularly and updating various stores.
  • ๐Ÿš€ Fast. Exporting and publishing for a jam sized game takes only 2 minutes.
  • ๐ŸŽฅ Restrospect. Check out how your game looked at an arbitrary point in the past without opening the editor.
  • ๐Ÿ’ฐ Cost effective. You get unlimited GH Actions minutes for open source projects and 3000 minutes for the Pro plan. That could easily equal 600 builds a month!
  • ๐Ÿคธ Flexible. No need to publish on every push, you can change the triggers to publish on every push to a release branch or simply on a fixed schedule.
  • ๐Ÿ”ญ Extensible. Add jobs to publish to other stores or platforms.

It would be amazing if you let me know your thoughts on this solution. Maybe you have a much better automated process or ideas on how to improve this one!

Plague - Godot Wild Jam 18


My friend Jay and I recently took part in Godot Wild Jam, a week long game jam where entries must be made using Godot Engine.

We had an absolute blast! The result is Plague, a procedurally generated action platformer. You can play it in the browser and use either a gamepad or keyboard!

.Get "linkText"

Don’t congratulate us on the visuals just yet, we used the Rogue Noir asset pack. However, you can check out our messy code on Github.

The main theme of the Jam was “Plague” although there were three aditional optional wildcards:

  • ๐Ÿ•บ 80s Baby! - Recreate the visual style of 1980s media.
  • ๐ŸŽฒ Take a chance on me - Create a system of chance in your game.
  • โ˜” I wish it would rain - Implement weather effects.

Even though many aspects of the game could be improved, we’re quite satisfied with the outcome. Especially because we had to manage day jobs and other compromises alongside the jam. Hopefully, I will get around to write a full post-mortem after the voting period ends and the final results come out.

In the meantime, give it a go and let us know what you think!

FOSDEM 2020 - Survival Guide


This weekend FOSDEM 2020 will take place in Brussels. FOSDEM is a yearly conference about open source software. It’s totally free and no registration is required. As a consequence, it’s massive and chaotic, but also a lot of fun! I attended in 2017 and loved it, so I really look forward to this year’s edition.

If this is your first time, here’s a few tips that may come in handy.

Attending talks

FOSDEM packs over 800 sessions in almost 40 rooms spanning multiple buildings of the Solbosch Campus (Universitรฉ Libre de Bruxelles). It’s impossible to attend everything and it’s advisable to come prepared.

I encourage you to download the companion app and build your own schedule. You can bookmark all the sessions you may be interested in and the app will nicely highlight conflicts.

Quite frequently, you get a very popular talk in a very small room. Room capacity is strictly monitored for safety reasons. Full signs will be posted othe door. With 8000 attendees, it may get tricky. I recommend arriving to the room for the session that precedes the one you absolutely don’t want to misss. Worst case scenario, you can stream any session live.

There’s always interesting people and conversations outside the rooms. I typically get very anxious about socialising in this context. However, it’s something I want to work on. I hardly ever regret getting over the initial awkwardness.

Transport and accommodation

The Solbosch Campus is not in the center, 1h walk from Grand Place. It’s relatively well connected with a couple buses and trams going there. With so many people, public transport and Uber will get busy. Be careful if you have to rush off right after closing!


A good area to stay is between the center and the venue. A good compromise that will make it easy to move around. Accommodation in Brussels is not super cheap by default. With so many people attending, prices will rise. Make sure to book in advance!


The center of Brussels is packed with places to eat of all price ranges. However, it’s a different story at the venue. You can choose between the cafeteria or the food trucks outside. Both will be crowded and won’t have great variety. At least, the cafeteria staff are quite fast.

Alternatively, there’s a couple of places you can grab a quick bite walking distance from the campus.

Satellite events

There are quite a few events organised around the FOSDEM weekend. Make sure to check them out in case you want to adjust your travel dates. For example, the Godot community is organising a couple.



Brussels is a great city. If you’ve never visited, it would be a shame to spend all of your time at the conference. Make sure to check it out!

Grand Place


Belgium is world famous for its beer. There are thousands of interesting brews to check out. FOSDEM even organises a beer event on Friday. Be careful though, Belgian beers are famously strong. Beer is also available during the day at the venue.

Make sure to stay hydrated (with water!) to avoid a massive hangover on the first day of the conference. Do not forget to follow the code of conduct, it also applies to all associated events.

Unfortunately, if you don’t drink alcohol, the Friday event may not be your vibe.


Have a great time!