
Keyless

--[[
Paint Flags — Auto Paint
Author: @Dark_Fire
Version: 1.1
Feel free to use, modify, and share it.
If you repost it, I'd appreciate a mention — but no pressure either way.
TG: @Dark_Firex
---
Paint Flags — Авто-покраска
Автор: @Dark_Fire
Версия: 1.1
Можешь свободно использовать, изменять и распространять.
Если будешь репостить — буду благодарен за упоминание, но это не обязательно.
TG: @Dark_Firex
]]
local STALL_LIMIT = 4
local RS = game:GetService("ReplicatedStorage")
local player = game:GetService("Players").LocalPlayer
local cam = workspace.CurrentCamera
local DESC_RU = [[КАК ПОЛЬЗОВАТЬСЯ
1) Подойди к свободному холсту и нажми Claim Canvas.
2) В открывшемся меню выбери флаг и нажми Paint.
3) Дождись пока флаг появится на холсте и запусти скрипт.
Скрипт автоматически закрасит весь флаг. Камера поднимется вверх, и ты увидишь как холст заполняется (или не увидишь лол). Когда всё готово — остановится сам.
⚠️ Скрипт красит очень быстро.
Если покраска не идёт — возможно, сервер защищён от скриптов.]]
local DESC_EN = [[HOW TO USE
1) Walk up to a free canvas and press Claim Canvas.
2) In the menu that opens, pick a flag and press Paint.
3) Wait for the flag to appear on the canvas, then run the script.
The script automatically paints the entire flag. The camera will rise above the canvas so you can watch it fill in (or maybe you won't see it lol). When done, it stops on its own.
⚠️ The script paints very fast.
If the painting is not going on, it is possible that the server is protected from scripts.]]
local STALL_RU = "Покраска не проходит на сервер. Возможно, на сервере стоит защита от таких скриптов."
local STALL_EN = "Paints aren't reaching the server. The server may have protection against scripts like this."
local THEME = {
scrim = Color3.fromRGB(0, 0, 0),
card = Color3.fromRGB(20, 21, 25),
field = Color3.fromRGB(14, 15, 18),
stroke = Color3.fromRGB(46, 48, 56),
strokeSoft = Color3.fromRGB(34, 35, 41),
text = Color3.fromRGB(238, 239, 242),
subtext = Color3.fromRGB(150, 153, 162),
accent = Color3.fromRGB(80, 120, 248),
onAccent = Color3.fromRGB(255, 255, 255),
danger = Color3.fromRGB(216, 84, 84),
warning = Color3.fromRGB(224, 164, 74),
}
local FONT = Enum.Font.Gotham
local FONT_MED = Enum.Font.GothamMedium
local FONT_BOLD = Enum.Font.GothamBold
local function viewportSize()
return (cam and cam.ViewportSize) or Vector2.new(1280, 720)
end
local function fitScale(baseW, baseH)
local vp = viewportSize()
local s = math.min((vp.X - 28) / baseW, (vp.Y - 28) / baseH)
return math.clamp(s, 0.45, 1)
end
local function corner(inst, r)
local c = Instance.new("UICorner")
c.CornerRadius = UDim.new(0, r or 12)
c.Parent = inst
return c
end
local function stroke(inst, col, th)
local s = Instance.new("UIStroke")
s.Color = col or THEME.stroke
s.Thickness = th or 1
s.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
s.Parent = inst
return s
end
local function pad(inst, t, r, b, l)
local p = Instance.new("UIPadding")
p.PaddingTop = UDim.new(0, t)
p.PaddingRight = UDim.new(0, r or t)
p.PaddingBottom = UDim.new(0, b or t)
p.PaddingLeft = UDim.new(0, l or r or t)
p.Parent = inst
return p
end
local function vstack(parent, gap)
local l = Instance.new("UIListLayout")
l.FillDirection = Enum.FillDirection.Vertical
l.SortOrder = Enum.SortOrder.LayoutOrder
l.Padding = UDim.new(0, gap or 12)
l.Parent = parent
return l
end
local function bindScale(card, sc, baseW, baseH)
if not cam then return end
local conn
conn = cam:GetPropertyChangedSignal("ViewportSize"):Connect(function()
if card and card.Parent then
sc.Scale = fitScale(baseW, baseH)
elseif conn then
conn:Disconnect()
end
end)
card.Destroying:Connect(function() if conn then conn:Disconnect() end end)
end
local guis = {}
local function makeGui()
local gui = Instance.new("ScreenGui")
local nm = ""
for _ = 1, math.random(8, 12) do nm = nm .. string.char(math.random(97, 122)) end
gui.Name = nm
gui.ResetOnSpawn = false
gui.IgnoreGuiInset = true
gui.DisplayOrder = 999999
gui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
local ok = pcall(function()
gui.Parent = (gethui and gethui()) or game:GetService("CoreGui")
end)
if not ok then gui.Parent = player:WaitForChild("PlayerGui") end
guis[#guis+1] = gui
gui.Destroying:Connect(function()
local idx = table.find(guis, gui)
if idx then table.remove(guis, idx) end
end)
return gui
end
local function scrim(gui)
local f = Instance.new("Frame")
f.Size = UDim2.fromScale(1, 1)
f.BackgroundColor3 = THEME.scrim
f.BackgroundTransparency = 0.38
f.BorderSizePixel = 0
f.Parent = gui
return f
end
local function buildCard(parent, width, baseH)
local card = Instance.new("Frame")
card.AnchorPoint = Vector2.new(0.5, 0.5)
card.Position = UDim2.fromScale(0.5, 0.5)
card.Size = UDim2.fromOffset(width, 0)
card.AutomaticSize = Enum.AutomaticSize.Y
card.BackgroundColor3 = THEME.card
card.BorderSizePixel = 0
card.Parent = parent
corner(card, 14)
stroke(card, THEME.stroke, 1)
local sc = Instance.new("UIScale")
sc.Scale = fitScale(width + 40, baseH or 320)
sc.Parent = card
bindScale(card, sc, width + 40, baseH or 320)
return card
end
local function header(card, title, accentColor, order)
local holder = Instance.new("Frame")
holder.BackgroundTransparency = 1
holder.Size = UDim2.new(1, 0, 0, 0)
holder.AutomaticSize = Enum.AutomaticSize.Y
holder.LayoutOrder = order or 1
holder.Parent = card
vstack(holder, 5)
local tag = Instance.new("TextLabel")
tag.BackgroundTransparency = 1
tag.Size = UDim2.new(1, 0, 0, 0)
tag.AutomaticSize = Enum.AutomaticSize.Y
tag.Font = FONT_BOLD
tag.TextSize = 12
tag.Text = "AUTO-PAINT"
tag.TextColor3 = accentColor or THEME.accent
tag.TextXAlignment = Enum.TextXAlignment.Left
tag.LayoutOrder = 1
tag.Parent = holder
local ttl = Instance.new("TextLabel")
ttl.BackgroundTransparency = 1
ttl.Size = UDim2.new(1, 0, 0, 0)
ttl.AutomaticSize = Enum.AutomaticSize.Y
ttl.Font = FONT_BOLD
ttl.TextSize = 21
ttl.Text = title
ttl.TextColor3 = THEME.text
ttl.TextWrapped = true
ttl.TextXAlignment = Enum.TextXAlignment.Left
ttl.TextYAlignment = Enum.TextYAlignment.Top
ttl.LayoutOrder = 2
ttl.Parent = holder
return holder
end
local function divider(card, order)
local d = Instance.new("Frame")
d.Size = UDim2.new(1, 0, 0, 1)
d.BackgroundColor3 = THEME.strokeSoft
d.BorderSizePixel = 0
d.LayoutOrder = order or 2
d.Parent = card
return d
end
local function bodyText(card, text, order)
local l = Instance.new("TextLabel")
l.BackgroundTransparency = 1
l.Size = UDim2.new(1, 0, 0, 0)
l.AutomaticSize = Enum.AutomaticSize.Y
l.Font = FONT
l.TextSize = 15
l.Text = text
l.TextColor3 = THEME.subtext
l.TextWrapped = true
l.TextXAlignment = Enum.TextXAlignment.Left
l.TextYAlignment = Enum.TextYAlignment.Top
l.LayoutOrder = order or 3
l.Parent = card
return l
end
local function makeButton(parent, text, kind, order)
local b = Instance.new("TextButton")
b.AutoButtonColor = true
b.Font = FONT_MED
b.TextSize = 15
b.Text = text
b.BorderSizePixel = 0
b.Size = UDim2.new(1, 0, 0, 46)
b.LayoutOrder = order or 1
b.Parent = parent
corner(b, 10)
if kind == "primary" then
b.BackgroundColor3 = THEME.accent
b.TextColor3 = THEME.onAccent
else
b.BackgroundColor3 = THEME.field
b.TextColor3 = THEME.text
stroke(b, THEME.stroke, 1)
end
return b
end
local function buttonRow(card, order)
local row = Instance.new("Frame")
row.BackgroundTransparency = 1
row.Size = UDim2.new(1, 0, 0, 46)
row.LayoutOrder = order or 4
row.Parent = card
local h = Instance.new("UIListLayout")
h.FillDirection = Enum.FillDirection.Horizontal
h.HorizontalAlignment = Enum.HorizontalAlignment.Center
h.VerticalAlignment = Enum.VerticalAlignment.Center
h.SortOrder = Enum.SortOrder.LayoutOrder
h.Padding = UDim.new(0, 10)
h.Parent = row
return row
end
local function showAlert(title, body, color)
local gui = makeGui()
scrim(gui)
local card = buildCard(gui, 380, 300)
pad(card, 20)
vstack(card, 14)
header(card, title, color, 1)
divider(card, 2)
bodyText(card, body, 3)
local ok = makeButton(card, "OK", "primary", 4)
local ev = Instance.new("BindableEvent")
ok.MouseButton1Click:Connect(function() ev:Fire() end)
ev.Event:Wait()
ev:Destroy()
gui:Destroy()
end
local function askYesNo(title, body)
local gui = makeGui()
scrim(gui)
local card = buildCard(gui, 380, 300)
pad(card, 20)
vstack(card, 14)
header(card, title, THEME.accent, 1)
divider(card, 2)
bodyText(card, body, 3)
local row = buttonRow(card, 4)
local no = makeButton(row, "Нет / No", "secondary", 1)
no.Size = UDim2.new(0.5, -5, 1, 0)
local yes = makeButton(row, "Да / Yes", "primary", 2)
yes.Size = UDim2.new(0.5, -5, 1, 0)
local ev = Instance.new("BindableEvent")
yes.MouseButton1Click:Connect(function() ev:Fire(true) end)
no.MouseButton1Click:Connect(function() ev:Fire(false) end)
local result = ev.Event:Wait()
ev:Destroy()
gui:Destroy()
return result
end
local function showInfo()
local gui = makeGui()
scrim(gui)
local card = Instance.new("Frame")
card.AnchorPoint = Vector2.new(0.5, 0.5)
card.Position = UDim2.fromScale(0.5, 0.5)
card.Size = UDim2.fromOffset(440, 560)
card.BackgroundColor3 = THEME.card
card.BorderSizePixel = 0
card.Parent = gui
corner(card, 14)
stroke(card, THEME.stroke, 1)
local sc = Instance.new("UIScale")
sc.Scale = fitScale(480, 600)
sc.Parent = card
bindScale(card, sc, 480, 600)
pad(card, 20)
local tag = Instance.new("TextLabel")
tag.BackgroundTransparency = 1
tag.Position = UDim2.fromOffset(0, 0)
tag.Size = UDim2.new(1, 0, 0, 16)
tag.Font = FONT_BOLD
tag.TextSize = 12
tag.Text = "AUTO-PAINT"
tag.TextColor3 = THEME.accent
tag.TextXAlignment = Enum.TextXAlignment.Left
tag.Parent = card
local title = Instance.new("TextLabel")
title.BackgroundTransparency = 1
title.Position = UDim2.fromOffset(0, 22)
title.Size = UDim2.new(1, 0, 0, 28)
title.Font = FONT_BOLD
title.TextSize = 21
title.Text = "Описание / Description"
title.TextColor3 = THEME.text
title.TextXAlignment = Enum.TextXAlignment.Left
title.Parent = card
local seg = Instance.new("Frame")
seg.Position = UDim2.fromOffset(0, 60)
seg.Size = UDim2.new(1, 0, 0, 40)
seg.BackgroundColor3 = THEME.field
seg.BorderSizePixel = 0
seg.Parent = card
corner(seg, 10)
stroke(seg, THEME.strokeSoft, 1)
pad(seg, 4)
local ruBtn = Instance.new("TextButton")
ruBtn.AnchorPoint = Vector2.new(0, 0.5)
ruBtn.Position = UDim2.new(0, 0, 0.5, 0)
ruBtn.Size = UDim2.new(0.5, -3, 1, 0)
ruBtn.AutoButtonColor = false
ruBtn.Font = FONT_MED
ruBtn.TextSize = 14
ruBtn.Text = "Русский"
ruBtn.BorderSizePixel = 0
ruBtn.Parent = seg
corner(ruBtn, 8)
local enBtn = Instance.new("TextButton")
enBtn.AnchorPoint = Vector2.new(1, 0.5)
enBtn.Position = UDim2.new(1, 0, 0.5, 0)
enBtn.Size = UDim2.new(0.5, -3, 1, 0)
enBtn.AutoButtonColor = false
enBtn.Font = FONT_MED
enBtn.TextSize = 14
enBtn.Text = "English"
enBtn.BorderSizePixel = 0
enBtn.Parent = seg
corner(enBtn, 8)
local scroll = Instance.new("ScrollingFrame")
scroll.Position = UDim2.fromOffset(0, 112)
scroll.Size = UDim2.new(1, 0, 1, -(112 + 58))
scroll.BackgroundColor3 = THEME.field
scroll.BorderSizePixel = 0
scroll.ScrollBarThickness = 5
scroll.ScrollBarImageColor3 = THEME.subtext
scroll.ScrollBarImageTransparency = 0.25
scroll.ScrollingDirection = Enum.ScrollingDirection.Y
scroll.CanvasSize = UDim2.new(0, 0, 0, 0)
scroll.AutomaticCanvasSize = Enum.AutomaticSize.Y
scroll.Parent = card
corner(scroll, 10)
stroke(scroll, THEME.strokeSoft, 1)
pad(scroll, 14)
local body = Instance.new("TextLabel")
body.BackgroundTransparency = 1
body.Size = UDim2.new(1, 0, 0, 0)
body.AutomaticSize = Enum.AutomaticSize.Y
body.Font = FONT
body.TextSize = 15
body.Text = DESC_RU
body.TextColor3 = THEME.text
body.TextWrapped = true
body.TextXAlignment = Enum.TextXAlignment.Left
body.TextYAlignment = Enum.TextYAlignment.Top
body.Parent = scroll
local function setLang(lang)
if lang == "ru" then
body.Text = DESC_RU
ruBtn.BackgroundColor3 = THEME.accent; ruBtn.TextColor3 = THEME.onAccent
enBtn.BackgroundColor3 = THEME.field; enBtn.TextColor3 = THEME.subtext
else
body.Text = DESC_EN
enBtn.BackgroundColor3 = THEME.accent; enBtn.TextColor3 = THEME.onAccent
ruBtn.BackgroundColor3 = THEME.field; ruBtn.TextColor3 = THEME.subtext
end
end
setLang("ru")
ruBtn.MouseButton1Click:Connect(function() setLang("ru") end)
enBtn.MouseButton1Click:Connect(function() setLang("en") end)
local okBtn = Instance.new("TextButton")
okBtn.AnchorPoint = Vector2.new(0.5, 1)
okBtn.Position = UDim2.new(0.5, 0, 1, 0)
okBtn.Size = UDim2.new(1, 0, 0, 46)
okBtn.AutoButtonColor = true
okBtn.Font = FONT_MED
okBtn.TextSize = 15
okBtn.Text = "Понятно / Got it"
okBtn.BackgroundColor3 = THEME.accent
okBtn.TextColor3 = THEME.onAccent
okBtn.BorderSizePixel = 0
okBtn.Parent = card
corner(okBtn, 10)
local ev = Instance.new("BindableEvent")
okBtn.MouseButton1Click:Connect(function() ev:Fire() end)
ev.Event:Wait()
ev:Destroy()
gui:Destroy()
end
local function killAll()
for _, g in ipairs(guis) do pcall(function() g:Destroy() end) end
table.clear(guis)
end
local function stopMsg(title, body, color)
showAlert(title, body, color)
killAll()
end
local wantInfo = askYesNo("Авто-покраска", "Показать короткую инструкцию?\nShow a short how-to?")
if wantInfo then showInfo() end
local run = askYesNo("Запуск / Run", "Запустить покраску сейчас?\nStart painting now?")
if not run then return end
local claimedBase = nil
local bases = workspace:FindFirstChild("Bases")
if bases then
for _, b in pairs(bases:GetChildren()) do
if b:IsA("BasePart") and b:GetAttribute("Owner") == player.UserId then
claimedBase = b
break
end
end
end
if not claimedBase then
showAlert("Холст не занят / Canvas Not Claimed",
"Подойди к свободному холсту и нажми Claim Canvas, потом запусти скрипт снова.\n\nWalk up to a free canvas and press Claim Canvas, then run the script again.",
THEME.warning)
return
end
local folder = workspace:FindFirstChild(tostring(player.UserId))
local canvasBase = folder and folder:FindFirstChild("CanvasBase")
if not canvasBase then
showAlert("Флаг не выбран / No Flag Selected",
"Холст занят, но флаг ещё не выбран. Выбери флаг в меню → нажми Paint → дождись загрузки → запусти скрипт.\n\nCanvas is claimed but no flag selected. Pick a flag → press Paint → wait for it to load → run the script.",
THEME.warning)
return
end
local ColorPixel = RS.RemoteEvents.ColorPixel
local SetCurrentColor = RS.RemoteEvents.SetCurrentColor
local GetPixelInfo = RS.RemoteFunctions.GetPixelInfo
local CheckIfPainted = RS.RemoteFunctions.CheckIfPainted
local W = canvasBase.Size.X * 2
local H = canvasBase.Size.Z * 2
local RADIUS = player:GetAttribute("BrushRadius") or 8
local STEP = math.floor(RADIUS * 1.8)
local pixelMap = GetPixelInfo:InvokeServer()
if not pixelMap then
showAlert("Флаг не выбран / No Flag Selected",
"Холст занят, но флаг ещё не выбран. Выбери флаг в меню → нажми Paint → дождись загрузки → запусти скрипт.\n\nCanvas is claimed but no flag selected. Pick a flag → press Paint → wait for it to load → run the script.",
THEME.warning)
return
end
local hasPixels = false
for _, rows in pairs(pixelMap) do
for _, ci in pairs(rows) do
if ci ~= 0 then hasPixels = true break end
end
if hasPixels then break end
end
if not hasPixels then
showAlert("Флаг не выбран / No Flag Selected",
"Холст занят, но флаг ещё не выбран. Выбери флаг в меню → нажми Paint → дождись загрузки → запусти скрипт.\n\nCanvas is claimed but no flag selected. Pick a flag → press Paint → wait for it to load → run the script.",
THEME.warning)
return
end
local char = player.Character or player.CharacterAdded:Wait()
local hrp = char:WaitForChild("HumanoidRootPart", 5)
if not hrp then
stopMsg("Ошибка / Error",
"Персонаж не найден. Сделай ресет и попробуй снова.\n\nCharacter not found. Reset and try again.",
THEME.danger)
return
end
cam.CameraType = Enum.CameraType.Scriptable
cam.CFrame = CFrame.new(
canvasBase.Position + Vector3.new(0, math.max(canvasBase.Size.X, canvasBase.Size.Z) * 1.2, 0),
canvasBase.Position
)
local function c2w(col, row)
local lx = (col - 0.5) / W * canvasBase.Size.X - canvasBase.Size.X / 2
local lz = canvasBase.Size.Z / 2 - (row - 0.5) / H * canvasBase.Size.Z
return canvasBase.CFrame:PointToWorldSpace(Vector3.new(lx, 3, lz))
end
hrp.Anchored = true
local lastRem = math.huge
local stalls = 0
for round = 1, 10 do
local pm = CheckIfPainted:InvokeServer() or {}
local plan = {}
local rem = 0
for col, rows in pairs(pixelMap) do
for row, ci in pairs(rows) do
if ci ~= 0 and not (pm[col] and pm[col][row] == true) then
rem += 1
local gc = math.ceil(col / STEP)
local gr = math.ceil(row / STEP)
local ac = math.clamp((gc-1)*STEP + math.ceil(STEP/2), 1, W)
local ar = math.clamp((gr-1)*STEP + math.ceil(STEP/2), 1, H)
local key = gc * 100000 + gr
if not plan[ci] then plan[ci] = {} end
if not plan[ci][key] then plan[ci][key] = {ac=ac, ar=ar, px={}} end
local t = plan[ci][key].px
t[#t+1] = {col, row}
end
end
end
if rem == 0 then
hrp.Anchored = false
cam.CameraType = Enum.CameraType.Custom
killAll()
return
end
if rem >= lastRem then stalls += 1 else stalls = 0 end
lastRem = rem
if stalls >= STALL_LIMIT then
hrp.Anchored = false
cam.CameraType = Enum.CameraType.Custom
stopMsg("Покраска не проходит / Blocked", STALL_RU .. "\n\n" .. STALL_EN, THEME.danger)
return
end
local ops = 0
for ci, cells in pairs(plan) do
SetCurrentColor:FireServer(ci)
for _, cell in pairs(cells) do
hrp.CFrame = CFrame.new(c2w(cell.ac, cell.ar)) * hrp.CFrame.Rotation
ColorPixel:FireServer(cell.px)
ops += 1
if ops % 15 == 0 then task.wait() end
end
end
task.wait(2)
end
hrp.Anchored = false
cam.CameraType = Enum.CameraType.Custom
stopMsg("Не успел / Timed Out",
"Не закрасило всё за отведённое время. Просто запусти скрипт ещё раз.\n\nCouldn't finish in time. Just run the script again.",
THEME.warning)
Nice