WildflowerJS Reactive JS, No BS*

A no-build reactive JavaScript framework, rooted in the web platform.
No build step. No dependencies. No lock-in.

<script src="wildflower.min.js"></script> ...and start building.

Back to Basics

The code you write is 100% web standard code. HTML stays HTML. JavaScript stays JavaScript. CSS stays CSS. No JSX, no templating language, no custom syntax to learn. If you know the web platform, you already know how to use this.

WildflowerJS extends the web platform. It doesn't replace it.

Your Development Simplified

Because you develop with 100% web standards, every tool in your existing chain already understands the code: IDE, browser DevTools, linter, formatter, screen reader, SEO crawler. Nothing to install, no custom file types, no sourcemaps. Save the file, refresh, and your change is live.

Just be a web developer.

Batteries Included: One Mental Model

Router, SSR, stores, computed properties, two-way binding, event modifiers, data pools, and TypeScript types, all built in, all speaking the same language. Learn data-bind once and you know binding everywhere: lists, pools, stores, forms. There's no five-library stack to keep in sync.

One script tag. Everything you need.

<div data-component="counter">
  <span data-bind="count"></span>
  <button data-action="increment">
    +1
  </button>
</div>

<script>
wildflower.component('counter', {
  state: { count: 0 },
  increment() { this.count++ }
})
</script>

How It Works

data-bind connects state to the DOM.

data-action connects events to methods.

this.count++ triggers a precise DOM update.

Mutate state. The DOM updates.

Two Reactivity Modes

data-list for automatic reactivity: mutate state, DOM updates. data-pool for explicit control: plain objects, zero proxy overhead, you say what changed.

Same template syntax. Different performance profile. From interactive forms to per-frame particle systems. You choose the right tradeoff for the job.

Try it. Right-click, inspect this demo. Every dot is a real DOM element.

See full demo →

* Build Step

Zero Toolchain

Modern frameworks ask you to install a compiler, a bundler, a package manager, hundreds of fragile transitive dependencies, and a framework-specific file format, before you write a single line of your application.

WildflowerJS was built starting from a single principle: no build step, no tooling. Ever.

WildflowerJS asks you to add a script tag.

There's no CLI scaffolding step, no config files, no .vue/.jsx/.svelte source format. You don't debug through sourcemaps or wait on a build pipeline. Your project has zero dependencies.

Performance isn't a tradeoff. Build steps optimize bundle delivery, not the runtime work that follows it. WildflowerJS writes directly to the DOM, with no virtual DOM or reconciliation pass between state change and update, so it doesn't need a build step to be fast.

The framework is full-featured without the toolchain: router, SSR, stores, computed properties, transitions, pools. You don't need a toolchain to use any of it.

my-app/
  index.html
  app.js
  style.css
  wildflower.min.js

That's the entire project. No package.json.
No node_modules. No config files. Ship it.

Zero Install. Zero Attack Surface.

Every dependency you install is trust extended to a maintainer you've never met, running scripts on your dev machine and in your CI. A typical React + Vite + UI‑lib setup pulls in 300+ transitive packages before you write a feature.

Each one is a potential intrusion vector. NPM worms, OAuth chains compromising deploy platforms, postinstall hijacking: the supply chain is now where production code gets compromised, not the deploy. And signing isn't a backstop: Mini Shai‑Hulud (May 2026) compromised 170+ packages whose malicious versions carried valid SLSA Build Level 3 provenance, because the attestation came from build infrastructure the worm had already taken over.

WildflowerJS users don't have this attack surface, by construction. There is no npm install, no postinstall script, no transitive package graph. The framework is one file you copy or pin by hash.

As of v1.1, the same holds for building the framework itself. WildflowerJS bundles with a vendored rollup and terser pipeline pulled as three SHA‑512‑pinned tarballs: no npm install, no transitive packages, no postinstall scripts in the build path. The entire toolchain is three files you verify by hash.

Zero dependencies is the absence of a problem the rest of the industry has not properly addressed.

A typical React/Vue project:

  npm install
  ├── hundreds of packages
  ├── from hundreds of maintainers
  ├── postinstall scripts run on install
  └── tens to hundreds of MB of transitive code

WildflowerJS:

  <script src="wildflower.min.js"></script>
  └── 1 file.
      No transitive dependencies.

