Skip to content

Introducing Kerf.

The smallest cut. 6.6 KB. No virtual DOM. No compiler. No magic. Reactive UI that touches only the bytes that changed.
import { signal, mount } from 'kerfjs';
const count = signal(0);
mount(document.getElementById('app')!, () => (
<div>
<button data-action="inc">+</button>
<span>{count.value}</span>
</div>
));

That’s it. Your JSX renders to HTML strings, kerf’s native diff applies the minimum DOM mutations to make the live tree match, and signals re-run the render only when something they read actually changed.

Built for AI-assisted coding

Tiny public surface (15 exports), no compiler magic, no hidden lifecycle. An LLM holds the framework in context and predicts behaviour — your AI agent generates code that works the first time.

Smallest cut

6.6 KB gzipped including signals. Fine-grained reactivity re-runs only what changed; the diff touches only the DOM nodes that differ.

No virtual DOM, no compiler

JSX → HTML strings → native diff. DevTools shows the real DOM because it is the DOM.

Focus, selection, listeners survive re-renders

We morph instead of rebuilding. Caret stays put, drag keeps moving, delegated handlers keep firing.

Plain TS, plain JSX, plain ESM

Drops into anything using esbuild / Vite / tsup. No plugin chain.

Read the full pillars →

  • AI-generated apps — your LLM holds the framework in context; no hallucinated APIs.
  • Hybrid desktop apps (Tauri / Electron) — small bundle, predictable diff, debuggable runtime.
  • Embedded widgets — chat bubbles, comment boxes, dashboards dropped into someone else’s page.
  • Server-rendered apps with islands — Rails / Phoenix / Django / Hono. mount per island; delegate survives turbo-frame swaps.
  • Admin panels & internal tools — reactivity without 200 KB of framework + state lib + router.
  • Replacing jQuery — incremental migration; same delegation mental model, modern primitives.
  • Prototyping — entire mental model on a postcard.

Full use-cases grid → · When to reach for something else →

A kerf is the narrow strip a saw blade removes when cutting — the smallest possible cut. The framework’s job is the same: apply the smallest possible mutation to update your DOM.

(And yes, kerformanceperformance jokes were written. They were also rejected.)