motion-presets-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +174 -0
- package/bin/cli.mjs +115 -0
- package/bin/skill.mjs +94 -0
- package/dist/chunk-GU3ZCMLK.js +537 -0
- package/dist/chunk-GU3ZCMLK.js.map +1 -0
- package/dist/chunk-ONXBTJWT.js +167 -0
- package/dist/chunk-ONXBTJWT.js.map +1 -0
- package/dist/chunk-PFZKSPJW.js +164 -0
- package/dist/chunk-PFZKSPJW.js.map +1 -0
- package/dist/components.cjs +719 -0
- package/dist/components.cjs.map +1 -0
- package/dist/components.d.cts +199 -0
- package/dist/components.d.ts +199 -0
- package/dist/components.js +4 -0
- package/dist/components.js.map +1 -0
- package/dist/index-DtNOkqyg.d.cts +112 -0
- package/dist/index-DtNOkqyg.d.ts +112 -0
- package/dist/index.cjs +890 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/presets.cjs +334 -0
- package/dist/presets.cjs.map +1 -0
- package/dist/presets.d.cts +3 -0
- package/dist/presets.d.ts +3 -0
- package/dist/presets.js +4 -0
- package/dist/presets.js.map +1 -0
- package/package.json +117 -0
- package/scripts/postinstall.mjs +75 -0
- package/skill/motion-presets-kit/SKILL.md +221 -0
package/package.json
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "motion-presets-kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Set tipado y validado en runtime de helpers y presets para motion/react: fade, slide, scale, clipReveal, parentVariants, más componentes como TextAnimate, Marquee, Draggable y el hook useCounter.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"motion",
|
|
7
|
+
"motion-react",
|
|
8
|
+
"framer-motion",
|
|
9
|
+
"animation",
|
|
10
|
+
"presets",
|
|
11
|
+
"variants",
|
|
12
|
+
"react",
|
|
13
|
+
"typescript",
|
|
14
|
+
"zod",
|
|
15
|
+
"agent-skill",
|
|
16
|
+
"ai"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Orlando Lopez",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/OrlandoDev17/motion-presets-kit.git"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/OrlandoDev17/motion-presets-kit#readme",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/OrlandoDev17/motion-presets-kit/issues"
|
|
27
|
+
},
|
|
28
|
+
"type": "module",
|
|
29
|
+
"main": "./dist/index.cjs",
|
|
30
|
+
"module": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"import": {
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"default": "./dist/index.js"
|
|
37
|
+
},
|
|
38
|
+
"require": {
|
|
39
|
+
"types": "./dist/index.d.cts",
|
|
40
|
+
"default": "./dist/index.cjs"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"./presets": {
|
|
44
|
+
"import": {
|
|
45
|
+
"types": "./dist/presets.d.ts",
|
|
46
|
+
"default": "./dist/presets.js"
|
|
47
|
+
},
|
|
48
|
+
"require": {
|
|
49
|
+
"types": "./dist/presets.d.cts",
|
|
50
|
+
"default": "./dist/presets.cjs"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"./components": {
|
|
54
|
+
"import": {
|
|
55
|
+
"types": "./dist/components.d.ts",
|
|
56
|
+
"default": "./dist/components.js"
|
|
57
|
+
},
|
|
58
|
+
"require": {
|
|
59
|
+
"types": "./dist/components.d.cts",
|
|
60
|
+
"default": "./dist/components.cjs"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"./package.json": "./package.json"
|
|
64
|
+
},
|
|
65
|
+
"files": [
|
|
66
|
+
"dist/**/*.js",
|
|
67
|
+
"dist/**/*.cjs",
|
|
68
|
+
"dist/**/*.d.ts",
|
|
69
|
+
"dist/**/*.d.cts",
|
|
70
|
+
"dist/**/*.map",
|
|
71
|
+
"bin",
|
|
72
|
+
"scripts",
|
|
73
|
+
"skill",
|
|
74
|
+
"README.md",
|
|
75
|
+
"LICENSE"
|
|
76
|
+
],
|
|
77
|
+
"bin": {
|
|
78
|
+
"motion-presets-kit": "./bin/cli.mjs"
|
|
79
|
+
},
|
|
80
|
+
"sideEffects": false,
|
|
81
|
+
"scripts": {
|
|
82
|
+
"build": "tsup",
|
|
83
|
+
"dev": "tsup --watch",
|
|
84
|
+
"typecheck": "tsc --noEmit",
|
|
85
|
+
"test": "pnpm build && node --test --experimental-test-module-mocks \"test/**/*.test.mjs\"",
|
|
86
|
+
"lint": "biome check .",
|
|
87
|
+
"lint:fix": "biome check --write .",
|
|
88
|
+
"playground": "pnpm --filter playground dev",
|
|
89
|
+
"postinstall": "node ./scripts/postinstall.mjs",
|
|
90
|
+
"prepublishOnly": "pnpm typecheck && pnpm lint && pnpm test"
|
|
91
|
+
},
|
|
92
|
+
"peerDependencies": {
|
|
93
|
+
"motion": "^12.0.0",
|
|
94
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
95
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
96
|
+
"zod": "^4.0.0"
|
|
97
|
+
},
|
|
98
|
+
"devDependencies": {
|
|
99
|
+
"@biomejs/biome": "^2.2.4",
|
|
100
|
+
"@types/node": "^24.0.0",
|
|
101
|
+
"@types/react": "^18.3.0",
|
|
102
|
+
"@types/react-dom": "^18.3.0",
|
|
103
|
+
"motion": "^12.0.0",
|
|
104
|
+
"react": "^18.3.0",
|
|
105
|
+
"react-dom": "^18.3.0",
|
|
106
|
+
"tsup": "^8.5.0",
|
|
107
|
+
"typescript": "^5.8.0",
|
|
108
|
+
"zod": "^4.4.0"
|
|
109
|
+
},
|
|
110
|
+
"publishConfig": {
|
|
111
|
+
"access": "public",
|
|
112
|
+
"provenance": false
|
|
113
|
+
},
|
|
114
|
+
"engines": {
|
|
115
|
+
"node": ">=18"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { createInterface } from "node:readline";
|
|
4
|
+
import {
|
|
5
|
+
detectTargets,
|
|
6
|
+
installSkill,
|
|
7
|
+
PACKAGE_ROOT,
|
|
8
|
+
SKILL_NAME,
|
|
9
|
+
} from "../bin/skill.mjs";
|
|
10
|
+
|
|
11
|
+
const PROMPT_TIMEOUT_MS = 10_000;
|
|
12
|
+
|
|
13
|
+
function note(message) {
|
|
14
|
+
if (process.env.MOTION_PRESETS_KIT_DEBUG) {
|
|
15
|
+
console.log(`[${SKILL_NAME}] ${message}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function ask(question) {
|
|
20
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
21
|
+
return new Promise((resolveAnswer) => {
|
|
22
|
+
const timer = setTimeout(() => {
|
|
23
|
+
resolveAnswer("");
|
|
24
|
+
rl.close();
|
|
25
|
+
}, PROMPT_TIMEOUT_MS);
|
|
26
|
+
rl.question(question, (reply) => {
|
|
27
|
+
clearTimeout(timer);
|
|
28
|
+
resolveAnswer(reply.trim());
|
|
29
|
+
rl.close();
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function main() {
|
|
35
|
+
if (process.env.MOTION_PRESETS_KIT_SKIP_SKILL) {
|
|
36
|
+
return note("omitida por MOTION_PRESETS_KIT_SKIP_SKILL");
|
|
37
|
+
}
|
|
38
|
+
if (process.env.CI) return note("omitida en CI");
|
|
39
|
+
if (process.env.npm_config_global === "true") {
|
|
40
|
+
return note("omitida en instalación global");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const initCwd = process.env.INIT_CWD
|
|
44
|
+
? resolve(process.env.INIT_CWD)
|
|
45
|
+
: process.cwd();
|
|
46
|
+
if (initCwd === PACKAGE_ROOT) return note("omitida en el repo de la librería");
|
|
47
|
+
|
|
48
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
49
|
+
console.log(
|
|
50
|
+
`[${SKILL_NAME}] ¿Usas agentes de IA? Instala la skill con: npx motion-presets-kit add-skill`,
|
|
51
|
+
);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const answer = await ask(
|
|
56
|
+
`[${SKILL_NAME}] ¿Instalar la skill para tu agente de IA (opencode/Claude/agents)? [y/N] `,
|
|
57
|
+
);
|
|
58
|
+
if (!/^y(es)?$/i.test(answer)) {
|
|
59
|
+
console.log(
|
|
60
|
+
`[${SKILL_NAME}] Puedes instalarla después con: npx motion-presets-kit add-skill`,
|
|
61
|
+
);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const targets = detectTargets({ tool: "all" });
|
|
66
|
+
const results = installSkill(targets);
|
|
67
|
+
for (const result of results) {
|
|
68
|
+
const suffix = result.status === "exists" ? "ya existía" : "instalada";
|
|
69
|
+
console.log(`[${SKILL_NAME}] Skill ${suffix}: ${result.destination}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
main().catch((error) => {
|
|
74
|
+
note(`postinstall omitido: ${error instanceof Error ? error.message : error}`);
|
|
75
|
+
});
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: motion-presets-kit
|
|
3
|
+
description: Guía de uso de motion-presets-kit, presets y componentes de animación para motion/react (fade, slide, scale, clipReveal, parentVariants, TextAnimate, Marquee, Draggable, useCounter). Úsala siempre que escribas animaciones con motion-presets-kit para conocer la API, los valores por defecto y los patrones correctos.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# motion-presets-kit
|
|
7
|
+
|
|
8
|
+
Set tipado y validado en runtime (Zod) de helpers y presets para `motion/react`.
|
|
9
|
+
La API es **variant-returning**: funciones puras que devuelven `Variants`, no
|
|
10
|
+
componentes wrapper. También incluye componentes para casos complejos.
|
|
11
|
+
|
|
12
|
+
## Instalación
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm add motion-presets-kit motion zod react react-dom
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`motion`, `zod`, `react` y `react-dom` son **peer dependencies**. Compatible con
|
|
19
|
+
React 18+ / 19 y `motion` ^12.
|
|
20
|
+
|
|
21
|
+
## Entry points
|
|
22
|
+
|
|
23
|
+
| Import | Contenido |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `motion-presets-kit` | todo (presets + componentes + schemas) |
|
|
26
|
+
| `motion-presets-kit/presets` | `fade`, `slide`, `scale`, `clipReveal`, `parentVariants` |
|
|
27
|
+
| `motion-presets-kit/components` | `TextAnimate`, `Marquee`, `Draggable`, `useCounter` |
|
|
28
|
+
|
|
29
|
+
Importa desde el entry point más específico posible: cada preset es
|
|
30
|
+
tree-shakeable.
|
|
31
|
+
|
|
32
|
+
## Opciones comunes a todos los presets
|
|
33
|
+
|
|
34
|
+
| Opción | Default | Descripción |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `duration` | `0.5` | Segundos de la transición. |
|
|
37
|
+
| `delay` | `0` | Retardo en segundos. |
|
|
38
|
+
| `ease` | `[0.16, 1, 0.3, 1]` | Nombre, bezier de 4 números o función. |
|
|
39
|
+
| `spring` | — | Si se define, **sobrescribe** `duration` y `ease`. |
|
|
40
|
+
| `excludeDelay` | `false` | Omite el `delay` propio (para heredar el stagger del padre). |
|
|
41
|
+
| `reducedMotion` | `true` | Respeta `prefers-reduced-motion`. |
|
|
42
|
+
|
|
43
|
+
Uso:
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { motion } from "motion/react";
|
|
47
|
+
import { fade } from "motion-presets-kit/presets";
|
|
48
|
+
|
|
49
|
+
<motion.div variants={fade({ direction: "up" })} initial="initial" animate="animate">
|
|
50
|
+
Hola
|
|
51
|
+
</motion.div>;
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Presets
|
|
55
|
+
|
|
56
|
+
### `fade(options?)`
|
|
57
|
+
|
|
58
|
+
Fade de entrada con dirección, blur y escala opcionales.
|
|
59
|
+
Extras: `direction` (`"up" | "down" | "left" | "right" | "none"`, default `"up"`),
|
|
60
|
+
`distance` (`60`), `blur` (`0`, px), `scale` (`1`).
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
fade({ direction: "left", distance: 40, blur: 8, scale: 0.98 });
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `slide(options?)`
|
|
67
|
+
|
|
68
|
+
Desplazamiento puro **sin `opacity`**.
|
|
69
|
+
Extras: `direction` (default `"right"`), `distance` (`100`).
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
slide({ direction: "right" }); // initial { x: -100 } → animate { x: 0 }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### `scale(options?)`
|
|
76
|
+
|
|
77
|
+
Entrada con escala + opacidad: `from` → `1` y `opacity: 0 → 1`.
|
|
78
|
+
Extras: `from` (default `0.8`).
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
scale({ from: 0.5 });
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `clipReveal(options?)`
|
|
85
|
+
|
|
86
|
+
Reveal cinematográfico animando `clipPath` (con escala opcional).
|
|
87
|
+
Extras: `direction` (default `"up"`), `scale` (opcional, sin default).
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
clipReveal({ direction: "up", scale: 1.1 });
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `parentVariants(options?)`
|
|
94
|
+
|
|
95
|
+
Contenedor para animar hijos en cascada. Extras: `delayChildren` (`0`) y
|
|
96
|
+
`startDelay` (`0`).
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
<motion.div variants={parentVariants({ delayChildren: 0.12 })} initial="initial" animate="animate">
|
|
100
|
+
{items.map((item) => (
|
|
101
|
+
<motion.li key={item} variants={fade({ excludeDelay: true })}>
|
|
102
|
+
{item}
|
|
103
|
+
</motion.li>
|
|
104
|
+
))}
|
|
105
|
+
</motion.div>;
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Componentes y hooks
|
|
109
|
+
|
|
110
|
+
### `<TextAnimate>`
|
|
111
|
+
|
|
112
|
+
Anima texto por palabra o letra, preservando HTML inline, con resaltado.
|
|
113
|
+
|
|
114
|
+
- `text` (requerido, string; **acepta HTML inline**)
|
|
115
|
+
- `as` (tag intrínseco, default `"p"`)
|
|
116
|
+
- `by` (`"word" | "letter"`, default `"word"`)
|
|
117
|
+
- `type` (`"blurIn" | "slideUp" | "slideDown" | "slideLeft" | "slideRight" | "typeWriter"`, default `"slideUp"`)
|
|
118
|
+
- `duration` (`0.4`), `startDelay` (`0`)
|
|
119
|
+
- `highlight` (`string[]`), `highlightClassName` (`string`)
|
|
120
|
+
- `reducedMotion` (`true`)
|
|
121
|
+
- Usa `whileInView` con `viewport={{ once: true }}`.
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
<TextAnimate text="Hola <strong>mundo</strong>" by="letter" type="blurIn" highlight={["mundo"]} />
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Advertencia: el HTML inline se inyecta con `dangerouslySetInnerHTML`; sanitiza el
|
|
128
|
+
`text` si viene de input no confiable.
|
|
129
|
+
|
|
130
|
+
### `<Marquee>`
|
|
131
|
+
|
|
132
|
+
Scroll infinito en CSS puro (`@keyframes`), con children duplicados.
|
|
133
|
+
|
|
134
|
+
- `children` (requerido), `speed` (segundos/vuelta, default `20`; debe ser > 0)
|
|
135
|
+
- `direction` (`"left" | "right"`, default `"left"`)
|
|
136
|
+
- `pauseOnHover` (`true`), `gap` (default `"2rem"`)
|
|
137
|
+
- `reducedMotion` (`true`)
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
<Marquee speed={30} direction="right" gap="1.5rem">
|
|
141
|
+
<span>Logo 1</span>
|
|
142
|
+
<span>Logo 2</span>
|
|
143
|
+
</Marquee>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### `<Draggable>`
|
|
147
|
+
|
|
148
|
+
Wrapper de `motion.div` con drag configurable.
|
|
149
|
+
|
|
150
|
+
- `axis` (`"x" | "y" | "both"`, default `"both"`)
|
|
151
|
+
- `bounds` (`"parent" | "document" | { top, right, bottom, left }`)
|
|
152
|
+
- `snapToGrid: [number, number]`
|
|
153
|
+
- `dragElastic`, `dragMomentum`, `dragControls`
|
|
154
|
+
- `onDragStart` / `onDrag` / `onDragEnd`
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
<Draggable axis="x" bounds="parent" snapToGrid={[20, 20]}>
|
|
158
|
+
<div>Arrastrame</div>
|
|
159
|
+
</Draggable>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Con `bounds="parent"` el elemento se restringe a su contenedor; el contenedor
|
|
163
|
+
debe poder medirse (normalmente `position: relative`).
|
|
164
|
+
|
|
165
|
+
### `useCounter(ref, options?)`
|
|
166
|
+
|
|
167
|
+
Contador animado que escribe el valor formateado en `ref.current.textContent` y
|
|
168
|
+
expone el valor actual de forma reactiva.
|
|
169
|
+
|
|
170
|
+
- `from` (`0`), `to` (`100`), `decimals` (`0`)
|
|
171
|
+
- `prefix`, `suffix`, `separator` (`","`)
|
|
172
|
+
- `format: (value: number) => string` (sobrescribe el formateo)
|
|
173
|
+
- `duration` (`1`), `reducedMotion` (`true`)
|
|
174
|
+
- Devuelve `{ value, start, reset }`.
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
const ref = useRef<HTMLSpanElement>(null);
|
|
178
|
+
const { start, reset } = useCounter(ref, { to: 1250, suffix: " px" });
|
|
179
|
+
return (
|
|
180
|
+
<>
|
|
181
|
+
<span ref={ref} />
|
|
182
|
+
<button onClick={start}>Start</button>
|
|
183
|
+
<button onClick={reset}>Reset</button>
|
|
184
|
+
</>
|
|
185
|
+
);
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Reducción de movimiento
|
|
189
|
+
|
|
190
|
+
Todos los presets aceptan `reducedMotion` (default `true`). Con
|
|
191
|
+
`prefers-reduced-motion: reduce` activo:
|
|
192
|
+
|
|
193
|
+
- Los presets devuelven `initial === animate` con el estado final.
|
|
194
|
+
- `TextAnimate` muestra el texto sin animar.
|
|
195
|
+
- `Marquee` no reproduce el loop.
|
|
196
|
+
- `useCounter` muestra el valor final directamente.
|
|
197
|
+
|
|
198
|
+
En SSR/servidor `reducedMotion` se evalúa como `false` (no hay `window`), por lo
|
|
199
|
+
que los presets devuelven variants estáticas y no rompen el render.
|
|
200
|
+
|
|
201
|
+
## Errores comunes
|
|
202
|
+
|
|
203
|
+
- **Olvidar `initial`/`animate`**: los presets devuelven `Variants`; el elemento
|
|
204
|
+
`motion.*` debe declarar `initial="initial"` y `animate="animate"` (o
|
|
205
|
+
`whileInView="animate"`).
|
|
206
|
+
- **Stagger que no funciona**: los hijos dentro de `parentVariants()` deben usar
|
|
207
|
+
`excludeDelay: true`, si no su `delay` propio sobrescribe el del padre (CL-001).
|
|
208
|
+
- **`slide` no desvanece**: es intencional, `slide` no incluye `opacity`.
|
|
209
|
+
- **`bounds="parent"` sin contenedor posicionado**: el padre debe existir y
|
|
210
|
+
poder medirse; usa `position: relative`.
|
|
211
|
+
- **Opciones inválidas**: no lanzan; se emite un `warn()` con prefijo
|
|
212
|
+
`[motion-presets-kit]` y se usan los valores por defecto.
|
|
213
|
+
- **`format`/`ease`/`spring` inválidos**: Zod los valida en runtime; si no son
|
|
214
|
+
válidos se avisa y se usan los defaults.
|
|
215
|
+
|
|
216
|
+
## Referencia rápida
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
import { fade, slide, scale, clipReveal, parentVariants } from "motion-presets-kit/presets";
|
|
220
|
+
import { TextAnimate, Marquee, Draggable, useCounter } from "motion-presets-kit/components";
|
|
221
|
+
```
|