No virtual DOM. No hooks. No signals. Just plain JavaScript classes compiled into surgical DOM updates — faster than Solid, smaller than Svelte.
Gea is a compiler-first reactive UI framework for JavaScript that eliminates the virtual DOM entirely. Instead of diffing at runtime, Gea's Vite plugin analyzes your JSX at build time, traces every state access, and generates surgical DOM patches — code that updates only the specific DOM nodes that depend on changed state. No reconciliation, no diffing, no runtime overhead.
Created by Armagan Amcalar (known in the JavaScript community as dashersw), Gea represents the culmination of 16 years of framework design experience. Amcalar previously created tartJS (the framework behind the world's first client-side rendered single-page e-commerce application) and erste (a modernized version that powered mobile apps in Cordova shells). Gea v1.3.0, released in June 2026, is the third generation of this vision.
The core idea is that JavaScript is enough. You don't need to learn new primitives — just write plain classes.
Here's a complete interactive counter component in Gea:
class Counter extends Component {
count = 0
increment() { this.count++ }
decrement() { this.count-- }
template() {
return (
<div class="counter">
<span>{this.count}</span>
<button click={this.increment}>+</button>
<button click={this.decrement}>-</button>
</div>
)
}
}
That's everything. State is a class property. Methods mutate it directly. The template reads it.
this.count++ triggers a DOM update. No useState, no signals,
no dependency arrays, no wrappers. Just a JavaScript class.
The compiler traces that this.count is used inside the JSX template. When
count changes, it generates a surgical patch that updates only the <span>
containing the value — not the whole component, not a virtual DOM subtree.
For state shared between components, Gea provides Store — a Proxy-wrapped base class:
class CounterStore extends Store {
count = 0
increment() { this.count++ }
decrement() { this.count-- }
}
Stores work exactly like component-local state: plain properties, plain methods. The Proxy wrapper
intercepts property access so the compiler can track dependencies and trigger updates when values
change. Arrays are intercepted at the method level — push, splice,
sort, and other mutating methods produce fine-grained change events.
Computed values are just JavaScript getters:
class TodoStore extends Store {
items = []
get activeCount() {
return this.items.filter(i => !i.done).length
}
get completedCount() {
return this.items.filter(i => i.done).length
}
}
The compiler recognizes getters that depend on store properties and re-evaluates them automatically when their dependencies change. No explicit memoization needed.
Gea also supports function components for simpler cases:
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>
}
Function components receive props as a destructured argument and return JSX. They're compiled the same way as class components — no runtime overhead difference.
The magic — and the performance — comes from Gea's Vite plugin, which runs as a build-time compilation step:
textContent, setAttribute, or DOM insertion/removal as appropriate.
This is fundamentally different from the virtual DOM approach used by React and Vue. Instead of re-rendering a virtual tree and diffing against the previous version, Gea's compiler generates code that says: "when property X changes, update DOM node Y." No diffing, no reconciliation — just direct DOM surgery.
The numbers are remarkable. Let's look at two data points: hello-world (proving the compiler can disappear) and a real todo application (proving the runtime stays lean when the app actually does something).
| Framework | Version | Raw JS | Brotli JS | vs Gea |
|---|---|---|---|---|
| Gea | 1.3.0 | 214 B | 121 B | 1.0x |
| Solid | 1.9.12 | 10,196 B | 3,601 B | 29.8x |
| Svelte | 5.55.5 | 23,461 B | 8,537 B | 70.6x |
| Vue | 3.5.33 | 58,174 B | 20,711 B | 171.2x |
| React 19 | 19.2.5 / React DOM 19.2.5 | 189,717 B | 50,816 B | 420.0x |
Measured from fresh Vite 8.0.10 production builds, summing JavaScript assets only. React, Vue, and Svelte used equivalent minimal hello-world components.
| Framework | Version | Raw JS | Brotli JS | Total Raw | Total Brotli |
|---|---|---|---|---|---|
| Gea | 1.3.0 | 15,364 B | 4,896 B | 18,075 B | 5,664 B |
| Solid | 1.9.12 | 16,181 B | 5,721 B | 18,892 B | 6,485 B |
| Svelte | 5.55.5 | 38,812 B | 13,661 B | 41,523 B | 14,429 B |
| Vue | 3.5.33 | 63,676 B | 22,585 B | 66,387 B | 23,411 B |
| React 19 | 19.2.5 / React DOM 19.2.5 | 192,330 B | 51,460 B | 195,041 B | 52,287 B |
CSS was identical across all builds: 2,711 B raw, 746 B brotli.
The js-framework-benchmark is the industry standard for measuring UI framework runtime performance. It constructs a table of 1,000 rows, performs operations like selecting, updating, and swapping rows, and measures the time each framework takes.
| Framework | Score | vs Vanilla JS |
|---|---|---|
| Vanilla JS | 1.00 | — |
| Gea 1.3 | 1.02 | +2% |
| Solid 1.9 | 1.10 | +10% |
| Svelte 5 | 1.10 | +10% |
| Vue 3.6 | 1.22 | +22% |
| React 19 | 1.43 | +43% |
Gea scores 1.02 — within 2% of hand-written vanilla JavaScript. This is the closest any compiled UI framework has come to matching raw DOM manipulation performance.
Gea ships as a batteries-included toolkit, not just a rendering library:
A built-in RouterView and Link component with route params,
wildcards, and programmatic navigation. The router is tree-shaken — importing it when you
need it adds no overhead when you don't.
The @geajs/ui package provides 35+ accessible UI primitives built on
Zag.js: dialogs, menus, tooltips, accordions, comboboxes,
and more. These are headless components — you style them with your own CSS while the
accessibility logic (ARIA attributes, keyboard navigation, focus management) is handled
automatically.
Built on the experience from erste (Amcalar's earlier mobile framework), Gea Mobile provides iOS-style navigation, gesture handling, swipe-back gestures, and mobile-specific transitions for building native-feeling web applications in a Cordova/Capacitor shell.
Objects and arrays passed as props remain connected to the parent's reactive proxy.
A child component mutating a prop object directly updates the parent — no explicit events,
no v-model. Primitives are passed by value as expected.
Gea supports Hot Module Replacement during development. Edit a component and see the result instantly without losing state. A VS Code extension is also in development.
Gea enters a space where Svelte and Solid already compete. Here's how they compare:
Svelte pioneered the "compile away" approach — it turns components into efficient imperative code at build time. However, Svelte still ships a runtime reactivity system. Gea takes compilation further by using Proxy-based stores that let the compiler trace dependencies precisely and eliminate virtually all runtime code.
Solid uses fine-grained reactivity via signals — each reactive value is tracked individually,
enabling precise DOM updates without a virtual DOM. But signals require explicit creation
(createSignal, createEffect), which is a small conceptual overhead.
Creating a new Gea project is straightforward:
npm create gea
cd my-gea-app
npm run dev
The scaffold creates a Vite 8.0 project with TypeScript, JSX compilation, and the Gea plugin pre-configured. Official example projects on GitHub demonstrate counters, todo apps, routing patterns, and server-side rendering.
Gea is genuinely innovative — the compiler-first approach delivers benchmark results that seemed impossible a year ago. But as with any new framework, the decision depends on your context:
Consider Gea if:
Stick with established frameworks if:
For most projects, the established frameworks are the right choice. But Gea represents a genuine step forward in what's possible with compiled UI frameworks, and its approach to eliminating runtime overhead through compiler analysis is likely to influence the next generation of tools — regardless of whether you use it directly.
npm create gea and follow the interactive prompt. The scaffold creates a Vite 8.0 project with TypeScript support, JSX compilation, and the Gea plugin configured. There are also official example projects on GitHub covering counter, todo, routing, and server-side rendering.I build production applications with React, Next.js, Node.js, and modern JavaScript frameworks. Gea, Svelte, or Solid — whatever fits your project best.