Skip to content
New: Customize your theme with an AI assistant. Read the guide

Animations & Interactions

Files: src/config/config.toml, page and section content files · Skill level: Beginner

Ecozen’s motion is calm by design: content fades and rises into place as it scrolls into view, some large photos drift as you scroll, and scrolling is smoothed. Every animation respects the visitor’s reduce motion setting.

Fade-In On Scroll

[settings.animation]
enable = true
respectReducedMotion = true
easing = "cubic-bezier(0.22, 1, 0.36, 1)"
duration = "" # e.g. "900ms" to use one duration everywhere
distance = "2rem" # how far content rises while fading in
blur = "10px" # how blurred content starts
rootMargin = "0px 0px -8% 0px"
threshold = 0.14 # how much of an element is visible before it starts

Set enable = false to show everything without fading. It also turns off the scroll motion, count-ups, and accordion and mobile submenu animation below. The hero slides, the benefits marquee, the statement text, and the footer drawings still move: they stop only with reduced motion. Keep respectReducedMotion = true: some visitors get dizzy from motion.

Turn Off Fade-In On One Page

Add scrollReveal: false to the frontmatter of a page’s content file. Sections on that page then show at once instead of fading in. The main homepage ships this way, in src/content/homepage/english/-index.md (and the other language folders):

---
footerLayout: "wordmark"
headerLayout: "transparent"
scrollReveal: false # Sections show at once, no fade-in on scroll
title: "Solar panels, battery storage, and EV charging"
---

Delete the line, or set scrollReveal: true, to bring the fade-in back. The scroll motion, count-up numbers, and hero slides on that page still run.

Scroll Motion

Some sections move with the scroll itself. There is no option for these, and they only run in browsers that support scroll-driven animations; other browsers show the still layout.

WhereWhat it does
Large photos: the services band, the results split photo, the call to action (both layouts), the careers band, and the contact bandThe photo drifts a little slower than the page (parallax)
Services, band layoutThe photo band opens from an inset card to full width as it scrolls in (not on /services/, where it is the page header)
Benefits, stack layoutA card shrinks and dims as the next one slides over it
How it works, steps layoutA line draws across the top of the step cards
wordmark footerThe large outlined wordmark rises into place

To add parallax to another photo, add a bare data-scroll-parallax attribute to an image that fills a box with overflow-hidden, as in src/layouts/components/sections/CTASection.astro. The rules are in src/styles/animation.css.

Hero Slides

The photo hero on the main homepage shows its slides one after another: the photos crossfade with a slow zoom, and the progress bar of the active tab shows how long the slide stays. options.interval in hero-section.md sets that time in milliseconds (7000 by default). The slides pause while the pointer is on the tabs, while a tab, button, or link in the hero has focus, or after a click on the pause button. With reduced motion on, slides don’t change on their own and the pause button is hidden: the tabs still switch them. See Section Layouts.

Smooth Scrolling

[settings.smoothScroll]
enable = true
respectReducedMotion = true
duration = 1.1 # higher feels slower and smoother
easing = "expo" # expo | linear | easeOutQuad | easeOutCubic

Set enable = false for the browser’s normal scrolling. Touch devices always keep their normal scrolling. The table has 11 keys in all, and developers can reach the running instance as window.__themeLenis: see Smooth Scroll.

Custom Cursor

[settings.cursor]
enable = false # true adds an animated cursor that follows the mouse

It is off by default and never shows on touch screens.

Section Animations

These are set in each section’s content file:

WhereOptionWhat it does
Benefits (benefits-section.md)marquee.enable, marquee.items, marquee.durationThe scrolling line of short phrases over the wide photo (shown when image is set). A higher duration, such as "60s", scrolls slower
Benefitsoptions.layout: "stack"Photo cards that stack on top of each other as you scroll
Hero (hero-section.md)slides, options.intervalSlides with tabs and progress bars in the photo layout
Hero, panel layout(no option)The photo tile under the pointer widens and shows its caption
BenefitsvideoA play button over the wide photo that opens a video
Savings calculator(no option)Results update live as the slider moves
Statement (statement-section.md)(no option)The words turn from muted to ink as the paragraph scrolls into view
Feature slider (feature-slider-section.md)(no option)Arrows step through the items, and the photo changes with each one
Product tabs (tabs-section.md)(no option)Tab buttons swap the panel; without JavaScript every panel shows
Testimonials (testimonial-section.md)options.layoutArrows move between reviews in the slider and quote layouts
Header menu(no option)On large screens, one shared dropdown panel changes size and content as you move between menu items
cta and wordmark footers(no option)The line-drawn wind turbines turn (cta) and the solar panels tilt to follow the sun (wordmark)
PricingpaymentToggleSwitches every card between upfront and monthly prices
ButtonshoverEffecttext-flip, creative-fill, magnetic, or magnetic-text-flip on hover. See Button Options

Count-Up Numbers

Statistics count up from 0 to their value when they scroll into view: the results section, the about page rating, the careers band, the charging speeds, the testimonials rating, the cost comparison table, the project facts, the savings calculator’s first results, the monitoring panel shortcode, and the key figures of the split hero. They count up on pages with scrollReveal: false too.

  • The number keeps the format you wrote, in any language: "$1,190", "38K t", "98%", "5,5", "62 %", "1 190 €", "350+". Only the first number in the text counts; the prefix and suffix stay as they are.
  • The page’s HTML always holds the final value, so search engines, screen readers, and visitors without JavaScript see the real number.
  • Numbers that are hidden when the page loads (for example in a closed tab) show their final value.
  • It is off with reduced motion, and when [settings.animation] enable = false: the final value shows at once.

In those sections, every value you write in the content file counts up on its own, so write each value as one number with an optional prefix or suffix. A value with no number in it shows as it is.

Add it to a new number. In a component, wrap the value in the AnimatedNumber component:

---
import AnimatedNumber from "@/components/utilities/AnimatedNumber.astro";
---
<AnimatedNumber value="38K t" />

In any HTML, including an .mdx or .md body, add a bare data-count attribute to the element that holds the number:

<span data-count>2,400+</span>

The script that runs it, src/layouts/components/widgets/CountUp.astro, is loaded once on every page by Base.astro.

Accordions And Menus

Every <details> element, such as the FAQ questions, opens and closes with a short height animation instead of jumping. Submenus in the mobile menu panel slide open too. Icons in a summary can turn with the details-open: Tailwind variant, for example details-open:rotate-45 on a plus icon.

To keep one <details> without the animation, add data-motion="off" to it. The script is src/layouts/components/widgets/DetailsMotion.astro, loaded once by Base.astro. With reduced motion on, or [settings.animation] enable = false, details open and close at once.

Type something to search...