Murder Drones Heads Up Display
Key Required

Murder Drones Heads Up Display

[UP] Just a baseplate.KenophobiaKenophobia 1.3K views 3.9K executesUpdated Sep 20, 2026
Unrated
00
Lua Script•5302 lines (107700 chars)
--!nocheck
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local SoundService = game:GetService("SoundService")
local StarterGui = game:GetService("StarterGui")

print("[Murder Drones HUD] v18.11 booting...")

-- Cobalt provides STATE during live-reload execution. Luau's analyzer
-- does not know about that injected global, so resolve it through _G.
-- A small fallback is included for environments that do not provide STATE.
local STATE = rawget(_G, "STATE")

if not STATE then
	local stateConnections = {}
	local stateCleanups = {}

	STATE = {}

	function STATE.connect(signal, callback)
		local connection = signal:Connect(callback)
		table.insert(stateConnections, connection)
		return connection
	end

	function STATE.onCleanup(callback)
		table.insert(stateCleanups, callback)
	end

	function STATE.cleanup()
		for _, connection in ipairs(stateConnections) do
			if connection then
				connection:Disconnect()
			end
		end

		for _, callback in ipairs(stateCleanups) do
			pcall(callback)
		end

		table.clear(stateConnections)
		table.clear(stateCleanups)
	end
end

local LocalPlayer = Players.LocalPlayer
local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")

local YELLOW = Color3.fromRGB(255, 221, 70)
local YELLOW_DIM = Color3.fromRGB(166, 145, 42)
local DARKTINT = Color3.fromRGB(10, 14, 17)
local RED = Color3.fromRGB(255, 72, 82)
local RED_DIM = Color3.fromRGB(125, 32, 42)
local STEEL = Color3.fromRGB(150, 165, 175)
local DEATH_BG = Color3.fromRGB(4, 6, 8)

-- Forward declarations for Luau analyzer visibility. These values/functions are
-- used by HUD callbacks that are defined before their implementation blocks.
local SCAN_RANGE = 90
local SCAN_ARC = 150
local SCAN_DURATION = 0.95
local scanActive = false
local scanStartTime = 0

local terminateNormalCamera
local playConnectionTerminated
local clearClones
local setCamsVisible
local buildClone
local syncPose

local FOOT_TRAIL_LIFETIME = 60
local FOOT_TRAIL_MIN_DIST = 1.5
local FOOTPRINT_HEIGHT = 0.035
local FOOTPRINT_MAX = 250
local FOOTPRINT_BACKTRACK = 10
local FOOTPRINT_HISTORY_INTERVAL = 0.2

-- ============================================================
-- LOCAL AUDIO
-- ============================================================

local AUDIO_FOLDER = "murder_drones_audio"

local AUDIO_FILES = {
	open = AUDIO_FOLDER .. "/hud_open.wav",
	close = AUDIO_FOLDER .. "/hud_close.wav",
	boot = AUDIO_FOLDER .. "/hud_boot.wav",
	signalLost = AUDIO_FOLDER .. "/signal_lost.wav",
	targetLock = AUDIO_FOLDER .. "/target_lock.wav",
	tick = AUDIO_FOLDER .. "/ui_tick.wav",
	wingFlap = AUDIO_FOLDER .. "/wing_flap.wav",
	flightLoop = AUDIO_FOLDER .. "/flight_loop.wav",
}

local function getLocalAudio(path)
	if type(getcustomasset) ~= "function" then
		warn("[Murder Drones HUD] getcustomasset() unavailable: " .. path)
		return nil
	end

	if type(isfile) == "function" then
		local exists = false

		local ok = pcall(function()
			exists = isfile(path)
		end)

		if ok and not exists then
			warn("[Murder Drones HUD] Missing local audio: " .. path)
			return nil
		end
	end

	local ok, asset = pcall(
		getcustomasset,
		path
	)

	if ok and type(asset) == "string" and asset ~= "" then
		return asset
	end

	warn("[Murder Drones HUD] Failed to load local audio: " .. path)

	return nil
end

local OPEN_SOUND_ID =
	getLocalAudio(AUDIO_FILES.open)

local CLOSE_SOUND_ID =
	getLocalAudio(AUDIO_FILES.close)

local INIT_SOUND_ID =
	getLocalAudio(AUDIO_FILES.boot)

local SIGNAL_LOST_SOUND_ID =
	getLocalAudio(AUDIO_FILES.signalLost)

local TARGET_LOCK_SOUND_ID =
	getLocalAudio(AUDIO_FILES.targetLock)

local UI_TICK_SOUND_ID =
	getLocalAudio(AUDIO_FILES.tick)

local WING_FLAP_SOUND_ID =
	getLocalAudio(AUDIO_FILES.wingFlap)

local FLIGHT_LOOP_SOUND_ID =
	getLocalAudio(AUDIO_FILES.flightLoop)

local playSound

-- ============================================================
-- CLEAN OLD HUDS
-- ============================================================

for _, name in ipairs({
	"DroneScanner",
	"MD_DeathHUD",
	"MurderDronesHUD"
}) do
	local g = PlayerGui:FindFirstChild(name)

	if g then
		g:Destroy()
	end
end

-- ============================================================
-- STATE
-- ============================================================

local S = {}

S.systemEnabled = false
S.expanded = false

S.trackedPlayer = nil
S.playerEntries = {}

S.activeVisual = nil

S.camClones = {
	third = nil,
	first = nil,
	sourceChar = nil,
	environmentCenter = nil,
}

S.camsVisible = false

S.footprintRecords = {}
S.footprintHistory = {}
S.lastHistorySample = 0

-- ============================================================
-- SOLVER / SPYWARE STATE
-- ============================================================

S.solverEnabled = false
S.spywareMode = false
S.spywareTargets = {}
S.spywareFeeds = {}

S.solverRayParts = {}
S.solverContacts = {}
S.scanPopupToken = 0
S.scanResultEntries = {}
S.scanResultSerial = 0
S.scanTargetCount = 0

S.wingsEnabled = false
S.flying = false
S.jumpPressCount = 0
S.lastJumpPress = 0
S.wingModel = nil
S.wingMotors = {}
S.flightVelocity = nil
S.flightGyro = nil
S.flightSound = nil
S.lastFlapSound = 0
S.flightInputDown = nil
S.flightInputUp = nil
S.flightControls = { F = 0, B = 0, L = 0, R = 0, Q = 0, E = 0 }
S.tailModel = nil
S.tailParts = {}
S.tailTools = {}
S.tailLoading = false
S.tailConnections = {}
S.tailWeld = nil
S.tailBaseC0 = nil
local setWingsEnabled

local rebuildSpywareFeeds

S.normalCameraTermination = nil

-- ============================================================
-- MAIN GUI
-- ============================================================

local gui = Instance.new("ScreenGui")

gui.Name = "MurderDronesHUD"
gui.ResetOnSpawn = false
gui.IgnoreGuiInset = true
gui.DisplayOrder = 999
gui.Enabled = true
gui.Parent = PlayerGui

STATE.onCleanup(function()
	gui:Destroy()
end)

-- ============================================================
-- ROGUE HUD WATCHER
-- ============================================================

local watcherConn = RunService.Heartbeat:Connect(function()
	for _, name in ipairs({
		"DroneScanner"
	}) do
		local rogue = PlayerGui:FindFirstChild(name)

		if rogue then
			rogue:Destroy()
		end
	end
end)

STATE.onCleanup(function()
	watcherConn:Disconnect()
end)

-- ============================================================
-- SCANNER ROOT
-- ============================================================

local scannerRoot = Instance.new("Frame")

scannerRoot.Name = "ScannerRoot"
scannerRoot.Size = UDim2.fromScale(1, 1)
scannerRoot.BackgroundTransparency = 1
scannerRoot.Visible = false
scannerRoot.Parent = gui

-- ============================================================
-- TINT
-- ============================================================

local tint = Instance.new("Frame")

tint.Size = UDim2.fromScale(1, 1)
tint.BackgroundColor3 = DARKTINT
tint.BackgroundTransparency = 0.88
tint.BorderSizePixel = 0
tint.Parent = scannerRoot

-- ============================================================
-- TOP BAR
-- ============================================================

local topBar = Instance.new("Frame")

topBar.Size = UDim2.new(1, -40, 0, 8)
topBar.Position = UDim2.new(0, 20, 0, 12)
topBar.BackgroundColor3 = YELLOW
topBar.BackgroundTransparency = 0.2
topBar.BorderSizePixel = 0
topBar.Parent = scannerRoot

Instance.new(
	"UICorner",
	topBar
).CornerRadius = UDim.new(1, 0)

-- ============================================================
-- SCANLINE
-- ============================================================

local scanline = Instance.new("Frame")

scanline.Size = UDim2.new(1, 0, 0, 3)
scanline.BackgroundColor3 = YELLOW
scanline.BackgroundTransparency = 0.6
scanline.BorderSizePixel = 0
scanline.Parent = scannerRoot

STATE.connect(RunService.RenderStepped, function()
	local t = (tick() % 4) / 4

	scanline.Position =
		UDim2.new(0, 0, t, 0)
end)

-- ============================================================
-- DRONE OVERLAY / BASE HUD
-- ============================================================

local function hudText(text, position, size, color, z)
	local label = Instance.new("TextLabel")
	label.BackgroundTransparency = 1
	label.Position = position
	label.Size = size
	label.Font = Enum.Font.Code
	label.Text = text
	label.TextColor3 = color or YELLOW_DIM
	label.TextSize = 11
	label.TextXAlignment = Enum.TextXAlignment.Left
	label.ZIndex = z or 4
	label.Parent = scannerRoot
	return label
end

local hudTL = hudText("UZI // UNIT-00A", UDim2.new(0, 24, 0, 22), UDim2.fromOffset(220, 18), YELLOW, 5)
local hudTR = hudText("OPTICAL LINK :: 100%", UDim2.new(1, -244, 0, 22), UDim2.fromOffset(220, 18), YELLOW, 5)
hudTR.TextXAlignment = Enum.TextXAlignment.Right
local hudBL = hudText("CORE TEMP 031C\nTHRUSTER STANDBY\nNETWORK LOCAL", UDim2.new(0, 24, 1, -112), UDim2.fromOffset(260, 88), STEEL, 5)
local hudBR = hudText("", UDim2.new(1, -294, 1, -112), UDim2.fromOffset(270, 88), YELLOW, 5)
hudBR.TextXAlignment = Enum.TextXAlignment.Right

local normalTelemetry = Instance.new("Frame")
normalTelemetry.Name = "TelemetryPanel"
normalTelemetry.Size = UDim2.fromOffset(250, 122)
normalTelemetry.Position = UDim2.new(1, -320, 1, -254)
normalTelemetry.BackgroundColor3 = DARKTINT
normalTelemetry.BackgroundTransparency = 0.35
normalTelemetry.BorderSizePixel = 0
normalTelemetry.ZIndex = 5
normalTelemetry.Parent = scannerRoot
local normalTelemetryStroke = Instance.new("UIStroke")
normalTelemetryStroke.Color = YELLOW_DIM
normalTelemetryStroke.Thickness = 1
normalTelemetryStroke.Parent = normalTelemetry
local telemetryText = hudText("", UDim2.fromOffset(10, 8), UDim2.new(1, -20, 1, -16), STEEL, 6)
telemetryText.Parent = normalTelemetry

local solverTelemetry = Instance.new("Frame")
solverTelemetry.Name = "SolverTelemetry"
solverTelemetry.Size = UDim2.fromOffset(300, 176)
solverTelemetry.Position = UDim2.new(0, 22, 0, 285)
solverTelemetry.BackgroundColor3 = DARKTINT
solverTelemetry.BackgroundTransparency = 0.28
solverTelemetry.BorderSizePixel = 0
solverTelemetry.Visible = false
solverTelemetry.ZIndex = 6
solverTelemetry.Parent = scannerRoot
local solverTelemetryStroke = Instance.new("UIStroke")
solverTelemetryStroke.Color = RED
solverTelemetryStroke.Thickness = 1.25
solverTelemetryStroke.Parent = solverTelemetry
local solverTelemetryText = hudText("", UDim2.fromOffset(10, 8), UDim2.new(1, -20, 1, -16), YELLOW, 7)
solverTelemetryText.Parent = solverTelemetry

local solverSystemPanel = Instance.new("Frame")
solverSystemPanel.Name = "SolverSystemPanel"
solverSystemPanel.Size = UDim2.fromOffset(300, 150)
solverSystemPanel.Position = UDim2.new(1, -320, 0, 214)
solverSystemPanel.BackgroundColor3 = DARKTINT
solverSystemPanel.BackgroundTransparency = 0.28
solverSystemPanel.BorderSizePixel = 0
solverSystemPanel.Visible = false
solverSystemPanel.ZIndex = 6
solverSystemPanel.Parent = scannerRoot
local solverSystemStroke = Instance.new("UIStroke")
solverSystemStroke.Color = YELLOW
solverSystemStroke.Thickness = 1.25
solverSystemStroke.Parent = solverSystemPanel
local solverSystemText = hudText("", UDim2.fromOffset(10, 8), UDim2.new(1, -20, 1, -16), STEEL, 7)
solverSystemText.Parent = solverSystemPanel

local reticle = Instance.new("Frame")
reticle.Name = "DroneReticle"
reticle.Size = UDim2.fromOffset(34, 34)
reticle.AnchorPoint = Vector2.new(0.5, 0.5)
reticle.Position = UDim2.fromScale(0.5, 0.5)
reticle.BackgroundTransparency = 1
reticle.ZIndex = 4
reticle.Parent = scannerRoot
for _, data in ipairs({
	{UDim2.new(0, 0, 0, 0), UDim2.fromOffset(10, 1)},
	{UDim2.new(1, -10, 0, 0), UDim2.fromOffset(10, 1)},
	{UDim2.new(0, 0, 1, -1), UDim2.fromOffset(10, 1)},
	{UDim2.new(1, -10, 1, -1), UDim2.fromOffset(10, 1)},
}) do
	local line = Instance.new("Frame")
	line.Position = data[1]
	line.Size = data[2]
	line.BackgroundColor3 = YELLOW_DIM
	line.BorderSizePixel = 0
	line.Parent = reticle
end

