Português English

Blogs

Open Asset Package feature
2026.06.16

Open Asset Package

Games ship an astonishing number of files. Textures, meshes, audio, shaders, scenes, scripts — a single modern title can easily contain tens of thousands of individual assets. Managing this “asset tax” is one of the quiet challenges of game development.

Traditional archive formats such as Tar and ZIP remain common fallbacks, but they were designed for very different environments. Tar originated in the late 1970s for magnetic tape systems, while ZIP was introduced in the late 1980s to improve storage efficiency on floppy disks. Both remain useful general-purpose formats, yet neither was designed around the way modern game engines load and stream assets.

As projects grow, engines frequently adopt specialized packaging systems of their own. Unreal Engine uses .pak files, Unity relies on Asset Bundles, Godot distributes exported projects using .pck archives, and raylib provides the open rres format. Each addresses a subset of the same problems, but they are typically tied to specific ecosystems, tooling, or assumptions about how assets should be organized.

Open Asset Package (OAP) is an attempt to address these challenges with an open, engine-agnostic format designed specifically for modern game asset workflows.

The core problem

Game engines typically need three capabilities from an asset container:

  1. Random access, allowing a single asset to be located quickly without scanning through an entire archive.
  2. Streaming support, enabling assets to be fetched incrementally using HTTP range requests rather than downloading large monolithic files.
  3. Stable identity, ensuring that asset references remain valid even when filenames, directory structures, or packaging strategies evolve.

Traditional archive formats only partially address these requirements.

Tar was designed for sequential media. Finding a particular file requires traversing archive entries one after another, resulting in linear lookup times. When combined with stream compression such as tar.gz, extracting a single asset requires decompressing the entire archive.

ZIP improves substantially by introducing a central directory that allows direct lookups. However, the directory resides at the end of the archive, local headers duplicate metadata, and encryption support has evolved through multiple extensions over the years. ZIP remains a flexible general-purpose archive format rather than a system optimized for asset streaming and stable asset identities.

Game engine formats often solve these limitations in ways that reflect the priorities of their respective ecosystems.

Unity Asset Bundles prioritize integration with Unity’s editor and runtime. Early implementations relied heavily on monolithic LZMA compression, while newer versions introduced chunked LZ4 compression to improve loading behavior. Despite these advances, the format remains closely tied to Unity itself.

Unreal’s PAK format is among the most feature-rich approaches, supporting advanced compression methods, encryption, and layered package mounting. However, it is deeply integrated into Unreal’s virtual file system and asset pipeline.

Godot’s PCK format focuses on simplicity and seamless engine integration. Assets are primarily identified by path, and the packaging system is designed around Godot’s export process rather than general-purpose asset management.

Raylib’s rres is perhaps philosophically the closest relative to OAP. It offers an open specification with support for compression and encryption while maintaining a lightweight implementation. It intentionally leaves concerns such as dependency management and large-scale asset identity to higher-level systems.

OAP was designed to address these requirements directly: fast random access, efficient streaming, stable asset identities, and explicit dependency relationships in a format that is independent of any particular engine.

Design highlights

Fixed-size header: OAP organizes packages using a straightforward index-last layout. A fixed-size header is stored at the beginning of the file, while a sorted index resides at a known offset near the end. Asset data occupies the space in between. Opening a package therefore becomes a simple process: read the header, jump directly to the index, and perform a binary search to locate the desired asset. No scanning through asset contents is required. When packages are hosted remotely, locating an asset typically requires only two HTTP range requests: one to retrieve the header and another to access the index.

Independent asset features: Compression and encryption are defined on a per-asset basis rather than at the package level. One asset may be stored without compression for fast loading, while another may use DEFLATE compression and ChaCha20 encryption. Reading a single asset never requires decompressing or decrypting the entire archive. Encryption keys are intentionally excluded from the package itself, providing protection against casual extraction without attempting to function as a digital rights management system.

