# Forces

Like Middleware, Forces allow us to define custom functions that apply to a tween.

The previous lesson stated that Middleware is applied at the Timeline level, and converts non-tweenable values (stings etc.) to tweenable values (numbers).

Forces differ in that they are applied at the Shape level. Their role is to adjust the value of a Shape's points and/or attributes post-tween.

Why might we want to adjust a Shape's values?

The main use case for a Force is to apply an "external force" to a Shape. An external force could be a motion path, rotation or physics.

Let's take the case of a motion path. Normally, when we animate a Shape from position A to position B, the movement between the two positions will occur in a straight line. To move the Shape along a motion path instead, we can use a Force. This Force would offset the Shape depending on its position in the tween.

## Create a force

A Force is just a function that is called on each tick of a tween. The function receives two arguments.

1. A Frame Shape – the data required to render a Shape. A Frame Shape is calculated by tweening between two Keyframes. It takes the form of an object that can contain three properties.
1. `points` – shape data as defined by Points.
2. `attributes` – an object of additional Shape attributes (eg. `fill`).
3. `childFrameShape` – an array of child Frame Shapes.
2. A Frame Position – a number (between 0 and 1 inc.) representing the Shape's current progress between two Keyframes.

A Force must return a Frame Shape.

As an example, let's create a Force called `shakeForce`, that randomly adjusts the `x` and `y` value of each point in a Shape.

```
import { shape, timeline, render, play } from 'wilderness'

const randomlyAdjustPoint = point => ({
...point,
x: point.x + Math.floor(Math.random() * 10) - 5,
y: point.y + Math.floor(Math.random() * 10) - 5
})

const shakeForce = ({ points, attributes, childFrameShapes }, framePosition) => ({
attributes,
childFrameShapes
})

const plainShapeObject = {
type: 'rect',
x: 5,
y: 5,
width: 10,
height: 10,
fill: '#1F9FFD'
}

const keyframe1 = plainShapeObject

const keyframe2 = {
...plainShapeObject,
transforms: [[ 'offset', 80 ]],
forces: [ shakeForce ]
}

const shakyRect = shape(keyframe1, keyframe2)

const animation = timeline(shakyRect, {
duration: 2000,
iterations: Infinity,
alternate: true
})

render(document.querySelector('svg'), animation)

play(animation)
```

Wowzers. What a shaky little guy.

Notice in the example above that we add Forces to a Shape by defining a `forces` array on the Keyframe we are tweening to.

## Force helpers

Wilderness has a couple of Force function helpers built in.