Responsive - breakpoints

Every animation and every modifier can be gated by viewport width. Breakpoints are min-width, mobile-first, and use single letters xs/s/m/l/xl so they never collide with Tailwind's sm/md/lg or Bootstrap's dash syntax.

xs475px - phones (custom, not in Tailwind)
s640px - Tailwind sm
m768px - Tailwind md
l1024px - Tailwind lg
xl1280px - Tailwind xl

Config lives in Config.js:75 defaults.breakpoints {xs:475,s:640,m:768,l:1024,xl:1280}. Override before initAnimations(): defaults.breakpoints.l = 992 to match Bootstrap.

Syntax - gating animations

Prefix any animation with bp:. No animation if the breakpoint is inactive.

html
<div class="spawn-up"> always - no prefix </div>
<div class="m:spawn-up"> from 768 up - inert below m </div>
<div class="l:float"> from 1024 up </div>
<div class="s:spawn-text-spawn-up"> SplitText variant also gates - s:spawn-text-spawn-up </div>
<div class="m:pin"> pin only on tablet+ </div>
spawn-up
resize to <768 - m:spawn-up stays staticresize to >=768 - spawns via gsap.matchMedia

Gating is live - Listeners.js:26,202 registers gsap.matchMedia("(min-width: 768px)") via runWithBreakpointForSel. Resizing across the threshold auto creates/kills the tween and its ScrollTrigger without re-calling initAnimations().

Syntax - breakpoint modifiers

Any numeric or string modifier also accepts bp:. Largest active wins (mobile-first).

html
<!-- time: base 1s, 3s from m, 0.5s from l -->
<div class="appear spawn-up time-1 m:time-3 l:time-0.5">…</div>

<!-- amount: 10 base, 40 from m -->
<div class="shake amount-10 m:amount-40">…</div>

<!-- ease and priority also -->
<div class="spawn-up ease-power2.out m:ease-bounce.out">…</div>
<div class="spawn-up order priority-1 m:priority-5">…</div>

<!-- other modifiers work the same -->
<div class="scramble m:amount-9 m:reveal-delay-0.3 m:chars-[XYZ]">…</div>
<div class="count m:spawn-num-10">…</div>
<div class="draw m:fill-time-0.8">…</div>
<div class="parallax-0.5 m:parallax-0.8">…</div>

Resolution order at width 1100 with class="amount-10 s:amount-30 m:amount-50 l:amount-80" → 80 (l wins). At 500 → 10 (no bp active, fallback to base). At 700 → 30 (s). If only m:time-2 exists and width is 500, it falls back to default time-1.

Modifiers are read at wiring time (Listeners.js:237 getActivePrefixedClass, Animations.js:13 lazy helpers). Gating is live, but a modifier value change (e.g. time-1 → m:time-3) needs a re-wire to rebuild the tween with the new duration. The visual harness in dev-react-strict does this with a key remount; in production either re-call initAnimations() on resize (debounced) or use separate elements per breakpoint.

Combining gating + modifiers

html
<!-- anim only from m, and when it does, its modifiers also switch at l -->
<div class="m:spawn-up time-1 m:time-2 l:time-0.4 m:amount-20 l:amount-50">…</div>

<!-- different anims per breakpoint: small screens fade, large screens slide -->
<div class="spawn-fade m:spawn-up l:spawn-right">…</div> <!-- not recommended - pick one anim + bp modifiers instead -->

<!-- loop amount that grows with viewport -->
<div class="float amount-10 s:amount-30 m:amount-60 l:amount-100">…</div>

Tailwind / Bootstrap coexistence

GClass uses s/m/l not sm/md/lg, so m:spawn-up never matches Tailwind's md:spawn-up (which Tailwind would ignore anyway as unknown). Layout and animation can share the same element:

html
<div class="grid grid-cols-1 s:grid-cols-2 m:spawn-up time-1 m:time-2 p-4">
  Tailwind: 1 col → 2 cols at s (640)
  GClass: spawn-up base, duration 2s from m (768)
</div>

Tailwind ignores unknown s:spawn-up and GClass ignores s:grid-cols-2. No @custom-variant or safelist needed. Bootstrap's col-md-* dash syntax also never collides.

Config

js
import { defaults } from 'gclass-anims'

// match your Tailwind config or Bootstrap
defaults.breakpoints = { xs: 475, s: 640, m: 768, l: 1024, xl: 1280 }
// or
defaults.breakpoints.l = 992 // only change l

import { initAnimations } from 'gclass-anims'
initAnimations() // reads breakpoints at init

Edge cases

Only bp variant, no base - m:spawn-upInert below m, no fallback. Add a base if you want a default.
No xp: prefixAlways runs - same as before.
Unknown bp - xl2:spawn-upIgnored (not in defaults.breakpoints).
Multiple same modifier - amount-10 m:amount-20 m:amount-30Last largest active wins (mobile-first).
m:order with scroll - m:order + scrollOnly stagger is gated; scroll still fires below m (fixed beta.22.2 per-animation runWithBreakpointForSel)

Fixed beta.22.2: m:order and other bp:order / bp:priority-* / bp:ease-* / bp:time-* modifiers no longer gate scroll or scroll-progress. Before Listeners.js:1200 used a generic per-element gate so any bp:* on the element disabled its scroll animation on small screens. Now runWithBreakpointForSel gates per animation selector, so only m:scroll gates scroll.