You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/COMPARISON.md
+91Lines changed: 91 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -338,4 +338,95 @@ This gives you Spectre's polished formatting with SharpConsoleUI's window manage
338
338
339
339
---
340
340
341
+
## Rendering Architecture Deep Dive
342
+
343
+
TUI frameworks differ most fundamentally in how they turn a tree of controls into pixels on screen. This section explains where SharpConsoleUI sits and why the differences matter.
|**Immediate-mode**| Redraw entire UI into a single buffer each frame | Ratatui (Rust) |
351
+
|**Retained-mode, shared buffer**| Widget tree paints into one buffer with dirty tracking | Textual (Python), Terminal.Gui (.NET) |
352
+
|**Retained-mode, per-window buffers**| Each window has its own buffer; a compositor merges them | SharpConsoleUI (.NET) |
353
+
354
+
Most TUI frameworks use a single shared buffer. SharpConsoleUI gives each window its own `CharacterBuffer`, then composites them together -- a pattern borrowed from desktop window managers (DWM, Quartz, Wayland compositors), adapted for character cells.
The visible regions calculator uses rectangle subtraction to determine which pixels of each window are actually visible on screen. Occluded regions are skipped entirely rather than painted and overwritten.
372
+
373
+
Each window's render also supports compositor hooks: `PreBufferPaint` fires before controls (for gradients, custom backgrounds), then controls paint, then `PostBufferPaint` fires (for effects like blur or fade).
374
+
375
+
### Frame-Coupled Animations
376
+
377
+
The animation system runs inside the main render loop, not on separate timers:
Delta time is capped at 33ms to prevent animations from completing instantly after idle periods. This is what enables smooth transitions in controls like NavigationView -- the animation and layout run in the same frame tick.
385
+
386
+
### DOM Layout
387
+
388
+
SharpConsoleUI uses a three-pass DOM layout (Measure → Arrange → Paint) similar to WPF and Avalonia. Each control reports its desired size, receives its final bounds from its parent, then paints into its window buffer. This is what allows the responsive NavigationView to detect its actual width and switch display modes.
389
+
390
+
---
391
+
392
+
## Cross-Ecosystem Comparison
393
+
394
+
Different languages have their own established TUI frameworks. Here's how the major ones compare architecturally.
**Ratatui** is a lightweight Rust library where you own the event loop and redraw the entire UI each frame. Clean and fast, but no retained state or compositing -- you manage everything yourself.
419
+
420
+
**BubbleTea** uses the Elm architecture in Go -- your `View()` returns a string, the framework diffs it. Elegant for single-screen apps. The string-based model doesn't support pixel-level compositing.
421
+
422
+
**Textual** has its own segment-based compositor that merges overlapping widget output. It uses a spatial grid for fast hit-testing and supports CSS-like animations and styling. The most feature-rich Python TUI framework.
423
+
424
+
**Terminal.Gui** is the most mature .NET TUI library with the widest control set. v2 (beta) adds overlapping window support. Uses a shared buffer with painter's algorithm rendering.
425
+
426
+
**SharpConsoleUI** takes the compositor approach further with per-window buffers, occlusion culling via rectangle subtraction, and compositor hooks for visual effects. The animation system and DOM layout pipeline enable features like the responsive NavigationView with animated mode transitions.
427
+
428
+
Each framework makes different tradeoffs. The compositor approach adds complexity but enables desktop-class features (window management, visual effects, animated responsive controls) that are difficult to achieve with a shared buffer or string-based model.
0 commit comments