Skip to content

ImageLabel

Every other type in the Particiliary renders into the 3D world or post-processes the rendered camera image. ImageLabel is different. It emits flat 2D particles into the GUI layer — the same overlay that draws your scoreboard, inventory, health bar, and any other interface element on top of the game world.

Useful for damage numbers floating up over an enemy, score popups, UI sparkles, “+1” notifications, achievement flashes, ammo-pickup animations — any moment in your interface that benefits from particle-style behaviour rather than a single tween.

The architectural model is unlike anything we’ve seen so far. Position is UDim2 (a Roblox UI coordinate, not a 3D CFrame). Motion is polar: a single emission angle plus a spread, in degrees. Velocity is in pixels per second, not studs. Particles parent into a ScreenGui, not into workspace or Lighting. The flipbook system has two sources — child Decal instances or a single spritesheet with grid coordinates.

A Roblox ImageLabel instance.

The plugin doesn’t care where the source ImageLabel is parented at authoring time — Studio’s Explorer, a ScreenGui in StarterGui, a BillboardGui somewhere in the workspace. Transform marks the ImageLabel as a Part-Icles emitter and stamps it with the emit-control attributes. At emit time, the duplicates parent to the EmitParent if set, or to a managed ScreenGui the plugin maintains automatically (covered below).

The first thing to understand is that ImageLabel particles don’t exist in 3D space at all. They live in the camera-relative GUI layer. Their Position is a UDim2 — Roblox’s standard UI coordinate type that combines a scale component (a fraction of the parent’s size, from 0 to 1) and an offset component (a fixed pixel value).

A Position of UDim2.fromScale(0.5, 0.5) (the default) places the particle in the centre of the parent — half the width across, half the height down. A Position of UDim2.fromOffset(100, 200) places it 100 pixels right and 200 pixels down from the parent’s top-left corner. Mixed values combine both: UDim2.new(0.5, 50, 0.5, -20) means “centre, plus 50 pixels right and 20 pixels up.”

Each particle starts at the source’s Position (you set this in the panel, or in Studio’s UI editor) and offsets in pixel space from there as motion accumulates. The Scale component never changes during a particle’s life; only the Offset does.

Workspace types use cartesian motion: a SpreadAngle cone, a Speed magnitude graph, motion vectors in 3D. ImageLabel uses polar motion: a single launch angle and a magnitude.

Two properties define the launch direction:

  • EmissionAngle — a single angle in degrees. is right (positive X). 90° is up (negative Y in GUI coordinates, where Y grows downward). 180° is left. 270° is down. This is the central direction every particle launches in.
  • SpreadAngle — a single number in degrees giving the random spread around the EmissionAngle. Each particle picks a random angle within EmissionAngle ± SpreadAngle/2. A SpreadAngle of 0 produces a tight beam; a SpreadAngle of 360 produces a fully omnidirectional burst.

The Speed graph is in pixels per second. A Speed of 100 moves a particle 100 pixels along its launch angle each second. A graph that ramps from 200 to 0 is a particle that launches fast and decelerates to a halt over its lifetime — useful for damage-number popups that “rise and slow.”

Acceleration is a Vector2 in pixels-per-second-squared, applied to both axes. A common pattern is (0, 200) for a “gravity-like fall” — every particle’s downward velocity grows by 200 pixels per second per second. Combined with an upward initial velocity, this produces an arc.

Drag works the same as on workspace types: an exponential decay applied to velocity each frame.

The full surface area, grouped by panel section.

