Skip to content

@idlekitjs/mechanics

Headless gameplay mechanics for idle games: producers, modifiers, collections, projects, crafting, boosts and smaller reusable primitives.

What it provides

  • @idlekitjs/mechanics/producers for tiered production and purchases.
  • @idlekitjs/mechanics/modifiers for stat modifier registration and resolution.
  • @idlekitjs/mechanics/collections for card-like collectibles and packs.
  • @idlekitjs/mechanics/projects for purchasable project completion.
  • @idlekitjs/mechanics/crafting for jobs over machines and resources.
  • @idlekitjs/mechanics/boosts for temporary statuses and modifier effects.
  • @idlekitjs/mechanics/containers for finite-capacity content holders.
  • @idlekitjs/mechanics/timers for recurring timer schedules.
  • @idlekitjs/mechanics/pickups for temporary collectible opportunities.
  • Optional Economy bridge subpaths under @idlekitjs/mechanics/<mechanic>/economy.

The root barrel re-exports core mechanics for convenience. Prefer documented subpaths for lean imports and clear ownership.

When to use it

Use @idlekitjs/mechanics when you want a reusable gameplay primitive without hard-coding a state shape, UI, resource name or balance table. Games supply definitions, state accessors and callbacks; mechanics supply the behavior.

Economy is optional. Native mechanic APIs remain usable without @idlekitjs/economy; use bridge subpaths when you want explicit resources, transaction diagnostics, cost formatting or reward tokens around a mechanic.

Basic usage

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

interface State {
  coins: number;
  producers: {
    owned: number[];
    total: number[];
    progress: number[];
  };
}

const engine = createEngine<State>({ initialState });

const production = producers<State>({
  definitions: [{ id: "worker", cycleTime: 1, yieldPerUnit: 1, baseCost: 10, costGrowth: 1.15 }],
  getColumn: (state) => state.producers,
  setColumn: (state, patch) => {
    state.producers = { ...state.producers, ...patch };
  },
  resource: {
    get: (state) => state.coins,
    add: (state, amount) => {
      state.coins += amount;
    },
  },
});

engine.use(production);
production.purchase(0, engine.state);

Boundaries

Mechanics are headless gameplay primitives. They do not render UI, own save backends, know browser APIs or encode game-specific balancing.

Core mechanic modules do not import Economy. Official bridges live beside the mechanic that owns the adapted state shape, for example:

ts
import { economyPurchase } from "@idlekitjs/mechanics/producers/economy";
import { cardResources } from "@idlekitjs/mechanics/collections/economy";
import { recipeCost } from "@idlekitjs/mechanics/crafting/economy";
import { projectFromTransaction } from "@idlekitjs/mechanics/projects/economy";
import { activateBoost } from "@idlekitjs/mechanics/boosts/economy";

These bridges are public and optional, but they are subpath-only: they are not re-exported by the @idlekitjs/mechanics barrel.