<smart-motion>
<smart-effects>

Animations & Page Transitions

Two Web Components that together handle every animation need in a SmartComponents Django project. SmartMotion owns page-to-page transitions using Barba.js — it intercepts link clicks, runs a visual transition, swaps the content, and fires lifecycle events. SmartEffects owns element-level animations using Anime.js — it listens for those same lifecycle events to re-animate content on every navigation, and also handles scroll-triggered, hover, click, and manual animations independently.

Both components are zero-config in base.html — drop in two tags and every page in your project gets fluid transitions and entrance animations automatically.

Barba.js Transitions Anime.js Effects 5 Transition Types 8 Animation Presets Scroll Triggers Auto Mode
How they communicate
User clicks link
<smart-motion>
smart-page-leave
Barba swaps DOM
smart-page-enter
<smart-effects>
Animates new content
<script type="module" src="smart_motion.js"></script> <script type="module" src="smart_effect.js"></script>

base.html Setup

Both components live outside the Barba container — they must survive every page transition. The Barba wrapper, container, global singletons, and both animation components are the only elements that should be outside .

<body>
  <!-- Barba wrapper — wraps everything -->
  <div data-barba="wrapper">
    <div data-barba="container"
         data-barba-namespace="  default  ">

      <!-- Global singletons — stay here, never re-mount on nav -->
      <smart-toast position="top-right" max="5"></smart-toast>
      <smart-modal></smart-modal>
      <smart-loader type="overlay"></smart-loader>

       --  
    </div>
  </div>

  <!-- Animation components — outside container, survive every transition -->
  <smart-motion type="panel" duration="400"></smart-motion>
  <smart-effects auto></smart-effects>

  <!-- CDN deps -->
  <script src="https://cdn.jsdelivr.net/npm/@barba/core"></script>
  <script src="https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js"></script>

  <!-- Components -->
  <script type="module" src="< static 'resources/js/components/smart_motion.js' >"></script>
  <script type="module" src="< static 'resources/js/components/smart_effect.js' >"></script>
</body>
Why outside the container? Barba.js replaces the data-barba="container" element on every navigation. Anything inside that element is destroyed and re-created. SmartMotion and SmartEffects must persist across navigations — they hold the Barba instance, the overlay DOM element, scroll observers, and event listeners. Place them directly in <body> after the wrapper.
<smart-motion>

SmartMotion

Initializes Barba.js, intercepts all link clicks on the page, runs the chosen transition between pages, re-executes page scripts in the new container, swaps < block extra_head > styles, and fires three window events for other components to hook into.

Script re-execution: After each navigation SmartMotion re-runs all <script> tags found inside the new container. CDN scripts (cross-origin) are loaded once and cached — never re-fetched. Local/same-origin scripts are re-executed on every navigation so their DOMContentLoaded and init logic runs fresh. Inline scripts always re-run, wrapped in an IIFE for scope isolation.

Transition Types

Set type on <smart-motion>. The type is fixed at initialization — it applies to every navigation for the session.

default
type
overlay
Blocks screen, swaps content, reveals
type
👁
fade
Current fades out, new fades in
type
slide
Slides up on leave, slides in from bottom
type
scale
Zooms out on leave, zooms in on enter
recommended
type
panel
Full-screen cover slides in from left, exits right. Includes spinner.
type
panel-down
Full-screen cover slides in from left, exits right. Includes spinner.
type
panel-left
Full-screen cover slides in from left, exits right. Includes spinner.
type
panel-right
Full-screen cover slides in from left, exits right. Includes spinner.
<!-- Pick one type — applies to every page transition -->
<smart-motion type="overlay" duration="400"></smart-motion>
<smart-motion type="fade"    duration="300"></smart-motion>
<smart-motion type="slide"   duration="350"></smart-motion>
<smart-motion type="scale"   duration="400"></smart-motion>
<smart-motion type="panel"   duration="400"></smart-motion>

// duration controls each half of the transition.
// Panel total = ~duration * 1.3ms (leave + enter overlap slightly)

Lifecycle Events

SmartMotion dispatches three events on window during every navigation. SmartEffects listens to smart-page-enter automatically. Your own page scripts can listen to all three.

EventdetailWhen it fires
smart-page-leave { namespace } When the current page begins leaving — transition starts, old container still visible.
smart-page-enter { namespace, container } After the new container is fully mounted and scripts have re-run. Safe to query DOM. SmartEffects listens here.
smart-page-mounted { namespace, container } Fired immediately after smart-page-enter. Convenience alias for code that needs a separate listener.
// Listen from any script — e.g. re-init a third-party widget after navigation
window.addEventListener('smart-page-enter', (e) => {
  const { namespace, container } = e.detail;
  console.log('Navigated to:', namespace);

  // container is the new data-barba="container" element
  // Safe to query DOM here — scripts have already re-run
  container.querySelectorAll('[data-chart]').forEach(el => initChart(el));
});

