Skip to content
fovea-enginePublic

About

Material Design 3 inspired immediate-mode GUI library for raylib. Build modern, beautiful user interfaces in C++ with automatic resource management.

Topics

Resources

Stars

28 stars

Watchers

0 watching

Forks

Repository files navigation

raym3 - Material Design 3 UI Library for Raylib

raym3 is a Material Design 3 inspired immediate-mode GUI library built on raylib. It provides a subset of Material Design 3 components with automatic resource management, making it easy to create modern, beautiful user interfaces in C++ applications.

Author: Jordan Miller (@nanofuxion)

Demo

raym3 demo

The clip is a fresh capture of the v2 demo: same-frame layout, an editable text field, notification badge, selected chip, navigation indicator, bottom-sheet motion, carousel, checkbox motion, and shape morphs. The GIF is a visual sampler; the v2 component catalog and text/font/rendering features are listed below.

Features

  • Material Design 3 Inspired - Implements Material Design 3 design principles and components
  • v2 Composable API - Retained raym3::v2 View tree with style objects, same-frame layout, a Material component catalog, text input editing, CSS transitions, a mutation-batch protocol, and Flutter-style CSS density scaling
  • Immediate-Mode API - Simple, intuitive API similar to raygui
  • Automatic Resource Management - Icons and fonts are automatically discovered or can be embedded
  • Optional Yoga Layout - Flexbox layout support for advanced UI composition
  • Roboto Font Support - Roboto v3 (from roboto-3-classic); can be loaded from disk or embedded for portable deployment
  • Light and Dark Themes - Full theme support with Material Design 3 color system
  • SVG Icon Support - Material Design icons with multiple variations (filled, outlined, round, sharp, two-tone)
  • Inline SVG Rendering - Rasterize and cache arbitrary SVG documents, including RGBA fills and opacity
  • Platform Font Fallback - Native system UI fonts by default, CSS-family resolution, and glyph coverage fallback
  • Transformed Overflow Clipping - Rounded clipping and hit testing follow nested rotation and scale transforms
  • Zero External Dependencies - Can be built as a standalone library (raylib is fetched automatically)
  • Scissor Stack API - Stack-based clipping with PushScissor/PopScissor, debug visualization

Components

raym3 currently implements the following Material Design 3 components:

Input Components

  • Button - Text, Filled, Outlined, Tonal, Elevated variants with keyboard activation and optional tooltips
  • IconButton - Buttons with Material Design icons, keyboard activation, and optional tooltips
  • TextField - Single-line text input with word/line navigation, double-click word selection, triple-click select all, word/character drag extension, Escape to revert, and I-beam cursor
  • SearchBar - M3 contained search input with leading/trailing icon slots
  • Checkbox - Standard checkbox with label, keyboard activation (Space/Enter), pointer cursor, and optional tooltips
  • Switch - Toggle switch with keyboard activation (Space/Enter), pointer cursor, and optional tooltips
  • RadioButton - Radio button with label, keyboard activation (Space/Enter), pointer cursor, and optional tooltips
  • Slider - Value slider with keyboard navigation (Arrow/Page/Home/End), mouse wheel, focus ring, pointer/resize cursors, and optional tooltips
  • RangeSlider - Multi-thumb range slider with Tab key thumb cycling, keyboard navigation, focus ring, and optional tooltips
  • Chip - Assist, filter, input, and suggestion chips with M3 selection and state layers
  • FloatingActionButton - FAB and extended FAB with regular/medium/large M3 Expressive sizes and color roles

Display Components

  • AppBar - Small, center-aligned, medium, and large app bars with navigation/actions
  • Badge - Small status dots and large labeled badges for icons/navigation
  • Card - Elevated surface container with multiple variants
  • Dialog - Modal dialog with customizable buttons
  • Modal - Full-screen modal component with backdrop and text input support
  • Menu - Dropdown menu with leading/trailing icons, dividers, gaps, icon-only mode, disabled items, pointer cursor, and per-item tooltips
  • List - Material Design list component with keyboard navigation (Arrow/Page/Home/End), Shift multi-select, Ctrl+A select all, typeahead search, drag reorder, pointer cursor, and per-item tooltips
  • NavigationBar / NavigationRail - M3 destination navigation with active indicators, labels, and badges
  • SegmentedButton - Segmented button groups
  • ProgressIndicator - Circular and linear progress indicators
  • Divider - Horizontal and vertical dividers
  • Text - Typography component with multiple weights and alignments
  • Icon - Material Design icons with multiple variations

