Pages
Buy Template
Custom Animations

Sienna offers 2 custom animations:

blur-fade

fade-up-scroll

The blur-fade animation fades text in with a blur effect word by word.

The fade-up-scroll animation fades in text line by line. This is best used for animating paragraphs. But since this is a scroll-based animation, the parenting div needs the data-scroll-trigger attribute. If not, the animation will not work.

There are several attributes available to control the animations

data-scroll-trigger is used to trigger a scroll-based animation.

data-start is the ScrollTrigger's starting scroll position. default value is data-start="top 80%". When you don't specify data-start parameters, it will fall back to using the default values.

data-end is the ScrollTrigger's ending scroll position. default value is data-end="bottom 20%". When you don't specify data-end parameters, it will fall back to using the default values.

data-gsap-delay is used to control the delay before the blur-fade animation get's played. Default value is delay: 0.4;. When the data-gsap-delay attribute isn't used, it will fall back to that value. Units are in seconds. so 0.4 = 400ms, 2 = 2000ms or 2 sec, and so on... . We deliberately chose data-gsap-delay over data-delay as it interferes with Webflow animations.


To add the blur-fade animation to a text element, you simply need the add this custom attribute: data-animation="blur-fade"
To add the fade-up-scroll animation to a text or paragraph element, you simply need the add this custom attribute: data-animation="fade-up-scroll". But remember to add data-scroll-trigger="" to the parent or the animation will not trigger. Although not neccessary in most cases, it's a good idea to fine-tune this type of animation with the data-start attribute.

Examples

Here you can see an example of how the blur-fade animation is added to a title and controlled by using the data-gsap-delay attribute.



Example of the fade-up-scroll animation being used on a paragraph. First image shows how to trigger this scroll-based animation and control it by add the data-start attribute.

Code

Below is the code used for these animations. In case something goes wrong, you can copy-paste this code in the "custom code" section of the site settings. Make sure to paste it in the bottom "Footer code" text field.

<script>
gsap.registerPlugin(SplitText, ScrollTrigger);

// Unified init: wait for DOM & fonts
Promise.all([
  document.fonts.ready,
  new Promise(res => {
    if (document.readyState === 'complete' || document.readyState === 'interactive') res();
    else window.addEventListener('DOMContentLoaded', res, { once: true });
  })
]).then(() => {
  fadePerWord('[data-animate="blur-fade"]');
  fadeUpPerLineOnScroll('[data-scroll-trigger]', '[data-animate="fade-up-scroll"]');
});

// Blur Fade In Animation
function fadePerWord(selector) {
  document.querySelectorAll(selector).forEach(el => {
    const split = SplitText.create(el, { type: "words" });
    const start = el.getAttribute("data-start") || "top 80%";
    const end = el.getAttribute("data-end") || "bottom 20%";
    const delay = el.hasAttribute("data-gsap-delay")
      ? parseFloat(el.getAttribute("data-gsap-delay")) || 0
      : 0.4;

    gsap.from(split.words, {
      delay: delay,
      duration: 0.6,
      autoAlpha: 0,
      stagger: 0.09,
      filter: "blur(12px)",
      ease: "power1.out",
      scrollTrigger: {
        trigger: el,
        start: start,
        end: end || undefined,
        once: true
      }
    });
  });
}
  
// Scrolling Fade In Animation
function fadeUpPerLineOnScroll(containerSelector, textSelector) {
  gsap.set(textSelector, { opacity: 1 });
  document.querySelectorAll(containerSelector).forEach(container => {
    const texts = container.querySelectorAll(textSelector);
    if (!texts.length) return;
    texts.forEach(text => {
      const start = container.getAttribute("data-start") || "top 80%";
      const end = container.getAttribute("data-end") || "bottom 20%";

      SplitText.create(text, {
        type: "lines",
        linesClass: "line",
        autoSplit: true,
        onSplit: instance => {
          gsap.from(instance.lines, {
            yPercent: 120,
            stagger: 0.05,
            autoAlpha: 0,
            ease: "power1.out",
            scrollTrigger: {
              trigger: container,
              scrub: true,
              start: start,
              end: end,
              markers: false // Only used for debugging scrolling animations
            }
          });
        }
      });
    });
  });
}

// Firefox/lazy images fix: refresh triggers after all resources loaded
window.addEventListener('load', () => {
  ScrollTrigger.refresh();
});
</script>