window.addEventListener('smart-page-leave', (e) => {
  // Tear down things before the page exits
  destroyWebSockets();
});

// Also available: barba:afterEnter (back-compat alias fired by SmartMotion)
window.addEventListener('barba:afterEnter', (e) => {
  const container = e.detail.container;
});

Preventing Transitions

SmartMotion automatically skips Barba for same-page anchor links, external URLs, and hash-only hrefs. Use data-no-barba on any link to opt it out explicitly.

<!-- These are skipped automatically -->
<a href="#section">Anchor — no transition</a>
<a href="https://external.com">External — no transition</a>

<!-- Opt out individual links -->
<a href="/download/" data-no-barba>Force full page load</a>

<!-- Barba namespace per page — optional, used in smart-page-enter detail -->
< block namespace >home< endblock >
<!-- In the template: -->
<div data-barba="container"
     data-barba-namespace="< block namespace >default< endblock >">

// In views.py — pass namespace for analytics or per-namespace effects
def dashboard(request):
    return render(request, 'dashboard.html')

SmartMotion Reference

AttributeTypeDescriptionDefault
type string overlay · fade · slide · scale · panel. Applies to every page navigation. overlay
duration number Duration in ms for each half of the transition (leave or enter). Panel type uses this value for both phases with slight overlap. 400

Global helpers exposed on window by SmartMotion for page scripts:

FunctionDescription
window.barbaExecuteScripts(container?) Manually trigger SmartMotion's post-navigation setup — re-runs scripts, reinits Bootstrap, fires smart-page-enter. Useful after programmatic DOM injection.
window.barbaCleanup(names[]) Delete named globals from window before the next page loads. Pass variable names from the current page that would otherwise leak.
<smart-effects>

SmartEffects

Anime.js animation engine as a Web Component. Declare what to animate, when to animate it, and with which preset or custom parameters — all via HTML attributes. Works standalone or coordinated with SmartMotion. On every navigation, SmartEffects receives smart-page-enter, clears animated flags on the new container, and re-fires all animations on fresh elements.

Re-animation on every page: SmartEffects tracks which elements have already animated via a data-smart-animated attribute. When SmartMotion fires smart-page-enter with the new container, SmartEffects removes all those flags so the elements animate again on the fresh DOM — giving each page its own entrance animation without any per-page configuration.

Built-in Presets

Use type="preset-name" to run a preset. Each preset is a function that receives the current scope (Barba container or document) and returns an Anime.js config object.

card-stagger
All .card elements pop in with a staggered translateY + opacity from.
fade-up
Generic fade-up for .fade-up-item or a custom target.
modal-pop
Scales in a Bootstrap .modal-dialog from 0.88 with easeOutBack bounce.
sidebar-slide
Slides .sidebar in from -300px on the X axis.
table-stagger
Staggers all table tr rows in with a slight left-slide and fade.
button-click
Scale micro-interaction (1 → 1.08 → 1) for button press feedback.
input-focus
Pulses a blue box-shadow on focused inputs.
error-shake
Shakes .is-invalid / .form-error elements horizontally.
card-stagger live demo — click any preset button above to re-trigger
Card 1
Card 2
Card 3
Card 4
<!-- Run a preset once on page load -->
<smart-effects type="card-stagger"></smart-effects>

<!-- Run preset on scroll (fires when elements enter viewport) -->
<smart-effects type="table-stagger" trigger="scroll"></smart-effects>

<!-- Preset with a custom target selector override -->
<smart-effects type="fade-up" target=".my-items"></smart-effects>

// From JS — call a preset programmatically:
const fx = document.querySelector('smart-effects');
fx.playPreset('card-stagger');
fx.playPreset('error-shake', '.my-form .is-invalid'); // with target override

Trigger Modes

Control when the animation fires using the trigger attribute.

