Skip to main content
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:
Swap 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-flash for 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 add vfx-smoke on 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_item shader; this recipe is spatial/particles.
  • The user wants stylized magic flame (blue, purple, ethereal) — use this recipe and load the magic-fire variant 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-in ParticleProcessMaterial 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 ONE summer_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.
A missing 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 with vfx-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 + unshaded and 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 = false for fire (continuous). One-shot is for vfx-muzzle-flash and vfx-hit-spark.
  • Missing cull_disabled. Particles billboard toward camera; if you cull backfaces, the flame disappears at certain angles.
  • depth_draw_opaque on the visual material. You’ll z-fight with anything inside the flame (the torch handle). Use depth_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_ID into a per-particle seed in vertex() and passes it to fragment() via a varying.
  • Reading CUSTOM in fragment(). In a spatial shader CUSTOM does not exist at all (“SHADER ERROR: Unknown identifier in expression: ‘CUSTOM’”). The particle built-in is INSTANCE_CUSTOM, it is vertex-stage only, and INSTANCE_CUSTOM.x is 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, so flame_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 OmniLight3D shadow cast, and use a 64×64 noise texture instead of FBM if FPS dips.
  • LOD: in the controller’s _process, scale amount_ratio by clamp(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_add skips 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_height to 0.4, noise_speed to 0.3, and tint everything blue-green via the color ramp.
  • Wind affecting the flame. The simple process_material doesn’t know about wind. Either drive pm.gravity = Vector3(wind.x, 0.6, wind.z) from a script polling a wind vector, or use the fire_process.gdshader and pass a wind uniform.
  • Fire on a moving object (torch held by NPC). Set local_coords = true so 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:
  1. Create the files at addons/vfx/_building-blocks/ and addons/vfx/fire/ with the contents above.
  2. Add a GPUParticles3D node, attach fire_controller.gd.
  3. Set process_material to a new ParticleProcessMaterial (the script configures it on _ready).
  4. Set draw_pass_1 to a new QuadMesh (size 1×1), with the mesh’s material set to a ShaderMaterial whose shader is fire.gdshader.
  5. Save as fire.tscn and instantiate at every torch / brazier.
  6. Check the Errors dock — a missing .gdshaderinc fails 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 an OmniLight3D with 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 — generate fire crackle, dry wood, soft pops, 2s loop and wire to an AudioStreamPlayer3D on 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 settings
  • vfx-smoke — sister recipe for the column rising above
  • vfx-dissolve — for objects burning away
  • vfx-magic-glow — for the light source pulsing
  • game-feel — non-particle game-feel pairings
  • gdscript-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; when summer --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

  • 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.