Skip to main content

max / alloy

Depend on makeover instead of a path into the MNW checkout theme-common was reachable only as ../MNW/shared/theme-common, so Alloy could not be built by anyone without that repo. It is now the standalone makeover crate, consumed as a tagged git dependency. The theme files moved with it. The dev fallback used to walk up to MNW/shared/themes; it now asks makeover for the themes it ships, so a fresh clone comes up themed instead of erroring. Packaged themes at /usr/share/alloy/themes still take precedence on an installed system.
Author: Max Johnson <me@maxj.phd> · 2026-07-19 19:15 UTC
Signed with PGP, not checked
Commit: e54dd477c6d002e5e158e659107dbbdb82d3002c
Parent: 79635c6
17 files changed, +62 insertions, -61 deletions
M Cargo.lock +10 -10
@@ -24,18 +24,18 @@
24 24 "alloy_tui",
25 25 "anyhow",
26 26 "clap",
27 + "makeover",
27 28 "ratatui",
28 29 "serde",
29 30 "serde_json",
30 - "theme-common",
31 31 ]
32 32
33 33 [[package]]
34 34 name = "alloy_tui"
35 35 version = "0.0.0"
36 36 dependencies = [
37 + "makeover",
37 38 "ratatui",
38 - "theme-common",
39 39 ]
40 40
41 41 [[package]]
@@ -716,6 +716,14 @@
716 716 "winapi",
717 717 ]
718 718
719 + [[package]]
720 + name = "makeover"
721 + version = "0.8.0"
722 + dependencies = [
723 + "serde",
724 + "toml",
725 + ]
726 +
719 727 [[package]]
720 728 name = "memchr"
721 729 version = "2.8.2"
@@ -1424,14 +1432,6 @@
1424 1432 "winapi",
1425 1433 ]
1426 1434
1427 - [[package]]
1428 - name = "theme-common"
1429 - version = "0.7.0"
1430 - dependencies = [
1431 - "serde",
1432 - "toml",
1433 - ]
1434 -
1435 1435 [[package]]
1436 1436 name = "thiserror"
1437 1437 version = "1.0.69"
M Cargo.toml +1 -1
@@ -11,7 +11,7 @@
11 11
12 12 [workspace.dependencies]
13 13 ratatui = "0.30"
14 - theme-common = { path = "../MNW/shared/theme-common" }
14 + makeover = { git = "https://git.sr.ht/~maxmj/makeover", tag = "v0.8.0" }
15 15
16 16 [profile.release]
17 17 lto = "thin"
@@ -6,7 +6,7 @@
6 6
7 7 `alloy_tui` exposes:
8 8
9 - - **Design tokens** as a runtime `Theme` value resolving theme-common intents into ratatui `Color` / `Style`. Single source of truth for everything in [DESIGN-LANGUAGE.md](DESIGN-LANGUAGE.md).
9 + - **Design tokens** as a runtime `Theme` value resolving makeover intents into ratatui `Color` / `Style`. Single source of truth for everything in [DESIGN-LANGUAGE.md](DESIGN-LANGUAGE.md).
10 10 - **Themed primitives** configured against the tokens: blocks, list rows, tags, form fields, status bars, log panes. Each carries its focus/selected/disabled variants.
11 11 - **Layout helpers**: Alloy-flavored wrappers over ratatui's `Layout` constraint solver (section spacing measured in cells).
12 12 - **A focus + keymap model**: the piece ratatui does not give you. Rendering is immediate-mode, but input is event-driven, so the crate owns the navigation model the app drives from its event loop: `FocusRing` across panes, `Cursor` down a list.
@@ -143,9 +143,9 @@
143 143
144 144 ## Design tokens
145 145
146 - Tokens are the single source of truth, and they are read at runtime. Earlier drafts of this document described a `tokens.toml` at the crate root compiled to Rust constants by a `build.rs` step. That pipeline was replaced by theme-common before `alloy_tui` was written, and no part of it exists. [TOKENS.md](TOKENS.md) is authoritative; this section only describes the crate-side shape.
146 + Tokens are the single source of truth, and they are read at runtime. Earlier drafts of this document described a `tokens.toml` at the crate root compiled to Rust constants by a `build.rs` step. That pipeline was replaced by makeover before `alloy_tui` was written, and no part of it exists. [TOKENS.md](TOKENS.md) is authoritative; this section only describes the crate-side shape.
147 147
148 - Themes are theme-common `.toml` files, the same schema every make-family app reads, living in `MNW/shared/themes/` and `~/.config/alloy/themes/`. `alloy_tui` loads one, resolves the intents it needs into ratatui colors, and derives two Alloy-specific tokens locally so theme files stay minimal and cross-app compatible:
148 + Themes are makeover `.toml` files, the same schema every make-family app reads, living in makeover's `themes/` and `~/.config/alloy/themes/`. `alloy_tui` loads one, resolves the intents it needs into ratatui colors, and derives two Alloy-specific tokens locally so theme files stay minimal and cross-app compatible:
149 149
150 150 ```
151 151 border-subtle = mix(line.border, surface.page, 60%) decorative divider
@@ -174,6 +174,6 @@
174 174
175 175 ## Late-term: a design tool, and the token seam
176 176
177 - The theme file is the deliberate seam where external design tooling could live, and it is toolkit-agnostic: anything that emits a valid theme-common `.toml` is a viable producer (a hand-edited file, Tokens Studio, a future Alloy-built tool). The move to theme-common widened that seam rather than closing it, since the format is now shared with every make-family app instead of being Alloy's own. A speculative token-sync tool keeps the working name **`cast`** (alloys are cast; the tool casts a design source into Alloy tokens). The broader research question of a design tool native to immediate-mode UI is captured in [RESEARCH-IMMEDIATE-MODE-DESIGN.md](RESEARCH-IMMEDIATE-MODE-DESIGN.md); with the pivot to ratatui, that question now targets terminal compositions rather than GPU-drawn ones, but the architecture is the same.
177 + The theme file is the deliberate seam where external design tooling could live, and it is toolkit-agnostic: anything that emits a valid makeover `.toml` is a viable producer (a hand-edited file, Tokens Studio, a future Alloy-built tool). The move to makeover widened that seam rather than closing it, since the format is now shared with every make-family app instead of being Alloy's own. A speculative token-sync tool keeps the working name **`cast`** (alloys are cast; the tool casts a design source into Alloy tokens). The broader research question of a design tool native to immediate-mode UI is captured in [RESEARCH-IMMEDIATE-MODE-DESIGN.md](RESEARCH-IMMEDIATE-MODE-DESIGN.md); with the pivot to ratatui, that question now targets terminal compositions rather than GPU-drawn ones, but the architecture is the same.
178 178
179 179 The commitment that keeps the door open: **tokens are a file, not Rust source.** As long as the theme file is the authority and Rust holds no hex values of its own, the producer is swappable and the design system stays portable. Runtime loading strengthens that commitment: swapping a theme is now a file change and a relaunch rather than a rebuild.
M docs/CONSOLE.md +4 -4
@@ -22,8 +22,8 @@
22 22 alloy update # system updates: rpm-ostree front
23 23 alloy sync # syncthing front (see CONTINUITY.md)
24 24 alloy config <path> # schema-driven TOML/KDL editor
25 - alloy theme <name> # swap the runtime theme; reads MNW/shared/themes/*.toml
26 - # or ~/.config/alloy/themes/*.toml via theme-common
25 + alloy theme <name> # swap the runtime theme; reads makeover's themes/*.toml
26 + # or ~/.config/alloy/themes/*.toml via makeover
27 27 ```
28 28
29 29 `alloy mesh` was named `alloy tail` when this document was written. It is
@@ -111,7 +111,7 @@
111 111
112 112 ## `alloy_tui`: the ratatui design system
113 113
114 - `alloy_tui` **is** Alloy's design system. The pivot dropped the egui `alloy_ui` sibling, so there is no GUI counterpart, and this crate carries the whole authored visual identity. It consumes theme-common `.toml` theme files at runtime (see [TOKENS.md](TOKENS.md)); palette and semantic colors render as terminal chrome.
114 + `alloy_tui` **is** Alloy's design system. The pivot dropped the egui `alloy_ui` sibling, so there is no GUI counterpart, and this crate carries the whole authored visual identity. It consumes makeover `.toml` theme files at runtime (see [TOKENS.md](TOKENS.md)); palette and semantic colors render as terminal chrome.
115 115
116 116 Contents (v1). Shipped:
117 117 - Themed `ratatui` widget wrappers: `AlloyBlock`, `AlloyList`, `AlloyStatusBar`, `AlloyLog`.
@@ -142,7 +142,7 @@
142 142 - **Shipped.** `alloy net`, `alloy audio`, `alloy mesh`. Plus the shell they share: frame, reserved keys, focus, command-log pane, background tick.
143 143 - **Next.** `alloy config`, with schemas for the v0-adopted TOML configs (rio, yazi, mako, and others; the sway config takes the text-edit fallback). The largest remaining piece: schema-DSL v1 parser, `toml_edit` roundtrip layer, and the form widgets together.
144 144 - **Blocked on the target machine.** `alloy display` and `alloy update` front `swaymsg`/`wlr-randr` and `rpm-ostree`, none of which exist on a non-Fedora, non-sway development box. Writing them now would mean shipping parsers checked against nothing but their own fixtures, which is exactly how the two parser bugs found so far got written. They want the QEMU image or real hardware.
145 - - **Then.** `alloy sync`, `alloy theme`. `alloy theme` swaps the runtime theme in place (theme-common consumer, no re-login). First-boot flow (see [CONTINUITY.md](CONTINUITY.md)) is a thin shim over `alloy mesh` and `alloy sync` enrollments.
145 + - **Then.** `alloy sync`, `alloy theme`. `alloy theme` swaps the runtime theme in place (makeover consumer, no re-login). First-boot flow (see [CONTINUITY.md](CONTINUITY.md)) is a thin shim over `alloy mesh` and `alloy sync` enrollments.
146 146 - **v1.x.** Additional adopted-tool schemas as the v0 stack grows. (`alloy hinged` was shelved with the FW12 tablet flow in the pivot.)
147 147 - **v2+.** Third-party subcommand registration (a well-known directory of ratatui adapters the console discovers at runtime), if a real ecosystem case emerges. Not planned.
148 148
@@ -32,7 +32,7 @@
32 32
33 33 Immediate-mode reframes the unit of design work. There is no screen, only a *function rendered every frame from current state*. So the meaningful artifacts a designer produces are:
34 34
35 - 1. **Tokens**: palette, type scale, spacing, radii, motion (or its absence). Flat data, already covered by the theme-common theme files described in [COMPONENT-LIBRARY.md](COMPONENT-LIBRARY.md).
35 + 1. **Tokens**: palette, type scale, spacing, radii, motion (or its absence). Flat data, already covered by the makeover theme files described in [COMPONENT-LIBRARY.md](COMPONENT-LIBRARY.md).
36 36 2. **Themed primitives**: buttons, text fields, tags, focus rings. Visual specification of state variants.
37 37 3. **Composition vocabulary**: "this is a card with these slots," "this is a list row with this arrangement," "this section is dense; this one is breathy." A *grammar*, not a pixel layout.
38 38 4. **Data shapes the composition accepts.** A `PackageRow` accepts `(name, version, urgency, icon)`. The designer specifies what fields render in what arrangement; the engineer provides the data.
@@ -49,7 +49,7 @@
49 49
50 50 ### Token-first authoring
51 51
52 - Most design work is the token graph. The tool's primary editing surface is the palette, the typography scale, the spacing scale, the radii, the elevation steps. Changes propagate instantly to every component preview. This is already most of Figma's value, and it round-trips cleanly to a theme-common theme file (the `cast` tool idea generalized).
52 + Most design work is the token graph. The tool's primary editing surface is the palette, the typography scale, the spacing scale, the radii, the elevation steps. Changes propagate instantly to every component preview. This is already most of Figma's value, and it round-trips cleanly to a makeover theme file (the `cast` tool idea generalized).
53 53
54 54 ### Composition grammar, not pixel layout
55 55
@@ -78,7 +78,7 @@
78 78
79 79 ### Engineer-facing output
80 80
81 - The artifacts produced are: a theme-common theme file (tokens), `<Component>.alloy.ron` files (compositions), and a small registry of which components exist. The engineer wires these into the authored TUIs (the console). There is no pixel-perfect mockup to translate; the composition file *is* the spec.
81 + The artifacts produced are: a makeover theme file (tokens), `<Component>.alloy.ron` files (compositions), and a small registry of which components exist. The engineer wires these into the authored TUIs (the console). There is no pixel-perfect mockup to translate; the composition file *is* the spec.
82 82
83 83 ## Open research questions
84 84
@@ -104,7 +104,7 @@
104 104
105 105 Almost nothing. The architectural decisions already made in [COMPONENT-LIBRARY.md](COMPONENT-LIBRARY.md) keep the door open:
106 106
107 - - Tokens live in a TOML file, not in Rust source. Any tool that emits a valid theme-common theme file is a viable producer.
107 + - Tokens live in a TOML file, not in Rust source. Any tool that emits a valid makeover theme file is a viable producer.
108 108 - The crate exposes a small, stable set of layout combinators and themed primitives. These would be the vocabulary the composition grammar references.
109 109
110 110 The further commitments Alloy *could* make to keep this even more open (small, low-cost, worth considering):
M docs/TOKENS.md +9 -9
@@ -4,9 +4,9 @@
4 4
5 5 The rules these tokens implement live in [DESIGN-LANGUAGE.md](DESIGN-LANGUAGE.md). This file is where the rules become storage, derivation, and gates.
6 6
7 - ## Storage format: theme-common
7 + ## Storage format: makeover
8 8
9 - Alloy consumes themes in the [theme-common](../../MNW/shared/theme-common/) TOML format, the same schema GoingsOn, Balanced Breakfast, audiofiles, and makenot.work already consume. A theme file has seven sections:
9 + Alloy consumes themes in the [makeover](https://git.sr.ht/~maxmj/makeover) TOML format, the same schema GoingsOn, Balanced Breakfast, audiofiles, and makenot.work already consume. A theme file has seven sections:
10 10
11 11 ```toml
12 12 [meta]
@@ -45,13 +45,13 @@
45 45 six = "#305858"
46 46 ```
47 47
48 - Alloy's default light theme is **[Akari Dawn](../../MNW/shared/themes/akari-dawn.toml)**; the default dark is **[Akari Night](../../MNW/shared/themes/akari-night.toml)**. Both are based on Shu Kutsuzawa's [Akari](https://github.com/cappyzawa/akari-theme) (MIT). Users pick a mode at startup (`--theme` flag or `$COLORFGBG` / OSC background query); users can also drop any theme-common `.toml` into `~/.config/alloy/themes/` and pass its name to swap.
48 + Alloy's default light theme is **[Akari Dawn](https://git.sr.ht/~maxmj/makeover/tree/main/item/themes/akari-dawn.toml)**; the default dark is **[Akari Night](https://git.sr.ht/~maxmj/makeover/tree/main/item/themes/akari-night.toml)**. Both are based on Shu Kutsuzawa's [Akari](https://github.com/cappyzawa/akari-theme) (MIT). Users pick a mode at startup (`--theme` flag or `$COLORFGBG` / OSC background query); users can also drop any makeover `.toml` into `~/.config/alloy/themes/` and pass its name to swap.
49 49
50 - **Why theme-common as the storage format:** the future user-facing theme catalog (a website of downloadable `.toml` files) is only useful if every make-family app renders any downloaded theme the same way. Sharing the format across apps buys that with zero adapter code.
50 + **Why makeover as the storage format:** the future user-facing theme catalog (a website of downloadable `.toml` files) is only useful if every make-family app renders any downloaded theme the same way. Sharing the format across apps buys that with zero adapter code.
51 51
52 52 ## Alloy-specific derived tokens
53 53
54 - Alloy needs three token tiers theme-common ships one of: `border-subtle`, `border`, `border-strong`. Rather than extend the schema (which would break existing consumers), Alloy computes the outer two from `line.border` at load time:
54 + Alloy needs three token tiers makeover ships one of: `border-subtle`, `border`, `border-strong`. Rather than extend the schema (which would break existing consumers), Alloy computes the outer two from `line.border` at load time:
55 55
56 56 ```
57 57 border-subtle = mix(line.border, surface.page, 60%) # pulled toward surface — decorative divider
@@ -74,12 +74,12 @@
74 74
75 75 ## Gate: the WCAG audit
76 76
77 - Any theme, downloaded or authored, is audited by [`tools/wcag_audit.py`](../tools/wcag_audit.py). It reads a theme-common `.toml`, converts hex to linear sRGB to WCAG 2.1 relative luminance, and reports pass/fail for every affordance-carrying pair (text-on-surface, borders-on-surface, accents-on-surface, elevation deltas). Also computes `border-subtle` / `border-strong` via the same derivation Alloy uses at runtime.
77 + Any theme, downloaded or authored, is audited by [`tools/wcag_audit.py`](../tools/wcag_audit.py). It reads a makeover `.toml`, converts hex to linear sRGB to WCAG 2.1 relative luminance, and reports pass/fail for every affordance-carrying pair (text-on-surface, borders-on-surface, accents-on-surface, elevation deltas). Also computes `border-subtle` / `border-strong` via the same derivation Alloy uses at runtime.
78 78
79 79 Run:
80 80
81 81 ```
82 - python3 tools/wcag_audit.py MNW/shared/themes/akari-dawn.toml
82 + python3 tools/wcag_audit.py ../Libraries/makeover/themes/akari-dawn.toml
83 83 ```
84 84
85 85 The audit is not a hard-fail gate: a theme with accents that only reach AA-UI on some surface tiers is still shippable if the accent-on-glyph rule is honored. The audit's job is to make trade-offs visible.
@@ -133,9 +133,9 @@
133 133
134 134 ## How this file is consumed
135 135
136 - Themes at [`MNW/shared/themes/*.toml`](../../MNW/shared/themes/) are the ground truth. `alloy_tui` at load time:
136 + The themes [makeover ships](https://git.sr.ht/~maxmj/makeover/tree/main/item/themes/) are the ground truth. `alloy_tui` at load time:
137 137
138 - 1. Reads the selected theme file via the `theme_common` crate.
138 + 1. Reads the selected theme file via the `makeover` crate.
139 139 2. Computes the two derived tokens (`border-subtle`, `border-strong`) from `line.border`.
140 140 3. Exposes the full token map as a runtime `Theme` of ratatui `Style` / `Color` values.
141 141 4. Optionally emits a 256-color fallback table for terminals without truecolor.
@@ -1,20 +1,20 @@
1 1 #!/usr/bin/env python3
2 - """WCAG 2.1 contrast audit for theme-common theme files.
2 + """WCAG 2.1 contrast audit for makeover theme files.
3 3
4 - Reads any theme-common .toml (surface/content/action/status/line/
4 + Reads any makeover .toml (surface/content/action/status/line/
5 5 category sections), converts hex to WCAG 2.1 relative luminance,
6 6 and reports pass/fail against AA-text (>= 4.5) and AA-UI (>= 3.0)
7 7 for every affordance-carrying token pair.
8 8
9 9 Also computes Alloy's derived tokens (border-subtle, border-strong)
10 - via mix formulas and audits those too, so a theme-common file that
10 + via mix formulas and audits those too, so a makeover file that
11 11 was authored without Alloy's discipline still gets a full report.
12 12
13 13 Usage:
14 14 python3 tools/wcag_audit.py <path/to/theme.toml>
15 15
16 16 Example:
17 - python3 tools/wcag_audit.py ../../MNW/shared/themes/akari-dawn.toml
17 + python3 tools/wcag_audit.py https://git.sr.ht/~maxmj/makeover/tree/main/item/themes/akari-dawn.toml
18 18 """
19 19 import sys
20 20 import os
@@ -77,11 +77,11 @@
77 77 # ---------------------------------------------------------------- derivation
78 78
79 79 def derive(theme):
80 - """Compute Alloy's extended tokens from a theme-common theme.
80 + """Compute Alloy's extended tokens from a makeover theme.
81 81
82 - theme-common ships one border tone (line.border); Alloy renders
82 + makeover ships one border tone (line.border); Alloy renders
83 83 three tiers via mix. Formula lives here (not in the theme file)
84 - so any theme-common .toml downloaded from the wild gets a full
84 + so any makeover .toml downloaded from the wild gets a full
85 85 Alloy-shaped token map.
86 86 """
87 87 border = theme["line"]["border"]
@@ -19,4 +19,4 @@
19 19 ratatui.workspace = true
20 20 serde = { version = "1.0.229", features = ["derive"] }
21 21 serde_json = "1.0.150"
22 - theme-common.workspace = true
22 + makeover.workspace = true
@@ -1,7 +1,7 @@
1 1 [package]
2 2 name = "alloy_tui"
3 3 version = "0.0.0"
4 - description = "Alloy design system: theme-common intents rendered as ratatui Color/Style, plus themed widgets for the alloy console and siblings."
4 + description = "Alloy design system: makeover intents rendered as ratatui Color/Style, plus themed widgets for the alloy console and siblings."
5 5 edition.workspace = true
6 6 rust-version.workspace = true
7 7 license.workspace = true
@@ -10,4 +10,4 @@
10 10
11 11 [dependencies]
12 12 ratatui.workspace = true
13 - theme-common.workspace = true
13 + makeover.workspace = true