Developer Guide

Theme Development

Developing themes is a key part of using Open Joystick Display. Getting started is easy and will allow you to make your device unique to your stream.

Required Knowledge

These are the basic things you'll neeed to understand to build themes. If you need help, check out our Learning Resources section.

  • Basic Coding Skills
  • HTML
  • CSS
  • Graphic Design + Vector/SVG Skills Recommeneded (But Not Required)

Recommended Tools

These are the tools you'll need to get to work. Software examples are provided below in both free and paid options.

  • Text Editor/Coding Interface
  • Raster Design Software (For Images, Not Required)
  • Vector Design Software (For SVG, Not Required)

Text Editors/Coding Interface Application Examples

Raster Design Software

Vector Design Software

Learning Resources

If you're new or just a little rusty- use these resources below to help you learn the skills to build themes.

HTML Tutorials

CSS Tutorials

Learning by Example

Maybe you just want to cut to the chase and ignore the rest of this document. You can download all of our system themes from our github page and use them as a guide for your own themes. Below are links to each of the current system themes you can work off of.

Package Contents

The package contents for your theme is important for Open Joystick Display to understand that it is a theme. Below is a simple directory structure of each theme package.

  |- theme.json
  |- theme.html
  |- theme.css

Theme Folder

This is the folder in which all of your theme contents are in. The name of the folder should match the ID in the theme.json file.


This contains the metadata for your theme as well as the unique identifier of your theme. Below is an example theme.json file.

	"name":"SFC Controller",
	"author":"Anthony Dragoni (RetroWeeb)",
	"copyright":"Copyright 2019 Anthony Dragoni, Open Joystick Display",
	"license":"BSD 4-Clause Attribution",


This contains all of your HTML syntax. Anything goes in here, however <script><object><embed><iframe><video> tags are forbidden and will be stripped alongside any javascript events such as onClick or onMouseOver.


This is the stylesheet for your theme. This will be autoloaded alongside your editor. Any class or id with the text ojd will be removed. You can use general element tags but you may mess up the application if your selectors are too liberal. However we're in the boat of giving you enough rope to hang yourself.

Adding Asset Folders

While you could include all of your image and svg files in the root directory. Feel free to add folders such as images/ to your theme directory. In the next section we'll go over how to reference these external assets.

Defining Styles (Sub-Themes)

New in 1.0 we have styles. This allows you to define multiple styles in a theme. This allows for multiple color profiles or even entirely different controllers in relation to your theme. Examples of this are the various styles of Xbox controllers or SNES controllers.

Simple Style Definition

A simple style is just a style that uses the same theme.html and theme.css but loads another theme file to override certian settings in your CSS file. This is useful if you're just changing colors.

To get started you'll want to make a add attribute to your theme.json file (example below)

	{"id":"purple", "name":"Purple"},
	{"id":"silver", "name":"Silver"}

You'll see both a purple and silver theme in this style array. After that all you need to do is create a theme-purple.css and theme-silver.css (Obviously, if these are not the name of your styles, name these files using the defined style id as theme-YOUR_STYLE_ID.css) and make your CSS changes in there. Refresh or reload and you will now see a list of styles in the profile theme menu.

Complex Style Definition

Maybe changing a color isn't enough, you actually want to do a whole new layout as well. You can do this by following the steps above and then adding the file and mastercss attributes to your style object (example below).

{"id":"streamer-white", 	"name":"Streamer (White Active)", 	"file":"theme-streamer.html", 	"mastercss":"theme-streamer.css"},
{"id":"streamer-purple", 	"name":"Streamer (Purple Active)", 	"file":"theme-streamer.html", 	"mastercss":"theme-streamer.css"},

Once you have done that you can create your custom CSS and HTML files associated with that complex theme. Note that you can also still follow the simple style definition alongside of a complex one. For the example above, while you have theme-streamer.html (replacing theme.html) and theme-streamer.css (replacing theme.css) you can also make a file called theme-streamer-white.css to help simplify your workflow.

Referencing Assets

Sometimes you may want to include an image or svg into your theme. Here is how you do it while keeping it portable.


You can use the %DIRECTORY% keyword as an absolute pathing for your img or svg tags.

<img class='sfc-logo' src="%DIRECTORY%/images/logo.png"/>


Thankfully your stylesheet is smart enough to understand relative pathing. Adding a resource is is fairly simple.

.sfc-logo-div {

Using SVGs

Using SVGs is a little different in Open Joystick Display than in regular HTML. We don't use object tags. To get started, you'll want to make a div in your theme HTML file with the following attributes.

<div ojd-svg='%DIRECTORY%/PATH_TO_YOUR_FILE'></div>

This will load your SVG directly into the theme without you having to do so. This comes with the added benefit of being able to directly manipulate individual objects and adding active classes like you would with regular CSS/HTML. You will want to modify your svg file with the correct `class` and `ojd` tags where you want direct manipulation. Here is an example of an L button being mapped correctly in an SVG.

       ojd-button="L" />


In this section we'll teach you how to map buttons to your theme. Doing so is fairly simple. On any element you wish to have activated add the tag ojd-button and the value of whatever button you want it to represent such as START. Once an button is activated it will append the CSS class active. This will allow you to control the visualization of the active state.


<div class='sfc-button' ojd-button='START'>START</div>
.sfc-button {
} {

Valid Button Keywords

To control the scope and quality of themes we have a limited mapping of buttons avaliable. Below is the list of valid ojd-button keywords.

A, B, C, X, Y, Z, CROSS, CIRCLE, SQUARE, TRIANGLE, L, L2, L3, R, R2, R3, START, SELECT, ACTION, PS, XBOX, CAPTURE, RUN, PLUS, MINUS, HOME, UP, DOWN, LEFT, RIGHT, CUP, CDOWN, CLEFT, CRIGHT, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20

You can also see these in the [Input Mapper] in Open Joystick Display itself. If you feel there is a keyword missing, put an issue in at our GitHub. Rule of thumb, if you can justify it with a real life example, we'll add it.


In general there are a few types of directionals. D-pads, c-pads, and analogs. D-pads and c-pads can be mapped as buttons, so see the above section for those. However, for analog directionals, it's a little different since the input for those are more non-specific.

Since analogs work on an X and Y axis, we want to represent this as fluid movement. To make this work you need to make a wrapper element and then put a stick element inside of that wrapper. That stick element will move in accordance to the [Input Mapper] directional ID. This stick element will have the tag ojd-directional with the value of 0 to infinity (this is the directional ID from [Input Mapper]).

You can also add the active class to change the visualization of the stick while in movement. Check out the example below.

<div class='xbox-analog-wrapper'>
	<div ojd-directional='0' class='xbox-analog'></div>
.xbox-analog-wrapper {
	border:1px solid #CCC;
.xbox-analog {

You'll see above that we have the wrapper element xbox-analog-wrapper and inside of it, the stick element xbox-analog. The xbox-analog element will move when directional 0 moves.

Good design of analog inputs should go from left to right, so for example on an XBox 360 controller directional ojd-directional=0 would be the left analog and ojd-directional=1 for the right analog. Following these mapping rules will ensure your theme is portable to others mappings.


Much like analog sticks, these also have non-specific values. However, the difference is that they are only on a single axis. There are a few way to represent triggers in your theme.

Scale Triggers

We allow for scaling up using ojd-trigger-scale and scaling down ojd-trigger-scale-inverted.

ojd-trigger-scale starts with a height=0% and then goes all the way up to height=100%

ojd-trigger-scale-inverted does the reverse, starts with height=100% and goes down to height=0%.

The value of ojd-trigger-scale and ojd-trigger-scale-inverted work just like analog directionals, they are the trigger ID from [Input Mapper]. Let's look at the example below.

<div class='gc-trigger-wrapper gc-l-trigger'>
	<div ojd-trigger='0' ojd-trigger-scale-inverted='0' class='gc-trigger'>L</div>
div.gc-trigger-wrapper {
div.gc-trigger {
	border-radius:20px 20px 0 0;

Movement Triggers

We allow for movement up using ojd-trigger-move and scaling down ojd-trigger-move-inverted.

ojd-trigger-move starts with a top=0% and then goes all the way up to top=100%

ojd-trigger-move-inverted does the reverse, starts with top=100% and goes down to top=0%.

The value of ojd-trigger-move and ojd-trigger-move-inverted work just like analog directionals, they are the trigger ID from [Input Mapper]. Let's look at the example below.

<div class='move-wrapper'>
	<div class='move' ojd-trigger='0' ojd-trigger-move='0'></div>
.move-wrapper {
	border:1px solid white;
.move {

Triggers as Buttons

This is as simple as adding ojd-button to your trigger and adding a active class in your stylesheet just like with buttons. However, it's up to the user in the [Input Mapper] to make sure that trigger activates that button.

Arcade and Fight Sticks

These are classic four-position sticks like an Atari/Commodore or a Fight Stick. Adding these are as easy as building an directional (analog) stick.

<div class='move-wrapper'>
	<div class='move' ojd-arcade-directional='true' ></div>

Follow the design guide for directional sticks and just add the attribute ojd-arcade-directional. This will allow this pseudo-analog stick to be activated by the UP,DOWN,LEFT,RIGHT buttons.


Distribution of themes is as simply putting your theme directory in an archive such as a zip or a tar.gz.