Try dragging on the Emotion wheel to see the face change accordingly!
<iframe style="border: none" width="375" height="700" src="https://rive.app/s/prkQY3ESnEGSvUb1vrJnsQ/embed?runtime=rive-renderer" allowfullscreen allow="autoplay"></iframe>
Keep reading to find out how to interpolate smoothly beyond the native 2 dimensions that Rive Joysticks by default provide~
## Inspiration 🔥
I saw this great demo from JCToon at Rive for animating thru facial expressions
https://rive.app/community/files/669-1300-facial-expression-demo/
![[JCToonAimationDemoFast.mov]]
It was so cool to animate thru different emotions smoothly using the state machine!
But I wished for a better UX than adding buttons, and I didn't want to reach for a deeper Runtime driven integration just yet!
I want to be able to create more expressions for my character, _Aam_ in my app, [Bolo Baccho](https://bolobaccho.imagimationstudios.org)
## Setup
### Rigging states
I started with a simple face, grouping all the parts
![[01_Simple_face.png]]
Then, I added some bones for the paths I want to move and weighted them accordingly
This picture shows the hilightedbones associated with the Mouth's path
![[02_Bones_face.png]]
Next, add unique timelines for each individual facial movement, these will be used later
<iframe style="border: none" width="375" height="375" src="https://rive.app/s/rGQP46R6vU29fW4ymFy39Q/embed?runtime=rive-renderer" allowfullscreen allow="autoplay"></iframe>
Next, add joysticks to drive each of these facial movements
The joystics should be mapped accordingly to each timeline we created for the facial movements
![[03_Joystick_face.png]]
Next, add a unique timeline for each emotion by adjusting the joysticks until you get your desired expression for each primary emotion
- Anticipation
- Joy
- Acceptance
- Fear
- Surprise
- Sadness
- Disgust
- Anger
- Neutral
Interpolate from neutral to the extreme
<iframe style="border: none" width="375" height="375" src="https://rive.app/s/e6M3KR4tzkySKYiGA1i2-g/embed?runtime=rive-renderer" allowfullscreen allow="autoplay"></iframe>
## Composing the Emotion Animations
### "Dial" control
We want to create a target that has its movement constrained to a circle, similar to a dial.
![[Dial constraint.mov]]
- We create a target `group` in the _center_ (I've added a red and green big circle to make it more visible)
- We create a `bone` from the _center_ out to the max distance we want
- Create a target`group` to the rod end (cyan and orange circle)
- (This is important for our `mix` controls later)
- Create a target `group` to later track the position of the pointer
- Create an `IK Constraint` on the bone to the pointer target
- Create a `Distance Constraint` on the pointer target to the center group (to keep it closer than the max distance of the rod)
- ![[IK_Dial_Constraint.png]]
With this ready, we can use the dial to drive the interpolated emotion dimensions we'll use in the next step
### Emotion Dimension
For each emotion to work in a designated direction for our rig, we'll need to achieve 3 things
- Control the `intensity` on the main-axis
- Control the `mix` on the cross-axis
- Prevent the opposite emotion from interfering with our `mix`
Below, you can see how we achieve the first to goals using this `T` arrangement of Joysticks
The cross-axis controls the `mix` animating from 0 at the extremes, to 100 in the center
The main-axis animated from 0 to 100 monotonically
- Set the cross axis control's `Handle Source` to target the _rod end_ `group` from the previous section
- Set the main axis control's `Handle Source` to target the _pointer target_ `group` from the previous section
![[Composed Emotion Vector.mov]]
### Solving the opposite emotion `mix` issues
By just using this, we'll run into a problem when we include opposite emotions
Since opposite emotions share a common axis, their `mix`es will interfere with eachother and the most extremes of emotions will actually be pulled back down to neutral 😁😐😢
When we try to interpolate at the extremes, `Rive` thinks that both Joy and Sadness should be mixed to 100%, so they cancel out and we underwhelmingly get a neutral face when we expect a happy face
To prevent this, you'll need a trick!
- Ensure sure the `joystick`s have ticked, the `Draw in World Space` option
- Make a `group` to hold the cross axis (cmd + g)
- In the _intensity_ timeline of the Joy emotion, set the rotation of the `group` we just created to 90 degrees
This will create this cool mechanical effect which solves our conflicting mapping issue since at the intensity extreme of Joy, the `mix` for Sadness will be sent to 0 via the combined effect of the handle source and the rotation of the `joystick`
Cosine ftw!
![[Opposite Axis Mix Solution.mov]]
### Interpolating all the emotions
You can now repeat this process for all of the emotion dimensions and you'll end up with this really satisfying effect that is reminiscent of the `Trammel of Archimedes`
![[Trammel of Archimedes.mov]]
I hope you found this useful and _Rive_ -eting