Asset identity: OAP separates asset identity from filesystem organization. Assets are identified using stable 128-bit identifiers, while human-readable paths are treated as metadata rather than primary keys. This enables practical workflows for patches and downloadable content. A small package containing only modified assets can be mounted alongside an existing package, and lookups resolve using asset identifiers rather than filenames. Renaming or reorganizing files no longer invalidates references throughout a project.

Asset dependency graph: OAP allows assets to declare dependencies directly within the package index. Materials can reference textures, scenes can reference meshes, and prefabs can reference supporting resources. By making these relationships explicit, engines can construct loading graphs, perform dependency analysis, and implement more sophisticated streaming strategies without relying on separate metadata systems.

Technical specification

The OAP format is documented independently in SPEC.md. The specification is language-agnostic and intentionally small: a conforming reader requires only little-endian integer parsing, a CRC-32/ISO-HDLC implementation, and a raw DEFLATE decoder — all of which ship in every major standard library. A minimal reader is a few hundred lines in any language with byte-buffer access. Alternative implementations in other languages are explicitly welcome; the repository includes a porting guide (docs/implementing.md) and a canonical test fixture (testdata/sample.oap) to validate against.

How it compares

General-purpose archive formats

Feature tar.gz ZIP OAP
Open specification Yes Yes Yes
Asset lookup Sequential O(n) Central directory O(1) Sorted binary-search index O(log n)
HTTP range-friendly Poor Limited Excellent
Per-asset compression No (whole-archive only) Yes Yes
Per-asset encryption External only Legacy / AES extensions ChaCha20 per asset
Stable asset identity No No Yes (128-bit ID)
Integrity checking None Optional CRC-32 Mandatory CRC-32
Dependency tracking No No Yes
Typical entry overhead 512 bytes ~76+ bytes 64 bytes fixed

Game engine asset formats

Feature Unity
Asset Bundles
raylib
rres
Godot
PCK
Unreal
PAK
OAP
Open specification No Yes Yes No Yes
Asset lookup Indexed O(1) Sequential O(n) Sequential O(n) Indexed Sorted binary-search O(log n)
HTTP range-friendly Limited Moderate Limited Moderate Excellent
Per-asset compression Chunk-based (LZ4) Yes No Yes Yes
Per-asset encryption No Yes Package-level Yes Yes (ChaCha20)
Stable asset identity No 32-bit IDs Path-based Path hashes 128-bit IDs
Integrity checking Yes Yes Yes Yes Mandatory CRC-32
Dependency tracking External (Addressables) No External External Built-in
Engine-independent tooling No Yes Limited No Yes

OAP does not attempt to replace engine-specific asset pipelines. Instead, it focuses on providing a portable packaging format that incorporates capabilities commonly found in specialized solutions while remaining straightforward to implement and independent of any particular engine ecosystem.

Performance

The following table compares OAP against tar and tar.gz on a synthetic game asset workload: 360 assets totalling approximately 114 MB of raw data, mixing compressible content (scripts, configuration, scene descriptions) with incompressible blobs (pre-compressed audio and textures). All OAP figures use a ReleaseFast-optimised build on x86_64 Linux; tar figures include subprocess spawn overhead.

Format Pack time Archive size vs raw Sequential read Random access
OAP — auto (deflate where beneficial) 153 ms 89.6 MB −21.8% 72 ms 71 ms
OAP — store (no compression) 100 ms 114.6 MB +0.0% 65 ms 66 ms
tar 155 ms 114.9 MB +0.2% 80 ms N/A
tar.gz 1 399 ms 89.6 MB −21.8% 123 ms N/A

OAP with automatic compression packs in the same time as plain tar while matching tar.gz’s compression ratio — which takes nine times as long to produce and nearly twice as long to read. Sequential read is faster than both tar variants. Random access — unavailable for tar formats without full extraction — completes in roughly the same time as a full sequential scan, owing to the O(log n) binary search over the sorted index.

Reference implementation CLI tool

The reference implementation ships as a single executable named oap, intended both as a practical utility and as an example of how the format is used in real applications.

