MotionFX

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.

  1. 1Effect builderNo code to write

    Pick tracks, drag sliders while the curves update, and copy the finished Luau into your game.

  2. 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.

  3. 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:

ScriptWhere it goesWhat it is
MotionFX ModuleScriptReplicatedStorageThe package itself. Keep the name, since scripts require it as ReplicatedStorage.MotionFX.
Example Script, RunContext ClientStays in the modelOptional. 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.
  1. Get MotionFX on the Creator Store, then insert it into your place from the Toolbox (Inventory → My Models).
  2. To try the demo, press Play. The example script runs straight from the model, and the keys are listed on the Examples page.
  3. Move the MotionFX ModuleScript into ReplicatedStorage, then delete the rest of the model. The example stops working once the module isn't next to it.
  4. Require MotionFX from your own client scripts, as in the Quick start below.
Client only.

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)
Naming tip.

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:

ModulePurpose
TrackReady-made tracks: shakes, kicks, flashes and more, no drivers needed.
DriveDriver constructors and combinators, for building tracks by hand.
TypesThe public type definitions for the whole API. It has no runtime code.
Enum, Sounds, OverlaysPreset and view names, named sound asset ids, and ready-made overlay sheets.
PresetsBuilt-in Impact and Injury effects, written with the public API.
RuntimeOwns running effects (handles) and the per-frame loop.
RegistryStores named definitions and validates them when you call Create.
ChannelsOne channel per primitive. Each combines that frame's contributions and applies them once. Sound and Overlay instead play each track on its own.
CameraRigThe only code that writes to workspace.CurrentCamera.
ViewCamera views (first person, over the shoulder, back view) and smoothing.