Idle and incremental game template (BRINEWORKS)
Net Forge, the open-source multiplayer browser game engine built for AI coding agents, is published on npm under @netforge with source at github.com/netnetdev/net-forge.
BRINEWORKS is a complete multiplayer idle game: up to eight players each run a works on one salt flat, where pumps draw brine, pans boil it into salt, kilns cut salt into crystals, and salt buys and levels more plants. Everyone ships crystals to one shared contract, and a shift lasts fifteen minutes before a fresh one starts.
npm create netforge@latest my-game -- --template idle --yes
cd my-game
npm run playSpace rakes salt by hand (or click your plot), keys 1 to 5 buy a plant, and S ships crystals. Open the link in more tabs to see several works on the same flat.
What you get
| Part | What it does | Where |
|---|---|---|
| The flat | Shift length, how long a works runs after its last tend, raking, conversion ratios, the shared contract | saltFlat({...}) |
| Plants | 1 to 8 plants of kind pump, pan or kiln, each with a cost, a price growth per level and a rate | plant(...) |
| Upgrades | Plant output (might), raking speed (haste), salt per rake (amount) | upgrade(...) |
| Shared goal | One contract barge everyone ships crystals to | saltFlat({ contract }) |
| Fairness rules | No offline accrual, works stall when untended, a raking cooldown, a minimum time before the first payout | enforced by the build |
| Playtest bots | Four players for four minutes, plus a check of the fastest possible first payout | npm test |
Measured on an Apple M2 Pro, Node 22: four bots over four minutes (7,200 ticks at 30 Hz) packed 172 crates and each fired the first earn rule, at 0.003 ms per server tick on average.
1. Tune progress
cost is kg of salt for the first level, growth is the price rise per level, and rate is output per second per level (litres of brine for pumps, kg of salt for pans, crystals for kilns). A lower growth keeps levels cheap for longer.
import { plant } from "@netforge/engine";
plant("hand_pump", { model: "style.lowpoly.barrel", kind: "pump", cost: 15, growth: 1.15, rate: 3 });
plant("deep_bore", { model: "style.lowpoly.generator_large", kind: "pump", cost: 5000, growth: 1.2, rate: 200 });A game needs at least one pump, one pan and one kiln. Give a new plant a label in src/names.json; the bar shows plants in the order you declare them.
2. Change the shift and the contract
import { saltFlat } from "@netforge/engine";
saltFlat({
shift: 1200,
tend: 120,
start: 20,
rake: { salt: 3, cooldown: 0.4 },
brinePerSalt: 3,
saltPerCrystal: 25,
packEvery: 150,
contract: { crystals: 120 },
});A shift is 600 to 3,600 seconds, and tend is at most 300 seconds: a works nobody tends stops, so an idle tab makes nothing.
3. Add an earn rule
import { earn } from "@netforge/engine";
earn.rule("first_crate", { when: "salt.packed", n: 30, pay: 5, oncePer: "run" });Events are salt.packed, crystal.cut, crystal.shipped, plant.built, plant.upgraded (each credits the player) and contract.filled. The build simulates a fresh works with perfect play and with pure raking, and fails a rule that would pay sooner than 180 seconds in, printing the number. Raise packEvery or the rule's n if it does.
4. Check it with bots
npm testHow it works
This is a board genre: the rules run as a deterministic module in @netforge/engine/rules on the room's clock, with integer state and a seeded random number. Production happens only on the room's ticks while a player is in the room. Nothing accrues offline, and a player who leaves and comes back starts a fresh works. That is a deliberate design choice for a shared, server-checked idle game, and it differs from single-player incremental games that keep progress while closed. See Simulation and ECS.
Earn rules fire locally and pay nothing. Paying them in a game token is an optional upgrade on the hosted Net Forge service.
The full guide is Build an idle or incremental game.
Alternatives
- Phaser is a 2D HTML5 framework. Pick it for a single-player idle game with sprite art and your own save format.
- A plain web stack (a UI framework plus local storage) is often all a single-player clicker needs, and keeps offline progress simple.
- Net Forge fits when several players should share one world, fill one goal together, and have every number computed on the server.
FAQ
Does the idle template have offline progress?
No. Production runs only on the room's clock while you are in the room, and an untended works stalls after tend seconds. This keeps a shared world fair. For a single-player game with offline progress, a plain web stack is a better fit.
How many players share one idle world?
Up to eight, each with their own works on the same flat, all shipping to one contract.
How long is a round?
A shift is 600 to 3,600 seconds (the template uses 900). When it ends, a new shift starts from nothing.
Why does the build reject my earn rule?
The build checks that no earn rule can pay sooner than 180 seconds into a fresh works, even with perfect play. Raise packEvery or the rule's n, or slow raking, and run npm test again.