Home

Tweening

Tweening is a technique to create animation by smoothly transitioning an element from one state to another. In Famo.us, it’s common to animate the position of elements, but we can also easily animate rotation, scale, distortion, and opacity — any property we can control with a modifier.

To create basic animations in Famo.us, we begin with a starting state, and then transition the element to the desired ending state. It’s fairly simple to accomplish this type of animation using modifiers with functions, but Famo.us also provides a module called Transitionable to make it more convenient.

Unless you need to create complex (or more open-ended) animation behavior, transitionables are the recommended way to animate between states.

Transitionables

A Transitionable instance’s job is to change a numeric value smoothly over time. We set a starting value and an ending value; we get the intermediate values over time. (The transitionable instance will manage that value’s progression from the starting value to the ending value.)

Here’s the boilerplate: We instantiate a new instance of Transitionable, giving the constructor a starting numeric value (or an array of them) as the first and only argument. Then we immediately call .set() to set the ending value — also optionally passing a transition specification as the second argument. Finally, we call .get() to retrieve the intermediate values.

var transitionable = new Transitionable(0);
transitionable.set(1, { duration: 1000 });

// Elsewhere, we fetch the intermediate value calculated
// for the current time.
transitionable.get(); 

Here’s an example of a transitionable in action. Note that we’ve used an array of numeric values instead of a single one.

// @famous-block
// @famous-block-option preset famous-0.3.0-globals
// @famous-block-group transitionable1
// @famous-block-option textPanelActive true
var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var Modifier = famous.core.Modifier;
var Transitionable = famous.transitions.Transitionable;

var context = Engine.createContext();

// First we set the starting state.
// We can use a single numeric value,
// or an array of numeric values.
var transitionable = new Transitionable([0, 0]);

// Then we set the ending state, with the
// desired transition properties.
transitionable.set([.5, .5], { duration: 1000 });

var modifier = new Modifier({
    size: [100, 100],
    origin: [0, 0],
    align: [0, 0]
});

modifier.alignFrom(function() {
    return transitionable.get();
});

var surface = new Surface({
    properties: {
        backgroundColor: '#fa5c4f'
    }
});

context.add(modifier).add(surface);
// @famous-block
// @famous-block-option preset famous-0.3.0-globals
// @famous-block-group transitionable1
// @famous-block-filename en.md
# A basic transitionable

In this example, we transition the `align` property from `[0, 0]` to `[.5, .5]`, that is, from the top-left corner to the middle of the screen. (Note that we've left the `origin` value alone.)

The modifier's `alignFrom` method is called on every frame. Each frame, the transitionable's `.get()` method returns a new updated value.

Transitionables can be used to animate the align, origin, opacity, size, and proportions of renderables. To animate the transform components (translation, rotation, scale, skew), use a TransitionableTransform.

Chaining animations

We can use transitionables to chain animations together, such that one animation begins as soon as the previous one completes. To do so, we pass a callback function as the third argument to the transitionable instance’s constructor.

// @famous-block
// @famous-block-option preset famous-0.3.0-globals
var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var Modifier = famous.core.Modifier;
var Transitionable = famous.transitions.Transitionable;

var context = Engine.createContext();

var transitionable = new Transitionable([0, 0]);

moveToMiddle();

function moveToMiddle() {
    transitionable.set([.5, .5], { duration: 1000 }, moveToTopLeft);
}

function moveToTopLeft() {
    transitionable.set([0, 0], { duration: 500 }, moveToMiddle);
}

var modifier = new Modifier({
    size: [100, 100],
    origin: [0, 0],
    align: [0, 0]
});

modifier.alignFrom(function() {
    return transitionable.get();
});

var surface = new Surface({
    properties: {
        backgroundColor: '#fa5c4f'
    }
});

context.add(modifier).add(surface);

Halting / interrupting animations

If need be, we can interrupt an animation in progress. Transitionable instances have a .halt() method that can stop the animation at any time.

// @famous-block
// @famous-block-option preset famous-0.3.0-globals
var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var Modifier = famous.core.Modifier;
var Transitionable = famous.transitions.Transitionable;

var context = Engine.createContext();

var transitionable = new Transitionable([0, 0]);

moveToMiddle();

function stopMoving() {
    transitionable.halt();
}

function moveToMiddle() {
    transitionable.set([.5, .5], { duration: 2000 }, moveToTopLeft);
}

function moveToTopLeft() {
    transitionable.set([0, 0], { duration: 2000 }, moveToMiddle);
}

var modifier = new Modifier({
    size: [100, 100],
    origin: [0, 0],
    align: [0, 0]
});

modifier.alignFrom(function() {
    return transitionable.get();
});

var surface = new Surface({
    content: 'Click/tap me to halt',
    properties: {
        backgroundColor: '#fa5c4f'
    }
});

surface.on('click', stopMoving);
surface.on('touchstart', stopMoving);

context.add(modifier).add(surface);

To begin a new animation after halting, we’d need to call .set() on the transitionable instance again. Animations can be stopped and restarted as many times as needed.

TransitionableTransform

The Transitionable instance is handy, but limited, since it doesn’t allow us to succintly create transitions for the four transform components — translation, scale, rotation, and skew. To transition the transform property of a modifier, we need to use the TransitionableTransform module.

Using a TransitionableTransform instance is similar to using a Transitionable instance, except we pass its constructor a Transform instead of a numeric value.

// @famous-block
// @famous-block-option preset famous-0.3.0-globals
var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var Modifier = famous.core.Modifier;
var TransitionableTransform = famous.transitions.TransitionableTransform;

var context = Engine.createContext();

var transitionableTransform = new TransitionableTransform();

transitionableTransform.setTranslate([150, 150], { duration: 1500 });
transitionableTransform.setScale([2.0, 2.0, 1], { duration: 2000 });
transitionableTransform.setRotate([2 * Math.PI, 2 * Math.PI, 2 * Math.PI], { duration: 2000 });
transitionableTransform.setSkew([.5, .5, .5], { duration: 1000 });

var modifier = new Modifier({
    size: [100, 100],
    origin: [0, 0],
    align: [0, 0]
});

modifier.transformFrom(function() {
    return transitionableTransform.get();
});

var surface = new Surface({
    properties: {
        backgroundColor: '#fa5c4f'
    }
});

context.add(modifier).add(surface);

StateModifier

The StateModifier module encapsulates the transitionable-modifier-renderable pattern behind one interface, making it convenient to produce multiple transitions at once. It includes methods for transitioning all of a renderables properties: size, align, origin, opacity, and transform. (It’s called StateModifier because it’s so closely coupled to the renderable state.)

Rather than build our own relationship between a set of transitionables and a modifier, we can use just a single StateModifier instance which will take care of this setup for us. After the initial state is set, we can call .setSize(), .setAlign(), .setOrigin(), .setOpacity() or .setTransform() at any time to create an animation to the new state.

The second argument to each of these methods is the optional transition specification, and the third is an optional callback which will be fired when the animation completes.

// @famous-block
// @famous-block-option preset famous-0.3.0-globals
var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var StateModifier = famous.modifiers.StateModifier;

var context = Engine.createContext();

var stateModifier = new StateModifier({
    size: [100, 100],
    origin: [0, 0],
    align: [0, 0]
});

// The StateModifier manages the transitionables for us.
stateModifier.setAlign([0.5, 0.5], { duration: 1000 });

var surface = new Surface({
    properties: {
        backgroundColor: '#fa5c4f'
    }
});

context.add(stateModifier).add(surface);

Next: Easing Curves »