Packing Sprites into a Texture Atlas in MonoGame

While building Vulcard for the Game Programming Lab at ETH Zurich, we accumulated dozens of individual sprite PNGs for icons and UI elements. Loading each as a separate texture works fine early on. It’s not how you want to ship, though. Every SpriteBatch.Draw call that switches textures flushes the GPU batch, and 60 sprites can easily mean 60 separate draw calls per frame. The fix is a texture atlas: one large texture containing everything, so the batch stays intact. We have already been using MLEM which supports spritesheets in the form of its DataTextureAtlas. However, images have to be manually merged into a single file and documented in a .atlas metadata file. To automate this process I built Vulcard.AtlasPacker, a content pipeline extension that reads a plain-text .atlaspack file and produces a packed texture plus the companion .atlas metadata file at content build time. This post walks through installation, the manifest format, processor options, and how to load the result at runtime using MLEM’s DataTextureAtlas. ...

23.06.2026 · 8 min · Luca Schafroth

Formally Verified ASN.1 Encoders and Decoders

When a satellite sends telemetry data to a ground station, both sides need to agree on exactly how that data is structured in binary. The same goes for network protocols, aircraft systems, and anything else where machines exchange precisely formatted messages. Get the encoding wrong and you get garbage. Get the decoding wrong and you may silently recover incorrect data. ...

29.05.2026 · 9 min · Luca Schafroth

Bundling a Game Made with MonoGame

While developing Vulcard for this year’s iteration of the Game Programming Lab at ETH Zurich, we wanted to integrate the Steam API and package the game for multiple platforms. This process came with a few unexpected hurdles. In this post, I’ll walk through the complete solution we ended up using. If you’re looking to publish a MonoGame project on Steam, this might save you some time. ...

05.06.2025 · 4 min · Luca Schafroth

Loading Sass files with Lit

Like Polymer before, Lit-Element uses javascript or typescript files for code, templates and styles by default, to enable the use of javascript variables. While this may be useful in some cases, personally I prefer having my style definitions in separate files mainly to benefit from Sass, but also the added benefit of editor assistance like highlighting and autocompletion. Fortunately this can be changed with a bundler like Webpack. ...

18.07.2022 · 3 min · Luca Schafroth

Randomized Algorithms: Game Tree Evaluation

Imagine you are playing a game of TicTacToe against your friend. Obviously you want to find an ideal strategy to increase your chances of winning. How can you determine your next move? ...

09.07.2022 · 6 min · Luca Schafroth

Some technical information about the Polyring widget

As those following the news about the Polyring may have read on xyquadrat, our widget can now be styled with themes. For those interested about the inner workings I will provide some technical information here. The component makes heavy use of css variables alongside the attribute theme, which can be set on the component. Let’s walk through the needed setup, which consists of both javascript code and css descriptions. ...

27.04.2021 · 3 min · Luca Schafroth

Using steganography to send messages hidden in an image

There are multiple ways to send a secret message. The best known and usually used, especially over the internet, is by encrypting the message and later decrypting it. But it’s not the only possibilty. Steganography is the process of hiding information within another carrier medium, fooling everyone else into thinking that the carrier is the only message. The basic principle ist simple: Add a start and end tag to our message. Convert the message to a byte string using UTF8. Overwriting the least significant bits in each pixel with our byte string until the whole message is stored. Let’s look at the last step if we want to use the two least significant bits: As an example we want to store 10 in a channel that currently stores 10100111. First we apply a bit mask with the ‘and’ operation, then we apply our data with an ‘or’ operation. This pixel data is then written back into the image. ...

19.04.2021 · 2 min · Luca Schafroth