Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3,856 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

RTS β€” TypeScript that flies

rts_

TypeScript compiled to a native binary. No runtime. No heavy GC. No excuses.

A vulture in sunglasses is never in a hurry β€” it has already arrived.

Cranelift Rust License Single Binary

Bun/Node parity

🌐 Cross-runtime parity

JS spec compatibility validated against Bun and Node over 679 standalone TS fixtures.

[β–°β–°β–°β–°β–°β–°β–°β–°β–°β–°β–°β–°β–°β–°β–±β–±β–±β–±β–±β–±] 72.5%   479/661 fixtures passing
Metric Value
Parity 72.5% (479/661)
βœ… RTS = Bun = Node 479
❌ RTS diverges 97
πŸ’₯ RTS runtime error 85
πŸ› οΈ Left to fix 182
⚠️ Bun β‰  Node (skip) 18
🚫 Rejected (RTS-only) 0
πŸ“¦ Total fixtures 679

Updated: 2026-07-24 β€” how to add a fixture


πŸ¦… What it is

RTS is a compiler + runtime that takes your .ts and spits out a native .exe. It is not a transpiler, not a bundler, not a wrapper around V8 β€” it is Cranelift generating machine code directly from the SWC AST, with a minimal Rust runtime and a typed, boxing-free ABI.

Two paths, same codegen:

Mode Command What it does
πŸš€ JIT rts run app.ts Compiles to executable memory and runs. Zero disk.
πŸ“¦ AOT rts compile -p app.ts out Object file β†’ linker β†’ standalone binary (~3 KB).

⚑ Performance β€” honest numbers, new engine

Context. The engine was rewritten from scratch on a sound value model (PolyValue NaN-box + shapes + inline caches) and the campaign so far has been correctness-first (parity badge above). The deleted old engine's peak (Monte Carlo AOT 16.9 ms, 5.4Γ— faster than Bun; HTTP 29k req/s) is the documented performance target to re-clear, not the current state. Numbers below are end-to-end process time (startup included β€” AOT runtime init is ~70 ms of every figure) measured now on the new engine.

πŸ“Š Measured benchmarks (auto-updated by CI)

End-to-end process time (includes startup/JIT compile), median of 20 runs after 3 warmups, GitHub Actions windows-latest β€” commit 777e6e3.

Bench Bun Node Deno RTS JIT RTS AOT AOT vs Bun AOT vs Node
Monte Carlo Ο€ 10M (same xorshift algorithm) 4.81 s 7.42 s 3.58 s 220 ms 131 ms 36.74Γ— 56.65Γ—
Monte Carlo Ο€ 10M (JS Math.random) 118 ms 267 ms 214 ms 218 ms 126 ms 0.94Γ— 2.12Γ—
Ο€ decimal ~30 digits (i128 vs BigInt) 50 ms 55 ms 40 ms 124 ms 31 ms 1.60Γ— 1.77Γ—
Monte Carlo 10M threaded (vs Bun Workers) 164 ms β€” β€” 195 ms 107 ms 1.54Γ— β€”
Ο€ Machin f64 (RTS only) β€” β€” β€” 118 ms 31 ms β€” β€”

Updated: 2026-07-24 β€” run locally with powershell -File bench/benchmark.ps1

Why native wins (and where the work is). RTS compiles TS to machine code via Cranelift β€” no JIT warmup, no interpreter tier, native 64-bit integer arithmetic JS engines can't touch without BigInt. The PolyValue NaN-box only pays where code is actually polymorphic and the Cranelift egraph folds redundant box/unbox away β€” the design that made the old engine 5Γ— faster than Bun is intact; wiring the new engine's hot paths back to it (plus cutting the ~70 ms AOT startup) is the tuning phase after the parity campaign.


🧰 The runtime stack β€” the whole std::*, in pure Rust

40+ namespaces today β€” being reshaped into per-module rts:* imports (camelCase, JS globals for everything the language already covers): see docs/specs/rts-std-surface.md. No dependency on OpenSSL, schannel, libuv, or any external runtime.

