
Animation Master
- 2 installs
- 1 repo stars
- Updated June 1, 2026
- kaneyoung1994/motion-skill
Reusable CSS motion library that copies and wires bundled .t-* animation effects into a project for UI transitions, text motion, hovers, and page transitions.
About
A CSS animation library that installs bundled .t-* effect files into a target project and wires them to elements via classes and state hooks. A developer uses it to add element motion, UI transitions, text effects, or one-click CSS animation snippets.
- Effects live in assets/css as reusable .t-* classes; copy only what's needed
- Preserves prefers-reduced-motion blocks and uses state hooks like is-open
Animation Master by the numbers
- 2 all-time installs (skills.sh)
- Ranked #1,863 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Jul 8, 2026 (Skillselion catalog sync)
npx skills add https://github.com/kaneyoung1994/motion-skill --skill animation-masterAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 1 |
| Last updated | June 1, 2026 |
| Repository | kaneyoung1994/motion-skill ↗ |
What it does
Reusable CSS motion library that copies and wires bundled .t-* animation effects into a project for UI transitions, text motion, hovers, and page transitions.
Files
Animation Master
Use this skill to apply the bundled Animation Master CSS effects to a website or app. The CSS files are stored in assets/css/ and use reusable .t-* class names.
Treat this skill as the source library for Animation Master motion. Browser extensions, preview sites, or copied prompts are consumers of the skill; they should not narrow the skill's available effect set or routing model.
Workflow
1. Choose the effect category and file.
- Read
references/catalog.mdwhen selecting an effect or mapping a request to a CSS file. - Prefer copying only the CSS file(s) needed for the requested effect.
2. Copy CSS into the target project.
- Use
scripts/install_motion_css.py --target <directory> <effect-name>for selected effects. - Use
scripts/install_motion_css.py --target <directory> --allonly when the user wants the full library.
3. Wire the effect in markup.
- Add the corresponding
.t-*class to the element. - Preserve the class names and keyframe names unless the user asks for a naming change.
- Keep existing
prefers-reduced-motionblocks.
4. Add state hooks when required.
- UI transition files commonly use state classes or attributes such as
.is-open,.is-closing,.is-previewing,.is-animating,data-state, ordata-page. - Text effects use
.t-text-animation, the specific text class, and.is-previewing. - For existing page text, prefer the text integration contract below instead of mutating the original text node directly.
5. Verify visually after integration.
- For local web work, run or reuse the local dev server and inspect the page in the browser.
- Check that the animation starts, stops, or replays according to the requested interaction.
Resources
assets/css/: packaged CSS effects copied from the Animation Master site.references/catalog.md: effect categories, filenames, primary classes, and typical usage.scripts/install_motion_css.py: utility to list or copy CSS files into another project.
Integration Notes
- Preserve each CSS file's native playback semantics unless the user asks for a different behavior. Some element effects are continuous, text reveals are usually one-shot, and UI effects are state-driven.
- Element effects are usually transforms on a single element.
- UI effects often need wrapper markup and a state toggle.
- Text effects are split into individual files; do not re-aggregate them unless the user asks.
transitions-root.csscontains shared UI motion tokens and can be copied when a page uses several UI transition effects.
Text And Digit Integration Contract
Use this contract when applying text, typewriter, digitGroup, or digitRoll effects to existing page content. The goal is to preserve the original DOM flow, typography, and layout.
- Do not replace the target element's font family, font size, weight, line height, color, letter spacing, alignment, white-space, or word-break.
- Do not flatten the target element's full
textContentinto one overlay. Preserve the existing DOM and only wrap eligible visible text nodes. - Skip text inside
script,style,noscript,template,svg,canvas, media, embeds, form controls, and editable controls. - For normal text effects, replace each eligible text node with an inline wrapper such as
.web-animator-text-node.am-target-text.t-text-animation.<effect>.is-previewing, then split inside that wrapper according totextMode. - For
textMode: char, group Latin text by word so letters inside one word do not wrap separately; keep CJK text naturally wrappable. Set sequential--ion animated characters. FortextMode: word, use words for Latin text and character-like runs for CJK. - For
digitGroup, only replace numeric runs with inline.web-animator-digit-nodewrappers. Create one.t-digitper numeric character and set sequential--i; do not animate the whole number as one unit. - For
digitRoll, only replace numeric runs with inline.web-animator-digit-nodewrappers. Keep each original digit's footprint with an invisible anchor, place the viewport/reel over that anchor, and avoid fixed widths that change real page text flow or baseline. - Text and digit effects are normally one-shot: play once and leave the final visible state. Do not restart by repeatedly rebuilding wrappers unless explicitly requested.
- Apply requested
customProperties, duration variables, or intensity variables to the animation carrier. Ignoring them changes the selected motion. - If the target element already has a transform, preserve that base transform and compose the motion transform on top of it instead of replacing positioning transforms.
interface:
display_name: "Animation Master"
short_description: "Reusable CSS motion effects"
default_prompt: "Use $animation-master to add reusable motion CSS to my page."
/* Animation master - Avatar hover */
/*
Usage:
<div class="t-avatar-hover">
<span class="t-avatar-hover-item">A</span>
<span class="t-avatar-hover-item">B</span>
</div>
Set `--avatar-hover-shift` and `--avatar-hover-active-scale`
on each item to create the grouped hover lift.
*/
:root {
--avatar-hover-lift: -4px;
--avatar-hover-dur: 320ms;
--avatar-hover-ease-in: cubic-bezier(0.22, 1, 0.36, 1);
--avatar-hover-ease-out: cubic-bezier(0.34, 3.85, 0.64, 1);
--avatar-hover-scale: 1.05;
--avatar-hover-falloff: 0.45;
}
.t-avatar-hover {
display: flex;
align-items: center;
}
.t-avatar-hover-item {
width: 32px;
height: 32px;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-right: -8px;
border: 1.5px solid #f9f9f9;
border-radius: 50%;
background: var(--avatar-color, #d9d9d9);
color: rgba(0, 0, 0, 0.68);
cursor: pointer;
font-size: 12px;
font-weight: 650;
overflow: hidden;
position: relative;
transform:
translateY(var(--avatar-hover-shift, 0px))
scale(var(--avatar-hover-active-scale, 1));
transform-origin: center;
transition: transform var(--avatar-hover-dur) var(--avatar-hover-ease-in);
will-change: transform;
}
.t-avatar-hover-item:last-child {
margin-right: 0;
}
.t-avatar-hover-more {
background: color-mix(in srgb, #f9f9f9 80%, #000 20%);
color: #0d0d0d;
cursor: default;
}
@media (prefers-reduced-motion: reduce) {
.t-avatar-hover-item {
transition: none !important;
}
}
/* Animation master - Badge */
/*
Usage:
<span class="t-badge" data-open="true">
<span class="t-badge-dot"></span>
</span>
State: set data-open="true" or "false" on `.t-badge`.
The badge slides in first, then the dot scales and fades.
*/
:root {
--badge-slide-dur: 260ms;
--badge-pop-dur: 500ms;
--badge-pop-close-dur: 180ms;
--badge-fade-dur: 400ms;
--badge-fade-close-dur: 180ms;
--badge-blur: 2px;
--badge-offset-x: -8.2px;
--badge-offset-y: 12.4px;
--badge-slide-ease: cubic-bezier(0.22, 1, 0.36, 1);
--badge-pop-ease: cubic-bezier(0.34, 1.36, 0.64, 1);
--badge-close-ease: cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes t-badge-slide-in {
from {
transform: translate(var(--badge-offset-x), var(--badge-offset-y));
}
to {
transform: translate(0, 0);
}
}
.t-badge {
position: absolute;
top: -6px;
right: -8px;
pointer-events: none;
will-change: transform;
}
.t-badge[data-open="true"] {
animation: t-badge-slide-in var(--badge-slide-dur) var(--badge-slide-ease);
}
.t-badge-dot {
display: block;
transform-origin: center;
transform: scale(1);
opacity: 1;
filter: blur(0);
transition:
transform var(--badge-pop-dur) var(--badge-pop-ease),
opacity var(--badge-fade-dur) var(--badge-pop-ease),
filter var(--badge-pop-dur) var(--badge-pop-ease);
will-change: transform, opacity, filter;
}
.t-badge[data-open="false"] .t-badge-dot {
transform: scale(0);
opacity: 0;
filter: blur(var(--badge-blur));
transition:
transform var(--badge-pop-close-dur) var(--badge-close-ease),
opacity var(--badge-fade-close-dur) var(--badge-close-ease),
filter var(--badge-pop-close-dur) var(--badge-close-ease);
}
@media (prefers-reduced-motion: reduce) {
.t-badge,
.t-badge-dot {
animation: none !important;
transition: none !important;
}
}
/* Animation master - Blink swing */
/*
Usage:
<div class="t-blink-swing">...</div>
Put `.t-blink-swing` on any icon, badge, card, or control
that should pop in, swing left and right, then blink out.
*/
:root {
--blink-swing-dur: 1000ms;
--blink-swing-scale-min: 0.001;
--blink-swing-rotate-a: 20deg;
--blink-swing-rotate-b: -20deg;
}
.t-blink-swing {
animation: t-blink-swing var(--blink-swing-dur) infinite both;
transform-origin: center;
will-change: transform;
}
@keyframes t-blink-swing {
0% {
transform: rotate(var(--blink-swing-rotate-a)) scale(var(--blink-swing-scale-min));
animation-timing-function: ease-in-out;
}
15% {
transform: rotate(var(--blink-swing-rotate-a)) scale(1);
animation-timing-function: ease-in-out;
}
30% {
transform: rotate(var(--blink-swing-rotate-b)) scale(1);
animation-timing-function: ease-in-out;
}
45% {
transform: rotate(var(--blink-swing-rotate-a)) scale(1);
animation-timing-function: ease-in-out;
}
58.33% {
transform: rotate(var(--blink-swing-rotate-b)) scale(1);
animation-timing-function: ease-in-out;
}
75% {
transform: rotate(var(--blink-swing-rotate-a)) scale(1);
animation-timing-function: linear;
}
88.33%,
100% {
transform: rotate(var(--blink-swing-rotate-a)) scale(var(--blink-swing-scale-min));
}
}
@media (prefers-reduced-motion: reduce) {
.t-blink-swing {
animation: none !important;
}
}
/* Animation master - Blink */
/*
Usage:
<div class="t-blink">...</div>
Put `.t-blink` on any icon, badge, card, or control
that should repeatedly pop in and blink out.
*/
:root {
--blink-dur: 1000ms;
--blink-scale-min: 0.001;
--blink-scale-max: 1;
--blink-ease-in: cubic-bezier(0.218, 0.809, 0.58, 1);
}
.t-blink {
animation: t-blink var(--blink-dur) infinite both;
transform-origin: center;
will-change: transform;
}
@keyframes t-blink {
0% {
transform: scale(var(--blink-scale-min));
animation-timing-function: var(--blink-ease-in);
}
25% {
transform: scale(var(--blink-scale-max));
animation-timing-function: ease-in-out;
}
50% {
transform: scale(var(--blink-scale-min));
animation-timing-function: ease-out;
}
75% {
transform: scale(var(--blink-scale-max));
animation-timing-function: ease-in-out;
}
100% {
transform: scale(var(--blink-scale-min));
}
}
@media (prefers-reduced-motion: reduce) {
.t-blink {
animation: none !important;
}
}
/* Animation master - blur-out-up */
/*
Usage:
<div class="t-text-animation t-blur-out-up is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-blur-out-up` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-blur-out-up.is-previewing .t-word {
animation: t-blur-out-up 850ms var(--text-motion-ease-out) both;
animation-delay: calc(var(--i) * 65ms);
}
@keyframes t-blur-out-up {
0% {
opacity: 0;
transform: translateY(14px);
filter: blur(8px);
}
55% {
opacity: 1;
transform: translateY(0);
filter: blur(0);
}
100% {
opacity: 0;
transform: translateY(-12px);
filter: blur(0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-blur-out-up,
.t-blur-out-up * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - bottom-up-letters */
/*
Usage:
<div class="t-text-animation t-bottom-up-letters is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-bottom-up-letters` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-bottom-up-letters.is-previewing .t-char {
animation: t-bottom-up-letters 660ms var(--text-motion-ease-out) both;
animation-delay: calc(var(--i) * 32ms);
}
@keyframes t-bottom-up-letters {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-bottom-up-letters,
.t-bottom-up-letters * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - Button animation */
/*
Usage:
<button class="t-button-animation">...</button>
Put `.t-button-animation` on any button or control to create
a subtle repeated click/press animation.
*/
:root {
--button-animation-dur: 1150ms;
--button-animation-ease: cubic-bezier(0.25, 0, 0.62, 1);
}
.t-button-animation {
animation: t-button-animation var(--button-animation-dur) var(--button-animation-ease) infinite;
transform-origin: center;
will-change: transform;
}
@keyframes t-button-animation {
0% {
transform: scale(1, 1);
}
13.04% {
transform: scale(0.878, 0.877);
}
30.44% {
transform: scale(1, 1);
}
43.48% {
transform: scale(0.904, 0.904);
}
60.87% {
transform: scale(1, 1);
}
72.46% {
transform: scale(0.941, 0.937);
}
100% {
transform: scale(1, 1);
}
}
@media (prefers-reduced-motion: reduce) {
.t-button-animation {
animation: none !important;
}
}
/* Animation master - Click */
/*
Usage:
<button class="t-click">...</button>
Put `.t-click` on any button, icon, card, or control
that should show a repeated pointer click motion.
*/
:root {
--click-dur: 1000ms;
--click-ease: ease-in-out;
--click-scale: 0.88;
--click-rotate: -25deg;
--click-x: 4.75px;
--click-y: 10.1px;
}
.t-click {
animation: t-click var(--click-dur) var(--click-ease) infinite;
transform-origin: center;
will-change: transform;
}
@keyframes t-click {
0% {
transform: translate(0, 0) rotate(0deg) scale(1);
}
25% {
transform:
translate(var(--click-x), var(--click-y))
rotate(var(--click-rotate))
scale(var(--click-scale));
}
50% {
transform: translate(0, 0) rotate(0deg) scale(1);
}
75% {
transform:
translate(var(--click-x), var(--click-y))
rotate(var(--click-rotate))
scale(var(--click-scale));
animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
}
100% {
transform: translate(0, 0) rotate(0deg) scale(1);
}
}
@media (prefers-reduced-motion: reduce) {
.t-click {
animation: none !important;
}
}
/* Animation master - Digit roll */
/*
Usage:
<span class="t-digit-roll is-animating">
<span class="t-digit-roll-slot t-digit-roll-item">
<span class="t-digit-roll-anchor">3</span>
<span class="t-digit-roll-viewport">
<span class="t-digit-roll-reel">
<span class="t-digit-roll-cell">0</span>
<span class="t-digit-roll-cell">1</span>
<span class="t-digit-roll-cell">2</span>
<span class="t-digit-roll-cell">3</span>
</span>
</span>
</span>
<span class="t-digit-roll-item">.</span>
<span class="t-digit-roll-viewport t-digit-roll-item">
<span class="t-digit-roll-reel">
<span class="t-digit-roll-cell">0</span>
<span class="t-digit-roll-cell">1</span>
</span>
</span>
</span>
Set `--digit-roll-scroll-distance`, `--digit-roll-duration`,
and `--digit-roll-stagger` on each reel/item to control timing.
*/
:root {
--digit-roll-dur: 500ms;
--digit-roll-distance: 8px;
--digit-roll-stagger: 70ms;
--digit-roll-blur: 2px;
--digit-roll-ease: cubic-bezier(0.34, 1.45, 0.64, 1);
--digit-roll-dir-x: 0;
--digit-roll-dir-y: 1;
--digit-roll-settle-overshoot: 1.8px;
}
.t-digit-roll {
display: inline;
align-items: baseline;
font-variant-numeric: inherit;
}
.t-digit-roll-item {
display: inline-block;
will-change: transform, opacity, filter;
}
.t-digit-roll.is-animating .t-digit-roll-item {
animation: t-digit-roll-pop-in var(--digit-roll-dur) var(--digit-roll-ease) both;
animation-delay: calc(var(--digit-roll-stagger) * var(--digit-roll-stagger-index, 0));
}
.t-digit-roll-viewport {
width: 0.62em;
height: 1.08em;
overflow: hidden;
}
.t-digit-roll-slot {
position: relative;
display: inline-block;
vertical-align: baseline;
line-height: inherit;
}
.t-digit-roll-anchor {
visibility: hidden;
}
.t-digit-roll-slot .t-digit-roll-viewport {
position: absolute;
inset: 0 auto auto 0;
width: 100%;
height: 1lh;
}
.t-digit-roll-reel {
display: flex;
flex-direction: column;
transform: translateY(calc(-1 * var(--digit-roll-scroll-distance, 0em)));
will-change: transform;
}
.t-digit-roll.is-animating .t-digit-roll-reel {
animation: t-digit-roll-scroll var(--digit-roll-duration, var(--digit-roll-dur)) cubic-bezier(0.2, 0.82, 0.16, 1) forwards;
}
.t-digit-roll-cell {
display: block;
width: 0.62em;
height: 1.08em;
line-height: 1.08em;
text-align: center;
}
.t-digit-roll-slot .t-digit-roll-cell {
width: 100%;
height: 1lh;
line-height: inherit;
}
@keyframes t-digit-roll-pop-in {
0% {
transform: translate(
calc(var(--digit-roll-distance) * var(--digit-roll-dir-x)),
calc(var(--digit-roll-distance) * var(--digit-roll-dir-y))
);
opacity: 0;
filter: blur(var(--digit-roll-blur));
}
100% {
transform: translate(0, 0);
opacity: 1;
filter: blur(0);
}
}
@keyframes t-digit-roll-scroll {
0% {
transform: translateY(0);
}
62% {
transform: translateY(calc(-1 * var(--digit-roll-scroll-distance, 0em) - var(--digit-roll-settle-overshoot)));
}
78% {
transform: translateY(calc(-1 * var(--digit-roll-scroll-distance, 0em) + var(--digit-roll-settle-overshoot) * 0.34));
}
90% {
transform: translateY(calc(-1 * var(--digit-roll-scroll-distance, 0em) - var(--digit-roll-settle-overshoot) * 0.12));
}
100% {
transform: translateY(calc(-1 * var(--digit-roll-scroll-distance, 0em)));
}
}
@media (prefers-reduced-motion: reduce) {
.t-digit-roll,
.t-digit-roll * {
animation: none !important;
filter: none !important;
}
}
/* Animation master - Digit */
/*
Usage:
<span class="t-digit-group">
<span class="t-digit">1</span>
<span class="t-digit">2</span>
</span>
Put `.t-digit-group` around number characters and add
`.is-animating` when each character should pop into place.
*/
:root {
--digit-dur: 500ms;
--digit-distance: 8px;
--digit-stagger: 70ms;
--digit-blur: 2px;
--digit-ease: cubic-bezier(0.34, 1.45, 0.64, 1);
--digit-dir-x: 0;
--digit-dir-y: 1;
}
@keyframes t-digit-pop-in {
0% {
transform: translate(
calc(var(--digit-distance) * var(--digit-dir-x)),
calc(var(--digit-distance) * var(--digit-dir-y))
);
opacity: 0;
filter: blur(var(--digit-blur));
}
100% {
transform: translate(0, 0);
opacity: 1;
filter: blur(0);
}
}
.t-digit-group {
display: inline;
align-items: baseline;
}
.t-digit {
display: inline-block;
will-change: transform, opacity, filter;
}
.t-digit-group.is-animating .t-digit {
animation: t-digit-pop-in var(--digit-dur) var(--digit-ease) both;
animation-delay: calc(var(--digit-stagger) * var(--i, 0));
}
.t-digit-group.is-animating .t-digit[data-stagger="1"] {
animation-delay: var(--digit-stagger);
}
.t-digit-group.is-animating .t-digit[data-stagger="2"] {
animation-delay: calc(var(--digit-stagger) * 2);
}
@media (prefers-reduced-motion: reduce) {
.t-digit-group .t-digit {
animation: none !important;
}
}
/* Animation master - Drift down */
/*
Usage:
<div class="t-drift-down">...</div>
Put `.t-drift-down` on any icon, badge, card, or control
that should appear, rotate, and drift downward.
*/
:root {
--drift-down-dur: 1000ms;
--drift-down-y: 128px;
--drift-down-rotate: 129deg;
--drift-down-scale-min: 0.001;
}
.t-drift-down {
animation: t-drift-down var(--drift-down-dur) infinite both;
transform-origin: center;
will-change: transform;
}
@keyframes t-drift-down {
0% {
transform: translateY(0) rotate(0deg) scale(var(--drift-down-scale-min));
animation-timing-function: ease-in-out;
}
13.33% {
transform: translateY(0) rotate(17deg) scale(1);
animation-timing-function: ease-in-out;
}
76.67% {
transform: translateY(calc(var(--drift-down-y) * 0.75)) rotate(99deg) scale(1);
animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
}
100% {
transform: translateY(var(--drift-down-y)) rotate(var(--drift-down-rotate)) scale(var(--drift-down-scale-min));
}
}
@media (prefers-reduced-motion: reduce) {
.t-drift-down {
animation: none !important;
}
}
/* Animation master - Dropdown */
/*
Usage:
<div class="t-dropdown" data-origin="top-center">...</div>
State: add `.is-open` to show the menu, then `.is-closing`
while dismissing it. Use data-origin to control transform origin.
*/
:root {
--dropdown-open-dur: 250ms;
--dropdown-close-dur: 150ms;
--dropdown-pre-scale: 0.97;
--dropdown-closing-scale: 0.99;
--dropdown-ease: cubic-bezier(0.22, 1, 0.36, 1);
}
.t-dropdown {
transform-origin: top left;
transform: scale(var(--dropdown-pre-scale));
opacity: 0;
pointer-events: none;
transition:
transform var(--dropdown-open-dur) var(--dropdown-ease),
opacity var(--dropdown-open-dur) var(--dropdown-ease);
will-change: transform, opacity;
}
.t-dropdown[data-origin="top-right"] {
transform-origin: top right;
}
.t-dropdown[data-origin="top-center"] {
transform-origin: top center;
}
.t-dropdown[data-origin="bottom-left"] {
transform-origin: bottom left;
}
.t-dropdown[data-origin="bottom-center"] {
transform-origin: bottom center;
}
.t-dropdown[data-origin="bottom-right"] {
transform-origin: bottom right;
}
.t-dropdown.is-open {
transform: scale(1);
opacity: 1;
pointer-events: auto;
}
.t-dropdown.is-closing {
transform: scale(var(--dropdown-closing-scale));
opacity: 0;
pointer-events: none;
transition:
transform var(--dropdown-close-dur) var(--dropdown-ease),
opacity var(--dropdown-close-dur) var(--dropdown-ease);
}
@media (prefers-reduced-motion: reduce) {
.t-dropdown {
transition: none !important;
}
}
/* Animation master - Error shake */
/*
Usage:
<div class="t-error-shake-wrap">
<div class="t-error-shake">
<input class="t-error-shake-input">
</div>
<p class="t-error-shake-message">Please enter a valid email.</p>
</div>
State: add `.is-error` to wrapper and input shell.
Add `.is-shaking` to `.t-error-shake` to replay the shake.
*/
:root {
--error-shake-distance: 6px;
--error-shake-overshoot: 4px;
--error-shake-dur-a: 80ms;
--error-shake-dur-b: 60ms;
--error-shake-ease: cubic-bezier(0.22, 1, 0.36, 1);
--error-shake-border: #e23014;
--error-shake-text: #d62b11;
--error-shake-revert-hold: 3000ms;
--error-shake-revert-dur: 280ms;
}
.t-error-shake-wrap {
width: 220px;
display: flex;
flex-direction: column;
gap: 4px;
}
.t-error-shake {
height: 36px;
display: flex;
align-items: center;
padding: 4px 4px 4px 12px;
border: 1px solid #dcdcdc;
border-radius: 8px;
background: #ffffff;
outline: none;
transition: border-color 150ms ease-out;
will-change: transform;
}
.t-error-shake:focus-within {
border-color: #585858;
}
.t-error-shake.is-error {
border-color: var(--error-shake-border);
transition: border-color var(--error-shake-revert-dur) ease-out;
}
.t-error-shake-input {
min-width: 0;
width: 100%;
height: 100%;
padding: 0;
border: 0;
outline: none;
background: transparent;
color: #0d0d0d;
font: inherit;
font-size: 13px;
line-height: 1.4;
}
.t-error-shake-input::placeholder {
color: #6c6c6c;
}
.t-error-shake-message {
margin: 0;
color: var(--error-shake-text);
font-size: 13px;
line-height: 1.4;
opacity: 0;
visibility: hidden;
transition:
opacity var(--error-shake-revert-dur) ease-out,
visibility 0s linear var(--error-shake-revert-dur);
}
.t-error-shake-wrap.is-error .t-error-shake-message {
opacity: 1;
visibility: visible;
transition:
opacity var(--error-shake-revert-dur) ease-out,
visibility 0s linear 0s;
}
.t-error-shake.is-shaking {
animation: t-error-shake calc(var(--error-shake-dur-a) * 2 + var(--error-shake-dur-b) * 2) linear;
}
@keyframes t-error-shake {
0% {
transform: translateX(0);
animation-timing-function: var(--error-shake-ease);
}
28.57% {
transform: translateX(var(--error-shake-distance));
animation-timing-function: var(--error-shake-ease);
}
57.14% {
transform: translateX(calc(var(--error-shake-distance) * -1));
animation-timing-function: var(--error-shake-ease);
}
78.57% {
transform: translateX(var(--error-shake-overshoot));
animation-timing-function: var(--error-shake-ease);
}
100% {
transform: translateX(0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-error-shake {
animation: none !important;
transition: none !important;
}
}
/* Animation master - fade-through */
/*
Usage:
<div class="t-text-animation t-fade-through is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-fade-through` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-fade-through.is-previewing .t-text-whole {
animation: t-fade-through 720ms var(--text-motion-ease-out) both;
}
@keyframes t-fade-through {
0% {
opacity: 0;
}
34% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.t-fade-through,
.t-fade-through * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - Float rise */
/*
Usage:
<div class="t-float-rise">...</div>
Put `.t-float-rise` on any icon, badge, card, or control
that should drift upward and softly rotate back.
*/
:root {
--float-rise-dur: 1000ms;
--float-rise-y: 57px;
--float-rise-rotate: 27deg;
}
.t-float-rise {
animation: t-float-rise var(--float-rise-dur) infinite both;
transform-origin: center;
will-change: transform;
}
@keyframes t-float-rise {
0% {
transform: translateY(0) rotate(0deg);
animation-timing-function: ease-in-out;
}
50% {
transform: translateY(calc(var(--float-rise-y) * -1)) rotate(var(--float-rise-rotate));
animation-timing-function: ease-in-out;
}
100% {
transform: translateY(0) rotate(0deg);
}
}
@media (prefers-reduced-motion: reduce) {
.t-float-rise {
animation: none !important;
}
}
/* Animation master - Float */
/*
Usage:
<div class="t-float">...</div>
Put `.t-float` on any element that should gently float.
*/
:root {
--float-dur: 1000ms;
--float-y: 20px;
--float-rot-a: -1.5deg;
--float-rot-b: 8deg;
--float-rot-c: -8deg;
}
.t-float {
transform-origin: center center;
animation:
t-float-y var(--float-dur) infinite,
t-float-rotate var(--float-dur) infinite;
will-change: translate, rotate;
}
@keyframes t-float-y {
0% {
translate: 0 0;
animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
}
50% {
translate: 0 calc(var(--float-y) * -1);
animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
}
100% {
translate: 0 0;
}
}
@keyframes t-float-rotate {
0% {
rotate: var(--float-rot-a);
animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
}
25% {
rotate: var(--float-rot-b);
animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
}
75% {
rotate: var(--float-rot-c);
animation-timing-function: cubic-bezier(0.42, 0, 1, 1);
}
100% {
rotate: var(--float-rot-a);
}
}
@media (prefers-reduced-motion: reduce) {
.t-float {
animation: none !important;
}
}
/* Animation master - focus-blur-resolve */
/*
Usage:
<div class="t-text-animation t-focus-blur-resolve is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-focus-blur-resolve` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-focus-blur-resolve.is-previewing .t-text-whole {
animation: t-focus-blur-resolve 900ms var(--text-motion-ease-out) both;
}
@keyframes t-focus-blur-resolve {
from {
opacity: 0;
filter: blur(18px);
transform: scale(1.02);
}
to {
opacity: 1;
filter: blur(0);
transform: scale(1);
}
}
@media (prefers-reduced-motion: reduce) {
.t-focus-blur-resolve,
.t-focus-blur-resolve * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - Heartbeat */
/*
Usage:
<div class="t-heartbeat">...</div>
Put `.t-heartbeat` on any icon, badge, card, or control
that should pulse with a repeated heartbeat rhythm.
*/
:root {
--heartbeat-dur: 1000ms;
--heartbeat-scale-a: 0.7;
--heartbeat-scale-b: 0.77;
--heartbeat-scale-c: 0.895;
}
.t-heartbeat {
animation: t-heartbeat var(--heartbeat-dur) infinite both;
transform-origin: center;
will-change: transform;
}
@keyframes t-heartbeat {
0% {
transform: scale(1);
animation-timing-function: ease-in-out;
}
16.67% {
transform: scale(var(--heartbeat-scale-a));
animation-timing-function: ease-in-out;
}
35% {
transform: scale(1);
animation-timing-function: ease-in-out;
}
51.67% {
transform: scale(var(--heartbeat-scale-b));
animation-timing-function: ease-in-out;
}
70% {
transform: scale(1);
animation-timing-function: cubic-bezier(0.478, 0.279, 0.458, 1.186);
}
85% {
transform: scale(var(--heartbeat-scale-c));
animation-timing-function: cubic-bezier(0.586, 0.07, 0.415, 0.973);
}
100% {
transform: scale(1);
}
}
@media (prefers-reduced-motion: reduce) {
.t-heartbeat {
animation: none !important;
}
}
/* Animation master - Icon swap */
/*
Usage:
<span class="t-icon-swap" data-state="a">
<span class="t-icon" data-icon="a">...</span>
<span class="t-icon" data-icon="b">...</span>
</span>
State: set data-state="a" or "b" on `.t-icon-swap`.
*/
:root {
--icon-swap-dur: 200ms;
--icon-swap-blur: 2px;
--icon-swap-start-scale: 0.25;
--icon-swap-ease: ease-in-out;
}
.t-icon-swap {
position: relative;
display: inline-grid;
}
.t-icon-swap .t-icon {
grid-area: 1 / 1;
transition:
opacity var(--icon-swap-dur) var(--icon-swap-ease),
filter var(--icon-swap-dur) var(--icon-swap-ease),
transform var(--icon-swap-dur) var(--icon-swap-ease);
will-change: opacity, filter, transform;
}
.t-icon-swap[data-state="a"] .t-icon[data-icon="a"],
.t-icon-swap[data-state="b"] .t-icon[data-icon="b"] {
opacity: 1;
filter: blur(0);
transform: scale(1);
}
.t-icon-swap[data-state="a"] .t-icon[data-icon="b"],
.t-icon-swap[data-state="b"] .t-icon[data-icon="a"] {
opacity: 0;
filter: blur(var(--icon-swap-blur));
transform: scale(var(--icon-swap-start-scale));
}
@media (prefers-reduced-motion: reduce) {
.t-icon-swap .t-icon {
transition: none !important;
}
}
/* Animation master - Jump */
/*
Usage:
<div class="t-jump">...</div>
Put `.t-jump` on any icon, badge, card, or control
that should bounce upward with a squash-and-stretch motion.
*/
:root {
--jump-dur: 1000ms;
--jump-y: 59px;
--jump-squash-x: 1.15;
--jump-squash-y: 0.85;
--jump-stretch-x: 0.85;
--jump-stretch-y: 1.15;
}
.t-jump {
animation: t-jump var(--jump-dur) infinite;
transform-origin: center bottom;
will-change: transform;
}
@keyframes t-jump {
0%,
3.33% {
transform: translateY(0) scale(1, 1);
animation-timing-function: ease-in-out;
}
23.33% {
transform: translateY(0) scale(var(--jump-squash-x), var(--jump-squash-y));
animation-timing-function: cubic-bezier(0.245, 0.53, 0.58, 1);
}
43.33% {
transform:
translateY(calc(var(--jump-y) * -1))
scale(var(--jump-stretch-x), var(--jump-stretch-y));
animation-timing-function: cubic-bezier(0.727, -0.016, 0.58, 1);
}
63.33% {
transform: translateY(0) scale(var(--jump-squash-x), var(--jump-squash-y));
animation-timing-function: ease-in-out;
}
75% {
transform: translateY(0) scale(0.895, 1.067);
animation-timing-function: cubic-bezier(0.393, 0, 0.55, 1);
}
85% {
transform: translateY(0) scale(1.024, 0.945);
animation-timing-function: cubic-bezier(0.494, 0.293, 0.58, 1);
}
95%,
100% {
transform: translateY(0) scale(1, 1);
}
}
@media (prefers-reduced-motion: reduce) {
.t-jump {
animation: none !important;
}
}
/* Animation master - kinetic-center-build */
/*
Usage:
<div class="t-text-animation t-kinetic-center-build is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-kinetic-center-build` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-kinetic-center-build.is-previewing .t-word {
animation: t-kinetic-center-build 780ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
animation-delay: calc(var(--i) * 220ms);
}
@keyframes t-kinetic-center-build {
from {
opacity: 0;
transform: translateX(88px) translateY(6px) scale(0.992);
filter: blur(3.5px);
}
to {
opacity: 1;
transform: translateX(0) translateY(0) scale(1);
filter: blur(0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-kinetic-center-build,
.t-kinetic-center-build * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - line-by-line-slide */
/*
Usage:
<div class="t-text-animation t-line-by-line-slide is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-line-by-line-slide` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-line-by-line-slide.is-previewing .t-line {
animation: t-line-by-line-slide 680ms var(--text-motion-ease-out) both;
animation-delay: calc(var(--i) * 110ms);
}
@keyframes t-line-by-line-slide {
from {
opacity: 0;
transform: translateX(-28px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-line-by-line-slide,
.t-line-by-line-slide * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - mask-reveal-up */
/*
Usage:
<div class="t-text-animation t-mask-reveal-up is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-mask-reveal-up` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-mask-reveal-up {
overflow: hidden;
}
.t-mask-reveal-up.is-previewing .t-line {
animation: t-mask-reveal-up 760ms var(--text-motion-ease-out) both;
animation-delay: calc(var(--i) * 95ms);
}
@keyframes t-mask-reveal-up {
from {
opacity: 0;
transform: translateY(105%);
clip-path: inset(100% 0 0 0);
}
to {
opacity: 1;
transform: translateY(0);
clip-path: inset(0 0 0 0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-mask-reveal-up,
.t-mask-reveal-up * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - Meteor */
/*
Usage:
<div class="t-meteor">...</div>
Put `.t-meteor` on any icon, badge, card, or control
that should shoot upward diagonally and fade out.
*/
:root {
--meteor-dur: 1000ms;
--meteor-x: 140px;
--meteor-y: -167px;
--meteor-rotate: 311deg;
--meteor-scale-min: 0.001;
}
.t-meteor {
animation: t-meteor var(--meteor-dur) infinite both;
transform-origin: center;
will-change: transform, opacity;
}
@keyframes t-meteor {
0%,
3.33% {
opacity: 1;
transform: translate(0, 0) rotate(0deg) scale(var(--meteor-scale-min));
animation-timing-function: ease-in-out;
}
11.67% {
opacity: 1;
transform: translate(0, 0) rotate(45deg) scale(1);
animation-timing-function: ease-in-out;
}
70% {
opacity: 1;
}
80% {
opacity: 1;
transform: translate(var(--meteor-x), var(--meteor-y)) rotate(var(--meteor-rotate)) scale(1);
}
81.67%,
100% {
opacity: 0;
transform: translate(var(--meteor-x), var(--meteor-y)) rotate(var(--meteor-rotate)) scale(1);
}
}
@media (prefers-reduced-motion: reduce) {
.t-meteor {
animation: none !important;
}
}
/* Animation master - micro-scale-fade */
/*
Usage:
<div class="t-text-animation t-micro-scale-fade is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-micro-scale-fade` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-micro-scale-fade.is-previewing .t-text-whole {
animation: t-micro-scale-fade 520ms var(--text-motion-ease-out) both;
}
@keyframes t-micro-scale-fade {
from {
opacity: 0;
transform: scale(0.96);
}
to {
opacity: 1;
transform: scale(1);
}
}
@media (prefers-reduced-motion: reduce) {
.t-micro-scale-fade,
.t-micro-scale-fade * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - Modal */
/*
Usage:
<div class="t-modal">...</div>
State: add `.is-open` to show the modal, then `.is-closing`
while dismissing it.
*/
:root {
--modal-open-dur: 250ms;
--modal-close-dur: 150ms;
--modal-scale: 0.96;
--modal-scale-close: 0.96;
--modal-ease: cubic-bezier(0.22, 1, 0.36, 1);
}
.t-modal {
transform-origin: center;
transform: scale(var(--modal-scale));
opacity: 0;
pointer-events: none;
transition:
transform var(--modal-open-dur) var(--modal-ease),
opacity var(--modal-open-dur) var(--modal-ease);
will-change: transform, opacity;
}
.t-modal.is-open {
transform: scale(1);
opacity: 1;
pointer-events: auto;
}
.t-modal.is-closing {
transform: scale(var(--modal-scale-close));
opacity: 0;
pointer-events: none;
transition:
transform var(--modal-close-dur) var(--modal-ease),
opacity var(--modal-close-dur) var(--modal-ease);
}
@media (prefers-reduced-motion: reduce) {
.t-modal {
transition: none !important;
}
}
/* Animation master - Page side-by-side */
/*
Usage:
<div class="t-page-slide" data-page="1">
<section class="t-page" data-page-id="1">...</section>
<section class="t-page" data-page-id="2">...</section>
</div>
State: set data-page="1" or "2" on `.t-page-slide`.
Page 1 exits to the left, page 2 exits to the right.
*/
:root {
--page-slide-dur: 200ms;
--page-fade-dur: 200ms;
--page-slide-distance: 8px;
--page-blur: 3px;
--page-stagger: 0ms;
--page-exit-enabled: 1;
--page-slide-ease: cubic-bezier(0.22, 1, 0.36, 1);
--page-fade-ease: cubic-bezier(0.22, 1, 0.36, 1);
}
.t-page-slide {
position: relative;
}
.t-page-slide .t-page[data-page-id="1"] {
--t-page-from-x: calc(var(--page-slide-distance) * -1);
}
.t-page-slide .t-page[data-page-id="2"] {
--t-page-from-x: var(--page-slide-distance);
}
.t-page-slide .t-page {
position: absolute;
inset: 0;
opacity: 0;
pointer-events: none;
transform: translateX(calc(var(--t-page-from-x, 0px) * var(--page-exit-enabled)));
filter: blur(calc(var(--page-blur) * var(--page-exit-enabled)));
transition:
opacity var(--page-fade-dur) var(--page-fade-ease),
transform var(--page-slide-dur) var(--page-slide-ease),
filter var(--page-slide-dur) var(--page-slide-ease);
will-change: opacity, transform, filter;
}
.t-page-slide[data-page="1"] .t-page[data-page-id="1"],
.t-page-slide[data-page="2"] .t-page[data-page-id="2"] {
opacity: 1;
pointer-events: auto;
transform: translateX(0);
filter: blur(0);
transition-delay: var(--page-stagger);
}
@media (prefers-reduced-motion: reduce) {
.t-page-slide .t-page {
transition: none !important;
}
}
/* Animation master - Panel slide */
/*
Usage:
<div class="t-panel-slide" data-open="false">...</div>
State: set data-open="true" or "false" on `.t-panel-slide`.
The panel slides upward from the bottom and removes blur.
*/
:root {
--panel-open-dur: 400ms;
--panel-close-dur: 350ms;
--panel-translate-y: 100px;
--panel-blur: 2px;
--panel-ease: cubic-bezier(0.22, 1, 0.36, 1);
}
.t-panel-slide {
transform: translateY(var(--panel-translate-y));
opacity: 0;
filter: blur(var(--panel-blur));
pointer-events: none;
transition:
transform var(--panel-close-dur) var(--panel-ease),
opacity var(--panel-close-dur) var(--panel-ease),
filter var(--panel-close-dur) var(--panel-ease);
will-change: transform, opacity, filter;
}
.t-panel-slide[data-open="true"] {
transform: translateY(0);
opacity: 1;
filter: blur(0);
pointer-events: auto;
transition:
transform var(--panel-open-dur) var(--panel-ease),
opacity var(--panel-open-dur) var(--panel-ease),
filter var(--panel-open-dur) var(--panel-ease);
}
@media (prefers-reduced-motion: reduce) {
.t-panel-slide {
transition: none !important;
}
}
/* Animation master - per-character-rise */
/*
Usage:
<div class="t-text-animation t-per-character-rise is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-per-character-rise` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-per-character-rise.is-previewing .t-char {
animation: t-per-character-rise 720ms var(--text-motion-ease-out) both;
animation-delay: calc(var(--i) * 24ms);
}
@keyframes t-per-character-rise {
from {
opacity: 0;
transform: translateY(22px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-per-character-rise,
.t-per-character-rise * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - per-word-crossfade */
/*
Usage:
<div class="t-text-animation t-per-word-crossfade is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-per-word-crossfade` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-per-word-crossfade.is-previewing .t-word {
animation: t-per-word-crossfade 700ms var(--text-motion-ease-out) both;
animation-delay: calc(var(--i) * 90ms);
}
@keyframes t-per-word-crossfade {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-per-word-crossfade,
.t-per-word-crossfade * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - Resize */
/*
Usage:
<div class="t-resize">...</div>
Put `.t-resize` on any element whose width and height
should animate smoothly when its size changes.
*/
:root {
--resize-dur: 300ms;
--resize-ease: cubic-bezier(0.22, 1, 0.36, 1);
}
.t-resize {
transition:
width var(--resize-dur) var(--resize-ease),
height var(--resize-dur) var(--resize-ease);
will-change: width, height;
}
@media (prefers-reduced-motion: reduce) {
.t-resize {
transition: none !important;
}
}
/* Animation master - scale-down-fade */
/*
Usage:
<div class="t-text-animation t-scale-down-fade is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-scale-down-fade` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-scale-down-fade.is-previewing .t-text-whole {
animation: t-scale-down-fade 760ms var(--text-motion-ease-out) both;
}
@keyframes t-scale-down-fade {
from {
opacity: 0;
transform: scale(1.08);
}
to {
opacity: 1;
transform: scale(1);
}
}
@media (prefers-reduced-motion: reduce) {
.t-scale-down-fade,
.t-scale-down-fade * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - Shake */
/*
Usage:
<div class="t-shake">...</div>
Put `.t-shake` on any icon, badge, card, or control
that should rock side to side with a repeated shake motion.
*/
:root {
--shake-dur: 1000ms;
--shake-rot-a: 12deg;
--shake-rot-b: -13deg;
}
.t-shake {
animation: t-shake var(--shake-dur) infinite;
transform-origin: center bottom;
will-change: transform;
}
@keyframes t-shake {
0% {
transform: rotate(var(--shake-rot-a));
animation-timing-function: cubic-bezier(0.261, -0.019, 0.58, 1);
}
50% {
transform: rotate(var(--shake-rot-b));
animation-timing-function: ease-in-out;
}
100% {
transform: rotate(var(--shake-rot-a));
}
}
@media (prefers-reduced-motion: reduce) {
.t-shake {
animation: none !important;
}
}
/* Animation master - shared-axis-y */
/*
Usage:
<div class="t-text-animation t-shared-axis-y is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-shared-axis-y` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-shared-axis-y.is-previewing .t-word {
animation: t-shared-axis-y 520ms var(--text-motion-ease-out) both;
animation-delay: calc(var(--i) * 70ms);
}
@keyframes t-shared-axis-y {
from {
opacity: 0;
transform: translateY(18px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-shared-axis-y,
.t-shared-axis-y * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - shared-axis-z */
/*
Usage:
<div class="t-text-animation t-shared-axis-z is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-shared-axis-z` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-shared-axis-z.is-previewing .t-text-whole {
animation: t-shared-axis-z 560ms var(--text-motion-ease-out) both;
}
@keyframes t-shared-axis-z {
from {
opacity: 0;
transform: scale(0.88);
}
to {
opacity: 1;
transform: scale(1);
}
}
@media (prefers-reduced-motion: reduce) {
.t-shared-axis-z,
.t-shared-axis-z * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - shimmer-sweep */
/*
Usage:
<div class="t-text-animation t-shimmer-sweep is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-shimmer-sweep` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-shimmer-sweep.is-previewing .t-text-whole {
background: linear-gradient(
90deg,
currentColor 0%,
currentColor 42%,
rgba(255, 255, 255, 0.96) 50%,
currentColor 58%,
currentColor 100%
);
background-size: 240% 100%;
background-position: 100% 0;
background-repeat: no-repeat;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
animation: t-shimmer-sweep 850ms var(--text-motion-ease-out) both;
}
.t-shimmer-sweep:not(.is-previewing) .t-text-whole {
background: none;
-webkit-text-fill-color: currentColor;
}
@keyframes t-shimmer-sweep {
from {
opacity: 0;
transform: translateX(-22px);
filter: blur(8px);
background-position: 100% 0;
}
92% {
opacity: 1;
transform: translateX(0);
filter: blur(0);
background-position: 0 0;
}
to {
opacity: 1;
transform: translateX(0);
filter: blur(0);
background-position: 0 0;
}
}
@media (prefers-reduced-motion: reduce) {
.t-shimmer-sweep,
.t-shimmer-sweep * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - short-slide-down */
/*
Usage:
<div class="t-text-animation t-short-slide-down is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-short-slide-down` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-short-slide-down.is-previewing .t-word {
animation: t-short-slide-down 620ms var(--text-motion-ease-out) both;
animation-delay: calc(var(--i) * 150ms);
}
@keyframes t-short-slide-down {
from {
opacity: 0;
transform: translateY(-22px);
filter: blur(4px);
}
to {
opacity: 1;
transform: translateY(0);
filter: blur(0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-short-slide-down,
.t-short-slide-down * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - short-slide-right */
/*
Usage:
<div class="t-text-animation t-short-slide-right is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-short-slide-right` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-short-slide-right.is-previewing {
animation: t-short-slide-right-stage 520ms var(--text-motion-ease-out) both;
}
.t-short-slide-right.is-previewing .t-word {
animation: t-short-slide-right-word 420ms var(--text-motion-ease-out) both;
animation-delay: calc(var(--i) * 80ms);
}
@keyframes t-short-slide-right-stage {
from {
transform: translateX(-20px);
}
to {
transform: translateX(0);
}
}
@keyframes t-short-slide-right-word {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.t-short-slide-right,
.t-short-slide-right * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - soft-blur-in */
/*
Usage:
<div class="t-text-animation t-soft-blur-in is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-soft-blur-in` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-soft-blur-in.is-previewing .t-char {
animation: t-soft-blur-in 900ms var(--text-motion-ease-out) both;
animation-delay: calc(var(--i) * 25ms);
}
@keyframes t-soft-blur-in {
from {
opacity: 0;
transform: translateY(16px);
filter: blur(12px);
}
to {
opacity: 1;
transform: translateY(0);
filter: blur(0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-soft-blur-in,
.t-soft-blur-in * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - spring-scale-in */
/*
Usage:
<div class="t-text-animation t-spring-scale-in is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-spring-scale-in` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-spring-scale-in.is-previewing .t-word {
animation: t-spring-scale-in 650ms var(--text-motion-spring) both;
animation-delay: calc(var(--i) * 70ms);
}
@keyframes t-spring-scale-in {
from {
opacity: 0;
transform: scale(0.78);
}
70% {
opacity: 1;
transform: scale(1.06);
}
to {
opacity: 1;
transform: scale(1);
}
}
@media (prefers-reduced-motion: reduce) {
.t-spring-scale-in,
.t-spring-scale-in * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - Success check */
/*
Usage:
<span class="t-success-check" data-state="out">...</span>
State: set data-state="in" to show the success mark.
Add `.is-exiting` when dismissing it.
*/
:root {
--success-check-opacity-dur: 550ms;
--success-check-rotate-dur: 550ms;
--success-check-rotate-from: 80deg;
--success-check-bob-dur: 450ms;
--success-check-y: 40px;
--success-check-blur-dur: 500ms;
--success-check-blur-from: 10px;
--success-check-blur-out: 4px;
--success-check-path-dur: 550ms;
--success-check-path-delay: 80ms;
--success-check-out-dur: 500ms;
--success-check-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--success-check-ease-opacity: cubic-bezier(0.22, 1, 0.36, 1);
--success-check-ease-rotate: cubic-bezier(0.22, 1, 0.36, 1);
--success-check-ease-bob: cubic-bezier(0.34, 1.35, 0.64, 1);
--success-check-ease-path: cubic-bezier(0.22, 1, 0.36, 1);
}
.t-success-check {
width: 48px;
height: 48px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 48px;
background: #35ba00;
box-shadow:
0 0 0 1px rgba(0, 0, 0, 0.05) inset,
0 1px 1px rgba(0, 0, 0, 0.1),
0 1px 4px rgba(0, 0, 0, 0.08),
0 -1px 1px rgba(0, 0, 0, 0.09) inset;
opacity: 0;
transform-origin: center;
will-change: transform, opacity, filter;
}
.t-success-check svg {
width: 48px;
height: 48px;
display: block;
overflow: visible;
}
.t-success-check path {
stroke-dasharray: 20;
stroke-dashoffset: 20;
}
.t-success-check[data-state="in"] {
animation:
t-success-check-fade var(--success-check-opacity-dur) var(--success-check-ease-opacity) forwards,
t-success-check-rotate var(--success-check-rotate-dur) var(--success-check-ease-rotate) forwards,
t-success-check-blur var(--success-check-blur-dur) var(--success-check-ease-out) forwards,
t-success-check-bob var(--success-check-bob-dur) var(--success-check-ease-bob) forwards;
}
.t-success-check[data-state="in"] path {
animation: t-success-check-draw var(--success-check-path-dur) var(--success-check-ease-path) var(--success-check-path-delay) forwards;
}
.t-success-check.is-exiting {
animation:
t-success-check-fade-out var(--success-check-out-dur) var(--success-check-ease-out) forwards,
t-success-check-blur-out var(--success-check-out-dur) var(--success-check-ease-out) forwards;
}
@keyframes t-success-check-fade {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes t-success-check-fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes t-success-check-rotate {
from { transform: rotate(var(--success-check-rotate-from)); }
to { transform: rotate(0deg); }
}
@keyframes t-success-check-blur {
from { filter: blur(var(--success-check-blur-from)); }
to { filter: blur(0); }
}
@keyframes t-success-check-blur-out {
from { filter: blur(0); }
to { filter: blur(var(--success-check-blur-out)); }
}
@keyframes t-success-check-bob {
from { translate: 0 var(--success-check-y); }
to { translate: 0 0; }
}
@keyframes t-success-check-draw {
to { stroke-dashoffset: 0; }
}
@media (prefers-reduced-motion: reduce) {
.t-success-check,
.t-success-check path {
animation: none !important;
filter: none !important;
}
}
/* Animation master - Text swap */
/*
Usage:
<span class="t-text-swap">Transaction processing...</span>
Add `.is-exit` before changing text, then briefly add
`.is-enter-start` to let the new text enter from below.
*/
:root {
--text-swap-dur: 200ms;
--text-swap-translate-y: 8px;
--text-swap-blur: 2px;
--text-swap-ease: ease-out;
}
.t-text-swap {
display: inline-block;
transform: translateY(0);
filter: blur(0);
opacity: 1;
transition:
transform var(--text-swap-dur) var(--text-swap-ease),
filter var(--text-swap-dur) var(--text-swap-ease),
opacity var(--text-swap-dur) var(--text-swap-ease);
will-change: transform, filter, opacity;
}
.t-text-swap.is-exit {
transform: translateY(calc(var(--text-swap-translate-y) * -1));
filter: blur(var(--text-swap-blur));
opacity: 0;
}
.t-text-swap.is-enter-start {
transform: translateY(var(--text-swap-translate-y));
filter: blur(var(--text-swap-blur));
opacity: 0;
transition: none;
}
@media (prefers-reduced-motion: reduce) {
.t-text-swap {
transition: none !important;
}
}
/* Animation master - top-down-letters */
/*
Usage:
<div class="t-text-animation t-top-down-letters is-previewing">
<span class="t-text-row"><span class="t-text-whole">China Ad</span></span>
<span class="t-text-row"><span class="t-text-whole">Product Design</span></span>
</div>
Add `.t-top-down-letters` and `.is-previewing` to run this text animation.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-top-down-letters.is-previewing .t-char {
animation: t-top-down-letters 660ms var(--text-motion-ease-out) both;
animation-delay: calc(var(--i) * 32ms);
}
@keyframes t-top-down-letters {
from {
opacity: 0;
transform: translateY(-30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
.t-top-down-letters,
.t-top-down-letters * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
/* Animation master - Shared motion tokens */
:root {
--resize-dur: 300ms;
--resize-ease: cubic-bezier(0.22, 1, 0.36, 1);
--digit-dur: 500ms;
--digit-distance: 8px;
--digit-stagger: 70ms;
--digit-blur: 2px;
--digit-ease: cubic-bezier(0.34, 1.45, 0.64, 1);
--digit-dir-x: 0;
--digit-dir-y: 1;
--badge-slide-dur: 260ms;
--badge-pop-dur: 500ms;
--badge-pop-close-dur: 180ms;
--badge-fade-dur: 400ms;
--badge-fade-close-dur: 180ms;
--badge-blur: 2px;
--badge-offset-x: -8.2px;
--badge-offset-y: 12.4px;
--badge-slide-ease: cubic-bezier(0.22, 1, 0.36, 1);
--badge-pop-ease: cubic-bezier(0.34, 1.36, 0.64, 1);
--badge-close-ease: cubic-bezier(0.4, 0, 0.2, 1);
--text-swap-dur: 200ms;
--text-swap-translate-y: 8px;
--text-swap-blur: 2px;
--text-swap-ease: ease-out;
--dropdown-open-dur: 250ms;
--dropdown-close-dur: 150ms;
--dropdown-pre-scale: 0.97;
--dropdown-closing-scale: 0.99;
--dropdown-ease: cubic-bezier(0.22, 1, 0.36, 1);
--modal-open-dur: 250ms;
--modal-close-dur: 150ms;
--modal-scale: 0.96;
--modal-scale-close: 0.96;
--modal-ease: cubic-bezier(0.22, 1, 0.36, 1);
--panel-open-dur: 400ms;
--panel-close-dur: 350ms;
--panel-translate-y: 100px;
--panel-blur: 2px;
--panel-ease: cubic-bezier(0.22, 1, 0.36, 1);
--page-slide-dur: 200ms;
--page-fade-dur: 200ms;
--page-slide-distance: 8px;
--page-blur: 3px;
--page-stagger: 0ms;
--page-exit-enabled: 1;
--page-slide-ease: cubic-bezier(0.22, 1, 0.36, 1);
--page-fade-ease: cubic-bezier(0.22, 1, 0.36, 1);
--icon-swap-dur: 200ms;
--icon-swap-blur: 2px;
--icon-swap-start-scale: 0.25;
--icon-swap-ease: ease-in-out;
}
/* Animation master - typewriter */
/*
Usage:
<div class="t-text-animation t-typewriter is-previewing">
<span class="t-text-row">
<span class="t-char" style="--i: 0">C</span>
<span class="t-char" style="--i: 1">h</span>
<span class="t-char" style="--i: 2">i</span>
</span>
</div>
Add `.t-typewriter` and `.is-previewing` to run this text animation.
Wrap each character in `.t-char` and set an incremental `--i` value.
*/
:root {
--text-motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--text-motion-ease-in: cubic-bezier(0.64, 0, 0.78, 0);
--text-motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--typewriter-char-dur: 1ms;
--typewriter-stagger: 46ms;
}
.t-text-animation {
display: inline-flex;
flex-wrap: wrap;
justify-content: inherit;
align-content: inherit;
gap: 0;
color: inherit;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char,
.t-text-animation .t-word,
.t-text-animation .t-line,
.t-text-animation .t-text-row,
.t-text-animation .t-text-whole {
display: inline-block;
opacity: 1;
transform-origin: center;
will-change: transform, opacity, filter, clip-path, background-position;
}
.t-text-animation .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-line {
flex-basis: 100%;
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-text-whole {
max-width: 100%;
white-space: inherit;
overflow-wrap: inherit;
word-break: inherit;
}
.t-text-animation .t-char-space {
width: 0.32em;
}
.t-text-animation .t-text-word-group {
display: inline-block;
white-space: nowrap;
}
/* Optional preview wrapper for Animation master demo pages. */
.text-preview {
width: 272px;
max-width: calc(100% - 24px);
min-height: 120px;
display: inline-flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: wrap;
gap: 0;
padding: 4px 0 6px;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: inherit;
font-size: 28px;
font-weight: 760;
letter-spacing: 0;
text-align: center;
line-height: 1.09;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-line {
flex-basis: 100%;
max-width: 100%;
line-height: 1.09;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-row {
display: block;
flex: 0 0 100%;
width: 100%;
max-width: 100%;
line-height: inherit;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-text-whole {
max-width: 100%;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.text-preview .t-char-space {
width: 0.32em;
}
.text-preview:not(.is-previewing) .t-char,
.text-preview:not(.is-previewing) .t-word,
.text-preview:not(.is-previewing) .t-line,
.text-preview:not(.is-previewing) .t-text-whole {
animation: none;
}
.t-typewriter .t-char {
opacity: 1;
}
.t-typewriter:not(.is-previewing) .t-char {
animation: none;
}
.t-typewriter.is-previewing .t-char {
animation: t-typewriter var(--typewriter-char-dur) steps(1, end) backwards;
animation-delay: calc(var(--i) * var(--typewriter-stagger));
}
@keyframes t-typewriter {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.t-typewriter,
.t-typewriter * {
animation: none !important;
transition: none !important;
filter: none !important;
}
}
Animation Master CSS Catalog
Use this catalog to map a requested effect to the bundled CSS file in assets/css/.
This catalog describes Animation Master as a reusable motion skill. The preview site and any browser extension are consumers of this same library; do not remove or hide base skill effects only because one consumer chooses not to expose them.
Element Motion
| Effect | File | Primary class | Typical demo |
|---|---|---|---|
| Button animation | button-animation.css | .t-button-animation | Button press feedback |
| Float | float.css | .t-float | Floating star or prompt |
| Click | click.css | .t-click | Pointer/click gesture |
| Jump | jump.css | .t-jump | Gift bounce |
| Shake | shake.css | .t-shake | Money bag shake |
| Blink | blink.css | .t-blink | Sparkle blink |
| Blink swing | blink-2.css | .t-blink-swing | Bell swing and blink |
| Drift down | drift-down.css | .t-drift-down | Snow or leaf drift |
| Float rise | float-2.css | .t-float-rise | Rising icon |
| Heartbeat | heartbeat.css | .t-heartbeat | Heart pulse |
| Meteor | meteor.css | .t-meteor | Diagonal fast pass |
| Digit roll | digit-roll.css | .t-digit-roll | Numeric rolling counter |
UI Motion
| Effect | File | Primary class | State hook |
|---|---|---|---|
| Resize | resize.css | .t-resize | Size change |
| Digit group | digit.css | .t-digit-group | .is-animating |
| Badge | badge.css | .t-badge | data-open |
| Text swap | text-swap.css | .t-text-swap | Text replacement |
| Dropdown | dropdown.css | .t-dropdown | .is-open, .is-closing |
| Modal | modal.css | .t-modal | .is-open, .is-closing |
| Panel slide | panel-slide.css | .t-panel-slide | data-open |
| Page slide | page-slide.css | .t-page-slide | data-page |
| Icon swap | icon-swap.css | .t-icon-swap | data-state |
| Success check | success-check.css | .t-success-check | data-state |
| Avatar hover | avatar-hover.css | .t-avatar-hover | hover / custom properties |
| Error shake | error-shake.css | .t-error-shake-wrap, .t-error-shake | .is-error, .is-shaking |
| Shared tokens | transitions-root.css | :root variables | Optional shared UI tokens |
Text Motion
Each text effect is standalone. Use .t-text-animation, the listed class, and .is-previewing.
When applying text effects to existing page text, preserve the page's typography and layout. See the text integration contract in SKILL.md for overlay and character wrapping guidance.
| Effect | File | Primary class | Split mode |
|---|---|---|---|
| Soft blur in | soft-blur-in.css | .t-soft-blur-in | char |
| Per character rise | per-character-rise.css | .t-per-character-rise | char |
| Per word crossfade | per-word-crossfade.css | .t-per-word-crossfade | word |
| Spring scale in | spring-scale-in.css | .t-spring-scale-in | word |
| Mask reveal up | mask-reveal-up.css | .t-mask-reveal-up | line |
| Line by line slide | line-by-line-slide.css | .t-line-by-line-slide | line |
| Typewriter | typewriter.css | .t-typewriter | char |
| Micro scale fade | micro-scale-fade.css | .t-micro-scale-fade | whole |
| Shimmer sweep | shimmer-sweep.css | .t-shimmer-sweep | whole |
| Fade through | fade-through.css | .t-fade-through | whole |
| Shared axis Y | shared-axis-y.css | .t-shared-axis-y | word |
| Shared axis Z | shared-axis-z.css | .t-shared-axis-z | whole |
| Blur out up | blur-out-up.css | .t-blur-out-up | word |
| Scale down fade | scale-down-fade.css | .t-scale-down-fade | whole |
| Focus blur resolve | focus-blur-resolve.css | .t-focus-blur-resolve | whole |
| Bottom up letters | bottom-up-letters.css | .t-bottom-up-letters | char |
| Top down letters | top-down-letters.css | .t-top-down-letters | char |
| Kinetic center build | kinetic-center-build.css | .t-kinetic-center-build | word |
| Short slide right | short-slide-right.css | .t-short-slide-right | word |
| Short slide down | short-slide-down.css | .t-short-slide-down | word |
Copying Rules
- Copy the CSS file exactly first, then adapt variables or durations in the target project.
- Keep
@media (prefers-reduced-motion: reduce)blocks. - Keep
.t-*names when the user wants compatibility with this skill. - Use
transitions-root.csswhen a page benefits from centralized shared tokens, but individual files are designed to work independently.
#!/usr/bin/env python3
"""Copy Animation Master CSS assets into a target directory."""
from __future__ import annotations
import argparse
import re
import shutil
from pathlib import Path
SKILL_DIR = Path(__file__).resolve().parents[1]
CSS_DIR = SKILL_DIR / "assets" / "css"
def normalize(value: str) -> str:
value = value.strip().lower()
if value.endswith(".css"):
value = value[:-4]
value = value.lstrip(".")
if value.startswith("t-"):
value = value[2:]
return value.replace("_", "-").replace(" ", "-")
def css_files() -> list[Path]:
return sorted(CSS_DIR.glob("*.css"))
def aliases_for(path: Path) -> set[str]:
text = path.read_text(encoding="utf-8")
aliases = {path.name.lower(), path.stem.lower(), normalize(path.name), normalize(path.stem)}
aliases.update(normalize(match) for match in re.findall(r"\.t-[A-Za-z0-9_-]+", text))
return aliases
def build_index() -> dict[str, Path]:
index: dict[str, Path] = {}
for path in css_files():
for alias in aliases_for(path):
index.setdefault(alias, path)
return index
def resolve_names(names: list[str]) -> list[Path]:
index = build_index()
resolved: list[Path] = []
missing: list[str] = []
for name in names:
path = index.get(normalize(name)) or index.get(name.lower())
if path is None:
missing.append(name)
continue
if path not in resolved:
resolved.append(path)
if missing:
available = ", ".join(path.name for path in css_files())
raise SystemExit(f"Unknown effect(s): {', '.join(missing)}\nAvailable files: {available}")
return resolved
def copy_files(paths: list[Path], target: Path) -> None:
target.mkdir(parents=True, exist_ok=True)
for path in paths:
destination = target / path.name
shutil.copy2(path, destination)
print(destination)
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("effects", nargs="*", help="Effect names, class names, or CSS filenames to copy.")
parser.add_argument("--target", "-t", type=Path, help="Directory to copy CSS files into.")
parser.add_argument("--all", action="store_true", help="Copy the full CSS library.")
parser.add_argument("--list", action="store_true", help="List bundled CSS files.")
parser.add_argument("--include-root", action="store_true", help="Also copy transitions-root.css.")
args = parser.parse_args()
if args.list:
for path in css_files():
print(path.name)
return
if not args.target:
raise SystemExit("--target is required unless --list is used")
selected = css_files() if args.all else resolve_names(args.effects)
if args.include_root:
root = CSS_DIR / "transitions-root.css"
if root.exists() and root not in selected:
selected.insert(0, root)
if not selected:
raise SystemExit("No effects selected. Pass effect names or use --all.")
copy_files(selected, args.target)
if __name__ == "__main__":
main()