Amino 2: Overall Design

When redesigning Amino I had a few core goals. These goals are in place to guide the product and ensure we created something genuinely useful, and not become "yet another gfx lib".

Goals

Amino 2 must be:

  • Simple: the api must be simple and easy to understand
  • Responsive: the goal is to hit a consistent fps for all graphics on screen. 60fps on desktop and 30fps on mobile. This should be very doable with modern devices. The UI must always be responsive, even at the cost of accuracy or graphics complexity.
  • Rich: complex effects and animation should be possible(shadows, gradients, real world textures, animation) while still hitting a consistent FPS.
  • Speedable: we should be able to add speed improvements, including hardware acceleration, purely in the implementation. Speedups shouldn't affect the API. Existing apps just get faster over time.
  • Subsettable: You should be able to use just the parts you need.
  • Portable: Nothing of the underlying graphics implementation should be exposed. (we aren't there yet).
  • Flexible: for lots of tasks you can just compose nodes together, but sometimes you may want to dig down to the lower levels. This should be possible, as long as you realize your code might not be as portable anymore.

Structure

With these goals in mind, here is the basic structure:

A Node is an object in the tree with a draw function. Anything which draws or affects drawing is a subclass of Node. This means all shapes, groups, transforms, imageviews, etc. Nodes also track their dirty state, and if they contain a given point (used for input processing). All nodes have parents (except the top most node)

A Parent is simple a node that implements the Parent interface. Currently only Group and Transform are parents.

A Scene is a tree of Nodes (a non-cyclical directed graph).

Everything is done on a single GUI thread. Touching nodes or trying to draw off the GUI thread is an error.

Resources (images, gradients, colors, textures) are immutable, to enable transparent caching.

Amino's internal system handles repaints, animation, and input events for you. you just create the tree of nodes and you are off to the races. By letting Amino handle these things we can ensure a consistent framerate and the best performance possible.

All events are generated by the system (usually by wrapping native events) and passed to your handlers through the event bus. You can listen to either a particular kind of event on a particular object, or all of that kind of event throughout the system. For example: Give me all mouse press events or Tell me when this node is clicked. Events will be automatically transformed into local coordinates when you click on transformed objects, and they are passed along with the target node of the event.

A quick note on cross platform support. My goal is to make the Java and JavaScript APIs identical. Wherever possible this is true. However, due to the difference between the languages (namely that JavaScript uses prototype based inheritance) there will be minor differences. In general the same code should work under both with only minor syntactic changes.

Example

The following code creates two colored rectangles with method chaining. Then it creates a square that spins and slides back and forth across the screen. I've included both Java and Javascript versions so you can see the minor differences.

Javascript

var runner = new Runner();
runner.setCanvas(document.getElementById("canvas")); var g = new Group();
g.add(new Rect().setWidth(100).setHeight(50).setFill("green")) .add(new Rect().setWidth(50).setHeight(50).setY(100).setFill("yellow"))
; var r = new Rect().set(-25,-25,50,50).setFill("white"); var t = new Transform(r).setTranslateX(100).setTranslateY(100);
g.add(t);
runner.addAnim(new Anim(t,"rotation",0,90,1).setLoop(true).setAutoReverse(false));
runner.addAnim(new Anim(t,"translateX",100,500,4).setLoop(true).setAutoReverse(true));
runner.addAnim(new Anim(t,"translateY",100,150,0.5).setLoop(true).setAutoReverse(true)); runner.root = g;
runner.start();

Java

final Core runner = new Core();
runner.setSize(600,400);
runner.setBackground(Color.BLACK); Group g = new Group();
g.add(new Rect().setWidth(100).setHeight(50).setFill(Color.GREEN)) .add(new Rect().setWidth(50).setHeight(50).setFill(Color.YELLOW).setY(100))
; Rect r = new Rect().set(-25, -25, 50, 50);
r.setFill(Color.WHITE);
Transform t = new Transform(r).setTranslateX(100).setTranslateY(100);
g.add(t);
runner.addAnim(new PropAnim(t,"rotation",0,90,1).setLoop(true).setAutoReverse(false));
runner.addAnim(new PropAnim(t,"translateX",100,500,4).setLoop(true).setAutoReverse(true));
runner.addAnim(new PropAnim(t,"translateY",100,150,0.5).setLoop(true).setAutoReverse(true)); runner.root = g;
runner.start();

Download

Amino 2 is still very much a work in progress, but so far I'm happy with the design. I've made several TouchPad apps already with decent performance, and the API really simplifies Java2D coding. Next I'm working on more graphics primitives, buffered effects, and a simple path API.

You can download a daily build here. Please join the Amino Dev List to provide feedback or contribute to the project.

Thanks!

Talk to me about it on Twitter

Posted March 14th, 2011

Tagged: code