# tachyonfx
[](https://crates.io/crates/tachyonfx)
[](https://docs.rs/tachyonfx)
[](https://github.com/junkdog/tachyonfx/blob/main/LICENSE)
[](https://crates.io/crates/tachyonfx)
[](https://deps.rs/repo/github/junkdog/tachyonfx)
A [ratatui][ratatui] library for creating shader-like effects in terminal UIs. Build complex animations by composing and layering simple effects, bringing smooth transitions and visual polish to the terminal.

## ✨ Features
- **25 unique effects** — color transformations, text animations, geometric distortions, plus support for custom effects
- **Shader-like API** — effects operate on rendered cells, allowing complex visual transformations
- **Effect composition** — chain and combine effects for sophisticated animations
- **Interactive browser editor** — design and preview effects in real-time with [TachyonFX FTL][tfx-ftl]
- **Runtime effect compilation** — create effects from strings using the built-in DSL
- **Cell-precise targeting** — apply effects to specific regions or cells matching custom criteria
## 🚀 Quick Start
Add tachyonfx to your `Cargo.toml`:
```bash
cargo add tachyonfx
```
Create your first effect:
```rust
use std::{io, time::Instant};
use ratatui::{crossterm::event, prelude::*, widgets::Paragraph};
use tachyonfx::{fx, EffectManager, Interpolation};
fn main() -> io::Result<()> {
let mut terminal = ratatui::init();
let mut effects: EffectManager<()> = EffectManager::default();
// Add a simple fade-in effect
let fx = fx::fade_to(Color::Cyan, Color::Gray, (1_000, Interpolation::SineIn));
effects.add_effect(fx);
let mut last_frame = Instant::now();
loop {
let elapsed = last_frame.elapsed();
last_frame = Instant::now();
terminal.draw(|frame| {
let screen_area = frame.area();
// Render your content
let text = Paragraph::new("Hello, TachyonFX!").alignment(Alignment::Center);
frame.render_widget(text, screen_area);
// Apply effects
effects.process_effects(elapsed.into(), frame.buffer_mut(), screen_area);
})?;
// Exit on any key press
if event::poll(std::time::Duration::from_millis(16))? {
if let event::Event::Key(_) = event::read()? {
break;
}
}
}
ratatui::restore();
Ok(())
}
```
## 📸 Examples
Explore the examples to see effects in action:
```bash
# Basic effects showcase
cargo run --example basic-effects
# Interactive DSL playground
cargo run --example dsl-playground
# Effect timeline visualization
cargo run --example fx-chart
# Minimal setup example
cargo run --example minimal
```
## 🎯 Getting Started
### Try it in your browser
[TachyonFX FTL][tfx-ftl] is a browser-based editor for creating and tweaking effects in real-time.
### Basic Concepts
1. **Effects are stateful** — Create once, apply every frame
2. **Effects transform rendered content** — Apply after widgets render
3. **Effects compose** — Build complex animations from simple pieces
### Simple Example: Fade In
```rust
use tachyonfx::{fx, Effect, CellFilter};
// Create a fade-in effect
let mut fade = fx::fade_from(Color::Black, Color::White,
EffectTimer::from_ms(500, QuadOut));
// Apply to red text only
fade.set_cell_filter(CellFilter::FgColor(Color::Red));
// In your render loop
fade.process(delta_time, buf, area);
```
### Combining Effects
```rust
// Run multiple effects in parallel
let effects = fx::parallel(&[
fx::fade_from_fg(Color::Red, 500),
fx::slide_in(Direction::LeftToRight, 800),
]);
// Or sequence them
let effects = fx::sequence(&[
fx::fade_from_fg(Color::Black, 300),
fx::coalesce(500),
]);
```
### Using the DSL
Create effects from strings at runtime:
```rust
use tachyonfx::dsl::EffectDsl;
let effect = EffectDsl::new()
.compiler()
.compile("fx::dissolve(500)")
.expect("valid effect");
```
## 📦 Effect Reference
### Color Effects
Transform colors over time for smooth transitions.
- `fade_from` / `fade_to` — Transition colors
- `fade_from_fg` / `fade_to_fg` — Foreground color transitions
- `hsl_shift` — Animate through HSL color space
- `term256_colors` — Downsample to 256-color mode
### Text & Motion Effects
Animate text and cell positions for dynamic content.
- `coalesce` / `dissolve` — Text materialization effects
- `slide_in` / `slide_out` — Directional sliding animations
- `sweep_in` / `sweep_out` — Color sweep transitions
- `explode` — Particle dispersion effect
### Control Effects
Fine-tune timing and behavior.
- `parallel` — Run multiple effects simultaneously
- `sequence` — Chain effects one after another
- `repeat` — Loop effects with optional limits
- `ping_pong` — Play forward then reverse
- `with_duration` — Override effect duration
### Geometry Effects
Transform positions and layout.
- `translate` — Move content by offset
- `resize_area` — Scale effect bounds
- `translate_buf` — Copy and move buffer content
## 🔧 Advanced Features
### Cell Filtering
Apply effects selectively:
```rust
// Only apply to cells with specific colors
fx::dissolve(500)
.with_filter(CellFilter::FgColor(Color::Red))
// Target specific regions
let filter = CellFilter::AllOf(vec![
CellFilter::Outer(Margin::new(1, 1)),
CellFilter::Text,
]);
```
### Custom Effects
Create your own effects:
```rust
timer.progress()
})
```
Alternatively, implement the `Shader` trait and use it together with `.into_effect()`.
### Effect DSL
The DSL supports:
- Most built-in effects (excludes: `effect_fn`, `effect_fn_buf`, `glitch`, `offscreen_buffer`, `resize_area`, `translate`, `translate_buf`)
- Variable bindings
- Method chaining
- Complex compositions
```rust
let expr = r#"
let duration = 300;
fx::sequence(&[
fx::fade_from(black, white, duration),
fx::dissolve(duration)
])
"#;
```
## 🛠️ Configuration
### Features
- `dsl` — Effect DSL support (enabled by default)
- `sendable` — Make effects `Send` (but not `Sync`)
- `std-duration` — Use `std::time::Duration` instead of 32-bit custom type
- `web-time` — WebAssembly compatibility
## 🤝 Contributing
Contributions welcome! Please check existing issues or create new ones to discuss changes.
## 📝 License
MIT License - see [LICENSE](LICENSE) for details.
[ratatui]: https://ratatui.rs/
[tfx-ftl]: https://junkdog.github.io/tachyonfx-ftl/