Skip to main content
vfx-hit-spark 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. Hit-spark effect: a one-shot burst of additive particles oriented to the surface, fired on impact.

When your agent uses it

  • Authoring a hit-spark effect — impact spark, bullet hit, sword clash, ricochet, sparks at a hit point
  • Melee hits, bullet impacts, or ricochets have no visual feedback at the contact point

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

Tiny stretched additive billboards spraying outward from an impact point, oriented to the surface normal so the burst points the right way. Used for: bullets hitting metal, sword clashes, footsteps on stone, ricochets, lightning endpoints, hammer strikes. The recipe is a GPUParticles3D configured for one-shot bursts plus a spawn_hit_spark(position, normal) static helper that orients the emitter, restarts it, and frees after lifetime.

When to use

  • “Sparks when the bullet hits the wall.”
  • “Sword clash sparks.”
  • “Sparks under the hammer when the blacksmith works.”
  • “Footstep sparks on stone for the heavy armor.”
  • “Ricochet sparks when the projectile glances off.”
  • “Mining: sparks fly when pickaxe hits rock.”
  • Endpoint sparks on vfx-lightning and vfx-muzzle-flash recipes (they reference this).

When NOT to use

  • The user wants a flash at the impact, not a spray of particles — use vfx-muzzle-flash (recolor it).
  • The user wants debris chunks (rock pieces, splinters) — those are physics objects, not particles. Spawn RigidBody3D shards, then sparks on top.
  • The user wants water droplets at a water impact — recolor this recipe blue/white (it works) or pair with vfx-water-ripple for the ring on the surface.
  • The user wants persistent burning sparks that linger and cool down — that’s a hybrid; use this for the burst, then tiny vfx-fire particles for residual embers.

Recipe

1. Files to create

No custom shader — uses the canonical additive billboard material (see _building-blocks/additive-billboard-particles.md). A StandardMaterial3D with the right flags is enough. (BaseMaterial3D is abstract: BaseMaterial3D.new() is a parse error. Its enum constants are still the right names to use.)

2. GDScript controller

addons/vfx/hit-spark/hit_spark.gd:

3. Node tree

The script builds material and process material on _ready if missing, so the .tscn can be empty besides the script.

4. Wire it in (MCP calls)

This recipe is a .tscn you instantiate per impact, not added once to the open scene. Building that .tscn is itself an MCP job — summer_create_scene makes it, summer_set_prop attaches the script, summer_save_scene writes it out. Every scene-mutating call takes an explicit scenePath, and summer_set_prop uses key (not property).
Note on the script lane: summer_run_script operates on the open scene, and this recipe builds a standalone hit_spark.tscn — so the summer_create_scene / summer_replace_node chain above stays the right wiring here. Reach for scene-scripting only if you are placing many pre-spawned spark emitters into the open scene with computed positions.

4b. Verify

hit_spark.gd is the whole recipe — if it did not parse, every spawn_hit_spark call is a no-op.
Then from any impact handler:

5. Parameters to tune

Cookbook — named variants

bullet-on-metal (default)

Bright orange, fast, gravity arcs them downward.

sword-clash

Wide spray, brief, white-hot.

water-droplet

No emission boost, blue-white, gravity-heavy, round dots.

blood-spurt

Recolor + heavy gravity. Pair with a small decal on the floor where they land.

electric-discharge (paired with lightning endpoints)

Cool blue, low gravity (sparks float briefly), high emission.

