# two C++ graphics and UI toolkit review

> two is a C++ prototyping toolkit for live graphical applications and games, combining graphics, a declarative UI, reflection, and low-level generic algorithms. Its main adoption constraint is a source-oriented GENie workflow with several related repositories and no published GitHub releases.

**hugoam/two** — c++ toolkit for rapid development of live graphical apps and games

- Repository: https://github.com/hugoam/two
- Stars: 1,731 · Forks: 98
- Language: C++
- License: Zlib
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/hugoam-two

## two's place in C++ graphical prototyping

two targets developers who need to construct small graphical applications and games in C++ without first assembling rendering, interface, reflection, and utility code themselves. The README describes it as an all-purpose app prototyping library rather than a game with a fixed runtime or a general editor. Its intended audience includes programmers experimenting with scenes, shaders, materials, interfaces, live views, and reusable graphical building blocks.

The central design choice is separation. two exposes a graphics API for scenes, shapes, meshes, models, lights, materials, passes, and post-processing. It also exposes a UI API for an auto-layout, stylable interface with widgets, docking, tabs, nodes, text editors, inputs, and curves. The README says these layers can be used independently and also identifies them as separate projects, twfx and twui. That separation can prevent an interface choice from forcing an application to adopt every part of the toolkit.

The project is opinionated, though. It assumes that graphical application code can be expressed through immediate-looking calls and that style sheets can describe both widget layout and appearance. This is a closer fit to tools, experiments, and games with custom interfaces than to an application that expects a mature widget toolkit with a stable product-specific documentation set. The README is strongest when describing the API direction, but it does not provide a release history, supported compiler matrix, platform requirements, or production support policy.

## Declarative UI structure and frame processing

two's UI is described as halfway between immediate mode and retained mode. Calls look like an immediate-mode API, but the final widget tree corresponds to the declarations traversed during a frame. Events are processed and rendering happen later, rather than every call immediately creating and drawing a final interface object. The practical distinction is that application code can describe widgets in a compact hierarchy while the library keeps frame handling and rendering in separate stages.

A minimal application creates a Shell and passes a callback named pump. The callback calls app.pump(), leaving space for interface and graphics declarations. Once a window has been created and its root begin() call is made, widgets can be declared against it. Labels, buttons, color editors, and other widgets receive a parent widget, and a button result can drive application behavior.

Styling is handled through JSON style sheets. According to the README, style sheets control both layout and appearance, including aspects beyond the visible colors of controls. The README also states that switching style sheets at runtime changes the appearance of the entire interface. Individual widgets can receive a Style argument when a local departure from the active style sheet is needed. This design is useful for editors and prototypes, but the README does not explain style-sheet discovery paths, validation behavior, defaults, migration between styles, or the runtime cost of changing sheets. Those details should be checked in `docs/ui.md` and the UI examples before building a maintained interface around them.

## Graph node calls and scene assembly

The graphics layer follows the same immediate-looking calling convention as the UI, but its nodes form a graphics hierarchy. A viewer provides a scene graph, and calls such as gfx::node, gfx::shape, gfx::model, and gfx::animated add or configure items. A node transform applies to its children, which means a model, shape, or animation can inherit placement from the node beneath which it is declared.

The documented model example creates a scene viewer, begins the graph, places a transformed node, adds a cube shape to that node, adds an OBJ model, and attaches an Animated item. The animation is then played by name. This gives prototypes a readable construction path for demonstrating a scene without requiring the application to expose a separate serialized scene format first.

The graphics API also covers cameras, materials, lights, particle examples, post-processing, selection, glTF examples, sky rendering, shaders, and multiple viewports. Those names come from the README and repository example directories rather than a complete API contract. The README does not state which resource formats are guaranteed, how OBJ and glTF loading failures are reported, or which rendering backends are supported on each operating system. A team should therefore treat model import, shader compilation, and platform-specific rendering as validation points rather than assuming that every example is a portable starting point.

## Building two with GENie and native toolchains

The documented installation path is source-based. The README instructs users to clone bx, bimg, and bgfx, then clone two recursively. GENie binaries for Windows and Linux are included in the `bin` directory. GENie generates project files for the two libraries and the examples, after which the selected native build system compiles them.

For Linux with GCC, the documented sequence is below. The commands are copied from the README's Linux build instructions. The expected result is a generated project tree under `build/projects/gmake-linux`, followed by the selected `make` configuration.