Zero Lock-in

WildflowerJS works with the DOM, not instead of it. There's no virtual DOM intercepting your code and no compiler rewriting your markup. The render cycle is yours.

That means Leaflet, DataTables, Chart.js, D3, Three.js, any library that touches the DOM, just works. No wrapper packages or framework-specific escape hatches required. Drop in a script tag and use it.

Because your code is standard HTML and JavaScript, you're never locked in. Your skills transfer and your code is more portable. If you outgrow the framework, your knowledge doesn't expire.

This also means your "ecosystem" is all of the world of vanilla JS. Without compromises or hacks.

<!-- Use any library directly -->
<div data-component="map-view">
  <div id="map" style="height: 400px"></div>
</div>
wildflower.component('map-view', {
  state: { lat: 51.505, lng: -0.09 },
  init() {
    // Leaflet works as-is. No wrappers.
    this._map = L.map('map')
      .setView([this.lat, this.lng], 13);
    L.tileLayer('https://{s}.tile.osm.org'
      + '/{z}/{x}/{y}.png').addTo(this._map);
  }
})

Precise Reactivity

When you write this.count++, WildflowerJS updates the single DOM node bound to count. Nothing else is touched. There's no tree diffing or reconciliation pass to figure that out.

This isn't a tradeoff. You get fine-grained updates and a simple mental model. Change a property, the bound element updates. That's the entire reactivity model.

Other frameworks ask you to learn signals, accessors, memos, effects, and subscription lifecycles to achieve what WildflowerJS does with a property assignment.

wildflower.component('dashboard', {
  state: {
    users: 1420,
    status: 'healthy'
  },
  computed: {
    summary() {
      return this.users + ' users, ' + this.status;
    }
  },
  refresh() {
    this.users = 1421;
    // Only the elements bound to 'users'
    // and 'summary' update. Everything
    // else on the page is untouched.
  }
})

One Reactivity Model. Everywhere.

Components, Stores, and Plugins all share the same reactive foundation. State, computed properties, and methods work identically no matter where they live. Learn it once, it works the same way in a UI component, a global store, or a framework plugin.

Other frameworks make you learn a different system for each layer. React components use hooks, but stores need Redux or Zustand, which are completely different APIs. Vue components use reactive data, but Pinia stores have their own patterns. Every layer is a new mental model.

In WildflowerJS, there's one model. A store is a component without a template. A plugin is an entity that extends the framework itself, adding directives, lifecycle hooks, and services. The same this.count++ triggers the same reactivity everywhere.

This unlocks patterns other frameworks can't express. A store can run headless physics simulations with tick(), feeding data into a component that renders it through a pool, all using the same reactive primitives, no glue code required.

// Component: reactive UI
wildflower.component('cart', {
  state: { items: [] },
  computed: {
    total() { return this.items.length; }
  }
})

// Store: global shared state
wildflower.store('user', {
  state: { name: '', role: 'guest' },
  computed: {
    isAdmin() { return this.role === 'admin'; }
  }
})

// Plugin: extends the framework
wildflower.plugin({
  name: 'notifications',
  state: { items: [], unreadCount: 0 },
  computed: {
    hasUnread() { return this.unreadCount > 0; }
  },
  add(msg) { this.items.push(msg); this.unreadCount++; }
})
// Access globally: wildflower.$notifications.add(...)

// Same state. Same computed. Same methods.

Data Pools

Every framework wraps collection items in reactive proxies, whether the item needs it or not. WildflowerJS gives you a choice: data-list for push reactivity (automatic), data-pool for pull reactivity (explicit control, zero proxy overhead).

Pools render plain objects with the same template syntax as lists. Mutate the object, call markDirty(), and only that item updates. Full CRUD, selection, bulk operations, all faster than the push-reactive path.

And because pools use pull-based rendering, they scale to simulations, games, particle systems, and data visualizations at native frame rate. Use cases that would choke a virtual DOM. No other framework has anything like this.

<div data-component="user-table">
  <tbody data-pool="users" data-key="id">
    <template>
      <tr>
        <td data-bind="name"></td>
        <td data-bind="status"
            data-bind-class="status === 'active'
              ? 'badge success'
              : 'badge inactive'"></td>
      </tr>
    </template>
  </tbody>
