World-Builder Guide

Monster Design Guide

Author monsters that are fair, readable, and fun — grounded in the live combat math.

How to author monsters that are fair, readable, and fun — not damage sponges, not one-shot machines, not zero-threat furniture. Every number here matches how the game actually plays. Pairs with Item System guide — the field-by-field JSON reference for what each key is.


0. The one rule

A monster is tuned against a specific player, at a specific level, with specific gear. "Is this monster too strong/weak?" is meaningless until you name the player you mean. This guide gives you that reference player per tier, so you can always compute the answer instead of guessing.


1. The math you're tuning against

This is exactly how combat resolves. You can't design a fair monster without it.

Player damage → monster

physical = max(0, floor(Strength     × scaling) − monster.Defense)
magic    = max(0, floor(Intelligence × scaling) − monster.Resistance)

then × the elemental multiplier.

Monster damage → player

base   = random(damage_min .. damage_max)        # one roll per attack
scaled = floor(base × attack.scaling_factor)
hit    = max(0, scaled − player.Defense|Resistance)   # Def for physical, Res for magic
hit    = hit × player's elemental multiplier          # players are ×1 today (no resist gear)

then the QTE can reduce it further (dodge/parry).

⚠️ Mitigation is FLAT SUBTRACTION, not percentage

This is the single most important fact for not writing a monster that sucks. A few points of defense completely null out a low roll. A monster whose floor(roll × scaling) doesn't clear the target's defense by a healthy margin does zero and is a boring waste. Always tune damage against the expected defense at that level (§3), not against a bare level-1.

Player power by level


2. Tiers are keyed to expected player level

The engine allows tiers 1–10. This bundle uses 1–3. A tier is a promise about who fights this monster:

TierExpected levelRoleReference player (see §3)
1L1–4trash / fodder — you meet these first, in packsNovice
2L4–8elite / mini-boss — a real threat, killable solo with careAdventurer
3L8–12zone boss — a gear+skill check, better with friendsVeteran (+group)
4–10~+4 levels/tierfuture / federated end-gamescale §3 forward

Progression pace check: reaching L5 (1600 XP) ≈ 40 tier-2 kills or ~18 tier-3 kills — i.e. clearing the early/mid zones. By the maze/cave_4 bosses a player is plausibly L5–10, which is why tier 3 targets L8–12 or a group of slightly lower players.


3. The reference player per tier

A "median" player for that band: some points spent on a combat build + tier-appropriate gear. Tune every monster against its tier's reference player.

Novice (T1, L1–4)Adventurer (T2, L4–8)Veteran (T3, L8–12)
HP~110~180~270
STR / INT13 / 1119 / 1528 / 24
DEF / RES7 / 614 / 920 / 15
ability scaling~1.0~1.2~1.5
gear assumedstarter (iron sword, leather)steel sword, scale armor, life amuletgauntlets/dragon scale/archmage tier

4. Stat budget per tier (author to this)

Numbers are the monster's stats. "Lands/hit" and "TTK" are computed against the §3 reference player and are the real targets — hit those, not the raw numbers.

StatTier 1Tier 2Tier 3 (boss)
HP20–5555–95120–200 (bosses use phases, §7)
damage_min6–1012–1616–22
damage_max10–1618–2626–40 (burst attacks)
defense0–44–78–12
resistance (general)0–22–58–12
scaling_factor0.8–1.01.0–1.51.0–2.5 (multi-phase)
speed (feel knob, §5)5–85–95–7
aggro_radius4–75–86–10
respawn_time (s)25–6030–120300–3600

Target feel (what those budgets should produce)

Tier 1Tier 2Tier 3
effective dmg/hit vs ref player~2–7 (2–6% HP)~5–12 (4–8% HP)~8–20, burst to ~35 (up to ~15%)
player TTK (turns to kill it)3–55–88–15 solo · 4–7 grouped

Hard invariants (a linter could enforce)

monster can roll a 0 against its own tier's reference player, it's under-tuned.

tier-(N+1) floor. (The old skeleton had def 10 > the tier-3 boss's 8.)

was squishier than a 50-HP goblin.)

T2 0.05, T3 0.02. Soulbound is uncapped.

How to sanity-check a monster in 30 seconds

  1. Compute its dmg on the ref player: floor(damage_max × scaling) − refDEF. In the feel band above?
  2. Compute ref player's dmg on it: floor(refSTR × abilityScaling) − monster.DEF, divide HP → TTK in the band?
  3. If either is ~0 or wildly off, retune. Done.

5. Movement speed = a feel knob, NOT power

A monster takes a step roughly every quarter-second, at a rate set by its speed:

