Skip to content

Model

A Part emitter spawns Parts. An Attachment emitter spawns Attachments. What about a particle that’s more than one Part?

A spinning gem with its own glowing aura is two visible elements (the gem mesh, the glow halo). A toy aircraft is dozens (fuselage, wings, propeller, lights). A magic sigil with three concentric rings is three Parts welded together. None of those work as a single-Part emit — they’re inherently composite.

That’s the case Model handles. When you transform a Model, every emission produces a duplicate of the entire model — the PrimaryPart, every descendant, attachments, beams, meshes, scripts, the whole subtree. The duplicate moves and rotates as one unit, scales as one unit, and is created and destroyed as one unit.

Any Roblox Model instance with a PrimaryPart set.

The plugin requires PrimaryPart so it has a deterministic anchor to compute the duplicate’s spawn position from. (Roblox’s Model:PivotTo() and Model:ScaleTo() will technically work on a Model without a PrimaryPart — the engine falls back to the Model’s first BasePart, or to world origin — but the resulting pivot can shift if you reorder children, which makes spawn placement unstable. The plugin’s check sidesteps that.) Transform blocks the operation if PrimaryPart is missing, with a warning. Set the PrimaryPart on the source Model in Studio’s Explorer first, then click Transform.

When a Model emits, the engine clones the entire RenderTemplate subtree with Model:Clone(). That’s potentially many BaseParts, Attachments, Beams, Decals, lights — all duplicated together as one structure with the same internal geometry the source has. The clone is parented to EmitParent (or to the Model’s parent if EmitParent is empty), then placed via Model:PivotTo() at the spawn position computed from the usual spawning properties.

Each frame after that, the engine updates the Model duplicate’s position by computing a new local CFrame (driven by Speed, Acceleration, Drag exactly like a Part) and calling :PivotTo() to apply it. The whole hierarchy moves together — relative positions of descendants are preserved.

The same per-frame call is made for scale. The Model’s Scale graph is sampled at each frame and applied via Model:ScaleTo(). The scale cascades through every descendant uniformly: every BasePart shrinks, every MeshPart shrinks, every SpecialMesh size shrinks, every attachment offset stays locally placed but at the smaller scale.

This is the key architectural difference from Part. Part has three independent axis-graphs (SizeX, SizeY, SizeZ) that scale the single Part along each axis. Model has one uniform Scale graph, and that single value affects everything in the subtree at once.

The full surface area, grouped by panel section.

Panel labelData attributeTypeDefaultWhat it does
RateRatenumber10Models emitted per second
LifetimeLifetimeNumberRange1Seconds each Model lives
SpreadAngleSpreadAngleVector2(0, 0)Cone of random deviation
DirectionEmissionDirectionenumTopWhich face Models fly out of
PositionPosX, PosY, PosZthree NumberRange0Random offset from PrimaryPart at spawn
Pos. ModePosModeenumLocalFrame the position offsets roll in
OrientationOrientationenumNoneHow the Model faces camera or velocity
Z-OffsetZOffsetnumber0Render-depth bias for layering
EmitCountEmitCountnumber0One-shot burst count
EmitDelayEmitDelaynumber0Wait before first Model
EmitDurationEmitDurationnumber0Seconds of continuous loop after the initial bursts. 0 skips the loop
Panel labelData attributeTypeDefaultWhat it does
ScaleScaleNumberSequence1Uniform scale graph cascaded to every descendant
Panel labelData attributeTypeDefaultWhat it does
SpeedSpeedNumberSequence0Velocity magnitude over life
AccelerationAccelerationVector3(0,0,0)Constant force vector each frame
DragDragnumber0Exponential velocity decay
Dir. ModeDirModeenumRigidLocalWhich frame the direction is in
Reverse MotionInvertMotionbooleanfalsePlays trajectory in reverse
RotationRotX, RotY, RotZthree NumberRange0Random initial rotation per axis at spawn
Rotation ModeRotModeenumOverLifeWhether RotSpeed is per-life or per-second
Rotation SpeedRotSpeedX, Y, Zthree NumberSequence0Rotation speed per axis
Panel labelData attributeTypeDefaultWhat it does
Anim. StepsTotalKeyFramesnumber100Pre-sample resolution for the graphs
LingerPartLifenumber0Seconds the Model lingers after Lifetime
Emit IntoEmitParentInstancenilWhere Model duplicates parent
Link Dir.Link (ObjectValue)InstancenilBind Model emission to another instance
LinkSourceLinkSourceenumNoneWhere to look up the Link
Link ModeLinkModeenumWeldHow linking inherits CFrame

That’s the entire panel. No Appearance section — Models don’t have a unified Color, Transparency, or Brightness graph. Each child instance keeps its own appearance. No Shape section — Models don’t have a configurable spawn region (the spawn position is the PrimaryPart’s location, plus the Position offsets). No Flipbook — children with their own flipbook setups handle that themselves.

The trade-off is intentional. A Model can contain anything (Parts, Beams, lights, attachments, scripts, animations), and the plugin can’t reasonably author a single Color graph that affects all of them sensibly. Each descendant is responsible for its own visual properties. If you want every Part in a Model to fade together, you set Transparency on each Part individually (or use a child script).


A NumberSequence graph for uniform scale, applied via Model:ScaleTo() to the duplicate’s entire hierarchy.

Scale = 1 (the default) is no scaling — the duplicate is the same size as the source Model. Scale = 2 is double the size; Scale = 0.5 is half. A graph that ramps from 0.1 to 2 makes each Model duplicate start small and grow as it ages — useful for “bursting from nothing” effects (a magic glyph that materialises into existence and grows).

The scale cascades through every descendant. Each BasePart’s Size is multiplied; each MeshPart’s mesh is rendered at the scaled size; each Attachment’s offset is scaled accordingly. Roblox’s :ScaleTo() handles the whole subtree in one call.

The plugin samples the Scale graph each frame and re-applies :ScaleTo() with the new value. This is potentially expensive on large Models. A Model with fifty descendants requires fifty descendant updates per frame per active particle. With thirty active duplicates, that’s 1,500 internal property updates per frame just for scaling. For high-rate emitters or detailed Models, this can affect frame rate. The plugin doesn’t skip frames where the scale hasn’t changed, so a constant-scale graph still incurs the per-frame call.

If you don’t need animated scale, set the graph to a single keypoint (1 throughout) and the cost is one :ScaleTo() call per frame regardless. The cost scales with descendant count, not with how much the scale changes.


Nested emitters — the composite-of-composites pattern

Section titled “Nested emitters — the composite-of-composites pattern”

A Model can contain other transformed items as descendants — a Beam attached to two Attachments inside the Model, a PointLight parented to a child Part, a child Part that’s also been transformed. When the outer Model emits, those nested emitters emit too, automatically.

Concretely: when a Model duplicate is created, the engine walks its descendants and checks each one for the Transformed attribute (the marker Transform stamps on every item it processes). For each transformed descendant, the engine clears its EmitDelay (so it doesn’t wait through the parent Model’s already-elapsed delay) and calls the same EnableEmit path that a top-level click on that descendant would. The nested emitter uses its own properties — its own Rate, its own Lifetime, its own graphs — not anything inherited from the parent Model except for parent-scale (covered below).

This produces a composite particle: one Model duplicate carrying its own internal Beam pulse, its own emitted PointLight flashes, its own child Part-particles flying outward from somewhere inside the Model’s hierarchy. All happening at once, all timed to the parent Model’s emission.

The most common pattern is a fireball: a Model containing a textured Sphere Part (the visible orb), a Beam (the trailing flame), and a PointLight (the glow it casts on the world). Each child emitter must be Transformed individually — Transforming only the Model marks the Model itself but leaves the child Sphere / Beam / PointLight as plain visual decoration. With each child also Transformed (Transformed = true), every fireball-particle has its sphere, its trailing beam, and its glow, all emitted together.

Each nested emitter’s particles inherit the parent Model’s current Scale value. The plugin tracks this through a _parentScaleMap table — when a nested Beam’s particles update each frame, they read the parent’s current scale and multiply their Width0/Width1/CurveSize values accordingly. So a fireball Model whose Scale shrinks from 1 to 0.1 over its life produces nested Beam-particles whose widths also shrink in proportion.

The implementation cost is one extra graph evaluation per nested-particle frame, on top of the parent’s scale cost. For deeply nested setups, this compounds — but the visual result is what most authors expect.

A subtle implementation detail: when the engine clones a Model, the child emitters’ configs are not immediately scaled. If they were, repeated Transforms or re-emits would compound the scaling (a 2x-scaled Model containing a Beam whose Width was already 2x the original would produce 4x-scaled beams). To avoid that, the plugin reads the parent scale at runtime and applies it on the fly.

This is the right architecture. It costs a bit more at runtime but means the source configs stay clean and re-emitting always produces predictable sizes.


A few Model-specific quirks.

PrimaryPart is required and not auto-assigned. If you click Transform on a Model without a PrimaryPart, the plugin warns and refuses. Set it manually in Studio’s Explorer first. Most workflows already have a “main” Part in mind for a Model — that’s usually the right PrimaryPart.

Cloning cost grows with descendant count. A Model with twenty visible descendants costs roughly twenty times the duplication of a single Part. The plugin doesn’t warn — your frame rate will. Keep Model emitters reasonable in scope: if a Model has fifty descendants and you’re emitting at Rate = 30, that’s 1,500 descendant clones per second going through the engine.

No Color/Transparency/Brightness at the Model level. Each descendant is responsible for its own appearance. A “fade out the whole Model over time” effect requires either (a) graph-driven children (each Part with its own Transparency graph, set up before Transform) or (b) a script attached to the Model that animates child properties.

Material doesn’t propagate. Setting Material on a Model has no effect on its descendants. Each child Part keeps its own Material. To change all Parts’ Material together, edit them all (or use the bulk-edit tools — see Toolbench).

Motor6D animations are preserved but not driven. If your Model has a Motor6D rig with an AnimationController and an animation script, the cloned RenderTemplate keeps the rig intact. But the plugin doesn’t trigger animation playback per particle — if you want each duplicate to play an animation, add a Script to the source Model that starts playback on Instance.AddedSignal or similar.

PivotTo() is the position primitive. Linking, motion, all positional updates on Models go through Model:PivotTo(). The PrimaryPart’s CFrame is what :PivotTo() reads from, but the rest of the descendants follow. If you find Model duplicates spawning at the wrong position, check the source Model’s PrimaryPart placement first.

Workspace types are done. The remaining types in the Particiliary are different in kind: screen-space effects that animate over the camera’s rendered output rather than in 3D space. The next four — Blur, Bloom, ColorCorrection, Atmosphere — have no position, no spread cone, no movement. What’s left is property animation, applied to a global lighting effect. Where does an “emitted Blur” even live, and how can you have more than one of it at once if Roblox only renders one Blur effect on Lighting?