Live Character Stats
Key RequiredUniversal

Live Character Stats

Universal Scripttheobscured102theobscured102 1.3K views 630 executesUpdated Apr 24, 2026
Unrated
00
Lua Script•317 lines (7867 chars)
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local RunService = game:GetService("RunService")

local LocalPlayer = Players.LocalPlayer
local Mouse = LocalPlayer:GetMouse()

local FONT = Enum.Font.SourceSans
local MAX_PLAYERS = Players.MaxPlayers

local function formatSmart(n)
	local rounded = math.round(n)
	if math.abs(n - rounded) < 1e-9 then
		return tostring(rounded)
	end
	return string.format("%.2f", n)
end

local function formatGravity(n)
	return string.format("%.2f", n)
end

local function formatPing(n)
	return tostring(math.max(0, math.round(n)))
end

local function formatFps(n)
	return string.format("%.1f", n)
end

local function createLabel(adornee, size, offset)
	local gui = Instance.new("BillboardGui")
	gui.Name = "StatLabel"
	gui.Size = size
	gui.StudsOffset = offset
	gui.AlwaysOnTop = true
	gui.LightInfluence = 0
	gui.MaxDistance = 1000
	gui.Adornee = adornee
	gui.Parent = adornee.Parent

	local label = Instance.new("TextLabel")
	label.Size = UDim2.fromScale(1, 1)
	label.BackgroundTransparency = 1
	label.BorderSizePixel = 0
	label.TextScaled = true
	label.Font = FONT
	label.TextSize = 18
	label.TextColor3 = Color3.new(1, 1, 1)
	label.TextStrokeTransparency = 0
	label.Parent = gui

	return gui, label
end

local function getPreciseState(humanoid, rootPart)
	if humanoid.Health <= 0 then
		return "Dead"
	end

	local state = humanoid:GetState()
	local grounded = humanoid.FloorMaterial ~= Enum.Material.Air
	local velocity = rootPart.AssemblyLinearVelocity
	local yVelocity = velocity.Y
	local horizontalVelocity = Vector3.new(velocity.X, 0, velocity.Z).Magnitude
	local moveMagnitude = humanoid.MoveDirection.Magnitude

	if humanoid.Sit then
		if state == Enum.HumanoidStateType.Seated then
			return "Seated"
		end
		return "Sitting"
	end

	if humanoid.PlatformStand then
		return "Physics"
	end

	if state == Enum.HumanoidStateType.Swimming then
		return "Swimming"
	end

	if state == Enum.HumanoidStateType.Climbing then
		return "Climbing"
	end

	if state == Enum.HumanoidStateType.Ragdoll then
		return "Ragdoll"
	end

	if state == Enum.HumanoidStateType.FallingDown then
		return "FallingDown"
	end

	if state == Enum.HumanoidStateType.GettingUp then
		return "GettingUp"
	end

	if state == Enum.HumanoidStateType.Jumping then
		return "Jumping"
	end

	if state == Enum.HumanoidStateType.Landed then
		return "Landed"
	end

	if state == Enum.HumanoidStateType.Freefall then
		if grounded then
			if moveMagnitude < 0.05 and horizontalVelocity < 0.1 and math.abs(yVelocity) < 1 then
				return "Idle"
			end
			return "Running"
		end

		if yVelocity > 1 then
			return "Jumping"
		end

		return "Freefall"
	end

	if state == Enum.HumanoidStateType.Running or state == Enum.HumanoidStateType.RunningNoPhysics then
		if grounded then
			if moveMagnitude < 0.05 and horizontalVelocity < 0.1 and math.abs(yVelocity) < 1 then
				return "Idle"
			end
			return "Running"
		end

		if yVelocity > 1 then
			return "Jumping"
		end

		return "Freefall"
	end

	if state == Enum.HumanoidStateType.Physics then
		return "Physics"
	end

	if state == Enum.HumanoidStateType.Dead then
		return "Dead"
	end

	return state.Name
end

local function getClientPingMs()
	local ok, ping = pcall(function()
		return LocalPlayer:GetNetworkPing()
	end)

	if ok and typeof(ping) == "number" then
		return ping * 1000
	end

	return 0
end

local function getPlayerText()
	local totalPlayers = #Players:GetPlayers()
	local friendCount = 0

	for _, otherPlayer in ipairs(Players:GetPlayers()) do
		if otherPlayer ~= LocalPlayer then
			local ok, isFriend = pcall(function()
				return otherPlayer:IsFriendsWith(LocalPlayer.UserId)
			end)

			if ok and isFriend then
				friendCount += 1
			end
		end
	end

	local currentPlayers = math.max(totalPlayers - friendCount, 0)

	if friendCount > 0 then
		return "Player: " .. tostring(currentPlayers) .. "+" .. tostring(friendCount) .. "/" .. tostring(MAX_PLAYERS)
	end

	return "Player: " .. tostring(currentPlayers) .. "/" .. tostring(MAX_PLAYERS)
end

local function setHidden(labels, hidden, alpha)
	local textTransparency = hidden and 1 or alpha
	local strokeTransparency = hidden and 1 or math.clamp(alpha + 0.15, 0, 1)

	for _, label in ipairs(labels) do
		label.TextTransparency = textTransparency
		label.TextStrokeTransparency = strokeTransparency
	end
end

