--!strict -- NEO PORTFOLIO SOURCE SAMPLE / ROBLOX STUDIO TEST REQUIRED -- Place as a LocalScript in StarterPlayer > StarterPlayerScripts. -- Requires MapVoting.server.luau in ServerScriptService. -- UI is generated by code, no imported assets needed. local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local player = Players.LocalPlayer local sendVote = ReplicatedStorage:WaitForChild("NeoMapVoteAction") :: RemoteEvent local stateEvent = ReplicatedStorage:WaitForChild("NeoMapVoteState") :: RemoteEvent local snapshot = ReplicatedStorage:WaitForChild("NeoMapVoteSnapshot") :: RemoteFunction local MAP_NAMES = {"Neon City", "Sky Islands", "Frost Base"} local ACCENT = Color3.fromRGB(192, 175, 255) local BG = Color3.fromRGB(29, 26, 49) local MUTED = Color3.fromRGB(168, 160, 195) local function rounded(parent: Instance, pixels: number) local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, pixels) corner.Parent = parent end local gui = Instance.new("ScreenGui") gui.Name = "NeoPortfolioMapVoting" gui.ResetOnSpawn = false gui.Parent = player:WaitForChild("PlayerGui") local root = Instance.new("Frame") root.Name = "VotingPanel" root.AnchorPoint = Vector2.new(0.5, 0.5) root.Position = UDim2.fromScale(0.5, 0.5) root.Size = UDim2.fromOffset(510, 305) root.BackgroundColor3 = BG root.BorderSizePixel = 0 root.Parent = gui rounded(root, 16) local frameStroke = Instance.new("UIStroke") frameStroke.Color = Color3.fromRGB(104, 91, 145) frameStroke.Parent = root local layout = Instance.new("UIListLayout") layout.SortOrder = Enum.SortOrder.LayoutOrder layout.Padding = UDim.new(0, 13) layout.Parent = root local padding = Instance.new("UIPadding") padding.PaddingLeft = UDim.new(0, 22) padding.PaddingRight = UDim.new(0, 22) padding.PaddingTop = UDim.new(0, 21) padding.PaddingBottom = UDim.new(0, 20) padding.Parent = root local function textLabel(value: string, height: number, order: number, size: number, color: Color3): TextLabel local label = Instance.new("TextLabel") label.BackgroundTransparency = 1 label.Size = UDim2.new(1, 0, 0, height) label.Text = value label.TextColor3 = color label.TextSize = size label.TextXAlignment = Enum.TextXAlignment.Left label.Font = Enum.Font.Gotham label.LayoutOrder = order label.Parent = root return label end local eyebrow = textLabel("NEO / MAP VOTING", 19, 1, 11, ACCENT) eyebrow.Font = Enum.Font.GothamBold local title = textLabel("Choose the next arena", 34, 2, 24, Color3.fromRGB(245, 241, 255)) title.Font = Enum.Font.GothamBold local countdown = textLabel("Loading state...", 20, 3, 13, MUTED) local holder = Instance.new("Frame") holder.BackgroundTransparency = 1 holder.Size = UDim2.new(1, 0, 0, 97) holder.LayoutOrder = 4 holder.Parent = root local row = Instance.new("UIListLayout") row.FillDirection = Enum.FillDirection.Horizontal row.Padding = UDim.new(0, 9) row.Parent = holder local buttons: {[string]: TextButton} = {} for _, name in MAP_NAMES do local button = Instance.new("TextButton") button.Name = name button.Size = UDim2.new(1/3, -6, 1, 0) button.BackgroundColor3 = Color3.fromRGB(50, 45, 79) button.BorderSizePixel = 0 button.TextColor3 = Color3.fromRGB(237, 230, 255) button.TextSize = 13 button.TextWrapped = true button.Font = Enum.Font.GothamBold button.Text = name .. "\n0 votes" button.Parent = holder rounded(button, 9) buttons[name] = button button.MouseButton1Click:Connect(function() sendVote:FireServer(name) end) end local footnote = textLabel("Vote once or change your choice. Demo: no map teleporting.", 25, 5, 10, MUTED) footnote.TextWrapped = true local scale = Instance.new("UIScale") scale.Parent = root local function sizeForViewport() local camera = workspace.CurrentCamera if camera then local viewport = camera.ViewportSize scale.Scale = math.min(1, math.max(0.60, (viewport.X - 28)/510)) end end sizeForViewport() local camera = workspace.CurrentCamera if camera then camera:GetPropertyChangedSignal("ViewportSize"):Connect(sizeForViewport) end local personalSelection: string? = nil local knownRound = -1 local function render(state: any) if type(state) ~= "table" or type(state.counts) ~= "table" then return end local results = state.phase == "results" if type(state.round) == "number" and state.round ~= knownRound then knownRound = state.round personalSelection = nil end if type(state.selected) == "string" then personalSelection = state.selected end local remaining = math.max(0, tonumber(state.remaining) or 0) countdown.Text = if results then "Winning map: " .. tostring(state.winner or "Unknown") .. " • next vote in " .. remaining .. "s" else "Voting ends in " .. remaining .. "s" for _, name in MAP_NAMES do local button = buttons[name] local votes = tonumber(state.counts[name]) or 0 button.Text = name .. "\n" .. votes .. " votes" button.Active = not results button.AutoButtonColor = not results button.BackgroundColor3 = if not results and personalSelection == name then Color3.fromRGB(88, 87, 108) else Color3.fromRGB(50, 45, 79) end if results then footnote.Text = "Results are for the voting demo. Connect an arena loader separately." else footnote.Text = "Select a map. You can change your vote until voting closes." end end stateEvent.OnClientEvent:Connect(render) local ok, initial = pcall(function() return snapshot:InvokeServer() end) if ok then render(initial) else countdown.Text = "Could not load vote state" end