World
EffectService
Define visual effects once (particles, sounds, lights, decals, models and camera shake), then play them pooled, quality-scaled and broadcast from the server.
Getting it
local EffectService = Engine:GetService("EffectService")Overview
An effect is a named recipe: a list of particle emitters, sounds, lights, decals, models and camera shakes that play together. You define it once with Define, then play it anywhere by name. EffectService takes care of the rest:
- Pooling: the instances for each effect are built once and reused, so playing an explosion 50 times a second does not create 50 new emitters.
- Quality scaling: effects read PerformanceService
Qualityand use the matching level of detail, so low-end devices get fewer particles and no shadows. - Distance culling: effects farther from the camera than
MaxDistanceare skipped. - Broadcasting: the server calls
Broadcastand every relevant client plays the effect locally, sent through NetworkService in batches.
Effects are visual, so they play on the client. The server only broadcasts. Define each effect on both sides (a shared ModuleScript that both require is the easiest way), because the client needs the recipe to play it and the server needs it to know its MaxDistance when broadcasting.
local Engine = require(game:GetService("ReplicatedStorage"):WaitForChild("Engine"))
local EffectService = Engine:GetService("EffectService")
EffectService:Define("Explosion", {
Duration = 1.5,
MaxDistance = 400,
PoolSize = 8,
Particles = {
{ Texture = "rbxassetid://123", Burst = 60, Speed = NumberRange.new(20, 40), Lifetime = NumberRange.new(0.4, 0.9) },
},
Sounds = {
{ SoundId = "rbxassetid://456", Volume = 0.8, RollOffMaxDistance = 300 },
},
Lights = {
{ Kind = "Point", Color = Color3.fromRGB(255, 170, 60), Brightness = 4, Range = 24, Flicker = { Speed = 20 } },
},
Shakes = {
{ Magnitude = 3, Radius = 80 },
},
Lod = {
{ MinQuality = 7 }, -- full effect on good devices
{ MinQuality = 3, ParticleRateScale = 0.5 }, -- half the particles
{ MinQuality = 0, ParticleRateScale = 0.25, DisableLights = true },
},
})
return trueOn the server (on the server the Engine you require is ServerScriptService.Engine, see Server and Client):
EffectService:Broadcast("Explosion", position)Defining effects
Define
EffectService:Define(id: string, def: EffectDef)Registers an effect. Each id can be defined once. Invalid definitions raise an error that names the wrong field.
| Field | Description |
|---|---|
Particles: { ParticleDef }? | Particle emitters. |
Sounds: { SoundDef }? | Sounds played at the effect. |
Lights: { LightDef }? | Point or spot lights, optionally flickering. |
Decals: { DecalDef }? | Decals on the host part, or on a small carrier part. |
Models: { ModelDef }? | Copies of a model or part placed at the effect. |
Shakes: { ShakeDef }? | Camera shakes, fading with distance. |
Duration: number? | Seconds before the effect stops by itself. Without it (or with Loop) it plays until you stop it. |
Loop: boolean? | Keep playing until stopped. |
MaxConcurrent: number? | Most copies at once; the oldest is removed to make room. |
PoolSize: number? | Copies to keep ready, and to build in advance with PreloadAsync. |
MaxDistance: number? | Do not play when the camera is farther away. Also the default broadcast radius. |
Lod: { LodTier }? | Level of detail tiers, see below. |
ParticleDef
Any of: Texture, Color, Size, Transparency, Lifetime, Rate, Burst, Speed, SpreadAngle, Acceleration, Drag, RotSpeed, Rotation, LightEmission, LightInfluence, Squash, EmissionDirection, Orientation, ZOffset. They map to the ParticleEmitter properties of the same name; numbers are accepted where Roblox wants a NumberSequence or NumberRange. With Burst, the emitter emits that many particles once instead of emitting continuously at Rate.
SoundDef
SoundId (required), Volume, PlaybackSpeed, RollOffMode, RollOffMinDistance, RollOffMaxDistance, Looped.
LightDef
Kind ("Point" or "Spot", required), Color, Brightness, Range, Angle (spot lights), Shadows, Flicker ({ Speed?, Intensity? }, a smooth random flicker).
DecalDef
Texture (required), Face, Transparency, Color3, Size (used for the carrier part when there is no host part), ResampleMode (an Enum.ResamplerMode, such as Pixelated for pixel art).
Decals = { { Texture = "rbxassetid://1234567", ResampleMode = Enum.ResamplerMode.Pixelated } }ModelDef
Template (an Instance, required), Offset (CFrame relative to the effect), Scale.
ShakeDef
Magnitude, Roughness, FadeInTime, FadeOutTime, and Radius: the shake fades out linearly with the camera's distance from the effect and is skipped beyond Radius.
LodTier
| Field | Description |
|---|---|
MinQuality: number | The tier applies when quality is at least this. The highest matching tier wins. |
ParticleRateScale, LightBrightnessScale | Multipliers. |
DisableParticles, DisableLights, DisableDecals, DisableModels, DisableShakes | Switch parts of the effect off. |
Quality is PerformanceService.Quality + EffectService.QualityBias. Attached effects update their tier when quality changes.
Playing effects (client)
Play
EffectService:Play(id: string, at: Vector3 | CFrame | Instance, config: PlayConfig?): EffectPlays an effect at a position, a CFrame, or on a BasePart, Attachment or Model. On a part, lights and decals go onto that part. Returns a handle; when the effect is culled by distance the handle is a stand-in that does nothing.
Attach
EffectService:Attach(id: string, instance: BasePart | Model, config: PlayConfig?): EffectPlays an effect that follows a part or model, such as a burning torch or a speed trail.
PlayConfig
| Field | Description |
|---|---|
Scale: number? | Multiplies particle sizes. |
Color: Color3? | Tints particles. |
Volume: number? | Multiplies sound volumes. |
Params: { [string]: any }? | Reserved; not read by the current version. |
Effect handle
| Member | Description |
|---|---|
:Stop() | Stops emitting and lets existing particles and sounds finish, then returns the effect to the pool. |
:Destroy() | Ends the effect immediately. |
Ended: Signal | Fires once when the effect is fully done. |
Playing, Destroyed, Position, Definition | State. |
PreloadAsync
EffectService:PreloadAsync(ids: { string }): PromisePreloads every texture and sound the effects use and builds PoolSize copies of each, so the first play has no delay. Call it during a loading screen.
Broadcasting (server)
Broadcast
EffectService:Broadcast(id: string, at: Vector3 | CFrame | Instance, config: PlayConfig?, filter: Filter?)Tells clients to play an effect. Without a filter it goes to players whose character is within the effect's MaxDistance (or to everyone when the effect has none).
| Filter | Description |
|---|---|
Players: { Player }? | Exactly these players. |
Radius: number? | Players within this many studs. |
Center: Vector3? | Measure the radius from here instead of the effect position. |
Inspection
| Method | Description |
|---|---|
:GetDefinition(id) | The validated definition, or nil. |
:GetActiveCount(id) | Copies playing right now. |
:GetPoolStats(id) | { Size, FreeCount, InUseCount } of the effect's pool (client). |
Properties
| Property | Description |
|---|---|
QualityBias: number | Added to the performance quality when choosing a level of detail. Use a negative value to make effects lighter than the device could handle, for example in busy scenes. |
Configuration
DefaultConfiguration/Services/EffectService20 settings| Setting | Default | What it does |
|---|---|---|
| DefaultBroadcastRate | 20 | Packets per second the shared Broadcast Remote's Stream flushes at. |
| DefaultParticleTexture | "rbxasset://textures/particles/sparkles_main.dds" | Texture a Particle def gets when it sets none. |
| DefaultParticleRate | 20 | Emit rate a Particle def gets when it sets none. |
| DefaultParticleLifetime | 1 | Seconds a Particle def's particles live when it sets none; also the release-grace floor. |
| DefaultLightBrightness | 1 | Brightness a Light def gets when it sets none. |
| DefaultLightRange | 16 | Range a Light def gets when it sets none. |
| DefaultSpotAngle | 90 | Cone angle a SpotLight def gets when it sets none. |
| DefaultFlickerSpeed | 10 | Flicker speed a Light def gets when Flicker is set without one. |
| DefaultFlickerIntensity | 0.3 | Flicker intensity a Light def gets when Flicker is set without one. |
| DefaultFlickerReleaseGraceSeconds | 0.2 | Minimum release grace when any Light in an effect flickers. |
| DefaultSoundVolume | 0.5 | Volume a Sound def gets when it sets none. |
| DefaultSoundRollOffMin | 10 | RollOffMinDistance a Sound def gets when it sets none. |
| DefaultSoundRollOffMax | 100 | RollOffMaxDistance a Sound def gets when it sets none. |
| DefaultDecalSize | Vector2.new(1, 1) | Size of the carrier a Decal gets when there is no host BasePart to decal directly. |
| DefaultShakeMagnitude | 1 | Camera shake magnitude when a Shake def sets none. |
| DefaultShakeRoughness | 10 | Camera shake roughness when a Shake def sets none. |
| DefaultShakeFadeInTime | 0.1 | Seconds a camera shake ramps in when a Shake def sets none. |
| DefaultShakeFadeOutTime | 0.3 | Seconds a camera shake ramps out when a Shake def sets none. |
| ShakeRotationDegreesPerMagnitude | 0.5 | Degrees of rotational shake per unit of Magnitude. |
| ShakeMaxRotationDegrees | 8 | Hard clamp on rotational shake regardless of Magnitude. |
Types
export type EffectDef
export type ParticleDef
export type SoundDef
export type LightDef
export type LightFlicker = { Speed: number?, Intensity: number? }
export type DecalDef
export type ModelDef
export type ShakeDef
export type LodTier
export type PlayConfig
export type Effect
export type Filter = { Players: { Player }?, Radius: number?, Center: Vector3? }