</div>
wildflower.component('user-table', {
  pools: { users: {} },

  init() {
    // Populate: plain objects, no proxies
    data.forEach(u => this.pools.users.add(u));
  },

  // Optional: add tick() and the same pool
  // renders every frame. Same template, same
  // data, different rendering frequency.
  // That's the only difference between a
  // display table and a particle system.
})

Built for AI-Assisted Development

Because WildflowerJS is standard HTML and JavaScript, AI code assistants already know how to write it. There's no custom syntax to hallucinate or compiler quirks to work around. The code an AI generates runs exactly as written, with no build step between generation and execution.

We go further. WildflowerJS ships an AI-optimized reference page with patterns, anti-patterns, and examples designed for code generation context windows. Our llms.txt file follows the llms.txt convention for machine-readable documentation.

And for structured app generation, our Universal App Manifest lets you describe an entire application as a JSON schema (components, state, computed properties, methods, templates) and have an AI generate the working code from the manifest, mediated through framework-specific idiom files.

You: "Build me a todo app with
WildflowerJS"

AI reads llms.txt or ai-assistant.html
     ↓
Generates standard HTML + JS
     ↓
<div data-component="todo-app">
  <input data-model="newItem">
  <button data-action="addItem">
    Add
  </button>
  <ul data-list="items">
    <template>
      <li data-bind="text"></li>
    </template>
  </ul>
</div>
     ↓
Open in your browser. It works, and you can read and understand the code.

Transitions CORE+

Add smooth CSS animations to elements when they appear or disappear using the data-transition attribute.

Key Concept: Transitions automatically apply CSS classes during show/hide operations, enabling smooth animations without manual JavaScript. The framework handles timing, cleanup, and even rapid toggle interruptions.

How Transitions Work

When an element with data-transition changes visibility, the framework applies CSS classes in a specific sequence:

Entering (showing)
  1. .{name}-enter - Initial state (e.g., opacity: 0)
  2. .{name}-enter-active - Active state with transition (opacity: 1)
  3. Classes removed after transition completes
Leaving (hiding)
  1. .{name}-leave - Initial state (e.g., opacity: 1)
  2. .{name}-leave-active - Active state with transition (opacity: 0)
  3. Element hidden after transition completes

Basic Usage

Add data-transition to any element with data-show or data-render:

<div data-component="fade-demo">
    <button class="btn btn-primary" data-action="toggle">Toggle Fade</button>

    <div data-show="isVisible" data-transition="fade"
         class="alert alert-success mt-3">
        I fade in and out smoothly!
    </div>
</div>
wildflower.component('fade-demo', {
    state: { isVisible: true },

    toggle() {
        this.isVisible = !this.isVisible
    }
})
Live Preview

CSS Requirements

For transitions to work, you need to define the CSS classes. Here's the fade transition CSS:

/* Define the transition CSS classes */
.fade-enter {
    opacity: 0;
}
.fade-enter-active {
    transition: opacity 0.3s ease;
    opacity: 1;
}
.fade-leave {
    opacity: 1;
}
.fade-leave-active {
    transition: opacity 0.3s ease;
    opacity: 0;
}

Built-in Transition Patterns

Here are common transition patterns you can use. Just define the CSS classes:

Fade

Simple opacity transition - great for modals and overlays.

.fade-enter { opacity: 0; }
.fade-enter-active { transition: opacity 0.3s ease; opacity: 1; }
.fade-leave { opacity: 1; }
.fade-leave-active { transition: opacity 0.3s ease; opacity: 0; }

Slide

Horizontal slide effect - great for sidebars and panels.

.slide-enter {
    transform: translateX(-100%);
    opacity: 0;
}
.slide-enter-active {
    transition: transform 0.3s ease, opacity 0.3s ease;
    transform: translateX(0);
    opacity: 1;
}
.slide-leave {
    transform: translateX(0);
    opacity: 1;
}
.slide-leave-active {
    transition: transform 0.3s ease, opacity 0.3s ease;
    transform: translateX(100%);
    opacity: 0;
}

Scale

Zoom effect - great for popups and cards.

<div data-component="scale-demo">
    <button class="btn btn-primary" data-action="toggle">Toggle Scale</button>

    <div class="d-flex justify-content-center mt-3">
        <div data-show="isVisible" data-transition="scale"
             class="card" style="width: 200px;">
            <div class="card-body text-center">
                <h5 class="card-title">Popup Card</h5>
                <p class="card-text">I scale up from nothing!</p>
            </div>
        </div>
    </div>
