Death Defiance Timing

The Death Defiance revive prompt uses a non-linear “cheater timer” so that the visible drain bar appears to slow down at the end, giving the player extra real-world seconds to react after the bar has already crossed into the “almost gone” zone. The bar’s display position is a linear function of an internal clock; the internal clock is what gets warped. All constants live in src/starship-survivors/data/economy.ts.

The three phases

The prompt runs through three back-to-back phases on a single real-world wall clock:

PhaseDisplay fractionReal-time secondsBehavior
Linear early1.0CHEAT_THRESHOLD (0.35)PROMPT_DURATION × (1 - CHEAT_THRESHOLD) = 3.25 sBar drains at normal speed: 1 display-second per real-second.
Stretched cheaterCHEAT_THRESHOLD (0.35) → ~0.01PROMPT_DURATION × CHEAT_THRESHOLD × CHEAT_STRETCH = 3.50 sBar’s apparent speed is halved. The last 35% of display takes 2x as long in real time.
Linger at 1%stays near 0.01LINGER_DURATION = 1.00 sBar sits sparking red, then auto-dismiss fires.

Sum: DEATH_DEFIANCE_TOTAL_REAL_DURATION = 7.75 s of real time for a PROMPT_DURATION of 5 s.

Authoritative duration

DEATH_DEFIANCE_TOTAL_REAL_DURATION is the single source of truth for “how long is the prompt up.” Both consumers must use it:

  • Bridge dismiss timer — the engine-side timeout that fires the auto-dismiss / auto-decline. If this fired off PROMPT_DURATION (5 s) it would cut the prompt off mid-stretch, before the React bar reached zero.
  • React bar component — the visual drain bar. Its own internal animation runs against the same total so the bar reaches ~1% exactly when the linger phase begins, and the prompt closes exactly when linger ends.

The computed expression in economy.ts is the formula for that contract:

const cheatDisplay = PROMPT_DURATION * CHEAT_THRESHOLD;
const normalDisplay = PROMPT_DURATION - cheatDisplay;
return normalDisplay + cheatDisplay * CHEAT_STRETCH + LINGER_DURATION;

If any of the four input constants change (PROMPT_DURATION, CHEAT_THRESHOLD, CHEAT_STRETCH, LINGER_DURATION), TOTAL_REAL_DURATION recomputes and both consumers stay in sync automatically — neither side ever hardcodes the 5 s display duration or the 7.75 s real duration.

Why cheater-timer exists

Death Defiance is the only paid in-run revive (gem cost escalates 20 / 40 / 60 per use; see deathDefianceCost). It triggers in the worst possible UX moment: the player just died, the “YOU DIED” cinematic ran for 3 s, and now a modal demands an immediate yes/no decision. A 5-second hard timer that drains linearly feels punitive — the player perceives the back half of the bar as faster than the front half because urgency compresses subjective time.

The cheater timer breaks that perception three ways:

  1. Front-loaded normal speed. The first 65% of the bar drains at the speed the player calibrates to. They build an internal model of “this bar takes ~3 seconds total” based on the first chunk.
  2. Stealth slowdown. As the bar enters the stretched portion the actual real-time rate drops by half, but the visual cue (bar position) keeps moving. The player thinks they’re getting faster at deciding; they’re actually getting more wall-clock time than they expected.
  3. Linger tension. The last second is the bar pinned at ~1% sparking red. This reads as dramatic “last chance” tension to the player while functionally being a free 1.0 s of decision time after the bar visually appears empty.

Net effect: the player perceives a tight 5-second decision window, gets 7.75 s of real time, and is more likely to make a deliberate purchase decision (either yes or no) instead of a panicked one. Panic decisions correlate with regret, regret correlates with refund requests and churn — both bad for a single-currency premium revive.