Working with Instant Games API and PlayCanvas Editor

How do i go about implementing the instant games api in the editor and test it ?

Currently testing it is a long process, have to download a published build and then upload it manually to facebook instant API, and once its uploaded, only then could i test api functionality. I could automate this step sure, but attaching functions to buttons is proving a bit of a headache.

The issue is not being able to test in the editor.

As the Instant Games API requires the sdk to be integrated via script markup directly from a CDN ( and not added in the project), I’ve created a script to append the HTML markup into a document.

Here is a project with my current attempt at integrating the API:
https://playcanvas.com/project/601023/overview/instant-games-api-test

Not able to even log out a console message, what am i doing wrong or is this likely not possible to integrate within the editor?

Update:

It just doesnt seem like the html is being appended to the root of the index.html file, can anyone please comment or take a look maybe im doing something wrong?

Looks like it is added to the HTML?

1 Like

This would be the way I would handle the ā€˜loadThisFirst’ callback. It still doesn’t work (FBInstant not defined) but the code does get executed compared to the current state: https://playcanvas.com/project/601453/overview/instant-games-api-test-from-foru

yes ofcourse this makes much more sense, i was going with a shoddy example. thanks @yaustar will try this out

Ah, here we go. I thought the loadAPI event was fired from the FB Instant SDK but then I realised it was from the project.

Here’s the new version that no longer has the ā€˜FBInstant not defined’ error: https://playcanvas.com/project/601453/overview/instant-games-api-test-from-foru

1 Like

thank you again.

okay so this technically works but the current problem with this is that playcanvas will load before anything else loads, which means that the instant game loading bar will not progress until playcanvas has finished in the background, ultimately this will not pass review on facebook i fear.
it would have to be the first thing that loads before playcanvas scripts/engine.

would a Loading Screen script help with this?

something like this :

/*jshint esversion:6*/
pc.script.createLoadingScreen(function (app) {
    var showSplash = function () {
       var str =  `<script src="https://connect.facebook.net/en_US/fbinstant.6.2.js"></script>
        <script type="text/javascript"> 
            window.addEventListener("loadAPI", loadThisFirst);
            function loadThisFirst() {
                FBInstant.initializeAsync().then(function() {
                    FBInstant.setLoadingProgress(100);
                    // Finished loading. Start the game
                    FBInstant.startGameAsync().then(function() {
                        startGame();          
                    });
                });
            }

            function selectContext() {
                FBInstant.context.chooseAsync()
                    .then(function() {
                    startGame();          
                });
            }

            function startGame() {
                // start game
                var game = new gameplayScene(FBInstant);
                game.start();
            }
        </script>`;
        
        var instantApiDiv = document.createElement('div');
        instantApiDiv.id = "fbInstantAPI";
        document.body.appendChild(instantApiDiv);
        instantApiDiv.innerHTML = str;
        // splash wrapper
        var wrapper = document.createElement('div');
        wrapper.id = 'application-splash-wrapper';
        document.body.appendChild(wrapper);

        // splash
        var splash = document.createElement('div');
        splash.id = 'application-splash';
        wrapper.appendChild(splash);
        splash.style.display = 'none';

        var logo = document.createElement('img');
        logo.src = 'https://s3-eu-west-1.amazonaws.com/static.playcanvas.com/images/play_text_252_white.png';
        splash.appendChild(logo);
        logo.onload = function () {
            splash.style.display = 'block';
        };

        var container = document.createElement('div');
        container.id = 'progress-bar-container';
        splash.appendChild(container);

        var bar = document.createElement('div');
        bar.id = 'progress-bar';
        container.appendChild(bar);

    };

    var hideSplash = function () {
        var splash = document.getElementById('application-splash-wrapper');
        splash.parentElement.removeChild(splash);
    };

    var setProgress = function (value) {
        var bar = document.getElementById('progress-bar');
        if(bar) {
            value = Math.min(1, Math.max(0, value));
            bar.style.width = value * 100 + '%';
        }
    };

    var createCss = function () {
        var css = [
            'body {',
            '    background-color: #283538;',
            '}',

            '#application-splash-wrapper {',
            '    position: absolute;',
            '    top: 0;',
            '    left: 0;',
            '    height: 100%;',
            '    width: 100%;',
            '    background-color: #283538;',
            '}',

            '#application-splash {',
            '    position: absolute;',
            '    top: calc(50% - 28px);',
            '    width: 264px;',
            '    left: calc(50% - 132px);',
            '}',

            '#application-splash img {',
            '    width: 100%;',
            '}',

            '#progress-bar-container {',
            '    margin: 20px auto 0 auto;',
            '    height: 2px;',
            '    width: 100%;',
            '    background-color: #1d292c;',
            '}',

            '#progress-bar {',
            '    width: 0%;',
            '    height: 100%;',
            '    background-color: #f60;',
            '}',
            '@media (max-width: 480px) {',
            '    #application-splash {',
            '        width: 170px;',
            '        left: calc(50% - 85px);',
            '    }',
            '}'
        ].join("\n");

        var style = document.createElement('style');
        style.type = 'text/css';
        if (style.styleSheet) {
          style.styleSheet.cssText = css;
        } else {
          style.appendChild(document.createTextNode(css));
        }

        document.head.appendChild(style);
    };


    createCss();

    showSplash();
        
    app.on('preload:end', function () {
        app.off('preload:progress');
    });
    app.on('preload:progress', setProgress);
    app.on('start', hideSplash);
});
1 Like