Layout Components

  • Container - Flexbox-based layout container (requires Yoga)
  • View3D - 3D viewport component

Feedback Components

  • Tooltip - Hover tooltips with smart timing, configurable placement, and developer-defined text
  • Snackbar - Temporary notification messages
  • TabBar - Browser-style tab bar with closeable tabs, drag reorder, icons, and tooltips

Note: This is a partial implementation of Material Design 3. The immediate-mode list above names the established raym3:: components. The raym3::v2 catalog is broader, but catalog presence does not guarantee a complete spec implementation: some entries use generic token-driven rendering. See the v2 guide and component audit for coverage and limitations.

Composable v2 API

The v2 API builds a persistent View tree and lays it out in the current frame. Alongside View, Text, TextInput, Button, and custom render nodes, its M3Component catalog names: AppBar, Badge, Banner, BottomAppBar, BottomSheet, DataTable, DockedToolbar, FloatingToolbar, ButtonGroup, Button, Card, Carousel, Checkbox, Chip, DatePicker, Dialog, Divider, ExtendedFab, Fab, FabMenu, IconButton, List, LoadingIndicator, Menu, MenuItem, NavigationBar, NavigationBarItem, NavigationDrawer, NavigationRail, ProgressIndicator, RadioButton, RangeSlider, Search, SegmentedButton, SideSheet, Slider, Snackbar, SplitButton, Switch, Tabs, TextField, TimePicker, Toolbar, Tooltip, and Popover.

Core v2 capabilities include:

  • Same-frame layout, retained node identity, transforms, rounded overflow clipping, and clipped hit testing.
  • CSS-like styles, multi-layer and linear/conic gradients, transitions, density and OS font scaling, text spans, selection geometry, and selectable text.
  • Text input with caret/selection, word navigation, multi-click selection and drag extension, plus host hooks for clipboard, haptics, and native editor integration.
  • Native system UI font selection, CSS family/weight/style resolution, missing-glyph fallback, SVG view rendering, and platform emoji font support.

Component details and implementation caveats are tracked in the v2 guide. Start with v2 best practices when wiring up an app: it covers the build options, retained trees, and the per-frame input loop.

Quick Start

#include "raym3/raym3.h"
#include <raylib.h>

int main() {
    InitWindow(800, 600, "raym3 Example");
    SetTargetFPS(60);
    
    raym3::Initialize();
    raym3::SetTheme(false); // Light mode
    
    char textBuffer[256] = "";
    bool checked = false;
    float sliderValue = 50.0f;
    std::vector<float> rangeValues = {20.0f, 80.0f};
    int selectedMenuItem = 0;
    
    while (!WindowShouldClose()) {
        BeginDrawing();
        ClearBackground(raym3::Theme::GetColorScheme().surface);
        
        raym3::BeginFrame();
        
        if (raym3::Button("Click Me", {100, 100, 120, 40})) {
            // Button clicked
        }
        
        raym3::IconButton("home", {100, 150, 48, 48}, 
                         raym3::ButtonVariant::Filled,
                         raym3::IconVariation::Filled);
        
        // TextField with custom background and automatic cursor inversion
        raym3::TextFieldOptions options;
        options.backgroundColor = PURPLE;
        options.textColor = WHITE;
        raym3::TextField(textBuffer, sizeof(textBuffer), {100, 210, 200, 56}, "Label", options);
        
        raym3::Checkbox("Check me", {100, 280, 200, 24}, &checked);
        
        // Slider with discrete mode and tick marks
        raym3::SliderOptions sliderOpts;
        sliderOpts.stepValue = 10.0f;
        sliderOpts.showTickMarks = true;
        sliderOpts.showStopIndicators = true;
        sliderValue = raym3::Slider({100, 320, 200, 40}, sliderValue, 0.0f, 100.0f, "Slider", sliderOpts);
        
        // Range slider for selecting a range
        raym3::RangeSliderOptions rangeOpts;
        rangeOpts.showValueIndicators = true;
        rangeValues = raym3::RangeSlider({100, 380, 200, 40}, rangeValues, 0.0f, 100.0f, "Range", rangeOpts);
        
        // Menu with icons, dividers, and gaps
        static raym3::MenuItem menuItems[] = {
            {"Home", "home"},
            {"Settings", "settings"},
            {nullptr, nullptr, nullptr, nullptr, true}, // Divider
            {"Profile", "person"},
            {nullptr, nullptr, nullptr, nullptr, false, true}, // Gap
            {"Logout", "logout"}
        };
        raym3::Menu({100, 440, 200, 240}, menuItems, 6, &selectedMenuItem);
        
        raym3::EndFrame();
        EndDrawing();
    }
    
    raym3::Shutdown();
    CloseWindow();
    return 0;
}

