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 startsSet 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 scrolltitle: "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.
| Where | What it does |
|---|---|
Large photos: the services band, the results split photo, the call to action (both layouts), the careers band, and the contact band | The photo drifts a little slower than the page (parallax) |
Services, band layout | The 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 layout | A card shrinks and dims as the next one slides over it |
How it works, steps layout | A line draws across the top of the step cards |
wordmark footer | The 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 | easeOutCubicSet 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 mouseIt is off by default and never shows on touch screens.
Section Animations
These are set in each section’s content file:
| Where | Option | What it does |
|---|---|---|
Benefits (benefits-section.md) | marquee.enable, marquee.items, marquee.duration | The scrolling line of short phrases over the wide photo (shown when image is set). A higher duration, such as "60s", scrolls slower |
| Benefits | options.layout: "stack" | Photo cards that stack on top of each other as you scroll |
Hero (hero-section.md) | slides, options.interval | Slides 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 |
| Benefits | video | A 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.layout | Arrows 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) |
| Pricing | paymentToggle | Switches every card between upfront and monthly prices |
| Buttons | hoverEffect | text-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.