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 format | Native x64 Windows PE32+ |
| Runtime dependencies | 0 (no VM, no linker, no libc) |
| Builtins | ~80 built-in primitives |
| Standard library | 44 functions (std.sk, tree-shaken) |
| GUI widgets | 4 native Win32 objects |
| Flagship | Self-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→ producesprogram.exein the same folder. - Entry point: every program needs
func Main(). - No build system, no package manager. The
.exeis 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 expressionreturns a value.- Implicit
return 0: a function that falls through withoutreturnautomatically 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):
int | 64-bit integer (also serves as pointer/address) |
float | 32-bit floating point |
double | 64-bit floating point |
string | pointer to null-terminated bytes |
bool | truth value (true / false) |
ptr | pointer (in struct fields) |
int[] | array of 64-bit values (stack array) |
Struct field types:
i8 | 1 byte |
i16 | 2 bytes |
i32 | 4 bytes |
i64 | 8 bytes |
f32 | 4 bytes (float) |
f64 | 8 bytes (double) |
ptr | 8 bytes (pointer) |
char[N] | N bytes (fixed character buffer) |
bytes[N] | N bytes (fixed byte buffer) |
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 integer | 42 |
| Hex integer | 0xFF8A3D |
| Floating point | 3.5, 7.25 |
| String | "hello" |
| Boolean | true, 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 Cchar*) — values get truncated to 1 byte.int[]arrays (e.g.int[] a = [1,2,3]), by contrast, are 8-byte indexed.- Use the
peek/pokefamily 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.fieldlowers to peek/poke atbase + 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
Prints a string literal, string variable, or evaluated expression to the console. Statement, no return value.
Reads a line from the console into the already-declared variable. Supports int and string variables.
Reserves size bytes locally (VirtualAlloc, READWRITE). Returns the base address (0 = error).
Releases local memory (VirtualFree). Returns nonzero on success.
Reads 1 byte locally (zero-extended).
Reads 2 bytes locally (zero-extended).
Reads 4 bytes locally.
Reads 8 bytes locally (for addresses/pointer chains/module bases).
Writes the lowest byte of value locally to addr.
Writes the lowest 2 bytes of value locally to addr.
Writes 4 bytes of value locally to addr.
Writes 8 bytes of value locally to addr.
3.2 Remote process: handle & raw memory
Opens a process with PROCESS_ALL_ACCESS. Returns a handle (0 = failed, e.g. without admin rights).
Closes a handle. Returns nonzero on success.
Reads length bytes from the target process into the local buffer. Returns 1 on success.
Writes length bytes from the local buffer into the target process. Returns 1 on success.
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.
Reads 1 byte remotely (zero-extended).
Reads 2 bytes remotely (zero-extended).
Reads 4 bytes remotely (zero-extended).
Reads 4 bytes remotely, signed.
Reads 8 bytes remotely (a pointer).
Reads a 4-byte float remotely.
Reads an 8-byte double remotely.
Writes 1 byte remotely. Returns 1 on success.
Writes 2 bytes remotely. Returns 1 on success.
Writes 4 bytes remotely. Returns 1 on success.
Writes 8 bytes remotely. Returns 1 on success.
Writes value as a 4-byte float remotely. Returns 1 on success.
Writes value as an 8-byte double remotely. Returns 1 on success.
3.4 Remote process: allocation & protection
Reserves size bytes in the target process as EXECUTE_READWRITE (VirtualAllocEx). Returns the remote address (0 = error).
Releases remote memory reserved with allocEx. Returns nonzero on success.
Changes memory protection on a remote region (VirtualProtectEx). Returns the old protection value (0 = failed).
3.5 Threads & injected code
Starts a thread in the target process at startAddress; param arrives in rcx. Returns a thread handle (0 = error).
Waits on an object/thread; ms = -1 means wait forever. Returns the wait result (0 = signaled).
Return value of the thread/injected code (GetExitCodeThread).
Ends a thread with exit code 0. Returns nonzero on success.
Opens a thread with THREAD_SUSPEND_RESUME. Returns a thread handle (0 = error).
Pauses a thread. Returns the previous suspend count.
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).
Snapshot of all processes. Returns a snapshot handle.
Snapshot of a process's modules. Returns a snapshot handle.
Snapshot of all threads. Returns a snapshot handle.
Reads the first process entry. Returns 1 while an entry came back.
Reads the next process entry. Returns 1 while an entry came back.
Reads the first module entry. Returns 1 while an entry came back.
Reads the next module entry. Returns 1 while an entry came back.
Reads the first thread entry. Returns 1 while an entry came back.
Reads the next thread entry. Returns 1 while an entry came back.
3.7 Own process & system
Base handle of an already-loaded module in the OWN process (GetModuleHandleA). Returns a handle (0 = not loaded).
Address of an exported function (GetProcAddress). Returns the address (0 = not found).
PID of the own process.
Windows error code of the last failed API call (query it immediately after).
Pauses for ms milliseconds.
Compile-time constant: size of a struct in bytes. The argument is a type name, not an expression.
3.8 Input & window
1 while the key with virtual-key code vk is held (global, focus-independent).
Next typed character from the WM_CHAR ring buffer, 0 if none is pending (for editor/IDE text input).
Address of the embedded 8×16 bitmap font in .rdata (128 glyphs of 16 bytes each; glyph c lives at fontAddr()+c*16).
Width of a window's client area.
Height of a window's client area.
3.9 File I/O
Opens a file for reading (OPEN_EXISTING). Returns a file handle.
Opens/creates a file for writing (CREATE_ALWAYS). Returns a file handle.
Reads up to length bytes into buffer. Returns the number of bytes read.
Writes length bytes from buffer. Returns the number of bytes written.
File size in bytes (64-bit).
Starts a directory search, fills a WIN32_FIND_DATA. Returns a search handle (INVALID = -1).
Next search result. Returns nonzero while entries follow.
Ends a directory search. Returns nonzero on success.
Deletes a file. Returns nonzero on success.
Renames/moves a file (MoveFileA). Returns nonzero on success.
3.10 Clipboard & global memory
Opens the clipboard. Returns nonzero on success.
Closes the clipboard. Returns nonzero on success.
Empties the clipboard. Returns nonzero on success.
Gets the CF_TEXT handle from the clipboard. Returns a global-memory handle.
Sets hMem as the CF_TEXT content. Returns the handle / nonzero on success.
Reserves movable global memory (GMEM_MOVEABLE). Returns a global handle.
Locks global memory. Returns a pointer to the data.
Unlocks global memory. Returns nonzero if still locked.
3.11 Process launch
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.
[address:8][last value:8]. Access conveniently via candAddr(results, i) / candVal(results, i).4.1 Numbers
Reinterprets a 32-bit value that was read as unsigned, signed.
4.2 Strings (null-terminated, byte-wise)
Compares two null-terminated strings by content. Returns 1 if equal, else 0.
Length of a null-terminated string, in bytes.
4.3 Processes & modules
PID of a process by its exe name (name is a pointer to the name). Returns the PID (0 = not found).
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.
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).
Single-offset variant: base + o0.
Two-level chain. Returns the address (0 = null pointer).
Three-level chain.
Four-level chain.
4.5 Signature scanning (AOB with wildcards)
Searches for a byte pattern in the range [start..+size). mask[i]==0 means any byte (wildcard). Returns the hit address (0 = no match).
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)
Address of the i-th candidate.
Last value of the i-th candidate.
Scans [start..+size) 4 bytes at a time for value, appending hits to results (max maxN). Returns the hit count.
Like firstScan, but across the ENTIRE committed, readable address space. Returns the hit count.
Snapshots ALL values in a region (for "unknown initial value" scans). Returns the number of values captured.
Keeps candidates whose current value == value; updates the snapshot. Returns the remaining count.
Relative comparison against the last snapshot. mode: 0 = changed, 1 = unchanged, 2 = increased, 3 = decreased. Returns the remaining count.
Comparison against an operand. mode: 0 = equal, 1 = greater, 2 = less. Returns the remaining count.
4.7 Byte patching & injection
Overwrites len bytes at addr with 0x90 (NOP). Returns the result of writeMem.
Writes len raw bytes from src to addr. Returns the result of writeMem.
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).
Injects a DLL via LoadLibraryA (dllPath is a pointer to a null-terminated path). Returns the load thread's return value (0 = failed).
Injects a tiny API-free asm loop that keeps writing value to addr. Returns a thread handle (0 = failed); undo with terminateThread(th).
Finds a signature and overwrites the hit with replaceBuf (makes the page writable first). Returns the hit address (0 = no match).
Finds a signature and NOPs nopLen bytes at the hit. Returns the hit address (0 = no match).
4.8 Threads: suspend / resume a process
Counts a process's threads.
Pauses every thread of a process. Returns the number of threads paused.
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.
Draws a glyph (8×16) at (x,y).
Draws a null-terminated string starting at (x,y). Returns the end x position.
Horizontal line.
Vertical line.
Filled rectangle.
Rectangle outline.
4.10 Clipboard
Puts a null-terminated string on the clipboard. Returns 1 on success.
Reads clipboard text into buf (max bytes including null). Returns the length read.
4.11 Directory entries (WIN32_FIND_DATAA)
Checks whether the current entry is a directory. Returns nonzero if it is.
Address of the current entry's null-terminated file name.
4.12 External process
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.
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.
Resizes the window (MoveWindow; also sets its position to 100,100).
Shows (true/1 → SW_SHOW + UpdateWindow) or hides the window. Non-blocking; the message loop runs through isOpen().
Copies a 32bpp framebuffer (top-down) into the window via StretchDIBits, scaled to the client area.
Pumps all pending window messages, then reports status. Returns 1 while the window exists, 0 after it closes.
Mouse position in client coordinates (negative or beyond the client area when outside it).
Queries a mouse button (0 = left, 1 = right, 2 = middle). Returns 1 while held, else 0.
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.
Queries and clears the click bit. Returns 1 exactly once per click, else 0.
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.
Adds an entry (string literal).
Sets the current selection (takes an expression).
Index of the selected entry, or −1 if nothing is selected.
Number of entries.
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):
Shows/hides the overlay.
Draws the framebuffer into the overlay (black pixels stay transparent).
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.skobjpanel (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 access —
buf[i]byte indexing,&buf[i],else if, truthy conditions,sizeof, implicitreturn 0. - Modules & tree-shaken stdlib —
#use ... as, the#adminUAC 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 soif (name == "foo.sk")just works. - Struct field indexing —
ctx.buf[i]should lower directly instead of needing a local pointer first. - Richer graphics primitives —
drawLine, 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
strAppendplus 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.