TextField Features

The TextField component supports several advanced features:

  • Custom Colors: Set backgroundColor and textColor in TextFieldOptions
  • Automatic Cursor Inversion: Cursor color automatically inverts based on background luminance
  • Password Mode: Set passwordMode = true to mask input
  • Input Masking: Use regex patterns via inputMask for validation
  • Undo/Redo: Built-in support with configurable history depth via maxUndoHistory
  • Icons: Add leadingIcon and trailingIcon with click callbacks
  • Read-Only: Set readOnly = true to prevent editing
  • Multi-click Selection: Completed stationary double/triple clicks select words or all text; dragging after a multi-click extends the selection by word or character

SVG Rendering

raym3::SvgRenderer::DrawDocument(source, bounds, opacity) renders an inline SVG document into a cached texture. Repeated source documents reuse the bounded cache. This supports native v2::View SVG rendering as well as direct raym3 drawing. SVG fill RGBA and composed fill opacity are preserved.

Native Font Selection

On native platforms the default body face follows the system UI font. CSS family stacks can resolve platform fonts by family, weight, and style, with system fallback faces selected for missing glyphs. Emscripten continues to use bundled Roboto. Embedded resources do not change the native default.

Rendering and Clipping

Nested overflow clips account for rotation, scale, rounded corners, and hit testing. The renderer also fixes clipping balance, texture and atlas releases during a frame, and frame statistics when multiple rendering contexts are used.

Menu Component Features

The Menu component supports:

  • Leading Icons: Display icons on the left side of menu items
  • Trailing Text/Icons: Show additional text or icons on the right
  • Dividers: Add visual separators with isDivider = true
  • Gaps: Create spacing between items with isGap = true
  • Icon-Only Mode: Set iconOnly = true for compact horizontal menus
  • Disabled Items: Set disabled = true to prevent interaction

Slider Component Features

The Slider component supports M3 Expressive customization:

  • Discrete Mode: Set stepValue > 0 to snap to specific increments
  • Tick Marks: Enable showTickMarks to display step indicators in discrete mode
  • Stop Indicators: Enable showStopIndicators to show dots at min/max positions
  • Inset Icons: Add icons inside the track (startIcon, endIcon)
  • Value Indicator: Show a value bubble above the thumb on drag (showValueIndicator)
  • Start/End Text: Add text labels
  • Track Colors: Customize active/inactive track colors
  • Handle Color: Customize the handle thumb color
  • End Dot: Customize or hide the end-of-track dot

RangeSlider Component Features

The RangeSlider component provides multi-thumb range selection:

  • Multiple Thumbs: Support for any number of thumbs via std::vector<float>
  • Range Fill: Active track fill between first and last thumb
  • Thumb Constraints: Thumbs cannot cross each other
  • Minimum Distance: Set minDistance to enforce spacing between thumbs
  • Discrete Mode: Supports stepValue and showTickMarks like Slider
  • Value Indicators: Show value bubbles for all thumbs when dragging
  • Stop Indicators: Display min/max position markers

Building

Basic Usage (CMake)

add_subdirectory(raym3)
target_link_libraries(your_target raym3)

Yoga Layout (on by default)

v2 layout uses Yoga flexbox, so alignItems, justifyContent and the rest behave like CSS. It is fetched automatically, or found as a sibling yoga directory. To use your own copy:

add_subdirectory(yoga)
add_subdirectory(raym3)
target_link_libraries(your_target raym3)

RAYM3_USE_YOGA=OFF swaps in a basic stacking layout that ignores flex alignment.

Anti-aliasing (on by default)

raym3 requests 4x MSAA for the raylib window, so shapes have smooth edges. The request happens before main(), so no code is needed. To turn it off:

set(RAYM3_ANTIALIASING OFF CACHE BOOL "" FORCE)

macOS window transparency and titlebars

RayM3 can configure raylib's native Cocoa window without replacing raylib's renderer. Request a transparent framebuffer before creating the window, then configure Cocoa after InitWindow:

SetConfigFlags(FLAG_WINDOW_TRANSPARENT);
InitWindow(800, 600, "My transparent app");

raym3::platform::MacOSWindowOptions windowOptions;
windowOptions.transparentBackground = true;
windowOptions.fullSizeContentView = true;
windowOptions.transparentTitlebar = true;
raym3::platform::ConfigureMacOSWindow(windowOptions);

