MotionText
45 source-mapped text effects, four registry reveals, scramble, inline caller media and interactive focus blur.
Overview
TxMotionText preserves the 45 original Amicro catalog IDs and seven independent registry/source additions. Each preset keeps its own direction, grouping, stagger, scale, blur, mask, 3D transform or continuous rhythm. MOTION_TEXT_VARIANTS provides typed names, groups, segmentation and fixed source references; MOTION_TEXT_VARIANT_IDS is the complete ID list.
Entrance and decorative playback are separate from value changes. A mounted TxTextMorph owns every text update; there is no second diff engine and replay does not remount it. The original is exposed to screen readers once. Only one text layer is selectable: the decorative original during normal playback, the unchanged original during scramble, and the TextMorph layer at rest. Whitespace, newlines, emoji ZWJ sequences and combining marks are retained.
Usage
All source variants
Select any of the 52 IDs in the live catalog, filter by group/name/ID, use Next to traverse them, edit multilingual text, or replay repeatedly. Hover presets respond to individual graphemes/words and support keyboard focus. Pause restores the complete readable text, including during typewriter and scramble playback.
Source interactions
Scramble is real hover/focus-driven substitution, not a static title. It can reveal from the start, end or center using whole graphemes, and can use the original character pool or caller-supplied characters. Whitespace is never scrambled. focus-blur takes caller items: links remain native links and items without href are buttons emitting select. The hovered/focused item remains sharp while peers soften; focus brackets use the shared spring.
<TxMotionText
text="ไฟ็ ๐ฉ๐ฝโ๐ป ๅ eฬ"
variant="scramble-hover"
sequential
reveal-direction="center"
:use-original-chars-only="false"
characters="ABC123โฆ"
/>
<TxMotionText
variant="focus-blur"
:items="[
{ id: 'design', label: 'Design', href: '/design' },
{ id: 'motion', label: 'Motion' },
]"
@select="item => selectedId = item.id"
/>
Inline media uses caller mediaSrc, image/video properties, or the media slot. With the default hover trigger, leaving both pointer and keyboard focus closes the media. trigger="manual" uses the exposed animate()/reset() methods; trigger="in-view" opens on visibility. Reduced motion reveals media immediately without a width/scale animation. Built-in and slotted videos pause when motion is inactive or the media closes; slotted media receives active and open for its own resource lifecycle.
<TxMotionText
variant="media-between-text"
first-text="Crafting"
second-text="experiences"
:media-src="imageUrl"
media-alt="Abstract texture"
/>
<TxMotionText variant="media-between-text" first-text="Your" second-text="media">
<template #media="{ active, open }">
<img :src="imageUrl" alt="Caller illustration">
</template>
</TxMotionText>
Best Practices
- Keep
text, media and items caller-owned. No demo business data is embedded in the component. - Keep the component mounted when replacing text. Use
replayKeyorreplay()for decorative replay rather than keying the component by the value. - Use a valid
localefor Chinese word segmentation. Grapheme effects never split a family emoji or a combining mark; withoutIntl.Segmenter, decorative grapheme playback keeps the whole value as a safe unit. - Hover effects are decoration, not action buttons. Use the native
focus-bluritems or a separate semantic control for navigation/actions. - Use
pausedto stop all owned animations, scramble timeouts and video playback. Ambient effects run only while mounted, intersecting, document-visible, enabled and not reduced, including across KeepAlive suspension. - The morph engine does not soft-wrap. Supply explicit newlines (
text-revealanimates each line) or choose a wrapping text primitive for prose. - Tracking presets converge to natural body spacing. Glow crossfades two static shadow layers, and hover colors change immediately rather than tweening.
API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | '' | Original text for the catalog, registry and scramble effects. |
variant | MotionTextVariant | 'txt-dia' | One of the 52 IDs below. |
size | 'xs' | 'sm' | 'md' | 'lg' | 'md' | Token-controlled content sizing. |
tag | 'span' | 'div' | 'p' | 'h1' | 'h2' | 'h3' | 'span' | Root semantic element. |
locale | string | 'en' | Word/grapheme segmentation and TextMorph locale. |
paused | boolean | false | Cancel motion and show the complete readable value. |
trigger | 'in-view' | 'hover' | 'manual' | Source-dependent | Entrances/ambient effects default to in-view; scramble/media to hover. Character/word hover and focus items retain their native interactions. |
replayKey | string | number | โ | Changing the key replays the effect without remounting TextMorph. |
durationMs | number | Source-dependent | Timed-effect duration in ms. A physical spring owns its settling duration. |
staggerMs | number | Source-dependent | Override each source unit delay in ms. |
transition | Transition | Source-dependent | Shared 'snappy' | 'smooth' | 'bouncy', { stiffness?, damping?, mass? }, or { duration, ease? }; overrides source timing. |
initialBlur | number | 8 | Registry blur-text blur radius, in pixels. |
yOffset | number | 15 | Registry character-stagger vertical start offset. |
scrambleSpeed | number | 40 | Milliseconds between scramble frames. |
maxIterations | number | 10 | Non-sequential scramble iterations. |
sequential | boolean | false | Reveal a growing set of whole graphemes per frame. |
revealDirection | 'start' | 'end' | 'center' | 'start' | Sequential scramble reveal direction. |
useOriginalCharsOnly | boolean | true | Pick replacements from the original non-whitespace graphemes. |
characters | string | Latin letters, digits and symbols | Custom replacement pool when original-only is false. |
firstText | string | '' | Text preceding inline media. |
secondText | string | '' | Text following inline media. |
mediaSrc | string | โ | Caller image/video URL; no fabricated fallback. |
mediaType | 'image' | 'video' | 'image' | Built-in media renderer. |
mediaAlt | string | '' | Image alternative text / video accessible name. |
mediaPoster | string | '' | Caller video poster. |
mediaWidth | number | 70 | Expanded inline media width in pixels. |
mediaHeight | number | 40 | Inline media height in pixels. |
mediaAutoplay | boolean | true | Request playback only while active and open; browser autoplay policy can reject it. |
mediaLoop | boolean | true | Loop built-in video only while active. |
mediaMuted | boolean | true | Built-in video muted state. |
mediaPlaysinline | boolean | true | Built-in video inline playback attribute. |
items | readonly MotionTextItem[] | [] | Focus items { id, label, href? }. Stable IDs preserve mounted label engines. |
blurAmount | number | 4 | Blur radius for inactive focus items, in pixels. |
opacityAmount | number | 0.4 | Opacity of inactive focus items. |
showBrackets | boolean | true | Shared-spring focus brackets. |
Events
| Event | Payload | Description |
|---|---|---|
animation-start | MotionTextVariant | Decorative playback or a text-value morph begins. |
animation-complete | MotionTextVariant | A finite playback/morph completes. Ambient loops do not periodically announce completion. |
animation-cancel | MotionTextVariant | A running finite playback/morph is interrupted. |
select | MotionTextItem | A focus item is activated. Native links keep their navigation behavior. |
media-error | Event | The caller image/video reports a real load error. |
Slots
| Slot | Scope | Description |
|---|---|---|
media | { open: boolean, active: boolean } | Replace the built-in image/video while retaining hover/manual/in-view geometry and activity control. |
Exposed Methods
| Method | Description |
|---|---|
replay() | Cancel the prior decorative run and replay; opens inline media. |
animate() | Same explicit playback/open action for the upstream ref-trigger contract. |
reset() | Cancel work, restore the original and close media; clears focus-item decoration. |
MotionTextProps, MotionTextItem, MotionTextVariant, MotionTextVariantInfo, MotionTextTrigger, MotionTextRevealDirection, MotionTextMediaSlotProps, MotionTextSlots, MotionTextExpose and TxMotionTextInstance are exported from @talex-touch/tuffex/motion-text.
Variant catalogue
| Original ID | Effect retained |
|---|---|
txt-dia | Polygon mask reveal plus 8px blur, 850ms. |
txt-blur | Whole text 12px blur, 0.9โ1 scale and fade, 700ms. |
txt-shimmer | Static clipped gradient with a 2s opacity shimmer. |
txt-typewriter | Whole-grapheme stepping over 1.2s with a moving blinking cursor. |
txt-reveal | Horizontal inset-mask reveal, 750ms. |
txt-fade-char | Grapheme fade, 300ms / 50ms stagger. |
txt-fade-word | Word fade, 400ms / 150ms stagger. |
txt-fade-text | Whole-text fade, 800ms. |
txt-blurup-word | Words rise 15px out of 8px blur, 500ms / 120ms. |
txt-blurup-char | Graphemes rise 15px out of 8px blur, 400ms / 40ms. |
txt-stagger | Words rise 20px with expo easing, 500ms / 100ms. |
txt-slideup-char | Masked graphemes from +100% Y, 400ms / 40ms. |
txt-slideup-word | Masked words from +100% Y, 500ms / 100ms. |
txt-slideup-text | Masked whole text from +100% Y, 600ms. |
txt-slidedown-char | Masked graphemes from โ100% Y, 400ms / 40ms. |
txt-slidedown-word | Masked words from โ100% Y, 500ms / 100ms. |
txt-slideleft-char | Graphemes from +40px X with fade, 400ms / 40ms. |
txt-slideright-char | Graphemes from โ40px X with fade, 400ms / 40ms. |
txt-dropin-char | Graphemes drop 50px, spring 500/25, 40ms stagger. |
txt-riseup-word | Words rise 30px and scale 0.8โ1, spring 400/22, 120ms stagger. |
txt-bouncein-char | Grapheme scale 0โ1.3โ1 and fade, 500ms / 50ms. |
txt-scalein-char | Grapheme scale 0โ1, spring 450/22, 40ms stagger. |
txt-scalein-word | Word scale 0.4โ1 and fade, 400ms / 120ms. |
txt-scalein-text | Whole-text scale 0.5โ1 and fade, spring 400/25. |
txt-zoomin-text | Whole-text scale 0.2โ1 and fade, 600ms. |
txt-zoomout-text | Whole-text scale 1.8โ1 and fade, 600ms. |
txt-flipy-char | Grapheme Y-axis 90ยฐโ0ยฐ rotation, 500ms / 50ms. |
txt-flipx-char | Grapheme X-axis 90ยฐโ0ยฐ rotation, 500ms / 50ms. |
txt-rotatein-char | Grapheme โ45ยฐโ0ยฐ plus 0.5โ1 scale/fade, 400ms / 40ms. |
txt-swing-word | Top-origin word X rotation โ90ยฐโ0ยฐ, spring 350/18, 120ms stagger. |
txt-stretchx-char | Grapheme X scale 2.5โ1 and fade, 400ms / 40ms. |
txt-stretchy-char | Grapheme Y scale 2.5โ1 and fade, 400ms / 40ms. |
txt-skewx-char | Grapheme X skew โ30ยฐโ0ยฐ and fade, 400ms / 40ms. |
txt-trackingin-text | Wide 0.6em spread converges to natural spacing, 700ms. |
txt-trackingout-text | Tight โ0.2em spread expands to natural spacing, 700ms. |
txt-spring-text | Per-grapheme hover lift โ8px and scale 1.2, spring 500/15. |
txt-hoverlift-char | The source's same per-grapheme hover lift/scale trajectory. |
txt-hoverlift-word | Word hover lift โ6px, spring 400/18. |
txt-hoverscale-char | Grapheme hover scale 1.4, spring 500/18. |
txt-hoverscale-word | Word hover scale 1.25, spring 400/20. |
txt-float-char | 0โโ6pxโ0, 2s cycle / 100ms phase per grapheme. |
txt-float-word | 0โโ8pxโ0, 2.4s cycle / 200ms phase per word. |
txt-pulse-char | 0.3โ1โ0.3 opacity, 1.5s cycle / 80ms phase. |
txt-pulse-word | 0.3โ1โ0.3 opacity, 1.8s cycle / 250ms phase. |
txt-glow-text | Crossfading 10px/25px ambient shadow layers, 2s cycle. |
registry-blur-text | Registry per-grapheme blur/fade, configurable radius, 500ms / 20ms. |
character-stagger | Registry per-grapheme rise/0.8 scale/fade, spring 300/18/0.8, 15ms stagger. |
text-reveal | Registry per-line +100% Y masked reveal, 800ms / 150ms. |
word-reveal | Registry words rise 15px and scale 0.9โ1 with cubic easing, 500ms / 40ms. |
scramble-hover | Hover/focus scramble; iterative or start/end/center sequential reveal. |
media-between-text | Caller media expands/fades/scales between two morphing text values. |
focus-blur | Actual pointer/keyboard peer blur with native item activation and spring brackets. |
CSS Variables
| Variable | Default | Description |
|---|---|---|
--tx-motion-text-font-size | Size-dependent | Inherited motion-text content size. |
--tx-motion-text-line-height | 1.5 (lg: 1.75) | Content leading; large has more breathing room without enlarging body text. |
--tx-motion-text-media-width | 70px | Inline width derived from mediaWidth. |
--tx-motion-text-media-height | 40px | Inline height derived from mediaHeight. |
Ink, glow, focus, surfaces and rings use the existing --tx-* theme tokens.
Technologies
- Fixed upstream Amicro commit
43c29ce9cdd16459e3eab4992381b8d35b38776a; MIT, Copyright (c) 2026 SYED SUBHAN UDDIN. - The 45 catalog rows map to
src/data/textAnimations.tsand their individualsrc/components/text/AnimatedText.tsxbranches. The four registry sources live inregistry/ui/text/. Extra sources areScrambleHover.tsx,MediaBetweenText.tsx, and bothFocusBlur.tsximplementations. Exact ranges are exported inMOTION_TEXT_VARIANTSand shown by the demo. - Implementation:
motion-text/src/TxMotionText.vue, source trajectories insrc/presets.ts, typed API insrc/types.ts. Decorative WAAPI resources and the single scramble timeout have an idempotent cancel boundary throughuseMotionActivity; value changes reuseTxTextMorph, word grouping reusesstream-text/src/segment.ts, and spring easing reusesliquid/src/spring.ts. - Typewriter is stepped by whole graphemes rather than cropping half a glyph. Spacing settles to natural body spacing. The two hover catalog IDs that share an upstream switch branch remain separately discoverable without pretending to have different source trajectories.
- This page documents implementation behavior; integration/build/browser acceptance is performed by the owning workflow, not claimed by this page.