Experimental native framework

Web markup.
Native pixels.

TSGPUI transforms a supported subset of HTML and CSS into native GPUI elements by default, with an optional system WebView for browser fidelity.

Typical Electron app
Ships Chromium and Node.js with every app
TSGPUI
GPUI is the default renderer; choose WebView when browser layout matters
  • index.html
  • styles.css
  • backend.ts
TSGPUI • Native Counter
GPUI NATIVE RENDERING

TSGPUI

HTML + CSS + TypeScript. Native GPUI rendering.

CLICK COUNTER 0 Click below to update native UI state.

Backend actions run in embedded QuickJS, not Bun at runtime.

Simulated preview of examples/counter. Its buttons run in the browser and do not use the TSGPUI runtime.

Interactive demo

Source on the left. Native window on the right.

These are the real files from examples/counter/src, shown with syntax highlighting. Switch tabs to read each one.

<!doctype html>
<html>
  <body>
    <main class="shell">
      <section class="card">
        <div class="badge">GPUI NATIVE RENDERING</div>
        <h1>TSGPUI</h1>
        <p class="subtitle">HTML + CSS + TypeScript. Native GPUI rendering.</p>
        <div class="counter-panel">
          <span class="eyebrow">CLICK COUNTER</span>
          <span class="count" data-bind="count">0</span>
          <span class="hint">Click below to update native UI state.</span>
        </div>
        <div class="buttons">
          <button id="decrement" class="secondary" data-onclick="decrement">− Decrease</button>
          <button id="increment" class="primary" data-onclick="increment">+ Increase</button>
          <button id="reset" class="ghost" data-onclick="reset">Reset</button>
        </div>
        <p class="footer">Backend actions run in embedded QuickJS, not Bun at runtime.</p>
      </section>
    </main>
  </body>
</html>
TSGPUI • Native Counter · 900 × 600
GPUI NATIVE RENDERING

TSGPUI

HTML + CSS + TypeScript. Native GPUI rendering.

CLICK COUNTER 0 Click below to update native UI state.

Backend actions run in embedded QuickJS, not Bun at runtime.

Interactive simulation of the counter's layout and colours. The real window is drawn by the GPUI host from the compiled .tgp.

How it works

Three parts, each with one job.

Markup is compiled ahead of time, logic runs in a small sandbox, and the pixels come from a native GPUI host. Nothing in the shipped app asks for a browser or a JavaScript runtime.

Markup and styles

A strict subset of HTML and CSS is parsed at build time into an element tree with explicit keys. CSS selectors, specificity and inheritance are resolved before anything reaches the window, so the layout you write is the layout that ships.

TypeScript backend

One backend.ts exports state and actions. It is transpiled to JavaScript and run in embedded QuickJS on the UI thread. Actions are synchronous and see only get, set and update.

One executable

Packaging copies a prebuilt GPUI host and appends the app bundle to it. The result is a single .exe that runs without Bun, Node or Rust on the machine.

Compilation pipeline

From source files to one native executable.

Each stage writes a file you can inspect. The bundle is plain JSON, so you can open it and see exactly what the host will render.

Source

Your project

  • src/index.html
  • src/styles.css
  • src/backend.ts
  • tsgpui.config.json
Compile

tsgpui compile

Parses the HTML subset, resolves CSS, transpiles the backend and writes a .tgp document.

{
  "format": "tsgpui-1",
  "name": "tsgpui-counter",
  "title": "TSGPUI • Native Counter",
  "width": 900,
  "height": 600,
  "root": { "tag": "body", … },
  "backend_js": "…"
}
Package

tsgpui build

Copies the prebuilt host and appends the bundle, then the host reads it back at startup.

host bundle len TSGPUI01

Host executable, then the bundle JSON, an 8-byte little-endian length and the TSGPUI01 marker.

→ dist/tsgpui-counter.exe

Architecture

Native rendering with a small, contained backend.

The design trades browser breadth for a smaller, inspectable system. These are the properties the current prototype is built around.

  1. Parse

    Strict HTML subset to an element tree with explicit keys and attributes. Unsupported tags fail the build.

  2. Style

    CSS parsed with PostCSS. Descendant matching, class and id selectors, inheritance and specificity are resolved.

  3. Transpile

    The single backend file is compiled with the TypeScript compiler to CommonJS (ES2020).

  4. Render

    The GPUI host opens a GPU-accelerated window and draws the tree. Media queries are evaluated at compile time.

  5. Run

    Clicks invoke actions in QuickJS. The view takes a state snapshot and redraws. QuickJS has an approximate heap cap, not a CPU-time limit.

Two renderer paths

GPUI is the default. Select a system WebView when your interface depends on browser layout or CSS.

No Node or Bun at runtime

Bun or Node is needed for development. The distributed app does not need either one installed.

Fast iteration

Changing HTML, CSS or TypeScript recompiles the bundle and reuses the existing host. Rust is not rebuilt.

Plain-text bundle

The .tgp document is JSON. Its format and contents can be read and checked directly.

Compile-time components

<template data-component> is expanded at compile time. Recursive uses and duplicate IDs are rejected.

Explicit data binding

data-bind and {{stateKey}} read backend state. data-onclick dispatches named actions.

Quick start

Build the counter from a checkout.

Requires Bun or Node 20+ for the developer CLI. Compiling the bundle does not need Rust. Building the native host does.

1. Check and compile the example

bun install
bun run test
bun run gpui:compile

Writes examples/counter/dist/tsgpui-counter.tgp.

2. Get a native host, once per machine

Either point TSGPUI_HOST at a host you trust, or compile one with the Rust toolchain. On Windows that also needs the MSVC build tools.

bun run gpui:host

3. Package the executable

bun run gpui

Writes examples/counter/dist/tsgpui-counter.exe.

Or start a new project with the CLI

tsgpui init my-app
cd my-app
tsgpui dev

tsgpui dev rebuilds and restarts the host on save. It is a fast reload, not state-preserving hot module replacement. tsgpui build writes the single executable.

Docs

The reference, rendered here.

The architecture, supported syntax and safety model, read directly on this page.

Loading…

Status

An experimental prototype, stated plainly.

TSGPUI is not a production-ready GUI SDK. The supported subset is small on purpose, and the list below is what the project currently documents.

Works today

  • Strict HTML subset with class, id, data-bind and data-onclick
  • Forms, text inputs, textareas and keyboard editing
  • Images, repeated data lists and optional virtual scrolling
  • Media queries that update when the window is resized
  • CSS with element, class, id and compound selectors, specificity and inheritance
  • Flex and grid layout, including mixed px/fr tracks
  • Synchronous backend actions with get, set and update
  • Confirmation prompts, clipboard, file access and allowlisted network requests
  • Compile-time <template> components
  • Single-executable packaging with the appended bundle

Not yet

  • General-purpose native dialogs beyond confirmation and file picker prompts
  • Unequal sizing for pure fr grid tracks and explicit grid placement
  • Sandbox isolation for untrusted backend code; execution time and heap limits are not a sandbox
  • Built-in signing, encryption or tamper-proof packages

Only run backend code you trust: execution limits are not a sandbox. The container format is a prototype, and the Windows host is still being validated through CI.