⚠️ This project is still a work in progress.
Named after Alan Kay, Kay is a C++ toolkit for building fast and efficient graphical user interfaces on top of OpenGL. Designed specifically for Wayland applications and compositors on Linux, it simplifies complex tasks like damage tracking and layout management, allowing you to focus on creating clean, responsive interfaces.
- Prebuilt Components: A collection of built-in components that react to user events.
- Custom Components: APIs to create custom UI elements using Skia.
- Flexbox Layouts: A Flexbox-compliant layout system powered by Yoga.
- Damage Tracking: Efficient rendering with built-in damage tracking.
- Fractional Scaling: Support for high-DPI displays and fractional scaling.
- Screen Transforms: Handle rotated or flipped screens with ease.
- Event System: Easy integration with input event subsystems.
Kay specializes in UI rendering and requires an OpenGL context along with external input events to function. For window management and related functionality, consider:
- Marco: For building Wayland applications.
- Louvre: For building Wayland compositors.
- SRM + Libinput: A combination for creating DRM/KMS applications.
-
AKScene:
TheAKScene
manages a tree of nodes, calculating their positions and dimensions, rendering them, and handling tasks like damage tracking. It ensures efficient composition and rendering of the entire UI hierarchy. -
AKTarget:
AnAKTarget
defines where a scene renders, providing essential details like the viewport, scaling factor, buffer age, and optional clipping. It also grants access to damage and opaque regions generated by the scene.- For Applications: Typically, each window has its own scene and target, as components are usually displayed in one window at a time.
- For Compositors: A single scene can be shared across multiple targets (e.g., one per screen), enabling features like dragging windows between screens. Nodes maintain their state per target, ensuring damage regions are managed correctly for each rendering context.
-
AKNode:
AnAKNode
is the fundamental building block for components with its own layout and nesting capabilities. Depending on its role, a node can function as:- AKContainer: A node with no rendering capabilities, serving only as a container for other nodes. It can also optionally clip its children by its bounds.
- AKRenderable: Nodes with an
onRender()
virtual method to draw content directly into the current target using internal shaders (AKPainter). They are useful for displaying textures (e.g., Wayland surfaces), solid colors, and creating efficient mask effects. Examples of built-in renderable nodes include AKImage and AKSolidColor. Skia can also be used within anonRender()
event, but its performance is considerably worse than the built-in shaders, so it is recommended to be used sparingly. - AKBakeable: These nodes have their own framebuffer with dimensions given by the current target properties (e.g., scaling factor). They have an
onBake()
event and can be used to avoid re-creating complex components each time, allowing the scene to re-composite them efficiently if they only move. Their framebuffers only grow in size when resized to avoid re-creating them each time, but can be automatically or manually shrunk if memory needs to be saved. They are a subclass of AKRenderable, but the defaultonRender()
implementation is used to perform their composition into the target. - AKSubScene: A subclass of AKBakeable that renders its children into its own framebuffer. This allows for sophisticated post-processing effects and avoids frequent re-compositing of subtrees. Since children nodes are baked into the framebuffer, they are always clipped by its bounds.
- AKBackgroundEffect: A subclass of AKRenderable used to generate effects such as shadows, blur, etc.
Example running on top of Louvre (everything being rendered and composited by Kay):