</div>
wildflower.component('scale-demo', {
    state: { isVisible: true },

    toggle() {
        this.isVisible = !this.isVisible
    }
})
Live Preview

Scale transition CSS:

.scale-enter {
    transform: scale(0);
    opacity: 0;
}
.scale-enter-active {
    transition: transform 0.3s ease, opacity 0.3s ease;
    transform: scale(1);
    opacity: 1;
}
.scale-leave {
    transform: scale(1);
    opacity: 1;
}
.scale-leave-active {
    transition: transform 0.3s ease, opacity 0.3s ease;
    transform: scale(0);
    opacity: 0;
}

Slide Down

Vertical expand/collapse - great for accordions and dropdowns.

<div data-component="accordion-demo">
    <div class="accordion">
        <div class="accordion-item">
            <button class="btn btn-outline-primary w-100 text-start"
                    data-action="toggleSection" data-section="1">
                Section 1
            </button>
            <div data-show="section1Open" data-transition="slide-down">
                <div>
                    <div class="p-3 bg-light border">
                        <p class="mb-0">Content for section 1. This slides down smoothly.</p>
                    </div>
                </div>
            </div>
        </div>
        <div class="accordion-item mt-2">
            <button class="btn btn-outline-primary w-100 text-start"
                    data-action="toggleSection" data-section="2">
                Section 2
            </button>
            <div data-show="section2Open" data-transition="slide-down">
                <div>
                    <div class="p-3 bg-light border">
                        <p class="mb-0">Content for section 2. Each section animates independently.</p>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
wildflower.component('accordion-demo', {
    state: {
        section1Open: false,
        section2Open: false
    },

    toggleSection(e) {
        const section = e.target.dataset.section
        const key = 'section' + section + 'Open'
        this[key] = !this[key]
    }
})
Live Preview

Slide down transition CSS:

/* Base: grid + transition are permanent so the layout is stable before any class toggle */
[data-transition="slide-down"] {
    display: grid;
    grid-template-rows: 1fr;
    transition: grid-template-rows 0.3s ease;
}
[data-transition="slide-down"] > * { overflow: hidden; min-height: 0; }

/* Transition classes only change the track size */
.slide-down-enter { grid-template-rows: 0fr; }
.slide-down-enter-active { grid-template-rows: 1fr; }
.slide-down-leave-active { grid-template-rows: 0fr; }
Why grid-template-rows? The max-height trick requires a magic pixel value and produces mismatched timing. grid-template-rows: 0fr → 1fr animates the actual content height with no guesswork. The base styles keep display: grid and transition permanent so the grid layout is stable before any class toggle. Important: the direct child of the transition element must be a bare wrapper with no padding or border, otherwise the grid track can't collapse to zero. Put visual styling on an inner element.

With data-show vs data-render

Transitions work with both conditional directives:

data-show + transition

Element remains in DOM, visibility toggled. Animation plays on each show/hide.

<div data-show="visible"
     data-transition="fade">
    Content
</div>
data-render + transition

Element inserted/removed from DOM. Animation plays on insert/removal.

<div data-render="exists"
     data-transition="scale">
    Content
</div>

JavaScript Lifecycle Hooks

For advanced control, components can define transition hooks that are called at key moments:

wildflower.component('advanced-transitions', {
    state: { isVisible: true },

    toggle() {
        this.isVisible = !this.isVisible
    },

    // Called before enter transition starts
    onBeforeEnter(el) {
        console.log('About to show:', el)
    },

    // Called when enter transition starts
    onEnter(el, done) {
        console.log('Entering:', el)
        // Call done() if you want to control when transition completes
    },

    // Called after enter transition completes
    onAfterEnter(el) {
        console.log('Fully visible:', el)
    },

    // Called before leave transition starts
    onBeforeLeave(el) {
        console.log('About to hide:', el)
    },

    // Called when leave transition starts
    onLeave(el, done) {
        console.log('Leaving:', el)
    },

    // Called after leave transition completes
    onAfterLeave(el) {
        console.log('Fully hidden:', el)
    }
})
Use Cases for Hooks:
  • Focus management (focus an input after modal appears)
  • Analytics tracking (log when content becomes visible)
  • Cleanup operations (cancel pending requests when hiding)
  • Chained animations (start another animation after one completes)

