Chakra UI v2 to v3 Migration
chakra-ui/chakra-ui
Guides an upgrade from Chakra UI v2 to v3: inspect the project, swap packages, run the official codemod, then fix provider, color mode, props, theming and Next.js code.
Production-ready UI motion system for React/Next.js. An agent skill from templetongroup/radiant.
$ npx skills add templetongroup/radiant --skill motion-ui -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install templetongroup/radiant motion-ui --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/templetongroup/radiant.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/motion-ui .claude/skills/motion-ui && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "motion-ui" agent skill from https://github.com/templetongroup/radiant/tree/master/skills/motion-ui into .claude/skills/motion-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-ui", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/templetongroup/radiant/tree/master/skills/motion-uiType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add templetongroup/radiant --skill motion-ui -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install templetongroup/radiant motion-ui --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/templetongroup/radiant.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/motion-ui .agents/skills/motion-ui && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "motion-ui" agent skill from https://github.com/templetongroup/radiant/tree/master/skills/motion-ui into .agents/skills/motion-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-ui", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add templetongroup/radiant --skill motion-ui -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install templetongroup/radiant motion-ui --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/templetongroup/radiant.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/motion-ui .cursor/skills/motion-ui && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "motion-ui" agent skill from https://github.com/templetongroup/radiant/tree/master/skills/motion-ui into .cursor/skills/motion-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-ui", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/templetongroup/radiant.git --path skills/motion-ui--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add templetongroup/radiant --skill motion-ui -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install templetongroup/radiant motion-ui --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/templetongroup/radiant.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/motion-ui .gemini/skills/motion-ui && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "motion-ui" agent skill from https://github.com/templetongroup/radiant/tree/master/skills/motion-ui into .gemini/skills/motion-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-ui", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install templetongroup/radiant motion-uiInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add templetongroup/radiant --skill motion-ui -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/templetongroup/radiant.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/motion-ui .github/skills/motion-ui && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "motion-ui" agent skill from https://github.com/templetongroup/radiant/tree/master/skills/motion-ui into .github/skills/motion-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-ui", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add templetongroup/radiant --skill motion-ui -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install templetongroup/radiant motion-ui --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/templetongroup/radiant.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/motion-ui .opencode/skills/motion-ui && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "motion-ui" agent skill from https://github.com/templetongroup/radiant/tree/master/skills/motion-ui into .opencode/skills/motion-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-ui", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
motion-uiProduction-ready UI motion system for React/Next.js. An agent skill from templetongroup/radiant.
Motion UI is an agent skill from templetongroup/radiant. Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.
Its SKILL.md is about 3.5k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Frontend & Design. It works with React, Next.js and Motion. The repository describes itself as: A local coding harness for Mac. Chat with coding agents across cloud and local models, watch every tool call in a live activity feed, and drive a real terminal — in one window… The licence is MIT.
Read from SKILL.md and the folder at commit 94838ca. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
npmFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use npm, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Motion UI loads about 3.5k tokens when it runs. Until then it costs about 32 tokens; SKILL.md has 684 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from templetongroup/radiant at commit 94838ca, republished under its MIT licence (© templetongroup). 684 words, ~3,460 tokens.
.claude/skills/motion-ui/SKILL.md (or your agent's skills folder).Production-ready UI motion system for React / Next.js.
Focused on performance, accessibility, and usability — not decoration.
Use this motion system when motion:
Motion must:
If it does none → remove it.
npm install motionmotion/react - default for current Motion for React projects (package: motion)framer-motion - legacy import path for projects that still depend on Framer MotionDo not mix. Mixing causes conflicting internal schedulers and broken AnimatePresence contexts — components from one package will not coordinate exit animations with components from the other.
To check which version your project uses:
cat package.json | grep -E '"motion"|"framer-motion"'Always import from one source consistently:
// Correct (modern)
import { motion, AnimatePresence } from "motion/react"
// Correct (legacy)
import { motion, AnimatePresence } from "framer-motion"
// Never mix both in the same project// motionTokens.ts
export const motionTokens = {
duration: {
fast: 0.18,
normal: 0.35,
slow: 0.6
},
// Use these as the `ease` value inside a `transition` object:
// transition={{ duration: motionTokens.duration.normal, ease: motionTokens.easing.smooth }}
easing: {
smooth: [0.22, 1, 0.36, 1] as [number, number, number, number],
sharp: [0.4, 0, 0.2, 1] as [number, number, number, number]
},
distance: {
sm: 8,
md: 16,
lg: 24
}
}Usage example:
import { motionTokens } from "@/lib/motionTokens"
<motion.div
initial={{ opacity: 0, y: motionTokens.distance.md }}
animate={{ opacity: 1, y: 0 }}
transition={{
duration: motionTokens.duration.normal,
ease: motionTokens.easing.smooth
}}
/>Safe
Avoid
Rule: responsiveness > smoothness
The heuristic combines CPU core count and available memory for a more reliable signal. deviceMemory is available on Chrome/Android; the fallback covers Safari and Firefox.
const isLowEnd =
typeof navigator !== "undefined" && (
// Low memory (Chrome/Android only; undefined elsewhere → treat as capable)
(navigator.deviceMemory !== undefined && navigator.deviceMemory <= 2) ||
// Few cores AND no memory API (covers Safari/Firefox on weak hardware)
(navigator.deviceMemory === undefined && navigator.hardwareConcurrency <= 4)
)
const duration = isLowEnd ? 0.2 : 0.4import { motion, useReducedMotion } from "motion/react"
export function FadeIn() {
const reduce = useReducedMotion()
return (
<motion.div
initial={{ opacity: 0, y: reduce ? 0 : 24 }}
animate={{ opacity: 1, y: 0 }}
/>
)
}@media (prefers-reduced-motion: reduce) {
.motion-safe-transition {
transition: opacity 0.2s;
}
.motion-reduce-transform {
transform: none !important;
}
}<div class="motion-safe:animate-fade motion-reduce:opacity-100"></div>| Scenario | Pattern |
|---|---|
| Hover feedback | whileHover |
| Tap / press feedback | whileTap |
| Reveal on scroll | whileInView |
| Scroll-linked value | useScroll + useTransform |
| Conditional mount/unmount | AnimatePresence |
| Small layout shifts (single element, < ~300px change) | layout prop |
| Large layout shifts or full-page reflows | Avoid layout; use CSS transitions or page-level routing instead |
| Complex, imperative sequences | useAnimate |
Why avoid
layouton large containers? Framer's layout animation usestransformto reconcile positions, but on elements that span the full viewport or trigger deep reflow, the measurement cost causes visible jank and CLS. Prefer CSS Grid/Flexbox transitions or coordinate withlayoutIdon specific child elements only.
layoutId (must be unique per mounted instance)AnimatePresence (see mode guidance below)modeAlways specify mode explicitly — the default ("sync") runs enter and exit simultaneously, which causes visual overlap in most UI patterns.
mode | When to use |
|---|---|
"wait" | Exit completes before enter starts. Use for modals, toasts, page transitions. |
"sync" (default) | Enter and exit overlap. Use only when overlap is intentional (e.g., crossfade carousels). |
"popLayout" | Exiting element is popped out of flow immediately; remaining items animate to fill. Use for lists, tabs, dismissible cards. |
// Modal — always use "wait"
<AnimatePresence mode="wait">
{open && <Modal key="modal" />}
</AnimatePresence>
// Dismissible list item — use "popLayout"
<AnimatePresence mode="popLayout">
{items.map(item => <Card key={item.id} />)}
</AnimatePresence>layoutId)AnimatePresence mode="wait" so exit animation completes before the next modal entersimport React, { useEffect, useRef, useState } from "react"
import { motion, AnimatePresence } from "motion/react"
function useFocusTrap(ref: React.RefObject<HTMLDivElement | null>, active: boolean) {
useEffect(() => {
if (!active || !ref.current) return
const el = ref.current
const focusable = el.querySelectorAll<HTMLElement>(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
)
const first = focusable[0]
const last = focusable[focusable.length - 1]
function handleKey(e: KeyboardEvent) {
if (e.key !== "Tab") return
if (e.shiftKey && document.activeElement === first) {
e.preventDefault()
last?.focus()
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault()
first?.focus()
}
}
el.addEventListener("keydown", handleKey)
first?.focus()
return () => el.removeEventListener("keydown", handleKey)
}, [active, ref])
}
function useScrollLock(active: boolean) {
useEffect(() => {
if (!active) return
const prev = document.body.style.overflow
document.body.style.overflow = "hidden"
return () => { document.body.style.overflow = prev }
}, [active])
}
function Modal({ open, closeModal }: { open: boolean; closeModal: () => void }) {
const ref = useRef<HTMLDivElement>(null)
useFocusTrap(ref, open)
useScrollLock(open)
useEffect(() => {
function onKey(e: KeyboardEvent) {
if (e.key === "Escape") closeModal()
}
if (open) window.addEventListener("keydown", onKey)
return () => window.removeEventListener("keydown", onKey)
}, [open, closeModal])
return (
// mode="wait" ensures exit animation finishes before any new modal enters
<AnimatePresence mode="wait">
{open && (
<motion.div
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
className="fixed inset-0 flex items-center justify-center bg-black/40"
>
<motion.div
ref={ref}
initial={{ scale: 0.95, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.95, opacity: 0 }}
transition={{ duration: 0.2, ease: [0.22, 1, 0.36, 1] }}
className="bg-white p-6 rounded"
>
<h2 id="modal-title">Dialog Title</h2>
<button onClick={closeModal}>Close</button>
</motion.div>
</motion.div>
)}
</AnimatePresence>
)
}
export function Example() {
const [open, setOpen] = useState(false)
return (
<>
<button onClick={() => setOpen(true)}>Open</button>
<Modal open={open} closeModal={() => setOpen(false)} />
</>
)
}initial explicitly)"use client" in Next.js App RouterCheck:
motion/react and framer-motion)"use client" directive in Next.js App Routerkey prop on AnimatePresence childrenlayout prop misuse on large containers causing reflow jankrole="dialog", aria-modal="true")useReducedMotion + CSS media query)AnimatePresence mode set explicitly on all usage siteswidth, height, top, left)staggerChildren ≤ 0.1s; beyond that it feels slow)layout on large or full-viewport containersmode on AnimatePresence (default "sync" causes visual overlap)Motion is interaction design.
If motion does not improve UX → remove it.
import { motion } from "motion/react"
export function Button() {
return (
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.97 }}
transition={{ duration: 0.15, ease: [0.4, 0, 0.2, 1] }}
>
Click me
</motion.button>
)
}import { motion, useReducedMotion } from "motion/react"
export function FadeIn() {
const reduce = useReducedMotion()
return (
<motion.div
initial={{ opacity: 0, y: reduce ? 0 : 24 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: reduce ? 0.1 : 0.35, ease: [0.22, 1, 0.36, 1] }}
/>
)
}import { motion } from "motion/react"
const container = {
hidden: {},
visible: {
transition: { staggerChildren: 0.08 } // keep ≤ 0.1s to avoid sluggishness
}
}
const item = {
hidden: { opacity: 0, y: 10 },
visible: { opacity: 1, y: 0, transition: { duration: 0.3, ease: [0.22, 1, 0.36, 1] } }
}
export function List() {
return (
<motion.ul variants={container} initial="hidden" animate="visible">
{[1, 2, 3].map(i => (
<motion.li key={i} variants={item}>Item {i}</motion.li>
))}
</motion.ul>
)
}import { motion, AnimatePresence } from "motion/react"
export function Modal({ open }: { open: boolean }) {
return (
<AnimatePresence mode="wait">
{open && (
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
transition={{ duration: 0.2, ease: [0.22, 1, 0.36, 1] }}
/>
)}
</AnimatePresence>
)
}import { useScroll, useTransform, motion } from "motion/react"
export function Parallax() {
const { scrollYProgress } = useScroll()
const y = useTransform(scrollYProgress, [0, 1], [0, -80])
return <motion.div style={{ y }} />
}import { motion } from "motion/react"
export function Skeleton() {
return (
<motion.div
className="bg-gray-200 h-6 w-full rounded"
animate={{ opacity: [0.5, 1, 0.5] }}
transition={{
duration: 1.5, // comfortable pulse — was missing, caused fast flash
repeat: Infinity,
ease: "easeInOut"
}}
/>
)
}import { motion } from "motion/react"
// layoutId must be unique per mounted instance.
// If multiple instances can exist simultaneously, append a unique id:
// layoutId={`shared-${item.id}`}
export function Shared() {
return <motion.div layoutId="shared" />
}© templetongroup, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in skills/motion-ui of templetongroup/radiant.
Open the folder on GitHubat commit 94838ca
Motion UI next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Motion UI this skilltempletongroup/radiant | 113 | — | ~3.5k | Automated safety check: Pass | MIT | |
| Chakra UI v2 to v3 Migrationchakra-ui/chakra-ui | 41k | — | ~3.4k | Automated safety check: Pass | MIT | |
| Motion Dev Animations199-biotechnologies/motion-dev-animations-skill | 133 | 1 repos | ~2.8k | Automated safety check: Notes | MIT | |
| Goey Toastanl331/goey-toast | 1.3k | — | ~1.3k | Automated safety check: Warn | MIT | |
| Animatedelphi-ai/animate-skill | 113 | — | ~1.3k | Automated safety check: Pass | None | |
| Awwwards-Level React AnimationsHainrixz/editor-pro-max | 264 | — | ~4.4k | Automated safety check: Pass | Custom licence |
chakra-ui/chakra-ui
Guides an upgrade from Chakra UI v2 to v3: inspect the project, swap packages, run the official codemod, then fix provider, color mode, props, theming and Next.js code.
199-biotechnologies/motion-dev-animations-skill
Creates 120fps GPU-accelerated animations with Motion.dev (Framer Motion successor) for React, Next.js, Svelte, and Astro projects.
anl331/goey-toast
Install and use goey-toast — a gooey, morphing React toast component built on Sonner with Framer Motion.
delphi-ai/animate-skill
Animation patterns and best practices for Next.js/React applications.
Hainrixz/editor-pro-max
Guides React animation work with GSAP, Motion, Anime.js and Lenis for scroll effects, page transitions, text effects and generative visuals, with a library decision table.
softmaple/softmaple
Animation skill for Motion (prev Framer Motion) and CSS animation.
templetongroup/radiant
A skill your agent uses to generate or audit design systems, check visual consistency, and review PRs that touch styling.
templetongroup/radiant
Design, redesign, build, audit, polish, and production-verify exceptional interfaces across web, mobile, and native apps.
templetongroup/radiant
Expert guidance for developing with the tinystruct Java framework.
templetongroup/radiant
Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets.
templetongroup/radiant
Read a plan document, decompose it into steps, design a per-step agent chain from the ECC catalogue, and emit ready-to-paste /orchestrate custom prompts.
templetongroup/radiant
Ask the user to rate the code/output just produced on a 1-5 star scale, then ask rating-appropriate follow-up questions, log the rating, and iterate until the work reaches 4+ stars.
Categories
Production-ready UI motion system for React/Next.js. An agent skill from templetongroup/radiant. Motion UI is an agent skill from templetongroup/radiant.js.
Motion UI fits situations like: implementing animations; motion patterns.
Run `npx skills add templetongroup/radiant --skill motion-ui -a claude-code`. Or copy the skill folder (skills/motion-ui in templetongroup/radiant) into .claude/skills/motion-ui in your project. Claude Code loads it when a task matches its description.
Run `npx skills add templetongroup/radiant --skill motion-ui -a codex`. Or copy the skill folder (skills/motion-ui in templetongroup/radiant) into .agents/skills/motion-ui in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add templetongroup/radiant --skill motion-ui -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/motion-ui, .gemini/skills/motion-ui, .github/skills/motion-ui and .opencode/skills/motion-ui in your project.
Going by SKILL.md and its folder, Motion UI needs the command-line tools its instructions call (npm). Our summary lists: Node.js.
SKILL.md contains no URLs. Its commands use npm, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Motion UI is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.5k tokens (SKILL.md is roughly 14k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Motion UI: Chakra UI v2 to v3 Migration (chakra-ui/chakra-ui, 41k stars), Motion Dev Animations (199-biotechnologies/motion-dev-animations-skill, 133 stars), Goey Toast (anl331/goey-toast, 1.3k stars) and Animate (delphi-ai/animate-skill, 113 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
templetongroup (a GitHub user) maintains it in templetongroup/radiant, which has 113 GitHub stars. The repository holds 9 skills in this directory. The repository was last updated on October 6, 2026.
Source: templetongroup/radiant on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.