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)
- Material Design 3 Inspired - Implements Material Design 3 design principles and components
- 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 - Embedded Roboto fonts with custom font loading
- 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)
- Zero External Dependencies - Can be built as a standalone library (raylib is fetched automatically)
raym3 currently implements the following Material Design 3 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, drag selection, triple-click select all, Escape to revert, and I-beam cursor
- 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
- 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
- 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
- Container - Flexbox-based layout container (requires Yoga)
- View3D - 3D viewport component
- 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. Many components from the full specification (such as AppBar, BottomNavigation, NavigationDrawer, Chips, DataTables, FloatingActionButton, BottomSheet, Date/Time Pickers, etc.) are not yet implemented.
#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;
}The TextField component supports several advanced features:
- Custom Colors: Set
backgroundColorandtextColorinTextFieldOptions - Automatic Cursor Inversion: Cursor color automatically inverts based on background luminance
- Password Mode: Set
passwordMode = trueto mask input - Input Masking: Use regex patterns via
inputMaskfor validation - Undo/Redo: Built-in support with configurable history depth via
maxUndoHistory - Icons: Add
leadingIconandtrailingIconwith click callbacks - Read-Only: Set
readOnly = trueto prevent editing
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 = truefor compact horizontal menus - Disabled Items: Set
disabled = trueto prevent interaction
The Slider component supports M3 Expressive customization:
- Discrete Mode: Set
stepValue > 0to snap to specific increments - Tick Marks: Enable
showTickMarksto display step indicators in discrete mode - Stop Indicators: Enable
showStopIndicatorsto 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
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
minDistanceto enforce spacing between thumbs - Discrete Mode: Supports
stepValueandshowTickMarkslike Slider - Value Indicators: Show value bubbles for all thumbs when dragging
- Stop Indicators: Display min/max position markers
add_subdirectory(raym3)
target_link_libraries(your_target raym3)add_subdirectory(yoga)
set(RAYM3_USE_YOGA ON CACHE BOOL "" FORCE)
add_subdirectory(raym3)
target_link_libraries(your_target raym3)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)andPopLayer()to control rendering order - Component Blocking: Cards and panels automatically block input to elements beneath them
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
}
}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, only icons that are actually used in your code are embedded. This significantly reduces the library size. 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)raym3 automatically discovers resources in the following order:
- Embedded Resources (if
RAYM3_EMBED_RESOURCES=ON) - CMake-defined resource directory (set at build time)
- 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
...
- raylib (required) - Automatically fetched via CMake FetchContent
- yoga (optional) - Flexbox layout engine, enabled via
RAYM3_USE_YOGA
raym3 is built using the following excellent open-source projects:
-
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
-
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 - Material Design typeface
- License: Apache License 2.0
- Copyright (c) Google LLC
- Embedded font files for consistent typography
- Material Design 3 - Google's Material Design system
- Design guidelines and specifications
- Color system, typography, and component specifications
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.
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:
- AppBar/TopAppBar
- BottomNavigation
- NavigationDrawer
- Chips
- DataTables
- FloatingActionButton (FAB)
- BottomSheet
- Date/Time Pickers
If you find raym3 useful and would like to support its development, you can:
raym3 is an independent, self-contained project. All resources (icons and fonts) are included in the repository, making it easy to use in any project without external dependencies.
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.
- 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), andPopId()for advanced manual ID control in complex layouts. - Backward Compatible: All existing code continues to work.
SetIdOffsetmaintains compatibility while integrating with the hash-based system.
- Buffered Cursor System: Added
RequestCursor()API - cursor is set once per frame inEndFrame()to prevent flickering when multiple components render. Components callRequestCursor()instead ofSetMouseCursor()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
tooltipandtooltipPlacementfields toButtonOptions,SliderOptions,RangeSliderOptions,IconButtonOptions,CheckboxOptions,SwitchOptions,RadioButtonOptions,ListItem,MenuItem, andTabItem. - 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.
- Tooltip Component: New
Tooltip()function andTooltipManagerfor deferred tooltip rendering - TabBar Component: Browser-style tab bar with closeable tabs, drag reorder, loading/audio indicators, add tab callback, and text truncation
- Removed Native Text Input: The
useNativeInputoption inTextFieldOptionshas been removed along with theRAYM3_ENABLE_NATIVE_TEXT_INPUTCMake 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.
raym3 provides built-in tools for debugging layouts and understanding component bounds:
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
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()beforeLayout::Begin()when rendering each tab's content - Call
InvalidatePreviousFrame()when switching between tabs to reset layout state
- 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 inEndFrame(). 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.
