---
title: "Projectiles bullets and ranged weapons"
description: "The player fires and something flies out or an instant beam hits. There is no `ProjectileComponent`, `HitscanWeaponComponent`, or `WeaponSlotComponent` (all stripped); a weapon is a fire action plus a spawn-and-launch or a shapecast."
engineVersion: v1.0.234
date: 2026-09-28
license: "(c) Gessa, proprietary. Cite with attribution to https://gessa.ai/docs/. Terms: https://gessa.ai/terms/."
canonical: https://gessa.ai/docs/knowledge/playbooks/projectiles-and-ranged-weapons/
---

# Projectiles bullets and ranged weapons

## When to use

The player fires and something flies out or an instant beam hits. There is no
`ProjectileComponent`, `HitscanWeaponComponent`, or `WeaponSlotComponent` (all
stripped); a weapon is a fire action plus a spawn-and-launch or a shapecast.

## The recipe

Author with `project_apply_script_semantic_patch` using the `ai_safe` op pack.

1. Bind the trigger: declare a `fire` action (see
   input-mapping-actions-bindings) and `addActionHandler`
   `{ "actionKey":"fire" }`.
2. Spawned projectile (grenade, arrow, fireball): build a projectile prefab once
   with `project_create_prefab` carrying a `RigidBodyComponent` and a trigger
   `ColliderComponent` (`collision:"trigger"`). In the fire handler,
   `spawnEntityFromTemplate` `{ "prefabKey": <projectile>, "config": {...} }` at
   the muzzle, then push it with `ctx.physics.command` using a launch body
   command (VelocityComponent's contract note: launch bodies via
   `Physics.command { type: "launch" }`; never patch `VelocityComponent`
   directly, it is engine-internal). Damage on contact via `addTriggerHandler`
   on the projectile that applies damage (see combat-damage-and-respawn) and
   `despawnEntity` the bullet.
3. Hitscan (instant hit): in the fire handler body (GessaScript via
   `replaceScriptFromGessaScript`), call `ctx.physics.shapecast` from the muzzle
   along the aim direction; if it returns a hit, apply damage to the hit entity
   and spawn an impact effect. No projectile entity is spawned.
4. Rate limit: guard the fire handler with a cooldown (a `TimerComponent` or a
   last-fired timestamp in state; see timers-countdowns-and-waves) so holding
   fire does not spawn one bullet per tick.
5. Muzzle flash and impact: pair with particles-and-visual-effects for the burst
   and a `DecalComponent` scorch at the hit point.

## Pitfalls

- Never write `VelocityComponent` to move a bullet; it is hidden from AI/SDK and
  runtime-owned. Launch through `ctx.physics.command`.
- `spawnEntityFromTemplate` and `ctx.world.spawn` are authority-gated
  (`spawn.bounds`); spawn on the server, at a bounded position near the muzzle.
- Bullets that never despawn accumulate and hit the collider budget (1000 per
  tick). Despawn on impact and add a lifetime timeout.
- A projectile collider must be `trigger`, not `solid`, or it will be blocked by
  the target instead of passing through and reporting the hit.
- Aim direction must come from the shooter's facing (camera or transform),
  resolved in the handler; there is no built-in "forward vector" field to read
  blindly.

## Verify

- `simulation_run` (`qa.run.start`) to prove a shot spawns and travels, a hit
  applies damage, and the projectile despawns on impact or timeout.
- `project_get_graph_snapshot` to confirm the fire action handler and the
  projectile prefab exist.
