Skip to content

What is IdleKit?

IdleKit is a modular TypeScript toolkit for building idle and incremental games. It gives you the parts every idle game needs — a deterministic game loop, reactive state, economic transactions, gameplay primitives, saving, offline progress — as small, composable packages, and stays out of the way for everything that makes your game yours: content, balancing, art and UI.

The naming says it all: IdleKit provides the engine; your game is what you build on top of it. You create an Engine, feed it your state and systems, and everything installable plugs into it.

ts
import { createEngine } from "@idlekitjs/core";
import { producers } from "@idlekitjs/mechanics/producers";
import { autosave } from "@idlekitjs/plugins/autosave";

The problem

Every idle game re-implements the same machinery: a loop that stays stable when the tab is throttled, state that drives the UI without redrawing everything each tick, cost curves and bulk-buy math, save files that survive schema changes, offline catch-up that doesn't distort non-linear mechanics.

That machinery is genuinely hard to get right — and none of it is your game. Game frameworks are built around scenes and sprites, not cost curves and prestige loops. UI frameworks give you rendering but nothing else. So most idle games start from a pile of copy-pasted, half-debugged loops.

The solution

IdleKit splits that machinery into focused packages with strict boundaries:

  • A headless engine (@idlekitjs/core) — fixed-step loop, proxy-based reactive state, typed events, versioned saves with migrations, big-number Decimal, seeded RNG. It never touches a browser global: the same code runs in a browser, a test, or Node.
  • Economy vocabulary (@idlekitjs/economy) — explicit resources, costs, rewards, requirements, cost curves, formatting view models and atomic transactions. It reads your state through accessors and never owns the state.
  • Gameplay mechanics (@idlekitjs/mechanics) — producers (tiered production), modifiers (stat bonuses), collections (gacha/cards), projects (one-shot upgrades), crafting (timed transformation) and boosts (temporary effects). Each one is a generic, serializable primitive: you supply data, it supplies behavior.
  • Engine policies (@idlekitjs/plugins) — autosave and offline progress as one-line opt-ins; the tab pause/resume bridge lives in @idlekitjs/browser.
  • Persistence backends (@idlekitjs/storage) — a tiny SaveAdapter contract with in-memory and localStorage implementations.
  • DOM bindings (@idlekitjs/dom) — an optional renderer with declarative bindings that only touch the DOM when the state they read actually changed. No framework required; none imposed.

Everything installable is an Extension<T>: one contract (engine.use(...)) for mechanics and plugins alike, typed against your state.

Design principles

Headless first. The engine runs without a DOM. Rendering is injected, never assumed. This is what makes headless testing and server-side simulation trivial.

Primitives, not templates. A mechanic ships the mechanism — cycle math, drop tables, job lifecycles — and nothing else. Names, icons, balancing and "what a sandwich is" stay in your game. You will never fight a built-in theme.

Transactions are explicit. Economy actions declare their requirements, costs, rewards and effects. Continuous simulation still belongs to mechanics; atomic economic actions go through Economy when you opt into it.

Serializable by construction. Every piece of runtime state a mechanic manages is plain JSON in your state object, accessed through getters/setters you provide. Saving is JSON.stringify away; nothing hides in closures.

Typed end to end. createEngine<MyState> propagates your state type through systems, extensions, mechanics and saves. Most wiring mistakes are compile errors.

Dogfooded. The repository ships several complete games built on the toolkit (a paperclips-style clicker, two cascade-production games, a survival idle). Every API documented here is exercised by at least one of them and by the test suite (300+ tests).

What IdleKit is not

  • Not a game engine — no scenes, sprites, physics or audio. Pair it with plain DOM (built-in support), or any rendering stack you like.
  • Not a UI framework@idlekitjs/dom is a thin binding layer for vanilla DOM. You can ignore it entirely and read engine.state from React or Vue.
  • Not a content pack — there is no built-in "mine gold" button. IdleKit is the machinery under your content.
  • Not a second core@idlekitjs/economy does not schedule frames, own state, save data or replace mechanics.

Next steps

  • Skim the core concepts — five ideas explain the whole toolkit.
  • Follow the quickstart to build a running game.
  • Browse the mechanics to see the gameplay primitives.