Example: Modal Dialog

A complete modal implementation with fade transition:

<div data-component="modal-demo">
    <button data-action="openModal">Open Modal</button>

    <div data-show="isOpen" data-transition="fade" class="modal-overlay">
        <div class="modal-content">
            <h3>Modal Title</h3>
            <p>This modal fades in and out smoothly.</p>
            <button data-action="closeModal">Close</button>
        </div>
    </div>
</div>
.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}

.modal-content {
    background: white;
    padding: 30px;
    border-radius: 8px;
    max-width: 400px;
}

/* Fade transition */
.fade-enter { opacity: 0; }
.fade-enter-active { transition: opacity 0.3s ease; opacity: 1; }
.fade-leave { opacity: 1; }
.fade-leave-active { transition: opacity 0.3s ease; opacity: 0; }
wildflower.component('modal-demo', {
    state: { isOpen: false },

    openModal() {
        this.isOpen = true
    },

    closeModal() {
        this.isOpen = false
    },

    // Focus trap when modal opens
    onAfterEnter(el) {
        const firstButton = el.querySelector('button')
        if (firstButton) firstButton.focus()
    }
})

Example: Accordion

Collapsible sections with slide-down animation:

<div data-component="accordion-demo">
    <button data-action="toggleSection" data-section="1">Section 1</button>
    <div data-show="section1Open" data-transition="slide-down">
        <div>
            <div class="accordion-content">
                <p>Content for section 1.</p>
            </div>
        </div>
    </div>

    <button data-action="toggleSection" data-section="2">Section 2</button>
    <div data-show="section2Open" data-transition="slide-down">
        <div>
            <div class="accordion-content">
                <p>Content for section 2.</p>
            </div>
        </div>
    </div>
</div>
wildflower.component('accordion-demo', {
    state: {
        section1Open: false,
        section2Open: false
    },

    toggleSection(e) {
        const section = e.target.dataset.section
        const key = `section${section}Open`
        this[key] = !this[key]
    }
})

Example: Notification Stack

Using data-render with transitions for notifications that are added/removed from DOM:

<div data-component="notification-stack">
    <button data-action="addNotification">Add Notification</button>

    <div class="notification-area">
        <div data-render="notifications.length > 0">
            <div data-list="notifications">
                <template>
                    <div data-transition="slide" class="notification">
                        <span data-bind="message"></span>
                        <button data-action="dismiss">×</button>
                    </div>
                </template>
            </div>
        </div>
    </div>
</div>

Rapid Toggle Handling

The framework gracefully handles rapid state changes during transitions:

  • If visibility changes mid-transition, the current transition is cancelled
  • The new transition starts immediately from the current visual state
  • No "stuck" states or animation conflicts occur
  • Final state always matches the last state change
wildflower.component('rapid-toggle-demo', {
    state: { isVisible: true },

    rapidToggle() {
        // Even rapid toggles work correctly
        for (let i = 0; i < 5; i++) {
            setTimeout(() => {
                this.isVisible = !this.isVisible
            }, i * 50)
        }
    }
})

Custom Transition Names

Use any name you want - just match it in your CSS:

<!-- Use a custom transition name -->
<div data-show="active" data-transition="bounce">
    Bouncy content!
</div>
/* Custom bounce transition */
.bounce-enter {
    transform: scale(0.3);
    opacity: 0;
}
.bounce-enter-active {
    transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55),
                opacity 0.3s ease;
    transform: scale(1);
    opacity: 1;
}
.bounce-leave {
    transform: scale(1);
    opacity: 1;
}
.bounce-leave-active {
    transition: transform 0.3s ease, opacity 0.3s ease;
    transform: scale(0.3);
    opacity: 0;
}

Best Practices

Do
  • Keep transitions short (200-400ms) for responsiveness
  • Use transform and opacity for best performance
  • Match enter and leave durations for consistency
  • Use will-change for frequently animated elements
  • Test transitions on slower devices
Don't
  • Animate width, height, or top/left (causes reflow)
  • Use transitions longer than 500ms for UI elements
  • Forget the -active classes (nothing will animate)
  • Animate too many elements simultaneously
  • Ignore users who prefer reduced motion

Respecting User Preferences

Consider users who prefer reduced motion:

@media (prefers-reduced-motion: reduce) {
    .fade-enter-active,
    .fade-leave-active,
    .slide-enter-active,
    .slide-leave-active,
    .slide-down-enter-active,
    .slide-down-leave-active,
    .scale-enter-active,
    .scale-leave-active {
        transition: none !important;
    }
}

Simple Syntax

Transitions use a single attribute with CSS class conventions:

<!-- Apply fade transition -->
<div data-transition="fade" data-show="isVisible">
    Content fades in and out
</div>

No wrapper elements required. The transition name maps directly to CSS classes (.fade-enter, .fade-leave, etc.), giving you full control over the animation with standard CSS.

List Item Animations with AutoAnimate

WildflowerJS transitions (data-transition) handle individual element show/hide. For list item animations (smoothly animating items as they are added, removed, reordered, or filtered), use AutoAnimate, a zero-config FLIP animation library.

Why AutoAnimate? Frameworks like Vue and Svelte have built-in <TransitionGroup> components for list animations. WildflowerJS takes a different approach: rather than building a custom solution, we recommend AutoAnimate, a framework-agnostic library that works with any DOM manipulation, including WildflowerJS's data-list rendering.

Setup

AutoAnimate is loaded on demand via dynamic import(). No build step needed:

wildflower.component('animated-list', {
    state: {
        items: [
            { id: 1, name: 'First item' },
            { id: 2, name: 'Second item' }
        ],
        nextId: 3
    },

    init() {
        var self = this;
        var listEl = this.element.querySelector('[data-list]');
        if (!listEl) return;

        // Load AutoAnimate and apply to the list container
        import('https://cdn.jsdelivr.net/npm/@formkit/auto-animate@0.8.2/+esm')
            .then(function(mod) {
                self._animController = mod.default(listEl, { duration: 150 });
            }).catch(function() {});
    },

    addItem() {
        this.items.push({
            id: this.nextId++,
            name: 'Item ' + this.nextId
        });
    },

    removeItem(event, element, details) {
        var index = details.index;
        this.items.splice(index, 1);
    },

    destroy() {
        // Always clean up: disable the observer when component is removed
        if (this._animController) this._animController.disable();
    }
});
<div data-component="animated-list">
    <button data-action="addItem">Add Item</button>
    <ul data-list="items" data-key="id">
        <template>
            <li>
                <span data-bind="name"></span>
                <button data-action="removeItem">Remove</button>
            </li>
        </template>
    </ul>
</div>

Using with SortableJS (Drag and Drop)

When combining AutoAnimate with SortableJS for drag-and-drop, disable AutoAnimate during drag operations to prevent the two libraries from conflicting:

init() {
    var self = this;
    var listEl = this.element.querySelector('.sortable-list');

    // SortableJS for drag and drop
    this._sortable = new Sortable(listEl, {
        animation: 75,
        onStart: function() {
            if (self._animController) self._animController.disable();
        },
        onEnd: function(evt) {
            // Re-enable after one frame so SortableJS finishes
            // removing ghost/chosen classes first
            requestAnimationFrame(function() {
                if (self._animController) self._animController.enable();
            });
            // ... handle reorder via store
        }
    });

    // AutoAnimate for add/remove/filter animations
    import('https://cdn.jsdelivr.net/npm/@formkit/auto-animate@0.8.2/+esm')
        .then(function(mod) {
            self._animController = mod.default(listEl, { duration: 150 });
        }).catch(function() {});
},

destroy() {
    if (this._sortable) this._sortable.destroy();
    if (this._animController) this._animController.disable();
}
Cleanup: Always disable or destroy third-party library instances in your component's destroy() method to prevent memory leaks. See Third-Party Integration for more details.

Configuration Options

AutoAnimate accepts an options object:

// Customize animation behavior
autoAnimate(element, {
    duration: 150,      // Animation duration in ms (default: 250)
    easing: 'ease-out'  // CSS easing function (default: 'ease-in-out')
});

// The returned controller can enable/disable animations
var controller = autoAnimate(element);
controller.disable();   // Pause animations
controller.enable();    // Resume animations
controller.isEnabled(); // Check status