Panel labelData attributeTypeDefaultWhat it does
ModeEmissionModeenumEmitEmit (per-emission clones) or Animate (singleton, looping)
LoopAnimateLoopbooleanfalseWhether Animate mode loops the cycle
EnabledEnabled (attribute)booleanfalseMaster on/off
RateRatenumber10Particles per second
LifetimeLifetimeNumberRange1Seconds each particle lives
RotationImgRotRangeNumberRange0Random initial rotation in degrees
RotationImgRotSpeedNumberSequence0Spin graph during life
Rotation ModeImgRotModeenumOverLifeWhether RotSpeed is per-life or per-second
Panel labelData attributeTypeDefaultWhat it does
ImageImagestring""Roblox asset ID for the texture
ImageColorImageColor3ColorSequencewhiteRGB tint over each particle’s life
TransparencyImageTransparencyNumberSequence0Image opacity over each particle’s life
BG ColorBackgroundColor3ColorSequencewhiteBackground colour graph (for non-transparent backgrounds)
BG TransparencyBackgroundTransparencyNumberSequence1Background opacity graph (default fully transparent)
ScaleTypeScaleTypeenumStretchHow the Image fits inside the particle’s Size — Stretch/Slice/Tile/Fit/Crop
ResampleModeResampleModeenumDefaultTexture filtering — Default (smooth) or Pixelated (nearest-neighbour)
Panel labelData attributeTypeDefaultWhat it does
PositionPositionUDim2(0.5, 0, 0.5, 0)Base spawn position — Scale + Offset per axis
SizeImgSizeUDim2(0, 100, 0, 100)Base particle size — pixels by default
SizeScaleSizeScaleX, SizeScaleYtwo NumberSequence1Per-axis size multipliers, animated over life
AnchorPointAnchorPointVector2(0.5, 0.5)Where on the particle the Position anchors (centre by default)
ZIndexZIndexnumber1Draw order within the parent ScreenGui
Panel labelData attributeTypeDefaultWhat it does
SpeedImgSpeedNumberSequence0Velocity magnitude graph, in pixels per second
EmissionAngleEmissionAnglenumber90Central launch angle in degrees (90° = up)
SpreadAngleImgSpreadAnglenumber0Random spread around EmissionAngle in degrees
AccelerationImgAccelerationVector2(0, 0)Constant 2D acceleration in pixels/sec²
DragImgDragnumber0Exponential velocity decay
Reverse MotionImgInvertMotionbooleanfalsePlays trajectory in reverse
Panel labelData attributeTypeDefaultWhat it does
SourceImgFlipbookSourceenumDecalsWhere frames come from — Decals folder or Spritesheet
PlayModeImgFlipbookModeenumLoopHow frames play — Loop, OneShot, PingPong, Random
GridGridCols, GridRowstwo number(8, 8)Spritesheet grid dimensions (only shown if Source = Spritesheet)
FramerateImgFlipbookFramerateNumberRange10Frames per second
StartRandomImgFlipbookStartRandombooleanfalseRandom start frame per particle
ReverseImgFlipbookReversebooleanfalsePlays backwards
Panel labelData attributeTypeDefaultWhat it does
Anim. StepsTotalKeyFramesnumber100Pre-sample resolution for the graphs
LingerPartLifenumber0Seconds the particle persists after Lifetime
Emit IntoEmitParentInstancenilWhere particles parent — overrides the default ScreenGui
PreloadTexturePreloadTexturebooleanfalseForce-loads the Image asset before emit begins

Per-property prose for the distinctive bits

Section titled “Per-property prose for the distinctive bits”

A UDim2 for the base spawn position. The panel input is a comma-separated "sx, ox, sy, oy" format — Scale-X, Offset-X, Scale-Y, Offset-Y. So "0.5, 0, 0.5, 0" (the default) is “centre of parent.” "0, 50, 1, -50" is “fifty pixels in from the left, fifty pixels up from the bottom.”

Particles spawn at this Position and accumulate their motion as a delta to the Offset component. The Scale component stays constant — particles don’t reflow with parent size changes mid-life.

A UDim2 for the base size of each particle. Default is (0, 100, 0, 100)100 pixels wide and 100 pixels tall, with no scale-relative sizing. To make particles size relative to the parent (so they grow when the screen is bigger), use scale values: (0.1, 0, 0.1, 0) is “10% of the parent in each axis.”

The base Size is multiplied by the SizeScale graphs each frame; the result is the rendered size at any given moment.

Two independent NumberSequence graphs (SizeScaleX and SizeScaleY) that multiply the base Size each frame.

A particle that grows wider mid-life uses an oscillating SizeScaleX while keeping SizeScaleY at 1.0. A particle that stretches vertically uses the opposite. A particle that pulses (grows and shrinks together) uses identical graphs on both axes.

This is how 2D particles get their “anime impact” feel — exaggerated horizontal stretch on a hit-flash, vertical squash for a damage-up popup.

A single number in degrees. The central direction every particle launches in.

is right (positive X axis in screen space). 90° is up (Y grows downward in GUI coordinates, so “up” is the negative Y direction — the plugin handles the inversion internally). 180° is left. 270° is down. The default is 90° — particles launch upward by default, which is the most common pattern (damage numbers float up, sparkles rise).

For sideways effects like a directional impact splash, use or 180°. For omnidirectional bursts, leave EmissionAngle alone and crank SpreadAngle to 360.

A single number in degrees. Each particle’s actual launch angle is randomly picked from EmissionAngle ± SpreadAngle/2.

