| Crates.io | egui-thematic |
| lib.rs | egui-thematic |
| version | 0.1.1 |
| created_at | 2025-12-14 06:48:53.300851+00 |
| updated_at | 2025-12-14 06:53:48.200651+00 |
| description | A theme editor and configuration system for egui applications with live preview, preset management, random theme generation, and persistence. |
| homepage | https://github.com/matthewjberger/egui-thematic |
| repository | https://github.com/matthewjberger/egui-thematic |
| max_upload_size | |
| id | 1983928 |
| size | 169,621 |
A theme editor and configuration system for egui applications with live preview, preset management, random theme generation, and persistence.
Complete Theme Configuration: Full control over all 73 egui visual properties
Two-Level Interface:
Live Preview Window: Separate window shows changes instantly with Apply/Revert buttons
Smart Global Controls: Automatically detect when widget states have mixed values
9 Built-in Presets: Dark, Light, Dracula, Nord, Gruvbox, Solarized (Dark/Light), Monokai, One Dark, Tokyo Night, Catppuccin Mocha
Random Theme Generation: Generate completely random themes with a single click for exploration and inspiration
Code Export: Export themes as JSON or Rust code for easy integration
Persistence: Save and load themes to/from JSON files for easy sharing and reuse
Add this to your Cargo.toml:
[dependencies]
egui-thematic = "0.1.1" # supports egui 0.33.0
Add egui-thematic to your egui application, here's an example using the nightshade game engine:
Cargo.toml:
[dependencies]
nightshade = "0.6.7"
egui-thematic = "0.1.1"
main.rs:
use egui_thematic::{render_theme_panel, ThemeEditorState};
use nightshade::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
launch(ThemeEditorDemo::default())?;
Ok(())
}
#[derive(Default)]
struct ThemeEditorDemo {
theme_editor_state: ThemeEditorState,
show_theme_editor: bool,
}
impl State for ThemeEditorDemo {
fn title(&self) -> &str {
"egui-thematic Demo"
}
fn initialize(&mut self, world: &mut World) {
world.resources.user_interface.enabled = true;
self.show_theme_editor = true;
}
fn ui(&mut self, _world: &mut World, ui_context: &egui::Context) {
render_theme_panel(
ui_context,
&mut self.theme_editor_state,
&mut self.show_theme_editor,
);
egui::TopBottomPanel::top("top_panel").show(ui_context, |ui| {
ui.horizontal(|ui| {
if ui.button("Toggle Theme Editor").clicked() {
self.show_theme_editor = !self.show_theme_editor;
}
});
});
}
fn on_keyboard_input(&mut self, world: &mut World, key_code: KeyCode, key_state: KeyState) {
if matches!((key_code, key_state), (KeyCode::KeyQ, KeyState::Pressed)) {
world.resources.window.should_exit = true;
}
}
}
use egui_thematic::ThemeConfig;
// Use built-in presets
let dark_theme = ThemeConfig::dark_preset();
let light_theme = ThemeConfig::light_preset();
// Apply to egui context
ctx.set_visuals(dark_theme.to_visuals());
use egui_thematic::ThemeConfig;
use std::path::Path;
// Save theme to file
let theme = ThemeConfig::dark_preset();
theme.save_to_file(Path::new("my_theme.theme.json"))?;
// Load theme from file
let loaded_theme = ThemeConfig::load_from_file(Path::new("my_theme.theme.json"))?;
use egui_thematic::ThemeConfig;
// Generate a completely random theme
let random_theme = ThemeConfig::randomize();
// Apply it
ctx.set_visuals(random_theme.to_visuals());
The randomize feature can be used for:
A demo application is included that showcases the features of egui-thematic.
Using just:
just run
Or directly with cargo:
cargo run --release --manifest-path ./demo/Cargo.toml
The demo includes:
Using justfile for convenience:
just run - Run the demo application in release modejust build - Build the crate in release modejust check - Run cargo check and format verificationjust format - Format all code with rustfmtjust fix - Run clippy with auto-fixesjust lint - Run clippy with warnings as errorsjust test - Run all testsjust versions - Display tool versionsThe ThemeConfig struct provides complete control over all 73 egui visual properties:
pub struct ThemeConfig {
pub name: String,
pub dark_mode: bool,
// Text colors (2 properties)
pub override_text_color: Option<[u8; 4]>,
pub override_weak_text_color: Option<[u8; 4]>,
// Windows (5 properties)
pub override_window_fill: Option<[u8; 4]>,
pub override_window_stroke_color: Option<[u8; 4]>,
pub override_window_stroke_width: Option<f32>,
pub override_window_corner_radius: Option<u8>,
pub override_window_shadow_size: Option<u8>,
// Panels (1 property)
pub override_panel_fill: Option<[u8; 4]>,
// Selection (3 properties)
pub override_selection_bg: Option<[u8; 4]>,
pub override_selection_stroke_color: Option<[u8; 4]>,
pub override_selection_stroke_width: Option<f32>,
// Widget States (5 states × 8 properties = 40 properties)
// Each state has: bg_fill, weak_bg_fill, bg_stroke (color + width),
// corner_radius, fg_stroke (color + width), expansion
pub override_widget_noninteractive_*: Option<...>,
pub override_widget_inactive_*: Option<...>,
pub override_widget_hovered_*: Option<...>,
pub override_widget_active_*: Option<...>,
pub override_widget_open_*: Option<...>,
// UI Controls (8 properties)
pub override_resize_corner_size: Option<f32>,
pub override_text_cursor_width: Option<f32>,
pub override_clip_rect_margin: Option<f32>,
pub override_button_frame: Option<bool>,
pub override_collapsing_header_frame: Option<bool>,
pub override_indent_has_left_vline: Option<bool>,
pub override_striped: Option<bool>,
pub override_slider_trailing_fill: Option<bool>,
}
All overrides are optional - when None, egui's default values for the selected mode (dark/light) are used. This allows for:
Licensed under the MIT License. See LICENSE for details.