<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>tsrun - TypeScript Interpreter in Rust</title>
<meta name="description" content="A minimal TypeScript runtime in Rust for embedding. Use TypeScript for config files with IDE autocompletion, type checking, and error highlighting. No Node.js required.">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
</head>
<body>
<nav class="nav">
<div class="nav-container">
<a href="/" class="nav-brand">
<span>tsrun</span>
</a>
<ul class="nav-links">
<li><a href="/playground/">Playground</a></li>
<li><a href="/getting-started/">Getting Started</a></li>
<li><a href="/docs/">Documentation</a></li>
<li><a href="/examples/">Examples</a></li>
</ul>
<div class="nav-actions">
<a href="https://github.com/DmitryBochkarev/tsrun" class="github-link" aria-label="GitHub">
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/>
</svg>
</a>
</div>
</div>
</nav>
<main>
<section class="hero">
<div class="container">
<h1>tsrun</h1>
<p class="tagline">TypeScript Interpreter in Rust</p>
<p class="description">
A minimal TypeScript runtime designed for embedding in applications. Perfect for configuration files where you want autocompletion, type checking, and error highlighting in your editor.
</p>
<div class="hero-buttons">
<a href="/playground/" class="btn btn-primary">
Try Playground
</a>
<a href="/getting-started/" class="btn btn-secondary">
Get Started
</a>
</div>
</div>
</section>
<section class="features">
<div class="container">
<div class="section-header">
<h2>Features</h2>
<p>TypeScript for configs with IDE autocompletion - embedded in your application</p>
</div>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">📦</div>
<h3>ES Modules</h3>
<p>Full import/export support with step-based module loading. Load modules from filesystem, network, or virtual sources.</p>
</div>
<div class="feature-card">
<div class="feature-icon">⏳</div>
<h3>Async/Await</h3>
<p>Promises, async functions, Promise.all/race/allSettled. Pause execution for host-provided async operations.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🏛</div>
<h3>Classes</h3>
<p>Full class support with inheritance, static blocks, private fields, getters and setters.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔄</div>
<h3>Generators</h3>
<p>function*, yield, yield*, and for...of iteration. Create lazy sequences and iterators.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🧰</div>
<h3>Built-ins</h3>
<p>Array, String, Object, Map, Set, Date, RegExp, JSON, Math, Proxy, Reflect, Symbol and more.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🏷</div>
<h3>TypeScript Native</h3>
<p>Enums, interfaces, decorators, namespaces, generics, and type annotations. Types are stripped at runtime.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔗</div>
<h3>Minimal & Embeddable</h3>
<p>Small footprint with Rust and C APIs. No Node.js dependency. Ideal for config files and scripting in host applications.</p>
</div>
</div>
</div>
</section>
<section class="install">
<div class="container">
<div class="section-header">
<h2>Installation</h2>
<p>Multiple ways to use tsrun in your projects</p>
</div>
<div class="install-options">
<div class="install-card">
<h3>CLI</h3>
<div class="code-block">
<div class="code-header">
<span class="lang">bash</span>
<button class="copy-btn">Copy</button>
</div>
<div class="code-content">
<pre><code class="language-bash">cargo install tsrun</code></pre>
</div>
</div>
</div>
<div class="install-card">
<h3>Rust Library</h3>
<div class="code-block">
<div class="code-header">
<span class="lang">toml</span>
<button class="copy-btn">Copy</button>
</div>
<div class="code-content">
<pre><code class="language-toml">[dependencies]
tsrun = "0.1"</code></pre>
</div>
</div>
</div>
<div class="install-card">
<h3>C/C++ Embedding</h3>
<div class="code-block">
<div class="code-header">
<span class="lang">bash</span>
<button class="copy-btn">Copy</button>
</div>
<div class="code-content">
<pre><code class="language-bash">cargo build --release --features c-api</code></pre>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="use-cases">
<div class="container">
<div class="section-header">
<h2>Use Cases</h2>
<p>TypeScript configurations embedded in your application</p>
</div>
<div class="tabs">
<button class="tab active" data-tab="kubernetes">Kubernetes</button>
<button class="tab" data-tab="game">Game Config</button>
<button class="tab" data-tab="api">API Routes</button>
<button class="tab" data-tab="build">Build Tools</button>
<button class="tab" data-tab="validation">Validation</button>
</div>
<div class="tab-content active" id="kubernetes">
<p class="example-desc">Generate type-safe Kubernetes manifests with IDE autocompletion for deployment configs.</p>
<div class="code-block">
<div class="code-header">
<span class="lang">rust</span>
<button class="copy-btn">Copy</button>
</div>
<div class="code-content">
<pre><code class="language-rust">use tsrun::{Interpreter, StepResult};
fn main() -> Result<(), tsrun::JsError> {
let mut interp = Interpreter::new();
interp.prepare(r#"
interface DeploymentConfig {
name: string;
image: string;
replicas: number;
port: number;
}
function deployment(config: DeploymentConfig) {
return {
apiVersion: "apps/v1",
kind: "Deployment",
metadata: { name: config.name },
spec: {
replicas: config.replicas,
selector: { matchLabels: { app: config.name } },
template: {
metadata: { labels: { app: config.name } },
spec: {
containers: [{
name: config.name,
image: config.image,
ports: [{ containerPort: config.port }]
}]
}
}
}
};
}
deployment({ name: "api", image: "myapp:v1.2.0", replicas: 3, port: 8080 })
"#, None)?;
loop {
match interp.step()? {
StepResult::Continue => continue,
StepResult::Complete(value) => {
let json = tsrun::js_value_to_json(value.value())?;
println!("{}", json);
break;
}
_ => break,
}
}
Ok(())
}</code></pre>
</div>
</div>
</div>
<div class="tab-content" id="game">
<p class="example-desc">Define game items with enums and computed loot tables for drop rates and pricing.</p>
<div class="code-block">
<div class="code-header">
<span class="lang">rust</span>
<button class="copy-btn">Copy</button>
</div>
<div class="code-content">
<pre><code class="language-rust">use tsrun::{Interpreter, StepResult};
fn main() -> Result<(), tsrun::JsError> {
let mut interp = Interpreter::new();
interp.prepare(r#"
enum Rarity { Common, Rare, Epic, Legendary }
interface Item {
name: string;
rarity: Rarity;
basePrice: number;
effects?: string[];
}
function createLootTable(items: Item[]) {
return items.map(item => ({
...item,
dropWeight: item.rarity === Rarity.Legendary ? 1 :
item.rarity === Rarity.Epic ? 5 :
item.rarity === Rarity.Rare ? 15 : 50,
sellPrice: Math.floor(item.basePrice * (1 + item.rarity * 0.5))
}));
}
createLootTable([
{ name: "Iron Sword", rarity: Rarity.Common, basePrice: 100 },
{ name: "Dragon Scale", rarity: Rarity.Legendary, basePrice: 5000,
effects: ["Fire Resistance", "+50 Defense"] }
])
"#, None)?;
loop {
match interp.step()? {
StepResult::Continue => continue,
StepResult::Complete(value) => {
let json = tsrun::js_value_to_json(value.value())?;
println!("{}", json);
break;
}
_ => break,
}
}
Ok(())
}</code></pre>
</div>
</div>
</div>
<div class="tab-content" id="api">
<p class="example-desc">Configure REST endpoints with typed middleware and rate limiting rules.</p>
<div class="code-block">
<div class="code-header">
<span class="lang">rust</span>
<button class="copy-btn">Copy</button>
</div>
<div class="code-content">
<pre><code class="language-rust">use tsrun::{Interpreter, StepResult};
fn main() -> Result<(), tsrun::JsError> {
let mut interp = Interpreter::new();
interp.prepare(r#"
interface Route {
method: "GET" | "POST" | "PUT" | "DELETE";
path: string;
handler: string;
middleware?: string[];
rateLimit?: { requests: number; window: string };
}
const routes: Route[] = [
{
method: "GET",
path: "/users/:id",
handler: "users::get",
middleware: ["auth", "cache"]
},
{
method: "POST",
path: "/users",
handler: "users::create",
middleware: ["auth", "validate"],
rateLimit: { requests: 10, window: "1m" }
},
{
method: "DELETE",
path: "/users/:id",
handler: "users::delete",
middleware: ["auth", "admin"]
}
];
routes
"#, None)?;
loop {
match interp.step()? {
StepResult::Continue => continue,
StepResult::Complete(value) => {
let json = tsrun::js_value_to_json(value.value())?;
println!("{}", json);
break;
}
_ => break,
}
}
Ok(())
}</code></pre>
</div>
</div>
</div>
<div class="tab-content" id="build">
<p class="example-desc">Create plugin-based build configurations similar to webpack or vite.</p>
<div class="code-block">
<div class="code-header">
<span class="lang">rust</span>
<button class="copy-btn">Copy</button>
</div>
<div class="code-content">
<pre><code class="language-rust">use tsrun::{Interpreter, StepResult};
fn main() -> Result<(), tsrun::JsError> {
let mut interp = Interpreter::new();
interp.prepare(r#"
interface Plugin {
name: string;
options?: Record<string, any>;
}
interface BuildConfig {
entry: string;
output: { path: string; filename: string };
plugins: Plugin[];
minify: boolean;
}
const config: BuildConfig = {
entry: "./src/index.ts",
output: {
path: "./dist",
filename: "[name].[hash].js"
},
plugins: [
{ name: "typescript", options: { target: "ES2022" } },
{ name: "minify", options: { dropConsole: true } },
{ name: "bundle-analyzer" }
],
minify: true
};
config
"#, None)?;
loop {
match interp.step()? {
StepResult::Continue => continue,
StepResult::Complete(value) => {
let json = tsrun::js_value_to_json(value.value())?;
println!("{}", json);
break;
}
_ => break,
}
}
Ok(())
}</code></pre>
</div>
</div>
</div>
<div class="tab-content" id="validation">
<p class="example-desc">Define form validation schemas with discriminated unions for type-safe rules.</p>
<div class="code-block">
<div class="code-header">
<span class="lang">rust</span>
<button class="copy-btn">Copy</button>
</div>
<div class="code-content">
<pre><code class="language-rust">use tsrun::{Interpreter, StepResult};
fn main() -> Result<(), tsrun::JsError> {
let mut interp = Interpreter::new();
interp.prepare(r#"
type Rule =
| { type: "required" }
| { type: "minLength"; value: number }
| { type: "maxLength"; value: number }
| { type: "pattern"; regex: string; message: string }
| { type: "email" };
interface FieldSchema {
name: string;
label: string;
rules: Rule[];
}
const userSchema: FieldSchema[] = [
{
name: "email",
label: "Email Address",
rules: [
{ type: "required" },
{ type: "email" }
]
},
{
name: "password",
label: "Password",
rules: [
{ type: "required" },
{ type: "minLength", value: 8 },
{ type: "pattern", regex: "[A-Z]", message: "Must contain uppercase" }
]
}
];
userSchema
"#, None)?;
loop {
match interp.step()? {
StepResult::Continue => continue,
StepResult::Complete(value) => {
let json = tsrun::js_value_to_json(value.value())?;
println!("{}", json);
break;
}
_ => break,
}
}
Ok(())
}</code></pre>
</div>
</div>
</div>
</div>
</section>
<div class="container">
<section class="cta">
<h2>Ready to try it?</h2>
<p>Run TypeScript code directly in your browser with our interactive playground.</p>
<a href="/playground/" class="btn btn-primary">Open Playground</a>
</section>
</div>
<footer class="footer">
<div class="container">
<div class="footer-content">
<div class="footer-links">
<a href="https://github.com/DmitryBochkarev/tsrun">GitHub</a>
<a href="/docs/">Documentation</a>
<a href="/examples/">Examples</a>
</div>
<p class="footer-copy">MIT License</p>
</div>
</div>
</footer>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/rust.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/typescript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/bash.min.js"></script>
<script src="/js/main.js"></script>
</body>
</html>