A permacomputing and game oriented language designed for constrained systems.

> Permacomputing is a design practice that encourages the maximization of hardware lifespan, minimization of energy usage and focuses on the use of already available computational resources. It values maintenance and refactoring of systems to keep them efficient, instead of planned obsolescence, permacomputing practices planned longevity. It is about using computation only when it has a strengthening effect on ecosystems.

The language's compiler is written in its own libc. Not all of C stdlib, a "lagom" (just enough) implementation. Undar targets the Uxntal VM Bytecode (16 bit interpreted VM) and the "Reality Engine" VM Bytecode (32 bit VM), both only require a C compiler to compile the VM which makes the language portable to any system with a C compiler.

This is similar to Java's "build once run anywhere" but even more flexable, a Undar program should be able to run on a Linux desktop, a website using Wasm, a embedded device, or even something obscure like a PDP-11.

Memory Management

System Specification: Frame-Scoped Region Allocator with Handle References
** Overview

A single-threaded, deterministic memory model where each call frame owns a dedicated memory region. References are strictly scoped to the call tree, complex types use length-prefixed handles, and memory is reclaimed immediately on frame teardown. Designed for fixed-size actors communicating via serialized message passing.
** Memory Layout

    Logical Heap: Partitioned into one region per call frame, laid out top-down from the previous frame's end (or memory start for the first call).
    Stack: Holds frame locals (bottom-up).
    Frame Metadata: Stores a handle/pointer to its heap region base, plus frame state.
    Allocation: Bump-style allocation within the region. No free-lists or fragmentation tracking within a live frame.

** Ownership & Lifecycle

    All allocations are owned by the frame that created them.
    Variables are modified in-place within their frame's region.
    On function return, the frame's region is immediately deallocated, deterministically freeing all owned memory.

** References, Handles & Complex Types

    Complex types (structs, arrays, strings) use reference handles instead of raw pointers.
    Every dynamic allocation prepends a length field to prevent buffer overflows and enable O(1) size queries.
    Handles are strictly scoped: they can be passed down to child frames but cannot outlive their frame. If a value must escape, it must be explicitly returned.
    No sharing or aliasing exists between frames. The structure is a strict tree (parent → child). Handles become invalid upon frame return.

** Resizing & Fragmentation Strategy

    When a complex type grows, a new block is allocated at the end of the region, and ownership transfers to the new allocation. The old block becomes dead space.
    Fragmentation is mitigated by design: the system encourages short-lived frames and compositional patterns (building up via smaller, focused functions) to ensure dead space is reclaimed quickly.
    Static-size complex types are pre-allocated upfront, so they never need to move on return.

** Parameter Passing & Returns

    Primitives: Passed by value.
    Complex types: Passed by handle/reference.
    If a passed complex type is modified/grown in a child frame, the new allocation occurs in the child's region, and ownership moves to the child (move semantics).
    Returns: Primitives are copied back. Complex types are returned via handle. Since return space is pre-allocated in the caller, the callee writes directly into it, making "move" and "copy" functionally identical for returns.

** Concurrency Model

    Not thread-safe. Designed for a single-threaded actor model where fixed-size actors communicate via serialized message passing. Each actor maintains its own isolated call-tree region.

** Key Constraints & Guarantees

    References cannot outlive their frame.
    No cross-frame sharing; strict parent→child data flow.
    Deterministic, O(1) deallocation on frame exit.
    Prepend length on all dynamic allocations for safety & performance.
    Region reuse encouraged via short-lived frames and compositional design.

Built in Types
Type Description
byte Character (architecture specific)
u8 exactly 8-bit unsigned int
i8 exactly 8-bit signed int
u16 exactly 16-bit unsigned int
i16 exactly 16-bit signed int
u32 exactly 32-bit unsigned integer
i32 exactly 32-bit signed integer
int 1 word signed number
nat 1 word unsigned number
real Q16.16 fixed-point real number
str string
bool true/false

Standard Library:
String functions
Array functions (sort, filter, etc.)
Fonts
Immediate Mode UI (buttons, forms, etc.) In the style of ImGUI / Raylib.
Trigonometry
Unit of measure
2D Graphics Math/Primitives
2D Collision/Physics
3D Graphics Math/Primitives
3D Collision/Physics
Localization

Example: uPaint (paint.ul)
```ul
/**
* Constants
*/
const byte BLACK = 0;
const byte WHITE = 255;
const byte DARK_GRAY = 73;
const byte GRAY = 146;
const byte LIGHT_GRAY = 182;

byte selected_color = 255;

trait Device {
nat handle;
}

plex Screen implements Device {
nat handle;
nat width;
nat height;
byte[] buffer;

draw() {
write(this, this.buffer, this.buffer.length);
}
}

plex Mouse implements Device {
nat handle;
nat x;
nat y;
bool left;
bool right;
bool middle;
bool btn4;
}

/**
* Main function
*/
function main() {
Screen screen = open("/dev/screen/0", 0);
Mouse mouse = open("/dev/mouse/0", 0);

outline_swatch(screen, BLACK, 1, 1);
outline_swatch(screen, WHITE, 21, 1);
screen.draw();

loop {
mouse.refresh();
if (!mouse.left) continue;

int box_size = 20;
int x = 1;
int y = 1;
byte color = BLACK;
outlined_swatch(screen, color, x, y);
set_color(box_size, x, y, mouse.x, mouse.y, color);

color = WHITE;
x = 21;
outlined_swatch(screen, color, x, y);
set_color(box_size, x, y, mouse.x, mouse.y, color);
screen.draw();

rectangle(screen, selected_color, x, y, 5, 5);
}
exit(0);
}

/**
* Checks if the click is within the bound and update the selected color if so.
*/
function set_color(int box_size, int bx, int by, int mx, int my, byte color) {
int right = bx + box_size;
int bottom = by + box_size;

if (mx < bx) return;
if (mx > right) return;
if (my < by) return;
if (my > bottom) return;

selected_color = color;
}

/**
* Draw a color box with a grey outline, if selected use a darker color
*/
function outline_swatch(Device screen, byte color, int x, int y) {
byte bg_color = GRAY;
if (selected_color == color) {
bg_color = DARK_GRAY;
}

rectangle(screen, bg_color, x, y, 20, 20);
rectangle(screen, color, x + 2, y + 2, 17, 17);
}

/**
* Draw a rectangle
*/
function rectangle(Device screen, byte color, int x, int y, int width, int height) {
int base = y * screen.width + x + screen.buffer.ptr + 4;

for (int i = height; i > 0; i--) {
int row = base + width;
memset(screen.buffer, row, color, width);
base += screen.width;
}
}
```

