--[[ GIGAMENU v2.0 — by zyru Кастомизация самоката Kukirin G4 (workspace["Kukirin G4"]) Тип: LocalScript -> StarterPlayer > StarterPlayerScripts F вилли вкл/выкл (синхронно с переключателем Auto Wheelie [F]) Shift заморозить / разморозить самокат (пока сидишь на нём) RightShift показать / спрятать меню "—" свернуть меню в полоску, "X" — скрыть Страницы: Presets готовые пресеты Customization вилли, фриз, вилли-бар (ADD), трейл, Rainbow Kukirin G4, цвета Underglow подсветка снизу (без видимого блока — только свет) Test список деталей самоката: клик = подсветка на самокате + смена цвета Test2 PUBLIC / PRIVATE пресеты и Cloud key (поделиться темой с другом) Если что-то красится не то — смотри Output (F9): скрипт сам печатает, как разложил детали по группам. Имена можно вписать в PART_NAMES. ]] local Players = game:GetService("Players") local UIS = game:GetService("UserInputService") local RS = game:GetService("RunService") local Workspace = game:GetService("Workspace") local TweenService = game:GetService("TweenService") local HttpService = game:GetService("HttpService") local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") do local old = playerGui:FindFirstChild("GIGAMENU") if old then old:Destroy() end end local RGB = Color3.fromRGB local WHITE, BLACK = Color3.new(1, 1, 1), Color3.new(0, 0, 0) --------------------------------------------------------------- -- НАСТРОЙКИ --------------------------------------------------------------- local CONFIG = { SCOOTER_NAME = "Kukirin G4", WHEELIE_KEY = Enum.KeyCode.F, FREEZE_KEY = Enum.KeyCode.J, MENU_KEY = Enum.KeyCode.RightShift, WHEELIE_HOLD = false, -- true = вилли пока держишь клавишу, false = вкл/выкл по нажатию WHEELIE_ANGLE = 65, -- градусов WHEELIE_POWER = 6, WHEELIE_RAMP = 80, -- град/сек -- Куда у PrimaryPart смотрит "нос" (локальные координаты). -- Если вместо вилли самокат задирает ЗАД — Vector3.new(0, 0, 1). FORWARD_LOCAL = Vector3.new(0, 0, -1), RIDE_RADIUS = 8, -- если нет сиденья/сварки: считаем что ты "на самокате", когда ближе стадов UNDERGLOW_HEIGHT = 0.08, -- высота источника света (доля высоты модели) GLOW_BRIGHTNESS = 4, GLOW_RANGE = 20, TRAIL_WIDTH = nil, -- nil = подобрать по колесу (в студах) TRAIL_LIFETIME = 1.2, STRETCH_VALUE = 0.75, -- для пресета "Resolution 4:3" WHEELIE_BAR_COLLIDE = false, -- true = вилли-бар физически касается земли RAINBOW_SPEED = 0.25, -- скорость радуги RAINBOW_SPREAD = 0.6, -- насколько радуга "растянута" вдоль самоката (0 = весь одним цветом) SWEEP_INTERVAL = 0.1, -- как часто перепроверять цвета (сек) — защита от игры, которая их сбрасывает STRIP_TEXTURES = true, -- убирать SurfaceAppearance/TextureID при покраске (иначе цвет не виден) UNCLASSIFIED_TO_FRAME = true, -- если Frame не найден — красить неопознанные детали как раму } local PART_NAMES = { Frame = {"Frame", "Body", "Deck"}, Wheel = {"FrontWheel", "BackWheel"}, Handlebar = {"Handlebar", "Bars", "Steering"}, Suspension = {"Suspension", "Shock"}, WheelieBar = {"WheelieBar"}, } local GROUP_ORDER = {"WheelieBar", "Wheel", "Suspension", "Handlebar", "Frame"} local GROUP_SET = {} for _, g in ipairs(GROUP_ORDER) do GROUP_SET[g] = true end local KEYWORDS = { WheelieBar = {"wheelie"}, Wheel = {"wheel", "tire", "tyre", "rim"}, Suspension = {"suspension", "shock", "spring", "fork"}, Handlebar = {"handlebar", "handle", "steer", "grip"}, Frame = {"frame", "body", "deck", "chassis", "stem"}, } --------------------------------------------------------------- -- СОСТОЯНИЕ --------------------------------------------------------------- local state = { colors = {}, -- [группа] = Color3 (nil = заводской) materials = {}, -- [группа] = Enum.Material partColors = {}, -- [путь детали] = Color3 (страница Test) underglow = true, glowColor = RGB(0, 90, 255), trail = false, trailColor = RGB(0, 255, 255), smokeColor = nil, -- nil = как в игре wheelieBar = false, -- нажали ADD } local settings = {stretch = false} local rainbow = {} -- [цель] = true (All / Trail / Underglow / Smoke / группа) local wheelie = {on = false, target = 0} local freeze = {on = false, saved = {}} local riding = false local conns = {} local function connect(signal, fn) local c = signal:Connect(fn) table.insert(conns, c) return c end -- то, что определяется ниже (GUI), но нужно раньше local notify, updateStatus, refreshTestList, closeTestPanel local wheelieToggleUI, freezeToggleUI, wbButtonUpdate local testVisible = false local function getHumanoid() local c = player.Character return c and c:FindFirstChildOfClass("Humanoid") end --------------------------------------------------------------- -- ДВИЖОК ПОКРАСКИ -- Цвет считается из state (деталь > группа), и принудительно -- возвращается, если игра его сбросила (сразу по сигналу + раз в 0.1с). --------------------------------------------------------------- local originals = setmetatable({}, {__mode = "k"}) local partKeyOf = setmetatable({}, {__mode = "k"}) local partGroupOf = setmetatable({}, {__mode = "k"}) local phaseOf = setmetatable({}, {__mode = "k"}) local hooked = setmetatable({}, {__mode = "k"}) local groups = {} for _, g in ipairs(GROUP_ORDER) do groups[g] = {} end local unclassified, allParts, partsByKey, keyList = {}, {}, {}, {} local scooter, rootPart, dirty, descConn = nil, nil, true, nil local scanVersion = 0 local rainbowT, rainbowColor = 0, Color3.fromHSV(0, 1, 1) local function stripTexture(p, force) if not CONFIG.STRIP_TEXTURES then return end local o = originals[p] if not o then return end if o.stripped and not force then return end o.stripped = true for _, ch in ipairs(p:GetChildren()) do if ch:IsA("SurfaceAppearance") then o.sa = o.sa or {} table.insert(o.sa, ch) ch.Parent = nil end end if p:IsA("MeshPart") and p.TextureID ~= "" then o.tex = p.TextureID pcall(function() p.TextureID = "" end) end end local function restoreTexture(p) local o = originals[p] if not o or not o.stripped then return end o.stripped = false if o.sa then for _, sa in ipairs(o.sa) do pcall(function() sa.Parent = p end) end o.sa = nil end if o.tex then local t = o.tex pcall(function() p.TextureID = t end) o.tex = nil end end local function sameColor(a, b) return math.abs(a.R - b.R) < 0.002 and math.abs(a.G - b.G) < 0.002 and math.abs(a.B - b.B) < 0.002 end local function desiredColor(p) if rainbow.All then return Color3.fromHSV((rainbowT + (phaseOf[p] or 0)) % 1, 1, 1) end local pk = partKeyOf[p] local pc = pk and state.partColors[pk] if pc then return pc end local g = partGroupOf[p] if g then if rainbow[g] then return rainbowColor end return state.colors[g] end return nil end local function desiredMaterial(p) local g = partGroupOf[p] return g and state.materials[g] or nil end local function enforcePart(p) if not p.Parent then return end local want = desiredColor(p) if want then local o = originals[p] if o and not o.stripped then stripTexture(p) end if p:IsA("UnionOperation") and not p.UsePartColor then p.UsePartColor = true end if not sameColor(p.Color, want) then p.Color = want end end local m = desiredMaterial(p) if m and p.Material ~= m then p.Material = m end end local function hasPaint() return next(state.colors) ~= nil or next(state.materials) ~= nil or next(state.partColors) ~= nil or next(rainbow) ~= nil end local function enforceAll() if not hasPaint() then return end for _, p in ipairs(allParts) do enforcePart(p) end end -- вернуть всё в заводское и накатить текущее состояние заново local function repaintAll() for _, p in ipairs(allParts) do local o = originals[p] if o and p.Parent then restoreTexture(p) if not sameColor(p.Color, o.Color) then p.Color = o.Color end if p.Material ~= o.Material then p.Material = o.Material end if o.UsePartColor ~= nil and p:IsA("UnionOperation") then p.UsePartColor = o.UsePartColor end end end enforceAll() end local function hookPart(p) if hooked[p] then return end hooked[p] = true local function recheck() if p.Parent and not rainbow.All then enforcePart(p) end end p:GetPropertyChangedSignal("Color"):Connect(recheck) p:GetPropertyChangedSignal("Material"):Connect(recheck) p.ChildAdded:Connect(function(ch) if ch:IsA("SurfaceAppearance") and desiredColor(p) then stripTexture(p, true) end end) if p:IsA("MeshPart") then p:GetPropertyChangedSignal("TextureID"):Connect(function() if desiredColor(p) and p.TextureID ~= "" then stripTexture(p, true) end end) end end --------------------------------------------------------------- -- САМОКАТ: поиск и группы деталей --------------------------------------------------------------- local lastSearch = -100 local function isFx(obj) return obj.Name:sub(1, 5) == "GIGA_" or obj:FindFirstAncestor("GIGA_FX") ~= nil end local function classify(part) for _, g in ipairs(GROUP_ORDER) do for _, n in ipairs(PART_NAMES[g]) do if part.Name == n then return g end end end local node = part while node and node ~= scooter do local ln = node.Name:lower() for _, g in ipairs(GROUP_ORDER) do for _, kw in ipairs(KEYWORDS[g]) do if ln:find(kw, 1, true) then return g end end end node = node.Parent end return nil end local function relPath(p) local names = {} local node = p while node and node ~= scooter do table.insert(names, 1, node.Name) node = node.Parent end if #names == 0 then return p.Name end return table.concat(names, "/") end local function normName(n) return (n:lower():gsub("[^%w]", "")) end local function searchScooter() local now = os.clock() if now - lastSearch < 2 then return nil end lastSearch = now local s = Workspace:FindFirstChild(CONFIG.SCOOTER_NAME, true) if s then return s end local needle = normName(CONFIG.SCOOTER_NAME) for _, d in ipairs(Workspace:GetDescendants()) do if d:IsA("Model") or d:IsA("BasePart") then local n = normName(d.Name) if n == needle or n:find("kukirin", 1, true) then return d end end end return nil end local function pickNearest(list) if #list <= 1 then return list[1] end local char = player.Character local hrp = char and char:FindFirstChild("HumanoidRootPart") if not hrp then return list[1] end local best, bd = nil, math.huge for _, s in ipairs(list) do local pos = s:IsA("Model") and s:GetPivot().Position or s.Position local d = (pos - hrp.Position).Magnitude if d < bd then best, bd = s, d end end return best end local function directCandidates() local list = {} for _, c in ipairs(Workspace:GetChildren()) do if c.Name == CONFIG.SCOOTER_NAME and (c:IsA("Model") or c:IsA("BasePart")) then table.insert(list, c) end end return list end local function getScooter() local s = scooter -- если ты сидишь в самокате — это и есть наш самокат local hum = getHumanoid() local seat = hum and hum.SeatPart local ridden = seat and seat:FindFirstAncestor(CONFIG.SCOOTER_NAME) if ridden and ridden ~= scooter and (ridden:IsA("Model") or ridden:IsA("BasePart")) then s = ridden elseif not (s and s:IsDescendantOf(Workspace)) then s = pickNearest(directCandidates()) or searchScooter() end if s ~= scooter then scooter = s dirty = true if descConn then descConn:Disconnect() descConn = nil end if s then descConn = s.DescendantAdded:Connect(function() dirty = true end) end end return scooter end local function rescan() for _, g in ipairs(GROUP_ORDER) do groups[g] = {} end unclassified, allParts, partsByKey, keyList = {}, {}, {}, {} rootPart = nil scanVersion += 1 local s = scooter if not s then if updateStatus then updateStatus() end return end local biggest, biggestVol = nil, 0 local list = s:GetDescendants() if s:IsA("BasePart") then table.insert(list, s) end for _, obj in ipairs(list) do if obj:IsA("BasePart") and not isFx(obj) then if not originals[obj] then local entry = {Color = obj.Color, Material = obj.Material, Transparency = obj.Transparency} if obj:IsA("UnionOperation") then entry.UsePartColor = obj.UsePartColor end originals[obj] = entry end hookPart(obj) local g = classify(obj) partGroupOf[obj] = g if g then table.insert(groups[g], obj) else table.insert(unclassified, obj) end table.insert(allParts, obj) local key = relPath(obj) partKeyOf[obj] = key local bucket = partsByKey[key] if not bucket then bucket = {} partsByKey[key] = bucket table.insert(keyList, key) end table.insert(bucket, obj) local vol = obj.Size.X * obj.Size.Y * obj.Size.Z if vol > biggestVol then biggest, biggestVol = obj, vol end end end table.sort(keyList) if s:IsA("Model") and s.PrimaryPart then rootPart = s.PrimaryPart else rootPart = biggest end if CONFIG.UNCLASSIFIED_TO_FRAME and #groups.Frame == 0 then for _, p in ipairs(unclassified) do table.insert(groups.Frame, p) partGroupOf[p] = "Frame" end end -- фаза радуги: позиция детали вдоль самоката if rootPart then local f = CONFIG.FORWARD_LOCAL local dist, lo, hi = {}, math.huge, -math.huge for _, p in ipairs(allParts) do local v = rootPart.CFrame:PointToObjectSpace(p.Position):Dot(f) dist[p] = v if v < lo then lo = v end if v > hi then hi = v end end local span = math.max(hi - lo, 0.001) for p, v in pairs(dist) do phaseOf[p] = (v - lo) / span * CONFIG.RAINBOW_SPREAD end end -- новые/пересозданные детали красим сразу же enforceAll() if updateStatus then updateStatus() end end local function ensure() getScooter() if dirty then dirty = false rescan() end end local function getRoot() ensure() return rootPart end local function getFxFolder() local s = getScooter() if not s then return nil end local f = s:FindFirstChild("GIGA_FX") if not f then f = Instance.new("Folder") f.Name = "GIGA_FX" f.Parent = s end return f end local function cleanupOld() local s = scooter if not s then return end for _, d in ipairs(s:GetDescendants()) do if d.Name:sub(1, 5) == "GIGA_" then d:Destroy() end end end local function getRearWheel(fwd) local rear, best = nil, math.huge for _, w in ipairs(groups.Wheel) do local d = w.Position:Dot(fwd) if d < best then best, rear = d, w end end return rear end local function debugPrint() ensure() print("[GIGAMENU] scooter:", scooter and scooter:GetFullName() or "НЕ НАЙДЕН (проверь CONFIG.SCOOTER_NAME)") print("[GIGAMENU] root part:", rootPart and rootPart:GetFullName() or "nil") for _, g in ipairs(GROUP_ORDER) do local names = {} for _, p in ipairs(groups[g]) do table.insert(names, p.Name) end print(string.format("[GIGAMENU] %-10s (%d): %s", g, #names, table.concat(names, ", "))) end local un = {} for _, p in ipairs(unclassified) do table.insert(un, p.Name) end print(string.format("[GIGAMENU] без группы (%d): %s", #un, table.concat(un, ", "))) end -- следим за появлением нового самоката (респавн / клон при посадке) — ищем без задержки connect(Workspace.DescendantAdded, function(d) if d.Name == CONFIG.SCOOTER_NAME and (d:IsA("Model") or d:IsA("BasePart")) then lastSearch = -100 dirty = true end end) local function groupDisplayColor(g) if state.colors[g] then return state.colors[g] end ensure() local p = groups[g][1] local o = p and originals[p] return o and o.Color or RGB(255, 255, 255) end --------------------------------------------------------------- -- "НА САМОКАТЕ?" и ЗАМОРОЗКА (Shift) --------------------------------------------------------------- local function isRiding() local s = scooter local char = player.Character local hrp = char and char:FindFirstChild("HumanoidRootPart") if not (s and char and hrp) then return false end local hum = char:FindFirstChildOfClass("Humanoid") local seat = hum and hum.SeatPart if seat and seat:IsDescendantOf(s) then return true end local root = rootPart if not root then return false end local ok, parts = pcall(function() return root:GetConnectedParts(true) end) if ok then for _, p in ipairs(parts) do if p:IsDescendantOf(char) then return true end end end return (hrp.Position - root.Position).Magnitude <= CONFIG.RIDE_RADIUS end local function resetFreezeState() freeze.on = false freeze.saved = {} if freezeToggleUI then freezeToggleUI.set(false) end end -- возвращает true, если состояние стало таким, как просили local function setFreeze(on) if on == freeze.on then return true end if on then ensure() if not rootPart or not isRiding() then return false end freeze.saved = {} for _, p in ipairs(allParts) do if p.Parent then freeze.saved[p] = p.Anchored p.AssemblyLinearVelocity = Vector3.zero p.AssemblyAngularVelocity = Vector3.zero p.Anchored = true end end freeze.on = true else for p, was in pairs(freeze.saved) do if p.Parent then p.Anchored = was end end freeze.saved = {} freeze.on = false end if freezeToggleUI then freezeToggleUI.set(freeze.on) end return true end local function checkFreeze() local hum = getHumanoid() local char = player.Character local hrp = char and char:FindFirstChild("HumanoidRootPart") if not hum or hum.Health <= 0 or not hrp or not rootPart or (hrp.Position - rootPart.Position).Magnitude > 40 then setFreeze(false) end end --------------------------------------------------------------- -- ВИЛЛИ-БАР (кнопка ADD): две распорки назад от заднего колеса + перекладина --------------------------------------------------------------- local function newBarPart(folder, root, localCF, size) local p = Instance.new("Part") p.Name = "WheelieBar" p.Size = size p.Material = Enum.Material.Metal p.Color = RGB(28, 28, 30) p.TopSurface = Enum.SurfaceType.Smooth p.BottomSurface = Enum.SurfaceType.Smooth p.CanCollide = CONFIG.WHEELIE_BAR_COLLIDE p.CanQuery = false p.CanTouch = false p.Massless = true p.CFrame = root.CFrame * localCF p.Parent = folder local w = Instance.new("WeldConstraint") w.Part0 = root w.Part1 = p w.Parent = p return p end local function buildWheelieBar() ensure() local root, s = rootPart, scooter if not root or not s then return false end local old = s:FindFirstChild("WheelieBarAdded") if old then old:Destroy() end local fwd = root.CFrame:VectorToWorldSpace(CONFIG.FORWARD_LOCAL) local rear = getRearWheel(fwd) local back = -CONFIG.FORWARD_LOCAL.Unit local side = CONFIG.FORWARD_LOCAL:Cross(Vector3.yAxis).Unit local center, r, halfW if rear then center = root.CFrame:PointToObjectSpace(rear.Position) r = math.max(rear.Size.X, rear.Size.Y, rear.Size.Z) / 2 halfW = math.min(rear.Size.X, rear.Size.Y, rear.Size.Z) / 2 + 0.2 else center = back * (math.max(root.Size.X, root.Size.Z) / 2) + Vector3.new(0, -root.Size.Y / 2 + 0.4, 0) r, halfW = 0.4, 0.4 end local t = math.clamp(r * 0.18, 0.06, 0.2) local a = center + back * (r * 0.4) + Vector3.new(0, r * 0.35, 0) local b = center + back * (r * 1.9) + Vector3.new(0, -r * 0.6, 0) local folder = Instance.new("Folder") folder.Name = "WheelieBarAdded" folder.Parent = s for _, sgn in ipairs({-1, 1}) do local A = a + side * (sgn * halfW) local B = b + side * (sgn * halfW) local len = (B - A).Magnitude newBarPart(folder, root, CFrame.lookAt((A + B) / 2, B), Vector3.new(t, t, len)) end newBarPart(folder, root, CFrame.lookAt(b, b + side), Vector3.new(t * 1.4, t * 1.4, halfW * 2 + t)) dirty = true -- пересканируем: новые детали попадут в группу WheelieBar и сразу покрасятся return true end --------------------------------------------------------------- -- АНДЕРГЛОУ: только свет (невидимый источник, приварен к самокату) --------------------------------------------------------------- local glow = {} local function destroyGlow() if glow.part then glow.part:Destroy() end glow = {} end local function setGlowColorRaw(c) if glow.point then glow.point.Color = c end if glow.surface then glow.surface.Color = c end end local function localBounds(root, model) local minV = Vector3.new(math.huge, math.huge, math.huge) local maxV = Vector3.new(-math.huge, -math.huge, -math.huge) local list = model:GetDescendants() if model:IsA("BasePart") then table.insert(list, model) end for _, p in ipairs(list) do if p:IsA("BasePart") and not isFx(p) then local rel = root.CFrame:ToObjectSpace(p.CFrame) local h = p.Size / 2 for _, sx in ipairs({-1, 1}) do for _, sy in ipairs({-1, 1}) do for _, sz in ipairs({-1, 1}) do local c = rel * Vector3.new(h.X * sx, h.Y * sy, h.Z * sz) minV = Vector3.new(math.min(minV.X, c.X), math.min(minV.Y, c.Y), math.min(minV.Z, c.Z)) maxV = Vector3.new(math.max(maxV.X, c.X), math.max(maxV.Y, c.Y), math.max(maxV.Z, c.Z)) end end end end end return minV, maxV end local function buildGlow() destroyGlow() if not state.underglow then return end local root = getRoot() local folder = getFxFolder() if not root or not folder then return end local minV, maxV = localBounds(root, scooter) local size = maxV - minV local center = (minV + maxV) / 2 local y = minV.Y + math.max(size.Y * CONFIG.UNDERGLOW_HEIGHT, 0.12) local emitter = Instance.new("Part") emitter.Name = "GIGA_Underglow" emitter.Size = Vector3.new(0.2, 0.2, 0.2) emitter.Transparency = 1 -- блока не видно, светят только лампы emitter.CanCollide = false emitter.CanQuery = false emitter.CanTouch = false emitter.CastShadow = false emitter.Massless = true emitter.Material = Enum.Material.SmoothPlastic emitter.CFrame = root.CFrame * CFrame.new(center.X, y, center.Z) emitter.Parent = folder local weld = Instance.new("WeldConstraint") weld.Part0 = root weld.Part1 = emitter weld.Parent = emitter local c = state.glowColor local point = Instance.new("PointLight") point.Color = c point.Brightness = CONFIG.GLOW_BRIGHTNESS point.Range = CONFIG.GLOW_RANGE point.Shadows = false point.Parent = emitter local surf = Instance.new("SurfaceLight") surf.Face = Enum.NormalId.Bottom surf.Angle = 170 surf.Color = c surf.Brightness = CONFIG.GLOW_BRIGHTNESS surf.Range = CONFIG.GLOW_RANGE surf.Shadows = false surf.Parent = emitter glow = {part = emitter, point = point, surface = surf, root = root} end --------------------------------------------------------------- -- ТРЕЙЛ: плоская полоса света по земле за задним колесом --------------------------------------------------------------- local trail = {} local function destroyTrail() for _, o in pairs(trail) do if typeof(o) == "Instance" then o:Destroy() end end trail = {} end local function buildTrail() destroyTrail() if not state.trail then return end local root = getRoot() if not root then return end local fwd = root.CFrame:VectorToWorldSpace(CONFIG.FORWARD_LOCAL) local rear = getRearWheel(fwd) local localPos, r, width if rear then localPos = root.CFrame:PointToObjectSpace(rear.Position) r = math.max(rear.Size.X, rear.Size.Y, rear.Size.Z) / 2 width = math.clamp(math.min(rear.Size.X, rear.Size.Y, rear.Size.Z) * 2.5, 0.8, 3) else localPos = -CONFIG.FORWARD_LOCAL * (math.max(root.Size.X, root.Size.Z) / 2) + Vector3.new(0, -root.Size.Y / 2, 0) r = 0.3 width = 1 end width = CONFIG.TRAIL_WIDTH or width -- поперёк самоката (локальная "правая" ось) -> лента лежит плоско на земле local side = CONFIG.FORWARD_LOCAL:Cross(Vector3.yAxis).Unit local ground = localPos + Vector3.new(0, -r + 0.06, 0) local a0 = Instance.new("Attachment") a0.Name = "GIGA_TrailA0" a0.Position = ground - side * (width / 2) a0.Parent = root local a1 = Instance.new("Attachment") a1.Name = "GIGA_TrailA1" a1.Position = ground + side * (width / 2) a1.Parent = root local t = Instance.new("Trail") t.Name = "GIGA_Trail" t.Attachment0 = a0 t.Attachment1 = a1 t.Color = ColorSequence.new(state.trailColor) t.Transparency = NumberSequence.new({NumberSequenceKeypoint.new(0, 0.05), NumberSequenceKeypoint.new(1, 1)}) t.LightEmission = 1 t.Lifetime = CONFIG.TRAIL_LIFETIME t.MinLength = 0.05 t.FaceCamera = false t.Parent = root trail = {obj = t, a0 = a0, a1 = a1} end --------------------------------------------------------------- -- ДЫМ (Burnout Smoke) --------------------------------------------------------------- local smoke = {list = {}} local smokeOrig = setmetatable({}, {__mode = "k"}) local function setSmokeColor(c) for _, e in ipairs(smoke.list) do e.Color = ColorSequence.new(c) end if smoke.own then smoke.own.Color = ColorSequence.new(c) end end local function restoreSmoke() for _, e in ipairs(smoke.list) do if smokeOrig[e] then e.Color = smokeOrig[e] end end if smoke.own then smoke.own.Color = ColorSequence.new(RGB(230, 230, 230)) end end local function destroySmoke() if smoke.own then smoke.own:Destroy() end if smoke.att then smoke.att:Destroy() end smoke = {list = {}} end local function buildSmoke() destroySmoke() local s = getScooter() local root = getRoot() if not s or not root then return end -- ищем дым, который уже есть в модели игры local list = {} for _, d in ipairs(s:GetDescendants()) do if d:IsA("ParticleEmitter") and not isFx(d) then local n = (d.Name .. " " .. (d.Parent and d.Parent.Name or "")):lower() if n:find("smoke", 1, true) or n:find("burnout", 1, true) then if not smokeOrig[d] then smokeOrig[d] = d.Color end table.insert(list, d) end end end smoke.list = list -- нет своего дыма в модели — делаем дым у заднего колеса (идёт пока включено вилли) if #list == 0 then local fwd = root.CFrame:VectorToWorldSpace(CONFIG.FORWARD_LOCAL) local rear = getRearWheel(fwd) local pos if rear then local r = math.max(rear.Size.X, rear.Size.Y, rear.Size.Z) / 2 pos = root.CFrame:PointToObjectSpace(rear.Position) + Vector3.new(0, -r * 0.6, 0) else pos = -CONFIG.FORWARD_LOCAL * (math.max(root.Size.X, root.Size.Z) / 2) + Vector3.new(0, -root.Size.Y / 2, 0) end local att = Instance.new("Attachment") att.Name = "GIGA_SmokeAtt" att.CFrame = CFrame.lookAt(pos, pos - CONFIG.FORWARD_LOCAL) att.Parent = root local e = Instance.new("ParticleEmitter") e.Name = "GIGA_Smoke" e.Texture = "rbxasset://textures/particles/smoke_main.dds" e.Color = ColorSequence.new(RGB(230, 230, 230)) e.Rate = 45 e.Lifetime = NumberRange.new(0.7, 1.3) e.Speed = NumberRange.new(4, 8) e.SpreadAngle = Vector2.new(20, 20) e.Rotation = NumberRange.new(0, 360) e.RotSpeed = NumberRange.new(-60, 60) e.Size = NumberSequence.new({NumberSequenceKeypoint.new(0, 1), NumberSequenceKeypoint.new(1, 4)}) e.Transparency = NumberSequence.new({NumberSequenceKeypoint.new(0, 0.45), NumberSequenceKeypoint.new(1, 1)}) e.EmissionDirection = Enum.NormalId.Front e.Enabled = wheelie.on e.Parent = att smoke.own = e smoke.att = att end if state.smokeColor then setSmokeColor(state.smokeColor) end end --------------------------------------------------------------- -- RAINBOW (All = весь Kukirin, либо по каждой цели отдельно) --------------------------------------------------------------- local function savedColor(target) if target == "Underglow" then return state.glowColor end if target == "Trail" then return state.trailColor end if target == "Smoke" then return state.smokeColor end return state.colors[target] end local function setRainbow(target, on) rainbow[target] = on or nil if on then return end if target == "Underglow" then setGlowColorRaw(state.glowColor) elseif target == "Trail" then if trail.obj then trail.obj.Color = ColorSequence.new(state.trailColor) end elseif target == "Smoke" then if state.smokeColor then setSmokeColor(state.smokeColor) else restoreSmoke() end else repaintAll() -- All или группа деталей end end local function stopAllRainbow() local had = next(rainbow) ~= nil for k in pairs(rainbow) do rainbow[k] = nil end if had then setGlowColorRaw(state.glowColor) if trail.obj then trail.obj.Color = ColorSequence.new(state.trailColor) end if state.smokeColor then setSmokeColor(state.smokeColor) else restoreSmoke() end end end --------------------------------------------------------------- -- ПОДСВЕТКА ДЕТАЛИ НА САМОКАТЕ (страница Test) --------------------------------------------------------------- local hlList = {} local function clearHighlight() for _, h in ipairs(hlList) do h:Destroy() end hlList = {} end local function highlightKey(key) clearHighlight() local list = partsByKey[key] local folder = getFxFolder() if not list or not folder then return end for i, p in ipairs(list) do if i > 30 then break end local h = Instance.new("Highlight") h.Name = "GIGA_Highlight" h.Adornee = p h.FillColor = RGB(0, 220, 255) h.OutlineColor = WHITE h.FillTransparency = 0.8 h.OutlineTransparency = 0 h.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop h.Parent = folder table.insert(hlList, h) end end --------------------------------------------------------------- -- ГЛАВНЫЙ ЦИКЛ КАДРА: радуга, быстрая проверка цветов, пульс подсветки --------------------------------------------------------------- local sweepAcc = 0 connect(RS.RenderStepped, function(dt) rainbowT = os.clock() * CONFIG.RAINBOW_SPEED rainbowColor = Color3.fromHSV(rainbowT % 1, 1, 1) -- что-то добавилось/пересоздалось в самокате — пересканируем и красим ДО отрисовки кадра if dirty then ensure() end local needParts = rainbow.All if not needParts then for k in pairs(rainbow) do if GROUP_SET[k] then needParts = true break end end end sweepAcc += dt if needParts or sweepAcc >= CONFIG.SWEEP_INTERVAL then sweepAcc = 0 enforceAll() end if rainbow.Underglow then setGlowColorRaw(rainbowColor) end if rainbow.Trail and trail.obj then trail.obj.Color = ColorSequence.new(rainbowColor, Color3.fromHSV((rainbowT - 0.15) % 1, 1, 1)) end if rainbow.Smoke then setSmokeColor(rainbowColor) end if #hlList > 0 then local k = math.sin(os.clock() * 6) * 0.5 + 0.5 for _, h in ipairs(hlList) do h.FillTransparency = 0.7 + 0.3 * k h.OutlineTransparency = 0.3 * (1 - k) end end end) --------------------------------------------------------------- -- ВИЛЛИ (F) --------------------------------------------------------------- local function setWheelie(on) wheelie.on = on if wheelieToggleUI then wheelieToggleUI.set(on) end if smoke.own then smoke.own.Enabled = on end end local function stepWheelie(dt) local goal = wheelie.on and CONFIG.WHEELIE_ANGLE or 0 local maxStep = CONFIG.WHEELIE_RAMP * dt wheelie.target = wheelie.target + math.clamp(goal - wheelie.target, -maxStep, maxStep) if not wheelie.on and wheelie.target < 0.05 then wheelie.target = 0 return end local root = getRoot() if not root or root.Anchored then return end local fwd = root.CFrame:VectorToWorldSpace(CONFIG.FORWARD_LOCAL).Unit local right = fwd:Cross(Vector3.yAxis) if right.Magnitude < 0.1 then return end right = right.Unit local pitch = math.deg(math.asin(math.clamp(fwd.Y, -1, 1))) local err = wheelie.target - pitch local rate = root.AssemblyAngularVelocity:Dot(right) local want = math.clamp(math.rad(err) * CONFIG.WHEELIE_POWER, -4, 4) local newRate = rate + (want - rate) * math.clamp(dt * 12, 0, 1) local dW = right * (newRate - rate) root.AssemblyAngularVelocity = root.AssemblyAngularVelocity + dW -- вращаем вокруг оси заднего колеса, чтобы оно не вдавливалось в землю local rear = getRearWheel(fwd) if rear then root.AssemblyLinearVelocity = root.AssemblyLinearVelocity + dW:Cross(root.AssemblyCenterOfMass - rear.Position) end end --------------------------------------------------------------- -- ПРИМЕНИТЬ ВСЁ + watchdog (респавн самоката, посадка/слезание) --------------------------------------------------------------- local printedDebug = false local function applyAll() ensure() enforceAll() buildGlow() buildTrail() buildSmoke() if state.wheelieBar and scooter and not scooter:FindFirstChild("WheelieBarAdded") then buildWheelieBar() end local total = 0 for _, g in ipairs(GROUP_ORDER) do total = total + #groups[g] end if total == 0 then warn("[GIGAMENU] детали самоката не распознаны — смотри вывод ниже и впиши имена в PART_NAMES") end if not printedDebug then printedDebug = true debugPrint() end end local appliedTo, wdAcc = nil, 1 connect(RS.Heartbeat, function(dt) stepWheelie(dt) wdAcc += dt if wdAcc < 0.25 then return end wdAcc = 0 ensure() local s = scooter riding = (s ~= nil) and isRiding() if s ~= appliedTo then if freeze.on then resetFreezeState() end appliedTo = s if s then cleanupOld() dirty = true ensure() applyAll() end elseif s then if state.underglow and (not glow.part or not glow.part.Parent or glow.root ~= rootPart) then buildGlow() end if state.trail and (not trail.obj or not trail.obj.Parent) then buildTrail() end if state.wheelieBar and not s:FindFirstChild("WheelieBarAdded") then buildWheelieBar() end if freeze.on then checkFreeze() end end if updateStatus then updateStatus() end if testVisible and refreshTestList then refreshTestList(false) end end) -- посадка / слезание: сразу пересканируем самокат do local function watchCharacter(char) local hum = char:WaitForChild("Humanoid", 10) if not hum then return end hum:GetPropertyChangedSignal("SeatPart"):Connect(function() dirty = true wdAcc = 1 end) end if player.Character then task.spawn(watchCharacter, player.Character) end connect(player.CharacterAdded, function(char) task.spawn(watchCharacter, char) end) end --------------------------------------------------------------- -- СОХРАНЕНИЕ ТЕМ: данные <-> Cloud key --------------------------------------------------------------- local ui = {refreshers = {}} local function syncUI() for _, fn in ipairs(ui.refreshers) do fn() end end local hex, encodeKey, decodeKey, captureData, applyData do function hex(c) return string.format("%02x%02x%02x", math.floor(c.R * 255 + 0.5), math.floor(c.G * 255 + 0.5), math.floor(c.B * 255 + 0.5)) end local function unhex(s) if type(s) ~= "string" or #s ~= 6 then return nil end local r, g, b = tonumber(s:sub(1, 2), 16), tonumber(s:sub(3, 4), 16), tonumber(s:sub(5, 6), 16) if r and g and b then return RGB(r, g, b) end return nil end local B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" local B64IDX = {} for i = 1, #B64 do B64IDX[B64:byte(i)] = i - 1 end local function b64enc(s) local out, n = {}, 0 for i = 1, #s, 3 do local a, b, c = s:byte(i, i + 2) local v = a * 65536 + (b or 0) * 256 + (c or 0) local c1 = bit32.rshift(v, 18) % 64 local c2 = bit32.rshift(v, 12) % 64 local c3 = bit32.rshift(v, 6) % 64 local c4 = v % 64 local piece = B64:sub(c1 + 1, c1 + 1) .. B64:sub(c2 + 1, c2 + 1) if b then piece = piece .. B64:sub(c3 + 1, c3 + 1) end if c then piece = piece .. B64:sub(c4 + 1, c4 + 1) end n += 1 out[n] = piece end return table.concat(out) end local function b64dec(s) local out = {} for i = 1, #s, 4 do local chunk = s:sub(i, i + 3) local cnt = #chunk if cnt == 1 then return nil end local v = 0 for j = 1, 4 do local ch = chunk:byte(j) local x = ch and B64IDX[ch] if ch and not x then return nil end v = v * 64 + (x or 0) end table.insert(out, string.char(bit32.rshift(v, 16) % 256)) if cnt >= 3 then table.insert(out, string.char(bit32.rshift(v, 8) % 256)) end if cnt == 4 then table.insert(out, string.char(v % 256)) end end return table.concat(out) end local KEY_PREFIX = "GM1" local function checksum(s) local h = 7 for i = 1, #s do h = (h * 31 + s:byte(i)) % 65521 end return string.format("%04x", h) end function encodeKey(d) local ok, json = pcall(function() return HttpService:JSONEncode(d) end) if not ok then return nil end local payload = b64enc(json) return KEY_PREFIX .. "." .. payload .. "." .. checksum(payload) end function decodeKey(key) key = (tostring(key or ""):gsub("%s+", "")) if key == "" then return nil, "empty" end if #key > 40000 then return nil, "too long" end local prefix, payload, sum = key:match("^(%w+)%.([%w%-_]+)%.(%x+)$") if prefix ~= KEY_PREFIX then return nil, "wrong format" end if checksum(payload) ~= sum then return nil, "key is damaged" end local json = b64dec(payload) if not json then return nil, "bad data" end local ok, d = pcall(function() return HttpService:JSONDecode(json) end) if not ok or type(d) ~= "table" then return nil, "bad data" end return d end -- снимок текущей темы function captureData(name) local d = {v = 1, n = name, c = {}, m = {}, p = {}} for g, c in pairs(state.colors) do d.c[g] = hex(c) end for g, m in pairs(state.materials) do d.m[g] = m.Name end for k, c in pairs(state.partColors) do d.p[k] = hex(c) end d.g, d.go = hex(state.glowColor), state.underglow and 1 or 0 d.t, d.to = hex(state.trailColor), state.trail and 1 or 0 if state.smokeColor then d.s = hex(state.smokeColor) end if rainbow.All then d.r = 1 end return d end -- применить тему из данных (всё остальное сбрасывается в заводское) function applyData(d) for k in pairs(rainbow) do rainbow[k] = nil end state.colors, state.materials, state.partColors = {}, {}, {} if type(d.c) == "table" then for g, h in pairs(d.c) do local c = unhex(h) if c and GROUP_SET[g] then state.colors[g] = c end end end if type(d.m) == "table" then for g, n in pairs(d.m) do local ok, m = pcall(function() return Enum.Material[n] end) if ok and m and GROUP_SET[g] then state.materials[g] = m end end end if type(d.p) == "table" then for k, h in pairs(d.p) do local c = unhex(h) if c and type(k) == "string" then state.partColors[k] = c end end end local gc = unhex(d.g) if gc then state.glowColor = gc end if d.go ~= nil then state.underglow = (d.go == 1) end local tc = unhex(d.t) if tc then state.trailColor = tc end if d.to ~= nil then state.trail = (d.to == 1) end state.smokeColor = unhex(d.s) if d.r == 1 then rainbow.All = true end repaintAll() buildGlow() buildTrail() if state.smokeColor then setSmokeColor(state.smokeColor) else restoreSmoke() end syncUI() end end -- serialization --------------------------------------------------------------- -- ПРЕСЕТЫ --------------------------------------------------------------- local N, M, S = Enum.Material.Neon, Enum.Material.Metal, Enum.Material.SmoothPlastic -- классические пресеты (красят только раму/колёса, андерглоу — если указан) local function classic(name, frame, wheel, glowColor) return {name = name, kind = "classic", colors = {Frame = frame, Wheel = wheel, WheelieBar = frame}, glow = glowColor} end local READY_PRESETS = { {name = "Full Black", kind = "classic", colors = {Frame = BLACK, Wheel = BLACK, Handlebar = BLACK, Suspension = BLACK, WheelieBar = BLACK}}, classic("Black + White", BLACK, WHITE, nil), classic("Black + Blue", BLACK, RGB(0, 90, 255), nil), classic("White + Red", WHITE, RGB(255, 0, 0), nil), classic("Black + Purp", BLACK, RGB(140, 0, 255), nil), classic("White + Pink + Underglow", WHITE, RGB(255, 120, 200), RGB(255, 120, 200)), classic("Black + Cyan + Underglow", BLACK, RGB(0, 255, 255), RGB(0, 255, 255)), {name = "Resolution 4:3", kind = "resolution"}, } local function classicToData(p) local d = {v = 1, n = p.name, c = {}, m = {}, p = {}} for g, c in pairs(p.colors) do d.c[g] = hex(c) end if p.glow then d.g, d.go = hex(p.glow), 1 end return d end local function setStretch(on) settings.stretch = on pcall(function() RS:UnbindFromRenderStep("GIGA_Stretch") end) if on then RS:BindToRenderStep("GIGA_Stretch", Enum.RenderPriority.Camera.Value + 1, function() local cam = Workspace.CurrentCamera if cam then cam.CFrame = cam.CFrame * CFrame.new(0, 0, 0, 1, 0, 0, 0, CONFIG.STRETCH_VALUE, 0, 0, 0, 1) end end) end end local function applyPreset(p) if p.kind == "resolution" then setStretch(not settings.stretch) if notify then notify("Resolution 4:3 " .. (settings.stretch and "ON" or "OFF")) end return end stopAllRainbow() state.materials = {} state.partColors = {} for g, c in pairs(p.colors) do state.colors[g] = c end if p.glow then state.underglow = true state.glowColor = p.glow end repaintAll() if p.glow then buildGlow() end syncUI() end --------------------------------------------------------------- -- GUI: палитра и хелперы (стиль как в видео) --------------------------------------------------------------- local C = { bg = RGB(18, 22, 28), row = RGB(24, 28, 37), rowHi = RGB(30, 35, 45), btn = RGB(34, 40, 50), tabOff = RGB(14, 18, 22), tabOn = RGB(26, 31, 40), text = RGB(235, 238, 245), dim = RGB(110, 118, 130), head = RGB(74, 128, 150), accent = RGB(60, 124, 152), red = RGB(226, 84, 80), track = RGB(30, 35, 44), } local function new(class, props, parent) local o = Instance.new(class) for k, v in pairs(props) do o[k] = v end if parent then o.Parent = parent end return o end local function corner(inst, r) local c = Instance.new("UICorner") c.CornerRadius = UDim.new(0, r or 6) c.Parent = inst return c end local counters = setmetatable({}, {__mode = "k"}) local function bump(parent) counters[parent] = (counters[parent] or 0) + 1 return counters[parent] end local function trim(s) return (tostring(s or ""):gsub("^%s+", ""):gsub("%s+$", "")) end local gui = new("ScreenGui", { Name = "GIGAMENU", ResetOnSpawn = false, DisplayOrder = 50, ZIndexBehavior = Enum.ZIndexBehavior.Sibling, }, playerGui) -- всплывающая подсказка снизу local toast = new("TextLabel", { AnchorPoint = Vector2.new(0.5, 1), Position = UDim2.new(0.5, 0, 1, -28), Size = UDim2.fromOffset(0, 28), AutomaticSize = Enum.AutomaticSize.X, BackgroundColor3 = C.bg, BackgroundTransparency = 0.1, Text = "", TextColor3 = C.text, Font = Enum.Font.GothamMedium, TextSize = 12, Visible = false, ZIndex = 10, BorderSizePixel = 0, }, gui) corner(toast, 8) new("UIPadding", {PaddingLeft = UDim.new(0, 14), PaddingRight = UDim.new(0, 14)}, toast) local toastToken = 0 notify = function(text) toastToken += 1 local my = toastToken toast.Text = text toast.Visible = true task.delay(2.2, function() if my == toastToken then toast.Visible = false end end) end local function makeDraggable(frame, handle) local dragging, dragStart, startPos = false, nil, nil handle.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = true dragStart = input.Position startPos = frame.Position end end) connect(UIS.InputChanged, function(input) if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then local d = input.Position - dragStart frame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + d.X, startPos.Y.Scale, startPos.Y.Offset + d.Y) end end) connect(UIS.InputEnded, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = false end end) end -- слайдер 0..255 (как R/G/B в видео) local function makeSlider(parent, position, size, initial, fillColor, onChange, scrollFrame) local hit = new("Frame", {Position = position, Size = size, BackgroundTransparency = 1, Active = true}, parent) local bar = new("Frame", { AnchorPoint = Vector2.new(0, 0.5), Position = UDim2.new(0, 0, 0.5, 0), Size = UDim2.new(1, 0, 0, 6), BackgroundColor3 = C.track, BorderSizePixel = 0, }, hit) corner(bar, 3) local fill = new("Frame", {Size = UDim2.new(0, 0, 1, 0), BackgroundColor3 = fillColor, BorderSizePixel = 0}, bar) corner(fill, 3) local knob = new("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Size = UDim2.fromOffset(12, 12), Position = UDim2.new(0, 0, 0.5, 0), BackgroundColor3 = WHITE, BorderSizePixel = 0, ZIndex = 2, }, bar) corner(knob, 6) local function visual(v) local a = math.clamp(v / 255, 0, 1) fill.Size = UDim2.new(a, 0, 1, 0) knob.Position = UDim2.new(a, 0, 0.5, 0) end visual(initial) local dragging = false local function update(x) local a = math.clamp((x - bar.AbsolutePosition.X) / math.max(bar.AbsoluteSize.X, 1), 0, 1) local v = math.floor(a * 255 + 0.5) visual(v) onChange(v) end local function lock(l) if scrollFrame then scrollFrame.ScrollingEnabled = not l end end hit.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = true lock(true) update(input.Position.X) end end) connect(UIS.InputChanged, function(input) if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then update(input.Position.X) end end) connect(UIS.InputEnded, function(input) if dragging and (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) then dragging = false lock(false) end end) return {set = function(v) visual(v) end} end -- три слайдера R/G/B внутри panel; onChange вызывается только когда двигает пользователь local CHANS = {{"R", RGB(240, 80, 84)}, {"G", RGB(80, 250, 81)}, {"B", RGB(83, 80, 238)}} local function makeRGBSliders(panel, page, onChange, startOrder) local draft = {255, 255, 255} local sliders, labels = {}, {} for i, ch in ipairs(CHANS) do local line = new("Frame", {Size = UDim2.new(1, 0, 0, 18), BackgroundTransparency = 1, LayoutOrder = startOrder + i - 1}, panel) new("TextLabel", { Size = UDim2.fromOffset(14, 18), BackgroundTransparency = 1, Text = ch[1], TextColor3 = ch[2], Font = Enum.Font.GothamBold, TextSize = 10, }, line) labels[i] = new("TextLabel", { AnchorPoint = Vector2.new(1, 0), Position = UDim2.new(1, 0, 0, 0), Size = UDim2.fromOffset(30, 18), BackgroundTransparency = 1, Text = "255", TextColor3 = C.dim, Font = Enum.Font.Gotham, TextSize = 10, TextXAlignment = Enum.TextXAlignment.Right, }, line) sliders[i] = makeSlider(line, UDim2.fromOffset(20, 0), UDim2.new(1, -56, 1, 0), 255, ch[2], function(v) draft[i] = v labels[i].Text = tostring(v) onChange(RGB(draft[1], draft[2], draft[3])) end, page) end return { get = function() return RGB(draft[1], draft[2], draft[3]) end, set = function(c) draft = {math.floor(c.R * 255 + 0.5), math.floor(c.G * 255 + 0.5), math.floor(c.B * 255 + 0.5)} for i = 1, 3 do sliders[i].set(draft[i]) labels[i].Text = tostring(draft[i]) end end, } end local function textBox(parent, props) local tb = new("TextBox", { BackgroundColor3 = C.btn, TextColor3 = C.text, PlaceholderColor3 = C.dim, Font = Enum.Font.Gotham, TextSize = 11, TextXAlignment = Enum.TextXAlignment.Left, ClearTextOnFocus = false, BorderSizePixel = 0, ClipsDescendants = true, Text = "", }, nil) for k, v in pairs(props) do tb[k] = v end corner(tb, 6) new("UIPadding", {PaddingLeft = UDim.new(0, 8), PaddingRight = UDim.new(0, 8)}, tb) tb.Parent = parent return tb end --------------------------------------------------------------- -- GUI: окно --------------------------------------------------------------- local W, H, HEAD_H = 480, 330, 46 local main = new("Frame", { Name = "Main", Size = UDim2.fromOffset(W, H), Position = UDim2.new(0.5, -W / 2, 0.5, -H / 2), BackgroundColor3 = C.bg, BackgroundTransparency = 0.08, BorderSizePixel = 0, ClipsDescendants = true, Active = true, }, gui) corner(main, 10) new("UIStroke", {Color = WHITE, Transparency = 0.92, Thickness = 1}, main) local sidebar, content, setMenuVisible do local topBar = new("Frame", {Name = "TopBar", Size = UDim2.new(1, 0, 0, HEAD_H), BackgroundTransparency = 1, Active = true}, main) makeDraggable(main, topBar) local dot = new("Frame", {Position = UDim2.fromOffset(12, 18), Size = UDim2.fromOffset(8, 8), BackgroundColor3 = C.accent, BorderSizePixel = 0}, topBar) corner(dot, 4) new("TextLabel", { Position = UDim2.fromOffset(28, 6), Size = UDim2.fromOffset(86, 18), BackgroundTransparency = 1, Text = "GIGAMENU", TextColor3 = C.text, Font = Enum.Font.GothamBold, TextSize = 14, TextXAlignment = Enum.TextXAlignment.Left, }, topBar) new("TextLabel", { Position = UDim2.fromOffset(28, 23), Size = UDim2.fromOffset(80, 14), BackgroundTransparency = 1, Text = "by матвейбадяг", TextColor3 = C.dim, Font = Enum.Font.Gotham, TextSize = 10, TextXAlignment = Enum.TextXAlignment.Left, }, topBar) local badge = new("TextLabel", { Position = UDim2.fromOffset(114, 12), Size = UDim2.fromOffset(36, 15), BackgroundColor3 = C.accent, Text = "v2.0", TextColor3 = WHITE, Font = Enum.Font.GothamBold, TextSize = 9, }, topBar) corner(badge, 4) local minBtn = new("TextButton", { Position = UDim2.new(1, -58, 0, 11), Size = UDim2.fromOffset(24, 24), BackgroundTransparency = 1, Text = "—", TextColor3 = C.dim, Font = Enum.Font.GothamBold, TextSize = 13, }, topBar) local closeBtn = new("TextButton", { Position = UDim2.new(1, -30, 0, 14), Size = UDim2.fromOffset(18, 18), BackgroundColor3 = RGB(70, 100, 114), Text = "X", TextColor3 = WHITE, Font = Enum.Font.GothamBold, TextSize = 10, AutoButtonColor = true, }, topBar) corner(closeBtn, 9) sidebar = new("Frame", {Position = UDim2.fromOffset(10, 50), Size = UDim2.new(0, 112, 1, -60), BackgroundTransparency = 1}, main) new("UIListLayout", {Padding = UDim.new(0, 5), SortOrder = Enum.SortOrder.LayoutOrder}, sidebar) content = new("Frame", {Position = UDim2.fromOffset(130, 50), Size = UDim2.new(1, -140, 1, -60), BackgroundTransparency = 1}, main) local opener = new("TextButton", { Name = "Opener", AnchorPoint = Vector2.new(0.5, 0), Position = UDim2.new(0.5, 0, 0, 6), Size = UDim2.fromOffset(84, 22), BackgroundColor3 = C.bg, BackgroundTransparency = 0.25, Text = "GIGAMENU", TextColor3 = C.text, Font = Enum.Font.GothamBold, TextSize = 10, BorderSizePixel = 0, Visible = false, }, gui) corner(opener, 11) function setMenuVisible(v) main.Visible = v opener.Visible = not v end closeBtn.MouseButton1Click:Connect(function() setMenuVisible(false) end) opener.MouseButton1Click:Connect(function() setMenuVisible(true) end) -- свернуть в полоску local minimized = false local function setMinimized(v) minimized = v if v then sidebar.Visible = false content.Visible = false end TweenService:Create(main, TweenInfo.new(0.18, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), { Size = UDim2.fromOffset(W, v and HEAD_H or H), }):Play() if not v then task.delay(0.18, function() if not minimized then sidebar.Visible = true content.Visible = true end end) end end minBtn.MouseButton1Click:Connect(function() setMinimized(not minimized) end) end -- window --------------------------------------------------------------- -- GUI: страницы и элементы --------------------------------------------------------------- local PAGE_ORDER = {"Presets", "Customization", "Underglow", "Test", "Test2"} local pages = {} for _, name in ipairs(PAGE_ORDER) do local p = new("ScrollingFrame", { Name = name, Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, BorderSizePixel = 0, ScrollBarThickness = 3, ScrollBarImageColor3 = RGB(70, 110, 130), ScrollBarImageTransparency = 0.3, CanvasSize = UDim2.new(), AutomaticCanvasSize = Enum.AutomaticSize.Y, Visible = false, }, content) new("UIListLayout", {Padding = UDim.new(0, 6), SortOrder = Enum.SortOrder.LayoutOrder}, p) new("UIPadding", {PaddingBottom = UDim.new(0, 8), PaddingRight = UDim.new(0, 8)}, p) pages[name] = p end local presetsPage, customPage, glowPage = pages.Presets, pages.Customization, pages.Underglow local testPage, test2Page = pages.Test, pages.Test2 local sideButtons = {} local function showPage(name) for n, p in pairs(pages) do p.Visible = (n == name) end for n, b in pairs(sideButtons) do local active = (n == name) b.BackgroundColor3 = active and C.tabOn or C.tabOff b.TextColor3 = active and C.text or C.dim end testVisible = (name == "Test") if testVisible then if refreshTestList then refreshTestList(false) end elseif closeTestPanel then closeTestPanel() end end for i, name in ipairs(PAGE_ORDER) do local b = new("TextButton", { Size = UDim2.new(1, 0, 0, 29), BackgroundColor3 = C.tabOff, Text = name, TextColor3 = C.dim, Font = Enum.Font.GothamMedium, TextSize = 11, AutoButtonColor = false, BorderSizePixel = 0, LayoutOrder = i, }, sidebar) corner(b, 7) sideButtons[name] = b b.MouseButton1Click:Connect(function() showPage(name) end) end local function sectionTitle(parent, text) return new("TextLabel", { Size = UDim2.new(1, 0, 0, 18), BackgroundTransparency = 1, Text = "| " .. text, TextColor3 = C.head, Font = Enum.Font.GothamBold, TextSize = 10, TextXAlignment = Enum.TextXAlignment.Left, LayoutOrder = bump(parent), }, parent) end local function presetButton(parent, text, callback) local b = new("TextButton", { Size = UDim2.new(1, 0, 0, 35), BackgroundColor3 = C.row, Text = text, TextColor3 = C.text, Font = Enum.Font.Gotham, TextSize = 12, TextXAlignment = Enum.TextXAlignment.Left, AutoButtonColor = false, BorderSizePixel = 0, LayoutOrder = bump(parent), }, parent) corner(b, 7) new("UIPadding", {PaddingLeft = UDim.new(0, 12)}, b) b.MouseEnter:Connect(function() b.BackgroundColor3 = C.rowHi end) b.MouseLeave:Connect(function() b.BackgroundColor3 = C.row end) b.MouseButton1Click:Connect(callback) return b end local function row(parent, text) local r = new("Frame", { Size = UDim2.new(1, 0, 0, 40), BackgroundColor3 = C.row, BorderSizePixel = 0, LayoutOrder = bump(parent), }, parent) corner(r, 7) local l = new("TextLabel", { Size = UDim2.new(1, -150, 1, 0), Position = UDim2.fromOffset(12, 0), BackgroundTransparency = 1, Text = text, TextColor3 = C.text, Font = Enum.Font.Gotham, TextSize = 12, TextXAlignment = Enum.TextXAlignment.Left, }, r) return r, l end local function makeToggle(r, initial, callback) local b = new("TextButton", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, -10, 0.5, 0), Size = UDim2.fromOffset(55, 22), Font = Enum.Font.GothamBold, TextSize = 10, AutoButtonColor = false, BorderSizePixel = 0, }, r) corner(b, 6) local on = initial local function render() b.Text = on and "ON" or "OFF" b.BackgroundColor3 = on and C.accent or C.btn b.TextColor3 = on and WHITE or C.dim end render() b.MouseButton1Click:Connect(function() on = not on render() callback(on) end) return {set = function(v) on = v render() end} end -- строка выбора цвета: swatch + EDIT, внутри разворачивается пикер R/G/B + SAVE + RAINBOW local closeOpenPicker = nil local function colorRow(parent, page, labelText, target, getColor, onSave) local wrap = new("Frame", { Size = UDim2.new(1, 0, 0, 0), AutomaticSize = Enum.AutomaticSize.Y, BackgroundTransparency = 1, LayoutOrder = bump(parent), }, parent) new("UIListLayout", {Padding = UDim.new(0, 4), SortOrder = Enum.SortOrder.LayoutOrder}, wrap) local r = new("Frame", {Size = UDim2.new(1, 0, 0, 40), BackgroundColor3 = C.row, BorderSizePixel = 0, LayoutOrder = 1}, wrap) corner(r, 7) new("TextLabel", { Size = UDim2.new(1, -150, 1, 0), Position = UDim2.fromOffset(12, 0), BackgroundTransparency = 1, Text = labelText, TextColor3 = C.text, Font = Enum.Font.Gotham, TextSize = 12, TextXAlignment = Enum.TextXAlignment.Left, }, r) local sw = new("Frame", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, -74, 0.5, 0), Size = UDim2.fromOffset(43, 18), BackgroundColor3 = getColor(), BorderSizePixel = 0, }, r) corner(sw, 5) local editBtn = new("TextButton", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, -10, 0.5, 0), Size = UDim2.fromOffset(55, 22), BackgroundColor3 = C.btn, Text = "EDIT", TextColor3 = RGB(200, 205, 212), Font = Enum.Font.GothamBold, TextSize = 10, AutoButtonColor = false, }, r) corner(editBtn, 6) local panel = new("Frame", { Size = UDim2.new(1, 0, 0, 0), AutomaticSize = Enum.AutomaticSize.Y, BackgroundColor3 = C.row, BorderSizePixel = 0, Visible = false, LayoutOrder = 2, }, wrap) corner(panel, 7) new("UIPadding", { PaddingTop = UDim.new(0, 8), PaddingBottom = UDim.new(0, 8), PaddingLeft = UDim.new(0, 8), PaddingRight = UDim.new(0, 8), }, panel) new("UIListLayout", {Padding = UDim.new(0, 6), SortOrder = Enum.SortOrder.LayoutOrder}, panel) local picker = makeRGBSliders(panel, page, function(c) sw.BackgroundColor3 = c end, 1) local saveBtn = new("TextButton", { Size = UDim2.new(1, 0, 0, 26), BackgroundColor3 = C.accent, Text = "SAVE", TextColor3 = WHITE, Font = Enum.Font.GothamBold, TextSize = 10, AutoButtonColor = true, LayoutOrder = 4, }, panel) corner(saveBtn, 6) local rainbowBtn = new("TextButton", { Size = UDim2.new(1, 0, 0, 26), BackgroundColor3 = C.btn, Text = "RAINBOW", TextColor3 = C.text, Font = Enum.Font.GothamBold, TextSize = 10, AutoButtonColor = true, LayoutOrder = 5, }, panel) corner(rainbowBtn, 6) local function renderRainbow() if rainbow[target] then rainbowBtn.Text = "STOP" rainbowBtn.BackgroundColor3 = C.red rainbowBtn.TextColor3 = WHITE else rainbowBtn.Text = "RAINBOW" rainbowBtn.BackgroundColor3 = C.btn rainbowBtn.TextColor3 = C.text end end local function close() panel.Visible = false editBtn.Text = "EDIT" sw.BackgroundColor3 = getColor() if closeOpenPicker == close then closeOpenPicker = nil end end editBtn.MouseButton1Click:Connect(function() if panel.Visible then close() return end if closeOpenPicker then closeOpenPicker() end closeOpenPicker = close picker.set(getColor()) sw.BackgroundColor3 = getColor() renderRainbow() panel.Visible = true editBtn.Text = "CLOSE" end) saveBtn.MouseButton1Click:Connect(function() local c = picker.get() if rainbow[target] then setRainbow(target, false) end onSave(c) panel.Visible = false editBtn.Text = "EDIT" sw.BackgroundColor3 = c if closeOpenPicker == close then closeOpenPicker = nil end end) rainbowBtn.MouseButton1Click:Connect(function() setRainbow(target, not rainbow[target]) renderRainbow() end) table.insert(ui.refreshers, function() if not panel.Visible then sw.BackgroundColor3 = getColor() end renderRainbow() end) end --------------------------------------------------------------- -- СТРАНИЦА: PRESETS (без Imba) --------------------------------------------------------------- local warnLabel = new("TextLabel", { Size = UDim2.new(1, 0, 0, 34), BackgroundColor3 = RGB(60, 28, 28), BorderSizePixel = 0, TextWrapped = true, TextColor3 = RGB(255, 170, 160), Font = Enum.Font.Gotham, TextSize = 10, Visible = false, LayoutOrder = 0, TextXAlignment = Enum.TextXAlignment.Left, }, presetsPage) corner(warnLabel, 7) new("UIPadding", {PaddingLeft = UDim.new(0, 10), PaddingRight = UDim.new(0, 10)}, warnLabel) sectionTitle(presetsPage, "READY PRESETS") for _, p in ipairs(READY_PRESETS) do presetButton(presetsPage, p.name, function() applyPreset(p) end) end --------------------------------------------------------------- -- СТРАНИЦА: CUSTOMIZATION --------------------------------------------------------------- sectionTitle(customPage, "MODIFICATIONS") do local r = row(customPage, "Auto Wheelie [" .. CONFIG.WHEELIE_KEY.Name .. "]") wheelieToggleUI = makeToggle(r, false, function(on) setWheelie(on) end) end do local r = row(customPage, "Freeze Scooter [" .. (CONFIG.FREEZE_KEY.Name:gsub("^Left", "")) .. "]") freezeToggleUI = makeToggle(r, false, function(on) if not setFreeze(on) then freezeToggleUI.set(false) notify("Sit on the scooter first") end end) end local wbButton do local r = row(customPage, "Wheelie Bar") wbButton = new("TextButton", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, -10, 0.5, 0), Size = UDim2.fromOffset(55, 22), BackgroundColor3 = C.accent, BackgroundTransparency = 1, Text = "N/A", TextColor3 = C.dim, Font = Enum.Font.GothamBold, TextSize = 10, AutoButtonColor = false, BorderSizePixel = 0, }, r) corner(wbButton, 6) wbButton.MouseButton1Click:Connect(function() ensure() if #groups.WheelieBar > 0 then return end if not isRiding() then notify("Sit on the scooter to add the wheelie bar") return end if buildWheelieBar() then state.wheelieBar = true ensure() if wbButtonUpdate then wbButtonUpdate() end notify("Wheelie bar added") end end) end wbButtonUpdate = function() if not wbButton then return end if #groups.WheelieBar > 0 then wbButton.Text = "DONE" wbButton.BackgroundTransparency = 1 wbButton.TextColor3 = C.text elseif riding then wbButton.Text = "ADD" wbButton.BackgroundTransparency = 0 wbButton.BackgroundColor3 = C.accent wbButton.TextColor3 = WHITE else wbButton.Text = "N/A" wbButton.BackgroundTransparency = 1 wbButton.TextColor3 = C.dim end end do local r = row(customPage, "Light Trail") local t = makeToggle(r, state.trail, function(on) state.trail = on buildTrail() end) table.insert(ui.refreshers, function() t.set(state.trail) end) end do local r = row(customPage, "Rainbow Kukirin G4") local t = makeToggle(r, false, function(on) setRainbow("All", on) end) table.insert(ui.refreshers, function() t.set(rainbow.All == true) end) end local function colorOf(target) return savedColor(target) or (target == "Smoke" and WHITE) or groupDisplayColor(target) end local function saveColor(target, c) if target == "Trail" then state.trailColor = c if trail.obj then trail.obj.Color = ColorSequence.new(c) end elseif target == "Underglow" then state.glowColor = c setGlowColorRaw(c) elseif target == "Smoke" then state.smokeColor = c setSmokeColor(c) else state.colors[target] = c for _, p in ipairs(groups[target] or {}) do enforcePart(p) end end end local COLOR_ROWS = { {"Trail Color", "Trail"}, {"Suspension Color", "Suspension"}, {"Handlebar Color", "Handlebar"}, {"Wheelie Bar Color", "WheelieBar"}, {"Burnout Smoke Color", "Smoke"}, } for _, cr in ipairs(COLOR_ROWS) do local target = cr[2] colorRow(customPage, customPage, cr[1], target, function() return colorOf(target) end, function(c) saveColor(target, c) end) end --------------------------------------------------------------- -- СТРАНИЦА: UNDERGLOW --------------------------------------------------------------- sectionTitle(glowPage, "UNDERGLOW LIGHTING") do local r = row(glowPage, "Underglow State") local t = makeToggle(r, state.underglow, function(on) state.underglow = on buildGlow() end) table.insert(ui.refreshers, function() t.set(state.underglow) end) end colorRow(glowPage, glowPage, "Underglow Color", "Underglow", function() return state.glowColor end, function(c) saveColor("Underglow", c) end) --------------------------------------------------------------- -- СТРАНИЦА: TEST (детали самоката) --------------------------------------------------------------- do -- Test page local testRows = {} -- [путь] = {row, swatch, order, title} local testToken, testSig = 0, "" local selectedKey = nil sectionTitle(testPage, "SCOOTER PARTS") new("TextLabel", { Size = UDim2.new(1, 0, 0, 28), BackgroundTransparency = 1, TextWrapped = true, Text = "Click a part: it lights up on the scooter and you can change its color live.", TextColor3 = C.dim, Font = Enum.Font.Gotham, TextSize = 10, TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top, LayoutOrder = bump(testPage), }, testPage) local testSearch = textBox(testPage, { Size = UDim2.new(1, 0, 0, 28), PlaceholderText = "Search parts...", LayoutOrder = bump(testPage), }) local testEmpty = new("TextLabel", { Size = UDim2.new(1, 0, 0, 30), BackgroundTransparency = 1, TextWrapped = true, Visible = false, Text = "No parts found. Make sure the scooter exists in workspace.", TextColor3 = RGB(255, 170, 160), Font = Enum.Font.Gotham, TextSize = 10, TextXAlignment = Enum.TextXAlignment.Left, LayoutOrder = bump(testPage), }, testPage) local testPanel = new("Frame", { Size = UDim2.new(1, 0, 0, 0), AutomaticSize = Enum.AutomaticSize.Y, BackgroundColor3 = C.rowHi, BorderSizePixel = 0, Visible = false, LayoutOrder = 100000, }, testPage) corner(testPanel, 7) new("UIPadding", { PaddingTop = UDim.new(0, 8), PaddingBottom = UDim.new(0, 8), PaddingLeft = UDim.new(0, 8), PaddingRight = UDim.new(0, 8), }, testPanel) new("UIListLayout", {Padding = UDim.new(0, 6), SortOrder = Enum.SortOrder.LayoutOrder}, testPanel) local testTitle = new("TextLabel", { Size = UDim2.new(1, 0, 0, 16), BackgroundTransparency = 1, Text = "", TextColor3 = C.text, Font = Enum.Font.GothamBold, TextSize = 11, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, LayoutOrder = 1, }, testPanel) local function currentKeyColor(key) local c = state.partColors[key] if c then return c end local list = partsByKey[key] local p = list and list[1] return p and p.Color or WHITE end local testPicker = makeRGBSliders(testPanel, testPage, function(c) if not selectedKey then return end state.partColors[selectedKey] = c for _, p in ipairs(partsByKey[selectedKey] or {}) do enforcePart(p) end local r = testRows[selectedKey] if r then r.swatch.BackgroundColor3 = c end end, 2) local testBtns = new("Frame", {Size = UDim2.new(1, 0, 0, 26), BackgroundTransparency = 1, LayoutOrder = 6}, testPanel) local resetBtn = new("TextButton", { Size = UDim2.new(0.5, -3, 1, 0), BackgroundColor3 = C.btn, Text = "RESET", TextColor3 = C.text, Font = Enum.Font.GothamBold, TextSize = 10, AutoButtonColor = true, BorderSizePixel = 0, }, testBtns) corner(resetBtn, 6) local closePanelBtn = new("TextButton", { Position = UDim2.new(0.5, 3, 0, 0), Size = UDim2.new(0.5, -3, 1, 0), BackgroundColor3 = C.accent, Text = "CLOSE", TextColor3 = WHITE, Font = Enum.Font.GothamBold, TextSize = 10, AutoButtonColor = true, BorderSizePixel = 0, }, testBtns) corner(closePanelBtn, 6) closeTestPanel = function() selectedKey = nil testPanel.Visible = false clearHighlight() end local function selectKey(key) local r = testRows[key] if not r then return end if selectedKey == key then closeTestPanel() return end selectedKey = key testPanel.LayoutOrder = r.order + 1 testTitle.Text = r.title testPicker.set(currentKeyColor(key)) testPanel.Visible = true highlightKey(key) end resetBtn.MouseButton1Click:Connect(function() if not selectedKey then return end state.partColors[selectedKey] = nil repaintAll() local c = currentKeyColor(selectedKey) testPicker.set(c) local r = testRows[selectedKey] if r then r.swatch.BackgroundColor3 = c end end) closePanelBtn.MouseButton1Click:Connect(function() closeTestPanel() end) local function applyFilter() local q = testSearch.Text:lower() for key, r in pairs(testRows) do r.row.Visible = (q == "" or key:lower():find(q, 1, true) ~= nil) end if selectedKey and testRows[selectedKey] and not testRows[selectedKey].row.Visible then closeTestPanel() end end testSearch:GetPropertyChangedSignal("Text"):Connect(applyFilter) refreshTestList = function(force) ensure() local sig = #keyList .. ":" .. #allParts if not force and sig == testSig then return end testSig = sig testToken += 1 local token = testToken local keepSel = selectedKey closeTestPanel() for _, r in pairs(testRows) do r.row:Destroy() end testRows = {} testEmpty.Visible = (#keyList == 0) local keys = keyList task.spawn(function() for i, key in ipairs(keys) do if token ~= testToken then return end local list = partsByKey[key] if list and #list > 0 then local leaf = key:match("([^/]+)$") or key local title = leaf .. (#list > 1 and (" x" .. #list) or "") local grp = partGroupOf[list[1]] or "no group" local order = 100 + i * 2 local b = new("TextButton", { Size = UDim2.new(1, 0, 0, 38), BackgroundColor3 = C.row, Text = "", AutoButtonColor = false, BorderSizePixel = 0, LayoutOrder = order, }, testPage) corner(b, 7) new("TextLabel", { Position = UDim2.fromOffset(12, 3), Size = UDim2.new(1, -70, 0, 18), BackgroundTransparency = 1, Text = title, TextColor3 = C.text, Font = Enum.Font.Gotham, TextSize = 12, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, }, b) new("TextLabel", { Position = UDim2.fromOffset(12, 21), Size = UDim2.new(1, -70, 0, 13), BackgroundTransparency = 1, Text = grp .. " · " .. key, TextColor3 = C.dim, Font = Enum.Font.Gotham, TextSize = 9, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, }, b) local sw = new("Frame", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, -10, 0.5, 0), Size = UDim2.fromOffset(40, 16), BackgroundColor3 = currentKeyColor(key), BorderSizePixel = 0, }, b) corner(sw, 5) b.MouseEnter:Connect(function() b.BackgroundColor3 = C.rowHi end) b.MouseLeave:Connect(function() b.BackgroundColor3 = C.row end) b.MouseButton1Click:Connect(function() selectKey(key) end) testRows[key] = {row = b, swatch = sw, order = order, title = title} end if i % 15 == 0 then task.wait() end end if token == testToken then applyFilter() if keepSel and testRows[keepSel] then selectKey(keepSel) end end end) end end -- Test page --------------------------------------------------------------- -- СТРАНИЦА: TEST2 (PUBLIC / PRIVATE пресеты + Cloud key) --------------------------------------------------------------- do -- Test2 page local privatePresets = {} local FILE = "GIGAMENU_presets.json" local function savePrivate() if typeof(writefile) ~= "function" then return end pcall(function() writefile(FILE, HttpService:JSONEncode(privatePresets)) end) end local function loadPrivate() if typeof(isfile) ~= "function" or typeof(readfile) ~= "function" then return end local ok, data = pcall(function() if isfile(FILE) then return HttpService:JSONDecode(readfile(FILE)) end return nil end) if ok and type(data) == "table" then for _, e in ipairs(data) do if type(e) == "table" and type(e.name) == "string" and type(e.data) == "table" then table.insert(privatePresets, e) end end end end loadPrivate() -- строка пресета: название слева, кнопки справа. actions = {{текст, ширина, функция, фон?, цвет текста?}, ...} local function presetRow(parent, title, actions) local r = new("Frame", {Size = UDim2.new(1, 0, 0, 38), BackgroundColor3 = C.row, BorderSizePixel = 0, LayoutOrder = bump(parent)}, parent) corner(r, 7) local x, total = -8, 0 for i = #actions, 1, -1 do local a = actions[i] local b = new("TextButton", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, x, 0.5, 0), Size = UDim2.fromOffset(a[2], 22), BackgroundColor3 = a[4] or C.btn, Text = a[1], TextColor3 = a[5] or C.text, Font = Enum.Font.GothamBold, TextSize = 10, AutoButtonColor = true, BorderSizePixel = 0, }, r) corner(b, 6) b.MouseButton1Click:Connect(a[3]) x = x - a[2] - 4 total = total + a[2] + 4 end new("TextLabel", { Size = UDim2.new(1, -(total + 20), 1, 0), Position = UDim2.fromOffset(12, 0), BackgroundTransparency = 1, Text = title, TextColor3 = C.text, Font = Enum.Font.Gotham, TextSize = 12, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, }, r) return r end local keyBox -- создаётся ниже local function showKey(key, name) if not key then notify("Could not build the key") return end keyBox.Text = key if typeof(setclipboard) == "function" then pcall(setclipboard, key) notify("Key copied: " .. name) else notify("Key is in the box below: select it and press Ctrl+C") end pcall(function() keyBox:CaptureFocus() task.defer(function() keyBox.SelectionStart = 1 keyBox.CursorPosition = #keyBox.Text + 1 end) end) end -- PUBLIC: общие (готовые) пресеты sectionTitle(test2Page, "PUBLIC PRESETS") for _, p in ipairs(READY_PRESETS) do if p.kind == "classic" then presetRow(test2Page, p.name, { {"APPLY", 52, function() applyPreset(p) notify("Applied: " .. p.name) end, C.accent, WHITE}, {"KEY", 38, function() showKey(encodeKey(classicToData(p)), p.name) end}, }) end end -- PRIVATE: свои пресеты sectionTitle(test2Page, "PRIVATE PRESETS") local nameBox = textBox(test2Page, {Size = UDim2.new(1, -78, 0, 28), PlaceholderText = "Name for current look..."}) local saveRow = new("Frame", {Size = UDim2.new(1, 0, 0, 28), BackgroundTransparency = 1, LayoutOrder = bump(test2Page)}, test2Page) nameBox.Parent = saveRow local saveNowBtn = new("TextButton", { AnchorPoint = Vector2.new(1, 0), Position = UDim2.new(1, 0, 0, 0), Size = UDim2.fromOffset(72, 28), BackgroundColor3 = C.accent, Text = "SAVE", TextColor3 = WHITE, Font = Enum.Font.GothamBold, TextSize = 10, AutoButtonColor = true, BorderSizePixel = 0, }, saveRow) corner(saveNowBtn, 6) local privHolder = new("Frame", { Size = UDim2.new(1, 0, 0, 0), AutomaticSize = Enum.AutomaticSize.Y, BackgroundTransparency = 1, LayoutOrder = bump(test2Page), }, test2Page) new("UIListLayout", {Padding = UDim.new(0, 6), SortOrder = Enum.SortOrder.LayoutOrder}, privHolder) local rebuildPrivate rebuildPrivate = function() for _, ch in ipairs(privHolder:GetChildren()) do if not ch:IsA("UIListLayout") then ch:Destroy() end end counters[privHolder] = 0 if #privatePresets == 0 then new("TextLabel", { Size = UDim2.new(1, 0, 0, 24), BackgroundTransparency = 1, Text = "No private presets yet.", TextColor3 = C.dim, Font = Enum.Font.Gotham, TextSize = 10, TextXAlignment = Enum.TextXAlignment.Left, LayoutOrder = bump(privHolder), }, privHolder) return end for i, e in ipairs(privatePresets) do presetRow(privHolder, e.name, { {"APPLY", 52, function() applyData(e.data) notify("Applied: " .. e.name) end, C.accent, WHITE}, {"KEY", 38, function() showKey(encodeKey(e.data), e.name) end}, {"X", 26, function() table.remove(privatePresets, i) savePrivate() rebuildPrivate() end, C.red, WHITE}, }) end end rebuildPrivate() saveNowBtn.MouseButton1Click:Connect(function() local name = trim(nameBox.Text):sub(1, 24) if name == "" then name = "Preset " .. (#privatePresets + 1) end table.insert(privatePresets, {name = name, data = captureData(name)}) savePrivate() rebuildPrivate() nameBox.Text = "" notify("Saved: " .. name) end) -- CLOUD KEY: импорт / экспорт sectionTitle(test2Page, "CLOUD KEY") local importRow = new("Frame", {Size = UDim2.new(1, 0, 0, 28), BackgroundTransparency = 1, LayoutOrder = bump(test2Page)}, test2Page) local importBox = textBox(importRow, {Size = UDim2.new(1, -78, 1, 0), PlaceholderText = "Paste a Cloud key here..."}) local importBtn = new("TextButton", { AnchorPoint = Vector2.new(1, 0), Position = UDim2.new(1, 0, 0, 0), Size = UDim2.fromOffset(72, 28), BackgroundColor3 = C.accent, Text = "IMPORT", TextColor3 = WHITE, Font = Enum.Font.GothamBold, TextSize = 10, AutoButtonColor = true, BorderSizePixel = 0, }, importRow) corner(importBtn, 6) keyBox = textBox(test2Page, { Size = UDim2.new(1, 0, 0, 28), PlaceholderText = "Press KEY on a preset to get its Cloud key here", LayoutOrder = bump(test2Page), }) importBtn.MouseButton1Click:Connect(function() local d, err = decodeKey(importBox.Text) if not d then notify("Invalid key: " .. tostring(err)) return end local name = (type(d.n) == "string" and trim(d.n) ~= "") and trim(d.n):sub(1, 24) or "Imported" applyData(d) table.insert(privatePresets, {name = name, data = captureData(name)}) savePrivate() rebuildPrivate() importBox.Text = "" notify("Imported: " .. name) end) end -- Test2 page --------------------------------------------------------------- -- статус (показывается только если что-то не так) + кнопка Wheelie Bar --------------------------------------------------------------- updateStatus = function() local txt if not scooter then txt = 'Самокат не найден: workspace["' .. CONFIG.SCOOTER_NAME .. '"]. Проверь CONFIG.SCOOTER_NAME.' else local total = 0 for _, g in ipairs(GROUP_ORDER) do total = total + #groups[g] end if total == 0 then txt = "Детали самоката не распознаны — смотри Output (F9), впиши имена в PART_NAMES." end end warnLabel.Visible = (txt ~= nil) if txt then warnLabel.Text = txt end if wbButtonUpdate then wbButtonUpdate() end end updateStatus() --------------------------------------------------------------- -- ВВОД: F = вилли, Shift = заморозка, RightShift = меню --------------------------------------------------------------- connect(UIS.InputBegan, function(input, processed) if processed then return end if input.UserInputType ~= Enum.UserInputType.Keyboard then return end if input.KeyCode == CONFIG.MENU_KEY then setMenuVisible(not main.Visible) elseif input.KeyCode == CONFIG.WHEELIE_KEY then if CONFIG.WHEELIE_HOLD then setWheelie(true) else setWheelie(not wheelie.on) end elseif input.KeyCode == CONFIG.FREEZE_KEY then if setFreeze(not freeze.on) then notify(freeze.on and "Scooter frozen" or "Scooter unfrozen") else notify("Sit on the scooter first") end end end) connect(UIS.InputEnded, function(input) if CONFIG.WHEELIE_HOLD and input.UserInputType == Enum.UserInputType.Keyboard and input.KeyCode == CONFIG.WHEELIE_KEY then setWheelie(false) end end) --------------------------------------------------------------- -- СТАРТ --------------------------------------------------------------- showPage("Presets") warn("[GIGAMENU v2.0] loaded — by zyru | " .. CONFIG.WHEELIE_KEY.Name .. " = wheelie, " .. CONFIG.FREEZE_KEY.Name .. " = freeze, " .. CONFIG.MENU_KEY.Name .. " = menu")