Family Namespaces
I/O & FS io fs path process env os
Compute math num bigfloat fmt hash crypto
Memory gc buffer mem alloc ptr ffi
Concurrency thread atomic sync parallel
Network net tls http_server (embedded actix-web)
Data collections string regex json date
Async events (EventEmitter), native Promise + Function
Meta runtime test trace hint

🌐 Painless HTTPS: rustls + webpki-roots (Mozilla CAs embedded in the binary) 🧡 Threading: 4 coexisting mechanisms β€” spawn/join, spawn_async, spawn_detached (8-worker pool, 5M spawn/s), scope auto-join πŸ”’ Shard-aware HandleTable: 32 mutually lock-free shards


πŸ•ΈοΈ Native HTML/CSS render engine

The UrubuCode β€” the mascot, drawn with nothing but CSS boxes and animated by the RTS render engine

The mascot above is an HTML page β€” no images: just CSS boxes + @keyframes, rendered and animated by the engine.

RTS has its own HTML+CSS render engine, in pure Rust (crates/rts-dom), following the canonical browser pipeline: DOM β†’ CSS cascade β†’ layout (x,y,w,h) β†’ display list β†’ paint. The backend (egui/wgpu) only paints β€” the DOM owns everything, headless and testable without a window.

What already renders faithfully (validated number by number against real Chrome, getBoundingClientRect element by element β€” the Bootstrap cover and the .row/.col grid come out pixel-perfect):

  • Full cascade (specificity, !important, inheritance, @media per viewport) with per-element custom properties (var() with per-component override)
  • Flexbox: grow/shrink/basis, align-self, order, real stretch, column with absorbing margin:auto, gap, wrap
  • Units: rem/em/%/vw/vh and calc() (fluid typography), negative margins, box-sizing
  • Flow: rich inline (links/bold flowing inside a paragraph), float, position: absolute/fixed v1, scroll containers with their own scrollbars
  • CSS animations: @keyframes + transition with full easing β€” colors, sizes, and margins interpolating (the vulture above flaps its wings with this)
  • External resources: local <link rel="stylesheet"> + @import

Test any local page with one line:

rts run examples/view.ts examples/urubu.html                            # the mascot
rts run examples/view.ts examples/bootstrap-5.3.8-examples/cover/index.html  # real Bootstrap
rts run examples/view.ts path/to/your/index.html                    # your site

Full state and technical backlog: issue #1793.


🎯 What the language understands today

βœ… Control flow β€” if/else, while, do-while, for, for-of/for-in (real iterator protocol with IteratorClose on break), switch (native jump table via br_table when all cases are integer literals), labeled break/continue

βœ… Functions β€” declaration, expression, arrow, closures with mutable capture (cells), tail call optimization (return f(x) becomes return_call), first-class function pointers, call/apply/bind/toString, new Function (runtime compile), spread call f(...args)

βœ… Classes β€” constructor, methods, this, extends, super(...), super.method(...), static methods/fields + static {}, getters/setters, real C.prototype + constructor.name, shape-keyed virtual dispatch, private fields #x, Rust-style operator overload (a + b becomes a.add(b) at compile time)

βœ… Generators & async β€” function*/yield/yield* (lazy state machine), async generators + for await, async/await with a real microtask queue (.then chains in spec order), Promise combinators (all/allSettled/race/any), thenable adoption, withResolvers

βœ… Objects β€” hidden-class shapes + inline caches, getters/setters in literals, computed keys, spread, Object.* statics, property descriptors, freeze/seal, prototype chain, Proxy (get/set/delete/apply/ownKeys traps)

  • Reflect, Symbol (+ well-known, Symbol.iterator protocol)

