Skip to main content
Skip table of contents

Iframe Stages

This document explains how to customize the loading screens, UI behavior, and communication flow when embedding an Unreal Engine Pixel Streaming application using the Eagle 3D Streaming (E3DS) iframe integration.

By following this guide, you will understand:

  • How to customize loading screens at different connection stages

  • The purpose of each iframe connection stage

  • Which UI elements can be customized per stage

  • When webpage-to-Unreal Engine communication becomes available

Follow the guide below:

Stage 1. In Queue (stage1_inqueued)

Triggered when the user enters the queue to connect to the app.

CODE
case "stage1_inqueued":
    //add your code here
    break;

Purpose: Show the first loading screen.

You can customize: Queue waiting screen (spinner, estimated wait time, branding).

Stage 2. De-Queued (stage2_deQueued)

Triggered when the user leaves the queue and is about to start app preparation.

CODE
case "stage2_deQueued":
    // loading screen 1 hides
    break;

Purpose: End the queue loading UI.

You can customize: Transition animation from queue to loading phase.

Stage 3. Slot Occupied (stage3_slotOccupied)

Triggered when the server has reserved a slot for the user’s app session.

CODE
case "stage3_slotOccupied":
    // add your code here
    break;

Purpose: Hide queue UI and show app loading UI.

You can customize: Loading animation, progress bar, status messages.

Stage 4. Play Button Showed Up (stage4_playBtnShowedUp)

Triggered when the play button is available to start the Pixel Streaming session.

CODE
case "stage4_playBtnShowedUp":
    loaderStep2.style.visibility = "hidden";
    iframeElem.style.visibility = "visible";
    let playButton = document.getElementById("playButtonParent");
    playButton.click();
    onPlayBtnPressed();
    break;

Purpose: Hide loading, show iframe, automatically click play.

You can customize: Play screen, confirmation message before starting.

Stage 5. Play Button Pressed (stage5_playBtnPressed)

Triggered after the play button is pressed — the app is now running and interactive.

CODE
case "stage5_playBtnPressed":
    sidebar.style.visibility = "visible";
    loaderStep2.style.display = "none";
    iframeElem.style.visibility = "visible";
    $('#iframe_1').focus();
    break;

Purpose: Show sidebar and make iframe interactive.

Important: Only after this stage, you can start sending data from the webpage to the Unreal Engine app.

Other Events

  • ResponseFromUE4 → Receives messages from Unreal Engine. (Triggered whenever UE app sends data to webpage.)

  • QueueNumberUpdated →Shows updated queue position. (E.g., from position 4 → 3 → 2 → 1.)

  • stage3_1_AppAcquiringProgress → Shows download progress (only triggered if the app is not yet downloaded on the streamer machine).

  • stage3_2_AppPreparationProgress → Shows preparation progress (only triggered if the app is being extracted on the streamer machine).

  • isIframe → Sends confirmation that this is inside an iframe.

  • shortCuts → Logs key press shortcuts.

  • Error_Redirect → Handles errors and focuses iframe.

Check the complete message.js implementation for a full working example here: https://github.com/e3ds/E3DS-Iframe-Demo/blob/main/js/message.js

Full Code Example:

CODE
const messageHandler = (event) => {
    const loaderStep1 = document.getElementById("loaderStep1");
    const loaderStep2 = document.getElementById("loaderStep2");
    const loaderStep3 = document.getElementById("loaderStep3");
    const iframeElem = document.getElementById("iframe_1");
    const sidebar = document.getElementById("sidebar");

    console.log("received data event type " + event.data.type);
    switch (event.data.type) {
        case "ResponseFromUE4":
            console.log("UE4->iframe: " + event.data.descriptor);
            myHandleResponseFunction(event.data.descriptor);
            break;

        case "stage1_inqueued":
            loaderStep1.style.visibility = "visible";
            break;

        case "stage2_deQueued":
            // loading screen 1 hides
            break;

        case "stage3_slotOccupied":
            loaderStep1.style.display = "none";
            loaderStep2.style.visibility = "visible";
            break;

        case "stage4_playBtnShowedUp":
            loaderStep2.style.visibility = "hidden";
            iframeElem.style.visibility = "visible";
            let playButton = document.getElementById("playButtonParent");
            playButton.click();
            onPlayBtnPressed();
            break;

        case "stage5_playBtnPressed":
            sidebar.style.visibility = "visible";
            loaderStep2.style.display = "none";
            iframeElem.style.visibility = "visible";
            $('#iframe_1').focus();
            break;

        case "_focus":
            document.getElementById("iframe_1").focus();
            break;

        case "isIframe":
            let obj = { cmd: 'isIframe', value: true };
            document.getElementById("iframe_1").focus();
            document.getElementById("iframe_1").contentWindow.postMessage(JSON.stringify(obj), "*");
            break;

        case "QueueNumberUpdated":
            console.log("QueueNumberUpdated. New queuePosition: " + event.data.queuePosition);
            break;

        case "stage3_1_AppAcquiringProgress":
            console.log("stage3_1_AppAcquiringProgress percent: " + JSON.stringify(event.data.percent));
            break;

        case "stage3_2_AppPreparationProgress":
            console.log("stage3_2_AppPreparationProgress percent: " + JSON.stringify(event.data.percent));
            break;

        case "shortCuts":
            console.log("Key pressed");
            break;

        case "Error_Redirect":
            loaderStep2.style.display = "none";
            iframeElem.style.visibility = "visible";
            $('#iframe_1').focus();
            break;

        default:
            console.error("Unhandled message data type");
            break;
    }
};


Need help?

🛠️ Contact our Support Team

💬 Join the Community on Discord

🆓 Get Started for free

 

Follow us on:

Facebook | GitHub | LinkedIn | YouTube

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.