# The (Finite) State of Reactive Animations

Canonical: https://davidk.dev/talks/the-finite-state-of-reactive-animations-fedc-taiwan-2018/
Video: https://www.youtube.com/watch?v=ZENUkQUl1_w
Speaker: David Khourshid (@DavidKPiano), creator of XState
Type: Conference talk · Event: FEDC Taiwan 2018 · Year: 2018 · Duration: 39:41 · Views: 874 (as of 2026-10-19)
Topics: Reactive programming, CSS & animation, Statecharts, State machines, Visual modeling

## Summary
Observables are core to what's known as reactive animations, and this differs from normal animations. One of my favorite quotes is any sufficiently complicated state management library contains part of a state machine, so we see all of these libraries that have invented ways of doing state machines.

## Key takeaways (quoted from the transcript)
- Let's say we're doing a sample search app, right where we have an initial state of idle, we're trying to search for something so then we could model that. (17:00)
- The reason nothing is happening is because our state machine tells us that when we're in that state and we get a submit event, nothing happens. (20:00)
- We needed to model this, and so that's why I used a state machine that looks just like this now. (23:00)
- The way you would use this is you would create a state machine, which is just these pairing of states and actions and events. (31:00)
- If you're using finite state machines, then you reduce the complexity at first. (35:00)

## Chapters
- 0:00 Introduction
- 10:00 Put in the password and you get the link if the…
- 13:00 First of all, it's very difficult to test this code
- 15:00 In this case, we're going to be modeling a promise…
- 22:00 Such as signing in, signed in, sharing, shared, joining, joined
- 27:00 The way you would use this is you would create a…
- 33:00 NASA used statecharts for modeling the software for the Curiosity rover
- 38:00 Making that a lot easier to do so…

## Transcript
[0:00] Hello everyone, good afternoon. I think you guys already have your lunch already. I hope you enjoy like me. Our session starts here. As a fine developer, we always need to deal with a lot of stuff. With JavaScript and CSS, CSS variables are here and are much more powerful. And you think in this talk we will have a poem, the many possibilities with RS J's with CSS variables that we have. A Devi crocheted the finest day.

[0:00] Over-reactive animations. That's a wrong screen. One minute, Okay, there we go. So my name is David Khourshid and I'm very excited to be here in Taipei, Taiwan. I've been enjoying all the food and I'm going to be here until Wednesday, enjoying even more of the food. I do a lot of animation, it's my passion. I work at Microsoft, where I don't get to do too much animation. At least not quite yet.

[1:00] But right now, me and one my friends. We set up a streaming site in which we create reactive animations and just all types of complex animations, and we stream them live weekly on Twitch.Tv. Slash, key framers and so the kinds of things we do are just designs that you would see on Tribble, where they're not the simplest. Animations. So we described how you would actually create these animations using CSS, HTML, and a little bit of JavaScript.

[1:00] And so they ranged in complexity. We do 3D animations and even just complex app animations that you would actually use when creating various applications. So so, yeah, please, you know, check us out keep Riemer's their Twitch TV slash key framers now. I was actually worried about coming here because I saw this as I was, you know, planning my trip. But this is something just to give you an idea of where I'm from.

[2:00] This is something that we have in common because I live here in Florida, so we also have hurricanes, typhoons. But one problem that all developers have is the concept of time in dealing with time. I think that the most neglected variable is time, especially because as developers, we have so many different ways of describing time. We have callbacks, promises, async/await. And my favorite observed a balls. And so this is the one that I want to focus on, because I think that observables are one of the.

[3:00] Best ways of managing time because observables treats time as a first-class citizen, how many of you have heard of observables or RxJS? Or, okay, not very many people, or maybe you're all shy. Observables are core to what's known as reactive animations, and this differs from normal animations. That you would see, like, is sort of like a movie. A timeline, a reactive animation instead depends on what the user does or what events are happening.

[3:00] For example, we could take audio input and we could generate these visualizations based on that, or we could take the users mouse clicks or finger movements on a touchpad or a screen. And we could turn those into animations. And so the official definition is that a reactive animation is one that involves discretes changes. These are the animations due to events, and these events can come from anywhere. And so just to give you an idea of the best way to think about an observable in JavaScript or any language.