The core library consists of approximately 500 lines of code and relies exclusively on Zig’s standard library for compression and cryptographic functionality. The build process produces both a static library (liboap.a) and the oap command-line utility. Applications written in C, C++, C#, or other FFI-friendly languages can integrate OAP without requiring Zig throughout the rest of the codebase.

PACK: Creating packages is performed using the pack command, which recursively scans a directory and produces an .oap archive: oap pack assets/ game.oap. Compression can be enabled or disabled as needed, package metadata can be customized, and assets may optionally be encrypted using ChaCha20. By default, asset identifiers are generated deterministically from virtual paths, ensuring consistent identities across builds.

INSPECT: Several commands are available for inspecting package contents. The inspect command displays package metadata such as the format version, manifest information, asset count, index location, and encryption status. The list command provides a more detailed inventory of packaged assets, including their identifiers, compression methods, encryption methods, sizes, and virtual paths.

UNPACK: Packages can be extracted using the unpack command, restoring assets according to their virtual paths. Encrypted packages can be unpacked by supplying the appropriate encryption key.

VALIDATE: For automated workflows, the validate command verifies both package metadata and the CRC-32 checksum of every asset contained within the archive: oap validate game.oap. This makes it suitable for use in continuous integration pipelines or for validating packages distributed through content delivery networks.

Part of Turian

OAP originated within the Turian game engine ecosystem but was designed as a standalone format suitable for any engine or application that requires efficient asset packaging.

Source code and the complete specification

Open Asset Package
Launching Turian feature
2026.06.13

Launching Turian

It’s finally time to talk about what I’ve been cooking. After a massive technical pivot and a lot of “mad scientist” hours in the lab, I am super excited to announce that Turian is officially live.

Turian is a 3D game engine built entirely in Zig. But to understand why it exists, we have to look back at where I was just a few months ago.

The Road Through C#

If you’ve followed my work, you know I’m incredibly proud of Guinevere, the C# GUI library I designed. I love that project. But as I tried to use it to build a full-blown engine studio, things got… complicated. I even tried a hybrid approach using Avalonia—which is a rock-solid piece of tech—but it just didn’t feel right for what I wanted to achieve. Plus, let’s be honest, the C# game engine scene is pretty crowded already.

When I started my “side quest” into Zig, something clicked. Programming in Zig was just fun. I found an existing Zig IMGUI library that let me start building the Turian Studio from day one. It’s not as powerful as I want it to be yet—I’ll probably end up forking it or investing heavily in enhancing it—but it got the ball rolling.

Some Technical Magic

