Read this to learn the history of Layers that drove the project into what it is today.

Why Layers

Layers has been significantly refactored and redefined since its inception in 2018 (the project existed for some time without any version control). This document explains why Layers came to be what it is today by going through the project's history.

NOTE: Some of the concepts and features that are described (and shown within images presented) in this document may be missing from current implementations of Layers/Vortex. Much of the user-editing functionality has become temporarily dormant and is now deferred as future Vortex work.

Layers started as a theme editor

Layers was originally a library that provided a template for building desktop (Qt) apps that specifically extended theming and UI styling to end-users. The goal was largely:

"Can an app extend advanced but user-friendly interfaces directly to end-users where they gain the ability to customize and adapt the entire app appearance, and could this capability be made generally available so that other developers could build their apps with it."

Over time, the feature set began to reflect the goal. This concept from 2023 shows roughly the idea: the user would be able to navigate through a tree in the sidebar and make changes to the selected style. The tree represented the entire app hierarchy so that a user could modify very specific UI elements.

Old Theme Editor Dialog Concept Image

Features implemented as needed

Since values needed to be changed conditionally (like when a widget needs to look different on mouse hover), states were implemented, arriving in 2021.

In 2023, linking was implemented so that attributes could share their values. Even the management of links was originally extended to the user:

Old Attribute Editor Image

Change propagation was implemented to ensure repainting when live changes were made. Since users edited relationships live, in a running app, the engine had to resolve at runtime.

Constant data restructuring

Importantly, during all of this time, the underlying data structure was constantly shifting.

Theme segmentation

Prior to October 2023, a theme was a massive set of data that contained values for nearly every UI element for the app(s) that the theme was supposed to work in. This led to the idea of breaking these UI definitions down into what eventually became known as styles (now referred to as layers, inheriting the project name). Segmentation meant that developers could define their UI across an arbitrary number of "style files".

Migration to JSON

Along with originally being unsegmented, themes were binary serialized, meaning they weren't human readable, and making changes to them required special code for updating. So, themes were migrated to JSON.

// Sample JSON style file, circa October 2023

"Color Dialog": {
    "attributes": { ... },
    "children": {
        "Apply Button": { ... },
        "Color Name Editor": { ... },
        "Color Unit Label": { ... },
        "Hue Label": { ... },
        "Hue Line Editor": { ... },
        "Hue Radio Button": { ... },
        "Hue Unit Label": { ... },
        "Saturation Label": { ... },
        "Saturation Line Editor": { ... },
        "Saturation Radio Button": { ... },
        "Saturation Unit Label": { ... },
        "Value Label": { ... },
        "Value Line Editor": { ... },
        "Value Radio Button": { ... },
        "Value Unit Label": { ... }
    }
}

Splitting the data from the UI

Also in October 2023, the Layers project was split. The Qt and UI half of the project moved to a separated project initially called QLayers but eventually renamed to Vortex, and Layers kept the JSON data half. This is where the "Layers is custom conventions over JSON" framing came from, through Layers versions 1.x - 2.x.

Since the split, other improvements were made like inheritance, key expansion, and order preservation.

// Sample JSON style file, circa January 2026

"Combo Box": {
    "->": "S:Box",
    "Fill": "L:Theme/Tertiary",
    "Corner Radii.(Top,Bottom) (Left,Right)": 3,
    "Padding.(Left,Top,Right,Bottom)": 8,
    "Text Color": "L:Theme/Foreground",
    "Font.Size": 14
}

Redefining Layers as a custom language

The conventions that had accumulated in JSON became real syntax. Now, with version 3.x, Layers has become a custom language. The above style can be rewritten as the following:

Combo Box << Box:
    Fill: Theme/Tertiary
    Corner Radii.(Top,Bottom) (Left,Right): 3
    Padding.(Left,Top,Right,Bottom): 8
    Text Color: Theme/Foreground
    Font.Size: 14

When not to use Layers

Layers is a C++ engine with a runtime model, and that is not always the right answer:

  • If you evaluate once and ship static output, a compile-time tool is simpler and fits existing pipelines.
  • If your main problem is enforcing a schema, Layers does not solve it. Layers does not validate your data; it resolves it.
  • Layers can't express arithmetic (yet).
  • Data doesn't always carry relationships. A flat settings file with twenty independent keys does not need inheritance, links, or states.
  • Layers has only been implemented in C++ at this time. It can integrate anywhere with a C++ FFI, but a stack with no native layer at all has no place to put the engine.

Related

If you're interested in the UI that used to be part of Layers, check out the Vortex project.

Appearance
Theme
—