A port of the Foldkit counter playground (foldkit/examples/counter) to Val Town — no build step, no bundler.
Foldkit is a TypeScript frontend framework built on Effect, using
The Elm Architecture: one immutable
Model, typed Messages, a pure update, and a view. The original example
is compiled with Vite. Here it runs straight in the browser via an
import map that pulls Foldkit + Effect from
esm.sh.
Rendering mermaid diagram...
| File | Role |
|---|---|
main.ts | HTTP handler. Serves the shell, the client module, and a /source redirect. |
index.html | The shell: Twind (runtime Tailwind), the import map, and <div id="root">. |
client.js | The Foldkit app — a faithful port of the example's main.ts + entry.ts. |
client.js uses the exact bare specifiers Foldkit's own source uses
(effect, foldkit/runtime, foldkit/html, foldkit/message). A browser
import map in index.html resolves them to esm.sh:
- The Foldkit subpaths are requested with
?external=effect,@effect/platform-browserso they don't bundle their own copy of Effect. "effect"and"effect/"both point at the same pinned Effect build. Foldkit imports theeffectnamespace;@effect/platform-browserimports granular subpaths (effect/Effect,effect/Schema, …). Both forms resolve to the same chunks, so Effect stays a single shared instance — without that, Effect's Context tags wouldn't match and the runtime would fail.
The only port-level change from the upstream TypeScript is dropping the
type annotations (and the type-only withReturnType) so the file is plain JS the
browser runs as-is. The Model, Message, update, init, and view are
otherwise identical to the original.
- Styling uses Twind so the original Tailwind utility classes work with no build. Twind rewrites them to hashed class names at runtime — the visual result is the same.
- DevTools are enabled via
devTools: { Message }, matching the upstreamentry.ts. - Click view source (bottom-right) to open this val.