[4:00] Really. Think of a value, so a value is a single object, it could be string, it could be a number in object, just anything. Now we have a race and arrays, our collections of these types of values. Neither values nor arrays exist over time, they exist at this very moment, and so they have no concept of time. But that's why we have promises native to JavaScript. In other languages, they might be called deferred or futures or tasks, but in JavaScript we know these as promises.

[5:00] And a promise is a value that occurs over time. But what if we combine arrays and promises? Then we have observables? Observables are multiple values that occur over time, so you could think of them as an array, and the promise combines together. So I use arcs J yes to create observables. There's many other libraries that you could use, such as most J. S. Bacon, kefir. But RxJS is by far the most popular in JavaScript.

[5:00] And so what you would do is from here, you would npm install' RX.Js, and they even have some really great documentation at reactive XZO Slash RxJS, and this is actually brand new documentation. So I really encourage you to check this out. But while you would typically do like grabbing a mouse move from an event listener, instead, we use some built-in. Functions in ARCs GS, such as from events and built-in operators that take these streams and transform them, such as map.

[6:00] So, for example, to create a simple mouse move stream, you would do from events on the body and you would capture the Mousemove event. And so this represents an observable stream of mouse move values over time, so whenever you move your mouse, it's going to emit those values. And then you could transform those using the pipe operator, or using pipe and using operators into various positions. So once you have these streams of values, you could then subscribe to them.

[6:00] And what that means is, whenever one of these values are emitted, then you could take that value and you could do anything you want with it. One of my favorite things to do is take those values and set them as CSS variables. So how many of you have heard of CSS variables or custom properties? Okay, so that's, that's a lot more of you, which is great. There's many applications to using CSS variables, and one my favorite is for doing reactive animations.

[7:00] So this is a dog I created from a Tribble Baikal shear, and I thought it was really cute and I decided to make it using CSS only. However, someone commented that they thought the dog was moving too fast. So what I did was I created an observable, and I, I made that observable. Listen to these values over here in this input so that I could reduce the info that's too fast. Sorry, juicy addendum make it go a lot slower.

[7:00] And so those variables are being transferred over to CSS, and then I could use those to determine the animation duration. So another one is this by the same dribbble author Gal Sheer. And so I could just swing the cat, and so what I'm doing here is something pretty similar. I'm using Hammer J S in order to listen to these touch events, so these pan events, and so it listens to it. And then whenever I let go of the mouse or let go of my finger, it will swing the cat, so just like that.

[8:00] And this is a more complex example. But this gets to what I'm going to be talking about in this talk, which is designing complex user interface interactions. So this. One same thing we set up and observable to listen to the values over here, so that it changes each of the numbers in a smooth way. But you could see that there's other things going on, for example, the numbers at the bottom, they're growing, and the text at the left and right, they're moving away.

[9:00] Whenever, whenever my mouse is still on the slider. So the question is, how can we model the behavior of these complex user interfaces? Especially when we have a design or some sort of interaction that we need to model? And we need to represent and code in a way that's easily maintainable and also fast in performance and something that will make the user happy. So when we think about API is just normal programming, we think about its structure, its documented, you know, we understand it, it's predictable and it's testable, so dealing with computers is pretty, pretty straightforward.

[9:00] You know, we, we know exactly what's going to happen, however.

[10:00] And this is one of the reasons that I both love and hates. Front-end development is because we have to deal with human API's. They are undocumented, unpredictable and completely untestable. So what we need to do is think of a framework. Lissa Proach I. I don't want to come here and talk about how to do this in React, or how to do this in view or Angular. If anyone here uses it, probably not.

[10:00] So we're going to be talking about state machines today. In order to do that. One of my favorite quotes is any sufficiently complicated state management library contains part of a state machine, so we see all of these libraries that have invented ways of doing state machines. But it's it's very valuable to learn exactly what, what is the state machine, so to exemplify why it's important to do state machines. I saw this model I wanted to create recreated, because even though it looks simple, there's a lot of little things going on.

[11:00] And I wanted to capture the behavior of this mogul so that we could actually put it to code. So let's start off not thinking about, say, machines, just doing it like we normally would. In this case, I'm using reacts, but you could use whatever you want, so the first thing we would do is it's a. By the way, let's go back. This is a simple modal for you. Put in the password and you get the link if the password is correct.

