Icon system
Skill almasumdev/awesome-mobile-design-system-agent-skills/.github/skills/assets/icon-system
Cross-platform icon pipeline — SVG source, Android VectorDrawable, SF Symbols, Flutter/RN delivery, sizing, and parity. Use this when adding or refactoring the icon set.From its SKILL.md
npx -y skills add almasumdev/awesome-mobile-design-system-agent-skills --skill icon-systemAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
6.0 KB, ~1.5k tokens by cl100k_base, as published. Nobody here has run it
Icon System
Instructions
Icons are part of the component library, not a loose folder of assets. One SVG source, deterministic platform outputs, tokenized sizes, and a single public API per platform.
1. One Source, Many Targets
assets/icons/
├── source/ # authoring SVG (24 × 24 grid)
│ ├── check.svg
│ ├── chevron-right.svg
│ └── ...
├── android/ # generated .xml VectorDrawables
├── ios/ # generated .xcassets (+ fallback for non-SF-Symbols)
├── flutter/ # generated IconData (from a custom font) or SVG widgets
└── rn/ # generated TypeScript components (react-native-svg)
2. Authoring Rules
- 24 × 24 grid, 1.5–2pt strokes, rounded line caps/joins by default.
- Monochrome only. Color comes from the
tintColor/colorprop driven by tokens. - No hard-coded fill; use
currentColor(fill="currentColor"/stroke="currentColor"). - Export with
viewBox="0 0 24 24"; nowidth/heightattributes. - One visual per file; do not merge states into a single SVG.
3. Android / Compose
Convert SVG → VectorDrawable with Android Studio's importer or vd-tool, then expose via a generated Icons object.
object DsIcons {
val Check: ImageVector = Icons.Filled.Check
val ChevronRight: ImageVector = vectorResource(R.drawable.ic_chevron_right)
}
@Composable
fun DsIcon(icon: ImageVector, size: Dp = 24.dp, tint: Color = LocalContentColor.current) {
Icon(imageVector = icon, contentDescription = null, tint = tint, modifier = Modifier.size(size))
}
4. iOS / SwiftUI
Prefer SF Symbols for platform idiom when an exact-match symbol exists. For brand-specific icons, ship a multicolor-capable asset catalog.
public enum DSIcon: String {
case check = "checkmark" // SF Symbol
case chevronRight = "chevron.right" // SF Symbol
case brandLogo = "ds.brand.logo" // asset catalog
}
public struct DSIconView: View {
let icon: DSIcon
let size: CGFloat
public var body: some View {
if icon.rawValue.contains(".") {
Image(systemName: icon.rawValue)
.font(.system(size: size, weight: .regular))
} else {
Image(icon.rawValue).resizable().frame(width: size, height: size)
}
}
}
Rule: never ship a bespoke checkmark on iOS when checkmark exists in SF Symbols; use the system glyph so it inherits Dynamic Type.
5. Flutter
Two acceptable approaches:
- Icon font (most efficient): generate a custom font from SVGs via FontForge / IcoMoon, declare
IconData. - Vector widgets via
flutter_svg: simpler, zero font tooling, slightly heavier runtime cost.
class DsIcons {
static const IconData check = IconData(0xe001, fontFamily: 'DsIcons');
static const IconData chevronRight = IconData(0xe002, fontFamily: 'DsIcons');
}
class DsIcon extends StatelessWidget {
const DsIcon(this.data, {super.key, this.size = 24, this.color});
final IconData data; final double size; final Color? color;
@override
Widget build(BuildContext context) => Icon(data,
size: size, color: color ?? IconTheme.of(context).color);
}
6. React Native
Generate one *.tsx per icon with react-native-svg. A bundler treeshakes unused icons.
// generated
export const IconCheck = (props: SvgProps) => (
<Svg viewBox="0 0 24 24" {...props}>
<Path d="M20 6L9 17l-5-5" stroke={props.color ?? 'currentColor'} strokeWidth={2}
strokeLinecap="round" strokeLinejoin="round" fill="none" />
</Svg>
);
export const Icon = ({ name, size = 24, color }: IconProps) => {
const C = REGISTRY[name];
return <C width={size} height={size} color={color} />;
};
7. Sizing via Tokens
{
"size": {
"icon": {
"sm": { "$value": "16px", "$type": "dimension" },
"md": { "$value": "20px", "$type": "dimension" },
"lg": { "$value": "24px", "$type": "dimension" },
"xl": { "$value": "32px", "$type": "dimension" }
}
}
}
Components accept a size variant and map to the token — not arbitrary px/dp.
8. Accessibility
- Decorative icons: explicit
null/ empty content description; never auto-generate. - Icon-only buttons: provide an accessibility label that describes the action, not the glyph ("Close", not "X").
- Minimum hit target: 44×44 iOS / 48×48 Android, regardless of icon size — pad the tap area.
9. Parity Strategy
Maintain a canonical registry (icons.json) listing every icon, its semantic name, and its per-platform mapping. A CI check fails if a name exists without a mapping on every platform.
{
"check": { "android": "ic_check", "ios": "checkmark", "flutter": 57345, "rn": "IconCheck" },
"chevron-right": { "android": "ic_chevron_right", "ios": "chevron.right", "flutter": 57346, "rn": "IconChevronRight" }
}
10. Anti-Patterns
- PNG icons in a modern mobile app (except raster app icons).
- Re-drawing SF Symbols with bespoke SVGs.
- Baked-in color inside icon source.
- Icon padding inside the SVG itself (breaks hit-testing math).
- Shipping every icon of the set in the binary; tree-shake or lazy-load rarely-used ones.
Checklist
- All icons authored as 24×24 monochrome SVGs with
currentColor. - Platform outputs generated deterministically from source; manual edits to outputs are rejected in review.
- SF Symbols used on iOS when a system equivalent exists.
- Icon sizes and colors come from tokens; no raw values in components.
-
icons.jsonregistry enforces parity; CI fails on missing mappings. - Icon-only buttons have action-describing accessibility labels and 44/48pt hit areas.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.