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 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

#test — inline test cases

counter.tape
import ui from "ui";
import widgets from "widgets";

component Counter {
    var count: i64 = 0;

    fn increment() { count = count + 1; }
    fn decrement() { count = count - 1; }

    view {
        ui.Column {
            widgets.Label { text: count; size: 24; }
            ui.Row {
                widgets.Button { label: "+"; on_click: increment; }
                widgets.Button { label: "-"; on_click: decrement; }
            }
        }
    }
}
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 {
    prop label: string;
    event on_click();

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

    fn on_pointer_enter() { hovered = true; }
    fn on_pointer_leave() { hovered = false; }
    fn on_pointer_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 drive styling through #style pseudo-selectors.

event — typed callback slot

fire — invoke bound handler

state — bool flags for :hover, :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 x86-64 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 directly. ELF or PE. No LLVM, no Cranelift, no external toolchain.

09

C at the edges

Fast internal ABI. Thin trampolines at library boundaries. extern fn for C interop.