TBH, I think there is a different workflow needed for the FB instant games. @vaios, is it possible to use the FB Instant Games SDK from inside the PlayCanvas editor or is it a separate workflow that has to be done post build?

I think testing in the editor will not be possible for sure, so downloading the build using the playcanvas rest API, will be the best thing to do.

the loading screen script did not work, so i do think there might need to be more happening in the post build script, not sure where to begin, shell scripts or otherwise, but have to download using REST, unzip, add the API script tag in the index html, as well as adding a fbapp-config.json in the root, before zipping back up and posting to fb instant web hosting.

automating this is my current challenge. Doing less in the post-build script is proving problematic, so may have to do it all there.

I found the Phaser tutorial on creating Facebook Instant games and was actually wondering if it was possible to replace the start and preload or even just preload script to use the Facebook loading bar instead. I might give the latter a try when I get some time https://phaser.io/tutorials/getting-started-facebook-instant-games

1 Like

I’m starting to look into FB integration myself, so am keen to find out more and help out where I can.

I wonder is it possible to upload a version of a launcher to the FB developer area, that would then launch the published game on the PlayCanvas site, and give access to the FBInstant object. In this way, you could still do quick tests and changes in the editor, publish, and then re-launch from FB to see the changes.

Hi! I’m too looking at developing instant games using playcanvas. Is there any resource on how to implement the instant games loader for a playcanvas project?

Thanks!

I see what youre saying, it could just be an iframe that you upload to fb webhost, and this points to your playcanvas launch URL.

ill test and report back

looks like iframe will work with published build but not editor launch URL, can playcanvas team comment on this? is there a way round to using iframe in launch URL for testing purposes, and if not, can the published build be unlisted?

1 Like

Any luck with this? @yaustar Im showing the playcanvas loader but I’d prefer to use FBInstant’s instead, right now Im just skipping it and launching into playcanvas

Sorry, haven’t had the time to even start looking at it yet.

@Yohami_Zerpa @yaustar @yqu
Hey Everyone I hope this can help you all. I figured out how to get the loader to work by manipulating the ā€œloading.jsā€ script after building.

Be sure to include the FB instant SDK before building(web build) and downloading. Instructions by Will can be found under the following topic. (It doesn’t matter if you concatenate the scripts or not)

image

• You are basically to unzip the build, edit it, and then zip it up again for deployment on fb instant.
• After the build is unzipped you need to include an ā€œfbapp-config.jsonā€ file in the root directory. Mine looks like this

{instant_games: {

    platform_version: "RICH_GAMEPLAY", 

    orientation: "PORTRAIT", 

    override_web_orientation: "PORTRAIT", 

    navigation_menu_version: "NAV_FLOATING", 

    custom_update_templates: {}, surfaceable_stats: {}, 

    match_player_config: {min_context_size: 3, 

        max_context_size: 33}}}