0 produces a tight, parallel beam — every particle launches in exactly the EmissionAngle direction. 30 produces a moderate fan. 90 produces a quarter-circle spread. 360 produces a fully omnidirectional burst.

Combined with EmissionAngle, this is the entire direction model. There are no per-axis Position offsets like the workspace types — if you want particles to spawn in different places, set up multiple emitters at different Positions, or script the Position before each Particle:Emit() call.

A NumberSequence graph for velocity magnitude in pixels per second. Multiplied against the unit-vector launch direction each frame.

A Speed of 100 constant moves a particle 100 pixels along its launch direction per second. A graph that decays from 200 to 0 is a “rise and slow” pattern — fast launch, gradual stop. A graph that ramps upward is a “drift and accelerate” — useful for explosion debris animations.

A Vector2 in pixels-per-second-squared. Applied to every particle’s velocity each frame, regardless of launch direction.

Since GUI Y grows downward, (0, 300) is “gravity pulling particles toward the bottom of the screen” — useful for damage numbers that float up briefly and then fall. (50, 0) is “a sideways breeze pushing particles to the right.” (0, -100) is “a constant upward force” — particles that gain altitude over time regardless of launch direction.

Exponential decay applied to velocity each frame. Same role as on workspace types. A Drag of 1 cuts velocity to about 37% per second.

For 2D effects, drag is especially useful for particles that should settle rather than just fly — a damage-number popup that drifts up briefly and then comes to a stop in the air uses Drag to slow itself down without a falling-Speed graph.

Three properties together control rotation:

  • RotRange — a NumberRange for random initial rotation. Each particle picks a random rotation within this range at spawn. (-30, 30) gives ±30° random orientation; (0, 0) gives every particle the same starting rotation (zero).
  • RotSpeed — a NumberSequence for rotation speed during life. The semantics depend on RotMode.
  • RotMode — an enum: OverLife (the graph value at age t is the absolute angle in degrees — a graph ramping from 0 to 360 spins each particle once over its life, regardless of how long that life is; a constant graph holds a fixed rotation) or Speed (the graph value at age t is the rotation rate in degrees-per-second; the engine accumulates value × dt each frame, so a constant 360 spins once per second).

Same model as the workspace types’ rotation, just on the single 2D axis (rotation around the screen normal — particles spin like coins on a table).

An enum that picks where the flipbook frames come from. Two options:

  • Decals — same model as the mesh flipbooks for Part and Beam. The plugin reads child Decal instances of an ImageFlipbooks folder under the source ImageLabel, sorted numerically by name. Each Decal’s Texture becomes one frame.
  • Spritesheet — a single Image asset divided into a grid. The plugin computes a Rect for each frame based on GridCols and GridRows and animates the particle’s ImageRectOffset and ImageRectSize properties. The default 8×8 (64-frame square) covers most spritesheet authoring; 8×1 horizontal strips, vertical strips, square 4×4 grids, or any other arrangement work too.

For most authoring, Decals mode is easier (one image per frame, no math). Spritesheet mode is more efficient for animation-heavy effects since one texture loads once.

How frames advance. Four options. Same idea as the mesh-flipbook Mode, but with two extra modes that the mesh / beam flipbooks don’t currently support.

Loop (default) — frames cycle continuously at Framerate FPS for the particle’s whole life. Use cases:

  • Continuously animating UI sparkles or glints behind a button.
  • Looping power-up pulses overlaying a HUD.
  • Cycling glow patterns on damage-number popups so the popup itself is always “alive.”

OneShot — frames play once linearly across Lifetime. The first frame appears at age 0, the last frame at age 1, with the last frame holding for any time after the sequence completes. Use cases:

  • A “+1” pickup popup whose frames are: appear → swell → settle → fade. The frame progression is the popup’s life cycle.
  • Damage numbers whose first frame is a sharp impact effect, then progressively soften.
  • UI achievement flashes whose frames trace the bloom-and-fade arc once per emit.

PingPong — frames play forward then backward then forward, oscillating. The animation has a “rest” frame at each end of the cycle and a “peak” frame in the middle. Use cases:

  • Breathing or pulsing effects where the texture should swell and contract repeatedly. A 5-frame pingpong (small → medium → large → medium → small → medium → large …) reads as an organic breath.
  • UI markers that bob — a hovering arrow whose frames sweep up and back down.
  • A loading spinner that doesn’t snap-loop. Where Loop reads as “frame N+1 right after frame N → snap to frame 1,” PingPong reads as a smooth back-and-forth wave with no visual jump.

