How to Convert GSAP to Webflow Interactions
Write GSAP in a mapping-friendly way so Flowboard can convert simple animation intent into native Webflow IX3 while preserving harder GSAP as runtime or fallback code.
Flowboard prioritizes correctness over native coverage. If a GSAP block cannot be represented safely as Webflow IX3, it stays supplemental instead of becoming misleading native output.
Memberstack published a detailed walkthrough showing how Flowboard can fit into an AI to GSAP to Webflow workflow.
Watch the Memberstack tutorialBest-results checklist
- Use literal class or ID selectors for animated targets.
- Keep values literal and explicit.
- Prefer
gsap.from(...),gsap.fromTo(...), and simplegsap.timeline(...)chains. - For color/background tweens, use
fromTo(...)or seed a start state withgsap.set(...). - Keep native-safe GSAP in separate
<script>blocks from plugins, callbacks, dynamic selectors, and app logic. - For fallback GSAP tests, make sure the element, CSS, and GSAP selector use the same literal class.
- Check
gsapWarningsafter conversion. Warnings explain why Flowboard preserved fallback GSAP.
What maps natively
Static tween targets
Flowboard supports gsap.to(...), gsap.from(...), and gsap.fromTo(...) when the target is static and the properties are supported.
gsap.to(".box", { x: 100, opacity: 0.5, duration: 0.4 });
gsap.from(".card", { y: 24, opacity: 0, duration: 0.5 });
gsap.fromTo(
".hero-title",
{ y: 32, opacity: 0 },
{ y: 0, opacity: 1, duration: 0.7, ease: "power3.out" }
);Transform values
Supported transforms include numeric values and safe string units. Flowboard maps x/y pixel strings to numeric pixels, percent x/y strings to xPercent/yPercent, and degree strings to numeric rotation values.
gsap.to(".box", {
x: "20px",
y: "-20px",
xPercent: 100,
rotation: "-45deg",
scale: 1.1,
scaleX: 0.95,
scaleY: 1.05
});
gsap.to(".panel", { x: "100%", y: "-100%" });Opacity and style properties
Opacity maps as a transform-style IX3 property. Supported color/style properties can map when Flowboard has a safe start and end state.
gsap.to(".box", { opacity: 0 });
gsap.fromTo(
".badge",
{ backgroundColor: "#111827", color: "#ffffff" },
{ backgroundColor: "#ffffff", color: "#111827", duration: 0.25 }
);
gsap.set(".badge", { backgroundColor: "#111827" });
gsap.to(".badge", { backgroundColor: "#ffffff", duration: 0.25 });Direct style-only to(...) tweens without a known start state are preserved as fallback to avoid native output plus residual GSAP replaying the same visual behavior.
Common AI wrappers
Flowboard can unwrap common static wrappers that AI tools often generate.
document.addEventListener("DOMContentLoaded", () => {
gsap.to(".box", { x: 100 });
});
(() => {
gsap.from(".hero", { opacity: 0, y: 20 });
})();
gsap.context(() => {
gsap.to(".card", { y: 0, opacity: 1 });
});Static selector aliases
Literal selector aliases can map when the selector source is direct and static. Flowboard intentionally does not propagate arbitrary variables such as const selector = ".box"; document.querySelector(selector).
const box = document.querySelector(".box");
gsap.to(box, { x: 100 });
const cards = document.querySelectorAll(".card");
gsap.to(cards, { opacity: 1 });
const hero = document.getElementById("hero");
gsap.to(hero, { y: 20 });
const items = gsap.utils.toArray(".item");
gsap.from(items, { opacity: 0, y: 20 });
const q = gsap.utils.selector(".scope");
gsap.to(q(".child"), { x: 100 });Safe forEach loops
Simple loops can map when the loop variable comes directly from a literal selector collection and tween values do not depend on index, dataset, conditionals, computed values, or external state.
document.querySelectorAll(".card").forEach((card) => {
gsap.to(card, { opacity: 1, y: 0 });
});
gsap.utils.toArray(".tile").forEach((tile) => {
gsap.from(tile, { opacity: 0, y: 20 });
});Timeline labels and positions
Static labels and relative timeline positions can map. Supported positions include <, >, <+=0.2, >-=0.2, label, label+=0.2, and label-=0.2.
const tl = gsap.timeline();
tl.to(".a", { x: 100, duration: 1 })
.addLabel("mid")
.to(".b", { y: 100, duration: 1 }, "mid+=0.2")
.to(".c", { opacity: 0 }, "<");Click and hover controls
const panelTl = gsap.timeline({ paused: true, reversed: true });
panelTl.fromTo(".panel", { xPercent: 100 }, { xPercent: 0, duration: 0.35 });
document.querySelector(".panel-toggle").addEventListener("click", () => {
if (panelTl.reversed()) {
panelTl.play();
} else {
panelTl.reverse();
}
});Basic safe ScrollTrigger
Basic ScrollTrigger config can map when it uses static selectors and safe options.
gsap.fromTo(
".feature-card",
{ y: 40, opacity: 0 },
{
y: 0,
opacity: 1,
duration: 0.8,
scrollTrigger: {
trigger: ".feature-card",
start: "top 80%",
end: "bottom 40%",
scrub: true
}
}
);What intentionally falls back
Flowboard preserves runtime/fallback GSAP for behavior that cannot be represented faithfully as native IX3.
- Unsupported transform units:
rem,em,vh,vw - These units are preserved as fallback because their pixel value depends on runtime CSS, viewport size, or browser settings. Flowboard does not guess those values for native IX3.
- Expressions:
calc(...),var(...), mixed CSS expressions, and template expressions. - Unsupported string scale values.
- Unsupported direct style properties such as
filter. - Callbacks:
onStart,onUpdate,onComplete, and function-valued payloads. keyframes,repeat,repeatDelay,repeatRefresh, andyoyo.- Unsafe or advanced ScrollTrigger behavior such as
pin,snap, callbacks, non-literal config, custom scrollers, or variable references. - Dynamic selectors, string concatenation selectors, function-returned selectors, and selector variables from external state.
- Loops that depend on index, dataset, computed values, conditionals, nested dynamic selectors, or external state.
- Unresolved labels, dynamic position variables, computed timeline positions,
tl.call(...), complextl.add(...), and callback labels. - Unsupported plugins such as
MotionPathPlugin,Flip,Draggable,MorphSVGPlugin,ScrollSmoother,Observer, andInertiaPlugin.
Examples that fall back
gsap.to(".box", { x: "10rem" });
gsap.to(".box", { filter: "blur(4px)" });
gsap.to(".box", { opacity: 0, repeat: -1, yoyo: true });
gsap.to(document.querySelector(`.${name}`), { x: 100 });
document.querySelectorAll(".card").forEach((card, i) => {
gsap.to(card, { delay: i * 0.1, opacity: 1 });
});
const tl = gsap.timeline();
tl.to(".a", { x: 100 }).to(".b", { filter: "blur(4px)" });How to split GSAP scripts
Use script block boundaries to keep simple native-safe GSAP away from fallback-only GSAP. This avoids whole-block fallback and duplicate-risk cases where the same original GSAP block would need to be preserved.
Recommended
<script>
gsap.from(".hero-title", { y: 32, opacity: 0, duration: 0.6 });
gsap.to(".hero-cta", { scale: 1.05, duration: 0.2 });
</script>
<script>
gsap.registerPlugin(MotionPathPlugin);
gsap.to(".orbit-dot", {
motionPath: { path: "#orbit-path" },
repeat: -1
});
</script>Avoid mixing native-safe and fallback-only GSAP
<script>
gsap.from(".hero-title", { y: 32, opacity: 0 });
gsap.to(".orbit-dot", { motionPath: { path: "#orbit-path" } });
</script>The first script can become native IX3. The second script stays supplemental GSAP. Keeping them separate gives Flowboard the cleanest result without duplicating animation behavior.
Fallback selector classes
When Flowboard preserves a GSAP block as runtime/fallback code, the original GSAP selector still has to find an element on the published page.
For simple literal class selectors, Flowboard preserves the selector class for runtime targeting, even when Webflow displays a different styling class in the Style panel. For example, Webflow may show the element label as motion-card in the Navigator while the active style selector is block. The important runtime check is whether .motion-card still selects the element.
Good fallback test pattern
<div class="motion-card" style="width: 220px; padding: 28px; background: #7c3aed; color: white; border-radius: 12px;">
Runtime fallback card
</div>
<script>
gsap.to(".motion-card", {
x: "8rem",
rotation: "12deg",
repeat: -1,
yoyo: true,
duration: 0.9,
ease: "power2.inOut"
});
</script>This falls back because rem and repeat/yoyo must be preserved by GSAP, but the selector should still work because the target class is literal and attached to the animated element.
How to tell if mapping worked
- Check the conversion report for mapped GSAP counts.
- Review
gsapWarningsfor deterministic fallback reasons. - If a native-safe tween falls back, split it into its own script block and remove dynamic/plugin-heavy behavior.
- If fallback GSAP does not move, check the published page console with
document.querySelector(".your-class"). The class in the Navigator and the active Style panel selector may not be the same thing. - Retry one simple tween at a time, then add complexity back.
Prompt for AI-generated GSAP
Generate GSAP that is compatible with Flowboard's HTML-to-Webflow converter. Rules: - Use literal class or ID selectors only. - Prefer direct selectors like .hero-title or simple descendants like .hero .title. - Use gsap.from, gsap.to, gsap.fromTo, gsap.set, or simple gsap.timeline chains only. - Use px, %, deg, numeric scale, and numeric opacity values. - Keep all tween values literal and explicit. - For color/background changes, use gsap.fromTo or gsap.set before gsap.to. - Allowed triggers: page load, simple click, simple hover, basic ScrollTrigger. - Do not use unsupported plugins, callbacks, keyframes, repeat/yoyo, complex selectors, or DOM mutation side effects. - Put native-friendly GSAP in separate script blocks from plugin-heavy, dynamic, callback, and app logic.