step rate ≈ speed × 0.4 tiles/sec. speed 1 = 0.4 t/s (crawls), speed 8 = 3.2 t/s (smooth), speed 10 = the max useful value (higher is wasted).

It moves monsters only — player movement is input-driven.

knight) ≈ 5, normal (goblin, mage) ≈ 6–7, fast (rat, shadow) ≈ 8–9.

faster. When you raise speed, trim aggro_radius a notch or it becomes inescapable.


6. Attacks & QTE — the moment-to-moment fun

Full field reference in Item System guide §7. Design guidance:

Attack type decides who gets hit

for deliberate "everyone's in danger" beats, not as the whole kit.

It's ANTICIPATION, not reaction

The QTE is not a flash you react to. When a monster attacks, the game telegraphs it: a marker sweeps around a ring toward a fixed target zone, and it starts up to ~1.5 seconds before the window opens. The player watches it approach and presses when it lines up — so the skill is rhythm and anticipation, not reflex. Near-perfect timing is a reachable ceiling, not luck. Don't design around "reaction time": there is plenty of time to see the hit coming — the challenge is nailing the exact moment.

The scoring model — a parry is a razor's edge

Damage negation is continuous, not all-or-nothing:

window (about ±20 ms).

ramping up to a full hit at the outer edge (about ±200 ms out).

You author two numbers per attack:

quarter of this.

Both are ± tolerances around the window's centre — not durations.

Windows only get HARDER, never easier

There's a hard floor: the perfect zone can't be wider than about ±25 ms and the outer edge can't be wider than about ±220 ms, no matter what you write.

demanding baseline (parry 80 / dodge 200).

So there's no such thing as a "generous" window. You tune difficulty up from an already-hard floor by tightening; leaving the defaults is the easiest an attack can be.

Tierparrydodgefeel
180 (default)200 (default)the hard baseline — already demanding
260160tighter
340120punishing — for boss burst beats only

Two rules that keep the telegraph honest:

  1. Set parry/dodge at the top level of the qte, not per-input. A per-input override

makes the on-screen ring disagree with the actual result (it can read MISS but resolve as a parry). Keep them top-level.

  1. Centre the window on the tolerance: window_start = centre − parry,

window_end = centre + parry, so the zone the player sees matches how it scores.

Fighting above your level is lethal

A monster's outgoing damage scales with its power tier — roughly ×1.6 for each tier above the player (a tier-2 hits about 1.6× as hard as a tier-1, a tier-3 about 2.6×, and so on). Same-tier fights are unaffected — so tune against the reference player (§3) as normal. But someone who wanders into a zone above their level meets damage that dwarfs their HP, and because even a good-but-not-perfect parry leaks a little, a single hit can kill them. That "don't punch above your weight" wall is automatic — you don't build it, and you shouldn't try to fake it with a huge damage_max.

The player's own strike timing

Attacking uses the same skill in reverse. After choosing an action and target, the player times a press on a one-second strike sweep: perfect timing lands 1.5× damage, sliding down to 0.5× at the edge, and no press at all = 0.5× (a weak hit — you have to engage). The TTK figures in §4 assume roughly neutral strikes (~1.0×): a skilled player clears faster, a passive one much slower.

Damage × QTE together

A tight QTE on a hard-hitting attack is the real threat. A tight QTE on a 0-damage attack is just annoying. Scale window tightness with the damage that lands (§4/I1) — and since the floor is already hard, reserve tier-3 tightness for attacks whose damage justifies demanding a near-perfect save.


7. Multi-phase bosses & the trigger system