page scroll hover click manual
triggerBehaviourUse case
page Fires once on initial page load and again on every Barba navigation. Default. Hero sections, card grids, page-level entrance animations.
scroll Uses IntersectionObserver. Elements are pre-hidden (opacity:0) and animate in when they enter the viewport. Cleaned up correctly on navigation. Long pages with sections below the fold. Timeline items, feature lists.
hover Attaches mouseenter listeners to all matching target elements. Re-wired on every navigation. Card hover effects, icon bounce on hover.
click Attaches click listeners to all matching target elements. Can use a preset or attribute-driven config. Button press feedback, toggle animations.
manual Does nothing automatically. Call fx.play() or fx.playPreset() from your own JS. Animations triggered by form submission, AJAX response, or custom logic.
<!-- Page trigger (default) -->
<smart-effects type="card-stagger"></smart-effects>

<!-- Scroll trigger — elements animate when they scroll into view -->
<smart-effects
  trigger="scroll"
  target=".feature-item"
  translateY="40"
  opacity="0"
  duration="700"
></smart-effects>

<!-- Hover trigger -->
<smart-effects
  trigger="hover"
  target=".card"
  scale="0.97"
  duration="200"
></smart-effects>

<!-- Click trigger with button-click preset -->
<smart-effects
  trigger="click"
  type="button-click"
  target=".btn"
></smart-effects>

<!-- Manual trigger — call from JS -->
<smart-effects id="myFx" trigger="manual" type="card-stagger"></smart-effects>

document.querySelector('smart-form').addEventListener('smart-form-success', () => {
  document.getElementById('myFx').play();
});

Custom Attribute-Driven Animations

When no type preset is set, SmartEffects builds an Anime.js config directly from the element's attributes. Set any transform or opacity attribute and SmartEffects animates from that value to its natural resting state (0 for transforms, 1 for opacity). If no attributes are set, it defaults to a simple fade-up.

<!-- Fade up from 40px below -->
<smart-effects
  target=".hero"
  translateY="40"
  opacity="0"
  duration="900"
  easing="easeOutExpo"
></smart-effects>

<!-- Slide in from left -->
<smart-effects
  target=".sidebar-nav"
  translateX="-60"
  opacity="0"
  duration="500"
></smart-effects>

<!-- Scale pop-in -->
<smart-effects
  target=".badge"
  scale="0.5"
  opacity="0"
  duration="400"
  easing="easeOutBack"
></smart-effects>

<!-- Rotation entrance -->
<smart-effects
  target=".icon-spin"
  rotate="-45"
  opacity="0"
  duration="600"
></smart-effects>

<!-- Initial delay -->
<smart-effects
  target=".cta-section"
  translateY="24"
  opacity="0"
  delay="400"
  duration="700"
></smart-effects>

// All attributes: translateX · translateY · scale · rotate · opacity
// · delay · duration · easing (any Anime.js easing string)

Auto Mode

Add the auto boolean attribute for zero-config animations. SmartEffects scans the page for standard element groups and applies appropriate presets automatically. It also wires nav link click micro-interactions. This is the recommended mode for base.html — it covers the most common cases without any per-page configuration.

<!-- Drop in base.html — animates everything automatically -->
<smart-effects auto></smart-effects>

// What auto mode targets automatically:
// .card              → card-stagger preset  (translateY + opacity stagger)
// table tr           → table-stagger preset (translateX + opacity stagger)
// .list-group-item   → translateX fade      (custom, no preset needed)
// .sidebar           → sidebar-slide preset (slides in from left)
// .nav-link          → scale click effect   (micro-interaction on click)

You can combine auto with a specific type or target — auto mode runs alongside, not instead of, any other configuration:

<!-- Auto mode + explicit hero animation -->
<smart-effects auto target=".hero-title" translateY="60" opacity="0" duration="1000"></smart-effects>

<!-- Auto mode + scroll preset for below-fold sections -->
<smart-effects auto></smart-effects>
<smart-effects trigger="scroll" target=".section-block" translateY="30" opacity="0"></smart-effects>

<!-- Multiple smart-effects tags are allowed — each runs independently -->

SmartEffects Reference

AttributeTypeDescriptionDefault
auto boolean Enable zero-config auto mode. Scans for .card, table tr, .list-group-item, .sidebar, and .nav-link elements. false
type string Name of a built-in preset: card-stagger · fade-up · modal-pop · sidebar-slide · table-stagger · button-click · input-focus · error-shake.
target string CSS selector for elements to animate. Required when using custom attribute animation. Used as override target for presets that support it.
trigger string page · scroll · hover · click · manual. When to fire the animation. page
delay number Initial delay before the animation starts (ms). For staggered presets, this becomes the stagger start offset. 0
duration number Animation duration in ms. 700
easing string Any valid Anime.js easing string: easeOutCubic, easeOutExpo, easeOutBack, spring(1,80,10,0), etc. easeOutCubic
translateX number Animate from this X offset (px) → 0. Positive = from right, negative = from left.
translateY number Animate from this Y offset (px) → 0. Positive = from below, negative = from above.
scale number Animate from this scale → 1. Use values like 0.8 for scale-in, 1.2 for scale-down.
rotate number Animate from this rotation (deg) → 0.
opacity number Animate from this opacity → 1. Use 0 for a fade-in.