For desktop transparency, clear/draw with alpha zero in areas that should reveal the desktop. raylib's FLAG_WINDOW_TRANSPARENT must be set before InitWindow; setting Cocoa's window opacity afterward cannot add the missing framebuffer alpha channel. Existing opaque ClearBackground calls will continue to produce an opaque surface. Cocoa compositing is native desktop transparency; it is not Liquid Glass, which is a system material effect rather than a general raylib drawing API. Set hideTitlebar to hide the native titlebar while retaining standard window controls. fullSizeContentView allows custom raylib content to extend into the titlebar area. These options are macOS-specific and are no-ops on other platforms.

Windows and Linux support is a future platform task: Windows needs evaluation of layered/composition window support and its interaction with raylib's swapchain; Linux support depends on compositor and X11/Wayland backend capabilities. Neither is implemented yet.

On macOS, SetMacOSWindowMaterialRegions places rounded AppKit blur materials behind specified raylib-coordinate regions. SetMacOSWindowDragRegions marks blank custom-titlebar areas that should initiate native window dragging. Drag regions intercept mouse input, so keep custom controls out of them. The native close, minimize, and zoom buttons still receive clicks and hover when a drag region covers them. In v2, Style.opacity applies opacity to an individual view/container and its rendered contents; background colors can also carry alpha independently.

Set MacOSWindowOptions::showWindowBorder to draw a native rounded edge around a transparent window (off by default; windowBorderCornerWidth can make the corners heavier than the edges), and call SetMacOSWindowControlsPosition to place the close, minimize, and zoom buttons in raylib window coordinates while retaining their native behavior.

Font Configuration (Project-Agnostic)

RayM3 supports Roboto v3.015 from roboto-3-classic. Native UI text defaults to the platform system UI face; Emscripten uses the bundled Roboto faces. This applies to projects using RayM3 as a submodule or standalone on macOS, Windows, Linux, Android, and Web/WASM.

  • Native UI default: SF, Segoe UI, or the platform fontconfig-selected face. It remains the default whether resources are embedded or not.
  • Web UI default: bundled Roboto regular/bold faces; no system font file lookup is required.
  • Resource embedding (RAYM3_EMBED_RESOURCES): controls icon/resource embedding and does not switch the native system UI font to Roboto.
set(RAYM3_EMBED_RESOURCES ON CACHE BOOL "" FORCE)  # Bundle icon/resources
add_subdirectory(raym3)

With Input Layers Support

To enable the layer-based input system with automatic input blocking and capture:

set(RAYM3_USE_INPUT_LAYERS ON CACHE BOOL "" FORCE)
add_subdirectory(raym3)
target_link_libraries(your_target raym3)

Input Layers Features:

  • Automatic Input Blocking: Higher Z-order layers automatically block input to lower layers
  • Input Capture: Drag operations must start within component bounds (prevents accidental drags)
  • Explicit Z-Ordering: Use PushLayer(zOrder) and PopLayer() to control rendering order
  • Component Blocking: Cards and panels automatically block input to elements beneath them
  • Overlay Layer Threshold: Layers with zOrder >= 100 bypass layout scissor clipping (for menus, tooltips, dialogs)

Usage Example:

raym3::BeginFrame();

// Layer 0 - Background
raym3::Button("Background", {100, 100, 120, 40});

// Layer 1 - Overlay panel
raym3::PushLayer(1);
raym3::Card({200, 150, 400, 300}, raym3::CardVariant::Elevated);
raym3::Button("Overlay Button", {220, 170, 120, 40});
raym3::PopLayer();

raym3::EndFrame();

Input Capture for Viewports:

Rectangle viewportBounds = {100, 100, 400, 300};

// Register as blocking region
raym3::InputLayerManager::RegisterBlockingRegion(viewportBounds, true);

// Only process camera controls if drag started in viewport
bool canProcessInput = raym3::InputLayerManager::BeginInputCapture(
    viewportBounds, 
    true  // requireStartInBounds = true
);

if (canProcessInput) {
    // Process camera rotation/zoom
    if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) {
        // Rotate camera
    }
}

Emscripten / WebAssembly

raym3 supports building for Emscripten. The CMake configuration automatically sets GRAPHICS_API_OPENGL_ES3 for WebAssembly targets.

Embed Resources into Library

To embed SVG icons and fonts directly into the static library (no external files needed):

set(RAYM3_EMBED_RESOURCES ON CACHE BOOL "" FORCE)
add_subdirectory(raym3)
target_link_libraries(your_target raym3)

Icon Optimization: By default, when RAYM3_EMBED_RESOURCES=ON, raym3 embeds the lightweight manifest in resources/icons/core-icons.txt, or a custom newline-delimited manifest provided with RAYM3_ICON_MANIFEST. This avoids embedding the full 10,000+ SVG catalog. If you need all icons embedded (e.g., for dynamic icon loading), set:

set(RAYM3_EMBED_RESOURCES ON CACHE BOOL "" FORCE)
set(RAYM3_EMBED_ALL_ICONS ON CACHE BOOL "" FORCE)
add_subdirectory(raym3)

Resource Management

raym3 automatically discovers resources in the following order:

  1. Embedded Resources (if RAYM3_EMBED_RESOURCES=ON)
  2. CMake-defined resource directory (set at build time)
  3. Relative paths (./resources/icons, ./raym3/resources/icons, etc.)

Icons are expected in the structure:

resources/
  icons/
    filled/
      icon_name.svg
    outlined/
      icon_name.svg
    round/
      icon_name.svg
    sharp/
      icon_name.svg
    two-tone/
      icon_name.svg

Fonts are expected in:

resources/
  fonts/
    Roboto/
      Roboto-Regular.ttf
      Roboto-Bold.ttf
      ...

Icon Manifests & Autocomplete

raym3 embeds and installs a lightweight icon subset by default. To generate an app-specific manifest from source usage:

cd raym3 && python3 tools/generate_icon_manifest.py --root ../your-app --output resources/icons/app-icons.txt

Then configure with:

set(RAYM3_ICON_MANIFEST "${CMAKE_CURRENT_SOURCE_DIR}/raym3/resources/icons/app-icons.txt" CACHE FILEPATH "" FORCE)

Use RAYM3_EMBED_ALL_ICONS=ON or RAYM3_INSTALL_ALL_ICONS=ON only when dynamic icon names require the full catalog.

Dependencies

  • raylib (required) - Automatically fetched via CMake FetchContent, default tag 6.0
  • yoga (optional) - Flexbox layout engine, enabled via RAYM3_USE_YOGA, default tag v3.2.1

See docs/v2-upgrade.md for the new v2 API, same-frame layout, dependency, and icon manifest details.

Credits and Acknowledgments

raym3 is built using the following excellent open-source projects:

Core Libraries

  • raylib - A simple and easy-to-use library to enjoy videogames programming

    • License: zlib/libpng
    • Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
  • NanoSVG - Simple stupid SVG parser

    • License: zlib/libpng
    • Copyright (c) 2013-14 Mikko Mononen memon@inside.org
    • Used for parsing and rasterizing SVG icons
  • Yoga - A cross-platform layout engine

    • License: MIT
    • Copyright (c) Meta Platforms, Inc. and affiliates
    • Optional dependency for flexbox layout support

Resources

  • Material Design Icons - Material Design icon set

    • License: Apache License 2.0
    • Copyright (c) Google LLC
    • Over 10,000 SVG icons included in multiple variations (filled, outlined, round, sharp, two-tone)
  • Roboto Font Family (v3.015) - Material Design typeface

    • License: Apache License 2.0
    • Copyright (c) Google LLC
    • Native builds default to the system UI face; Emscripten defaults to bundled Roboto

Design System

  • Material Design 3 - Google's Material Design system
    • Design guidelines and specifications
    • Color system, typography, and component specifications

License

raym3 is licensed under the zlib/libpng license, the same as raylib.

Copyright (c) 2025 Jordan Miller (@nanofuxion)

See LICENSE file for full license text.

Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.

We're particularly interested in contributions that add more Material Design 3 components to expand the library's functionality. Some high-priority components that would be valuable additions include:

  • NavigationDrawer
  • DataTables
  • BottomSheet
  • SideSheet
  • Carousel
  • Date/Time Pickers

Support

If you find raym3 useful and would like to support its development, you can:

ko-fi

Project Status

raym3 is an independent, self-contained project. Icons come from the material-design-icons submodule. Native UI text uses the platform system font by default, while Emscripten uses bundled Roboto. Resource embedding does not change the native font default.

Current Status: Partial implementation of Material Design 3 components. The library is functional and ready to use, but many components from the full Material Design 3 specification are not yet implemented.

Changelog

v2.0.0 - Rayact sync (in the repo, not tagged as a release yet)

This brings in the work done for Rayact: text spans and selection, real CSS gradients, retained layout, external views, a system UI font and OS text-size scaling. It has breaking changes, listed first.

