-- FINAL Compact Chat Spy – EVERYTHING FIXED (Typewriter, Settings, Hashtags)
local Players = game:GetService("Players")
local TextChatService = game:GetService("TextChatService")
local gui = Instance.new("ScreenGui")
gui.Name = "ChatSpyFinal"
gui.ResetOnSpawn = false
gui.DisplayOrder = 999
gui.Parent = game:GetService("CoreGui")
local mainFrame = Instance.new("Frame")
mainFrame.Size = UDim2.new(0, 320, 0, 260)
mainFrame.Position = UDim2.new(0, 10, 0, 10)
mainFrame.BackgroundColor3 = Color3.fromRGB(20, 20, 20)
mainFrame.BorderSizePixel = 3
mainFrame.BorderColor3 = Color3.fromRGB(255, 0, 255)
mainFrame.Parent = gui
-- Title Bar
local titleBar = Instance.new("Frame")
titleBar.Size = UDim2.new(1, 0, 0, 40)
titleBar.BackgroundColor3 = Color3.fromRGB(150, 0, 255)
titleBar.Parent = mainFrame
local titleLabel = Instance.new("TextLabel")
titleLabel.Size = UDim2.new(1, -80, 1, 0)
titleLabel.BackgroundTransparency = 1
titleLabel.Text = "🔥 SPY LOADED 🔥"
titleLabel.TextColor3 = Color3.new(1, 1, 1)
titleLabel.Font = Enum.Font.GothamBold
titleLabel.TextSize = 18
titleLabel.TextXAlignment = Enum.TextXAlignment.Left
titleLabel.Position = UDim2.new(0, 10, 0, 0)
titleLabel.Parent = titleBar
task.spawn(function()
for i = 1, 5 do
titleBar.BackgroundColor3 = Color3.fromRGB(255, 0, 255)
task.wait(0.3)
titleBar.BackgroundColor3 = Color3.fromRGB(150, 0, 255)
task.wait(0.3)
end
titleLabel.Text = "🔍 Chat Spy"
end)
local closeBtn = Instance.new("TextButton")
closeBtn.Size = UDim2.new(0, 35, 0, 35)
closeBtn.Position = UDim2.new(1, -40, 0, 2.5)
closeBtn.BackgroundColor3 = Color3.fromRGB(200, 0, 0)
closeBtn.Text = "X"
closeBtn.TextColor3 = Color3.new(1, 1, 1)
closeBtn.Parent = titleBar
closeBtn.MouseButton1Click:Connect(function() gui:Destroy() end)
-- Draggable
local dragging = false
local dragStart, startPos
titleBar.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
dragging = true
dragStart = input.Position
startPos = mainFrame.Position
end
end)
titleBar.InputChanged:Connect(function(input)
if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then
local delta = input.Position - dragStart
mainFrame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
end
end)
game:GetService("UserInputService").InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = false end
end)
-- Tabs
local tabFrame = Instance.new("Frame")
tabFrame.Size = UDim2.new(1, 0, 0, 35)
tabFrame.Position = UDim2.new(0, 0, 0, 40)
tabFrame.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
tabFrame.Parent = mainFrame
local logTab = Instance.new("TextButton")
logTab.Size = UDim2.new(0.5, 0, 1, 0)
logTab.Text = "Log"
logTab.BackgroundColor3 = Color3.fromRGB(120, 0, 240)
logTab.TextColor3 = Color3.new(1,1,1)
logTab.Font = Enum.Font.GothamBold
logTab.TextSize = 16
logTab.Parent = tabFrame
local settingsTab = Instance.new("TextButton")
settingsTab.Size = UDim2.new(0.5, 0, 1, 0)
settingsTab.Position = UDim2.new(0.5, 0, 0, 0)
settingsTab.Text = "Settings"
settingsTab.BackgroundColor3 = Color3.fromRGB(60, 60, 60)
settingsTab.TextColor3 = Color3.new(1,1,1)
settingsTab.Font = Enum.Font.GothamBold
settingsTab.TextSize = 16
settingsTab.Parent = tabFrame
-- Log Frame
local logFrame = Instance.new("ScrollingFrame")
logFrame.Size = UDim2.new(1, -10, 1, -85)
logFrame.Position = UDim2.new(0, 5, 0, 80)
logFrame.BackgroundTransparency = 1
logFrame.ScrollBarThickness = 6
logFrame.Visible = true
logFrame.Parent = mainFrame
local logLayout = Instance.new("UIListLayout")
logLayout.Padding = UDim.new(0, 4)
logLayout.Parent = logFrame
-- Settings Scroll
local settingsScroll = Instance.new("ScrollingFrame")
settingsScroll.Size = UDim2.new(1, -10, 1, -85)
settingsScroll.Position = UDim2.new(0, 5, 0, 80)
settingsScroll.BackgroundTransparency = 1
settingsScroll.ScrollBarThickness = 6
settingsScroll.Visible = false
settingsScroll.Parent = mainFrame
local settingsLayout = Instance.new("UIListLayout")
settingsLayout.Padding = UDim.new(0, 10)
settingsLayout.Parent = settingsScroll
-- Settings Variables
local msgColor = Color3.new(1, 1, 1)
local tabActive = Color3.fromRGB(120, 0, 240)
local typewriter = false
local autoScroll = true
local unfiltered = false
-- Color Picker Function
local function makePicker(name, default, callback)
local frame = Instance.new("Frame")
frame.Size = UDim2.new(1, 0, 0, 120)
frame.BackgroundColor3 = Color3.fromRGB(45, 45, 55)
frame.Parent = settingsScroll
local title = Instance.new("TextLabel")
title.Size = UDim2.new(1, 0, 0, 25)
title.BackgroundTransparency = 1
title.Text = name
title.TextColor3 = Color3.new(1,1,1)
title.Font = Enum.Font.GothamBold
title.TextSize = 15
title.TextXAlignment = Enum.TextXAlignment.Left
title.Position = UDim2.new(0, 8, 0, 0)
title.Parent = frame
local preview = Instance.new("Frame")
preview.Size = UDim2.new(0, 60, 0, 60)
preview.Position = UDim2.new(1, -70, 0, 25)
preview.BackgroundColor3 = default
preview.BorderSizePixel = 2
preview.BorderColor3 = Color3.new(1,1,1)
preview.Parent = frame
local r, g, b = math.floor(default.R*255), math.floor(default.G*255), math.floor(default.B*255)
local function box(ch, y)
local tb = Instance.new("TextBox")
tb.Size = UDim2.new(0, 45, 0, 25)
tb.Position = UDim2.new(0, 8, 0, 30 + y)
tb.BackgroundColor3 = Color3.fromRGB(70,70,80)
tb.Text = tostring(ch == 1 and r or ch == 2 and g or b)
tb.TextColor3 = Color3.new(1,1,1)
tb.Parent = frame
tb.FocusLost:Connect(function()
local v = math.clamp(tonumber(tb.Text) or 0, 0, 255)
tb.Text = v
if ch == 1 then r = v elseif ch == 2 then g = v else b = v end
local newC = Color3.fromRGB(r, g, b)
preview.BackgroundColor3 = newC
callback(newC)
if name == "Active Tab Color" then
tabActive = newC
if logFrame.Visible then logTab.BackgroundColor3 = newC else settingsTab.BackgroundColor3 = newC end
end
end)
end
box(1, 0)
box(2, 30)
box(3, 60)
end
makePicker("Text Color", msgColor, function(c) msgColor = c end)
makePicker("Active Tab Color", tabActive, function(c) tabActive = c end)
-- Toggles
local typeBtn = Instance.new("TextButton")
typeBtn.Size = UDim2.new(1, 0, 0, 40)
typeBtn.BackgroundColor3 = Color3.fromRGB(60, 60, 70)
typeBtn.Text = "Typewriter: OFF"
typeBtn.TextColor3 = Color3.new(1,1,1)
typeBtn.Font = Enum.Font.GothamBold
typeBtn.TextSize = 16
typeBtn.Parent = settingsScroll
typeBtn.MouseButton1Click:Connect(function()
typewriter = not typewriter
typeBtn.Text = "Typewriter: " .. (typewriter and "ON" or "OFF")
end)
local scrollBtn = Instance.new("TextButton")
scrollBtn.Size = UDim2.new(1, 0, 0, 40)
scrollBtn.BackgroundColor3 = Color3.fromRGB(60, 60, 70)
scrollBtn.Text = "Auto-Scroll: ON"
scrollBtn.TextColor3 = Color3.new(1,1,1)
scrollBtn.Font = Enum.Font.GothamBold
scrollBtn.TextSize = 16
scrollBtn.Parent = settingsScroll
scrollBtn.MouseButton1Click:Connect(function()
autoScroll = not autoScroll
scrollBtn.Text = "Auto-Scroll: " .. (autoScroll and "ON" or "OFF")
end)
local filterBtn = Instance.new("TextButton")
filterBtn.Size = UDim2.new(1, 0, 0, 40)
filterBtn.BackgroundColor3 = Color3.fromRGB(80, 40, 40)
filterBtn.Text = "Unfiltered Mode: OFF"
filterBtn.TextColor3 = Color3.new(1,1,1)
filterBtn.Font = Enum.Font.GothamBold
filterBtn.TextSize = 16
filterBtn.Parent = settingsScroll
filterBtn.MouseButton1Click:Connect(function()
unfiltered = not unfiltered
filterBtn.Text = "Unfiltered Mode: " .. (unfiltered and "ON" or "OFF")
filterBtn.BackgroundColor3 = unfiltered and Color3.fromRGB(150, 50, 50) or Color3.fromRGB(80, 40, 40)
end)
settingsLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function()
settingsScroll.CanvasSize = UDim2.new(0, 0, 0, settingsLayout.AbsoluteContentSize.Y + 10)
end)
-- Tab Switch
logTab.MouseButton1Click:Connect(function()
logFrame.Visible = true
settingsScroll.Visible = false
logTab.BackgroundColor3 = tabActive
settingsTab.BackgroundColor3 = Color3.fromRGB(60,60,60)
end)
settingsTab.MouseButton1Click:Connect(function()
logFrame.Visible = false
settingsScroll.Visible = true
settingsTab.BackgroundColor3 = tabActive
logTab.BackgroundColor3 = Color3.fromRGB(60,60,60)
end)
-- Name Color
local function getNameColor(id)
local p = Players:GetPlayerByUserId(id)
if p and p.Team then return p.Team.TeamColor.Color end
local cols = {Color3.fromRGB(253,41,67), Color3.fromRGB(1,162,255), Color3.fromRGB(2,184,87), Color3.fromRGB(217,133,252)}
return cols[(id % #cols) + 1]
end
-- Add Message – Typewriter FIXED (no broken tags)
local function add(chName, msg)
local src = msg.TextSource
if not src then return end
local name = Players:GetPlayerByUserId(src.UserId) and Players:GetPlayerByUserId(src.UserId).DisplayName or "Unknown"
local rawText = msg.Text or ""
local displayText = unfiltered and rawText or (msg.PrefixText or rawText)
local time = os.date("%H:%M")
local kind = chName:find("Whisper") and "[WHISPER]" or chName:find("Team") and "[TEAM]" or "[PUBLIC]"
local team = Players:GetPlayerByUserId(src.UserId) and Players:GetPlayerByUserId(src.UserId).Team and " ("..Players:GetPlayerByUserId(src.UserId).Team.Name..")" or ""
local col = getNameColor(src.UserId)
local hex = "#" .. col:ToHex()
local formatted = displayText:gsub("(#%w+)", "%1")
local full = string.format("[%s] %s %s%s: %s", time, kind, hex, name, team, formatted)
local label = Instance.new("TextLabel")
label.Size = UDim2.new(1, 0, 0, 0)
label.BackgroundTransparency = 1
label.TextColor3 = msgColor
label.TextSize = 13
label.Font = Enum.Font.Gotham
label.TextXAlignment = Enum.TextXAlignment.Left
label.TextWrapped = true
label.RichText = true
label.AutomaticSize = Enum.AutomaticSize.Y
label.Parent = logFrame
local pad = Instance.new("UIPadding", label)
pad.PaddingLeft = UDim.new(0, 6)
if typewriter then
label.Text = ""
local i = 1
while i <= #full do
local startTag = full:find("<", i)
if startTag then
label.Text = label.Text .. full:sub(i, startTag - 1)
local endTag = full:find(">", startTag)
if endTag then
label.Text = label.Text .. full:sub(startTag, endTag)
i = endTag + 1
else
break
end
else
label.Text = label.Text .. full:sub(i)
break
end
task.wait(0.02)
end
else
label.Text = full
end
if autoScroll then
logFrame.CanvasPosition = Vector2.new(0, logFrame.AbsoluteCanvasSize.Y)
end
end
-- Connect
local function connectChannel(ch)
if ch:IsA("TextChannel") then
ch.MessageReceived:Connect(function(m) add(ch.Name, m) end)
end
end
for _, ch in TextChatService.TextChannels:GetChildren() do connectChannel(ch) end
TextChatService.TextChannels.ChildAdded:Connect(connectChannel)
TextChatService.OnIncomingMessage:Connect(function(m)
if m.TextSource then add("Unknown", m) end
end)
logLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function()
logFrame.CanvasSize = UDim2.new(0, 0, 0, logLayout.AbsoluteContentSize.Y + 10)
if autoScroll then logFrame.CanvasPosition = Vector2.new(0, logFrame.AbsoluteCanvasSize.Y) end
end)
print("FINAL Chat Spy – Everything fixed: Typewriter, Settings, Hashtags, Unfiltered 👀🔥")