wizz-method 1.3.2 → 1.4.1
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-plugin/marketplace.json +4 -4
- package/README.md +1 -1
- package/evals/routing/dataset.json +290 -0
- package/evals/routing/run-routing-eval.mjs +89 -0
- package/package.json +11 -3
- package/skills-registry.yaml +72 -25
- package/src/modules/wizz/agents/wizz-ads/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-copy/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-designer/SKILL.md +6 -8
- package/src/modules/wizz/agents/wizz-growth/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-maestro/SKILL.md +6 -5
- package/src/modules/wizz/agents/wizz-memoria/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-qa/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-seo/SKILL.md +1 -1
- package/src/modules/wizz/agents/wizz-social/SKILL.md +1 -1
- package/src/skills-lib/ai-product-design/SKILL.md +85 -0
- package/src/skills-lib/ai-product-design/references/LICENSE +21 -0
- package/src/skills-lib/ai-product-design/references/ai-alignment-reasoning/bias-detection-design/SKILL.md +37 -0
- package/src/skills-lib/ai-product-design/references/ai-alignment-reasoning/consent-and-agency/SKILL.md +37 -0
- package/src/skills-lib/ai-product-design/references/ai-alignment-reasoning/escalation-design/SKILL.md +40 -0
- package/src/skills-lib/ai-product-design/references/ai-alignment-reasoning/guardrail-design/SKILL.md +36 -0
- package/src/skills-lib/ai-product-design/references/ai-alignment-reasoning/harm-anticipation/SKILL.md +108 -0
- package/src/skills-lib/ai-product-design/references/ai-alignment-reasoning/transparency-patterns/SKILL.md +36 -0
- package/src/skills-lib/ai-product-design/references/ai-alignment-reasoning/trust-calibration/SKILL.md +102 -0
- package/src/skills-lib/ai-product-design/references/ai-alignment-reasoning/value-specification/SKILL.md +39 -0
- package/src/skills-lib/ai-product-design/references/design-agent-orchestration/agent-role-design/SKILL.md +37 -0
- package/src/skills-lib/ai-product-design/references/design-agent-orchestration/failure-recovery/SKILL.md +37 -0
- package/src/skills-lib/ai-product-design/references/design-agent-orchestration/handoff-protocols/SKILL.md +45 -0
- package/src/skills-lib/ai-product-design/references/design-agent-orchestration/human-in-the-loop/SKILL.md +39 -0
- package/src/skills-lib/ai-product-design/references/design-agent-orchestration/observability-design/SKILL.md +48 -0
- package/src/skills-lib/ai-product-design/references/design-agent-orchestration/state-management/SKILL.md +95 -0
- package/src/skills-lib/ai-product-design/references/design-agent-orchestration/task-decomposition/SKILL.md +36 -0
- package/src/skills-lib/ai-product-design/references/evaluation/comparative-evaluation/SKILL.md +39 -0
- package/src/skills-lib/ai-product-design/references/evaluation/failure-taxonomy/SKILL.md +47 -0
- package/src/skills-lib/ai-product-design/references/evaluation/heuristic-evaluation-ai/SKILL.md +46 -0
- package/src/skills-lib/ai-product-design/references/evaluation/longitudinal-measurement/SKILL.md +38 -0
- package/src/skills-lib/ai-product-design/references/evaluation/output-quality-rubrics/SKILL.md +41 -0
- package/src/skills-lib/ai-product-design/references/evaluation/task-success-metrics/SKILL.md +35 -0
- package/src/skills-lib/ai-product-design/references/evaluation/user-satisfaction-signals/SKILL.md +50 -0
- package/src/skills-lib/ai-product-design/references/model-interaction-design/context-window-design/SKILL.md +28 -0
- package/src/skills-lib/ai-product-design/references/model-interaction-design/conversation-patterns/SKILL.md +37 -0
- package/src/skills-lib/ai-product-design/references/model-interaction-design/feedback-loops/SKILL.md +35 -0
- package/src/skills-lib/ai-product-design/references/model-interaction-design/frustration-detection/SKILL.md +91 -0
- package/src/skills-lib/ai-product-design/references/model-interaction-design/generative-ui/SKILL.md +34 -0
- package/src/skills-lib/ai-product-design/references/model-interaction-design/mixed-initiative-flow/SKILL.md +39 -0
- package/src/skills-lib/ai-product-design/references/model-interaction-design/multimodal-orchestration/SKILL.md +94 -0
- package/src/skills-lib/ai-product-design/references/model-interaction-design/progressive-disclosure/SKILL.md +33 -0
- package/src/skills-lib/ai-product-design/references/prompt-architecture/chain-of-thought-design/SKILL.md +45 -0
- package/src/skills-lib/ai-product-design/references/prompt-architecture/constraint-specification/SKILL.md +50 -0
- package/src/skills-lib/ai-product-design/references/prompt-architecture/context-engineering/SKILL.md +45 -0
- package/src/skills-lib/ai-product-design/references/prompt-architecture/few-shot-patterns/SKILL.md +47 -0
- package/src/skills-lib/ai-product-design/references/prompt-architecture/prompt-versioning/SKILL.md +42 -0
- package/src/skills-lib/ai-product-design/references/prompt-architecture/system-prompt-structure/SKILL.md +50 -0
- package/src/skills-lib/ai-product-design/references/prompt-architecture/template-design/SKILL.md +42 -0
- package/src/skills-lib/ai-product-design/references/system-behavior-shaping/behavioral-consistency/SKILL.md +36 -0
- package/src/skills-lib/ai-product-design/references/system-behavior-shaping/cultural-adaptation/SKILL.md +38 -0
- package/src/skills-lib/ai-product-design/references/system-behavior-shaping/domain-voice/SKILL.md +51 -0
- package/src/skills-lib/ai-product-design/references/system-behavior-shaping/emotional-design/SKILL.md +51 -0
- package/src/skills-lib/ai-product-design/references/system-behavior-shaping/error-personality/SKILL.md +45 -0
- package/src/skills-lib/ai-product-design/references/system-behavior-shaping/persona-architecture/SKILL.md +38 -0
- package/src/skills-lib/ai-product-design/references/system-behavior-shaping/tone-calibration/SKILL.md +39 -0
- package/src/skills-lib/algorithmic-art/LICENSE.txt +202 -0
- package/src/skills-lib/algorithmic-art/SKILL.md +405 -0
- package/src/skills-lib/algorithmic-art/templates/generator_template.js +223 -0
- package/src/skills-lib/algorithmic-art/templates/viewer.html +599 -0
- package/src/skills-lib/animate/README.md +41 -0
- package/src/skills-lib/animate/SKILL.md +179 -0
- package/src/skills-lib/animate/examples/animate-height.tsx +75 -0
- package/src/skills-lib/animate/examples/app-store-card.tsx +164 -0
- package/src/skills-lib/animate/examples/card-hover.tsx +79 -0
- package/src/skills-lib/animate/examples/feedback-popover.tsx +119 -0
- package/src/skills-lib/animate/examples/multi-step-flow.tsx +128 -0
- package/src/skills-lib/animate/examples/shared-layout.tsx +64 -0
- package/src/skills-lib/animate/examples/text-reveal.tsx +70 -0
- package/src/skills-lib/animate/examples/toast-stacking.tsx +95 -0
- package/src/skills-lib/animate/references/css-animations.md +232 -0
- package/src/skills-lib/animate/references/easing-and-timing.md +105 -0
- package/src/skills-lib/animate/references/framer-motion.md +356 -0
- package/src/skills-lib/animate/references/performance-accessibility.md +185 -0
- package/src/skills-lib/auth-and-secrets/SKILL.md +38 -10
- package/src/skills-lib/canvas-design/LICENSE.txt +202 -0
- package/src/skills-lib/canvas-design/SKILL.md +130 -0
- package/src/skills-lib/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
- package/src/skills-lib/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/src/skills-lib/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
- package/src/skills-lib/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/src/skills-lib/design-motion-principles/SKILL.md +122 -0
- package/src/skills-lib/design-motion-principles/references/accessibility.md +52 -0
- package/src/skills-lib/design-motion-principles/references/anti-checklist.md +274 -0
- package/src/skills-lib/design-motion-principles/references/audit-checklist.md +137 -0
- package/src/skills-lib/design-motion-principles/references/creation-gotchas.md +36 -0
- package/src/skills-lib/design-motion-principles/references/demo-shell.html +275 -0
- package/src/skills-lib/design-motion-principles/references/emil-kowalski.md +121 -0
- package/src/skills-lib/design-motion-principles/references/jakub-krehel.md +80 -0
- package/src/skills-lib/design-motion-principles/references/jhey-tompkins.md +122 -0
- package/src/skills-lib/design-motion-principles/references/motion-cookbook.md +529 -0
- package/src/skills-lib/design-motion-principles/references/output-format.md +346 -0
- package/src/skills-lib/design-motion-principles/references/performance.md +82 -0
- package/src/skills-lib/design-motion-principles/references/report-template.html +1006 -0
- package/src/skills-lib/design-motion-principles/workflows/audit.md +203 -0
- package/src/skills-lib/design-motion-principles/workflows/create.md +87 -0
- package/src/skills-lib/desktop-security/SKILL.md +35 -4
- package/src/skills-lib/premium-landing-ui-researcher/SKILL.md +52 -2083
- package/src/skills-lib/premium-landing-ui-researcher/references/audit-protocol.md +124 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/component-sources.md +336 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/core-goal.md +62 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/dashboard-and-portfolio-modes.md +92 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/handoffs.md +55 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/landing-page-strategy.md +227 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/mandatory-process.md +36 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/output-format-and-quality.md +129 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/prompt-templates.md +206 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/site-levels.md +515 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/source-first-protocol.md +144 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/source-links.md +39 -0
- package/src/skills-lib/premium-landing-ui-researcher/references/stack-and-visual-direction.md +118 -0
- package/src/skills-lib/taste-skill/SKILL.md +33 -1177
- package/src/skills-lib/taste-skill/references/anti-slop-tells.md +110 -0
- package/src/skills-lib/taste-skill/references/architecture-conventions.md +39 -0
- package/src/skills-lib/taste-skill/references/block-library.md +61 -0
- package/src/skills-lib/taste-skill/references/brief-and-dials.md +89 -0
- package/src/skills-lib/taste-skill/references/dark-mode.md +23 -0
- package/src/skills-lib/taste-skill/references/design-directives.md +191 -0
- package/src/skills-lib/taste-skill/references/design-systems.md +267 -0
- package/src/skills-lib/taste-skill/references/motion-patterns.md +167 -0
- package/src/skills-lib/taste-skill/references/pattern-vocabulary.md +78 -0
- package/src/skills-lib/taste-skill/references/performance-a11y.md +33 -0
- package/src/skills-lib/taste-skill/references/preflight-checklist.md +73 -0
- package/src/skills-lib/taste-skill/references/redesign-protocol.md +52 -0
- package/src/skills-lib/web-security/SKILL.md +74 -6
- package/src/skills-lib/wizz-router/SKILL.md +21 -243
- package/src/skills-lib/wizz-router/references/auditoria-360.md +21 -0
- package/src/skills-lib/wizz-router/references/routing-table-flat.md +95 -0
- package/src/squads/advisory-board/agents/ray-dalio.md +0 -20
- package/tools/hooks/README.md +17 -0
- package/tools/hooks/security-defensive-context.js +70 -0
- package/tools/hooks/session-rules.js +38 -0
- package/tools/hooks/wizz-router-enforce.js +188 -0
- package/tools/installer/modules/skills-lib.js +70 -1
- package/tools/sync-global.mjs +84 -0
- package/.claude/settings.local.json +0 -8
- package/src/core-skills/wizz-party-mode/scripts/__pycache__/resolve_party.cpython-314.pyc +0 -0
- package/src/skills-lib/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
- package/src/skills-lib/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
- package/src/skills-lib/ui-ux-pro-max/scripts/__pycache__/search.cpython-314.pyc +0 -0
- package/src/skills-lib/ui-ux-pro-max/scripts/graphify-out/cache/0964cef300f753b5cee0cc49777ca97035c85d45c212099405d9ee4da36e523f.json +0 -1
- package/src/skills-lib/ui-ux-pro-max/scripts/graphify-out/cache/21a40f6810c3a6f17acc3580f106171daf78c7b41bbd066bc80448a821ea0adf.json +0 -1
- package/src/skills-lib/ui-ux-pro-max/scripts/graphify-out/cache/69ea15a020ac81b8459e37ef63654398a50c1035fc01c43d8069df217389f7f3.json +0 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Step Flow Animation
|
|
3
|
+
*
|
|
4
|
+
* Animated wizard/stepper with directional slide transitions.
|
|
5
|
+
* Steps slide in from the direction of navigation.
|
|
6
|
+
*
|
|
7
|
+
* Key techniques:
|
|
8
|
+
* - AnimatePresence mode="popLayout" for exit animations
|
|
9
|
+
* - custom prop for directional variants (slide left or right)
|
|
10
|
+
* - useMeasure for animating container height
|
|
11
|
+
* - useReducedMotion for accessibility
|
|
12
|
+
* - MotionConfig for shared transition settings
|
|
13
|
+
*/
|
|
14
|
+
"use client";
|
|
15
|
+
|
|
16
|
+
import { useMemo, useState } from "react";
|
|
17
|
+
import {
|
|
18
|
+
AnimatePresence,
|
|
19
|
+
MotionConfig,
|
|
20
|
+
motion,
|
|
21
|
+
useReducedMotion,
|
|
22
|
+
} from "framer-motion";
|
|
23
|
+
import useMeasure from "react-use-measure";
|
|
24
|
+
|
|
25
|
+
// Directional slide variants
|
|
26
|
+
const variants = {
|
|
27
|
+
initial: (direction: number) => ({
|
|
28
|
+
x: `${110 * direction}%`,
|
|
29
|
+
opacity: 0,
|
|
30
|
+
}),
|
|
31
|
+
active: {
|
|
32
|
+
x: "0%",
|
|
33
|
+
opacity: 1,
|
|
34
|
+
},
|
|
35
|
+
exit: (direction: number) => ({
|
|
36
|
+
x: `${-110 * direction}%`,
|
|
37
|
+
opacity: 0,
|
|
38
|
+
}),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Reduced motion alternative - just fade
|
|
42
|
+
const reducedMotionVariants = {
|
|
43
|
+
initial: { opacity: 0 },
|
|
44
|
+
active: { opacity: 1 },
|
|
45
|
+
exit: { opacity: 0 },
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default function MultiStepComponent() {
|
|
49
|
+
const [currentStep, setCurrentStep] = useState(0);
|
|
50
|
+
const [direction, setDirection] = useState<number>(0);
|
|
51
|
+
const [ref, bounds] = useMeasure();
|
|
52
|
+
const reducedMotion = useReducedMotion();
|
|
53
|
+
|
|
54
|
+
const content = useMemo(() => {
|
|
55
|
+
switch (currentStep) {
|
|
56
|
+
case 0:
|
|
57
|
+
return (
|
|
58
|
+
<>
|
|
59
|
+
<h2>Step One</h2>
|
|
60
|
+
<p>First step content goes here.</p>
|
|
61
|
+
</>
|
|
62
|
+
);
|
|
63
|
+
case 1:
|
|
64
|
+
return (
|
|
65
|
+
<>
|
|
66
|
+
<h2>Step Two</h2>
|
|
67
|
+
<p>Second step with different content length.</p>
|
|
68
|
+
<p>Extra paragraph to show height animation.</p>
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
71
|
+
case 2:
|
|
72
|
+
return (
|
|
73
|
+
<>
|
|
74
|
+
<h2>Step Three</h2>
|
|
75
|
+
<p>Final step - you made it!</p>
|
|
76
|
+
</>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}, [currentStep]);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<MotionConfig transition={{ duration: 0.5, type: "spring", bounce: 0 }}>
|
|
83
|
+
{/* Container animates height based on content */}
|
|
84
|
+
<motion.div
|
|
85
|
+
className="multi-step-wrapper"
|
|
86
|
+
animate={reducedMotion ? {} : { height: bounds.height }}
|
|
87
|
+
>
|
|
88
|
+
<div className="multi-step-inner" ref={ref}>
|
|
89
|
+
{/* AnimatePresence handles exit animations */}
|
|
90
|
+
<AnimatePresence mode="popLayout" initial={false} custom={direction}>
|
|
91
|
+
<motion.div
|
|
92
|
+
key={currentStep}
|
|
93
|
+
variants={reducedMotion ? reducedMotionVariants : variants}
|
|
94
|
+
initial="initial"
|
|
95
|
+
animate="active"
|
|
96
|
+
exit="exit"
|
|
97
|
+
custom={direction}
|
|
98
|
+
>
|
|
99
|
+
{content}
|
|
100
|
+
</motion.div>
|
|
101
|
+
</AnimatePresence>
|
|
102
|
+
|
|
103
|
+
{/* Buttons use layout animation to stay in place */}
|
|
104
|
+
<motion.div className="actions" layout={!reducedMotion}>
|
|
105
|
+
<button
|
|
106
|
+
disabled={currentStep === 0}
|
|
107
|
+
onClick={() => {
|
|
108
|
+
setCurrentStep((prev) => prev - 1);
|
|
109
|
+
setDirection(-1); // Slide from left
|
|
110
|
+
}}
|
|
111
|
+
>
|
|
112
|
+
Back
|
|
113
|
+
</button>
|
|
114
|
+
<button
|
|
115
|
+
disabled={currentStep === 2}
|
|
116
|
+
onClick={() => {
|
|
117
|
+
setCurrentStep((prev) => prev + 1);
|
|
118
|
+
setDirection(1); // Slide from right
|
|
119
|
+
}}
|
|
120
|
+
>
|
|
121
|
+
Continue
|
|
122
|
+
</button>
|
|
123
|
+
</motion.div>
|
|
124
|
+
</div>
|
|
125
|
+
</motion.div>
|
|
126
|
+
</MotionConfig>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Layout Animation
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates Framer Motion's layoutId for seamless transitions
|
|
5
|
+
* between two different elements/positions.
|
|
6
|
+
*
|
|
7
|
+
* Key techniques:
|
|
8
|
+
* - layoutId creates a shared identity between elements
|
|
9
|
+
* - Motion automatically animates position and size changes
|
|
10
|
+
* - style={{ borderRadius }} prevents border radius distortion during animation
|
|
11
|
+
*/
|
|
12
|
+
"use client";
|
|
13
|
+
|
|
14
|
+
import { motion } from "framer-motion";
|
|
15
|
+
import { useState } from "react";
|
|
16
|
+
|
|
17
|
+
// styles.css
|
|
18
|
+
const styles = `
|
|
19
|
+
.wrapper {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
gap: 24px;
|
|
23
|
+
align-items: center;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.element {
|
|
27
|
+
width: 100px;
|
|
28
|
+
height: 100px;
|
|
29
|
+
background: #3b82f6;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.second-element {
|
|
33
|
+
width: 200px;
|
|
34
|
+
height: 200px;
|
|
35
|
+
background: #3b82f6;
|
|
36
|
+
}
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
export default function SharedLayoutExample() {
|
|
40
|
+
const [showSecond, setShowSecond] = useState(false);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className="wrapper">
|
|
44
|
+
<button onClick={() => setShowSecond((s) => !s)}>
|
|
45
|
+
Animate
|
|
46
|
+
</button>
|
|
47
|
+
|
|
48
|
+
{/* Same layoutId = smooth transition between the two */}
|
|
49
|
+
{showSecond ? (
|
|
50
|
+
<motion.div
|
|
51
|
+
layoutId="rectangle"
|
|
52
|
+
className="second-element"
|
|
53
|
+
style={{ borderRadius: 12 }}
|
|
54
|
+
/>
|
|
55
|
+
) : (
|
|
56
|
+
<motion.div
|
|
57
|
+
layoutId="rectangle"
|
|
58
|
+
className="element"
|
|
59
|
+
style={{ borderRadius: 12 }}
|
|
60
|
+
/>
|
|
61
|
+
)}
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text Reveal Animation
|
|
3
|
+
*
|
|
4
|
+
* Staggered letter-by-letter text reveal animation using CSS keyframes.
|
|
5
|
+
* Each letter animates in sequence with a delay based on its index.
|
|
6
|
+
*
|
|
7
|
+
* Key techniques:
|
|
8
|
+
* - Split text into individual spans
|
|
9
|
+
* - CSS custom property (--index) for stagger delay
|
|
10
|
+
* - @keyframes for the reveal animation
|
|
11
|
+
* - animation-fill-mode: backwards to hide before animation
|
|
12
|
+
* - cubic-bezier for smooth easing
|
|
13
|
+
*/
|
|
14
|
+
"use client";
|
|
15
|
+
|
|
16
|
+
import { useState } from "react";
|
|
17
|
+
|
|
18
|
+
// text-reveal.css
|
|
19
|
+
const styles = `
|
|
20
|
+
.h1 {
|
|
21
|
+
font-size: 4rem;
|
|
22
|
+
font-weight: bold;
|
|
23
|
+
overflow: hidden;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.h1 span {
|
|
27
|
+
display: inline-block;
|
|
28
|
+
animation: reveal 1.3s cubic-bezier(0.19, 1, 0.22, 1);
|
|
29
|
+
animation-fill-mode: backwards;
|
|
30
|
+
animation-delay: calc(var(--index) * 0.03s);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@keyframes reveal {
|
|
34
|
+
from {
|
|
35
|
+
transform: translateY(100%);
|
|
36
|
+
opacity: 0;
|
|
37
|
+
}
|
|
38
|
+
to {
|
|
39
|
+
transform: translateY(0);
|
|
40
|
+
opacity: 1;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
const WORD = "Animations";
|
|
46
|
+
|
|
47
|
+
export default function TextReveal() {
|
|
48
|
+
const [reset, setReset] = useState(0);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className="flex flex-col gap-4">
|
|
52
|
+
{/* Key change forces re-render and replays animation */}
|
|
53
|
+
<div key={reset}>
|
|
54
|
+
<h1 className="h1">
|
|
55
|
+
{WORD.split("").map((char, index) => (
|
|
56
|
+
<span
|
|
57
|
+
key={index}
|
|
58
|
+
style={{ "--index": index } as React.CSSProperties}
|
|
59
|
+
>
|
|
60
|
+
{char}
|
|
61
|
+
</span>
|
|
62
|
+
))}
|
|
63
|
+
</h1>
|
|
64
|
+
</div>
|
|
65
|
+
<button onClick={() => setReset(reset + 1)}>
|
|
66
|
+
Replay animation
|
|
67
|
+
</button>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toast Stacking Animation
|
|
3
|
+
*
|
|
4
|
+
* Animated toast notifications that stack vertically with smooth transitions.
|
|
5
|
+
* Uses CSS custom properties (--index) for dynamic positioning.
|
|
6
|
+
*
|
|
7
|
+
* Key techniques:
|
|
8
|
+
* - CSS custom properties for dynamic values
|
|
9
|
+
* - data-* attributes to trigger CSS transitions
|
|
10
|
+
* - useEffect to trigger mount animation
|
|
11
|
+
* - calc() for computing stack positions
|
|
12
|
+
*/
|
|
13
|
+
"use client";
|
|
14
|
+
|
|
15
|
+
import { useEffect, useState } from "react";
|
|
16
|
+
|
|
17
|
+
// toast-animation.css
|
|
18
|
+
const styles = `
|
|
19
|
+
.toast {
|
|
20
|
+
position: absolute;
|
|
21
|
+
bottom: 0;
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
gap: 4px;
|
|
25
|
+
padding: 10px 14px 13px;
|
|
26
|
+
width: 100%;
|
|
27
|
+
font-size: 13px;
|
|
28
|
+
border-radius: 8px;
|
|
29
|
+
background: white;
|
|
30
|
+
box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.08),
|
|
31
|
+
0px 1px 2px -1px rgba(0, 0, 0, 0.08),
|
|
32
|
+
0px 2px 4px 0px rgba(0, 0, 0, 0.04);
|
|
33
|
+
|
|
34
|
+
/* Animation - starts hidden below */
|
|
35
|
+
transition-property: transform, opacity;
|
|
36
|
+
transition-duration: 350ms;
|
|
37
|
+
transition-timing-function: ease;
|
|
38
|
+
transform: translateY(100%);
|
|
39
|
+
opacity: 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Animate to stacked position when mounted */
|
|
43
|
+
.toast[data-mounted="true"] {
|
|
44
|
+
transform: translateY(calc(var(--index) * (100% + var(--gap)) * -1));
|
|
45
|
+
opacity: 1;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.toaster {
|
|
49
|
+
position: absolute;
|
|
50
|
+
left: 50%;
|
|
51
|
+
bottom: 80px;
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
gap: var(--gap);
|
|
55
|
+
width: 356px;
|
|
56
|
+
transform: translateX(-50%);
|
|
57
|
+
--gap: 16px;
|
|
58
|
+
}
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
export default function Toaster() {
|
|
62
|
+
const [toasts, setToasts] = useState(0);
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className="toast-wrapper">
|
|
66
|
+
<div className="toaster">
|
|
67
|
+
{Array.from({ length: toasts }).map((_, i) => (
|
|
68
|
+
<Toast key={i} index={toasts - (i + 1)} />
|
|
69
|
+
))}
|
|
70
|
+
</div>
|
|
71
|
+
<button onClick={() => setToasts(toasts + 1)}>
|
|
72
|
+
Add toast
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function Toast({ index }: { index: number }) {
|
|
79
|
+
const [mounted, setMounted] = useState(false);
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
setMounted(true);
|
|
83
|
+
}, []);
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<div
|
|
87
|
+
className="toast"
|
|
88
|
+
style={{ "--index": index } as React.CSSProperties}
|
|
89
|
+
data-mounted={mounted}
|
|
90
|
+
>
|
|
91
|
+
<span className="title">Event Created</span>
|
|
92
|
+
<span className="description">Monday, January 3rd at 6:00pm</span>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# CSS Animations Reference
|
|
2
|
+
|
|
3
|
+
## Transforms
|
|
4
|
+
|
|
5
|
+
Transforms change an element's position, size, or rotation without affecting layout. They are GPU-accelerated and performant.
|
|
6
|
+
|
|
7
|
+
### Transform Functions
|
|
8
|
+
|
|
9
|
+
```css
|
|
10
|
+
/* Translation (movement) */
|
|
11
|
+
transform: translateX(10px);
|
|
12
|
+
transform: translateY(-20px);
|
|
13
|
+
transform: translate(10px, -20px); /* X, Y */
|
|
14
|
+
transform: translate3d(10px, 20px, 30px); /* X, Y, Z */
|
|
15
|
+
|
|
16
|
+
/* Scale */
|
|
17
|
+
transform: scale(1.1); /* Uniform scale */
|
|
18
|
+
transform: scaleX(0.5);
|
|
19
|
+
transform: scaleY(1.5);
|
|
20
|
+
transform: scale(0.5, 1.5); /* X, Y */
|
|
21
|
+
|
|
22
|
+
/* Rotation */
|
|
23
|
+
transform: rotate(45deg);
|
|
24
|
+
transform: rotateX(45deg); /* 3D - around X axis */
|
|
25
|
+
transform: rotateY(45deg); /* 3D - around Y axis */
|
|
26
|
+
transform: rotateZ(45deg); /* Same as rotate() */
|
|
27
|
+
|
|
28
|
+
/* Combining transforms */
|
|
29
|
+
transform: translateY(-10px) scale(1.05) rotate(5deg);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Transform Origin
|
|
33
|
+
|
|
34
|
+
Controls the point around which transforms occur:
|
|
35
|
+
|
|
36
|
+
```css
|
|
37
|
+
transform-origin: center; /* Default */
|
|
38
|
+
transform-origin: top left;
|
|
39
|
+
transform-origin: 50% 100%; /* Center bottom */
|
|
40
|
+
transform-origin: 0 0; /* Top left corner */
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 3D Transforms
|
|
44
|
+
|
|
45
|
+
```css
|
|
46
|
+
/* Enable 3D space on parent */
|
|
47
|
+
.parent {
|
|
48
|
+
perspective: 1000px; /* Distance from viewer */
|
|
49
|
+
perspective-origin: center;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* 3D transforms on children */
|
|
53
|
+
.child {
|
|
54
|
+
transform: rotateY(45deg);
|
|
55
|
+
transform-style: preserve-3d; /* Maintain 3D for nested elements */
|
|
56
|
+
backface-visibility: hidden; /* Hide back of element */
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Transitions
|
|
61
|
+
|
|
62
|
+
Transitions animate property changes over time.
|
|
63
|
+
|
|
64
|
+
### Syntax
|
|
65
|
+
|
|
66
|
+
```css
|
|
67
|
+
/* Individual properties */
|
|
68
|
+
transition-property: transform, opacity;
|
|
69
|
+
transition-duration: 200ms;
|
|
70
|
+
transition-timing-function: ease-out;
|
|
71
|
+
transition-delay: 0ms;
|
|
72
|
+
|
|
73
|
+
/* Shorthand */
|
|
74
|
+
transition: transform 200ms ease-out, opacity 150ms ease-out 50ms;
|
|
75
|
+
/* property duration timing property duration timing delay */
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Common Transition Patterns
|
|
79
|
+
|
|
80
|
+
```css
|
|
81
|
+
/* Hover lift effect */
|
|
82
|
+
.card {
|
|
83
|
+
transition: transform 200ms ease-out, box-shadow 200ms ease-out;
|
|
84
|
+
}
|
|
85
|
+
.card:hover {
|
|
86
|
+
transform: translateY(-4px);
|
|
87
|
+
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Button press effect */
|
|
91
|
+
.button {
|
|
92
|
+
transition: transform 100ms ease-out;
|
|
93
|
+
}
|
|
94
|
+
.button:active {
|
|
95
|
+
transform: scale(0.97);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Fade in/out */
|
|
99
|
+
.element {
|
|
100
|
+
opacity: 0;
|
|
101
|
+
transition: opacity 200ms ease-out;
|
|
102
|
+
}
|
|
103
|
+
.element.visible {
|
|
104
|
+
opacity: 1;
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Performance-Safe Properties
|
|
109
|
+
|
|
110
|
+
These properties are GPU-accelerated and won't cause layout recalculation:
|
|
111
|
+
- `transform`
|
|
112
|
+
- `opacity`
|
|
113
|
+
|
|
114
|
+
Avoid animating (cause layout/paint):
|
|
115
|
+
- `width`, `height`
|
|
116
|
+
- `top`, `left`, `right`, `bottom`
|
|
117
|
+
- `margin`, `padding`
|
|
118
|
+
- `border-width`
|
|
119
|
+
|
|
120
|
+
## Keyframe Animations
|
|
121
|
+
|
|
122
|
+
For complex, multi-step animations.
|
|
123
|
+
|
|
124
|
+
### Basic Syntax
|
|
125
|
+
|
|
126
|
+
```css
|
|
127
|
+
@keyframes fadeIn {
|
|
128
|
+
from {
|
|
129
|
+
opacity: 0;
|
|
130
|
+
transform: translateY(10px);
|
|
131
|
+
}
|
|
132
|
+
to {
|
|
133
|
+
opacity: 1;
|
|
134
|
+
transform: translateY(0);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@keyframes pulse {
|
|
139
|
+
0%, 100% {
|
|
140
|
+
transform: scale(1);
|
|
141
|
+
}
|
|
142
|
+
50% {
|
|
143
|
+
transform: scale(1.05);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.element {
|
|
148
|
+
animation: fadeIn 300ms ease-out forwards;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Animation Properties
|
|
153
|
+
|
|
154
|
+
```css
|
|
155
|
+
animation-name: fadeIn;
|
|
156
|
+
animation-duration: 300ms;
|
|
157
|
+
animation-timing-function: ease-out;
|
|
158
|
+
animation-delay: 0ms;
|
|
159
|
+
animation-iteration-count: 1; /* or 'infinite' */
|
|
160
|
+
animation-direction: normal; /* or 'reverse', 'alternate' */
|
|
161
|
+
animation-fill-mode: forwards; /* 'none', 'forwards', 'backwards', 'both' */
|
|
162
|
+
animation-play-state: running; /* or 'paused' */
|
|
163
|
+
|
|
164
|
+
/* Shorthand */
|
|
165
|
+
animation: fadeIn 300ms ease-out 0ms 1 normal forwards;
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Fill Modes Explained
|
|
169
|
+
|
|
170
|
+
- `none`: No styles applied before/after animation
|
|
171
|
+
- `forwards`: Retains final keyframe styles after animation
|
|
172
|
+
- `backwards`: Applies initial keyframe styles during delay
|
|
173
|
+
- `both`: Applies both forwards and backwards
|
|
174
|
+
|
|
175
|
+
## Clip-Path Animations
|
|
176
|
+
|
|
177
|
+
Clip-path creates masked areas that can be animated.
|
|
178
|
+
|
|
179
|
+
### Common Shapes
|
|
180
|
+
|
|
181
|
+
```css
|
|
182
|
+
/* Circle */
|
|
183
|
+
clip-path: circle(50% at center);
|
|
184
|
+
clip-path: circle(0% at center); /* Hidden */
|
|
185
|
+
|
|
186
|
+
/* Ellipse */
|
|
187
|
+
clip-path: ellipse(50% 30% at center);
|
|
188
|
+
|
|
189
|
+
/* Inset (rectangle) */
|
|
190
|
+
clip-path: inset(0); /* Full visibility */
|
|
191
|
+
clip-path: inset(50%); /* Hidden (collapsed to center) */
|
|
192
|
+
clip-path: inset(0 50% 0 0); /* Right half hidden */
|
|
193
|
+
/* inset(top right bottom left) */
|
|
194
|
+
|
|
195
|
+
/* Polygon */
|
|
196
|
+
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); /* Rectangle */
|
|
197
|
+
clip-path: polygon(50% 0, 100% 100%, 0 100%); /* Triangle */
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Clip-Path Animation Example (Image Comparison Slider)
|
|
201
|
+
|
|
202
|
+
```css
|
|
203
|
+
.before-image {
|
|
204
|
+
clip-path: inset(0 50% 0 0); /* Show left half */
|
|
205
|
+
transition: clip-path 0ms; /* Instant update */
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* JavaScript updates the clip-path based on slider position */
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Tab Indicator with Clip-Path
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
// Active tab background slides using clip-path
|
|
215
|
+
<div className="relative">
|
|
216
|
+
{tabs.map((tab, index) => (
|
|
217
|
+
<button
|
|
218
|
+
key={tab}
|
|
219
|
+
onClick={() => setActive(index)}
|
|
220
|
+
className="relative z-10 px-4 py-2"
|
|
221
|
+
>
|
|
222
|
+
{tab}
|
|
223
|
+
</button>
|
|
224
|
+
))}
|
|
225
|
+
<div
|
|
226
|
+
className="absolute inset-0 bg-blue-500 rounded transition-all duration-200"
|
|
227
|
+
style={{
|
|
228
|
+
clipPath: `inset(0 ${100 - (activeIndex + 1) * (100 / tabs.length)}% 0 ${activeIndex * (100 / tabs.length)}% round 8px)`
|
|
229
|
+
}}
|
|
230
|
+
/>
|
|
231
|
+
</div>
|
|
232
|
+
```
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Easing and Timing Reference
|
|
2
|
+
|
|
3
|
+
## Core Principles
|
|
4
|
+
|
|
5
|
+
Animations should feel natural and purposeful. The goal is to make interfaces feel responsive without drawing attention to the animation itself.
|
|
6
|
+
|
|
7
|
+
## Easing Functions
|
|
8
|
+
|
|
9
|
+
### When to Use Each Easing Type
|
|
10
|
+
|
|
11
|
+
| Easing | Use Case | Timing |
|
|
12
|
+
|--------|----------|--------|
|
|
13
|
+
| `ease-out` | Elements entering the screen | 200-300ms |
|
|
14
|
+
| `ease-in-out` | Elements moving on screen | 200-300ms |
|
|
15
|
+
| `ease-in` | Elements exiting the screen | 150-200ms |
|
|
16
|
+
| `ease` | Hover effects | 150ms |
|
|
17
|
+
| `linear` | Opacity changes, progress bars | varies |
|
|
18
|
+
|
|
19
|
+
### Custom Easing Variables
|
|
20
|
+
|
|
21
|
+
Define these CSS custom properties for consistent animations:
|
|
22
|
+
|
|
23
|
+
```css
|
|
24
|
+
:root {
|
|
25
|
+
/* Recommended easing curves */
|
|
26
|
+
--ease-out-quint: cubic-bezier(.23, 1, .32, 1);
|
|
27
|
+
--ease-in-out-cubic: cubic-bezier(.645, .045, .355, 1);
|
|
28
|
+
--ease-out-cubic: cubic-bezier(.33, 1, .68, 1);
|
|
29
|
+
--ease-in-cubic: cubic-bezier(.32, 0, .67, 0);
|
|
30
|
+
|
|
31
|
+
/* Spring-like feel */
|
|
32
|
+
--ease-out-back: cubic-bezier(.34, 1.56, .64, 1);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Cubic Bezier Explained
|
|
37
|
+
|
|
38
|
+
`cubic-bezier(x1, y1, x2, y2)` defines a curve with two control points:
|
|
39
|
+
- `(x1, y1)` - First control point (influences start of animation)
|
|
40
|
+
- `(x2, y2)` - Second control point (influences end of animation)
|
|
41
|
+
|
|
42
|
+
Values > 1 create overshoot effects (like `ease-out-back`).
|
|
43
|
+
|
|
44
|
+
## Timing Guidelines
|
|
45
|
+
|
|
46
|
+
### Duration Sweet Spots
|
|
47
|
+
|
|
48
|
+
- **General animations**: 200-300ms (the sweet spot)
|
|
49
|
+
- **Hover effects**: 150ms
|
|
50
|
+
- **Modal enter**: 200ms
|
|
51
|
+
- **Modal exit**: 150ms (exits should be faster than enters)
|
|
52
|
+
- **Page transitions**: 300-400ms
|
|
53
|
+
- **Micro-interactions**: 100-150ms
|
|
54
|
+
|
|
55
|
+
### Rules of Thumb
|
|
56
|
+
|
|
57
|
+
1. **Exits faster than enters**: Exit animations should be ~75% of enter duration
|
|
58
|
+
2. **Smaller elements = faster animations**: Scale duration with element size
|
|
59
|
+
3. **User-initiated = faster response**: Direct actions should feel immediate
|
|
60
|
+
4. **System-initiated = can be slower**: Background transitions can take longer
|
|
61
|
+
|
|
62
|
+
## Spring Animations
|
|
63
|
+
|
|
64
|
+
Springs are excellent for interruptible animations and natural-feeling motion.
|
|
65
|
+
|
|
66
|
+
### Spring Parameters
|
|
67
|
+
|
|
68
|
+
| Parameter | Effect |
|
|
69
|
+
|-----------|--------|
|
|
70
|
+
| `mass` | Weight of the object (higher = slower, more momentum) |
|
|
71
|
+
| `tension` (stiffness) | Spring tightness (higher = faster, snappier) |
|
|
72
|
+
| `friction` (damping) | Resistance (higher = less oscillation) |
|
|
73
|
+
| `velocity` | Initial speed |
|
|
74
|
+
|
|
75
|
+
### Framer Motion Spring Config
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
// Snappy spring (UI elements)
|
|
79
|
+
const snappy = { type: "spring", stiffness: 400, damping: 30 }
|
|
80
|
+
|
|
81
|
+
// Gentle spring (larger elements)
|
|
82
|
+
const gentle = { type: "spring", stiffness: 200, damping: 20 }
|
|
83
|
+
|
|
84
|
+
// Bouncy spring (playful interactions)
|
|
85
|
+
const bouncy = { type: "spring", stiffness: 300, damping: 10 }
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Duration-Based Springs (Framer Motion)
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
// Using duration instead of physics
|
|
92
|
+
const durationSpring = {
|
|
93
|
+
type: "spring",
|
|
94
|
+
duration: 0.3,
|
|
95
|
+
bounce: 0.2 // 0 = no bounce, 1 = max bounce
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## When NOT to Animate
|
|
100
|
+
|
|
101
|
+
- Loading states that block interaction
|
|
102
|
+
- Error messages that need immediate attention
|
|
103
|
+
- Accessibility: respect `prefers-reduced-motion`
|
|
104
|
+
- When animation adds no value to the experience
|
|
105
|
+
- Repeated actions the user performs frequently
|