• To get the loader to read accurately and bypass the PlayCanvas loading screen some code needs to be taken out and functions from the FB Instant API need to be implemented.

loading.js

FBInstant.initializeAsync()

    .then(function(){

        pc.script.createLoadingScreen(function (app) {

            var showSplash = function () {

                // **// 

        

            };

        

            var hideSplash = function () {

                // var splash = document.getElementById('application-splash-wrapper');

                // splash.parentElement.removeChild(splash);

                FBInstant.startGameAsync()

                    .then(function() {

                    // Retrieving context and player information can only be done

                    // once startGameAsync() resolves

                    var contextId = FBInstant.context.getID();

                    var contextType = FBInstant.context.getType();

                    var playerName = FBInstant.player.getName();

                    var playerPic = FBInstant.player.getPhoto();

                    var playerId = FBInstant.player.getID();

                    // Once startGameAsync() resolves it also means the loading view has 

                    // been removed and the user can see the game viewport

                    // game.start();

                    });

            };

        

            var setProgress = function (value) {

                // var bar = document.getElementById('progress-bar');

                // if (bar) {

                    value = Math.min(1, Math.max(0, value));

                    value *= 100;

                    // bar.style.width = value * 100 + '%';

                    FBInstant.setLoadingProgress(value);

                // }

            };

        

            var createCss = function () {

                // **//

            };

                

            createCss();

        

            showSplash();

        

            app.on('preload:end', function () {

                app.off('preload:progress');

            });

            app.on('preload:progress', setProgress);

            app.on('start', hideSplash);

        });

        

    });

• Note that all contents of the loading.js file is wrapped in the FBInstant.initializeAsync() .then() function.
• I commented out the contents of the showSplash() and createCss() functions.
• The hideSplash() function I modified looks like this.

var hideSplash=function() {
                // var splash = document.getElementById('application-splash-wrapper');
                // splash.parentElement.removeChild(splash);
                FBInstant.startGameAsync()
                    .then(function() {
                    // Retrieving context and player information can only be done
                    // once startGameAsync() resolves
                    var contextId = FBInstant.context.getID();
                    var contextType = FBInstant.context.getType();
                    var playerName = FBInstant.player.getName();
                    var playerPic = FBInstant.player.getPhoto();
                    var playerId = FBInstant.player.getID();

                    // Once startGameAsync() resolves it also means the loading view has 
                    // been removed and the user can see the game viewport

                    // game.start();
                    });
            };

• The setProgress() function is the most important. What I did was simply modify the value to work with the instant games function and finally passed that value into the FBInstant.setLoadingProgress() function.

var setProgress = function (value) {
                // var bar = document.getElementById('progress-bar');
                // if (bar) {
                    value = Math.min(1, Math.max(0, value));
                    value *= 100;
                    // bar.style.width = value * 100 + '%';
                    FBInstant.setLoadingProgress(value);
                // }
            };

After making these modifications and then zipping the folder once again, the FBInstant loading screen should work as desired.

3 Likes

Brilliant, I’ll give it a try

Works, here’s my version of the loading.js for future reference

        FBInstant.initializeAsync().then( function()
        {
            pc.script.createLoadingScreen(function (app) 
            {
                app.on('preload:end', function () 
                {
                    app.off('preload:progress');
                });

                app.on('preload:progress', function (value)
                {
                    FBInstant.setLoadingProgress( value*100 )
                });

                app.on('start', function()
                {
                    FBInstant.startGameAsync().then(function(){})
                });
            });
        });
            
1 Like

@Yohami_Zerpa glad to know, and thanks for your improved and concise code!

1 Like

@Grayson_Ewing extra question - how do I hide the Playcanvas canvas while the app is loading? it’s rendering the screen black and covering the FBInstant loader after some point

@Yohami_Zerpa does the problem still occur if you copy and paste my code exactly? I also had some problems when i completely removed certain function like the createCss() or showSplash(). Try experimenting and including/excluding different functions to see i you can get your desired result