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

  1. 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).
  2. Duplicate the file to your drafts.
  3. Open it in Dev Mode (top-right toggle, or press Shift + D).
  4. Pick one frame — recommended: a single-screen design like a login, settings detail, or tip calculator. Avoid multi-screen flows for this lab.
  5. 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:

  1. Assets.xcassets → right-click → New Color Set
  2. Name it semantically (brandPrimary, surfaceCard, textPrimary) — not by hex
  3. Attributes Inspector → Appearances: Any, Dark
  4. Set Any to the Figma hex value
  5. 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:

FigmaSwiftUI
Frame with Auto Layout: verticalVStack
Frame with Auto Layout: horizontalHStack
Frame with Auto Layout: wrapLazyVGrid or HStack + flexible
GroupZStack 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:

  1. Run the app on iPhone 16 simulator
  2. Take a screenshot (Cmd+S in simulator)
  3. Open both screenshots — reference.png (Figma export) and your simulator screenshot — in Preview side by side
  4. Use Preview’s “Tools → Adjust Size” or layer them in a Figma comparison frame
  5. Note every discrepancy: spacing off by 2pt, wrong font weight, missing shadow, etc.
  6. 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+A in 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 .accessibilityLabel where 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.swift and 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.md documents 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:) or Color(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.


Next: Lab 3.2 — HIG & Accessibility Audit