local function attachStats(character)
	local humanoid = character:WaitForChild("Humanoid")
	local rootPart = character:WaitForChild("HumanoidRootPart")
	local torso = character:FindFirstChild("UpperTorso") or character:FindFirstChild("Torso") or rootPart

	local speedGui, speedLabel = createLabel(torso, UDim2.new(0, 108, 0, 22), Vector3.new(-4, 1.55, 0))
	local jumpGui, jumpLabel = createLabel(torso, UDim2.new(0, 122, 0, 22), Vector3.new(4, 1.55, 0))
	local stateGui, stateLabel = createLabel(torso, UDim2.new(0, 128, 0, 22), Vector3.new(-4, 0.5, 0))
	local playersGui, playersLabel = createLabel(torso, UDim2.new(0, 128, 0, 22), Vector3.new(4, 0.5, 0))
	local pingGui, pingLabel = createLabel(torso, UDim2.new(0, 128, 0, 22), Vector3.new(-4, -0.5, 0))
	local fpsGui, fpsLabel = createLabel(torso, UDim2.new(0, 128, 0, 22), Vector3.new(4, -0.5, 0))

	local alive = true
	local hidden = false
	local speedSample = 0
	local fpsValue = 0
	local fpsFrames = 0
	local fpsElapsed = 0

	local connections = {}

	local function disconnectAll()
		for _, connection in ipairs(connections) do
			if connection.Connected then
				connection:Disconnect()
			end
		end
	end

	local function destroyAll()
		if speedGui then speedGui:Destroy() end
		if jumpGui then jumpGui:Destroy() end
		if stateGui then stateGui:Destroy() end
		if playersGui then playersGui:Destroy() end
		if pingGui then pingGui:Destroy() end
		if fpsGui then fpsGui:Destroy() end
	end

	local function stop()
		if not alive then
			return
		end

		alive = false
		disconnectAll()
		destroyAll()
	end

	table.insert(connections, humanoid.Died:Connect(stop))

	table.insert(connections, Mouse.Button1Down:Connect(function()
		if not alive or humanoid.Health <= 0 or not character.Parent then
			return
		end

		if Mouse.Target == torso then
			hidden = not hidden
		end
	end))

	task.spawn(function()
		local previousPosition = rootPart.Position

		while alive and humanoid.Health > 0 and character.Parent do
			local currentPosition = rootPart.Position
			speedSample = (currentPosition - previousPosition).Magnitude
			previousPosition = currentPosition
			task.wait(1)
		end
	end)

	table.insert(connections, RunService.RenderStepped:Connect(function(dt)
		if not alive then
			return
		end

		if not character.Parent or humanoid.Health <= 0 then
			stop()
			return
		end

		local camera = Workspace.CurrentCamera
		if not camera then
			return
		end

		fpsFrames += 1
		fpsElapsed += dt

		if fpsElapsed >= 1 then
			fpsValue = fpsFrames / fpsElapsed
			fpsFrames = 0
			fpsElapsed = 0
		end

		local state = getPreciseState(humanoid, rootPart)
		local pingMs = getClientPingMs()
		local currentPos = rootPart.Position
		local distanceAlpha = math.clamp(((camera.CFrame.Position - currentPos).Magnitude - 12) / 28, 0, 1)

		speedLabel.Text = "Speed: " .. formatSmart(humanoid.WalkSpeed) .. " (" .. formatSmart(speedSample) .. ")"
		jumpLabel.Text = "Jump: " .. formatSmart(humanoid.UseJumpPower and humanoid.JumpPower or humanoid.JumpHeight) .. " (" .. formatGravity(Workspace.Gravity) .. ")"
		stateLabel.Text = "State: " .. state
		playersLabel.Text = getPlayerText()
		pingLabel.Text = "Ping: " .. formatPing(pingMs) .. " ms"
		fpsLabel.Text = "FPS: " .. formatFps(fpsValue)

		setHidden({
			speedLabel,
			jumpLabel,
			stateLabel,
			playersLabel,
			pingLabel,
			fpsLabel,
		}, hidden, distanceAlpha)
	end))
end

LocalPlayer.CharacterAdded:Connect(attachStats)

if LocalPlayer.Character then
	attachStats(LocalPlayer.Character)
end

Features & Information

Update: Recoded Client-side Roblox stat overlay system attached to the player character. Features: 1. Real-time floating stat display using BillboardGui labels attached around the torso 2. Live movement speed tracking - Displays current WalkSpeed - Displays real movement speed sampled from position delta every second 3. Jump and gravity monitor - Displays current JumpPower or JumpHeight - Displays live Workspace gravity value 4. Advanced humanoid state detection - Detects: - Idle - Running - Jumping - Freefall - Swimming - Climbing - Ragdoll - Sitting / Seated - Physics - FallingDown - GettingUp - Dead - Uses grounded checks, velocity checks, and humanoid states for more accurate detection 5. Player counter system - Displays: - Current non-friend players - Friends in server - Server max player capacity - Format: - Player: current+friends/max 6. Friend detection support - Detects friends currently inside the server 7. Live ping monitor - Uses GetNetworkPing() - Converts ping into milliseconds 8. Live FPS counter - Updates every second - Displays FPS with 1 decimal precision 9. Distance-based transparency fading - Labels smoothly fade depending on camera distance from character 10. Manual visibility toggle - Clicking the torso hides or shows all stat labels 11. Automatic cleanup system - Disconnects connections and loops after death 12. Character respawn support - Reattaches the entire stat system automatically after respawn 13. Smart numeric formatting - Separate formatting handling for: - Speed - Gravity - Ping - FPS 14. Performance-conscious structure - Uses RenderStepped for visual updates - Uses timed sampling for movement speed calculations - Prevents connection leaks with cleanup handling

Community Comments (2)

borutoontoppshabborutoontoppshabApr 24, 2026

working?

XacFtXacFtApr 24, 2026

Will the modification be displa*?

More Scripts for Universal Scripts