From a3d75655648f69bd4a0a02faea1b030094229518 Mon Sep 17 00:00:00 2001 From: dev Date: Sun, 21 Jun 2026 14:37:06 +0200 Subject: [PATCH] demo(motion): loops + lifecycle + staggered cascade with an SVG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A `/demos/motion` page showcasing the content domain: - Loops (spin/pulse/ping/bounce) on clean SVG via `motionAttrs`. - Enter → loop → exit lifecycle on a pigeon SVG adapted from the `/demos` paloma (the page has no ActiveEidos provider, so it loads the static eidos CSS and replicates ``'s exit inline). - Staggered list: container-driven cascade IN (first item first) and OUT in reverse (last leaves first), retained then unmounted — the §D.13.2 bridge. Co-Authored-By: Claude Opus 4.8 (1M context) --- web/routes/demos/motion/+page.svelte | 449 ++++++++++++++++++++++++++ web/routes/demos/motion/pigeon.svelte | 55 ++++ 2 files changed, 504 insertions(+) create mode 100644 web/routes/demos/motion/+page.svelte create mode 100644 web/routes/demos/motion/pigeon.svelte diff --git a/web/routes/demos/motion/+page.svelte b/web/routes/demos/motion/+page.svelte new file mode 100644 index 000000000..f14bcbc2c --- /dev/null +++ b/web/routes/demos/motion/+page.svelte @@ -0,0 +1,449 @@ + + +
+
+

UIX · motion · content domain

+

Loops & lifecycle

+

+ A motion preset on plain content. Loops run forever while present; + enter / exit ride the element's mount & removal. No JS engine — the foundation + CSS does it, and reduced-motion stops it. +

+
+ + +
+

Loops — infinite, content domain

+
+ {#each loops as loop (loop.name)} +
+
+ {#if loop.name === 'spin'} + + + + + {:else if loop.name === 'pulse'} + + + + {:else if loop.name === 'ping'} + + + + + {:else} + + + + {/if} +
+
+ motion="{loop.name}" + {loop.blurb} +
+
+ {/each} +
+

+ Applied with {'{...motionAttrs(preset)}'} on the SVG (or the ring, for ping). + The preset is the primary trigger — no event, no state to compose with. +

+
+ + +
+

Enter / exit — the content lifecycle

+
+
+ {#if show} +
+
+ +
+
+ {/if} +
+ +
+ + + + + + +

+ <Motion motion="{enterExit}"> plays enter on mount, exit on removal + (it retains the node for the eidos-declared duration). The loop on the inner element runs the + whole time it's present — enter → loop → exit, the full content lifecycle. +

+
+
+
+ + +
+

Staggered list — container-driven cascade, in & out

+
+
+ {#if listMounted} +
+ {#each listItems as item (item)} +
+ {item} +
+ {/each} +
+ {/if} +
+ +
+ + + + +

+ The [data-stagger] container's data-state drives its direct children. + Enter cascades in (first item first); exit cascades out in reverse (last leaves + first) via --motion-stagger-index-rev. The pragmatic CSS bridge: the container is + retained for the stagger window, then unmounts — no JS orchestration engine. +

+
+
+
+
+ + diff --git a/web/routes/demos/motion/pigeon.svelte b/web/routes/demos/motion/pigeon.svelte new file mode 100644 index 000000000..82a84ec29 --- /dev/null +++ b/web/routes/demos/motion/pigeon.svelte @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +