-
Notifications
You must be signed in to change notification settings - Fork 1
Improve the Motion-family doc examples #638
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
titouanmathis
merged 4 commits into
feature/motion-autoplay-opt-in
from
feature/motion-examples-feedback
Aug 13, 2026
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
e3ef5b0
Improve the ambient MotionView stories
titouanmathis e5273a5
Add MotionScrollTimeline progress and parallax examples
titouanmathis 3c34b7a
Add a MotionSequence hero intro example
titouanmathis 7c0cebb
Make the mount animations observable in the doc previews
titouanmathis File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import { registerComponents } from '@studiometa/js-toolkit'; | ||
| import { Action } from '@studiometa/ui'; | ||
| import { Motion } from '@studiometa/ui-motion'; | ||
|
|
||
| registerComponents(Motion); | ||
| registerComponents(Action, Motion); |
32 changes: 24 additions & 8 deletions
32
packages/docs/reference/items/Motion/stories/basic/app.twig
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,25 @@ | ||
| <div | ||
| data-component="Motion" | ||
| data-option-initial='{ "opacity": 0, "y": 24, "scale": 0.9 }' | ||
| data-option-animate='{ "opacity": 1, "y": 0, "scale": 1 }' | ||
| data-option-transition='{ "type": "spring", "bounce": 0.3, "duration": 0.8 }' | ||
| data-option-autoplay | ||
| class="px-6 py-4 rounded-lg bg-blue-400 dark:bg-blue-600 text-white font-bold"> | ||
| Hello, I animate on mount! | ||
| {# The animation plays once, on mount. A preview boots before you look at it, | ||
| so the story pairs it with a replay button. The keyframes are written as | ||
| `[from, to]` arrays on purpose: a single target value would animate from | ||
| whatever the element currently shows, so a replay of a settled animation | ||
| would have nothing to move. #} | ||
| <div class="grid justify-items-start gap-4"> | ||
| <div | ||
| id="basic-box" | ||
| data-component="Motion" | ||
| data-option-initial='{ "opacity": 0, "y": 24, "scale": 0.9 }' | ||
| data-option-animate='{ "opacity": [0, 1], "y": [24, 0], "scale": [0.9, 1] }' | ||
| data-option-transition='{ "type": "spring", "bounce": 0.3, "duration": 0.8 }' | ||
| data-option-autoplay | ||
| class="rounded-lg bg-blue-400 px-6 py-4 font-bold text-white dark:bg-blue-600"> | ||
| Hello, I animate on mount! | ||
| </div> | ||
|
|
||
| <button | ||
| type="button" | ||
| data-component="Action" | ||
| data-on:click="Motion(#basic-box)->target.play()" | ||
| class="rounded bg-zinc-200 px-4 py-2 dark:bg-zinc-800"> | ||
| Replay | ||
| </button> | ||
| </div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
packages/docs/reference/items/MotionScrollTimeline/stories/parallax-layers/app.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| import { registerComponents } from '@studiometa/js-toolkit'; | ||
| import { MotionScrollTimeline } from '@studiometa/ui-motion'; | ||
|
|
||
| registerComponents(MotionScrollTimeline); |
36 changes: 36 additions & 0 deletions
36
packages/docs/reference/items/MotionScrollTimeline/stories/parallax-layers/app.twig
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| <p class="py-8 text-center text-current/60"> | ||
| Scroll down ↓ | ||
| </p> | ||
|
|
||
| {# One timeline, one scroll range, three Motion children: only the travelled | ||
| distance differs. The far layer moves the least and the near one the most, | ||
| so the speed difference alone reads as depth — no per-layer wiring, the | ||
| timeline scrubs them all with the same progress. #} | ||
| <section data-component="MotionScrollTimeline" class="relative h-[250vh]"> | ||
| <div | ||
| class="sticky top-0 grid h-screen grid-cols-1 grid-rows-1 place-items-center overflow-hidden"> | ||
| <div | ||
| data-component="Motion" | ||
| data-option-animate='{ "y": [80, -80] }' | ||
| class="col-start-1 row-start-1 size-72 rounded-full bg-blue-400/30 dark:bg-blue-600/30"></div> | ||
| <div | ||
| data-component="Motion" | ||
| data-option-animate='{ "y": [180, -180] }' | ||
| class="col-start-1 row-start-1 w-64 rounded-lg bg-white p-6 text-black shadow-2xl dark:bg-zinc-100"> | ||
| <h2 class="text-xl font-bold">Parallax layers</h2> | ||
| <p class="mt-2 text-black/60"> | ||
| Same range, three speeds. | ||
| </p> | ||
| </div> | ||
| <div | ||
| data-component="Motion" | ||
| data-option-animate='{ "y": [300, -300] }' | ||
| class="col-start-1 row-start-1 mt-56 ml-56 rounded-full bg-emerald-400 px-4 py-2 font-bold text-white dark:bg-emerald-600"> | ||
| Closest | ||
| </div> | ||
| </div> | ||
| </section> | ||
|
|
||
| <p class="py-8 text-center text-current/60"> | ||
| Done ↑ | ||
| </p> | ||
4 changes: 4 additions & 0 deletions
4
packages/docs/reference/items/MotionScrollTimeline/stories/reading-progress/app.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| import { registerComponents } from '@studiometa/js-toolkit'; | ||
| import { MotionScrollTimeline } from '@studiometa/ui-motion'; | ||
|
|
||
| registerComponents(MotionScrollTimeline); |
58 changes: 58 additions & 0 deletions
58
packages/docs/reference/items/MotionScrollTimeline/stories/reading-progress/app.twig
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| {# The article itself is the timeline, and the `offset` maps progress 0 to its | ||
| top reaching the top of the viewport and progress 1 to its bottom reaching | ||
| the bottom — the reading range. The single Motion child inside the sticky | ||
| bar is scrubbed by that progress, so its scaleX track reads as the share of | ||
| the article already scrolled. #} | ||
| <section | ||
| data-component="MotionScrollTimeline" | ||
| data-option-offset='["start start", "end end"]' | ||
| class="relative"> | ||
| <div class="sticky top-0 h-1.5 bg-zinc-200 dark:bg-zinc-800"> | ||
| <div | ||
| data-component="Motion" | ||
| data-option-animate='{ "scaleX": [0, 1] }' | ||
| class="h-full origin-left bg-blue-500 dark:bg-blue-400"></div> | ||
| </div> | ||
|
|
||
| <article class="mx-auto max-w-xl px-6 py-16 flex flex-col gap-6"> | ||
| <h2 class="text-3xl font-bold">Reading progress</h2> | ||
| <p> | ||
| Scroll this article: the bar above sticks to the top of the section and | ||
| fills from left to right as the content goes by. Nothing listens to the | ||
| scroll event — the timeline binds the bar to the scroll position once, on | ||
| mount. | ||
| </p> | ||
| <p> | ||
| The bar is a plain <code>Motion</code> child. It declares a single | ||
| <code>scaleX</code> track from 0 to 1, keeps its | ||
| <code>autoplay</code> off, and the timeline takes over its playback: the animation | ||
| never runs on its own clock, it is scrubbed. | ||
| </p> | ||
| <p> | ||
| Scaling is the cheap way to draw a progress bar: the browser animates a | ||
| transform instead of a width, and the | ||
| <code>origin-left</code> class anchors the growth to the left edge. | ||
| </p> | ||
| <p> | ||
| The default <code>offset</code> would start the bar as soon as the section enters | ||
| the viewport from the bottom, so the bar would already be part-filled on the | ||
| first paint. The | ||
| <code>["start start", "end end"]</code> range instead follows the section's | ||
| own scroll, which is what a reader expects from a progress indicator. | ||
| </p> | ||
| <p> | ||
| Any number of children can share the same timeline. A second | ||
| <code>Motion</code> could fade a "back to top" button in over the last part | ||
| of the range, without a single line of JavaScript. | ||
| </p> | ||
| <p> | ||
| Where the browser supports <code>ScrollTimeline</code>, the link is | ||
| hardware-accelerated and runs off the main thread; elsewhere Motion falls | ||
| back to a scroll listener with the same result. | ||
| </p> | ||
| <p> | ||
| The link is released when the timeline is destroyed, so a section that | ||
| leaves the page leaves nothing behind. | ||
| </p> | ||
| </article> | ||
| </section> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
packages/docs/reference/items/MotionSequence/stories/hero-intro/app.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import { registerComponents } from '@studiometa/js-toolkit'; | ||
| import { Action } from '@studiometa/ui'; | ||
| import { MotionSequence } from '@studiometa/ui-motion'; | ||
|
|
||
| registerComponents(Action, MotionSequence); |
58 changes: 58 additions & 0 deletions
58
packages/docs/reference/items/MotionSequence/stories/hero-intro/app.twig
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| {# One choreography, played on mount: `data-option-autoplay` belongs to the | ||
| sequence, never to the children — the sequence owns their playback. The | ||
| badge and the heading follow one another in DOM order, the paragraph joins | ||
| the heading with `data-option-at="<"`, and the button overlaps the end of | ||
| the paragraph with the relative offset `data-option-at="-0.2"`. The replay | ||
| button below drives the whole timeline with a single `play()`. #} | ||
| <div | ||
| id="hero-sequence" | ||
| data-component="MotionSequence" | ||
| data-option-autoplay | ||
| class="grid max-w-xl justify-items-start gap-4 rounded-lg p-8 ring"> | ||
| <span | ||
| data-component="Motion" | ||
| data-option-initial='{ "opacity": 0, "scale": 0.8 }' | ||
| data-option-animate='{ "opacity": [0, 1], "scale": [0.8, 1] }' | ||
| data-option-transition='{ "type": "spring", "bounce": 0.5 }' | ||
| class="rounded-full bg-emerald-400/20 px-3 py-1 text-sm font-bold text-emerald-700 ring ring-emerald-400 dark:text-emerald-300"> | ||
| New | ||
| </span> | ||
|
|
||
| <h2 | ||
| data-component="Motion" | ||
| data-option-initial='{ "opacity": 0, "y": 24 }' | ||
| data-option-animate='{ "opacity": [0, 1], "y": [24, 0] }' | ||
| data-option-transition='{ "type": "spring", "bounce": 0.2 }' | ||
| class="text-3xl font-bold"> | ||
| Animate the whole hero as one timeline | ||
| </h2> | ||
|
|
||
| <p | ||
| data-component="Motion" | ||
| data-option-initial='{ "opacity": 0, "y": 16 }' | ||
| data-option-animate='{ "opacity": [0, 1], "y": [16, 0] }' | ||
| data-option-at="<" | ||
| class="text-current/70"> | ||
| This paragraph starts with the heading, not after it: <code>"<"</code> | ||
| positions a segment at the start of the previous one. | ||
| </p> | ||
|
|
||
| <button | ||
| type="button" | ||
| data-component="Motion" | ||
| data-option-initial='{ "opacity": 0, "y": 12, "scale": 0.9 }' | ||
| data-option-animate='{ "opacity": [0, 1], "y": [12, 0], "scale": [0.9, 1] }' | ||
| data-option-transition='{ "type": "spring", "bounce": 0.4 }' | ||
| data-option-at="-0.2" | ||
| class="rounded bg-blue-600 px-4 py-2 font-semibold text-white"> | ||
| Get started | ||
| </button> | ||
| </div> | ||
|
|
||
| <button | ||
| type="button" | ||
| data-component="Action" | ||
| data-on:click="MotionSequence(#hero-sequence)->target.play()" | ||
| class="mt-4 rounded bg-zinc-200 px-4 py-2 dark:bg-zinc-800"> | ||
| Replay the sequence | ||
| </button> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 15 additions & 14 deletions
29
packages/docs/reference/items/MotionView/stories/ambient-bind-if/app.twig
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: Match parallax distances to the documented travel values
The keyframes move the disc from
y: 80toy: -80, resulting in 160 pixels of travel rather than the documented 80 pixels; the other layers likewise travel 360 and 600 pixels instead of 180 and 300. Use[0, 80],[0, 180], and[0, 300](or update the documentation to describe the actual displacement).Confidence: high.
Reviewed by @weareikko/code-review v0.9.5 for commit 3c34b7a.