UI/SplashScreen.razor

A UI component for a splash screen written as a Razor PanelComponent. It displays an optional background image and logo, renders configurable text lines with color and font size, plays an optional sound, runs timed delays to fade out, and then loads a configured scene file.

File Access
@using Sandbox;
@using Sandbox.UI;
@using System.Threading.Tasks;
@using System.Collections.Generic;
@using System;
@inherits PanelComponent

<root class="@(IsFadingOut ? "fade-out" : "fade-in")" style="background-image: @(!string.IsNullOrEmpty(BackgroundImage) ? $"url({BackgroundImage})" : "none");">
    
    <div class="content">
        @* Logo Image (.png / .jpg) *@
        @if (!string.IsNullOrEmpty(LogoImage))
        {
            <img class="logo" src="@LogoImage" />
        }
        
        @* Text Lines *@
        @if (TextLines != null && TextLines.Count > 0)
        {
            <div class="text-container">
                @foreach (var line in TextLines)
                {
                    <label style="color: @line.TextColor.Hex; font-size: @(line.FontSize)px;">
                        @line.Text
                    </label>
                }
            </div>
        }
    </div>

</root>

@code {
    // === CUSTOM DATA CLASS FOR TEXT LINES ===
    
    public class SplashTextLine
    {
        [Property, Description("The text to display.")] 
        public string Text { get; set; } = "NEW LINE";

        [Property, Description("Text color for this specific line.")] 
        public Color TextColor { get; set; } = Color.White;

        [Property, Description("Font size for this specific line.")] 
        public float FontSize { get; set; } = 80f;
    }


    // === IMAGE SETTINGS ===
    
    [Property, ImageAssetPath, Group("Images"), Description("Supports .png and .jpg. If empty, the background will be black.")] 
    public string BackgroundImage { get; set; }

    [Property, ImageAssetPath, Group("Images"), Description("Main logo image (.png / .jpg). Appears above the text if both are set.")] 
    public string LogoImage { get; set; }


    // === TEXT SETTINGS ===

    [Property, Group("Text"), Description("Add text lines with individual settings (color, size).")]
    public List<SplashTextLine> TextLines { get; set; } = new();


    // === AUDIO & SCENE SETTINGS ===

    [Property, Group("Audio"), Description("Select a Sound Event (.sound) that contains your .mp3 or .ogg file.")] 
    public SoundEvent SplashSound { get; set; }

    [Property, Group("Scene"), Description("The scene to load after the splash screen finishes.")] 
    public SceneFile NextScene { get; set; }


    // === LOGIC ===
    
    public bool IsFadingOut { get; set; } = false;

    protected override void OnStart()
    {
        base.OnStart();
        
        // Start the asynchronous sequence
        _ = RunSplashSequence();
    }

    private async Task RunSplashSequence()
    {
        // 1. Wait half a second before starting to avoid stuttering during load
        await Task.Delay(500);

        // 2. Play the assigned sound (.mp3 / .ogg via Sound Event)
        if (SplashSound != null)
        {
            Sound.Play(SplashSound);
        }

        // 3. Wait while the logo/text is visible on the screen (3 seconds)
        await Task.Delay(3000);

        // 4. Trigger the fade-out animation
        IsFadingOut = true;
        StateHasChanged(); // Notify the UI to update CSS classes

        // 5. Wait for the fade-out animation to finish (matches the CSS transition time)
        await Task.Delay(2000);

        // 6. Load the next scene
        if (NextScene != null)
        {
            Scene.Load(NextScene);
        }
        else
        {
            Log.Warning("Next Scene is not assigned in the Splash Screen component!");
            GameObject.Destroy(); // Destroy the component if no scene is assigned
        }
    }
}