Currently, the Roblox PlayerModule does not expose CameraModule’s API. Although it is easy to fork and make the API accessible yourself, the module still lacks some methods and events you might need. For example, the FirstPerson Enter/Leave events and the :IsInFirstPerson() method. Additionally, the default MouseLock feature does not support mobile devices. Since I needed all of these features, I created an altered version of PlayerModule that provides this functionality.
API Example
--// Require PlayerModule
local PlayerModule = require(script.Parent:WaitForChild("PlayerModule"))
--// [ Camera Module: ]
--// Get Camera Module
local CameraModule = PlayerModule:GetCameras()
--// Check If Player Is In First Person
print(CameraModule:IsFirstPerson() and "You are in first person!" or "You are NOT in first person!")
--// First Person Enter/Leave Connection
CameraModule.FirstPersonEvent:Connect(function(IsFirstPerson: boolean)
print(IsFirstPerson and "You have entered first person mode!" or "You have left first person mode!")
end)
--// [ MouseLock Controller: ]
--// Get MouseLockController
local MouseLockController = CameraModule:GetMouseLockController()
--// Check If Player Is Mouse Locked
print(MouseLockController:GetIsMouseLocked() and "Your mouse is locked!" or "Your mouse is NOT locked!")
--// Mouse Lock Toggle Event
MouseLockController.MouseLockEvent:Connect(function(IsMouseLocked: boolean)
print(IsMouseLocked and "Your mouse was locked!" or "Your mouse was unlocked!")
end)
--// Toggle Mouse Lock
MouseLockController:ToggleMouseLock(true)
MouseLockController:ToggleMouseLock(false)
--// Change Mouse Lock Offset
MouseLockController:UpdateMouseLockOffset(Vector3.new(-1.75, 0, 0)) --// You have to re-toggle MouseLock for this to update
MouseLock Settings
CHARACTER_SMOOTH_ROTATION = true; --// If your character should rotate smoothly or not
CHARACTER_ROTATION_SPEED = 3; --// How quickly character rotates smoothly
OFFSET_TRANSITION_DAMPER = 0.8; --// Camera transition spring damper, test it out to see what works for you
OFFSET_TRANSITION_IN_SPEED = 15; --// How quickly locked camera moves to offset position
OFFSET_TRANSITION_OUT_SPEED = 20; --// How quickly locked camera moves back from offset position
LOCKED_CAMERA_OFFSET = Vector3.new(1.75, 0, 0); --// Locked camera offset
LOCKED_MOUSE_ICON = --// Locked mouse icon
"rbxasset://textures/MouseLockedCursor.png";
SHIFT_LOCK_KEYBINDS = --// Shift lock keybinds
{ Enum.KeyCode.LeftShift, Enum.KeyCode.RightShift };
MOBILE_SUPPORT = true; --// If supports mobile
MOBILE_BUTTON_APPEARANCE = { --// Mobile button appearance
SIZE = UDim2.new(0, 50, 0, 50);
POSITION = UDim2.new(0.775, 0, -0.33, 0);
ICON_IMAGE = "rbxassetid://17027749156";
MOUSE_LOCKED_COLOR = Color3.fromRGB(50, 105, 255);
MOUSE_UNLOCKED_COLOR = Color3.fromRGB(255, 255, 255);
};
NOTE: I tried to change the PlayerModule as little as possible. The changes should not cause any bugs, but I cannot promise that they won’t.
I edited the PlayerModule version from 2025-06-30.
You can get the edited PlayerModule with API example here:
You might have also noticed that, using the default PlayerModule camera system, you cannot look up or down more than 80 degrees. That limit is configurable in the BaseCamera module:
-- Note: DotProduct check in CoordinateFrame::lookAt() prevents using values within about
-- 8.11 degrees of the +/- Y axis, that's why these limits are currently 80 degrees
local MIN_Y = math.rad(-80)
local MAX_Y = math.rad(80)
However, even if you change these limits to 90 degrees, as mentioned here, CFrame:LookAt() will still prevent the camera from rotating that far.
To combat this problem, I have also created a second version of my edited PlayerModule that changes how the camera’s look angle is calculated, thereby making a 90-degree camera pitch possible. This version also supports camera animations like rolling without making the camera flip. I really hope this functionality will be included in the official PlayerModule someday, as currently the camera seems rather limited.
Here is it in action:
And here is an example of doing camera animations with it:
As you can see, it allows smooth, extreme camera rotations (greater than 90-degree pitch) without flipping or glitching. Additionally, you do not need to use deltas when animating the camera and applying a camera offset is as simple as:
--// Applying Camera Offset
local Workspace = game:GetService("Workspace")
local RunService = game:GetService("RunService")
local Camera = Workspace.CurrentCamera
local CameraOffset = CFrame.Angles(-math.rad(10), 0, 0) --// No need for deltas
RunService:BindToRenderStep("CameraOffset", Enum.RenderPriority.Camera.Value + 1, function(DeltaTime: number) --// Can be just .RenderStepped:Connect()
Camera.CFrame *= CameraOffset
end)
NOTES:
-
I do not recommend using this in games, as it was an experimental modification that has not been thoroughly tested and may cause issues.
-
If your camera pitch exceeds 90 degrees, character movement will be reversed. I have not yet found a solution for this, but it should be possible to fix.
-
Additionally, MouseLock behavior is reversed when the pitch is over 90 degrees.
-
Finally, all scripts that change camera orientation may not work as intended, since you no longer need to use deltas to offset or move the camera.
If you want to try it, you can get it here: