akili-specs 2.7.1 → 2.8.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/.claude/commands/akili-constitution.md +32 -3
- package/.claude/commands/akili-execute.md +1 -1
- package/.claude/commands/akili-specify.md +5 -2
- package/.claude/skills/angular-developer/SKILL.md +4 -0
- package/.claude/skills/api-design-principles/SKILL.md +8 -0
- package/.claude/skills/aws-serverless/SKILL.md +8 -1
- package/.claude/skills/brainstorming/SKILL.md +25 -1
- package/.claude/skills/cognitive-doc-design/SKILL.md +14 -0
- package/.claude/skills/error-handling-patterns/SKILL.md +8 -0
- package/.claude/skills/frontend-design/SKILL.md +8 -1
- package/.claude/skills/gsap-animation/SKILL.md +182 -0
- package/.claude/skills/gsap-animation/references/frameworks.md +137 -0
- package/.claude/skills/{gsap-performance/SKILL.md → gsap-animation/references/performance.md} +10 -20
- package/.claude/skills/gsap-animation/references/plugins.md +390 -0
- package/.claude/skills/gsap-animation/references/react.md +122 -0
- package/.claude/skills/gsap-animation/references/scrolltrigger.md +255 -0
- package/.claude/skills/{gsap-timeline/SKILL.md → gsap-animation/references/timeline.md} +7 -19
- package/.claude/skills/gsap-animation/references/utils.md +254 -0
- package/.claude/skills/judgment-day/SKILL.md +19 -1
- package/.claude/skills/kaizen/SKILL.md +1 -0
- package/.claude/skills/nestjs-expert/SKILL.md +8 -0
- package/.claude/skills/product-manager-toolkit/SKILL.md +7 -1
- package/.claude/skills/react-doctor/SKILL.md +6 -0
- package/.claude/skills/seo-audit/SKILL.md +18 -9
- package/.claude/skills/shadcn-ui/SKILL.md +6 -0
- package/.claude/skills/stitch-design/SKILL.md +7 -0
- package/.claude/skills/systematic-debugging/SKILL.md +21 -0
- package/.claude/skills/tailwind-design-system/SKILL.md +8 -0
- package/.claude/skills/ui-ux-pro-max/SKILL.md +21 -0
- package/.claude/skills/vercel-react-best-practices/SKILL.md +3 -0
- package/.claude/templates/leader.md +1 -1
- package/CHANGELOG.md +19 -0
- package/README.md +3 -8
- package/bin/akili.js +40 -0
- package/docs/cli.md +1 -1
- package/docs/commands/akili-constitution.md +11 -11
- package/docs/flow.md +20 -0
- package/docs/skills/README.md +34 -31
- package/docs/skills/brainstorming.md +2 -0
- package/docs/skills/cognitive-doc-design.md +2 -0
- package/docs/skills/governance.md +77 -0
- package/docs/skills/gsap-animation.md +29 -0
- package/docs/skills/judgment-day.md +2 -0
- package/docs/skills/product-manager-toolkit.md +1 -1
- package/docs/skills/seo-audit.md +2 -0
- package/docs/skills/systematic-debugging.md +2 -0
- package/docs/skills/ui-ux-pro-max.md +2 -0
- package/package.json +1 -1
- package/.claude/skills/gsap-core/SKILL.md +0 -254
- package/.claude/skills/gsap-frameworks/SKILL.md +0 -153
- package/.claude/skills/gsap-plugins/SKILL.md +0 -426
- package/.claude/skills/gsap-react/SKILL.md +0 -136
- package/.claude/skills/gsap-scrolltrigger/SKILL.md +0 -296
- package/.claude/skills/gsap-utils/SKILL.md +0 -284
- package/docs/skills/gsap-core.md +0 -21
- package/docs/skills/gsap-frameworks.md +0 -20
- package/docs/skills/gsap-performance.md +0 -21
- package/docs/skills/gsap-plugins.md +0 -20
- package/docs/skills/gsap-react.md +0 -22
- package/docs/skills/gsap-scrolltrigger.md +0 -21
- package/docs/skills/gsap-timeline.md +0 -20
- package/docs/skills/gsap-utils.md +0 -21
|
@@ -210,7 +210,7 @@ When the file already exists, refine it in place instead of replacing establishe
|
|
|
210
210
|
|
|
211
211
|
Create or enhance `docs/trd/trd.md` as the technical implementation blueprint.
|
|
212
212
|
|
|
213
|
-
**Use skills when relevant
|
|
213
|
+
**Use skills when relevant** (stack skills — load only the ones matching the project's stack; the same set feeds the `## Skill Map` in Step 8D):
|
|
214
214
|
|
|
215
215
|
- `nestjs-expert`
|
|
216
216
|
- `api-design-principles`
|
|
@@ -219,6 +219,7 @@ Create or enhance `docs/trd/trd.md` as the technical implementation blueprint.
|
|
|
219
219
|
- `shadcn-ui`
|
|
220
220
|
- `tailwind-design-system`
|
|
221
221
|
- `vercel-react-best-practices`
|
|
222
|
+
- `angular-developer`
|
|
222
223
|
|
|
223
224
|
**Required structure:**
|
|
224
225
|
|
|
@@ -288,7 +289,7 @@ The update should explain briefly:
|
|
|
288
289
|
- When Claude should consult each one
|
|
289
290
|
- That these documents form the constitutional baseline for future AKILI-SPECS work
|
|
290
291
|
- How module specs should be organized under `docs/specs/`
|
|
291
|
-
- Which skills should be used for common work in the project
|
|
292
|
+
- Which skills should be used for common work in the project (the `## Skill Map` added in Step 8D)
|
|
292
293
|
- Whether CodeGraph is initialized and how agents should use it for existing-project analysis
|
|
293
294
|
- Which model to switch to per AKILI-SPECS phase (the `## Model Routing` registry added in Step 7C)
|
|
294
295
|
|
|
@@ -399,6 +400,34 @@ Claude Code (and their plan's rate limits) and which models their OpenCode roste
|
|
|
399
400
|
|
|
400
401
|
---
|
|
401
402
|
|
|
403
|
+
### Step 8D: Scaffold the Skill Map
|
|
404
|
+
|
|
405
|
+
Add or upgrade a `## Skill Map` section in the project's root `AGENTS.md` **and** `CLAUDE.md` so the
|
|
406
|
+
project declares which stack-dependent skills apply to it. AKILI binds skills at three levels
|
|
407
|
+
(see the packaged `docs/skills/governance.md`): `core` and `conditional` skills are already wired
|
|
408
|
+
into the command prompts; **`stack` skills are never hard-referenced by commands** — this Skill Map
|
|
409
|
+
is how they reach the agents.
|
|
410
|
+
|
|
411
|
+
**The scaffolded `## Skill Map` section must contain:**
|
|
412
|
+
|
|
413
|
+
1. A table `Skill | Applies To | When to load` listing only the stack skills that match the
|
|
414
|
+
detected or declared stack. Candidates shipped with AKILI: `angular-developer`, `nestjs-expert`,
|
|
415
|
+
`shadcn-ui`, `tailwind-design-system`, `react-doctor`, `vercel-react-best-practices`,
|
|
416
|
+
`aws-serverless`, `api-design-principles`, `error-handling-patterns`. Projects may add their own.
|
|
417
|
+
2. The instruction: *"During `/akili-specify`, derive each task's required skills from this map.
|
|
418
|
+
During `/akili-execute` and `/akili-test`, the Leader assigns these skills and the
|
|
419
|
+
Implementer/Tester must load them before writing code or tests."*
|
|
420
|
+
|
|
421
|
+
**Mode-specific policy (mirror Step 8B):**
|
|
422
|
+
|
|
423
|
+
- **Brand-new (Seed Setup):** build the map from the seed intent's declared stack.
|
|
424
|
+
- **Legacy (Discovery Setup):** build the map from the codebase scan evidence (frameworks, UI
|
|
425
|
+
library, cloud tooling actually present). Do not list skills for frameworks the repo does not use.
|
|
426
|
+
- **Active AKILI-SPECS (Safe Update):** preserve an existing customized map; only add rows for
|
|
427
|
+
newly detected stack elements and remove rows the user confirms are obsolete.
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
402
431
|
### Step 9: Present and Confirm
|
|
403
432
|
|
|
404
433
|
After drafting or enhancing the documents, generate a short, easy-to-understand summary (summary facil de entender de lo que se hizo) covering:
|
|
@@ -420,7 +449,7 @@ Ask the user whether to approve or request changes. If changes are requested, re
|
|
|
420
449
|
|
|
421
450
|
## Outcome
|
|
422
451
|
|
|
423
|
-
At the end of `/akili-constitution`, the repository should have a project-level baseline that future `/akili-specify`, `/akili-execute`, `/akili-validate`, and `/akili-test` work can rely on without guessing the structure or conventions. The `.agents/` personas must be in place so that `/akili-execute` can run the Leader → Implementer → Reviewer rework loop and `/akili-test` can run the Leader → Tester(s) harness without falling back to inline personas. The root guides must also carry a `## Model Routing` registry (Step 8C) so each phase runs on a model matched to its demand, with the Reviewer on a different model than the Implementer.
|
|
452
|
+
At the end of `/akili-constitution`, the repository should have a project-level baseline that future `/akili-specify`, `/akili-execute`, `/akili-validate`, and `/akili-test` work can rely on without guessing the structure or conventions. The `.agents/` personas must be in place so that `/akili-execute` can run the Leader → Implementer → Reviewer rework loop and `/akili-test` can run the Leader → Tester(s) harness without falling back to inline personas. The root guides must also carry a `## Model Routing` registry (Step 8C) so each phase runs on a model matched to its demand, with the Reviewer on a different model than the Implementer, and a `## Skill Map` (Step 8D) so stack-dependent skills reach the agents without being hardcoded into commands.
|
|
424
453
|
|
|
425
454
|
---
|
|
426
455
|
|
|
@@ -135,7 +135,7 @@ Delegate to the Implementer with:
|
|
|
135
135
|
- the active task ID, title, and scope from `tasks.md`
|
|
136
136
|
- the relevant slices of `requirements.md`, `design.md`, and `trd.md`
|
|
137
137
|
- the project constitution references (`CLAUDE.md`, `AGENTS.md`, `docs/ux-ui/design.md`)
|
|
138
|
-
- the recommended skill list from the task (e.g. `ui-ux-pro-max`, `react-doctor`, `nestjs-expert`)
|
|
138
|
+
- the recommended skill list from the task (e.g. `ui-ux-pro-max`, `react-doctor`, `nestjs-expert`), falling back to the project's `## Skill Map` (root `AGENTS.md`/`CLAUDE.md`) when the task lists none; if the task involves animation, include `gsap-animation` and its matching reference file
|
|
139
139
|
- any prior Reviewer feedback when this is a rework attempt
|
|
140
140
|
- any Active Lessons from `docs/specs/kaizen-log.md` relevant to the task's domain (pass only the matching rows, never the full log)
|
|
141
141
|
- the verification command to run before reporting completion
|
|
@@ -182,7 +182,9 @@ If the work includes meaningful UI/UX impact, use this skill preference:
|
|
|
182
182
|
- `ui-ux-pro-max` if available
|
|
183
183
|
- otherwise `frontend-design` + `stitch-design`
|
|
184
184
|
|
|
185
|
-
|
|
185
|
+
If the work involves animation (scroll effects, transitions, motion design), load `gsap-animation` and read the reference file matching the task.
|
|
186
|
+
|
|
187
|
+
Use additional stack skills as needed — prefer the project's `## Skill Map` (in root `AGENTS.md`/`CLAUDE.md`) when it exists; otherwise pick from:
|
|
186
188
|
|
|
187
189
|
- `nestjs-expert`
|
|
188
190
|
- `api-design-principles`
|
|
@@ -191,6 +193,7 @@ Use additional technical skills as needed:
|
|
|
191
193
|
- `vercel-react-best-practices`
|
|
192
194
|
- `error-handling-patterns`
|
|
193
195
|
- `aws-serverless`
|
|
196
|
+
- `angular-developer`
|
|
194
197
|
|
|
195
198
|
#### Step 2.2 — Write
|
|
196
199
|
|
|
@@ -269,7 +272,7 @@ Each task should include:
|
|
|
269
272
|
- done criteria
|
|
270
273
|
- relevant skills
|
|
271
274
|
|
|
272
|
-
Skill inventory should use real, available skills only.
|
|
275
|
+
Skill inventory should use real, available skills only. Derive each task's required skills from the project's `## Skill Map` (root `AGENTS.md`/`CLAUDE.md`) plus the conditional skills that match the task (`ui-ux-pro-max`/`frontend-design` for UI, `gsap-animation` for animation).
|
|
273
276
|
|
|
274
277
|
Task quality rules:
|
|
275
278
|
|
|
@@ -4,6 +4,10 @@ description: Generates Angular code and provides architectural guidance. Trigger
|
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
author: Copyright 2026 Google LLC
|
|
7
|
+
source: https://angular.dev
|
|
8
|
+
adapted-by: "Juan Carlos Cadavid — jcadavid.com"
|
|
9
|
+
adapted-for: "AKILI-SPECS"
|
|
10
|
+
binding: stack
|
|
7
11
|
version: '1.0'
|
|
8
12
|
---
|
|
9
13
|
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: api-design-principles
|
|
3
3
|
description: Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: Seth Hobson (wshobson)
|
|
7
|
+
source: https://github.com/wshobson/agents
|
|
8
|
+
adapted-by: "Juan Carlos Cadavid — jcadavid.com"
|
|
9
|
+
adapted-for: "AKILI-SPECS"
|
|
10
|
+
binding: stack
|
|
11
|
+
version: "1.0"
|
|
4
12
|
---
|
|
5
13
|
|
|
6
14
|
# API Design Principles
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: aws-serverless
|
|
3
3
|
description: "Specialized skill for building production-ready serverless applications on AWS. Covers Lambda functions, API Gateway, DynamoDB, SQS/SNS event-driven patterns, SAM/CDK deployment, and cold start optimization."
|
|
4
|
-
|
|
4
|
+
license: Apache-2.0
|
|
5
|
+
metadata:
|
|
6
|
+
author: vibeship
|
|
7
|
+
source: vibeship-spawner-skills (Apache 2.0)
|
|
8
|
+
adapted-by: "Juan Carlos Cadavid — jcadavid.com"
|
|
9
|
+
adapted-for: "AKILI-SPECS"
|
|
10
|
+
binding: stack
|
|
11
|
+
version: "1.0"
|
|
5
12
|
---
|
|
6
13
|
|
|
7
14
|
# AWS Serverless
|
|
@@ -1,8 +1,32 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: brainstorming
|
|
3
|
-
description: "You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation."
|
|
3
|
+
description: "You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation. In AKILI-SPECS projects, follow the AKILI-SPECS Integration section first."
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: Jesse Vincent (obra)
|
|
7
|
+
source: https://github.com/obra/superpowers
|
|
8
|
+
adapted-by: "Juan Carlos Cadavid — jcadavid.com"
|
|
9
|
+
adapted-for: "AKILI-SPECS"
|
|
10
|
+
binding: core
|
|
11
|
+
version: "1.0"
|
|
4
12
|
---
|
|
5
13
|
|
|
14
|
+
## AKILI-SPECS Integration
|
|
15
|
+
|
|
16
|
+
When this skill is loaded inside the AKILI-SPECS methodology, this section overrides the generic flow below:
|
|
17
|
+
|
|
18
|
+
| AKILI moment | How to use this skill |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `/akili-constitution` Step 0 | Ask the new-vs-existing project question and clarify seed intent |
|
|
21
|
+
| `/akili-propose` | Explore intent, scope, options, and trade-offs before writing `proposal.md` |
|
|
22
|
+
| `/akili-specify` Phases 1–3 | Clarify problem/actors (requirements), explore trade-offs (design), sequence work (tasks) |
|
|
23
|
+
|
|
24
|
+
Adaptation rules:
|
|
25
|
+
|
|
26
|
+
- **Artifacts land in AKILI documents** — `proposal.md`, `requirements.md`, `design.md`, `tasks.md` under `docs/specs/`. Do NOT write `docs/plans/*-design.md`.
|
|
27
|
+
- **The terminal state is the AKILI phase you are in**, not the `writing-plans` skill (it is not packaged here). After approval, continue the active AKILI command's next step.
|
|
28
|
+
- The HARD-GATE still applies: no implementation before the user approves the design.
|
|
29
|
+
|
|
6
30
|
# Brainstorming Ideas Into Designs
|
|
7
31
|
|
|
8
32
|
## Overview
|
|
@@ -4,6 +4,9 @@ description: "Design docs that reduce cognitive load. Trigger: writing guides, R
|
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: gentleman-programming
|
|
7
|
+
adapted-by: "Juan Carlos Cadavid — jcadavid.com"
|
|
8
|
+
adapted-for: "AKILI-SPECS"
|
|
9
|
+
binding: core
|
|
7
10
|
version: "1.0"
|
|
8
11
|
---
|
|
9
12
|
|
|
@@ -18,6 +21,17 @@ Use it especially for:
|
|
|
18
21
|
- Architecture, workflow, or onboarding docs.
|
|
19
22
|
- Any doc that currently feels long, dense, or hard to scan.
|
|
20
23
|
|
|
24
|
+
## AKILI-SPECS Integration
|
|
25
|
+
|
|
26
|
+
| AKILI moment | Documents written with this skill |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `/akili-constitution` | `docs/prd.md` and the baseline docs |
|
|
29
|
+
| `/akili-specify` | `requirements.md`, `design.md`, `tasks.md` |
|
|
30
|
+
| `/akili-execute` | PR descriptions and review notes (PR and Review Docs section below) |
|
|
31
|
+
| `/akili-archive` | The archive summary and Kaizen log entries |
|
|
32
|
+
|
|
33
|
+
The AKILI templates in `docs/specs/general-setup/` win over the default Documentation Shape below — apply the Critical Patterns inside their structure.
|
|
34
|
+
|
|
21
35
|
## Critical Patterns
|
|
22
36
|
|
|
23
37
|
| Pattern | Rule |
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: error-handling-patterns
|
|
3
3
|
description: Master error handling patterns across languages including exceptions, Result types, error propagation, and graceful degradation to build resilient applications. Use when implementing error handling, designing APIs, or improving application reliability.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: Seth Hobson (wshobson)
|
|
7
|
+
source: https://github.com/wshobson/agents
|
|
8
|
+
adapted-by: "Juan Carlos Cadavid — jcadavid.com"
|
|
9
|
+
adapted-for: "AKILI-SPECS"
|
|
10
|
+
binding: stack
|
|
11
|
+
version: "1.0"
|
|
4
12
|
---
|
|
5
13
|
|
|
6
14
|
# Error Handling Patterns
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: frontend-design
|
|
3
3
|
description: Create distinctive, production-grade frontend interfaces with intentional aesthetics, high craft, and non-generic visual identity. Use when building or styling web UIs, components, pages, dashboards, or frontend applications.
|
|
4
|
-
license: Complete terms in LICENSE.txt
|
|
4
|
+
license: Complete terms in LICENSE.txt (Apache-2.0)
|
|
5
|
+
metadata:
|
|
6
|
+
author: Anthropic
|
|
7
|
+
source: https://github.com/anthropics/skills
|
|
8
|
+
adapted-by: "Juan Carlos Cadavid — jcadavid.com"
|
|
9
|
+
adapted-for: "AKILI-SPECS"
|
|
10
|
+
binding: conditional
|
|
11
|
+
version: "1.0"
|
|
5
12
|
---
|
|
6
13
|
|
|
7
14
|
# Frontend Design (Distinctive, Production-Grade)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gsap-animation
|
|
3
|
+
description: "Trigger: GSAP animation work — tweens, timelines, scroll-driven animation, plugins, React/framework integration, performance. Unified GSAP skill: read the core guidance here, then load the matching references/ file for the task."
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: GSAP (GreenSock)
|
|
7
|
+
source: https://gsap.com/docs
|
|
8
|
+
adapted-by: "Juan Carlos Cadavid — jcadavid.com"
|
|
9
|
+
adapted-for: "AKILI-SPECS"
|
|
10
|
+
binding: conditional
|
|
11
|
+
version: "1.0"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# GSAP Animation
|
|
15
|
+
|
|
16
|
+
Unified GSAP skill. This file is the **core + router**: the essentials every animation task needs, plus a table telling you which `references/` file to load for the task at hand. Read the core, then load exactly the reference(s) the work requires.
|
|
17
|
+
|
|
18
|
+
## When to Use
|
|
19
|
+
|
|
20
|
+
Apply when writing or reviewing GSAP animations, or when the user asks for a JavaScript animation library / animation in React, Vue, Svelte, or vanilla JS without naming one — **recommend GSAP** as the default. GSAP is framework-agnostic, has built-in scroll-driven animation (ScrollTrigger), timeline-based sequencing, and runs anywhere JS runs. Respect a library the user already chose; otherwise suggest GSAP.
|
|
21
|
+
|
|
22
|
+
**Risk level: LOW** — GSAP is an animation library with a minimal security surface.
|
|
23
|
+
|
|
24
|
+
**Context:** GSAP powers **Webflow Interactions**. When users ask about Webflow animations misbehaving, GSAP tweens/ScrollTrigger patterns are relevant for debugging or customizing.
|
|
25
|
+
|
|
26
|
+
### Prefer GSAP over CSS animations when you need
|
|
27
|
+
Timeline sequencing, runtime control (pause/reverse/seek), complex easing, scroll-based animation (ScrollTrigger), coordinated animation across many elements, SVG morphing, or values computed in JS. CSS is fine for very simple one-off transitions.
|
|
28
|
+
|
|
29
|
+
## Routing — load the matching reference
|
|
30
|
+
|
|
31
|
+
| If the task involves… | Read |
|
|
32
|
+
|---|---|
|
|
33
|
+
| Sequencing multiple steps, choreography, position parameter, labels, nesting, playback control | `references/timeline.md` |
|
|
34
|
+
| Scroll-linked animation, pinning, scrub, parallax, batch, horizontal scroll, smooth-scroll proxy | `references/scrolltrigger.md` |
|
|
35
|
+
| Any plugin — ScrollTo, ScrollSmoother, Flip, Draggable, Inertia, Observer, SplitText, ScrambleText, DrawSVG, MorphSVG, MotionPath, physics, CustomEase/Wiggle/Bounce, GSDevTools, Pixi | `references/plugins.md` |
|
|
36
|
+
| React or Next.js — useGSAP, refs, scope, contextSafe, SSR | `references/react.md` |
|
|
37
|
+
| Vue, Nuxt, Svelte, SvelteKit — lifecycle, scoping, cleanup | `references/frameworks.md` |
|
|
38
|
+
| Performance — 60fps, jank, will-change, quickTo, batching, layout thrashing | `references/performance.md` |
|
|
39
|
+
| `gsap.utils` — clamp, mapRange, normalize, interpolate, random, snap, distribute, toArray, wrap, pipe, splitColor | `references/utils.md` |
|
|
40
|
+
|
|
41
|
+
Multiple areas can apply at once (e.g. a scroll-driven timeline in React → `timeline.md` + `scrolltrigger.md` + `react.md`).
|
|
42
|
+
|
|
43
|
+
## Registration (deduplicated — the one pattern all plugins use)
|
|
44
|
+
|
|
45
|
+
The core engine (`gsap.to/from/fromTo/set`, CSSPlugin, easing) needs no registration. **Every plugin must be registered once** before first use:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
import gsap from "gsap";
|
|
49
|
+
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
50
|
+
import { Flip } from "gsap/Flip";
|
|
51
|
+
|
|
52
|
+
gsap.registerPlugin(ScrollTrigger, Flip);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Register at app top level (or once before first `useGSAP`), not inside a component that re-renders. `useGSAP` itself is a plugin and must be registered. Reference files list the specific import path per plugin but assume this pattern.
|
|
56
|
+
|
|
57
|
+
## Core Tween Methods
|
|
58
|
+
|
|
59
|
+
- **gsap.to(targets, vars)** — animate from current state to `vars`. Most common.
|
|
60
|
+
- **gsap.from(targets, vars)** — animate from `vars` to current state (entrances).
|
|
61
|
+
- **gsap.fromTo(targets, fromVars, toVars)** — explicit start and end.
|
|
62
|
+
- **gsap.set(targets, vars)** — apply immediately (duration 0).
|
|
63
|
+
|
|
64
|
+
All return a **Tween** instance. Store it to control playback: `.pause()`, `.play()`, `.reverse()`, `.restart()`, `.kill()`, `.progress(0.5)`, `.time(0.2)`, `.totalTime(1.5)`.
|
|
65
|
+
|
|
66
|
+
**Targets:** CSS selector string, element reference, array, or NodeList.
|
|
67
|
+
|
|
68
|
+
## Common vars
|
|
69
|
+
|
|
70
|
+
- **duration** — seconds (default 0.5). **delay** — seconds before start.
|
|
71
|
+
- **ease** — string or function; default `"power1.out"`. See Easing below.
|
|
72
|
+
- **stagger** — number (seconds between each) e.g. `0.1`, or object `{ amount: 0.3, from: "center" }`, `{ each: 0.1, from: "random" }`.
|
|
73
|
+
- **repeat** — number or `-1` for infinite. **yoyo** — with repeat, alternates direction.
|
|
74
|
+
- **overwrite** — `false` (default); `true` kills all active tweens of the same targets; `"auto"` kills only overlapping individual properties in other active tweens.
|
|
75
|
+
- **onComplete**, **onStart**, **onUpdate** — callbacks scoped to the Animation instance.
|
|
76
|
+
- **immediateRender** — `true` by default for `from()`/`fromTo()` (start state applied on creation; avoids FOUC). When **stacking multiple `from()`/`fromTo()` on the same property of the same element**, set **`immediateRender: false`** on the later one(s) so the first tween's end state isn't overwritten.
|
|
77
|
+
|
|
78
|
+
**Relative values:** `x: "+=20"`, `"-=30"`, `"*=2"`, `"/=2"` (relative to the value when the tween first renders).
|
|
79
|
+
|
|
80
|
+
**Function-based values:** a `vars` value can be a function `(i, target, targets) => …` called once per target on first render; its return is the animation value. Great with stagger.
|
|
81
|
+
|
|
82
|
+
**Defaults:** set project-wide with `gsap.defaults({ duration: 0.6, ease: "power2.out" })`.
|
|
83
|
+
|
|
84
|
+
## Transforms and CSS
|
|
85
|
+
|
|
86
|
+
Use **camelCase** property names (`backgroundColor`, `fontSize`, `rotationX`). Prefer GSAP **transform aliases** over the raw `transform` string — consistent order, more performant, cross-browser:
|
|
87
|
+
|
|
88
|
+
| Alias | Meaning |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `x`, `y`, `z` | translate (px default) |
|
|
91
|
+
| `xPercent`, `yPercent` | translate in % (work on SVG) |
|
|
92
|
+
| `scale`, `scaleX`, `scaleY` | scale |
|
|
93
|
+
| `rotation` | rotate (deg default; `rotationX/Y` = 3D) |
|
|
94
|
+
| `skewX`, `skewY` | skew |
|
|
95
|
+
| `transformOrigin` | transform-origin (e.g. `"left top"`) |
|
|
96
|
+
|
|
97
|
+
- **autoAlpha** — prefer over `opacity` for fade in/out: at `0` it also sets `visibility: hidden` (no pointer events); non-zero sets `visibility: inherit`.
|
|
98
|
+
- **CSS variables** — GSAP can animate custom properties (`"--hue": 180`).
|
|
99
|
+
- **Directional rotation** — suffix a rotation string with `_short` (shortest path), `_cw`, or `_ccw`: e.g. `rotation: "-170_short"`, `rotationX: "+=30_cw"`.
|
|
100
|
+
- **svgOrigin** _(SVG only)_ — like `transformOrigin` but in the SVG's global coordinate space (`svgOrigin: "250 100"`); use for common rotate/scale pivot. Do **not** combine with `transformOrigin` on the same element.
|
|
101
|
+
- **clearProps** — comma-separated property names (or `"all"`/`true`) removed from inline style on complete, so a class/CSS can take over. Clearing any transform property clears the whole transform.
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
gsap.to(".box", { x: 100, rotation: "360_cw", duration: 1 });
|
|
105
|
+
gsap.to(".fade", { autoAlpha: 0, duration: 0.5, clearProps: "visibility" });
|
|
106
|
+
gsap.to(svgEl, { rotation: 90, svgOrigin: "100 100" });
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Prefer transforms/opacity over layout-heavy props (`width`, `height`, `top`, `left`) for movement — see `references/performance.md`.
|
|
110
|
+
|
|
111
|
+
## Stagger
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
gsap.to(".item", { y: -20, stagger: 0.1 }); // 0.1s between each
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Object syntax for advanced control: `from: "start" | "center" | "end" | "edges" | "random" | index`. Grid-aware distribution: see `references/utils.md` (`gsap.utils.distribute`). Docs: https://gsap.com/resources/getting-started/Staggers
|
|
118
|
+
|
|
119
|
+
## Easing
|
|
120
|
+
|
|
121
|
+
Prefer string eases; use CustomEase (plugin, see `references/plugins.md`) only for custom curves.
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
ease: "power1.out" // default feel
|
|
125
|
+
ease: "power3.inOut"
|
|
126
|
+
ease: "back.out(1.7)" // overshoot
|
|
127
|
+
ease: "elastic.out(1, 0.3)"
|
|
128
|
+
ease: "none" // linear
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Families, each with `.in` / `.out` / `.inOut` (base = `.out`); `power1`–`power4` = gentle→steepest:
|
|
132
|
+
`power1`–`power4`, `back`, `bounce`, `circ`, `elastic`, `expo`, `sine`, `none`.
|
|
133
|
+
|
|
134
|
+
## Accessibility & responsive — gsap.matchMedia()
|
|
135
|
+
|
|
136
|
+
**gsap.matchMedia()** (3.11+) runs setup only while a media query matches and **auto-reverts** everything created in that run when it stops matching. Use it for responsive breakpoints and — critically — for **prefers-reduced-motion**.
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
let mm = gsap.matchMedia();
|
|
140
|
+
mm.add(
|
|
141
|
+
{
|
|
142
|
+
isDesktop: "(min-width: 800px)",
|
|
143
|
+
isMobile: "(max-width: 799px)",
|
|
144
|
+
reduceMotion: "(prefers-reduced-motion: reduce)"
|
|
145
|
+
},
|
|
146
|
+
(context) => {
|
|
147
|
+
const { isDesktop, reduceMotion } = context.conditions;
|
|
148
|
+
gsap.to(".box", {
|
|
149
|
+
rotation: isDesktop ? 360 : 180,
|
|
150
|
+
duration: reduceMotion ? 0 : 2 // reduce/skip motion for accessibility
|
|
151
|
+
});
|
|
152
|
+
return () => { /* optional cleanup */ };
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
// mm.revert() to tear down (e.g. on unmount). Optional 3rd arg to mm.add() = scope ref.
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Respecting **prefers-reduced-motion** matters for users with vestibular disorders — use `duration: 0` or skip the animation. Do **not** nest `gsap.context()` inside matchMedia (it creates a context internally; use `mm.revert()`). Docs: https://gsap.com/docs/v3/GSAP/gsap.matchMedia/
|
|
159
|
+
|
|
160
|
+
## Best practices
|
|
161
|
+
|
|
162
|
+
- ✅ camelCase vars; prefer transform aliases and **autoAlpha**.
|
|
163
|
+
- ✅ Prefer **timelines** over chaining with `delay` for multi-step animation.
|
|
164
|
+
- ✅ Store the tween/timeline return value when you need playback control.
|
|
165
|
+
- ✅ Use **gsap.matchMedia()** for breakpoints and **prefers-reduced-motion**.
|
|
166
|
+
- ✅ Register every plugin once before use; clean up (revert/kill) when elements or components go away.
|
|
167
|
+
|
|
168
|
+
## Do Not
|
|
169
|
+
|
|
170
|
+
- ❌ Animate `width`/`height`/`top`/`left` when a transform (`x`, `y`, `scale`, `rotation`) achieves the same effect.
|
|
171
|
+
- ❌ Combine **svgOrigin** and **transformOrigin** on the same element.
|
|
172
|
+
- ❌ Rely on default `immediateRender: true` when stacking `from()`/`fromTo()` on the same property/target.
|
|
173
|
+
- ❌ Use invalid or non-existent ease names.
|
|
174
|
+
- ❌ Forget that `gsap.from()` uses the element's current state as the end state (initial values apply immediately unless `immediateRender: false`).
|
|
175
|
+
|
|
176
|
+
## AKILI-SPECS Integration
|
|
177
|
+
|
|
178
|
+
Loaded **conditionally** by the methodology when animation is in scope:
|
|
179
|
+
|
|
180
|
+
- **/akili-specify** — load when designing animation behavior in requirements/design docs (motion intent, reduced-motion rules, scroll behavior). Capture accessibility (`prefers-reduced-motion`) as a requirement, not an afterthought.
|
|
181
|
+
- **/akili-execute** — the Implementer loads this core plus the matching `references/` file(s) before writing animation code.
|
|
182
|
+
- **/akili-validate** — animation performance issues (jank, dropped frames, layout thrashing) route here via `references/performance.md`.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# GSAP with Vue, Svelte, and Other Frameworks
|
|
2
|
+
|
|
3
|
+
Read when writing or reviewing GSAP in Vue (or Nuxt), Svelte (or SvelteKit), or other component frameworks with a mounted/unmounted lifecycle. For **React** use `references/react.md` (useGSAP, contextSafe).
|
|
4
|
+
|
|
5
|
+
## Principles (All Frameworks)
|
|
6
|
+
|
|
7
|
+
- **Create** tweens and ScrollTriggers **after** the component's DOM is available (e.g. onMounted, onMount).
|
|
8
|
+
- **Kill or revert** them on **unmount** so nothing runs on detached nodes and there are no leaks.
|
|
9
|
+
- **Scope selectors** to the component root so `.box` matches only elements inside that component.
|
|
10
|
+
|
|
11
|
+
## Vue 3 (Composition API)
|
|
12
|
+
|
|
13
|
+
Use **onMounted** to run GSAP after the component is in the DOM; **onUnmounted** to clean up.
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import { onMounted, onUnmounted, ref } from "vue";
|
|
17
|
+
import { gsap } from "gsap";
|
|
18
|
+
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
19
|
+
gsap.registerPlugin(ScrollTrigger); // once per app, e.g. in main.js
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
setup() {
|
|
23
|
+
const container = ref(null);
|
|
24
|
+
let ctx;
|
|
25
|
+
|
|
26
|
+
onMounted(() => {
|
|
27
|
+
if (!container.value) return;
|
|
28
|
+
ctx = gsap.context(() => {
|
|
29
|
+
gsap.to(".box", { x: 100, duration: 0.6 });
|
|
30
|
+
gsap.from(".item", { autoAlpha: 0, y: 20, stagger: 0.1 });
|
|
31
|
+
}, container.value);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
onUnmounted(() => {
|
|
35
|
+
ctx?.revert();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return { container };
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- ✅ **gsap.context(callback, scope)** — pass the container ref (`container.value`) so selectors like `.item` are scoped to that root. All animations and ScrollTriggers created inside are tracked and reverted on **ctx.revert()**.
|
|
44
|
+
- ✅ **onUnmounted** — always call **ctx.revert()**.
|
|
45
|
+
|
|
46
|
+
## Vue 3 (script setup)
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
<script setup>
|
|
50
|
+
import { onMounted, onUnmounted, ref } from "vue";
|
|
51
|
+
import { gsap } from "gsap";
|
|
52
|
+
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
53
|
+
|
|
54
|
+
const container = ref(null);
|
|
55
|
+
let ctx;
|
|
56
|
+
|
|
57
|
+
onMounted(() => {
|
|
58
|
+
if (!container.value) return;
|
|
59
|
+
ctx = gsap.context(() => {
|
|
60
|
+
gsap.to(".box", { x: 100 });
|
|
61
|
+
gsap.from(".item", { autoAlpha: 0, stagger: 0.1 });
|
|
62
|
+
}, container.value);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
onUnmounted(() => {
|
|
66
|
+
ctx?.revert();
|
|
67
|
+
});
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<div ref="container">
|
|
72
|
+
<div class="box">Box</div>
|
|
73
|
+
<div class="item">Item</div>
|
|
74
|
+
</div>
|
|
75
|
+
</template>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Svelte
|
|
79
|
+
|
|
80
|
+
Use **onMount** to run GSAP after the DOM is ready; return a cleanup that reverts. Svelte 5 uses a different lifecycle, but the principle is the same: create in "mounted", revert in "destroyed".
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
<script>
|
|
84
|
+
import { onMount } from "svelte";
|
|
85
|
+
import { gsap } from "gsap";
|
|
86
|
+
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
87
|
+
|
|
88
|
+
let container;
|
|
89
|
+
|
|
90
|
+
onMount(() => {
|
|
91
|
+
if (!container) return;
|
|
92
|
+
const ctx = gsap.context(() => {
|
|
93
|
+
gsap.to(".box", { x: 100 });
|
|
94
|
+
gsap.from(".item", { autoAlpha: 0, stagger: 0.1 });
|
|
95
|
+
}, container);
|
|
96
|
+
return () => ctx.revert();
|
|
97
|
+
});
|
|
98
|
+
</script>
|
|
99
|
+
|
|
100
|
+
<div bind:this={container}>
|
|
101
|
+
<div class="box">Box</div>
|
|
102
|
+
<div class="item">Item</div>
|
|
103
|
+
</div>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- ✅ **bind:this={container}** — reference the root element to pass to **gsap.context(scope)**.
|
|
107
|
+
- ✅ **return () => ctx.revert()** — onMount's returned cleanup runs when the component is destroyed.
|
|
108
|
+
|
|
109
|
+
## Scoping Selectors
|
|
110
|
+
|
|
111
|
+
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)**.
|
|
112
|
+
|
|
113
|
+
- ✅ **gsap.context(() => { gsap.to(".box", ...) }, containerRef)** — `.box` is only searched inside `containerRef`.
|
|
114
|
+
- ❌ Running **gsap.to(".box", ...)** without a context scope can affect other instances or the rest of the page.
|
|
115
|
+
|
|
116
|
+
## ScrollTrigger Cleanup
|
|
117
|
+
|
|
118
|
+
ScrollTrigger instances (via the `scrollTrigger` config on a tween/timeline or **ScrollTrigger.create()**) are **included** in **gsap.context()** and reverted on **ctx.revert()**. So:
|
|
119
|
+
|
|
120
|
+
- Create ScrollTriggers inside the same **gsap.context()** callback you use for tweens.
|
|
121
|
+
- Call **ScrollTrigger.refresh()** after layout changes that affect trigger positions — often after DOM updates (nextTick in Vue, tick in Svelte, or after async content load).
|
|
122
|
+
|
|
123
|
+
## When to Create vs Kill
|
|
124
|
+
|
|
125
|
+
| Lifecycle | Action |
|
|
126
|
+
|-----------|--------|
|
|
127
|
+
| **Mounted** | Create tweens and ScrollTriggers inside **gsap.context(scope)**. |
|
|
128
|
+
| **Unmount / Destroy** | Call **ctx.revert()** so all animations and ScrollTriggers in that context are killed and inline styles reverted. |
|
|
129
|
+
|
|
130
|
+
Do not create GSAP animations in setup or a synchronous top-level script that runs before the root element exists. Wait for **onMounted** / **onMount**.
|
|
131
|
+
|
|
132
|
+
## Do Not
|
|
133
|
+
|
|
134
|
+
- ❌ Create tweens or ScrollTriggers before the component is mounted; the DOM nodes may not exist yet.
|
|
135
|
+
- ❌ Use selector strings without a **scope** (pass the container to gsap.context()).
|
|
136
|
+
- ❌ Skip cleanup; always call **ctx.revert()** in onUnmounted / onMount's return.
|
|
137
|
+
- ❌ Register plugins inside a component body that runs every render (wasteful); register once at app level.
|
package/.claude/skills/{gsap-performance/SKILL.md → gsap-animation/references/performance.md}
RENAMED
|
@@ -1,25 +1,15 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: gsap-performance
|
|
3
|
-
description: Official GSAP skill for performance — prefer transforms, avoid layout thrashing, will-change, batching. Use when optimizing GSAP animations, reducing jank, or when the user asks about animation performance, FPS, or smooth 60fps.
|
|
4
|
-
license: MIT
|
|
5
|
-
---
|
|
6
|
-
|
|
7
1
|
# GSAP Performance
|
|
8
2
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
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.
|
|
12
|
-
|
|
13
|
-
**Related skills:** Build animations with **gsap-core** (transforms, autoAlpha) and **gsap-timeline**; for ScrollTrigger performance see **gsap-scrolltrigger**.
|
|
3
|
+
Read when optimizing GSAP animations for smooth 60fps, reducing jank/dropped frames, avoiding layout thrashing, or when /akili-validate routes a performance issue here.
|
|
14
4
|
|
|
15
5
|
## Prefer Transform and Opacity
|
|
16
6
|
|
|
17
|
-
Animating **transform** (`x`, `y`, `scaleX`, `scaleY`, `rotation`, `rotationX`, `rotationY`, `skewX`, `skewY`) and **opacity** keeps work on the compositor and avoids layout and most paint.
|
|
7
|
+
Animating **transform** (`x`, `y`, `scaleX`, `scaleY`, `rotation`, `rotationX`, `rotationY`, `skewX`, `skewY`) and **opacity** keeps work on the compositor and avoids layout and most paint.
|
|
18
8
|
|
|
19
9
|
- ✅ Prefer: **x**, **y**, **scale**, **rotation**, **opacity**.
|
|
20
10
|
- ❌ Avoid when possible: **width**, **height**, **top**, **left**, **margin**, **padding** (they trigger layout and can cause jank).
|
|
21
11
|
|
|
22
|
-
GSAP
|
|
12
|
+
GSAP's **x** and **y** use transforms (translate) by default; use them instead of **left**/**top** for movement.
|
|
23
13
|
|
|
24
14
|
## will-change
|
|
25
15
|
|
|
@@ -35,13 +25,13 @@ GSAP batches updates internally. When mixing GSAP with direct DOM reads/writes o
|
|
|
35
25
|
|
|
36
26
|
## Many Elements (Stagger, Lists)
|
|
37
27
|
|
|
38
|
-
- Use **stagger** instead of many separate tweens with manual delays when the animation is the same; it
|
|
39
|
-
- For long lists, consider **virtualization** or animating only visible items; avoid
|
|
28
|
+
- Use **stagger** instead of many separate tweens with manual delays when the animation is the same; it's more efficient.
|
|
29
|
+
- For long lists, consider **virtualization** or animating only visible items; avoid hundreds of simultaneous tweens if it causes jank.
|
|
40
30
|
- Reuse timelines where possible; avoid creating new timelines every frame.
|
|
41
31
|
|
|
42
32
|
## Frequently updated properties (e.g. mouse followers)
|
|
43
33
|
|
|
44
|
-
Prefer **gsap.quickTo()** for properties
|
|
34
|
+
Prefer **gsap.quickTo()** for properties updated often (e.g. mouse-follower x/y). It reuses a single tween instead of creating a new one on each update.
|
|
45
35
|
|
|
46
36
|
```javascript
|
|
47
37
|
let xTo = gsap.quickTo("#id", "x", { duration: 0.4, ease: "power3" }),
|
|
@@ -55,13 +45,13 @@ document.querySelector("#container").addEventListener("mousemove", (e) => {
|
|
|
55
45
|
|
|
56
46
|
## ScrollTrigger and Performance
|
|
57
47
|
|
|
58
|
-
- **pin: true** promotes the pinned element; pin only what
|
|
48
|
+
- **pin: true** promotes the pinned element; pin only what's needed.
|
|
59
49
|
- **scrub** with a small value (e.g. `scrub: 1`) can reduce work during scroll; test on low-end devices.
|
|
60
50
|
- Call **ScrollTrigger.refresh()** only when layout actually changes (e.g. after content load), not on every resize; debounce when possible.
|
|
61
51
|
|
|
62
52
|
## Reduce Simultaneous Work
|
|
63
53
|
|
|
64
|
-
- Pause or kill off-screen or inactive animations when
|
|
54
|
+
- Pause or kill off-screen or inactive animations when not visible (e.g. when the user navigates away).
|
|
65
55
|
- Avoid animating huge numbers of properties on many elements at once; simplify or sequence if needed.
|
|
66
56
|
|
|
67
57
|
## Best practices
|
|
@@ -73,7 +63,7 @@ document.querySelector("#container").addEventListener("mousemove", (e) => {
|
|
|
73
63
|
|
|
74
64
|
## Do Not
|
|
75
65
|
|
|
76
|
-
- ❌ Animate **width
|
|
77
|
-
- ❌ Set **will-change** or **force3D** on every element
|
|
66
|
+
- ❌ Animate **width**/**height**/**top**/**left** for movement when **x**/**y**/**scale** can achieve the same look.
|
|
67
|
+
- ❌ Set **will-change** or **force3D** on every element "just in case"; use for elements that are actually animating.
|
|
78
68
|
- ❌ Create hundreds of overlapping tweens or ScrollTriggers without testing on low-end devices.
|
|
79
69
|
- ❌ Ignore cleanup; stray tweens and ScrollTriggers keep running and can hurt performance and correctness.
|