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.