local hudTick = 0
STATE.connect(RunService.RenderStepped, function(dt)
	hudTick += dt
	local pulse = 0.38 + math.sin(hudTick * 2.4) * 0.10
	hudTL.TextTransparency = pulse
	hudTR.TextTransparency = pulse
	local char = LocalPlayer.Character
	local humanoid = char and char:FindFirstChildOfClass("Humanoid")
	local root = char and char:FindFirstChild("HumanoidRootPart")
	local velocity = root and root.AssemblyLinearVelocity.Magnitude or 0
	local health = humanoid and math.max(0, humanoid.Health) or 0
	local maxHealth = humanoid and math.max(1, humanoid.MaxHealth) or 100
	local ping = 0
	pcall(function() ping = math.floor(LocalPlayer:GetNetworkPing() * 1000 + 0.5) end)
	local players = math.max(0, #Players:GetPlayers() - 1)
	local targetDistance = S.trackedPlayer and S.trackedPlayer.Character and S.trackedPlayer.Character:FindFirstChild("HumanoidRootPart") and root and (S.trackedPlayer.Character.HumanoidRootPart.Position - root.Position).Magnitude or nil
	hudBL.Text = string.format("CORE TEMP %03dC\nTHRUSTER %-7s\nNETWORK LOCAL\nVITALS %03d / %03d", 31 + math.floor(math.sin(hudTick) * 2), S.flying and "FLIGHT" or "STANDBY", health, maxHealth)
	hudBR.Text = S.solverEnabled and string.format("ABSOLUTE SOLVER\nMODE %s\nVELOCITY %03d\nTARGET %s", S.spywareMode and "SPYWARE" or (scanActive and "SCANNING" or "ACTIVE"), velocity, targetDistance and string.format("%.1f ST", targetDistance) or "NONE") or string.format("SIGNAL %03d%%\nPING %03dMS\nDRONES %02d", math.clamp(100 - math.floor(ping / 8), 0, 100), ping, players)
	telemetryText.Text = string.format("// TELEMETRY\nALTITUDE %06.1f\nSPEED %06.1f\nHEALTH %03d%%\nPLAYERS %02d\nTRACK %s\nFLIGHT %s", root and root.Position.Y or 0, velocity, math.floor((health / maxHealth) * 100 + 0.5), players, S.trackedPlayer and S.trackedPlayer.Name or "NONE", S.flying and "ONLINE" or "STANDBY")
	if S.solverEnabled then
		local scanState = scanActive and string.format("SWEEP %03d%%", math.floor(math.clamp((os.clock() - scanStartTime) / SCAN_DURATION, 0, 1) * 100)) or "READY"
		solverTelemetryText.Text = string.format("// SOLVER TELEMETRY\nSTATE ACTIVE\nSCAN %s\nRANGE %03d STUDS\nARC %03d DEG\nTARGETS %02d\nWINGS %s\nFLIGHT %s", scanState, SCAN_RANGE, SCAN_ARC, S.scanTargetCount, S.wingsEnabled and "ONLINE" or "STANDBY", S.flying and "ONLINE" or "STANDBY")
		solverSystemText.Text = string.format("// SYSTEM OVERRIDE\nCORE ABSOLUTE SOLVER\nEYE LINK ONLINE\nSPYWARE %02d / 06\nLOCK %s\nMOBILITY %s\nSCAN ENGINE ONE-PASS\nRAYCAST %s", #S.spywareTargets, S.trackedPlayer and S.trackedPlayer.Name or "NONE", S.flying and "FLIGHT" or "GROUND", scanActive and "ACTIVE" or "READY")
		solverTelemetry.Visible = true
		-- Do not display the Solver System Override panel over spectator cameras
		-- or the spyware camera grid.
		solverSystemPanel.Visible =
			not S.camsVisible
			and not S.spywareMode
	else
		solverTelemetry.Visible = false
		solverSystemPanel.Visible = false
	end
end)

-- ============================================================
-- BANNER
-- ============================================================

local banner = Instance.new("TextLabel")

banner.Size = UDim2.fromOffset(360, 30)
banner.AnchorPoint = Vector2.new(0.5, 0)
banner.Position = UDim2.new(0.5, 0, 0, 60)
banner.BackgroundTransparency = 1
banner.Font = Enum.Font.Code
banner.TextColor3 = YELLOW
banner.TextSize = 22
banner.Text = ""
banner.Parent = scannerRoot

-- ============================================================
-- PLAYER LIST
-- ============================================================

local listPanel = Instance.new("Frame")

listPanel.Name = "PlayerList"
listPanel.Size = UDim2.fromOffset(200, 32)
listPanel.Position = UDim2.new(0, 20, 0, 40)
listPanel.BackgroundColor3 = DARKTINT
listPanel.BackgroundTransparency = 0.3
listPanel.BorderSizePixel = 0
listPanel.ClipsDescendants = true
listPanel.Parent = scannerRoot

local listStroke = Instance.new("UIStroke")

listStroke.Color = YELLOW
listStroke.Thickness = 1.5
listStroke.Parent = listPanel

local header = Instance.new("TextButton")

header.Size = UDim2.new(1, 0, 0, 32)
header.BackgroundTransparency = 1
header.Font = Enum.Font.Code
header.TextColor3 = YELLOW
header.TextSize = 16
header.Text = "\226\150\184 DRONES (0)"
header.Parent = listPanel

-- ============================================================
-- SPYWARE BUTTON
-- ============================================================

local spywareButton = Instance.new("TextButton")

spywareButton.Name = "SpywareMode"
spywareButton.Size = UDim2.fromOffset(112, 24)
spywareButton.Position = UDim2.new(0, 208, 0, 44)
spywareButton.BackgroundColor3 = DARKTINT
spywareButton.BackgroundTransparency = 0.22
spywareButton.BorderSizePixel = 0
spywareButton.Font = Enum.Font.Code
spywareButton.Text = "SPYWARE [P]"
spywareButton.TextColor3 = YELLOW_DIM
spywareButton.TextSize = 12
spywareButton.AutoButtonColor = false
spywareButton.Visible = false
spywareButton.Parent = scannerRoot

local spywareStroke = Instance.new("UIStroke")

spywareStroke.Color = YELLOW_DIM
spywareStroke.Thickness = 1
spywareStroke.Parent = spywareButton

local wingsButton = Instance.new("TextButton")

wingsButton.Name = "WingsMode"
wingsButton.Size = UDim2.fromOffset(112, 24)
wingsButton.Position = UDim2.new(0, 328, 0, 44)
wingsButton.BackgroundColor3 = DARKTINT
wingsButton.BackgroundTransparency = 0.22
wingsButton.BorderSizePixel = 0
wingsButton.Font = Enum.Font.Code
wingsButton.Text = "WINGS [OFF]"
wingsButton.TextColor3 = YELLOW_DIM
wingsButton.TextSize = 12
wingsButton.AutoButtonColor = false
wingsButton.Visible = false
wingsButton.Parent = scannerRoot

local wingsStroke = Instance.new("UIStroke")

wingsStroke.Color = YELLOW_DIM
wingsStroke.Thickness = 1
wingsStroke.Parent = wingsButton

local raycastButton = Instance.new("TextButton")
raycastButton.Name = "SolverScanButton"
raycastButton.Size = UDim2.fromOffset(112, 24)
raycastButton.Position = UDim2.new(0, 448, 0, 44)
raycastButton.BackgroundColor3 = DARKTINT
raycastButton.BackgroundTransparency = 0.22
raycastButton.BorderSizePixel = 0
raycastButton.Font = Enum.Font.Code
raycastButton.Text = "SCAN [R]"
raycastButton.TextColor3 = RED
raycastButton.TextSize = 12
raycastButton.AutoButtonColor = false
raycastButton.Visible = false
raycastButton.Parent = scannerRoot

local raycastStroke = Instance.new("UIStroke")
raycastStroke.Color = RED
raycastStroke.Thickness = 1
raycastStroke.Parent = raycastButton

-- ============================================================
-- SCROLLER
-- ============================================================

local scroller = Instance.new("ScrollingFrame")

scroller.Position = UDim2.new(0, 0, 0, 32)
scroller.Size = UDim2.new(1, 0, 1, -32)
scroller.BackgroundTransparency = 1
scroller.BorderSizePixel = 0
scroller.ScrollBarThickness = 4
scroller.ScrollBarImageColor3 = YELLOW
scroller.AutomaticCanvasSize = Enum.AutomaticSize.Y
scroller.CanvasSize = UDim2.new(0, 0, 0, 0)
scroller.Parent = listPanel

local listLayout = Instance.new("UIListLayout")

listLayout.SortOrder = Enum.SortOrder.LayoutOrder
listLayout.Parent = scroller

local function updateHeaderCount()
	local count = 0

	for _ in pairs(S.playerEntries) do
		count += 1
	end

	header.Text =
		(S.expanded and "\226\150\190 " or "\226\150\184 ")
		.. "DRONES ("
		.. count
		.. ")"
end

local function setExpanded(state)
	S.expanded = state

	local targetHeight =
		S.expanded and 220 or 32

	TweenService:Create(
		listPanel,
		TweenInfo.new(
			0.25,
			Enum.EasingStyle.Quad
		),
		{
			Size = UDim2.fromOffset(
				200,
				targetHeight
			)
		}
	):Play()

	updateHeaderCount()
end

header.MouseButton1Click:Connect(function()
	setExpanded(not S.expanded)
end)

-- ============================================================
-- TARGET VISUAL
-- ============================================================

local function clearActiveVisual()
	if not S.activeVisual then
		return
	end

	if S.activeVisual.highlight then
		S.activeVisual.highlight:Destroy()
	end

	if S.activeVisual.billboard then
		S.activeVisual.billboard:Destroy()
	end

	if S.activeVisual.charConn then
		S.activeVisual.charConn:Disconnect()
	end

	S.activeVisual = nil
end

local function attachVisualTo(plr)
	clearActiveVisual()

	if not plr then
		return
	end

	local function build(char)
		clearActiveVisual()

		local hrp =
			char:WaitForChild(
				"HumanoidRootPart",
				5
			)

		local head =
			char:WaitForChild(
				"Head",
				5
			)

		if not hrp or not head then
			return
		end

		local highlight = Instance.new("Highlight")

		highlight.FillTransparency = 1
		highlight.OutlineColor = YELLOW
		highlight.OutlineTransparency = 0
		highlight.DepthMode =
			Enum.HighlightDepthMode.Occluded
		highlight.Enabled = S.systemEnabled
		highlight.Parent = char

		local billboard = Instance.new("BillboardGui")

		billboard.Name = "TrackerTag"
		billboard.Size = UDim2.fromOffset(105, 22)
		billboard.StudsOffset =
			Vector3.new(0, 2.8, 0)
		billboard.Enabled = S.systemEnabled
		billboard.Adornee = head
		billboard.Parent = char

		local label = Instance.new("TextLabel")

		label.BackgroundTransparency = 1
		label.Size = UDim2.fromScale(1, 1)
		label.Font = Enum.Font.Code
		label.TextColor3 = YELLOW
		label.TextStrokeTransparency = 0.4
		label.TextScaled = true
		label.Text = plr.Name
		label.Parent = billboard

		S.activeVisual = {
			highlight = highlight,
			billboard = billboard,
			hrp = hrp,
			lastFootPos = hrp.Position,
			char = char,
			backtrackSeeded = false,
		}
	end

	if plr.Character then
		build(plr.Character)
	end

	local conn

	conn = plr.CharacterAdded:Connect(build)

	if S.activeVisual then
		S.activeVisual.charConn = conn
	else
		S.activeVisual = {
			charConn = conn
		}
	end
end

-- ============================================================
-- SPYWARE SELECTION
-- ============================================================

local function isSpywareSelected(plr)
	for _, target in ipairs(S.spywareTargets) do
		if target == plr then
			return true
		end
	end

	return false
end

local function refreshPlayerButtonColors()
	for p, entry in pairs(S.playerEntries) do
		if S.spywareMode then
			entry.listButton.TextColor3 =
				isSpywareSelected(p)
				and RED
				or YELLOW
		else
			entry.listButton.TextColor3 =
				(p == S.trackedPlayer)
				and RED
				or YELLOW
		end
	end
end

local function selectTarget(plr)
	if S.spywareMode then
		local found = nil

		for i, target in ipairs(S.spywareTargets) do
			if target == plr then
				found = i
				break
			end
		end

		if found then
			table.remove(
				S.spywareTargets,
				found
			)
		else
			if #S.spywareTargets < 6 then
				table.insert(
					S.spywareTargets,
					plr
				)
			else
				playSound(
					UI_TICK_SOUND_ID,
					0.35,
					1.08,
					false
				)
			end
		end

		rebuildSpywareFeeds()

		banner.Text =
			"SOLVER :: SPYWARE // "
			.. tostring(#S.spywareTargets)
			.. " TARGETS"

		refreshPlayerButtonColors()

		return
	end

	if S.trackedPlayer == plr then
		S.trackedPlayer = nil
		clearActiveVisual()
	else
		S.trackedPlayer = plr
		attachVisualTo(plr)

		playSound(
			TARGET_LOCK_SOUND_ID,
			0.7,
			1,
			false
		)
	end

	refreshPlayerButtonColors()
end

-- ============================================================
-- FOOTPRINTS
-- ============================================================

local function dropFootprint(
	position,
	direction,
	normal
)
	local model = Instance.new("Model")

	model.Name = "MurderDronesFootprint"
	model.Parent = workspace

	local flatDirection = Vector3.new(
		direction and direction.X or 0,
		0,
		direction and direction.Z or 0
	)

	if flatDirection.Magnitude < 0.05 then
		flatDirection =
			Vector3.new(0, 0, -1)
	end

	local groundNormal =
		(normal and normal.Magnitude > 0.5)
		and normal.Unit
		or Vector3.new(0, 1, 0)

	local lookCf = CFrame.lookAt(
		position,
		position + flatDirection.Unit,
		groundNormal
	)

	local function makePart(size, offset)
		local p = Instance.new("Part")

		p.Name = "Print"
		p.Size = size
		p.Anchored = true
		p.CanCollide = false
		p.CanTouch = false
		p.CanQuery = false
		p.CastShadow = false
		p.Material = Enum.Material.Neon
		p.Color = YELLOW
		p.Transparency = 0.15

		p.CFrame =
			lookCf
			* CFrame.new(
				offset.X,
				FOOTPRINT_HEIGHT,
				offset.Z
			)

		p.Parent = model

		return p
	end

	makePart(
		Vector3.new(
			0.42,
			0.045,
			0.52
		),
		Vector3.new(0, 0, 0.28)
	)

	makePart(
		Vector3.new(
			0.58,
			0.045,
			0.78
		),
		Vector3.new(0, 0, -0.28)
	)

	table.insert(
		S.footprintRecords,
		{
			created = os.clock(),
			model = model,
		}
	)

	while #S.footprintRecords >
		FOOTPRINT_MAX do

		local old =
			table.remove(
				S.footprintRecords,
				1
			)

		if old and old.model then
			old.model:Destroy()
		end
	end
end

local function addHistorySample(
	plr,
	char,
	hrp
)
	if not plr or not char or not hrp then
		return nil
	end

	local history =
		S.footprintHistory[plr]

	if not history then
		history = {}

		S.footprintHistory[plr] =
			history
	end

	local last =
		history[#history]

	if last
		and (
			hrp.Position
			- last.position
		).Magnitude < FOOT_TRAIL_MIN_DIST
	then
		return nil
	end

	local rayParams =
		RaycastParams.new()

	rayParams.FilterType =
		Enum.RaycastFilterType.Exclude

	rayParams.FilterDescendantsInstances =
		{
			char
		}

	rayParams.IgnoreWater = true

	local result =
		workspace:Raycast(
			hrp.Position
				+ Vector3.new(0, 4, 0),
			Vector3.new(0, -12, 0),
			rayParams
		)

	if not result then
		return nil
	end

	local direction =
		last
		and (
			hrp.Position
			- last.position
		)
		or hrp.CFrame.LookVector

	local sample = {
		time = os.clock(),
		position = hrp.Position,
		ground = result.Position,
		normal = result.Normal,
		direction = direction,
	}

	table.insert(
		history,
		sample
	)

	local cutoff =
		os.clock()
		- FOOTPRINT_BACKTRACK

	for i = #history, 1, -1 do
		if history[i].time < cutoff then
			table.remove(history, i)
		end
	end

	return sample
end

local function spawnBacktrack(plr)
	local history =
		S.footprintHistory[plr]

	if not history
		or #history == 0
	then
		return
	end

	local cutoff =
		os.clock()
		- FOOTPRINT_BACKTRACK

	for _, sample in ipairs(history) do
		if sample.time >= cutoff then
			dropFootprint(
				sample.ground,
				sample.direction,
				sample.normal
			)
		end
	end
end

local function clearFootprints()
	for _, record in ipairs(
		S.footprintRecords
	) do
		if record.model then
			record.model:Destroy()
		end
	end

	table.clear(
		S.footprintRecords
	)
end

local function pruneFootprintHistory()
	local cutoff =
		os.clock()
		- FOOTPRINT_BACKTRACK

	for plr, history in pairs(
		S.footprintHistory
	) do

		for i = #history, 1, -1 do
			if history[i].time < cutoff then
				table.remove(history, i)
			end
		end

		if #history == 0
			and not plr.Parent
		then
			S.footprintHistory[plr] =
				nil
		end
	end
end

local function pruneFootprints()
	local now = os.clock()

	for i = #S.footprintRecords, 1, -1 do
		local record =
			S.footprintRecords[i]

		if not record.model
			or not record.model.Parent
			or now - record.created
				>= FOOT_TRAIL_LIFETIME
		then

			if record.model then
				record.model:Destroy()
			end

			table.remove(
				S.footprintRecords,
				i
			)
		end
	end
end

STATE.connect(
	RunService.Heartbeat,
	function()
		pruneFootprints()
		pruneFootprintHistory()
	end
)

STATE.onCleanup(function()
	clearFootprints()
	table.clear(
		S.footprintHistory
	)
end)

-- ============================================================
-- PLAYER LIST ENTRIES
-- ============================================================

local function setupListEntry(plr)
	if plr == LocalPlayer
		or S.playerEntries[plr]
	then
		return
	end

	local entry = {}

	S.playerEntries[plr] =
		entry

	local btn = Instance.new("TextButton")

	btn.Size =
		UDim2.new(
			1,
			0,
			0,
			26
		)

	btn.BackgroundTransparency = 1
	btn.Font = Enum.Font.Code
	btn.Text = plr.Name
	btn.TextColor3 = YELLOW
	btn.TextSize = 14
	btn.TextXAlignment =
		Enum.TextXAlignment.Left
	btn.Parent = scroller

	btn.MouseButton1Click:Connect(
		function()
			selectTarget(plr)
		end
	)

	entry.listButton = btn

	updateHeaderCount()
end

local function teardownListEntry(plr)
	local entry =
		S.playerEntries[plr]

	if not entry then
		return
	end

	-- Preserve a viewed target's camera briefly so the user sees a real
	-- disconnect/static sequence instead of the feed vanishing instantly.
	if S.trackedPlayer == plr and not S.spywareMode then
		clearActiveVisual()
		terminateNormalCamera(plr.Name)
	end

	local leavingFeed = S.spywareFeeds[plr]
	if leavingFeed and not leavingFeed.terminating then
		leavingFeed.terminating = true
		local feedRef = leavingFeed
		playConnectionTerminated(feedRef.termination, plr.Name, function()
			if feedRef.root and feedRef.root.Parent then
				feedRef.root:Destroy()
			end
			if S.spywareFeeds[plr] == feedRef then
				S.spywareFeeds[plr] = nil
			end
		end)
	end

	if entry.listButton then
		entry.listButton:Destroy()
	end

	if S.trackedPlayer == plr and not S.normalCameraTermination then
		S.trackedPlayer = nil
		clearActiveVisual()
	end

	for i = #S.spywareTargets, 1, -1 do
		if S.spywareTargets[i] == plr then
			table.remove(
				S.spywareTargets,
				i
			)
		end
	end

	if S.spywareFeeds[plr] and not S.spywareFeeds[plr].terminating then
		if S.spywareFeeds[plr].root then
			S.spywareFeeds[plr].root:Destroy()
		end

		S.spywareFeeds[plr] = nil
	end

	S.playerEntries[plr] = nil

	updateHeaderCount()
end

for _, plr in ipairs(
	Players:GetPlayers()
) do
	setupListEntry(plr)
end

STATE.connect(
	Players.PlayerAdded,
	setupListEntry
)

STATE.connect(
	Players.PlayerRemoving,
	teardownListEntry
)

-- Remove stale HUD/world visuals from previous executions. This prevents an
-- older copy of the script from leaving the old Drone Core icon, Solver eye,
-- wings, or flight movers behind when this version starts.
for _, oldGui in ipairs(LocalPlayer:WaitForChild("PlayerGui"):GetChildren()) do
	if oldGui.Name == "MurderDronesHUD" and oldGui ~= gui then
		oldGui:Destroy()
	end
end

local startupCharacter = LocalPlayer.Character
if startupCharacter then
	for _, staleName in ipairs({
		"AbsoluteSolverEye_Client",
		"SolverWings_Client",
		"SolverFlightVelocity",
		"SolverFlightGyro",
	}) do
		local stale = startupCharacter:FindFirstChild(staleName)
		if stale then stale:Destroy() end
	end
end

for _, obj in ipairs(workspace:GetChildren()) do
	if obj:IsA("BasePart") and (obj.Name == "SolverRay" or obj.Name:match("^SolverRay_")) then
		obj:Destroy()
	end
end

-- ============================================================
-- SOLVER SYMBOL (3D ONLY)
-- ============================================================

-- World-space Solver glyph: a real client-side 3D model welded to the
-- player's head. It is yellow and sits slightly forward of the eye so
-- hair/accessories cannot cover it. No screen-space image is used here.
local solverEyeModel = nil
local solverEyeParts = {}

local function clearSolverEyeModel()
	if solverEyeModel then
		solverEyeModel:Destroy()
		solverEyeModel = nil
	end
	table.clear(solverEyeParts)
end

local function makeSolverEyePart(name, size, cframe, shape)
	local part = Instance.new("Part")
	part.Name = name
	part.Size = size
	part.CFrame = cframe
	part.Anchored = false
	part.CanCollide = false
	part.CanTouch = false
	part.CanQuery = false
	part.Massless = true
	part.CastShadow = false
	part.Material = Enum.Material.Neon
	part.Color = YELLOW
	part.Shape = shape or Enum.PartType.Block
	part.Parent = solverEyeModel
	table.insert(solverEyeParts, part)
	return part
end

local function buildSolverEyeModel()
	if not S.solverEnabled then return end
	local char = LocalPlayer.Character
	local head = char and char:FindFirstChild("Head")
	if not head then return end
	clearSolverEyeModel()

	solverEyeModel = Instance.new("Model")
	solverEyeModel.Name = "AbsoluteSolverEye_Client"
	solverEyeModel.Parent = char

	-- Canonical Absolute Solver / Main Translate silhouette:
	-- a glowing central hexagon with three thick branches ending in arrowheads.
	-- The reference has a solid center rather than the old hollow double-hex.
	local base = head.CFrame * CFrame.new(0.24, 0.10, -0.74)
	local thickness = 0.045

	local function segment(name, a, b, width)
		local mid = (a + b) * 0.5
		local delta = b - a
		local length = delta.Magnitude
		local part = makeSolverEyePart(name, Vector3.new(length, width or thickness, width or thickness), CFrame.lookAt(mid, b) * CFrame.Angles(0, math.rad(90), 0))
		local weld = Instance.new("WeldConstraint")
		weld.Part0 = head
		weld.Part1 = part
		weld.Parent = part
		return part
	end

	-- Filled hexagonal core, constructed from three crossed neon bars.
	-- At eye scale this reads as the six-sided central block from the reference.
	local core = {
		{Vector3.new(-0.105, 0, 0), Vector3.new(0.105, 0, 0)},
		{Vector3.new(-0.052, -0.091, 0), Vector3.new(0.052, 0.091, 0)},
		{Vector3.new(-0.052, 0.091, 0), Vector3.new(0.052, -0.091, 0)},
	}
	for i, pair in ipairs(core) do
		segment("CoreHex_" .. i, base:PointToWorldSpace(pair[1]), base:PointToWorldSpace(pair[2]), 0.10)
	end

	-- Thin six-sided border around the filled center.
	local r = 0.145
	local points = {}
	for i = 0, 5 do
		local a = math.rad(30 + i * 60)
		points[i + 1] = Vector3.new(math.cos(a) * r, math.sin(a) * r, -0.012)
	end
	for i = 1, 6 do
		segment("HexBorder_" .. i, base:PointToWorldSpace(points[i]), base:PointToWorldSpace(points[i % 6 + 1]), 0.028)
	end

	-- Three evenly spaced translate arms. Each has a shaft, shoulder, and
	-- broad triangular arrowhead, matching the reference image.
	local armLength = 0.34
	local armWidth = 0.052
	local directions = {
		math.rad(90),
		math.rad(210),
		math.rad(330),
	}
	for i, angle in ipairs(directions) do
		local dir = Vector2.new(math.cos(angle), math.sin(angle))
		local perp = Vector2.new(-dir.Y, dir.X)
		local start2 = dir * 0.14
		local neck2 = dir * 0.43
		local tip2 = dir * 0.62

		segment("Arm_" .. i,
			base:PointToWorldSpace(Vector3.new(start2.X, start2.Y, 0)),
			base:PointToWorldSpace(Vector3.new(neck2.X, neck2.Y, 0)),
			armWidth)

		local shoulderA = neck2 + perp * 0.085
		local shoulderB = neck2 - perp * 0.085
		segment("ShoulderA_" .. i,
			base:PointToWorldSpace(Vector3.new(shoulderA.X, shoulderA.Y, 0)),
			base:PointToWorldSpace(Vector3.new(tip2.X, tip2.Y, 0)),
			0.050)
		segment("ShoulderB_" .. i,
			base:PointToWorldSpace(Vector3.new(shoulderB.X, shoulderB.Y, 0)),
			base:PointToWorldSpace(Vector3.new(tip2.X, tip2.Y, 0)),
			0.050)

		-- A short central ridge makes the arrowheads visibly solid rather than
		-- looking like three separate lines.
		local arrowBase = tip2 - dir * 0.15
		segment("ArrowRidge_" .. i,
			base:PointToWorldSpace(Vector3.new(arrowBase.X, arrowBase.Y, 0)),
			base:PointToWorldSpace(Vector3.new(tip2.X, tip2.Y, 0)),
			0.070)
	end
end

local function updateSolverEyeModel()
	if S.solverEnabled then
		if not solverEyeModel or solverEyeModel.Parent ~= LocalPlayer.Character then
			buildSolverEyeModel()
		end
	else
		clearSolverEyeModel()
	end
end

STATE.connect(RunService.RenderStepped, updateSolverEyeModel)
STATE.onCleanup(clearSolverEyeModel)

-- ============================================================
-- SOLVER SCAN RESULT POPUP
-- ============================================================

local scanResult = Instance.new("Frame")
scanResult.Name = "SolverScanResults"
scanResult.Size = UDim2.fromOffset(330, 430)
scanResult.AnchorPoint = Vector2.new(1, 0.5)
scanResult.Position = UDim2.new(1, -28, 0.5, 0)
scanResult.BackgroundTransparency = 1
scanResult.BorderSizePixel = 0
scanResult.ZIndex = 40
scanResult.Parent = scannerRoot

local scanResultLayout = Instance.new("UIListLayout")
scanResultLayout.HorizontalAlignment = Enum.HorizontalAlignment.Right
scanResultLayout.VerticalAlignment = Enum.VerticalAlignment.Center
scanResultLayout.SortOrder = Enum.SortOrder.LayoutOrder
scanResultLayout.Padding = UDim.new(0, 6)
scanResultLayout.Parent = scanResult

local function clearScanResultEntries()
	S.scanPopupToken += 1
	for player, entry in pairs(S.scanResultEntries) do
		if entry.frame then entry.frame:Destroy() end
		S.scanResultEntries[player] = nil
	end
end

local function hideSolverScanResult()
	clearScanResultEntries()
end

local function showSolverScanResult(player, distance)
	if not player then return end
	S.scanResultSerial += 1
	local old = S.scanResultEntries[player]
	if old and old.frame then old.frame:Destroy() end
	local frame = Instance.new("Frame")
	frame.Name = "Target_" .. player.UserId
	frame.Size = UDim2.fromOffset(330, 76)
	frame.BackgroundColor3 = DARKTINT
	frame.BackgroundTransparency = 0.12
	frame.BorderSizePixel = 0
	frame.LayoutOrder = -S.scanResultSerial
	frame.ZIndex = 40
	frame.Parent = scanResult
	local stroke = Instance.new("UIStroke")
	stroke.Color = RED
	stroke.Thickness = 1.5
	stroke.Parent = frame
	local header = Instance.new("TextLabel")
	header.Size = UDim2.new(1, -20, 0, 18)
	header.Position = UDim2.fromOffset(10, 6)
	header.BackgroundTransparency = 1
	header.Font = Enum.Font.Code
	header.Text = "// SOLVER TARGET ACQUIRED"
	header.TextColor3 = RED
	header.TextSize = 10
	header.TextXAlignment = Enum.TextXAlignment.Right
	header.ZIndex = 41
	header.Parent = frame
	local nameLabel = Instance.new("TextLabel")
	nameLabel.Size = UDim2.new(1, -20, 0, 26)
	nameLabel.Position = UDim2.fromOffset(10, 24)
	nameLabel.BackgroundTransparency = 1
	nameLabel.Font = Enum.Font.Code
	nameLabel.Text = player.Name
	nameLabel.TextColor3 = YELLOW
	nameLabel.TextSize = 18
	nameLabel.TextXAlignment = Enum.TextXAlignment.Right
	nameLabel.TextTruncate = Enum.TextTruncate.AtEnd
	nameLabel.ZIndex = 41
	nameLabel.Parent = frame
	local distanceLabel = Instance.new("TextLabel")
	distanceLabel.Size = UDim2.new(1, -20, 0, 18)
	distanceLabel.Position = UDim2.fromOffset(10, 50)
	distanceLabel.BackgroundTransparency = 1
	distanceLabel.Font = Enum.Font.Code
	distanceLabel.Text = string.format("DISTANCE // %.1f STUDS", distance)
	distanceLabel.TextColor3 = STEEL
	distanceLabel.TextSize = 11
	distanceLabel.TextXAlignment = Enum.TextXAlignment.Right
	distanceLabel.ZIndex = 41
	distanceLabel.Parent = frame
	S.scanResultEntries[player] = {frame = frame, serial = S.scanResultSerial}
	local token = S.scanResultSerial
	task.delay(5, function()
		local current = S.scanResultEntries[player]
		if current and current.serial == token and current.frame == frame then
			local tween = TweenService:Create(frame, TweenInfo.new(0.25), {BackgroundTransparency = 1})
			local t1 = TweenService:Create(nameLabel, TweenInfo.new(0.25), {TextTransparency = 1})
			local t2 = TweenService:Create(distanceLabel, TweenInfo.new(0.25), {TextTransparency = 1})
			local t3 = TweenService:Create(header, TweenInfo.new(0.25), {TextTransparency = 1})
			tween:Play(); t1:Play(); t2:Play(); t3:Play()
			tween.Completed:Wait()
			if S.scanResultEntries[player] and S.scanResultEntries[player].frame == frame then
				S.scanResultEntries[player] = nil
				frame:Destroy()
			end
		end
	end)
end

STATE.onCleanup(hideSolverScanResult)

-- ============================================================
-- SOLVER SCANNER
-- ============================================================

local scanReportedPlayers = {}
local function clearSolverContacts()
	for char, highlight in pairs(S.solverContacts) do
		if highlight then
			highlight:Destroy()
		end
		S.solverContacts[char] = nil
	end
end

local function clearSolverRays()
	for _, part in ipairs(S.solverRayParts) do
		if part then
			part:Destroy()
		end
	end
	table.clear(S.solverRayParts)
end

-- A single large forward sweep. It is triggered manually and runs once from
-- the left edge of the scan cone to the right edge, then disappears.
local function beginSolverScan()
	if not S.solverEnabled or scanActive then return end

	scanActive = true
	scanStartTime = os.clock()
	table.clear(scanReportedPlayers)
	S.scanTargetCount = 0
	clearSolverContacts()
	clearSolverRays()

	local rayPart = Instance.new("Part")
	rayPart.Name = "SolverRay_Scan"
	rayPart.Anchored = true
	rayPart.CanCollide = false
	rayPart.CanTouch = false
	rayPart.CanQuery = false
	rayPart.CastShadow = false
	rayPart.Material = Enum.Material.Neon
	rayPart.Color = YELLOW
	rayPart.Size = Vector3.new(0.09, 0.09, SCAN_RANGE)
	rayPart.Transparency = 0.18
	rayPart.Parent = workspace
	table.insert(S.solverRayParts, rayPart)
end

local function endSolverScan()
	scanActive = false
	table.clear(scanReportedPlayers)
	clearSolverRays()
	clearSolverContacts()
end

-- ============================================================
-- SOLVER WINGS / FLIGHT
-- ============================================================

-- The wings use a real articulated Motor6D hierarchy.  The old version
-- treated the feathers as large wedges laid across the back; this version
-- keeps every piece in a controlled local coordinate system so the finished
-- wing is with a broad horizontal silhouette and long pointed outer fingers.
local WING_ASSET_ID = 112392473220517
local WING_SCALE = 2.0
local WING_OFFSET_X = 0.0
local WING_OFFSET_Y = 0.65
local WING_OFFSET_Z = -0.85
local WING_DEPLOY_TIME = 0.85
local WING_POP_DISTANCE = 1.05
local TAIL_ASSET_ID = 80416389405287
local TAIL_SCALE = 1.0
local TAIL_WAG_SPEED = 3.2
local TAIL_WAG_AMOUNT = 0.14
local IY_FLY_SPEED = 1
local FLIGHT_SPEED = 50

local wingDeployAlpha = 0
local wingDeployStarted = 0

local function getFlightRig()
	local char = LocalPlayer.Character
	if not char then return nil, nil, nil end
	local humanoid = char:FindFirstChildOfClass("Humanoid")
	local root = char:FindFirstChild("HumanoidRootPart")
	local torso = char:FindFirstChild("UpperTorso") or char:FindFirstChild("Torso")
	return humanoid, root, torso
end

local function stopFlight()
	S.flying = false
	if S.flightInputDown then S.flightInputDown:Disconnect(); S.flightInputDown = nil end
	if S.flightInputUp then S.flightInputUp:Disconnect(); S.flightInputUp = nil end
	if S.flightVelocity then S.flightVelocity:Destroy(); S.flightVelocity = nil end
	if S.flightGyro then S.flightGyro:Destroy(); S.flightGyro = nil end
	if S.flightSound then S.flightSound:Destroy(); S.flightSound = nil end
	S.flightControls = {F = 0, B = 0, L = 0, R = 0, Q = 0, E = 0}
	local humanoid = select(1, getFlightRig())
	if humanoid then humanoid.PlatformStand = false; humanoid.AutoRotate = true end
	pcall(function() workspace.CurrentCamera.CameraType = Enum.CameraType.Custom end)
end

-- ============================================================
-- CATALOG-MODEL WINGS
-- ============================================================
-- Instead of approximating the reference with Parts/WedgeParts, this build
-- asks Roblox for the actual UGC accessory model by catalog asset ID.  The
-- accessory is cloned locally and attached to the live character, so the
-- visible wing geometry/material/tears come from the catalog model itself.

local function findAccessoryModel(container)
	for _, child in ipairs(container:GetDescendants()) do
		if child:IsA("Accessory") then
			return child
		end
	end
	return nil
end

local function loadCatalogWingAccessory()
	local description = Instance.new("HumanoidDescription")
	description.ShouldersAccessory = tostring(WING_ASSET_ID)

	local ok, dummyOrError = pcall(function()
		return Players:CreateHumanoidModelFromDescriptionAsync(
			description,
			Enum.HumanoidRigType.R15
		)
	end)
	description:Destroy()

	if not ok or not dummyOrError then
		warn("[Murder Drones HUD] Failed to load catalog wing asset:", dummyOrError)
		return nil
	end

	local dummy = dummyOrError
	local sourceAccessory = findAccessoryModel(dummy)
	if not sourceAccessory then
		-- A few catalog items are classified as back accessories even when the
		-- thumbnail/description presents them as shoulder-mounted wings.
		local fallbackDescription = Instance.new("HumanoidDescription")
		fallbackDescription.BackAccessory = tostring(WING_ASSET_ID)
		local fallbackOk, fallbackDummy = pcall(function()
			return Players:CreateHumanoidModelFromDescriptionAsync(
				fallbackDescription,
				Enum.HumanoidRigType.R15
			)
		end)
		fallbackDescription:Destroy()
		dummy:Destroy()
		if not fallbackOk or not fallbackDummy then
			warn("[Murder Drones HUD] Catalog wing could not be resolved as a shoulder or back accessory:", fallbackDummy)
			return nil
		end
		dummy = fallbackDummy
		sourceAccessory = findAccessoryModel(dummy)
	end

	if not sourceAccessory then
		dummy:Destroy()
		warn("[Murder Drones HUD] Catalog wing asset returned no Accessory instance.")
		return nil
	end

	local clone = sourceAccessory:Clone()
	dummy:Destroy()
	return clone
end

local function scaleCatalogAccessory(accessory, scale)
	local handle = accessory and accessory:FindFirstChild("Handle")
	if not handle or not handle:IsA("BasePart") then return end

	-- Scale the actual mesh assembly around the Handle. Attachment.CFrame is
	-- local to its parent, so capture each local attachment transform BEFORE
	-- moving/scaling the parent parts, then scale only its local position.
	local pivot = handle.CFrame
	local attachmentFrames = {}
	for _, descendant in ipairs(accessory:GetDescendants()) do
		if descendant:IsA("Attachment") then
			attachmentFrames[descendant] = descendant.CFrame
		end
	end

	for _, descendant in ipairs(accessory:GetDescendants()) do
		if descendant:IsA("BasePart") then
			local relative = pivot:ToObjectSpace(descendant.CFrame)
			descendant.Size *= scale
			descendant.CFrame = pivot * CFrame.fromMatrix(
				relative.Position * scale,
				relative.XVector,
				relative.YVector,
				relative.ZVector
			)
			local specialMesh = descendant:FindFirstChildOfClass("SpecialMesh")
			if specialMesh then
				specialMesh.Scale *= scale
			end
		end
	end

	for attachment, localCF in pairs(attachmentFrames) do
		if attachment and attachment.Parent then
			attachment.CFrame = CFrame.new(localCF.Position * scale) * localCF.Rotation
		end
	end
end

local function attachCatalogAccessory(accessory, character)
	if not accessory or not character then return nil end
	local torso = character:FindFirstChild("UpperTorso") or character:FindFirstChild("Torso")
	if not torso then return nil end

	local handle = accessory:FindFirstChild("Handle")
	if not handle or not handle:IsA("BasePart") then
		return nil
	end

	local handleAttachment
	for _, child in ipairs(handle:GetChildren()) do
		if child:IsA("Attachment") then
			handleAttachment = child
			break
		end
	end

	local bodyAttachment
	if handleAttachment then
		bodyAttachment = torso:FindFirstChild(handleAttachment.Name)
	end

	accessory.Parent = character
	handle.CanCollide = false
	handle.CanTouch = false
	handle.CanQuery = false
	handle.Massless = true

	-- Rebuild the accessory weld against the live torso.  This preserves the
	-- exact mesh while letting the HUD animate the whole catalog accessory.
	for _, child in ipairs(handle:GetChildren()) do
		if child:IsA("Weld") or child:IsA("WeldConstraint") or child:IsA("Motor6D") then
			child:Destroy()
		end
	end

	local weld = Instance.new("Weld")
	weld.Name = "SolverCatalogWingWeld"
	weld.Part0 = handle
	weld.Part1 = torso
	if handleAttachment and bodyAttachment then
		-- Keep the catalog attachment orientation, but deliberately move the
		-- entire wing assembly up and behind the torso.  The previous build
		-- snapped the UGC attachment directly onto the torso attachment, which
		-- put the wings at the character's lower-back/"ass" position.
		weld.C0 = handleAttachment.CFrame
		weld.C1 = bodyAttachment.CFrame * CFrame.new(WING_OFFSET_X, WING_OFFSET_Y, WING_OFFSET_Z)
	else
		weld.C0 = CFrame.identity
		weld.C1 = CFrame.new(WING_OFFSET_X, WING_OFFSET_Y, WING_OFFSET_Z)
	end
	weld.Parent = handle

	return {
		accessory = accessory,
		handle = handle,
		weld = weld,
		baseC0 = weld.C0,
	}
end

local function clearWings()
	stopFlight()
	for _, assembly in ipairs(S.wingMotors) do
		if assembly.accessory and assembly.accessory.Parent then
			assembly.accessory:Destroy()
		end
	end
	table.clear(S.wingMotors)
	if S.wingModel then S.wingModel:Destroy(); S.wingModel = nil end
	S.wingLoading = false
	wingDeployAlpha = 0
end

local function buildWings()
	if S.wingModel and S.wingModel.Parent then return end
	if S.wingLoading then return end
	local character = LocalPlayer.Character
	if not character then return end

	S.wingLoading = true
	task.spawn(function()
		local accessory = loadCatalogWingAccessory()
		if not S.wingsEnabled or LocalPlayer.Character ~= character then
			if accessory then accessory:Destroy() end
			S.wingLoading = false
			return
		end
		if not accessory then
			S.wingLoading = false
			return
		end

		local model = Instance.new("Model")
		model.Name = "SolverWings_CatalogMesh"
		model.Parent = character
		S.wingModel = model

		scaleCatalogAccessory(accessory, WING_SCALE)
		local record = attachCatalogAccessory(accessory, character)
		if not record then
			accessory:Destroy()
			model:Destroy()
			S.wingModel = nil
			S.wingLoading = false
			return
		end

		accessory.Parent = model
		table.insert(S.wingMotors, record)
		wingDeployAlpha = 0
		wingDeployStarted = os.clock()
		S.wingLoading = false
	end)
end

-- ============================================================
-- LEGACY MURDER DRONES TAIL
-- ============================================================
-- The supplied Tail asset is an old client-side character script rather than
-- a normal accessory. We borrow its model/tool-replication approach, but keep
-- the final pose anchored to the character instead of the mouse/cursor.

local function clearTail()
	for _, connection in ipairs(S.tailConnections) do
		if connection then connection:Disconnect() end
	end
	table.clear(S.tailConnections)

	for _, part in ipairs(S.tailParts) do
		if part and part.Parent then part:Destroy() end
	end
	table.clear(S.tailParts)
	local backpack = LocalPlayer:FindFirstChild("Backpack")
	for _, tool in ipairs(S.tailTools) do
		if tool and tool.Parent then
			local fake = tool:FindFirstChild("FakeHandle")
			if fake then fake:Destroy() end
			local handle = tool:FindFirstChild("Handle")
			if handle then
				for _, child in ipairs(handle:GetChildren()) do
					if child.Name == "SolverTailWeld" or (child:IsA("Weld") and child.Part0 == fake) then child:Destroy() end
				end
			end
			if backpack then tool.Parent = backpack end
		end
	end
	table.clear(S.tailTools)

	if S.tailModel and S.tailModel.Parent then
		S.tailModel:Destroy()
	end
	S.tailModel = nil
	S.tailWeld = nil
	S.tailBaseC0 = nil
	S.tailLoading = false
end

local function loadCatalogTailAccessory()
	local function findAccessoryModel(container)
		for _, child in ipairs(container:GetDescendants()) do
			if child:IsA("Accessory") then
				return child
			end
		end
		return nil
	end

	local function tryDescription(propertyName)
		local description = Instance.new("HumanoidDescription")
		if propertyName == "BackAccessory" then
			description.BackAccessory = tostring(TAIL_ASSET_ID)
		else
			description.WaistAccessory = tostring(TAIL_ASSET_ID)
		end
		local ok, dummyOrError = pcall(function()
			return Players:CreateHumanoidModelFromDescriptionAsync(
				description,
				Enum.HumanoidRigType.R15
			)
		end)
		description:Destroy()
		if not ok or not dummyOrError then
			return nil, dummyOrError
		end
		local dummy = dummyOrError
		local accessory = findAccessoryModel(dummy)
		if not accessory then
			dummy:Destroy()
			return nil, "no Accessory returned"
		end
		local clone = accessory:Clone()
		dummy:Destroy()
		return clone
	end

	local accessory, err = tryDescription("BackAccessory")
	if not accessory then
		accessory, err = tryDescription("WaistAccessory")
	end
	if not accessory then
		warn("[Murder Drones HUD] Solver tail accessory could not be loaded:", err)
		return nil
	end
	return accessory
end

local function scaleTailAccessory(accessory, scale)
	if not accessory or scale == 1 then return end
	local handle = accessory:FindFirstChild("Handle")
	if not handle or not handle:IsA("BasePart") then return end

	local pivot = handle.CFrame
	local attachmentFrames = {}
	for _, descendant in ipairs(accessory:GetDescendants()) do
		if descendant:IsA("Attachment") then
			attachmentFrames[descendant] = descendant.CFrame
		end
	end

	for _, descendant in ipairs(accessory:GetDescendants()) do
		if descendant:IsA("BasePart") then
			local relative = pivot:ToObjectSpace(descendant.CFrame)
			descendant.Size *= scale
			descendant.CFrame = pivot * CFrame.fromMatrix(
				relative.Position * scale,
				relative.XVector,
				relative.YVector,
				relative.ZVector
			)
			local mesh = descendant:FindFirstChildOfClass("SpecialMesh")
			if mesh then mesh.Scale *= scale end
		end
	end

	for attachment, localCF in pairs(attachmentFrames) do
		if attachment and attachment.Parent then
			attachment.CFrame = CFrame.new(localCF.Position * scale) * localCF.Rotation
		end
	end
end

local function attachCatalogTail(accessory, character)
	if not accessory or not character then return nil end
	local torso = character:FindFirstChild("UpperTorso")
		or character:FindFirstChild("LowerTorso")
		or character:FindFirstChild("Torso")
		or character:FindFirstChild("HumanoidRootPart")
	if not torso or not torso:IsA("BasePart") then return nil end

	local handle = accessory:FindFirstChild("Handle")
	if not handle or not handle:IsA("BasePart") then return nil end

	local handleAttachment
	for _, child in ipairs(handle:GetChildren()) do
		if child:IsA("Attachment") then
			handleAttachment = child
			break
		end
	end

	local bodyAttachment
	if handleAttachment then
		bodyAttachment = torso:FindFirstChild(handleAttachment.Name)
	end
	if not bodyAttachment then
		for _, name in ipairs({"BodyBackAttachment", "WaistBackAttachment", "BackAttachment"}) do
			local candidate = torso:FindFirstChild(name)
			if candidate and candidate:IsA("Attachment") then
				bodyAttachment = candidate
				break
			end
		end
	end

	accessory.Parent = character
	handle.CanCollide = false
	handle.CanTouch = false
	handle.CanQuery = false
	handle.Massless = true

	for _, child in ipairs(handle:GetChildren()) do
		if child:IsA("Weld") or child:IsA("WeldConstraint") or child:IsA("Motor6D") then
			child:Destroy()
		end
	end

	local weld = Instance.new("Weld")
	weld.Name = "SolverTailWeld"
	weld.Part0 = handle
	weld.Part1 = torso
	if handleAttachment and bodyAttachment then
		weld.C0 = handleAttachment.CFrame
		weld.C1 = bodyAttachment.CFrame
	else
		weld.C0 = CFrame.new(0, -0.1, 0.45)
		weld.C1 = CFrame.identity
	end
	weld.Parent = handle

	return {
		accessory = accessory,
		handle = handle,
		weld = weld,
		baseC0 = weld.C0,
	}
end

local function buildTail()
	if S.tailModel and S.tailModel.Parent then return end
	if S.tailLoading then return end
	local character = LocalPlayer.Character
	if not character then return end

	S.tailLoading = true
	task.spawn(function()
		local accessory = loadCatalogTailAccessory()
		if not accessory then
			S.tailLoading = false
			return
		end
		if not S.wingsEnabled or LocalPlayer.Character ~= character then
			accessory:Destroy()
			S.tailLoading = false
			return
		end

		local model = Instance.new("Model")
		model.Name = "SolverTail_CatalogMesh"
		model.Parent = character
		S.tailModel = model

		scaleTailAccessory(accessory, TAIL_SCALE)
		local record = attachCatalogTail(accessory, character)
		if not record then
			accessory:Destroy()
			model:Destroy()
			S.tailModel = nil
			S.tailLoading = false
			warn("[Murder Drones HUD] Solver tail accessory had no usable Handle/attachment.")
			return
		end

		accessory.Parent = model
		S.tailWeld = record.weld
		S.tailBaseC0 = record.baseC0
		S.tailLoading = false
	end)
end

local function startFlight()
	if S.flying or not S.wingsEnabled or not S.solverEnabled then return end
	local humanoid, root = getFlightRig(); if not humanoid or not root then return end
	buildWings(); S.flying=true; humanoid.PlatformStand=true; humanoid.AutoRotate=false
	S.flightControls={F=0,B=0,L=0,R=0,Q=0,E=0}
	S.flightVelocity=Instance.new("BodyVelocity"); S.flightVelocity.Name="SolverFlightVelocity"; S.flightVelocity.MaxForce=Vector3.new(9e9,9e9,9e9); S.flightVelocity.Velocity=Vector3.zero; S.flightVelocity.Parent=root
	S.flightGyro=Instance.new("BodyGyro"); S.flightGyro.Name="SolverFlightGyro"; S.flightGyro.P=9e4; S.flightGyro.MaxTorque=Vector3.new(9e9,9e9,9e9); S.flightGyro.CFrame=root.CFrame; S.flightGyro.Parent=root
	S.flightInputDown=UserInputService.InputBegan:Connect(function(input,processed)
		if processed then return end
		if input.KeyCode==Enum.KeyCode.W then S.flightControls.F=IY_FLY_SPEED elseif input.KeyCode==Enum.KeyCode.S then S.flightControls.B=-IY_FLY_SPEED elseif input.KeyCode==Enum.KeyCode.A then S.flightControls.L=-IY_FLY_SPEED elseif input.KeyCode==Enum.KeyCode.D then S.flightControls.R=IY_FLY_SPEED elseif input.KeyCode==Enum.KeyCode.E then S.flightControls.Q=IY_FLY_SPEED*2 elseif input.KeyCode==Enum.KeyCode.Q then S.flightControls.E=-IY_FLY_SPEED*2 end
	end)
	S.flightInputUp=UserInputService.InputEnded:Connect(function(input,processed)
		if processed then return end
		if input.KeyCode==Enum.KeyCode.W then S.flightControls.F=0 elseif input.KeyCode==Enum.KeyCode.S then S.flightControls.B=0 elseif input.KeyCode==Enum.KeyCode.A then S.flightControls.L=0 elseif input.KeyCode==Enum.KeyCode.D then S.flightControls.R=0 elseif input.KeyCode==Enum.KeyCode.E then S.flightControls.Q=0 elseif input.KeyCode==Enum.KeyCode.Q then S.flightControls.E=0 end
	end)
	if FLIGHT_LOOP_SOUND_ID then
		S.flightSound=Instance.new("Sound"); S.flightSound.Name="SolverFlightLoop"; S.flightSound.SoundId=FLIGHT_LOOP_SOUND_ID; S.flightSound.Looped=true; S.flightSound.Volume=.25; S.flightSound.Parent=root; S.flightSound:Play()
	end
end

setWingsEnabled = function(state)
	S.wingsEnabled = state and S.solverEnabled
	wingsButton.Text = S.wingsEnabled and "WINGS [ON]" or "WINGS [OFF]"
	wingsButton.TextColor3 = S.wingsEnabled and RED or YELLOW_DIM
	wingsStroke.Color = S.wingsEnabled and RED or YELLOW_DIM
	if S.wingsEnabled then buildWings(); buildTail() else clearWings(); clearTail() end
end

wingsButton.MouseButton1Click:Connect(function()
	if S.solverEnabled then setWingsEnabled(not S.wingsEnabled) end
end)

raycastButton.Text = "SCAN [R]"
raycastButton.TextColor3 = YELLOW_DIM
raycastStroke.Color = YELLOW_DIM

raycastButton.MouseButton1Click:Connect(function()
	beginSolverScan()
end)

STATE.connect(UserInputService.InputBegan, function(input, processed)
	if processed or not S.solverEnabled then return end
	if input.KeyCode == Enum.KeyCode.R then
		beginSolverScan()
	end
end)

STATE.connect(RunService.RenderStepped, function(dt)
	if not S.wingsEnabled then return end
	if not S.wingModel or not S.wingModel.Parent then buildWings() end

	local now = os.clock()
	local deployT = math.clamp((now - wingDeployStarted) / WING_DEPLOY_TIME, 0, 1)
	wingDeployAlpha = 1 - ((1 - deployT) ^ 3)
		if S.flying and now - S.lastFlapSound >= 0.24 then
		S.lastFlapSound = now
		playSound(WING_FLAP_SOUND_ID, 0.32, 1.05, false)
	end

	for _, wing in ipairs(S.wingMotors) do
		if wing.weld and wing.weld.Parent then
			local flapAngle = 0
			if S.flying then
				flapAngle = math.sin(now * 8.2) * 0.16
			else
				flapAngle = math.sin(now * 1.8) * 0.018
			end
			local deployAlpha = wingDeployAlpha
			local deployAngle = math.rad(18 * (1 - deployAlpha))
			local pop = WING_POP_DISTANCE * (1 - deployAlpha)
			wing.weld.C0 = wing.baseC0 * CFrame.new(0, 0, -pop) * CFrame.Angles(deployAngle + flapAngle, 0, 0)
		end
	end

	-- The tail never reads the mouse/camera. Its motion is a small autonomous
	-- idle wag so it stays attached to the character.
	if S.tailModel and S.tailModel.Parent then
		local torso = LocalPlayer.Character and (LocalPlayer.Character:FindFirstChild("LowerTorso") or LocalPlayer.Character:FindFirstChild("UpperTorso") or LocalPlayer.Character:FindFirstChild("Torso"))
		if torso then
			local wag = math.sin(now * TAIL_WAG_SPEED) * TAIL_WAG_AMOUNT
			-- Legacy/tool tails are already driven from the body-relative offsets above.
			-- Do not cumulatively rotate their parts here; doing so causes drift.
			if S.tailWeld and S.tailWeld.Parent then
				-- Animate the weld, not a welded part's world CFrame.
				S.tailWeld.C0 = (S.tailBaseC0 or S.tailWeld.C0) * CFrame.Angles(0, wag * 0.35, 0)
			end
		end
	end

	if not S.flying then return end

	local humanoid, root = getFlightRig()
	if not humanoid or not root or not S.flightVelocity or not S.flightGyro then
		stopFlight()
		return
	end

	local camera = workspace.CurrentCamera
	if not camera then return end
	local controlX = S.flightControls.L + S.flightControls.R
	local controlZ = S.flightControls.F + S.flightControls.B
	local controlY = S.flightControls.Q + S.flightControls.E
	if controlX ~= 0 or controlZ ~= 0 or controlY ~= 0 then
		S.flightVelocity.Velocity = ((camera.CFrame.LookVector * controlZ) + ((camera.CFrame * CFrame.new(controlX, (controlZ + controlY) * 0.2, 0).Position) - camera.CFrame.Position)) * FLIGHT_SPEED
	else
		S.flightVelocity.Velocity = Vector3.zero
	end
	S.flightGyro.CFrame = camera.CFrame
end)

local function updateSolver()
	if not S.solverEnabled or not scanActive then
		if #S.solverRayParts > 0 or next(S.solverContacts) ~= nil then
			clearSolverRays()
			clearSolverContacts()
		end
		return
	end

	local elapsed = os.clock() - scanStartTime
	local progress = math.clamp(elapsed / SCAN_DURATION, 0, 1)
	if progress >= 1 then
		endSolverScan()
		return
	end

	local char = LocalPlayer.Character
	local hrp = char and char:FindFirstChild("HumanoidRootPart")
	local head = char and char:FindFirstChild("Head")
	if not hrp or not head then
		endSolverScan()
		return
	end

	-- One pass only: left edge -> center -> right edge. The ray now originates
	-- from the player's character, so camera movement cannot move the scanner.
	local halfArc = math.rad(SCAN_ARC * 0.5)
	local scanAngle = -halfArc + (halfArc * 2 * progress)
	local flatLook = Vector3.new(hrp.CFrame.LookVector.X, 0, hrp.CFrame.LookVector.Z)
	if flatLook.Magnitude < 0.01 then
		flatLook = Vector3.new(0, 0, -1)
	end
	flatLook = flatLook.Unit
	local baseAngle = math.atan2(-flatLook.Z, flatLook.X)
	local rayAngle = baseAngle + scanAngle
	local direction = Vector3.new(math.cos(rayAngle), 0, -math.sin(rayAngle)).Unit
	local origin = hrp.Position + Vector3.new(0, 0.15, 0)

	local targetCharacters = {}
	for _, player in ipairs(Players:GetPlayers()) do
		if player ~= LocalPlayer and player.Character then
			table.insert(targetCharacters, player.Character)
		end
	end

	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Include
	params.FilterDescendantsInstances = targetCharacters
	params.IgnoreWater = true

	local result = #targetCharacters > 0 and workspace:Raycast(origin, direction * SCAN_RANGE, params) or nil
	local distance = result and (result.Position - origin).Magnitude or SCAN_RANGE
	local rayPart = S.solverRayParts[1]
	if rayPart then
		rayPart.Size = Vector3.new(0.09, 0.09, distance)
		rayPart.CFrame = CFrame.lookAt(origin + direction * distance * 0.5, origin + direction * distance)
		rayPart.Color = result and RED or YELLOW
		rayPart.Transparency = result and 0.02 or 0.18
	end

	if result then
		local model = result.Instance:FindFirstAncestorOfClass("Model")
		local player = model and Players:GetPlayerFromCharacter(model)
		if player and player ~= LocalPlayer then
			if not S.solverContacts[model] then
				local h = Instance.new("Highlight")
				h.Name = "SolverContact"
				h.FillTransparency = 1
				h.OutlineColor = RED
				h.OutlineTransparency = 0
				h.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
				h.Parent = model
				S.solverContacts[model] = h
			end
			if not scanReportedPlayers[player] then
				scanReportedPlayers[player] = true
				S.scanTargetCount += 1
				showSolverScanResult(player, distance)
			end
		end
	end
end

STATE.connect(
	RunService.Heartbeat,
	function()
		if S.solverEnabled
			and S.systemEnabled
		then

			updateSolver()
		end
	end
)

-- ============================================================
-- CAMERA HOLDER
-- ============================================================

local camHolder =
	Instance.new("Frame")

camHolder.Size =
	UDim2.fromOffset(
		180,
		0
	)

camHolder.AnchorPoint =
	Vector2.new(
		1,
		0
	)

camHolder.Position =
	UDim2.new(
		1,
		-30,
		0,
		20
	)

camHolder.BackgroundTransparency =
	1

camHolder.ClipsDescendants =
	true

camHolder.Parent =
	scannerRoot

-- ============================================================
-- CAMERA BOX FACTORY
-- ============================================================

local function makeCamBox(
	labelText,
	yOffset
)
	local box =
		Instance.new("Frame")

	box.Size =
		UDim2.new(
			1,
			0,
			0,
			100
		)

	box.Position =
		UDim2.new(
			0,
			0,
			0,
			yOffset
		)

	box.BackgroundColor3 =
		DARKTINT

	box.BackgroundTransparency =
		0.3

	box.BorderSizePixel =
		0

	box.Parent =
		camHolder

	local stroke =
		Instance.new("UIStroke")

	stroke.Color =
		YELLOW

	stroke.Thickness =
		1.5

	stroke.Parent =
		box

	local label =
		Instance.new("TextLabel")

	label.BackgroundTransparency =
		1

	label.Size =
		UDim2.new(
			1,
			0,
			0,
			16
		)

	label.Font =
		Enum.Font.Code

	label.Text =
		labelText

	label.TextColor3 =
		YELLOW

	label.TextSize =
		15

	label.Parent =
		box

	local viewport =
		Instance.new(
			"ViewportFrame"
		)

	viewport.Size =
		UDim2.new(
			1,
			-6,
			1,
			-20
		)

	viewport.Position =
		UDim2.new(
			0,
			3,
			0,
			18
		)

	viewport.BackgroundColor3 =
		Color3.fromRGB(
			28,
			34,
			42
		)

	viewport.BackgroundTransparency =
		0

	viewport.Ambient =
		Color3.fromRGB(
			190,
			205,
			220
		)

	viewport.LightColor =
		Color3.fromRGB(
			255,
			235,
			190
		)

	viewport.ImageColor3 =
		Color3.fromRGB(
			235,
			242,
			255
		)

	viewport.ImageTransparency =
		0

	viewport.Parent =
		box

	local worldModel =
		Instance.new(
			"WorldModel"
		)

	worldModel.Parent =
		viewport

	local cam =
		Instance.new(
			"Camera"
		)

	cam.FieldOfView =
		70

	cam.Parent =
		viewport

	viewport.CurrentCamera =
		cam

	viewport.Visible =
		true

	viewport.ZIndex =
		2

	return {
		box = box,
		viewport = viewport,
		worldModel = worldModel,
		camera = cam,
	}
end

local thirdPersonCam =
	makeCamBox(
		"3RD PERSON",
		0
	)

local firstPersonCam =
	makeCamBox(
		"1ST PERSON",
		110
	)

-- ============================================================
-- CAMERA CONNECTION TERMINATION EFFECTS
-- ============================================================

local STATIC_CHARS = " .:*#@%+=-_/\\|"

local function randomStaticLine(width)
	local out = table.create(width)
	for i = 1, width do
		local index = math.random(1, #STATIC_CHARS)
		out[i] = STATIC_CHARS:sub(index, index)
	end
	return table.concat(out)
end

local function makeTerminationOverlay(parent, name)
	local overlay = Instance.new("Frame")
	overlay.Name = name
	overlay.Size = UDim2.fromScale(1, 1)
	overlay.Position = UDim2.fromScale(0, 0)
	overlay.BackgroundColor3 = Color3.fromRGB(2, 3, 4)
	overlay.BackgroundTransparency = 0.04
	overlay.BorderSizePixel = 0
	overlay.ZIndex = 80
	overlay.Visible = false
	overlay.ClipsDescendants = true
	overlay.Parent = parent

	local static = Instance.new("TextLabel")
	static.Name = "Static"
	static.Size = UDim2.new(1, -12, 1, -12)
	static.Position = UDim2.fromOffset(6, 6)
	static.BackgroundTransparency = 1
	static.Font = Enum.Font.Code
	static.TextColor3 = STEEL
	static.TextTransparency = 0.18
	static.TextSize = 9
	static.TextWrapped = false
	static.TextXAlignment = Enum.TextXAlignment.Left
	static.TextYAlignment = Enum.TextYAlignment.Top
	static.ZIndex = 81
	static.Parent = overlay

	local message = Instance.new("TextLabel")
	message.Name = "Message"
	message.Size = UDim2.new(1, -20, 0, 44)
	message.Position = UDim2.new(0, 10, 0.5, -22)
	message.BackgroundTransparency = 1
	message.Font = Enum.Font.Code
	message.TextColor3 = RED
	message.TextSize = 13
	message.TextWrapped = true
	message.TextXAlignment = Enum.TextXAlignment.Center
	message.TextYAlignment = Enum.TextYAlignment.Center
	message.TextTransparency = 1
	message.ZIndex = 82
	message.Parent = overlay

	local stroke = Instance.new("UIStroke")
	stroke.Color = RED
	stroke.Thickness = 1
	stroke.Transparency = 1
	stroke.Parent = message

	return {
		root = overlay,
		static = static,
		message = message,
		stroke = stroke,
	}
end

playConnectionTerminated = function(effect, displayName, onFinished)
	if not effect or not effect.root or not effect.root.Parent then
		if onFinished then onFinished() end
		return
	end

	effect.token = (effect.token or 0) + 1
	local token = effect.token
	effect.root.Visible = true
	effect.root.BackgroundTransparency = 0.04
	effect.static.TextTransparency = 0.18
	effect.message.TextTransparency = 1
	effect.stroke.Transparency = 1

	task.spawn(function()
		for frame = 1, 10 do
			if token ~= effect.token or not effect.root.Parent then return end
			effect.static.Text = randomStaticLine(42) .. "\n" .. randomStaticLine(42) .. "\n" .. randomStaticLine(42) .. "\n" .. randomStaticLine(42) .. "\n" .. randomStaticLine(42) .. "\n" .. randomStaticLine(42)
			effect.static.Rotation = math.random(-1, 1)
			effect.root.BackgroundTransparency = math.random(0, 16) / 100
			task.wait(0.035)
		end

		if token ~= effect.token or not effect.root.Parent then return end
		effect.static.Text = randomStaticLine(42) .. "\n" .. randomStaticLine(42) .. "\n" .. randomStaticLine(42)
		effect.message.Text = "// CONNECTION TERMINATED\n" .. string.upper(displayName or "UNKNOWN")
		effect.message.TextTransparency = 0
		effect.stroke.Transparency = 0.15
		task.wait(0.45)

		if token ~= effect.token or not effect.root.Parent then return end
		local fade = TweenInfo.new(0.34, Enum.EasingStyle.Quad, Enum.EasingDirection.In)
		TweenService:Create(effect.root, fade, {
			BackgroundTransparency = 1,
			Size = UDim2.new(1, 0, 0, 0),
			Position = UDim2.new(0, 0, 0.5, 0),
		}):Play()
		TweenService:Create(effect.static, fade, {TextTransparency = 1}):Play()
		TweenService:Create(effect.message, fade, {TextTransparency = 1}):Play()
		TweenService:Create(effect.stroke, fade, {Transparency = 1}):Play()
		task.wait(0.36)

		if token == effect.token and effect.root.Parent then
			effect.root.Visible = false
		end
		if onFinished then onFinished() end
	end)
end

terminateNormalCamera = function(displayName)
	if S.normalCameraTermination then return end
	local effect = makeTerminationOverlay(camHolder, "NormalCameraTermination")
	S.normalCameraTermination = effect
	playConnectionTerminated(effect, displayName, function()
		if S.normalCameraTermination == effect then
			effect.root:Destroy()
			S.normalCameraTermination = nil
		end
		S.trackedPlayer = nil
		clearActiveVisual()
		clearClones()
		setCamsVisible(false)
		banner.Text = ""
	end)
end

-- ============================================================
-- SPYWARE CAMERA GRID
-- ============================================================

local spywareHolder =
	Instance.new("Frame")

spywareHolder.Name =
	"SpywareCameras"

spywareHolder.Size =
	UDim2.fromOffset(
		420,
		440
	)

spywareHolder.AnchorPoint =
	Vector2.new(
		1,
		0
	)

spywareHolder.Position =
	UDim2.new(
		1,
		-30,
		0,
		20
	)

spywareHolder.BackgroundTransparency =
	1

spywareHolder.Visible =
	false

spywareHolder.Parent =
	scannerRoot

local spywareLayout =
	Instance.new(
		"UIGridLayout"
	)

spywareLayout.CellSize =
	UDim2.fromOffset(
		205,
		210
	)

spywareLayout.CellPadding =
	UDim2.fromOffset(
		8,
		8
	)

spywareLayout.SortOrder =
	Enum.SortOrder.LayoutOrder

spywareLayout.Parent =
	spywareHolder

-- ============================================================
-- HUD OVERLAP AVOIDANCE
-- ============================================================

local movableHudPanels = {
	{
		gui = hudTR,
		base = UDim2.new(1, -244, 0, 22),
		candidates = {
			UDim2.new(1, -244, 0, 22),
			UDim2.new(0, 24, 0, 150),
			UDim2.new(1, -244, 0, 150),
			UDim2.new(0, 24, 1, -145),
		},
	},
	{
		gui = normalTelemetry,
		base = UDim2.new(1, -320, 1, -254),
		candidates = {
			UDim2.new(1, -320, 1, -254),
			UDim2.new(1, -320, 1, -390),
			UDim2.new(0, 20, 1, -254),
			UDim2.new(0, 20, 1, -145),
			UDim2.new(0, 20, 0, 78),
		},
	},
	{
		gui = solverSystemPanel,
		base = UDim2.new(1, -320, 0, 214),
		candidates = {
			UDim2.new(1, -320, 0, 214),
			UDim2.new(0, 20, 0, 78),
			UDim2.new(1, -320, 0, 474),
			UDim2.new(0, 20, 1, -190),
		},
	},
}

local function rectsOverlap(aPos, aSize, bPos, bSize, padding)
	padding = padding or 0
	return aPos.X - padding < bPos.X + bSize.X
		and aPos.X + aSize.X + padding > bPos.X
		and aPos.Y - padding < bPos.Y + bSize.Y
		and aPos.Y + aSize.Y + padding > bPos.Y
end

local function guiRect(guiObject)
	return guiObject.AbsolutePosition, guiObject.AbsoluteSize
end

local function candidateRect(guiObject, candidate)
	local parent = guiObject.Parent
	local parentPos = parent and parent.AbsolutePosition or Vector2.zero
	local parentSize = parent and parent.AbsoluteSize or Vector2.zero
	local size = guiObject.AbsoluteSize
	local pos = parentPos + Vector2.new(
		candidate.X.Scale * parentSize.X + candidate.X.Offset - guiObject.AnchorPoint.X * size.X,
		candidate.Y.Scale * parentSize.Y + candidate.Y.Offset - guiObject.AnchorPoint.Y * size.Y
	)
	return pos, size
end

local fixedHudObstacles = {hudTL, hudBL, hudBR, banner, camHolder, spywareHolder, listPanel}

local function applyHudPanelLayout()
	local spyVisible = spywareHolder.Visible
	local camsVisible = camHolder.Visible and camHolder.AbsoluteSize.Y > 1

	-- Spyware gets a dedicated RIGHT-SIDE lane.  The player list owns the
	-- upper-left lane, so spyware is never allowed to occupy that rectangle.
	-- This is deliberately enforced every layout pass because the player list
	-- expands to ~220px tall when opened.
	if spyVisible then
		local spyCandidates = {
			UDim2.new(1, -30, 0, 88),
			UDim2.new(1, -30, 0, 116),
			UDim2.new(1, -30, 1, -460),
		}

		local spyChosen = spyCandidates[1]
		for _, candidate in ipairs(spyCandidates) do
			local pos, size = candidateRect(spywareHolder, candidate)
			local blocked = false

			for _, fixed in ipairs({listPanel, hudTL, hudBL, hudBR, banner}) do
				if fixed ~= spywareHolder and fixed.Visible then
					local fpos, fsize = guiRect(fixed)
					if rectsOverlap(pos, size, fpos, fsize, 8) then
						blocked = true
						break
					end
				end
			end

			if not blocked then
				spyChosen = candidate
				break
			end
		end

		spywareHolder.Position = spyChosen
		spywareHolder.ZIndex = 2

		-- Normal telemetry is removed while the spyware grid is active; there
		-- is no reason to let it compete for the remaining screen space.
		if normalTelemetry then
			normalTelemetry.Visible = false
		end

		-- The System Override panel is deliberately REMOVED while spyware is
		-- active. Do not move it around to make room for the camera grid.
		solverSystemPanel.Visible = false
		return
	end

	if normalTelemetry then
		normalTelemetry.Visible = true
	end

	-- When spectating a tracked player, the camera feed owns its space.
	-- The Solver System Override panel is simply removed instead of being
	-- shuffled around the screen. It will be restored when the camera closes.
	if camsVisible then
		solverSystemPanel.Visible = false
		return
	end

	-- Normal telemetry lives above the bottom-right status text when there is
	-- enough vertical room.
	local telemetryCandidates = {
		UDim2.new(1, -320, 1, -254),
		UDim2.new(0, 20, 1, -254),
		UDim2.new(0, 20, 0, 78),
	}
	local telemetryChosen = telemetryCandidates[1]
	for _, candidate in ipairs(telemetryCandidates) do
		local pos, size = candidateRect(normalTelemetry, candidate)
		local blocked = false
		for _, fixed in ipairs({hudTL, hudBL, hudBR, banner, camHolder, solverSystemPanel, listPanel}) do
			if fixed ~= normalTelemetry and fixed.Visible then
				local fpos, fsize = guiRect(fixed)
				if rectsOverlap(pos, size, fpos, fsize, 6) then
					blocked = true
					break
				end
			end
		end
		if not blocked then
			telemetryChosen = candidate
			break
		end
	end
	normalTelemetry.Position = telemetryChosen

	-- Solver override gets its own responsive lane.
	local solverCandidates
	if camsVisible then
		solverCandidates = {
			UDim2.new(0, 20, 0, 78),
			UDim2.new(0, 20, 1, -190),
			UDim2.new(1, -320, 1, -190),
		}
	else
		solverCandidates = {
			UDim2.new(1, -320, 0, 214),
			UDim2.new(0, 20, 0, 78),
			UDim2.new(1, -320, 1, -190),
		}
	end

	local chosen = solverCandidates[1]
	for _, candidate in ipairs(solverCandidates) do
		local pos, size = candidateRect(solverSystemPanel, candidate)
		local blocked = false
		for _, fixed in ipairs({hudTL, hudBL, hudBR, banner, camHolder, normalTelemetry, listPanel}) do
			if fixed ~= solverSystemPanel and fixed.Visible then
				local fpos, fsize = guiRect(fixed)
				if rectsOverlap(pos, size, fpos, fsize, 6) then
					blocked = true
					break
				end
			end
		end
		if not blocked then
			chosen = candidate
			break
		end
	end
	solverSystemPanel.Position = chosen
end

local overlapAccumulator = 0
STATE.connect(RunService.RenderStepped, function(dt)
	overlapAccumulator += dt
	if overlapAccumulator >= 0.12 then
		overlapAccumulator = 0
		applyHudPanelLayout()
	end
end)


-- Forward declarations because Spyware

-- feeds are created before the normal camera
-- clone functions are declared below.

local buildClone
local cloneEnvironment
local syncPose

-- ============================================================
-- SPYWARE FEED
-- ============================================================

local function createSpywareFeed(
	plr,
	order
)
	local root =
		Instance.new("Frame")

	root.Name =
		"SpyFeed_"
		.. plr.Name

	root.BackgroundColor3 =
		DARKTINT

	root.BackgroundTransparency =
		0.22

	root.BorderSizePixel =
		0

	root.LayoutOrder =
		order

	root.Parent =
		spywareHolder

	local stroke =
		Instance.new(
			"UIStroke"
		)

	stroke.Color =
		YELLOW

	stroke.Thickness =
		1.2

	stroke.Parent =
		root

	local title =
		Instance.new(
			"TextLabel"
		)

	title.Size =
		UDim2.new(
			1,
			0,
			0,
			18
		)

	title.BackgroundTransparency =
		1

	title.Font =
		Enum.Font.Code

	title.Text =
		"SPYWARE // "
		.. plr.Name

	title.TextColor3 =
		YELLOW

	title.TextSize =
		11

	title.Parent =
		root

	local third =
		makeCamBox(
			"3RD",
			0
		)

	third.box.Parent =
		root

	third.box.Size =
		UDim2.new(
			0.5,
			-3,
			1,
			-22
		)

	third.box.Position =
		UDim2.new(
			0,
			2,
			0,
			20
		)

	local thirdLabel =
		third.box:FindFirstChildOfClass(
			"TextLabel"
		)

	if thirdLabel then
		thirdLabel.Text =
			"3RD"

		thirdLabel.TextSize =
			10
	end

	local first =
		makeCamBox(
			"1ST",
			0
		)

	first.box.Parent =
		root

	first.box.Size =
		UDim2.new(
			0.5,
			-3,
			1,
			-22
		)

	first.box.Position =
		UDim2.new(
			0.5,
			1,
			0,
			20
		)

	local firstLabel =
		first.box:FindFirstChildOfClass(
			"TextLabel"
		)

	if firstLabel then
		firstLabel.Text =
			"1ST"

		firstLabel.TextSize =
			10
	end

	local termination = makeTerminationOverlay(root, "ConnectionTermination")
	termination.root.ZIndex = 90

	return {
		plr = plr,
		root = root,
		third = third,
		first = first,
		character = nil,
		thirdClone = nil,
		center = nil,
		termination = termination,
		terminating = false,
	}
end

local function clearSpywareFeeds()
	for _, feed in pairs(
		S.spywareFeeds
	) do

		if feed.root then
			feed.root:Destroy()
		end
	end

	table.clear(
		S.spywareFeeds
	)
end

rebuildSpywareFeeds =
	function()

		clearSpywareFeeds()

		if not S.spywareMode then
			return
		end

		for i, plr in ipairs(
			S.spywareTargets
		) do

			if plr
				and plr.Parent
			then

				S.spywareFeeds[plr] =
					createSpywareFeed(
						plr,
						i
					)
			end
		end
	end

local function prepareSpywareFeed(
	feed,
	char
)
	if not feed or not char then
		return
	end

	feed.third.worldModel:
		ClearAllChildren()

	feed.first.worldModel:
		ClearAllChildren()

	feed.thirdClone =
		buildClone(
			char,
			feed.third.worldModel
		)

	local hrp =
		char:FindFirstChild(
			"HumanoidRootPart"
		)

	feed.center =
		hrp
		and hrp.Position
		or nil

	if hrp then

		cloneEnvironment(
			feed.third.worldModel,
			hrp.Position,
			90
		)

		cloneEnvironment(
			feed.first.worldModel,
			hrp.Position,
			90
		)
	end

	feed.character =
		char
end

local function updateSpywareFeeds()
	if not S.spywareMode then
		return
	end

	for plr, feed in pairs(
		S.spywareFeeds
	) do

		local char =
			plr.Character

		local hrp =
			char
			and char:FindFirstChild(
				"HumanoidRootPart"
			)

		local head =
			char
			and char:FindFirstChild(
				"Head"
			)

		if char
			and hrp
			and head
			and char.Parent
		then

			if feed.character ~= char
				or (
					feed.center
					and (
						hrp.Position
						- feed.center
					).Magnitude >= 55
				)
			then

				prepareSpywareFeed(
					feed,
					char
				)
			end

			if feed.thirdClone then

				syncPose(
					char,
					feed.thirdClone
				)

				local cloneHrp =
					feed.thirdClone:
					FindFirstChild(
						"HumanoidRootPart",
						true
					)

				if cloneHrp then

					local target =
						cloneHrp.Position
						+ Vector3.new(
							0,
							1.5,
							0
						)

					feed.third.camera.CFrame =
						CFrame.lookAt(
							target
								- cloneHrp.CFrame.LookVector
								* 8
								+ Vector3.new(
									0,
									2.1,
									0
								),

							target
						)
				end
			end

			feed.first.camera.CFrame =
				head.CFrame
				* CFrame.new(
					0,
					0.05,
					-0.15
				)

			feed.third.viewport.BackgroundColor3 =
				Color3.fromRGB(
					28,
					34,
					42
				)

			feed.first.viewport.BackgroundColor3 =
				Color3.fromRGB(
					28,
					34,
					42
				)

		else

			feed.third.viewport.BackgroundColor3 =
				RED_DIM

			feed.first.viewport.BackgroundColor3 =
				RED_DIM
		end
	end
end

-- ============================================================
-- NORMAL CAMERA CLONING
-- ============================================================

buildClone =
	function(char, worldModel)
		if not char
			or not char.Parent
		then
			return nil
		end

		local oldArchivable =
			char.Archivable

		char.Archivable =
			true

		local ok, clone =
			pcall(
				function()
					return char:Clone()
				end
			)

		char.Archivable =
			oldArchivable

		if not ok
			or not clone
		then

			warn(
				"[MurderDronesHUD] Could not clone character for camera:",
				clone
			)

			return nil
		end

		for _, inst in ipairs(
			clone:GetDescendants()
		) do

			if inst:IsA("Script")
				or inst:IsA("LocalScript")
			then

				inst:Destroy()

			elseif inst:IsA("BasePart") then

				inst.Anchored =
					true

				inst.CanCollide =
					false

				inst.CanTouch =
					false

				inst.CanQuery =
					false
			end
		end

		local humanoid =
			clone:FindFirstChildOfClass(
				"Humanoid"
			)

		if humanoid then

			humanoid.DisplayDistanceType =
				Enum.HumanoidDisplayDistanceType.None

			humanoid.AutoRotate =
				false
		end

		clone.Parent =
			worldModel

		return clone
	end

cloneEnvironment =
	function(
		worldModel,
		centerPosition,
		radius
	)
		local params =
			OverlapParams.new()

		params.FilterType =
			Enum.RaycastFilterType.Exclude

		params.FilterDescendantsInstances =
			{
				LocalPlayer.Character
			}

		local parts =
			workspace:GetPartBoundsInRadius(
				centerPosition,
				radius,
				params
			)

		local cloned = 0

		for _, part in ipairs(parts) do

			if cloned >= 450 then
				break
			end

			if part:IsA("BasePart")
				and part.Transparency < 1
				and not (
					LocalPlayer.Character
					and part:IsDescendantOf(
						LocalPlayer.Character
					)
				)
			then

				local model =
					part:FindFirstAncestorOfClass(
						"Model"
					)

				local isCharacter =
					model
					and model:FindFirstChildOfClass(
						"Humanoid"
					)

				if not isCharacter then

					local oldArchivable =
						part.Archivable

					part.Archivable =
						true

					local ok, copy =
						pcall(
							function()
								return part:Clone()
							end
						)

					part.Archivable =
						oldArchivable

					if ok
						and copy
					then

						for _, inst in ipairs(
							copy:GetDescendants()
						) do

							if inst:IsA("Script")
								or inst:IsA("LocalScript")
							then

								inst:Destroy()

							elseif inst:IsA("BasePart") then

								inst.Anchored =
									true

								inst.CanCollide =
									false

								inst.CanTouch =
									false

								inst.CanQuery =
									false
							end
						end

						copy.Parent =
							worldModel

						cloned += 1
					end
				end
			end
		end
	end

clearClones = function()
	if S.camClones.third then
		S.camClones.third:Destroy()
		S.camClones.third = nil
	end

	if S.camClones.first then
		S.camClones.first:Destroy()
		S.camClones.first = nil
	end

	thirdPersonCam.worldModel:
		ClearAllChildren()

	firstPersonCam.worldModel:
		ClearAllChildren()

	S.camClones.sourceChar =
		nil

	S.camClones.environmentCenter =
		nil
end

local function refreshClones(char)
	clearClones()

	S.camClones.third =
		buildClone(
			char,
			thirdPersonCam.worldModel
		)

	S.camClones.first =
		nil

	local hrp =
		char:FindFirstChild(
			"HumanoidRootPart"
		)

	if hrp then

		local center =
			hrp.Position

		cloneEnvironment(
			thirdPersonCam.worldModel,
			center,
			120
		)

		cloneEnvironment(
			firstPersonCam.worldModel,
			center,
			120
		)

		S.camClones.environmentCenter =
			center
	end

	S.camClones.sourceChar =
		char
end

syncPose =
	function(
		originalChar,
		cloneChar
	)
		if not originalChar
			or not cloneChar
		then
			return
		end

		for _, part in ipairs(
			originalChar:GetDescendants()
		) do

			if part:IsA("BasePart") then

				local clonePart =
					cloneChar:FindFirstChild(
						part.Name,
						true
					)

				if clonePart
					and clonePart:IsA(
						"BasePart"
					)
				then

					clonePart.CFrame =
						part.CFrame

					clonePart.Transparency =
						part.Transparency
				end
			end
		end
	end

setCamsVisible = function(state)
	if state == S.camsVisible then
		return
	end

	S.camsVisible =
		state

	local targetSize =
		state
		and UDim2.fromOffset(
			180,
			220
		)
		or UDim2.fromOffset(
			180,
			0
		)

	TweenService:Create(
		camHolder,
		TweenInfo.new(
			0.3,
			Enum.EasingStyle.Quad
		),
		{
			Size = targetSize
		}
	):Play()

	camHolder.Visible =
		not S.spywareMode

	spywareHolder.Visible =
		state
		and S.spywareMode
		and S.solverEnabled
end

-- ============================================================
-- MAIN TRACKING HEARTBEAT
-- ============================================================

STATE.connect(
	RunService.Heartbeat,
	function()

		if S.spywareMode
			and S.systemEnabled
			and S.solverEnabled
		then

			updateSpywareFeeds()
		end

		if S.activeVisual then

			S.activeVisual.highlight.Enabled =
				S.systemEnabled

			S.activeVisual.billboard.Enabled =
				S.systemEnabled
		end

		-- Keep a rolling 10-second history for every player
		-- while the tracker is active.

		if S.systemEnabled
			and os.clock()
				- S.lastHistorySample
				>= FOOTPRINT_HISTORY_INTERVAL
		then

			S.lastHistorySample =
				os.clock()

			for _, plr in ipairs(
				Players:GetPlayers()
			) do

				if plr ~= LocalPlayer then

					local char =
						plr.Character

					local hrp =
						char
						and char:FindFirstChild(
							"HumanoidRootPart"
						)

					if char
						and hrp
						and char.Parent
					then

						addHistorySample(
							plr,
							char,
							hrp
						)
					end
				end
			end
		end

		if S.systemEnabled
			and S.trackedPlayer
			and S.activeVisual
		then

			local history =
				S.footprintHistory[
					S.trackedPlayer
				]

			if history
				and #history > 0
				and not S.activeVisual.backtrackSeeded
			then

				spawnBacktrack(
					S.trackedPlayer
				)

				S.activeVisual.backtrackSeeded =
					true

				S.activeVisual.lastSpawnedHistoryTime =
					history[#history].time
			end

			if history
				and #history > 0
			then

				local newest =
					history[#history]

				if newest.time
					~= S.activeVisual.lastSpawnedHistoryTime
				then

					dropFootprint(
						newest.ground,
						newest.direction,
						newest.normal
					)

					S.activeVisual.lastSpawnedHistoryTime =
						newest.time
				end
			end
		end

		if S.systemEnabled
			and S.trackedPlayer
			and not S.spywareMode
		then

			local char =
				S.trackedPlayer.Character

			local hrp =
				char
				and char:FindFirstChild(
					"HumanoidRootPart"
				)

			local head =
				char
				and char:FindFirstChild(
					"Head"
				)

			if hrp
				and head
				and char.Parent
			then

				banner.Text =
					"TARGET LOCK :: "
					.. S.trackedPlayer.Name

				banner.TextColor3 =
					YELLOW

				setCamsVisible(
					true
				)

				if S.camClones.sourceChar
					~= char

					or (
						S.camClones.environmentCenter
						and (
							hrp.Position
							- S.camClones.environmentCenter
						).Magnitude >= 70
					)
				then

					refreshClones(
						char
					)
				end

				if S.camClones.third then

					syncPose(
						char,
						S.camClones.third
					)

					local cloneHrp3 =
						S.camClones.third:
						FindFirstChild(
							"HumanoidRootPart",
							true
						)

					if cloneHrp3 then

						local target =
							cloneHrp3.Position
							+ Vector3.new(
								0,
								1.5,
								0
							)

						local camPos =
							target
							- cloneHrp3.CFrame.LookVector
							* 9
							+ Vector3.new(
								0,
								2.5,
								0
							)

						thirdPersonCam.camera.CFrame =
							CFrame.lookAt(
								camPos,
								target
							)
					end
				end

				firstPersonCam.camera.CFrame =
					head.CFrame
					* CFrame.new(
						0,
						0.05,
						-0.15
					)

			else

				if not S.normalCameraTermination then
					banner.Text =
						"SIGNAL LOST // TARGET MISSING"

					banner.TextColor3 =
						RED

					setCamsVisible(
						false
					)

					clearClones()
				end
			end

		elseif S.systemEnabled
			and S.spywareMode
			and S.solverEnabled
		then

			banner.Text =
				"SOLVER :: SPYWARE // "
				.. tostring(
					#S.spywareTargets
				)
				.. " TARGETS"

			banner.TextColor3 =
				RED

			setCamsVisible(
				false
			)

			spywareHolder.Visible =
				true

			clearClones()

		elseif S.solverEnabled then

			banner.Text =
				"SOLVER :: ACTIVE"

			banner.TextColor3 =
				YELLOW

			setCamsVisible(
				false
			)

			spywareHolder.Visible =
				false

			clearClones()

		else

			banner.Text = ""

			setCamsVisible(
				false
			)

			spywareHolder.Visible =
				false

			clearClones()
		end
	end
)

-- ============================================================
-- SPYWARE MODE
-- ============================================================

local function setSpywareMode(state)
	if not S.solverEnabled then
		state = false
	end

	if S.spywareMode == state then
		return
	end

	S.spywareMode =
		state

	spywareButton.TextColor3 =
		state
		and RED
		or YELLOW_DIM

	spywareButton.Text =
		state
		and "SPYWARE [ON]"
		or "SPYWARE [P]"

	camHolder.Visible =
		not state

	spywareHolder.Visible =
		state
		and S.systemEnabled
		and S.solverEnabled

	if state then

		S.trackedPlayer =
			nil

		clearActiveVisual()

		rebuildSpywareFeeds()

		banner.Text =
			"SOLVER :: SPYWARE // "
			.. tostring(
				#S.spywareTargets
			)
			.. " TARGETS"

	else

		clearSpywareFeeds()

		spywareHolder.Visible =
			false

		setCamsVisible(
			S.systemEnabled
			and S.trackedPlayer ~= nil
		)

		banner.Text =
			S.trackedPlayer
			and (
				"TARGET LOCK :: "
				.. S.trackedPlayer.Name
			)
			or "SOLVER :: ACTIVE"

		refreshPlayerButtonColors()
	end
end

spywareButton.MouseButton1Click:Connect(
	function()
		if S.solverEnabled then
			setSpywareMode(
				not S.spywareMode
			)
		end
	end
)

-- ============================================================
-- AUDIO PLAYBACK
-- ============================================================

playSound =
	function(
		id,
		volume,
		speed,
		glitch
	)

		if not id
			or id == ""
		then
			return
		end

		local s =
			Instance.new(
				"Sound"
			)

		s.SoundId =
			id

		s.Volume =
			volume
			or 1

		s.PlaybackSpeed =
			speed
			or 1

		s.Parent =
			SoundService

		s:Play()

		s.Ended:Connect(
			function()
				s:Destroy()
			end
		)
	end

-- ============================================================
-- OPEN ANIMATION
-- ============================================================

local function animateOpen()
	scannerRoot.Visible =
		true

	scannerRoot.Position =
		UDim2.fromScale(
			0,
			-0.04
		)

	tint.BackgroundTransparency =
		1

	TweenService:Create(
		tint,
		TweenInfo.new(
			0.25
		),
		{
			BackgroundTransparency =
				0.88
		}
	):Play()

	TweenService:Create(
		scannerRoot,
		TweenInfo.new(
			0.3,
			Enum.EasingStyle.Back,
			Enum.EasingDirection.Out
		),
		{
			Position =
				UDim2.fromScale(
					0,
					0
				)
		}
	):Play()

	playSound(
		OPEN_SOUND_ID,
		0.6,
		0.92,
		true
	)
end

-- ============================================================
-- CLOSE ANIMATION
-- ============================================================

local function animateClose()
	local tween =
		TweenService:Create(
			scannerRoot,
			TweenInfo.new(
				0.2,
				Enum.EasingStyle.Quad,
				Enum.EasingDirection.In
			),
			{
				Position =
					UDim2.fromScale(
						0,
						-0.04
					)
			}
		)

	tween:Play()

	TweenService:Create(
		tint,
		TweenInfo.new(
			0.2
		),
		{
			BackgroundTransparency =
				1
		}
	):Play()

	playSound(
		CLOSE_SOUND_ID,
		0.55,
		0.82,
		true
	)

	tween.Completed:Connect(
		function()
			scannerRoot.Visible =
				false
		end
	)
end

local function setSolverEnabled(state)
	if S.solverEnabled == state then
		if not state then
			endSolverScan()
			setWingsEnabled(false)
			wingsButton.Visible = false
			raycastButton.Visible = false
			spywareButton.Visible = false
			hideSolverScanResult()
			solverTelemetry.Visible = false
			solverSystemPanel.Visible = false
		end
		return
	end

	S.solverEnabled = state

	if not state then
		endSolverScan()
		hideSolverScanResult()
		solverTelemetry.Visible = false
		solverSystemPanel.Visible = false
		setWingsEnabled(false)
		S.spywareMode = false
		spywareButton.Visible = false
		wingsButton.Visible = false
		raycastButton.Visible = false
		spywareButton.TextColor3 = YELLOW_DIM
		spywareButton.Text = "SPYWARE [P]"
		table.clear(S.spywareTargets)

		for _, feed in pairs(S.spywareFeeds) do
			if feed.root then feed.root:Destroy() end
		end
		table.clear(S.spywareFeeds)
		spywareHolder.Visible = false
		camHolder.Visible = true
		banner.Text = S.trackedPlayer and ("TARGET LOCK :: " .. S.trackedPlayer.Name) or ""
	else
		spywareButton.Visible = true
		wingsButton.Visible = true
		raycastButton.Visible = true
		raycastButton.Text = "SCAN [R]"
		raycastButton.TextColor3 = YELLOW_DIM
		raycastStroke.Color = YELLOW_DIM
		setWingsEnabled(false)
		banner.Text = "X SOLVER :: ACTIVE"
		playSound(TARGET_LOCK_SOUND_ID, 0.5, 1.08, true)
	end
end


-- ============================================================
-- INPUT
-- ============================================================

STATE.connect(
	UserInputService.InputBegan,
	function(
		input,
		gameProcessed
	)

		if gameProcessed then
			return
		end

		-- M = HUD
		if input.KeyCode ==
			Enum.KeyCode.M
		then

			S.systemEnabled =
				not S.systemEnabled

			if S.systemEnabled then

				animateOpen()

			else

				clearFootprints()

				setSolverEnabled(
					false
				)

				animateClose()
			end

		-- N = Solver
		elseif input.KeyCode ==
			Enum.KeyCode.N
			and S.systemEnabled
		then

			setSolverEnabled(
				not S.solverEnabled
			)

		-- P = Spyware
		elseif input.KeyCode ==
			Enum.KeyCode.P
			and S.systemEnabled
			and S.solverEnabled
		then

			setSpywareMode(
				not S.spywareMode
			)
		end
	end
)

-- First Space jumps from the ground; the next two presses while airborne
-- activate flight when the solver wings are enabled.
STATE.connect(UserInputService.InputBegan, function(input)
	if input.KeyCode ~= Enum.KeyCode.Space
		or UserInputService:GetFocusedTextBox()
		or S.flying
	then
		return
	end

	local humanoid = select(1, getFlightRig())
	if not humanoid then
		return
	end

	local now = os.clock()
	if now - S.lastJumpPress > 1.2 then
		S.jumpPressCount = 0
	end
	S.lastJumpPress = now

	if humanoid.FloorMaterial ~= Enum.Material.Air then
		S.jumpPressCount = 1
		return
	end

	S.jumpPressCount += 1
	if S.jumpPressCount >= 3 and S.wingsEnabled and S.solverEnabled then
		S.jumpPressCount = 0
		startFlight()
	end
end)

-- ============================================================
-- BOOT SEQUENCE
-- ============================================================

local boot =
	Instance.new("Frame")

boot.Name =
	"BootSequence"

boot.Size =
	UDim2.fromScale(
		1,
		1
	)

boot.BackgroundColor3 =
	Color3.fromRGB(
		4,
		7,
		9
	)

boot.BackgroundTransparency =
	0.08

boot.BorderSizePixel =
	0

boot.ZIndex =
	100

boot.Parent =
	gui

local bootTitle =
	Instance.new("TextLabel")

bootTitle.Size =
	UDim2.fromOffset(
		700,
		42
	)

bootTitle.AnchorPoint =
	Vector2.new(
		0.5,
		0.5
	)

bootTitle.Position =
	UDim2.fromScale(
		0.5,
		0.44
	)

bootTitle.BackgroundTransparency =
	1

bootTitle.Font =
	Enum.Font.Code

bootTitle.Text =
	"MURDER DRONES // DRONE HUD"

bootTitle.TextColor3 =
	YELLOW

bootTitle.TextSize =
	26

bootTitle.Parent =
	boot

local bootStatus =
	Instance.new("TextLabel")

bootStatus.Size =
	UDim2.fromOffset(
		700,
		28
	)

bootStatus.AnchorPoint =
	Vector2.new(
		0.5,
		0.5
	)

bootStatus.Position =
	UDim2.fromScale(
		0.5,
		0.51
	)

bootStatus.BackgroundTransparency =
	1

bootStatus.Font =
	Enum.Font.Code

bootStatus.Text =
	"INITIALIZING..."

bootStatus.TextColor3 =
	STEEL

bootStatus.TextSize =
	13

bootStatus.Parent =
	boot

local bootLine =
	Instance.new("Frame")

bootLine.Size =
	UDim2.fromOffset(
		440,
		2
	)

bootLine.AnchorPoint =
	Vector2.new(
		0.5,
		0.5
	)

bootLine.Position =
	UDim2.fromScale(
		0.5,
		0.56
	)

bootLine.BackgroundColor3 =
	YELLOW

bootLine.BorderSizePixel =
	0

bootLine.Parent =
	boot

playSound(
	INIT_SOUND_ID,
	0.65,
	0.9,
	true
)

task.spawn(
	function()

		for _, text in ipairs({
			"CONNECTING TO DRONE NETWORK...",
			"LOADING NEURAL LINK...",
			"CALIBRATING OPTICAL SENSORS // 03...",
			"CORE LINK ESTABLISHED // READY",
		}) do

			if not boot.Parent then
				return
			end

			bootStatus.Text =
				text

			task.wait(
				0.24
			)
		end

		TweenService:Create(
			bootTitle,
			TweenInfo.new(
				0.45,
				Enum.EasingStyle.Quad,
				Enum.EasingDirection.Out
			),
			{
				TextTransparency =
					1
			}
		):Play()

		TweenService:Create(
			bootStatus,
			TweenInfo.new(
				0.45,
				Enum.EasingStyle.Quad,
				Enum.EasingDirection.Out
			),
			{
				TextTransparency =
					1
			}
		):Play()

		TweenService:Create(
			bootLine,
			TweenInfo.new(
				0.45,
				Enum.EasingStyle.Quad,
				Enum.EasingDirection.Out
			),
			{
				BackgroundTransparency =
					1
			}
		):Play()

		local fade =
			TweenService:Create(
				boot,
				TweenInfo.new(
					0.55,
					Enum.EasingStyle.Quad,
					Enum.EasingDirection.Out
				),
				{
					BackgroundTransparency =
						1
				}
			)

		fade:Play()
		fade.Completed:Wait()

		if boot.Parent then
			boot:Destroy()
		end
	end
)

STATE.onCleanup(
	function()
		if boot then
			boot:Destroy()
		end
	end
)

-- ============================================================
-- DEATH SCREEN
-- ============================================================

local deathFrame =
	Instance.new("Frame")

deathFrame.Name =
	"DeathRoot"

deathFrame.Size =
	UDim2.new(
		1,
		0,
		1,
		0
	)

deathFrame.BackgroundTransparency =
	1

deathFrame.Visible =
	false

deathFrame.ZIndex =
	50

deathFrame.Parent =
	gui

local overlay =
	Instance.new("Frame")

overlay.Size =
	UDim2.new(
		1,
		0,
		1,
		0
	)

overlay.BackgroundColor3 =
	DEATH_BG

overlay.BackgroundTransparency =
	1

overlay.BorderSizePixel =
	0

overlay.ZIndex =
	50

overlay.Parent =
	deathFrame

local logFrame =
	Instance.new("Frame")

logFrame.Size =
	UDim2.new(
		1,
		-40,
		0,
		120
	)

logFrame.Position =
	UDim2.new(
		0,
		20,
		0,
		20
	)

logFrame.BackgroundTransparency =
	1

logFrame.ZIndex =
	51

logFrame.Parent =
	overlay

local prompt =
	Instance.new("TextLabel")

prompt.Size =
	UDim2.new(
		1,
		-40,
		0,
		30
	)

prompt.Position =
	UDim2.new(
		0,
		20,
		1,
		-50
	)

prompt.BackgroundTransparency =
	1

prompt.Text =
	"WOULD YOU LIKE TO SEND AN ERROR REPORT?"

prompt.TextColor3 =
	Color3.fromRGB(
		140,
		40,
		50
	)

prompt.TextTransparency =
	1

prompt.Font =
	Enum.Font.Code

prompt.TextSize =
	13

prompt.TextXAlignment =
	Enum.TextXAlignment.Left

prompt.ZIndex =
	51

prompt.Parent =
	overlay

local deathLoopToken =
	0

local function showDeathScreen()
	deathLoopToken += 1

	local myToken =
		deathLoopToken

	StarterGui:SetCoreGuiEnabled(
		Enum.CoreGuiType.All,
		false
	)

	for _, c in ipairs(
		logFrame:GetChildren()
	) do
		c:Destroy()
	end

	deathFrame.Visible =
		true

	overlay.BackgroundTransparency =
		1

	prompt.TextTransparency =
		1

	TweenService:Create(
		overlay,
		TweenInfo.new(
			0.42,
			Enum.EasingStyle.Quart,
			Enum.EasingDirection.Out
		),
		{
			BackgroundTransparency =
				0.08
		}
	):Play()

	local headerLine =
		Instance.new(
			"TextLabel"
		)

	headerLine.Size =
		UDim2.new(
			1,
			-40,
			0,
			28
		)

	headerLine.Position =
		UDim2.new(
			0,
			20,
			0,
			-4
		)

	headerLine.BackgroundTransparency =
		1

	headerLine.Text =
		"! DRONE RECOVERY // CORE FAILURE"

	headerLine.TextColor3 =
		RED

	headerLine.TextTransparency =
		0.08

	headerLine.Font =
		Enum.Font.Code

	headerLine.TextSize =
		16

	headerLine.TextXAlignment =
		Enum.TextXAlignment.Left

	headerLine.ZIndex =
		51

	headerLine.Parent =
		logFrame

	local logLines = {
		"DIAGNOSTIC HANDSHAKE ACCEPTED...",
		"MATERIAL FORM :: UNSTABLE",
		"ABSOLUTE SOLVER ACCESS :: DENIED",
		"BACKUP CORE :: RESTORE QUEUED",
	}

	for i, line in ipairs(
		logLines
	) do

		local label =
			Instance.new(
				"TextLabel"
			)

		label.Size =
			UDim2.new(
				1,
				0,
				0,
				22
			)

		label.Position =
			UDim2.new(
				0,
				0,
				0,
				26
					+ (i - 1) * 22
			)

		label.BackgroundTransparency =
			1

		label.Text =
			""

		label.TextColor3 =
			(i == #logLines)
			and RED
			or STEEL

		label.TextTransparency =
			(i == #logLines)
			and 0.12
			or 0.3

		label.Font =
			Enum.Font.Code

		label.TextSize =
			12

		label.TextXAlignment =
			Enum.TextXAlignment.Left

		label.ZIndex =
			51

		label.Parent =
			logFrame

		task.delay(
			0.16
				+ (i - 1) * 0.18,
			function()

				if myToken
					~= deathLoopToken
				then
					return
				end

				for j = 1, #line do

					if not label.Parent
						or myToken
							~= deathLoopToken
					then
						break
					end

					label.Text =
						string.sub(
							line,
							1,
							j
						)

					task.wait(
						0.012
					)
				end
			end
		)
	end

	local statusPanel =
		Instance.new(
			"Frame"
		)

	statusPanel.Size =
		UDim2.new(
			0,
			360,
			0,
			82
		)

	statusPanel.Position =
		UDim2.new(
			0,
			20,
			0,
			142
		)

	statusPanel.BackgroundColor3 =
		Color3.fromRGB(
			12,
			14,
			17
		)

	statusPanel.BackgroundTransparency =
		0.2

	statusPanel.BorderSizePixel =
		0

	statusPanel.ZIndex =
		51

	statusPanel.Parent =
		overlay

	local statusStroke =
		Instance.new(
			"UIStroke"
		)

	statusStroke.Color =
		RED_DIM

	statusStroke.Thickness =
		1

	statusStroke.Transparency =
		0.2

	statusStroke.Parent =
		statusPanel

	local status =
		Instance.new(
			"TextLabel"
		)

	status.Size =
		UDim2.new(
			1,
			-18,
			0,
			30
		)

	status.Position =
		UDim2.new(
			0,
			9,
			0,
			8
		)

	status.BackgroundTransparency =
		1

	status.Text =
		"CORE STATUS :: OFFLINE"

	status.TextColor3 =
		RED

	status.TextTransparency =
		0.05

	status.Font =
		Enum.Font.Code

	status.TextSize =
		19

	status.TextXAlignment =
		Enum.TextXAlignment.Left

	status.ZIndex =
		52

	status.Parent =
		statusPanel

	local subStatus =
		Instance.new(
			"TextLabel"
		)

	subStatus.Size =
		UDim2.new(
			1,
			-18,
			0,
			22
		)

	subStatus.Position =
		UDim2.new(
			0,
			9,
			0,
			42
		)

	subStatus.BackgroundTransparency =
		1

	subStatus.Text =
		"REBOOTING SENSOR ARRAY..."

	subStatus.TextColor3 =
		STEEL

	subStatus.TextTransparency =
		0.15

	subStatus.Font =
		Enum.Font.Code

	subStatus.TextSize =
		11

	subStatus.TextXAlignment =
		Enum.TextXAlignment.Left

	subStatus.ZIndex =
		52

	subStatus.Parent =
		statusPanel

	local bars = {}

	for i = 1, 5 do

		local bar =
			Instance.new(
				"Frame"
			)

		bar.Size =
			UDim2.new(
				1,
				0,
				0,
				1
			)

		bar.Position =
			UDim2.new(
				0,
				0,
				0,
				250
					+ i * 52
			)

		bar.BackgroundColor3 =
			(i % 2 == 0)
			and YELLOW_DIM
			or RED_DIM

		bar.BackgroundTransparency =
			0.82

		bar.BorderSizePixel =
			0

		bar.ZIndex =
			50

		bar.Parent =
			overlay

		table.insert(
			bars,
			bar
		)
	end

	task.spawn(
		function()

			while myToken
				== deathLoopToken
				and deathFrame.Visible
			do

				for _, bar in ipairs(
					bars
				) do

					if myToken
						~= deathLoopToken
					then
						break
					end

					local startY =
						bar.Position.Y.Offset

					bar.Position =
						UDim2.new(
							0,
							0,
							0,
							startY - 10
						)

					TweenService:Create(
						bar,
						TweenInfo.new(
							0.7,
							Enum.EasingStyle.Linear
						),
						{
							Position =
								UDim2.new(
									0,
									0,
									0,
									startY + 10
								)
						}
					):Play()
				end

				task.wait(
					0.75
				)
			end
		end
	)

	task.delay(
		0.6,
		function()

			if myToken
				~= deathLoopToken
			then
				return
			end

			TweenService:Create(
				prompt,
				TweenInfo.new(
					0.35
				),
				{
					TextTransparency =
						0.45
				}
			):Play()
		end
	)

	if LocalPlayer.Character then
		LocalPlayer.CharacterAdded:Wait()
	end

	if myToken
		~= deathLoopToken
	then
		return
	end

	TweenService:Create(
		overlay,
		TweenInfo.new(
			0.55,
			Enum.EasingStyle.Quad,
			Enum.EasingDirection.In
		),
		{
			BackgroundTransparency =
				1
		}
	):Play()

	task.delay(
		0.6,
		function()

			if myToken
				~= deathLoopToken
			then
				return
			end

			deathFrame.Visible =
				false

			StarterGui:SetCoreGuiEnabled(
				Enum.CoreGuiType.All,
				true
			)

			if statusPanel then
				statusPanel:Destroy()
			end

			for _, bar in ipairs(
				bars
			) do

				if bar then
					bar:Destroy()
				end
			end
		end
	)
end

STATE.onCleanup(
	function()
		StarterGui:SetCoreGuiEnabled(
			Enum.CoreGuiType.All,
			true
		)
	end
)

local function hookDeath(
	plr,
	char
)
	local humanoid =
		char:WaitForChild(
			"Humanoid",
			5
		)

	if not humanoid then
		return
	end

	STATE.connect(
		humanoid.Died,
		showDeathScreen
	)
end

if LocalPlayer.Character then
	hookDeath(
		LocalPlayer,
		LocalPlayer.Character
	)
end

STATE.connect(
	LocalPlayer.CharacterAdded,
	function(char)
		hookDeath(
			LocalPlayer,
			char
		)
	end
)

-- ============================================================
-- CLEANUP
-- ============================================================

STATE.onCleanup(
	function()

		setSolverEnabled(
			false
		)

		clearActiveVisual()
		clearClones()
		clearSpywareFeeds()
		clearTail()
	end
)

print(
	"MurderDronesHUD v18.13 // ABSOLUTE SOLVER // DOUBLE CATALOG WINGS // POP DEPLOY // AUTONOMOUS TAIL // CAMERA-SAFE HUD"
)

Features & Information

Player tracking, visible foot trail backing to ten seconds, first / third person view of up to six players at once, non-FE (Meaning only you can see it) wings, raycast for dark areas ENTIRELY vibe-coded. Please tell me if there are any issues you come across while using this. Universal script, put it for baseplate because universal requires an image and at the time of posting, that feature isn't fucntional.
#vibecoded

Community Comments (0)

No comments yet for this script.

More Scripts for [UP] Just a baseplate.