Multiple instances of HTML target

I have a small 3D application that I ported from Flash using OpenFL. It is working well in a single instance running in HTML, but I need to run two or more instances on the same webpage.

This is causing some issues in Lime / OpenFL, as I think that this use case is beyond it’s usual scope (ie games, often full screen).

I hacked the code base a little to remove some static variables, including the GL.hx class, and I’m now at the stage that both 3D outputs are displayed, but they are on the same div - one 3D canvas on top of the other! I’m unsure if it is worth further hacking to try to get this to work, as I’m unsure how many static variables there are that are shared between the two, or more, instances.

Is there a better way to do this in Javascript? ( I seem to recall that this could be done in Flash with flash.system.ApplicationDomain).

Regards, Jake Lewis

I thought that separate copies of OpenFL would each run in a JS module, meaning they are isolated from the global scope (so long as you don’t use -Dmodular). Does this not work?

http://www.workboy.com/jake/HTML5tests/OpenFLsamples/HelloTriangle/Export/html5/debug/bin/index2.html

Above is link to the Hello Triangle demo( built with stock OpenFL 4.5.1 / Lime 3.5.1) with two instances of the hello triangle loaded. Neither is rendered at all. If either of the lime.embed() methods below are remarked out, then the other will render successfully.

> <div id="openfl-content1"></div>
> <div id="openfl-content2"></div>
> 	<script type="text/javascript">
> 		lime.embed ("openfl-content1", 0, 0, "FF0000");
> 		lime.embed ("openfl-content2", 0, 0, "00FF00");
> 	</script>

(In my project I’m actually using webGL rather that Stage3D, but if this demo works in Stage3D that would be progress.)
Jake

Probably you can use following hack: insert each lime app using iframe

I’m not sure I understand what you mean by JS module?

Also, I searched the OpenFl and Lime libraries and found no reference to ‘#if modular’

Static globals such as lime.app.Application.current will be overwritten when the second instance is loaded. I’ve fixed a few of these in my branch of lime/openfl but I’m unsure how many there are of them!

Jake

Thanks restorer, but sadly other design restrictions prevent me from using iframes :frowning:

I just got it working :success:

It was caused by lime.embed being overwritten. As a temporary solution (it should be a parameter to the embed method, but I’m open to ideas here) I have just committed changes to Lime and OpenFL, and exposed “lime.(name of application file).embed” in addition to the ordinary embed method.

I created two separate projects, “MultiEmbedA” and “MultiEmbedB”, and built them both. This resulted in “MultiEmbedA.js” and “MultiEmbedB.js”, which expose unique lime.MultiEmbedA.embed and lime.MultiEmbedB.embed entry points. My quick test page source looks like this:

<!DOCTYPE html>
<html lang="en">
<head>
	
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
	
	<title>MultiEmbedA</title>
	
	<meta id="viewport" name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
	<meta name="apple-mobile-web-app-capable" content="yes">
	
	
	<link rel="shortcut icon" type="image/png" href="./favicon.png">
	
	
	<script type="text/javascript" src="./lib/howler.min.js"></script>
	<script type="text/javascript" src="./lib/pako.min.js"></script>
	<script type="text/javascript" src="./MultiEmbedA.js"></script>
	<script type="text/javascript" src="./MultiEmbedB.js"></script>
	
	<script>
		window.addEventListener ("touchmove", function (event) { event.preventDefault (); }, false);
		if (typeof window.devicePixelRatio != 'undefined' && window.devicePixelRatio > 2) {
			var meta = document.getElementById ("viewport");
			meta.setAttribute ('content', 'width=device-width, initial-scale=' + (2 / window.devicePixelRatio) + ', user-scalable=no');
		}
	</script>
	
	<style>
		html,body { margin: 0; padding: 0; height: 100%; overflow: hidden; }
		#openfl-content { background: #000000; width: 300px; height: 300px; }
		#openfl-content2 { background: #000000; width: 300px; height: 300px; }
		
	</style>
	
</head>
<body>
	
	<noscript>This webpage makes extensive use of JavaScript. Please enable JavaScript in your web browser to view this page.</noscript>
	
	<div id="openfl-content"></div>
	<div id="openfl-content2"></div>
	
	<script type="text/javascript">
		lime.MultiEmbedA.embed ("openfl-content", 0, 0, "FFFFFF");
		lime.MultiEmbedB.embed ("openfl-content2", 0, 0, "FFFFFF");
	</script>
	
</body>
</html>

I hope to make multi-module projects (like this) easier to manage in the future. Thanks again for any input on how this should work from an ergonomic/API perspective :slight_smile:

Have a great day

Hi again,

I am concerned about name collisions, but I think that using (app file name).embed (or the <app file="" /> name) should be flexible enough to probably use it as the default name for templates. As a result, I’ve changed OpenFL and Lime on the development version to use this instead of lime.embed

For example, the Pirate Pig sample would have PiratePig.embed and not lime.embed in the “index.html” file

The -Dmodular setting is done in the “include.xml” for Lime and OpenFL, and does not impact the source code. In order to use multiple different OpenFL applications on the same page, and use modular code, we will have to look at our use of static variables, and perhaps use macros to cache global values (such as openfl.media.SoundMixer) using some kind of application domain.

In the meantime, two full embeds should work, the file size might be a little larger for multiple embeds on the same page, but it should be functional :slight_smile:

Let me know if you have any trouble, though

Thanks for the rapid response. I’ll have a look at this tomorrow with a fresh mind.

A big headache I was having with statics was the openfl.Lib singleton. How would you envisage application domain working in Javascript - for each rendercycle and each event, the application would need to overwrite Lib, SoundMixer, GL etc - where would be a good place to implement that?

Jake

Hi Jake,

We had a similar issue when deploying OpenFL HTML5 exports into a system which enforced strict AMD. Adhering to the AMD solved the issue for us, but we had to modify the way that export (we did it by hand :flushed:) to get a bootstrap process that looks like this.

  openFl.init(_console, openFl.services, window);
  openFl.services.lime.embed (dom.children[0].children[0], 0, 0, "FFFFFF", config.baseUrl + 'runtime/assets/');

The modification looks something like this in the built js:

-  var exports = {};
+  var exports = { services: {} };


-(function (console, $hx_exports, $global) { "use strict";
+exports.init = (function (console, $hx_exports, $global) { "use strict";
-})(typeof console != "undefined" ? console : {log:function(){}}, typeof window != "undefined" ? window : exports, typeof window != "undefined" ? window : typeof global != "undefined" ? global : typeof self != "undefined" ? self : this);
+});

The init function had to be added to avoid having the initialisation function kickoff on its own.

I am making custom graphs and I was hoping to re-use the one application in multiple places on a webpage. Your solution has 2 different applications? Any ideas on how to allow multiple instances on one web page?

There might be problems with static values if you embed multiple times, but I’m tracking it here:

Fixed in the latest development builds :smile:

1 Like

Awesome, thank you. I will check it out

Hej guys,
So finally, what the trick to embed 2 instances of a SAME app in a single HTML file please ?

I’m using OpenFL 8.2.2, and when trying to embed 3 instances of the same HTML5 app it doesn’t work correctly. Only the 1st assets load and the cursor change on the 3rd div when touching the 1st one …
And also I had to do Assets.loadBitmapData instead of simple Assets.getBitmapData that works when there is only one instance…
Is it possible to embed many OpenFL instances on the same web page please ? How to do it ? And what about this problem : https://github.com/openfl/lime/issues/967

Best,
Michal

Multiple embeds don’t currently use closures, so static values are shared between them. We do have multiple embeds on our website for the NPM learn section, but specifically to your question, the Haxelib-based approach right now uses unique string names per project. Embedding the same project twice will cause a collision since they both share the same name. The big thing here (again) is in anything static, but if you are careful, I know I have gotten it working before.

Happy if anyone has suggestions for better using closures to make every embed unique, static and otherwise

Thanks for you answer Joshua,
Yes it would be great if someone fiond a solution for that.
BTW, do you mean If I rename my project (export app js file you mean right) it will work correctly ?

Yes, I think it may work better. Might be worth a quick test, though at that point, it may load the JavaScript twice, so more download time

This should be enabled in the new dev version of Lime, and will go out in the next release, assuming all feedback comes back fine:

static values are now isolated between multiple embeds, which should fix a lot of different issues!