Caca.NET 1.0.0

dotnet add package Caca.NET --version 1.0.0
                    
NuGet\Install-Package Caca.NET -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Caca.NET" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Caca.NET" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Caca.NET" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Caca.NET --version 1.0.0
                    
#r "nuget: Caca.NET, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Caca.NET@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Caca.NET&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Caca.NET&version=1.0.0
                    
Install as a Cake Tool

Icon

Caca.NET

A cross platform .NET port of cacalabs/libcaca: 💩 Colour ASCII Art Library.

There is no native dependency. It is pure IL — clone, dotnet run, done, on Windows, Linux or macOS.

Installation

dotnet add package Caca.NET

Usage

Everything public lives in the Caca namespace, apart from the backend extension point in Caca.Drivers. A whole program:

using Caca;

using Display dp = new();          /* owns a canvas sized to the terminal */
Canvas cv = dp.Canvas;
dp.Title = "sample";
dp.DisplayTime = 20000;            /* microseconds per frame; 0 runs flat out */

while (true)
{
    Event ev = dp.GetEvent(EventType.KeyPress | EventType.Quit);
    if (ev.Type == EventType.Quit || ev.KeyCh == (int)EventKey.Escape)
        break;

    cv.SetColorAnsi(AnsiColor.LightGray, AnsiColor.Black);
    cv.Clear();
    cv.SetColorAnsi(AnsiColor.White, AnsiColor.Blue);
    cv.FillBox(2, 1, 24, 3, ' ');
    cv.PutStr(4, 2, $"{cv.Width}x{cv.Height}");
    cv.DrawLine(0, 0, cv.Width - 1, cv.Height - 1, '*');
    dp.Refresh();
}

Canvas

A grid of cells, each one character plus a 32-bit attribute. new Canvas() starts empty and new Canvas(w, h) starts sized; Width and Height are read-only, changed through Resize. A canvas attached to a Display is resized for you when the terminal changes.

Member
PutChar(x, y, ch), PutStr(x, y, s) Write cells in the current attribute. Anything off-canvas is silently dropped, as in libcaca
GetChar(x, y), GetAttr(x, y) Read one back
Clear() Fill with spaces in the current attribute
SetColorAnsi(fg, bg) The attribute later writes use, as AnsiColor or int
CurrentAttr That same attribute, packed
DrawLine, FillBox, FillEllipse, FillTriangle Primitives, each taking the character to draw with
Blit(x, y, src, mask) Copy src in, but only the cells mask marks
DitherBitmap(x, y, w, h, dither, pixels) Draw an image — see Dither below

Blit is how the wipes work: draw a shape into a scratch canvas, then blit the incoming frame through it as a mask.

Display

Binds a canvas to an output backend, paces the frame rate and delivers input. It is IDisposable, and disposing it is what puts the terminal back.

Member
new Display() A display over a new canvas, sized to the output
new Display(canvas) Adopts your canvas, resizing it to fit
new Display(canvas, driver) Adopts a driver too, ignoring CACA_DRIVER
Canvas The canvas being painted
Refresh() Paint, then wait out the rest of the frame interval
DisplayTime Minimum microseconds between refreshes; 0 runs flat out
Title Window title, where the backend has one (set-only)
GetEvent(mask) The next event matching mask, or Event.None

GetEvent never blocks. Resize events are applied to the canvas whether or not you asked for them, so Canvas.Width is always current.

Events

Event is a struct: Type, KeyCh for key presses, and Width/Height for resizes. EventType is a flags enum — KeyPress, Quit, Resize, Any and the rest — used both as the GetEvent mask and as the event's own kind.

KeyCh carries a character where the key has one, so ' ' and ' ' compare directly. Keys that do not are the EventKey values: Escape, Up, Down, Left, Right, Home, End, PageUp, PageDown, F1–F12, Delete and the Ctrl-x codes.

Colour

AnsiColor is the sixteen ANSI colours in libcaca's DOS order, plus Default and Transparent. AnsiStyle is a flags enum of Bold, Italics, Underline and Blink. The static Attr class packs and unpacks the 32-bit cell attribute if you want to work with it directly: FromAnsi, ToAnsiFg, ToAnsiBg, ToRgb12Fg, ToRgb12Bg, ToStyle.

Dither

Dither describes how a bitmap becomes coloured characters: the pixel format going in, the palette, and the glyph ramp coming out. Static factories cover the usual formats, and each takes an optional pitch in bytes for rows that are not tightly packed:

Factory Format
Dither.Indexed8(w, h, pitch = 0) 8bpp through a palette, grayscale until you call SetPalette
Dither.Rgb24(w, h, pitch = 0) 24bpp packed RGB
Dither.Rgb32(w, h, pitch = 0) 32bpp 0x00RRGGBB words, alpha ignored
Dither.Argb32(w, h, pitch = 0) 32bpp 0xAARRGGBB words, alpha honoured

The constructor is still there for anything else: new Dither(bpp, width, height, pitch, rmask, gmask, bmask, amask), matching caca_create_dither. Masks apply to the pixel as a native-endian word, so on a little-endian machine Rgb32 is the byte order B, G, R, unused.

Pixels reach DitherBitmap as a ReadOnlySpan<byte> whatever the format, so a uint[] buffer goes in through MemoryMarshal.AsBytes.

Member
SetPalette(red, green, blue, alpha) 256 entries each, 0–0xfff, 8bpp only
SetCharset(name) "ascii" (the default), "shades" or "blocks"
Antialias Average every source pixel under a cell. On by default
Gamma, Invert As libcaca
Brightness, Contrast Accepted and reported back, but do nothing — see Scope of the library

Drivers

CACA_DRIVER picks a built-in backend, exactly as it does for libcaca:

Value Behaviour
ansi ANSI escape sequences on the terminal (the default when stdout is a TTY)
null Render nothing; useful headless, for benchmarks and tests

To paint somewhere else — an in-memory buffer for tests, a GUI, a recording — implement Caca.Drivers.IDriver and hand it to new Display(canvas, driver):

public sealed class MyDriver : IDriver
{
    public int Width => 80;
    public int Height => 25;

    public void Refresh(Canvas canvas) { /* canvas.GetChar / GetAttr per cell */ }
    public Event PollEvent() => Event.None;      /* or Event.Key / Quit / Resized */
    public void SetTitle(string title) { }
    public void Dispose() { }
}

The display takes ownership: disposing the display disposes the driver.

CACA_SYNC overrides the synchronized-output detection described below: 0 never emits it, 1 always does, and anything else leaves it to the query.

Licence

cacademo and libcaca are distributed under the WTFPL, and so is this port. See LICENSE.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 89 9/2/2026
1.0.0-rc001 93 9/2/2026