Forest
- YEAR
- 2025—Present
- ROLE
- Design
Implementation
- DISCIPLINES
- API Design
Systems/Engine Programming
Forest is a reusable framework implemented from scratch to support my games and software. Basically, it's Lena, but for big boy games.
I like to call Forest an 'engine toolkit', because it's somewhere between framework and engine. It's far, far more opinionated and structurally narrow-minded than a typical framework but equally does not interfere with or make assumptions about the architecture of games or programs it supports.
Even in its early infancy it's already successfully supporting three different projects I'm working on quietly behind the scenes — two different prototype games that will be advancing to being made some day (one with extremely high performance requirements) and a high performance desktop application prototype doing graphics work.
None of the following writing should be considered concrete documentation. Forest is a work-in-progress and constantly undergoes large changes, primarily due to its simplicity enabling rapid revision and refactoring.
Philosophy and Structure
Forest emerged from a basic problem I was having: I kept finding that I would build an interesting or useful 'component' in a prototype game or piece of software, which would then languish somewhere on my filesystem after the prototype was abandoned; I'd either lose interest or find the idea just wasn't that fun or scaleable into a full game.
Every time I'd start messing around with a new prototype, I'd find myself quickly searching around my system for the most recent iteration of that thing, or the most simple/performant version of it, or even times I had previously copy-pasted bits of an engine to quickly bootstrap a new one, and I found I'd struggle to identify which was the best one.
I got fed up with this. Forest was the result of my spending a week or so going around my filesystem and picking apart old prototypes for useful features, components and paradigms. I assembled all of that into a large Odin package. I even ported a number of interesting bits of code I'd written in other languages, like Go, Rust and even some Lua.
This amounted to approximately ten thousand lines of extremely useful code that I almost always want some (or all) of at my fingertips while trying to stand up a new software or game project.
I unified the code style and naming conventions, but most importantly unified the typing; everything in Forest is compatible without any casting, which is hugely useful: interacting with libraries and constantly having to cast elements between different library paradigms is maddening and, however small the impact actually is in practice, this does have an effect on performance.
Eventually, it wound up being composed of several packages because simple modularity — without too many Odin -defines — became king. There are several more, but here are some of the important ones:
- 🪵
mossis the core library - 🪴
stemis a spatial audio mixer - 🌱
seedis a format and serialisation library - 🍁
leafis a UI toolkit (renderer-agnostic) - 🎻
bardis a font-loading/text-handling tool (renderer-agnostic) - 🎨
daubis a dedicated cross-platform tablet handler
Also, there are some high-level libraries that offer quick and dirty drop-in tools, like animation libraries, simple sprite-batching, rendering of primitives and basic textures, etc.. These are designed to be used to quickly stand up a prototype but be replaced in short order with dedicated, application-specific tooling rendering:
- 🌿
fernis a 2D-focused library - 🪨
rockis a 3D-focused library
I describe Forest as 'both more and less than a framework' — hence 'engine toolkit' — when explaining it to people. Not much about Forest is 'game-ready' in the sense of a framework or engine. It's just a lot of tools for quickly building an engine, with composability as its guiding principle — rather than abstraction.
The 'core' package, moss, is the most important one. All other packages in Forest depend on moss, while each set of packages have no inter-dependencies. moss is both the shared layer of this larger shared library collection, but also serves as the entry point for game or GUI projects.
moss is primarily based on the API design and patterns of Lena and could be described as a general purpose framework on its own — except it provides no default audio or rendering capabilities. It creates windows and surfaces, sets up Vulkan/Metal/OpenGL, handles input and provides most of the primitive types, structures and associated utilities all of the Forest packages require, but basically everything else is up to you.
package main
import "forest:moss"
// opengl is compiled-in and initialised via a
// command-line argument to the Odin compiler
// MOSS_BACKEND="OPENGL"
main :: proc() {
moss.init("Title", 1920, 1080, {.FULLSCREEN, .VSYNC, .TABLET})
defer moss.destroy()
for delta_time in moss.step() {
moss.opengl_clear_screen()
// do stuff
moss.opengl_present()
}
}Design Principles
Forest adheres to a few simple design principles.
- Data-oriented. There are no classes or component systems here.
- All components are visible. Very little is private in Forest and it exposes everything it can.
- Code is shallow. Procedures do not beget procedures layers and layers deep.
- Procedures do one job. 80% of the Forest API consists of procedures that do a single thing really fast.
- If procedures don't do one job, they're designed for re-implementation: the higher-level packages build monolithic procedures out of primitives to quickly carry out common tasks I need across projects. Annoyingly, sometimes I need one of their five or six internal steps to be different. Because all of its components are visible, re-implementing a minor variation at the application level is always trivial.
- Modular. All of Forest's packages can seamlessly interoperate with each other down to type-level. Each package provides a common, desirable addition to Forest's functionality in a way that's entirely opt-in — if the project is 2D but doesn't suit
fern's way of thinking, its API won't be sitting there blocking you. You can just go around. - Inversely Modular. Equally, if
fern's sprite animation system and data structures are attractive in a different context, they can be imported and used without invoking the rest of Forest. Any program can benefit from the higher-order packages because while they build on top ofmoss, the previous design principles mean they're almost never inseparably intertwined together. - API that doesn't function isn't exported: I hate APIs with comments like 'does nothing on Windows platforms'. In Forest, procedures that are platform-specific are only exported on those platforms and require you to make conscious choices in user-code about applying them. It's also obvious when reading back that a call is platform-specific.
when moss.IS_WINDOWS {
moss.windows_title_color({0.3, 0.4, 0.2, 1.0})
}
when moss.IS_DARWIN {
path := moss.darwin_get_bundle_resource_path(allocator)
} else {
path := moss.get_executable_path(allocator)
}and so on...
Forest is under active development. There are no plans to open-source it or share it with others. It's designed as a platform for my future and far more ambitious software and game projects and for the time being, the Forest will be gardened and refined while I build them.
