In-world web browsing in OpenSim #1

Prototype in-world browser in OpenSim grid

Prototype in-world browser in OpenSim grid

Web browsing in OpenSim

Web browsing inside OpenSim (or even Second Life™, for those still left there) is never going to be as seamless as through a browser. You might ask, “What’s the point?” but, in fact, there is a point in certain limited circumstances, i.e. when a number of people want to look at the same resources together in a virtual environment. The 3D metaverse isn’t about replicating real life at all but rather being able to meet people in a simulated physical environment in order to share the same space. It is an immersive discussion forum and therefore one can easily imagine wanting to show people things on the Web and discuss them within that immersive environment.

Media On A Prim doesn’t do the job

Why don’t I just use Media On A Prim (MOAP)? The reason that I am not using Media On A Prim (MOAP) is because (a) it seems to be broken in OpenSim at present, so every time you click on a link it reverts to the previous page straight away so you cannot navigate; (b) the texture does not immediately render without user intervention and it does not look the same for every viewer. Despite it being technically better in supporting Flash, audio, video and native scrolling (if it wasn’t apparently broken), it isn’t ideal for collaborative use. My method uses the OsDynamicTextureURL* functions, which ensure that all viewers see the same texture.

My image-based solution

Aside from MOAP, this has been done before but there is apparently no open source code available nor any advice on how it was done. Well, realising this made me want to find a way to replicate it and provide exactly that. I have now made a mostly functional prototype web browser inside OpenSim. It relies ultimately on WebKit through PhantomJS, itself described as a “headless WebKit scriptable with a JavaScript API”, i.e. a set of tools that can test web pages without a visible browser and, amongst other things, render the output into image files. However, manipulating the relatively arcane directives of PhantomJS directly proved difficult, so I naturally turned to CasperJS as suggested, which is “an open source navigation scripting & testing utility written in Javascript” in order to make PhantomJS easier to deploy. Although it’s not altogether different and there is still a level of complexity, especially for someone like me who only crudely hacks JavaScript, it does live up to its aim: it makes it considerably easier to use PhantomJS for its intended purpose.

The LSL/OSSL script communicates by HTTP POST with a PHP script on our server, which requests an image of the web site from the JavaScript, which processes clicks on the surface coordinates that it was sent to the links in the page and renders the resulting page as an image.

The JavaScript

Let’s call this imagecapture.js (see the code below) and put it on a server somewhere. The location does not have to be public once it’s out of testing – in fact, if you want the secret key to remain secret, it had better not be so. We should make this HTTP request from OpenSim using TLS i.e HTTPS, still often incorrectly known as SSL, it’s predecessor in cryptography. That way, we are not transmitting the secret key in clear text. Effectively, we are producing a secure image-based proxy.

There are instructions elsewhere on the Web for how to install PhantomJS and CasperJS, which I won’t repeat – not least because it will depend upon your *nix distribution. I found it reasonably easy to install PhantomJS using apt-get or aptitude on Ubuntu. It was mildly harder to install CasperJS on Ubuntu 14.04 but a little research should accomplish it easily.

There are some things that you will not be able to do, like plugins showing live video or audio of any kind. But you can do this in other ways in OpenSim already. Some JavaScript links will not work, although those using onClick="location.href=''", for example, will work fine. Normal anchor links with or without images will work fine too. In order to make anything work at all, I must tell you now that you will need access to a web server and know how to use it. Here is the JavaScript, to start with:

var casper = require('casper').create({
  pageSettings: {
    javascriptEnabled: true,
    loadImages: true,
    loadPlugins: true

var webPage = require('webpage');
var page = webPage.create();

var args = require('system').args;
var startURL = args[4];

var width = 1024; // 1024;
var height = 768;
var zoom = 1; // DO NOT CHANGE THIS

casper.options.viewportSize = {width: width, height: height};

x = parseFloat(args[5]);
y = parseFloat(args[6]);

x = Math.round(x * width);
y = Math.round(y * height);


// code to click x, y
casper.then(function() {, y); // clicks at coordinates x, y

  documentHeight = this.evaluate(function() {
    return __utils__.getDocumentHeight();


var address = startURL;

var clipHeight = casper.evaluate(function(){
  return document.querySelector('body').offsetHeight;

casper.then(function() {
  address = this.getCurrentUrl();
  this.capture('cache/image.png', {
    top: 0,
    left: 0,
    width: width, // clipWidth,
    height: documentHeight // clipHeight

This code is basically my own and is released under the GNU General Public Licence (GPL) 3.0 for public use. It has been created with the considerable help of the CasperJS and PhantomJS documentation. While not complete, this is pretty helpful and I have to take off my hat to the developers, who are clearly very clever and able people.

The PHP script

It won’t run without some PHP, which I have also written and release under the same licence. Change the “secret key”: may I suggest using SHA2 for a secret hash? Mine is just a single letter for testing, so far – terribly secure! Let’s call this imagecapture.php and put it on the same server.

$secretKey="l"; // change this after testing
if ( isset($_POST['secretKey']) && $_POST['secretKey'] == $secretKey ) {
  if ( isset($_POST['searchURL']) ) {
  $searchURL = stripslashes($_POST['searchURL']);
  if ( isset($_POST['x']) ) {
    $searchURL .= ' ' . $_POST['x'];
    if ( isset($_POST['y']) ) { $searchURL .= ' ' . $_POST['y']; }
  $execString = '/usr/bin/casperjs --ignore-ssl-errors=yes ./imagecapture.js ' . $searchURL;
  //$execString = '/usr/bin/phantomjs --ssl-protocol=any ./imagecreate.js ' . $searchURL; // Old version before I used CasperJS
  exec($execString, $output, $return_var);
  echo addslashes('imageURL').'='.addslashes(''); //$imageURL;
  echo '&'.addslashes('returnURL').'='.addslashes($output[0]);
  list($width, $height, $type, $attr) = getimagesize("cache/image.png");
  echo '&'.addslashes('width').'='.addslashes($width);
  echo '&'.addslashes('height').'='.addslashes($height);

Put it all together

Once this is out of testing, adjust the location of the above imagecapture.js file and change the location in this script to reflect this. You ought to make sure that these are owned by the Apache or Nginx user (usually www-data), which will mean they will not write the file image.png when you run them from the command line. When we call them later via HTTP request to the web server from within OpenSim, however, they will do so properly.

This is all obviously quite snazzy, though it does have limitations like lack of audio or video. It has no Flash.  Audio can be done in other ways but MOAP isn’t optimal as described, but perhaps at some point these could be somehow resolved in one neat package. Until then, this fills a gap. Simple JavaScript links will work but most fancier bits won’t, so expect some broken links etc.

Now all we have to do is create a web browser in OpenSim. As we speak, I am about 75% through this process. I have to add scroll bars, back and forward functionality and do a fair bit of checking. However, the basic thing works. If you want to see it in its incomplete state, please get in touch with me personally and I will tell you where in my grid Ocean Grid you can find it. Once it is complete, I will then release a full version in IAR format as well as the various LSL/OSSL scripts that are required.

This is the end of part one. So far, we have created a way by which a set of HTTP POST variables can be sent to a PHP script, which in turn calls some JavaScript that writes an image of the web page and returns the URL (which may have changed e.g. via 301 redirects on the web server). The PHP then returns all of this stuff in POST data to the requesting script inside OpenSim.


The slow death of Viewer 1.x, the half-life of the hypergrid, and other stories

Despite the popularity of third-party viewers such as Phoenix (formerly Emerald) and the disastrous design and usability problems of Linden Viewer 2.0, it has now become clear that Viewer 1.x is dying a slow death. The final release of the Phoenix viewer is out, to be replaced by a new Firestorm viewer based on the 2.0 codebase, and there are similar plans for Imprudence to be replaced by the new Kokua viewer (whose name, I’m afraid, does not strike me as nearly as memorable – what’s wrong with Phoenix 2.0 and Imprudence 2.0 for names, rather than changing them just when they start to get well-known?)

This is, of course, a demonstration that the world of OpenSim grids, so dependent on the Linden codebase, is still very much semi-detached from development in SL, and interoperability will always remain a core issue.

One reason for this is mesh, coming soon (but we’re still not sure when) to a simulator near you. Look out, OpenSim and ModRex! Despite the latter’s support for mesh being far older than the Linden effort, ported back from RealXtend‘s version of the OpenSim codebase to a region module for OpenSim, it has never caught on. Although OpenSim developers seem to be working on mesh, it’s no longer clear if ModRex is the main plank of this effort. It still only works in standalone mode, not in grid mode. The pace of development on ModRex seems still to be incredibly slow, after an initial burst of activity, and it’s blog and web presence remains embryonic and dated.

The 1.x codebase can support some newer backported features such as Display Names (which is not likely to be complex code) but it will be increasingly difficult, and most likely impossible, to continue developing viewers that work for both OpenSim and SL without embracing the viewer 2.0 codebase. Incidentally, Display Names will not work on OpenSim, but apparently will on Aurora based-grids (see below). Hopefully, however, the terrible viewer  design will be completely ignored. Even the developer of Kirsten’s viewer, which rather slavishly avoids any affront to Linden Lab by providing direct support for OpenSim (which is a simple matter of using the open source grid manager code from the Hippo viewer), has been critical of the Viewer 2.0 design. I should say, in Kirsten’s defence, that it is not completely impossible to use the present version of the viewer with OpenSim.

Meanwhile, new forks of the OpenSim server codebase are appearing, notably Aurora, which provides a great deal of core functionality that users have been crying out for. The new Kokua Viewer (a separate project loosely associated with Aurora, previously known as Imprudence) will support some of these extra features. At present, things like profiles, groups, search and web interfaces have to be hacked together once per upgrade, and database changes leave all of these side projects struggling to keep up with the OpenSim codebase.

OpenSim developers, after their huge success with Hypergrid, have managed to undo their own work by fracturing the community into no less than three mutually incompatible and often unreliable versions of what is the most fundamental part of the open metaverse. At present, Hypergrid is barely working at all, and it is a major victory to teleport off one’s own servers. Yesterday I finally managed to reach OSGrid (though it’s misconfigured locally, so that one cannot leave) using a test grid running Aurora, although I cannot do so with any revision of OpenSim 0.7.1-dev on which it is based. Admittedly the latter is development code, but many grids are already running it, including OSGrid. People were astonished to see someone arrive from the outside: one said it had been a year since they had known it to be working! Obviously, some of the unreliability is down to local server configurations, which is an operational problem. But why keep breaking Hypergrid with every new release? Why does it have to be so hard? This is no way to help grow the open source metaverse.

It seems that the OpenSim developers do not seem to see the hypergrid as a priority even though it is what makes people compare OpenSim grids to the Web and its rich competitor SL to the once-mighty AOL. At present, documentation and communication about OpenSim remain amateur and patchy. Of course, the developers make the blinkered ideological claim that they are NOT a competitor to SL, but such claims are often made by those who are manifestly failing to capitalise on their obvious strategic advantages. However talented the OpenSim developers are, they are terrible salesmen. And they are convincing nobody. Their user base certainly is competing with SL, even if they personally, as developers, are not. Remember, the user is queen – or even king!

Get it together again! All this fine work needs a bit more coordination, no?