In the last couple of days I was playing around with LiveView, function components and animations. I ended up with a little prototype which allows you to control animations directly from the server.
The key difference is, that the actual animations will happen in a very performant way directly on the client. So there is nothing like “send every animation frame over the wire happening”.
What do you think about that? I’m thinking to turn this into a library.
That’s pretty neat! I wonder how <.motion /> is implemented?
Quite nice how you can abstract away things such as animations using Phoenix function components. It reminds me of React.
I assume every animation frame is sent over the wire via LiveView (using slightly different style attribute).
Oh, and this is quite a stretch perhaps, but if you turn this into a library it would be nice to have an option to enable client-side animation. Cause I can imagine if a user is on a less stable connection (on mobile for example) the animation may not be so smooth.
^ Oh I misread, the animations do happen client side?
Exactly, the animations fully happen on the client. The only thing which is sent over the wire are the animation props animate and transition. There is also a prop initial which allows you to set an initial state (think of enter animations where you need the state to be something else on initial mount).
This also works flawlessly when re-triggering animations. When you hammer the button in the video, it will just animate in the other direction from the exact point when you clicked at it. You can even do complex animations with multiple steps by just providing e.g. animate={[x: [0, 200, 100, 50, 100]}.
The function component itself currently is extremely simple. I’ll just paste it.
There is a phx-hook involved which utilities a tiny JS library (motion.dev) that performs animations using the browser WebAnimations API.
I took heavy inspiration in the API from framer-motion (Production-Ready Animation Library for React | Framer Motion). I really like their api design and the paradigm for declaring animations. Still, I have to implement a few features and figure out things, like:
Exit/Unmount animations (Presence).
Declaring animations for pure client side interactions. My idea here is currently a thin wrapper around LiveView.JS.
Dependant animations (layouts).
Scroll animations
Gestures, …
A lot of ideas, but I think in general most of it is somewhat possible.
I’m pretty amazed what you can do with LiveView. I just played around with declaring fully client-side interactions using a thin wrapper around LiveView.JS.
Toggle animations declared on the server, performed on the client without a round-trip. And you can even mix and match animations being updated from the server and the animations already running locally .
When clicking the square, the server updates the LiveView state, therefore updating the animation (again, it just sends one single declaration, nothing more).
When clicking the “Toggle me” button, no round-trip is made.
Hammering both just smoothly animates. Feels magical to me.
Thanks for the feedback. I appreciate it very much. So as I have quite a lot of fun building this anyway, I’ll release this as a library. It’s still missing a few features and tests - and docs of course.
I’ll have more time to work on it in a week, so I expect a first releasable version in two weeks or so. I’m pretty excited what else can be achieved here.
Elixir Desktop seems really nice. I’d love to give it a try sometime! It’s absolutely awesome that LiveView can be used to create native applications.
Meanwhile I got seamless page transitions running. It’s as easy as just defining an exit prop to the motion component. There are three awesome things happening with it.
Automatically animate exits triggered from the server. This happens for example by a conditional render based on a prop. (e.g. @is_visible or something like this).
Trigger exits manually by e.g. binding it. phx-click={LiveMotion.JS.hide(to: "#main-content").
Automagically handle page transitions triggered by e.g. live_redirect.
Can’t wait until I can ship the first version of the library.
EDIT: If you like to see it live, you can test it on https://benvp.co (which is my little page )
As the default phoenix installation moved away from adding node I’d like to make the installation as easy as possible without requiring node. So probably I’ll bundle the motion package inside the hex package. I might provide an option to pass the functions from motion during the setup in case somebody wants to use npm instead.
For what it’s worth handling it in the dom update makes sense to me as it’s the same way that vue.js is meant to be propagated and as Chris says it’s the way to go.