muzzleFlash
The bloom at a barrel the instant a weapon fires. A ragged ball of light sits at the muzzle, a lick of flame runs down the bore line, unburnt powder sprays out in a tight cone, and a point light fires with it and decays faster than the flash that threw it. One width in metres sizes all of it, so the same asset covers a pistol at 0.12 and a tank gun at 1.2.
effects.play("@builtin::systems.effects.combat.muzzleFlash", {
position = barrel.position,
params = { size = 0.28, direction = { 0, 0, 1 } },
})
Parameters
| Parameter | Type | Default | Range | What it changes |
|---|---|---|---|---|
size | number | 0.28 | 0.02 – 4.0 | Width of the flash at the muzzle, in metres. The bloom, the lick, the spark speed and the light's range and intensity are all proportioned off it. |
direction | vec3 | {0, 0, 1} | world space | Which way the barrel points. The lick and the spark cone run down it. play's own direction option overrides it. |
color | color | {1.0, 0.82, 0.42} | linear 0..1 | Colour of the flash. Cordite runs yellow-orange, a rail weapon runs blue-white. |
duration | number | 0.09 | 0.02 – 1.5 | Seconds until the last spark has gone and everything is released. |
light | number | 1.0 | 0.0 – 8.0 | Strength of the light thrown into the scene. At 0 no light entity is spawned. |
sparks | number | 1.0 | 0.0 – 4.0 | Powder thrown, as a multiple of 40 sparks. At 0 the spark emitter is not leased at all. |
A parameter outside its range is held at the bound and the holding is reported. A name the effect does not declare raises, and names the ones it does.
Cost
<!-- cost: quoted verbatim from effect.yaml -->| gpuMs | vramBytes | measuredOn |
|---|---|---|
| 0.01 | 34820 | see effect.yaml |
The size is what the effect's own backends report they hold at a representative
instant — handle:stats().bytes — read identically on every engine, in every
scene and on every repeat. The emitter vertex buffers an effect draws from come
out of a pool shared across the process that grows in chunks, so a
renderer.gpuMemory() delta taken around one play is that pool's growth as much
as the effect's; what those buffers cost at the declared slot counts is below.
The span is the median of five interleaved idle/loaded windows of the frame's
measured GPU pass sum, which read 0.000 ms with a spread of about 0.008 ms: the
effect costs less GPU time than that instrument resolves, and 0.01 is the bound
the reading supports.
34,820 bytes of emitter simulation state, plus 30,400 bytes of emitter vertex
geometry — the spark emitter's 40 declared slots at 760 bytes each. Both follow
the declared slot count rather than the live particle count, so the figure is
the same at every flash width. At sparks = 0 no emitter is leased and the
effect holds nothing.
What it draws with
| Asset | Role |
|---|---|
combat/materials/combat_glow | the family's one additive material — the bloom and the lick |
combat/glow | the module that leases the cards and writes their lanes |
The flash is procedural: the bloom's silhouette is carved by ridged fBm from
fx_noise and the lick is a gradient along its own rod. No texture is sampled,
so the effect adds nothing to a frame's bind budget.
The handle
local h = effects.play("@builtin::systems.effects.combat.muzzleFlash", { position = { 0, 2, 0 } })
h.stats() -- { size, direction, bloomDiameter, lickLength, sparksEmitted,
-- sparkSlots, particlesAlive, lightIntensity, age, duration }
Everything the flash spawns is temporary, so a shot fired while somebody is authoring cannot end up in a saved scene.
See also
guides { path: "topics/visual-effects" }— finding, playing and parameterising effects.@builtin::systems.effects.combat.tracer— the round the shot sends out.@builtin::systems.effects.demo.combat_showcase— the demo scene, which fires the whole family on a loop with no setup.
Scoped to this part · feeds back into the world's score.