GAMBIT MILK / TEMPLATE GUIDE
GSAP Guidelines
A little movement. A lot of personality. Learn how Gambit’s animations work, what to adjust, and how to keep every interaction comfortable.
How to Edit GSAP Animations
The homepage’s page-level footer custom code contains GSAP motion only: the main scroll and hover script, followed by a short dialog entrance-animation script. The main script checks for GSAP, ScrollTrigger and SplitText before initializing. Native HTML dialog and button commands control product previews; Webflow’s native navigation, sliders and commerce keep their own behavior.
The motion vocabulary
RISE brings text and content upward into view. POP adds a short overshoot to stickers and badges. DRIFT moves decorative artwork with scrolling. In the homepage script, DUR_TEXT, DUR_RISE, DUR_POP, STAGGER_WORD, STAGGER_ITEM, RISE_Y, and START control timing, stagger, distance, and scroll-trigger position.
Homepage animation selector map
These selectors are used by the homepage footer script. A selector that is absent from a layout is skipped. Edit selectors and their matching Designer classes together; preserve native CMS bindings when duplicating content.
Hero text and navigation
.h1heading; .headernavigation
Masked word entrance and optional navigation slide. Generated .GmWord wrappers belong to SplitText; do not author or rename them.
Hero CTA and stickers
.contentwrapper:is(.homehero,.homehero2,.homehero3,.homehero4) .buttoncontainer03; .headingcontainer:is(.homehero,.homehero2,.homehero3,.homehero4) :is(.imagewrapper,.imagewrapper2).callout
CTA rise and sticker pop during the load timeline.
Hero artwork
:is(.imagewrapper,.imagewrapper2).herodivider img; :is(.imagewrapper,.imagewrapper2).herodivider02 img
Splash fade/scale and carton rise.
Other headings
.h1heading, .h2heading
Headings after the hero reveal on scroll; all use the shared word-reveal helper.
Intro and product grid
:is(.imagewrapper,.imagewrapper2).fire; :is(.imagewrapper,.imagewrapper2).cow01; .productlist .gridblock; .productlist
Fire pop, cow entrance and inner-image float; product cards rise using the product list as their trigger.
Benefits
.benefitscontainer; :is(.imagewrapper,.imagewrapper2).middlecarton; [data-benefit-side="left"] .benefitcallout; [data-benefit-side="right"] .benefitcallout; .blurbcallout
Carton rise/inner-image float, mirrored sticker entrances and bubble pop. Preserve left/right attributes on both responsive right-column variants.
Subscription
.columnsubs:is(.home,.home2); .paragraph.white; .buttoncontainer03; .contentimage.subsfront; .contentimage.behindsubs
Copy and button rise inside the subscription section; front image rises and the rear image drifts with scrolling.
Reviews
.slider.reviews; .testimonialcard; .reviewcircle; .cowimagewrapper.cow
Review cards rise, circular details pop, and cow artwork enters/floats. The native Webflow slider track is not animated by this script.
Stats and delivery
.herostatgrid; .herostatbox; .statlargenumber; .truckimagewrapper:is(.home,.home2) img; .truckimagewrapper:is(.home,.home2)
Statistic cards reveal, numbers count up, and the truck enters from the left.
Footer
.footerlogoimagewrapper img; .sociallinklarge; .footergrid .gridblock02; .footergrid; .legalwrap a
Optional footer logo, social icons, columns and legal links reveal when their matching layout is present.
Decorative parallax
.cowgraphicbackground
Decorative cow artwork drifts with scroll.
Hover motion
.buttonlinkblock; .rightarrows; .productlist .productbox; .benefitcallout; .sociallinklarge; .callouttabwrapper; .plusiconwrapper
Buttons scale with arrow movement, product cards lift, stickers scale, social icons tilt, and preview plus icons rotate. Mouse leave restores the resting state.
Dialog entrance motion
dialog.gambitproductdialog; .popupcontainer; .productbox.productbottomwrapper; .productinfoholder; .contentblockpdp
A separate short GSAP block animates the opened native dialog panel and its content, then resets styles on close. It does not open, close, submit forms or intercept keys.
Popup scope boundary
.popups
The main scroll/hover query helpers exclude this subtree so they do not compete with dialog entrance motion.
Editable code examples
These are excerpts of existing code, not additional scripts to paste onto the page. Open Home → Page settings → Before </body> code and edit the corresponding values.
Shared timing and easing
var DUR_TEXT = 0.9;
var DUR_RISE = 1;
var DUR_POP = 0.75;
var EASE_RISE = "power3.out";
var EASE_POP = "back.out(1.6)";
var STAGGER_WORD = 0.05;
var STAGGER_ITEM = 0.12;
var RISE_Y = 44;
var START = "top 86%";Duration values are seconds; increasing them slows the effect. Stagger is the interval between targets. RISE_Y is the entrance distance in pixels. START begins a reveal when the target’s top reaches 86% of the viewport; a smaller percentage starts it later. Change one value and preview before changing the next.
Reveal duration and direction
rise(leftStickers, {
x: -90, y: 0,
duration: 0.9, stagger: 0.1,
trigger: container
});This is the existing left benefit-label reveal. The right-column call uses x: 90 with the same duration and stagger. Keep those values paired for mirrored timing. The rise helper accepts an ease override and start override; otherwise it uses EASE_RISE and START.
Delay and timeline placement
// In riseWords(el, delay, trigger):
delay: delay || 0
// Existing hero timeline placement:
tl.add(riseWords(heroHeading), 0.15);The second riseWords argument supplies a delay in seconds. The hero call above instead places its word reveal 0.15 seconds into the hero timeline. Adjust the existing placement or delay argument rather than adding a duplicate reveal.
ScrollTrigger settings
scrollTrigger: {
trigger: opts.trigger || targets[0],
start: opts.start || START,
once: true
}This is the existing rise helper’s ScrollTrigger block. trigger selects the element whose position is watched; start controls when the animation begins; once makes a reveal play once per page load. Decorative drift instead uses start: "top bottom", end: "bottom top" and scrub: true so movement follows scroll progress.
Native dialog entrance
gsap.fromTo(panel,
{ opacity: 0, y: 16 },
{ opacity: 1, y: 0,
duration: 0.4, ease: "power2.out" }
);
gsap.fromTo(content,
{ opacity: 0, y: 18 },
{ opacity: 1, y: 0, duration: 0.4,
stagger: 0.07, ease: "power2.out" }
);Edit these existing tween values in the second footer script to change the dialog entrance. The native dialog toggle event starts the animation. The close event kills only these panel/content tweens and restores their resting styles. Reduced-motion visitors see the content immediately.
Editing reveals safely
Edit the existing values rather than pasting a second copy of the animation. Keep each reveal’s setup and cleanup together. The examples below match the homepage footer script. If removing a reveal, remove its matching pre-hide setup too so the content remains visible. Preserve the main script’s GSAP context, SplitText cleanup and reduced-motion cleanup.
Native product preview dialogs
The homepage product-preview buttons use native button commands: command="show-modal" opens the dialog identified by commandfor. A close button uses command="close" with the same dialog ID. Keep each dialog ID unique and keep its buttons’ commandfor values matched when duplicating or renaming a preview. The browser provides modal focus handling and Escape dismissal; custom submit and keydown handlers are not required. Keep an accessible dialog label and a labelled close button. The preview’s product CTA links to its current CMS product page, where customers choose quantity and add to cart.
Reduced motion
The homepage honors the visitor’s prefers-reduced-motion setting. Decorative movement should end within five seconds, and essential shopping interactions must remain usable with motion disabled. Test changing the preference while the page is open as well as loading with reduced motion already enabled.
Remove animations safely
- Duplicate or back up the page before editing its footer code.
- To remove only the benefits entrance, remove or comment out the existing benefits(); call inside start(). This prevents that section’s reveal ScrollTriggers and float tweens from being created on the next load. Keep the native layout and left/right attributes.
- For another section, remove its matching start() call and any pre-hide setup that targets it. The hero and heading selectors are hidden near the PRE-HIDE comment: never remove their reveal while leaving that setup behind.
- To remove all custom page motion, remove the entire first footer script, including its initial gsap.set calls. To remove only dialog entrance motion, remove the entire second script that queries dialog.gambitproductdialog; keep the native dialog elements, button commands, labels and CMS product links.
- Save and fully reload preview. Reloading discards old tween and ScrollTrigger instances, and removed code no longer recreates them. If editing the initialization lifecycle rather than removing it, preserve motionContext.revert(), SplitText revert cleanup and removal of the settleUnreachable refresh listener. Do not globally kill another page or component’s ScrollTriggers.
- Check every affected section at desktop, tablet and phone widths. Removed motion means content appears immediately in its authored position. Verify headings, native dialogs, keyboard access, product links and cart controls; then save and republish only when ready.
Before publishing changes
Preview at desktop, tablet and phone widths. Use Enter and Space on each native preview button, then test Tab, Shift+Tab, Escape, the close button and focus returning to the opener. Verify each preview CTA reaches the matching CMS product page and that the native product-page cart controls still work. Check that headings are visible, hover effects reset and no animation causes horizontal overflow. Test with reduced motion enabled and with animation code removed in a safe copy. Publish only after completing your own checks.