A boss is an entity with multiple phases; each turn the engine picks the highest-index phase whose trigger fires, re-evaluated with fresh (HP%, turn count, living player count). Triggers AND together; an all-zero trigger always fires (that's phase 0).

There are three trigger types, all supported:

FieldFires whenUse for
hp_pct_belowHP% < Xescalation ("enrage at 30%")
turn_count_aboveturn > Xenrage timer / DPS check
players_alive_belowliving players < Xgroup gating / anti-attrition

Design notes:

brutal phase turns on. The clean way to make a long solo attempt lethal (§8).

than 3 are alive — solo/duo trip it immediately. Use only for designated raid bosses.

size entry locks. Don't design a boss whose fairness depends on them.


8. Making a monster "better with friends" (no new mechanic)

Grouping already helps two ways, automatically:

  1. DPS stacks — N players → ~1/N the turns → far fewer dangerous QTEs endured.
  2. Targeted damage spreads — a targeted attack hits 1 of N, so each player is hit

1/N as often.

So solo = a long fight where you must win every QTE; grouped = a short fight where danger is shared and allies finish the kill if you slip. To lean a monster that way:

LeverEffect
High HPlong solo TTK (attrition risk); a group's stacked DPS keeps it short
Mostly targeted attacksdamage spreads 1/N across the party
Tight QTEsone slip over a long solo fight = death
Big per-hit damagetanking every hit solo is lethal; grouped you tank a fraction

Recipe: HP so solo TTK ≈ 15–20 turns but 3-player ≈ 5–7 · pool mostly targeted, one aoe for pressure · tight QTEs · optional turn_count_above enrage as the hard check.

Trap: an all-global boss barely rewards grouping for survival (everyone eats every hit) and just becomes a DPS race — often harder to coordinate. Keep it targeted.


8.5 Reinforcement / add-swarm encounters (a soft timer made of bodies)

Some encounters are hard not because one monster is strong, but because more keep joining the fight — a horde-anchor pattern. This is fully emergent from existing systems; there is no "summon" ability:

  1. An anchor monster (e.g. a mage/boss) sits near several add spawns.
  2. While you fight the anchor, the adds' chase_player brain walks them toward you.
  3. Join-on-contact: a monster that reaches a player already in combat is added to

that combat's roster mid-fight — it joins the turn order on the next turn.

  1. Adds respawn_time refreshes the horde, so waves recur.

The soft timer = how long until the next wave lands:

X ≈ add.respawn_time + (distance_to_fight ÷ (add.speed × 0.4 tiles/sec))

Kill the anchor before X and you fight it clean; take too long and a fresh wave joins — which is exactly the dark_mage in cave_4, ringed by skeleton spawns today.

Why this is a prime "bring friends" tool

A group bursts the anchor before the horde compounds, or splits off to intercept adds. Solo, you can't out-DPS the anchor and survive the accumulating adds — the swarm is the wall. It stacks naturally with §8 (each add's targeted hits spread across the party).

How to author one (it's level layout, not stats)

overtune the individual add, or it's just unfair (the old def-10/dmg-30 skeleton × a horde was a death trap).

(adds arrive single-file); open ground lets them swarm. Design the room to the intent.

Live example — cave_4 (dark_mage + skeletons)

This is already a reinforcement encounter and should stay one: the dark_mage anchor with skeletons trickling in. Now that skeletons are retuned to fair tier-2 (def 5, dmg 8–14, spd 8, holy-weak — the balance notes), the horde is a legitimate group gate rather than a death trap. The skeleton count is the mechanic — don't blanket-cut it; tune the per-add stats and the respawn cadence instead.

Limits

chase + join. You tune it in spawns.json (placement, count, respawn), not on the boss.


9. Anti-patterns — "monsters that suck" (a checklist of real mistakes)

Every one of these was found live in this bundle. Don't repeat them.

visible sweep; it's an anticipation test, not a reflex one. "Generous ±200 ms" windows are a myth — the engine clamps them to the hard baseline anyway (perfect ±20, edge 200). Tune tighter for harder, never wider expecting easier. (§6.)

on-screen ring disagrees with the server ruling (parry reads MISS then resolves PARRY). Top-level only. (§6.)

is the threat, not each body. (A def-10/dmg-30 skeleton × 6 was a death trap; §8.5.)

encounter. Tune respawn cadence + per-add stats instead of deleting adds. (§8.5)


10. Worked examples (author to the reference player)

Tier 1 — a proper goblin (target: Novice, L1–4)

HP 55 · dmg 8–14 · def 3 · scaling 1.0 · speed 6 · aggro 5 · targeted slash, generous QTE.

Tier 2 — a shadow stalker (target: Adventurer, L4–8; fast skirmisher)

HP 60 · dmg 12–18 · def 4 · scaling 1.5 · speed 9 · dark element · targeted, tight QTE (~250/120 ms).

Tier 3 — a "bring friends" zone boss (target: Veteran L8–12, or a group)

Phases:

  1. {} — HP 600 · swing dmg 15–25 ×1.2 physical targeted · def 10 · speed 5.
  2. { "hp_pct_below": 40 } — adds beam dmg 15–25 ×2.0 magic targeted, def 12.
  3. { "turn_count_above": 14 } — ENRAGE: global dmg 20–30 ×2.5 (the DPS check).
  4. Beam on Veteran: floor(20×2.0) − 15 = 25/hit (≈9% HP) — real phase-2 pressure.
  5. Veteran DPS: floor(28×1.5) − 10 = 32/hit → 600 HP ≈ 19 turns solo (past the turn-14

enrage → death) but ≈ 6–7 turns for a trio → beat it before enrage. ✅ exactly the "better with friends" shape, using only existing mechanics.


11. Author checklist (before you ship a monster)