Layered camera effects for Roblox. Shakes, impacts, injuries, colour grades and camera views, all built from eight primitives and a small library of composable drivers.
Ready-made tracks
Shake, Kick, Edge, Flash and more. Build effects without drivers.
Effect builder
Tweak tracks with sliders and live curves, then copy the code.
MotionFX
Create, play, stop and query effects. Switch views and smoothing.
Drive
Tweens, envelopes, noise, springs, live bindings, and ways to combine them.
Primitives
FOV, Position, Rotation, Blur, Color, Vignette, Sound and Overlay, and how they stack.
Overlays
Flipbooks over the screen: fire, snow, splatter. Make your own from a video with the Overlay maker.
Presets
Explosion, Earthquake, Recoil, Concussion, BrainDamage and more, ready to play.
Three ways to build an effect
Start at the top. Each step down takes a little more code and gives you more control. Stop at whichever level does what you need, and mix levels freely in one effect.
-
1Effect builderNo code to write
Pick tracks, drag sliders while the curves update, and copy the finished Luau into your game.
-
2Ready-made tracksA line of code per move
Shake, Kick, Edge, Flash and more, each with a few options. Because it's code, values can come from your game: a shake that grows with damage, a tint picked per status effect.
-
3Primitives & driversFull control
Drive any of the eight primitives with any curve: follow live data like health or speed, chain and loop shapes, move the camera's position, layer coloured rings in the vignette, and react to where a hit came from.
Installation
MotionFX comes as a single model that lands in Workspace, with two scripts inside:
| Script | Where it goes | What it is |
|---|---|---|
MotionFX ModuleScript | ReplicatedStorage | The package itself. Keep the name, since scripts require it as ReplicatedStorage.MotionFX. |
| Example Script, RunContext Client | Stays in the model | Optional. A test script that puts every preset and example on a key. It requires the MotionFX module next to it, so it runs as soon as you insert the model. Delete it once you've tried things out. |
- Get MotionFX on the Creator Store, then insert it into your place from the Toolbox (Inventory → My Models).
- To try the demo, press Play. The example script runs straight from the model, and the keys are listed on the Examples page.
- Move the
MotionFXModuleScript intoReplicatedStorage, then delete the rest of the model. The example stops working once the module isn't next to it. - Require MotionFX from your own client scripts, as in the Quick start below.
MotionFX asserts RunService:IsClient() when it loads. Require it from a LocalScript, a Script with its RunContext set to Client, or a module one of those uses. To trigger effects from the server, fire a RemoteEvent and call MotionFX:Play on the client.
Quick start
Play a built-in preset by its enum entry or by its plain string name. Both resolve through the same lookup:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local MotionFX = require(ReplicatedStorage.MotionFX)
local FX, Drive = MotionFX.Enum, MotionFX.Drive
MotionFX:Play(FX.Impact.Explosion) -- or MotionFX:Play("Explosion")
-- Options: scale it down and push the camera backwards
MotionFX:Play(FX.Impact.Explosion, {
Intensity = 0.6,
Params = { Direction = Vector3.new(0, 0, 1) },
})
Define your own effect from ready-made tracks. No drivers needed, and the Effect builder writes this for you:
local Track = MotionFX.Track
MotionFX:Create("Hit", {
Tracks = {
Track.Kick({ Pitch = 4 }),
Track.Shake({ Strength = 1, Release = 0.6 }),
Track.Edge({ Color = Color3.fromRGB(150, 0, 0) }),
Track.Sound(MotionFX.Sounds.Shake),
},
})
MotionFX:Play("Hit")
For full control, build each track from one primitive and one driver (Your first effect walks through it step by step):
MotionFX:Create("Heartbeat", {
Retrigger = "Refresh",
Tracks = {
{ Primitive = "Sound", SoundId = MotionFX.Sounds.Heartbeat, Volume = 0.8, FadeOut = 0.3 },
{
Primitive = "FOV",
Driver = Drive.Sequence(
Drive.Spring({ Kick = -2.5, Frequency = 5, Damping = 0.5 }),
Drive.Spring({ Kick = -1.5, Frequency = 5, Damping = 0.5 })
),
},
},
})
local handle = MotionFX:Play("Heartbeat")
handle.Finished:Wait()
Or skip naming an effect and drive a primitive directly:
-- Desaturate the screen until stopped
local grade = MotionFX:Apply("Color", Drive.Constant({ Saturation = -0.6 }), { FadeIn = 0.3 })
task.wait(2)
grade:Stop(0.5)
Keep the preset enum in a local named FX, not Enum. Naming it Enum shadows Roblox's global Enum (Enum.KeyCode, Enum.EasingStyle and so on).
What's inside
The MotionFX ModuleScript is the whole API. These are the modules inside it:
| Module | Purpose |
|---|---|
Track | Ready-made tracks: shakes, kicks, flashes and more, no drivers needed. |
Drive | Driver constructors and combinators, for building tracks by hand. |
Types | The public type definitions for the whole API. It has no runtime code. |
Enum, Sounds, Overlays | Preset and view names, named sound asset ids, and ready-made overlay sheets. |
Presets | Built-in Impact and Injury effects, written with the public API. |
Runtime | Owns running effects (handles) and the per-frame loop. |
Registry | Stores named definitions and validates them when you call Create. |
Channels | One channel per primitive. Each combines that frame's contributions and applies them once. Sound and Overlay instead play each track on its own. |
CameraRig | The only code that writes to workspace.CurrentCamera. |
View | Camera views (first person, over the shoulder, back view) and smoothing. |
