Oct 2025 — Present
Stax
A reactive UI framework built on Effect.ts — strongly-typed, effectful components with first-class SSR, static generation, and surgical DOM updates (no virtual DOM). It powers this very site.
- TypeScript
- Effect.ts
- Vite
What it is
Stax is my own frontend framework. It brings Effect.ts to the browser: components are Effects, so a component’s type signature tells you everything up front — whether it’s async, whether it can fail and with what errors, and exactly which context it depends on. If you forget to handle an error or provide a dependency, the app won’t compile.
// The return type says it all: renders a div, can fail with two
// specific errors, and requires AuthContext — enforced at compile time.
const Profile = ({ userId }: { userId: string }) =>
$.div(UserInfo({ userId }), Posts({ userId }));
// => Element<HTMLDivElement, UserNotFoundError | PostsNotFoundError, AuthContext>
There’s no JSX and no virtual DOM. You build UIs with plain function calls
($.div(...), $.button(...)), and updates are surgical — reactive
Signals patch exactly the nodes that changed, rather than re-rendering a tree
and diffing it.
What’s in it
- Strongly-typed, effectful components — the type system carries success, error, and dependency information through the whole component tree.
- Full Effect.ts interop — schemas, layers, dependency injection, structured concurrency; it’s all just Effect.
- Reactivity for real state —
Signals and control-flow helpers (when,match,each) that update the DOM in place, with first-class support for arrays, maps, sets, and records. - Enter/exit animations — including the hard case, exit animations, baked in.
- SPA, SSR, and SSG from day one — the same code renders on the server, hydrates on the client, or pre-renders to static HTML.
- A type-safe router — routes with schema-validated params, static path generation, and layouts.
How it fits together
The core primitive is Element, which is really just an Effect that produces a
DOM node. @stax-ui/dom gives you the element builders and reactivity, @stax-ui/router
adds type-safe routing, and @stax-ui/platform handles SSR/SSG and hydration. A Vite
plugin ties it together and strips server-only code (loaders, node:fs) out of the
client bundle.
This site is the proof: every page you’re looking at — the blog, this project list, the animated home page — is Stax, statically generated and hydrated.
Links
- Docs & live demo: stax-ui.dev
- The origin story: Schrödinger’s Tiger — why I built it and what it taught me about reactivity and API design.