Concepts
MotionFX has a handful of moving parts. Once you know them, every preset reads like a recipe.
Mental model
- Primitives are the eight things an effect can change:
FOV,Position,Rotation,Blur,Color,Vignette,SoundandOverlay. See Primitives & Tracks. - Drivers are factories.
Driver.Start(context)returns a fresh sampler(t, dt) -> value, so stateful drivers like noise and springs get new state on everyPlay(). One definition can run many times at once. See Drive. - Effects never touch the camera. Each primitive has a channel. The channel collects every active contribution, combines them, and applies the result once per frame.
Frame pipeline
The runtime binds two RenderStep callbacks around Roblox's own camera script:
| Priority | Step | What happens |
|---|---|---|
Camera - 1 | CameraRig.Strip() | Restores the CFrame the camera script produced last frame. Scripts that read camera.CFrame back never see or compound the shake. Also adopts FOV changes made by other code. |
Camera | Roblox camera script | Runs normally. Mouse, gamepad and touch input all still drive it. |
Camera + 1 | step(dt) | Samples every driver, then channels combine and apply. The view picks the base placement and this frame's offset goes on top. |
The loop is bound only while an effect is running, or while a view or smoothing is active. When everything finishes, channels release their instances (BlurEffect, ColorCorrectionEffect, vignette GUI), the camera is reset, and the loop unbinds.
How channels combine
| Primitive | Combine rule | Applied to |
|---|---|---|
FOV | Sum of degree deltas | Added to the base FieldOfView |
Position | Sum of Vector3 | Camera-space offset (studs) |
Rotation | Sum of Vector3 | Euler offset in degrees (pitch, yaw, roll) |
Blur | Max, so the strongest wins | Its own BlurEffect in Lighting |
Color | Tints multiply. Saturation, Contrast and Brightness add. | Its own ColorCorrectionEffect |
Vignette | Grouped into layers by Inset and Image. The strongest wins within a layer, and layers stack. | A ScreenGui in PlayerGui |
Sound | Not combined. Each track spawns its own Sound. | SoundService |
Overlay | Not combined. Each track shows its own flipbook image. | A ScreenGui in PlayerGui |
Intensity and fades
Each frame, every non-sound track's value is scaled toward neutral before it reaches the channel:
contribution = Scale(value, handle.Intensity * fade * stopMultiplier * track.Weight)
handle.Intensityis the master scale. It is set byPlayOptions.Intensityand changed byhandle:SetIntensity(value, fadeTime).faderamps in overFadeInseconds. For effects with a fixed duration, it also ramps out over the lastFadeOutseconds.stopMultiplierramps from 1 to 0 over the fade time passed toStop(fadeTime).- Scaling is type-aware. Numbers and vectors multiply. A
ColorValuetint fades toward white. AVignetteLayerfades only its opacity.
The effect-level FadeIn/FadeOut don't apply to sound tracks. A sound uses its own FadeIn and FadeOut, scaled by intensity and the stop fade.
Retrigger policies
EffectDefinition.Retrigger decides what happens when you play an effect while an instance of it is already running:
| Policy | Behaviour | Returns |
|---|---|---|
"Stack" default | Runs both, and their contributions add up. When there are already MaxInstances (default 8), the oldest fade out over 0.1 s. | New handle |
"Refresh" | Restarts the existing instance in place with the new options. Its sounds are cut with a 0.05 s fade and restart. | The existing handle |
"Replace" | Fades out the old instances with their default fade, then starts a new one. | New handle |
"Ignore" | Does nothing. | The running handle |
Duration inference
An effect's length is resolved in this order:
PlayOptions.DurationEffectDefinition.Duration- Inferred: the longest
driver.Duration + track.Delay.
If any driver is open-ended (Constant, Noise, Bind, Cycle, or a combination that contains one), or a sound is Looped, the inferred duration is nil. The effect then runs until you stop it with handle:Stop(), MotionFX:Stop(name) or MotionFX:StopAll().
When a driver finishes, it holds its neutral or end value. Effects fade because their values return to zero, so drivers need no special release logic.
Validation
MotionFX:Create validates definitions up front, so mistakes fail early with a readable message instead of surfacing mid-frame. Examples are a misspelled primitive, a raw number where a driver belongs, a negative Delay, or an unknown Retrigger. Tracks returned by Build are validated each time Build runs.
MotionFX "Heartbeat", track #2: Driver must be built with MotionFX.Drive (got number)