 We've heard a whole bunch of great talks already, awesome stuff. We've heard a lot about user experience, and I don't think that's a coincidence. I think we're clearly a community that gets the value of user experience, and it flows directly out of some of the core ember values, right? We work hard on shared solutions and infrastructure so that we spend progressively less and less time on that minutia. And then the work that's left over, the work we never get rid of, is the hard stuff, right? It's deciding how to generate that great experience for our users. And when you think about user experience design, most people think right away about building experiences for end users, right? If you're front-end dev, that's, you do that a lot, maybe you work with somebody whose title is actually user experience designer, and those people are awesome, they help an awful lot. So I want to argue that every developer period, full stop, is always a user experience designer. Sometimes your user is an end user, sometimes your user is another developer who's going to have to interact with your code, sometimes that user is your future self, that you're either helping or punishing when you're going to come back to that code months later to look at it, right? So this talk today is going to talk, I'm talking about user experience and there's two key audiences whose experience, I want to talk about today. The first is the end users that we're serving and building great experiences for them. But the second, of course, is the great experience for ember developers, right? And those are two sides of the same coin. I don't think you can have one without the other. So that's the kind of big picture of where I'm going with this talk. So computers, right? They're really abstract and that's what's awesome about them. They're almost infinitely flexible, right? The kind of things that you can present to the user are limited almost just by your imagination. And that's one of the things that makes them awesome, but it's also exactly why computers are so intimidating and frustrating for so many users and so many people because we have all this amazing machinery in our heads, in our eyes for processing the physical world, right? The physical world is what our brains evolve to process. We have all these cues and hints that we take advantage of and take completely for granted that almost every human being can do and it makes it's ways of thinking, ways of perceiving, ways of understanding where you are and what you're doing, what's going on around you. And when you take human beings and you drop them into a screen world with very abstract shapes and things that don't behave physically, they get lost and all of a sudden you actually disable whole chunks of their own ability to think and perceive, right? There's a lot of different ways humans think and perceive and we leave a lot of that behind when we limit ourselves to a very abstract visual kind of in the square box. Now that's actually a really big problem that's bigger than anything we can address right now here. We're going to talk about attacking that problem and chipping away at it. The larger problem is one that we're all going to work on over the long term as we build better and better interface technologies. But we can talk about at least making the visual piece that we do have control over much closer to physical reality. And we do that by bringing in constraints. So your computer can't show anything, right? You don't have to pretend that the objects on the screen have mass or momentum or that they cast shadows, right? They can go anywhere they want. When they're not on screen, they're not really anywhere, right? But that's deeply weird to human beings. And so when we constrain ourselves and we put in the extra effort to pretend we're physical, that's the underlying reason that we see all these. That's why we feel so great about the user experiences of more physical UIs. So some of our earlier talks have already mentioned Google's material design spec. Material design is a, it's a wonderful document, you should check it out. And like Lauren Tan said to us yesterday, remember that design is not about how it looks, right? It's about how it works. And so even if you have no interest in making your app look like Google's apps that they write when they design with material design, the principles in there are extremely good stuff. And they touched directly on my earlier point about physical constraints. So here's a quote from the introduction to material design. And I highlighted in big bold letters without breaking the rules of physics. And the doc goes into a lot more detail about what they mean by that. But there's, the kind of examples are things like two objects should not really be able to pass through each other. Or things that are on top of each other actually do cast shadows. Or things don't accelerate instantly from zero to going fast, right? All these little things, the fundamentals of light surface and movement. There's that word movement again, right? Motion respects and reinforces the user as the prime mover. So this is why we care about motion, right? We had a great demo of all those polymer driven animations. That's exactly what I'm talking about. The reason that stuff is so appealing, the reason we immediately get it is because it's appealing to that part of our mind that makes these things seem more physical to us. So then of course the key question is, how does this fall into Ember's broader architecture? And this is where we switch the focus from the experience of the end users to the experience of the Ember developer, right? The challenge that we always have as we develop Ember and we evolve it together as a community is to find great APIs that we cannot live with and work together with and build great conventions and tools and move on to build the next great thing. So what I'm gonna talk about today is where you fit all this stuff in to the Ember architecture and how you do it. So animations and motion in general, right? When I saw, I guess I should first point out, right? I'm kind of using the terms interchangeably. Animation can mean a lot of things. Remember the principle I just had on the last slide about, the user is the prime mover, right? That's really the kind of animation we're talking about. The user does something and then we have smooth motion in reaction to the user, as opposed to the kind of animation that we have always had in terms of like flash ads where you have to whack the monkey or, you know, that's not the kind of animation I'm talking about. So animations really live in the gaps between what was and then what becomes, right? The animation is what's happening in between what the state was and what the state becomes. And so it's not really something that's a property of your, say for example, a template in Ember because the template is the static thing at the end, right? You have a template before, you have a template after and that's the conventions that work great for us. So you need to find a place for the animation that is neither here nor there, but in between. And so that was the kind of key insight that led me to publish the Liquid Fire Animation Library back in July, which came out of some great conversations and talks that I did at Ember Comp last year. So I'm going to do a, I'm going to launch into a little demo of some Liquid Fire stuff and talk about how we find a place in the Ember architecture for all these kinds of rich behaviors. So the first step of course is installing it and yay for Ember add-ons. We just have one command to install it. Right now we do have two branches because of all the evolution in Ember. This is a project that I care a lot about supporting across the whole wide range. So it actually is tested in CI against everything from Ember 1.8 all the way through to Canary. We're committed to supporting that. And I'm really excited to be announcing a 1.0 alongside Embers 2.0 this summer. And yeah, that's really good, right? Yeah, thank you. And that's really kind of my point about this whole demo, which is that we want this to be something that every Ember app can do and it shouldn't be that, it shouldn't be a big extra deal, right? The goal is to make it so easy that it's almost, why would you not build rich interactive applications, right? So I'm going to show a demo here. And I guess I'll turn it up my font size. So, do I fit? This is an Ember app. The EmberComp website is not actually an Ember app. I did not have the source code to it. I just decided it was kind of a nice example data to play with. So I web scraped it. And I did it. I ran like WGit before I got on the plane to fly out here. So I would have it all. And this is kind of a fun trick you'd do with Ember actually. You could take somebody else's website. Grab all the static output. Not even knowing how it was assembled on the server or whatever. Drop it into your application template, boot up member CLI, and you have an Ember app, right? And you can start to very incrementally refactor it into an actual Ember app. You can take out the pieces, start to make them templates, start to take the repetitive data out and put it into models. That's what I did to put this together. So it's very simple, right? We have our list of speakers here and I already have the fancy stuff turned on, I wasn't intending to do it that way. Let's see. We're gonna go back a bunch of commits. Okay, okay, so this is a very stock Ember app. The point of this is to say there's nothing up my sleeve, okay? This is a standard Ember app that's doing very standard Ember things. You're gonna see the templates in a minute, but we have a speaker's list. They do have this nice little physical bountiness right now. That's very simple, right? That's one CSS rule to say, unhover, translate up a little bit, right? That's nicely self-contained, right? There's a lot of little subtle details in building physical design that are self-contained enough that you don't need to go use some big library to do it, right? A lot of these are little details that you just have to get right as you design and as you build and those ones are the easy ones because they're local, right? We're gonna talk about some of the less local things. I have a shuffle button here that just reorders the people, okay? And we can go and see the details of each of these people. And I've also, just to give us something else to play with, I've put an inline editor in here where you can click and edit, right? And change something and save it and go back, okay? So that's our simple demo app, right? So we wanna give some nice richer interactions to this. And so we do the npm install liquid fire, right? I have that already. Let's move up one more commit here. So by the first thing I'm gonna do, I'm gonna be switching back and forth to the code and the demo. I might as well just do it like this. Let's see. So the first thing I'm gonna do is, this is my, so at my top level route of this is called emberconf.hbs. And I had an outlet before between a header and a footer component that I, this is just the stuff I copied off the website, right? I made an outlet. I'm switching it to a liquid outlet. That comes from the library. And that's not gonna change any of my behavior yet. Well, it's gonna do one subtle thing. Let's take a look. Let's see if you notice. So when I go to the next view, I have one little subtle bit of motion. My footer's going up and down. So that's the first observation about what we're doing here. One of the tricky things about putting animation into your existing applications is the management of context and flow in your document, right? No matter what kind of animations you're trying to put in, whether you're implementing them on the web animations API, on my default one I use in this library is Velocity.js, where they're using CSS transforms. A lot of these things work best if you are absolutely positioning your content. But that's a real pain in the butt when you're just laying out your normal flows. You want to be able to take advantage of all the kind of layout that you do normally in your templates in CSS. So the first thing you'll notice is that the liquid outlet is a smart container for us. It is actually not interrupting our flow at all. You'll notice I was able to drop it in. I didn't have to change any style sheets, but it also has this behavior. It notices that stuff's changing inside of it, and it'll measure the before and after states and smoothly change so that I'm already doing, being a little less jumpy, right? But it's not doing anything cooler yet. So the next thing we're going to do, go into my next change. Geez, I need to find a way to switch between these. Can you guys see them okay at this size if I don't go full screen? Okay, okay. So I can zoom in anyway. There we go. So the next thing I'm going to do is I'm creating a new file called app slash transitions.js, and this is a conventional thing from the library. It's, so your transitions file, you can think of it analogous to your router map. It's intended to be a global place to gather up rules about how your application behaves. And this is a kind of important thing. You'll notice that I didn't go into the liquid outlet that I added and set a bunch of configuration about how it should animate. I think that's the wrong place. Because that outlet, right now it might only be running these two routes, but as our application grows, right, we still want to have that great experience in being able to refactor and understand and grow. And you can have very sophisticated reasons for animating different ways at different times. Much more than you can express just by setting a few properties on that component. So that's why I came up with this idea of having a separate transition map that can let you lay out logically in a kind of imaginary physical space where all your, where are your routes and components and views, how they relate with each other. So in this case, I'm using two constraints, a from route constraint and a to route constraint. And I'm saying, and then I'm saying what animation to use. In a moment we'll show you where the animation's come from. So already we're going to do better now, right? We're going to fade nicely from one to the next. You'll notice that the fade happens when I go from the list of all to the detail. It doesn't happen on the return yet. That's because my rules here are directional, right? I said that the from route has to be the speakers. So because this is, but because this is directional and because directional is a very common thing, we have a shortcut for that, right? We can swap it so that we now have separate things for both the forward and the reverse. So let's see. Now we go back and forth. So the important thing here is that we have a way to declare separate from our content. And notice I haven't touched my templates. This was a totally stock application. I'm beginning to add this behavior without polluting those templates with complexity. Now let's talk about where that fade animation comes from and how it's implemented. Because this is actually one of the things I don't think people have appreciated, even some people who use liquid fire. So let's see. Make it bigger. This is the wrong one. There we go. Now let's do the simple one. Transitions. So I wanted to show you a kind of minimalist example of how you implement animations. Because I think a lot of people, even those of you who might have tried out this library, tend to be using the handful of built-in animations that I have. Fade to left to right to up. And that's great. That's what they're there for. But one of my goals is to get us to arrive on a very comfortable API where we have composable, extensible ways to define animations and literally just drop them into Ember add-ons. And you could actually write a cool animation, put in an Ember add-on, and publish it, and somebody else could just import it to their app and put it in their transition app and use it. So this is an example here of a very straightforward fade animation. In this case, I'm using Velocity, which is a pretty nice animation library to do the actual animation. But LiquidFire is not an animation library, really. All it is is a way to organize Ember applications and give you a place to put your animation calls. And so in this case, I'm using Velocity. But that's not at all required. You can use your CSS3 transform here. You can use your web animation API, just like the Polymer stuff we saw in that other talk. All those kind of things can go right in here. So all it has to do is it's receiving a context that has things like the old element and the new element. They're both already in the DOM. The new one is invisible. And they're already absolutely positioned for you, based on where they're going to end up in their final flow. That's a lot of the hard work of building one of these kind of behaviors, is getting that all set up. And that's really the point of what LiquidFire is doing. It's getting you set up to do an animation, and then letting you drop in something that's going to do it. In this case, we're going to animate the old thing to opacity 0. And then once the promise resolves, we're going to animate the new thing to opacity 1. And that visibility visible, that's a shorthand that Velocity gives us to bring it visible at the start of the animation. So we don't want to get any flicker. So let's do the next thing. So up till now, this is stuff people have probably seen if they've checked out the library. But now I'm going to show some newer things. So I mentioned really wanting to be able to compose rich behaviors out of smaller pieces. And I think now, as we approach a 1.0 API, I'm settling on a much simpler way to implement this stuff. Here's an example of a new transition called explode. Now explode doesn't by itself actually move things around, but what it does is it gives you the ability to then basically animate separate pieces of your page separately. We're going to explode the old and new views. Pick new here means for the new view, find an image, and then use the 2f transition on it. And then the 2f at the bottom is for everything else that didn't match. So now when I go over, the final image you'll notice it's coming up from the bottom. Let's slow it down so we can see it better. I think that's my next commit. And this will show you that all of these animations, they can take parameters too. We passed them through. When you implement animations, they can just receive arguments just the way functions should. So now they should go slower. And you can see a little better what they're doing. So now let's take a look at, because we have this explode capability, explode is really, remember that every transition has both an old and a new element that we're comparing. And explode is no different. So it can match up elements on the old and elements on the new. So let's switch to this new match by. So it looks like this. I'm going to say match by data speaker ID. Now that's just an attribute that I put on my elements where I've bound the speaker ID into the DOM. So it's nicely accessible. And did I get a reload yet? There we go. So there's that hero transition. Let's make it work both directions. So let's add the reverse. The reverse is very similar. We're still going to explode match by data speaker ID, fly to your partner. But we're going to switch the underlying one for all the background stuff to the other direction. So now we'll have it two-way. And they're going to match right up. So you notice I didn't do anything into my templates again. This is still stock. And so when I'm designing those that before state and that after state, I don't have to think about my animation. I can go and add them afterward. And I could refactor this whole layout. And as long as I still have those elements, there's still going to match. There's no more work to do. So this fly to animation actually, it's implemented the same as that fade when I showed you. The point of it is just that it's going to measure the initial and final positions of those elements and do a nice smooth transition across. So after the great Polymer talk we saw, showing all these transitions, our speaker Brian pointed out that why don't more people use this web? Animations API is really cool. So I said, yeah, that's a good idea. So while I was sitting in the back just now, I re-implemented the fly to on that API instead. And it doesn't really fit on one screen. It's actually more of a verbose API than velocities. And the biggest reason for it is that velocity lets you break out all the separate pieces of the transform property and animate them separately. And it does the merging for you. And in this API you don't. Also, I have to do the promise wrapping myself. But let's go just drop over to our transitions map. And instead of saying fly to, we could say web fly to. And yes, please save anyway. Yeah, the reverse, well, one of them is going one way and the other is going the other. They're using different APIs in both directions. But they look pretty close, actually. There's a little bit of subtle weirdness in the web API, I want just because it's using a different easing function than my background is using right now. That would be easy to fix. But this is pretty good for doing it in like 10 minutes in the back of the room, right? Yeah. So let's do some different things now. So far I showed you one liquid outlet. And that's an example of a template helper that is, you always have some topmost thing that is stable. That's kind of your pivot point that's going to let you be able to animate it all. There's some topmost point that is the entry point for all of the things below it that are going to move around. Sometimes it might even be like the whole page. It might just be your topmost view. But there's always one. And so liquid outlet is one of those. And here I'm inserting a liquid width, which is another. Now all of these are named analogous to the built-in helper's number, outlet width, if we'll get to those. And they have the same basic semantics. The point of liquid width is you could actually think of this. You'll see right here it's using the block-cram syntax to yield up current model, right? Liquid width model as current model. Now this is using really nice new stuff that the block-crams unlocks for us. You could think of this actually internally as it runs in each. It's going to yield more than once with different versions of that model as they've changed. That's how we get multiple things in the DOM together. So the model here, this is our list of speakers, right? The model is our list. By putting it in a liquid each, now I'm going to have the ability to target that list for animation. So let's jump up to the next commit. And oh, actually this was me changing. Let's see, was this just the reverse slide, too, still? Let's see what we have. Oh, there we go. Yeah. I didn't show you the rule yet. I skipped that part. Let's go. So we need a transition rule, too. Actually, I think I've skipped ahead. That wasn't supposed to be so cool yet. Yeah? OK. I don't know. I guess it's cool that I thought it was. I was going to do an intermediate one that was more boring, but we'll go right to the cool one. So yeah, so all I'm doing here, when I click shuffle, right, all I'm doing is putting out a new list that's sorted differently. And the liquid width is, because it's bound to the list, it's going to say, oh, this list is changing. I'm going to hold on to the old one, keep it in the DOM, render the new one invisible, then delegate to the transition mapping service and say, I've got all this stuff. Do you want to animate it? And so in this case, the transition rule is this one. So here I'm using a different kind of mapping. I don't say this is not routes involved. I'm saying for a child of the speaker icons element, use explode, match by speaker ID, and then fly to each other. So this is all the config it takes to do that thing. And we have this easing function here. That's why they bounce nicely. This is just a syntax velocity use, is to give spring values, basically, so that when they get to their final location, they bounce a little. Pretty nice. Yeah, so let's show off one more thingy. So I mentioned that we have this interaction here, where we can edit. Let's make that a little nicer, too. So let's see. Now I don't know where I was in my commits. I'm going to have to just live code, huh? See, I was trying to avoid that. OK, that looks good. Yeah, so here's the rule already that's going to do it. I'm going to write a transition for the liquid if helper. And one thing I want to clarify, so all of these things where I'm saying when to do what, these are all constraints. In helper, to model, child of, route from. All of these are just constraints. And a rule matches when all the constraints match. So in this case, if I'm in helper, liquid if, and I'm going to the state true, the model in the case of an if is the predicate you're passing into the if. If it's going to true, use up. If it's going from true, that's the reverse state. We'll use to down. And so then in the template, let's see, speaker details here. So before I had if editing, I'm just going to do liquid if editing, so that now this element will respect the transition map. And it'll go find that rule. Did I reload already? There we go. Yeah, so. So mister, that's mister to you. So that's the demo. So that's the point of the way we're trying to bake this stuff in so that it's not just a great experience for users, but a great experience for Ember developers. And so I'm very excited to be moving this toward a 1.0 API. I think I showed you these code already. Yeah. Oh, and so that's the liquid if. And so here's my, oh, and I didn't mention, there's one other project I did want to mention, which is called Ember Paper. That's a project started to try to give you out-of-the-box components that have the Google Material Design features. It doesn't have a lot of the really rich, complicated motion stuff that I was showing, but we'd love to get those all together and make it actually work for people who are interested in doing that kind of stuff. It's a cool project. You should check it out. They have some really neat, already have things like inputs and radio buttons and buttons that have those nice behaviors where you see the radiating action out when you touch them. Definitely check out the Material Design spec, like I said. It's really reading in detail. And definitely check out LiquidFire. And I'm really excited to have people contributing. We've had really great contributions already. And it's wonderful to see people filing issues, fixing issues. It's great. So I would have actually said, a few days ago I would have said that I think I knew exactly what the 1.0 API was and that we were done and it was ready to go. But Glimmer is really exciting. It's actually going to unlock some newer things, I think, that might let us simplify even further and be able to possibly cut down the number of different kind of helpers you need to just one. So watch for great things before we do the beta in June before we hit the 1.0. And I hope you try it out and I hope you contribute. Thanks.