Security Camera System

Physical Security Camera System

This system creates physical Live CCTV camera feeds using ViewportFrames.

| CCTV.rbxl (102.6 KB) | — | Creator Store |

It supports:

  • Multiple cameras
  • Multiple display screens
  • Camera grouping via the CameraGroup attribute
  • StreamingEnabled support
  • Automatic discovery of tagged instances

For example, you could create a prison with:

  • CameraGroup = "CellBlockA"
  • CameraGroup = "CellBlockB"

Displays assigned to each group will automatically show the appropriate camera feeds.



Quick Setup

1. Install

Place the SecurityCamera package inside ServerScriptService.


2. Tag Cameras

Tag every camera part with:

SecurityCamera.Camera

3. Tag Displays

Tag every monitor/display part with:

SecurityCamera.Display

4. (Optional) Configure Renderable Objects

You can limit what appears inside CCTV feeds by either:

  • Tagging instances with
SecurityCamera.Renderable

or placing renderable objects inside

Workspace.CCTVRenderable

5. (Optional) Configure Camera & Display Attributes

Attributes override the global defaults for individual cameras or displays.


6. Start the Service

local Workspace = game:GetService("Workspace")

local SecurityCameraService = require(script:WaitForChild("SecurityCameraService"))

local cameraService = SecurityCameraService.new({
	RenderSourceFolder = Workspace:FindFirstChild("CCTVRenderable"),

	PixelsPerStud = 90,
	Face = Enum.NormalId.Front,

	MaxSelectedCameras = 4,
	MaxActiveScreensPerPlayer = 2,
	MaxActiveFeedsPerPlayer = 4,
	ActivationRange = 80,

	RenderOnlyConfiguredSources = true,

	MirrorCharactersForStreaming = true,
	CharacterMirrorUpdateRate = 10,

	UpdateRate = 10,
	Debug = false,
	AutoDiscover = true,
})

cameraService:Start()

API Documentation

Tags

SecurityCamera.Camera

Assign this tag to any BasePart that should function as a CCTV camera.

The part’s CFrame determines the camera’s position and viewing direction.


SecurityCamera.Display

Assign this tag to any BasePart that should display CCTV feeds.

When a player is close enough, the system automatically creates a client-side SurfaceGui on the specified face.


SecurityCamera.Renderable

Optional

Use this tag on parts, models, or folders that should appear inside CCTV feeds.

When RenderOnlyConfiguredSources = true, feeds render in the following order:

  1. Tagged SecurityCamera.Renderable instances
  2. Workspace.CCTVRenderable
  3. Player characters

If RenderOnlyConfiguredSources = false, eligible Workspace content is rendered automatically.


Camera Attributes

These attributes are applied to parts tagged with SecurityCamera.Camera.

DisplayName: string

Display name shown above the feed.

DisplayName = Lobby Camera

If omitted, an ID such as CAM_001 is generated automatically.


FieldOfView: number

Camera field of view.

FieldOfView = 70

Default: 70

Range: 1–120


CameraGroup: string

Groups cameras and displays together.

CameraGroup = Lobby

Displays with the same group automatically receive those camera feeds.


Face: string

Surface of the display that receives the SurfaceGui.

Face = Front

PixelsPerStud: number

Viewport resolution density.

PixelsPerStud = 90

MaxSelectedCameras: number

Maximum number of feeds shown simultaneously.

MaxSelectedCameras = 4

Constructor

SecurityCameraService.new(props)

Rendering

RenderSourceFolder: Instance?

Fallback folder or model used when no tagged renderables exist.

Typically:

Workspace:FindFirstChild("CCTVRenderable")

RenderOnlyConfiguredSources: boolean?

Default:

true

When enabled, feeds render only:

SecurityCamera.Renderable
Workspace.CCTVRenderable

When disabled, feeds clone all eligible Workspace content except:

Terrain
Camera instances
Scripts
LocalScripts
Player character models

PixelsPerStud: number?

Default:

80

Face: Enum.NormalId?

Default:

Enum.NormalId.Front

Display Limits

MaxSelectedCameras

