Color system
Skill almasumdev/awesome-mobile-design-system-agent-skills/.github/skills/foundations/color-system
Agent skills for building and maintaining mobile design systems, tokens, and component libraries.
npx -y skills add almasumdev/awesome-mobile-design-system-agent-skills --skill color-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.
What its author says it does
Copied from the file, not written here
Building a mobile color system with HSL/HCT base, Material 3 tonal palettes, semantic aliases, and verified contrast. Use this when defining or refining color tokens.
SKILL.md
4.6 KB, as published. Nobody here has run it
Color System
Instructions
A production color system is layered: perceptual primitives at the bottom, tonal palettes above, and semantic aliases at the top. Components only ever consume the semantic layer.
1. Pick a Perceptual Base
Use HCT (Material 3) or OKLCH for authoring — they keep perceived lightness stable as hue changes, so palettes feel consistent. Fall back to HSL only for documentation.
Generate palettes with the Material 3 HCT algorithm (@material/material-color-utilities) or Leonardo. Do not hand-pick hex ramps.
2. Tonal Palettes (Reference Layer)
For each key hue, generate a 13-stop tonal palette keyed by tone (0 = black, 100 = white):
{
"color": {
"$type": "color",
"brand": {
"0": { "$value": "#000000" },
"10": { "$value": "#14101F" },
"20": { "$value": "#271F3A" },
"30": { "$value": "#3C2F56" },
"40": { "$value": "#524173" },
"50": { "$value": "#695491" },
"60": { "$value": "#8269AE" },
"70": { "$value": "#9C82CB" },
"80": { "$value": "#B79AE8" },
"90": { "$value": "#D3B4FF" },
"95": { "$value": "#EAD9FF" },
"99": { "$value": "#FFFBFF" },
"100": { "$value": "#FFFFFF" }
}
}
}
Repeat for neutral, neutralVariant, success, warning, danger, info.
3. Semantic Aliases (System Layer)
Components consume these. Pair every background with a content token whose contrast is verified.
{
"color": {
"surface": {
"default": { "$value": "{color.neutral.99}" },
"subtle": { "$value": "{color.neutral.95}" },
"inverse": { "$value": "{color.neutral.10}" }
},
"content": {
"default": { "$value": "{color.neutral.10}" },
"muted": { "$value": "{color.neutral.40}" },
"inverse": { "$value": "{color.neutral.99}" },
"onAction": { "$value": "{color.neutral.99}" }
},
"action": {
"primary": {
"bg": { "$value": "{color.brand.40}" },
"bgHover": { "$value": "{color.brand.30}" },
"fg": { "$value": "{color.neutral.99}" }
}
},
"feedback": {
"danger": { "bg": { "$value": "{color.danger.40}" }, "fg": { "$value": "{color.neutral.99}" } },
"success": { "bg": { "$value": "{color.success.40}" }, "fg": { "$value": "{color.neutral.99}" } }
}
}
}
4. Dark Theme = Different Aliasing, Same Palettes
Do not ship a separate palette. Swap the alias mappings:
{
"color": {
"surface": {
"default": { "$value": "{color.neutral.10}" }
},
"content": {
"default": { "$value": "{color.neutral.95}" }
}
}
}
Roughly: light uses tones 90–99 for surfaces and 10–40 for content; dark inverts to tones 0–20 for surfaces and 80–95 for content.
5. Contrast Contract
- Body text against its surface: WCAG 2.2 AA ≥ 4.5:1 (or APCA Lc 60+).
- Large text (≥ 18pt or 14pt bold): ≥ 3:1.
- Non-text UI (icons, focus ring, borders that convey state): ≥ 3:1.
- Encode the pairing in
$extensionsso a linter can verify it.
6. Platform Delivery
Compose:
val LightScheme = lightColorScheme(
primary = ds.color.action.primary.bg,
onPrimary = ds.color.action.primary.fg,
surface = ds.color.surface.default,
onSurface = ds.color.content.default,
)
SwiftUI: emit a .xcassets color set per semantic token with Any Appearance + Dark Appearance entries, then use Color("surface/default").
Flutter: declare a ThemeExtension<AppColors> holding the semantic map and attach to ThemeData.
7. Anti-Patterns
- Using
Colors.black.withOpacity(0.6)in components — unverifiable contrast. - Sharing a single "text primary" token for both light and dark without re-aliasing.
- Encoding state into color only (no iconography, no stroke change).
- More than ~8 semantic surfaces / content levels — it becomes unmanageable.
Checklist
- Palettes are generated from a perceptual model (HCT/OKLCH), not hand-mixed hex.
- Semantic aliases exist for
surface,content,action,feedback,border. - Dark theme is produced by remapping aliases to the same tonal palettes.
- Every content-on-surface pair meets WCAG AA contrast; a CI check verifies it.
- Components never reference reference (tonal) tokens directly.
- No component uses
opacityas the sole mechanism for disabled/muted state.