question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal: New Animation & States API

See original GitHub issue

We’re changing the way animations are defined and how they interact with states. There are a couple of reasons for this:

  • There are two ways to animate a layer now: With layer.states.switch and layer.animate , we would like to combine them
  • The current way of animating a layer directly needs the properties: keyword, which is confusing for beginners
  • It’s not obvious how to specify animation options for state switches

This proposal tries to provide a solution for the above problems. please provide us with your feedback in the comments!

Basic animation of a layer

Just change a property

layer = new Layer

## Before

layer.animate
  properties:
    x: 100

## After

layer.animate
  x: 100

Change the animation timing

## Before

layer.animate
  properties:
    x: 100
  time: 0.5

## After

layer.animate
  x: 100
  options:
    time: 0.5

Change the animation curve

## Before

layer.animate
  properties:
    x: 100
  curve: "spring(250, 50, 0)"

## After

layer.animate
  x: 100
  options:
    curve: "spring(250, 50, 0)"

States

Add a single state

## Before

layer.states.add
  stateA:
    x: 100

## After

layer.states.stateA = 
  x: 100

Define multiple states

## Before

layer.states.add
  stateB:
    x: 200
  stateC:
    x: 400

## After

layer.states =
  stateB:
    x: 200
  stateC:
    x: 400

Notice the subtle difference between calling a function and setting a property. This means that where previously it was possible to add multiple states multiple times, in the new API we will override the existing states when calling layer.states = ... again. However, this is really unlikely and one could still achieve this by doing:

layer.states =
  stateA:
    x: 100
  stateB:
    x: 200

layer.states = _.extend layer.states,
  stateC:
    x: 300
  stateD:
    x: 400

Animate to state

## Before

layer.states.switch "stateA"

## After

layer.animate "stateA"

Add animation options to a state change

The options for an animation can be provided in a state as well

## Before

layer.states.add
  stateE:
    x: 200

layer.states.switch "stateE",
  curve: "ease-in"

## After

layer.states.stateE =
    x: 200
    options:
      curve: "ease-in"

layer.animate "stateE"

Instantly switch to a state

Switching instantly will become an option of the animation

## Before

layer.states.switchInstant "stateB"

## After

layer.switchInstant "stateB"

## Which will be a shorthand for:

layer.animate "stateB",
    instant: true

This means it can also be defined directly in a state itself:

layer.states = 
   stateA:
     x: 100
     options:
         instant: true

Move to the next state

## Before

layer.states.next()
layer.states.next("stateB","stateC")

## After

layer.animateToNextState()
layer.animateToNextState ["stateB","stateC"]  # Preferred
layer.animateToNextState "stateB","stateC"    # Also valid
layer.animateToNextState ["stateB","stateC"],
    time: 0.5

Notice how we use an array of states names here, to support animation options as second argument

Special states

There are three special states that will be set automatically and can’t be overridden:

  • layer.states.initial - The state the layer had upon creation. This will contain the properties that are provided to the constructor, not ones that were set in a layer stage (i.e. with layer.height = 100)
  • layer.states.previous - The previous state the layer was in
  • layer.states.current - The current state the layer is in

These states contain the actual values and not (as is the case with layer.states.current now) the state string. The name of the previous an current states will still be available through layer.states.previousName and layer.states.currentName.

Notice the absence of layer.states.next, this functionality will be provided by layer.animateToNextState() as described above.

Listing all the states

We will add a new property layer.stateNames that lists all the names of states currently defined on a layer. This list will contain layer.states.initial, but won’t contain previous and current.

layer.states = 
    left:
        x: Align.left
    right:
        x: Align.right

layer.animateToNextState()
print layer.states.currentName # "left"
print layer.stateNames # ["initial", "left", "right"]

Determinism

Out of this proposal, moved to #384 Is the previous state API the order state changes occurred influenced the resulting position of the layer. Consider the following example:

background = new BackgroundLayer
layer = new Layer

layer.states.add
    right: 
        x: Align.right
    bottom:
        y: Align.bottom
    left: 
        x: Align.left
    top:
        y: Align.top

background.onClick ->
    layer.states.next()

(Also available here: http://share.framerjs.com/ff6vwjpn0wet/)

Because not all states define all properties, you can end up with some in-between state (try clicking quickly in the example). Therefor we would like to make states deterministic. That is: every state defines every property. If you omit a property during the definition of the state, we use the initial state as the default value for that property.

Examples of this can be found here: http://share.framerjs.com/kthdx2kmp00m/ The red layer shows deterministic states, but all derived from the initial states, this layer will always end up in one of the corners, but never reach the bottom right corner The blue layer has deterministic states, and defines the x and y for every state, resulting in the intended behaviour.

Details

The formal API of layer.animate will be:

layer.animate(properties, options)

However, by adding the options key to the properties object, you can take a shortcut that looks nicer in coffeescript:

layer.animate
  x: 100
  options:
    curve: "spring"
    delay: 1

The same will work for states, so animation options can be specified directly in the state:

layer.states.stateD = 
  y: 100
  options:
    delay: 1
    time: 0.25

layer.animate "stateD"

## But could also be used like this:

layer.animate layer.states.stateD

## When options are provided, they override the options of the state

layer.animate "stateD",
  delay: 0 # Delay will be 0 and not 1

It used to be possible to set layer.states.animationOptions to change the animation option of every state change. This will be broadened to set the animationOptions for all animations on a layer:

## Before

layer.states.animationOptions =
  curve: "spring"

## After

layer.animationOptions =
  curve: "spring"

Pitfalls

Common pitfalls we expect with the new approach, so we should have excellent documentation and (if possible) error messages for them:

  • Setting one of the preserved state names: initial, previous, or current
  • Checking layer.states.current expecting a string

Issue Analytics

  • State:open
  • Created 7 years ago
  • Reactions:19
  • Comments:33 (8 by maintainers)

github_iconTop GitHub Comments

3reactions
nvhcommented, Sep 15, 2016

This has just been merged into master. The changes are fully backwards compatible, so every project should keep working if you choose ‘Update Framer Library’

2reactions
nvhcommented, Jul 14, 2016

Quick question, do we really need the key “options”?

Yes we do. Not only can the options potentially clash with properties on the layer, we also need a hook to support Auto-Code for animation options in the future

Read more comments on GitHub >

github_iconTop Results From Across the Web

Animation States - Unity - Manual
A new state can be added by right-clicking on an empty space in the Animator Controller Window and selecting Create State->Empty from the...
Read more >
Delightful UI Animations With Shared Element Transitions API ...
Shared Element Transitions API is a game-changing feature that will enable us to create impressive and elaborate UI animations easily.
Read more >
New feature proposal: Popover API · Issue #7785 · whatwg/html
This is a general class of UI that always appear on top of all other content, and have both one-at-a-time and "light-dismiss" behaviors....
Read more >
Proposal: Bring Nouns to life! Nouns Animation Generator ...
Nouns Animation Generator & Interactive App ... to programmatically access any of these animations instantly and seamlessly through an API.
Read more >
CSS Animation Worklet API - W3C
This animator can have local state and animation worklet guarantees ... is a new concept being proposed for addition to web animation API....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found