Default:

4

MaxActiveScreensPerPlayer

Maximum nearby displays rendered by each player.

Default:

2

MaxActiveFeedsPerPlayer

Maximum active feeds rendered per player.

Default:

MaxSelectedCameras or 4

ActivationRange

Distance required before a display activates.

Default:

80

Streaming Support

MirrorCharactersForStreaming

Default:

true

When enabled, server-side character mirrors are replicated so CCTV feeds continue displaying players when StreamingEnabled unloads their Workspace character.


CharacterMirrorUpdateRate

Mirror update frequency.

Default:

UpdateRate or 10

UpdateRate

Feed refresh rate.

Default:

10

Tags

CameraTag

Default:

SecurityCamera.Camera

DisplayTag

Default:

SecurityCamera.Display

RenderableTag

Default:

SecurityCamera.Renderable

Discovery

AutoDiscover

Default:

true

When disabled, manually refresh tagged instances:

cameraService:RefreshTaggedInstances()

Debug

Default:

false

Enables debug output.


Service Methods

Start

cameraService:Start()

Starts the system.

This will:

  • Discover tagged cameras and displays
  • Replicate configuration
  • Start character mirrors
  • Deploy the client package
  • Listen for newly tagged instances

Destroy

cameraService:Destroy()

Stops the system.

This:

  • Disconnects listeners
  • Removes replicated configuration
  • Removes character mirrors
  • Removes deployed client packages
  • Clears camera and display registries

RefreshTaggedInstances

cameraService:RefreshTaggedInstances()

Manually rescans tagged cameras and displays.

Useful when:

AutoDiscover = false

AddCamera

cameraService:AddCamera(id, cameraPart, displayName, fieldOfView)

Example:

cameraService:AddCamera(
	"VaultCam",
	workspace.VaultCameraPart,
	"Vault Camera",
	70
)

AddScreen

cameraService:AddScreen(id, screenPart, cameraIds, displayName)

Automatic camera assignment:

cameraService:AddScreen(
	"LobbyScreen",
	workspace.LobbyMonitor,
	nil,
	"Lobby Monitor"
)

Specific cameras:

cameraService:AddScreen(
	"VaultScreen",
	workspace.VaultMonitor,
	{"VaultCam", "HallwayCam"},
	"Vault Monitor"
)

RemoveCamera

cameraService:RemoveCamera("VaultCam")

RemoveScreen

cameraService:RemoveScreen("VaultScreen")

Multiplayer

Each player renders CCTV feeds locally.

This means:

  • Camera selection is per-player.
  • Displays activate independently for each player.
  • Distant displays consume no rendering cost.
  • Feed rendering is limited by MaxActiveScreensPerPlayer.
  • Individual displays are limited by MaxActiveFeedsPerPlayer and MaxSelectedCameras.

StreamingEnabled

When using StreamingEnabled, distant player characters may not exist on the client.

Keep:

MirrorCharactersForStreaming = true

The server creates mirrors inside:

ReplicatedStorage.SecurityCameraCharacterMirrors

Feeds automatically use:

  • the real streamed character when available
  • the replicated mirror otherwise

Mirrors remove:

Scripts
LocalScripts
Sounds

to prevent duplicated character sounds.


Recommended Settings

General

MaxSelectedCameras = 4
MaxActiveScreensPerPlayer = 2
MaxActiveFeedsPerPlayer = 4
ActivationRange = 80
RenderOnlyConfiguredSources = true
MirrorCharactersForStreaming = true
CharacterMirrorUpdateRate = 10
UpdateRate = 10
PixelsPerStud = 90

Performance-Focused

MaxSelectedCameras = 2
MaxActiveScreensPerPlayer = 1
MaxActiveFeedsPerPlayer = 2
CharacterMirrorUpdateRate = 6
UpdateRate = 6
RenderOnlyConfiguredSources = true
1 Like


This is…Unfortunate.

1 Like

Hmm, I made this with a base r6 character and did not come across this. After testing with my regular player model, it does seem it has difficulties replicating certain clothing and attachments.

I will try looking for a fix.