Shooting Star System
Shooting stars are rare collectible entities that spawn in the world during the second half of each level. Touching one freezes the game and queues a special meta-pick reward screen — a 2-choice offer drawn from a category pool that is disjoint from regular level-up rewards. The pool emphasizes utility (extra reroll, banish, or refuel charges) alongside broad-stroke power spikes (level up every weapon, ascend every artifact, full Star Power buff). Shooting-star picks always render at legendary rarity and are placed on a separate spawn schedule from regular reward picks.
Source: engine/world/shooting-star.ts (spawn + entity), engine/world/leveling.ts (generateShootingStarChoices, applyChoice case 'shooting_star'), engine/rendering/draw-shooting-star.ts (visuals).
Spawn schedule
Shooting stars run on their own log-normal spawn timer, fully independent of XP-driven level-ups.
- Window: only active during the second half of each level (
missionElapsed >= missionTimerMax / 2). Outside that window the spawner is dormant. - Cadence: ~1 star per current tier across the 120s window. Median interval is
120 / tierLevelseconds (tier 1 → 120s median, tier 5 → 24s median), drawn from a log-normal distribution with sigma 0.5 and clamped to[5s, 120s]. - First star: on entering the window, the initial timer is rolled at half the normal interval so the first appearance comes sooner.
- Spawn position: 600 px from the player at a random angle, with base velocity ~154 px/s aimed back through the player.
In-world entity
The star itself is a moving pickup, not a passive marker.
- Visual signature: a 5-pointed white-hot star with an orange/gold gradient core, wrapped in a golden spinning ring of radius 100 px with 8 tick marks, and trailing a rainbow tail (red → orange → yellow → green → blue → indigo → violet) capped with a white-hot core line.
- Collection radius: the outer golden ring at 100 px (world space) is the hitbox, not the 8 px star body. Touching anywhere inside the ring counts.
- Player-reactive speed: as the player approaches, the star decelerates over 4.5s down to 0.5× speed, then accelerates back to 1.0× to “exit” — a chase that gives the player a real shot but isn’t free.
- Trail buff: the rainbow tail (last ~3.6s of path, 120 sampled points) is also an active zone — the player gets +30% speed while inside
TRAIL_BUFF_RADIUS = 60 pxof any trail point. Threading the trail is part of the catch loop. - Despawn: stars only despawn when more than 3000 px from the player (roughly 3 screens away). Lifetime-based despawn is intentionally removed — a star must never vanish in front of the player.
- Pickup bumps: nearby gems and weapon boxes are knocked by the star as it passes, with golden spark particles.
Collection sequence
On ring touch:
- Multi-phase golden particle burst centered on the player (ring shatter, gold sparks, white starburst, gold confetti, upward geyser, white-hot core flash).
- Expanding ring-pop VFX at the collection point.
- Game enters weapon-chest-style freeze (
game._weaponChestFreeze = true,timeDilation = 0). - Star flies from its world position to screen center over 0.6s, growing 1.0× → 1.5× scale and spinning faster.
- Reward screen appears with the shooting-star choices.
Reward categories
generateShootingStarChoices builds a pool of up to 8 categories, shuffles, and presents 2. All cards render as rarity: 'legendary'. Categories split into three families.
Power-spike rewards
Eligibility-gated. Only appear if the player has something for them to act on.
- ALL WEAPONS (
weapons) —+1level on every owned weapon, capped atMAX_WEAPON_LEVEL = 20. Eligible if ship has any weapons. - ALL SHIP MODS (
ship_upgrades) — bump every owned modifier by 1 level, capped at each mod’smaxLevel. Each rank is applied through_applyModifierPickso the mod system receives a normal registration. Eligible if any mod is owned. - ALL ARTIFACTS (
artifacts) — ascend every owned artifact by 1 tier viagrantArtifact. Eligible if any artifact is owned. - FORGE STRIKE (
lowest_weapon) — add 3 levels to the lowest-level weapon (ties resolved by first-in-array). Eligible if any weapon exists belowMAX_WEAPON_LEVEL.
Buff reward
- STAR POWER (
player_buff) — 60 seconds of the exclusivestarpowerstate viaapplyExclusiveState(ship, 'starpower', 60). While active: invulnerable, 2× damage, +20% speed, no heat. Always eligible.
Utility / charge-grant rewards
Always eligible. These exist to refill the run’s meta resources. Card metadata is fixed strings, not stat-scaled.
- +1 REROLL (
grant_reroll) —game.rerolls += 1. Adds a reroll charge for future selection screens. - +1 BANISH (
grant_banish) —game.banishes += 1. Adds a banish charge. - +1 REFUEL (
grant_refuel) —game.refuels += 1. Adds a mid-run refuel charge that restores fuel.
Non-banishable cards
The three charge-grant categories (grant_reroll, grant_banish, grant_refuel) return null from banishKeyForChoice, which means the banish button is suppressed on those cards. The reasoning is encoded directly in the source: banishing a +1 REROLL card would block the only path to refilling rerolls for the rest of the run — same policy logic that applies to the other charge-grant cards.
Every other shooting-star category banishes under the key shooting_star|<category>. Banished categories are filtered out of the eligible pool by generateShootingStarChoices, so once you banish ALL WEAPONS it won’t reappear for the rest of the run.
The shooting-star pool is also independent of the regular reward pools (weapon, weapon_upgrade, artifact, modifier, etc.) — banishing inside the shooting-star pool does not affect what shows up at normal level-ups.
Tracking
Each shooting-star pick appends shooting_star_<category> to game.tracking.upgradesChosen, so post-run tracking can distinguish shooting-star picks from regular level-up choices.
Key constants
| Constant | Value | Purpose |
|---|---|---|
STAR_RING_COLLISION_RADIUS | 100 px | Collision = the visible golden ring, not the star body. |
STAR_DESPAWN_DISTANCE | 3000 px | Stars only cull when ~3 screens away from the player. |
STAR_FLY_DURATION | 0.6 s | Collected-star fly-to-center animation length. |
TRAIL_SAMPLE_INTERVAL | 0.03 s | Trail records a point every 30 ms. |
TRAIL_MAX_LENGTH | 120 points | ≈3.6 s of trail history = the +30% speed buff zone. |
TRAIL_BUFF_RADIUS | 60 px | Distance from a trail point to count as “in the trail”. |
TRAIL_BUFF_REFRESH_SECONDS | 0.12 s | Boost timer refresh per frame in-trail (>1 sim step to avoid flicker). |
MAX_WEAPON_LEVEL | 20 | Cap for ALL WEAPONS and FORGE STRIKE. |
| spawn distance | 600 px | Distance from player at spawn. |
| spawn base speed | ~154 px/s ± 20 | Initial velocity aimed at player. |
Files
starship-survivors/src/starship-survivors/engine/world/shooting-star.ts— entity, spawner, update loop, collection, trail buff, ring-pop VFX.starship-survivors/src/starship-survivors/engine/world/leveling.ts—generateShootingStarChoices,applyChoicecase 'shooting_star',banishKeyForChoice,_SHOOTING_STAR_CARDSmetadata.starship-survivors/src/starship-survivors/engine/rendering/draw-shooting-star.ts— rainbow trail, golden ring, 5-pointed star, fly-to-center animation.