โšก
Stasis - Write WebAssembly modules using familiar TypeScript syntax. Get predictable performance with no GC pauses or runtime surprises. Perfect for games, simulations, and real-time applications where every millisecond counts.
Built-in testing, automatic JavaScript bindings, and tiny output files. Start coding in minutes, not hours.
Initializing...
๐Ÿ“Š Output
Waiting for compilation... Auto-compile is enabled by default.

๐Ÿ“ Familiar TypeScript-like Syntax

Write code in a language you already know. Structs, functions, and control flow just like TypeScript.

struct Player {
  health: u8;
  name: string[32];
  position: Vec3;
}

function heal(player: Player, amount: u8) {
  player.health = min(100, player.health + amount);
}

โšก Predictable Performance

No garbage collection pauses. No malloc overhead. Know exactly how your memory is used.

// All memory allocated at compile time
global gameState: struct {
  players: Player[100];  // Fixed array
  particles: Particle[1000];
  score: u32;
};

๐Ÿงช Built-in Testing

Write tests alongside your code. Tests run in development, automatically excluded from production.

test playerTakesDamage(): bool {
  let p: Player;
  p.health = 100;
  takeDamage(p, 30);
  return p.health == 70;
}

๐Ÿ”ง Seamless JavaScript Integration

Automatic TypeScript definitions. Memory inspection tools. Works in browsers and Node.js.

// Auto-generated clean API
const game = new GameModule();
await game.loadFromUrl("game.wasm");

game.initPlayer(0, "Alice");
const health = game.players[0].health;

๐Ÿš€ Why Choose Stasis?

โœ… Easy to Learn

  • If you know TypeScript or JavaScript, you already know 90% of Stasis
  • No complex memory management or pointer arithmetic
  • Clear error messages that guide you to solutions
  • Interactive playground to experiment and learn

โœ… Fast Development

  • Write once, run everywhere WASM is supported
  • Auto-generated JavaScript/TypeScript bindings
  • Built-in test framework for TDD
  • Hot reload support for rapid iteration

โœ… Production Ready

  • Predictable performance - no sudden GC pauses
  • Tiny binaries - only include code you actually use
  • Useful for games and simulations
  • Works in browsers and Node.js
  • Future: Embedded systems

โœ… Real-World Use Cases

  • Games: Physics engines, game logic, AI
  • Audio/Video: DSP, codecs, filters
  • Science: Simulations, data processing
  • Embedded: IoT devices, microcontrollers

๐Ÿ“š About Stasis

Purpose & Philosophy

Stasis is a statically-allocated, TypeScript-like language that compiles directly to WebAssembly bytecode. Unlike traditional languages that rely on dynamic memory allocation and garbage collection, Stasis takes a radically different approach: all memory is allocated at compile time. This design choice eliminates entire classes of bugs, provides predictable performance, and makes the language perfect for real-time applications, games, and embedded systems.

Key Design Principles

  • Zero Dynamic Allocation: No malloc, no GC, no memory fragmentation. All memory layout is determined at compile time.
  • Predictable Performance: No GC pauses or allocation overhead. Execution time is deterministic.
  • Opcode-Direct Functions: Built-in functions compile to direct WASM opcodes with zero function call overhead.
  • Tree-Shaking by Default: Only code that's actually used gets included in the output.
  • Built-in Testing: Write tests alongside your code. Tests run in development, automatically excluded from production.
  • Type Safety: Complete compile-time type checking with struct layout computation.

Compiler Architecture

The Stasis compiler uses a sophisticated 3-phase architecture optimized for WebAssembly generation:

  1. Phase 1 - Function Signature Discovery: Fast single-pass scan to collect all function signatures, enabling forward references.
  2. Phase 2 - Tree-Shaking & Analysis: Starting from exported functions, recursively parse only reachable code.
  3. Phase 3 - WASM Generation: Generate minimal WASM with optimal section ordering and zero unreferenced code.

Memory Model

Stasis uses a unique memory model where all application state lives in a single global Data structure. Memory offsets and sizes are computed at compile time based on struct definitions. Arrays have fixed sizes, strings are fixed-length UTF-8 buffers, and all memory accesses compile to direct WASM load/store instructions.

๐Ÿ”ง Advanced Features

Opcode-Direct Functions

Functions can compile directly to WASM opcodes for zero overhead:

// Direct WASM opcode - no function call!
function add(a: i32, b: i32): i32 {
    opcode 0x6A;  // i32.add
}

// With immediate values
function getConstant(): i32 {
    opcode 0x41, 42;  // i32.const 42
}

Parameterized Structs

Compile-time struct parameters for flexible data structures:

struct Collection(size: i32) {
    count: i32;
    maxSize: i32 = size;
    items: Item[size];
}

// Different types at compile time
global small: Collection(10);
global large: Collection(100);

Array Management

Controlled allocation-like behavior with static guarantees:

let enemies: Enemy[100];

// Check if space available
if (enemies.can_add()) {
    // Get unused slot
    let enemy = enemies.add();
    enemy.health = 100;
}

// Mark as unused
enemies.delete(enemy);

Method-Style Invocation

Natural syntax that compiles identically to function calls:

// These compile identically:
player.takeDamage(10);
takeDamage(player, 10);

// Works with arrays too
enemies[5].update();
update(enemies[5]);

๐ŸŽฏ Perfect For

๐ŸŽฎ Games & Graphics

Predictable frame times, no GC pauses. Perfect for physics engines, renderers, and game logic where every millisecond counts.

๐ŸŽต Audio Processing

Real-time DSP, synthesizers, and effects. Static allocation ensures glitch-free audio with consistent latency.

๐Ÿ”ฌ Scientific Computing

Simulations and data processing with deterministic performance. Know exactly how much memory you're using.

๐Ÿค– Embedded Systems

Future support for microcontrollers and IoT devices. Fixed memory footprint ideal for constrained environments.

Quick Language Reference

Basic Types

// Numbers
let age: u8 = 25;          // 0 to 255
let score: i32 = -100;     // ยฑ2 billion
let distance: f32 = 3.14;  // floating point

// Text
let name: string[32] = "Alice";  // up to 32 chars

// Arrays  
let scores: i32[10];       // 10 integers
let matrix: f32[3][3];     // 3x3 matrix

Structs & Functions

// Define a struct
struct Enemy {
  health: u8;
  pos: f32[2];  // x, y
  active: bool;
}

// Function with struct parameter
function damageEnemy(e: Enemy, dmg: u8) {
  if (dmg >= e.health) {
    e.health = 0;
    e.active = false;
  } else {
    e.health = e.health - dmg;
  }
}

Control Flow

// Conditions
if (player.health > 0) {
  // still alive
} else {
  gameOver();
}

// Loops
for (let i: i32 = 0; i < 10; i = i + 1) {
  enemies[i].update();
}

// Iterate arrays
foreach (enemy in enemies) {
  if (enemy.active) {
    renderEnemy(enemy);
  }
}

Global Data & Exports

// All data lives here
global gameData: struct {
  enemies: Enemy[100];
  player: Player;
  score: u32;
};

// Export functions for JavaScript
export function startGame(): void {
  initEnemies();
  gameData.score = 0;
}

export function getScore(): u32 {
  return gameData.score;
}