DEV Community

Cover image for One Terminal, Everything at Once: What SharpConsoleUI Actually Does
Nikolaos Protopapas
Nikolaos Protopapas

Posted on

One Terminal, Everything at Once: What SharpConsoleUI Actually Does

One Terminal, Everything at Once

Here's a question I've been asking other terminal-UI frameworks, and the honest answer keeps coming back no:

Can you play an MP4 in one floating window, run a live process monitor in an embedded terminal next to it, drive a four-panel dashboard with real-time graphs above them, render all of that over an animated Matrix-rain desktop, and then re-theme the entire scene — without restarting, without flicker, all compositing through a single diff'd cell buffer?

The thing that makes this hard isn't any single feature. Plenty of libraries can draw a table or animate a spinner. The hard part is doing all of it simultaneously, in overlapping windows, smoothly. That's a desktop window manager — z-order, occlusion culling, per-cell alpha blending, dirty-region diffing — rendered into character cells. That's the architecture SharpConsoleUI is built on, and it's why the scene holds together.

And here's the part I want to be upfront about: every line of code in that video ships in one example appExamples/DemoApp. No private branch, no staged demo rig. You can dotnet run --project Examples/DemoApp and reproduce the whole thing. So let's walk through what's on screen, with the real code.


The dashboard: a real 2D grid, not stacked panes

dashboard — 4-column grid with spans, gaps, per-cell borders, live graphs

That ServerHub-style dashboard is a WinUI-style grid: star/auto tracks, column and row gaps, cells that span, draggable splitters, and per-cell borders and backgrounds. This is the actual builder call from GridDemoWindow.cs:

var grid = Controls.Grid()
    .Columns(GridLength.Star(1), GridLength.Star(1), GridLength.Star(1), GridLength.Star(1))
    .Rows(GridLength.Auto(), GridLength.Star(1), GridLength.Star(1), GridLength.Star(1))
    .RowGap(1)
    .ColumnGap(2)
    .ColumnSplitterAfter(1)              // drag-resize between columns 1 and 2
    .RowSplitterAfter(1)                 // drag-resize between content rows 1 and 2
    .ColumnGridlines()                   // thin rules between columns
    .RowGridlines()
    .GridlineStyle(BorderStyle.Single)
    .Place(header, 0, 0, colSpan: 4)     // header spans all 4 columns
    .Place(settingsPanel, 1, 2)
    .Place(alertsLog, 1, 3, rowSpan: 2)  // alerts tile spans two rows
    .Build();

// Per-cell styling — real per-cell border + background, not a global theme:
grid.Cell(1, 0).Border = BorderStyle.Rounded;          // frame the CPU tile
grid.Cell(1, 1).Background = new Color(40, 44, 60);     // slate fill behind resources
grid.Cell(1, 3).Border = BorderStyle.Rounded;          // frame the spanning alerts tile
Enter fullscreen mode Exit fullscreen mode

The tiles aren't decoration — every one is a live, interactive control. The bars use semantic color roles, so they re-tint with the theme instead of carrying hardcoded colors:

Controls.BarGraph().WithLabel("Mem ").WithValue(56).WithMaxValue(100)
    .WithColorRole(ColorRole.Warning).ShowValue().Build();
Enter fullscreen mode Exit fullscreen mode

And the splitters animate — grab one, or collapse a track programmatically:

grid.AnimateColumnWidth(1, 0, TimeSpan.FromMilliseconds(250));   // collapse
grid.AnimateRowHeight(1, savedRowCells ?? 5, TimeSpan.FromMilliseconds(250));
Enter fullscreen mode Exit fullscreen mode

Examples/DemoApp/DemoWindows/GridDemoWindow.cs


Video, actually playing, in a window

sample_bunny.mp4 playing half-block inside a floating window

That's sample_bunny.mp4 decoded through FFmpeg and rendered into the terminal as half-blocks (two pixels per cell). Press M mid-playback to cycle Half-Block → ASCII → Braille → Kitty graphics (on terminals that support it). The control is four lines:

var videoControl = Controls.Video()
    .Fill()
    .WithLooping()
    .WithOverlay()
    .Build();
Enter fullscreen mode Exit fullscreen mode

…and you hand it a file:

var filePath = await FileDialogs.ShowFilePickerAsync(ws,
    startPath: AppContext.BaseDirectory,
    filter: "*.mp4;*.mkv;*.avi;*.webm;*.mov;*.flv;*.wmv");

videoControl.PlayFile(filePath);
Enter fullscreen mode Exit fullscreen mode

