Search docs
Search guides, modules and symbols
Custom camera

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.

ModeValueView
DISABLED0Player eye position and angles
CONTROLLED1Camera origin and angles
CONTROLLED_POSITION2Camera origin, player-controlled angles
FOLLOW_POSITION3Offset 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