sk.

Reference

skeet is a systems language that compiles straight to native x64 Windows executables (PE32+) — no runtime, no linker, no libc, no dependencies. One .sk file in, one standalone .exe out. The compiler is written in Java (org.skeet.*); the IDE is written entirely in skeet itself.

$ skeet -c skeet_ide.sk
calculating best possible hitchance...
aced headshot 'skeet_ide.exe' hitchance 62%
Target formatNative x64 Windows PE32+
Runtime dependencies0 (no VM, no linker, no libc)
Builtins~80 built-in primitives
Standard library44 functions (std.sk, tree-shaken)
GUI widgets4 native Win32 objects
FlagshipSelf-hosted IDE, 893 lines of skeet

1. Toolchain

The entire toolchain is two words. Write a Main function, compile, run.

// hello.sk
func Main() {
    out("hello, world")
}
$ skeet -c hello.sk
aced headshot 'hello.exe' hitchance 62%

$ ./hello.exe
hello, world
  • Compile: skeet -c program.sk → produces program.exe in the same folder.
  • Entry point: every program needs func Main().
  • No build system, no package manager. The .exe is self-contained — copy it to any Windows machine, it runs.
  • Tree-shaking: only the stdlib functions you actually call end up in the executable.

2. Language reference

2.1 Basic rules

  • One statement per line. Multiple statements on one line are only allowed inside { } (separated by line breaks).
  • Comments: // to end of line.
  • Entry point: func Main() { ... }.
  • C-family form with curly braces for blocks.
// this is a comment
func Main() {
    out("start")      // one statement
    out("end")         // another one
}

2.2 Functions

func name(int a, int b) {
    return a + b
}
  • Declared with func, parameters with type and name.
  • return expression returns a value.
  • Implicit return 0: a function that falls through without return automatically yields 0 — void-style functions don't need a trailing return.
  • Call: name(1, 2).
  • Structs are allowed as parameters (they pass the address).

2.3 Types

Variable types (local variables & parameters):

int64-bit integer (also serves as pointer/address)
float32-bit floating point
double64-bit floating point
stringpointer to null-terminated bytes
booltruth value (true / false)
ptrpointer (in struct fields)
int[]array of 64-bit values (stack array)

Struct field types:

i81 byte
i162 bytes
i324 bytes
i648 bytes
f324 bytes (float)
f648 bytes (double)
ptr8 bytes (pointer)
char[N]N bytes (fixed character buffer)
bytes[N]N bytes (fixed byte buffer)
Note: in skeet, int is 64-bit and carries every address/pointer too — memory work runs through int variables holding an address.

2.4 Variables

int    n = 42
float  f = 3.5
double d = 7.25
string s = "skeet"
bool   b = true
int[]  a = [10, 20, 30]
  • Declaration is Type name = value.
  • Assignment to an existing variable: name = value.

2.5 Literals

Decimal integer42
Hex integer0xFF8A3D
Floating point3.5, 7.25
String"hello"
Booleantrue, false
Array[10, 20, 30]

2.6 Operators

Arithmetic: + - * / %

int r = a + b * 2
int m = x % 4

Bitwise: & | ^ ~ << >>

int masked = flags & 0xF
int shifted = value << 3
int inverted = ~bits

Comparison: == != < <= > >= — yield 1 (true) or 0 (false).

Logical: && || !

if (a > 0 && b < 10) { ... }
if (!done) { ... }

Compound assignment: += -= *= /= %= &= |= ^= <<= >>=

x += 5
score *= 2
mask &= 0xFF

Increment / decrement: ++ --

i++
count--

Unary: -x (negation), +x, ~x (bit invert), !x (logical not)

Memory operators: &x (address of), *p (dereference)

2.7 Truthy conditions

Conditions treat any nonzero value as "true". Boolean flags read naturally because of it:

if (menuOpen) { ... }        // instead of menuOpen == 1
if (!dragging) { ... }       // instead of dragging == 0
if (count && ready) { ... }

2.8 Control flow

if / else if / else:

if (hp <= 0) {
    dead = 1
} else if (hp < 25) {
    warn = 1
} else {
    warn = 0
}

while:

while (frame.isOpen()) {
    render()
}

for:

for (int i = 0; i < n; i++) {
    out(i)
}

break / continue:

for (int i = 0; i < n; i++) {
    if (skip(i)) { continue }
    if (done)    { break }
}

return: return expression — or implicit return 0 on fallthrough.

2.9 Pointers & memory

int buf = alloc(256)     // reserve 256 bytes

// buf[i] is char*-style byte access:
buf[0] = 72              // same as poke8(buf+0, 72)
int c = buf[i]           // same as peek8(buf+i)
int p = &buf[2]          // address of the element (buf+2)

// wider access via peek/poke:
poke32(buf, 0xDEAD)      // write 32 bits
int v = peek32(buf)      // read 32 bits

free(buf)                // release memory
  • buf[i] on a scalar pointer is byte-wise (like C char*) — values get truncated to 1 byte.
  • int[] arrays (e.g. int[] a = [1,2,3]), by contrast, are 8-byte indexed.
  • Use the peek/poke family for 16/32/64-bit access.

2.10 Structs

Definition (must come before first use):

struct Player {
    i32 health; i32 mana
    f32 posX;   f32 posY
    char name[32]
}
  • Fields separated by ; or line breaks, several per line allowed.
  • Natural C alignment.

Usage:

Player p = alloc(sizeof(Player))
p.health = 9999          // field access with .
out(p.posX)
  • A struct variable holds an address; x.field lowers to peek/poke at base + offset.
  • sizeof(Player) is a compile-time constant with the struct size in bytes.
  • Structs work as function parameters (the address gets passed).

2.11 Arrays

int[] a = [10, 20, 30]
out(a[0])                // 10
a[1] = 99
  • int[] arrays are stack arrays with 8-byte elements.
  • Access and assignment via a[index].

2.12 Modules

Split across multiple files with #use:

// main.sk
#use [util.sk] as u

func Main() {
    out(u.helper(7))     // function from util.sk, via alias u
}
// util.sk
func helper(int n) { return n * n }

#use [file.sk] as alias binds a module; its functions are called via alias.function(...).

2.13 The #admin directive

#admin

func Main() { ... }

Embeds a requireAdministrator UAC manifest into the PE, so the program launches with admin rights (needed for accessing other processes without permission errors).

3. Builtins

Built-in functions that lower directly to machine code and Windows API calls, usable without the stdlib. Argument order and return values come straight from the compiler source.

3.1 Console & local memory

out(text)

Prints a string literal, string variable, or evaluated expression to the console. Statement, no return value.

in(var)

Reads a line from the console into the already-declared variable. Supports int and string variables.

alloc(size) → int

Reserves size bytes locally (VirtualAlloc, READWRITE). Returns the base address (0 = error).

free(addr) → int

Releases local memory (VirtualFree). Returns nonzero on success.

peek8(addr) → int

Reads 1 byte locally (zero-extended).

peek16(addr) → int

Reads 2 bytes locally (zero-extended).

peek32(addr) → int

Reads 4 bytes locally.

peek64(addr) → int

Reads 8 bytes locally (for addresses/pointer chains/module bases).

poke8(addr, value)

Writes the lowest byte of value locally to addr.

poke16(addr, value)

Writes the lowest 2 bytes of value locally to addr.

poke32(addr, value)

Writes 4 bytes of value locally to addr.

poke64(addr, value)

Writes 8 bytes of value locally to addr.

3.2 Remote process: handle & raw memory

openProcess(pid) → int

Opens a process with PROCESS_ALL_ACCESS. Returns a handle (0 = failed, e.g. without admin rights).

closeHandle(handle) → int

Closes a handle. Returns nonzero on success.

readMem(handle, address, buffer, length) → int

Reads length bytes from the target process into the local buffer. Returns 1 on success.

writeMem(handle, address, buffer, length) → int

Writes length bytes from the local buffer into the target process. Returns 1 on success.

queryMem(handle, address, buffer) → int

Fills a MEMORY_BASIC_INFORMATION (48 bytes) into buffer (VirtualQueryEx). Returns the number of bytes written (48) or 0.

3.3 Remote process: typed reads/writes

Base-plus-offset workflow. Reads return 0 on failure; integer reads zero-extend, except readIntS.

readByte(handle, address) → int

Reads 1 byte remotely (zero-extended).

readShort(handle, address) → int

Reads 2 bytes remotely (zero-extended).

readInt(handle, address) → int

Reads 4 bytes remotely (zero-extended).

readIntS(handle, address) → int

Reads 4 bytes remotely, signed.

readPtr(handle, address) → int

Reads 8 bytes remotely (a pointer).

readFloat(handle, address) → double

