data/props.ts — World-Prop Catalog
Typed destructible catalog. Props share the crate idiom (off-screen spawn, ship-contact break, drop XP orbs) but vary by silhouette, drop richness, density, and break VFX. Per-planet density = crate density × densityMult.
Slay
- Defines the seven prop tiers used by the prop-spawner + weighted-roll pipeline.
- Single source of truth for HP, radius, sticker emoji, rim color, orb drops, density multiplier, and break VFX.
- HP exists for a future Slice 2 (weapon-fire damage); Slice 1 always one-shots on ship contact.
- Exports
PROP_TYPES(readonly array) +getPropType(id)(throws on unknown).
Cross
PropTypeDef (interface)
| Field | Type | Meaning |
|---|---|---|
id | string | Stable id used by spawner + telemetry. |
label | string | Debug-HUD label only — never user-facing. |
hp | number | Max HP; Slice 1 always one-shots via ship contact. |
radius | number | Visible silhouette radius — spawn placement + collision. |
emoji | string | Baked sticker sprite glyph. |
rimColor | string | Inner-rim halo color (rarity ring around sticker). |
orbCount | number | XP-orb pickups dropped on break. |
orbXpFracPerOrb | number | XP per orb as a fraction of current level bar. |
densityMult | number | Multiplier vs the crate density slider (0–1). |
vfx.sparkRgb | [r,g,b] | Spark cloud color. |
vfx.chunkRgb | [r,g,b] | Debris chunk color. |
vfx.ringColor | string | Ring-flash color. |
vfx.sparkCount | number | Particle count of the spark cloud. |
vfx.ringBurstCount | number | Extra outward burst-ring particles. |
edgeArrow? | boolean | HUD draws screen-edge directional arrow when off-screen. Rare-tier only. |
Exports
PROP_TYPES: readonly PropTypeDef[]— seven-entry catalog (see Styx).getPropType(id: string): PropTypeDef— linear scan; throwsUnknown prop type id: <id>on miss. No silent fallback.
Styx
Tier table (catalog order)
| id | Label | HP | Radius | Emoji | rimColor | orbCount | orbXp/orb | Approx. % level bar | densityMult | edgeArrow |
|---|---|---|---|---|---|---|---|---|---|---|
scrap_pile | Scrap Pile | 10 | 32 | 🗑️ | #9aa3ad slate | 4 | 0.018 | ~7.2% | 1.00 | — |
drone_wreck | Drone Wreck | 18 | 30 | 🤖 | #5fc8ff cyan | 6 | 0.020 | ~12% | 0.60 | — |
comet_fragment | Comet Fragment | 8 | 26 | ☄️ | #c8ddff ice | 7 | 0.015 | ~10.5% | 0.40 | — |
mineral_vein | Mineral Vein | 40 | 34 | 🪨 | #5fe07a green | 10 | 0.024 | ~24% | 0.25 | — |
volatile_crystal | Volatile Crystal | 25 | 30 | 💎 | #ff5fcb magenta | 8 | 0.022 | ~17.6% | 0.35 | — |
supply_pod | Supply Pod | 80 | 40 | 📦 | #ffaa44 amber | 12 | 0.035 | ~42% | 0.15 | yes |
magnetar_pulse | Magnetar Pulse | 35 | 32 | 🌀 | #a050ff violet | 6 | 0.020 | ~12% | 0.20 | yes |
Break-VFX table
| id | sparkRgb | chunkRgb | ringColor | sparkCount | ringBurstCount |
|---|---|---|---|---|---|
scrap_pile | [220,220,220] dust-white | [110,110,110] grey | #cfd6df | 14 | 0 |
drone_wreck | [120,220,255] electric blue | [80,120,160] dark blue | #7fd5ff | 18 | 0 |
comet_fragment | [220,235,255] ice-white | [150,180,220] pale blue | #dfeaff | 20 | 8 |
mineral_vein | [120,230,130] emerald | [60,140,80] forest | #7fe89a | 24 | 10 |
volatile_crystal | [255,100,220] hot magenta | [180,60,180] deep magenta | #ff3fb0 | 22 | 18 |
supply_pod | [255,200,100] amber | [200,150,80] bronze | #ffcc44 | 30 | 14 |
magnetar_pulse | [180,110,255] violet | [110,50,200] deep purple | #a060ff | 26 | 16 |
Design intent (per tier)
- Scrap Pile — workhorse common; HP-10 one-ram break; grey dust; no ring burst.
- Drone Wreck — workhorse-alt; HP-18 reads as “metal carcass” (two rams or short burst); cyan circuitry palette.
- Comet Fragment — light snack; HP-8 fragile; 7 orbs at lower XP for a “shooting-star streak” rhythm; small 8-particle ring burst.
- Mineral Vein — sustained-DPS reward; HP-40 between Volatile (25) and Supply (80); rewards weapon-fire builds; ~24% level bar bundle.
- Volatile Crystal — risk-reward; HP-25; magenta matches the
volatileelite-affix palette; heavy 18-particle outward ring burst. - Supply Pod — rare iconic; HP-80 ≈ 3–4 s of base-DPS; biggest spark burst (30); ~42% level bar; edge-arrow telegraph.
- Magnetar Pulse — rare field-control; HP-35; break grants a 1s gravity field (value is in the pull, not XP); 6 orbs × 0.020; edge-arrow second tier.
Density math
- Per-planet density derives from the same
destructiblesslider crates use:propDensity = crateDensity × densityMult. - Weight distribution (relative): Scrap 1.00, Drone 0.60, Comet 0.40, Volatile 0.35, Mineral 0.25, Magnetar 0.20, Supply 0.15.
- Comment-asserted: Supply Pods ≈ ~10% of total prop spawns; capped at ~1–2 active by shared
MAX_DENSITY = 10. Magnetar pulses are roughly Supply-Pod frequency, ~1–2 active.
Edge-arrow tier
Reserved for high-value rare props that need a screen-edge directional arrow when off-screen (Survivor.io / Vampire Survivors loot-pointer telegraph). Currently supply_pod and magnetar_pulse. Field defaults to undefined/false; common props stay quiet.
Lookup
getPropType('scrap_pile') // => PropTypeDef
getPropType('unknown') // throws Error('Unknown prop type id: unknown')Linear scan over PROP_TYPES. Typo’d ids are bugs, not runtime fallbacks — crash on bad data, per project rule.
EXTRACT-CANDIDATE: The XP-yield-per-tier column (orbCount × orbXpFracPerOrb → “approx % level bar”) is derived in this doc only. If a balance/economy roll-up page wants this, extract to a shared constant or a propXpYield() helper rather than duplicating the arithmetic. The Magnetar Pulse “1s gravity field on break” effect is referenced in the description but not encoded as a field — it lives in the spawner/effect layer; if a designer-authoring guide extends PropTypeDef with an onBreakEffect field, fold the comment into a structured slot.