Breaking: source changes (your code stops compiling)

  • LinearGradient now starts with GradientKind kind, then angleDegrees, centerX, centerY, stops. LinearGradient{90.0f, {...}} no longer compiles. Use designated initializers or assign the fields.
  • TextLayoutOptions, PreparedSegment, RenderStats gained members in the middle (fontStyle, maxLines, overflow, spanIndex, paintedCount). Positional brace-initialisation breaks or silently shifts values. Use designated initializers.
  • v2::Node has a new const stableId, so it can be copied but no longer assigned or swapped. Construct a new node instead of assigning.
  • Node::preparedTextKey is removed. It is replaced by preparedTextGeneration and preparedTextRevision. Compare preparedTextCache->source and ->options plus the generation instead.
  • TextFieldVariant gained Plain. A switch over it without default warns, and errors under -Werror=switch.
  • ActiveAnimation::elapsedMs is now a double. Only code that binds a float& to it is affected.
  • TextCacheKey(...) and BeginInputFrame(...) gained trailing defaulted parameters. Calls compile as before. Function pointers or std::function bound to the old signatures do not.
  • TextStyle gained many fields in the middle. Designated initializers are fine, positional ones break.
  • Style.h now includes <algorithm> and Density.h.
  • CMake: with RAYM3_USE_YOGA=ON, RAYM3_FETCH_DEPS=OFF and no yogacore target, configure now stops with an error. It used to warn and turn Yoga off.

Breaking: behaviour changes (same code, different result)

  • Gradient angles follow CSS. 0 points up and angles run clockwise, so 180 is top to bottom and 90 is left to right. Before, angles snapped to four blends and 90 painted top to bottom. Multi-stop gradients now honour every stop. Rewrite 90 as 180 for a vertical gradient.
  • Alpha is honoured for backgroundColor and borderColor. Semi-transparent colours used to paint opaque.
  • font-size is the em size. Text draws roughly 10-15% larger than before (a 24 px label measured about 11% wider) and wraps sooner, so layouts shift.
  • The default font on native platforms is the system UI font (SF, Segoe UI, fontconfig), not Roboto. Roboto is the default only on Emscripten.
  • Long unbreakable words wrap at the line width. They used to produce one letter per line.
  • OS text scale applies to text and text fields once the host calls Density::SetFontScale. The default is 1.0, so nothing changes until then. Opt out per run with allowFontScaling = false.
  • Node ids are never reused. DisposeNode now removes the node from its parent, and clears root if the root is disposed. It used to stay alive and keep painting.
  • Scrolling: the fling velocity tracker scales to the real frame rate, and a second flick within 400 ms adds the leftover momentum of the first.
  • Fixed-position z-order uses a precomputed key. The old sort had undefined behaviour, so ties may order differently.
  • Clipping: a scissor that does not overlap now pushes an empty rect, which fixes an unbalanced clip stack. Vulkan (rlvk) uses real stencil rounded clipping. WebGPU (rlwg) falls back to a square scissor.
  • Emoji: Windows uses DirectWrite and macOS/iOS use CoreText. A custom emoji font now overrides the OS rasteriser.
  • overflow: hidden still clips to the outer edge of the border, not the padding box. This is unchanged, but note it if you put images in bordered, rounded nodes.

v2.1.0 - Text, fonts, SVG, and clipping

  • TextField double-click selects a word, triple-click selects all, and dragging after multi-click extends selection.
  • Native UI uses platform system fonts with CSS-family resolution and missing-glyph fallback; WebAssembly continues to use bundled Roboto.
  • Added cached inline SVG document rendering with RGBA fill and opacity support.
  • Fixed transformed rounded overflow clipping and descendant hit testing, along with renderer resource lifetime and frame-stat handling.
  • Improved emoji font selection and rendering across supported platforms.
  • Yoga flexbox layout and 4x MSAA anti-aliasing are on by default (RAYM3_USE_YOGA, RAYM3_ANTIALIASING). v1 Layout was a no-op without Yoga.
  • v2 TextInput follows HTML input rules with a mouse: mousedown focuses, double-click selects a word, drag extends by words, autoFocus works.
  • Cursor no longer flickers or sticks as an I-beam; EndFrame only changes the OS cursor when the request changes.
  • v1 checkbox, radio, and switch draw vector marks instead of an icon font raym3 does not ship.
  • New example_v1_demo, rebuilt v2 demo, and docs: v2 best practices and v1 immediate mode.