[11:00] And so it sends it off to the server to check if the password is correct. So the first thing we would do is we would probably have some method where we send the password to an API and then we get the results, hopefully the passwords, right? Maybe it's not, but there's more complex interactivity. We also have to hide the loading screen once the password comes in and show the results, so we have to add this code.

[12:00] But also, what if there's an error? Or, well, what if we have to handle the case where the password is invalid? Because, of course, they might choose an invalid password, and then we have to also remember to hide the error screen if the user tries again. And we have to manage what happens if something else fails, like maybe the password didn't fail, but the server, the API failed somewhere, so we have to capture that behavior as well.

[12:00] And then what if we wanted to cancel, like, what if the user was trying to search or trying to trying to send the password? But it was taking too long, so they decided to cancel. So adding cancellation comes with a lot more complexity. I know that's pretty small for you to see, I'll make it bigger, so, but yeah, so you can see that the code quickly becomes very, very complex.

[13:00] And this is called the bottom-up approach. So the bottom-up approach is when we as developers, we take an event, and it could be any event. A mouse click, pressing Gus, submits, pressing any key. And then based on that, we do a bunch of actions based only on that event. And then some of these actions might update the state and some of them might not. This is how we typically develop, but this has a lot of problems.

[13:00] So, first of all, it's very difficult to test this code. Because different actions can change the state in different parts, and you cannot predict when those changes are going to happen. It's also very difficult to understand, you can't just read the code and be able to tell someone, Okay, I know exactly, you know how this is. Supposed to behave, what features it's supposed to have? It will contain bugs, and I'm not saying it might contain bugs, I'm saying it will contain bugs.

[14:00] Because the number of possibilities in edge cases in your code are so many that it's impossible for you to completely cover every single use case. It's also going to be difficult to enhance. So you have all this complex code and then someone tells you that you need to add a feature. Now, it becomes a lot harder to add that feature because you have to make sure that none of your other code will break.

[14:00] And also, adding features makes it worse because it increases the complexity of the code. So there's many problems to this bottom-up approach. So, we discover a few things when we're really thinking about our code. First of all, components are not independent, components depend on each other. Sometimes, in fact, more often than you would think, for example, in this animation example, when were swiping left and right.

[15:00] It's not only the bottom part that moves, but also the top part that moves as well, and so those components are related to each other. Also, actions cannot be based on events alone. So when you add a click handler, you need to know what the current state of your application is in order to do the right behavior when you're handling that click. And so with this, the event action paradigm is much too simple.

[15:00] We all so have to think about what state in the application we're in. So that brings us to finite state machines and statecharts, so finite state machines are. Actually. It's a very simple model of software, software design. It's you could think of it as you have one initial state. So in this case, we're going to be modeling a promise, so your initial state is idle. The promise isn't doing anything yet. It has a finite number of states, so a promise can be idle, pending and then either fulfilled or rejected.

[16:00] There's a finite number of vents that can happen. So once you fetch the promise, it could go from idle to pending, or be promised, could resolve, or it could reject as well. And then you have a state transitions, and these transitions map one state to the next state, based on what event. Just occurred. So, for example, if your promise is pending, two things can happen. It could either resolve or it could reject.

[16:00] And then you go into those next states. If it's pending and it resolves, you go into fulfilled and reject is the same, and then you. According to the definition, you also have five final states, so you could consider fulfilled and rejected the final states. And so let's say we're doing a sample search app, right where we have an initial state of idle, we're trying to search for something so then we could model that.

[17:00] As once a user click search, you go into this searching state, and only when you're in the searching state. Do you go to either the success or the failure state. Based on the results of the promise. So one way to do this is by using switch statements or if-then statements. But what I prefer to use is just an object, and so this object structure I have. I. I have an initial state which is idle, right here, I had a bunch of states which is idle searching success and failure.

[17:00] And so in order to determine what the next state is, we just take the current state which is searching, and then we take the events that just happened, so in this case, we take resolve and then from that we get our next state. So when you're searching and you do a resolve event, you go to success. And so that's that's in that function at the very bottom, the transition function. So all it is, it's an object lookup, you could use which statements, you could use if statements, but I prefer using an object.

