Docs: research-based Combat Attack & Ability Feel Guidelines (DRAFT for review) + session log
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
---
|
||||
title: Combat Attack & Ability Feel Guidelines (research-based)
|
||||
date: 2026-07-20
|
||||
tags: [game-design, combat, feel, clarity, animation, vfx, guidelines, lantern]
|
||||
status: DRAFT — pending operator review
|
||||
permalink: gamevault/02-game-design/combat-attack-feel-guidelines
|
||||
---
|
||||
|
||||
# Combat Attack & Ability Feel Guidelines
|
||||
|
||||
> **Why this doc:** the 07-19 melee weight pass surfaced a systemic problem — the cleave arc telegraphs 2.6 m
|
||||
> (3.9 m finisher) while the axe + arm visually covers ~1.7–1.8 m; at our camera (Distance 13, FOV 55°, ~13.5 m
|
||||
> visible plane) the finisher arc reads at **>2× the weapon's visual reach**. Rather than patch one number, this
|
||||
> is the **research-based grammar for every attack and ability** in LANTERN — player melee, the 4-socket kit
|
||||
> (projectile / cone / zone / movement), and enemy attacks. Deep-research run `wf_1e5183c1-13c`: 21 sources,
|
||||
> ~95 extracted claims, 3-vote adversarial verification on the top 25 — **12 confirmed (3-0/2-0), 0 refuted
|
||||
> anywhere, 13 unverified only because verifier agents died on session quota (each still carries a verbatim
|
||||
> source quote from the fetch pass)**. The confirmed set covers the load-bearing rules: the hit-stop canon (R5),
|
||||
> the D4 readability hierarchy (R6), the cancel/buffer taxonomy (R7), and the SoD skillshot framing (R9).
|
||||
> Sources cited inline. Scope + reach-philosophy + reference set approved by operator 07-19 (full grammar ·
|
||||
> research-derived reach proposal · +Souls/MH +D4/PoE2 schools).
|
||||
|
||||
**The one-sentence thesis:** *feel* is made by how an attack spends its time (anticipation → contact → recovery),
|
||||
*clarity* is made by drawing exactly what the simulation does — when it does it — inside a strict loudness
|
||||
hierarchy; every rule below is one of those two statements specialized.
|
||||
|
||||
---
|
||||
|
||||
## Part 1 — The research base (what the five schools agree on)
|
||||
|
||||
### R1. Every attack is three phases, and the contact phase is nearly instant
|
||||
Decompose every attack into **Anticipation → Contact → Recovery** ([gdkeys — Anatomy of an Attack](https://gdkeys.com/keys-to-combat-design-1-anatomy-of-an-attack/)).
|
||||
The contact (active) portion is a *few frames*, constant speed; weight and readability are bought in the other
|
||||
two phases. Published example frame data (Hollow Knight's Hornet @30fps): Dash = 15f anticipation / 10f attack /
|
||||
10f recovery.
|
||||
|
||||
### R2. Player vs enemy anticipation INVERTS
|
||||
For the **player**, anticipation frames trade weight against responsiveness — too few reads weightless, too many
|
||||
reads as input lag ([gameanim — 12 Principles in Games](https://www.gameanim.com/2019/05/15/the-12-principles-of-animation-in-video-games/), [slynyrd — Melee Attacks](https://www.slynyrd.com/blog/2018/9/8/pixelblog-9-melee-attacks)).
|
||||
For **enemies**, anticipation IS the telegraph and should be deliberately *longer* — its function is giving the
|
||||
player time to react. Telegraph lead-time formula ([gdkeys](https://gdkeys.com/keys-to-combat-design-1-anatomy-of-an-attack/)):
|
||||
**lead = human reaction (0.25 s) + the player's escape-move trigger time + difficulty buffer.**
|
||||
|
||||
### R3. Weight = slower anticipation + longer recovery — never a slowed contact
|
||||
Perceived weight is inversely tied to speed, but the fix is *where the time goes*: heavy weapons get slower
|
||||
wind-ups and added hold frames while **smear/contact frames stay few and fast** ([gameanim](https://www.gameanim.com/2019/05/15/the-12-principles-of-animation-in-video-games/), [slynyrd](https://www.slynyrd.com/blog/2018/9/8/pixelblog-9-melee-attacks)).
|
||||
Recovery is the *safer* place to spend weight-frames than anticipation (the action already resolved). This is the
|
||||
Souls/MH commitment school: weight lives in commitment, not in slow-motion swings.
|
||||
|
||||
### R4. Honesty: the damage volume must match what is drawn — when it is drawn
|
||||
- **Diablo IV's "payload" rule**: damage areas animate over frames so the hit region *tracks the VFX in time* —
|
||||
AoEs expand outward with the visual, melee damage areas follow the weapon's motion ([D4 Quarterly Dec 2021](https://news.blizzard.com/en-us/diablo4/23746639/diablo-iv-quarterly-update-december-2021)).
|
||||
- **Smash's sword-lines rule**: when a hitbox is disjointed from the body, make the *visual* honest — add trails /
|
||||
enlarge the weapon at full extension — rather than shrinking the hitbox ([TVTropes — Hitbox Dissonance](https://tvtropes.org/pmwiki/pmwiki.php/Main/HitBoxDissonance)).
|
||||
- **Monster Hunter's lesson**: hitboxes grossly beyond the visual (Plesioth hipcheck) are infamous; MH:World moved
|
||||
to animation-driven honesty where only the attacking appendage damages.
|
||||
- **Generosity has a direction**: mismatches are tuned *in the player's favor only* — small player hurtboxes,
|
||||
Disc Room's ~50 ms lethal-contact grace, Overwatch's inflated friendly-projectile hitboxes ([Game-feel survey, arXiv 2011.09201](https://arxiv.org/pdf/2011.09201), [TVTropes](https://tvtropes.org/pmwiki/pmwiki.php/Main/HitBoxDissonance)).
|
||||
- **Reach tricks are legitimate**: animators deliberately elongate the weapon/arms at max swing extent and mark
|
||||
the dangerous part of a swing with a trail ([slynyrd](https://www.slynyrd.com/blog/2018/9/8/pixelblog-9-melee-attacks), [gdkeys](https://gdkeys.com/keys-to-combat-design-1-anatomy-of-an-attack/)).
|
||||
|
||||
### R5. Hit-stop is the cheapest weight in games — scale it, cap it, spend it beyond hits
|
||||
Sakurai: hit-stop (a brief pause at the moment of connection) is *critical* — "the same game plays completely
|
||||
differently with versus without it" ([Sakurai on Creating Games — Hit Stop](https://www.youtube.com/watch?v=OdVkEOzdCPw), [Source Gaming translation of Famitsu vol. 490](https://sourcegaming.info/2015/11/11/thoughts-on-hitstop-sakurais-famitsu-column-vol-490-1/)).
|
||||
The canon:
|
||||
- **Scales with damage** (Smash: ~8f for a mid hit in Melee up to 15f in Ultimate; hard caps 20–30f ≈ 333–500 ms).
|
||||
- **Both parties freeze together**, same duration; the victim *vibrates* during the freeze (visual only).
|
||||
- **Hand-tuned per attack**, not purely formula: sword tips ×1.25, electric ×1.5, projectiles get *less*.
|
||||
- Old-school flat values work too: Final Fight = a universal 6f; Capcom pauses only attacker+victim, the rest of
|
||||
the world keeps simulating ([shane-sicienski hitstop analysis](https://shane-sicienski.com/blog/blog-post-title-one-55pmn), [SSBWiki — Hitlag](https://www.ssbwiki.com/Hitlag)).
|
||||
- **Spend the technique beyond hits**: "boss stop" on kill-confirms and any big moment; brief slow-mo that snaps back.
|
||||
|
||||
### R6. Readability = a strict loudness hierarchy + ownership colors + fill-up timing
|
||||
- **D4's intensity hierarchy**: visual loudness is *keyed to ability power* — spammable skills deliberately quiet,
|
||||
ultimates loud; a skill's VFX intensity grows as its power grows ([D4 Quarterly Dec 2021](https://news.blizzard.com/en-us/diablo4/23746639/diablo-iv-quarterly-update-december-2021)).
|
||||
- **D4's dark-scene rule** (LANTERN-critical): pure PBR lighting muddies gameplay readability in the dark, so
|
||||
combat VFX deliberately break physics — they are *emissive and cast their own light*.
|
||||
- **Directional, body-part hit feedback**: impacts flow with the attack's direction and emit from the struck spot,
|
||||
not a generic centered flash.
|
||||
- **WildStar's telegraph canon** ([wiki](https://wildstar.fandom.com/wiki/Telegraph)): fixed ownership colors
|
||||
(blue = yours, red = enemy, green = ally); a **fill line whose arrival at the border = the impact moment**; the
|
||||
fill *direction* encodes one-shot vs persistent effects. Documented failure mode: red telegraphs on red floors.
|
||||
- **SoD's cautionary tale**: even a praised skillshot game saturates into unreadability in 4-player co-op when
|
||||
every ability is loud ([GameCritics review](https://gamecritics.com/gc-staff/shape-of-dreams-review/)) — the
|
||||
hierarchy must be enforced *per on-screen actor budget*, not per ability in isolation.
|
||||
- **SoD's accessibility rule**: every enemy attack has a *visual* telegraph; audio is reinforcement, never the
|
||||
sole channel.
|
||||
|
||||
### R7. Responsiveness = buffers + cancel windows anchored to contact frames
|
||||
God of War's combat designer ([Eric Williams — Combat Canceled](https://www.gamedeveloper.com/pc/combat-canceled-i-god-of-war-i-action-game-design)):
|
||||
cancel-window design is a *primary determinant* of whether combat reads crisp or sluggish (Kratos: ~4,000 authored
|
||||
cancel branches in GoW2). The taxonomy: **partial cancels** open in windows anchored to the hit frame (pre-hit /
|
||||
post-hit); Ninja Gaiden allows *zero* pre-hit cancels (full commitment school); inputs arrive via a **buffer**
|
||||
(stored, fires when the window opens — the forgiving default) or **instant** (frame-exact). Buffer norms: a few
|
||||
frames up to ~0.23 s ([arXiv survey](https://arxiv.org/pdf/2011.09201)); too-long buffers execute stale intent
|
||||
([yosispring — Input Buffering](https://medium.com/@yosispring/input-buffering-action-canceling-and-also-forbidden-knowledge-47a3f8a95151)).
|
||||
|
||||
### R8. Juice has an optimum — medium-high, not maximum
|
||||
Empirical result (Kao study, via [arXiv survey](https://arxiv.org/pdf/2011.09201)): medium and high juiciness
|
||||
outperform both extremes. The canonical kit (screen shake, recoil, color flash, particles — *Juice it or lose it*,
|
||||
Nijman's *Art of Screenshake*, Swink's *Game Feel*) is applied **proportionally to significance**, and the loudest
|
||||
levels are *reserved* so they stay meaningful.
|
||||
|
||||
### R9. The SoD kit grammar (our closest cousin, by design lineage)
|
||||
Shape of Dreams = MOBA QWER grammar (HotS + RoR2 lineage, per the [director interview](https://screenrant.com/shape-of-dreams-eunseop-shim-interview/), [Loot Level Chill interview](https://lootlevelchill.com/features/shape-of-dreams-interview-we-are-standing-on-the-shoulders-of-giants/)):
|
||||
manual-aim skillshots, 4 slotted "memories" + essence modifiers, **cooldown-gated (no resource)**, positioning as
|
||||
the core skill, short compact fights, and difficulty redesigned away from real-time pressure *so players can read
|
||||
their abilities*. Its praised feel comes from the MOBA cast grammar; its documented failure is VFX saturation in
|
||||
co-op. We inherit the first and must budget against the second.
|
||||
|
||||
> **Research gaps (flagged honestly):** Hades primary sources (Noclip documentary, Supergiant GDC talks) and
|
||||
> PoE2 / Last Epoch / V Rising specifics resisted extraction (video-heavy sources) — the Hades school here rides
|
||||
> on the general R1–R5 principles it exemplifies rather than on quoted primary material. If we want its exact
|
||||
> numbers (e.g., dash-cancel windows), that's a follow-up frame-count session, not a blocker for these rules.
|
||||
|
||||
---
|
||||
|
||||
## Part 2 — The LANTERN rulebook (the grammar applied to this game)
|
||||
|
||||
Ground truth these rules bind to: 60 Hz server-auth prediction; swing/cast anim window = `CastFacingTicks` (26t ≈
|
||||
0.43 s) < `MeleeRecoverTicks` (30t ≈ 0.50 s); cleave = instant server cone at `SwingStartTick`; camera Distance 13
|
||||
/ FOV 55° (≈13.5 m visible plane); Rukhanka client-derived anim; procedural FX; the murk (Exp² teal fog, emissive
|
||||
reads win — R6 *is* our art direction's physics).
|
||||
|
||||
### G1 — Time signature: every attack declares its three phases in ticks
|
||||
Author every player attack/ability as **(anticipation, contact, recovery)** ticks against the R1/R3 template:
|
||||
- **Player light verbs** (Swing1/2): anticipation ≤ 10t (~0.17 s), contact 2–4t, recovery carries the weight.
|
||||
- **Player heavy verbs** (finisher, slam): anticipation 15–22t, *held* top-of-swing frames allowed, contact still 2–4t.
|
||||
- **Enemy attacks**: anticipation ≥ **reaction + escape + buffer** = 15t (0.25 s) + dash-trigger (~6t) + 9–15t
|
||||
difficulty buffer → **≥ 30t (0.5 s) floor for basics, 45–60t for heavies** (Grunt/Charger windups already comply).
|
||||
- Contact is *never* slowed to add weight (R3). Weight lives in anticipation holds + recovery + impact (G5).
|
||||
|
||||
### G2 — Reach honesty: the damage cone, the weapon, and the arc must be one object
|
||||
**The fix for the driving complaint**, per R4 (recommended package, operator-approvable line by line):
|
||||
1. **Damage resolves at the contact tick, not the swing-start tick.** Today the cleave lands at `SwingStartTick`
|
||||
while the animation's blade contact is ~16t later — damage precedes the visible hit. Move the server cone
|
||||
resolve to `SwingStartTick + ContactTick` (per-step, from the clip's WindUp take length). This is D4's payload
|
||||
rule (hit region tracks the visual *in time*) and makes the arc a *true* record of the blade. *(Netcode note:
|
||||
a scheduled-tick pattern identical to enemy `AttackWindup` — well-trodden, but it is a gameplay change: light
|
||||
melee gains a ~0.2 s windup. The heavy fantasy wants exactly this; flag for feel-test.)*
|
||||
2. **Shrink the drawn arc to the real cone and the real cone to the believable weapon**: `MeleeRange` 2.6 → **2.2 m**
|
||||
(axe tip ~1.8 m + a 0.4 m player-favoring margin per R4-generosity; still comfortably beats enemy melee range),
|
||||
finisher ×1.5 → **×1.25 range** (keep ×1.5 on damage/recover — reach was the offender, not power).
|
||||
3. **Sell the remaining reach visually** (R4 reach-tricks): scale the axe ×1.25 (Synty proportions absorb it);
|
||||
anchor a short **weapon-tip trail** (the smear) that traces the actual swept edge from the blade, not a
|
||||
body-centered ring; keep the ground arc as the *hit-region* record but draw its outer rim AT 2.2 m so rim = truth.
|
||||
4. **The arc sweep must finish WITH the contact** (R6 fill-timing): sweep-reveal completes at the contact tick,
|
||||
then only fades — never still-painting reach after the blade has passed.
|
||||
|
||||
### G3 — Ownership palette (the WildStar canon, LANTERN-toned)
|
||||
Locked vocabulary across every system (already ~true; now it's law):
|
||||
- **Enemy threat = red family** (per-kind hue variants stay: amber/crimson/toxic/yellow) — ground decals only for
|
||||
*incoming* danger, fill-to-border = impact moment (already our `EnemyDangerTelegraphSystem` contract).
|
||||
- **Local player = warm-white/teal weapon-anchored FX**; the finisher's lamp-amber is *the* warm accent (light is
|
||||
territory — warm = ours).
|
||||
- **Ally = dimmer cool-blue of the same shapes** (RemoteSlashColor already complies).
|
||||
- **Never red for player/ally anything; never warm-amber for enemies.** Murk-red-on-red check: the seabed is teal —
|
||||
we're structurally safe from WildStar's red-floor failure, keep it that way (no red biomes without re-audit).
|
||||
|
||||
### G4 — Loudness hierarchy + the co-op budget (SoD's failure is our ceiling)
|
||||
Priority when pixels compete: **enemy telegraphs > local player contact/impact > ally attacks > ambient**.
|
||||
- Per-ability loudness is keyed to *cost/cooldown/power* (R6-D4): the melee chain and spammable sockets stay quiet
|
||||
(current toned arc = correct); big-cooldown sockets get the loud pass; "ultimate-grade" reserved for rare moments.
|
||||
- **Budget rule:** at 4 players + a wave on screen, ally FX auto-degrade first (fewer particles, shorter lives —
|
||||
a `FeelConfig` ally-fx scalar), enemy telegraphs *never* degrade. Add a dev toggle that spawns the worst case
|
||||
(4 casters + 12 enemies) as the standing saturation test.
|
||||
- **All combat VFX are emissive** (R6 dark-scene rule) — never rely on scene light to read an attack in the murk.
|
||||
Audio reinforces but never solely carries a threat (SoD accessibility rule; our per-kind windup voices are the
|
||||
reinforcement layer, the decal is the message).
|
||||
|
||||
### G5 — Impact ladder (hit-stop canon mapped to our camera-only stack)
|
||||
`Time.timeScale` stays banned (netcode); our hit-stop = camera `Hold` + FOV kick + flash — same ladder, per R5:
|
||||
- **Scale with significance:** chip hit = flash only; solid melee hit = 2-frame hold (current) + directional
|
||||
hit-flash; **finisher/slam connect = 4–5 frame hold + the victim-vibrate trick** (offset the enemy's *render*
|
||||
child ±3 cm for the hold frames — visual only, zero sim); kill = the loudest (existing kill-pop) — a "boss-stop"
|
||||
grade hold (~8 frames + flash) reserved for elite/boss kills.
|
||||
- **Per-attack hand-tuning is expected** (R5): expose the hold frames per verb in `FeelConfig`, don't derive.
|
||||
- **Cap it:** ≤ 8 frames (~130 ms) — beyond Smash's feel-cap territory scaled to our pace.
|
||||
- Directional feedback (R6): hit-flash bursts flow *along the swing direction* from the struck body part
|
||||
(`EmitColored` already takes a position — use the contact point, not the enemy center).
|
||||
|
||||
### G6 — Cast grammar for the 4-socket kit (the SoD inheritance, made explicit)
|
||||
- **Move-cast is the default** (SoD/MOBA school): sockets never self-root; the cast window turns the body
|
||||
(`CastFacingTicks`) while legs keep the move vector (already our model — now it's the rule for every new Spark).
|
||||
- **Cooldown-gated, no resource** (R9) — matches the socket model; any future resource is a per-Spark exception.
|
||||
- **Every socket declares its G1 time signature + a G3-compliant visual**: projectile = muzzle + tracer (its trail
|
||||
*is* its honesty); cone = the G2 arc rules; zone = a WildStar-grade fill decal (fill completes at damage start,
|
||||
one-shot vs persistent encoded by fill direction per R6); movement = trail + i-frame shimmer (no telegraph — it's
|
||||
an escape verb).
|
||||
- **Skillshots stay honest**: no homing-by-default; assist only where a Spark explicitly buys it (the existing
|
||||
`AutoTargetRange = 0` default per DR-050).
|
||||
|
||||
### G7 — Responsiveness contract (buffers + cancels, netcode-shaped)
|
||||
- **Input buffer ≈ 6–10 ticks (0.1–0.17 s)** for melee-chain and socket presses: a press during the last ~10t of
|
||||
a lock fires on the first legal tick (R7 buffer method; our `InputEvent`s already latch per tick — the buffer is
|
||||
a server-side "held intent" check against `LockUntilTick`, deterministic and rollback-safe). Never longer — stale
|
||||
intent (R7's SSBU warning).
|
||||
- **Cancel taxonomy per class fantasy** (R7): the **Bathynaut commits** — no pre-contact cancel on swings (Ninja
|
||||
Gaiden school; the dash already refuses to interrupt a swing — keep); **post-contact, dash-cancel opens** (spend
|
||||
recovery on weight but hand back agency for the escape verb — the Souls-roll compromise). The **Harpooner** is
|
||||
the crisp school: pre-contact cancel on line-casts at the cost of the cooldown tick.
|
||||
- Movement-commit (`MeleeSwingMoveScale` 0.35) is the melee's "self-root lite" — keep; it is the commitment read.
|
||||
|
||||
### G8 — Enemy telegraph compliance (mostly ratifying what exists)
|
||||
The existing system already matches canon (per-kind color + shape + voice, fill-ends-at-impact, strike beep at 8t).
|
||||
Additions to make it law: every NEW enemy attack ships **decal shape = true damage volume** (G2 honesty applies to
|
||||
enemies doubly — their generosity direction is *toward the player*: decal may be ≥ the true volume, never smaller);
|
||||
anticipation floors per G1; one **signature silhouette pose** per kind's windup (readable without the decal, R2).
|
||||
|
||||
---
|
||||
|
||||
## Part 3 — Review items (the forks in this doc)
|
||||
|
||||
| # | Fork | Recommendation | Status |
|
||||
|---|---|---|---|
|
||||
| 1 | **Damage at contact tick** (G2.1) — light melee gains ~0.2 s real windup | DO — it's the honest heavy-weapon model; feel-test behind a knob | ☐ operator |
|
||||
| 2 | **Reach retune** (G2.2) — `MeleeRange` 2.6→2.2, finisher reach ×1.5→×1.25 | DO with #1 as one package | ☐ operator |
|
||||
| 3 | **Weapon scale ×1.25 + tip trail** (G2.3) | DO — cheapest honesty win | ☐ operator |
|
||||
| 4 | Victim-vibrate + finisher hold ladder (G5) | DO — pure presentation | ☐ operator |
|
||||
| 5 | Input buffer 6–10t (G7) — a small predicted-sim change | DO after #1 lands (same system) | ☐ operator |
|
||||
| 6 | Class cancel policies (G7) — Bathynaut commit / Harpooner crisp | Ratify as design law | ☐ operator |
|
||||
| 7 | Hades frame-count follow-up session (fill the research gap) | Optional, low priority | ☐ operator |
|
||||
|
||||
*Checklist for any new attack/ability (the doc in one box):* declare G1 ticks → G2 volume==visual==timing →
|
||||
G3 color → G4 loudness tier → G5 impact tier → G6 cast grammar → G7 buffer/cancel policy → (enemy) G8 decal+pose.
|
||||
Reference in New Issue
Block a user