Skip to main content

tui_vfx_shadow/
lib.rs

1// <FILE>crates/tui-vfx-shadow/src/lib.rs</FILE> - <DESC>Shadow rendering effects for TUI applications</DESC>
2// <VERS>VERSION: 0.3.0</VERS>
3// <WCTX>Phase 0 dramatic color-shadow rollout: re-export compositing mode and grade config</WCTX>
4// <CLOG>Add ShadowCompositeMode and ShadowGradeConfig to crate-root re-exports and update crate docs</CLOG>
5
6//! # TUI VFX Shadow
7//!
8//! Shadow rendering effects for terminal user interfaces.
9//!
10//! This crate provides theme-aware shadow rendering with multiple styles,
11//! configurable offsets, edge selection, and animation support.
12//!
13//! ## Features
14//!
15//! - **Multiple shadow styles**: HalfBlock, Braille, MediumShade, Solid, and Gradient
16//! - **Sub-cell precision**: Half-block characters provide smooth shadow edges
17//! - **Configurable offsets**: Position shadows in any direction (±x, ±y)
18//! - **Edge selection**: Render shadows on specific edges (top, bottom, left, right)
19//! - **Animation support**: Animate shadows in/out with progress parameter
20//! - **Theme integration**: Works with any color from your theme system
21//!
22//! ## Architecture & Pipeline Position
23//!
24//! Shadows are rendered **before** the element they belong to, following the
25//! standard rendering order:
26//!
27//! ```text
28//! 1. Background layer (surface color)
29//! 2. Shadow layer        ← render_shadow() goes here
30//! 3. Element layer       ← your UI element
31//! 4. Compositor effects  ← wipes, dissolves, fades, etc.
32//! ```
33//!
34//! This ensures shadows appear "behind" elements and can be animated
35//! independently using the compositor pipeline.
36//!
37//! ## Quick Start
38//!
39//! ```
40//! use tui_vfx_shadow::{render_shadow, ShadowConfig, ShadowEdges, ShadowStyle};
41//! use tui_vfx_types::{Color, OwnedGrid, Rect};
42//!
43//! // Create a grid to render into
44//! let mut grid = OwnedGrid::new(40, 20);
45//!
46//! // Define the element that casts the shadow
47//! let element_rect = Rect::new(10, 5, 15, 8);
48//!
49//! // Configure the shadow
50//! let config = ShadowConfig::new(Color::BLACK.with_alpha(128))
51//!     .with_offset(2, 1)
52//!     .with_style(ShadowStyle::HalfBlock)
53//!     .with_edges(ShadowEdges::BOTTOM_RIGHT)
54//!     .with_soft_edges(true);
55//!
56//! // Render the shadow (progress=1.0 for full shadow)
57//! render_shadow(&mut grid, element_rect, &config, 1.0);
58//! ```
59//!
60//! ## Shadow Styles
61//!
62//! ### Style Comparison
63//!
64//! | Style | Characters | Sub-cell | Compatibility | Best For |
65//! |-------|------------|----------|---------------|----------|
66//! | HalfBlock | ▐▄▌▀ | Yes (2x) | Good | Default, most UIs |
67//! | Braille | ⣿⡇⠿ | Yes (2x4) | Variable | Dithered effects |
68//! | MediumShade | ▒ | No | Good | Textured full-cell shade |
69//! | Solid | (space) | No | Excellent | Maximum compat |
70//! | Gradient | (space) | No | Excellent | Soft drop shadows |
71//!
72//! ### HalfBlock (Default)
73//!
74//! Uses Unicode half-block characters for sub-cell precision. The shadow
75//! edge uses half-block characters with `fg=shadow_color` and `bg=surface_color`,
76//! while the shadow interior uses solid background color.
77//!
78//! ```text
79//! ┌──────────┐
80//! │  Modal   │▐░░
81//! │  Window  │▐░░
82//! └──────────┘▐░░
83//!  ▄▄▄▄▄▄▄▄▄▄▄░░
84//!
85//! ▐ = RIGHT_HALF (soft edge)
86//! ▄ = LOWER_HALF (soft edge)
87//! ░ = solid shadow cells
88//! ```
89//!
90//! ```
91//! use tui_vfx_shadow::{ShadowConfig, ShadowStyle};
92//! use tui_vfx_types::Color;
93//!
94//! let config = ShadowConfig::new(Color::BLACK.with_alpha(128))
95//!     .with_style(ShadowStyle::HalfBlock)
96//!     .with_soft_edges(true)   // Use half-blocks at shadow boundary
97//!     .with_surface_color(Color::rgb(40, 40, 50));  // Background for blending
98//! ```
99//!
100//! ### Braille
101//!
102//! Uses braille patterns (U+2800-U+28FF) for dithered shadows. Each character
103//! provides a 2x4 subpixel grid (8 dots), allowing fine-grained density control.
104//!
105//! ```text
106//! Density mapping:
107//! 0.0 → ⠀ (empty)
108//! 0.25 → ⠃
109//! 0.5  → ⡇
110//! 0.75 → ⣷
111//! 1.0  → ⣿ (full)
112//! ```
113//!
114//! ```
115//! use tui_vfx_shadow::{ShadowConfig, ShadowStyle};
116//! use tui_vfx_types::Color;
117//!
118//! let config = ShadowConfig::new(Color::BLACK.with_alpha(200))
119//!     .with_style(ShadowStyle::braille(0.7)); // 70% density
120//! ```
121//!
122//! **Note:** Braille rendering depends on terminal font support. Some fonts
123//! may not render braille characters at the expected size.
124//!
125//! ### MediumShade
126//!
127//! Uses the Unicode medium shade character (`▒`) for a textured full-cell shadow.
128//! This style avoids braille dot patterns while retaining visual grain.
129//!
130//! ```
131//! use tui_vfx_shadow::{ShadowConfig, ShadowStyle};
132//! use tui_vfx_types::Color;
133//!
134//! let config = ShadowConfig::new(Color::BLACK.with_alpha(180))
135//!     .with_style(ShadowStyle::MediumShade);
136//! ```
137//!
138//! ### Solid
139//!
140//! The simplest style - fills shadow cells with solid background color.
141//! Maximum compatibility but no sub-cell precision.
142//!
143//! ```
144//! use tui_vfx_shadow::{ShadowConfig, ShadowStyle};
145//! use tui_vfx_types::Color;
146//!
147//! let config = ShadowConfig::new(Color::BLACK.with_alpha(100))
148//!     .with_style(ShadowStyle::Solid);
149//! ```
150//!
151//! ### Gradient
152//!
153//! Multi-layer shadows with progressively lighter colors. Each layer extends
154//! further from the element with decreasing intensity.
155//!
156//! ```text
157//! Layer 1 (closest):  alpha = base_alpha * 1.0
158//! Layer 2:            alpha = base_alpha * 0.67
159//! Layer 3 (furthest): alpha = base_alpha * 0.33
160//! ```
161//!
162//! ```
163//! use tui_vfx_shadow::{ShadowConfig, ShadowStyle};
164//! use tui_vfx_types::Color;
165//!
166//! let config = ShadowConfig::new(Color::BLACK.with_alpha(200))
167//!     .with_offset(1, 1)
168//!     .with_style(ShadowStyle::gradient(3)); // 3 gradient layers
169//! ```
170//!
171//! ## Edge Configuration
172//!
173//! Control which edges of the element cast shadows using [`ShadowEdges`]:
174//!
175//! ```
176//! use tui_vfx_shadow::ShadowEdges;
177//!
178//! // Common configurations
179//! let drop_shadow = ShadowEdges::BOTTOM_RIGHT;  // Standard drop shadow
180//! let all_sides = ShadowEdges::ALL;             // Shadow on all edges
181//! let custom = ShadowEdges::RIGHT | ShadowEdges::BOTTOM | ShadowEdges::TOP;
182//! ```
183//!
184//! Edge rendering depends on offset direction:
185//! - **RIGHT** edge: only rendered when `offset_x > 0`
186//! - **BOTTOM** edge: only rendered when `offset_y > 0`
187//! - **LEFT** edge: only rendered when `offset_x < 0`
188//! - **TOP** edge: only rendered when `offset_y < 0`
189//!
190//! ## Offset Configuration
191//!
192//! The offset determines shadow position relative to the element:
193//!
194//! ```
195//! use tui_vfx_shadow::ShadowConfig;
196//! use tui_vfx_types::Color;
197//!
198//! // Standard drop shadow (down-right)
199//! let config = ShadowConfig::new(Color::BLACK.with_alpha(128))
200//!     .with_offset(2, 1);  // 2 cells right, 1 cell down
201//!
202//! // Inverted shadow (up-left)
203//! let config = ShadowConfig::new(Color::BLACK.with_alpha(128))
204//!     .with_offset(-1, -1);  // 1 cell left, 1 cell up
205//!
206//! // Horizontal-only shadow
207//! let config = ShadowConfig::new(Color::BLACK.with_alpha(128))
208//!     .with_offset(2, 0);  // 2 cells right, no vertical offset
209//! ```
210//!
211//! ## Animation Support
212//!
213//! The `progress` parameter (0.0 to 1.0) controls shadow intensity, enabling
214//! smooth fade-in/fade-out animations:
215//!
216//! ```
217//! use tui_vfx_shadow::{render_shadow, ShadowConfig};
218//! use tui_vfx_types::{Color, OwnedGrid, Rect};
219//!
220//! let mut grid = OwnedGrid::new(40, 20);
221//! let rect = Rect::new(10, 5, 15, 8);
222//! let config = ShadowConfig::new(Color::BLACK.with_alpha(200));
223//!
224//! // Animate shadow from 0% to 100% over time
225//! for frame in 0..60 {
226//!     let progress = frame as f64 / 60.0;
227//!     render_shadow(&mut grid, rect, &config, progress);
228//! }
229//! ```
230//!
231//! The progress value interpolates the shadow color's alpha channel:
232//! - `progress = 0.0`: shadow alpha = 0 (invisible)
233//! - `progress = 0.5`: shadow alpha = base_alpha * 0.5
234//! - `progress = 1.0`: shadow alpha = base_alpha (full)
235//!
236//! ## Integration Patterns
237//!
238//! ### With the TUI-VFX Compositor
239//!
240//! Shadows render directly to the grid before compositor effects are applied:
241//!
242//! ```ignore
243//! use tui_vfx::prelude::*;
244//!
245//! // 1. Clear or prepare your destination grid
246//! dest.fill(Cell::default());
247//!
248//! // 2. Render shadow first
249//! render_shadow(&mut dest, modal_rect, &shadow_config, animation_progress);
250//!
251//! // 3. Render your element (modal, popup, etc.)
252//! render_modal(&mut dest, modal_rect, &theme);
253//!
254//! // 4. Apply compositor effects (wipe reveal, dissolve, etc.)
255//! render_pipeline(&source, &mut dest, width, height, 0, 0, compositor_options, None);
256//! ```
257//!
258//! ### With Theme Systems
259//!
260//! Create shadow configs from theme definitions:
261//!
262//! ```ignore
263//! // Example theme-driven shadow configuration
264//! fn shadow_from_theme(theme: &Theme) -> ShadowConfig {
265//!     ShadowConfig::new(theme.shadow.color)
266//!         .with_offset(theme.shadow.offset_x, theme.shadow.offset_y)
267//!         .with_surface_color(theme.surface.background)
268//!         .with_style(match theme.shadow.style {
269//!             "braille" => ShadowStyle::braille(theme.shadow.density),
270//!             "medium_shade" => ShadowStyle::MediumShade,
271//!             "gradient" => ShadowStyle::gradient(theme.shadow.layers),
272//!             "solid" => ShadowStyle::Solid,
273//!             _ => ShadowStyle::HalfBlock,
274//!         })
275//! }
276//! ```
277//!
278//! ### Synchronized with Modal Animations
279//!
280//! For modals with wipe animations, sync shadow progress with wipe progress:
281//!
282//! ```ignore
283//! fn render_modal_with_shadow(
284//!     grid: &mut impl Grid,
285//!     modal_rect: Rect,
286//!     shadow_config: &ShadowConfig,
287//!     wipe_progress: f64,  // 0.0 = closed, 1.0 = fully open
288//! ) {
289//!     // Shadow fades in with the modal
290//!     render_shadow(grid, modal_rect, shadow_config, wipe_progress);
291//!
292//!     // Modal content rendered separately with wipe mask...
293//! }
294//! ```
295//!
296//! ## Performance Considerations
297//!
298//! - **HalfBlock** and **Solid**: O(shadow_area) - linear in cells rendered
299//! - **Braille**: Same as HalfBlock, plus character lookup
300//! - **Gradient**: O(shadow_area × layers) - renders multiple overlapping layers
301//!
302//! For large shadows or performance-critical rendering:
303//! 1. Use **Solid** style for maximum speed
304//! 2. Limit **Gradient** layers to 2-3
305//! 3. Consider caching shadow renders for static elements
306//!
307//! ## Shadow Geometry vs Compositing
308//!
309//! Shadow geometry (style, offset, edges) and shadow compositing mode are
310//! independently configurable. Geometry controls where and how shadow cells
311//! are rendered; compositing mode controls how those cells are applied onto
312//! destination content. See [`ShadowCompositeMode`] for available modes.
313//!
314//! ## Module Structure
315//!
316//! - [`render_shadow`] - Main entry point for shadow rendering
317//! - [`render_shadow_simple`] - Convenience function with defaults
318//! - [`ShadowConfig`] - Configuration struct with builder pattern
319//! - [`ShadowStyle`] - Enum of rendering styles
320//! - [`ShadowCompositeMode`] - Compositing mode (glyph overlay vs grade underlying)
321//! - [`ShadowGradeConfig`] - Color grading parameters for grade-underlying mode
322//! - [`ShadowEdges`] - Bitflags for edge selection
323//! - [`renderers`] - Direct access to individual renderer implementations
324
325mod fnc_render_shadow;
326pub mod renderers;
327pub mod types;
328
329// Re-export main functions
330pub use fnc_render_shadow::{render_shadow, render_shadow_gradient_colors, render_shadow_simple};
331
332// Re-export types at crate root for convenience
333pub use types::{ShadowCompositeMode, ShadowConfig, ShadowEdges, ShadowGradeConfig, ShadowStyle};
334
335// Re-export renderers for direct access if needed
336pub use renderers::{
337    BrailleRenderer, GradientRenderer, HalfBlockRenderer, MediumShadeRenderer, SolidRenderer,
338};
339
340// <FILE>crates/tui-vfx-shadow/src/lib.rs</FILE> - <DESC>Shadow rendering effects for TUI applications</DESC>
341// <VERS>END OF VERSION: 0.3.0</VERS>