mcpField
M
morphing-icons

morphing-icons

github.com/raphaelsalajaデザイン・UI42362 回インストール今日更新
リポジトリ

morphing-icons について

morphing-iconsは、クロスフェードではなく形状変化で切り替わるアイコンを設計・監査するスキルです。3本のSVG線による共通構造と、遷移の一貫性やアクセシビリティの実装ルールを定めています。

主な機能

  1. 01各アイコンを3本のSVG線で定義
  2. 02未使用の形状に折りたたみ線を使用
  3. 03グループ化した回転バリアントのアニメーション
  4. 04viewBoxと動作のルール
  5. 05動きを減らす設定とアクセシビリティへの対応

活用シーン

  1. 01状態間で形状が変わるアイコンの作成
  2. 02ルールに沿ったアイコン実装の監査
  3. 03回転アイコンのバリアントの一貫性維持
  4. 04動きを減らす設定への対応

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/raphaelsalaja/skill --skill morphing-icons

インストール後、Claude Code で/morphing-iconsを入力して読み込まれたか確認します。

詳細

モーフィングアイコン

クロスフェードではなく、実際の形状変化で変形するアイコンを作成します。すべてのアイコンは同じ3本の線の構造を共有するため、どのアイコンからどのアイコンへもモーフィングできます。

基本概念

すべてのアイコンは、正確に3本のSVG線で構成されます。必要な線が少ないアイコンでは、余分な線を中心の見えない点に縮退させます。この制約により、あらゆる2つのアイコン間でシームレスなモーフィングが可能になります。

アーキテクチャ

1. 線の定義

各線には座標と、任意の不透明度があります。

interface IconLine {
  x1: number;
  y1: number;
  x2: number;
  y2: number;
  opacity?: number;
}
2. 縮退した線

3本未満の線を必要とするアイコンでは、縮退した線(中心にある長さ0の線)を使用します。

const CENTER = 7; // Center of 14x14 viewbox

const collapsed: IconLine = {
  x1: CENTER,
  y1: CENTER,
  x2: CENTER,
  y2: CENTER,
  opacity: 0,
};
3. アイコンの定義

各アイコンは、正確に3本の線と、任意の回転およびグループを持ちます。

interface IconDefinition {
  lines: [IconLine, IconLine, IconLine];
  rotation?: number;
  group?: string;
}
4. 回転グループ

groupを共有するアイコン間を遷移するときは、回転アニメーションが実行されます。一致するグループを持たないアイコンへの遷移では、新しい回転角度に即座に切り替わります。

// 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

実装ルール

morphing-three-lines

すべてのアイコンは、必ず3本の線を使用する必要があります。それより多くても少なくてもいけません。

不合格:

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
};

合格:

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

未使用の線には、省略やnullではなく、縮退定数を使用する必要があります。

不合格:

const minusIcon = {
  lines: [
    { x1: 2, y1: 7, x2: 12, y2: 7 },
    null,
    null,
  ],
};

合格:

const minusIcon = {
  lines: [
    { x1: 2, y1: 7, x2: 12, y2: 7 },
    collapsed,
    collapsed,
  ],
};
morphing-consistent-viewbox

すべてのアイコンで同じviewBoxを使用する必要があります(14x14を推奨)。

不合格:

// 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

合格:

const VIEWBOX_SIZE = 14;
const CENTER = 7;
// All coordinates within 0-14 range
morphing-group-variants

回転バリエーションとなるアイコンは、同じグループと基本の線を共有する必要があります。

不合格:

// 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!

合格:

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

グループ化されたアイコン間の回転には、自然な動きになるようスプリング物理を使用します。

不合格:

<motion.g animate={{ rotate: rotation }} transition={{ duration: 0.3 }} />

合格:

const rotation = useSpring(definition.rotation ?? 0, activeTransition);

<motion.g style={{ rotate: rotation, transformOrigin: "center" }} />
morphing-reduced-motion

アニメーションを無効にして、prefers-reduced-motionに対応します。

不合格:

function MorphingIcon({ icon }: Props) {
  return <motion.line animate={...} transition={{ duration: 0.4 }} />;
}

合格:

function MorphingIcon({ icon }: Props) {
  const reducedMotion = useReducedMotion() ?? false;
  const activeTransition = reducedMotion ? { duration: 0 } : transition;
  
  return <motion.line animate={...} transition={activeTransition} />;
}
morphing-jump-non-grouped

同じグループに属さないアイコン間を遷移するとき、回転は即座に切り替わる必要があります。

不合格:

// Always animating rotation regardless of group
useEffect(() => {
  rotation.set(definition.rotation ?? 0);
}, [definition]);

合格:

useEffect(() => {
  if (shouldRotate) {
    rotation.set(definition.rotation ?? 0); // Animate
  } else {
    rotation.jump(definition.rotation ?? 0); // Instant
  }
}, [definition, shouldRotate]);
morphing-strokelinecap-round

端をきれいに仕上げるため、線にはstrokeLinecap="round"を使用します。

不合格:

<motion.line strokeLinecap="butt" />

合格:

<motion.line strokeLinecap="round" />
morphing-aria-hidden

アイコンのSVGは装飾用のため、aria-hiddenにする必要があります。

不合格:

<svg width={size} height={size}>...</svg>

合格:

<svg width={size} height={size} aria-hidden="true">...</svg>

よくあるアイコンのパターン

2本線のアイコン(チェック、マイナス、イコール、山かっこ)

1本または2本の縮退した線を使用します。

const check = {
  lines: [
    { x1: 2, y1: 7.5, x2: 5.5, y2: 11 },
    { x1: 5.5, y1: 11, x2: 12, y2: 3 },
    collapsed,
  ],
};
3本線のアイコン(メニュー、アスタリスク、再生)

3本すべての線を使用します。

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 },
  ],
};
点のアイコン(その他、グリップ)

長さ0の線を点として使用します。

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 },
  ],
};

推奨する遷移

滑らかなモーフィングには、指数関数的なイーズアウトを使用します。

const defaultTransition: Transition = {
  ease: [0.19, 1, 0.22, 1],
  duration: 0.4,
};

出力形式

モーフィングアイコンの実装を監査するときは、次の形式で指摘事項を出力します。

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

まとめ表

指摘事項の後に、次のまとめを出力します。

ルール件数重大度
morphing-three-lines2HIGH
morphing-group-variants1HIGH
morphing-reduced-motion1MEDIUM

参考資料

コメント