βœ… Data β€” TypedArrays/ArrayBuffer/DataView/SharedArrayBuffer + Atomics, Map/Set/WeakMap/WeakSet (TS stdlib), WeakRef/ FinalizationRegistry (strong interim, #217), JSON (+JSON5), Date, RegExp (exec/matchAll/named groups/d flag), big decimal (bigfloat, i128 fixed-point ~30 digits), full destructuring (incl. assignment targets), template literals + tagged templates + String.raw

βœ… Errors β€” try/catch/finally, real throw/instanceof over the Error family, error slot + pending-error unwind at call edges

βœ… Web/Node surface β€” fetch/Headers/FormData/Blob/streams, URL, TextEncoder/Decoder, timers + microtasks, EventTarget/AbortController, console, node:fs/os/path/process/crypto/util shims, N-API addons (.node), import.meta

❌ Not there yet β€” decorators, full generics/type-checker, real weak semantics (#217), Intl (partial), full BigInt semantics, real async event loop for every path (#207), var hoisting edge cases (#301)


πŸ—οΈ Architecture

The cutover happened. The old engine (rts-codegen-old) and the MIR tier (rts-mir) are deleted — crates/rts-codegen-new/ is the only engine (single HIR→Cranelift path; PolyValue NaN-boxed value model in crates/rts-adapters/; hidden-class shapes + AOT-safe data inline caches; data-driven dispatch). Canonical design: docs/specs/rts-codegen-new-design.md. Public-surface direction: docs/specs/rts-std-surface.md.

Cargo workspace in crates/. src/ is the facade of the rts bin (re-exports the crates); real paths live under crates/<crate>/src/.

crates/
β”œβ”€ rts-ast/          internal AST
β”œβ”€ rts-parser/       SWC parse β†’ AST (+ generator/async state-machine desugar)
β”œβ”€ rts-diagnostics/  structured errors
β”œβ”€ rts-engine/       ⚑ heap GC + ABI contract (SPECS, AbiType, Intrinsic, symbols)
β”‚                    + Registry/builder + global shape registry
β”œβ”€ rts-hir/          typed HIR (I8..I128/F32/F64/Bool/Str/Handle/Array/Function/Class/Object/Any)
β”œβ”€ rts-adapters/     value model β€” PolyValue (64-bit NaN-box), Repr lattice,
β”‚                    shapes + data ICs, data-driven dispatch, runtime trampolines
β”œβ”€ rts-codegen-new/  THE engine β€” front/run (single HIRβ†’Cranelift lowering),
β”‚                    module_jit + module_aot, adapter_symbols (JIT table harvested from SPECS)
β”œβ”€ rts-primitives/   PRIMORDIAL classes (String/Object/Array/Function/Promise/Boolean/Number/Error…)
β”œβ”€ rts-shared/       non-primordial universal (collections/json/globals + stdlib/*.ts preludes)
β”œβ”€ rts-std/          backend (io/net/tokio/console/promise/streams/audio)
β”œβ”€ rts-runtime/      thin facade (pub use of the four above) + AOT staticlib
β”œβ”€ rts-node/         node:* shims (fs, os, path, process, crypto, util)
β”œβ”€ rts-napi/         N-API (.node addons) via libloading + HandleTable
β”œβ”€ rts-dom/          headless HTML+CSS engine (DOM β†’ cascade β†’ layout β†’ display list)
β”œβ”€ rts-egui/         window/paint backend (egui/wgpu) + render/input namespaces
β”œβ”€ rts-linker/       native link (system linker + object fallback, per-target archives)
└─ rts-cli/          run Β· compile Β· apis Β· init Β· repl Β· eval Β· ir

Pipeline (new engine β€” single path, no MIR)

TS β†’ SWC β†’ AST β†’ HIR (rts-hir) β†’ lower/ (HIR β†’ Cranelift IR, ONE path) β†’ Cranelift egraph β†’ JIT/AOT

There is no MIR tier and no dual AST/MIR in the new engine. The Cranelift egraph (use_egraphs=true) is the ONLY optimizer (const-fold, CSE, DCE, FMA, strength reduction, intraprocedural inlining). The front-end only does what Cranelift cannot (JS semantics): ToNumber/ToString/ToBoolean coercions, the polymorphic +, box/unbox insertion (pure IR the egraph folds), shape/IC site emission, narrow-int wrap, exception edges. AOT/JIT share compile_program (FnCtx.module is &mut dyn Module).

PRIMORDIAL-vs-Registry doctrine (central to the new engine): the engine NAMES only the primordial classes; everything else resolves via the data-driven Registry β€” no non-primordial name hardcoded in the front, not even in an "allow-list" (see CLAUDE.md Β§ anti-hardcode). The non-primordial globals (console, Map/Set, JSON, Date) live as prelude .ts (rts-shared/stdlib/*.ts) and call private engine.* bridges; the front does not name them.

Boxing-free ABI: each namespace function is a symbol #[no_mangle] extern "C" fn __RTS_FN_NS_<NS>_<NAME>(...). No JsValue, no central dispatcher. i64/f64 in native bits, strings as UTF-8 (ptr, len), opaque u64 handles for resources. In the new engine the JIT symbol table is DERIVED from SPECS (abi_gen.rs), not manual add_fn!.


πŸš€ Get started in 30 seconds

# Install
git clone https://github.com/UrubuCode/rts && cd rts
cargo build --release

# Run
./target/release/rts run examples/console.ts

# Compile to a binary (~3 KB, no runtime DLL)
./target/release/rts compile -p examples/console.ts hello
./hello

CLI

rts run file.ts                  # in-memory JIT
rts compile -p file.ts out       # AOT with use-based slicing
rts apis                         # list APIs registered in abi::SPECS
rts ir file.ts                   # dump Cranelift IR (for codegen debugging)
rts init my-app                  # project scaffolding

πŸ”¬ Codegen debugging

Want to see exactly what Cranelift is generating?

rts ir file.ts 2>&1 | head -50

Prints the IR of every user fn + __RTS_MAIN without executing. Great for hunting redundant loads/stores in hot loops, unnecessary extern calls, and intrinsic opportunities. See CLAUDE.md Β§ Codegen debugging.


🎯 JS/TS compatibility

Honest number: the new engine's real cross-runtime parity is the block 🌐 Cross-runtime parity at the top (generated by CI against Bun+Node). The old engine hit 100% (372/372) at tag v0.0-202606072107 β€” a local maximum of a hardcoded approach on an unsound value model; the redesign exists to break through that wall, not to repeat the number. Do NOT quote "1015/1015"/"100%" as current state.

What the new engine already covers (under construction, parity climbing):

  • Core syntax: classes (extends/super/static/getters/setters), destructuring, spread in literals, optional chaining, nullish coalescing, arrow/function expressions, template literals
  • Async: Promise + async/await (synchronous path without await; real event loop still open, #207)
  • JS globals as prelude .ts (data-driven): Object + statics, Boolean/Number/String prototypes, Error family, console.*, Map/Set, JSON, Date β€” none named in the front
  • Operators: JS-spec division (/ ALWAYS f64 β€” 44100/48000 === 0.91875, even when assigned to a const), comparisons, ternary, bitwise, shifts
  • try/catch/finally phase 1 (thread-local error slot; finally runs and re-propagates the error correctly)
  • Diagnostics: an unresolved identifier becomes a compile error, never a segfault β€” and never a wrong value (the redesign's soundness floor)

Heavy items still open (some in redesign phase): real async event loop (#207), closures with mutable capture (#195), TCO, Proxy (#218), typed arrays/DataView/ArrayBuffer, Symbol/Reflect/BigInt (#216/#219). Master JS/TS parity tracker: #226.


πŸ“š Documentation

  • πŸ› οΈ CLAUDE.md β€” internal architecture + codebase rules (includes Β§ anti-hardcode)
  • πŸ“– docs/specs/ β€” technical feature specs
  • πŸ—ΊοΈ docs/specs/rts-codegen-new-design.md β€” canonical plan of the engine redesign
  • πŸ› Issues: master JS/TS parity tracker at #226

πŸ›‘οΈ Guardrails

  • βœ‹ No xtask β€” the build is pure cargo
  • βœ‹ No runtime-support download at build time
  • βœ‹ No Rust/Cargo dependency in the AOT binary's final environment
  • βœ‹ Single distributed binary, runs on any Windows/Linux/macOS without installing anything

Made with πŸ¦… by UrubuCode

If Bun is a rocket, RTS is a bird of prey.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages