o
odinpkg.dev
packages / library / raylay

raylay

f86e1d0library

A Stupid Easy Flex Layout Library for Raylib

MIT · updated 11 months ago

Raylay - A Stupid Easy Flex Layout Library for Raylib

alt text

Still a WIP, but core functionality is there - Made mainly for my spectrum analyzer spectro

Why?

  • I wanted a simple immediate mode flex layout library with as little internal state as possible.
  • I wanted to build more advanced UIs faster that still looked good and didn't require so much manual control positioning.

Design Goals

  • Favor Intuitiveness and Simplicty over Advanced Features
  • Immediate Mode
  • Intelligent, Declarative Layouts

Features

  • Simple Rows and Columns (thats it, maybe grids laters)
  • Easy Stack-based nested layouts
  • Stupid simple API (like 3 core functions)
  • Resizeable and Auto-adjusting
  • Mix flexbox-like and fixed sizes
  • Vertical Alignment
  • Tiny (core features less than 600 lines of code)
  • Stack-based and fast

Coming Soon

  • Pure Header Only C for Native Raylib Integration
  • Grid Layout (maybe)
  • More alignments
  • Profiling & Timings Output

Quick Start

Just a few lines of code gets you a nice layout. Inside your raylib drawing loop:

See [examples/sidebar/sidebar.odin] for full code including boilerplate

		BeginDrawing()
		ClearBackground(bg_color)

		screen_w := f32(GetScreenWidth())
		screen_h := f32(GetScreenHeight())
		full_rect := rl.Rectangle{0, 0, screen_w, screen_h}

		// Configure Raylay defaults
		RLSetDefaultGap(10) // 10px gap between items
		RLSetDefaultPadAll(0)
		
		// Toplevel Column: 50px, stretch, 50px
		RLBeginColumn(full_rect, plan = {50, -1, 50}, pad = PadAll(10))

			// Header
			RLBeginRow(RLNext(-1, -1)) 			   // Use the plan size from the parent
				DebugButtonEx(RLNext(100, -1)) // Logo Area
				DebugButtonEx(RLNext(-1, -1))  // Rest of the headers
			RLEnd()

			// Content
			RLBeginRow(RLNext(), plan = {1, 3, 1}) // Flex 1, 3, 1
				DebugButtonEx(RLNext())            // Left Sidebar (deafults to -1, -1)
				DebugButtonEx(RLNext())       	   // Center Content
				DebugButtonEx(RLNext()) 		   // Right Sidebar
			RLEnd()

			// Footer
			RLBeginRow(RLNext())
				DebugButtonEx(RLNext())
			RLEnd()

		RLEnd() // Toplevel Column

		EndDrawing()

Result:

sidebar demo

API

This section documents the small set of core functions in Raylay. The library is intentionally tiny — you build layouts by creating containers (rows/columns), requesting child rectangles, then ending the container.

Core functions

  • RLBeginRow(bounds, pad = RL_DEFAULT_PAD, gap = RL_DEFAULT_GAP, plan = nil)

    • Begin a horizontal container (left → right).
    • bounds: rl.Rectangle - outer bounds for the container.
    • pad: RLPad - padding inside the container (defaults to RL_DEFAULT_PAD).
    • gap: f32 - space between children (defaults to RL_DEFAULT_GAP).
    • plan: []f32 (optional) - layout plan for children (see "Plan values" below).
    • Use RLBeginRow to push a row onto the internal stack; pair with RLEnd().
  • RLBeginColumn(bounds, pad = RL_DEFAULT_PAD, gap = RL_DEFAULT_GAP, plan = nil)

    • Begin a vertical container (top → bottom).
    • Same parameters/semantics as RLBeginRow, but lays out vertically.
  • RLNext(main = -1, cross = -1, pl = 0, pr = 0, pt = 0, pb = 0, valign = RL_DEFAULT_VALIGN) -> rl.Rectangle

    • Return the next child rectangle from the current container.
    • main: f32
      • = 0: fixed size along the main axis (width for rows, height for columns).

      • -1: in planned containers, use the next plan entry; in ad-hoc containers, fill the remaining main-axis space.
    • cross: f32
      • = 0: fixed size along the cross axis (height for rows, width for columns).

      • < 0: fill the entire cross axis available space.
    • pl, pr, pt, pb: f32 - apply inline padding to the returned rectangle (left/right/top/bottom).
    • valign: RLVAlign - vertical alignment for row containers (TOP, CENTER, BOTTOM, NONE). For column containers horizontal alignment is not yet supported.
    • Returns: rl.Rectangle positioned and sized according to the current container flow.
  • RLNextPanel(main, cross, pad_top = 35.0, pad_other = 10.0) -> (rl.Rectangle, RLPad)

    • Convenience helper that calls RLNext(main, cross) and returns a panel-style RLPad for title + margins.
    • Useful when placing framed panels with a header area.
  • RLEnd()

    • Pop the current container from the internal stack. Call once per RLBeginRow/RLBeginColumn.

Defaults and setters

  • RLSetDefaultGap(g: f32) — set the default gap between children.
  • RLSetDefaultPadAll(p: f32) — set a uniform default padding (applies to RL_DEFAULT_PAD).
  • RLSetDefaultVAlign(align: RLVAlign) — set default vertical alignment for RLNext calls.

Plan values (used by RLBeginRow/Column plan parameter)

  • v >= 20:fixed pixels. The child gets exactly v pixels on the main axis.
  • 0 < v < 20: flex weight. The value is treated as a weight; remaining flex space is divided proportionally.
  • v == -1: "fill" — treated as a flex weight of 1 (fills remaining space). Multiple -1 entries share space.
  • Values < -1 are ignored (treated as zero).

Notes on planned vs ad-hoc mode

  • Planned mode: supply a plan array when beginning a container. Each RLNext will use the next plan entry unless you explicitly pass a non-negative main value.
  • Ad-hoc mode: no plan provided. Each RLNext(-1) will fill the remaining main-axis space; or pass a concrete main size to request a fixed size.

Quick tips

  • Use small plan numbers (1,2,3...) to express flex ratios.
  • Use values >= 20 when you need exact pixel sizes.