# HFSM2: a header-only hierarchical state machine for C++11

> HFSM2 is a header-only C++11 state machine framework where the whole structure is fixed at compile time, with no dynamic allocation and no virtual methods, and transitions are type-safe template calls. The trade is deliberate: the state graph cannot change at runtime, and the documentation lives in the project wiki rather than in the repository.

**andrew-gresyk/HFSM2** — High-Performance Hierarchical Finite State Machine Framework

- Repository: https://github.com/andrew-gresyk/HFSM2
- Website: https://hfsm.dev
- Stars: 646 · Forks: 84
- Language: C++
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/andrew-gresyk-hfsm2

## The structure is fixed when you compile, not when you run

HFSM2 is described in the README as a header-only hierarchical FSM framework in C++11, with fully statically-defined structure and no dynamic allocations, built with variadic templates. That single sentence is the whole design. The state graph, the hierarchy of composite states and orthogonal regions, and the transitions between them are all part of the type of the machine, so the compiler sees the whole thing. At runtime there is no registry to look up and no container to grow, which is the point for an embedded target or a game loop where a frame budget is a hard constraint. The audience is a C++ developer who has outgrown a switch statement and wants the transitions to be part of the type system, and the repository topics place it squarely in game development and embedded systems. The project home is hfsm.dev, and the framework is MIT licensed.

## Type-safe transitions with optional payloads

The transition call is a template function on the machine, so the target state is part of the call rather than a string or an enum that is looked up at runtime. The README names it FSM.changeTo<TargetState>(), with optional payloads passed alongside. The benefit is that a transition to a state that does not exist, or a transition that does not compile in the current configuration, is a compile error rather than a silent no-op. The same static view applies to the rest of the machine: the README advertises that you can inspect anything, including previous and current transitions and state activation status. That is a debugging story, but it is also a design consequence of the same static structure. A second workflow is supported alongside the transition-driven one, a traditional event-based style using State::react(), so the framework can be adopted incrementally into a codebase that already dispatches events to objects.

## Hierarchies, composite states and orthogonal regions

The hierarchical part is what separates HFSM2 from a flat state machine library. The README describes a selection of composite sub-machines and orthogonal regions, and the wiki has a page dedicated to transitions within a hierarchy. The practical consequence is that a transition can be expressed relative to a level of the tree, so a sub-state handles its own internal moves without every parent having to know about them, and orthogonal regions let two independent parts of a machine be active at once, which is how a character that can be running and talking simultaneously gets expressed. Scalability comes from state re-use via state injections, so a large machine does not have to mean a large amount of duplicated code. The framework calls itself gamedev and embedded friendly, and the examples directory backs that up with projects that read like game problems rather than library demos.

## Planning, utility scoring and serializable history

Three features go beyond a state machine as most people picture one. The first is dynamic planning, with a wiki page for plans, which is aimed at game AI that chooses between available transitions rather than following a fixed script. The second is utility theory support, described as max score and ranked weighted random, which is the same idea from a different angle: instead of naming a destination, the agent scores the options and picks one. The third is serializability, with activity and transition history support, documented in the user guide. That last one is what makes the machine inspectable after the fact rather than only during execution, and it is the feature a tools or replay system would use. The README also notes built-in logging support and a debug-assisted mode, where defining HFSM_ENABLE_STRUCTURE_REPORT turns on an automatic structure and activity visualization API, so the machine can describe its own shape and what it has been doing.

## Configuration through macros, and what the code sample situation means

Feature selection is done with a family of HFSM2_ENABLE_* macros, which is how a header-only library can offer optional capabilities without forcing them on everyone. The two named in the README are HFSM_ENABLE_STRUCTURE_REPORT for the visualization API, and the release note mentions the ENABLE_ prefix generally, so the exact set of switches lives in the code rather than in a single table. What the repository does not contain is a code sample for the core use. The README's Quick Start section links out to the project wiki instead, with a Minimal Example page and an Extended Tutorial page, and the Documentation section points at the wiki alone. That is a real cost for evaluation: you cannot read the library's core API from the repository, and the wiki is the primary interface. The repository does carry a hfsm2.natvis file at the top level, which is the Visual Studio debugger visualisation file, so the debugging story is wired into the IDE.

## What the repository contains and how it is built

The top level shows a project with a real build system rather than a header and a hope. There is a CMakeLists.txt with a CMake directory and CMakePresets.json, plus premake.lua and premake.cmd for the Premake build route, and a projects directory. include/ holds the headers, test/ the tests, examples/ the sample projects, external/ the third-party code, tools/ and development/ the supporting scripts, and assets/ the logos. The examples are concrete: advanced_event_handling, basic_audio_player, basic_traffic_light, calculator, debug_logger_interface, and snippets. Two third-party libraries are named, doctest as the unit testing framework and XoShiRo as the random number generators, which is a hint that the random selection support in the utility scoring is built on a well-known generator. The CI badges show a matrix rather than a single compiler: a CMake workflow for GCC and Clang, a separate ARM GCC workflow using QEMU, and an MSBuild workflow for Visual Studio.