The file picker you see floating over everything? That's FileDialogs.ShowFilePickerAsync — a modal, awaited inside the window's own async thread, compositing on top of the running dashboard behind it.

Examples/DemoApp/DemoWindows/VideoDemoWindow.cs


A real terminal, embedded

embedded PTY terminal running a btop-style process + network monitor, semi-transparent over the desktop

Not a fake shell — a PTY-backed terminal emulator running your real system shell, here showing a live btop-style monitor with CPU cores, network graphs, and a process table. It's also semi-transparent, so the desktop shows through:

return new WindowBuilder(ws)
    .WithTitle("Terminal")
    .WithSize(100, 30)
    .Centered()
    .WithBackgroundColor(new Color(30, 30, 60, 180))   // semi-transparent chrome
    .AddControl(Controls.Terminal()
        .WithBackgroundColor(Color.Transparent)
        .Build())
    .BuildAndShow();
Enter fullscreen mode Exit fullscreen mode

Examples/DemoApp/DemoWindows/TerminalWindow.cs


The animated desktop behind it all

Matrix-rain katakana glyphs cascading behind the overlapping windows

The cascading green katakana behind every window is a desktop background with a paint callback — the framework hands you the cell buffer each tick and you draw whatever you like. There are built-in effects:

ws.DesktopBackground = DesktopEffects.ColorCycling();
ws.DesktopBackground = DesktopEffects.Pulse(new Color(15, 25, 60));
ws.DesktopBackground = DesktopEffects.DriftingGradient(/* ... */);
Enter fullscreen mode Exit fullscreen mode

…and Matrix rain is just a custom one. Here's the shape of it (from CreateMatrixRain()):

return new DesktopBackgroundConfig
{
    AnimationIntervalMs = 70,
    PaintCallback = (buffer, width, height, elapsed) =>
    {
        // per-column heads/speeds/trails over a Katakana glyph set,
        // bright white-green head fading to dark green trail
        for (int y = 0; y < height; y++)
            for (int x = 0; x < width; x++)
                buffer.SetCell(x, y, new Cell(' ', Color.Black, Color.Black));
        // ...advance each column, paint head + fading trail...
    }
};
Enter fullscreen mode Exit fullscreen mode

The whole desktop is behind the window compositor — the windows occlude it, alpha-blend over it, and it keeps animating in the gaps. That's the compositor doing its job.

Examples/DemoApp/DemoWindows/DesktopBackgroundWindow.cs


Re-theme the whole scene, live

the same scene re-tinted from Crimson to ModernGray via the toolbar dropdown

The toolbar dropdown switches themes, and because controls declare semantic roles rather than literal colors, the entire composited scene — borders, bars, panels, gradients — re-derives at once:

// a control says what it IS, not what color it is:
Controls.Checkbox("Auto-scale").WithColorRole(ColorRole.Success).Build();
Controls.Button(" Restart ").WithColorRole(ColorRole.Danger).Outline().Build();

// switching the theme re-derives every role's palette:
ws.ThemeStateService.SwitchTheme(themeName);
Enter fullscreen mode Exit fullscreen mode

No per-control recoloring. Danger is whatever the active theme says danger is.

Examples/DemoApp/DemoWindows/ControlRolesWindow.cs, LauncherWindow.cs


Why it composes

Every piece above is ordinary — a grid, a video control, a terminal, a background, a theme. The reason they run together is the rendering model: each window owns its own CharacterBuffer, a compositor merges them with occlusion culling and per-cell Porter-Duff alpha blending, and only changed cells are flushed. So a video updating at 30fps in one window, a sparkline ticking in another, and Matrix rain animating behind both cost you only the cells that actually changed — not a full-screen repaint each frame. That's what makes it smooth over SSH, not just locally.

It's the same pattern a desktop window manager uses, adapted to character cells. Most TUI frameworks share one buffer and repaint the frame; that's a fine model for a form or a wizard, and a wall when you want overlapping, independently-animating windows.

Try it

git clone https://github.com/nickprotop/ConsoleEx
cd ConsoleEx
dotnet run --project Examples/DemoApp
Enter fullscreen mode Exit fullscreen mode

Press Ctrl+L for the launcher. Everything in the video is a page in the sidebar — Grid Layout, Video Player, Terminal, Desktop Background, Control Roles — across ~50 demos in one app. The video features are flagged: video and terminal need FFmpeg on your PATH.

If you build something with it, I'd genuinely like to see it.

Top comments (0)