--[[ Paint an Album — Auto Paint Author: @Dark_Fire Version: 1.0 My first public script. Feel free to use, modify, and share it. If you repost it, I'd appreciate a mention — but no pressure either way. Requires: executor with getgc support. TG: @Dark_Firex --- Paint an Album — Авто-покраска Автор: @Dark_Fire Версия: 1.0 Мой первый публичный скрипт. Можешь свободно использовать, изменять и распространять. Если будешь репостить — буду благодарен за упоминание, но это не обязательно. Требуется: экзекьютор с поддержкой getgc. TG: @Dark_Firex ]] local CHUNK = 600 local DELAY = 0.12 local STAY_ON_CANVAS = true local MAX_ROUNDS = 60 local ROUND_WAIT = 1.0 local STALL_LIMIT = 6 local Players = game:GetService("Players") local RS = game:GetService("ReplicatedStorage") local player = Players.LocalPlayer local Camera = workspace.CurrentCamera local DESC_RU = [[КАК ПОЛЬЗОВАТЬСЯ 1) Подойди к холсту и сделай его своим (захвати). 2) Открой альбом и выбери картинку. 3) Дождись, пока картинка появится на холсте, и запусти скрипт. Скрипт красит картинку вживую — ты видишь, как она заполняется. Когда всё готово, он сам тихо остановится. Если снимешь холст («Unclaim plot»), покраска остановится. Нажми Claim plot снова, в окне «Unfinished Album» жми Resume (не Start Fresh!) и запусти скрипт ещё раз, чтобы дорисовать.]] local DESC_EN = [[HOW TO USE 1) Walk up to a canvas and make it yours (claim it). 2) Open an album and pick a picture. 3) Wait until the picture appears on the canvas, then run the script. The script paints the picture live — you can watch it fill in. When it's done, it just stops quietly. If you unclaim the plot, painting stops. Press Claim plot again, pick Resume in the "Unfinished Album" popup (not Start Fresh!), then run the script once more to finish.]] local UNCLAIM_RU = "Ты снял холст (Unclaim plot), и покраска остановилась.\n\nНажми Claim plot снова — игра покажет окно «Unfinished Album». Жми зелёную кнопку Resume (НЕ Start Fresh — она стирает прогресс!), дождись загрузки и запусти скрипт ещё раз, чтобы дорисовать." local UNCLAIM_EN = "You unclaimed the plot, so painting stopped.\n\nClaim it again — the game shows an \"Unfinished Album\" popup. Tap the green Resume button (NOT Start Fresh — it wipes progress!), wait for it to load, then run the script once more to finish." 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 (Camera and Camera.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 Camera then return end local conn conn = Camera: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 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 done = false ok.MouseButton1Click:Connect(function() done = true end) while not done do task.wait() end 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 result = nil yes.MouseButton1Click:Connect(function() result = true end) no.MouseButton1Click:Connect(function() result = false end) while result == nil do task.wait() end 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 done = false okBtn.MouseButton1Click:Connect(function() done = true end) while not done do task.wait() end 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 function getChar() local char = player.Character or player.CharacterAdded:Wait() local hrp = char:FindFirstChild("HumanoidRootPart") or char:WaitForChild("HumanoidRootPart", 10) return char, hrp end local allCanvases = workspace:WaitForChild("AllAlbumCanvases", 15) local function findMyCanvas() local uid = player.UserId for _, c in ipairs(allCanvases:GetChildren()) do local plane = c:FindFirstChild("CanvasPlane") if plane then local owner = c:GetAttribute("Owner") local co = c:GetAttribute("CoOwners") or "" if owner ~= nil and owner ~= 0 and tostring(owner) == tostring(uid) then return c, plane end if type(co) == "string" and string.find(co, "_" .. tostring(uid) .. "_") then return c, plane end end end return nil end local myCanvas, plane = findMyCanvas() if not myCanvas then showAlert("Нет холста / No canvas", "Не нашёл холст, который принадлежит тебе. Подойди к свободному холсту и захвати его — нажми кнопку Claim plot, потом запусти скрипт заново.\n\nCouldn't find a canvas that belongs to you. Walk up to a free canvas and claim it — press the Claim plot button, then run the script again.", THEME.warning) return end local function stillMine() if not myCanvas or not myCanvas.Parent then return false end local owner = myCanvas:GetAttribute("Owner") if owner ~= nil and owner ~= 0 and tostring(owner) == tostring(player.UserId) then return true end local co = myCanvas:GetAttribute("CoOwners") if type(co) == "string" and string.find(co, "_" .. tostring(player.UserId) .. "_") then return true end return false end local PaintTileEvent = RS:FindFirstChild("PaintTileEvent") or RS:WaitForChild("PaintTileEvent", 10) if not PaintTileEvent then showAlert("Игра обновилась / Game updated", "Похоже, игра обновилась и скрипт пока не работает. Подожди новую версию скрипта (если она конечно будет).\n\nLooks like the game updated and the script doesn't work for now. Wait for an updated version (if there even will be one).", THEME.danger) return end if type(getgc) ~= "function" then showAlert("Не подходит / Not supported", "Твоя эксплоит/инжектор для запуска скриптов не поддерживает этот скрипт. Попробуй другую (посвежее).\n\nYour script executor doesn't support this script. Try a different (newer) one.", THEME.danger) return end local function countRemaining(rend) local sm, pm, pal = rawget(rend, "stateMap"), rawget(rend, "pixelMap"), rawget(rend, "palette") if not sm or not pm or not pal then return 0 end local n = #pal local total = 0 pcall(function() for i = 0, buffer.len(sm) - 1 do if buffer.readu8(sm, i) ~= 1 then local ci = buffer.readu8(pm, i) if ci >= 1 and ci <= n then total = total + 1 end end end end) return total end local renderer do local img = plane:FindFirstChild("CanvasDisplay") img = img and img:FindFirstChild("Image") local ok, gc = pcall(getgc, true) local candidates = {} if ok and type(gc) == "table" then for _, t in ipairs(gc) do if type(t) == "table" then local good = pcall(function() return rawget(t, "stateMap") ~= nil and rawget(t, "pixelMap") ~= nil and rawget(t, "palette") ~= nil and rawget(t, "imageLabel") ~= nil end) if good and rawget(t, "stateMap") and rawget(t, "pixelMap") and rawget(t, "palette") and rawget(t, "imageLabel") then if not img or rawget(t, "imageLabel") == img then candidates[#candidates + 1] = t end end end end end local best, bestRem = nil, -1 for _, t in ipairs(candidates) do local pal = rawget(t, "palette") if pal and #pal > 0 then local rem = countRemaining(t) if rem > bestRem then bestRem, best = rem, t end end end renderer = best end if not renderer or not renderer.palette or #renderer.palette == 0 then showAlert("Нет картинки / No picture", "Ты не выбрал картинку. Открой альбом, выбери картинку и дождись, пока она появится на холсте. Потом запусти снова.\n\nYou haven't picked a picture. Open an album, choose one and wait until it shows on the canvas, then run again.", THEME.warning) return end local palette = renderer.palette if STAY_ON_CANVAS then pcall(function() local _, hrp = getChar() if hrp then hrp.CFrame = CFrame.new(plane.Position + Vector3.new(0, 3, 0)) end end) end local function scanRemaining() local groups, total = {}, 0 local ok = pcall(function() local sm, pm = renderer.stateMap, renderer.pixelMap local n = #palette for i = 0, buffer.len(sm) - 1 do if buffer.readu8(sm, i) ~= 1 then local ci = buffer.readu8(pm, i) if ci >= 1 and ci <= n then local g = groups[ci] if not g then g = {} groups[ci] = g end g[#g + 1] = i total = total + 1 end end end end) return groups, total, ok end local function applyLocal(indices, col) local ok = pcall(function() renderer:syncPaintStroke(indices, col) end) if not ok then pcall(function() local sm = renderer.stateMap for _, i in ipairs(indices) do if i >= 0 and i < buffer.len(sm) then buffer.writeu8(sm, i, 1) end end end) end end local function sendGroup(ci, idx) local col = palette[ci] local batch = {} for k = 1, #idx do batch[#batch + 1] = idx[k] if #batch >= CHUNK then if not stillMine() then return false end local b = batch pcall(function() PaintTileEvent:FireServer(myCanvas, b, col, ci) end) applyLocal(b, col) batch = {} task.wait(DELAY) end end if #batch > 0 then if not stillMine() then return false end local b = batch pcall(function() PaintTileEvent:FireServer(myCanvas, b, col, ci) end) applyLocal(b, col) task.wait(DELAY) end return true end local lastRemaining = math.huge local stalls = 0 for round = 1, MAX_ROUNDS do if not stillMine() then stopMsg("Холст снят / Unclaimed", UNCLAIM_RU .. "\n\n" .. UNCLAIM_EN, THEME.warning) return end local groups, remaining, ok = scanRemaining() if not ok then stopMsg("Холст снят / Unclaimed", UNCLAIM_RU .. "\n\n" .. UNCLAIM_EN, THEME.warning) return end if remaining == 0 then killAll() return end if remaining >= lastRemaining then stalls = stalls + 1 else stalls = 0 end lastRemaining = remaining if stalls >= STALL_LIMIT then stopMsg("Покраска не проходит / Blocked", STALL_RU .. "\n\n" .. STALL_EN, THEME.danger) return end if STAY_ON_CANVAS then pcall(function() local _, hrp = getChar() if hrp then hrp.CFrame = CFrame.new(plane.Position + Vector3.new(0, 3, 0)) end end) end for ci, idx in pairs(groups) do if not sendGroup(ci, idx) then stopMsg("Холст снят / Unclaimed", UNCLAIM_RU .. "\n\n" .. UNCLAIM_EN, THEME.warning) return end end task.wait(ROUND_WAIT) end stopMsg("Не успел докрасить / Timed out", "Не получилось докрасить за отведённое время. Просто запусти скрипт ещё раз.\n\nCouldn't finish in time. Just run the script again.", THEME.warning)