
Morphing Icons
- 230 installs
- 32 repo stars
- Updated March 17, 2026
- raphaelsalaja/skill
Implement animated icon components that morph between any two glyphs using a shared three-line SVG model.
About
Morphing Icons is an agent skill for solo builders shipping polished micro-interactions in React or similar frontends. It encodes a constraint-based design system: each icon is exactly three lines in a 14×14 viewbox, with spare lines collapsed to invisible center points so transitions interpolate real geometry rather than fading between unrelated paths. You define IconLine tuples, IconDefinition records with optional rotation and group keys, and wire animation between named states when users ask for morphing icons, icon transitions, or transform-between-icons behavior. The approach suits nav toggles, play/pause swaps, and theme controls where brand consistency matters. It assumes comfort with SVG attributes and component props—not a drop-in icon font. MIT licensed reference material ties back to morphing-icons MDX source for deeper patterns.
- Every icon uses exactly three SVG lines so any icon can morph into any other
- Collapsed center-point lines hide unused strokes in simpler glyphs
- IconDefinition includes optional rotation and rotation groups for coordinated transforms
- Shape transformation instead of opacity crossfades for crisp motion
- 14×14 viewbox convention with typed IconLine coordinates
Morphing Icons by the numbers
- 230 all-time installs (skills.sh)
- +12 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #820 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/raphaelsalaja/skill --skill morphing-iconsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 230 |
|---|---|
| repo stars | ★ 32 |
| Security audit | 3 / 3 scanners passed |
| Last updated | March 17, 2026 |
| Repository | raphaelsalaja/skill ↗ |
What it does
Implement animated icon components that morph between any two glyphs using a shared three-line SVG model.
Files
Morphing Icons
Build icons that transform through actual shape transformation, not crossfades. Any icon can morph into any other because they share the same underlying 3-line structure.
Core Concept
Every icon is composed of exactly three SVG lines. Icons that need fewer lines collapse the extras to invisible center points. This constraint enables seamless morphing between any two icons.
Architecture
1. Line Definition
Each line has coordinates and optional opacity:
interface IconLine {
x1: number;
y1: number;
x2: number;
y2: number;
opacity?: number;
}2. Collapsed Lines
Icons needing fewer than 3 lines use collapsed lines—zero-length lines at the center:
const CENTER = 7; // Center of 14x14 viewbox
const collapsed: IconLine = {
x1: CENTER,
y1: CENTER,
x2: CENTER,
y2: CENTER,
opacity: 0,
};3. Icon Definition
Each icon has exactly 3 lines, optional rotation, and optional group:
interface IconDefinition {
lines: [IconLine, IconLine, IconLine];
rotation?: number;
group?: string;
}4. Rotation Groups
Icons sharing a group animate rotation when transitioning between them. Icons without matching groups jump to the new rotation instantly:
// These rotate smoothly between each other
{ lines: plusLines, rotation: 0, group: "plus-cross" } // plus
{ lines: plusLines, rotation: 45, group: "plus-cross" } // cross
// These rotate smoothly between each other
{ lines: arrowLines, rotation: 0, group: "arrow" } // arrow-right
{ lines: arrowLines, rotation: 90, group: "arrow" } // arrow-down
{ lines: arrowLines, rotation: 180, group: "arrow" } // arrow-left
{ lines: arrowLines, rotation: -90, group: "arrow" } // arrow-upImplementation Rules
morphing-three-lines
Every icon MUST use exactly 3 lines. No more, no fewer.
Fail:
const checkIcon = {
lines: [
{ x1: 2, y1: 7.5, x2: 5.5, y2: 11 },
{ x1: 5.5, y1: 11, x2: 12, y2: 3 },
], // Only 2 lines
};Pass:
const checkIcon = {
lines: [
{ x1: 2, y1: 7.5, x2: 5.5, y2: 11 },
{ x1: 5.5, y1: 11, x2: 12, y2: 3 },
collapsed, // Third line collapsed
],
};morphing-use-collapsed
Unused lines must use the collapsed constant, not omission or null.
Fail:
const minusIcon = {
lines: [
{ x1: 2, y1: 7, x2: 12, y2: 7 },
null,
null,
],
};Pass:
const minusIcon = {
lines: [
{ x1: 2, y1: 7, x2: 12, y2: 7 },
collapsed,
collapsed,
],
};morphing-consistent-viewbox
All icons must use the same viewBox (14x14 recommended).
Fail:
// Mixing viewbox scales
const icon1 = { lines: [{ x1: 2, y1: 7, x2: 12, y2: 7 }, ...] }; // 14x14
const icon2 = { lines: [{ x1: 4, y1: 14, x2: 24, y2: 14 }, ...] }; // 28x28Pass:
const VIEWBOX_SIZE = 14;
const CENTER = 7;
// All coordinates within 0-14 rangemorphing-group-variants
Icons that are rotational variants MUST share the same group and base lines.
Fail:
// Different line definitions for arrows
const arrowRight = { lines: [{ x1: 2, y1: 7, x2: 12, y2: 7 }, ...] };
const arrowDown = { lines: [{ x1: 7, y1: 2, x2: 7, y2: 12 }, ...] }; // Different!Pass:
const arrowLines: [IconLine, IconLine, IconLine] = [
{ x1: 2, y1: 7, x2: 12, y2: 7 },
{ x1: 7.5, y1: 2.5, x2: 12, y2: 7 },
{ x1: 7.5, y1: 11.5, x2: 12, y2: 7 },
];
const icons = {
"arrow-right": { lines: arrowLines, rotation: 0, group: "arrow" },
"arrow-down": { lines: arrowLines, rotation: 90, group: "arrow" },
"arrow-left": { lines: arrowLines, rotation: 180, group: "arrow" },
"arrow-up": { lines: arrowLines, rotation: -90, group: "arrow" },
};morphing-spring-rotation
Rotation between grouped icons should use spring physics for natural motion.
Fail:
<motion.g animate={{ rotate: rotation }} transition={{ duration: 0.3 }} />Pass:
const rotation = useSpring(definition.rotation ?? 0, activeTransition);
<motion.g style={{ rotate: rotation, transformOrigin: "center" }} />morphing-reduced-motion
Respect prefers-reduced-motion by disabling animations.
Fail:
function MorphingIcon({ icon }: Props) {
return <motion.line animate={...} transition={{ duration: 0.4 }} />;
}Pass:
function MorphingIcon({ icon }: Props) {
const reducedMotion = useReducedMotion() ?? false;
const activeTransition = reducedMotion ? { duration: 0 } : transition;
return <motion.line animate={...} transition={activeTransition} />;
}morphing-jump-non-grouped
When transitioning between icons NOT in the same group, rotation should jump instantly.
Fail:
// Always animating rotation regardless of group
useEffect(() => {
rotation.set(definition.rotation ?? 0);
}, [definition]);Pass:
useEffect(() => {
if (shouldRotate) {
rotation.set(definition.rotation ?? 0); // Animate
} else {
rotation.jump(definition.rotation ?? 0); // Instant
}
}, [definition, shouldRotate]);morphing-strokelinecap-round
Lines should use strokeLinecap="round" for polished endpoints.
Fail:
<motion.line strokeLinecap="butt" />Pass:
<motion.line strokeLinecap="round" />morphing-aria-hidden
Icon SVGs should be aria-hidden since they're decorative.
Fail:
<svg width={size} height={size}>...</svg>Pass:
<svg width={size} height={size} aria-hidden="true">...</svg>Common Icon Patterns
Two-Line Icons (check, minus, equals, chevron)
Use one or two collapsed lines:
const check = {
lines: [
{ x1: 2, y1: 7.5, x2: 5.5, y2: 11 },
{ x1: 5.5, y1: 11, x2: 12, y2: 3 },
collapsed,
],
};Three-Line Icons (menu, asterisk, play)
Use all three lines:
const menu = {
lines: [
{ x1: 2, y1: 3.5, x2: 12, y2: 3.5 },
{ x1: 2, y1: 7, x2: 12, y2: 7 },
{ x1: 2, y1: 10.5, x2: 12, y2: 10.5 },
],
};Point Icons (more, grip)
Use zero-length lines as dots:
const more = {
lines: [
{ x1: 3, y1: 7, x2: 3, y2: 7 },
{ x1: 7, y1: 7, x2: 7, y2: 7 },
{ x1: 11, y1: 7, x2: 11, y2: 7 },
],
};Recommended Transition
Use exponential ease-out for smooth morphing:
const defaultTransition: Transition = {
ease: [0.19, 1, 0.22, 1],
duration: 0.4,
};Output Format
When auditing morphing icon implementations, output findings as:
file:line - [rule-id] description of issue
Example:
components/icon/index.tsx:45 - [morphing-three-lines] Icon "check" has only 2 lines, needs collapsed third
components/icon/index.tsx:78 - [morphing-group-variants] arrow-down uses different line definitions than arrow-rightSummary Table
After findings, output a summary:
| Rule | Count | Severity |
|---|---|---|
morphing-three-lines | 2 | HIGH |
morphing-group-variants | 1 | HIGH |
morphing-reduced-motion | 1 | MEDIUM |
References
Related skills
FAQ
Is Morphing Icons safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.