# 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. ```gdscript # 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/.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 |