Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Splash image support and new progress bar for HTML5 Web Export #91128

Merged
merged 1 commit into from
Apr 30, 2024

Conversation

patwork
Copy link
Contributor

@patwork patwork commented Apr 25, 2024

Intro

With the increasing popularity of the Godot engine, more and more users are reaching for it, often trying their hand at creating small games during organized compo/jams. Due to the nature of such events, the preferred export type for their production is HTML5.

So far, it's the only export that hasn't supported the ability to display a splash image when the game loads, despite the fact that the image is included in the saved project. The user has the option to create a custom HTML template, but for small games basically no one does this, relying on the engine's default settings.

That being said, I would like to propose an upgrade to the default HTML Shell used by Export to Web.

Goals

  1. Display splash image (Godot or user-selected) when loading game files in the browser. This required exposing a new constant $GODOT_SPLASH from /platform/web/export/export_plugin.cpp.

  2. Minor HTML, CSS and JS optimization to better handle the game loading status overlay.

  3. Unify the progress bar by using a <progress> element that supports both percentage progress and indeterminate mode display. Browser support

Demo

Loading example game:

loading-game

Loading in landscape mode:

loading-landscape

Loading in portrait mode:

loading-portrait

Error dialog:

error-status

Changes in HTML

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
        <title>$GODOT_PROJECT_NAME</title>
        <style>
/* styles... */
        </style>
        $GODOT_HEAD_INCLUDE
    </head>
    <body>
        <canvas id="canvas">
            Your browser does not support the canvas tag.
        </canvas>

        <noscript>
            Your browser does not support JavaScript.
        </noscript>

        <div id="status">
            <img id="status-splash" src="$GODOT_SPLASH" alt="">
            <progress id="status-progress"></progress>
            <div id="status-notice"></div>
        </div>

        <script src="$GODOT_URL"></script>
        <script>
/* script... */
        </script>
    </body>
</html>
  1. A warning has been added when JavaScript in the browser is disabled.

  2. The “status” div has been greatly simplified.

  3. An <img> tag has been added to display the splash image.

  4. HTML5 <progress> tag has been added in place of the custom created progress bar and spinning wheel.

Changes in CSS

html, body, #canvas {
    margin: 0;
    padding: 0;
    border: 0;
}

body {
    color: white;
    background-color: black;
    overflow: hidden;
    touch-action: none;
}

#canvas {
    display: block;
}

#canvas:focus {
    outline: none;
}

#status, #status-splash, #status-progress {
    position: absolute;
    left: 0;
    right: 0;
}

#status, #status-splash {
    top: 0;
    bottom: 0;
}

#status {
    background-color: #38363A;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    visibility: hidden;
}

#status-splash {
    max-height: 100%;
    max-width: 100%;
    margin: auto;
}

#status-progress, #status-notice {
    display: none;
}

#status-progress {
    bottom: 10%;
    width: 50%;
    margin: 0 auto;
}

#status-notice {
    background-color: #5b3943;
    border-radius: 0.5rem;
    border: 1px solid #9b3943;
    color: #e0e0e0;
    font-family: 'Noto Sans', 'Droid Sans', Arial, sans-serif;
    line-height: 1.3;
    margin: 0 2rem;
    overflow: hidden;
    padding: 1rem;
    text-align: center;
    z-index: 1;
}
  1. Common settings for elements are set together.

  2. The #status overlay is made invisible at first by visibility: hidden, so it doesn't obscure a possible error message about Javascript not being supported.

  3. Splash image is centered on viewport and responsive up to 100% horizontally and vertically.

  4. The progress bar displays over the splash image at 10% of the viepower height from the bottom.

  5. The background color of the error message has been changed to a more reddish.

Javascript

    const statusOverlay = document.getElementById('status');
    const statusProgress = document.getElementById('status-progress');
    const statusNotice = document.getElementById('status-notice');

    let initializing = true;
    let statusMode = '';

    function setStatusMode(mode) {
        if (statusMode === mode || !initializing) {
            return;
        }
        if (mode === 'hidden') {
            statusOverlay.remove();
            initializing = false;
            return;
        }
        statusOverlay.style.visibility = 'visible';
        statusProgress.style.display = mode === 'progress' ? 'block' : 'none';
        statusNotice.style.display = mode === 'notice' ? 'block' : 'none';
        statusMode = mode;
    }

    /* ... */

            'onProgress': function (current, total) {
                if (current > 0 && total > 0) {
                    statusProgress.value = current;
                    statusProgress.max = total;
                } else {
                    statusProgress.removeAttribute('value');
                    statusProgress.removeAttribute('max');
                }
            },
  1. Added reference to #status and removed references to #statusProgressInner and #statusIndeterminate

  2. Changed startup statusMode in case onProgress is never called before setStatusMode('hidden')

  3. Removed manual animation of the spinning wheel.

  4. Simplified setStatusMode removes the #status block completely when the status is changed to 'hidden' after loading the game.

  5. Simplified onProgress using the capabilities of the HTML5 <progress> element (when value and max are removed, the browser automatically displays a bounce animation).

export_plugin.cpp

    replaces["$GODOT_URL"] = p_name + ".js";

    /* ... */

+   replaces["$GODOT_SPLASH"] = p_name + ".png";        
    
    /* ... */
    
    Ref<Image> splash = _get_project_splash();
    const String splash_png_path = base_path + ".png";  
  1. The path to GODOT_SPLASH is created on the same basis as the path to the main Javascript file. The png extension is due to a piece of code that generates the image during export.

@@ -170,6 +170,7 @@ void EditorExportPlatformWeb::_fix_html(Vector<uint8_t> &p_html, const Ref<Edito
replaces["$GODOT_PROJECT_NAME"] = GLOBAL_GET("application/config/name");
replaces["$GODOT_HEAD_INCLUDE"] = head_include + custom_head_include;
replaces["$GODOT_CONFIG"] = str_config;
replaces["$GODOT_SPLASH"] = p_name + ".png";
Copy link
Member

@Calinou Calinou Apr 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a future PR, we could have Godot write a lossless WebP instead of PNG as it'll have a smaller file size. The downside is that WebP can't be used as an Open Graph image, but we don't define the splash as an Open Graph image right now (perhaps we could).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Calinou Usually, games aren't shared directly by the player link, so it's not that bad.

Copy link
Collaborator

@Faless Faless left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work! 💙

The only comment I have, is that between this change, and the change in #85939 we are again starting to add more and more substitution variables to the template, which is something we tried to avoid since #46200 .

That said, I don't think this is a blocker for the PR given it won't break the existing templates (that substitution is "optional").

Again, this looks fantastic, so I think it's worth merging as is!

@adamscott adamscott self-assigned this Apr 29, 2024
Copy link
Member

@adamscott adamscott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great PR, thanks!

@akien-mga akien-mga merged commit b1da4b2 into godotengine:master Apr 30, 2024
16 checks passed
@akien-mga
Copy link
Member

Thanks! And congrats for your first merged Godot contribution 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants