An effect bank is a named visual effect — an explosion, an engine trail, a shield
impact, a burning hull. Each is built from one or more renderer layers, and
can fire a sound bank alongside them.
Banks live in World/effect-banks.xml and are edited in Hydra's
Effect editor. They are id‑keyed and module‑layered like every other
resource.
Layers make an effect
A hull detonation is not one thing. It is a fireball, a flash, debris and a light, fired
together off one clock:
<effect-bank id="Explosion" category="death" instances="8">
<description>Standard hull detonation: what a DESTROYED object throws</description>
<alias>Object</alias>
<sound bank="Explosion" />
<layer renderer="fireball" />
<layer renderer="flash" />
<layer renderer="debris" />
<layer renderer="light" curve="blast" intensity="6" />
</effect-bank>
Every layer of one effect derives its time from a single clock, so the layers of one
explosion cannot drift apart from each other.
Compare that with a glancing hit, which is deliberately one layer and no fireball:
<effect-bank id="Impact Sparks" category="weapon" instances="12">
<layer renderer="sparks" space="world" rate="240" duration="120"
life="500" speed="26" spread="1" drag="6" color="#ffd08a" />
</effect-bank>
That contrast is most of effect authoring: what an effect leaves out is what makes it read
as a different event.
The renderers
Each layer names a renderer. The base game provides thirteen:
| Renderer | Draws |
fireball | An expanding burning ball. The core of a detonation. |
flash | A brief bright pop. |
debris | Thrown fragments. |
ring | An expanding shockwave ring. |
light | A real light that illuminates nearby geometry. |
sparks | Short‑lived hot particles. |
smoke | Rising, drifting volume. |
sprite | A single textured billboard that can grow, spin and fade. |
trail | A ribbon following a moving source. |
beam | A line between two points. |
blast, blast-classic | Particle bursts. |
wormhole | A lensed throat onto another sky. |
Bank attributes
| Attribute | Meaning |
id | How content references it. |
category | Grouping — weapon, death, damage, defense, light, trail, environment. |
instances | How many can run at once. Same reasoning as sound banks: shield hits want 16, a wormhole wants 2. |
persistent | The effect continues until told to stop, rather than playing once. Engine trails and hull fires are persistent; explosions are not. |
tier | Quality tier, for scaling detail down on weaker hardware. |
<alias> | Alternate names. As with sound banks, this is how legacy references (Object, Missile, Shield) still resolve. |
<sound bank="..."> | A sound bank to fire with the visual. |
The wrapper carries master-scale and clip-radius — overall
size calibration and the distance beyond which effects are not drawn.
The architectural point: the server does not understand a layer
This is the thing worth knowing, because it changes what you can do without touching the
engine.
Of everything on a <layer>, the server reads only
renderer and tier. Every other attribute is carried as opaque
key/value and forwarded to the client verbatim — as strings, unparsed.
So adding a new kind of effect is a client file plus data, with no engine
rebuild. There is no server‑side schema to extend and no C# to write.
Writing your own renderer
A renderer is a JavaScript module at /js/effects/<name>.js. Module
Html folders overlay one virtual web root by priority, so a module dropping
Html/js/effects/plasma-arc.js is served and imported exactly like a built‑in
one — and <layer renderer="plasma-arc" /> then works.
The default export is a class extending Mythrical, from
effect-kit.js:
constructor(ctx) // build; add everything to this.Group
Update(elapsed) // ms since last frame, slow-mo aware;
// call this.Dispose() when the effect is over
Stop() // optional: a persistent effect asked to end gracefully
Dispose() // release GPU resources; detach this.Group
ctx carries the layer's authored attributes in params, live game
state in bindings, the scene, what the effect is attached to
(source, null for a world‑anchored effect), the trigger
position and radius, and life — the one clock every
layer of the effect shares.
Params arrive as strings, because the server never parses them. Fold them
with the kit's FxNum and FxBool rather than parseFloat
alone: those refuse to poison a uniform with NaN, and FxBool handles the
"false" case, which is truthy as a bare string.
Use effect-kit.js rather than reimplementing its pieces. It exists because
writing a good renderer previously meant copying engine shader source — and the worst thing
to go without is the log‑depth handling, whose failure mode is not a warning: fragments
depth‑test in the wrong space and the effect hides behind the world, which presents as
"my effect does not draw".
Load textures through the kit's cached loader. Each renderer building its own loader leaked
a GPU texture per instance, so every projectile impact cost one.
Declare a static Manifest = { name, description, params, targets } and the
Effect editor can offer your renderer and edit its parameters. A renderer without one still
runs; the editor just flags it as not param‑editable.
Two things that will catch you
The file is generated, and comments do not survive a save.
effect-banks.xml round‑trips through the Effect editor, so any XML comment you
add is lost the next time it is saved. Per‑bank notes go in
<description>, which does round‑trip.
Offset is per‑layer and sits within the effect. A layer's
offset positions it relative to the effect; positioning the effect as a whole is
done by whatever placed it — a vessel class, a placement, or a mission action. Hull fires
are the example: each layer is offset to a point on the hull, and the effect rides the ship
because it is in the local frame.
Practical advice
- Build up from one layer. Add layers until it reads, then stop. The
one‑layer spark shower is as deliberate as the five‑layer detonation.
- Add a light to anything that should feel bright. A fireball with no
light layer does not touch the ships around it, and that is most of why an
explosion can look flat.
- Set
instances honestly. Shield hits happen in volleys.
- Mark continuous effects
persistent, or they will play once
and vanish.
- Use
description. It survives, and it is the only note that
does.