Skip to content

Creating a UI App

James Baicoianu edited this page May 2, 2018 · 10 revisions

UI Apps are packages which let the user can add to their client to extend its functionality. These allow you to add more advanced capabilities to the client, in a way which allows the user to bring these tools with them to other worlds. Apps can be used to provide improved editing functionality, bring in data from external sources, display information about the world or the player, or layer additional functionality such as VOIP, screen capture, streaming, etc.

JanusWeb comes with a default set of apps, which provide the basic functionality of the client. These include apps like navigation, which provides a smart URL bar with a loading progress indicator and built-in autosuggest; chat, which provides text chat functionality; or inventory, which lets users access 3D models from Google Poly, Sketchup, or other data sources.

In addition to the included apps, users can install apps from third parties as well. This opens up the platform to allow other users to improve the functionality of the client without having to modify the engine, and they can share their apps with other users and try out new ways of interacting.

Creating a custom app is simple if you already know some basic HTML and Javascript - you can build your apps out of standard HTML elements. In addition, we take advantage of HTML5 Web Components features, which allow us to define new HTML elements which extend the browser's built-in functionality.

For example, HTML doesn't have a tag which represents a tabbed content control. If you want tabs in HTML, you have to build them out of other elements, style them, and attach some JS to them. Web Components let us define a new custom HTML element, <ui-tabs>, and then we can define any number of <ui-tab label="My Tab">...</ui-tab> elements within it. This makes it super easy to reuse these controls as many times as you want on a page - they can be nested and arranged to create more complex UIs out of the basic building blocks.

Defining your App

We start with a JSON file which tells us what files and dependencies are involved in making this app. (NOTE - comments are not valid in JSON, they've been added here for readability - make sure you remove them if you copy-paste from this example!)

{
  // Apps can include other apps!
  "apps": {
    "otherapp": "https://mysite.com/apps/otherapp.json"
  },

  // A list of HTML files to load into named templates.
  // Paths that begin with ./ are loaded relative to their app's json file
  "templates": {
    "myapp.item": "./item.html"
  },
1
  // After the dependencies above have been loaded, load the following scripts and CSS
  // Paths that begin with ./ are loaded relative to their app's json file
  "scripts": [
    "./someLibrary-1.2.3.js",
    "./myapp.js"
  ],
  "css": [
    "./myapp.css"
  ],

  // List the components that this app exports
  "components": [
    "myapp-confabulator"
  ]

This defines an app which includes one other app (useful if you want to define libraries of apps), defines one template (more on this later), and then includes one external library, along with our app's main JS and CSS files. Within the JS file, we're going to define one component, an HTML element named <myapp-confabulator>. We'll start off just making it display some simple text, which will change when we click anywhere on the element.

Our JS file looks like this:

elation.elements.define('myapp-confabulator', class extends elation.elements.base {
  // The init function gets called to define the object, and is used to define any attributes the element has
  // Don't forget to call super.init() to set up any attributes which we've inherited!
  init() {
    super.init();
    this.defineAttributes({
      'done': { type: 'boolean', default: false }
    });
  }
  // The create function gets called for each instance of this element as it's added to the page
  create() {
    this.innerHTML = 'Hello world!';
    this.addEventListener('click', (ev) => this.handleClick(ev));
  }
  handleClick(ev) {
    console.log('I was clicked!');
    this.innerHTML = 'Goodbye everybody';
  }
});

Last but not least, we'll want to style our component. If we're composing something more complex using the built-in UI components this step may not be necessary for every element you define - but the option is there to tweak to your heart's content!

/* 
 * We've defined a new HTML element, <myapp-confabulator>, so our selector is an element selector
 * No classes or id necessary, but of course, always supported!
*/
myapp-confabulator {
  border: 1px solid black;
  background: rgba(255,0,0,.2);
}
/* Attribute-based selectors are very useful for styling the various states of our custom element */
myapp-confabulator[done] {
  background: rgba(0, 255, 0, .2);
}
Clone this wiki locally