Foldkit

the same pixel art editor implemented in both

Last verified:

Visit Foldkit

What is Foldkit?

Foldkit is a TypeScript frontend framework built on Effect-TS using The Elm Architecture (TEA). It provides a single, predictable pattern for building web applications: one immutable Model for all state, one pure update function for all state transitions, and one pure view function for rendering. Unlike React, Vue, Svelte, or Solid which leave architecture to developers, Foldkit prescribes the architecture so teams can focus on their domain logic.

Key features include: type-safe bidirectional routing, accessible UI components (dialog, menu, tabs, listbox, disclosure), Submodels for self-contained embedded programs, Subscriptions for model-bound Stream lifecycles, Managed Resources for WebSockets/AudioContext/RTCPeerConnection, per-field validation with sync/async support, Story and Scene testing primitives that require no DOM or mocking, DevTools with time-travel debugging and AI agent MCP connectivity, module-level memoization, Vite HMR plugin with state preservation, and Runtime.embed for embedding widgets in host applications.

Foldkit is for Effect developers who need a frontend (same ecosystem as their backend), developers who want architecture to prevent bugs rather than just catch them, teams needing one pattern for faster onboarding and alignment, and projects with complex state like auth flows, real-time data, or multi-step forms. It is not for large existing React codebases (requires rewrite, not incremental adoption), teams not ready to invest in Effect (no escape hatch), projects needing the React ecosystem (no Next.js or React component libraries), or teams requiring server-side rendering (client-side SPA only).

Foldkit pricing

Pricing model: Freemium

Foldkit is free and open source. No paid tiers mentioned. Available via npm with 'npx create-foldkit-app@latest' for getting started. The framework ships batteries included (routing, UI components, validation, testing, DevTools) without requiring additional paid libraries.

Foldkit pros

  • Single state tree: entire application state in one Schema-validated Model
  • One pure update function: all state transitions flow through it with no hidden mutations
  • Explicit side effects: Commands, Subscriptions, and Managed Resources are values returned, not callbacks
  • No hooks: eliminates stale closures and complex dependency array management
  • No local state: prevents state scattering across useState calls and multiple useReducer instances
  • Type-safe routing: URLs parse into typed routes and routes build back into URLs
  • Accessible UI components: headless primitives with built-in aria, focus, and keyboard navigation
  • Submodels: self-contained programs with their own Model, Messages, update, and view
  • Subscriptions: runtime handles subscribe/unsubscribe automatically based on Model state
  • Managed Resources: model-driven lifecycle for long-lived browser resources like WebSockets
  • Field validation: per-field validation state tracked as discriminated union with sync and async support
  • Story testing: synchronous state machine tests with zero mocking, zero DOM, zero async
  • Scene testing: interaction testing through virtual DOM with accessible locators, no jsdom
  • DevTools with time-travel: inspect Messages, Model state, and Commands; rewind UI to any past Model
  • AI-friendly architecture: correctness visible to LLMs for generation and review, MCP agent connectivity
  • Module-level memoization: createLazy and createKeyedLazy compare args element-by-element
  • Vite HMR plugin: state-preserving hot module replacement for view changes
  • Runtime.embed: embed Foldkit widgets in any host application with Schema-typed Ports
  • Exhaustive switching: M.tagsExhaustive turns forgotten Messages into compile errors
  • evo function: preserves references for unchanged fields so downstream memoization works without bookkeeping
  • Complete side effect inventory: all Commands declared in one file, all Subscriptions in another
  • Tests catch removed effects: unresolved Command fails the story, unlike React's silent regressions
  • Single pattern scales: 50-file app follows same patterns as 5-file app without complexity creep
  • No JSX: plain TypeScript with typed function-call DSL, no transform or compiler step

Foldkit cons

  • Not incremental: no React interop, no escape hatch from Effect, all-in or not-in
  • Requires Effect investment: teams must learn pipe, discriminated unions, and Effect throughout
  • No server-side rendering: client-side SPA only, static generation requires rolling your own
  • No React ecosystem: no Next.js, no React component libraries, no existing middleware
  • Migration requires rewrite: large existing React codebases cannot adopt incrementally
  • Component paradigm shift: no components, no hooks, no local state—entirely declarative and structured
  • Smaller ecosystem: 24 example apps vs React's massive library ecosystem
  • New mental model: developers must shift how they think about state, effects, and views
  • Effect knowledge required: if new to Effect, Foldkit immerses you fully with no gradual path
  • Version still early: v0.114.0 indicates active development, not yet stable long-term

Frequently asked questions about Foldkit

How does Foldkit compare to React?

