Lab 3.1 — Figma to SwiftUI
Duration: ~90 minutes Prereqs: Xcode 16+, Figma account (free tier works), a working iPhone simulator
Goal
Take a publicly available Figma design and ship a pixel-accurate SwiftUI implementation. You will exercise the full handoff workflow: status checking, Dev Mode inspection, token extraction, asset export, layout translation, and side-by-side visual diffing.
By the end you’ll have:
- A SwiftUI screen that matches the Figma frame within ~2pt accuracy
- Extracted design tokens (color, spacing, typography) defined in code
- Exported assets in the right formats
- A documented diff between your output and the source
Setup
- Open the iOS 17 UI Kit by Joey Banks on Figma Community (or any similar free iOS UI kit — pick one with a single “Tip Calculator” or “Login” screen).
- Duplicate the file to your drafts.
- Open it in Dev Mode (top-right toggle, or press
Shift + D). - Pick one frame — recommended: a single-screen design like a login, settings detail, or tip calculator. Avoid multi-screen flows for this lab.
- Take a full-resolution screenshot of the chosen frame (right-click → Export → PNG @2x). Save as
reference.png.
Steps
Step 1 — Audit the design (10 min)
Before writing code, inspect:
- Status: Is the frame marked “Ready for Dev”? (If not, set it.)
- Layout structure: Open the layers panel. Note the nesting (VStack/HStack equivalents).
- Colors used: Open Dev Mode → Variables panel. List every color → hex value AND token name if defined.
- Spacing: ⌥-drag between elements. Note the rhythm (likely 8, 16, 24, 32pt).
- Typography: Click each text element → note font, size, weight, line-height.
- Assets: List every image and icon. Note format needs (SF Symbol available? Custom?).
Document everything in a DESIGN_NOTES.md next to your Xcode project.
Step 2 — Create the Xcode project (5 min)
File → New → Project → iOS → App → SwiftUI → Swift
Name: FigmaToSwiftUI
Add an Asset Catalog DesignTokens.xcassets (or use the default Assets.xcassets).
Step 3 — Define design tokens (15 min)
Create DesignTokens.swift:
import SwiftUI
enum Spacing {
static let xs: CGFloat = 4
static let sm: CGFloat = 8
static let md: CGFloat = 16
static let lg: CGFloat = 24
static let xl: CGFloat = 32
}
enum AppFont {
static let title = Font.system(size: 28, weight: .bold)
static let body = Font.system(size: 17, weight: .regular)
static let caption = Font.system(size: 13, weight: .medium)
}
For each color from the Figma frame, add a Color Set to Asset Catalog:
Assets.xcassets→ right-click → New Color Set- Name it semantically (
brandPrimary,surfaceCard,textPrimary) — not by hex - Attributes Inspector → Appearances: Any, Dark
- Set Any to the Figma hex value
- Pick a sensible dark mode pair (desaturate brand colors ~15%)
Generated symbols give you Color(.brandPrimary) with compile-time checking.
Step 4 — Export assets (10 min)
For each asset in Figma:
- Icons: First check if SF Symbols 6 has it (
heart,gear,arrow.right, etc.). 90% of common UI icons are in SF Symbols. - Custom icons: Export as SVG from Figma. Convert to SF Symbol using the SF Symbols Mac app, OR drop into Asset Catalog as PDF (with “Preserve Vector Data” checked).
- Photos / illustrations: Export as PNG @1x and @3x. Drop into Asset Catalog as Image Set; Xcode auto-picks the right scale.
Export from Figma: select layer → right panel “Export” section → set format → click Export.
Step 5 — Build the layout (30 min)
Match the Figma frame structure to SwiftUI containers:
| Figma | SwiftUI |
|---|---|
| Frame with Auto Layout: vertical | VStack |
| Frame with Auto Layout: horizontal | HStack |
| Frame with Auto Layout: wrap | LazyVGrid or HStack + flexible |
| Group | ZStack or no container |
| Constraints “Hug contents” | natural sizing |
| Constraints “Fill container” | .frame(maxWidth: .infinity) |
| Padding on Auto Layout | .padding(...) |
| Gap (spacing between children) | VStack(spacing: ...) |
Example mapping for a card with title and subtitle:
VStack(alignment: .leading, spacing: Spacing.sm) {
Text("Title")
.font(AppFont.title)
.foregroundStyle(Color(.textPrimary))
Text("Subtitle here")
.font(AppFont.body)
.foregroundStyle(Color(.textSecondary))
}
.padding(Spacing.md)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(.surfaceCard))
.clipShape(RoundedRectangle(cornerRadius: 12))
Step 6 — Side-by-side visual diff (15 min)
In Xcode:
- Run the app on iPhone 16 simulator
- Take a screenshot (
Cmd+Sin simulator) - Open both screenshots —
reference.png(Figma export) and your simulator screenshot — in Preview side by side - Use Preview’s “Tools → Adjust Size” or layer them in a Figma comparison frame
- Note every discrepancy: spacing off by 2pt, wrong font weight, missing shadow, etc.
- Fix iteratively
For pixel-precise diffing, use the Pixel-Perfect Chrome extension or import both into Figma as PNGs and overlay with 50% opacity.
Step 7 — Document the diff (5 min)
In DESIGN_NOTES.md add a “Known Discrepancies” section:
- Font rendering differs because Figma uses macOS font hinting; iOS renders differently → acceptable
- Shadow blur 12pt vs 14pt in code → fix
- Etc.
Stretch goals
- Dark mode: cover the same frame in dark mode. Run the simulator in dark mode (
Cmd+Shift+Ain simulator). Verify Asset Catalog dark variants render correctly. - Dynamic Type: enable accessibility size XXL via Settings → Accessibility → Display & Text Size → Larger Text. Does your layout reflow gracefully?
- VoiceOver: turn on VoiceOver and navigate the screen. Are labels meaningful? Add
.accessibilityLabelwhere needed. - iPad: run on iPad simulator. Does the layout adapt or look stretched? Consider
NavigationSplitView.
Acceptance criteria
- Project builds and runs on iPhone 16 simulator
-
All tokens defined in
DesignTokens.swiftand Asset Catalog (no hex literals in views) - All Figma assets exported and added to Asset Catalog
- Layout matches reference within 2pt accuracy on each axis
-
DESIGN_NOTES.mddocuments tokens, assets, and known discrepancies - No SF Symbol replaced by a custom asset (icon work done right)
Common pitfalls
- Pixel-pushing with frames: don’t
.frame(width: 327, height: 64)everything. Use Auto Layout (HStack/VStack+ padding) like Figma does. Hard-coded sizes break with Dynamic Type. - Hardcoded colors: every
Color(red:green:blue:)orColor(hex:)is a future bug. Use Asset Catalog. - Custom icons when SF Symbol exists: search SF Symbols 6 first. Saves bytes, scales perfectly, supports color variants.
- Wrong Auto Layout direction: confused about HStack vs VStack? In Figma, look at the Auto Layout property: “↓” = VStack, “→” = HStack.
What you’ve learned
You’ve executed the full design → engineering handoff loop. You can now look at any Figma frame and build it in SwiftUI without the designer hand-holding. You understand why semantic tokens beat hex literals, why SF Symbols beat custom assets, and how to verify your work visually.
Real-world version: this is exactly the loop you’ll run on every feature, every PR, for the rest of your iOS career.