ctx is a configurable and lightweight 2D vector graphics stack with focus on remote and deferred rendering building on top of the HTML5 canvas 2D context specification. The project provides as single header library which implements both a binary and textual drawlist protocol. The ctx single-header library provides APIs for registering keybindings and pointer events with callbacks in user-relative coordinates. Events and rendering are abstracted for linux framebuffer, SDL2, braille in terminal and running in the ctx terminal. The ctx terminal is the binary built in the toplevel of a ctx git checkout. This terminal serves as a demanding example for app-development with ctx, it used to be faster - but peformance of minimal framebuffer touching has been replaced with well-formed vector output - for /dev/fb0 usage fbterm is a *lot* faster - but lacks the richer media of ctx, which permits the terminal to run inside itself with minimal overhead. From within the terminal even shell scripts get the ability to render vector graphics.

There are extensions for sending raster graphics with terminals, ranging from sixels through iterm2 base64 upload to kitty - that permit uploading buffers. With the increased pixel density of modern displays sending full framebuffers over the wire is too expensive for updating a buffer. WARNING: ctx is a work in progress, some terminal interactions are wonky - and display latency is good only for localized changes like text editing - global scrolling works less well, ctx is also relying on stb_image for image decoding support as well as providing in-band access to your microphone.

When programming in DOS or with SVGAlib the mono-spaced text rectangle can be upgraded to graphics mode. Similarly terminals have also not only provided a grid of monospaced text. Examples are DECs VTs with ReGIS, tektronix, BBSs with RIPscript and in some ways Display PostScript and NEWS.

The ctx terminal adds an escape code \e[?200hwhich opens a 2D vector drawing context with coordinate origin at the start of the current line. After this command has been issued, the terminal is no longer in ANSI/VT mode but in ctx mode, and commands according to the ctx protocol are accepted. This protocol is a superset of the SVG path data format, which includes an encoding of the 2D canvas context API. Commands have a long form in additon to the short, so for verbosity (and ease of prototyping), moveTo,curveTo can be used in place of m and l in addition (,,,) and ; are as a bonus treated as whitespace making some snippets almost copy pastable with javascript bits of code the parser for this format also supports suffixes, the clock.sh example uses this to create a clock proportional to the size of the terminal.

The ctx parser in the terminal that clock.sh creates a binary in-memory dawlist. This drawlist is played back in-place during the drawing commands used to draw the terminal with ctx. The terminal and its clients are thus merged into a single drawlist - which can include multiple tabs/windows.

The single drawlist is used for read-only access by independent worker-threads. The framebuffer to update is split into a grid (of at least 4 by 4) where each cell is a render job. Hashes of the drawlist are computed in parallel for all cells - and the cells where the hash differs from the last update are spread among the render threads. This permits for low latency updates for small changes, it is less optimal for fullscreen scrolling of large buffers. A cache that captures the rasterization of smallish shapes is currently disabled, since it glitches under threading - disabling it has the advantage of the threads being fully independent.

One of ctx' backends in addition to SDL2 and linux framebuffer is the ctx backend which outputs the ctx protocol on stdout and accepts keyboard/pointer input either as standard terminal escape sequences or in a passthrough mode of ctx' own event format, inherited from microraptor gui. Pointer events can be handled as global events like the ones delivered to the canvas element in HTML. But a better abstraction can be event callbacks registered for the active path under the current transform. Ctx maintains a list of these in draw order and examines them from to back for bounding box (and NYI inPath) and delivers events - with the ability to stop propagation when a later registered handler wants to override earlier registered ones.

Sending full frames of vectors becomes bandwidth intensive with complex interfaces, this will be remediated by reusing ranges from the previous frames bytestream, this is currently not implemented but will provide signficant bandwidth savings.

ctx is a work in progress and there is known bugs, on one important ergonomic measure, in this regard ctx seem to already be competetive with GPU accelerated terminals. Due to how framebuffer caching is done latency is higher with large updates and scrolling than without. It still is almost nice enough for the main author to be configured as his systems default terminal - but not quite.

The benchmarks to the right are shown in typometer, a utility to measure time from keyboard event to display update. The benchmarks have been done under the Xorg session with openbox on a debian system. ctx is using the SDL2 backend and is thus having higher overhead than should be neccesary using a more dedicated backend.


The measurements to the right are done under an xorg session of GNOME, the extra steps of compositing does increase latency somewhat.


Features and references

HTML5 Canvas 2D Context
Easily bindable C API and protocol builds directly on this standard. Compositing and blending is according to Compositing and Blending Level 2; ctx goes further than the standard and permits all blending modes to be combined with all compositing modes. The core ideas for a 2d vector vocabulary is however shared with PDF, cairo, OpenVG, directdraw and other API that have foundation in postscript.
Small footprint
Can be tuned for microcontrollers down to ~5kb of RAM + 30kb of code + 12kb of fontdata, combined with immediate mode UI that can be re-run, it is sufficient to have a framebuffer covering one scanline - making microcontrollers with 8kb of RAM a possible target - this has not yet been attempted.
Threaded/deferred rendering
The compact ctx protocol - in both text and binary form - can split the drawing from the renderering. Separate render threads each with a small RAM footprint can render shared read-only from the binary representation. The binary representation is also suitable for driving other backends like cairo or an external GPU renderer. .
utf8 native
Missing ligratures though, and beyond vttest charset support is not good and RTL is missing - harfbuzz intergration can fix this and more. Also currently lacking color emoji. The most efficient font format is the binary representation of the ctx protocol.
stb_truetype.h
If the declarations for stb_truetype are included before ctx.h - functions to load fonts from TTF/OTF files become available.
VT4xx, ECMA-48
Almost full vt100 and vt220 escape sequence handling, some of horizontal margins are supported, including smooth scroll and double width/height. From ECMA-48 and xterm handling of colors, word-wrap, proportional text, mouse and more.
ametameric palette
The terminal 16 color palette is optimized for legibility for both trichromats and dichromats
atty
audio recording and playback (only raw pcm for now, opus codec NYI)
sixels
DEC terminal family standard for raster graphics transfer
kitty graphics
kitty style raster graphics transfer
iterm2 inline images
iterm2 style raster grarphics transfer
bracketed paste
SDL2
Optional backend that works better than the framebuffer that gets included when SDL.h is included before ctx.h
cairo
support code to render to cairo contexts if cairo.h is included before ctx.h, useful for conformance verfication and SVG and PDF output.
/dev/fb0
Applications built with the ctx library can run directly on the linux framebuffer without X/wayland, for it to be fast a fast framebuffer is needed.
RGB and CMYK, 8pc and 32bit floating point
Already supporting RGB332, 565 and grayscale modes, with an architecture that also can support spectral, ICC integration is planned for.

Downloads

There is no tarball releases yet, but the development version can be cloned and contains some example/test clients in C and bash, if you've got the development headers for SDL2 the following builds a ctx binary.

$ git clone https://ctx.graphics/.git
$ cd ctx.graphics
$ make
ctx.h (browse)580KThe singleheader library ctx.
ctx-font-regular.h (browse)128KExample font to use with ctx
test-size.cexample
ctx-x86_64-SDL2ELF 64bit binary for linux dynamically linked against SDL2, should work in most distros.
ctx-x86_64-SDL2-AVX2ELF 64bit binary for linux dynamically linked against SDL2, should work in most distros but requires a cpu with AVX2 instructions.
ctx-x86_64-static64bit static linux binary - should work in more distros, but has only /dev/fb0 and braille rendering.
ctx-i486-static32bit static linux binary - should work in more distros, but has only /dev/fb0 and braille rendering.

license and funding

The terminal is available under GPLv3+, and ctx.h is available under LGPLv3+ you can encourage continued development of ctx and dissimilar technologies by financially supporting me, Øyvind Kolås who is doing independent pro-bono R&D through patreon and similar. If my income through such sources is above 4000USD per month for a year, or a similar amount in shorter time the protocol and rasterizer parts of ctx will be relicensed under the ISC license.

bugs

The current status of ctx is beyond proof of concept - but still does not fully realize a minimal system demonstrating it's capabilities - some features are also broken and need repair - and for third party use probably morge urgently than the following wishlist. When this list is nearing 0 it is time for a tarball release of ctx - event if the single header ctx.h already is the rolling release.

semi-ordered roadmap / wishlist