Added

  • Selectable Text (TextStyle::selectable) with shared selection geometry, and styled spans inside one Text node.
  • CSS gradients: linear and conic, evaluated per pixel with dithering, multiple background layers, border-area clipping.
  • ExternalView for native views embedded in the tree.
  • Percent dimensions, per-edge borders, caret and selection colours, maxLines, overflow, underline and line-through.
  • Density::Set/GetFontScale, FontManager glyph-cache helpers, system UI font lookup.
  • RetainedLayout* (opt-in), CancelFling, ReplayCurrentClips, SetSelectionMenuHost, SetHostClickCount.

Fixed

  • Rounded gradients drew nothing on plain raylib OpenGL/GLES. The gradient meshes (linear, conic and border-area) wind their triangles clockwise on screen, and raylib's plain GL path culls those. Culling is now switched off around each mesh, with the batch flushed on both sides. Checked by rendering linear gradients on macOS OpenGL 3.3. Conic and border-area got the same change but were not rendered, and the Metal, Vulkan and WebGPU backends were not run.
  • Rounded corners on a horizontal gradient came out chamfered. The extra rows for the corner were spread over the whole height. They are now packed into the two corner bands.
  • Layout no longer marks every node dirty each frame. Text cache keys are no longer rebuilt on every measure.
  • Clip-stack balance, mid-frame atlas and texture frees, frame stats read from the context that rendered.

v1.5.0 - Scissor API & Emscripten Support

  • Scissor Stack API: Public PushScissor, PopScissor, BeginScissor, GetCurrentScissorBounds for custom clipping regions. Scissors intersect and stack correctly.
  • Scissor Debug: SetScissorDebug, IsScissorDebug, DrawScissorDebug for visualizing active scissor regions.
  • Overlay Layer Threshold: Input layers with zOrder >= 100 bypass layout scissor (menus, tooltips, dialogs render above clipped content).
  • Emscripten: Automatic GRAPHICS_API_OPENGL_ES3 for WebAssembly builds.
  • Layout: Scroll containers and GetActiveScissorBounds now use the shared scissor stack.
  • Slider, TextField, RangeSlider: Use PushClipRect/PopClipRect to restore parent clip. For custom content in scroll containers, call PushScissor(Layout::GetActiveScissorBounds()) and PopScissor().

v1.4.0 - Stable Layout IDs

  • Layout Flicker Fix: Eliminated UI flicker when layout structure changes (adding/removing elements, switching tabs) by implementing stable hash-based node IDs instead of sequential numbering.
  • Stable Node IDs: Layout node IDs now use FNV-1a hashing based on tree hierarchy rather than sequential order. IDs remain stable when siblings are added/removed.
  • New Layout API: Added PushId(const char*), PushId(int), and PopId() for advanced manual ID control in complex layouts.
  • Backward Compatible: All existing code continues to work. SetIdOffset maintains compatibility while integrating with the hash-based system.

v1.3.0 - UX Overhaul & Tooltip System

  • Buffered Cursor System: Added RequestCursor() API - cursor is set once per frame in EndFrame() to prevent flickering when multiple components render. Components call RequestCursor() instead of SetMouseCursor() directly.
  • Tooltip Smart Timing: Tooltips show instantly (50ms) after the first tooltip in a session. Returns to normal delay after 2 seconds of inactivity.
  • Tooltip Support: Added optional tooltip and tooltipPlacement fields to ButtonOptions, SliderOptions, RangeSliderOptions, IconButtonOptions, CheckboxOptions, SwitchOptions, RadioButtonOptions, ListItem, MenuItem, and TabItem.
  • TextField Enhancements: Reduced horizontal padding, fade gradient for overflow text, triple-click select all, Escape to revert, Cmd+Backspace/Alt+Backspace word/line deletion, auto-scroll during drag selection, I-beam cursor on hover.
  • Slider & RangeSlider: Added focus management, keyboard navigation (Arrow keys with Shift 10x, Page Up/Down 20%, Home/End min/max), mouse wheel support, focus ring, pointer/resize cursors.
  • RangeSlider: Tab key cycles between thumbs when focused.
  • List Component: Added keyboard navigation (Up/Down/Home/End/Page Up/Page Down), Shift+Arrow for multi-select range, Ctrl+A select all, Escape to deselect, Enter to activate, Space to toggle, typeahead search with 500ms timeout.
  • Menu Component: Added pointer cursor on hover for icon-only and standard menus.
  • TabBar: Added tooltip support for individual tabs.
  • Button & IconButton: Added keyboard activation (Space/Enter) when focused, pointer cursor on hover.
  • Checkbox, RadioButton, Switch: Added keyboard activation (Space/Enter), pointer cursor, focus management with click-away blur.
  • Focus Management: All focusable components lose focus when clicking outside their bounds.