One of the biggest hurdles in Zig (compared to C#) is the lack of reflection. I needed the editor to be able to “see” and manipulate the code. I’m happy to say I’ve mostly solved this! Now, the editor can inspect your structs and give you a proper UI to tweak them.

But the feature I’m most proud of? The In-Editor Play Mode. I managed to implement this by compiling the user’s game code into a library and loading it at runtime. It feels just like working in Unity or Godot—you hit play, and you’re in the game instantly. When you’re ready to ship, the final game is still compiled as a single, lean, native executable.

Right now, you can create a project from scratch, drop in your 3D models, add scripts, and “cook” the final game with just a few clicks.

The Roadmap

We are moving fast. The engine is evolving every day. Here’s the general plan for the near future:

  • Refining the 3D World: We’re currently deep into improving materials, lighting, and shadows.
  • Studio Power: Making the editor more robust, user-friendly, and powerful.
  • The Big Three: Soon, we’ll be investing heavily in Audio, Physics, and a proper In-Game GUI system.

The goal is to give you everything you need to build a complete, functional game without leaving the ecosystem.

A New MEGA4

This release marks a reset for the MEGA4 initiative. Like the original plan, we’re embracing the “One Language” philosophy, and, this time, Turian is our starting point. Instead of starting from the GUI and building upwards, we’re are jumping some steps and then go down to the bottom of the stack.

I’m definitively not an expert in Zig, and building a game engine is most definitely not an easy task, so there is not lack of excitement.

It’s totally open-source (GPLv3). I’m having a fun time coding this project. Check it out at turian.mass4.org!

A Zig-Zag Adventure feature
2026.06.10

A Zig-Zag Adventure

I’m a huge fan of C#. I’ve spent years mastering it, and honestly, quite good at it. And C# is better than ever: with every release, gets faster and more robust—at this point, rivaling C++ and Rust in many benchmarks with barely any difference. I still love it, and many of my projects are (and will continue to be) built with it. It’s my “home base.”

But lately, I felt like I needed a new challenge—something more “raw”. That’s when I started playing with Zig as a hobby/educational project. And well, things escalated.

Why Zig? (And why not Rust?)

I did try Rust, but honestly? It’s just not fun for me. It’s way too strict. Instead of focusing on the code logic or the “big picture”, I’d spend hours fighting the grammar and the borrow checker. And don’t even get me started on the syntax—it’s full of abbreviated commands and esoteric punctuation that makes my eyes hurt.

Zig, on the other hand, is simple, direct, and what you see is what you get. No hidden runtime, no heavy-handed rules. It respects your intelligence.

It’s Not All Sunshine and Rainbows

Let’s be real: moving to Zig has been a massive uphill battle in some ways. Coming from the luxury of C#, I really miss things like Attributes and Reflection. Yes, reflection is slower, but man, it is incredibly powerful for building tools. Zig’s comptime is amazing and covers a lot of ground, but it’s a different beast entirely.

Then there’s the ecosystem. Zig is still young, and the documentation is… let’s say “sparse.” Even LLMs, which are usually my go-to for quick answers, constantly struggle to give the right solutions because there just aren’t enough examples out there yet.

It’s ABI is not stable. Some things that would be trivial in C, are not possible in Zig.

And don’t get me started on the IDE support. I’ve moved most of my coding to the Zed editor lately. I love how fast it is, but it’s definitely not Rider. When you’re used to the deep, “knows-everything” intelligence of JetBrains tools for C#, coding in Zig feels a bit like flying a plane with half the instruments missing.

The Perfect Side Project

So why do it? Because it is an adventure. I feel exploring a brand new world, sharing my findings with the community, and pushing the boundaries. It is like planing a day-one-released game without any walkthrough - you’re just trying to figure things out on your own.

What started as a “let’s see how this works” weekend project has turned into something much bigger. It’s been an incredible learning experience that has forced me to sharpen my skills. And that hobby project? It actually turned into a full-blown engine. But I’ll save the details of that “accidental” release for the next post.

Expedition To A Dream feature
2026.05.07

Expedition To A Dream

Rarely does a debut title from a new studio land with such thunderous impact as Sandfall Interactive’s Clair Obscur: Expedition 33. It is a game that feels both nostalgic and fiercely modern, blending the deliberate pacing of classic JRPGs with a visual fidelity that pushes current-gen hardware to its absolute limits. Set in a world inspired by Belle Époque France, it tells a haunting story of a Paintress who wipes away ages with a stroke of her brush.

World map

Blueprints and Whispers

From a technical standpoint, this is a showcase for Unreal Engine 5. The implementation of Nanite and Lumen is among the best I’ve seen, allowing for environments that are densely packed with ornate architectural details without sacrificing performance. What is particularly impressive is that the team achieved this level of complexity almost entirely using Unreal’s visual scripting Blueprints, with very little C++ code—a significant feat for a project of this scale and visual fidelity.

The “Paintress” aesthetic is more than just a lore point; it informs the entire rendering pipeline, with certain effects and transitions looking like brushstrokes coming to life. However, while the levels are visually breathtaking, their layout can be deceptively labyrinthine. I often found myself inadvertently looping back to the start, lost in the sheer density of the ornate French-inspired architecture.

One stylistic choice that deserves special mention is the voice acting. Eschewing the typical high-octane shouting of action games, the cast often speaks in low, almost whispering tones—even in moments of despair or intense action. It gives the game a unique, somber atmosphere that feels distinctly deliberate and “stylish.”

Combat

The Combat Conundrum

The most significant design decision is the “Active Turn-Based” combat. Unlike traditional JRPGs where you might select a command and watch it play out, Expedition 33 requires constant player engagement. Every enemy attack can be dodged or parried in real-time, and your own attacks benefit from timed button presses.

A crucial piece of advice for any newcomer: test if you truly enjoy this combat loop early on. Because the game is a massive RPG, you will be engaging in these mechanics hundreds, if not thousands, of times throughout the journey. If the rhythm of parrying and dodging doesn’t click for you, the sheer frequency of combat might eventually feel like a hurdle rather than a highlight. For me, it added a layer of tension but I was exausted by the end.

Narrative and Character Depth

The story is a melancholic trek through a dying world, and for the most part, the writing is superb. It tackles heavy themes of grief, death, and the core of human existence with genuine maturity. The chemistry between the members of the expedition feels earned, and their individual motivations are slowly unpeeled like an onion.

However, by the third act, the narrative starts to lose its subtle touch. Themes that were previously explored through atmosphere and subtext begin to be discussed quite plainly and repetitively, making the existential weight feel a bit more forced than it was in the game’s earlier hours.

Cutscene

Rinse and Repeat

While the “active” nature of the combat is its soul, it can also lead to fatigue. Some late-game bosses have massive health pools, and maintaining perfect parry timing for 20+ minutes can be mentally draining. A bit more variety in encounter pacing—perhaps some “puzzles” within the combat system that don’t rely solely on reflexes—would have been a welcome addition.

Clair Obscur: Expedition 33 is a triumph of art and ambition. It proves that the turn-based genre still has plenty of room for innovation. Despite some third-act heavy-handedness and occasionally confusing level design, it is an essential experience for anyone who appreciates bold art direction and deep, challenging systems.

My Rating: 7★★★★★★★
Metacritic: 92
The NUKE Uncertainty: When a Maestro Steps Away feature
2026.04.27

The NUKE Uncertainty: When a Maestro Steps Away

Other day iI woke to some unsettling news in the .NET ecosystem. Rumors are swirling—and some blog posts are starting to corroborate—that NUKE, the build system I’ve come to rely on for almost all my C# projects, is being effectively abandoned.

The word on the street is that the primary developer, Matthias Koch, has reached a breaking point. After years of pouring heart and soul into the project, the lack of financial incentive and the sheer weight of maintaining such a critical piece of infrastructure has taken its toll. What’s even more concerning is the talk that any future development might happen in a fork that could be closed-source or move to a paid model.

This hits home. Hard. I just wrote about how much I love Nuke, and now the foundation feels like it’s shifting under my feet.

The Search for a Substitute

When a tool you depend on enters “maintenance mode” or changes its licensing terms, the first instinct is to look for a lifeboat.

Interestingly, Cake 6.0 was recently released, and it seems the team there has been paying attention. They’ve introduced the Cake.Sdk, which feels very much like an answer to NUKE’s “code-first” philosophy. It moves away from the old .cake scripts and toward standard .cs files with a project-based approach. It’s got that IDE integration and strongly-typed feel that made me switch to NUKE in the first place.

Is it enough to make me jump ship? Not yet. For the time being, I’m sticking with NUKE. The existing code is MIT licensed, and even if the official repo is archived, the current version still works. But the long-term viability is definitely a question mark.

The Cost of “Free”

This situation shines a harsh spotlight on the open-source ecosystem. We—developers and businesses alike—have become incredibly comfortable building empires on the back of free labor. We depend on these “tiny” projects maintained by one or two people, and we often forget that there’s a human on the other side of that GitHub handle.

If we care about these tools, we have to support them. Whether it’s through GitHub Sponsors, Open Collective, or enterprise licenses, “free” always has a cost. If the maintainers can’t pay their bills or find a reason to keep going beyond “community spirit,” the project eventually collapses.

I’m at a crossroads here. Are you already testing the waters with Cake 6 or maybe something else like Modular Pipelines? For now, I’ll keep my Nuke scripts running, but I’ll be keeping a very close eye on the horizon.

Bruno MASSA