a programming language

One language,
kernel* to UI.

*we know, we built one

Freestanding kernel code, typed applications, quick scripts — same syntax, same toolchain, same mental model.

Explicit over implicit. Predictable over clever.

no LLVM / no forced GC / no generics / no closures / no magic

What it looks like

Single-file components

Regions in one file

Logic, components, and styles share a file. Each region has its own parser but compiles to the same IR. No context-switching between languages.

#code — functions, variables, logic

#view — declarative component trees

#style — property templates (planned)

#test — inline test cases

counter.tape
#code
import ui from "ui";
import str from "str";
import widgets from "widgets";

pub fn main() -> i32 {
    let app = Counter {};
    ui.run(app as *u8, 400, 200, "Counter");
    return 0;
}

#view
component Counter {
    var count: i64 = 0;
    var count_text: *u8 = "0";

    fn increment() {
        count = count + 1;
        count_text = str.i64_to_cstr(count);
    }

    view {
        ui.Column {
            widgets.Label { text: count_text; size: 24; }
            ui.Row {
                widgets.Button { label: "+"; on_click: increment; }
            }
        }
    }
}
io.tape
enum IoError : u8 {
    NotFound = 1: "file not found";
    ReadFailed = 2: "read failed";
}

fn open_file(path: string) -> File or IoError {
    let fd: i64 = sys_open(path);
    if (fd < 0) {
        return IoError.NotFound;
    }
    return File { fd: fd; };
}

fn load_config() -> Config or IoError {
    let f: File = open_file("config.ini") or return;
    let data: string = read_all(f) or return;
    return parse_config(data);
}

No exceptions

Errors are values

Functions return T or E where E is your own enum. No stack unwinding, no hidden control flow. Every error propagation is visible at the call site.

or return — propagate to caller

or { } — handle inline

enum descriptions — error IS the message

No generics needed

Compile-time execution

@tape {} runs tape code at compile time. Generate type-specialized structs and functions — same language, same debugger, no inference puzzles.

@emit — inject declarations

${T} — splice type names into identifiers

@sizeof, @typeof — reflect on types

collections.tape
struct Event {
    id: i64;
    name: [16]u8;
}

@tape fn gen_queue(T: type) {
    @emit struct Queue_${T} {
        items: *${T}; count: i64; cap: i64;
    }
    @emit fn queue_${T}_push(q: *Queue_${T}, item: ${T}) {
        // grow + append
    }
    @emit fn queue_${T}_pop(q: *Queue_${T}) -> ?${T} {
        // remove + return
    }
}

@tape { gen_queue(i64); }
@tape { gen_queue(Event); }
button.tape
component Button {
    @tape { ui.drawable(); }
    @tape { ui.interactive(); }

    prop label: *u8;
    event on_click();

    state hovered: bool = false;
    state active: bool = false;

    fn handle_pointer(ev: *ui.PointerEvent) {
        if (ev.kind == ui.PointerKind.Enter) { hovered = true; }
        if (ev.kind == ui.PointerKind.Leave) { hovered = false; }
        if (ev.kind == ui.PointerKind.Down) { active = true; }
        if (ev.kind == ui.PointerKind.Up) {
            active = false;
            fire on_click();
        }
    }

    view {
        widgets.Panel {
            widgets.Label { text: label; }
        }
    }
}

No closures needed

Events and state

Components declare typed events. Parents bind handlers — just function pointers, no hidden allocations. Interaction state flags are declared for styling — the #style region that consumes them is specified, not yet implemented.

event — typed callback slot

fire — invoke bound handler

state — bool flags for :hovered, :active

community

Join us on Discord

Follow the development, ask questions, share ideas, and help shape the language.

Join the Discord

What's in the box

01

Dual backend

VM interpreter for dev, native machine code for prod. Same TAC IR, same semantics.

02

Three-address IR

Explicit data flow. Values have names, not stack positions. Trivial to optimize.

03

@tape {} comptime

Run code at compile time. Generate types, compute tables, replace generics entirely.

04

Components

First-class props, slots, events, vtables. Built into the type system, not bolted on.

05

Source regions

#code, #view, #style, #test — sub-languages in one file, one IR out.

06

Three profiles

t0 kernel, t1 application, t2 scripting. Pick your strictness per module.

07

Error returns

T or Error. Propagate with `or return`, handle with `or {}`. No exceptions.

08

Direct codegen

Emits x86-64 and ARM64 directly. PE, ELF, or Mach-O. No LLVM, no Cranelift, no external toolchain.

09

C without bindings

extern fn calls into C, @export makes tape callable from it. Every @link symbol is verified at build time.