├── .config ├── eslint.config.js └── prettier.config.js ├── .editorconfig ├── .gitattributes ├── .github ├── codeowners └── release.yml ├── .gitignore ├── .prettierignore ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── bundler.config.ts ├── docs ├── README.md ├── club-plugins │ └── README.md ├── extra-eases │ └── README.md ├── extra-plugins │ └── README.md ├── options │ └── README.md ├── register-eases │ └── README.md └── register-effects │ └── README.md ├── package-lock.json ├── package.json ├── playground ├── components │ └── NavMain.vue ├── layouts │ └── default.vue ├── nuxt.config.ts ├── package.json └── pages │ ├── about │ └── index.vue │ └── index.vue ├── src ├── meta.ts ├── module.ts ├── types │ ├── module.ts │ └── options │ │ ├── club-plugins.ts │ │ ├── extra-eases.ts │ │ ├── extra-plugins.ts │ │ └── index.ts └── utils │ ├── serialize.ts │ └── templates.ts └── tsconfig.json /.config/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { jsConfig, tsConfig, ignores } from '@hypernym/eslint-config' 2 | 3 | export default [ 4 | jsConfig, 5 | tsConfig, 6 | { 7 | files: tsConfig.files, 8 | rules: { 9 | '@typescript-eslint/no-explicit-any': 'off', 10 | '@typescript-eslint/no-unused-vars': [ 11 | 'error', 12 | { ignoreRestSiblings: true }, 13 | ], 14 | }, 15 | }, 16 | { 17 | ignores: [...ignores, '**/.nuxt/**/*'], 18 | }, 19 | ] 20 | -------------------------------------------------------------------------------- /.config/prettier.config.js: -------------------------------------------------------------------------------- 1 | export { default } from '@hypernym/prettier-config' 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = 0 13 | trim_trailing_whitespace = false 14 | 15 | [COMMIT_EDITMSG] 16 | max_line_length = 0 17 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-vendored 2 | *.ts linguist-vendored=false 3 | -------------------------------------------------------------------------------- /.github/codeowners: -------------------------------------------------------------------------------- 1 | * @ivodolenc 2 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | categories: 3 | - title: Bug Fixes 4 | labels: 5 | - fix 6 | - title: New Features 7 | labels: 8 | - feat 9 | - title: Types 10 | labels: 11 | - types 12 | - title: Tests 13 | labels: 14 | - test 15 | - title: Documentation 16 | labels: 17 | - docs 18 | - title: Breaking Changes 19 | labels: 20 | - breaking-change 21 | - title: Other Changes 22 | labels: 23 | - '*' 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .private 4 | *.log* 5 | .nuxt 6 | .output 7 | .cache 8 | .env 9 | .npmrc 10 | dist 11 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *-lock.* 4 | *.lock 5 | *.log* 6 | *.min.* 7 | *.d.ts 8 | .git 9 | .private 10 | .cache 11 | .nuxt 12 | .output 13 | .env* 14 | output 15 | out 16 | coverage 17 | temp 18 | cache 19 | dist 20 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "esbenp.prettier-vscode", 5 | "EditorConfig.EditorConfig" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.formatOnSave": true, 4 | "eslint.options": { 5 | "overrideConfigFile": ".config/eslint.config.js" 6 | }, 7 | "prettier.configPath": ".config/prettier.config.js" 8 | } 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # What's New 2 | 3 | Check out the latest features and improvements. 4 | 5 | #### [Release Notes](https://github.com/hypernym-studio/nuxt-gsap/releases) 6 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Ivo Dolenc, Hypernym Studio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nuxt Gsap Module 2 | 3 | GSAP module for Nuxt. 4 | 5 | ## Features 6 | 7 | - Helps you integrate the GSAP animation library 8 | - Provides a solution for global use 9 | - Supports custom composables 10 | - Automatically registers plugins after activation 11 | - Allows you to easily register global effects & eases 12 | - Supports Club GreenSock premium plugins 13 | - Zero-config setup ready to go 14 | - TypeScript friendly 15 | - Super easy to use 16 | 17 | ## Quick Start 18 | 19 | 1. Install `@hypernym/nuxt-gsap` to your project 20 | 21 | ```sh 22 | npm i -D @hypernym/nuxt-gsap 23 | ``` 24 | 25 | 2. Enable the module in the main config file 26 | 27 | ```ts 28 | // nuxt.config.ts 29 | 30 | { 31 | modules: ['@hypernym/nuxt-gsap'] 32 | } 33 | ``` 34 | 35 | That's it! 36 | 37 | ## Module 38 | 39 | The module comes with a zero-config setup so after activation it automatically adds the GSAP core and it is globally available without additional settings. 40 | 41 | ```html 42 | 43 | 44 | 49 | 50 | 57 | ``` 58 | 59 | ## Options 60 | 61 | Nuxt Gsap Module is completely rewritten in TypeScript. It also improves the development experience with detailed descriptions, examples and code auto-completion. 62 | 63 | After plugin activation, it is immediately available globally, so there is no need to manually import or register. 64 | 65 | ```ts 66 | // nuxt.config.ts 67 | 68 | { 69 | modules: ['@hypernym/nuxt-gsap'], 70 | 71 | gsap: { 72 | // Module options 73 | } 74 | } 75 | ``` 76 | 77 | ## GSAP Core 78 | 79 | It can be used via a `provide` helper that will be available globally or via a custom `composable` that you can import where you need it. 80 | 81 | ### Provide 82 | 83 | GSAP core is enabled by default on module activation. 84 | 85 | ```ts 86 | // nuxt.config.ts 87 | 88 | { 89 | modules: ['@hypernym/nuxt-gsap'], 90 | } 91 | ``` 92 | 93 | **Available globally** 94 | 95 | ```html 96 | 103 | ``` 104 | 105 | To disable the _provide_ helper completely, set it to `false`. 106 | 107 | ```ts 108 | // nuxt.config.ts 109 | 110 | { 111 | gsap: { 112 | provide: false 113 | } 114 | } 115 | ``` 116 | 117 | ### Composable 118 | 119 | Imports the main `gsap` core as custom composable. 120 | 121 | To enable custom [_composables_](#composables), set it to `true`: 122 | 123 | ```ts 124 | // nuxt.config.ts 125 | 126 | { 127 | gsap: { 128 | composables: true 129 | } 130 | } 131 | ``` 132 | 133 | #### useGsap 134 | 135 | - Custom composable 136 | 137 | ```html 138 | 139 | 140 | 143 | 144 | 147 | ``` 148 | 149 | ```ts 150 | // Explicit import (optional) 151 | import { useGsap } from '#gsap' 152 | ``` 153 | 154 | ## Documentation 155 | 156 | Check the official [docs](./docs) for more info. 157 | 158 | ## Community 159 | 160 | Feel free to use the official [discussions](https://github.com/hypernym-studio/nuxt-gsap/discussions) for any additional questions. 161 | 162 | ## License 163 | 164 | ### Gsap Platform 165 | 166 | More details about GSAP licenses can be found in the official repository. 167 | 168 | ### Nuxt Gsap Module 169 | 170 | Developed in 🇭🇷 Croatia 171 | 172 | Released under the [MIT](LICENSE.txt) license. 173 | 174 | © Hypernym Studio 175 | -------------------------------------------------------------------------------- /bundler.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@hypernym/bundler' 2 | import { name, version } from './package.json' 3 | import { nuxtMetaTemplate, nuxtTypesTemplate } from './src/utils/templates.js' 4 | 5 | export default defineConfig({ 6 | entries: [ 7 | { 8 | input: './src/module.ts', 9 | externals: [/^@nuxt/], 10 | plugins: { 11 | replace: { 12 | preventAssignment: true, 13 | __name__: name, 14 | __version__: version, 15 | }, 16 | }, 17 | }, 18 | { 19 | types: './src/types/module.ts', 20 | output: './dist/module.d.ts', 21 | }, 22 | { 23 | template: true, 24 | output: './dist/module.json', 25 | content: nuxtMetaTemplate(), 26 | format: 'json', 27 | }, 28 | { 29 | template: true, 30 | output: './dist/types.d.ts', 31 | content: nuxtTypesTemplate(), 32 | format: 'dts', 33 | }, 34 | ], 35 | }) 36 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | - [Module Options](./options) 4 | - [Extra Plugins](./extra-plugins) 5 | - [Extra Eases](./extra-eases) 6 | - [Club Plugins](./club-plugins) 7 | - [Register Effects](./register-effects) 8 | - [Register Eases](./register-eases) 9 | -------------------------------------------------------------------------------- /docs/club-plugins/README.md: -------------------------------------------------------------------------------- 1 | # Club Plugins 2 | 3 | - Type: `object` 4 | - Default: `undefined` 5 | 6 | Specifies GSAP premium plugins. 7 | 8 | This is only available to club members as it requires a paid license. 9 | 10 | Keep in mind that premium plugins must be installed according to the official GSAP guidelines before use. 11 | 12 | For more information about club plugins, check the official pages. 13 | 14 | ## DrawSvg 15 | 16 | - Type: `boolean` 17 | - Default: `undefined` 18 | 19 | ```ts 20 | // nuxt.config.ts 21 | 22 | { 23 | gsap: { 24 | clubPlugins: { 25 | drawSvg: true 26 | } 27 | } 28 | } 29 | ``` 30 | 31 | **Available globally** 32 | 33 | ```ts 34 | const { $DrawSVGPlugin } = useNuxtApp() 35 | ``` 36 | 37 | ## useDrawSVGPlugin 38 | 39 | - Custom composable 40 | 41 | ```ts 42 | // nuxt.config.ts 43 | 44 | { 45 | gsap: { 46 | composables: true, 47 | clubPlugins: { 48 | drawSvg: true 49 | } 50 | } 51 | } 52 | ``` 53 | 54 | **Usage** 55 | 56 | ```ts 57 | useDrawSVGPlugin 58 | ``` 59 | 60 | ```ts 61 | // Explicit import (optional) 62 | import { useDrawSVGPlugin } from '#gsap' 63 | ``` 64 | 65 | ## ScrollSmoother 66 | 67 | - Type: `boolean` 68 | - Default: `undefined` 69 | 70 | ```ts 71 | // nuxt.config.ts 72 | 73 | { 74 | gsap: { 75 | clubPlugins: { 76 | scrollSmoother: true 77 | } 78 | } 79 | } 80 | ``` 81 | 82 | **Available globally** 83 | 84 | ```ts 85 | const { $ScrollSmoother } = useNuxtApp() 86 | ``` 87 | 88 | ## useScrollSmoother 89 | 90 | - Custom composable 91 | 92 | ```ts 93 | // nuxt.config.ts 94 | 95 | { 96 | gsap: { 97 | composables: true, 98 | clubPlugins: { 99 | scrollSmoother: true 100 | } 101 | } 102 | } 103 | ``` 104 | 105 | **Usage** 106 | 107 | ```ts 108 | useScrollSmoother 109 | ``` 110 | 111 | ```ts 112 | // Explicit import (optional) 113 | import { useScrollSmoother } from '#gsap' 114 | ``` 115 | 116 | ## GsDevTools 117 | 118 | - Type: `boolean` 119 | - Default: `undefined` 120 | 121 | ```ts 122 | // nuxt.config.ts 123 | 124 | { 125 | gsap: { 126 | clubPlugins: { 127 | gsDevTools: true 128 | } 129 | } 130 | } 131 | ``` 132 | 133 | **Available globally** 134 | 135 | ```ts 136 | const { $GSDevTools } = useNuxtApp() 137 | ``` 138 | 139 | ## useGSDevTools 140 | 141 | - Custom composable 142 | 143 | ```ts 144 | // nuxt.config.ts 145 | 146 | { 147 | gsap: { 148 | composables: true, 149 | clubPlugins: { 150 | gsDevTools: true 151 | } 152 | } 153 | } 154 | ``` 155 | 156 | **Usage** 157 | 158 | ```ts 159 | useGSDevTools 160 | ``` 161 | 162 | ```ts 163 | // Explicit import (optional) 164 | import { useGSDevTools } from '#gsap' 165 | ``` 166 | 167 | ## Inertia 168 | 169 | - Type: `boolean` 170 | - Default: `undefined` 171 | 172 | ```ts 173 | // nuxt.config.ts 174 | 175 | { 176 | gsap: { 177 | clubPlugins: { 178 | inertia: true 179 | } 180 | } 181 | } 182 | ``` 183 | 184 | **Available globally** 185 | 186 | ```ts 187 | const { $InertiaPlugin } = useNuxtApp() 188 | ``` 189 | 190 | ## useInertiaPlugin 191 | 192 | - Custom composable 193 | 194 | ```ts 195 | // nuxt.config.ts 196 | 197 | { 198 | gsap: { 199 | composables: true, 200 | clubPlugins: { 201 | inertia: true 202 | } 203 | } 204 | } 205 | ``` 206 | 207 | **Usage** 208 | 209 | ```ts 210 | useInertiaPlugin 211 | ``` 212 | 213 | ```ts 214 | // Explicit import (optional) 215 | import { useInertiaPlugin } from '#gsap' 216 | ``` 217 | 218 | ## MorphSvg 219 | 220 | - Type: `boolean` 221 | - Default: `undefined` 222 | 223 | ```ts 224 | // nuxt.config.ts 225 | 226 | { 227 | gsap: { 228 | clubPlugins: { 229 | morphSvg: true 230 | } 231 | } 232 | } 233 | ``` 234 | 235 | **Available globally** 236 | 237 | ```ts 238 | const { $MorphSVGPlugin } = useNuxtApp() 239 | ``` 240 | 241 | ## useMorphSVGPlugin 242 | 243 | - Custom composable 244 | 245 | ```ts 246 | // nuxt.config.ts 247 | 248 | { 249 | gsap: { 250 | composables: true, 251 | clubPlugins: { 252 | morphSvg: true 253 | } 254 | } 255 | } 256 | ``` 257 | 258 | **Usage** 259 | 260 | ```ts 261 | useMorphSVGPlugin 262 | ``` 263 | 264 | ```ts 265 | // Explicit import (optional) 266 | import { useMorphSVGPlugin } from '#gsap' 267 | ``` 268 | 269 | ## MotionPathHelper 270 | 271 | - Type: `boolean` 272 | - Default: `undefined` 273 | 274 | ```ts 275 | // nuxt.config.ts 276 | 277 | { 278 | gsap: { 279 | clubPlugins: { 280 | motionPathHelper: true 281 | } 282 | } 283 | } 284 | ``` 285 | 286 | **Available globally** 287 | 288 | ```ts 289 | const { $MotionPathHelper } = useNuxtApp() 290 | ``` 291 | 292 | ## useMotionPathHelper 293 | 294 | - Custom composable 295 | 296 | ```ts 297 | // nuxt.config.ts 298 | 299 | { 300 | gsap: { 301 | composables: true, 302 | clubPlugins: { 303 | motionPathHelper: true 304 | } 305 | } 306 | } 307 | ``` 308 | 309 | **Usage** 310 | 311 | ```ts 312 | useMotionPathHelper 313 | ``` 314 | 315 | ```ts 316 | // Explicit import (optional) 317 | import { useMotionPathHelper } from '#gsap' 318 | ``` 319 | 320 | ## Physics2d 321 | 322 | - Type: `boolean` 323 | - Default: `undefined` 324 | 325 | ```ts 326 | // nuxt.config.ts 327 | 328 | { 329 | gsap: { 330 | clubPlugins: { 331 | physics2d: true 332 | } 333 | } 334 | } 335 | ``` 336 | 337 | **Available globally** 338 | 339 | ```ts 340 | const { $Physics2DPlugin } = useNuxtApp() 341 | ``` 342 | 343 | ## usePhysics2DPlugin 344 | 345 | - Custom composable 346 | 347 | ```ts 348 | // nuxt.config.ts 349 | 350 | { 351 | gsap: { 352 | composables: true, 353 | clubPlugins: { 354 | physics2d: true 355 | } 356 | } 357 | } 358 | ``` 359 | 360 | **Usage** 361 | 362 | ```ts 363 | usePhysics2DPlugin 364 | ``` 365 | 366 | ```ts 367 | // Explicit import (optional) 368 | import { usePhysics2DPlugin } from '#gsap' 369 | ``` 370 | 371 | ## PhysicsProps 372 | 373 | - Type: `boolean` 374 | - Default: `undefined` 375 | 376 | ```ts 377 | // nuxt.config.ts 378 | 379 | { 380 | gsap: { 381 | clubPlugins: { 382 | physicsProps: true 383 | } 384 | } 385 | } 386 | ``` 387 | 388 | **Available globally** 389 | 390 | ```ts 391 | const { $PhysicsPropsPlugin } = useNuxtApp() 392 | ``` 393 | 394 | ## usePhysicsPropsPlugin 395 | 396 | - Custom composable 397 | 398 | ```ts 399 | // nuxt.config.ts 400 | 401 | { 402 | gsap: { 403 | composables: true, 404 | clubPlugins: { 405 | physicsProps: true 406 | } 407 | } 408 | } 409 | ``` 410 | 411 | **Usage** 412 | 413 | ```ts 414 | usePhysicsPropsPlugin 415 | ``` 416 | 417 | ```ts 418 | // Explicit import (optional) 419 | import { usePhysicsPropsPlugin } from '#gsap' 420 | ``` 421 | 422 | ## ScrambleText 423 | 424 | - Type: `boolean` 425 | - Default: `undefined` 426 | 427 | ```ts 428 | // nuxt.config.ts 429 | 430 | { 431 | gsap: { 432 | clubPlugins: { 433 | scrambleText: true 434 | } 435 | } 436 | } 437 | ``` 438 | 439 | **Available globally** 440 | 441 | ```ts 442 | const { $ScrambleText } = useNuxtApp() 443 | ``` 444 | 445 | ## useScrambleText 446 | 447 | - Custom composable 448 | 449 | ```ts 450 | // nuxt.config.ts 451 | 452 | { 453 | gsap: { 454 | composables: true, 455 | clubPlugins: { 456 | scrambleText: true 457 | } 458 | } 459 | } 460 | ``` 461 | 462 | **Usage** 463 | 464 | ```ts 465 | useScrambleText 466 | ``` 467 | 468 | ```ts 469 | // Explicit import (optional) 470 | import { useScrambleText } from '#gsap' 471 | ``` 472 | 473 | ## SplitText 474 | 475 | - Type: `boolean` 476 | - Default: `undefined` 477 | 478 | ```ts 479 | // nuxt.config.ts 480 | 481 | { 482 | gsap: { 483 | clubPlugins: { 484 | splitText: true 485 | } 486 | } 487 | } 488 | ``` 489 | 490 | **Available globally** 491 | 492 | ```ts 493 | const { $SplitText } = useNuxtApp() 494 | ``` 495 | 496 | ## useSplitText 497 | 498 | - Custom composable 499 | 500 | ```ts 501 | // nuxt.config.ts 502 | 503 | { 504 | gsap: { 505 | composables: true, 506 | clubPlugins: { 507 | splitText: true 508 | } 509 | } 510 | } 511 | ``` 512 | 513 | **Usage** 514 | 515 | ```ts 516 | useSplitText 517 | ``` 518 | 519 | ```ts 520 | // Explicit import (optional) 521 | import { useSplitText } from '#gsap' 522 | ``` 523 | 524 | ## CustomBounce 525 | 526 | - Type: `boolean` 527 | - Default: `undefined` 528 | 529 | ```ts 530 | // nuxt.config.ts 531 | 532 | { 533 | gsap: { 534 | clubPlugins: { 535 | customBounce: true 536 | } 537 | } 538 | } 539 | ``` 540 | 541 | **Available globally** 542 | 543 | ```ts 544 | const { $CustomBounce } = useNuxtApp() 545 | ``` 546 | 547 | ## useCustomBounce 548 | 549 | - Custom composable 550 | 551 | ```ts 552 | // nuxt.config.ts 553 | 554 | { 555 | gsap: { 556 | composables: true, 557 | clubPlugins: { 558 | customBounce: true 559 | } 560 | } 561 | } 562 | ``` 563 | 564 | **Usage** 565 | 566 | ```ts 567 | useCustomBounce 568 | ``` 569 | 570 | ```ts 571 | // Explicit import (optional) 572 | import { useCustomBounce } from '#gsap' 573 | ``` 574 | 575 | ## CustomWiggle 576 | 577 | - Type: `boolean` 578 | - Default: `undefined` 579 | 580 | ```ts 581 | // nuxt.config.ts 582 | 583 | { 584 | gsap: { 585 | clubPlugins: { 586 | customWiggle: true 587 | } 588 | } 589 | } 590 | ``` 591 | 592 | **Available globally** 593 | 594 | ```ts 595 | const { $CustomWiggle } = useNuxtApp() 596 | ``` 597 | 598 | ## useCustomWiggle 599 | 600 | - Custom composable 601 | 602 | ```ts 603 | // nuxt.config.ts 604 | 605 | { 606 | gsap: { 607 | composables: true, 608 | clubPlugins: { 609 | customWiggle: true 610 | } 611 | } 612 | } 613 | ``` 614 | 615 | **Usage** 616 | 617 | ```ts 618 | useCustomWiggle 619 | ``` 620 | 621 | ```ts 622 | // Explicit import (optional) 623 | import { useCustomWiggle } from '#gsap' 624 | ``` 625 | -------------------------------------------------------------------------------- /docs/extra-eases/README.md: -------------------------------------------------------------------------------- 1 | # Extra Eases 2 | 3 | - Type: `object` 4 | - Default: `undefined` 5 | 6 | Specifies GSAP extra eases. 7 | 8 | ## ExpoScale 9 | 10 | - Type: `boolean` 11 | - Default: `undefined` 12 | 13 | ```ts 14 | // nuxt.config.ts 15 | 16 | { 17 | gsap: { 18 | extraEases: { 19 | expoScale: true 20 | } 21 | } 22 | } 23 | ``` 24 | 25 | **Available globally** 26 | 27 | ```ts 28 | const { $ExpoScaleEase } = useNuxtApp() 29 | ``` 30 | 31 | ## useExpoScaleEase 32 | 33 | - Custom composable 34 | 35 | ```ts 36 | // nuxt.config.ts 37 | 38 | { 39 | gsap: { 40 | composables: true, 41 | extraEases: { 42 | expoScale: true 43 | } 44 | } 45 | } 46 | ``` 47 | 48 | **Usage** 49 | 50 | ```ts 51 | useExpoScaleEase 52 | ``` 53 | 54 | ```ts 55 | // Explicit import (optional) 56 | import { useExpoScaleEase } from '#gsap' 57 | ``` 58 | 59 | ## Rough 60 | 61 | - Type: `boolean` 62 | - Default: `undefined` 63 | 64 | ```ts 65 | // nuxt.config.ts 66 | 67 | { 68 | gsap: { 69 | extraEases: { 70 | rough: true 71 | } 72 | } 73 | } 74 | ``` 75 | 76 | **Available globally** 77 | 78 | ```ts 79 | const { $RoughEase } = useNuxtApp() 80 | ``` 81 | 82 | ## useRoughEase 83 | 84 | - Custom composable 85 | 86 | ```ts 87 | // nuxt.config.ts 88 | 89 | { 90 | gsap: { 91 | composables: true, 92 | extraEases: { 93 | rough: true 94 | } 95 | } 96 | } 97 | ``` 98 | 99 | **Usage** 100 | 101 | ```ts 102 | useRoughEase 103 | ``` 104 | 105 | ```ts 106 | // Explicit import (optional) 107 | import { useRoughEase } from '#gsap' 108 | ``` 109 | 110 | ## SlowMo 111 | 112 | - Type: `boolean` 113 | - Default: `undefined` 114 | 115 | ```ts 116 | // nuxt.config.ts 117 | 118 | { 119 | gsap: { 120 | extraEases: { 121 | slowMo: true 122 | } 123 | } 124 | } 125 | ``` 126 | 127 | **Available globally** 128 | 129 | ```ts 130 | const { $SlowMo } = useNuxtApp() 131 | ``` 132 | 133 | ## useSlowMo 134 | 135 | - Custom composable 136 | 137 | ```ts 138 | // nuxt.config.ts 139 | 140 | { 141 | gsap: { 142 | composables: true, 143 | extraEases: { 144 | slowMo: true 145 | } 146 | } 147 | } 148 | ``` 149 | 150 | **Usage** 151 | 152 | ```ts 153 | useSlowMo 154 | ``` 155 | 156 | ```ts 157 | // Explicit import (optional) 158 | import { useSlowMo } from '#gsap' 159 | ``` 160 | 161 | ## Custom 162 | 163 | - Type: `boolean` 164 | - Default: `undefined` 165 | 166 | ```ts 167 | // nuxt.config.ts 168 | 169 | { 170 | gsap: { 171 | extraEases: { 172 | custom: true 173 | } 174 | } 175 | } 176 | ``` 177 | 178 | **Available globally** 179 | 180 | ```ts 181 | const { $CustomEase } = useNuxtApp() 182 | ``` 183 | 184 | ## useCustomEase 185 | 186 | - Custom composable 187 | 188 | ```ts 189 | // nuxt.config.ts 190 | 191 | { 192 | gsap: { 193 | composables: true, 194 | extraEases: { 195 | custom: true 196 | } 197 | } 198 | } 199 | ``` 200 | 201 | **Usage** 202 | 203 | ```ts 204 | useCustomEase 205 | ``` 206 | 207 | ```ts 208 | // Explicit import (optional) 209 | import { useCustomEase } from '#gsap' 210 | ``` 211 | -------------------------------------------------------------------------------- /docs/extra-plugins/README.md: -------------------------------------------------------------------------------- 1 | # Extra Plugins 2 | 3 | - Type: `object` 4 | - Default: `undefined` 5 | 6 | Specifies GSAP extra plugins. 7 | 8 | ## Flip 9 | 10 | - Type: `boolean` 11 | - Default: `undefined` 12 | 13 | ```ts 14 | // nuxt.config.ts 15 | 16 | { 17 | gsap: { 18 | extraPlugins: { 19 | flip: true 20 | } 21 | } 22 | } 23 | ``` 24 | 25 | **Available globally** 26 | 27 | ```ts 28 | const { $Flip } = useNuxtApp() 29 | ``` 30 | 31 | ## useFlip 32 | 33 | - Custom composable 34 | 35 | ```ts 36 | // nuxt.config.ts 37 | 38 | { 39 | gsap: { 40 | composables: true, 41 | extraPlugins: { 42 | flip: true 43 | } 44 | } 45 | } 46 | ``` 47 | 48 | **Usage** 49 | 50 | ```ts 51 | useFlip 52 | ``` 53 | 54 | ```ts 55 | // Explicit import (optional) 56 | import { useFlip } from '#gsap' 57 | ``` 58 | 59 | ## ScrollTrigger 60 | 61 | - Type: `boolean` 62 | - Default: `undefined` 63 | 64 | ```ts 65 | // nuxt.config.ts 66 | 67 | { 68 | gsap: { 69 | extraPlugins: { 70 | scrollTrigger: true 71 | } 72 | } 73 | } 74 | ``` 75 | 76 | **Available globally** 77 | 78 | ```ts 79 | const { $ScrollTrigger } = useNuxtApp() 80 | ``` 81 | 82 | ## useScrollTrigger 83 | 84 | - Custom composable 85 | 86 | ```ts 87 | // nuxt.config.ts 88 | 89 | { 90 | gsap: { 91 | composables: true, 92 | extraPlugins: { 93 | scrollTrigger: true 94 | } 95 | } 96 | } 97 | ``` 98 | 99 | **Usage** 100 | 101 | ```ts 102 | useScrollTrigger 103 | ``` 104 | 105 | ```ts 106 | // Explicit import (optional) 107 | import { useScrollTrigger } from '#gsap' 108 | ``` 109 | 110 | ## Observer 111 | 112 | - Type: `boolean` 113 | - Default: `undefined` 114 | 115 | ```ts 116 | // nuxt.config.ts 117 | 118 | { 119 | gsap: { 120 | extraPlugins: { 121 | observer: true 122 | } 123 | } 124 | } 125 | ``` 126 | 127 | **Available globally** 128 | 129 | ```ts 130 | const { $Observer } = useNuxtApp() 131 | ``` 132 | 133 | ## useObserver 134 | 135 | - Custom composable 136 | 137 | ```ts 138 | // nuxt.config.ts 139 | 140 | { 141 | gsap: { 142 | composables: true, 143 | extraPlugins: { 144 | observer: true 145 | } 146 | } 147 | } 148 | ``` 149 | 150 | **Usage** 151 | 152 | ```ts 153 | useObserver 154 | ``` 155 | 156 | ```ts 157 | // Explicit import (optional) 158 | import { useObserver } from '#gsap' 159 | ``` 160 | 161 | ## ScrollTo 162 | 163 | - Type: `boolean` 164 | - Default: `undefined` 165 | 166 | ```ts 167 | // nuxt.config.ts 168 | 169 | { 170 | gsap: { 171 | extraPlugins: { 172 | scrollTo: true 173 | } 174 | } 175 | } 176 | ``` 177 | 178 | **Available globally** 179 | 180 | ```ts 181 | const { $ScrollToPlugin } = useNuxtApp() 182 | ``` 183 | 184 | ## useScrollToPlugin 185 | 186 | - Custom composable 187 | 188 | ```ts 189 | // nuxt.config.ts 190 | 191 | { 192 | gsap: { 193 | composables: true, 194 | extraPlugins: { 195 | scrollTo: true 196 | } 197 | } 198 | } 199 | ``` 200 | 201 | **Usage** 202 | 203 | ```ts 204 | useScrollToPlugin 205 | ``` 206 | 207 | ```ts 208 | // Explicit import (optional) 209 | import { useScrollToPlugin } from '#gsap' 210 | ``` 211 | 212 | ## Draggable 213 | 214 | - Type: `boolean` 215 | - Default: `undefined` 216 | 217 | ```ts 218 | // nuxt.config.ts 219 | 220 | { 221 | gsap: { 222 | extraPlugins: { 223 | draggable: true 224 | } 225 | } 226 | } 227 | ``` 228 | 229 | **Available globally** 230 | 231 | ```ts 232 | const { $Draggable } = useNuxtApp() 233 | ``` 234 | 235 | ## useDraggable 236 | 237 | - Custom composable 238 | 239 | ```ts 240 | // nuxt.config.ts 241 | 242 | { 243 | gsap: { 244 | composables: true, 245 | extraPlugins: { 246 | draggable: true 247 | } 248 | } 249 | } 250 | ``` 251 | 252 | **Usage** 253 | 254 | ```ts 255 | useDraggable 256 | ``` 257 | 258 | ```ts 259 | // Explicit import (optional) 260 | import { useDraggable } from '#gsap' 261 | ``` 262 | 263 | ## Easel 264 | 265 | - Type: `boolean` 266 | - Default: `undefined` 267 | 268 | ```ts 269 | // nuxt.config.ts 270 | 271 | { 272 | gsap: { 273 | extraPlugins: { 274 | easel: true 275 | } 276 | } 277 | } 278 | ``` 279 | 280 | **Available globally** 281 | 282 | ```ts 283 | const { $EaselPlugin } = useNuxtApp() 284 | ``` 285 | 286 | ## useEaselPlugin 287 | 288 | - Custom composable 289 | 290 | ```ts 291 | // nuxt.config.ts 292 | 293 | { 294 | gsap: { 295 | composables: true, 296 | extraPlugins: { 297 | easel: true 298 | } 299 | } 300 | } 301 | ``` 302 | 303 | **Usage** 304 | 305 | ```ts 306 | useEaselPlugin 307 | ``` 308 | 309 | ```ts 310 | // Explicit import (optional) 311 | import { useEaselPlugin } from '#gsap' 312 | ``` 313 | 314 | ## MotionPath 315 | 316 | - Type: `boolean` 317 | - Default: `undefined` 318 | 319 | ```ts 320 | // nuxt.config.ts 321 | 322 | { 323 | gsap: { 324 | extraPlugins: { 325 | motionPath: true 326 | } 327 | } 328 | } 329 | ``` 330 | 331 | **Available globally** 332 | 333 | ```ts 334 | const { $MotionPathPlugin } = useNuxtApp() 335 | ``` 336 | 337 | ## useMotionPathPlugin 338 | 339 | - Custom composable 340 | 341 | ```ts 342 | // nuxt.config.ts 343 | 344 | { 345 | gsap: { 346 | composables: true, 347 | extraPlugins: { 348 | motionPath: true 349 | } 350 | } 351 | } 352 | ``` 353 | 354 | **Usage** 355 | 356 | ```ts 357 | useMotionPathPlugin 358 | ``` 359 | 360 | ```ts 361 | // Explicit import (optional) 362 | import { useMotionPathPlugin } from '#gsap' 363 | ``` 364 | 365 | ## Pixi 366 | 367 | - Type: `boolean` 368 | - Default: `undefined` 369 | 370 | ```ts 371 | // nuxt.config.ts 372 | 373 | { 374 | gsap: { 375 | extraPlugins: { 376 | pixi: true 377 | } 378 | } 379 | } 380 | ``` 381 | 382 | **Available globally** 383 | 384 | ```ts 385 | const { $PixiPlugin } = useNuxtApp() 386 | ``` 387 | 388 | ## usePixiPlugin 389 | 390 | - Custom composable 391 | 392 | ```ts 393 | // nuxt.config.ts 394 | 395 | { 396 | gsap: { 397 | composables: true, 398 | extraPlugins: { 399 | pixi: true 400 | } 401 | } 402 | } 403 | ``` 404 | 405 | **Usage** 406 | 407 | ```ts 408 | usePixiPlugin 409 | ``` 410 | 411 | ```ts 412 | // Explicit import (optional) 413 | import { usePixiPlugin } from '#gsap' 414 | ``` 415 | 416 | ## Text 417 | 418 | - Type: `boolean` 419 | - Default: `undefined` 420 | 421 | ```ts 422 | // nuxt.config.ts 423 | 424 | { 425 | gsap: { 426 | extraPlugins: { 427 | text: true 428 | } 429 | } 430 | } 431 | ``` 432 | 433 | **Available globally** 434 | 435 | ```ts 436 | const { $TextPlugin } = useNuxtApp() 437 | ``` 438 | 439 | ## useTextPlugin 440 | 441 | - Custom composable 442 | 443 | ```ts 444 | // nuxt.config.ts 445 | 446 | { 447 | gsap: { 448 | composables: true, 449 | extraPlugins: { 450 | text: true 451 | } 452 | } 453 | } 454 | ``` 455 | 456 | **Usage** 457 | 458 | ```ts 459 | useTextPlugin 460 | ``` 461 | 462 | ```ts 463 | // Explicit import (optional) 464 | import { useTextPlugin } from '#gsap' 465 | ``` 466 | -------------------------------------------------------------------------------- /docs/options/README.md: -------------------------------------------------------------------------------- 1 | # Module Options 2 | 3 | ## Provide 4 | 5 | - Type: `boolean` 6 | - Default: `true` 7 | 8 | Provides the main `$gsap` core with plugins globally. 9 | 10 | ```ts 11 | // nuxt.config.ts 12 | 13 | { 14 | gsap: { 15 | provide: true 16 | } 17 | } 18 | ``` 19 | 20 | **Available globally** 21 | 22 | ```ts 23 | const { $gsap } = useNuxtApp() 24 | 25 | $gsap.to('.class', { rotation: 3, x: 100, duration: 1 }) 26 | ``` 27 | 28 | ## Composables 29 | 30 | - Type: `boolean` 31 | - Default: `undefined` 32 | 33 | Specifies custom composables. 34 | 35 | If enabled, allows the use of custom composables. 36 | 37 | ```ts 38 | // nuxt.config.ts 39 | 40 | { 41 | gsap: { 42 | composables: true 43 | } 44 | } 45 | ``` 46 | 47 | It is possible to use _provide_ helper and _composables_ in combination or separately, depending on preference. 48 | 49 | When using _only_ composables, it is recommended to disable global import. 50 | 51 | ```ts 52 | // nuxt.config.ts 53 | 54 | { 55 | gsap: { 56 | composables: true 57 | provide: false // global import 58 | } 59 | } 60 | ``` 61 | 62 | ## Auto Import 63 | 64 | - Type: `boolean` 65 | - Default: `true` 66 | 67 | Specifies the `auto-import` feature. 68 | 69 | If enabled, the composables will be available globally so there is no need to import them manually. 70 | 71 | Since this is an opinionated feature, you can disable global `auto-import` and use explicit import only where you need it. 72 | 73 | > [!NOTE]\ 74 | > Works only if the option `composables: true` is enabled. 75 | 76 | ```ts 77 | // nuxt.config.ts 78 | 79 | { 80 | gsap: { 81 | autoImport: false 82 | } 83 | } 84 | ``` 85 | -------------------------------------------------------------------------------- /docs/register-eases/README.md: -------------------------------------------------------------------------------- 1 | # Register Eases 2 | 3 | - Type: `object[]` 4 | - Default: `undefined` 5 | 6 | Provides an easy way to register global eases. 7 | 8 | Once the ease is registered, it can be accessed directly on the `gsap` animations. 9 | 10 | ```ts 11 | // nuxt.config.ts 12 | 13 | { 14 | gsap: { 15 | registerEases: [ 16 | { 17 | name: 'customEase', 18 | ease: (progress) => { 19 | return progress // linear 20 | }, 21 | }, 22 | { 23 | name: 'customEase2', 24 | // ... 25 | }, 26 | ] 27 | } 28 | } 29 | ``` 30 | 31 | **Available globally** 32 | 33 | ```ts 34 | const { $gsap } = useNuxtApp() 35 | 36 | $gsap.to('.class', { x: 100, ease: 'customEase' }) 37 | $gsap.to('#id', { x: 200, ease: 'customEase2' }) 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/register-effects/README.md: -------------------------------------------------------------------------------- 1 | # Register Effects 2 | 3 | - Type: `object[]` 4 | - Default: `undefined` 5 | 6 | Provides an easy way to register global effects. 7 | 8 | Once the effect is registered, it can be accessed directly on the `gsap.effects` object. 9 | 10 | To avoid possible linting warnings, use `// eslint-disable-next-line` and `// @ts-ignore` comments. 11 | 12 | ```ts 13 | // nuxt.config.ts 14 | 15 | { 16 | gsap: { 17 | registerEffects: [ 18 | { 19 | name: 'fade', 20 | defaults: { 21 | y: -100, 22 | opacity: 0, 23 | duration: 2, 24 | }, 25 | // eslint-disable-next-line 26 | // @ts-ignore 27 | effect: (targets, config) => { 28 | return gsap.to(targets, { 29 | y: config.y, 30 | opacity: config.opacity, 31 | duration: config.duration, 32 | }) 33 | }, 34 | }, 35 | { 36 | name: 'slideIn', 37 | // ... 38 | }, 39 | ] 40 | } 41 | } 42 | ``` 43 | 44 | **Available globally** 45 | 46 | ```ts 47 | const { $gsap } = useNuxtApp() 48 | 49 | $gsap.effects.fade('.class') 50 | $gsap.effects.slideIn('#id') 51 | ``` 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hypernym/nuxt-gsap", 3 | "version": "2.4.3", 4 | "author": "Hypernym Studio", 5 | "description": "GSAP module for Nuxt.", 6 | "license": "MIT", 7 | "repository": "hypernym-studio/nuxt-gsap", 8 | "homepage": "https://github.com/hypernym-studio/nuxt-gsap", 9 | "funding": "https://github.com/sponsors/ivodolenc", 10 | "type": "module", 11 | "types": "./dist/types.d.ts", 12 | "exports": { 13 | ".": { 14 | "import": "./dist/module.mjs", 15 | "types": "./dist/types.d.ts" 16 | } 17 | }, 18 | "files": [ 19 | "dist" 20 | ], 21 | "keywords": [ 22 | "nuxt", 23 | "nuxt-gsap", 24 | "nuxt-module", 25 | "gsap-module", 26 | "nuxt-animations", 27 | "nuxt-gsap-module", 28 | "animations", 29 | "gsap" 30 | ], 31 | "scripts": { 32 | "dev": "nuxt dev playground", 33 | "build": "hyperbundler", 34 | "build:play": "nuxt build playground", 35 | "generate:play": "nuxt generate playground", 36 | "preview:play": "nuxt preview playground", 37 | "lint": "eslint -c .config/eslint.config.js .", 38 | "lint:fix": "eslint -c .config/eslint.config.js --fix .", 39 | "format": "prettier --config .config/prettier.config.js --write .", 40 | "prepublishOnly": "npm run build" 41 | }, 42 | "dependencies": { 43 | "gsap": "^3.12.5" 44 | }, 45 | "devDependencies": { 46 | "@hypernym/bundler": "^0.9.3", 47 | "@hypernym/eslint-config": "^3.0.2", 48 | "@hypernym/prettier-config": "^3.0.1", 49 | "@types/node": "^22.5.0", 50 | "eslint": "^9.9.1", 51 | "nuxt": "^3.13.0", 52 | "prettier": "^3.3.3", 53 | "typescript": "^5.5.4" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /playground/components/NavMain.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /playground/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 24 | -------------------------------------------------------------------------------- /playground/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | import { defineNuxtConfig } from 'nuxt/config' 2 | import Module from '../src/module' 3 | 4 | export default defineNuxtConfig({ 5 | telemetry: false, 6 | 7 | modules: [Module], 8 | 9 | gsap: { 10 | extraPlugins: { 11 | scrollTrigger: true, 12 | }, 13 | }, 14 | }) 15 | -------------------------------------------------------------------------------- /playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "module-playground" 4 | } 5 | -------------------------------------------------------------------------------- /playground/pages/about/index.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /playground/pages/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | -------------------------------------------------------------------------------- /src/meta.ts: -------------------------------------------------------------------------------- 1 | export const name = '__name__' 2 | export const version = '__version__' 3 | export const configKey = 'gsap' 4 | export const compatibility = { 5 | nuxt: '>=3.0.0', 6 | } 7 | -------------------------------------------------------------------------------- /src/module.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineNuxtModule, 3 | addTemplate, 4 | addPluginTemplate, 5 | addImports, 6 | resolveAlias, 7 | } from '@nuxt/kit' 8 | import { serialize } from './utils/serialize' 9 | import { name, version, configKey, compatibility } from './meta' 10 | import type { ModuleOptions } from './types/module' 11 | 12 | export default defineNuxtModule({ 13 | meta: { 14 | name, 15 | version, 16 | configKey, 17 | compatibility, 18 | }, 19 | 20 | defaults: { 21 | provide: true, 22 | autoImport: true, 23 | }, 24 | 25 | setup(options, nuxt) { 26 | const { 27 | provide, 28 | composables, 29 | autoImport, 30 | extraPlugins: plugins, 31 | extraEases: eases, 32 | clubPlugins: club, 33 | registerEffects: regEffects, 34 | registerEases: regEases, 35 | } = options 36 | 37 | const fileBanner = `// Generated by ${name}` 38 | const pluginEffect: string[] = [] 39 | const pluginEase: string[] = [] 40 | 41 | // Global Effects 42 | if (regEffects) { 43 | for (const effect of regEffects) { 44 | pluginEffect.push(`gsap.registerEffect(${serialize(effect)});`) 45 | } 46 | } 47 | 48 | // Global Eases 49 | if (regEases) { 50 | for (const ease of regEases) { 51 | pluginEase.push( 52 | `gsap.registerEase(${serialize(ease.name)}, ${serialize( 53 | ease.ease, 54 | )});`, 55 | ) 56 | } 57 | } 58 | 59 | if (provide) { 60 | const templateName = 'gsapPlugin' 61 | const pluginImport: string[] = [] 62 | const pluginRegister: string[] = [] 63 | const pluginType: string[] = [] 64 | const pluginClient: string[] = [] 65 | 66 | const addPlugin = ({ 67 | name, 68 | subpath, 69 | }: { 70 | name: string 71 | subpath?: string 72 | }) => { 73 | pluginImport.push( 74 | `import { ${name} } from 'gsap/${subpath ? subpath : name}';`, 75 | ) 76 | pluginRegister.push(`${name}`) 77 | pluginType.push(`${name}: typeof ${name};`) 78 | } 79 | 80 | // Extra Plugins 81 | if (plugins?.flip) addPlugin({ name: 'Flip' }) 82 | if (plugins?.scrollTrigger) addPlugin({ name: 'ScrollTrigger' }) 83 | if (plugins?.observer) addPlugin({ name: 'Observer' }) 84 | if (plugins?.scrollTo) addPlugin({ name: 'ScrollToPlugin' }) 85 | if (plugins?.draggable) addPlugin({ name: 'Draggable' }) 86 | if (plugins?.easel) addPlugin({ name: 'EaselPlugin' }) 87 | if (plugins?.motionPath) addPlugin({ name: 'MotionPathPlugin' }) 88 | if (plugins?.pixi) addPlugin({ name: 'PixiPlugin' }) 89 | if (plugins?.text) addPlugin({ name: 'TextPlugin' }) 90 | 91 | // Extra Eases 92 | if (eases?.expoScale) 93 | addPlugin({ name: 'ExpoScaleEase', subpath: 'EasePack' }) 94 | if (eases?.rough) addPlugin({ name: 'RoughEase', subpath: 'EasePack' }) 95 | if (eases?.slowMo) addPlugin({ name: 'SlowMo', subpath: 'EasePack' }) 96 | if (eases?.custom) addPlugin({ name: 'CustomEase' }) 97 | 98 | // Club Plugins 99 | if (club?.drawSvg) addPlugin({ name: 'DrawSVGPlugin' }) 100 | if (club?.scrollSmoother) addPlugin({ name: 'ScrollSmoother' }) 101 | if (club?.gsDevTools) addPlugin({ name: 'GSDevTools' }) 102 | if (club?.inertia) addPlugin({ name: 'InertiaPlugin' }) 103 | if (club?.morphSvg) addPlugin({ name: 'MorphSVGPlugin' }) 104 | if (club?.motionPathHelper) addPlugin({ name: 'MotionPathHelper' }) 105 | if (club?.physics2d) addPlugin({ name: 'Physics2DPlugin' }) 106 | if (club?.physicsProps) addPlugin({ name: 'PhysicsPropsPlugin' }) 107 | if (club?.scrambleText) addPlugin({ name: 'ScrambleTextPlugin' }) 108 | if (club?.splitText) addPlugin({ name: 'SplitText' }) 109 | if (club?.customBounce) addPlugin({ name: 'CustomBounce' }) 110 | if (club?.customWiggle) addPlugin({ name: 'CustomWiggle' }) 111 | 112 | // Client mode 113 | if (plugins || eases || club || regEffects || regEases) { 114 | const registerPlugin = pluginRegister.length 115 | ? `gsap.registerPlugin(${pluginRegister.join(',')});` 116 | : '' 117 | 118 | pluginClient.push( 119 | `if(process.client) {`, 120 | ` ${registerPlugin}`, 121 | ` ${pluginEffect.join('\n')}`, 122 | ` ${pluginEase.join('\n')}`, 123 | `}`, 124 | ) 125 | } 126 | 127 | addTemplate({ 128 | filename: `${templateName}.d.ts`, 129 | write: true, 130 | getContents: () => 131 | [ 132 | fileBanner, 133 | `import { Plugin } from '#app';`, 134 | `import { gsap } from 'gsap';`, 135 | `${pluginImport.join('\n')}`, 136 | `declare const plugin: Plugin<{`, 137 | ` gsap: typeof gsap;`, 138 | ` ${pluginType.join('\n')}`, 139 | `}>;`, 140 | `export default plugin;`, 141 | ].join('\n'), 142 | }) 143 | 144 | addPluginTemplate({ 145 | filename: `${templateName}.mjs`, 146 | write: true, 147 | getContents: () => 148 | [ 149 | fileBanner, 150 | `import { defineNuxtPlugin } from '#app';`, 151 | `import { gsap } from 'gsap';`, 152 | `${pluginImport.join('\n')}`, 153 | `const plugin = defineNuxtPlugin(() => {`, 154 | ` ${pluginClient.join('\n')}`, 155 | ` return {`, 156 | ` provide: {`, 157 | ` gsap,`, 158 | ` ${pluginRegister.join(',\n')}`, 159 | ` }`, 160 | ` }`, 161 | `})`, 162 | `export default plugin;`, 163 | ].join('\n'), 164 | }) 165 | } 166 | 167 | if (composables) { 168 | const templateName = 'gsapComposables' 169 | const pluginImport: string[] = [] 170 | const pluginRegister: string[] = [] 171 | const pluginDeclare: string[] = [] 172 | const pluginType: string[] = [] 173 | 174 | const addComposable = ({ 175 | name, 176 | subpath, 177 | }: { 178 | name: string 179 | subpath?: string 180 | }) => { 181 | pluginImport.push( 182 | `import { ${name} } from 'gsap/${subpath ? subpath : name}';`, 183 | ) 184 | pluginRegister.push(`${name}`) 185 | pluginDeclare.push(`export const use${name} = ${name};`) 186 | pluginType.push(`export declare const use${name}: typeof ${name};`) 187 | } 188 | 189 | const alias = resolveAlias(`${nuxt.options.buildDir}/${templateName}`) 190 | nuxt.options.alias[`#${configKey}`] = alias 191 | 192 | // Core 193 | if (autoImport) addImports({ name: 'useGsap', from: alias }) 194 | 195 | // Extra Plugins 196 | if (plugins?.flip) { 197 | addComposable({ name: 'Flip' }) 198 | if (autoImport) addImports({ name: 'useFlip', from: alias }) 199 | } 200 | if (plugins?.scrollTrigger) { 201 | addComposable({ name: 'ScrollTrigger' }) 202 | if (autoImport) addImports({ name: 'useScrollTrigger', from: alias }) 203 | } 204 | if (plugins?.observer) { 205 | addComposable({ name: 'Observer' }) 206 | if (autoImport) addImports({ name: 'useObserver', from: alias }) 207 | } 208 | if (plugins?.scrollTo) { 209 | addComposable({ name: 'ScrollToPlugin' }) 210 | if (autoImport) addImports({ name: 'useScrollToPlugin', from: alias }) 211 | } 212 | if (plugins?.draggable) { 213 | addComposable({ name: 'Draggable' }) 214 | if (autoImport) addImports({ name: 'useDraggable', from: alias }) 215 | } 216 | if (plugins?.easel) { 217 | addComposable({ name: 'EaselPlugin' }) 218 | if (autoImport) addImports({ name: 'useEaselPlugin', from: alias }) 219 | } 220 | if (plugins?.motionPath) { 221 | addComposable({ name: 'MotionPathPlugin' }) 222 | if (autoImport) addImports({ name: 'useMotionPathPlugin', from: alias }) 223 | } 224 | if (plugins?.pixi) { 225 | addComposable({ name: 'PixiPlugin' }) 226 | if (autoImport) addImports({ name: 'usePixiPlugin', from: alias }) 227 | } 228 | if (plugins?.text) { 229 | addComposable({ name: 'TextPlugin' }) 230 | if (autoImport) addImports({ name: 'useTextPlugin', from: alias }) 231 | } 232 | 233 | // Extra Eases 234 | if (eases?.expoScale) { 235 | addComposable({ name: 'ExpoScaleEase', subpath: 'EasePack' }) 236 | if (autoImport) addImports({ name: 'useExpoScaleEase', from: alias }) 237 | } 238 | if (eases?.rough) { 239 | addComposable({ name: 'RoughEase', subpath: 'EasePack' }) 240 | if (autoImport) addImports({ name: 'useRoughEase', from: alias }) 241 | } 242 | if (eases?.slowMo) { 243 | addComposable({ name: 'SlowMo', subpath: 'EasePack' }) 244 | if (autoImport) addImports({ name: 'useSlowMo', from: alias }) 245 | } 246 | if (eases?.custom) { 247 | addComposable({ name: 'CustomEase' }) 248 | if (autoImport) addImports({ name: 'useCustomEase', from: alias }) 249 | } 250 | 251 | // Club Plugins 252 | if (club?.drawSvg) { 253 | addComposable({ name: 'DrawSVGPlugin' }) 254 | if (autoImport) addImports({ name: 'useDrawSVGPlugin', from: alias }) 255 | } 256 | if (club?.scrollSmoother) { 257 | addComposable({ name: 'ScrollSmoother' }) 258 | if (autoImport) addImports({ name: 'useScrollSmoother', from: alias }) 259 | } 260 | if (club?.gsDevTools) { 261 | addComposable({ name: 'GSDevTools' }) 262 | if (autoImport) addImports({ name: 'useGSDevTools', from: alias }) 263 | } 264 | if (club?.inertia) { 265 | addComposable({ name: 'InertiaPlugin' }) 266 | if (autoImport) addImports({ name: 'useInertiaPlugin', from: alias }) 267 | } 268 | if (club?.morphSvg) { 269 | addComposable({ name: 'MorphSVGPlugin' }) 270 | if (autoImport) addImports({ name: 'useMorphSVGPlugin', from: alias }) 271 | } 272 | if (club?.motionPathHelper) { 273 | addComposable({ name: 'MotionPathHelper' }) 274 | if (autoImport) addImports({ name: 'useMotionPathHelper', from: alias }) 275 | } 276 | if (club?.physics2d) { 277 | addComposable({ name: 'Physics2DPlugin' }) 278 | if (autoImport) addImports({ name: 'usePhysics2DPlugin', from: alias }) 279 | } 280 | if (club?.physicsProps) { 281 | addComposable({ name: 'PhysicsPropsPlugin' }) 282 | if (autoImport) 283 | addImports({ name: 'usePhysicsPropsPlugin', from: alias }) 284 | } 285 | if (club?.scrambleText) { 286 | addComposable({ name: 'ScrambleTextPlugin' }) 287 | if (autoImport) 288 | addImports({ name: 'useScrambleTextPlugin', from: alias }) 289 | } 290 | if (club?.splitText) { 291 | addComposable({ name: 'SplitText' }) 292 | if (autoImport) addImports({ name: 'useSplitText', from: alias }) 293 | } 294 | if (club?.customBounce) { 295 | addComposable({ name: 'CustomBounce' }) 296 | if (autoImport) addImports({ name: 'useCustomBounce', from: alias }) 297 | } 298 | if (club?.customWiggle) { 299 | addComposable({ name: 'CustomWiggle' }) 300 | if (autoImport) addImports({ name: 'useCustomWiggle', from: alias }) 301 | } 302 | 303 | addTemplate({ 304 | filename: `${templateName}.d.ts`, 305 | write: true, 306 | getContents: () => 307 | [ 308 | fileBanner, 309 | `import { gsap } from 'gsap';`, 310 | `${pluginImport.join('\n')}`, 311 | `export declare const useGsap: typeof gsap;`, 312 | `${pluginType.join('\n')}`, 313 | ].join('\n'), 314 | }) 315 | 316 | const registerPlugin = pluginRegister.length 317 | ? `gsap.registerPlugin(${pluginRegister.join(',')});` 318 | : '' 319 | 320 | addTemplate({ 321 | filename: `${templateName}.mjs`, 322 | write: true, 323 | getContents: () => 324 | [ 325 | fileBanner, 326 | `import { gsap } from 'gsap';`, 327 | `${pluginImport.join('\n')}`, 328 | `${registerPlugin}`, 329 | `${pluginEffect.join('\n')}`, 330 | `${pluginEase.join('\n')}`, 331 | `export const useGsap = gsap;`, 332 | `${pluginDeclare.join('\n')}`, 333 | ].join('\n'), 334 | }) 335 | } 336 | }, 337 | }) 338 | -------------------------------------------------------------------------------- /src/types/module.ts: -------------------------------------------------------------------------------- 1 | import type { NuxtModule } from '@nuxt/schema' 2 | import type { ExtraPlugins, ExtraEases, ClubPlugins } from './options' 3 | 4 | export interface ModuleOptions { 5 | /** 6 | * Provides the main `$gsap` core with plugins globally. 7 | * 8 | * @example 9 | * 10 | * ```ts 11 | * const { $gsap } = useNuxtApp() 12 | * 13 | * $gsap.to('.class', { rotation: 3, x: 100, duration: 1 }) 14 | * ``` 15 | * 16 | * @default true 17 | * 18 | * @since 2.3.0 19 | */ 20 | provide?: boolean 21 | /** 22 | * Specifies custom composables. 23 | * 24 | * If enabled, allows the use of custom composables. 25 | * 26 | * When using only composables, it is recommended to disable global import. 27 | * 28 | * @example 29 | * 30 | * ```ts 31 | * { 32 | * gsap: { 33 | * composables: true 34 | * provide: false // global import 35 | * } 36 | * } 37 | * ``` 38 | * 39 | * @default undefined 40 | * 41 | * @since 2.3.0 42 | */ 43 | composables?: boolean 44 | /** 45 | * Specifies the `auto-import` feature. 46 | * 47 | * If enabled, the composables will be available globally so there is no need to import them manually. 48 | * 49 | * Since this is an opinionated feature, you can disable global `auto-import` and use explicit import only where you need it. 50 | * 51 | * @note Works only if the option `composables: true` is enabled. 52 | * 53 | * @default true 54 | * 55 | * @since 2.3.0 56 | */ 57 | autoImport?: boolean 58 | /** 59 | * Specifies GSAP extra plugins. 60 | * 61 | * @default undefined 62 | * 63 | * @since 2.0.0 64 | */ 65 | extraPlugins?: ExtraPlugins 66 | /** 67 | * Specifies GSAP extra eases. 68 | * 69 | * @default undefined 70 | * 71 | * @since 2.0.0 72 | */ 73 | extraEases?: ExtraEases 74 | /** 75 | * Specifies GSAP premium plugins. 76 | * 77 | * This is only available to club members as it requires a paid license. 78 | * 79 | * Keep in mind that premium plugins must be installed according to the official GSAP guidelines before use. 80 | * 81 | * For more information about club plugins, check the official pages. 82 | * 83 | * @default undefined 84 | * 85 | * @since 2.0.0 86 | */ 87 | clubPlugins?: ClubPlugins 88 | /** 89 | * Provides an easy way to register global effects. 90 | * 91 | * Once the effect is registered, it can be accessed directly on the `gsap.effects` object. 92 | * 93 | * To avoid possible linting warnings, use `// @ts-ignore` and `// eslint-disable-next-line` comments. 94 | * 95 | * @example 96 | * 97 | * ```ts 98 | * { 99 | * registerEffects: [ 100 | * { 101 | * name: 'fade', 102 | * defaults: { 103 | * y: -100, 104 | * opacity: 0, 105 | * duration: 2 106 | * }, 107 | * // eslint-disable-next-line 108 | * // ts-ignore 109 | * effect: (targets, config) => { 110 | * return gsap.to(targets, { 111 | * y: config.y, 112 | * opacity: config.opacity, 113 | * duration: config.duration 114 | * }) 115 | * } 116 | * } 117 | * ] 118 | * } 119 | * ``` 120 | * 121 | * @default undefined 122 | * 123 | * @since 2.2.0 124 | */ 125 | registerEffects?: object[] 126 | /** 127 | * Provides an easy way to register global eases. 128 | * 129 | * Once the ease is registered, it can be accessed directly on the `gsap` animations. 130 | * 131 | * @example 132 | * 133 | * ```ts 134 | * { 135 | * registerEases: [ 136 | * { 137 | * name: 'customEase', 138 | * ease: progress => { 139 | * return progress // linear 140 | * }, 141 | * } 142 | * ] 143 | * } 144 | * ``` 145 | * 146 | * @default undefined 147 | * 148 | * @since 2.2.0 149 | */ 150 | registerEases?: { name: string; ease: { (progress: number): number } }[] 151 | } 152 | 153 | declare const module: NuxtModule 154 | 155 | export { module as default } 156 | -------------------------------------------------------------------------------- /src/types/options/club-plugins.ts: -------------------------------------------------------------------------------- 1 | export interface ClubPlugins { 2 | drawSvg?: boolean 3 | scrollSmoother?: boolean 4 | gsDevTools?: boolean 5 | inertia?: boolean 6 | morphSvg?: boolean 7 | motionPathHelper?: boolean 8 | physics2d?: boolean 9 | physicsProps?: boolean 10 | scrambleText?: boolean 11 | splitText?: boolean 12 | customBounce?: boolean 13 | customWiggle?: boolean 14 | } 15 | -------------------------------------------------------------------------------- /src/types/options/extra-eases.ts: -------------------------------------------------------------------------------- 1 | export interface ExtraEases { 2 | expoScale?: boolean 3 | rough?: boolean 4 | slowMo?: boolean 5 | custom?: boolean 6 | } 7 | -------------------------------------------------------------------------------- /src/types/options/extra-plugins.ts: -------------------------------------------------------------------------------- 1 | export interface ExtraPlugins { 2 | flip?: boolean 3 | scrollTrigger?: boolean 4 | observer?: boolean 5 | scrollTo?: boolean 6 | draggable?: boolean 7 | easel?: boolean 8 | motionPath?: boolean 9 | pixi?: boolean 10 | text?: boolean 11 | } 12 | -------------------------------------------------------------------------------- /src/types/options/index.ts: -------------------------------------------------------------------------------- 1 | export * from './extra-plugins' 2 | export * from './extra-eases' 3 | export * from './club-plugins' 4 | -------------------------------------------------------------------------------- /src/utils/serialize.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Serializes data. 3 | * 4 | * @since 2.2.0 5 | */ 6 | export function serialize(data: unknown): string { 7 | const type = (v: string) => typeof data === v 8 | 9 | if (data === null || data === undefined) 10 | return data === null ? 'null' : 'undefined' 11 | 12 | if (type('boolean') || type('number') || type('function')) 13 | return data.toString() 14 | 15 | if (Array.isArray(data)) return `[${data.map((v) => serialize(v)).join(',')}]` 16 | 17 | if (type('object')) 18 | return `{${Object.entries(data) 19 | .map(([key, val]) => `${key}: ${serialize(val)}`) 20 | .join(',')}}` 21 | 22 | return `'${data}'` 23 | } 24 | -------------------------------------------------------------------------------- /src/utils/templates.ts: -------------------------------------------------------------------------------- 1 | import { name, description, version, homepage } from '../../package.json' 2 | import { configKey, compatibility } from '../meta' 3 | 4 | /** 5 | * Generates `module.json` meta template. 6 | */ 7 | export function nuxtMetaTemplate() { 8 | const metaContent = JSON.stringify( 9 | { 10 | name, 11 | version, 12 | configKey, 13 | compatibility, 14 | }, 15 | null, 16 | 2, 17 | ) 18 | 19 | return metaContent 20 | } 21 | 22 | /** 23 | * Generates `shims` for `nuxt.config` auto-completion. 24 | */ 25 | export function nuxtTypesTemplate() { 26 | const comment = `/** 27 | * Nuxt Gsap Module 28 | * 29 | * ${description} 30 | * 31 | * @see [Repository](${homepage}) 32 | */` 33 | 34 | const typesContent = `import { ModuleOptions } from './module' 35 | 36 | declare module '@nuxt/schema' { 37 | interface NuxtConfig { 38 | ${comment} 39 | ['${configKey}']?: Partial 40 | } 41 | interface NuxtOptions { 42 | ${comment} 43 | ['${configKey}']?: ModuleOptions 44 | } 45 | } 46 | declare module 'nuxt/schema' { 47 | interface NuxtConfig { ['${configKey}']?: Partial } 48 | interface NuxtOptions { ['${configKey}']?: ModuleOptions } 49 | } 50 | 51 | export { ModuleOptions, default } from './module'` 52 | 53 | return typesContent 54 | } 55 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./playground/.nuxt/tsconfig.json" 3 | } 4 | --------------------------------------------------------------------------------