npx claudepluginhub heyadam/claudedesign-to-swiftui --plugin claudedesign-to-swiftuiThis skill uses the workspace's default tool permissions.
This skill converts a Claude-generated HTML/CSS prototype (delivered as a design URL from `api.anthropic.com/v1/design/h/...`, or a local `.tar.gz` archive) into a single SwiftUI View file inside the user's active Xcode workspace.
examples/01-landing-card/input.htmlexamples/01-landing-card/output.swiftexamples/02-list-with-rows/input.htmlexamples/02-list-with-rows/output.swiftreferences/asset-catalog-import.mdreferences/component-patterns.mdreferences/font-mapping.mdreferences/layout-mapping.mdreferences/styling-mapping.mdreferences/svg-path-translation.mdreferences/svg-to-sfsymbol.mdreferences/swiftui-gotchas.mdreferences/typography-mapping.mdscripts/fetch.shscripts/stop.shGuides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
This skill converts a Claude-generated HTML/CSS prototype (delivered as a design URL from api.anthropic.com/v1/design/h/..., or a local .tar.gz archive) into a single SwiftUI View file inside the user's active Xcode workspace.
The output is one self-contained .swift file: one View struct + a #Preview, plus inline Path-based icons and any imported image assets. No multi-screen navigation and no JS interactivity — visual layout fidelity only.
This skill calls into two MCP servers. If either is missing, stop and tell the user how to enable it.
xcode-tools (Apple's native Xcode MCP, ships with Xcode 26.3+ as xcrun mcpbridge). Bundled in this plugin's .mcp.json. The user must enable it once: Xcode → Settings (⌘,) → Intelligence → Xcode Tools → ON. Xcode must be running with the target project open.claude-in-chrome (user-installed). Used to render the HTML prototype for screenshotting.Follow these steps in order. Do not skip the build or visual-diff steps.
"${CLAUDE_PLUGIN_ROOT}/skills/claude-design-to-swiftui/scripts/fetch.sh" <design-url-or-tarball-path>
Accepts either a Claude design URL (https://api.anthropic.com/v1/design/h/<id>?open_file=<name>) or a local .tar.gz path. The script downloads (if needed), unpacks to a temp directory, starts a localhost-bound python3 -m http.server on a free port, and prints three lines on stdout:
http://127.0.0.1:51234/index.html)Entry resolution: URL-decoded open_file= query param → index.html → first *.html. The local server is required because Claude designs commonly use ES modules / fetch() which fail under file:// origins.
Note: design URLs are one-shot/short-lived. Fetch immediately; if it 404s, ask the user for a fresh URL.
Use claude-in-chrome to render the prototype at iPhone-class viewport:
mcp__claude-in-chrome__tabs_create_mcp → open the URL from step 1 (do not use file://).mcp__claude-in-chrome__resize_window → 390x844 (iPhone 15 Pro logical size).mcp__claude-in-chrome__computer (screenshot action) → capture the rendered page.Keep this screenshot — the prototype reference for step 7's diff loop.
Read the entry HTML and every linked stylesheet (<link rel="stylesheet">) and inline <style> block. Build a mental model of:
Also do an asset inventory pass (used in step 4):
<svg> elements — collect the unique ones (after whitespace normalization). Most Claude designs put icons inline this way.<link href="https://fonts.googleapis.com/css2?family=...". The &family= segments give the font families (URL-decode + to space).<img> tags — separate into local paths (relative to the entry HTML) vs external URLs (http:///https://).background-image: url(...)) — same separation as <img>.Skip <script> tags — JS behavior is out of scope. (For React/JSX prototypes, the JSX iconSvg map and component tree are still the source of truth for what gets rendered — read them like a description of the DOM.)
Walk the DOM top-down using the reference mappings (loaded on demand):
references/layout-mapping.md (flex/grid/block → VStack/HStack/ZStack/Grid/ScrollView)references/styling-mapping.md (padding, background, border, shadow → SwiftUI modifiers)references/typography-mapping.md (font-family/size/weight → .font() / .fontWeight() / .lineSpacing())references/component-patterns.mdFor the assets inventoried in step 3, run them through these handlers:
references/svg-to-sfsymbol.md (curated SF Symbol map). On miss, fall back to references/svg-path-translation.md (emit a fileprivate struct FooIcon: View with a hand-translated Path).references/font-mapping.md. Default behavior: map each detected family to its closest SwiftUI system equivalent and emit a // Fonts detected in prototype comment block at the top of the file. Original-font fidelity requires manual user steps (download .ttf, drag into Xcode, edit Info.plist UIAppFonts) — the Xcode 26.3 MCP exposes no tools for project-file or Info.plist mutation; see the "Original-font fidelity" section in references/font-mapping.md for the recipe to hand the user.<img> tags / CSS background-image → references/asset-catalog-import.md. Local files get imported into Assets.xcassets/<name>.imageset/; external URLs become AsyncImage.When unsure how a chunk maps, see examples/01-landing-card/ and examples/02-list-with-rows/ for end-to-end before/after pairs.
Translation rules:
<div> becomes a wrapping VStack (or whatever container fits).padding: 16px → .padding(16)); don't abstract into design tokens for v1.Color(hex:) from a fileprivate extension Color at the bottom of the file (so it doesn't collide with helpers in the user's project).Path-based icons go next to the Color extension as additional fileprivate struct FooIcon: View declarations. Reuse one struct across multiple usage sites of the same SVG.ScrollView if content is taller than 844pt.mcp__plugin_claudedesign-to-swiftui_xcode-tools__XcodeListWindows to find the open workspace and its on-disk root path.OnboardingView.swift, SettingsListView.swift). If multiple workspace folders exist, ask the user which target group to write into. If only one obvious group exists, write there.mcp__plugin_claudedesign-to-swiftui_xcode-tools__XcodeWrite with the chosen path and the generated SwiftUI source.Required file structure:
import SwiftUI
// Fonts detected in prototype (mapped to SF equivalents): ← only when Google Fonts detected
// Newsreader → .system(design: .serif)
// Geist Mono → .system(design: .monospaced)
struct MeaningfulName: View {
var body: some View {
// ...translated layout...
}
}
#Preview {
MeaningfulName()
}
// At file bottom, in this order, each only if used:
// 1. fileprivate extension Color { init(hex: String) ... } ← if any hex colors
// 2. fileprivate struct FooIcon: View { ... Path { ... } } ← one per unique custom SVG
fileprivate extension Color {
init(hex: String) { /* ... */ }
}
The file must compile standalone — no external packages, no references to types defined elsewhere in the user's project.
mcp__plugin_claudedesign-to-swiftui_xcode-tools__BuildProject for the active scheme.mcp__plugin_claudedesign-to-swiftui_xcode-tools__XcodeListNavigatorIssues to read structured diagnostics.references/swiftui-gotchas.md — most build failures here (expression-too-complex, ForEach Identifiable, Color(hex:) not found, foregroundColor vs foregroundStyle, etc.) have a known fix that's faster than diagnosing from the raw error.mcp__plugin_claudedesign-to-swiftui_xcode-tools__XcodeUpdate.BuildProject.For tall designs (anything that scrolls past 844pt — long landing pages, settings screens with many rows, dashboards with multiple cards): before calling RenderPreview, modify the #Preview { ... } block to force a frame tall enough to capture the whole layout, otherwise the preview only renders the iPhone viewport's top ~844pt and below-the-fold content goes un-diff'd:
#Preview {
MeaningfulName()
.previewLayout(.sizeThatFits)
.frame(width: 390, height: 1800) // estimate from prototype screenshot height
}
Pick the height by eyeballing the prototype screenshot from step 2 (use the rendered HTML's full document height, not the 844 viewport). Better to overshoot — the preview will whitespace-pad the bottom but at least nothing is hidden.
For single-screen designs (≤ 844pt), skip this — the default preview is fine.
mcp__plugin_claudedesign-to-swiftui_xcode-tools__RenderPreview for the file you just wrote — it returns the actual rendered preview as an image.mcp__plugin_claudedesign-to-swiftui_xcode-tools__XcodeUpdate, then go back to step 6 (build) → step 7 (re-render).When done, show the user: the prototype screenshot, the final preview screenshot, and the path to the file you wrote.
"${CLAUDE_PLUGIN_ROOT}/skills/claude-design-to-swiftui/scripts/stop.sh" <pid> <dir>
Pass the PID and directory captured in step 1. This kills the http.server process and removes the unpack directory. Always run this even if earlier steps failed.
If xcode-tools MCP is not available (e.g., Xcode < 26.3, MCP not enabled, or no project open):
Write tool to emit the .swift file. Ask the user where to put it.If claude-in-chrome MCP is not available: