Camera Basics: CameraType and CFrame
The camera in Roblox is accessed via workspace.CurrentCamera. By default, it follows the player character (CameraType = Custom). To take manual control, set CameraType to Scriptable — this disconnects the camera from the character and lets you position it freely via the CFrame property. CFrame (Coordinate Frame) defines both position and rotation. Set CurrentCamera.CFrame = CFrame.new(position, lookAtTarget) to place the camera at a position looking at a target point. When your cutscene ends, set CameraType back to Custom to return control to the player. Always store the original CameraType and CFrame before starting a cutscene so you can restore them exactly on completion or skip.
TweenService Camera Moves
The simplest cutscene technique is tweening the camera between CFrame values. Use TweenService:Create() to animate CurrentCamera.CFrame from its current value to a target CFrame. Set the duration, easing style, and easing direction in the TweenInfo. For a slow establishing shot, use 4-6 seconds with EasingStyle.Quad and EasingDirection.InOut for a smooth acceleration and deceleration. Chain multiple tweens sequentially for a multi-shot cutscene: tween to shot 1, wait for completion, tween to shot 2, and so on. Use the Tween.Completed event to trigger the next tween rather than task.wait(duration), which can desync if the tween is interrupted. For looking at a target while moving, interpolate both the position and a CFrame.lookAt() toward the target at each step using RunService.RenderStepped instead of a single tween.
- TweenService:Create(camera, TweenInfo.new(duration, easingStyle, easingDirection), {CFrame = targetCFrame})
- Use Enum.EasingStyle.Quad for natural cinematic motion
- Chain tweens with Tween.Completed signals, not task.wait()
- For look-at tracking, update CFrame every RenderStepped with CFrame.lookAt()
Bezier Curves for Cinematic Paths
Straight-line tweens look mechanical. Real camera work follows curves — sweeping arcs, crane shots, and orbit paths. Implement these with bezier curves. A quadratic bezier uses three control points: start, control, and end. The camera follows a smooth arc through the control point. A cubic bezier uses four points for S-curves and more complex paths. The math is straightforward: for a quadratic bezier at time t (0 to 1), the position is (1-t)^2 * P0 + 2*(1-t)*t * P1 + t^2 * P2. Place invisible parts in your scene as control points, then sample the curve in a RenderStepped loop, advancing t based on elapsed time. Combine the position bezier with a separate look-at target (either a fixed point or another bezier for the focus target) to create professional-feeling camera work. Place 3-4 control point parts in your scene, visualize the curve in Studio, and iterate until the path feels right.
- Quadratic bezier (3 points): good for simple arcs and crane shots
- Cubic bezier (4 points): good for S-curves and complex orbits
- Sample the curve every RenderStepped, advance t by dt/totalDuration
- Use separate bezier paths for camera position and look-at target for maximum control
Letterboxing and Cinematic UI
Letterbox bars (the black bars at the top and bottom of the screen) instantly signal "cutscene mode" to the player. Create two Frames in a ScreenGui — one anchored to the top and one to the bottom — with black BackgroundColor3 and a height of about 12% of the screen. Tween them in from off-screen (Y position from -0.12 to 0) over 0.5 seconds when the cutscene starts, and tween them back out when it ends. Add a subtle vignette effect with a full-screen ImageLabel using a radial gradient from transparent center to semi-transparent black edges. For story cutscenes, add a subtitle TextLabel positioned just above the bottom letterbox bar. Fade subtitles in and out with TweenService rather than instant text changes. Disable the player's HUD (health bar, hotbar, minimap) during cutscenes by toggling their ScreenGui Enabled property.