[18:00] Then I'll talk about why. So let's say that we took this state machine and we actually put it to a real app. I'll show you what that looks like. So right now we're in the idle state and so let's say I search for Taiwan. So now I could actually cancel and so that cancellation from that same object that I have. If I go to cancel search, then I go to this gallery state.

[18:00] Which means if the promise resolves, then nothing happens. It's not going to put the results on the screen because I cancelled, so let's search again and let it go through. Now we're on the. Second state which is which is gallery, and then we could click one of these photos and we could go to one of these photos. So this is a separate state in our state machine. And so I have an article talking about this at the very bottom CSS tricks Calm, where you could learn more about how I built this using finite state machines.

[19:00] So let's go back to our original example, where we have this password modal, right? So, we have a few states here, this one I call the idle states, and then a few things can happen. The first thing we have to consider is that the user could enter in incorrect password, and when that happens, we go to this incorrect password. States and then it reverts back to the current states. And now, if I do the correct password, that should go to the success state and so at state.

[20:00] Notice that clicking submit doesn't do anything, and so if I reset the form and I do that and I click submit, nothing is happening. And the reason nothing is happening is because our state machine tells us that when we're in that state and we get a submit event, nothing happens. So this is one of the things I love about state machines is that we could visualize application behavior. So let's say we're in this idle state and we click submit, then we're in the validating state.

[20:00] And then two things can happen, either a success or an error. And then we see from the error that we could actually go back to the idle state. And so here's another example. And this is one of my first uses of a finite state machine. Because there was a pretty complicated parts to making this, which I'll show you. So I'll drag up like it says, and it was this. When I was dragging up here, I had a bug, and the bug was if I started dragging up and then dragging left.

[21:00] Then it would also go to the left or go to the right, and I didn't want that, well, I wanted was. If I'm moving left and right. And I try to go up and down, it would still be fixed to left and right, and same thing up and down if I try to go left, right it. Wouldn't try to go left or right. And so to do this, I set up a state machine, which I know it looks pretty crazy, but the state machine we start in the idle state.

[21:00] And then once were, for example, panning up or panning down. Then we're in be vertical states. And so what this helps us do is make sure that if we pan let the rights, because we're in that vertical state. There are no transitions for panning left or right.

[22:00] And so we could control what happens when an event occurs on the states that, you know, says nothing should happen when this event occurs. And so we could fine tune the behavior of our applications that way. So I work at Microsoft and my last team, I just recently changed teams, I worked on. Visual Studio live share, and what life sure is, it's a. It's a collaborative coding platform using visual Studio code or visual Studio.

[22:00] We're two people from anywhere in the world can both code on the same project together, collaboratively. Now, there were a lot of complexity in the UI for doing this. I had to work on the sign-in flow because there's more than one way to sign-in, you could sign-in externally, you could also. I mean, this is a simplified version, but once you're signed in, the user could do one of two things. The user could either share a session and then it would copy a link and then you could give it to another user anywhere in the world.

[23:00] And they would be able to jump into your session and join your session. And of course, this sharing and joining it could succeed or it could fail. And we needed to model this, and so that's why I used a state machine that looks just like this now. I found a lot of advantages to modeling that as a state machine. And one of the advantages was that, first of all, we could capture rich analytics from the state machine.

[23:00] And that's because every single transition, every single possible thing that the user could do in the application was captured. So we could model exactly what's happening in the app. And so this was generated from those analytics and so we could see that a lot of people went from initializing to signing in, and then about. Half the people when from externally sign error to externally signing in or to signed in. And then we could see the error rates, so thankfully there weren't that many errors.

[24:00] When people try to, for example, share a session or join a session, but we could visually see that and analyze that. And so this means that you're thinking of your applicationnow as a directed graph. So each of these notes are states of your applications. Such as signing in, signed in, sharing, shared, joining, joined. And then we could see how many users are going from, for example, signed into sharing or signed into joining.

[24:00] And we could visualize that and see which one of these links is bigger. So another thing that same machines are useful for is writing integration tests, which are painful. And so we could do this by simply tracing the path through our application. And so that's why whenever I see developers write unit tests or integration tests for applications, they are not capturing every possible thing that can happen. And that's a problem because this is, for example, only one possible path, but you could see that there's many other paths that a user could take.

[25:00] So they could go from A to B, or A to B, the C or A to the E to E, or many, many, many other paths. And so you could use, for example, a shortest path algorithms such as Dykstra, Bellman-Ford, some of the other ones. Analytics can provide weights like we've seen before, and so we could determine which are the paths that we should be testing the most. And these represents pretty much all the happy paths, which a happy path is basically the shortest path from the initial states to the desired states.

[26:00] And, of course, these could also be automatically generated just by running the algorithm on, you know, these state machines and say, charts. So we could also use a deck first search algorithm and generate all the possible simple paths in the state machine. And so a simple path is, it's not the shortest path, but it's the path where no state is repeated, which is a typical use case. Because we know that our users are probably not going to be going back and forth on the same two states.

[26:00] That's a little silly and so. It represents all the possible user flows that a user can take, and it also reveals all of the edge cases in our application. These can also, of course, be automatically generated with the algorithm. But the good news and bad news is that it generates a ton of paths, and each one of those paths represents what a user could do in your application. And so I gave a workshop recently where we actually did generate a bunch of a bunch of these integration tests.

[27:00] And we ran them using Puppeteer by Google.

[27:00] And it opened a Chrome instance in, it, actually clicked through the app and made sure that everything was working. So it also makes software bugs visually clearer once you visualize these applications. So, for example, let's say that this is our state machine, and an error occurs. We could see visually that we're not handling the case where we have an error. And so we could just as a fix for that, by making a transition from loading to failure and showing some sort of failure or error state.

[27:00] And so you might be thinking - that we might have missing empty states, or missing, or states that are impossible to get out of that, for example, this failure state. We cannot escape that state and we cannot go back to loading, so we have to. We could visually see that, we have to add a retry button, so it does this scale. It's sort of. The problem is that sometimes states can be so numerous that you get into what's called state explosion, where you have many, many different states.

[28:00] And so this is where statecharts come in, so just to briefly talk about statecharts. Statecharts introduce new things on top of state machines. For example, they introduce actions such as on entry, on exit and transition actions. So let's say that were searching on. Thus, on entering the searching state, we could start fetching the results in telling the API that we need to fetch these results. We can also add guards, which are like conditional statements, so we could say that only search only.

[28:00] Transition from idle to searching if the query length is greater than zero, that is if the user actually typed something in. There's also hierarchy where we could nest states together, and orthogonality where we. Could represent states that happen at the same time and history, which is very useful. For example, if you're on the payments form and you go to the review page and then the user goes back. You want to remember what the last date was, so that your user doesn't have to redo everything again.

[29:00] And so this is an example of why it's good to have, for example, parallel states over here. Imagine a a text editor where you could either have bold, italic or underline. This is all the representation of those three buttons, where you can have a state where bold. Assaf at Alex's off, underline this off, and then any combination of those. However, if we have just three parallel states where you have bold on or off, italics on or off, and underline on or off.

[29:00] It simplifies the visualization of the state machine, and so hierarchy is another great way to simplify a state machine. For example, we see that these two success and failure states we could search again from them. So what we could do is we could group these together into one state and say this is the search state. They have sub states then of success or failure, and then you could resume the search from there.

[30:00] So I created a library called XState, and what XState does is. It allows you to create these state machines in a very simple way. So it looks just like JSON, and it acts just like JSON. It takes this definition of a state machine and it allows you to determine what the next state is based on the event. So it also includes support for actions, guards and hierarchy, also orthogonality in history states as well.

[31:00] So the way you would use this is you would create a state machine, which is just these pairing of states and actions and events. And then you would have some sort of send function where you determine what the next state is, and then once you determine the next state. It's up to you, in whichever way you like to, to update the state yourself and to execute all of the actions that are returned.

[31:00] And so this is just a reducer function, which means that you could use this in React in view using Redux. Mob acts, anything you're. Using. In fact, sometimes I take the framework, this approach, and I don't even use this within the framework. So I this is an example of where I would use XState and so on. This is another dribble that I created - oh sorry, dribble that I recreated. And it's this cool, complex interaction where the user could do many things.

[32:00] For example, the user could hover over many states and then maybe let go outside, or select these states, and click outside, or select the states, and then drag. So you can see, there's many actions that are possible. And let's say we could throw these away and we can make our sundaes very, very long, which I wish we could do in real life. So this is modeled by this state machine, and I know it's hard to read from back there, but basically I'm where we're moving from state to state.

