A demo of raygui — a single-header immediate-mode GUI library for raylib — building a complete set of interactive game menus.
A port of the clay-ui demo to raygui. Five fully-interactive scenes plus a modal form, in the same shared style. Hover, click, scroll, text input, floating overlays, scroll containers, tabbed views — most of what raygui + raylib needs to put on screen for a game's front-end.
1. Main menu![]() |
2. Character select![]() |
* Forge a new hero (modal)![]() |
3. Inventory![]() |
4. Settings![]() |
5. HUD / pause![]() |
| # | scene | demonstrates |
|---|---|---|
| 1 | Main menu | typography hierarchy, hover accent bars, info strips |
| 2 | Character select | data-driven cards, click selection, stat bars per slot |
| 3 | Inventory | scroll container with scissor clipping, filter pills, rarity colour |
| 4 | Settings | tabbed sub-views, sliders, toggles, steppers, key-binding rows |
| 5 | HUD / pause | layered HUD over a play space, floating pause overlay |
| * | Forge a new hero | a modal form: text input, class stepper, accent swatches, stat allocator |
brew install raylib # macOS, one-time
./run.shrun.sh builds incrementally and execs the binary. Tested on macOS 14+ / Apple Silicon with Raylib 5.5 and raygui 5.0. raygui is vendored as a single header (vendor/raygui.h).
1-5 (or click the sidebar) |
switch scene |
| Click | interact with anything that hovers |
| Scroll | scroll the inventory list |
ESC / P on the HUD |
toggle pause |
ESC in the new-hero form |
cancel |
| Typing | enters the hero name field when the form is open |
raygui is an immediate-mode GUI library, in contrast to Clay's declarative layout engine. Everywhere clay-ui says "give me a flexbox column with childGap = 8," raygui needs an explicit Rectangle per widget. The trade is more arithmetic per scene in exchange for zero layout-engine state.
The drawing model is also flatter: there are no render commands, no layout pass — every UI_Panel(...), GuiSliderBar(...), DrawText(...) issues straight to raylib's frame.
SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE | FLAG_MSAA_4X_HINT | FLAG_WINDOW_HIGHDPI);
InitWindow(1280, 800, "raygui Game Menus");
while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground((Color){ 12, 12, 18, 255 });
Rectangle sidebar = { 0, 0, 220, sh };
Rectangle scene = { 220, 0, sw - 220, sh - 32 };
Rectangle footer = { 220, sh - 32, sw - 220, 32 };
switch (state.scene) {
case SCENE_MAIN_MENU: Scene_MainMenu(&state, scene); break;
/* ... */
}
Sidebar(&state, sidebar);
Footer(footer);
EndDrawing();
}Patterns worth a look:
- Hover —
UI_Hovered(rect)is justCheckCollisionPointRec(GetMousePosition(), r)gated by a "modal active" latch. Switching background/border colours on hover is one ternary in the draw call. - Click handling —
if (UI_Hovered(r) && IsMouseButtonPressed(MOUSE_BUTTON_LEFT))per widget, inline with its draw. - Scroll —
BeginScissorMode(...)clips the list rect; rows are drawn with a-state->inventoryScrolly-offset. A small thumb on the right is drawn from the same offset. - Modals / overlays — a
g_modalActiveflag inui.cmakes the base layer'sUI_Hoveredreturn false while the modal is up, so the form and the pause overlay automatically eat all clicks beneath them. - Dynamic text —
UI_Fmt(...)writes to a per-frame string arena (src/ui.c) so format-strings can be drawn directly without a heap allocation.
src/
main.c entry, scene dispatcher, raylib glue, screenshot mode
ui.h / ui.c palette, sidebar, footer, StatBar, panel/text primitives, frame string arena
scenes.c five scenes + the new-hero form
vendor/
raygui.h raygui 5.0 (single header)
scripts/
capture.sh regenerate the screenshots in this README
The binary recognises three environment variables for non-interactive captures (no manual screenshotting needed):
| variable | meaning |
|---|---|
RAYGUI_SCREENSHOT |
basename of the PNG to write; the app exits a few frames after writing |
RAYGUI_SCENE |
start in scene 0-4 (main / character / inventory / settings / hud) |
RAYGUI_FORM=1 |
open the new-hero form (meaningful with RAYGUI_SCENE=1) |
RAYGUI_SCENE=1 RAYGUI_FORM=1 RAYGUI_SCREENSHOT=hero.png ./build/raygui-menusscripts/capture.sh regenerates everything in docs/assets/ in one go.
raygui and raylib are both Zlib-licensed. The demo code is yours to copy.
| Language | Files | Lines | Blanks | Comments | Code | Complexity |
|---|---|---|---|---|---|---|
| C | 3 | 1,605 | 185 | 88 | 1,332 | 196 |
| C Header | 2 | 6,165 | 893 | 1,235 | 4,037 | 1,092 |
| Markdown | 2 | 147 | 35 | 0 | 112 | 0 |
| Shell | 2 | 27 | 3 | 3 | 21 | 0 |
| Makefile | 1 | 23 | 7 | 0 | 16 | 0 |
| Total | 10 | 7,967 | 1,123 | 1,326 | 5,518 | 1,288 |
- Estimated Cost to Develop (organic): $162,355
- Estimated Schedule Effort (organic): 6.89 months
- Estimated People Required (organic): 2.09
- Processed: 371,630 bytes (0.372 megabytes)
Generated with scc on 2026-05-22





