Skip to content

twiks228/ClackUI

ClackUI

{51015F48-02F6-48AE-8F16-4ECCAAA73DF6}

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.

C++20 OpenGL License Platform Widgets


Why ClackUI?

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.

Themes

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 systemonSurface, primary, surfaceVariant, etc. — so every widget adapts automatically without any conditional logic in your code.


Widget Categories

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

Quick Start

Requirements

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)

Build

git clone https://github.com/twiks228/ClackUI.git
cd ClackUI
cmake -B out/build -DCMAKE_BUILD_TYPE=Debug
cmake --build out/build --config Debug

Run the sandbox:

out/build/bin/ClackUI.Sandbox.exe

Minimal Example

#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;
}

API at a Glance

Context Lifecycle

ClackContext *ctx = ClackContext::create(cfg);
ClackContext::setCurrentContext(ctx);

// every frame:
ctx->beginFrame(input);
// ... widget calls ...
DrawList &dl = ctx->endFrame();

ClackContext::destroy(ctx);

Themes

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, ...

Widgets

// 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();

Animations

// 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);

Project Structure

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

Colour System

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.


Roadmap

  • 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

Contributing

  1. Fork the repository and create a feature branch.
  2. Follow the .clang-format style (4-space indent, 100-column limit).
  3. Add or update tests in ClackUI.Tests/.
  4. 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.


License

MIT — see LICENSE for the full text.


Acknowledgements

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.

Star on GitHub · Documentation · Report Issues

About

Modern immediate-mode GUI library for C++20 and OpenGL 3.3 with themes, animations, advanced widgets, and editor tooling.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages