benlime

benlime

A library for high performance LiveView animations

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.

Here a little demo video: https://cleanshot-cloud-fra.accelerator.net/media/26144/JoVUJgqmm21U6URHXo5RBP8haH0NZOZQayGHEMYL.mp4

Most Liked

benlime

benlime

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.

  1. 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).
  2. Trigger exits manually by e.g. binding it. phx-click={LiveMotion.JS.hide(to: "#main-content").
  3. 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 :wink:)

Here is a quick demo:

benlime

benlime

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.

def motion(assigns) do
    rest = assigns_to_attributes(assigns, [:animate, :transition, :initial])

    initial =
      case assigns[:initial] do
        nil ->
          nil

        initial ->
          (initial || assigns.animate)
          |> LiveMotion.Style.create_styles()
          |> LiveMotion.Style.to_style_string()
      end

    assigns =
      assigns
      |> assign_new(:animate, fn -> [] end)
      |> assign_new(:transition, fn -> [] end)
      |> assign(:style, initial)
      |> assign(:rest, rest)

    ~H"""
    <div
      id={@id}
      phx-hook="Motion"
      data-motion={LiveMotion.animate(@animate, @transition)}
      style={@style}
      {@rest}
    >
      <%= render_slot(@inner_block) %>
    </div>
    """
  end

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.

benlime

benlime

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 :exploding_head:.

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.

benlime

benlime

I released the first version of the library → See 🍿 LiveMotion - High performance animations for Phoenix LiveView

03juan

03juan

Fantastic addition to the live view paradigm. I feel at this point you have no choice but to release it as a library, to be honest. :laughing:

With the upcoming changes in master this will be even more powerful

Where Next?

Popular in RFCs Top

bennydreamtech23
So recently I have been looking for ways to improve my workflow in elixir and I saw all the commands I need to run to setup a project and...
New
adamwight
I’ve written a crude module for retrieving files from a remote server using rsync, since I didn’t see any existing tools already. This c...
New
sleipnir
Hey! Want to contribute to a cool compiler project? Check out the good first issues in the Honey Potion Compiler! Honey Potion is a com...
New
c4710n
This package is a simple wrapper of beam-telemetry packages. It provides a modular approach for using beam-telemetry packages. The basi...
New
BartOtten
This thread once discussed Routex in it’s early form. It has been repurposed to gather feedback and discusses pre-releases. Currently: p...
New
marick
TL;DR I’ve forked the Lens package, changed the API some, added new lens makers and – most importantly – added a ton of documentation. In...
New
Billzabob
Hello! I have an idea for an Elixir library I’d like to work on, but wanted to get some thoughts from the community first. It would allo...
New
Hedgehog-ai
Hello I would like feedback on an experimental neuroevolution (including substrate encoding) library called Bardo based on the amazing wo...
New
KristerV
How I currently use Hexdocs I use hexdocs all day every day, but finding the right module and function takes too long even with my bookma...
New
weakwire
Hello people, Big fan of elixir &amp; phoenix LiveView. While designing LiveView applications I use LiveComponent extensively. Issue-I...
New

Other popular topics Top

lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement