
morphing-icons
Build icon components where any icon morphs into any other through SVG line transformation. Use when asked to "create morphing icons", "build icon transitions", "animate between icons", or "transform icons".
- Installs
- 120
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/raphaelsalaja/userinterface-wiki --skill morphing-icons- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads morphing-icons automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
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-up
Implementation 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 }, ...] }; // 28x28
Pass:
const VIEWBOX_SIZE = 14;
const CENTER = 7;
// All coordinates within 0-14 range
morphing-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-right
Summary 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
FAQ
What does the morphing-icons skill do?
Build icon components where any icon morphs into any other through SVG line transformation. Use when asked to "create morphing icons", "build icon transitions", "animate between icons", or "transform icons".
How do I install morphing-icons?
Run npx skills add https://github.com/raphaelsalaja/userinterface-wiki --skill morphing-icons in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/morphing-icons/ (personal) or .claude/skills/morphing-icons/ (project).
Which AI agents can use morphing-icons?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is morphing-icons safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains morphing-icons?
It is published by raphaelsalaja in raphaelsalaja/userinterface-wiki. It has 120 recorded installs.
More from raphaelsalaja/userinterface-wiki
userinterface-wiki
raphaelsalaja/userinterface-wiki
UI/UX best practices for web interfaces. Use when reviewing animations, CSS, audio, typography, UX patterns, prefetching, or icon implementations. Covers 11 categories from animation principles to typography. Outputs file:line findings.
12-principles-of-animation
raphaelsalaja/userinterface-wiki
Open the skill to read its SKILL.md instructions.
generating-sounds-with-ai
raphaelsalaja/userinterface-wiki
Open the skill to read its SKILL.md instructions.
sounds-on-the-web
raphaelsalaja/userinterface-wiki
Open the skill to read its SKILL.md instructions.
to-spring-or-not-to-spring
raphaelsalaja/userinterface-wiki
Open the skill to read its SKILL.md instructions.
mastering-animate-presence
raphaelsalaja/userinterface-wiki
Open the skill to read its SKILL.md instructions.
Popular other skills
hyperframes-cli
heygen-com/hyperframes
The HyperFrames CLI by job - scaffold, check, look at frames, edit the timeline, preview, render locally or in the cloud, publish, project history - plus reading its JSON and recovering from build or render failures.
triage
mattpocock/skills
Move issues and external PRs through a state machine of triage roles, categorise, verify, grill if needed, and write agent-ready briefs.
ask-matt
mattpocock/skills
Ask which skill or flow fits your situation. A router over the skills in this repo.
to-questionnaire
mattpocock/skills
Turn a decision you can't fully answer into a questionnaire for someone else to fill in.
loop-me
mattpocock/skills
Grill me about specs for the workflows I want to build, within this workspace.