## Compiler support, releases and the shape of the project

The compiler list in the README is precise and worth reading against your own toolchain before you plan an adoption. Visual Studio 2015, 2017, 2019 and 2022 are supported, GCC 10 through 15, with GCC 13 singled out for ARM, Clang 13 through 18, AppleClang 17 on Intel and AppleClang 15 and 17 on Apple platforms. The C++11 floor is stated twice, once as the language standard and once as the standard library of the target, and the README hedges it as modern(ish) C++11, which is a fair description of a library that uses variadic templates. The release cadence is steady, with 2.12.1 published on 2026-06-10, 2.12.0 on 2026-05-09 and 2.11.1 on 2026-04-15, and the last push to the repository was on 2026-06-27. The default branch is master and the project carries a CII Best Practices badge, which is a signal about the project's own process rather than about the library.

## The family of libraries around it, and when a flat machine is enough

The README lists the related projects, and they say something about scope. FFSM2 is the flat variant, at its own site, for when you do not need a hierarchy, and both libraries have Unreal Engine plugins. HFSM Mono is a set of monospaced bitmap Unicode fonts for visualising HFSM2 and FFSM2 machines, which tells you how much the author invests in making a state machine legible to a human. That legibility matters more than it sounds: a hierarchical machine that only exists in the debugger is hard to reason about, and the fonts, the structure report and the natvis file are all aimed at the same problem.

The point where HFSM2 is the wrong tool is a runtime-defined graph. If the set of states or the transitions between them come from a data file, from a server, or from a designer-authored table, a fully static structure cannot express that, and you would be rebuilding the graph by hand in a flat machine instead. A second mismatch is tooling. If your team wants the whole machine in a single header with no CMake, no premake and no project files, the build setup here is heavier than that. The hierarchy also costs something in compile time, since the structure is instantiated from variadic templates, so a very large machine on a slow toolchain is worth timing before committing.

## Conclusion

HFSM2 fits a C++ codebase with a fixed behaviour graph, an embedded target, or a game where the state machine is known at compile time and you want no allocation and no vtables, especially if you already accept the C++11 floor and the wiki as the documentation. It does not fit a project whose state graph is data-driven and changes at runtime, and it does not fit a team that needs the whole machine in one header with no CMake and no separate project files. Before you adopt it, check the compiler list, since the README names Visual Studio 2015 through 2022, GCC 10 through 15 with GCC 13 for ARM, and Clang 13 through 18, and read the Minimal Example page in the wiki, since the repository itself carries no code sample for the library's core use.

## FAQ

### What is HFSM2 and what does it replace?

HFSM2 is a header-only hierarchical finite state machine framework in C++11 with a fully static structure, no dynamic allocations and no virtual methods. It is meant for game development and embedded systems, where the state graph is known at compile time and transitions are written as type-safe template calls such as FSM.changeTo<TargetState>().

### How do I start using HFSM2?

The repository does not include a code sample for the core library. The README's Quick Start section points to a Minimal Example page and an Extended Tutorial in the project wiki, and the Documentation section points at the wiki as well, so the wiki is the place to start.

### Which compilers does HFSM2 support?

The README lists Visual Studio 2015, 2017, 2019 and 2022, GCC 10 through 15 with GCC 13 for ARM, Clang 13 through 18, and AppleClang 15 and 17 plus AppleClang 17 on Intel. The library targets C++11 and is header-only, with no separate library to link.

### Can HFSM2 do more than switch on a state variable?

Yes. The README lists dynamic planning support for game AI, utility theory support with max score and ranked weighted random selection, serializability with activity and transition history, an event-based workflow using State::react(), and a debug-assisted mode enabled by defining HFSM_ENABLE_STRUCTURE_REPORT for automatic structure and activity visualization.

### When would I use FFSM2 instead of HFSM2?

The README lists FFSM2 as the flat finite state machine companion project, for cases where the hierarchy is not needed. Both have Unreal Engine plugins, and both are covered by the HFSM Mono bitmap fonts project for visualising machine structure.

## Sources

- [andrew-gresyk/HFSM2 on GitHub](https://github.com/andrew-gresyk/HFSM2)
- [License: MIT](https://github.com/andrew-gresyk/HFSM2/blob/master/LICENSE)
- [Project website](https://hfsm.dev)
- [README](https://github.com/andrew-gresyk/HFSM2/blob/master/README.md)
- [Releases](https://github.com/andrew-gresyk/HFSM2/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/andrew-gresyk-hfsm2
