# visage puts a UI framework and a graphics library in one C++ package

> Visage is a GPU accelerated C++ library for native UI and 2D graphics that draws with Metal, Direct3D11, Vulkan or WebGL and transpiles one shader set across them. It suits engineers building audio plugins and creative tools who need a real UI rather than an embedded browser.

**VitalAudio/visage** — C++ UI library meets creative coding

- Repository: https://github.com/VitalAudio/visage
- Stars: 626 · Forks: 62
- Language: C++
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/vitalaudio-visage

## One window, one canvas, one event loop

The library is described as a GPU accelerated, cross platform C++ library for native UI and 2D graphics, merging the structure of a UI framework with the features of a creative graphics library. The full basic example is short enough to read as the specification of the whole architecture:

```cpp
#include <visage/app.h>

int main() {
  visage::ApplicationWindow app;

  app.onDraw() = [&app](visage::Canvas& canvas) {
    canvas.setColor(0xffff00ff);
    canvas.fill(0, 0, app.width(), app.height());
  };

  app.show(800, 600); // Opens as 800 x 600 pixel window
  app.runEventLoop(); // Runs window events. Returns when window is closed.
  return 0;
}
```

The shape is a window object with an onDraw callback that receives a canvas, a show call that opens the window at a given pixel size, and an event loop that returns when the window closes. That is the entire contract in one snippet. The audience is developers of native applications who need both a user interface and expressive two dimensional drawing, and the flagship use case in the repository is the plugin: there is an examples/ClapPlugin/ directory, and a plugin cannot embed a browser comfortably, cannot easily use a heavyweight toolkit and wants to look like a modern creative tool. The repository layout mirrors the layering, with visage_app/, visage_windowing/, visage_ui/, visage_widgets/, visage_graphics/, visage_utils/ and visage_file_embed/ as separate directories, plus a CMakeLists.txt, a cmake/ directory, an examples/ tree and clang tooling configuration in .clang-format, .clang-format-ignore and .clang-tidy.

## One shader set, three graphics APIs and a browser

The platform story is what makes this more than a toolkit. Windows uses Direct3D11, macOS uses Metal, Linux uses Vulkan, and the web and Emscripten build uses WebGL. The shader story is the part that saves the developer the most work. Shaders are written once and transpiled for Direct3d, Metal and OpenGL, which means a custom effect is authored in one place and runs on every target, including in a browser. That is a genuinely awkward problem to solve yourself, because the shading languages differ in syntax, in how they express a render target, and in what they call a varying. The graphics feature set on top of that is closer to a creative tool than a widget library. Blend modes are supported for combining layers, with additive and subtractive options, or you can draw a custom mask for the UI to pass through. Real-time effects such as large blur and bloom are included rather than left as an exercise. Automatic shape batching groups shapes for efficient GPU rendering, and there is access to the device pixel size for precise rendering without blurring, with partial rendering that redraws only the dirty regions for performance. There is also a Live Shader Editing example, which implies that shader sources can be reloaded at runtime rather than only at build time.

## UI plumbing that a cross platform app has to solve anyway

The UI feature list is short and each entry is a platform difference the library absorbs. Event normalization gives cross platform support for keyboard and mouse input, and window normalization covers opening and handling windows. Text entry is Unicode with multi line text editing, and emoji support is called out explicitly, with the documentation noting it is for people who are into that kind of thing. The interesting piece is partial rendering, which redraws only the dirty regions, and that connects the UI and graphics halves of the library. A UI framework that redraws everything each frame is fine for a form and wasteful for an audio plugin with a scrolling waveform. Because Visage already keeps a graphics context, dirty region tracking is a natural extension rather than a bolted on optimisation. That is the structural argument for the library existing as one package rather than as a UI toolkit with a graphics addon. The fluid motion behaviour follows the same logic, with new frames displayed at the monitor's refresh rate and animations kept smooth, which again assumes a graphics pipeline rather than a widget toolkit's invalidation model.

## Bringing your own window is a first class example