Plex

"Class" and "Struct" are very loaded terms with a lot of historical baggage. To try and fix this we call our structs "Plexes". A plex is a structure which, stores memory like a struct but can be used syntactically like a class. the naming of "plex" comes from douglas ross's paper "a generalized technique for symbol manipulation and numerical calculation". Unlike classes it should not describe a object in real life, but be a convenitent way to implement compositions + encodings instead of oop/polymorphisms. instances of a plex in memory are called "atoms".

Plexes support permacomputing by allowing the developer to use lower level traits with a friendly syntax.
```ul
plex Player {
str name;
real[3] pos;

init(str name, real[3] pos) {
this.name = name;
this.pos = pos;
}
update() {}
logout() {}
}
```
the language is statically typed and similar to c but with some array semantic ideas from fortran like row major, fortran style replaces need for vec or mat. arrays are first class values, the compiler uses optimized opcodes for array manipulation.
```ul
real[3] pos = [1.0, 2.0, 3.0];
real[3,3] mat = identity(3);
real[3] result = mat * pos; // compiler generates matrix-vector multiply
```
Row-major order
No vec3=/=mat4x4 structs needed
Supports composition, slicing, element-wise ops

it has a abstraction layer for devices that work as system calls that can open, read, write, close, and use ioclt for extra system calls that are beyond ops.
Devices

Core devices include
Window/Screen
Terminal
File I/O
Gamepad/Joystick
Sound
Networking
Cryptography
Random number generator
Date/Time
Mouse
Keyboard

Devices are accessed via a namespace "path/to/device" and are implemented outside of the VM's runtime. This allows for the trait of the system to be the same within the VM but allow for specific variations on a concept depending on the device it is running on.
Immediate Mode GUI

UI elements are draw directly on the canvas and syntactically are spacial to show which elements are child elements of each other. Calling a function is the equivalent of a redraw of that element
3D Modeling

3D Primitives (Similar to .kkrieger) allow for the construction of more complex 3D models from the manipulation of primitives. It also has the ability to create textures dynamically similar to .kkrieger.

Devices: Unified I/O (Plan 9 / 9P-Inspired)

Devices are an abstraction called a device which acts like a device like a screen, mouse, etc. that is inspired by Plan9. Plan 9 was an operating system developed at Bell Labs that treated all resources (including network connections and UI elements) as files in a hierarchical namespace. it allows files, web requests, sockets, etc. to be viewed through a simple unified trait. it is very similar to the 9p protocol where everything is a file in a filesystem, it just might be a file located on a server halfway across the world or on another planet. the only thing that is the difference is that it takes longer to read the file on mars compared to the file on your local system. the way the device system works is that it is written by a developer in another language like c, but from Undâr's pov the trait remains the same, its just a namespaced device like all the other devices, so that it is easy to understand by a new developer. so it is comparable with tcp/udp sockets or something esoteric like a lorawan network, or some new communication method that hasn't been invented yet.

```ul
Client client = Client("tcp://localhost:25565");
if (client.attach(auth)) {
Player[] players = client.read("players");
client.write("me", me.update());
client.close();
}
```
Device Operations
Op Meaning
.attach() Authenticate and open communication
.open() opens a device for doing operations on
.create() creates the plex from the database graph file from file structure
.remove() removes the plex from the database graph file from file structure
.read() reads from a device
.write() writes to a device
.walk() moves around the filesystem or through the graph
.flush() cancels long operation and dumps whatever is in buffer
.close() Close communication [also `clunk` works for historical accuracy]
.stat() returns the status of the file resource
.version() returns the version code for the connected device
Actor System

The "Reality Engine" VM uses a Actor System where multiple actors are assigned to a single core. Actors are used to partition memory efficiently. If we used a async/await system jumping between threads would wreck havock with the fast bump allocator. Actors have fixed sized pools that are decided by the developer at compile time which means the logic can remain the same.

Message passing allows for non-blocking and non-locking communications between actors.

Communication Protocol

Bounded mailbox system

Message flow:
Main thread sends via send_message()
Message copied into actor's mailbox
Actor processes in on_message() during next cycle
Actor sends response via send_response()

Failure Behaviors
Behavior |Action Example| / Use Case
--|--|--
RESTART |Reset region offset to 0 | Network reconnection
EXIT |Free region |Session termination
CRASH |Halt entire VM |Failure of core system
```