Edge-Arrow HUD (Off-Screen Indicator)
When a high-value world entity is off-screen, the HUD draws an amber chevron at the screen edge pointing toward it. Iconic Survivor.io / Vampire-Survivors-style loot-pointer telegraph — reserved for rare, kite-worthy props so the cue never spams the field.
Trigger
A prop participates in the edge-arrow system if and only if its PropTypeDef sets edgeArrow: true (src/starship-survivors/data/props.ts). Today exactly two prop tiers opt in:
| Prop | Rim color | Why arrowed |
|---|---|---|
Supply Pod (supply_pod) | #ffaa44 amber | 80 HP, 12 orbs × 0.035 XP frac (~42% of level bar). The big-bundle reward; worth the kite. |
Magnetar Pulse (magnetar_pulse) | #a050ff violet | 35 HP, break triggers a 1s gravity field. Findable like Supply Pods so the field-control beat doesn’t go missed. |
Common-tier props (Scrap Pile, Drone Wreck, Comet Fragment, Volatile Crystal, Mineral Vein) default to edgeArrow: undefined/false and stay quiet — adding the flag to a new tier opts it in with zero engine changes.
Iteration path
The prop pool exposes forEachEdgeArrowProp(cb) (engine/world/props.ts) which walks active slots and invokes the callback only for slots whose type def has edgeArrow: true. The HUD layer (engine/rendering/hud.ts, _drawSupplyPodArrows, despite the legacy name, handles all edge-arrow props) calls this each frame.
Per-frame cost is O(active edge-arrow props) — capped at ~1–2 active by densityMult weights (Supply Pod 0.15, Magnetar Pulse 0.20) against the shared MAX_DENSITY = 10. Well inside the HUD <2ms budget; ~6 ctx ops per draw.
Two states: off-screen vs on-screen
The same draw function handles both visibility states by checking whether the prop’s world coord projects inside the viewport (sx > 0 && sx < W && sy > 0 && sy < H).
Off-screen — edge chevron
Drawn on a circle of radius Math.min(W, H) * 0.42 around screen center, rotated to face the prop’s world angle from the ship. Amber palette: outer stroke #ffcc66 (3.2px), inner “hot core” filament #fff2c2 (1.6px), #ffaa44 shadow blur. Base pulse is a 4 Hz sine on alpha (same rhythm as the portal indicator).
On-screen — bobbing marker
Once the prop enters the viewport, the indicator switches to a downward chevron floating 70px above the prop, bobbing ±6px on a 3 Hz sine. Same color palette, slightly tighter footprint, no rotation.
Distance modulation — the “drama” ramp
Distance from ship to prop drives a drama scalar that intensifies the arrow when the prop is far away and calms it as the player closes in. The threshold is DRAMA_DIST_PX = 900 world units (about a screen width at default zoom).
drama = clamp((dist - 900) / 900, 0, 1)
- dist ≤ 900px:
drama = 0. The arrow rides the steady 4 Hz pulse so it doesn’t compete with the on-target glow the prop itself emits. - dist between 900 and 1800px:
dramaramps 0 → 1. - dist ≥ 1800px:
drama = 1. Maximum dramatic-telegraph mode.
Drama modulates three values:
| Property | Effect |
|---|---|
dramaThrob | Adds a slower 2 Hz overlay on the pulse — bigger “breathing” rhythm for distant pods. |
sizeMult = 1 + drama * 0.5 | Chevron grows up to 50% larger when far. |
shadowBlur | Increases from 10px to 18px (10 + 8 * drama). |
The combined pulse is capped at 1.2 so the alpha doesn’t oversaturate. Players see a fresh spawn pop hard from across the map, then settle into a calmer chevron as they kite toward it — the dramatic open, then the quiet closer.
No numeric distance label
There is no literal distance readout (no “150m” pip). The cue is purely intensity-driven: bigger + brighter = farther. This keeps the HUD readable on phone and reinforces the field-feel-first priority — the player just rotates toward the brightest amber arrow.
Relationship to other edge indicators
The edge-arrow HUD shares the chevron idiom with two sibling cues, all drawn in hud.ts:
| System | Function | Color | Trigger |
|---|---|---|---|
| Directional hit indicators | _drawHitIndicators | red | Recent damage from off-screen attacker |
| Portal navigation indicator | _drawPortalIndicator | purple | Persistent — extraction portal |
| Edge-arrow loot pointer (this page) | _drawSupplyPodArrows | amber / violet | Active prop with edgeArrow: true |
The shared chevron geometry keeps the HUD legible — every edge cue means “look this way” and the color says why.
Extending
Opt a new prop tier into the system by adding edgeArrow: true to its PropTypeDef entry in data/props.ts. No engine, pool, or HUD changes required — the iterator picks it up automatically and draws the same amber chevron. (A future enhancement could read per-prop arrow color from the rimColor field; today the chevron palette is hard-coded amber in hud.ts.)