What this is

Newly spawned enemies are skipped by all damage, collision, and targeting checks during a brief window at the start of their fade-in. The window is controlled by a per-enemy countdown timer _spawnT that decreases each frame from a positive initial value down to zero. While _spawnT is above a fixed threshold, the enemy is effectively non-existent to every projectile, AoE, beam, and targeting scan in the game.

The threshold

Every gameplay loop that iterates over enemies tests (e as any)._spawnT > 0.15 and skips the enemy when true. The threshold is a literal 0.15 in seconds, hard-coded inline at every call site (no shared constant).

FieldValueMeaning
_spawnT initial (standard enemy)0.3 sSet in spawnEnemy alongside _spawnDur: 0.3
_spawnT initial (orb bodyguard follower, index i)0.3 + i * 0.1 sStaggered fade-in for clustered followers
_spawnT skip threshold> 0.15 sEnemy excluded from collisions/damage/targeting
_spawnT tangible threshold<= 0.15 sEnemy enters the grid and receives hits
_spawnT zero (pop trigger)0 sSets _spawnPopT = 0.12 for squash-stretch
_spawnPopT duration0.12 sScale bounce 1.0 → 1.12 → 1.0 after fade-in

_spawnT decrements by dt each frame in bridge.ts until it reaches zero; at that point it is clamped to 0 and the pop timer is triggered. Given the standard 0.3 initial value, the immune window lasts the first 0.15 s of the 0.3 s fade-in — the latter half of the fade is fully tangible.

Which collision paths honor it

The skip check appears at every site that scans the enemy array for damage, collision, separation, or target acquisition. While _spawnT > 0.15, the enemy is ignored by:

PathSite (file)
Player bullet → enemy spatial grid insertionengine/combat/collision-resolver.ts (rebuildEnemyGrid)
Beam-trace line collision sweepengine/combat/collision-resolver.ts
Splash-AoE damage on bullet impactengine/combat/collision-resolver.ts
Mine proximity trigger scanengine/weapons/bullets.ts (mine armed phase)
Mine pulse damage (post-detonation)engine/weapons/bullets.ts
Mortar AoE damage with falloffengine/weapons/bullets.ts
Chain-lightning next-target acquisitionengine/weapons/bullets.ts
Tesla orbit per-target contact loopengine/weapons/bullets.ts
Cone weapon tick sweepengine/weapons/bullets.ts
Arc/sword swing target scanengine/weapons/bullets.ts
Shooting-star contact loopengine/weapons/bullets.ts
Shooting-star AoE on landingengine/weapons/bullets.ts
Bomb / hellfire / cluster impact AoEengine/weapons/bullets.ts
Zone-tick damage (ground hazards)engine/weapons/bullets.ts
Burst-fire target acquisitionengine/weapons/bullets.ts
Enemy-vs-enemy separation forcesengine/bridge.ts, engine/combat/collision-resolver.ts

Because the spatial grid is rebuilt every frame and excludes spawning enemies, bullets using grid-accelerated lookups also miss spawning enemies automatically — the skip is enforced both at insertion and at every iteration site.

Why

The spawn comment in spawner.ts states: No intangibility — enemies are targetable immediately. That comment refers to the visual fade-in (0.3 s) not gating gameplay overall — but for the first half of that fade, the _spawnT > 0.15 check enforces a tangible-but-untouchable window. The purpose is twofold:

  1. Prevent self-hit on overlapping spawn. When enemies spawn in clusters (orb bodyguard followers, biome packs, mini-boss adds), bodies frequently overlap on frame 1. Without a brief immune window, in-flight player bullets, persistent AoE zones, orbiting blades, and beam traces would all immediately damage every overlapping fresh spawn — instantly wiping packs the moment they appear, before the player has reacted to them.
  2. Stabilize the spatial grid. Inserting an enemy into enemyGrid before its position has settled into the fade-in tween would cause inconsistent collision results across paths that query the grid versus paths that iterate the full enemy array. Excluding the spawning enemy from the grid for the first 0.15 s ensures all collision paths agree the enemy is non-targetable.

The threshold is not configurable — it is a literal 0.15 repeated at every call site. The initial _spawnT value (and thus the total fade-in duration) is configurable per enemy: standard spawns use 0.3, orb followers use 0.3 + i * 0.1 for staggered visual entry.