Animation and scroll effects
Each frame, wckd-ui.js updates document.body with --scroll-progress, data-scroll-progress, and scroll-direction / edge flags. A separate idle pass toggles in-view on .animate nodes for entrance effects; add image-zoom beside animate on .background-image blocks to reuse the built-in still zoom.
Download & setup
Start with the package download and setup steps in Get Started, then use the style guide for utility and token references while implementing this component.
Default implementation
Live body hooks on this page
WCKD_BODY_SCROLL coalesces scroll/resize work to requestAnimationFrame. Read --scroll-progress, data-scroll-progress, and classes like at-top / scrolling-down from document.body in CSS or light scripts. In-view behaviour on .animate is covered under configuration options below.
Body: progress, data attribute, direction
Scroll this page, values read from the live body node. Full walkthrough: style guide.
Document progress (0 = top, 1 = bottom):
Markup
/* body , always updated when wckd-ui.js runs */
/* --scroll-progress, data-scroll-progress, .at-top, .at-bottom, .scrolling-up, .scrolling-down */
header.hero {
transform: scaleX(var(--scroll-progress, 0));
transform-origin: left center;
}
Configuration options
Use the default implementation block for body-level scroll variables and flags. Use the options below when you need viewport intersection: put animate on the node wckd-ui.js should observe, then author resting and .in-view CSS, or use animate image-zoom for the built-in background still zoom (demos mix inline <style> for motion examples only).
In-view: .animate
Elements with class animate are observed by wckdToggleInViewClass; when enough of the element is visible, the script adds in-view (and removes it when leaving). You define resting and .in-view looks, this demo uses scoped inline CSS for lift, slide, fade, blur, and scale-on-box patterns.
Scroll until each tile crosses the viewport. Default visibility threshold is 0.4 unless you set data-threshold on the node.
Lift (translateY)
Slide (translateX)
Fade only
Blur in
Scale (whole box)
Pop easing
Earlier threshold
Markup
<style>/* scope under a wrapper id in your theme */</style>
<div class="animate my-reveal">…</div>
/* CSS */
.my-reveal { opacity: 0; transform: translateY(12px); transition: … }
.my-reveal.in-view { opacity: 1; transform: none; }
In-view: .animate.image-zoom (still)
Add image-zoom alongside animate on the same element. The kit scales .background-image img from transform: scale(1) to 1.1 when in-view is on, Ken Burns–style motion on a hero or card still, without a second JS selector.
Use animate image-zoom on a wrapper that contains .background-image with a cover img. Rules live in wckd-ui.css; the script only toggles in-view on .animate.
Markup
<div class="animate image-zoom relative height-30 hide-overflow round">
<div class="background-image" aria-hidden="true">
<img src="/media/hero.jpg" width="1600" height="900" alt="" />
</div>
<div class="overlay relative tint-dark pad">…</div>
</div>
When to use
- Reading progress, gradient read-lines, and chapter position indicators.
- Tightening sticky header shadow on
scrolling-downor showing a footer CTA atat-bottom. - Entrance motion without a framework, using only CSS and
in-viewon.animate.
Implementation notes
- Body scroll tracking is not a separate bootstrap step; it runs when
wckd-ui.jsloads (flushScrollDirectionon scroll/resize). .hide-and-seekinwckd-ui.cssusesbody.scrolling-down/scrolling-upfor the auto-hiding site header.- Threshold for in-view:
parseFloat(parentCarousel?.dataset.threshold || el.dataset.threshold || '0.4')inwckdToggleInViewClass. - On very short pages,
at-topandat-bottomcan both be true; preferat-topto mean “not really scrolled” for header chrome.
Developer checklist
- Confirm the idle bootstrap still calls
wckdToggleInViewClasswhen the page uses.animatenodes. - Do not re-bind
windowscrollfor the same progress math, readbodyin CSS or usedata-scroll-progressin targeted scripts. - iOS overscroll can momentarily change edge flags; do not use them as the sole trigger for one-shot modals without debounce.