driftjs-org/driftjs

​A register-based reactivity system designed for dependency tracking and automated state synchronization within virtual machine architecture.

TypeScript

15

158 commits

updated Sep 20, 2026

See the code

See what people are saying (1)

SourceMessageScoreDate

DriftJS: My "Fine-Grained” Reactivity Was Re-rendering 1,000 Rows (r/javascript)

A post back I explained how DriftJS updates the DOM: a compile-time address table, direct jumps to bytecode positions, no diffing, no signals graph. What I didn't mention is that the first version of this had a real algorithmic bug, and I only found it because the numbers on the official…

1

Sep 20, 2026

README

⚡ DriftJS

Register-Based Bytecode Virtual Machine UI Framework
256-Register Virtual Machine • AOT Bytecode Stream • Comment-Anchored Reactive Regions • Zero Virtual DOM


DriftJS Logo

Have questions, feature ideas, or want to discuss compiler optimizations and register VM architecture?

Join Discord

Connect with core developers, ask questions, share feedback, and help shape the future of DriftJS.


📌 Overview

DriftJS is a frontend UI framework powered by an in-browser register-based Bytecode Virtual Machine (VM).

Unlike traditional Virtual DOM frameworks (e.g., React) that re-evaluate large tree structures or compiler-only reactive frameworks (e.g., Svelte), DriftJS compiles .drift single-file templates into compact binary-serializable bytecode streams (CompiledModule). At runtime, a lightweight 256-register VM executes these instructions directly against the DOM with minimal memory allocation and surgical updates.


🔥 Key Architectural Features

  • ⚡ 256-Register Virtual Machine: Executes a streamlined bytecode stream across dedicated register slots (r0r255) for DOM elements, text nodes, and primitives—avoiding the overhead and memory churn of virtual DOM trees.
  • 📦 AOT Bytecode & Constant Pool Emission: Compiles .drift Single File Components ahead-of-time into binary-like instruction streams and static constant pools, with reactive state dependencies mapped directly to bytecode program counters.
  • 📍 Comment-Anchored Reactive Regions: Uses DOM comment boundaries (<!--if-->, <!--for-->) to isolate dynamic subtrees, enabling surgical, in-place updates without traversing or re-evaluating surrounding component trees.
  • 🔄 Unified Client & Server VM Execution: The same compiled bytecode runs natively in the browser against the DOM (driftjs-dom) and headlessly on the server (driftjs-ssr), producing identical comment anchors for 1:1 SSR hydration.

🚀 Quick Start (CLI Scaffolder)

Create a new DriftJS app instantly using create-drift:

pnpm create drift my-app
# or using npm / yarn / bun
npm create drift my-app
  • The command will prompt you interactively for your choices to set up your DriftJS app in seconds!

📦 Monorepo Packages

DriftJS is organized as a monorepo published on npm:

PackagePathDescription
create-driftpackages/cliInteractive CLI scaffolding tool (npm create drift)
driftjs-compilerpackages/compilerLexer, Parser, Transformer, & Bytecode Generator emitting CompiledModule bytecode
driftjs-dompackages/dom256-Register Client VM, DOM reconciler, SSR hydration, & mount() API
driftjs-routerpackages/routerClient-side SPA routing engine with history drivers & matched route views
driftjs-ssrpackages/ssrHeadless Server-Side Rendering VM engine (renderToString())
driftjs-sharedpackages/utilsShared Scope, Context API, and Expression Evaluator engine
driftjs-vite-pluginpackages/vite-pluginVite plugin transforming .drift SFCs into synthetic ESM modules
driftjs-vscodepackages/vscode-pluginVS Code Extension for .drift SFC syntax highlighting & diagnostics
templatetemplateStarter project template with Vite, TypeScript, and .drift counter example

⚙️ Architecture & Compiler Pipeline

The compilation and execution workflow consists of 5 tightly decoupled stages:

.drift Template
   │
   ▼
[ DriftLexer ] ──────► On-demand parser-driven tokenization
   │
   ▼
[ DriftParser ] ─────► AST construction (ProgramNode, ElementNode, IfNode, ForNode, etc.)
   │
   ▼
[ DriftTransformer ] ─► Whitespace stripping & JS expression enrichment
   │
   ▼
[ DriftGenerator ] ───► Emits 15-Opcode Bytecode Array, Constant Pool, & Reactive Bindings
   │
   ▼
[ DriftClientVM / DriftServerVM ] ──► Executes Bytecode via 256 Registers & Reactive Anchors

📖 DriftJS Template Syntax Guide (.drift)

A .drift component blends standard HTML markup with JavaScript state logic inside top-level <script> blocks and control directives (@if, @for, @switch).

1. Script Logic & State Scope (<script>)

Declare component reactive state and functions inside a top-level <script> block. Any top-level let or const declarations automatically become part of the component's reactive scope.

<script>
  // Declare reactive state variables
  let user = "Alex";
  let items = [
    { id: 1, text: "Build DriftJS Compiler", done: true },
    { id: 2, text: "Write Keyed LIS Reconciler", done: true },
    { id: 3, text: "Deploy Web App", done: false }
  ];
  let filter = "all";

  // Event handlers & state mutation functions
  function toggleItem(id) {
    items = items.map(item => item.id === id ? { ...item, done: !item.done } : item);
  }

  function removeItem(id) {
    items = items.filter(item => item.id !== id);
  }

  function setFilter(newFilter) {
    filter = newFilter;
  }
</script>

2. Expression Interpolation ({ ... })

Embed dynamic values directly within DOM text content using curly braces {}. Any valid JavaScript expression is supported and evaluated inside the component scope.

<!-- Property access -->
<h1>Welcome back, {user}!</h1>

<!-- Calculations & JavaScript expressions -->
<p>Total Tasks: {items.length}</p>
<p>Completed Tasks: {items.filter(i => i.done).length}</p>

<!-- Ternary conditional expressions -->
<p>Status: {items.every(i => i.done) ? "All Completed! 🎉" : "In Progress ⏳"}</p>

3. Attributes & Event Delegation

Attributes can be static strings, dynamic JavaScript expressions, or event handlers.

Static & Dynamic Attributes

<!-- Static attributes -->
<div class="task-card" data-category="work">

<!-- Dynamic string evaluation -->
<div class={filter === "all" ? "tab active" : "tab"}>

<!-- Boolean attributes (attribute present when true, removed when false) -->
<button disabled={items.length === 0}>Clear All</button>

Event Delegation (onclick={...}, oninput={...})

Event handlers automatically hook into DriftJS's central event delegation engine. Any state mutated inside an event handler triggers targeted DOM updates automatically.

<!-- Direct function binding -->
<button onclick={ () => setFilter("all") }>Show All</button>
<button onclick={ () => setFilter("pending") }>Show Pending</button>

<!-- Inline arrow functions with parameters -->
<button onclick={ () => toggleItem(item.id) }>Toggle Status</button>
<button onclick={ () => removeItem(item.id) }>Delete Task</button>

4. Conditional Directives (@if, @else if, @else)

Render DOM subtrees conditionally based on reactive conditions. Conditional blocks are anchored by comment nodes (<!--if--> / <!--/if-->) for targeted sub-tree mounting.

@if filter === "all" {
  <p class="badge badge-info">Showing all {items.length} items</p>
}
@else if filter === "pending" {
  <p class="badge badge-warning">Showing pending items only</p>
}
@else {
  <p class="badge badge-success">Completed items view</p>
}

5. Loop Directives (@for)

Iterate over arrays using @for. DriftJS reconciliation uses the Keyed LIS (Longest Increasing Subsequence) algorithm to re-order and patch DOM elements efficiently with minimal node recreations.

Item Iteration

@for item in items {
  <div class="task-row">
    <span class={item.done ? "line-through" : ""}>{item.text}</span>
    <button onclick={ () => toggleItem(item.id) }>Check</button>
  </div>
}

Item + Index Iteration

@for (item, index) in items {
  <li class="list-item">
    <span class="index">#{index + 1}</span>
    <span class="title">{item.text}</span>
    <button onclick={ () => removeItem(item.id) }>Remove</button>
  </li>
}

6. Pattern Matching Directives (@switch, @case, @default)

Pattern match discriminant expressions into distinct @case branches.

@switch filter {
  @case "all" {
    <div class="view-all">All Tasks Summary</div>
  }
  @case "pending" {
    <div class="view-pending">Pending Tasks Overview</div>
  }
  @default {
    <div class="view-default">Custom Filter Mode</div>
  }
}

7. Complete Task Tracker Component Example

Here is an example of complete .drift component combining script scope, state reactivity, interpolations, conditional blocks, and loop reconciliation:

<script>
  let newTaskTitle = "";
  let priority = "medium";
  let tasks = [
    { id: 101, title: "Configure Vite Plugin", priority: "high", done: true },
    { id: 102, title: "Optimize VM Registers", priority: "high", done: false },
    { id: 103, title: "Write Benchmarks", priority: "medium", done: false }
  ];

  function toggleTask(id) {
    tasks = tasks.map(t => t.id === id ? { ...t, done: !t.done } : t);
  }

  function deleteTask(id) {
    tasks = tasks.filter(t => t.id !== id);
  }
</script>

<div class="app-container">
  <header class="app-header">
    <h1>Task Board</h1>
    <span class="counter">Pending: {tasks.filter(t => !t.done).length} / {tasks.length}</span>
  </header>

  @if tasks.length === 0 {
    <div class="empty-state">
      <p>🎉 All tasks are completed! Enjoy your day.</p>
    </div>
  }
  @else {
    <ul class="task-list">
      @for (task, idx) in tasks {
        <li class={task.done ? "task-item completed" : "task-item"}>
          <span class="task-num">#{idx + 1}</span>
          <span class="task-title">{task.title}</span>

          @switch task.priority {
            @case "high" { <span class="tag tag-red">High Priority</span> }
            @case "medium" { <span class="tag tag-amber">Medium Priority</span> }
            @default { <span class="tag tag-gray">Low Priority</span> }
          }

          <button onclick={ () => toggleTask(task.id) }>
            {task.done ? "Undo" : "Complete"}
          </button>
          <button class="danger" onclick={ () => deleteTask(task.id) }>Delete</button>
        </li>
      }
    </ul>
  }
</div>

🔢 Virtual Machine Instruction Set Architecture

DriftJS relies on a streamlined 15-opcode ISA. Detailed specifications are in docs/ISA.md.


🛠️ Getting Started & Local Development

Prerequisites

  • Node.js ^20.0.0 or higher
  • pnpm ^9.0.0 or higher

Installation & Setup

  1. Clone the repository:

    git clone https://github.com/hrutavmodha/driftjs.git
    cd driftjs
    
  2. Install dependencies:

    pnpm install
    
  3. Build all workspace packages:

    pnpm build
    
  4. Run the test suite:

    pnpm test
    

    All unit and integration tests across the test suites will run via Vitest.

  5. Typecheck workspace:

    pnpm typecheck
    
  6. Run starter application:

    cd template
    pnpm dev
    

📚 Test Suites Reference


🤝 Contributing

We welcome contributions of all kinds! Whether you want to fix bugs, optimize VM opcode execution, improve compiler error reporting, add developer tools, or expand benchmark coverage:

  1. Fork the repository and create your feature branch (git checkout -b feature/my-feature).
  2. Run tests to ensure everything passes (pnpm test).
  3. Ensure TypeScript typechecking passes (pnpm typecheck).
  4. Open a Pull Request detailing your changes.

Together, let's make DriftJS a production-grade, ultra-fast UI framework!


📄 License

MIT © Hrutav Modha

Contributors

driftjs-org/driftjs