v1.2.0 - Tooltip and TabBar

  • Tooltip Component: New Tooltip() function and TooltipManager for deferred tooltip rendering
  • TabBar Component: Browser-style tab bar with closeable tabs, drag reorder, loading/audio indicators, add tab callback, and text truncation

v1.1.0

  • Removed Native Text Input: The useNativeInput option in TextFieldOptions has been removed along with the RAYM3_ENABLE_NATIVE_TEXT_INPUT CMake option. The TextField component now provides full native-like text editing behavior (keyboard shortcuts, word/line navigation, selection, undo/redo) without requiring platform-specific backends. This simplifies cross-platform deployment and removes the Cocoa framework dependency on macOS.

Scissor API

raym3 provides a stack-based scissor (clipping) API for custom clipping regions:

  • PushScissor(Rectangle bounds) - Push a clipping region; intersects with current scissor
  • PopScissor() - Pop the current scissor and restore the previous one
  • BeginScissor(Rectangle bounds) - Convenience for PushScissor(bounds)
  • GetCurrentScissorBounds() - Get the current active scissor rectangle
  • SetScissorDebug(bool enabled) / IsScissorDebug() - Enable scissor debug overlay
  • DrawScissorDebug() - Draw green outlines of active scissor regions (call after your frame content)

The layout system and scroll containers use this API internally. Use layers with zOrder >= 100 for overlays (menus, tooltips, dialogs) so they render above layout clipping.

Debugging

raym3 provides built-in tools for debugging layouts and understanding component bounds:

Layout Debug Visualization

The layout system includes a powerful debug visualization tool that helps you understand how your UI is being laid out:

// Enable debug visualization
raym3::Layout::SetDebug(true);

// In your render loop, after Layout::End():
raym3::Layout::DrawDebug();

Features:

  • Color-Coded Boxes: Each layout node gets a unique color generated from its index, making it easy to distinguish between different components
  • Hover Highlighting: When you hover over a component, it darkens and becomes more opaque with a darker outline for clear identification
  • Low-Opacity Overlays: Non-hovered components use very low opacity (5%) so they don't obscure your actual UI
  • Visual Hierarchy: Helps you understand container nesting, padding, gaps, and flexbox behavior

Usage Tips:

  • Enable debug mode when your layout isn't behaving as expected
  • Hover over components to see their exact bounds
  • Use it to verify padding, gaps, and alignment are working correctly
  • Toggle it on/off at runtime to compare the visual layout with the debug overlay

Multi-Tab / MDI Layout State Isolation

When building tabbed interfaces or MDI (Multiple Document Interface) applications, each tab needs its own isolated layout state. Use these methods to prevent layout bleeding between tabs:

// Set a unique ID offset for each tab (e.g., tabIndex * 1000)
raym3::Layout::SetIdOffset(activeTabIndex * 1000);

// When switching tabs, invalidate previous frame bounds to force fresh layout
raym3::Layout::InvalidatePreviousFrame();

When to use:

  • Call SetIdOffset() before Layout::Begin() when rendering each tab's content
  • Call InvalidatePreviousFrame() when switching between tabs to reset layout state

Interaction Model

  • Click on Release: Components (Buttons, etc.) trigger their primary action on mouse release while hovering, rather than on press. This matches standard UI behavior and allows users to cancel a click by moving the mouse away before releasing.
  • Input Capture: Drag operations (sliders, scrollbars) capture input, allowing the user to drag outside the component bounds once the gesture has started.
  • Buffered Cursor: Cursor changes are buffered via RequestCursor() during the frame and applied once in EndFrame(). This prevents flickering when multiple components render.
  • Focus Management: Interactive components track focus state. Clicking a component gives it focus; clicking away removes focus. Focused components respond to keyboard input (Space/Enter for activation, Arrow keys for navigation).
  • Tooltip Smart Timing: After the first tooltip is shown, subsequent tooltips appear instantly (50ms) for 2 seconds, then revert to the normal delay. This matches native OS tooltip behavior.

Note: This README was generated with the assistance of AI and may contain errors. Please verify all information and report any issues.

About

Material Design 3 inspired immediate-mode GUI library for raylib. Build modern, beautiful user interfaces in C++ with automatic resource management.

Topics

Resources

Stars

28 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages