<!-- Source: https://motion.svelte.page/examples/lazy-motion -->

# LazyMotion

> Use LazyMotion, m, domMin, domAnimation, and domMax to choose the motion feature bundle for a subtree.

**Source:** [https://motion.svelte.page/examples/lazy-motion](https://motion.svelte.page/examples/lazy-motion)

**Markdown mirror:** [https://motion.svelte.page/examples/lazy-motion.md](https://motion.svelte.page/examples/lazy-motion.md)

---

This mirror preserves the prose, implementation notes, and runnable Svelte source behind the live example page.

## FIG-001: load features around m.

Wrap `m.*` components in LazyMotion and pass a feature bundle. The element still animates on mount, while gesture support comes from the selected bundle.

**Metadata:** tag: `LAZY` | bundle: `domAnimation`

### Notes

- `LazyMotion` provides the active feature bundle through context. Descendant `m.*` elements read that context before attaching gesture, drag, or layout behavior.
- `domAnimation` is the usual interactive bundle: mount/update animations plus hover, tap, focus, pan, and in-view gestures.

### Source

#### Default.svelte

Source file: [src/lib/examples/lazy-motion/demos/Default.svelte](https://github.com/humanspeak/svelte-motion/blob/main/docs/src/lib/examples/lazy-motion/demos/Default.svelte)

```svelte
<script lang="ts">
    import { LazyMotion, domAnimation, m, motion, styleString } from '@humanspeak/svelte-motion'

    let replayId = $state(0)
</script>

<!-- dk-strip: docs-kit positioning shell — stripped from the published code. -->
<div class="dk-demo-shell">
    <div class="strip">
        <div class="strip-head">
            <span class="micro">// lazy motion</span>
            <span class="micro readout">features: domAnimation</span>
        </div>

        <div class="stage">
            <LazyMotion features={domAnimation}>
                {#key replayId}
                    <m.button
                        initial={{ opacity: 0, y: 24, scale: 0.94 }}
                        animate={{ opacity: 1, y: 0, scale: 1 }}
                        whileHover={{ y: -4, scale: 1.04 }}
                        whileTap={{ scale: 0.96 }}
                        transition={{ duration: 0.35, ease: 'easeOut' }}
                        style={styleString(() => ({
                            fontFamily: 'var(--brut-mono, monospace)',
                            fontSize: '0.8125rem',
                            fontWeight: 700,
                            letterSpacing: '0.04em',
                            textTransform: 'uppercase',
                            border: '1px solid var(--brut-ink, #0a0a0a)',
                            backgroundColor: 'var(--brut-bg-2, #eef4f1)',
                            color: 'var(--brut-ink, #0a0a0a)',
                            padding: '0.75rem 1.25rem',
                            boxShadow: '6px 6px 0 var(--brut-rule, #d6dedb)',
                            cursor: 'pointer'
                        }))}
                    >
                        Lazy m.button
                    </m.button>
                {/key}
            </LazyMotion>
        </div>

        <div class="strip-foot">
            <motion.button
                type="button"
                onclick={() => (replayId += 1)}
                whileHover={{ scale: 1.04 }}
                whileTap={{ scale: 0.96 }}
                transition={{ type: 'spring', stiffness: 500, damping: 30 }}
                style={styleString(() => ({
                    fontFamily: 'var(--brut-mono, monospace)',
                    fontSize: '0.6875rem',
                    textTransform: 'uppercase',
                    letterSpacing: '0.08em',
                    border: '1px solid var(--brut-accent, #247768)',
                    backgroundColor: 'var(--brut-accent-soft, rgba(36, 119, 104, 0.1))',
                    color: 'var(--brut-accent, #247768)',
                    padding: '0.5rem 0.875rem',
                    cursor: 'pointer'
                }))}
            >
                ↻ replay
            </motion.button>
            <span class="micro">lazy-loaded feature bundle</span>
        </div>
    </div>
</div>

<style>
    .dk-demo-shell {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 1.5rem;
        min-height: 260px;
    }

    .strip {
        width: 100%;
        max-width: 420px;
        display: flex;
        flex-direction: column;
        gap: 0.75rem;
    }

    .micro {
        font-family: var(--brut-mono, monospace);
        font-size: 0.6875rem;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        color: var(--brut-ink-3, #9a9a9a);
    }

    .readout {
        color: var(--brut-accent, #247768);
    }

    .strip-head,
    .strip-foot {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        border-bottom: 1px dashed var(--brut-rule-2, #bbc4c0);
        padding-bottom: 0.5rem;
    }

    .strip-foot {
        border-bottom: none;
        border-top: 1px dashed var(--brut-rule-2, #bbc4c0);
        padding-top: 0.75rem;
        padding-bottom: 0;
    }

    .stage {
        height: 8rem;
        display: flex;
        align-items: center;
        justify-content: center;
    }
</style>
```

## FIG-002: compare domMin/domAnimation/domMax.

`domMin` keeps animation only, `domAnimation` enables gestures, and `domMax` adds drag/layout behavior for the subtree.

**Metadata:** tag: `BUNDLES` | split: `min / animation / max`

### Notes

- The same `m.div` receives different runtime capabilities depending on the nearest `LazyMotion` provider.
- Try hover/tap across all three cards. Drag is intentionally available only under `domMax`.

### Source

#### FeatureBundles.svelte

Source file: [src/lib/examples/lazy-motion/demos/FeatureBundles.svelte](https://github.com/humanspeak/svelte-motion/blob/main/docs/src/lib/examples/lazy-motion/demos/FeatureBundles.svelte)

```svelte
<script lang="ts">
    import {
        LazyMotion,
        domAnimation,
        domMax,
        domMin,
        m,
        styleString
    } from '@humanspeak/svelte-motion'

    const bundles = [
        { label: 'domMin', features: domMin, note: 'animation only' },
        { label: 'domAnimation', features: domAnimation, note: 'gestures enabled' },
        { label: 'domMax', features: domMax, note: 'gestures + drag + layout' }
    ]
</script>

<!-- dk-strip: docs-kit positioning shell — stripped from the published code. -->
<div class="dk-demo-shell">
    {#each bundles as bundle (bundle.label)}
        <LazyMotion features={bundle.features}>
            <section class="bundle">
                <header>
                    <span class="micro label">// {bundle.label}</span>
                    <span class="note">{bundle.note}</span>
                </header>
                <div class="stage">
                    <m.div
                        initial={{ opacity: 0, scale: 0.8 }}
                        animate={{ opacity: 1, scale: 1 }}
                        whileHover={{ scale: 1.14 }}
                        whileTap={{ scale: 0.92 }}
                        drag
                        style={styleString(() => ({
                            // Wide enough for the longest label (DOMANIMATION)
                            // with breathing room — 72px clipped it.
                            width: '120px',
                            height: '72px',
                            display: 'grid',
                            placeItems: 'center',
                            border: '1px solid var(--brut-ink, #0a0a0a)',
                            backgroundColor: 'var(--brut-accent-soft, rgba(36, 119, 104, 0.1))',
                            boxShadow: '4px 4px 0 var(--brut-rule, #d6dedb)',
                            color: 'var(--brut-ink, #0a0a0a)',
                            fontFamily: 'var(--brut-mono, monospace)',
                            fontSize: '0.625rem',
                            fontWeight: 700,
                            textTransform: 'uppercase',
                            letterSpacing: '0.04em',
                            cursor: 'grab',
                            userSelect: 'none'
                        }))}
                    >
                        {bundle.label}
                    </m.div>
                </div>
            </section>
        </LazyMotion>
    {/each}
</div>

<style>
    .dk-demo-shell {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 0.75rem;
        width: 100%;
        padding: 1rem;
    }

    .bundle {
        border: 1px solid var(--brut-rule-2, #bbc4c0);
        background: var(--brut-bg-2, #eef4f1);
        padding: 0.8rem;
    }

    header {
        display: grid;
        gap: 0.25rem;
        margin-bottom: 0.8rem;
    }

    .micro {
        font-family: var(--brut-mono, monospace);
        font-size: 0.6875rem;
        letter-spacing: 0.08em;
        text-transform: uppercase;
    }

    .label {
        font-weight: 700;
        color: var(--brut-accent, #247768);
    }

    .note {
        font-family: var(--brut-mono, monospace);
        font-size: 0.625rem;
        letter-spacing: 0.06em;
        text-transform: uppercase;
        color: var(--brut-ink-3, #9a9a9a);
    }

    .stage {
        min-height: 140px;
        display: grid;
        place-items: center;
        border: 1px dashed var(--brut-rule-2, #bbc4c0);
    }

    @media (max-width: 720px) {
        .dk-demo-shell {
            grid-template-columns: 1fr;
        }
    }
</style>
```
