Files
Bullosseum/systems/fx
richard a4d18e4928
CI / Decide whether to run (push) Has been cancelled
CI / Lint & headless tests (push) Has been cancelled
Move bull ability FX into the authorable systems/fx/ library
The bull's kick/dash/slam/roll and movement particles were ~112 lines of
hand-built CPUParticles3D in player.gd, bypassing the Fx system entirely
(Fx.spawn had zero callers) — so Siim couldn't author them in the inspector.

- Add six inspector-editable effect scenes (bull_slam/kick/dash one-shots +
  bull_hoof_dust/charge_trail/roll_sparks continuous); wire player.gd to
  Fx.spawn() / new Fx.attach(); register them + the gallery + smoke test.
- Extract the coded, non-particle slam rings + kick flash into a new
  bull_impact_fx.gd component (bull_legs.gd pattern).
- Drop 12 now-obsolete DP dust look-params (the .tscn owns the look now).
- Trim god-file comment noise: rewrite an AI-placeholder barrel block to typed
  code, drop dead commented-out bounce/topple code, fix stale post-reorg file
  paths (Assets/… → art/…, PascalCase scene names → snake_case).
- Document the Siim workflow in systems/fx/README.md; update CLAUDE.md.

player.gd 1307 → 944 lines. Full suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCyaJPTHCH9EDthpf4A5Sj
2026-09-08 14:35:25 +03:00
..

FX — the effect library

Gameplay code fires a named effect; the scene decides how it looks. That split is the whole point: a programmer writes Fx.spawn(&"blood_burst", hit_transform) once, and from then on every change to how a hit feels is a .tscn Siim edits in the inspector — no code, no recompile.

# anywhere in gameplay code
Fx.spawn(&"blood_burst", global_transform)          # one-shot: fire and forget (self-frees)
Fx.spawn(&"slam_dust", Transform3D(Basis(), point)) # at a world point
var trail := Fx.attach(&"bull_charge_trail", node)  # continuous: caller keeps it + toggles .emitting

Siim's workflow

  1. Open the gallery. Run fx/effect_gallery.tscn. It loops through every effect on a sand-lit stage with the effect's name on screen, so you see each one the way it reads in play.
  2. Pick an effect .tscn in fx/ (blood_burst, slam_dust, spark, hit_flash) and open it.
  3. Tune it in the inspector. Everything lives on the CPUParticles3D node and its material:
    • Colour → the node's Color Ramp (start colour → faded/transparent end).
    • Shape of the burst over time → Scale Amount Curve.
    • Amount / Lifetime / Explosiveness / Spread / Velocity / Gravity → the node's emission group.
    • The viewport previews particles live as you drag — no play needed.
  4. Save. That's the whole edit. Re-run the gallery to compare.

New effect? Add a fx/<name>.tscn (root = CPUParticles3D with one_shot_effect.gd attached — copy an existing one), then register its name → path in fx/fx.gd.

Bull ability effects

The bull's moves are wired to effect scenes here, so you can retune every one in the inspector — open the .tscn, drag its colour ramp / curves / emission, save. No code.

Ability Effect scene(s) Kind
Ground slam bull_slam.tscn (dust) one-shot burst
Back-kick bull_kick.tscn — dust + its stones and sparks child emitters one-shot burst
Dash / roll launch bull_dash.tscn one-shot burst
Hoof dust (walking / sprinting) bull_hoof_dust.tscn continuous
Charge trail (the blue streak) bull_charge_trail.tscn continuous
Roll sparks bull_roll_sparks.tscn continuous

Two kinds, edited the same way. One-shot effects fire once and clean themselves up — they show up in the gallery, so preview and tune them there. Continuous effects follow the bull and switch on and off with what it's doing (dust while moving, the trail during a roll); the gallery can't show those, so preview one by opening its .tscn and ticking Emitting on in the inspector's viewport.

Two things stay in code and aren't yours to tune here: the slam's expanding shockwave rings and the kick's white flash-pop — those are stretched flat meshes, not particles (actors/player/bull_impact_fx.gd). The dust's walk-vs-sprint size is also code (a fixed multiplier); its colour and shape are the .tscn.

Composite effect (like the kick): one scene, several CPUParticles3D — a root plus child emitters. one_shot_effect.gd fires every emitter in the scene together, so you can build a layered hit (dust + debris + sparks) as one file and tune each layer separately.

House style (keep effects reading as one game)

Palette — pull from these, don't invent per-effect colours:

Role Start End (fades to alpha 0)
Blood #FF0505 #400000
Dust #B89966 (tan) #8C7326
Ember #FFF299 → #FF8C1A transparent
Flash #FFFFFF transparent

Timing budgets — hits read best short: strike/flash effects ≤ 0.4 s, dust/settle ≤ 1.1 s. A one-shot effect frees itself lifetime + 0.5 s after spawn (one_shot_effect.gd), so keep lifetime honest.

PS1 look — materials are unshaded, alpha-blended, vertex-colour (colour comes from the ramp), cull disabled. Prefer few, chunky, low-poly billboarded quads over dense fine particles; the game runs the PS1 filter over everything, so subtlety is lost anyway.

Mobile — effects are CPUParticles3D, never GPUParticles3D. The web/GLES3/ANGLE target compiles particle shaders badly (see the notes in player.gd); CPU particles are just as tunable in the inspector and safe on-device. Keep this constraint when adding effects.

Files

File What it is
fx.gd The Fx autoload — spawn() (one-shot) / attach() (continuous); name→path registry
one_shot_effect.gd Root helper: fires every emitter in the scene once, frees it when done
blood_burst.tscn etc. The effects themselves — edit these
bull_*.tscn The bull's ability effects (see the table above) — edit these
effect_gallery.tscn Preview stage (run it to review)
_seed_placeholders.gd One-off generator that wrote the first-draft defaults; not used at runtime