Local script not working after my character dies?

so i have a script that applies an outline to the local player’s character, creates an isometric camera, and rotates the character to face where the mouse is pointing. it works REALLY well until the character dies. then it stops working. what’s even weirder is that there are no warnings or errors in the output, which leaves me thoroughly stumped.

footage of the bug in action:

-- config
local zoom = 125
local player_fov = 7
local lerping_factor = 0.1

-- services
local run_service = game:GetService("RunService")
local user_input_service = game:GetService("UserInputService")
local replicated_storage = game:GetService("ReplicatedStorage")
local tween_service = game:GetService("TweenService")
local local_player = game.Players.LocalPlayer
local mouse = local_player:GetMouse()
local character = local_player.Character or local_player.CharacterAdded:Wait()
local primary = character.PrimaryPart
local camera = workspace.CurrentCamera

local keybinds = {
	-- add more keybinds later
	["phone_out"] = "E", 
	["equip_weapon"] = "Q",
}

-- camera setup
camera.CameraType = Enum.CameraType.Custom

local body_gyro = Instance.new("BodyGyro")
body_gyro.Parent = primary
body_gyro.D = 40
body_gyro.P = 10000
body_gyro.MaxTorque = Vector3.new(4000000, 4000000, 4000000)

-- function to calculate intersection point on a plane
local function ray_plane(plane_point, plane_normal, origin, direction)
	return -((origin - plane_point):Dot(plane_normal)) / (direction:Dot(plane_normal))
end

-- self-explanatory
function create_keybinds()
	for action, key in pairs(keybinds) do
		user_input_service.InputBegan:Connect(function(input, game_processed)
			if not game_processed then
				if input.KeyCode == Enum.KeyCode[key] then
					-- print(action .. " key pressed")
					replicated_storage.remote_events.equip_tool:FireServer(action, character)
				end
			end
		end)
	end
end

function outline_character()
	local color_table = {
		
		["healthy"] = Color3.fromRGB(26, 255, 118),
		["unwell"] = Color3.fromRGB(255, 255, 74),
		["low_hp"] = Color3.fromRGB(255, 62, 97)
		
	}
	
	-- health thresholds
	local low_hp = 25
	local unwell_hp = 50
	local healthy_hp = 100
	
	if character.Head:FindFirstChild("face") then
		character.Head:FindFirstChild("face"):Destroy()
	end
	
	local highlight = Instance.new("Highlight")
	highlight.Parent = character
	highlight.FillTransparency = 1
	highlight.OutlineColor = color_table["healthy"]
	
	for i, child in ipairs(character:GetChildren()) do
		if child:IsA("BasePart") then
			if child.Name ~= "HumanoidRootPart" then
				child.Material = Enum.Material.Glass
				child.Transparency = 0.99
			end
		elseif child:IsA("Accessory") then
			if child.Handle then
				child.Handle.Material = Enum.Material.Glass
				child.Handle.Transparency = 0.99
			end
		end
	end
	
	local humanoid = character:FindFirstChildWhichIsA("Humanoid")
	local tween_info = TweenInfo.new(0.5, Enum.EasingStyle.Bounce, Enum.EasingDirection.In)

	humanoid.HealthChanged:Connect(function(health)
		if health <= low_hp then
			tween_service:Create(highlight, tween_info, {OutlineColor = color_table["low_hp"]}):Play()
		elseif health <= unwell_hp then
			tween_service:Create(highlight, tween_info, {OutlineColor = color_table["unwell"]}):Play()
		elseif health <= healthy_hp then
			tween_service:Create(highlight, tween_info, {OutlineColor = color_table["healthy"]}):Play()
		end
	end)
	
	if not character:FindFirstChildWhichIsA("Shirt") or character:FindFirstChildWhichIsA("Pants") then
		local shirt, pants = script.Shirt:Clone(), script.Pants:Clone()
		shirt.Parent = character
		pants.Parent = character
	end
end

-- function to initialize the camera
local function init()
	run_service.RenderStepped:Connect(function()
		camera.FieldOfView = player_fov
		if character and character:FindFirstChild("Head") then
			game:GetService("SoundService"):SetListener(Enum.ListenerType.ObjectCFrame, character.Head)
			camera.CFrame = CFrame.new(Vector3.new(character.Head.Position.X + zoom, (character.Head.Position.Y - 10) + zoom, character.Head.Position.Z + zoom), character.Head.Position)
		end
	end)
end

-- initialize the isometric camera
init()
outline_character()

-- main loop
while true do
	local ray = camera:ScreenPointToRay(mouse.X, mouse.Y)
	local t = ray_plane(local_player.Character.Head.Position, Vector3.new(0, 1, 0), ray.Origin, ray.Direction)

	local primary_pos = primary.Position

	local plane_intersection_point = (ray.Direction * t) + ray.Origin
	local target_cframe = CFrame.lookAt(primary_pos, plane_intersection_point)

	body_gyro.CFrame = body_gyro.CFrame:lerp(target_cframe, lerping_factor)
	task.wait()
end

Interesting, where is the script located?

the script is located in StarterPlayerScripts

You are only calling the init and outline_character functions once, when the player spawns in.

Add them both in a CharacterAdded function:

local_player.CharacterAdded:Connect(function()
	init()
	outline_character()
end)

sadly, it never runs. i even tried adding a print statement. it prints, the functions just never get called.

local_player.CharacterAdded:Connect(function()
	task.wait()
	print("character re-added")
	init()
	outline_character() -- never gets called for some reason
end)