Reads a 4-byte float remotely.

readDouble(handle, address) → double

Reads an 8-byte double remotely.

writeByte(handle, address, value) → int

Writes 1 byte remotely. Returns 1 on success.

writeShort(handle, address, value) → int

Writes 2 bytes remotely. Returns 1 on success.

writeInt(handle, address, value) → int

Writes 4 bytes remotely. Returns 1 on success.

writePtr(handle, address, value) → int

Writes 8 bytes remotely. Returns 1 on success.

writeFloat(handle, address, value) → int

Writes value as a 4-byte float remotely. Returns 1 on success.

writeDouble(handle, address, value) → int

Writes value as an 8-byte double remotely. Returns 1 on success.

3.4 Remote process: allocation & protection

allocEx(handle, size) → int

Reserves size bytes in the target process as EXECUTE_READWRITE (VirtualAllocEx). Returns the remote address (0 = error).

freeEx(handle, address) → int

Releases remote memory reserved with allocEx. Returns nonzero on success.

protectEx(handle, address, size, protect) → int

Changes memory protection on a remote region (VirtualProtectEx). Returns the old protection value (0 = failed).

3.5 Threads & injected code

createRemoteThread(handle, startAddress, param) → int

Starts a thread in the target process at startAddress; param arrives in rcx. Returns a thread handle (0 = error).

waitObject(handle, ms) → int

Waits on an object/thread; ms = -1 means wait forever. Returns the wait result (0 = signaled).

threadExitCode(threadHandle) → int

Return value of the thread/injected code (GetExitCodeThread).

terminateThread(threadHandle) → int

Ends a thread with exit code 0. Returns nonzero on success.

openThread(threadId) → int

Opens a thread with THREAD_SUSPEND_RESUME. Returns a thread handle (0 = error).

suspendThread(threadHandle) → int

Pauses a thread. Returns the previous suspend count.

resumeThread(threadHandle) → int

Resumes a thread. Returns the previous suspend count.

3.6 Toolhelp snapshots

Get the enumeration buffer yourself via alloc() and set its dwSize field (PROCESSENTRY32 = 304, MODULEENTRY32 = 568, THREADENTRY32 = 28).

snapProcs() → int

Snapshot of all processes. Returns a snapshot handle.

snapMods(pid) → int

Snapshot of a process's modules. Returns a snapshot handle.

snapThreads() → int

Snapshot of all threads. Returns a snapshot handle.

procFirst(snapshot, buffer) → int

Reads the first process entry. Returns 1 while an entry came back.

procNext(snapshot, buffer) → int

Reads the next process entry. Returns 1 while an entry came back.

modFirst(snapshot, buffer) → int

Reads the first module entry. Returns 1 while an entry came back.

modNext(snapshot, buffer) → int

Reads the next module entry. Returns 1 while an entry came back.

threadFirst(snapshot, buffer) → int

Reads the first thread entry. Returns 1 while an entry came back.

threadNext(snapshot, buffer) → int

Reads the next thread entry. Returns 1 while an entry came back.

3.7 Own process & system

getModule(nameStrPtr) → int

Base handle of an already-loaded module in the OWN process (GetModuleHandleA). Returns a handle (0 = not loaded).

procAddress(hModule, nameStrPtr) → int

Address of an exported function (GetProcAddress). Returns the address (0 = not found).

currentPid() → int

PID of the own process.

lastError() → int

Windows error code of the last failed API call (query it immediately after).

sleep(ms)

Pauses for ms milliseconds.

sizeof(StructName) → int

Compile-time constant: size of a struct in bytes. The argument is a type name, not an expression.

3.8 Input & window

key(vk) → int

1 while the key with virtual-key code vk is held (global, focus-independent).

pollChar() → int

Next typed character from the WM_CHAR ring buffer, 0 if none is pending (for editor/IDE text input).

fontAddr() → int

Address of the embedded 8×16 bitmap font in .rdata (128 glyphs of 16 bytes each; glyph c lives at fontAddr()+c*16).

clientWidth(hwnd) → int

Width of a window's client area.

clientHeight(hwnd) → int

Height of a window's client area.

3.9 File I/O

openFileRead(pathStrPtr) → int

Opens a file for reading (OPEN_EXISTING). Returns a file handle.

openFileWrite(pathStrPtr) → int

Opens/creates a file for writing (CREATE_ALWAYS). Returns a file handle.

