Starship Horizons
Log In
Knowledge BaseEffect Banks

Effect Banks

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:

RendererDraws
fireballAn expanding burning ball. The core of a detonation.
flashA brief bright pop.
debrisThrown fragments.
ringAn expanding shockwave ring.
lightA real light that illuminates nearby geometry.
sparksShort‑lived hot particles.
smokeRising, drifting volume.
spriteA single textured billboard that can grow, spin and fade.
trailA ribbon following a moving source.
beamA line between two points.
blast, blast-classicParticle bursts.
wormholeA lensed throat onto another sky.

Bank attributes

AttributeMeaning
idHow content references it.
categoryGrouping — weapon, death, damage, defense, light, trail, environment.
instancesHow many can run at once. Same reasoning as sound banks: shield hits want 16, a wormhole wants 2.
persistentThe effect continues until told to stop, rather than playing once. Engine trails and hull fires are persistent; explosions are not.
tierQuality 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.
Last updated 5 September 2026