vfx-fire is a skill from the Summer skill library: a guide your AI agent reads when the task matches, so it builds the good version on the first try. Fire effect: animated flames from GPUParticles3D, a particle shader and a noise color ramp.
When your agent uses it
- Authoring a fire visual effect — torch, campfire, bonfire, flame, burning object, candle
- Adding fire to props, hazards, or projectiles — torches, braziers, burning wreckage, a fireball or flame jet
Install
summer setup installs every skill for your agent. To add only this one:
claude-code for your agent, such as codex or cursor. See Skills for every option.
The skill
Fire in games is almost never a video clip and never an AI-generated sprite. It’s a pile of additive billboard quads emitted from a cone, each running a noise-distorted UV through a hot color ramp (red → orange → yellow → smoky alpha-out). Think Skyrim torches, Doom Eternal’s pyre, BotW’s bonfires — all built from this same recipe with different dials. This skill writes the shader, the controller, and the node tree, then wires them into the open scene. Authoring, not generating.When to use
- “Add fire to this torch.”
- “Make a campfire / bonfire / hearth flame.”
- “Light the brazier.”
- “I need a candle flame on this candlestick.”
- “The dragon needs a flame breath” (use this for the persistent emitter; pair with a one-shot
vfx-muzzle-flashfor the burst). - The player set something on fire and you need a continuous, physically-anchored flame.
When NOT to use
- The user wants an object to burn away (mesh disintegrating with a fire edge) — route to
vfx-dissolve. Fire is a separate effect; pair them. - The user wants smoke without flame — go straight to
vfx-smoke. (Most fires want a smoke trail above; spawn this recipe and addvfx-smokeon top.) - The user wants a one-frame muzzle flash from a gun — that’s
vfx-muzzle-flash, not fire. - The user wants 2D fire on a UI element — use
canvas_itemshader; this recipe isspatial/particles. - The user wants stylized magic flame (blue, purple, ethereal) — use this recipe and load the
magic-firevariant in the cookbook below.
Recipe
1. Files to create
fire.gdshader #includes the FBM noise file. A missing include is a hard compile
error, so copy _building-blocks/noise-3d-fbm.gdshaderinc from this skill into
res://addons/vfx/_building-blocks/ before writing the shader.
2. Visual shader code
addons/vfx/fire/fire.gdshader:
3. Particle process shader (optional)
For most fires the built-inParticleProcessMaterial is fine. Drop in this custom shader only if you need turbulence beyond the standard params:
addons/vfx/fire/fire_process.gdshader:
4. GDScript controller
addons/vfx/fire/fire_controller.gd:
5. Node tree
process_material and draw_pass_1 are resource properties on the one node, not
child nodes. surface_material_override belongs to MeshInstance3D and does not
apply here — a draw pass mesh carries its material in Mesh.material.
Add an OmniLight3D as a sibling (parented to the same anchor as the GPUParticles3D, NOT under it) for proper light cast. Recommended: light_color = Color(1.0, 0.6, 0.25), light_energy = 1.6, omni_range = 6.0. Pulse it lightly via the controller for free atmosphere.
6. Wire it in
Write the three files, then wire everything in ONEsummer_run_script call with
an explicit scenePath — transactional (rollback on a mid-script error), no
.tres sidecar files needed because the script builds the resources directly:
ParticleProcessMaterial is a Material, not a Node: the script assigns it to
process_material, it is never a child. ctx.add_node sets owners for you. Take
a summer_world_snapshot before, and verify after with summer_snapshot_diff
(exactly Fire + FireLight added) plus a summer_screenshot — flames are
pixels, judge them as pixels.
6a. Verify
Every file this recipe writes is compiled code. Check it before claiming the fire works.noise-3d-fbm.gdshaderinc and an un-copied shader both show up as compile
errors, not as an invisible flame. Read the errors before tuning any dial.
7. Parameters to tune
Cookbook — named variants
torch-flame (default)
Wall-mounted torch, ~1 m flame.bonfire
Wide, tall, hungry. Pair withvfx-smoke directly above.
candle-flame
Tiny, calm, mostly motionless. Lifetime small so it shimmers in place.magic-fire (blue / arcane)
Cool flame. Same dynamics, recolor the ramp.Anti-patterns
- Spatial-only shader on the visual quad. It still works, but you forgot
blend_add+unshadedand the flame looks like a flat orange triangle in shadow. Always:render_mode unshaded, blend_add, depth_draw_never;. - Looping a one-shot emitter.
one_shot = falsefor fire (continuous). One-shot is forvfx-muzzle-flashandvfx-hit-spark. - Missing
cull_disabled. Particles billboard toward camera; if you cull backfaces, the flame disappears at certain angles. depth_draw_opaqueon the visual material. You’ll z-fight with anything inside the flame (the torch handle). Usedepth_draw_never.- OmniLight3D parented under the GPUParticles3D. The particles emit in local space; the light moves with them. Sibling, not child.
- Procedural noise computed in world space without a per-instance seed. Every particle pulses identically, looking like a strobe. The included shader hashes
INSTANCE_IDinto a per-particle seed invertex()and passes it tofragment()via a varying. - Reading
CUSTOMinfragment(). In aspatialshaderCUSTOMdoes not exist at all (“SHADER ERROR: Unknown identifier in expression: ‘CUSTOM’”). The particle built-in isINSTANCE_CUSTOM, it is vertex-stage only, andINSTANCE_CUSTOM.xis the rotation angle — the age is in.y. - Hand-rolling the billboard as
VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0..2], MODEL_MATRIX[3]). That form discards per-particle scale and rotation, soflame_radius’s per-particle scale never reaches the screen. Use the full block in section 2. - Generating a fire image and using it as the particle texture. That’s the misroute this skill exists to prevent. The shader-driven look is more alive and trivially recolorable.
Performance notes
- Default 96 particles per fire is sub-millisecond on a desktop GPU and scales linearly with count. That is an order-of-magnitude expectation, not a measurement — profile your own scene before budgeting. Budget ~512 fire particles total in a scene before you should think about LOD.
- Mobile: drop default to 48, disable the
OmniLight3Dshadow cast, and use a 64×64 noise texture instead of FBM if FPS dips. - LOD: in the controller’s
_process, scaleamount_ratiobyclamp(1.0 - dist_to_camera / 30.0, 0.05, 1.0). Past 30 m, drop to a single billboard quad with the same shader (no particles). - The OmniLight3D shadow is the expensive part. Disable shadows on torches that aren’t doing dramatic work.
blend_addskips the depth write — good for perf, but means you can’t sort fires against each other. Avoid stacking 5 flames at the same Z.
Edge cases
- Underwater fire. Don’t. If the user insists (a magic underwater shrine), drop
flame_heightto 0.4,noise_speedto 0.3, and tint everything blue-green via the color ramp. - Wind affecting the flame. The simple
process_materialdoesn’t know about wind. Either drivepm.gravity = Vector3(wind.x, 0.6, wind.z)from a script polling a wind vector, or use thefire_process.gdshaderand pass a wind uniform. - Fire on a moving object (torch held by NPC). Set
local_coords = trueso particles emit in the torch’s local space. Otherwise they trail behind as the NPC walks. - Fire viewed in mirror / reflection probe. The flame won’t appear in baked reflections (it’s transparent). Add a fake glow card (MeshInstance3D with an emissive material) for reflections to pick up.
- Cinematic close-up of the flame. Default 96 particles looks sparse at 1080p. Bump to 256 for cinematics, drop back for gameplay.
Fallback (no MCP)
Section 6 is fully automatable —summer_write_file writes the shaders and the
controller, summer_create_scene + summer_add_node + summer_set_prop +
summer_save_scene build and save fire.tscn. Do not hand these steps to the user
when the MCP tools are available.
Without the MCP connection there is no engine to drive, so the user does it
manually in Summer Engine:
- Create the files at
addons/vfx/_building-blocks/andaddons/vfx/fire/with the contents above. - Add a
GPUParticles3Dnode, attachfire_controller.gd. - Set
process_materialto a newParticleProcessMaterial(the script configures it on_ready). - Set
draw_pass_1to a newQuadMesh(size 1×1), with the mesh’smaterialset to aShaderMaterialwhose shader isfire.gdshader. - Save as
fire.tscnand instantiate at every torch / brazier. - Check the Errors dock — a missing
.gdshaderincfails the whole shader.
Handoff
After firing this recipe, suggest neighbors:vfx-smoke— every fire that lasts > 5 s wants smoke rising above. Spawn 0.5 m above the flame top.vfx-dissolve— if the user wants the fuel (logs, body, paper) to gradually disappear as it burns.vfx-magic-glow— for anOmniLight3Dwith proper sin-wave pulsing if the default is too constant.game-feel— for a slight camera flicker / thermal heat-haze post-process near very large fires.sound-effect— generatefire crackle, dry wood, soft pops, 2s loopand wire to anAudioStreamPlayer3Don the same anchor.
See also
_building-blocks/noise-3d-fbm.gdshaderinc— the FBM noise this shader includes_building-blocks/additive-billboard-particles.md— canonical additive material settingsvfx-smoke— sister recipe for the column rising abovevfx-dissolve— for objects burning awayvfx-magic-glow— for the light source pulsinggame-feel— non-particle game-feel pairingsgdscript-patterns— for the controller’s idioms (signals, exports,@tool)
From a shell
No Summer MCP tools in this session? Run each one as a command; whensummer --version is missing or below 4.0, use npx -y summer-engine@latest in place of summer. Fields are flags in kebab-case (--scene-path res://main.tscn) or one --input '<json>', and summer ops describe <op> prints the exact input. The summer-cli skill has the rest.
Files in this skill
Related skills
scene-scripting: Build scenes, levels, HUDs and wiring with one editor GDScript (summer_run_script) instead of call chains.sound-effect: Make sound effects (swings, hits, whooshes, reloads, UI): three versions to pick from, then wire them.game-feel: Add juice: hit-flash, trauma camera shake and audio ducking, one hit fires all three.vfx-dissolve: Dissolve effect: a mesh burns away with a glowing edge, from a noise-threshold ShaderMaterial.vfx-hit-spark: Hit-spark effect: a one-shot burst of additive particles oriented to the surface, fired on impact.vfx-magic-glow: Magic-glow effect: a pulsing OmniLight3D, drifting additive motes and an optional emission shader.vfx-muzzle-flash: Muzzle-flash effect: a one-shot ~80 ms burst at a gun barrel, from particles or a star-burst quad.vfx-smoke: Smoke effect: a rising column or puff of soft particles with a noise and density falloff shader.
Source:
library/skills/vfx-fire/SKILL.md, rendered from summer-engine@4.3.0 on npm.