```bash
git clone https://github.com/hugoam/bx
git clone https://github.com/hugoam/bimg
git clone https://github.com/hugoam/bgfx
git clone --recursive https://github.com/hugoam/two
cd two
```

The Linux generation and build commands are separate because GENie creates the project files before `make` can compile them.

```bash
bin/linux/genie --gcc=linux-gcc gmake
cd build/projects/gmake-linux
make config=debug64 -j8
```

The README also documents `bin/darwin/genie --gcc=osx gmake` for macOS make projects, `bin/darwin/genie --xcode=osx xcode9` for Xcode, and `bin/windows/genie vs2017` for Visual Studio. The first application follows this shape.

```c++
#include <two/two.h>

using namespace two;

bool pump(Shell& app)
{
    return app.pump();
}

int main(int argc, char *argv[])
{
    Shell app(RESOURCE_PATH);
    app.run(pump);
}
```

The README says to add UI or graphics calls in the pump function. It does not document a package-manager installation, a binary distribution, or a one-command release artifact.

## Separate twfx and twui adoption paths

The repository's most consequential architectural boundary is the separation between two, twfx, and twui. The README says the graphics and UI layers are each available as their own libraries, `twfx` and `twui`, and that they are not tied to one another. This creates two adoption modes for a C++ team: use the combined toolkit when a prototype needs both layers, or depend on the narrower library when one side defines the application's boundary.

That distinction can reduce unnecessary coupling in editor tools, data viewers, or interface experiments. A project that only needs the declarative UI does not have to inherit the graphics abstraction simply because both APIs are documented under the two project. Conversely, a graphics experiment can use the renderer-oriented API without adopting the complete widget set.

The trade-off is that users must understand repository and library boundaries that the README describes in prose but does not fully map to installation packages or version compatibility rules. No GitHub releases are published, and the README gives no version tags, compatibility matrix, or upgrade procedure for two, twfx, and twui. The build tutorial therefore produces projects from repository state rather than guiding users toward a stable release sequence. For production use, the first review should cover which separate repository supplies each dependency and whether those repositories are expected to be updated together.

## Maintenance, licensing, and practical adoption limits

The repository is not archived. Its last push was on 2026-10-06, so the recorded maintenance signal is recent relative to the repository state, but the absence of GitHub releases means there is no published release cadence to inspect. The upgrade path is also more hands-on than a package-based library: the README requires cloning multiple repositories, including a recursive clone of two, then regenerating projects with GENie. That can impose recurring dependency and toolchain work when building from source.

two is published under the Zlib license, as stated in the README. That identifier is relevant when reviewing source reuse obligations and compatibility, but this article does not provide legal advice. The repository contains a `LICENSE.txt` file, which is the appropriate starting point for the exact terms.

The project also has a clear wrong-fit case. A team that wants a narrowly packaged rendering dependency, a conventional retained UI with a documented component model, or a turnkey game engine should not assume that two's source-oriented toolkit covers those needs. The examples demonstrate many possibilities, but the README does not document rollback, deployment packaging, supported graphics drivers, asset licensing, or a production troubleshooting guide. The practical decision depends on whether the project can operate the source build and whether its examples cover the exact interface and rendering features required.

## Conclusion

Adopt two when a C++ prototype needs live graphical scenes and a substantial UI without adopting a monolithic engine. Do not choose it when packaged releases, isolated dependency installation, or a documented production deployment path matter more than its source-level APIs. Verify first that the required examples build on the selected platform, that bx, bimg, and bgfx fit your dependency process, and that the live UI and graphics behavior matches the intended application.

## FAQ

### How do I build two on Linux with GCC?

Clone bx, bimg, bgfx, and two recursively, enter the two directory, run `bin/linux/genie --gcc=linux-gcc gmake`, then build from `build/projects/gmake-linux` with the documented `make config=debug64 -j8` command.

### What is the difference between immediate and declarative UI in two?

The API resembles immediate mode, but the final widget tree follows the declarations traversed during a frame. two processes events and rendering in a separate step, which is why the README calls the paradigm declarative.

### Can two's graphics and UI layers be used independently?

Yes. The README identifies the graphics and UI layers as separate libraries, `twfx` and `twui`, and states that they can be used independently and are not tied to one another.

## Sources

- [hugoam/two on GitHub](https://github.com/hugoam/two)
- [Issues](https://github.com/hugoam/two/issues)
- [License: Zlib](https://github.com/hugoam/two/blob/master/LICENSE)
- [README](https://github.com/hugoam/two/blob/master/README.md)

---

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