One thread, no locks, only the difference travels

Web pages that stay on the server

Routes and handlers like Spring Boot, pages built out of components like Vaadin — and the whole of both is .keal files. The C underneath opens sockets and moves bytes. It does not decide anything.

GET / · ws200 · one patch
site.livePage("/", { req ->
    var count = 0
    view({ -> column([
        h1("Clicked ${count} times"),
        button("Click me", { e -> count = count + 1 })
    ]) })
})
{"p":[["t","0.0.0","Clicked 1 times"]]}

One patch. The browser sets one text node — no JSON schema, no endpoint, no client state, nothing to keep in sync.

lineswhat it is
Keal6 604the whole framework: HTTP, routing, the component tree, the renderer, stylesheets, JSON, WebSocket framing, gzip, the scheduler, the session hub, the diff, the SQLite layer and the hashing security rests on
C786sockets, poll, byte blobs, files in pieces — two headers, no .c file
JavaScript143the browser client: open a socket, report an event, apply a patch

A whole program

GET /200 · a page
import "kealeb/kealeb.keal"

val site = app("Hello")

site.page("/", { req -> column([
    h1("Hello"),
    p("from Keal")
])})

site.run(8080)

Five lines and one import. It is a page, styled, in dark mode if the machine is, and it works in anything that can read HTML — there is no JavaScript on it at all.

One thread, no locks

Every socket is non-blocking, one poll drives everything, and a handler runs with nothing else running. Session state is an ordinary Keal object and a data race is not a thing that can be written here. The cost is stated rather than hidden: a handler that blocks blocks the server.

Only the difference travels

A live page keeps its tree on the server. An event runs a handler, the tree is built again, the two are compared, and what crosses the socket is the list of changes — seven kinds of patch, each one call in a browser.

Nothing is linked unless you ask

No dependencies. SQLite arrives with a second import and one flag; a program that never opens a database never links against one. The hashing, the compression and the WebSocket framing are Keal.

Checked by things that did not write it

SHA-256, HMAC and PBKDF2 against the vectors their specifications published. The gzip output handed to the system gzip and to Python, both required to give the bytes back. The browser client run against a real server on every build.