Added examples, llms.txt, and frameworks

This commit is contained in:
jackdoyle
2026-03-05 22:08:44 -06:00
parent 97b7cc3e4d
commit a80d23f971
18 changed files with 433 additions and 1 deletions
+43
View File
@@ -51,6 +51,46 @@ Clone this repo and copy the skill folders into the appropriate directory for yo
| **gsap-utils** | gsap.utils: clamp, mapRange, normalize, interpolate, random, snap, toArray, selector, wrap, pipe, and other helpers |
| **gsap-react** | React: useGSAP hook, refs, `gsap.context()`, cleanup, SSR |
| **gsap-performance** | Performance: transforms over layout props, will-change, batching, ScrollTrigger tips |
| **gsap-frameworks** | Vue, Svelte, etc.: lifecycle, scoping selectors, cleanup on unmount |
## Quick reference — Canonical snippet for AI agents
When suggesting or generating GSAP code, use this pattern as the shared starting point:
```javascript
// 1. Imports and plugin registration (once per app)
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
// 2. Single tween — prefer transform aliases and autoAlpha
gsap.to(".box", { x: 100, autoAlpha: 1, duration: 0.6, ease: "power2.inOut" });
// 3. Timeline for sequencing (prefer over chained delay)
const tl = gsap.timeline({ defaults: { duration: 0.5, ease: "power2" } });
tl.to(".a", { x: 100 })
.to(".b", { y: 50 }, "+=0.2")
.to(".c", { opacity: 0 }, "-=0.1");
// 4. ScrollTrigger — attach to timeline or top-level tween; call refresh after layout changes
const tl2 = gsap.timeline({
scrollTrigger: {
trigger: ".section",
start: "top center",
end: "bottom center",
scrub: true
}
});
tl2.to(".panel", { x: 100 })
.to(".panel", { rotation: 5, duration: 0.7 });
// After DOM/layout changes: ScrollTrigger.refresh();
// 5. React: useGSAP + scope + cleanup (no selector without scope)
// import { useGSAP } from "@gsap/react";
// gsap.registerPlugin(useGSAP);
// useGSAP(() => { gsap.to(ref.current, { x: 100 }); }, { scope: containerRef });
// Or: useEffect(() => { const ctx = gsap.context(() => { ... }, containerRef); return () => ctx.revert(); }, []);
```
## Structure
@@ -67,6 +107,7 @@ gsap-skills/
.cursor-plugin/ # Cursor plugin config (plugin.json, marketplace.json)
assets/ # Logo and icon assets (e.g. gsap-green.svg, gsap-icon-square.svg)
skills/
llms.txt # Skill index for agents (names, summaries, trigger terms)
gsap-core/ SKILL.md
gsap-timeline/ SKILL.md
gsap-scrolltrigger/ SKILL.md
@@ -74,6 +115,8 @@ gsap-skills/
gsap-utils/ SKILL.md
gsap-react/ SKILL.md
gsap-performance/ SKILL.md
gsap-frameworks/ SKILL.md
examples/ # Minimal reference demos (vanilla + React)
```
## GitHub Copilot
+17
View File
@@ -0,0 +1,17 @@
# GSAP skills — reference examples
Minimal demos that follow the skills exactly: transforms, autoAlpha, timelines, ScrollTrigger, and (in React) useGSAP with scope and cleanup.
## Vanilla (HTML + JS)
- **examples/vanilla/** — single HTML page + ES module.
- Uses GSAP from CDN (ESM). Open with a local server that supports ES modules (e.g. `npx serve examples/vanilla` from repo root).
- Patterns: `gsap.to()` with `x`/`autoAlpha`, `gsap.timeline()` with defaults and position parameter, ScrollTrigger on the timeline.
## React
- **examples/react/** — Vite + React + `@gsap/react`.
- From repo root: `cd examples/react && npm install && npm run dev`.
- Patterns: `useGSAP()` with `scope: containerRef`, refs for targets, no selectors without scope; cleanup is automatic on unmount.
These examples are intended as reference implementations for AI agents and for quick manual verification of the skill patterns.
+46
View File
@@ -0,0 +1,46 @@
/**
* Minimal GSAP React example — follows gsap-react skill: useGSAP, scope, cleanup.
* No selector without scope; refs for targets; automatic revert on unmount.
*/
import { useRef } from "react";
import { useGSAP } from "@gsap/react";
import { gsap } from "gsap";
// Register useGSAP once (could be in main.jsx for app-level)
gsap.registerPlugin(useGSAP);
function App() {
const containerRef = useRef(null);
const boxRef = useRef(null);
useGSAP(
() => {
// Scoped to containerRef — selectors only match inside container
gsap.to(boxRef.current, { x: 100, duration: 0.6, ease: "power2" });
gsap.from(".item", { autoAlpha: 0, y: 20, stagger: 0.1 });
},
{ scope: containerRef }
);
return (
<div ref={containerRef} style={{ padding: "2rem" }}>
<h1>GSAP React — useGSAP + scope + cleanup</h1>
<div
ref={boxRef}
className="box"
style={{
width: 80,
height: 80,
background: "#0fa",
borderRadius: 8,
marginBottom: "1rem",
}}
/>
<div className="item" style={{ margin: "0.5rem 0" }}>Item 1</div>
<div className="item" style={{ margin: "0.5rem 0" }}>Item 2</div>
<div className="item" style={{ margin: "0.5rem 0" }}>Item 3</div>
</div>
);
}
export default App;
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GSAP React — useGSAP + scope + cleanup</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/main.jsx"></script>
</body>
</html>
+9
View File
@@ -0,0 +1,9 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
+21
View File
@@ -0,0 +1,21 @@
{
"name": "gsap-skills-example-react",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@gsap/react": "^2.1.2",
"gsap": "^3.14.2",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.3.3",
"vite": "^5.4.10"
}
}
+7
View File
@@ -0,0 +1,7 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
root: ".",
});
+33
View File
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GSAP vanilla — canonical patterns</title>
<style>
body { font-family: system-ui, sans-serif; padding: 2rem; }
.box { width: 80px; height: 80px; background: #0fa; border-radius: 8px; margin: 1rem 0; }
.item { margin: 0.5rem 0; opacity: 0; }
.section { min-height: 120vh; padding: 2rem 0; }
.panel { width: 100px; height: 60px; background: #9cf; border-radius: 8px; }
</style>
</head>
<body>
<h1>GSAP vanilla — transforms, autoAlpha, timeline, ScrollTrigger</h1>
<h2>1. Single tween (transform + autoAlpha)</h2>
<div class="box" id="single" style="opacity: 0;"></div>
<h2>2. Timeline (sequencing)</h2>
<div class="box a">A</div>
<div class="box b">B</div>
<div class="box c">C</div>
<h2>3. ScrollTrigger (timeline + scrub)</h2>
<section class="section" id="scroll-section">
<div class="panel">Panel</div>
</section>
<script type="module" src="main.js"></script>
</body>
</html>
+36
View File
@@ -0,0 +1,36 @@
/**
* Minimal GSAP vanilla example — follows skills: transforms, autoAlpha, timeline, ScrollTrigger.
* Run from repo root: npx serve examples/vanilla (or open index.html with a local server that supports ES modules).
*/
import { gsap } from "https://cdn.jsdelivr.net/npm/gsap@3.14.2/index.js";
import { ScrollTrigger } from "https://cdn.jsdelivr.net/npm/gsap@3.14.2/ScrollTrigger.js";
gsap.registerPlugin(ScrollTrigger);
// 1. Single tween — transform alias x, autoAlpha
gsap.to("#single", {
x: 120,
autoAlpha: 1,
duration: 0.6,
ease: "power2"
});
// 2. Timeline for sequencing (defaults, position parameter)
const tl = gsap.timeline({ defaults: { duration: 0.5, ease: "power2" } });
tl.to(".a", { x: 100 })
.to(".b", { y: 40 }, "+=0.2")
.to(".c", { autoAlpha: 0 }, "-=0.1");
// 3. ScrollTrigger on timeline (not on child tween)
const tl2 = gsap.timeline({
scrollTrigger: {
trigger: "#scroll-section",
start: "top center",
end: "bottom center",
scrub: true
}
});
tl2.to(".panel", { x: 100 })
.to(".panel", { rotation: 5, duration: 0.7 });
// After dynamic layout changes you would call: ScrollTrigger.refresh();
+2
View File
@@ -10,6 +10,8 @@ license: MIT
Apply when writing or reviewing GSAP animations that use the core engine: single tweens, eases, staggers, or when explaining how GSAP tweens work.
**Related skills:** For sequencing multiple steps use **gsap-timeline**; for scroll-linked animation use **gsap-scrolltrigger**; for React use **gsap-react**; for plugins (Flip, Draggable, etc.) use **gsap-plugins**; for helpers (clamp, mapRange, etc.) use **gsap-utils**; for performance use **gsap-performance**.
**Context:** GSAP was acquired by Webflow and powers **Webflow Interactions**. Code generated or run by Webflow’s interaction system is GSAP-based; when users ask about Webflow animations or interactions not behaving as expected, GSAP docs and patterns (e.g. tweens, ScrollTrigger) are relevant for debugging or customizing.
## When to Use GSAP
+153
View File
@@ -0,0 +1,153 @@
---
name: gsap-frameworks
description: Use GSAP correctly in Vue, Svelte, and other non-React frameworks — lifecycle (when to create/kill tweens and ScrollTriggers), scoping selectors, cleanup on unmount. Use when animating in Vue, Nuxt, Svelte, SvelteKit, or when the user asks about GSAP with Vue, Svelte, onMounted, onUnmounted, onMount, onDestroy.
license: MIT
---
# GSAP with Vue, Svelte, and Other Frameworks
## When to Use This Skill
Apply when writing or reviewing GSAP code in Vue (or Nuxt), Svelte (or SvelteKit), or other component frameworks that use a lifecycle (mounted/unmounted). For **React** specifically, use **gsap-react** (useGSAP hook, gsap.context()).
**Related skills:** For tweens and timelines use **gsap-core** and **gsap-timeline**; for scroll-based animation use **gsap-scrolltrigger**; for React use **gsap-react**.
## Principles (All Frameworks)
- **Create** tweens and ScrollTriggers **after** the component’s DOM is available (e.g. onMounted, onMount).
- **Kill or revert** them in the **unmount** (or equivalent) cleanup so nothing runs on detached nodes and there are no leaks.
- **Scope selectors** to the component root so `.box` and similar only match elements inside that component, not the rest of the page.
## Vue 3 (Composition API)
Use **onMounted** to run GSAP after the component is in the DOM. Use **onUnmounted** to clean up.
```javascript
import { onMounted, onUnmounted, ref } from "vue";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger); // once per app, e.g. in main.js
export default {
setup() {
const container = ref(null);
let ctx;
onMounted(() => {
if (!container.value) return;
ctx = gsap.context(() => {
gsap.to(".box", { x: 100, duration: 0.6 });
gsap.from(".item", { autoAlpha: 0, y: 20, stagger: 0.1 });
}, container.value);
});
onUnmounted(() => {
ctx?.revert();
});
return { container };
}
};
```
- ✅ **gsap.context(scope)** — pass the container ref (e.g. `container.value`) as the second argument so selectors like `.item` are scoped to that root. All animations and ScrollTriggers created inside the callback are tracked and reverted when **ctx.revert()** is called.
- ✅ **onUnmounted** — always call **ctx.revert()** so tweens and ScrollTriggers are killed and inline styles reverted.
## Vue 3 (script setup)
Same idea with `<script setup>` and refs:
```javascript
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
const container = ref(null);
let ctx;
onMounted(() => {
if (!container.value) return;
ctx = gsap.context(() => {
gsap.to(".box", { x: 100 });
gsap.from(".item", { autoAlpha: 0, stagger: 0.1 });
}, container.value);
});
onUnmounted(() => {
ctx?.revert();
});
</script>
<template>
<div ref="container">
<div class="box">Box</div>
<div class="item">Item</div>
</div>
</template>
```
## Svelte
Use **onMount** to run GSAP after the DOM is ready. Use the **returned cleanup function** from onMount (or track the context and clean up in a reactive block / component destroy) to revert. Svelte 5 uses a different lifecycle; the same principle applies: create in “mounted” and revert in “destroyed.”
```javascript
<script>
import { onMount } from "svelte";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
let container;
onMount(() => {
if (!container) return;
const ctx = gsap.context(() => {
gsap.to(".box", { x: 100 });
gsap.from(".item", { autoAlpha: 0, stagger: 0.1 });
}, container);
return () => ctx.revert();
});
</script>
<div bind:this={container}>
<div class="box">Box</div>
<div class="item">Item</div>
</div>
```
- ✅ **bind:this={container}** — get a reference to the root element so you can pass it to **gsap.context(scope)**.
- ✅ **return () => ctx.revert()** — Svelte’s onMount can return a cleanup function; call **ctx.revert()** there so cleanup runs when the component is destroyed.
## Scoping Selectors
Do not use global selectors that can match elements outside the current component. Always pass the **scope** (container element or ref) as the second argument to **gsap.context(callback, scope)** so that any selector run inside the callback is limited to that subtree.
- ✅ **gsap.context(() => { gsap.to(".box", ...) }, containerRef)** — `.box` is only searched inside `containerRef`.
- ❌ Running **gsap.to(".box", ...)** without a context scope in a component can affect other instances or the rest of the page.
## ScrollTrigger Cleanup
ScrollTrigger instances are created when you use the `scrollTrigger` config on a tween/timeline or **ScrollTrigger.create()**. They are **included** in **gsap.context()** and reverted when you call **ctx.revert()**. So:
- Create ScrollTriggers inside the same **gsap.context()** callback you use for tweens.
- Call **ScrollTrigger.refresh()** after layout changes (e.g. after data loads) that affect trigger positions; in Vue/Svelte that often means after the DOM updates (e.g. nextTick in Vue, tick in Svelte, or after async content load).
## When to Create vs Kill
| Lifecycle | Action |
|-----------------|--------|
| **Mounted** | Create tweens and ScrollTriggers inside **gsap.context(scope)**. |
| **Unmount / Destroy** | Call **ctx.revert()** so all animations and ScrollTriggers in that context are killed and inline styles reverted. |
Do not create GSAP animations in the component’s setup or in a synchronous top-level script that runs before the root element exists. Wait for **onMounted** / **onMount** (or equivalent) so the container ref is in the DOM.
## Do Not
- ❌ Create tweens or ScrollTriggers before the component is mounted (e.g. in setup without onMounted); the DOM nodes may not exist yet.
- ❌ Use selector strings without a **scope** (pass the container to gsap.context() as the second argument) so selectors don’t match elements outside the component.
- ❌ Skip cleanup; always call **ctx.revert()** in onUnmounted / onMount’s return so animations and ScrollTriggers are killed when the component is destroyed.
- ❌ Register plugins inside a component body that runs every render (it doesn't hurt anything, it's just wasteful); register once at app level.
### Learn More
- **gsap-react** skill for React-specific patterns (useGSAP, contextSafe).
+2
View File
@@ -10,6 +10,8 @@ license: MIT
Apply when optimizing GSAP animations for smooth 60fps, reducing layout/paint cost, or when the user asks about performance, jank, or best practices for fast animations.
**Related skills:** Build animations with **gsap-core** (transforms, autoAlpha) and **gsap-timeline**; for ScrollTrigger performance see **gsap-scrolltrigger**.
## Prefer Transform and Opacity
Animating **transform** (`x`, `y`, `scaleX`, `scaleY`, `rotation`, `rotationX`, `rotationY`, `skewX`, `skewY`) and **opacity** keeps work on the compositor and avoids layout and most paint. Avoid animating layout-heavy properties when a transform can achieve the same effect.
+2
View File
@@ -10,6 +10,8 @@ license: MIT
Apply when using or reviewing code that uses GSAP plugins: registering plugins, scroll-to, flip/FLIP animations, draggable elements, SVG (DrawSVG, MorphSVG, MotionPath), text (SplitText, ScrambleText), physics, easing plugins (CustomEase, EasePack, CustomWiggle, CustomBounce), or GSDevTools. ScrollTrigger has its own skill (gsap-scrolltrigger).
**Related skills:** For core tweens use **gsap-core**; for ScrollTrigger use **gsap-scrolltrigger**; for React use **gsap-react**.
## Registering Plugins
Register each plugin once so GSAP (and bundlers) know to include it. Use **gsap.registerPlugin()** with every plugin used in the project:
+2
View File
@@ -10,6 +10,7 @@ license: MIT
Apply when writing or reviewing GSAP code in React (or React-based frameworks like Next.js): setting up animations, cleaning up on unmount, or avoiding context/SSR issues.
**Related skills:** For tweens and timelines use **gsap-core** and **gsap-timeline**; for scroll-based animation use **gsap-scrolltrigger**; for Vue/Svelte or other frameworks use **gsap-frameworks**.
## Installation
@@ -124,6 +125,7 @@ GSAP runs in the browser. Do not call gsap or ScrollTrigger during SSR.
## Do Not
- ❌ Target by **selector without a scope**; always pass **scope** (ref or element) in useGSAP or gsap.context() so selectors like `.box` are limited to that root and do not match elements outside the component.
- ❌ Animate using selector strings that can match elements outside the current component unless a `scope` is defined in useGSAP or gsap.context() so only elements inside the component are affected.
- ❌ Skip cleanup; always revert context or kill tweens/ScrollTriggers in the effect return to avoid leaks and updates on unmounted nodes.
- ❌ Run GSAP or ScrollTrigger during SSR; keep all usage inside client-only lifecycle (e.g. useGSAP).
+5 -1
View File
@@ -10,6 +10,8 @@ license: MIT
Apply when implementing scroll-driven animations: triggering tweens/timelines on scroll, pinning elements, scrubbing animation to scroll position, or when the user mentions ScrollTrigger, scroll animations, or pinning.
**Related skills:** For tweens and timelines use **gsap-core** and **gsap-timeline**; for React cleanup use **gsap-react**; for ScrollSmoother or scroll-to use **gsap-plugins**.
## Registering the Plugin
ScrollTrigger is a plugin. After loading the script, register it once:
@@ -278,7 +280,9 @@ In React, use the `useGSAP()` hook (@gsap/react NPM package) to ensure proper cl
## Do Not
- ❌ Nest ScrollTriggered animations inside of a parent timeline. ScrollTriggers should only exist on top-level animations. Wrong: `gsap.timeline().to(..., {scrollTrigger: {...}})`. Correct: `gsap.timeline({scrollTrigger: {...}}).to(...)` (the tween inside the timeline shouldn't have a ScrollTrigger).
- ❌ Put ScrollTrigger on a **child tween** when it's part of a timeline; put it on the **timeline** or a **top-level tween** only. Wrong: `gsap.timeline().to(".a", { scrollTrigger: {...} })`. Correct: `gsap.timeline({ scrollTrigger: {...} }).to(".a", { x: 100 })`.
- ❌ Forget to call **ScrollTrigger.refresh()** after DOM/layout changes (new content, images, fonts) that affect trigger positions; viewport resize is auto-handled, but dynamic content is not.
- ❌ Nest ScrollTriggered animations inside of a parent timeline. ScrollTriggers should only exist on top-level animations.
- ❌ Forget to **gsap.registerPlugin(ScrollTrigger)** before using ScrollTrigger.
- ❌ Use **scrub** and **toggleActions** together on the same ScrollTrigger; choose one behavior. If both exist, **scrub** wins.
- ❌ Use an ease other than **"none"** on the horizontal animation when using **containerAnimation** for fake horizontal scroll; it breaks the 1:1 scroll-to-position mapping.
+4
View File
@@ -10,6 +10,8 @@ license: MIT
Apply when building multi-step animations, coordinating several tweens in sequence or parallel, or when the user asks about timelines, sequencing, or keyframe-style animation in GSAP.
**Related skills:** For single tweens and eases use **gsap-core**; for scroll-driven timelines use **gsap-scrolltrigger**; for React use **gsap-react**.
## Creating a Timeline
```javascript
@@ -99,5 +101,7 @@ master.to(".c", { opacity: 0 }, "+=0.2");
## Do Not
- ❌ Chain animations with **delay** when a **timeline** can sequence them; prefer `gsap.timeline()` and the position parameter for multi-step animation.
- ❌ Forget to pass **defaults** (e.g. `defaults: { duration: 0.5, ease: "power2.out" }`) when many child tweens share the same duration or ease.
- ❌ Forget that **duration** on the timeline constructor is not the same as tween duration; timeline “duration” is determined by its children.
- ❌ Nest animations that contain a ScrollTrigger; ScrollTriggers should only be on top-level Tweens/Timelines.
+2
View File
@@ -10,6 +10,8 @@ license: MIT
Apply when writing or reviewing code that uses **gsap.utils** for math, array/collection handling, unit parsing, or value mapping in animations (e.g. mapping scroll to a value, randomizing, snapping to a grid, or normalizing inputs).
**Related skills:** Use with **gsap-core**, **gsap-timeline**, and **gsap-scrolltrigger** when building animations; CustomEase and other easing utilities are in **gsap-plugins**.
## Overview
**gsap.utils** provides pure helpers; no need to register. Use in tween vars (e.g. function-based values), in ScrollTrigger or Observer callbacks, or in any JS that drives GSAP. All are on **gsap.utils** (e.g. `gsap.utils.clamp()`).
+37
View File
@@ -0,0 +1,37 @@
# GSAP Skills — Index for AI Agents
Use this file to discover which skill to load. Each skill lives in a directory of the same name under skills/ and contains SKILL.md.
## Skills
gsap-core
Core API: gsap.to(), from(), fromTo(), easing, duration, stagger, defaults, transforms, autoAlpha.
Triggers: GSAP tweens, easing, stagger, basic animation, Webflow interactions, transform, opacity.
gsap-timeline
Timelines: gsap.timeline(), position parameter, labels, nesting, playback.
Triggers: sequencing, timeline, keyframes, choreograph, multi-step animation, animation order.
gsap-scrolltrigger
ScrollTrigger: scroll-linked animations, pinning, scrub, triggers, refresh, cleanup.
Triggers: scroll animation, ScrollTrigger, pin, parallax, scroll-driven, scrub.
gsap-plugins
Plugins: ScrollToPlugin, ScrollSmoother, Flip, Draggable, Inertia, Observer, SplitText, ScrambleText, SVG/physics, CustomEase, EasePack, GSDevTools.
Triggers: plugin, scroll-to, flip, draggable, SVG drawing, MorphSVG, DrawSVG, MotionPath, SplitText, ScrambleText, CustomEase, registerPlugin.
gsap-utils
gsap.utils: clamp, mapRange, normalize, interpolate, random, snap, toArray, wrap, pipe.
Triggers: gsap.utils, clamp, mapRange, random, snap, toArray, wrap, interpolation.
gsap-react
React: useGSAP hook, refs, gsap.context(), cleanup, SSR.
Triggers: React, Next.js, useGSAP, cleanup on unmount, GSAP React.
gsap-performance
Performance: transforms, will-change, batching, ScrollTrigger tips.
Triggers: performance, 60fps, jank, animation performance, optimize.
gsap-frameworks
Vue, Svelte, and other frameworks: lifecycle, when to create/kill tweens and ScrollTriggers, scoping selectors, cleanup on unmount.
Triggers: Vue, Svelte, Nuxt, SvelteKit, framework, lifecycle, onMounted, onUnmounted.