Random — every 1 / FlipbookFramerate seconds, each particle picks a fresh random frame independently. Unlike Loop’s linear advance through the frame sequence, Random produces a per-particle, jittery-feeling frame stream. Use cases:

  • Static-fuzz textures where order doesn’t matter — sparkle dust, screen-grain overlays, broken-signal effects.
  • Crackling energy where any of N frames is a valid look at any moment.
  • Anything where you want a population to feel desynchronised without authoring per-particle offsets.

Two numbers: GridCols (frames per row) and GridRows (number of rows). Only meaningful when Source = Spritesheet. The plugin computes:

  • Frame width = imageWidth / GridCols
  • Frame height = imageHeight / GridRows
  • Total frames = GridCols × GridRows
  • For frame i: ImageRectOffset = ((i % GridCols) × frameWidth, floor(i / GridCols) × frameHeight)

An 8, 8 grid is a 64-frame square (the default). A 4, 4 grid is a 16-frame square. An 8, 1 grid is an 8-frame horizontal strip. The plugin caches the image’s pixel dimensions on first emit, so the first emission may render the whole image without cropping for a frame or two while the dimension fetch completes.

The default parent for emitted particles is a managed ScreenGui the plugin creates lazily under CoreGui. You don’t need to think about this — it appears the first time an ImageLabel emits and is destroyed when you deactivate the plugin.

Override Emit Into to point at your own ScreenGui (or any UI container) when you want particles inside a specific frame, above specific other UI elements, or under your game’s Z-index management. A common pattern is to put a ScreenGui named Effects inside PlayerGui and point ImageLabel emitters at it, so the effects participate in your game’s UI render order.

A boolean. Same role as on Beam/Trail: forces the texture asset to load before emit begins, preventing the first few particles from rendering with no image while the asset streams in.

For tight cinematic timing, turn it on. For most uses, leave it off.


A few ImageLabel-specific quirks.

3D-to-screen tracking is your responsibility. ImageLabel particles don’t automatically follow 3D objects. If you want a damage number to appear above an enemy who’s somewhere in the 3D world, you have to compute the screen-space coordinate of the enemy yourself (typically with Camera:WorldToScreenPoint) and write it to the ImageLabel emitter’s Position attribute before triggering the emission. There’s no built-in “track this 3D point” toggle.

ImageColor3 multiplies, doesn’t replace. A red ImageColor3 doesn’t repaint the texture red — it multiplies the texture’s RGB by the colour’s RGB. If your texture is white, the result is red. If your texture is blue, the result is black (red × blue = no overlap). For solid-tint particles, start with a white-pixel texture; for textured particles, design the texture’s base colour with the multiplication in mind.

The default Position is centre-of-parent. (0.5, 0, 0.5, 0) puts the particle at the parent ScreenGui’s centre. For damage numbers over a 3D enemy, this is wrong — you’ll want to override Position before each emit. For UI flourishes that should always trigger from the same screen position (a heart icon flashing in the top-left), the default works fine.

Decals folder is hidden during emit. When the plugin clones the source ImageLabel for emission, it strips the ImageFlipbooks folder from the clone (the clone doesn’t need to carry around the frame Decals — the engine reads them from the source’s folder once, caches them, and uses the cached list per particle).

Animate mode is singleton. Same as the screen-space types — only one Animate-mode duplicate alive at a time, re-emits while alive are silently dropped. Works the same way for ImageLabel as for Blur/Bloom/ColorCorrection.

Performance tolerates high rates. UI rendering doesn’t go through the 3D pipeline (no skinning, no shaders, no shadow casting). High Rate values like 100 or 200 particles per second are viable on mid-range hardware. The cost is mostly in graph evaluation and per-particle property updates, not in the rendering itself.

The default Image = "". A new ImageLabel emitter with the default empty Image renders… nothing. You have to set an Image asset before particles will visibly appear. The panel’s Image field accepts rbxassetid://... URIs or the asset id directly.


That’s all eleven types. Workspace, screen-space, UI — eleven different ways to turn a Roblox instance into a custom particle emitter:

  • Workspace 3D: Part, Attachment, Beam, Trail, PointLight, Model.
  • Screen-space post-process: Blur, Bloom, ColorCorrection, Atmosphere.
  • UI 2D: ImageLabel.

You’ve now seen the architectural surface of every emitter the plugin supports. The next chapter shifts back from the type catalogue to broader plugin features, starting with Textures and Flipbooks — how textures and flipbooks land on a transformed emitter, and how the Dissect tool slices any public Roblox spritesheet into a flipbook at full resolution.