readBytes(handle, buffer, length) → int

Reads up to length bytes into buffer. Returns the number of bytes read.

writeBytes(handle, buffer, length) → int

Writes length bytes from buffer. Returns the number of bytes written.

fileSize(handle) → int

File size in bytes (64-bit).

findFirst(patternStrPtr, findDataBuffer) → int

Starts a directory search, fills a WIN32_FIND_DATA. Returns a search handle (INVALID = -1).

findNext(findHandle, findDataBuffer) → int

Next search result. Returns nonzero while entries follow.

findClose(findHandle) → int

Ends a directory search. Returns nonzero on success.

deleteFile(pathStrPtr) → int

Deletes a file. Returns nonzero on success.

renameFile(oldStrPtr, newStrPtr) → int

Renames/moves a file (MoveFileA). Returns nonzero on success.

3.10 Clipboard & global memory

openClip() → int

Opens the clipboard. Returns nonzero on success.

closeClip() → int

Closes the clipboard. Returns nonzero on success.

emptyClip() → int

Empties the clipboard. Returns nonzero on success.

getClipData() → int

Gets the CF_TEXT handle from the clipboard. Returns a global-memory handle.

setClipData(hMem) → int

Sets hMem as the CF_TEXT content. Returns the handle / nonzero on success.

globalAlloc(size) → int

Reserves movable global memory (GMEM_MOVEABLE). Returns a global handle.

globalLock(handle) → int

Locks global memory. Returns a pointer to the data.

globalUnlock(handle) → int

Unlocks global memory. Returns nonzero if still locked.

3.11 Process launch

run(cmdLineStrPtr) → int

Starts a process (CreateProcessA) and waits for it to end. Returns the exit code (-1 on launch failure). The cmdLine buffer must be writable (via an alloc() copy, or the std helper runCmd()).

4. Standard library

std.sk — 44 functions, bundled with the compiler, callable unqualified (a function you define with the same name takes priority). Only functions you actually use end up in the executable.

Scan result layout: 16 bytes per candidate = [address:8][last value:8]. Access conveniently via candAddr(results, i) / candVal(results, i).

4.1 Numbers

toSigned(v) → int

Reinterprets a 32-bit value that was read as unsigned, signed.

4.2 Strings (null-terminated, byte-wise)

strEq(a, b) → int

Compares two null-terminated strings by content. Returns 1 if equal, else 0.

strLen(s) → int

Length of a null-terminated string, in bytes.

4.3 Processes & modules

findProcess(name) → int

PID of a process by its exe name (name is a pointer to the name). Returns the PID (0 = not found).

moduleBase(pid, name) → int

Base address of a module in the target process. Returns the address (0 = not found).

4.4 Pointer chains

Cheat Engine convention: the last offset is added to the resolved address.

resolveChain(h, base, offs, count) → int

Resolves a chain with count offsets; offs points to count int offsets (4 bytes each). Returns the final address (0 = hit a null pointer along the way).

resolveChain1(h, base, o0) → int

Single-offset variant: base + o0.

resolveChain2(h, base, o0, o1) → int

Two-level chain. Returns the address (0 = null pointer).

resolveChain3(h, base, o0, o1, o2) → int

Three-level chain.

resolveChain4(h, base, o0, o1, o2, o3) → int

Four-level chain.

4.5 Signature scanning (AOB with wildcards)

aobScan(h, start, size, pattern, mask, len) → int

Searches for a byte pattern in the range [start..+size). mask[i]==0 means any byte (wildcard). Returns the hit address (0 = no match).

wideScan(h, start, size, needle, len) → int

Searches for an ASCII needle encoded as UTF-16 (for classic Notepad and similar). Returns the hit address (0 = no match).

4.6 Value scanning (Cheat Engine workflow)

candAddr(results, i) → int

Address of the i-th candidate.

candVal(results, i) → int

Last value of the i-th candidate.

firstScan(h, start, size, value, results, maxN) → int

Scans [start..+size) 4 bytes at a time for value, appending hits to results (max maxN). Returns the hit count.

scanAll(h, value, results, maxN) → int

Like firstScan, but across the ENTIRE committed, readable address space. Returns the hit count.

snapAll(h, start, size, results, maxN) → int

Snapshots ALL values in a region (for "unknown initial value" scans). Returns the number of values captured.

nextScanExact(h, results, count, value) → int

Keeps candidates whose current value == value; updates the snapshot. Returns the remaining count.