[32:00] And it reduces the complexity of the application a lot. Because we could visualize which state we're on and what actions and events happen when moving from one state to the next state. And so there's this selecting state and you're selected. And then once they're selected, you could drag them, and then you could dispose of the days, and then you could grab and drag the states or the days.

[33:00] So there's many advantages to using the statecharts. And one of the most important ones, in my opinion, is the Curiosity Rover by NASA. We the United states sent this Rover to the moon, but not before an incredible amount of testing and engineering effort. Because this thing costs like many billions of dollars. So they had one shot. And so imagine having a software project where if you had a single bug, then it would be a waste of a billion dollars.

[33:00] I mean, hopefully none of you have projects like that, but this is exactly what we had here. And so NASA used statecharts for modeling the software for the Curiosity rover. And so what they found was many advantages, including visualized modeling, very precise diagrams, code generation, and also test coverage too. So they use these date charts to generate tests and to make sure that every possible ping Beca go wrong was covered. And also accommodations of late-breaking requirement changes.

[34:00] This is one of the things I talked about. Earlier where? If someone comes to you and says, we need to change this, or we need to fix that, then. You don't need to go through your entire code base and figure out what needs to change because it's all very visual. And you could just look at the graph or look at the state machine and understand which parts of the state machine needs to change.

[34:00] So there are disadvantages, too. First of all, it is a learning curve. And I, I can't teach all of the different parts of state, statecharts and state machines to you in only 40 minutes. Which is why I provide a lot of resources for it. Also, this modeling requires planning ahead. So in the startup world, I guess we like to move fast and break things, so modeling your software sort of takes the opposite approach, it's more move slow.

[35:00] And make sure that things are properly modeled so that you know exactly how your application is going to behave based on how you modeled it. And also, statecharts can't be used to model absolutely everything, but they can help with a lot of the higher-level application structure and behavior. And so I like to visualize it this way. If you're doing software development, normally, the more code you add, the more complex your code gets.

[35:00] If you're using finite state machines, then you reduce the complexity at first. But once you add more and more states, you see the complexity exponentially grow. Statecharts are the opposite at first they make they might be complex to set up, but after a while you see that. Statecharts greatly reduce the complexity of your growing application. And you could also visualize tea charts too. So this is one of the examples of the gallery app.

[36:00] What I did was I copy and pasted that JSON structure from the gallery app and I put it in here. And from there, we could actually visualize the application as we're moving from state to state. And, you know, you could zoom in and like, just ensure that the behavior is correct. So, for example, in this gallery, we could select a photo which goes here, and then once we press exit, that goes back to the gallery.

[36:00] So we could ensure that the entire application behavior is correct. There's also a fervor. For the designers out there, there's a brand new site called Sketch dot systems in. This is an excellent project because Sketch thought systems allows you to create simple state machines and to actually use them for prototyping your applications. So this is much more powerful than sketch or envision, where you just only have one state at a time.

[37:00] Over here, you could model all of the possible actions of the components that you create, and so it's it's very visual. And actually, one of the great things about it is that you could export these state machines that you create in sketch systems over to XState. And so, I'm working very hard on XState. I'm working on creating more powerful visualization tools, testing tools, just because with state machines there is so much that you could do.

[37:00] And you're basically taking your code that you would normally write, and you're using the exact same code to analyze your application to generate tests for your application.

[38:00] And also make things like complex interactions, which are important in modeling these animations that you would have to handle in your app. Making that a lot easier to do so, there's many resources and tools available for you, especially this world of statecharts, which talks about the advantages of statecharts and basically everything you need to know about statecharts. And so, you know, I've heard the saying right once, right, anywhere, that's JavaScript, and then we had learned once, right, anywhere.

[38:00] And so that could be thought of as reacts, reacts native, but with statecharts were modeling once. And we're implementing absolutely anywhere. Because these could be carried not only just in JavaScript, but also in other languages as well. So thank you very much Taiwan, thank you and I, Otto Llama someday as long as your demo, and I do love the animation as well. So our next session will be in ten minutes, we will be back in 130.

[39:00] See you later guys. Thank you Davi again, show you a big hand.
