LoadingScreen.client.luau
Luau, 77 lines from UI overview
--!strict
-- LoadingScreen (LocalScript in ReplicatedFirst). Runs before anything else replicates.
-- Shows the game's own title card instead of Roblox's default, follows a REAL load stage set by
-- the main client script, and always gets out of the way (safety timeout) so a client error can't
-- trap the player behind it.
--
-- Contract with the main client script:
-- Players.LocalPlayer:SetAttribute("LoadStage", 0..1) -- as each boot step finishes
-- Players.LocalPlayer:SetAttribute("ClientReady", true) -- when the HUD is live
-- Players.LocalPlayer:SetAttribute("IntroWillPlay", true) -- optional: first join, intro next
local ReplicatedFirst = game:GetService("ReplicatedFirst")
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local SAFETY_TIMEOUT = 75
ReplicatedFirst:RemoveDefaultLoadingScreen()
local player = Players.LocalPlayer
local gui = script:WaitForChild("LoadingGui"):Clone() :: ScreenGui -- approved title card, built from HTML
gui.IgnoreGuiInset = true
gui.DisplayOrder = 1000
gui.ResetOnSpawn = false
gui.Parent = player:WaitForChild("PlayerGui")
local fill = gui:FindFirstChild("Fill", true) :: Frame
local status = gui:FindFirstChild("Status", true) :: TextLabel?
local function setStage(v: number)
TweenService:Create(fill, TweenInfo.new(0.3), { Size = UDim2.fromScale(math.clamp(v, 0.05, 1), 1) }):Play()
end
player:GetAttributeChangedSignal("LoadStage"):Connect(function()
setStage(player:GetAttribute("LoadStage") or 0)
end)
setStage(player:GetAttribute("LoadStage") or 0)
if status then status.Text = "Loading..." end
local closed = false
local function close()
if closed then return end
closed = true
setStage(1)
task.wait(0.25)
if player:GetAttribute("IntroWillPlay") then
-- the intro starts on this same title card: hand over without a fade, no flash between them
gui:Destroy()
return
end
for _, d in gui:GetDescendants() do
if d:IsA("GuiObject") then
TweenService:Create(d, TweenInfo.new(0.5), { BackgroundTransparency = 1 }):Play()
end
if d:IsA("TextLabel") then
TweenService:Create(d, TweenInfo.new(0.5), { TextTransparency = 1 }):Play()
elseif d:IsA("ImageLabel") then
TweenService:Create(d, TweenInfo.new(0.5), { ImageTransparency = 1 }):Play()
end
end
task.delay(0.55, function() gui:Destroy() end)
end
if player:GetAttribute("ClientReady") then
close()
else
player:GetAttributeChangedSignal("ClientReady"):Connect(function()
if player:GetAttribute("ClientReady") then close() end
end)
end
task.delay(SAFETY_TIMEOUT, function()
if not closed then
warn("LoadingScreen: safety timeout, ClientReady never arrived")
close()
end
end)