​A register-based reactivity system designed for dependency tracking and automated state synchronization within virtual machine architecture.

TypeScript

15

158 commits

updated Sep 20, 2026

See the code

See what people are saying (1)

SourceMessageScoreDate

DriftJS: My "Fine-Grained” Reactivity Was Re-rendering 1,000 Rows (r/javascript)

A post back I explained how DriftJS updates the DOM: a compile-time address table, direct jumps to bytecode positions, no diffing, no signals graph. What I didn't mention is that the first version of this had a real algorithmic bug, and I only found it because the numbers on the official…

1

Sep 20, 2026

README

⚡ DriftJS

Register-Based Bytecode Virtual Machine UI Framework
256-Register Virtual Machine • AOT Bytecode Stream • Comment-Anchored Reactive Regions • Zero Virtual DOM


DriftJS Logo

Have questions, feature ideas, or want to discuss compiler optimizations and register VM architecture?

Join Discord

Connect with core developers, ask questions, share feedback, and help shape the future of DriftJS.


📌 Overview

DriftJS is a frontend UI framework powered by an in-browser register-based Bytecode Virtual Machine (VM).

Unlike traditional Virtual DOM frameworks (e.g., React) that re-evaluate large tree structures or compiler-only reactive frameworks (e.g., Svelte), DriftJS compiles .drift single-file templates into compact binary-serializable bytecode streams (CompiledModule). At runtime, a lightweight 256-register VM executes these instructions directly against the DOM with minimal memory allocation and surgical updates.


🔥 Key Architectural Features

  • ⚡ 256-Register Virtual Machine: Executes a streamlined bytecode stream across dedicated register slots (r0r255) for DOM elements, text nodes, and primitives—avoiding the overhead and memory churn of virtual DOM trees.
  • 📦 AOT Bytecode & Constant Pool Emission: Compiles .drift Single File Components ahead-of-time into binary-like instruction streams and static constant pools, with reactive state dependencies mapped directly to bytecode program counters.
  • 📍 Comment-Anchored Reactive Regions: Uses DOM comment boundaries (<!--if-->, <!--for-->) to isolate dynamic subtrees, enabling surgical, in-place updates without traversing or re-evaluating surrounding component trees.
  • 🔄 Unified Client & Server VM Execution: The same compiled bytecode runs natively in the browser against the DOM (driftjs-dom) and headlessly on the server (driftjs-ssr), producing identical comment anchors for 1:1 SSR hydration.

🚀 Quick Start (CLI Scaffolder)

Create a new DriftJS app instantly using create-drift:

pnpm create drift my-app
# or using npm / yarn / bun
npm create drift my-app
  • The command will prompt you interactively for your choices to set up your DriftJS app in seconds!

📦 Monorepo Packages

DriftJS is organized as a monorepo published on npm:

PackagePathDescription
create-driftpackages/cliInteractive CLI scaffolding tool (npm create drift)
driftjs-compilerpackages/compilerLexer, Parser, Transformer, & Bytecode Generator emitting CompiledModule bytecode
driftjs-dompackages/dom256-Register Client VM, DOM reconciler, SSR hydration, & mount() API
driftjs-routerpackages/routerClient-side SPA routing engine with history drivers & matched route views
driftjs-ssrpackages/ssrHeadless Server-Side Rendering VM engine (renderToString())
driftjs-sharedpackages/utilsShared Scope, Context API, and Expression Evaluator engine
driftjs-vite-pluginpackages/vite-pluginVite plugin transforming .drift SFCs into synthetic ESM modules
driftjs-vscodepackages/vscode-pluginVS Code Extension for .drift SFC syntax highlighting & diagnostics
templatetemplateStarter project template with Vite, TypeScript, and .drift counter example

⚙️ Architecture & Compiler Pipeline

The compilation and execution workflow consists of 5 tightly decoupled stages:

.drift Template
   │
   ▼
[ DriftLexer ] ──────► On-demand parser-driven tokenization
   │
   ▼
[ DriftParser ] ─────► AST construction (ProgramNode, ElementNode, IfNode, ForNode, etc.)
   │
   ▼
[ DriftTransformer ] ─► Whitespace stripping & JS expression enrichment
   │
   ▼
[ DriftGenerator ] ───► Emits 15-Opcode Bytecode Array, Constant Pool, & Reactive Bindings
   │
   ▼
[ DriftClientVM / DriftServerVM ] ──► Executes Bytecode via 256 Registers & Reactive Anchors

📖 DriftJS Template Syntax Guide (.drift)

A .drift component blends standard HTML markup with JavaScript state logic inside top-level <script> blocks and control directives (@if, @for, @switch).

1. Script Logic & State Scope (<script>)

Declare component reactive state and functions inside a top-level <script> block. Any top-level let or const declarations automatically become part of the component's reactive scope.

<script>
  // Declare reactive state variables
  let user = "Alex";
  let items = [
    { id: 1, text: "Build DriftJS Compiler", done: true },
    { id: 2, text: "Write Keyed LIS Reconciler", done: true },
    { id: 3, text: "Deploy Web App", done: false }
  ];
  let filter = "all";

  // Event handlers & state mutation functions
  function toggleItem(id) {
    items = items.map(item => item.id === id ? { ...item, done: !item.done } : item);
  }

  function removeItem(id) {
    items = items.filter(item => item.id !== id);
  }

  function setFilter(newFilter) {
    filter = newFilter;
  }
</script>

2. Expression Interpolation ({ ... })

Embed dynamic values directly within DOM text content using curly braces {}. Any valid JavaScript expression is supported and evaluated inside the component scope.

<!-- Property access -->
<h1>Welcome back, {user}!</h1>

<!-- Calculations & JavaScript expressions -->
<p>Total Tasks: {items.length}</p>
<p>Completed Tasks: {items.filter(i => i.done).length}</p>

<!-- Ternary conditional expressions -->
<p>Status: {items.every(i => i.done) ? "All Completed! 🎉" : "In Progress ⏳"}</p>

3. Attributes & Event Delegation

Attributes can be static strings, dynamic JavaScript expressions, or event handlers.

Static & Dynamic Attributes

<!-- Static attributes -->
<div class="task-card" data-category="work">

<!-- Dynamic string evaluation -->
<div class={filter === "all" ? "tab active" : "tab"}>

<!-- Boolean attributes (attribute present when true, removed when false) -->
<button disabled={items.length === 0}>Clear All</button>

Event Delegation (onclick={...}, oninput={...})

Event handlers automatically hook into DriftJS's central event delegation engine. Any state mutated inside an event handler triggers targeted DOM updates automatically.

<!-- Direct function binding -->
<button onclick={ () => setFilter("all") }>Show All</button>
<button onclick={ () => setFilter("pending") }>Show Pending</button>

<!-- Inline arrow functions with parameters -->
<button onclick={ () => toggleItem(item.id) }>Toggle Status</button>
<button onclick={ () => removeItem(item.id) }>Delete Task</button>

4. Conditional Directives (@if, @else if, @else)

Render DOM subtrees conditionally based on reactive conditions. Conditional blocks are anchored by comment nodes (<!--if--> / <!--/if-->) for targeted sub-tree mounting.

@if filter === "all" {
  <p class="badge badge-info">Showing all {items.length} items</p>
}
@else if filter === "pending" {
  <p class="badge badge-warning">Showing pending items only</p>
}
@else {
  <p class="badge badge-success">Completed items view</p>
}

5. Loop Directives (@for)

Iterate over arrays using @for. DriftJS reconciliation uses the Keyed LIS (Longest Increasing Subsequence) algorithm to re-order and patch DOM elements efficiently with minimal node recreations.

Item Iteration

@for item in items {
  <div class="task-row">
    <span class={item.done ? "line-through" : ""}>{item.text}</span>
    <button onclick={ () => toggleItem(item.id) }>Check</button>
  </div>
}

Item + Index Iteration

@for (item, index) in items {
  <li class="list-item">
    <span class="index">#{index + 1}</span>
    <span class="title">{item.text}</span>
    <button onclick={ () => removeItem(item.id) }>Remove</button>
  </li>
}

6. Pattern Matching Directives (@switch, @case, @default)

Pattern match discriminant expressions into distinct @case branches.

@switch filter {
  @case "all" {
    <div class="view-all">All Tasks Summary</div>
  }
  @case "pending" {
    <div class="view-pending">Pending Tasks Overview</div>
  }
  @default {
    <div class="view-default">Custom Filter Mode</div>
  }
}

7. Complete Task Tracker Component Example

Here is an example of complete .drift component combining script scope, state reactivity, interpolations, conditional blocks, and loop reconciliation:

<script>
  let newTaskTitle = "";
  let priority = "medium";
  let tasks = [
    { id: 101, title: "Configure Vite Plugin", priority: "high", done: true },
    { id: 102, title: "Optimize VM Registers", priority: "high", done: false },
    { id: 103, title: "Write Benchmarks", priority: "medium", done: false }
  ];

  function toggleTask(id) {
    tasks = tasks.map(t => t.id === id ? { ...t, done: !t.done } : t);
  }

  function deleteTask(id) {
    tasks = tasks.filter(t => t.id !== id);
  }
</script>

<div class="app-container">
  <header class="app-header">
    <h1>Task Board</h1>
    <span class="counter">Pending: {tasks.filter(t => !t.done).length} / {tasks.length}</span>
  </header>

  @if tasks.length === 0 {
    <div class="empty-state">
      <p>🎉 All tasks are completed! Enjoy your day.</p>
    </div>
  }
  @else {
    <ul class="task-list">
      @for (task, idx) in tasks {
        <li class={task.done ? "task-item completed" : "task-item"}>
          <span class="task-num">#{idx + 1}</span>
          <span class="task-title">{task.title}</span>

          @switch task.priority {
            @case "high" { <span class="tag tag-red">High Priority</span> }
            @case "medium" { <span class="tag tag-amber">Medium Priority</span> }
            @default { <span class="tag tag-gray">Low Priority</span> }
          }

          <button onclick={ () => toggleTask(task.id) }>
            {task.done ? "Undo" : "Complete"}
          </button>
          <button class="danger" onclick={ () => deleteTask(task.id) }>Delete</button>
        </li>
      }
    </ul>
  }
</div>

🔢 Virtual Machine Instruction Set Architecture

DriftJS relies on a streamlined 15-opcode ISA. Detailed specifications are in docs/ISA.md.


🛠️ Getting Started & Local Development

Prerequisites

  • Node.js ^20.0.0 or higher
  • pnpm ^9.0.0 or higher

Installation & Setup

  1. Clone the repository:

    git clone https://github.com/hrutavmodha/driftjs.git
    cd driftjs
    
  2. Install dependencies:

    pnpm install
    
  3. Build all workspace packages:

    pnpm build
    
  4. Run the test suite:

    pnpm test
    

    All unit and integration tests across the test suites will run via Vitest.

  5. Typecheck workspace:

    pnpm typecheck
    
  6. Run starter application:

    cd template
    pnpm dev
    

📚 Test Suites Reference


🤝 Contributing

We welcome contributions of all kinds! Whether you want to fix bugs, optimize VM opcode execution, improve compiler error reporting, add developer tools, or expand benchmark coverage:

  1. Fork the repository and create your feature branch (git checkout -b feature/my-feature).
  2. Run tests to ensure everything passes (pnpm test).
  3. Ensure TypeScript typechecking passes (pnpm typecheck).
  4. Open a Pull Request detailing your changes.

Together, let's make DriftJS a production-grade, ultra-fast UI framework!


📄 License

MIT © Hrutav Modha

Contributors

Languages

TypeScript

89.1%

CSS

5.6%

JavaScript

3.3%