From mobile-design-kit
Design mobile app screens as HTML mockups with a reusable design system. Use when the user asks to "design a screen", "create a mobile mockup", "make mobile design", "build a mobile UI", or wants to convert a description/screenshot into an interactive HTML prototype.
How this skill is triggered — by the user, by Claude, or both
Slash command
/mobile-design-kit:make-mobile-design [screen-name or description][screen-name or description]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generate production-quality, mobile-first HTML mockups for app screens. Maintain a reusable design system and produce interactive prototypes that look and feel like real mobile apps.
android.mdassets/device-android.cssassets/device-chrome.cssassets/device-ios.cssassets/figma-export.jscomponents.mdcomponents/11-icons.mdcomponents/android/01-base-tokens.mdcomponents/android/02-status-bar.mdcomponents/android/03-navigation.mdcomponents/android/04-search-filters.mdcomponents/android/05-content.mdcomponents/android/06-elements.mdcomponents/android/07-interactive.mdcomponents/android/08-overlays.mdcomponents/android/09-navigation-drawer.mdcomponents/android/10-tablet-layouts.mdcomponents/ios/00-liquid-glass.mdcomponents/ios/01-base-tokens.mdcomponents/ios/02-status-bar.mdGenerate production-quality, mobile-first HTML mockups for app screens. Maintain a reusable design system and produce interactive prototypes that look and feel like real mobile apps.
Components are split into smaller files under components/. The index at components.md lists all files and when to load each one.
IMPORTANT: Before generating any screen:
design-system.html exists in the working directory, you MUST run the brand-suggestion flow in Step 1 below BEFORE asking the user any aesthetic questions. Do not invent your own aesthetic options (refined minimal / editorial dark / etc.) — the suggestions must come from VoltAgent/awesome-design-md via the fetch_design_style.py script.You MUST use components exactly as defined to ensure visual consistency. Do not reinvent components that already exist in the library.
Before applying platform rules, commit to a bold aesthetic direction. Generic, interchangeable mockups are the failure mode -- every screen should feel intentionally designed for its context.
Before coding, decide:
Bold maximalism and refined minimalism both work. The failure mode is the timid middle.
NEVER default to:
Vary between generations: light vs dark, serif vs grotesque vs mono display, dense vs airy. No two mockups in a session should converge on the same aesthetic unless the user is iterating on one.
animation-delay) lands harder than scattered micro-interactions. Use scroll-snap, hover surprises, and bouncy springs sparingly but precisely.When the target is iOS, the rules in ios.md constrain the aesthetic levers:
-apple-system, SF Pro) stays mandatory; aesthetic differentiation comes from weight, scale, color, and layout instead of webfont swaps.When the target is Android, the rules in android.md constrain differently:
Within those constraints, push the aesthetic levers above as hard as the brand allows. Implementation complexity should match the aesthetic vision: maximalism needs elaborate code; minimalism needs precision.
This skill targets two platforms: iOS (Apple HIG, iPhone) and Android (Material 3, Pixel). Each has its own scaffold, components, and rules. Pick one per screen — never mix.
AskUserQuestion ("Targeting Android (Material 3) — confirm?") before scaffolding. Strong signal (≥2 keywords or explicit "Android") can skip the confirmation but must state "Targeting Android (Material 3)" in the first user-facing line so the user can interrupt.After detection, set the platform target for the rest of the workflow:
ios.md, scaffold with create_ios_template.py, add tab bars with add_ios_tabbar.py, components live in components/ios/.android.md, scaffold with create_android_template.py, add bottom nav with add_android_navbar.py, components live in components/android/.Platform rules live in dedicated files (ios.md, android.md). Load the one matching the chosen target — they hold typography, color, density, motion, forbidden patterns, and compliance checklists for that platform.
After detecting the platform, decide form-factor: phone (default) or tablet. Form-factor is a second axis — each platform supports both.
iPad, Pixel Tablet, tablet, split view,
navigation rail, expanded window class, large screen,
list-detail.sidebar,
landscape) AND platform is iOS or Android → confirm with one
AskUserQuestion: "This looks like a tablet layout (iPad / Pixel
Tablet). Confirm form-factor?" with options phone / tablet.After detection, set the form-factor for the rest of the workflow:
create_ios_template.py /
create_android_template.py. Components from components/ios/ /
components/android/.create_ipad_template.py /
create_android_tablet_template.py. Additionally load
components/ios/13-tablet-layouts.md or
components/android/10-tablet-layouts.md for the layout wrappers
(split view, sidebar, nav rail, list-detail). Existing platform
components are reused unchanged for cell content.Tablet templates default to landscape; portrait is opt-in via
--orientation portrait on either scaffold script. Phone templates
remain portrait-only.
The platform rule files (ios.md, android.md) each have a Tablet
section that applies on top of phone rules when form-factor = tablet.
iOS-specific design rules (Apple HIG, type ramp, Liquid Glass, compliance checklist) live in ios.md. Load that file when target = iOS before generating the screen.
Android-specific design rules (Material 3, Roboto Flex, MD3 type scale, color roles, motion, compliance checklist) live in android.md. Load that file when target = Android before generating the screen.
The remainder of this file describes the platform-agnostic workflow (aesthetic thinking, brand suggestion, scaffolding, component-usage rules). Apply it on top of whichever platform rules file you loaded.
Before generating any screen:
design-system.html in the current working directorydesign-system.html exists, read it and use those token values to override the default :root variables from components.mdVoltAgent/awesome-design-md BEFORE asking any other aesthetic question. Do NOT generate aesthetic options from your own imagination — the 3 suggestions MUST be real brand entries from the script output. Flow:
python3 "${CLAUDE_PLUGIN_ROOT}/skills/make-mobile-design/scripts/fetch_design_style.py" list to get the brand index. This is mandatory — do not skip and do not substitute your own list.DESIGN.md via python3 ".../fetch_design_style.py" fetch <brand> and read it to ground your rationale (do not summarize from training-data assumptions about the brand).AskUserQuestion, each with a one-sentence rationale tying the brand's aesthetic to their product.design-system.html in the working directory for reuse across screens, or (b) apply it inline to this one screen only. Then proceed accordingly.design-system.html with the agreed tokens before proceeding.Ask the user (if not already clear from arguments or context):
If the user provides a screenshot, analyze it and reproduce the layout faithfully.
You MUST run the platform's scaffold script to create every new screen file. Do not write a screen HTML file by hand. The scaffold provides the pinned status bar, top chrome (Dynamic Island for iOS, hole-punch for Android), bottom indicator, and .device-content scroll region — all of which must remain unchanged.
Shared assets. Generated mockups link to stylesheets and the Copy-to-Figma serializer at ${CLAUDE_PLUGIN_ROOT}/skills/make-mobile-design/assets/ via absolute file:// URLs that the scaffold resolves at generation time. The device chrome CSS and tab/nav-bar CSS no longer live inline in each mockup — they're loaded from device-chrome.css + device-{ios,android}.css, and figma-export.js. One consequence: a mockup file is bound to the machine that produced it. Emailing the HTML to another machine, or moving the plugin install, breaks the chrome rendering. Keep mockups on the originating machine, or open them where the plugin is installed at the same path.
create_ios_template.pypython3 "${CLAUDE_PLUGIN_ROOT}/skills/make-mobile-design/scripts/create_ios_template.py" my-screen.html --title "My Screen"
This produces a self-contained HTML file with:
position:absolute; top:0; z-index:50<main class="device-content"> slot for your screen content (the scroll region)create_android_template.pypython3 "${CLAUDE_PLUGIN_ROOT}/skills/make-mobile-design/scripts/create_android_template.py" my-screen.html --title "My Screen"
This produces a Pixel 8 frame:
position:absolute; top:0; z-index:50--md-sys-color-*, --md-sys-typescale-*, --md-sys-shape-corner-*, --md-sys-elevation-*, --md-sys-motion-*) with a dark-mode override under prefers-color-scheme: dark<main class="device-content"> slot for screen contentcreate_ipad_template.pypython3 "${CLAUDE_PLUGIN_ROOT}/skills/make-mobile-design/scripts/create_ipad_template.py" my-screen.html --title "My Screen"
# Portrait (834×1194) instead of the default landscape (1194×834):
python3 "${CLAUDE_PLUGIN_ROOT}/skills/make-mobile-design/scripts/create_ipad_template.py" my-screen.html --orientation portrait
Produces an iPad Pro 11" frame: no Dynamic Island, 24px status bar
(time + signal/wifi/battery), home indicator pill, <main class="device-content">
slot, embedded Copy-to-Figma serializer. Use the layout wrappers from
components/ios/13-tablet-layouts.md
(.split-view, .sidebar-ipad, .detail-pane, .three-column) as the
first child of .device-content. Fill cells with existing iOS components.
create_android_tablet_template.pypython3 "${CLAUDE_PLUGIN_ROOT}/skills/make-mobile-design/scripts/create_android_tablet_template.py" my-screen.html --title "My Screen"
# Portrait (800×1280 dp) instead of the default landscape (1280×800 dp):
python3 "${CLAUDE_PLUGIN_ROOT}/skills/make-mobile-design/scripts/create_android_tablet_template.py" my-screen.html --orientation portrait
Produces a Pixel Tablet frame: no hole-punch (bezel camera), 24dp status
bar, MD3 tokens, Roboto Flex via Google Fonts, gesture-nav pill,
<main class="device-content"> slot, embedded Copy-to-Figma serializer.
Use the wrappers from
components/android/10-tablet-layouts.md
(.tablet-shell, .list-detail, .three-column-md) plus the existing
.nav-rail from components/android/09-navigation-drawer.md §A23.
After scaffolding, your job is to fill .device-content with components from components.md — iOS components for iOS screens, Android components for Android screens. Never mix.
Use the platform-appropriate script — never hand-write the markup. The scripts inject the chosen style above the bottom indicator and add the matching CSS to the existing <style> block.
add_ios_tabbar.pyYou MUST use add_ios_tabbar.py to add a tab bar — never hand-write the markup. The script injects the chosen style above the home indicator and adds the matching CSS to the existing <style> block.
python3 "${CLAUDE_PLUGIN_ROOT}/skills/make-mobile-design/scripts/add_ios_tabbar.py" my-screen.html \
--style pill-filled \
--item home:Home \
--item search:Search \
--item bookmark:Saved \
--item user:Profile \
--active 0
Pick a --style that matches the screen's aesthetic:
| Style | When to use |
|---|---|
icon-circle (default) | Generic floating capsule. Active item = dark filled circle. Icon-only. |
pill-outline | Active item expands into an outlined pill showing icon + label; others icon-only. Friendly, modern. |
pill-filled | Like pill-outline but the active pill has a light-tint fill instead of an outline. |
classic | iOS-native flat tab bar pinned above the home indicator. Every item shows icon + label. Use for utility apps, productivity tools. Supports --badge IDX:COUNT. |
glass | Liquid-glass translucent capsule (backdrop blur). Best on media-rich or photographic backgrounds. Per HIG, glass belongs on the navigation layer only. |
glass-split | Liquid-glass capsule plus a separate trailing glass circle for the last item. Use the trailing slot for a single distinct action (search, compose). Requires ≥ 2 items. |
Common arguments:
--item <icon>:<title> — repeat for each item. Title is the label / aria-label.<icon> is a built-in alias (home, menu, plus, mail, user, search, settings, heart, bell, bookmark, calendar, chat, compass, star, clock, phone, grid, mic) or any Iconify name (mdi:home-outline, lucide:plus, ph:user-circle, …). Use /ios-icon-gen search <keyword> to find icons.--active IDX — 0-based index of the highlighted item.--badge IDX:COUNT — notification badge on item IDX (only rendered for --style classic). Repeatable.--dark-color, --light-color, --accent-color — override to match the design system. Accent defaults to #1194AA for pills/glass and #007AFF for classic..device-content.Do NOT also include the older .tab-bar component from 03-navigation.md on the same screen — pick one tab bar style. The floating tab bar from add_ios_tabbar.py is the default for this skill.
add_android_navbar.pyYou MUST use add_android_navbar.py to add a Material 3 bottom navigation bar. The script injects the bottom nav above the gesture-nav pill with the canonical MD3 pill-shaped active indicator.
python3 "${CLAUDE_PLUGIN_ROOT}/skills/make-mobile-design/scripts/add_android_navbar.py" my-screen.html \
--item home:Home \
--item search:Search \
--item bookmark:Saved \
--item user:Profile \
--active 0 \
--badge 2:3
Arguments:
--item <icon>:<title> — repeat for each destination. Icon is a built-in alias (home, search, mail, user, settings, heart, bell, bookmark, calendar, chat, …) or any Iconify name (mdi:home, material-symbols:search, …). The script biases toward material-symbols for the default aliases — most native Android.--active IDX — 0-based index of the active destination.--badge IDX:COUNT — notification badge on item IDX. Repeatable.--style standard|elevated — elevated adds a level-2 shadow (default: standard).pointer-events: none; buttons have pointer-events: auto so scroll passes through inert footprint.Prohibitions (non-negotiable, both platforms unless tagged):
.device-content or in any element that scrolls..device / .device-content structure with a body-level scroll layout (e.g. body { min-height:100vh; } as the scroll container, status bar in normal flow).position:absolute; top:0; z-index:50 is the canonical form. Do not change it to static, relative, sticky, or fixed..device-content without pointer-events: none on the overlay wrapper and pointer-events: auto on its interactive children. Overlays that are siblings of .device-content swallow scroll/touch on their footprint and the screen feels unscrollable. The add_ios_tabbar.py and add_android_navbar.py outputs already do this — match the pattern for any hand-written overlay..device-content to display: flex; flex-direction: column. With a fixed-height container and overflow-y: auto, flex shrinks every child below its natural size to fit the viewport, so scrollHeight collapses to clientHeight and the screen stops scrolling entirely. Keep .device-content as block layout (the scaffold default).position: sticky; top: 0; z-index: 10 on the nav element, which lives as the first child inside .device-content. Do NOT leave a top nav in normal flow — it will scroll off with the content, which is wrong mobile behavior. iOS exception: large-title headers (.page-header, iOS components §3b) are intentionally part of the scroll region per HIG and must NOT be made sticky..device-content, never on .device-content itself. The scaffold sets .device-content { padding-top: 0 } so navigation bars and hero media can render their background behind the status bar to the top edge of the screen. The first child absorbs the safe-area height via its own padding-top. Do NOT add status-bar padding to .device-content, do NOT use negative margin-top on the nav (breaks sticky pinning), and do NOT use half-opacity tints or background-matching tricks.
.nav-header uses padding-top: calc(59px + var(--space-2)). See components/ios/02-status-bar.md "Status-bar safe area" and components/ios/03-navigation.md §3a / §3a-i.padding-top: calc(24px + 8dp). See components/android/02-status-bar.md and components/android/03-navigation.md.Re-read the platform rules file (ios.md or android.md) for the chosen target and apply every item in its Compliance Check before writing the file.
Create a single self-contained HTML file following these rules:
<style> tag<script> tag at the end[screen-name].htmlmax-width: 430px on body, centered with margin: 0 autowidth=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=noposition:absolute; top:0; z-index:50). Do not modify, relocate, or duplicate it.-webkit-font-smoothing: antialiasedcomponents/ios/01-base-tokens.md; Android: components/android/01-base-tokens.md. This is the :root block (and CSS reset on iOS).--color-primary, --space-4, --radius-md, …; Android: --md-sys-color-*, --md-sys-typescale-*, --md-sys-shape-corner-*, --md-sys-elevation-*).flexbox and grid for layoutscroll-snap for horizontal carousels-webkit-scrollbar: none and scrollbar-width: noneGenerated HTML includes a "Copy to Figma" button that serializes the .device frame to SVG for paste into Figma. The serializer lives at assets/figma-export.js (loaded via <script src="file://..."> reference) — edit it there, not in any mockup. The serializer has hard limits — author CSS with these in mind, otherwise the pasted result will diverge from the in-browser preview:
<svg> and <img> round-trip cleanly. Prefer them for icons and graphic shapes.mask / -webkit-mask icons (the background-color: currentColor + mask-image: url(...) pattern, including the iOS/Android nav scripts) are supported: the serializer pre-fetches the mask SVG and inlines it tinted with the element's background-color. Stick to this exact pattern if you need a tinted iconify icon — do NOT invent ad-hoc variants.filter, backdrop-filter, box-shadow, clip-path, CSS gradients used as mask-image, pseudo-elements (::before/::after) with content, transform: rotate/skew on the bounding rect (translate/scale OK).backdrop-filter. Don't try to fake it with extra CSS hacks; either accept the flattened result or model the chrome as a static SVG/<img> background.<svg> instead of CSS.components/ios/*.md for iOS, components/android/*.md for Android) -- do not rewrite or restyle themcomponents/ios/03-navigation.md (iOS §3) or components/android/03-navigation.md (Android §A3)components/ios/03-navigation.md) or Bottom Navigation Bar (Android §A4 in components/android/03-navigation.md)components/ios/04-search-filters.md (iOS §5) or components/android/04-search-filters.md (Android §A5)components/ios/05-content.md (iOS §8) or components/android/05-content.md (Android §A8) for all section dividerscomponents/ios/05-content.md (iOS §10) or components/android/05-content.md (Android §A10) for all row-based contentcomponents/11-icons.md (§25) for standard UI icons (chevrons, close, home, search, etc.)components/11-icons.md) -- see icon usage guide belowcomponents/ios/08-overlays.md; Android §A19 in components/android/08-overlays.md)components/ios/07-interactive.md; Android §A18 in components/android/07-interactive.md)After generating, suggest:
A scaffolded mockup references the device-chrome CSS and Copy-to-Figma serializer from a gitignored .design/ folder at the user's project root (created automatically on the first scaffold; subsequent scaffolds copy any missing assets into it but never overwrite an existing copy). Because the assets travel inside the user's project, the mockup is portable to any machine that clones / unzips the whole project tree — no need to have the plugin installed there.
If the user wants a single self-contained HTML (to email or paste into an issue tracker without sending the surrounding project), run the bundler to inline .design/ assets into the HTML:
python3 scripts/bundle_mockup.py <path/to/screen.html>
# → writes <path/to/screen.standalone.html>
# Add --no-figma to drop the Copy-to-Figma serializer and toolbar
External resources (Google Fonts, Iconify) stay as remote <link> tags either way — the recipient needs internet on first open.
If a plugin update brings new chrome behavior and the user wants their existing project to pick it up, tell them to delete .design/ and re-run a scaffold; the freshest assets will be copied in. Existing .design/ files are intentionally never overwritten so a plugin update doesn't silently change every mockup they've already rendered.
When creating design-system.html, structure it as a living reference page that displays all tokens visually:
design-system.html
- Color palette swatches (primary, secondary, semantic colors, grays)
- Typography scale (headings, body, captions with actual rendered examples)
- Spacing scale (visual blocks)
- Border radius examples
- Shadow examples
- Component library (buttons, cards, inputs, badges, chips, avatars, list items)
- Icon set (commonly used SVG icons)
This file serves as both documentation and a visual reference the user can open alongside mockups.
When a screen needs icons beyond the built-in SVG set (Section 25 of components.md), use the Iconify API to access 275,000+ open-source icons.
Two methods, depending on context:
Method 1: Inline <img> tag (simplest, for mockups)
<img src="https://api.iconify.design/mdi/receipt-text-outline.svg?width=24&height=24&color=%23currentColor" alt="receipt">
Method 2: CSS background (for buttons, list items)
.icon-receipt {
width: 24px; height: 24px;
background: url('https://api.iconify.design/mdi/receipt-text-outline.svg?width=24&height=24&color=%236B7280') no-repeat center/contain;
}
Replace the color hex (URL-encoded: %23 = #) to match your design tokens.
Before generating a mockup, use the /ios-icon-gen skill to search for icons:
/ios-icon-gen search <keyword>
/ios-icon-gen search <keyword> --prefix mdi
| Collection | Prefix | Style | Best for |
|---|---|---|---|
| Material Design | mdi | Filled + outline | General-purpose, Android-style |
| Phosphor | ph | 6 weights | Versatile, clean |
| Lucide | lucide | Thin stroke | Minimal, iOS-like |
| Tabler | tabler | Consistent stroke | Dashboard, tools |
| Heroicons | heroicons | Outline + solid | Tailwind-style |
https://api.iconify.design/{collection}/{icon-name}.svg?width={px}&height={px}&color=%23{hex}
Examples:
https://api.iconify.design/mdi/receipt-text-outline.svg?width=24&height=24&color=%232563EB
https://api.iconify.design/lucide/scan.svg?width=20&height=20&color=%236B7280
https://api.iconify.design/ph/address-book.svg?width=32&height=32&color=%23ffffff
After a mockup is approved, use the /ios-icon-gen skill to export icons as Xcode asset imagesets:
/ios-icon-gen mdi:receipt-text-outline myIconAsset --color 8E8E93 --output ./Assets.xcassets/icons
This bridges the design-to-code gap: icons chosen during mockup design can be directly exported as production-ready Xcode assets.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub trmquang93/mobile-design-kit --plugin mobile-design-kit