the complete script:

-- config
local zoom = 125
local player_fov = 7
local lerping_factor = 0.1

-- services
local run_service = game:GetService("RunService")
local user_input_service = game:GetService("UserInputService")
local replicated_storage = game:GetService("ReplicatedStorage")
local tween_service = game:GetService("TweenService")
local local_player = game.Players.LocalPlayer
local mouse = local_player:GetMouse()
local character = local_player.Character or local_player.CharacterAdded:Wait()
local primary = character.PrimaryPart
local camera = workspace.CurrentCamera

local keybinds = {
	-- add more keybinds later
	["phone_out"] = "E", 
	["equip_weapon"] = "Q",
}

-- camera setup
camera.CameraType = Enum.CameraType.Custom

local body_gyro = Instance.new("BodyGyro")
body_gyro.Parent = primary
body_gyro.D = 40
body_gyro.P = 10000
body_gyro.MaxTorque = Vector3.new(4000000, 4000000, 4000000)

-- function to calculate intersection point on a plane
local function ray_plane(plane_point, plane_normal, origin, direction)
	return -((origin - plane_point):Dot(plane_normal)) / (direction:Dot(plane_normal))
end

-- self-explanatory
function create_keybinds()
	for action, key in pairs(keybinds) do
		user_input_service.InputBegan:Connect(function(input, game_processed)
			if not game_processed then
				if input.KeyCode == Enum.KeyCode[key] then
					-- print(action .. " key pressed")
					replicated_storage.remote_events.equip_tool:FireServer(action, character)
				end
			end
		end)
	end
end

function outline_character()
	local color_table = {
		
		["healthy"] = Color3.fromRGB(26, 255, 118),
		["unwell"] = Color3.fromRGB(255, 255, 74),
		["low_hp"] = Color3.fromRGB(255, 62, 97)
		
	}
	
	-- health thresholds
	local low_hp = 25
	local unwell_hp = 50
	local healthy_hp = 100
	
	if character.Head:FindFirstChild("face") then
		character.Head:FindFirstChild("face"):Destroy()
	end
	
	local highlight = Instance.new("Highlight")
	highlight.Parent = character
	highlight.FillTransparency = 1
	highlight.OutlineColor = color_table["healthy"]
	
	for i, child in ipairs(character:GetChildren()) do
		if child:IsA("BasePart") then
			if child.Name ~= "HumanoidRootPart" then
				child.Material = Enum.Material.Glass
				child.Transparency = 0.99
			end
		elseif child:IsA("Accessory") then
			if child.Handle then
				child.Handle.Material = Enum.Material.Glass
				child.Handle.Transparency = 0.99
			end
		end
	end
	
	local humanoid = character:FindFirstChildWhichIsA("Humanoid")
	local tween_info = TweenInfo.new(0.5, Enum.EasingStyle.Bounce, Enum.EasingDirection.In)

	humanoid.HealthChanged:Connect(function(health)
		if health <= low_hp then
			tween_service:Create(highlight, tween_info, {OutlineColor = color_table["low_hp"]}):Play()
		elseif health <= unwell_hp then
			tween_service:Create(highlight, tween_info, {OutlineColor = color_table["unwell"]}):Play()
		elseif health <= healthy_hp then
			tween_service:Create(highlight, tween_info, {OutlineColor = color_table["healthy"]}):Play()
		end
	end)
	
	if not character:FindFirstChildWhichIsA("Shirt") or character:FindFirstChildWhichIsA("Pants") then
		local shirt, pants = script.Shirt:Clone(), script.Pants:Clone()
		shirt.Parent = character
		pants.Parent = character
	end
end

-- function to initialize the camera
local function init()
	run_service.RenderStepped:Connect(function()
		camera.FieldOfView = player_fov
		if character and character:FindFirstChild("Head") then
			game:GetService("SoundService"):SetListener(Enum.ListenerType.ObjectCFrame, character.Head)
			camera.CFrame = CFrame.new(Vector3.new(character.Head.Position.X + zoom, (character.Head.Position.Y - 10) + zoom, character.Head.Position.Z + zoom), character.Head.Position)
		end
	end)
end

-- initialize the isometric camera
init()
outline_character()

local_player.CharacterAdded:Connect(function()
	task.wait()
	print("character re-added")
	init()
	outline_character() -- never gets called for some reason
end)

function main_loop()
	while true do
		local ray = camera:ScreenPointToRay(mouse.X, mouse.Y)
		local t = ray_plane(local_player.Character.Head.Position, Vector3.new(0, 1, 0), ray.Origin, ray.Direction)

		local primary_pos = primary.Position

		local plane_intersection_point = (ray.Direction * t) + ray.Origin
		local target_cframe = CFrame.lookAt(primary_pos, plane_intersection_point)

		body_gyro.CFrame = body_gyro.CFrame:lerp(target_cframe, lerping_factor)
		task.wait()
	end
end

run_service.RenderStepped:Connect(main_loop)

Try passing the character to the function
image

as you’re using the character in the function before you declare the variable

when i do that, it turns the script into nothing but a buggy mess.
it vomits out errors galore, or will lag until studio crashes.

Thats because of this line:

run_service.RenderStepped:Connect(main_loop)

it cause that on every renderstepped a new while loop gets created to fix that wrap the while loop in a coroutine or use task.spawn

you should set ‘Character’ value on init function. because when it respawns it becomes no longer usable.