nextScanCmp(h, results, count, mode) → int

Relative comparison against the last snapshot. mode: 0 = changed, 1 = unchanged, 2 = increased, 3 = decreased. Returns the remaining count.

nextScanVal(h, results, count, mode, operand) → int

Comparison against an operand. mode: 0 = equal, 1 = greater, 2 = less. Returns the remaining count.

4.7 Byte patching & injection

nop(h, addr, len) → int

Overwrites len bytes at addr with 0x90 (NOP). Returns the result of writeMem.

patch(h, addr, src, len) → int

Writes len raw bytes from src to addr. Returns the result of writeMem.

injectCode(h, code, len, param) → int

Injects len bytes of machine code, runs it as a thread with param, waits for it to finish. Returns the code's return value (0 = failed).

dllInject(h, dllPath) → int

Injects a DLL via LoadLibraryA (dllPath is a pointer to a null-terminated path). Returns the load thread's return value (0 = failed).

freezeValue(h, addr, value) → int

Injects a tiny API-free asm loop that keeps writing value to addr. Returns a thread handle (0 = failed); undo with terminateThread(th).

patchAt(h, start, size, pattern, mask, patLen, replaceBuf, repLen) → int

Finds a signature and overwrites the hit with replaceBuf (makes the page writable first). Returns the hit address (0 = no match).

nopSig(h, start, size, pattern, mask, patLen, nopLen) → int

Finds a signature and NOPs nopLen bytes at the hit. Returns the hit address (0 = no match).

4.8 Threads: suspend / resume a process

countThreads(pid) → int

Counts a process's threads.

suspendProcess(pid) → int

Pauses every thread of a process. Returns the number of threads paused.

resumeProcess(pid) → int

Resumes every thread of a process. Returns the number of threads resumed.

4.9 UI: bitmap font, rectangles

The framebuffer fb is a 32bpp buffer of width fbW; colors are 0xRRGGBB.

drawChar(fb, fbW, x, y, ch, color)

Draws a glyph (8×16) at (x,y).

drawText(fb, fbW, x, y, str, color) → int

Draws a null-terminated string starting at (x,y). Returns the end x position.

hLine(fb, fbW, x, y, len, color)

Horizontal line.

vLine(fb, fbW, x, y, len, color)

Vertical line.

fillRect(fb, fbW, x, y, w, h, color)

Filled rectangle.

drawRect(fb, fbW, x, y, w, h, color)

Rectangle outline.

4.10 Clipboard

clipboardSet(strPtr) → int

Puts a null-terminated string on the clipboard. Returns 1 on success.

clipboardGet(buf, max) → int

Reads clipboard text into buf (max bytes including null). Returns the length read.

4.11 Directory entries (WIN32_FIND_DATAA)

isDir(findDataBuf) → int

Checks whether the current entry is a directory. Returns nonzero if it is.

fileName(findDataBuf) → int

Address of the current entry's null-terminated file name.

4.12 External process

runCmd(cmd) → int

Runs a command (copies the literal into a writable buffer) and waits for it to finish. Returns the exit code (-1 on launch failure).

5. GUI toolkit

Four native Win32 objects plus a software framebuffer you draw into by hand and push to the screen via blit. Each object's value is its Win32 HWND.

Literal constraint: constructor coordinates/text, and the arguments to setSize and blit, must be literals (compile-time evaluated). setSelected, setEnabled, and mouseDown, by contrast, take real expressions.

5.1 SFrame — a regular window

Constructor: new SFrame("Title") — one argument, the window title. Position CW_USEDEFAULT, initial size 800×600, style WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN.

frame.setSize(width, height)

Resizes the window (MoveWindow; also sets its position to 100,100).

frame.setVisible(bool)

Shows (true/1 → SW_SHOW + UpdateWindow) or hides the window. Non-blocking; the message loop runs through isOpen().

frame.blit(buffer, width, height)

Copies a 32bpp framebuffer (top-down) into the window via StretchDIBits, scaled to the client area.

frame.isOpen() → int

Pumps all pending window messages, then reports status. Returns 1 while the window exists, 0 after it closes.

frame.mouseX() / frame.mouseY() → int

Mouse position in client coordinates (negative or beyond the client area when outside it).

frame.mouseDown(button) → int

Queries a mouse button (0 = left, 1 = right, 2 = middle). Returns 1 while held, else 0.

frame.wheel() → int

Scroll-wheel notches since the last call (reset afterward). +1 per notch up, −1 per notch down.

5.2 SButton — a click button

Constructor: new SButton(frame, "Text", x, y, width, height) — parent SFrame, label, x, y, width, height. Style WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON. Max 31 buttons per program.

btn.clicked() → int

Queries and clears the click bit. Returns 1 exactly once per click, else 0.

btn.setEnabled(bool)

Enables/disables the control (1 = on, 0 = off).

5.3 SComboBox — a dropdown list

Constructor: new SComboBox(frame, x, y, width, height) — parent SFrame, x, y, width, height. height is the total height including the expanded list (Win32 semantics). Style CBS_DROPDOWNLIST.

box.addItem("Text")

Adds an entry (string literal).

box.setSelected(index)

Sets the current selection (takes an expression).

box.getSelected() → int

Index of the selected entry, or −1 if nothing is selected.

box.itemCount() → int

Number of entries.

box.setEnabled(bool)

Enables/disables the control (same as SButton).

5.4 SOverlay — a transparent overlay

Constructor: new SOverlay(width, height) — creates a borderless, always-on-top, click-through WS_POPUP window at (0,0) (WS_EX_LAYERED|WS_EX_TRANSPARENT|WS_EX_TOPMOST) with black as the color key: pure-black pixels (0x000000) are transparent. The basis for ESP/game overlays.

Methods (shares HWND handling with SFrame):

ov.setVisible(bool)

Shows/hides the overlay.

ov.blit(buffer, width, height)

Draws the framebuffer into the overlay (black pixels stay transparent).

ov.isOpen() → int

Pumps messages, returns 1 while the overlay exists.

6. The self-hosted IDE

skeet_ide.sk — a complete development environment, written entirely in 893 lines of skeet and compiled to a native .exe:

  • File tree on the left with expandable directories, right-click menu (new file, rename, delete).
  • Multiple tabs for open files, dynamically sized and scrollable.
  • Editor with syntax highlighting, cursor, text editing (typing, Enter, Backspace, Tab), horizontal & vertical scrolling via sliders.
  • Compiler output console at the bottom.
  • Compile/Run buttons and a movable project.skobj panel (project definition with entry point and dependencies).

It uses the same software renderer (framebuffer + blit) and the same GUI/file builtins as any other skeet program — proof that the language carries its own weight.

7. Roadmap

Three tiers: what ships today, what's actively being built, and the horizon.

Shipped

  • Native x64 PE backend — direct machine-code emission, no VM, no external linker, no C runtime.
  • Full type & operator set — int / float / double / string / bool / ptr, int[] arrays, structs with C layout, the complete arithmetic/bitwise/logical/compound-assignment operator set, ++/--.
  • Readable low-level accessbuf[i] byte indexing, &buf[i], else if, truthy conditions, sizeof, implicit return 0.
  • Modules & tree-shaken stdlib#use ... as, the #admin UAC manifest, a 44-function std.sk that only compiles in what's actually called.
  • ~80 compiler builtins — local & remote-process memory, threads, snapshots, file I/O, input, windowing, clipboard, process launch.
  • GUI toolkit — SFrame, SButton, SComboBox, SOverlay, plus a software framebuffer renderer.
  • Game-hacking suite — value scanning (first/next/exact/cmp/val), AOB scanning with wildcards, pointer chains, code & DLL injection, value freezing, process suspend/resume.
  • Self-hosted IDE — file tree, tabs, syntax-highlighted editor, scrollbars, compile/run — 893 lines of skeet.

In progress

  • String == by content — today == on strings compares pointers; strEq() is the workaround. Teaching the evaluator a string type so if (name == "foo.sk") just works.
  • Struct field indexingctx.buf[i] should lower directly instead of needing a local pointer first.
  • Richer graphics primitivesdrawLine, circles, and alpha blending in the software renderer.

Horizon

  • Enums & constants — named alternatives to magic-number flags.
  • String formatting / interpolation — building messages without hand-rolled strAppend plus number conversion.
  • for-each & array-of-structs sugar — iterating collections and typed blocks without manual index math.
  • Language server + debugger in the IDE — diagnostics while typing; stepping through a running .exe.
  • Self-hosting compiler — the endgame: skeet compiles skeet, the Java frontend retires.

All signatures and semantics come directly from the compiler source and standard library. Roadmap tiers reflect current status; scope and order can change.