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.
What it transforms
Section titled “What it transforms”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.
The composite emission model
Section titled “The composite emission model”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.
Properties at a glance
Section titled “Properties at a glance”The full surface area, grouped by panel section.
Spawning (shared)
Section titled “Spawning (shared)”| Panel label | Data attribute | Type | Default | What it does |
|---|---|---|---|---|
| Rate | Rate | number | 10 | Models emitted per second |
| Lifetime | Lifetime | NumberRange | 1 | Seconds each Model lives |
| SpreadAngle | SpreadAngle | Vector2 | (0, 0) | Cone of random deviation |
| Direction | EmissionDirection | enum | Top | Which face Models fly out of |
| Position | PosX, PosY, PosZ | three NumberRange | 0 | Random offset from PrimaryPart at spawn |
| Pos. Mode | PosMode | enum | Local | Frame the position offsets roll in |
| Orientation | Orientation | enum | None | How the Model faces camera or velocity |
| Z-Offset | ZOffset | number | 0 | Render-depth bias for layering |
| EmitCount | EmitCount | number | 0 | One-shot burst count |
| EmitDelay | EmitDelay | number | 0 | Wait before first Model |
| EmitDuration | EmitDuration | number | 0 | Seconds of continuous loop after the initial bursts. 0 skips the loop |
Scale (Model-specific)
Section titled “Scale (Model-specific)”| Panel label | Data attribute | Type | Default | What it does |
|---|---|---|---|---|
| Scale | Scale | NumberSequence | 1 | Uniform scale graph cascaded to every descendant |
Movement (shared)
Section titled “Movement (shared)”| Panel label | Data attribute | Type | Default | What it does |
|---|---|---|---|---|
| Speed | Speed | NumberSequence | 0 | Velocity magnitude over life |
| Acceleration | Acceleration | Vector3 | (0,0,0) | Constant force vector each frame |
| Drag | Drag | number | 0 | Exponential velocity decay |
| Dir. Mode | DirMode | enum | RigidLocal | Which frame the direction is in |
| Reverse Motion | InvertMotion | boolean | false | Plays trajectory in reverse |
| Rotation | RotX, RotY, RotZ | three NumberRange | 0 | Random initial rotation per axis at spawn |
| Rotation Mode | RotMode | enum | OverLife | Whether RotSpeed is per-life or per-second |
| Rotation Speed | RotSpeedX, Y, Z | three NumberSequence | 0 | Rotation speed per axis |
Advanced (shared)
Section titled “Advanced (shared)”| Panel label | Data attribute | Type | Default | What it does |
|---|---|---|---|---|
| Anim. Steps | TotalKeyFrames | number | 100 | Pre-sample resolution for the graphs |
| Linger | PartLife | number | 0 | Seconds the Model lingers after Lifetime |
| Emit Into | EmitParent | Instance | nil | Where Model duplicates parent |
| Link Dir. | Link (ObjectValue) | Instance | nil | Bind Model emission to another instance |
| LinkSource | LinkSource | enum | None | Where to look up the Link |
| Link Mode | LinkMode | enum | Weld | How 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).
Scale, in detail
Section titled “Scale, in detail”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.
How scaling propagates to nested emitters
Section titled “How scaling propagates to nested emitters”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.
Configs aren’t pre-scaled
Section titled “Configs aren’t pre-scaled”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.
Worth knowing
Section titled “Worth knowing”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.
What’s next
Section titled “What’s next”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?