Skip to content

konton-pro/enguia

Repository files navigation

Enguia

Hex.pm Docs

Declarative animations for Phoenix LiveView, powered by the Web Animations API.

Enguia lets you add smooth, performant animations to your LiveView templates using a clean Elixir DSL. No CSS files. No JavaScript boilerplate. Just functions.

<.motion animate={slide_up(delay: 100)} tag="section">
  <h1>Slides in when scrolled into view</h1>
</.motion>

<.motion animate={typewriter()} tag="p">
  Hello, world!
</.motion>

Features

  • 11 motion presets — fade, slide, scale, shake, pulse, bounce
  • 4 text effects — typewriter, split words, blur in, letter spacing in
  • 4 trigger modesmount, visible (scroll), hover, click
  • Scroll reveal — re-animate every time an element enters the viewport
  • Fully composable — override duration, delay, easing, fill, repeat per call
  • ~3 KB JavaScript hook, zero runtime dependencies

Installation

Add enguia to your mix.exs:

def deps do
  [
    {:enguia, "~> 0.1"}
  ]
end

JavaScript Setup

In assets/js/app.js, import and register the hook:

import EnguiaHook from "../../deps/enguia/priv/static/enguia.js"

let liveSocket = new LiveSocket("/live", Socket, {
  hooks: { EnguiaHook }
})

Usage

Import everything with use Enguia in your LiveView or component module:

defmodule MyAppWeb.PageLive do
  use MyAppWeb, :live_view
  use Enguia

  def render(assigns) do
    ~H"""
    <.motion animate={fade_in()}>
      <p>Fades in on mount</p>
    </.motion>

    <.motion animate={slide_up(delay: 100)} tag="section" class="hero">
      <h1>Slides up when scrolled into view</h1>
    </.motion>

    <.motion animate={bounce()} tag="button">
      Bouncing button
    </.motion>
    """
  end
end

Or import selectively:

import Enguia.Components
import Enguia.Presets

Motion Presets

All presets accept an optional keyword list to override defaults.

Function Default trigger Description
fade_in/1 :mount Fade from 0 to 1 opacity
fade_out/1 :mount Fade from 1 to 0 opacity
slide_up/1 :visible Slide up from below
slide_down/1 :visible Slide down from above
slide_left/1 :visible Slide in from the left
slide_right/1 :visible Slide in from the right
scale_in/1 :mount Scale from 80% to 100%
scale_out/1 :mount Scale from 100% to 80%
shake/1 :mount Horizontal shake (attention grabber)
pulse/1 :mount Infinite opacity pulse
bounce/1 :mount Infinite vertical bounce
fade_in(duration: 500, delay: 100, easing: "ease-out")
slide_up(trigger: :click, repeat: 2)
pulse(repeat: :infinity)   # default for pulse

Text Effects

Import from Enguia.TextAnimations (included via use Enguia):

Function Description
typewriter/1 Reveals text character by character
split_words/1 Animates each word in with a stagger
blur_in/1 Fades text in from blurred to sharp
letter_spacing_in/1 Animates from wide letter-spacing to normal
<.motion animate={typewriter(duration: 1500)} tag="p">
  One character at a time.
</.motion>

<.motion animate={split_words(stagger: 60)} tag="h2">
  One word at a time.
</.motion>

<.motion animate={blur_in()} tag="h1">
  Fades in from blur.
</.motion>

<.motion animate={letter_spacing_in()} tag="h1">
  Tracks in from wide spacing.
</.motion>

Triggers

Trigger When it fires
:mount Immediately when the component mounts
:visible When the element enters the viewport (IntersectionObserver)
:hover On mouse enter
:click On click

Scroll Reveal

By default, :visible animations fire once. Pass scroll_reveal: true to re-animate every time the element enters the viewport:

<.motion animate={slide_up(scroll_reveal: true)}>
  Animates each time you scroll past it.
</.motion>

Options Reference

All presets accept these keyword options:

Option Type Description
duration integer Duration in milliseconds
delay integer Delay before starting, in milliseconds
easing string Any CSS easing value ("ease", "ease-out", "linear", etc.)
fill string Fill mode: "forwards", "backwards", "both", "none"
trigger atom :mount, :visible, :hover, or :click
repeat integer or :infinity Number of iterations
scroll_reveal boolean Re-animate on each viewport entry (:visible only)

Custom Animations

Build animations from scratch using %Enguia.Animation{}:

alias Enguia.Animation

anim = %Animation{
  keyframes: [
    %{"transform" => "rotate(0deg)"},
    %{"transform" => "rotate(360deg)"}
  ],
  duration: 1000,
  easing: "linear",
  repeat: :infinity,
  trigger: :mount
}

<.motion animate={anim}>...</.motion>

The <.motion> Component

Attribute Type Default Description
animate Animation.t() required The animation struct
tag string "div" HTML tag to render
class string nil CSS class
id string auto-generated Element ID

Any other attributes are passed through to the element.

License

MIT — see LICENSE for details.

About

motion lib based in elixir

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors