No active sessions yet.

No games yet.

No conversations yet.

No characters yet.

Formulas and dials

The engine's own numbers are editable expressions — and why never to freeze one.

Dials are your plugin's tuning numbers

Declare a dial, ship a default, read it in your rules:

$.dial('foodDrainPerHour')

Values are namespaced by plugin, so two plugins may both declare baseRate and mean different numbers. $.dial() always reads your plugin's.

They appear as editable controls in your plugin's panel, which is the point: an author tuning your system should never have to open its code.

The engine's dials hold expressions, not coefficients

This is the part that surprises people. maxHp, travelSpeed and xpCurve are not numbers — they are formulas you can rewrite. You are editing the shape of the rule, not just its constants.

// maxHp, as shipped
50 + $.stat('might') * 1 + $.stat('resolve') * 3 + ($.stat('playerLevel') - 1) * 5

A game where toughness comes from Resolve alone writes exactly that:

40 + $.stat('resolve') * 6

A game where hit points never grow with level writes that too. Nothing about the shape is fixed.

Image: docs/formula-editor.png A formula dial in the editor — the expression box with the shipped maxHp formula and its live preview.

Never freeze a dial into a literal

A plugin reproducing a formula must read the dials, not copy their values.

$.damage({ amount: 0.4 })                          // wrong
$.damage({ amount: $.dial('starvationPerHour') })  // right

Hardcoding today's coefficient is correct right up until an author retunes the dial. Then you have two copies of a number that no longer agree, the game behaves inconsistently, and nothing errors — the frozen copy is perfectly valid code.

This is the same class of bug as missing values: silent, and invisible at the default tuning where both numbers still match.

Next

Seams — replacing a calculation outright rather than tuning it.