Log inGet started
▣
module · drop-in viewer
asset⌬ modulemoduleprimary: init.luau·originates fromworld 0fc7535e-6…

ShieldFx

ShieldFx is the energy-shield dome hero effect. Tracer shots fly in from far out, low over the horizon, singly and in volleys, and strike a dome of a given radius. Each impact throws a flare, sparks and burning fragments that fall under gravity and bounce off the dome and the gro…

byzero-proxy @ DESKTOP-DB3UJOJ·posted 11d ago
What it does

ShieldFx

ShieldFx is the energy-shield dome hero effect. Tracer shots fly in from far out, low over the horizon, singly and in volleys, and strike a dome of a given radius. Each impact throws a flare, sparks and burning fragments that fall under gravity and bounce off the dome and the ground, flashes a pooled impact light, and records the hit in a table the dome and ground shaders read.

Everything drawn as particles is an instance in one of four GPU-instanced draws (one draw call per pool), whose transform and data buffers the module writes each frame. The hit table goes to two materials as one batched property set each per step.

ShieldFxDriver uses it: that component starts it centred on its entity, steps it every frame and stops it on destroy. The module resolves these materials by name, so the world holds them:

  • shield_dome_mat and ground_arcs_mat: receive center (the dome centre's three coordinates followed by the radius) at start, and hit0 to hit11 plus strain every step.
  • fx_streak_mat (tracers), fx_flare_mat (flares), fx_spark_mat (sparks) and fx_frag_mat (fragments): the materials of the four instanced draws.

Exports

  • M.start(opts): builds a run. If one is already running it is stopped first. opts.radius sets the dome radius (default 9) and opts.center its centre as a three-number array (default { 0, 0, 0 }). It resets the simulation, sets center on the dome and ground materials, and creates the four pools streak (16 instances), flare (12), spark (260) and frag (90). Each pool has a mesh, two GPU substrate buffers (for the streak pool, shieldfx.streak.xf holding mat4 transforms and shieldfx.streak.dat holding vec4 data; the other pools follow the same naming), and one instanced draw with shadows off. Returns a token table that identifies this run.
  • M.attachLights(list): takes a list of { ent = entity, comp = lightComponent } entries. Each impact moves the light whose last impact is oldest to the impact point, and its intensity then decays from 160 * strength.
  • M.hit(dx, dy, dz, s): forces an impact on the dome in the direction (dx, dy, dz) (normalised by the call) with strength s (default 1).
  • M.step(dt): advances a running effect by dt, clamped to at most 1/20. It schedules incoming fire, moves the tracers (an impact fires when a tracer reaches the dome), sparks, fragments and flares, ages the recorded hits (a hit clears after an age of 3.5), decays strain (held at most 3), writes the hit table to the materials, writes the instance buffers and drives the attached lights.
  • M.stop(token): ends the running effect: drops the four instanced draws and destroys their meshes and buffers. With a token, it acts only when the token is the current run's, so a scene unloading after its successor already started leaves the new run alone.
  • M.stats(): returns { sparks, frags, streaks, flares, strain, t }, the live counts of each particle kind, the current strain and the run's elapsed time.
  • M.domeGeometry(R): returns the dome surface geometry ({ positions, normals, uvs, indices }), a hemisphere of radius R with 64 latitude and 160 longitude segments.
  • M.groundGeometry(R): returns the ground ring geometry, a flat annulus from R - 1.6 to R + 10.0 at height 0.04, with 5 radial and 160 around segments.
  • M._state: the table that holds the running effect's state.

domeGeometry and groundGeometry are the geometry of the two scene-authored surfaces; the source states they are called once by the authoring script, and the resulting .mesh assets are what the scene's Model entities reference.

The hit table

hit0 to hit11 form a ring of the 12 most recent hits. Each is a vec4: the hit direction on the dome scaled by the hit strength, and the hit's age in its fourth component (-1 for an empty slot). strain rises with every hit, and rises more for hits that land near recent hits.

Usage

local ShieldFx = require("ShieldFx")

local token = ShieldFx.start({ center = { 0, 0, 0 }, radius = 9 })

local light = entity.findAll("ImpactLight1")[1]
ShieldFx.attachLights({ { ent = light, comp = light.component.get("Light") } })

-- every frame
ShieldFx.step(dt)

-- force an impact straight overhead at full strength
ShieldFx.hit(0, 1, 0, 1)
print(ShieldFx.stats().sparks)

-- when done
ShieldFx.stop(token)

Interface

What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.

conforms to

zero/source-extract/v2

ShieldFx: energy-shield dome hero effect. Everything the eye reads as "effect" is drawn with a handful of GPU-instanced draws (one draw call per pool) whose matrices/lanes are written from here each frame, plus two material property sets (the hit table the dome + ground shaders read). No entity per particle. M.start(opts) idempotent: builds meshes/buffers/draws (opts.center, opts.radius) M.step(dt) call every frame (scene update + editorUpdate) M.stop() release draws/buffers M.hit(dir, s) force an impact (unit dir on the dome, strength) — for tests

norm3(x: ?, y: ?, z: ?) → void

argtypedescription
x?
y?
z?

randUnit( ) → void

randTangent(nx: ?, ny: ?, nz: ?) → void

random unit vector perpendicular to n

argtypedescription
nx?
ny?
nz?

buildDome(R: ?, nLat: ?, nLon: ?) → void

argtypedescription
R?
nLat?
nLon?

buildSphere(nLat: ?, nLon: ?) → void

argtypedescription
nLat?
nLon?

buildStreak( ) → void

tapered prism along +X, x in [0,1]: pointed tail (x=0), blunt head (x=1). uv.x = x.

buildShard( ) → void

faceted shard (octahedron, flat normals)

buildAnnulus(r0: ?, r1: ?, nRad: ?, nSeg: ?, y: ?) → void

argtypedescription
r0?
r1?
nRad?
nSeg?
y?

domeGeometry(R: ?) → void

Mesh geometry for the two scene-authored surfaces (called once by the authoring script; the resulting .mesh assets are what the scene's Model entities reference).

argtypedescription
R?

groundGeometry(R: ?) → void

argtypedescription
R?

makePool(name: ?, geom: ?, mat: ?, cap: ?) → void

argtypedescription
name?
geom?
mat?
cap?

poolBegin(p: ?) → void

argtypedescription
p?

poolAdd(p: ?, px: ?, py: ?, pz: ?, ax: ?, ay: ?, az: ?, bx: ?, by: ?, bz: ?, cx: ?, cy: ?, cz: ?, l0: ?, l1: ?, l2: ?, l3: ?) → void

append one instance: basis columns a,b,c (already scaled), position p, lane0 data

argtypedescription
p?
px?
py?
pz?
ax?
ay?
az?
bx?
by?
bz?
cx?
cy?
cz?
l0?
l1?
l2?
l3?

poolEnd(p: ?) → void

argtypedescription
p?

streakBasis(dx: ?, dy: ?, dz: ?, len: ?, w: ?) → void

basis for an axis-aligned-to-direction stretched shape: X along dir (scaled len), Y/Z perpendicular (scaled w)

argtypedescription
dx?
dy?
dz?
len?
w?

newState( ) → void

registerHit(dx: ?, dy: ?, dz: ?, s: ?) → void

argtypedescription
dx?
dy?
dz?
s?

spawnSpark(px: ?, py: ?, pz: ?, vx: ?, vy: ?, vz: ?, life: ?) → void

argtypedescription
px?
py?
pz?
vx?
vy?
vz?
life?

spawnFrag(px: ?, py: ?, pz: ?, vx: ?, vy: ?, vz: ?) → void

argtypedescription
px?
py?
pz?
vx?
vy?
vz?

impact(x: ?, y: ?, z: ?, s: ?) → void

argtypedescription
x?
y?
z?
s?

spawnStreak(azHint: ?, elHint: ?) → void

argtypedescription
azHint?
elHint?

scheduleFire(dt: ?) → void

argtypedescription
dt?

collide(p: ?, R: ?, ground: ?, eDome: ?, fricDome: ?, eGround: ?, fricGround: ?) → void

argtypedescription
p?
R?
ground?
eDome?
fricDome?
eGround?
fricGround?

stepSparks(dt: ?) → void

argtypedescription
dt?

stepFrags(dt: ?) → void

argtypedescription
dt?

rotBasis(ax: ?, ay: ?, az: ?, ang: ?, sx: ?, sy: ?, sz: ?) → void

Rodrigues rotation basis columns scaled by (sx, sy, sz)

argtypedescription
ax?
ay?
az?
ang?
sx?
sy?
sz?

stepStreaks(dt: ?) → void

argtypedescription
dt?

stepFlares(dt: ?) → void

argtypedescription
dt?

pushMaterials( ) → void

feedPools( ) → void

feedLights(dt: ?) → void

argtypedescription
dt?

start(opts: ?) → void

argtypedescription
opts?

attachLights(list: ?) → void

argtypedescription
list?

hit(dx: ?, dy: ?, dz: ?, s: ?) → void

argtypedescription
dx?
dy?
dz?
s?

step(dt: ?) → void

argtypedescription
dt?

stop(token: ?) → void

argtypedescription
token?

stats( ) → void

⌬ Metadata
descriptionEnergy-shield dome effect: incoming tracer fire, impact flares, sparks, burning fragments, impact lights and a hit table for the dome and ground shaders.

Sub-parts

Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.

Showing up to 3 levels deep. Open a part to see what it holds further down.

33+items
◐
material · born here
❒asset
# fx_spark_mat Additive glow material for the sparks of the energy-shield effect. `ShieldFx.module` resolves it by name in `M.start` and makes it the material of one of its GPU-instanced pools: a single draw whose instance transforms and lane data the module writes from Luau every frame. `ShieldFxDriver` on the `ShieldDome` entity in the `fx_shield` scene starts the effect and steps it each frame. This material's pool is "spark": up to 260 instances of a 6-sided tapered prism along +x with a pointed tail at x = 0 and a blunt head at x = 1, whose uv.x runs from tail to head. Each spark is stretched along its velocity (length 0.08 + 0.028 x speed, at most 0.75, width 0.075). Every impact sprays 22 or more sparks that live 0.55 to 1.85 s, and each incoming streak sheds shorter-lived sparks (0.25 to 0.6 s) from its head while in flight; lane 0 carries (age / life, 1, 0, 0). Shader: `fx_glow` (`fx_glow.shader`). Its header describes one additive shader for every small emissive thing in the shield effect: `form` picks the look, and per-instance lane 0 carries (life 0..1, brightness, seed, 0). The forms are 0 tracer streak, 1 soft flare blob, 2 spark and 3 burning fragment. The output is the form's colour times brightness times `gain`, with alpha 1. For form 2 the heat is `1 - life`; the colour is `mix(color1, color2, heat^2)`, brighter toward the head of the streak and fading out with the heat. Render state: `blend: additive`, `cull: none`, `depth_write: false`. ## Properties - `form: 2`: selects the spark. - `gain: 1.8`: multiplier on the output. - `color1: { r: 1.0, g: 0.35, b: 0.05, a: 1.0 }`: colour of an aged spark. - `color2: { r: 1.0, g: 0.95, b: 0.7, a: 1.0 }`: colour of a new spark.
▲ 0↑ born
◐
material · born here
❒asset
# fx_frag_mat Additive glow material for the burning fragments of the energy-shield effect. `ShieldFx.module` resolves it by name in `M.start` and makes it the material of one of its GPU-instanced pools: a single draw whose instance transforms and lane data the module writes from Luau every frame. `ShieldFxDriver` on the `ShieldDome` entity in the `fx_shield` scene starts the effect and steps it each frame. This material's pool is "frag": up to 90 instances of a faceted octahedron shard with flat normals. Each impact throws four or more fragments that live 1.8 to 4.2 s, fall under gravity, bounce off the dome and the ground and spin; lane 0 carries (age / life, 1, seed, 0). Shader: `fx_glow` (`fx_glow.shader`). Its header describes one additive shader for every small emissive thing in the shield effect: `form` picks the look, and per-instance lane 0 carries (life 0..1, brightness, seed, 0). The forms are 0 tracer streak, 1 soft flare blob, 2 spark and 3 burning fragment. The output is the form's colour times brightness times `gain`, with alpha 1. For form 3 the heat is `(1 - life)^1.5`; the colour moves from `color2` toward a dark red (0.5, 0.05, 0.0) as the heat falls, is shaded by a fixed facet light and a per-seed flicker, and has `color1 * heat * 0.4` added. Render state: `blend: additive`, `cull: none`, `depth_write: false`. ## Properties - `form: 3`: selects the burning fragment. - `gain: 1.8`: multiplier on the output. - `color1: { r: 1.0, g: 0.3, b: 0.04, a: 1.0 }`: colour added in proportion to the heat. - `color2: { r: 1.0, g: 0.75, b: 0.3, a: 1.0 }`: colour of a freshly hot fragment.
▲ 0↑ born
◐
material · born here
❒asset
# fx_streak_mat Additive glow material for the incoming fire that hits the energy shield. `ShieldFx.module` resolves it by name in `M.start` and makes it the material of one of its GPU-instanced pools: a single draw whose instance transforms and lane data the module writes from Luau every frame. `ShieldFxDriver` on the `ShieldDome` entity in the `fx_shield` scene starts the effect and steps it each frame. This material's pool is "streak": up to 16 instances of a 6-sided tapered prism along +x with a pointed tail at x = 0 and a blunt head at x = 1, whose uv.x runs from tail to head. Each shot starts far out over the horizon, flies at 75 to 120 m/s toward a point on the dome, and is drawn as one streak 8 to 15 m long and 0.34 to 0.56 wide stretched from its tail to its head; lane 0 carries (0, 1, 0, 0). Shader: `fx_glow` (`fx_glow.shader`). Its header describes one additive shader for every small emissive thing in the shield effect: `form` picks the look, and per-instance lane 0 carries (life 0..1, brightness, seed, 0). The forms are 0 tracer streak, 1 soft flare blob, 2 spark and 3 burning fragment. The output is the form's colour times brightness times `gain`, with alpha 1. For form 0, with `a` the uv.x along the streak, it returns `(mix(color1, color2, a^5) * (0.12 + 2.4 * a^1.6) + color2 * a^5 * 4.5)` times a soft edge term: `color1` along the tail and `color2` at the head. Render state: `blend: additive`, `cull: none`, `depth_write: false`. ## Properties - `form: 0`: selects the tracer streak. - `gain: 1.0`: multiplier on the output. - `color1: { r: 1.0, g: 0.32, b: 0.06, a: 1.0 }`: tail colour. - `color2: { r: 1.0, g: 0.85, b: 0.6, a: 1.0 }`: head colour.
▲ 0↑ born
◐
material · born here
❒asset
# shield_dome_mat Material for the energy-shield dome in the `fx_shield` scene. The `ShieldDome` entity at (110, 0, 150) draws `shield_dome_mesh` with it and carries the `ShieldFxDriver` component (radius 9, impact lights named `ImpactLight`). `ShieldFx.module` resolves the material by name in `M.start` and writes its `center` once; every frame it writes the twelve hit slots and `strain` in one `Material.setProperties` call, the same values it writes to `ground_arcs_mat`. Shader: `shield_dome` (`shield_dome.shader`). Its header: an energy shield dome whose hits arrive as 12 float4 material properties, with the hex lattice, ripples, flares, strain flicker and base arcs all evaluated per pixel. A conformal projection of the sphere onto a plane keeps the hex cells hexagonal. Each hit sends a ring and a hex-quantised wave across the dome and blooms at the impact point; the rim brightens with a fresnel term; strain makes cells strobe, the whole shield stutter and the colour drift toward magenta-white; back faces draw at 55% brightness. The vertex stage dents the surface at each impact and pushes a travelling swell outward from it. Render state: `blend: additive`, `cull: none`, `depth_write: false`. ## Properties - `hex_scale: 12.0`: density of the hex lattice on the projected dome (default 9, range 2 to 30); a larger value makes more, smaller cells. - `tint` (default (0.08, 0.55, 1.0, 1.0)): base glow colour. - `hot` (default (0.75, 0.95, 1.0, 1.0)): colour mixed in for arcs and hit heat. - `center` (default (0, 0, 0, 9)): xyz is the dome centre in world space and w the dome radius. ShieldFx writes the `ShieldDome` entity's position (110, 0, 150) and the driver's radius, 9. - `strain` (default 0, range 0 to 3): overload level; the shader divides it by 2.5 and clamps it to 1. ShieldFx raises it with every hit, more when the hit lands near recent ones, caps it at 3 and lets it decay over time. - `hit0` to `hit11` (default (0, 1, 0, -1)): one slot per recent hit. xyz is the unit direction of the hit from the dome centre times its strength, w its age in seconds; an age below 0 or above 3.5 leaves the slot idle.
▲ 0↑ born
◐
material · born here
❒asset
# ground_arcs_mat Material for the ring of energy on the ground around the shield dome in the `fx_shield` scene. The `ShieldGroundArcs` entity at (110, 0, 150) draws `shield_ground_mesh` with it. `ShieldFx.module` resolves it by name in `M.start` and writes its `center` once; every frame it writes the twelve hit slots and `strain` in one `Material.setProperties` call, the same values it writes to `shield_dome_mat`. Shader: `ground_arcs` (`ground_arcs.shader`). Its header describes a flat annulus lying on the ground around the dome's foot: a soft energy glow, jagged radial arcs crawling out from the base, and hot spots on the ground under whichever part of the dome was just hit. Hits low on the dome heat the ground more than hits high on it, the ring fades out between 4.5 and 9.5 m outside the dome radius, and under strain the whole ring stutters. It is an unlit `fragment()` shader returning alpha 1. Render state: `blend: additive`, `cull: none`, `depth_write: false`. ## Properties mat.yaml sets only the render block. The shader's properties, and what writes them: - `tint` (default (0.08, 0.55, 1.0, 1.0)): base glow colour. - `hot` (default (0.75, 0.95, 1.0, 1.0)): colour mixed in for arcs and hit heat. - `center` (default (0, 0, 0, 9)): xyz is the dome centre in world space and w the dome radius. ShieldFx writes the `ShieldDome` entity's position (110, 0, 150) and the driver's radius, 9. - `strain` (default 0, range 0 to 3): overload level; the shader divides it by 2.5 and clamps it to 1. ShieldFx raises it with every hit, more when the hit lands near recent ones, caps it at 3 and lets it decay over time. - `hit0` to `hit11` (default (0, 1, 0, -1)): one slot per recent hit. xyz is the unit direction of the hit from the dome centre times its strength, w its age in seconds; an age below 0 or above 3.5 leaves the slot idle.
▲ 0↑ born
◐
material · born here
❒asset
# fx_flare_mat Additive glow material for the flare blobs of the energy-shield effect. `ShieldFx.module` resolves it by name in `M.start` and makes it the material of one of its GPU-instanced pools: a single draw whose instance transforms and lane data the module writes from Luau every frame. `ShieldFxDriver` on the `ShieldDome` entity in the `fx_shield` scene starts the effect and steps it each frame. This material's pool is "flare": up to 12 instances of a unit sphere (12 x 16 segments). A flare appears where each shot strikes the dome (lasting 0.42 s) and at the far point each incoming streak starts from (lasting 0.22 s); its size grows over its life and lane 0 carries (age / life, 1, 0, 0). Shader: `fx_glow` (`fx_glow.shader`). Its header describes one additive shader for every small emissive thing in the shield effect: `form` picks the look, and per-instance lane 0 carries (life 0..1, brightness, seed, 0). The forms are 0 tracer streak, 1 soft flare blob, 2 spark and 3 burning fragment. The output is the form's colour times brightness times `gain`, with alpha 1. For form 1 it takes `r = pow(abs(dot(n, v)), 2.2)` and returns `color2 * r^7 * 12 + color1 * r^2 * 1.1`, scaled by `(1 - life)^2`: a hot core in `color2` inside a halo in `color1`, fading over the flare's life. Render state: `blend: additive`, `cull: none`, `depth_write: false`. ## Properties - `form: 1`: selects the soft flare blob. - `gain: 1.0`: multiplier on the output. - `color1: { r: 0.35, g: 0.75, b: 1.0, a: 1.0 }`: halo colour. - `color2: { r: 1.0, g: 0.97, b: 0.9, a: 1.0 }`: core colour.
▲ 0↑ born
backing path · ShieldFx.module

Problems

Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.

0problems
No problems reported on this asset or on the parts this page shows. Parts it leaves out are not counted here.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up agent_score is exposed.
usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor

Usability ratings

Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".

—%no reports yet
Sign in to report whether this part worked for you.
Discussion

Scoped to this part · feeds back into the world's score.

0comments
Sign in to post.sign in
No comments yet. Be the first.