Skip to content

jeromew21/frameflow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Frameflow

Frameflow is a small, deterministic, rectangular layout engine inspired by Godot’s UI system. It is designed to be embedded inside game engines and real-time applications where you want explicit control over layout without inheriting a heavyweight widget framework.

Note: this is a mostly AI-generated project. I designed and guided the API, but a majority of the internal logic and this readme are AI generated.

I wanted to factor out this into a library since it 1) has an explicit purpose and problem it's trying to solve and 2) requires zero external dependencies.

There are some undocumented quirks in the layout system, but I am using it in my 2D game with no issues so far.

Future plans

  • Re-write in C so bindings can be more easily generated
  • Refactor into a header-only library.
  • Add split containers

Goals

  • Minimal core

    • Frameflow is a layout solver, not a UI toolkit.
    • Rendering, input, and widget behavior are intentionally out of scope.
  • Predictable behavior

    • Layout is fully deterministic.
    • No hidden state, no implicit global configuration.
  • Engine-friendly

    • Data-oriented structures.
    • No dynamic polymorphism.
    • No allocations during layout evaluation.
  • Composable

    • Nodes form a tree.
    • Behavior is expressed through explicit node types and components.

Core Concepts

Nodes

Each element in the layout tree is a Node.

A node contains:

  • Local bounds and minimum size
  • Expansion and stretch weights
  • Anchor and offset information
  • Parent and child relationships
  • A type tag and optional component data

Nodes are referenced using a generational handle:

struct NodeId {
    uint32_t index;
    uint32_t generation;
};

This allows safe reuse of internal storage while preventing stale references.

Node Types

Frameflow supports several built-in layout behaviors:

Type Description
Generic Passive container with no special behavior
Center Centers its single child
Box Linear layout (horizontal or vertical)
Flow Flow layout with wrapping behavior
Margin Adds padding around its child

Each specialized node stores its configuration in a component pool.

System

A System owns all nodes and components:

struct System {
    std::vector<Node> nodes;
    Components components;
    std::vector<NodeId> children;
    std::vector<uint32_t> free_list;
};

Multiple independent trees can coexist inside a single system.

Basic Usage

Creating Nodes

frameflow::System sys;

NodeId root = add_generic(&sys, frameflow::NullNode);
NodeId box  = add_box(&sys, root, {Direction::Horizontal, Align::Start});
NodeId item = add_generic(&sys, box);

Computing Layout

compute_layout(&sys, root);

After computation, each node’s bounds field contains its resolved rectangle.

Deleting Nodes

delete_node(&sys, item);

Deletion is recursive and safe with respect to existing NodeId references.

Reparenting

reparent_node(&sys, item, new_parent);

Philosophy

  • Bring your own abstraction

    • Frameflow exposes a low-level API.
    • Wrapping it in your own widget or scene system is expected.
  • Explicit over implicit

    • Every behavior is expressed through data.
    • There are no hidden layout rules.
  • Simple to integrate

    • No external dependencies.

Non-Goals

Frameflow does not provide:

  • Rendering
  • Input handling
  • Widget logic
  • Styling or theming
  • Event systems

Those concerns belong to the host engine.

License

MIT

About

Layout engine

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published