Skip to content

RolandMarchand/anchors

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

anchors.lua

anchors.lua is a small library for building relative UI layouts in Lua using anchor-based positioning. It provides a declarative way to define UI elements that scale and position themselves relative to their parent containers.

Examples

local Anchors = require 'anchors'

-- Create a centered panel at 50% of screen size
local layout = {
  anchors = { 0.25, 0.25, 0.75, 0.75 }
}
local frame = Anchors.build(layout, 800, 600)
local x, y, width, height = frame:toXYWH()
-- Result: x=200, y=150, width=400, height=300

-- Create a sidebar with two vertically stacked panels
local layout = {
  anchors = { 0, 0, 0.3, 1 },  -- Left 30% of screen
  children = {
    { anchors = { 0, 0, 1, 0.5 } },      -- Top half of sidebar
    { anchors = { 0, 0.5, 1, 1 } }       -- Bottom half of sidebar
  }
}
local frame = Anchors.build(layout, 1920, 1080)

-- Create a fixed-size button with 10px padding
local layout = {
  anchors = { 0.5, 0.5, 0.5, 0.5 },  -- Centered anchor point
  offsets = { -60, -20, 0, 0 },      -- Offset from center
  size = { 120, 40 }                 -- Fixed 120x40px button
}
local frame = Anchors.build(layout, 800, 600)

Demo

COMING SOON

Interface

Layout Creation

local frame = Anchors.build(layout, screenWidth, screenHeight)

Creates a frame hierarchy from a layout definition.

  • layout is a table defining the UI structure (see Layout Structure below)
  • screenWidth is the width of the screen/container in pixels (default: 800)
  • screenHeight is the height of the screen/container in pixels (default: 600)
  • frame is the root Frame object containing the calculated rectangles

Layout Structure

A layout table can contain:

anchors

anchors = { left, top, right, bottom }

Defines the anchor points as normalized coordinates (0-1) relative to the parent:

  • left - X position of left edge (0 = parent's left, 1 = parent's right)
  • top - Y position of top edge (0 = parent's top, 1 = parent's bottom)
  • right - X position of right edge
  • bottom - Y position of bottom edge

Shortcuts:

  • anchors = 0.5 - Centers the element (expands to { 0.5, 0.5, 0.5, 0.5 })
  • anchors = { 0.5 } - Same as above
  • Default (on nil or invalid input): { 0, 0, 1, 1 } (fills parent)

offsets

offsets = { left, top, right, bottom }

Pixel offsets applied after anchor positioning:

  • Positive values move inward/rightward/downward
  • Negative values create padding/margins
  • Supports scalar expansion like anchors
  • Default: { 0, 0, 0, 0 }

size

size = { width, height }

Fixed pixel dimensions. When specified:

  • right and bottom anchors are ignored
  • Element is positioned from its top-left anchor point
  • Useful for fixed-size buttons, icons, etc.

children

children = { layout1, layout2, ... }

Array of child layouts. Each child:

  • Is positioned relative to its parent's calculated rectangle
  • Inherits the parent's position as its coordinate space
  • Can have its own children for deep nesting

Frame Methods

local x, y, width, height = frame:toXYWH()

Returns position and dimensions in screen coordinates.

local left, top, right, bottom = frame:toAABB()

Returns axis-aligned bounding box coordinates.

Frame Structure

frame = {
  rect = { left, top, right, bottom },  -- Pixel coordinates
  children = { frame1, frame2, ... }    -- Child frames (if any)
}

Anchor System Explained

Anchors work like attachment points:

Parent: 800x600px

anchors = { 0, 0, 0.5, 0.5 }
┌─────────┬─────────┐
│ Element │         │  Element fills top-left quadrant
├─────────┤         │  Left anchor: 0 = left edge (0px)
│         │         │  Top anchor: 0 = top edge (0px)
│         │         │  Right anchor: 0.5 = middle (400px)
└─────────┴─────────┘  Bottom anchor: 0.5 = middle (300px)

anchors = { 0.25, 0.25, 0.75, 0.75 }
┌───────────────────┐
│   ┌─────────┐     │  Element is centered with 25% margins
│   │ Element │     │  Spans from 25% to 75% on both axes
│   └─────────┘     │
└───────────────────┘

Common Patterns

Centering

-- Center with specific size
{ 
  anchors = 0.5, -- expands to { 0.5, 0.5, 0.5, 0.5 }
  offsets = { -100, -50, 0, 0 },
  size = { 200, 100 }
}

-- Center with relative size
{
  anchors = { 0.3, 0.3, 0.7, 0.7 }  -- 40% of parent, centered
}

Margins and Padding

-- 10px padding on all sides
{
  anchors = { 0, 0, 1, 1 }, -- could be nil
  offsets = { 10, 10, -10, -10 }
}

Sidebars and Panels

-- Left sidebar (30% width)
{ anchors = { 0, 0, 0.3, 1 } }

-- Right sidebar (25% width)
{ anchors = { 0.75, 0, 1, 1 } }

Grid Layouts

-- 2x2 grid
{
  anchors = { 0, 0, 1, 1 },
  children = {
    { anchors = { 0, 0, 0.5, 0.5 } },      -- Top-left
    { anchors = { 0.5, 0, 1, 0.5 } },      -- Top-right
    { anchors = { 0, 0.5, 0.5, 1 } },      -- Bottom-left
    { anchors = { 0.5, 0.5, 1, 1 } }       -- Bottom-right
  }
}

Gotchas / Warnings

  • Anchors are normalized coordinates (0-1), offsets are pixels
  • When size is specified, right and bottom anchors are ignored
  • Invalid anchors (NaN, infinity, wrong types) default to full-area layout { 0, 0, 1, 1 }
  • Invalid size/offset proprieties default to 0 (like { NaN, 10, 0, 0 } -> { 0, 10, 0, 0 }
  • Coordinates are floored to integer pixels to prevent subpixel rendering issues
  • The library validates all input, so you can't crash it with bad data
  • Layouts are retained-mode, they are not intended to be recalculated every frame, instead prefer to rebuild on resizes, on initial load, or when the layout changes

License

This library is licensed under the 0BSD license.

About

Lua library for generating retained-mode scalable UIs using anchors

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages