Join the RoClicks Discord
RoClicks

LoadingScreen.client.luau

Luau, 77 lines from UI overview

Download LoadingScreen.client.luau
--!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)