CutsceneService - Smooth cutscenes using Bézier curves


Smooth cutscenes using Bézier curves

Repository | Roblox model | Plugin

Hey developers,

TweenService is probably the best choice for tweening between 2 points. However, when you have more than 2 points, you have to do something like this:

This doesn’t look good and is pretty outdated. But there’s a solution: Bézier curves.

CutsceneService is a module which specializes in cutscenes. It is easy to use, fully customizable and has a wide range of features.


Create smooth cutscenes with CutsceneService! (Beginner Tutorial) - YouTube

Getting started

Note: It is highly recommended to use the plugin as it greatly facilitates the work.

Firstly, get the module here and insert into your game via the Toolbox (preferably ReplicatedStorage).

After that we’ll set up a cutscene. Create a folder in Workspace and name it Cutscene1.
Then insert parts (also called points) into it. Name the parts 1 , 2 , 3 , etc. The cutscene starts at 1 and ends at the last point.
Position the parts and make sure they are looking in the right direction.

The more points in a cutscene, the more calculations have to be done - don’t add unnecessarily many!

Now create a LocalScript in StarterGui and require the module:

local CutsceneService = require(game.ReplicatedStorage.CutsceneService)

Use the :Create(folder, duration) function to create a new cutscene.

local CutsceneService = require(game.ReplicatedStorage.CutsceneService)

local cutscene1 = CutsceneService:Create(workspace.Cutscene1, 5)

The cutscene object has 5 functions:

  • Play
  • Pause
  • Resume
  • Cancel
  • Destroy

After adding :Play(), run the game and see how the cutscene looks. You might want to reposition or rotate some parts.

local CutsceneService = require(game.ReplicatedStorage.CutsceneService)

local cutscene1 = CutsceneService:Create(workspace.Cutscene1, 5)

Easing & Special functions

You mostly don’t want just a plain cutscene. There are easing styles, easing directions and special functions which you can add to your cutscene.

When I told you that the Create function only has 2 parameters, I lied. You can actually add as many arguments as you want.

The order of the arguments (after the first two) doesn’t matter.

For easings, you can either use Enums or the name of a specific easing function (look in the child of the CutsceneService module).

CutsceneService:Create(workspace.Cutscene1, 5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut)

CutsceneService:Create(workspace.Cutscene1, 5, "InOutSine")

Unlike TweenService, CutsceneService has the EasingDirection OutIn (only callable through strings).

Special functions are called with a string. You can also use CutsceneService.Enum to quickly autocomplete the name. In this example we will use CurrentCameraPoint.

CutsceneService:Create(workspace.Cutscene1, 5, "CurrentCameraPoint")

CutsceneService:Create(workspace.Cutscene1, 5, CutsceneService.Enum.CurrentCameraPoint)

Here is an uncopylocked example place.


Queues let you play multiple cutscenes successively.
After creating some cutscenes, you can create a queue like this:

local queue1 = CutsceneService:CreateQueue(cutscene1, cutscene2, cutscene3)

Queues have the same 5 functions like cutscenes:

  • Play
  • Pause
  • Resume
  • Cancel
  • Destroy

It also has a property called CurrentCutscene, which represents the cutscene it currently plays.

Finally, it is possible to loop a single cutscene like this:

cutscene1.Next = cutscene1

You can loop a queue like this:

local queue = CutsceneService:CreateQueue(cutscene1, cutscene2, cutscene3)
cutscene3.Next = cutscene1

Please note the the Next property will be overwritten/removed when a function of it is called.

Happy creating! :grinning_face_with_smiling_eyes:

Advanced tips & tricks

This section requires full understanding of the other guides.

An advantage of CutsceneService is that many useful things, that are normally internal, are available as API here. However I won’t document most of them, that’s why I will present some of them in this section.

PreviousCameraType and PreviousCoreGuis

These are properties that get created when a cutscene or queue is played. They contain the CameraType and CoreGui settings from before the playback, since they need to be restored after the cutscene.

Hence you can for example make it so the camera doesn’t go back to the character immediately:

cutscene1.PreviousCameraType = Enum.CameraType.Scriptable
for k in next, cutscene1.PreviousCoreGuis do
	cutscene1.PreviousCoreGuis[k] = false
	workspace.CurrentCamera.CameraType = Enum.CameraType.Custom
	game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.All, true)

To be continued.


The main module, obtained with require().


Enum : {[string]: string}
Serves the purpose to quickly autocomplete special function names.

Settings : {[string]: any}
Contains settings for the CutsceneService module.


YieldPauseArgument : boolean
When using the waitTime argument of the Pause function, this yields the function.


Create(points : Instance | {CFrame}, duration : number, ...): Cutscene
Creates and returns the cutscene object. points can be an instance with the points as it’s children or an array with CFrames. EasingStyles, EasingDirections and special functions can be added after duration.

CreateQueue(...): Queue
Returns a queue of the cutscenes provided.


The cutscene object returned by Create.


PlaybackState : Enum.PlaybackState
Describes the current stage of the cutscene. Possible values

Progress : number
Describes the current progress of the cutscene which starts at 0 and ends at 1. To get a percentage, multiply it by 100.


Starts the cutscene. If a cutscene is already playing on the client, it is not possible to start it.

Pause(waitTime : number?)
Halts the playback of the cutscene. If a waitTime is given, it will automatically resume after it.

Resumes the cutscene. It must first be played and then paused to be able to resume it.

Cancels the playback of the cutscene.


Completed(playbackState : Enum.PlaybackState)
Fires when the cutscene finishes playing. This will happen either when the cutscene naturally finishes playing, or if it is stopped with Cancel. A function connected to this event will be passed the PlaybackState to give indication about why the tween ended (Can be Completed or Cancelled).


The queue object returned by CreateQueue.


PlaybackState : Enum.PlaybackState
refer to Cutscene

CurrentCutscene : Cutscene?
Represents the cutscene which is currently played. When the queue isn’t playing, it is nil.


refer to Cutscene

Pause(waitTime : number?)
refer to Cutscene

refer to Cutscene

refer to Cutscene


Completed(playbackState : Enum.PlaybackState)
refer to Cutscene

Special functions

Functions that enhance your cutscene. They are called at Cutscene:Play or right after the cutscene finished.
Arguments for special functions can be passed right after the string, like this: (..., "DefaultCameraPoint", 3, "DisableControls"). DefaultCameraPoint would be passed the argument 3. Everything except strings and Enums will count as an argument for a special function.


Parameters: customCamera : Camera
Made for ViewportFrames, changes the camera whose CFrame is tweened.


Disables the character controls so you can’t move.


Parameters: stopAnimations : boolean?
Anchors the HumanoidRootPart. The default for stopAnimations is true.


Parameters: position : number?
Sets the current camera CFrame as a point. position is the number where the point gets inserted: 1 would set it as the first point. The default is #points + 1.


Parameters: position : number?, useCurrentZoomDistance : boolean?
Calculates a CFrame which is behind the characters back and sets it as a point. The default for useCurrentZoomDistance is true, as you would have to change the CameraZoomDistance otherwise and there is only a workaround for that.


Version 1.4.1

  • Removed special function YieldAfterCutscene
  • Renamed CutsceneService.Functions to CutsceneService.Enum
  • Removed the resetCamera parameter of Cutscene:Cancel and Queue:Cancel
  • Small optimizations

Please reply with feedback, suggestions, bugs, improvements, etc. I hope it comes in handy! :slightly_smiling_face:


nice module, would you mind posting the source & and show an example cutscene in a video?


Like said before, i would love to use this, but is there anyway to post on a youtube video? Just for a better reference? Not saying your explanation isnt good or anything…


I made an example cutscene here, it’s uncopylocked.

1 Like

Great resources! Thanks!! I can’t wait to use them!

1 Like

The place is on private, cant really seem to do anything here.

Click on the 3 dots and then “Edit” to open it in Studio.

1 Like

Ah i see. Thanks for correcting me.

Thanks for the innovative asset! :innocent:

Added a new function and another parameter!

Do you mind explaining to me exactly how it works? I do building and work alone, but i need a cutscene system like yours.

I learned how to use Bézier curves in this article.


The module is now fully released! :smile:


I just released a complete overhaul of the module! Getting the new version is definitely worth it, but you have to rewrite parts of your code.


I love the module so much. Thank you for the update!

1 Like

Thanks for your feedback! :grinning_face_with_smiling_eyes:

1 Like

Quick Suggestion: If you request to :Play() a cutscene, while another one is playing, instead of erroring, add it to a “Queue” of cutscenes to play. Then, when one cutscene ends, if there’s another one in the queue, play that one.

1 Like

Also there’s a bug where if you’re triggering a cutscene in first person, the character model isn’t visible during the cutscene

Unfortunately I can’t fix this with a single change to the character because the PlayerModule is constantly overriding this.
Thanks for the report though.

I’ll consider this for the next update! :+1: