CutsceneService - Smooth cutscenes using Bézier curves


Smooth cutscenes using Bézier curves

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.

I’m happy to present you CutsceneService, which is easy to use, fully customizable and has a wide range of features.


Getting started


Firstly, get the module here and insert into your game via the Toolbox. You probably want to put it in 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 object.

local CutsceneService = require(game.ReplicatedStorage.CutsceneService)

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

The cutscene object has 4 functions:

  • Play
  • Pause
  • Resume
  • Cancel

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.Functions to quickly autocomplete the name like an Enum. In this example we will use EndWithCurrentCamera.

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

CutsceneService:Create(workspace.Cutscene1, 5, CutsceneService.Functions.EndWithCurrentCamera)

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 4 functions like cutscenes:

  • Play
  • Pause
  • Resume
  • Cancel

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

Please note the the Next property will be overwritten/removed when the cutscene is played in a queue.

Happy creating! :grinning_face_with_smiling_eyes:


The main module, obtained with require().


Dictionary Functions
Serves the purpose to quickly autocomplete special function names.

Dictionary Settings
Contains settings for the CutsceneService module.


boolean WarnErrors
Warns error messages instead of erroring.

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

boolean FireCompletedInQueue
Fires the Completed events of the cutscenes when played in a queue. The last cutscene will always fire.


cutscene Create(Instance | CFrameArray points, number duration, ...)
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.

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


The cutscene object returned by Create.


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

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


boolean? Play()
Starts the cutscene. If a cutscene is already playing on the client, it is not possible to start it. Like the other functions, it returns false if the function threw an error.

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

boolean? Resume()
Resumes the cutscene. It must first be played and then paused to be able to resume it.

boolean? Cancel()
Cancels the playback of the cutscene.


RBXScriptSignal Completed(PlaybackState 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 PlaybackState
refer to cutscene

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


void Play()
refer to cutscene

void Pause(number waitTime?)
refer to cutscene

void Resume()
refer to cutscene

void Cancel()
refer to cutscene


RBXScriptSignal Completed(PlaybackState playbackState)
refer to cutscene

Special functions

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


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


Disables the character controls so you can’t move.


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


Sets the current camera CFrame as the first point.


Sets the current camera CFrame as the last point.


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


Parameters: number waitTime
Yields the cutscene before changing the CameraType back for example. This could be used for displaying dialogues, etc. This also delays when the Completed event is fired.


Version 1.3.0

  • Added queues
  • Added ability to loop cutscenes
  • Added type annotations
  • Added 3 settings
  • Optimizations

My goals:

  • Queues that play multiple cutscenes successively
  • Improvement of some special functions
  • Plugin that helps with creating cutscenes and lets you instantly preview them

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!

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.

1 Like

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: