@rbxts/cmove-wrapper
v1.0.0
Published
A sophisticated Roblox camera controller with smooth movement, rotation tracking, and intelligent occlusion detection. Features configurable smoothing, multiple tracking modes (lock/follow), and automatic obstacle avoidance with customizable reactions.
Maintainers
Readme
@rbxts/cmove-wrapper
Roblox-ts library for sophisticated camera control with smooth movement, rotation tracking, and intelligent occlusion detection. Control camera position and rotation with configurable smoothing, multiple tracking modes, and automatic obstacle avoidance with customizable reactions.
Features
- Smooth camera movement with exponential interpolation (
PositionSmoothing,RotationSmoothing). - Flexible targeting: lock to positions/CFrames, follow BaseParts, or maintain distance with
FollowPosition. - Dual tracking modes:
Lock(precise targeting) andFollow(radius-based following). - Occlusion detection: raycast-based obstacle detection with immediate and debounced (250ms) state tracking.
- Occlusion reactions:
None,Passthrough(move through obstacles), orAvoid(shift sideways). - Signals:
MoveTargetOcclusionChanged,LookTargetOcclusionChanged, and deferred variants for debounced events. - Configurable raycast parameters: filter descendants, ignore water, respect CanCollide.
- Optional filter callback for custom position/rotation processing each frame.
Documentation
Full API documentation: https://irishfix.github.io/rbxts-cmove-wrapper/
Installation
npm install @rbxts/cmove-wrapperQuick start
import { CMover, CMoveWrapper, ActiveMode, OcclusionReaction } from "@rbxts/cmove-wrapper";
// Create a CMover for the workspace camera with occlusion checking enabled
const camera = Workspace.CurrentCamera!;
const mover = new CMover(camera, true);
// Configure smoothing (lower = snappier, higher = smoother)
mover.PositionSmoothing = 0.3;
mover.RotationSmoothing = 0.2;
// Set up occlusion reaction
mover.OcclusionReaction = OcclusionReaction.Avoid;
mover.OcclusionCheckActive = true;
// Move camera to a position and look at a target
const targetPart = Workspace.WaitForChild("Target") as BasePart;
mover.MoveToPosition(new Vector3(0, 50, 0));
mover.LookAt(targetPart);
// Subscribe to occlusion events
mover.MoveTargetOcclusionChanged.Connect((current, previous) => {
print(`Move target occlusion changed: ${previous} -> ${current}`);
});
// Activate the camera system
mover.Active = true;
// Or use the wrapper with a filter callback to constrain camera height
const player = Players.LocalPlayer;
let currentHRP: BasePart | undefined;
const wrappedMover = CMoveWrapper.Wrap(camera, true, (newPosition: Vector3, newRotation: CFrame) => {
if (currentHRP) {
// Keep camera at least 5 studs above the character
const filteredPosition = new Vector3(
newPosition.X,
math.max(currentHRP.Position.Y + 5, newPosition.Y),
newPosition.Z
);
return [filteredPosition, newRotation] as LuaTuple<[Vector3, CFrame]>;
}
return [newPosition, newRotation] as LuaTuple<[Vector3, CFrame]>;
});
player.CharacterAdded.Connect((character) => {
const hrp = character.WaitForChild("HumanoidRootPart") as BasePart;
const head = character.WaitForChild("Head") as BasePart;
currentHRP = hrp;
wrappedMover.FollowPosition(hrp, 20); // Follow within 20 studs
wrappedMover.LookAt(head);
wrappedMover.SetOcclusionCheckIgnore(OcclusionIgnoreTarget.All, [character], true);
wrappedMover.Active = true;
wrappedMover.OcclusionCheckActive = true;
});API hints
- Creation:
new CMover(camera, occlusionChecking?, filterCallback?)orCMoveWrapper.Wrap(camera, ...). - Movement:
MoveTo(cframe),MoveToPosition(vector3),MoveWith(part),FollowPosition(part, maxDistance). - Rotation:
LookAt(target), or set viaMoveTo/MoveWithfor combined control. - Modes:
PositionMode/RotationMode(set toActiveMode.LockorActiveMode.Follow). - Smoothing:
PositionSmoothing/RotationSmoothing(time constants in seconds, 0 = instant). - Occlusion:
SetOcclusionCheckIgnore(target, filterDescendants, ignoreWater?, prioritiseCanCollide?). - Control:
Active(enable/disable updates),OcclusionCheckActive(enable/disable occlusion detection). - Cleanup:
Destroy()to unbind from RenderStep and disconnect all connections.
