🚧 Glyx is pre-release software. APIs may change before v1.0. Get started →
Documentation
Core Concepts
Architecture

Architecture

Glyx is four layers working together. From your code to the screen:

Layer 1 — React

Your application is a standard React tree. You write components, hooks, and context exactly as you would for the web. Glyx exports its own primitive components (View, Text, Pressable, etc.) instead of DOM elements, but the React model is identical.

// This is just React
function Counter() {
  const [n, setN] = useState(0)
  return (
    <View>
      <Text>{n}</Text>
      <Pressable onPress={() => setN(n + 1)}>
        <Text>+</Text>
      </Pressable>
    </View>
  )
}

Layer 2 — Runtime

Glyx runs a purpose-built V8 runtime (not Node.js, not Deno). The runtime:

  • Starts from a V8 snapshot — a pre-warmed heap image that eliminates parse/compile time
  • Hosts a custom React reconciler that produces a scene graph instead of a DOM
  • Bridges JavaScript calls to native Rust bindings via a typed FFI

The reconciler translates React's virtual DOM into Glyx's native element tree — a data structure the GPU renderer can consume directly.

Layer 3 — Renderer

The positioned element tree is rasterized by one of two backends, selected automatically based on the hardware (renderMode: 'auto'):

BackendDefault onRSS (idle / under interaction load)Description
TinySkiaiGPU, no GPU, CI~27–40 MB, flat under loadPure CPU rasterizer + OS software present — no wgpu at all
VelloNVIDIA / AMD / Intel Arc dGPU~350–430 MB idle, spikes to 600–700 MB under loadwgpu GPU compute — best throughput on genuinely GPU-bound 2D scenes
Direct2D (Windows, experimental, opt-in)Never auto-selected~77–114 MB, flat under loadID2D1DeviceContext + DirectWrite — GPU-quality output without Vello's memory cost

Vello runs on DirectX 12 (Windows), Metal (macOS), and Vulkan (Linux). TinySkia runs on any machine with no GPU requirement. See Renderer & Engine Selection for full methodology and when each backend is the right call.

Every component — a View, a Text, a Canvas — becomes renderer draw calls. There is no intermediate HTML, no CSS layout engine, no DOM. Glyx runs layout through Taffy, a Rust flexbox (and grid) engine.

Taffy only computes geometry — it knows nothing about rendering. The bridge that makes it usable is a text measure function: each Text leaf carries a TextMeasureCtx, and when it has no explicit height, Taffy calls a closure that shapes the text (via Parley) and returns its wrapped (width, height). That is what lets multi-line text fit without a hard-coded height in JS. To keep frames cheap, prop updates are classified as layout-affecting (width, height, flex, padding, gap, text, font_size, …) versus visual-only; only the former trigger a Taffy recompute, and even then just the dirtied subtree is rebuilt. Scroll and hover frames skip the layout pass entirely, saving roughly a millisecond each.

Layer 4 — Shell

The shell handles OS integration: native windows, system tray, file dialogs, clipboard, notifications. It wraps the GPU surface and exposes the glyxWindow API to your React code.

Data flow

Your React code
      ↓  reconciler
 Element tree (Rust)
      ↓  layout (Taffy)
 Positioned boxes
      ↓  renderer (TinySkia / Vello auto-selected; Direct2D opt-in on Windows)
 Screen pixels

The entire path from a setState call to a repainted frame takes 1–3ms on modern hardware.

Internationalization (ICU)

Intl.* formatting (numbers, dates, currency, plural rules, collation) comes from ICU, which V8 loads once before it initializes. ICU's full data file is ~10 MB, so Glyx trims it to the locales an app declares in its config (locales: ['en', 'ja', 'de-DE']). At build time icupkg strips every top-level locale bundle except the requested locales plus root and each locale's parent prefixes (e.g. de for de-DE), typically cutting the data ~56%.

At runtime the data is loaded from an external icudtl.dat next to the executable (packaged apps) or the embedded copy (dev/tests). The default locale — the first entry in locales — is applied to V8 at startup, so Intl.NumberFormat() with no argument uses the app's primary language. Any locale you format with explicitly must also be declared, or it falls back to root data (numbers still format, but month/day names won't be localized).

What Glyx is NOT

  • Not a WebView wrapper — there is no HTML or CSS rendered
  • Not a transpiler — your React code runs as-is in V8
  • Not Electron — there is no Chromium, no Node.js, no ipcRenderer
  • Not a Rust framework — JS-only projects require no Rust at all. Native extension projects (glyx-cli create --native) let you write Rust to expose custom bindings, but this is opt-in.