Motion Primitives
component / motion / marketing
Six scroll-driven motion primitives — reveal, staggered group, marquee, scroll progress, sticky stack and count-up — with no animation library.
- type
- component
- files
- 2
- registry deps
- none
- npm deps
- none
installs
- components/automindz/motion-primitives.tsx
- styles/automindz-motion.css
- Import styles/automindz-motion.css once in your layout.
- No npm dependency, no client JS — CSS timelines only.
- Base state is the finished state: no support, no travel.
The stylesheet is not optional: add import "@/styles/automindz-motion.css" to your root layout once, or nothing moves. Skipping it is safe, never blank — every primitive renders its finished state, which is also the reduced-motion and no-support path. A reveal runs over its subject's entry phase and finishes as that subject lands fully in view, so no row stays half-faded; view() measures against the nearest scroll container, not the page. StickyStack needs opaque children.
Variations
one state per section
- 01Reveal on a card
- 02RevealGroup staggering a list
- 03Marquee of chips
- 04Reversed, pausing on hover
- 05ScrollProgress driven by a panel
- 06StickyStack of three panels
- 07CountUp row
Reveal on a card
Scroll the panel. The card lifts over its own entry phase and is finished the moment it is all the way inside the panel, which is a point every scroller can reach — so there is no scroll position, and no un-scrollable box, that leaves it faded. Scroll back up and it is still there: the resting style is the base state.
Scroll down. The card below starts just under the fold, where a section starts on a page nobody has scrolled yet.
Audit log retention
Thirteen months on every plan. Export is a signed URL that expires in fifteen minutes, so a log never sits in an inbox.
RevealGroup staggering a list
Watch the fifth row. Each row takes a later slice of one shared timeline, because a scroll timeline has no clock to delay against — but only the start moves. Every row ends inside the group's entry phase and the last one ends exactly as the group finishes entering, so by the time all five are on screen all five have arrived. The tail cannot be left dimmed.
Scroll down. Five rows, one timeline, staggered by start only.
Marquee of chips
Nothing to scroll. The content is rendered twice to hide the seam and the copy is aria-hidden and inert, so a screen reader hears six chips and Tab visits six. The track clips itself — the page never gains a scrollbar.
Reversed, pausing on hover
Hover it, or Tab into it. Same primitive with reverse and pauseOnHover; focus always pauses it whether asked or not. Under prefers-reduced-motion this row becomes a static, horizontally scrollable list, not a frozen half-pass.
ScrollProgress driven by a panel
Scroll inside the frame: the bar and the ring both track this panel, not the page, because the frame names its own scroll timeline. Both are aria-hidden — they duplicate the scrollbar — and both render nothing under reduced motion.
2.14.0
Session revocation is now instant across regions.
2.13.2
Invite links expire after seven days by default.
2.13.0
Audit log export moved to a signed download URL.
2.12.1
Org switcher keeps its scroll position on reopen.
2.12.0
Seat counts reconcile with Stripe hourly.
2.11.4
SCIM deprovisioning no longer waits for a sync.
2.11.0
Role templates can be scoped to one workspace.
2.10.3
Webhook retries back off to a six hour ceiling.
2.10.0
Data residency is selectable at workspace creation.
2.9.2
Billing portal links expire with the session.
StickyStack of three panels
Scroll inside the frame. Each panel parks a step below the one before and settles by scale, never opacity: watch the buried panels stay solid — the paragraph underneath must never read through them as ghost text.
Provision
Directory sync creates the account before anyone signs in, so the first login is not also the first write.
Authorise
Roles resolve per workspace, not per user, which is why a transfer never leaves a stale grant behind.
Audit
Every mutation lands in the log with the actor, the workspace and the request id that produced it.
This paragraph sits under the pile. If any of it is legible through a parked panel, the panel is not opaque — that is the bug this primitive refuses to reintroduce.
CountUp row
Scroll the panel to run all three counters together: the band names one view timeline and the numbers borrow it, which is the documented way to give a one-line number a longer run than its own height. They finish as the band lands, never later, so a counter can never sit on a half-counted number. The true value is real text underneath — what a screen reader reads, what reduced motion shows, what a headless render prints.
Scroll down. Three counters, one shared timeline.
- Workspaces provisioned
- 1240
- Median sign-in
- 380ms
- Directory sync uptime
- 99%
