## What are the changes about?
Allows the game of life animation to be ran with configurable rules, specifically: the neighbors required for birth and survival.
### Example: [B3/S12345 (Maze)](https://conwaylife.com/wiki/OCA:Maze)
(where numbers after B are neighbors required for birth, and S for survival)
<video src="/attachments/49120c5e-ce21-4025-852e-924befbc2621" title="Screencast_20260814_233338" controls></video>
Introduces two keys to the config:
```ini
# Sets the multiple amounts of neighbors needed for a cell to survive.
# Each numerical digit from 0 to 8 inclusive in this string becomes
# one of the targets required for this cell to survive.
# Example: a string of "23" makes the cell survive on 2 or 3 neighbors
gameoflife_param_survival = "23"
# Sets the multiple amounts of neighbors needed for a cell to be born.
# Each numerical digit from 0 to 8 inclusive in this string becomes
# one of the targets required for this cell to be born.
# Example: a string of "3" makes the cell be born on 3 neighbors
gameoflife_param_birth = "3"
```
## What existing issue(s) does this resolve?
Solves !1023
## Pre-requisites
- [x] I have tested & confirmed the changes work locally
- [x] I have read and fully adhere to the rules set in the contributing guidelines found in `CONTRIBUTING.md`
Reviewed-on: https://codeberg.org/fairyglade/ly/pulls/1041
Reviewed-by: AnErrupTion <anerruption+codeberg@disroot.org>
## What are the changes about?
TL;DR:

Slaps the entire LuaJIT runtime onto Ly, allowing for the creation of custom dynamic animations like GameOfLife, ColorWave, Doom, etc.
This PR adds the [ziglua](https://github.com/natecraddock/ziglua?ref=zig-0.16) dependency for its zig bindings and considerable buildtime config (mainly lua version selection).
### Example
<video src="/attachments/3f91cf72-ae24-459c-8ef6-099f71e866fd" title="Screencast_20260519_172320" controls></video>
```lua
ly.frame_delay = 5
local timer = 0
local clock = os.clock()
local clock_diff = 0
function draw()
timer = timer + 1
byte = string.byte(' ')
clock_diff = os.clock() - clock
clock = os.clock()
timer = timer + clock_diff
for x = 0, ly.width-1 do
for y = 0, ly.height-1 do
local xc = 0xFF
if x < 255 then xc = ((x + math.floor(timer / 2)) * 3) % 255 else xc = 0 end
local yc = 0xFF
if y < 255 then yc = ((y) * 3) % 255 else yc = 0 end
ly.putCell(byte, xc, bit.bor(xc, yc), x, y)
end
end
end
```
### The API
The API that Ly gives to the user is minimal. A table is globally available, named `ly`, which provides the following:
| Member | Purpose |
|---------|---------|
| `ly.width` & `ly.height` | Respective Width/Height from the `TerminalBuffer` |
| `ly.putCell(byte, fg, bg, x, y)` | Literally `Cell.init(byte, fg, bg).put(x, y)`.|
| `ly.clock()` | The current real-time, in microseconds. |
### Error Handling
On a Lua Error, Ly won't quit but will instead paint the entire background red. The lua error in question can be found in the Ly log file and on-screen.
```log
2026-05-19 16:13:40 [err/Lua] Error (Cannot call draw()): attempt to call a nil value
2026-05-19 11:05:51 [err/Lua] Lua Error: ...dsammyt/programming/probe/ly/scratch/testConfig/test.lua:30: bad argument #1 to 'ipairs' (table expected, got number)
```
## Pre-requisites
- [X] I have tested & confirmed the changes work locally
- [X] I have run `zig fmt` throughout my changes
Reviewed-on: https://codeberg.org/fairyglade/ly/pulls/1001
Reviewed-by: AnErrupTion <anerruption+codeberg@disroot.org>
## What are the changes about?
Fixes battery label positioning in regards to custom binds.
Since the label was on the top-left, it only accounted for the first line of built-in keybinds, and it didn't account for the other lines of custom ones.
This also fixes the custom keybinds not disappearing on `hide_key_hints = false`, which is my bad. whoops.
Also, with https://codeberg.org/fairyglade/ly/pulls/963 being a thing, we should probably think about deprecating this hardcoded battery label in favor of a custom label command, top-left by default.
## What existing issue does this resolve?
N/A
## Pre-requisites
- [x] I have tested & confirmed the changes work locally
- [x] I have run `zig fmt` throughout my changes
Reviewed-on: https://codeberg.org/fairyglade/ly/pulls/970
Reviewed-by: AnErrupTion <anerruption+codeberg@disroot.org>
## What are the changes about?
Fixes the order of custom labels and binds because of a HashMap shenanigan (no guaranteed order), so we use `ArrayHashMap` instead which preserves insertion order. They should now be shown in the order they are declared in the config.


## What existing issue does this resolve?
!950
## Pre-requisites
- [x] I have tested & confirmed the changes work locally
- [x] I have run `zig fmt` throughout my changes
Reviewed-on: https://codeberg.org/fairyglade/ly/pulls/951
Reviewed-by: AnErrupTion <anerruption+codeberg@disroot.org>
Co-authored-by: RadsammyT <radsammyt@gmail.com>
Co-committed-by: RadsammyT <radsammyt@gmail.com>
## What are the changes about?
Adds customizable commands and labels to ly.
Solves https://codeberg.org/fairyglade/ly/issues/905.
Since Ly doesn't use INI headers. I use them exclusively for declarations of custom commands and labels.
### Commands
Bind a keybind to a command, and add a hint to the HUD. Useful for use cases like display brightness, switching between GPUs, etc.
Supports localization in the `name` field only. ex: where `lang = es`: `$brightness_up` => `bajar brillo`
Declared in config.ini with the following:
```ini
[cmd:F8]
name = custom command 2
cmd = touch /tmp/ly.gaming
```
### Labels
Add a label to the HUD. As specified in #905.
The text of the label corresponds to the output of the command specified in `[lbl:NAME]`.
Only shows the first line of the output.
Declared in config.ini with the following:
```ini
[lbl:kernel]
cmd = uname -srn
refresh = 0
```
Example to add to the config.ini:
```ini
# Declare a command with the F8 binding.
[cmd:F8]
#The name of the command to show up in Ly.
name = custom command
cmd = touch /tmp/ly.gaming
# Declare a label with an ID. This ID should be unique across all labels.
[lbl:kernel]
cmd = uname -srn
# In frames, the time to re-run the command and update the label. If 0, only run once- do not refresh.
refresh = 0
# Once you're done setting up labels and commands, add an empty header
# below to continue configurating the rest of Ly.
# Put other settings not belonging to custom commands/labels below here.
[]
```
## Pre-requisites
- [x] I have tested & confirmed the changes work locally

Reviewed-on: https://codeberg.org/fairyglade/ly/pulls/945
Reviewed-by: AnErrupTion <anerruption+codeberg@disroot.org>
Co-authored-by: RadsammyT <radsammyt@gmail.com>
Co-committed-by: RadsammyT <radsammyt@gmail.com>
Added P,A,M characters to bigclock and added 12hr and seconds support to bigclock via `bigclock_12hr` and `bigclock_seconds` in the config.

Image has bigclock_12hr and bigclock_seconds enabled.
Farsi characters for P,A,M are blank since I don't know what it would look like in their language. (should i have just used the english characters as a placeholder?)
Reviewed-on: https://codeberg.org/fairyglade/ly/pulls/805
Reviewed-by: AnErrupTion <anerruption@disroot.org>
Co-authored-by: RadsammyT <radsammyt@gmail.com>
Co-committed-by: RadsammyT <radsammyt@gmail.com>
`drawConfinedLabel` didn't take into account the starting x axis
when checking to break for exceeding `max_length`.
This should fix the box title not appearing on
terminals with larger column counts.