A Resource for Lazy Programmers
Hello there. I am just open sourcing this. The scripts here I created because I found myself re-writing a lot of code similar to this. So, I thought it would be useful for me to open source this. Each script comes with a description on where when and how to use it. Most of these scripts aren’t really essential but I found if you find yourself re-writing a lot of these then you can simply copy-paste and use it in game jams or to reach deadlines etc.
Types
Love autocomplete? So, do I . As such I typed all the “untyped” but documented objects. Making autocomplete do the rest of the work for you. I found the most useful is the ChatService types which make scripting ChatModules a cinch.
Type
 local Types = {} export type dictionary<I,V> = {[I]: V} export type array<V> = {[number]: V} export type TerrainMaterial = {	Size: Vector3,	[number]: {{Enum.Material}} } export type TerrainOccupancy = {	Size: Vector3,	[number]: {{number}} } export type OnlineFriend = {	VisitorId: number,	UserName :string,	DisplayName :string,	LastOnline :string,	IsOnline :boolean,	LastLocation: string,	PlaceId: number,	GameId:	string,	LocationType: number } export type HttpRequestOptions = {	Url: string	,	Method: string?,	Headers: dictionary<string,string>?,	Body: string? } export type HttpResponse = {	Success: boolean,	StatusCode:	number,	StatusMessage: string,	Headers: dictionary<string,string>,	Body: any } export type ChatMessageConfig = {	Text: string,	Color: Color3?,	Font: Enum.Font?,	TextSize: number?, } export type NotificationConfig = {	Title: string,	Text: string,	Icon: string?,	Duration: number?,	Callback: BindableFunction?,	Button1: string?,	Button2: string? } export type AgentParameters = {	AgentRadius: number?,	AgentHeight: number?,	AgentCanJump: boolean?,	WaypointSpacing: number?,	Costs: dictionary<string,number>? } export type BoundActionInfo = {	stackOrder:number,	priorityLevel:number,	createTouchButton:boolean,	inputTypes:{Enum.UserInputType | Enum.KeyCode},	description:string?,	title:string?,	image:string?, } export type ExtraData = {	ChatColor: Color3,	NameColor: string,	Font: Enum.Font,	TextSize: number,	Tags: array<string>, } export type CustomRBXScriptSignal<Arguments> = {	Wait: (CustomRBXScriptSignal<Arguments>) -> (),	Connect: (CustomRBXScriptSignal<Arguments>,(Arguments: any) -> ()) -> (RBXScriptConnection),	ConnectParallel: (CustomRBXScriptSignal<Arguments>,(Arguments: any) -> ()) -> (RBXScriptConnection) } export type ChatService = {	AddChannel: (ChatService: ChatService, channelName: string) -> (ChatChannel),	RemoveChannel: (ChatService: ChatService, channelName: string) -> (),	GetChannel: (ChatService: ChatService, channelName: string) -> (ChatChannel),	AddSpeaker: (ChatService: ChatService, speakerName: string) -> (ChatSpeaker),	RemoveSpeaker: (ChatService: ChatService, speakerName: string) -> (),	GetSpeaker: (ChatService: ChatService, speakerName: string) -> (ChatSpeaker),	GetChannelList: (ChatService: ChatService) -> (array<string>),	GetAutoJoinChannelList: (ChatService: ChatService) -> (array<string>),	RegisterFilterMessageFunction: (ChatService: ChatService, functionId: string, func: (speaker: string, messageObject: ChatMessage, channelName: string) -> ()) -> (),	UnregisterFilterMessageFunction: (ChatService: ChatService, functionId: string) -> (),	RegisterProcessCommandsFunction: (ChatService: ChatService, functionId: string, func: (speakerName: string, message: string, channelName: string) -> ()) -> (),	UnregisterProcessCommandsFunction: (ChatService: ChatService, functionId: string) -> (),	ChannelAdded: RBXScriptSignal,	ChannelRemoved: RBXScriptSignal,	SpeakerAdded: RBXScriptSignal,	SpeakerRemoved: RBXScriptSignal, } export type ChatMessage = {	ID: number,	FromSpeaker: string,	OriginalChannel: string,	IsFiltered: boolean,	MessageLength: number,	Message: string,	MessageType: string,--"Message", "System", "MeCommand", "Welcome", "SetCore", "Whisper	Time: number,	ExtraData: ExtraData } export type ChatChannel = {	Name: string,	WelcomeMessage: string,	Joinable: boolean,	Leavable: boolean,	AutoJoin: boolean,	Private: boolean,	KickSpeaker: (speakerName: string, reason: string?) -> (),	MuteSpeaker: (speakerName: string, reason: string?, duration: number?) -> (),	UnmuteSpeaker: (speakerName: string) -> (),	IsSpeakerMuted: (speakerName: string) -> (boolean),	GetSpeakerList: () -> (array<string>),	SendSystemMessage: (message: string),	RegisterFilterMessageFunction: (functionId: string, func: (speaker: string, messageObject: ChatMessage, channelName: string) -> ()) ->(),	UnregisterProcessCommandsFunction: (functionId: string) -> (),	MessagePosted: RBXScriptSignal,	SpeakerJoined: RBXScriptSignal,	SpeakerLeft: RBXScriptSignal,	SpeakerMuted: RBXScriptSignal,	SpeakerUnmuted: RBXScriptSignal, } export type ChatSpeaker = {	Name: string,	JoinChannel: (ChatSpeaker, channelName: string) -> (),	LeaveChannel: (ChatSpeaker, channelName: string) -> (),	GetChannelList: (ChatSpeaker) -> ({channelName: string}),	IsInChannel: (ChatSpeaker, channelName: string) -> (boolean),	SayMessage: (ChatSpeaker, message: string,channelName: string,extraData: ExtraData?) -> (ChatMessage),	SendMessage: (ChatSpeaker, mesage: string,channelName: string,fromSpeaker: string) -> (),	SendSystemMessage: (ChatSpeaker, messsage: string,channelName: string) -> (),	GetPlayer: (ChatSpeaker) -> (Player?),	SetExtraData: (ChatSpeaker, key: string,data: ExtraData) -> (),	GetExtraData: (ChatSpeaker) -> (),	SetMainChannel: (ChatSpeaker, channelName: string) -> (nil),	SaidMessage: RBXScriptSignal,	ReceivedMessage: RBXScriptSignal,	ReceivedSystemMessage: RBXScriptSignal,	ChannelJoined: RBXScriptSignal,	ChannelLeft: RBXScriptSignal,	Muted: RBXScriptSignal,	Unmuted: RBXScriptSignal,	ExtraDataUpdated: RBXScriptSignal,	MainChannelSet: RBXScriptSignal, } return Types Example of use in action
Scripting Templates
This is probably helpful for people who already know what they want to do. I have only created a couple of templates. Most of the template are Classes. I am out of ideas for new templates. If you have any leave your idea down below.
ServerToolScript
--!strict -- Services local Players = game:GetService("Players") -- References local Tool: Tool = script.Parent -- Variable local ACTIVATED_Connection: RBXScriptConnection = nil -- Events Tool.Equipped:Connect(function()-- Connect events after equip	local Character = Tool.Parent	local Player: Player? = Players:GetPlayerFromCharacter(Character)	if Player then	ACTIVATED_Connection = Tool.Activated:Connect(function()	Tool.Deactivated:Wait()	end)	Tool.Unequipped:Wait() -- Disconnect events after unequip	ACTIVATED_Connection:Disconnect()	end end) ClientToolScript
--!strict -- Services local UserInputService = game:GetService("UserInputService") local ContextActionService = game:GetService("ContextActionService") local Players = game:GetService("Players") -- References local Tool: Tool = script.Parent local Player = Players.LocalPlayer -- Variable local LMB_Connection: RBXScriptConnection = nil local RMB_Connection: RBXScriptConnection = nil -- Events Tool.Equipped:Connect(function(mouse: Mouse)-- Connect events after equip	LMB_Connection = mouse.Button1Down:Connect(function()	local Origin: CFrame = mouse.Origin	mouse.Button1Up:Wait()	end)	RMB_Connection = mouse.Button2Down:Connect(function()	mouse.Button2Up:Wait()	end)	Tool.Unequipped:Wait() -- Disconnect events after unequip	LMB_Connection:Disconnect()	RMB_Connection:Disconnect() end) Object-Oriented-Programming Classes
Here is a list of different OOP methods I found on the devforum whilst making this imply copy and paste the templatess
Class
local Class = {} Class._index = Class function Class.new()	local self = setmetatable(	{	},	Class	)	return self end Class.Do = function(self) end return Class ClosureClass
local ClosureClass = {} function ClosureClass.new()	local self = {	}	local function Do()	end	return {	Do = Do	} end return ClosureClass ProxyClass
local ClassMain = {} local ClassProxy = {} local ClassMeta = {} local ChangedEvent = Instance.new("BindableEvent") ClassProxy.Changed = ChangedEvent.Event ClassMeta.__index = ClassProxy ClassMeta.__newindex = function(t, i, v)	if t[i] ~= v then	ClassProxy[i] = v	ChangedEvent:Fire(i, v)	end end function ClassMain.new(self)	self = setmetatable(ClassMain,ClassMeta)	return self end return ClassProxy NewConstructorClass
local Class = {} Class.__index = Class local function new()	local self = {	}	return setmetatable(self, Class) end setmetatable(Class, {__call = new}) function Class:Do() end return Class ChatModule
-- Type needed local Types = require(script.Parent.Types) type ChatService = Types.ChatService local function Run(ChatService: ChatService) end return Run Module
Other misc modules. Planning to add a simple data handler module.
MaidModule
local Maid = {} function Maid.new()	local self = {	_tasks = {},	}	setmetatable(self, Maid)	return self end function Maid:__index(key)	return Maid[key] or self._tasks[key] end function Maid:__newindex(key, newTask)	if Maid[key] then	error(string.format("Cannot use %q as a Maid key", tostring(key)))	end	local tasks = self._tasks	local oldTask = tasks[key]	tasks[key] = newTask	if oldTask then	Maid.cleanupTask(oldTask)	end end function Maid:give(task)	local tasks = self._tasks	tasks[#tasks+1] = task end function Maid.cleanupTask(task)	local taskTy = typeof(task)	if taskTy == 'function' then	task()	elseif taskTy == 'RBXScriptConnection' then	task:Disconnect()	elseif taskTy == 'Instance' then	task:Destroy()	elseif task.Destroy then	task:Destroy()	elseif task.destroy then	task:destroy()	elseif task.disconnect then	task:disconnect()	else	error("Unable to cleanup unknown task")	end end function Maid:clean()	local tasks = self._tasks	for key,task in pairs(tasks) do	if typeof(task) == 'RBXScriptConnection' then	tasks[key] = nil	task:Disconnect()	end	end	local index, task = next(tasks)	while task ~= nil do	tasks[index] = nil	Maid.cleanupTask(task)	index, task = next(tasks)	end end Maid.destroy = Maid.clean Maid.Destroy = Maid.clean return Maid Stack
Stack = {} Stack.__index = Stack function Stack.new() return setmetatable({}, Stack) end -- put a new object onto a stack function Stack:push(input)	self[#self+1] = input end -- take an object off a stack function Stack:pop()	assert(#self > 0, "Stack underflow")	local output = self[#self]	self[#self] = nil	return output end Ragdoll
RagdollModule
local CollectionService = game:GetService("CollectionService") local Players = game:GetService("Players") local RigTypes = require(script.RigTypes) local RAGDOLLED_TAG = "__Ragdoll_Active" local function ragdoll(model, humanoid)	assert(humanoid:IsDescendantOf(model))	if CollectionService:HasTag(model, RAGDOLLED_TAG) then	return	end	CollectionService:AddTag(model, RAGDOLLED_TAG)	-- Turn into loose body:	humanoid:ChangeState(Enum.HumanoidStateType.Physics)	-- Instantiate BallSocketConstraints:	local attachments = RigTypes.getAttachments(model, humanoid.RigType)	for name, objects in pairs(attachments) do	local parent = model:FindFirstChild(name)	if parent then	local constraint = Instance.new("BallSocketConstraint")	constraint.Name = "RagdollBallSocketConstraint"	constraint.Attachment0 = objects.attachment0	constraint.Attachment1 = objects.attachment1	constraint.LimitsEnabled = true	constraint.UpperAngle = objects.limits.UpperAngle	constraint.TwistLimitsEnabled = true	constraint.TwistLowerAngle = objects.limits.TwistLowerAngle	constraint.TwistUpperAngle = objects.limits.TwistUpperAngle	constraint.Parent = parent	end	end	-- Instantiate NoCollisionConstraints:	local parts = RigTypes.getNoCollisions(model, humanoid.RigType)	for _, objects in pairs(parts) do	local constraint = Instance.new("NoCollisionConstraint")	constraint.Name = "RagdollNoCollisionConstraint"	constraint.Part0 = objects[1]	constraint.Part1 = objects[2]	constraint.Parent = objects[1]	end	-- Destroy all regular joints:	for _, motor in pairs(model:GetDescendants()) do	if motor:IsA("Motor6D") then	motor:Destroy()	end	end end return ragdoll RigTypes
local RigTypes = {} local HEAD_LIMITS = {	UpperAngle = 60;	TwistLowerAngle = -60;	TwistUpperAngle = 60; } local LOWER_TORSO_LIMITS = {	UpperAngle = 20;	TwistLowerAngle = -30;	TwistUpperAngle = 60; } local HAND_FOOT_LIMITS = {	UpperAngle = 10;	TwistLowerAngle = -10;	TwistUpperAngle = 10; } local ELBOW_LIMITS = {	UpperAngle = 30;	TwistLowerAngle = 0;	TwistUpperAngle = 120; } local KNEE_LIMITS = {	UpperAngle = 30;	TwistLowerAngle = -120;	TwistUpperAngle = 0; } local SHOULDER_LIMITS = {	UpperAngle = 60;	TwistLowerAngle = -60;	TwistUpperAngle = 175; } local HIP_LIMITS = {	UpperAngle = 40;	TwistLowerAngle = -5;	TwistUpperAngle = 150; } local R6_HEAD_LIMITS = {	UpperAngle = 30;	TwistLowerAngle = -60;	TwistUpperAngle = 60; } local R6_SHOULDER_LIMITS = {	UpperAngle = 90;	TwistLowerAngle = -30;	TwistUpperAngle = 175; } local R6_HIP_LIMITS = {	UpperAngle = 60;	TwistLowerAngle = -5;	TwistUpperAngle = 120; } local function createJointData(attach0, attach1, limits)	assert(attach0)	assert(attach1)	assert(limits)	assert(limits.UpperAngle >= 0)	assert(limits.TwistLowerAngle <= limits.TwistUpperAngle)	return {	attachment0 = attach0,	attachment1 = attach1,	limits = limits	} end local function find(model)	return function(first, second, limits)	local part0 = model:FindFirstChild(first[1])	local part1 = model:FindFirstChild(second[1])	if part0 and part1 then	local attach0 = part0:FindFirstChild(first[2])	local attach1 = part1:FindFirstChild(second[2])	if attach0 and attach1 and attach0:IsA("Attachment") and attach1:IsA("Attachment") then	return createJointData(attach0, attach1, limits)	end	end	end end function RigTypes.getNoCollisions(model, rigType)	if rigType == Enum.HumanoidRigType.R6 then	return RigTypes.getR6NoCollisions(model)	elseif rigType == Enum.HumanoidRigType.R15 then	return RigTypes.getR15NoCollisions(model)	else	return {}	end end -- Get list of attachments to make ballsocketconstraints between: function RigTypes.getAttachments(model, rigType)	if rigType == Enum.HumanoidRigType.R6 then	return RigTypes.getR6Attachments(model)	elseif rigType == Enum.HumanoidRigType.R15 then	return RigTypes.getR15Attachments(model)	else	return {}	end end function RigTypes.getR6Attachments(model)	local rightLegAttachment = Instance.new("Attachment")	rightLegAttachment.Name = "RagdollRightLegAttachment"	rightLegAttachment.Position = Vector3.new(0, 1, 0)	rightLegAttachment.Parent = model:FindFirstChild("Right Leg")	local leftLegAttachment = Instance.new("Attachment")	leftLegAttachment.Name = "RagdollLeftLegAttachment"	leftLegAttachment.Position = Vector3.new(0, 1, 0)	leftLegAttachment.Parent = model:FindFirstChild("Left Leg")	local torsoLeftAttachment = Instance.new("Attachment")	torsoLeftAttachment.Name = "RagdollTorsoLeftAttachment"	torsoLeftAttachment.Position = Vector3.new(-0.5, -1, 0)	torsoLeftAttachment.Parent = model:FindFirstChild("Torso")	local torsoRightAttachment = Instance.new("Attachment")	torsoRightAttachment.Name = "RagdollTorsoRightAttachment"	torsoRightAttachment.Position = Vector3.new(0.5, -1, 0)	torsoRightAttachment.Parent = model:FindFirstChild("Torso")	local headAttachment = Instance.new("Attachment")	headAttachment.Name = "RagdollHeadAttachment"	headAttachment.Position = Vector3.new(0, -0.5, 0)	headAttachment.Parent = model:FindFirstChild("Head")	local leftArmAttachment = Instance.new("Attachment")	leftArmAttachment.Name = "RagdollLeftArmAttachment"	leftArmAttachment.Position = Vector3.new(0.5, 1, 0)	leftArmAttachment.Parent = model:FindFirstChild("Left Arm")	local ragdollRightArmAttachment = Instance.new("Attachment")	ragdollRightArmAttachment.Name = "RagdollRightArmAttachment"	ragdollRightArmAttachment.Position = Vector3.new(-0.5, 1, 0)	ragdollRightArmAttachment.Parent = model:FindFirstChild("Right Arm")	local query = find(model)	return {	Head = query(	{"Torso", "NeckAttachment"},	{"Head", "RagdollHeadAttachment"},	R6_HEAD_LIMITS),	["Left Arm"] = query(	{"Torso", "LeftCollarAttachment"},	{"Left Arm", "RagdollLeftArmAttachment"},	R6_SHOULDER_LIMITS),	["Right Arm"] = query(	{"Torso", "RightCollarAttachment"},	{"Right Arm", "RagdollRightArmAttachment"},	R6_SHOULDER_LIMITS),	["Left Leg"] = createJointData(torsoLeftAttachment, leftLegAttachment, R6_HIP_LIMITS),	["Right Leg"] = createJointData(torsoRightAttachment, rightLegAttachment, R6_HIP_LIMITS),	} end function RigTypes.getR15Attachments(model)	local query = find(model)	return {	Head = query(	{"UpperTorso", "NeckRigAttachment"},	{"Head", "NeckRigAttachment"},	HEAD_LIMITS),	LowerTorso = query(	{"UpperTorso", "WaistRigAttachment"},	{"LowerTorso", "WaistRigAttachment"},	LOWER_TORSO_LIMITS),	LeftUpperArm = query(	{"UpperTorso", "LeftShoulderRigAttachment"},	{"LeftUpperArm", "LeftShoulderRigAttachment"},	SHOULDER_LIMITS),	LeftLowerArm = query(	{"LeftUpperArm", "LeftElbowRigAttachment"},	{"LeftLowerArm", "LeftElbowRigAttachment"},	ELBOW_LIMITS),	LeftHand = query(	{"LeftLowerArm", "LeftWristRigAttachment"},	{"LeftHand", "LeftWristRigAttachment"},	HAND_FOOT_LIMITS),	RightUpperArm = query(	{"UpperTorso", "RightShoulderRigAttachment"},	{"RightUpperArm", "RightShoulderRigAttachment"},	SHOULDER_LIMITS),	RightLowerArm = query(	{"RightUpperArm", "RightElbowRigAttachment"},	{"RightLowerArm", "RightElbowRigAttachment"},	ELBOW_LIMITS),	RightHand = query(	{"RightLowerArm", "RightWristRigAttachment"},	{"RightHand", "RightWristRigAttachment"},	HAND_FOOT_LIMITS),	LeftUpperLeg = query(	{"LowerTorso", "LeftHipRigAttachment"},	{"LeftUpperLeg", "LeftHipRigAttachment"},	HIP_LIMITS),	LeftLowerLeg = query(	{"LeftUpperLeg", "LeftKneeRigAttachment"},	{"LeftLowerLeg", "LeftKneeRigAttachment"},	KNEE_LIMITS),	LeftFoot = query(	{"LeftLowerLeg", "LeftAnkleRigAttachment"},	{"LeftFoot", "LeftAnkleRigAttachment"},	HAND_FOOT_LIMITS),	RightUpperLeg = query(	{"LowerTorso", "RightHipRigAttachment"},	{"RightUpperLeg", "RightHipRigAttachment"},	HIP_LIMITS),	RightLowerLeg = query(	{"RightUpperLeg", "RightKneeRigAttachment"},	{"RightLowerLeg", "RightKneeRigAttachment"},	KNEE_LIMITS),	RightFoot = query(	{"RightLowerLeg", "RightAnkleRigAttachment"},	{"RightFoot", "RightAnkleRigAttachment"},	HAND_FOOT_LIMITS),	} end function RigTypes.getR6NoCollisions(model)	local list = {}	local function addPair(pair)	local part0 = model:FindFirstChild(pair[1])	local part1 = model:FindFirstChild(pair[2])	if part0 and part1 then	table.insert(list, {part0, part1})	end	end	addPair({"Head", "Torso"})	addPair({"Left Arm", "Torso"})	addPair({"Right Arm", "Torso"})	addPair({"Left Leg", "Torso"})	addPair({"Right Leg", "Torso"})	addPair({"Left Leg", "Right Leg"})	return list end function RigTypes.getR15NoCollisions(model)	local list = {}	local function addPair(pair)	local part0 = model:FindFirstChild(pair[1])	local part1 = model:FindFirstChild(pair[2])	if part0 and part1 then	table.insert(list, {part0, part1})	end	end	addPair({"Head", "UpperTorso"})	addPair({"UpperTorso", "LowerTorso"})	addPair({"UpperTorso", "LeftUpperArm"})	addPair({"LowerTorso", "LeftUpperArm"})	addPair({"LeftUpperArm", "LeftLowerArm"})	addPair({"LeftLowerArm", "LeftHand"})	addPair({"LeftUpperArm", "LeftHand"})	addPair({"UpperTorso", "RightUpperArm"})	addPair({"LowerTorso", "RightUpperArm"})	addPair({"RightUpperArm", "RightLowerArm"})	addPair({"RightLowerArm", "RightHand"})	addPair({"RightUpperArm", "RightHand"})	addPair({"LeftUpperLeg", "RightUpperLeg"})	addPair({"UpperTorso", "RightUpperLeg"})	addPair({"LowerTorso", "RightUpperLeg"})	addPair({"RightUpperLeg", "RightLowerLeg"})	addPair({"RightLowerLeg", "RightFoot"})	addPair({"RightUpperLeg", "RightFoot"})	addPair({"UpperTorso", "LeftUpperLeg"})	addPair({"LowerTorso", "LeftUpperLeg"})	addPair({"LeftUpperLeg", "LeftLowerLeg"})	addPair({"LeftLowerLeg", "LeftFoot"})	addPair({"LeftUpperLeg", "LeftFoot"})	-- Support weird R15 rigs	addPair({"UpperTorso", "LeftLowerLeg"})	addPair({"UpperTorso", "RightLowerLeg"})	addPair({"LowerTorso", "LeftLowerLeg"})	addPair({"LowerTorso", "RightLowerLeg"})	addPair({"UpperTorso", "LeftLowerArm"})	addPair({"UpperTorso", "RightLowerArm"})	local upperTorso = model:FindFirstChild("UpperTorso")	if upperTorso and upperTorso.Size.x <= 1.5 then	addPair({"Head", "LeftUpperArm"})	addPair({"Head", "RightUpperArm"})	end	return list end return RigTypes Dataset
local Set = {} Set.__index = Set -- Function to construct a set from an optional list of items function Set.new(items)	local newSet = {}	for key, value in ipairs(items or {}) do	newSet[value] = true	end	return setmetatable(newSet, Set) end -- Function to add an item to a set function Set:add(item)	self[item] = true end -- Function to remove an item from a set function Set:remove(item)	self[item] = nil end -- Function to check if a set contains an item function Set:contains(item)	return self[item] == true end -- Function to output set as a comma-delimited list for debugging function Set:output()	local elems = {}	for key, value in pairs(self) do	table.insert(elems, tostring(key))	end	print(table.concat(elems, ", ")) end function Set.getIntersection(set1, set2)	local result = Set.new()	for key, value in pairs(set1) do	if set2:contains(key) then	result:add(key)	end	end	return result end function Set:__add(otherSet)	local result = Set.new()	for entry in pairs(self) do	result[entry] = true	end	for entry in pairs(otherSet) do	result[entry] = true	end	return result end function Set:__sub(otherSet)	local result = Set.new()	for entry in pairs(self) do	result[entry] = true	end	for entry in pairs(otherSet) do	result[entry] = nil	end	return result end return Set Smooth Camera
-- Services local ContextActionService = game:GetService("ContextActionService") local RunService = game:GetService("RunService") local UserInputService = game:GetService("UserInputService") local GameSettings = UserSettings().GameSettings local RenderSettings = game:GetService("RenderSettings") -- References local Players = game:GetService("Players") local Camera = workspace.CurrentCamera local Player = Players.LocalPlayer -- Objects local SmoothCamera = {	CameraSubject = nil;	CameraRotation = {	X = 0,	Y = 45	};	CameraMaxZoomDistance = 50;	CameraMinZoomDistance = 0.1;	CameraDistance = 25;	LockToCharacter = true,	SmoothSpeed = 3 } -- Constants local sin, cos, rad = math.sin, math.cos, math.rad local clamp, abs = math.clamp, math.abs local Vector2new = Vector2.new local Vector3new = Vector3.new local min, max = math.min, math.max local RandomShake = Random.new() -- Variables local SubjectPosition = Vector3new() local PointerEvent: RBXScriptConnection = nil local CacheCFrame: CFrame = nil local Fullscreen: boolean = GameSettings:InFullScreen() local QualityLevel: number = GameSettings.SavedQualityLevel.Value local CameraRotationMatrix = CFrame.new() local qW = 30 -- Quaternion rotation speed local S = 1 local ShakeType = nil -- Functions local function UpdateCamera(DeltaTime)	local MouseDelta = UserInputService:GetMouseDelta() * -GameSettings.MouseSensitivity	SmoothCamera.CameraRotation.X += MouseDelta.X	SmoothCamera.CameraRotation.Y += MouseDelta.Y	-- UpValue S prevents camera from moving past clamp	--[[if abs(SmoothCamera.CameraRotation.Y) > 1000 then	S = 0	SmoothCamera.CameraRotation.Y = clamp(SmoothCamera.CameraRotation.Y,-1000,1000)	else	S = 1	end]]	-- Rotate Camera on Y Axis	CameraRotationMatrix *= (CFrame.new(0,0,0,rad(MouseDelta.Y * S),0,0,qW))	-- Rotate Camera on Z Axis	--CameraRotationMatrix *= (CFrame.Angles(0,rad(MouseDelta.X / 16),0))	CameraRotationMatrix = (CFrame.Angles(0,rad(MouseDelta.X / 16),0) * CameraRotationMatrix)	if SmoothCamera.LockToCharacter then	CacheCFrame = SmoothCamera.CameraSubject.CFrame:ToWorldSpace(CameraRotationMatrix)	else	CacheCFrame = CameraRotationMatrix + SmoothCamera.CameraSubject.Position	end	-- Lerp Camera Target	if SmoothCamera.CameraSubject.Position == SmoothCamera.CameraSubject.Position then	SubjectPosition = SubjectPosition:Lerp(	SmoothCamera.CameraSubject.Position,	min(0.5,DeltaTime * SmoothCamera.SmoothSpeed*3)--30	)	end	-- Lerp Camera Position and UpVector	Camera.CFrame = CFrame.lookAt(	Camera.CFrame.Position:Lerp(	CacheCFrame.Position+(CacheCFrame.LookVector * -SmoothCamera.CameraDistance),	min(0.5,DeltaTime * SmoothCamera.SmoothSpeed*2)--20	),	SubjectPosition,	Camera.CFrame.UpVector:Lerp(	CacheCFrame.UpVector,	min(0.5,DeltaTime * SmoothCamera.SmoothSpeed)--10	)	) end function ShakeCamera(DeltaTime)	Camera.CFrame += Vector3.new(RandomShake:NextNumber(-2,2),RandomShake:NextNumber(-2,2),0) end function SmoothCamera:Init(LockToCharacter: boolean?)	SmoothCamera.LockToCharacter = LockToCharacter or false	RunService:BindToRenderStep("SmoothCameraUpdate",Enum.RenderPriority.Camera.Value,UpdateCamera)	PointerEvent = UserInputService.PointerAction:Connect(function(Wheel,Pan,Pinch,GameProcessedEvent)	SmoothCamera.CameraDistance = clamp(	SmoothCamera.CameraDistance - (Wheel + Pinch) * GameSettings.MouseSensitivity * 5,	SmoothCamera.CameraMinZoomDistance,	SmoothCamera.CameraMaxZoomDistance	)	end) end function SmoothCamera:Term()	RunService:UnbindFromRenderStep("SmoothCameraUpdate")	PointerEvent:Disconnect() end function SmoothCamera:Shake(Duration: number)--,Type: number?)	--[[ Types: -- Not implemented yet	* UpDown	* LeftRight	* All	* Rotate	* InOut	]]	RunService:BindToRenderStep("Shake",Enum.RenderPriority.Camera.Value + 1,ShakeCamera)	task.delay(Duration,RunService.UnbindFromRenderStep,RunService,"Shake") end -- Events -- Init return SmoothCamera Method
This module is a collection of methods and functions that I found useful to me whilst scripting. If you have any thing more to add to this please leve it in the bottom or dm me on discord.
Method
 local newVector3 = Vector3.new local floor = math.floor local Methods = {	import = function(self, Table: {any})	local Environment = getfenv(0)	for Key, Value in ipairs(Table) do	Environment[tostring(Key)] = Value	end	return	end,	roundToNearest = function(self, number: number, roundTo: number)	local x = number + (roundTo / 2)	return x - (number % roundTo)	end,	nestedToFlat3 = function(self, position: Vector3,size: Vector3)	return (position.X) + ((position.Y - 1) * size.X) + ((position.Z - 1) * size.X * size.Y)	end,	flatToNested3 = function(self, i: number, size: Vector3)	return newVector3(	i % size.X,	floor((i / size.X) % size.Y + 1),	floor((i / size.Z + size.Z)/size.Y )	)	end,	lerp = function(self, x: number, y: number, alpha: number)	return alpha * (y - x) + x	end,	factorial = function(self, n)	if n <= 1 then -- base case	return 1	else	return n * self.factorial(n-1) -- recursive step	end	end,	createNestedArray = function(self, dimensions: number, defaultValue: any?,...:number)	local sizes = {...}	local array = {}	if dimensions < 2 then	error("Nested arrays require 2 or more dimensions.")	end	for x = 1, sizes[1] do	if dimensions == 2 then	array[x] = {}	else	table.remove(sizes,1)	array[x] = self.createNestedArray(dimensions - 1,table.unpack(sizes))	end	end	return array	end } return Methods server link: TuVzJ9xuzJ



