Get notified of new releases: click Watch → Custom → Releases to receive notifications when a new version is published.
AeonGUI is a cross-platform C++ GUI and SVG rendering library focused on game UI and interactive applications. It implements a subset of the SVG DOM and CSS styling pipeline, with a pluggable 2D rendering backend (Cairo or Skia) selected at build time.
Keywords: C++ GUI, SVG renderer, game UI, cross-platform UI library, CMake, Cairo, Skia, Pango, HarfBuzz, libxml2.
AeonGUI lets you describe user interfaces with SVG and style them with CSS, then render them on top of any graphics API your application already uses. The library parses an SVG document into a DOM tree, resolves CSS styles, performs text layout, and produces pixel output through a selectable 2D backend (Cairo or Skia)—but the rendered result is handed to your application as a plain pixel buffer, so it can be composited as a texture in OpenGL, Vulkan, Metal, or any other rendering pipeline.
The project is written in modern C++ (C++20) and built with CMake. All third-party dependencies are either vendored or fetched automatically, and the build integrates cleanly with vcpkg on Windows.
- SVG as a UI description language. UI elements are defined in standard SVG files and styled with CSS, so designers can work with familiar tools (Inkscape, Illustrator, text editors) instead of proprietary formats.
- Rendering-API agnostic. The core library never calls OpenGL, Vulkan, or Metal directly. It rasterises into a CPU-side pixel buffer that your engine composites however it sees fit.
- Pluggable 2D backend. Choose between Cairo and Skia at build time
via the
BACKENDCMake option. Both backends produce identical pixel-buffer output and share the same Pango + HarfBuzz text pipeline. - Minimal footprint. Only the parts of the SVG and DOM specifications that are useful for game and application UI are implemented—no scripting engine, no full browser layout model.
- Embeddable. The library is designed to be integrated into existing game engines and applications, not to be a standalone toolkit.
- Cross-platform from day one. CI tests run on Windows (MSVC and MSYS2 flavors), Ubuntu, and macOS on every commit.
- Not a web browser. There is no JavaScript engine and no networking stack. Basic HTML/XHTML layout (a flexbox-style subset powered by Yoga) is supported for embedding lightweight HTML inside the same DOM, but AeonGUI is not a substitute for a real browser—if you need one in your game, look at CEF or Ultralight.
- Not a desktop widget toolkit. AeonGUI does not provide buttons, scroll bars, or dialog boxes out of the box. It provides the rendering primitives you can use to build those things.
- Not a complete SVG implementation. Only the subset of SVG 2 that is useful for UI rendering is supported (basic shapes, paths, text, images, gradients, transforms, groups, defs, SMIL animations). Filters and advanced text features are out of scope for now.
- Not API-stable yet. The library is under active development, and public interfaces may change between releases.
AeonGUI is under active development and still evolving. APIs and behavior may change.
- Good fit: experimentation, prototyping, engine integration research, SVG-based UI workflows.
- Not yet ideal: long-term API stability guarantees.
- SVG DOM subset with scene graph traversal and element factory architecture.
- CSS-based styling through
libcss, including:hover,:active, and:focuspseudo-classes. - SMIL animation engine:
<animate>,<set>,<animateTransform>, and<animateMotion>elements with time-based and event-based (click,mouseenter, …) activation. - Text layout and font shaping via
Pango,HarfBuzz, andFontconfig. - XML parsing via
libxml2. - Raster image support with magic-based format detection. PCX decoding is
always available with no extra dependencies. PNG and JPEG decoding are
optional and enabled via
USE_PNGandUSE_JPEGrespectively (requireslibpng/libjpeg-turbo). - DOM geometry interfaces:
DOMMatrix,DOMPoint,DOMRectwith full read-only and mutable variants. - DOM event system:
EventTarget,Event,EventListener,AbortSignal. - Mouse input handling: hit-testing via
elementFromPoint, hover tracking, click and mouseenter/mouseleave dispatch. - Demo applications for OpenGL, Vulkan, Metal, and Direct3D12.
- Unit tests with GoogleTest/GoogleMock.
flowchart TD
svg["SVG file"]
parser["libxml2 parser"]
dom["DOM tree\n(Node / Element / Text)"]
css["CSS resolution\n(libcss)"]
text["Text layout\n(Pango / Fontconfig)"]
raster["Rasterisation\n(Cairo or Skia)"]
pixels["Pixel buffer"]
engine["Your engine composites\nthe buffer as a texture"]
svg --> parser
parser --> dom
dom --> css
css --> text
text --> raster
raster --> pixels
pixels --> engine
The Window class ties these stages together: it owns a Document (the DOM
tree), a Canvas (the rendering surface—CairoCanvas or SkiaCanvas
depending on the chosen backend), and a Location (the URL of the loaded
SVG). Your application creates a Window, points its Location at an SVG
file, calls Update() each frame to advance animations, calls Draw(), and
reads back pixels via GetPixels().
Mouse input is forwarded through HandleMouseMove(), HandleMouseDown(),
and HandleMouseUp(), which drive CSS pseudo-class state, hit-testing,
and DOM event dispatch for SMIL event-based triggers.
CI builds currently run on:
- Windows (MSVC)
- Windows (MSYS2:
mingw64,ucrt64,clang64) - Ubuntu
- Arch Linux (Docker)
- macOS
Core dependencies used by the project:
cairo(default backend) orskia(alternative backend)pangoharfbuzzfontconfiglibxml2yoga(HTML/XHTML layout; fetched automatically if not found)zliblibpng(optional, controlled byUSE_PNG)libjpeg-turbo(optional, controlled byUSE_JPEG)gtest/gmockfor tests
For MSVC builds, the repository is configured for vcpkg manifests (vcpkg.json).
| Backend | Text rendering pipeline | Package manager availability |
|---|---|---|
| Cairo | Pango + PangoCairo | vcpkg, apt, brew, MSYS2 pacman, Arch pacman |
| Skia | Pango + PangoFT2 + HarfBuzz draw API | vcpkg, MSYS2 pacman, AeonGames/ArchRepo |
git clone https://github.com/AeonGames/AeonGUI.git
cd AeonGUI# Cairo backend (default)
cmake -B build -DCMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake"
cmake --build build
# Skia backend
cmake -B build-skia -DCMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DBACKEND=Skia
cmake --build build-skia# Cairo backend (default)
cmake -G "MSYS Makefiles" -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
# Skia backend (requires mingw-w64-x86_64-skia or equivalent pacboy)
cmake -G "MSYS Makefiles" -B build-skia -DCMAKE_BUILD_TYPE=Release -DBACKEND=Skia
cmake --build build-skiacmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build buildSkia is not available in the official Arch repositories. Build and install
the skia-aeongui package from the
AeonGames/ArchRepo
PKGBUILD first:
git clone https://github.com/AeonGames/ArchRepo.git
cd ArchRepo/skia
makepkg -siThen configure AeonGUI with the Skia backend:
cmake -B build -DCMAKE_BUILD_TYPE=Release -DBACKEND=Skia
cmake --build buildctest --test-dir build --output-on-failureDemo executables are produced under build/bin/ (platform naming may vary).
Four rendering backends are included:
| Demo | Backend | Notes |
|---|---|---|
OpenGLDemo |
OpenGL | Cross-platform, easiest to get started. |
VulkanDemo |
Vulkan | Requires the Vulkan SDK. |
MetalDemo |
Metal | macOS only. |
Direct3D12Demo |
Direct3D12 | Windows only. |
Pre-built packages and build recipes are attached to each GitHub Release. Pick the method that matches your platform.
Install pre-built package:
Download the aeongui-<version>-1-x86_64.pkg.tar.zst file from the release
assets and install it with pacman:
sudo pacman -U aeongui-0.9.0-1-x86_64.pkg.tar.zstBuild from source using PKGBUILD:
Download PKGBUILD-arch-<version>.tar.gz from the release assets and build
with makepkg:
tar -xzf PKGBUILD-arch-0.9.0.tar.gz
makepkg -s --skippgpcheck
sudo pacman -U aeongui-0.9.0-1-x86_64.pkg.tar.zstInstall pre-built package:
Download the .pkg.tar.zst matching your MSYS2 environment (e.g.
mingw-w64-ucrt-x86_64-aeongui-<version>-1-any.pkg.tar.zst) and install
from the corresponding MSYS2 shell:
pacman -U mingw-w64-ucrt-x86_64-aeongui-0.9.0-1-any.pkg.tar.zstReplace ucrt-x86_64 with x86_64 (mingw64) or clang-x86_64 (clang64)
as needed.
Build from source using PKGBUILD:
Download PKGBUILD-msys2-<version>.tar.gz from the release assets and build
with makepkg-mingw:
tar -xzf PKGBUILD-msys2-0.9.0.tar.gz
makepkg-mingw -s --skippgpcheck
pacman -U mingw-w64-*-aeongui-*.pkg.tar.zstDownload aeongui-brew-<version>.tar.gz from the release assets and install
via a local tap. This builds AeonGUI from source using the formula:
tar -xzf aeongui-brew-0.9.0.tar.gz
brew tap-new --no-git local/aeongui
cp aeongui.rb "$(brew --repository)/Library/Taps/local/homebrew-aeongui/Formula/aeongui.rb"
brew install local/aeongui/aeonguiDownload the vcpkg port archive for your desired backend
(aeongui-vcpkg-port-cairo-<version>.tar.gz or
aeongui-vcpkg-port-skia-<version>.tar.gz) from the release assets.
Extract it into a local overlay port directory and point vcpkg at it:
mkdir -p overlay-ports/aeongui
tar -xzf aeongui-vcpkg-port-cairo-0.9.0.tar.gz -C overlay-ports/aeongui
vcpkg install aeongui --overlay-ports=overlay-ports-DBACKEND=Cairo|SkiaSelect the 2D rendering backend (default:Cairo).-DBUILD_UNIT_TESTS=ON|OFFBuild and register unit tests (default:ON).-DUSE_ZLIB=ON|OFFEnable/disable zlib integration.-DUSE_PNG=ON|OFFEnable/disable PNG decoding.-DUSE_JPEG=ON|OFFEnable/disable JPEG decoding (libjpeg-turbo).-DUSE_CUDA=ON|OFFEnable optional CUDA code path (unused right now, so it has no effect).-DCMAKE_DISABLE_PRECOMPILE_HEADERS=ONDisable PCH during iteration.-DCMAKE_BUILD_TYPE=Debug|Release|RelWithDebInfo|MinSizeRel
Example:
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DUSE_PNG=ON -DUSE_JPEG=ON| Directory | Contents |
|---|---|
core/ |
Main library implementation (Canvas, Color, Path…). |
core/dom/ |
SVG and DOM element classes, SMIL animation elements. |
core/parsers/ |
Internal data-type parsers. |
include/aeongui/ |
Public C++ headers. |
include/aeongui/dom/ |
Public DOM / SVG header files. |
css/ |
CSS engine (libcss, libparserutils, libwapcaplet). |
demos/OpenGL/ |
OpenGL demo application. |
demos/Vulkan/ |
Vulkan demo application. |
demos/Metal/ |
Metal demo application (macOS). |
demos/Direct3D12/ |
Direct3D12 demo application (Windows). |
images/ |
Sample SVG files and demo assets. |
tests/ |
Unit tests (GoogleTest / GoogleMock). |
tools/ |
Developer utilities (code generation scripts). |
cmake/ |
CMake helper modules and templates. |
AeonGUI is thread-safe for typical usage patterns. Internal synchronisation protects all shared mutable state:
| Component | Protection |
|---|---|
FontDatabase (singleton) |
std::recursive_mutex guards all static methods (Initialize, Finalize, AddFont*, Get*, CreateContext) |
Element factory (Construct, Destroy, Register/Unregister) |
std::shared_mutex — concurrent reads, exclusive writes |
| SVG path-data parser (Flex/Bison) | std::mutex serialises all ParsePathData calls |
| HarfBuzz draw-funcs singleton (Skia backend) | C++11 magic-static initialisation (thread-safe by language guarantee) |
CSS statics (unit_len_ctx, screen_media, select_handler) |
Immutable after static initialisation — safe for concurrent reads |
| Per-thread CSS hint buffer | thread_local storage — no contention |
Guidelines:
- A single
Document/Windowinstance must still be accessed from one thread at a time (DOM trees are not internally locked). - Different
Document/Windowinstances may be used from different threads concurrently. FontDatabase::Initialize()andFinalize()are safe to call from any thread; concurrentInitialize()calls are idempotent.
All errors are reported via exceptions (std::runtime_error or
DOMException subclasses). Before throwing, every error is logged to
std::cerr with a colour-coded severity prefix using ANSI escape sequences
(see include/aeongui/LogLevel.hpp):
| Level | Colour | Usage |
|---|---|---|
LogLevel::Debug |
Blue | Internal trace messages |
LogLevel::Info |
Green | Informational (font loading, plugin search) |
LogLevel::Warning |
Yellow | Non-fatal issues (unknown SVG tag) |
LogLevel::Error |
Red | Errors logged before every throw |
| Scenario | Behaviour |
|---|---|
| Document load failure (file not found, parse error) | Throws std::runtime_error |
| CSS parsing / selector error | Throws std::runtime_error |
Image load (RasterImage::Load*) |
Throws std::runtime_error |
Font database initialisation (Initialize) |
Throws std::runtime_error |
| Font context creation (uninitialised) | Throws std::runtime_error |
Plugin load (<script> element) |
Logs error, continues (no throw) |
| Unknown SVG element tag | Logs warning, creates generic Element |
| CSS deleter callbacks | Logs error (cannot throw from destructor path) |
Callers should be prepared to catch std::runtime_error from Initialize(),
Document::Load(), Element construction, and RasterImage::Load*().
DOMException subclasses (e.g. TypeError, InvalidStateError) are thrown
for DOM spec violations.
| Category | Elements |
|---|---|
| Structure | <svg>, <g>, <defs>, <use>, <symbol> |
| Shapes | <rect>, <circle>, <ellipse>, <line>, <polyline>, <polygon>, <path> |
| Text | <text>, <tspan>, <textPath> |
| Paint | <linearGradient>, <stop> |
| Images | <image> (PNG, JPEG, PCX) |
| Animation | <animate>, <set>, <animateTransform>, <animateMotion> |
| Scripting | <script> (native C plugin API, not JavaScript) |
| Filters | <filter>, <feDropShadow> |
fill,stroke,stroke-width,opacity,fill-opacity,stroke-opacityfont-family,font-size,font-weight,font-styletransform,viewBox,preserveAspectRatio- Pseudo-classes:
:hover,:active,:focus
<radialGradient><clipPath>,<mask><pattern>,<marker>- Filter primitives beyond
<feDropShadow>(<feGaussianBlur>,<feBlend>,<feColorMatrix>, etc.) stroke-dasharray,stroke-linecap,stroke-linejoin- CSS attribute selectors (
[attr=value]) <a>(hyperlinks)
- Use CMake out-of-source builds (
-B build). - A pre-commit hook is configured by CMake; it validates style and copyright notices.
- If iteration speed matters, disable PCH with
-DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON. - CI workflows in
.github/workflows/are the best reference for known-good dependency sets.
If you want to use Zsh on MSYS2 with the powerlevel10k theme:
pacman -S zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"After installing oh-my-zsh, install powerlevel10k with:
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
sed -i "s/^ZSH_THEME=.*/ZSH_THEME=\"powerlevel10k\/powerlevel10k\"/" ~/.zshrcTo make MSYS2 terminals default to zsh, edit the corresponding .ini files under C:\msys64 and add:
SHELL=/usr/bin/zshIf you use MSYS2 bash or zsh in VS Code, add this to .bashrc or .zshrc:
export PATH="$PATH:$(cygpath "$LOCALAPPDATA/Programs/Microsoft VS Code/bin")"
[[ "$TERM_PROGRAM" == "vscode" ]] && . "$(cygpath "$(code --locate-shell-integration-path <zsh|bash>)")"Replace <zsh|bash> with the shell you are configuring.
No. Historical experiments existed, but the current codebase is C++ focused and does not require V8.
Yes. AeonGUI renders into a CPU-side pixel buffer (BGRA), regardless of whether the Cairo or Skia backend is selected. You can upload that buffer as a texture in OpenGL, Vulkan, Metal, DirectX, or any other API and composite it however you like. The demo applications show how to do this for OpenGL, Vulkan, Metal, and Direct3D12.
Basic shapes (rect, circle, ellipse, line, polyline, polygon,
path), text and tspan, image, g, defs, use, linearGradient,
radialGradient, and svg root elements. Transforms, CSS styling, and
viewBox / preserveAspectRatio are supported.
SMIL animation elements are supported: <animate> (paint properties,
geometry attributes, and corner-radius path animations), <set> (discrete
value changes), <animateTransform> (rotate, scale, translate, skewX,
skewY), and <animateMotion> (path-based motion with arc-length
interpolation). Animations can be triggered by time or by DOM events such
as click and mouseenter.
CSS pseudo-classes :hover, :active, and :focus are resolved
dynamically based on mouse input.
Filters, clip-path, mask, and advanced text features are not yet
implemented. See the SVG Feature Support section
for details.
Build the docs target:
cmake --build build --target docsThe HTML documentation is generated in build/docs/AeonGUI/.
- Source code: https://github.com/AeonGames/AeonGUI
- Issue tracker: https://github.com/AeonGames/AeonGUI/issues
- Pull requests: https://github.com/AeonGames/AeonGUI/pulls
- CI workflows: https://github.com/AeonGames/AeonGUI/actions
AeonGUI is released under the Apache License 2.0.
Copyright (C) 2019-2026 Rodrigo Jose Hernandez Cordoba
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The Aeon Games logo is a trademark and is not covered by Apache 2.0, it may not be used without express permission.
- Rodrigo Hernandez (
kwizatzataeongamesdotcom)