<h1 align="center">
<br>
โฆ opaline
<br>
</h1>
<p align="center">
<strong>A token-based theme engine for Ratatui TUI applications</strong><br>
<sub>20 builtin themes · semantic tokens · multi-stop gradients · zero unsafe</sub>
</p>
<p align="center">
<a href="https://crates.io/crates/opaline">
<img src="https://img.shields.io/crates/v/opaline.svg?style=for-the-badge&logo=rust&logoColor=white&color=e135ff" alt="Crates.io">
</a>
<a href="https://docs.rs/opaline">
<img src="https://img.shields.io/docsrs/opaline?style=for-the-badge&logo=docs.rs&logoColor=white&color=80ffea" alt="docs.rs">
</a>
<a href="https://github.com/hyperb1iss/opaline/actions">
<img src="https://img.shields.io/github/actions/workflow/status/hyperb1iss/opaline/ci.yml?style=for-the-badge&logo=github-actions&logoColor=white&color=4C566A" alt="CI">
</a>
<a href="#-builtin-themes">
<img src="https://img.shields.io/badge/Themes-20_Built--in-ff6ac1?style=for-the-badge&logo=palette&logoColor=white" alt="20 Themes">
</a>
<a href="https://opensource.org/licenses/MIT">
<img src="https://img.shields.io/badge/License-MIT-50fa7b?style=for-the-badge&logoColor=white" alt="License">
</a>
</p>
<p align="center">
<a href="https://hyperb1iss.github.io/opaline/">Docs</a> •
<a href="https://hyperb1iss.github.io/opaline/llms.txt">llms.txt</a> •
<a href="#-quick-start">Quick Start</a> •
<a href="#-features">Features</a> •
<a href="#-builtin-themes">Themes</a> •
<a href="#-usage">Usage</a> •
<a href="#-custom-themes">Custom Themes</a> •
<a href="#-contributing">Contributing</a>
</p>
---
<div align="center">
<img src="https://raw.githubusercontent.com/hyperb1iss/opaline/main/docs/images/showcase-silkcircuit-neon.png" alt="SilkCircuit Neon" width="49%">
<img src="https://raw.githubusercontent.com/hyperb1iss/opaline/main/docs/images/showcase-silkcircuit-dawn.png" alt="SilkCircuit Dawn" width="49%">
</div>
<p align="center"><em>SilkCircuit Neon (dark) and SilkCircuit Dawn (light) โ two of 20 builtin themes</em></p>
---
## ๐ What is Opaline?
Opaline is a **theme engine** that brings consistent, beautiful color to [Ratatui](https://ratatui.rs) terminal applications. Instead of scattering hex codes across your codebase, you define themes as TOML files with a **palette โ token โ style โ gradient** resolution pipeline. Switch themes at runtime with a single call โ every widget updates instantly.
```
TOML file โ ThemeFile (serde) โ Resolver (palette โ tokens โ styles โ gradients) โ Theme
```
Opaline ships with **20 professionally crafted themes** spanning 8 colorscheme families, all enforced by a strict contract test suite that validates 40+ semantic tokens, 18 styles, and 5 gradients per theme.
## โฆ Features
| ๐จ **20 Builtin Themes** | SilkCircuit, Catppuccin, Dracula, Nord, Rose Pine, Gruvbox, Solarized, Tokyo Night, Kanagawa, Everforest, One Dark |
| ๐ **Semantic Tokens** | 40+ tokens across `text.*`, `bg.*`, `accent.*`, `git.*`, `diff.*`, `code.*` namespaces |
| ๐ **Multi-Stop Gradients** | Smooth color interpolation with `gradient_bar()`, `gradient_text_line()`, and `gradient_spans()` |
| ๐ฅ๏ธ **Deep Ratatui Integration** | `From` impls, `Styled` trait, inherent `span()`, `line()`, `text()`, `gradient_text()` on `Theme` |
| ๐๏ธ **ThemeSelector Widget** | Drop-in theme picker with live preview, search filtering, and cancel/restore |
| ๐ฌ **Color Manipulation** | `darken()`, `lighten()`, `desaturate()` for deriving colors from theme palettes |
| ๐๏ธ **ThemeBuilder** | Programmatic theme construction without TOML โ perfect for runtime customization |
| ๐งฉ **App-Level Derivation** | Register app-specific tokens/styles with `register_default_token()` โ TOML overrides respected |
| ๐ **Theme Discovery** | Scan `~/.config/` for user themes, list metadata for picker UIs |
| ๐ **Global State** | Optional process-wide `current()`/`set_theme()` behind a feature flag |
| ๐ก๏ธ **Strict Resolution** | Cycle detection, unresolvable token errors, compile-time theme validation |
| ๐จ๏ธ **CLI Adapter** | `colored` crate integration for ANSI terminal output outside of Ratatui |
| โก **Zero Cost Builtins** | Themes embedded via `include_str!` at compile time โ no file I/O at runtime |
## โก Quick Start
Add opaline to your `Cargo.toml`:
```toml
[dependencies]
opaline = "0.1"
```
Load a theme and start styling:
```rust
use opaline::load_by_name;
// Load any of 20 builtin themes
let theme = load_by_name("catppuccin-mocha").expect("theme exists");
// Use semantic colors and styles in your Ratatui widgets
let style = theme.style("keyword"); // bold accent color
let color = theme.color("accent.primary"); // OpalineColor
let span = theme.span("file_path", "src/main.rs"); // styled Span
```
### Run the interactive demo
```bash
cargo run --example theme-showcase
```
Browse all 20 themes, see every style and gradient rendered in real-time.
## ๐จ Builtin Themes
<div align="center">
<img src="https://raw.githubusercontent.com/hyperb1iss/opaline/main/docs/images/showcase-catppuccin-mocha.png" alt="Catppuccin Mocha" width="49%">
<img src="https://raw.githubusercontent.com/hyperb1iss/opaline/main/docs/images/showcase-rose-pine.png" alt="Rose Pine" width="49%">
</div>
<div align="center">
<img src="https://raw.githubusercontent.com/hyperb1iss/opaline/main/docs/images/showcase-catppuccin-latte.png" alt="Catppuccin Latte" width="49%">
<img src="https://raw.githubusercontent.com/hyperb1iss/opaline/main/docs/images/showcase-everforest-light.png" alt="Everforest Light" width="49%">
</div>
| **SilkCircuit** | Neon, Soft, Glow, Vibrant, Dawn | Electric meets elegant โ the signature design language |
| **Catppuccin** | Mocha, Latte | Soothing pastels for dark and light |
| **Rose Pine** | Base, Moon, Dawn | Botanical elegance across three variants |
| **Everforest** | Dark, Light | Warm green forest tones |
| **Tokyo Night** | Default, Storm | Neo-Tokyo neon aesthetic |
| **Dracula** | โ | The classic dark syntax theme |
| **Nord** | โ | Arctic, north-bluish clean |
| **Gruvbox** | Dark | Retro groove with warm contrast |
| **One Dark** | โ | Atom's iconic syntax palette |
| **Solarized** | Light | Precision colors for machines and people |
| **Kanagawa** | Wave | The great wave off Kanagawa |
Every theme is contract-tested: 40+ semantic tokens, 18 required styles, 5 required gradients.
## ๐ฎ Usage
### Colors and Styles
```rust
use opaline::Theme;
let theme = Theme::default(); // SilkCircuit Neon
// Semantic color access
let primary = theme.color("accent.primary");
let bg = theme.color("bg.base");
// Composed styles (fg + bg + modifiers)
let keyword = theme.style("keyword"); // bold accent
let error = theme.style("error_style"); // red foreground
let selected = theme.style("active_selected"); // accent on highlight bg
// Styled spans for inline text โ no trait import needed
let path = theme.span("file_path", "src/lib.rs");
let hash = theme.span("commit_hash", "a1b2c3d");
```
### Gradients
```rust
use opaline::{Theme, gradient_bar};
let theme = Theme::default();
// Render a gradient progress bar
if let Some(gradient) = theme.get_gradient("aurora") {
let bar = gradient_bar(40, 'โ', gradient); // Line with per-char colors
}
// Gradient-styled text (each character gets interpolated color)
let title = theme.gradient_text("primary", "Opaline Theme Engine");
```
### Theme Switching
```rust
use opaline::{list_available_themes, load_by_name};
// Enumerate all themes for a picker UI
let themes = list_available_themes();
for info in &themes {
println!("{} ({:?}) by {}", info.display_name, info.variant,
info.author.as_deref().unwrap_or("โ"));
}
// Hot-swap themes at runtime
let dracula = load_by_name("dracula").unwrap();
let nord = load_by_name("nord").unwrap();
```
### ThemeBuilder (Programmatic)
```rust
use opaline::ThemeBuilder;
let theme = ThemeBuilder::new("My Theme")
.palette("bg", "#1a1b26")
.palette("fg", "#c0caf5")
.palette("blue", "#7aa2f7")
.token("text.primary", "fg")
.token("bg.base", "bg")
.token("accent.primary", "blue")
.style("keyword", "accent.primary", None, true, false, false)
.build()
.expect("valid theme");
```
## ๐ช Custom Themes
Drop a `.toml` file in `src/builtins/` โ it's auto-discovered at compile time. Or load from any path at runtime.
```toml
[meta]
name = "My Theme"
author = "your name"
variant = "dark" # or "light"
description = "A custom theme"
[palette]
bg = "#1a1b26"
fg = "#c0caf5"
blue = "#7aa2f7"
purple = "#bb9af7"
[tokens]
"text.primary" = "fg"
"bg.base" = "bg"
"accent.primary" = "blue"
# ... 40+ tokens across text.*, bg.*, accent.*, git.*, diff.*, code.*, etc.
[styles]
keyword = { fg = "accent.primary", bold = true }
# ... 18 required styles
[gradients]
primary = ["blue", "purple"]
# ... 5 required gradients
```
The resolver validates everything at load time โ circular references, missing tokens, and invalid colors all produce clear error messages via `OpalineError`.
## โ๏ธ Feature Flags
| `builtin-themes` | โ | 20 embedded TOML themes via `include_str!` |
| `gradients` | โ | Multi-stop gradient interpolation |
| `ratatui` | โ | `From` impls, inherent `span()`/`line()`/`text()`/`gradient_text()` |
| `cli` | โ | `colored` crate adapter for ANSI output |
| `global-state` | โ | Process-wide `current()`/`set_theme()` |
| `discovery` | โ | Load user themes from `~/.config/` |
| `widgets` | โ | Theme selector widget with live preview |
## ๐๏ธ Architecture
```
TOML โ ThemeFile (serde) โ Resolver โ Theme
โ โ โ
โ palette โ โโโ color("token.name") โ OpalineColor
โ tokens โ โโโ style("style_name") โ OpalineStyle
โ styles โ โโโ gradient("name") โ Gradient
โ gradients โ โโโ meta (name, author, variant)
โ โ
โ โโโ palette โ token resolution
โ โโโ token โ style resolution
โ โโโ cycle detection
โ โโโ gradient stop resolution
```
| `OpalineColor` | RGB color with hex/tuple/array/u32 conversions + lerp + darken/lighten/desaturate |
| `OpalineStyle` | Composed style (fg, bg, 9 modifiers) with builder pattern |
| `Gradient` | Multi-stop color interpolation with `at(t)` and `generate(n)` |
| `Theme` | Fully resolved theme with `color()`, `style()`, `gradient()` accessors |
| `ThemeBuilder` | Programmatic theme construction without TOML |
| `ThemeInfo` | Metadata for theme discovery and picker UIs |
| `OpalineError` | Typed errors for IO, parsing, resolution, and validation failures |
## ๐งช Development
```bash
cargo check # Fast type check
cargo clippy --all-targets --all-features # Pedantic lint gate
cargo test --all-features # Full test suite (135 tests)
cargo doc --all-features --open # Generate docs
cargo run --example theme-showcase # Interactive TUI demo
```
Requires **Rust 1.85+** (Edition 2024). `unsafe_code = "forbid"`, `clippy::pedantic` deny.
## ๐ค Contributing
Contributions welcome! Adding a new builtin theme is as easy as dropping a `.toml` file in `src/builtins/` โ it's auto-discovered at compile time. Run `cargo test --all-features` to validate against the contract test suite.
## โ๏ธ License
Distributed under the MIT License. See `LICENSE` for details.
---
<div align="center">
๐ [Documentation](https://hyperb1iss.github.io/opaline/) ยท ๐ฆ [API Reference](https://docs.rs/opaline) ยท ๐ [Report Bug](https://github.com/hyperb1iss/opaline/issues) ยท ๐ก [Request Feature](https://github.com/hyperb1iss/opaline/issues)
</div>
<div align="center">
Created by [Stefanie Jane ๐ ](https://github.com/hyperb1iss)
If you find this useful, [buy me a Monster Ultra Violet](https://ko-fi.com/hyperb1iss)! โก๏ธ
</div>