Public JS API

MethodDescription
play(selector?) Manually trigger the animation. Pass an optional selector to override target. Use when trigger="manual".
playPreset(name, targetOverride?) Run a specific named preset programmatically. Optionally override the target selector. Safe to call at any time.

Card Stagger on Page Load

The most common pattern — a grid of cards that stagger in when the page loads and re-animates on every Barba navigation. SmartEffects automatically skips already-animated cards and re-animates them fresh on the next page visit.

Dashboard
Analytics
Reports
Settings
Users
Billing
<!-- In base.html — fires on every page automatically -->
<smart-effects auto></smart-effects>

<!-- Or explicitly on a specific page -->
<smart-effects type="card-stagger"></smart-effects>

<!-- Your Django template -->
<div class="row">
  < for item in items >
  <div class="col-md-4">
    <div class="card">
      <div class="card-body">
        <h5></h5>
      </div>
    </div>
  </div>
  < endfor >
</div>

Scroll-Triggered Sections

Use trigger="scroll" for content below the fold. SmartEffects pre-hides the targets at opacity:0 and triggers individual animations via IntersectionObserver as each element enters the viewport. On Barba navigation, all scroll observers are automatically disconnected and recreated for the new page.

Feature A
Feature B
Feature C
Feature D
<!-- One tag handles all .feature-item elements on the page -->
<smart-effects
  trigger="scroll"
  target=".feature-item"
  translateY="40"
  opacity="0"
  duration="700"
  easing="easeOutExpo"
></smart-effects>

<!-- Or combine with a preset -->
<smart-effects
  trigger="scroll"
  type="fade-up"
  target=".section-block"
></smart-effects>

// IntersectionObserver config used internally:
// threshold: 0.12 (fires when 12% visible)
// rootMargin: '0px 0px -40px 0px' (40px buffer from bottom)

Manual Trigger & JS API

Trigger animations from your own JavaScript — useful after form submissions, AJAX responses, SmartTable row loads, or any dynamic content insertion.

Python Django Barba
<!-- Declare with trigger="manual" -->
<smart-effects
  id="formFx"
  trigger="manual"
  type="card-stagger"
></smart-effects>

const fx = document.getElementById('formFx');

// After SmartForm success — animate new table rows
document.querySelector('smart-form').addEventListener(
  'smart-form-success', () => {
    fx.playPreset('table-stagger');
  }
);

// After inline validation — shake invalid fields
document.querySelector('smart-form').addEventListener(
  'smart-form-error', () => {
    fx.playPreset('error-shake', '.is-invalid');
  }
);

// Custom selector at call time — override target dynamically
fx.play('.newly-added-items');

// Works with smart-page-enter too — runs after every Barba nav
window.addEventListener('smart-page-enter', () => {
  fx.play();
});

Django + Barba Page Setup

Each Django template that uses Barba transitions needs only two things: extend base.html and set a namespace block. Page-specific scripts go inside so SmartMotion can re-execute them on every navigation. The is for styles only — SmartMotion extracts and re-injects those automatically.


< extends 'base.html' >
< load static >

 Dashboard 
 dashboard 


<!-- Page-specific styles (SmartMotion re-injects on navigation) -->
<style>
  .stat-card { border-radius: 12px; }
</style>
< endblock >


<div class="container py-4">
  <div class="row g-3">
    < for stat in stats >
    <div class="col-md-3">
      <div class="card stat-card"></div>
    </div>
    < endfor >
  </div>
</div>

<!--
  Page scripts go here — SmartMotion re-executes on every navigation.
  Use DOMContentLoaded OR just run directly (SmartMotion fires DOMContentLoaded too).
-->
<script>
  // This runs on first page load AND on every Barba navigation to this page
  document.addEventListener('DOMContentLoaded', () => {
    initDashboardCharts();
  });
</script>
< endblock >

# views.py — nothing special needed
def dashboard(request):
    return render(request, 'dashboard.html', {
        'stats': get_stats()
    })
Script scoping tip: Inline scripts inside < block content > are wrapped in an IIFE by SmartMotion before execution, so variable naming conflicts between navigations are avoided. Use window.barbaCleanup(['myVar', 'myChart']) in a smart-page-leave listener to clean up any globals from the current page before the next one loads.