Anti-patterns

  • Forgetting one_shot = true. Continuous-emission sparks look like a sparkler held still. One-shot + restart pattern is mandatory.
  • explosiveness < 1.0 for a one-shot. Particles spawn over the lifetime instead of in frame 1; the burst looks dribbly. Set explosiveness = 1.0.
  • Skipping the surface-normal orientation. Sparks always shoot upward regardless of impact direction. The spawn_hit_spark helper handles look_at + the −90° rotate-around-X (because look_at uses −Z as forward).
  • Spawning the spark scene as a child of the impacted object. If the object moves or frees, the sparks vanish. Spawn under the scene tree root.
  • BLEND_MODE_MIX instead of BLEND_MODE_ADD. Sparks don’t bloom; they look like flat orange triangles.
  • BaseMaterial3D.new(). BaseMaterial3D is abstract — that line is a parse error and takes the whole script down. Instantiate StandardMaterial3D; keep using the BaseMaterial3D.* enum constants.
  • Forgetting to free. The spawn_hit_spark helper creates a Timer-equivalent via get_tree().create_timer to free after lifetime. Otherwise spent emitters accumulate forever.
  • spark_lifetime > 1.0 for sharp impacts. Sparks lingering for a full second look like fairy dust. Keep ≤ 0.5 s for snappy hits.

Performance notes

  • One burst: 24 particles × 0.35 s = ~negligible. Spawning 60 bursts/sec (full-auto fire) = ~1500 live particles. Still well under the GPU budget.
  • For sustained automatic fire, pool the spark instances instead of instantiating per shot. Pre-create 16 spark scenes; round-robin them.
  • The look_at + rotate_object_local pair is the most expensive part of the spawn (one matrix decompose). If you spawn 100/frame, cache the orientation math.
  • Mobile: drop spark_count to 12, spark_lifetime to 0.20.

Edge cases

  • Surface normal points exactly UP. look_at with up = UP fails. The _safe_up helper picks RIGHT in that case.
  • Surface normal is zero (interior trigger volume hit). The function defaults to Vector3.UP if normal.length_squared() < 0.0001.
  • Impact inside a tight space (corner). Sparks penetrate walls visually. Either accept it (additive bloom hides it well) or use a Decal for the burn mark and skip particles.
  • First-person view, sparks from your own gun’s barrel hit. Use a smaller burst (intensity 0.4) so the camera isn’t flooded.
  • Networked multiplayer. Spawn sparks client-side based on hit events; never replicate the spark node itself (waste of bandwidth).
  • Slow-motion. Sparks freeze gracefully because Engine.time_scale slows the particle simulation. No special handling needed.

Fallback (no MCP)

Section 4 is fully automatable — summer_write_file writes the controller and summer_create_scene + summer_set_prop + summer_save_scene build hit_spark.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 addons/vfx/hit-spark/ with the two files above.
  2. Add a GPUParticles3D to a new scene, attach hit_spark.gd. Save as hit_spark.tscn.
  3. From any impact handler: HitSpark.spawn_hit_spark(get_tree().root, position, normal).
  4. Check the Errors dock before wiring the first impact.

Handoff

After firing this recipe, suggest:
  • vfx-muzzle-flash — pair on the gun side; this recipe handles the bullet-impact side.
  • vfx-lightning — automatically calls this at endpoints.
  • vfx-water-ripple — pair the water-droplet variant with a ripple ring at the impact for water surfaces.
  • game-feel — CameraShake.add_trauma(0.15) on heavy hits, hit-stop for crit kills.
  • sound-effect — generate metal-on-metal clang, sharp transient, short ring, 350ms per spark variant.

See also

  • _building-blocks/additive-billboard-particles.md — canonical additive material settings (this recipe uses them)
  • vfx-muzzle-flash — the gun-end companion
  • vfx-lightning — caller; spawns sparks at bolt endpoints
  • vfx-water-ripple — surface companion for water impacts
  • game-feel — shake/hit-stop pairings

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-fire: Fire effect: animated flames from GPUParticles3D, a particle shader and a noise color ramp.
  • vfx-lightning: Lightning bolt effect: a jagged procedural path with a glow shader, end sparks and screen shake.
  • vfx-muzzle-flash: Muzzle-flash effect: a one-shot ~80 ms burst at a gun barrel, from particles or a star-burst quad.
  • vfx-water-ripple: Water-ripple effect: animated normal-distortion ripples on a water plane or Decal, set off by impacts.

Source: library/skills/vfx-hit-spark/SKILL.md, rendered from summer-engine@4.3.0 on npm.