Custom camera
CS2’s experimental pawn-owned camera. pawn.getCustomCamera() returns CustomPlayerCamera | null and creates the camera on demand. Requires CS2’s September 9, 2026 engine update and a matching s2script runtime shim — an older shim cannot acquire the camera.
import { command } from '@s2script/sdk';
import { CustomCameraMode, Pawn } from '@s2script/cs2';
export function OnPluginStart(): void {
command('third', (cmd) => {
const pawn = Pawn.forSlot(cmd.callerSlot);
const camera = pawn?.getCustomCamera();
if (!camera || !pawn) return;
camera.setFollowConfig({
followEntity: pawn.ref,
followEyes: true,
cameraOffset: { x: -80, y: 0, z: 20 }
});
camera.setMode(CustomCameraMode.FOLLOW_POSITION);
});
}null if the pawn is stale or the camera bindings are unavailable.
Modes#
getMode() / setMode(mode) use CustomCameraMode. setMode returns false if the camera is stale, the mode is invalid, or the native rejected the call.
| Mode | Value | View |
|---|---|---|
DISABLED | 0 | Player eye position and angles |
CONTROLLED | 1 | Camera origin and angles |
CONTROLLED_POSITION | 2 | Camera origin, player-controlled angles |
FOLLOW_POSITION | 3 | Offset from a followed position, player-controlled angles |
Position a controlled camera with camera.ref.teleport(position, angles).
Follow#
Configure following before FOLLOW_POSITION. setFollowConfig requires followEntity; it returns false on invalid or stale input.
camera.setFollowConfig({
followEntity: pawn.ref, // required
followEyes: true, // default false — eyes instead of origin
followOffset: { x: 0, y: 0, z: 0 },
cameraOffset: { x: -80, y: 0, z: 16 }, // forward / left / up, rotated by eye angles
clipCameraOffset: true, // pull inward to avoid solids
cameraOffsetReturnStrength: 1 // default 1 (instant)
});Ownership#
The camera is borrowed and pawn-owned. Every script on that pawn shares the same engine entity; the latest mutation wins. Disable when finished (setMode(CustomCameraMode.DISABLED)). Do not remove() or delete it — the engine owns its association with the pawn. Plugin unload does not undo engine state.
getPlayer() returns the owning Pawn, or null if stale. isValid() is entity-liveness gated. Experimental, matching Valve.
Hazards#
- Disable, don’t delete —
setMode(DISABLED)when you are done. Removing the entity breaks the pawn’s camera association. - Shared state — another plugin can overwrite your mode or follow config. Treat the camera as a mutex you must release.
- Matching runtime — camera + observable HUD need the updated CS2 engine and the matching s2script shim.
See also#
- Entities —
EntityRef,Pawn, teleport - HUD — observable layouts from the same CS2 update
- CS2 module —
Pawn.getCustomCamera,CustomPlayerCamera,CustomCameraMode