Build the smoothest UIs you've ever experienced
Mark Jones explains how the Famo.us framework can be used to bring native application performance to the web.
Branches and leaves
To understand the effects of Modifiers we must first understand Famo.us' render tree. Luckily, the core ideas are simple: a Famo.us context is the root of the render tree. The render tree has a Surface for each leaf. A leaf is affected by exactly the Modifiers between it and the root.
var surface1 = new Surface();
var surface2 = new Surface();
var modifier1 = new Modifier();
var modifier2 = new Modifier();
var modifier3 = new Modifier();
context.add( modifier1 ).add( surface1 );
context.add( modifier2 ).add( modifier3 ).add( surface2 );
Adding a Modifier or Surface directly to our context creates a branch. Any Surfaces added to a branch (by chaining the add method) will only be affected by the Modifiers further up the branch. modifier3 being added to modifier2 demonstrates Modifier chaining, which is a pattern we can use to separate different parts of a modification.
For example, if we wanted to rotate and move surface2 , modifier2 could handle the rotation whilst modifier3 could handle the positioning.
Views
The key to building maintainable, scalable large applications is to create smaller composable pieces that can be brought together to form our application. Famo.us views allow us to group Surfaces, encapsulate functionality and also provide an event input and output, allowing communication with other views in a decoupled manner.
Unlike other frameworks, views in Famo.us are not renderable, so they will not change our application's appearance unless we have added Renderables to the view. Views have no default appearance; they are simply a collection of Modifiers and Surfaces, which themselves affect what is rendered.
Views are treated as a single leaf on the render tree's branch, causing any Surfaces that are added to it to be affected by Modifiers higher up the branch.
var surface = new Surface({
content: 'My first Surface'
});
var surface2 = new Surface({
content: 'Another surface'
});
var view = new View();
view.add( surface );
view.add( surface2 );
context.add( view );
Famo.us comes with many in-built views – such as FlexibleLayout, a view for providing ratio-based responsive layouts – that provide us with a starting point for our applications. By composing several of these views, we can quickly build common application layouts with minimal effort.
Get top Black Friday deals sent straight to your inbox: Sign up now!
We curate the best offers on creative kit and give our expert recommendations to save you time this Black Friday. Upgrade your setup for less with Creative Bloq.
Can touch this
Our application isn't going to be very interesting if we can't interact with it. Famo.us events are captured at three different levels. The first level is on the Surface, the second is the Surface's parent context, and the third and final level is the Engine.
surface.on( 'click', function( e ) {
console.log( 'Surface clicked', e );
});
context.on( 'resize', function() {
console.log( 'Context resized' );
});
Engine.on( 'keyup', function( e ) {
console.log( 'Keyup event', e );
});
Animation
We've covered many of Famo.us' basics, but we still seem to be focusing on displaying content, something that modern browser engines are pretty good at. Be it the animation of a scrollview or the transitions between screens and menus, our animations have to be smooth and feel natural to the user's input.
Famo.us achieves this by doing away with CSS animations, instead applying matrix transformations directly to the Surfaces it is animating. We will use a specific type of Modifier called a StateModifier , which is simply a Modifier which contains its own state via setTransform.
var context = Engine.createContext();
var surface = new Surface({
content: 'My first surface'
});
var modifier = new StateModifier();
context.add( modifier ).add( surface );
modifier.setTransform(
Transform.translate( 100, 300, 0 ),
{ duration : 1000, curve: Easing.inOutBack }
);
StateModifier's setTransform method allows animations to be triggered on Surfaces. The first parameter determines what we want to animate (such as rotations or opacity), and the second describes how it should perform the animation, including the duration and the type of animation curve. setTransform has a third parameter – a callback that runs once our animation is complete.
We're using Famo.us' Easing object to dictate the curve of our animation. The Easing object provides us with over 30 easing curves to use in our animations. Should we wish to sequence several animations, we can chain them by calling setTransform multiple times. When we chain animations, the previous animation will finish before the next one begins. Complex sequences of animations are simple to create using this pattern.
Physics
Where Famo.us really excels is the combination of its physics engine with animations. Our previous animation occurred over a fixed amount of time. Famo.us gives us the ability to create animations that occur for varying durations, depending on the way an element is interacted with, and with a choice of transition styles.
Transitionable.registerMethod( 'wall', WallTransition );
var surface = new Surface({
size: [ 150, 150 ],
properties: {
backgroundColor: '#67b2e8'
}
});
var modifier = new StateModifier();
context.add( modifier ).add( surface );
var wall = {
method: 'wall',
period: 500,
dampingRatio: 0.1
};
modifier.setTransform(
Transform.translate( 0, 400, 0 ), wall
);
This example shows how to register a Transitionable method called 'wall', which we use as the second argument to our StateModifier's setTransform method.
This causes our Surface to animate 400 pixels from the top of our context over a duration of 500 milliseconds, and when it arrives at its destination it bounces as if it has hit a wall, causing it to come to a gradual stop.
What's below the surface
Famo.us is an exiting framework that is simple to use whilst being incredibly powerful. This article couldn't cover everything it does, so check out the resources in the sidebars to find out more.
Words: Mark Jones
Mark Jones is lead front end developer at Kaldor Group. Follow him on twitter at @mark_jones. This article first appeared in net magazine issue 260.
Like this? Read this!
- Google releases 1,000th Chrome Experiment
- 14 top online coading courses
- 10 ways the Romans still influence architecture
Thank you for reading 5 articles this month* Join now for unlimited access
Enjoy your first month for just £1 / $1 / €1
*Read 5 free articles per month without a subscription
Join now for unlimited access
Try first month for just £1 / $1 / €1
The Creative Bloq team is made up of a group of design fans, and has changed and evolved since Creative Bloq began back in 2012. The current website team consists of eight full-time members of staff: Editor Georgia Coggan, Deputy Editor Rosie Hilder, Ecommerce Editor Beren Neale, Senior News Editor Daniel Piper, Editor, Digital Art and 3D Ian Dean, Tech Reviews Editor Erlingur Einarsson and Ecommerce Writer Beth Nicholls and Staff Writer Natalie Fear, as well as a roster of freelancers from around the world. The 3D World and ImagineFX magazine teams also pitch in, ensuring that content from 3D World and ImagineFX is represented on Creative Bloq.