The examples directory is where the library's actual range is visible, and one entry in particular changes how you should think about adoption. Alongside Basic, there are BlendModes, Bloom, Gradients, Paths, PostEffects, LiveShaderEditing, MouseEvents, MultiWindow, Layout, a demo of the feature set, BringYourOwnWindow and ClapPlugin, plus an emscripten_template.html for the web build. BringYourOwnWindow is the one that matters most for integration, because it says the library does not insist on owning the top level window. That matters for audio plugins, where the host supplies the window and your code draws into it, and for applications that already have a native window and want Visage for the content area only. The MultiWindow and Layout examples suggest a multi window scene graph is within reach. The ClapPlugin example is the clearest statement of intent about who this is for, since the CLAP plugin format is one of the modern audio plugin standards and plugins are exactly the case where embedding a browser is unwelcome. The examples also carry assets, with fonts/, icons/, images/ and shaders/ directories and an Info.plist.in for macOS packaging, which is a hint that these are meant to be built and run rather than read.

## Where a self drawn UI is the wrong choice

The main limitation is that Visage draws its own interface, so you inherit the consequences. Widget toolkit libraries exist because they have solved a decade of details you would otherwise rediscover: focus traversal, keyboard navigation conventions, screen readers, high contrast modes, right to left layout, and the platform look that users expect. Visage's own feature list mentions event normalization, text entry and windows, which is a short list compared with what a mature toolkit handles, so if your application is a settings dialog, a form or anything where accessibility matters, a native toolkit is the safer choice and you would use Visage only for a custom canvas area. A second boundary is the platform coverage. The renderer mapping is one API per platform, and the Linux path is Vulkan, so a machine without a Vulkan driver is a problem even though the API is otherwise available. The web target uses WebGL, which is a further step down from WebGPU and from a native context. A third consideration is the maturity of a project like this. The repository has no GitHub releases, so there is no published version history to diff against and no changelog to read, and although the last push was on 2026-10-15 and the repository is not archived, that means the API can change under you. The practical approach is to clone it, build the Basic example, and treat the source as the specification rather than a released library.

## Conclusion

Adopt Visage if you are writing a native C++ application, an audio plugin or a creative tool and want a modern UI with shaders, blend modes and partial redraw without embedding a web view. Do not adopt it if your project is web based, since the browser already provides a canvas, or if you need a full widget toolkit with mature accessibility and native controls, because this library draws its own interface. Before you start, read the basic example, confirm your platform maps to the renderer you need, and check the licensing of any fonts or images you load into the examples.

## FAQ

### What is Visage and what does it provide?

Visage is a GPU accelerated, cross platform C++ library for native UI and 2D graphics that merges the structure of a UI framework with the features of a creative graphics library. It includes event and window normalization, Unicode text entry, blend modes, shaders, real-time effects such as blur and bloom, and partial rendering.

### Which platforms and graphics APIs does Visage support?

Windows uses Direct3D11, macOS uses Metal, Linux uses Vulkan, and the web and Emscripten build uses WebGL. Shaders are written once and transpiled for Direct3d, Metal and OpenGL.

### How do I start a Visage application?

Create a visage::ApplicationWindow, assign a callback to its onDraw that receives a Canvas, then call show with the window size and runEventLoop. The full basic example in the documentation is about a dozen lines, and the Basic example in the examples directory builds it as an application.

### Can Visage be used inside an existing window?

Yes, there is a BringYourOwnWindow example in the examples directory, which is the case that matters for audio plugins where the host owns the window. A ClapPlugin example is also included, and a multi window example is present alongside it.

### What licence is Visage released under?

Visage is MIT licensed, with the licence file at the root of the repository. The examples directory also carries fonts, icons and images, which carry their own terms and should be checked separately if you reuse them.

## Sources

- [Issues](https://github.com/VitalAudio/visage/issues)
- [License: MIT](https://github.com/VitalAudio/visage/blob/main/LICENSE)
- [README](https://github.com/VitalAudio/visage/blob/main/README.md)
- [VitalAudio/visage on GitHub](https://github.com/VitalAudio/visage)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/vitalaudio-visage