The key difference isn't syntax or performance—it's that Foldkit prescribes the architecture instead of leaving it to you. React is a good library with an unmatched ecosystem, but Foldkit gives you structural guarantees React cannot provide by construction: guarantees about where state lives (single Model), how it changes (single update function), and what tests can see (Commands as return values). In React, state scatters across useState calls, multiple useReducer instances, React contexts, and remote state libraries. Side effects live in useEffect hooks disconnected from the reducer. In Foldkit, the Message union catalogs every event and the update function implements every transition—nowhere else. Performance is equivalent (~16.5ms vs ~16.7ms per frame for 32×32 grid rendering at 60fps).

Who is Foldkit for?

Foldkit is for Effect developers who need a frontend (their backend already uses Effect, so Foldkit is the missing frontend piece with same ecosystem and patterns), developers who want their architecture to prevent bugs rather than just catch them, teams that need to stay aligned with one pattern for state/effects/views for less disagreement and faster onboarding, and projects with complex state like auth flows, real-time data, or multi-step forms where the architecture handles complexity without losing clarity.

Who is Foldkit not for?

Foldkit is not for large existing React codebases (it's not incremental adoption—it's a different architecture requiring a rewrite; the middle path is Runtime.embed for embedding Foldkit widgets inside existing apps), teams not ready to invest in Effect (Foldkit leans on pipe, discriminated unions, and Effect throughout with no escape hatch—you're all in or not), projects that need the React ecosystem (no React component libraries, no Next.js, no existing middleware—you're building on different foundations), and teams that need server-side rendering (Foldkit is a client-side SPA framework; static generation is possible but you'll roll your own).

How does Foldkit handle side effects?

Side effects are Commands: named, typed values described as Effects that return Messages. You write the Effect, the runtime runs it. Commands are defined with Command.define, wrapping an Effect that describes the work. Each Command has a name, return type, and appears in DevTools alongside the Message that produced it and the Model diff. The complete list of effects your update function can emit is declared in command.ts. External event streams like keyboard and mouse release are handled through Subscriptions in subscription.ts. Per-element DOM work like focus or third-party library setup is declared inline in the view via OnMount. This makes side effects inspectable, testable, and traceable—unlike React's invisible useEffect hooks connected only through unverifiable dependency arrays.

How do I test Foldkit applications?

Foldkit provides two test primitives: Story and Scene. Story tests the state machine by sending Messages through update and asserting on the resulting Model and Commands—zero mocking, zero DOM, zero async, everything synchronous. Tests read as chronological user stories. Scene tests features through the view by driving the rendered virtual DOM with accessible locators (Scene.role, Scene.text, Scene.label), clicking buttons, typing into inputs, and asserting on re-rendered HTML—also no DOM, no mocking, no jsdom. Commands are resolved inline in the same synchronous pipeline. Unlike React tests that require @testing-library/react, jsdom, browser API mocking, and vi.waitFor() for async effects, Foldkit tests catch removed effects automatically (unresolved Command fails the story).

What UI components does Foldkit ship?

Foldkit UI is a set of headless, accessible UI components: Dialog, menu, tabs, listbox, and disclosure. Each component is renderless—you provide the markup and styling through a toView callback, and Foldkit UI provides accessibility attributes (aria, focus, keyboard navigation), and state management where applicable. Unlike Headless UI in React where state is internal and invisible to your reducer, Foldkit UI components have their own Model, Messages, and update function. You initialize them in your Model, delegate their Messages in your update, and compose their views. The state is yours: visible, serializable, and fully debuggable in DevTools.

How does Foldkit handle routing?

Foldkit provides type-safe bidirectional routing. URLs parse into typed routes and routes build back into URLs—no string matching, no mismatches between parsing and building. This is built into the framework as one coherent system, not a library you stitch together. Routes are typed through Effect Schema, ensuring compile-time safety for both parsing URLs to routes and building URLs from routes.

What is Submodel in Foldkit?

A Submodel is a self-contained Model, Messages, update, and view embedded inside a larger program. Children surface domain facts as typed OutMessages that parents handle in their update function. Every stateful Foldkit UI component ships as a Submodel. This enables composition while maintaining the single-pattern architecture—each Submodel follows the same Elm Architecture rules (one Model, one update, one view) but can be embedded and delegated within a parent program.

Can I use Foldkit with AI agents?

Yes. Foldkit's explicit, predictable architecture makes it unusually AI-friendly: the same properties that make code easy for humans to reason about make it easy for LLMs to generate and review. AI agents can connect directly to a running Foldkit app over the Model Context Protocol (MCP). They read the current Model, inspect Message history, rewind the UI to past states using time-travel, and dispatch Messages. DevTools shows the same data that MCP agents access programmatically. The architecture makes correctness visible whether the reader is a person or an LLM.

Categories

Use cases

Browse all AI tools on NeedAnAI