A modern, lightweight immediate-mode GUI library for C++20 and OpenGL 3.3.
Inspired by the visual language of Linear, Vercel, Raycast and Arc Browser — ClackUI delivers crisp typography, buttery-smooth animations and a fully themeable widget set with zero external dependencies beyond a C++20 compiler and OpenGL.
| Feature | Description |
|---|---|
| Zero dependencies | Only C++20 + OpenGL 3.3. No Qt, no ImGui, no SDL required. |
| Beautiful by default | Four production-ready themes — Dark, Light, Nord, Monokai. |
| Immediate mode | Familiar if (Button(...)) API — no retained state to manage. |
| Semantic theming | Widgets read from ThemeColors — no hardcoded hex values. |
| Smooth animations | 34 easing functions, spring physics, staggered appears. |
| Full Unicode | UTF-8 with Cyrillic, CJK, and FontAwesome icon font. |
| 44 widget types | Buttons to node editors, timelines, and 3D viewports. |
| Modular | Core, Platform, and Renderer are separate static libraries. |
Four built-in themes — switch at runtime with a single call:
| Theme | Inspiration | Primary | Background |
|---|---|---|---|
| ClackDark | Linear / Vercel | #6366F1 Indigo |
#111113 |
| ClackLight | GitHub / Notion / Figma | #2563EB Blue |
#FAFAFA |
| ClackNord | Nord (exact palette) | #88C0D0 Frost-2 |
#2E3440 |
| ClackMonokai | Monokai (classic) | #A6E22E Green |
#272822 |
All themes use a semantic colour system — onSurface, primary,
surfaceVariant, etc. — so every widget adapts automatically without
any conditional logic in your code.
| Category | Widgets |
|---|---|
| Buttons | Button, ButtonPrimary, ButtonSecondary, ButtonDanger, ButtonGhost, IconButton, ToggleButton |
| Input | TextInput, TextArea, NumberInput, SearchInput, PasswordInput, ComboBox |
| Selection | Checkbox, RadioButton, Toggle, Slider, RangeSlider |
| Display | Label, Heading, Code, Divider, Badge, Chip, Avatar, Spinner |
| Progress | ProgressBar (determinate + indeterminate) |
| Containers | Panel, Card, ScrollArea, Collapsible, TabBar, Modal, FloatingWindow |
| Navigation | Sidebar, SidebarItem, Toolbar, ToolbarButton, Breadcrumb, MenuItem |
| Data | Table, List, TreeView, PropertyGrid |
| Advanced | CodeEditor, CurveEditor, NodeEditor, Timeline, Viewport, Canvas |
| Overlays | Tooltip, Toast, ContextMenu, CommandPalette |
| Version | |
|---|---|
| C++ compiler | C++20 (MSVC 2022, GCC 12+, Clang 14+) |
| OpenGL | 3.3 Core Profile |
| CMake | 3.21+ |
| Windows SDK | 10.0+ (Win32 backend) |
git clone https://github.com/twiks228/ClackUI.git
cd ClackUI
cmake -B out/build -DCMAKE_BUILD_TYPE=Debug
cmake --build out/build --config DebugRun the sandbox:
out/build/bin/ClackUI.Sandbox.exe#include "clack/clack.h"
#include "clack/clack_context.h"
#include "clack/clack_platform_win32.h"
#include "clack/clack_renderer_opengl.h"
#include "clack/clack_widgets_button.h"
#include "clack/clack_widgets_text.h"
#include "clack/clack_nav_toast.h"
#include <glad/glad.h>
int main() {
using namespace clack;
// ── Platform ─────────────────────────────────────────────────────────
Win32Platform platform;
if (!platform.init("Hello ClackUI", 1280, 720, 3, 3)) return 1;
if (!gladLoadGL()) return 1;
// ── Renderer ──────────────────────────────────────────────────────────
ClackRendererOpenGL renderer;
if (!renderer.init()) return 1;
// ── Context ───────────────────────────────────────────────────────────
ContextConfig cfg{};
ClackContext *ctx = ClackContext::create(cfg);
ClackContext::setCurrentContext(ctx);
ctx->loadFont("resources/fonts/Inter-Regular.ttf", 16.0f);
ctx->setTheme(makeDarkTheme());
// ── Main loop ─────────────────────────────────────────────────────────
while (true) {
ClackInput input{};
if (!platform.pollInput(input)) break;
ctx->beginFrame(input);
// Your UI here
{
TextParams tp{};
tp.color = ctx->currentTheme().colors.onSurface;
Text("Hello, ClackUI!", tp);
}
SpacerV(12.0f);
{
ButtonParams bp{};
bp.variant = ButtonVariant::Primary;
bp.width = 160.0f;
if (Button("Click Me", bp))
ShowToast("Hello!", ToastType::Success, 2.0f);
}
DrawList &dl = ctx->endFrame();
ctx->fontSystem().resolveTextCommands(dl, renderer);
const i32 w = input.windowSize.x;
const i32 h = input.windowSize.y;
glViewport(0, 0, w, h);
glClearColor(0.07f, 0.07f, 0.09f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
renderer.renderDrawList(dl, (f32)w, (f32)h, w, h);
platform.swapBuffers();
}
// ── Cleanup ───────────────────────────────────────────────────────────
ClackContext::setCurrentContext(nullptr);
ClackContext::destroy(ctx);
renderer.shutdown();
platform.shutdown();
return 0;
}ClackContext *ctx = ClackContext::create(cfg);
ClackContext::setCurrentContext(ctx);
// every frame:
ctx->beginFrame(input);
// ... widget calls ...
DrawList &dl = ctx->endFrame();
ClackContext::destroy(ctx);ctx->setTheme(makeLightTheme()); // instant switch
ctx->setTheme(makeNordTheme());
ctx->setTheme(makeMonokaiTheme());
const ThemeColors &c = ctx->currentTheme().colors;
// c.primary, c.onSurface, c.surface, c.error, ...// Returns true on click
if (Button("Save", bp)) save();
// Text input
TextInput("Name", buf, sizeof(buf), tip);
// Slider
SliderParams sp{};
sp.min = 0.0f; sp.max = 1.0f; sp.showValue = true;
Slider("Volume", volume, sp);
// Layout
BeginRow(8.0f);
Button("A", bp);
Button("B", bp);
Badge("3");
EndRow();// 34 easing types
f32 t = easing::apply(EasingType::EaseOutBack, progress);
// Spring physics
Spring1D spring{};
spring.stiffness = 300.0f;
spring.damping = 20.0f;
spring.update(target, dt);
// Staggered appear
f32 p = staggeredProgress(index, time, 0.4f, 0.08f);ClackUI/
├── ClackUI.Core/ Core library (widgets, layout, draw, theme)
│ ├── include/clack/ Public C++ headers
│ └── src/
│ ├── advanced/ Canvas, CodeEditor, NodeEditor, Timeline, Viewport
│ ├── animation/ Easing functions, spring physics
│ ├── containers/ ScrollArea, Modal, TabBar, Collapsible, Window
│ ├── core/ ClackContext, WidgetID, Input
│ ├── data/ Table, List, TreeView, PropertyGrid
│ ├── dock/ DockSpace layout
│ ├── foundation/ Math, Memory, Hash, Log, Assert, Types
│ ├── layout/ Layout cursor, row layout, flex
│ ├── navigation/ Sidebar, Toolbar, Toast, Tooltip, Breadcrumb
│ ├── rendering/ DrawList, Font, FontAtlas, Icons, Image
│ ├── serialization/ JSON theme loader
│ ├── style/ Theme, ThemeColors, StyleSheet
│ └── widgets/ Button, Input, Slider, Text, Check, Color, Display
│
├── ClackUI.Editor/ IDE-style editor application
├── ClackUI.Platform.Win32/ Win32 window + WGL context + input
├── ClackUI.Platform.SDL3/ SDL3 cross-platform backend (in progress)
├── ClackUI.Renderer.OpenGL/ OpenGL 3.3 renderer + GLSL shaders
├── ClackUI.Sandbox/ Interactive demo (7 screens)
├── ClackUI.Tests/ Unit tests
│
├── resources/
│ ├── fonts/ Inter, JetBrains Mono, ClackIcons, FontAwesome
│ └── themes/ dark.json, light.json, nord.json
│
└── docs/ Full documentation
No widget ever uses a raw hex value. Every colour is resolved from ThemeColors:
ThemeColors
├── Surfaces surface · surfaceVariant · surfaceElevated · surfaceOverlay
├── Primary primary · primaryVariant · primaryHovered · primaryActive · onPrimary
├── Secondary secondary · onSecondary
├── Text onSurface · onSurfaceVariant · onSurfaceDisabled
├── Semantic error · onError · warning · success · info
├── Borders outline · outlineVariant · shadow
├── Interaction selection · selectionText · focus · link
├── Scrollbar scrollTrack · scrollThumb · scrollThumbHovered
└── Code codeBackground · codeForeground · codeKeyword
codeString · codeComment · codeNumber
buildWidgetStyles() derives every widget colour using only c.*, mt.*,
adjusted(), withAlpha() — so all four themes share one function body.
- Core widget set (44 types)
- Dark / Light / Nord / Monokai themes
- Win32 platform backend
- OpenGL 3.3 renderer
- 34 easing functions + spring physics
- Timeline, NodeEditor, CodeEditor, Viewport, Canvas
- Drag-to-dock live preview
- JSON theme hot-reload
- Vulkan renderer backend
- SDL3 backend (in progress)
- Accessibility labels and screen reader support
- RTL layout (Arabic, Hebrew)
- Web export via Emscripten
- Fork the repository and create a feature branch.
- Follow the
.clang-formatstyle (4-space indent, 100-column limit). - Add or update tests in
ClackUI.Tests/. - Open a pull request with a clear description.
Rule: All widgets must read colours from
ThemeColors— no hardcoded hex.
See CONTRIBUTING.md for the full guide.
MIT — see LICENSE for the full text.
| Resource | Author | License |
|---|---|---|
| Inter typeface | Rasmus Andersson | SIL OFL 1.1 |
| JetBrains Mono | JetBrains | SIL OFL 1.1 |
| Nord palette | Arctic Ice Studio | MIT |
| Tailwind CSS palette | Tailwind Labs | MIT |
| easings.net reference | Andrey Sitnik & Ivan Solovev | MIT |
| stb_truetype | Sean Barrett | Public Domain / MIT |
| glad | David Herberth | MIT / CC0 |
| FontAwesome Free | Fonticons, Inc. | CC BY 4.0 / SIL OFL 1.1 / MIT |
Made with care for modern C++ developers.