Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commite8beb5604c

README.md

DeprecatedSimpleParticleEmitter (deprecated)

Deprecated. This belongs to the earlier particle substrate. It stays loadable by identity and guid for content that already uses it; nothing new should use it, and search does not offer it. Particles are procgen sim nodes (sim.spawn, sim.particles, sim.shader) played through an effect: use @builtin::assetTypes.effect.

Roblox-shaped declarative particle system. Sits on top of NumberRange, NumberSequence, and ColorSequence to describe an emitter's emission cadence, per-particle motion, and per-particle visuals as data — no imperative per-frame code on the user side.

The simulation and rendering run on the GPU: a compute pass integrates every particle each frame and the whole system draws from one instanced pass. A single emitter carries thousands of live particles at a fixed per-frame CPU cost. The component is a thin adapter over the particles engine module (@builtin::deprecated.deprecatedParticles.engine).

Construct

The engine registers two builtin components under the leaf name ParticleEmitter, each with its own field vocabulary: this one, and @builtin::deprecated.deprecatedParticles.DeprecatedParticleEmitter. Address this one by its full identity, @builtin::deprecated.deprecatedParticles.DeprecatedSimpleParticleEmitter — the fields below are the ones it declares.

local em = entity.spawn("flame")
em.localPosition = { 0, 1, 0 }
em.component.add("@builtin::deprecated.deprecatedParticles.DeprecatedSimpleParticleEmitter", {
    rate     = 50,
    lifetime = NumberRange.new(1.0, 1.5),
    speed    = NumberRange.new(2.0, 3.0),
    acceleration = { 0, 5, 0 },
    color = ColorSequence.new({
        { time = 0, value = { 1, 0.9, 0.3 } },
        { time = 1, value = { 0.6, 0.1, 0 } },
    }),
    size = NumberSequence.new(0.4, 0.05),
    transparency = NumberSequence.new(0, 1),
    depthFade = 1.5,
})

depthFade is the distance, in world units, over which a particle dissolves into the surface drawn behind it, so a plume meeting a floor settles onto it instead of cutting a straight line along it. The default is 0, which is off. The particles engine module's README has the whole surface.

castsShadows states whether these particles block light — a caster is drawn into the shadow map as the geometry it is, so debris and rubble declare it while smoke and dust leave it alone. The default is false. renderLayer names the render layers the particles draw on, as a layer name or a space-separated string, so a camera or a capture can take the scene with the effect in it or without; the default is "default".

Instance methods

local em = entity.find("flame").component.get("@builtin::deprecated.deprecatedParticles.DeprecatedSimpleParticleEmitter")
em:emit(50)           -- burst spawn 50, independent of rate / emitting
em:clear()            -- clear every live particle right now
em.emitting = false   -- stop new emission; live particles complete

Permissive input shapes

The component accepts either the strict constructed handle or the common shorthand for each sequence/range field:

FieldStrictShorthand accepted
lifetime, speed, rotation, rotSpeedNumberRange.new(min, max)scalar, {min, max}, {min=, max=}
size, transparency, squashNumberSequence.new(...)scalar, {a, b}, {{time, value, envelope?}, ...}
colorColorSequence.new(...){r, g, b}, {r, g, b, a}, keypoint array
acceleration, emitterSize, spreadAngleVector record / arraysame

Emitter shape

shape selects where particles spawn and which way each one starts moving. It takes one of six names, in any letter case: Point, Box, Sphere, Cylinder, Disc or Cone. Any other name is refused when the emitter starts, with the six in the message. Box, Sphere, Cylinder and Disc are centred on the emitter, and emitterSize gives their extent along each axis; the table states where Point and Cone sit.

shapeWhere particles spawnStarting directionshapeStyleshapePartial
PointThe emitter's originStraight up (+Y)UnusedUnused
BoxA box emitterSize acrossVolume: away from the centre. Surface: out of the face it spawned onVolume fills it, Surface spawns on its facesUnused
SphereAn ellipsoid whose diameters are emitterSizeAway from the centreVolume fills it, Surface its shellAbove 0 keeps the upper half, flattened toward the equator; at 1 only the equator ring
CylinderAn upright cylinder, emitterSize.y tall, diameters emitterSize.x / .zOut from the axis, levelVolume fills it, Surface its side wallShortens the band particles spawn in about the centre, to half the height at 1
DiscA flat ellipse in the XZ plane, diameters emitterSize.x / .zOut from the centre, levelVolume fills the ring between the inner radius and the rim, Surface spawns half on the rim and half on the inner edgeThe inner radius as a fraction of the outer; at 0 the inner edge is the centre
ConeThe base of a cone whose apex is the emitter's origin and whose axis is +Y, emitterSize.y above the apexAlong the line from the apexUnusedThe half-angle as a fraction of 90 degrees; 0 is a single line straight up

shapeInOut sets the starting direction against the table's: Outward keeps it, Inward reverses it, and InAndOut picks one of the two for each particle. spreadAngle then tilts each direction by up to its larger component, in degrees, so every particle leaves within that angle of the direction the table gives it.

emissionDirection names the side of the emitter the shape's +Y faces, and turns the whole shape there: where particles spawn and the directions they leave in. It takes one of six names: Top (+Y, the default, which is the table as written), Bottom (-Y), Right (+X), Left (-X), Front (-Z, the way an entity faces) or Back (+Z). Any other name is refused with the six in the message: a write to a running emitter keeps the side it had, and an emitter added with one does not start. The turn is the shortest one from +Y, so a Point emitter set to Bottom sprays straight down, a Cone set to Front opens along -Z, and a Disc set to Right stands upright in the YZ plane with emitterSize.z still along Z. The sides are the world's axes: the emitter follows its entity's position, not its rotation.

local flame = entity.spawn("flame")
flame.component.add("@builtin::deprecated.deprecatedParticles.DeprecatedSimpleParticleEmitter", {
    shape        = "Cone",
    emitterSize  = { 0.6, 1.2, 0.6 },
    shapePartial = 0.4,
    rate         = 40,
})

The emitter tracks its owning entity's world position each frame, so parenting it to a moving part sweeps the emission origin along with the part.

Demo

The campfire showcase — a warm flame emitter + slow gray smoke emitter on a log, lit by a warm point light — lives on ZeroMind as the public world "Campfire" (3d69d10d-5388-4bee-88f4-b48eb85ae222).