Impact

Prerequisites

To compile the Ejecta project, you need a Mac and XCode 7.1 or newer. If you downloaded the release ZIP from this website, you should be able to compile and run the Ejecta.xcodeproj in the iOS Simulator without making any changes.

If you cloned the GitHub repo, you have to create the App/ folder and put an index.js in there first. Refer to the README.md that comes with it.

Note that you can't compare the performance in the Simulator to that on real hardware. Typically the simulator runs a good deal slower than actual hardware.

Getting Started

After you've downloaded and unzipped Ejecta and loaded the Ejecta.xcodeproj file in XCode, it's a good idea to rename the project: in XCode, select the project in the upper left corner of the sidebar and hit enter. You can now rename the project; hit enter again and XCode will ask you to rename a bunch of other stuff as well – choose Rename.

The XCode project has two build targets: "Ejecta" - for the iOS version and "Ejecta-TV" for the tvOS version.

To change the desired screen orientation of your iOS App (portrait or landscape), go to the project settings, select the "Ejecta" target and check the appropriate Device Orientation checkboxes. Note that iPad need to always support both portrait or both landscape modes (or all 4) as per the AppStore guidlines.

Also in the target settings, be sure to change the Bundle Identifier setting to something that represents you or your company and product name.

You should now be able to compile and run the project in the Simulator.

How Ejecta Works

Ejecta fires up the JavaScriptCore VM, attaches all native Obj-C Classes that should be exposed to JavaScript. It then executes the Source/Ejecta/Ejecta.js file that sets up a bunch of things and finally loads the App/index.js file - which is where you do your stuff.

The simplest possible index.js looks like this:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

// draw a pink square
ctx.fillStyle = '#ff00ff';
ctx.fillRect( 50, 50, 100, 100 ); 

While Ejecta tries to mimic the HTML5 APIs closely, there are some things that behave differently in Ejecta than they do in a Browser. Most importantly, most DOM operations are not supported in Ejecta. There's a very thin "fake" layer of DOM objects, that allows you do some common operations, but is by no means complete.

E.g. you can query the screen size for the current device through window.innerWidth and window.innerHeight. You can use console.log() like you're used and you can create Image and Canvas elements with document.createElement(). See Supported APIs & Methods for a detailed list and some more examples.

The App/ Directory

All your JavaScript source files as well as your assets (sounds/music) should be placed into the App/ directory. All files you reference from your code are relative to this directory. E.g. an image file in App/images/test.png can be loaded like so:

var img = new Image();
img.src = 'images/test.png';

You can also easily load other source files in your App/ directory with ejecta.include(). This function runs synchronously:

console.log('before executing code in more-code.js');

ejecta.include('lib/more-code.js');

console.log('after executing code in more-code.js');

The Canvas Element

Ejecta always creates the "Screen Canvas" for you, but you can create additional Canvas elements for off-screen drawing.

As you can see in the example above, you can get a reference to the Screen Canvas through document.getElementById('canvas') (you could also skip this line and use the canvas variable directly – getElementById was only implemented to be compatible with a script that would also run successfully in a Browser).

The size of the Screen Canvas is automatically set to the non retina screen size of the current device, but you can of course still render in retina resolution, by setting the width and height to the retina resolution while forcing the style to scale the canvas to the logical display resolution. This is in line with current browsers.

canvas.width = window.innerWidth * window.devicePixelRatio;
canvas.height = window.innerHeight * window.devicePixelRatio;
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';

// For 2D contexts you may want to zoom in afterwards
ctx.scale( window.devicePixelRatio, window.devicePixelRatio );

Antialiasing (MSAA) is disabled by default. If enabled, the default number of samples is 2, but you can instruct MSAA to use 4 samples at the cost of a bit of performance. MSAA will make vector drawings look a bit nicer, but has no effect for drawing images. It can be enabled when obtaining the canvas context:

var ctx = canvas.getContext('2d', {antialias: true, antialiasSamples: 4});

// Or for WebGL contexts

var gl = canvas.getContext('webgl', {antialias: true, antialiasSamples: 4});

For pixel style games and graphics you probably want crisp nearest-neighbor scaling instead of the default bilinear. You can set this on the Canvas Context:

ctx.imageSmoothingEnabled = false;

Drawing Images

Drawing images to the Canvas works exactly like in a Browser.

Minimal example:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var img = new Image();
img.onload = function() {
    ctx.drawImage( img, 0, 0 );
};
img.src = 'some-image.png';

Custom Fonts

In order to load and use custom TTF fonts not provided by the OS, you have to copy the font file into your App/ directory, and load the via ejecta.loadFont(). You can then use the font file like any other:

ejecta.loadFont("my-custom-font.ttf");
ctx.font = '16px MyCustomFont';