UI polish is HARDER for AI than features (here's how to fix it)
Author
Giovanni Lu
Date Published

Problem
When cloning the Grok iOS app I had Claude work on the UI first and then connect it to our backend. The resulting app worked end to end but didn't feel as nice as the real one. There were little things like Text sizes and weights were off, the greys were the wrong shade, and some gradients were missing. I'm too lazy to identify and fix each one of these little errors so I was going to leave it. Then I thought... Claude can probably fix this.
Action
Then I thought... Claude can probably fix this.
Screenshots and "just fix it" prompts aren't enough, I needed a way for Claude to see and use the real app so it can iterate over all the possible user interactions inside of the app. My first thought was to use Simulator + Xcode, but there's no way to get Grokbot onto simulator, so instead I wrapped the iphone mirroring app with a small script and that worked pretty dang good.
- Drove the iPhone from the Mac. A small CLI (you can find it in the
ios-app-parityskill) runs the macOS iPhone Mirroring window. It takes screenshots, taps, types, launches apps through Spotlight and records the screen. Both apps ran on the same phone, so captures line up pixel for pixel. - Measured instead of eyeballing. For each screen we captured Grok Bot and openGrok in the same state. Then we read off text heights, colours, spacing and corner radii from the pixels and converted them to points (≈1.54 px/pt on an iPhone 16 Pro Max).
- Took real assets where they exist. Grok Bot's 13 character shapes and its colour palette came from the Grok Bot desktop app's own avatar renderer, read over its debug port. They aren't redrawn by hand.
- Fixed, redeployed to the phone, re-shot. We repeated that until each screen matched, then moved to the next: home, chat, bot details (each tab), search, settings.
- Checked motion on video. We recorded the same tap-through in both apps and asked Gemini to compare the two videos. Then we checked its claims frame by frame, because it misread one transition (it called a push a sheet). It was right about our tab switching, so we fixed that.
Result
It's still not 100% the same, the cute animations of the bots when idling or working was not copied over (neither did I expect it to, to be honest), but it's at the point of diminishing returns. If I had time to take a crack at the animations I might do it, but it doesn't bother me at all to keep using it as is.
Home

- Avatars: each bot has Grok Bot's character shape (blob, cloud, square, sparkle, clover, heart, flower, teardrop, tablet, wedge, house, star, hex). The eyes are see-through, and the main bot wears the orange star coin.
- Colours: bot colours render in Display P3, so they are as saturated as Grok Bot's. Before, the same hex values looked washed out.
- Page: the background is Grok Bot's #FCFCFC, not pure white.
- List rows:
- Characters are 46 pt with a 15 pt gap to the text.
- Names are 17 pt regular, previews 15 pt grey, times 13 pt light grey.
- Section headers are lighter, with a thin chevron.
- Header: the initials coin replaces the glass capsule. The blue "N unread" pill replaces the brown "Needs attention".
Chat

- Title: the bot's avatar and name sit in a glass pill.
- Bubbles: messages are 17 pt in Grok Bot's neutral grey, and paragraphs are separated by a half-line gap instead of a blank line.
- Composer:
- A round "+" with composer actions sits beside the field.
- The field reads "Ask <bot>" and has a mic for on-device dictation.
- One black round button does voice, send or stop, depending on state.
- Timestamps: date dividers are lighter.
Bot details

- Info tab first, with Grok Bot's Character editor:
- All 13 shapes as bare silhouettes, plus the 11-colour palette and "Reset to default".
- Picking a shape or colour saves it to the bot.
- Below that come Instructions (the persona), Routines and Skills.
- Name card: smaller, in the same grey.
- Tabs: only the underline slides, on a spring. Before, the old and new tab content cross-faded over each other.
- Empty tabs: one quiet line ("No documents in this conversation yet") instead of an icon and paragraph.
- Media: a two-column grid of square tiles.
- Computer tab:
- The screen is a hairline-bordered card with a status line ("Can't reach <bot>'s screen").
- The bot's name label and a black "Take control" pill sit below it.
Search and settings

- Search: a sheet, not an inline field.
- At the top: close, a glass search field and a filter.
- Then every bot and group, each with its persona line and a quiet "Bot" or "Group Chat" label.
- Settings: grey cards on a near-white sheet, with no title.
- Sheets: they stop just below the home header and have no grabber, like Grok Bot's.
Also
- Status bar: limiting the app to one window keeps the status bar when it's shown through iPhone Mirroring.
- Reusable approach: it's packaged as the
ios-app-parityskill (prerequisites, scripts, the loop).
Not covered
- Below the first screen: iPhone Mirroring ignores synthesized scrolling, so content further down a screen wasn't compared.
- New chat: Grok Bot's "+" is disabled on this account, so the new-chat flow has no reference yet.
- Dictation: works in code, but needs the user to grant microphone and speech permission the first time.
(The chat "after" frame was taken just before one last fix: the "+" is black now, not blue.)
Get the skill
Skill
ios-app-parity
Make an iOS app look and feel like a reference app on the same iPhone: drive both through macOS iPhone Mirroring, measure the differences, fix, redeploy, and get a Gemini video comparison as a second opinion.
Download
ios-app-parity.zip
SKILL.md
---
name: ios-app-parity
description: Use when an iOS app should look and feel like a reference app that's installed on a real iPhone — "make our app match X", "compare our app with the real app", "polish to parity", "use iPhone Mirroring". Drives the reference and your app through macOS iPhone Mirroring (screenshots, taps, typing, screen recording), measures the differences, fixes them, redeploys to the phone, and gets a Gemini video comparison as a second opinion.
---
# iOS app parity via iPhone Mirroring
Make your iOS app match a reference app by looking at both on the same iPhone, one screen at a time.
**Before you start:** check [prerequisites.md](prerequisites.md): a Mac, the iPhone, Xcode, permissions and a Gemini key.
## The loop
1. **Build the tool:** `swiftc -O scripts/mirror.swift -o scripts/mirror`, then `scripts/mirror info` should say `accessibility granted`.
2. **Capture both apps on the same screen:**
```bash
M=scripts/mirror
$M open "Reference App"; $M shot /tmp/ref_home.png
$M open "Your App"; $M shot /tmp/ours_home.png
```
Move around with `$M tap X Y` (pixels from the screenshot), `type`, `key`, `home`.
3. **Measure, don't eyeball:** `scripts/measure.py box|color SHOT X0,Y0,X1,Y1`. This gives text heights, colours, spacing.
Turn them into points (≈1.54 px/pt on an iPhone 16 Pro Max).
4. **Fix your app**, then `scripts/deploy-device.sh App.xcodeproj Scheme com.your.bundle`.
5. **Re-shoot and compare.** Repeat until the screen matches, then move to the next screen.
6. **Check motion:** record the same tap-through in both apps (`scripts/flow.sh`, or `$M record-start` / `record-stop`).
Then run `scripts/compare.py ref.mov ours.mov "focus"`. Check Gemini's claims against frames
(`ffmpeg -i x.mov -vf fps=8,tile=10x1 …`). It sometimes misreads transitions.
7. **Commit each screen** with a message that lists what changed.
## Know before you go
- **No scrolling or swipes:** iPhone Mirroring ignores synthesized drags and scrolls; taps and keys work. Compare what's visible on the first screen, plus transitions.
- **Lock the phone to connect.** Picking up the phone ends the session.
- **Missing status bar:** if your app allows multiple scenes, Mirroring draws it without the status bar. Set `UIApplicationSupportsMultipleScenes = false`.
- **Steal real assets where you can:** if a desktop or web version of the reference app exists, read its SVGs and colour tokens (e.g. over the Chrome DevTools Protocol for an Electron app) instead of redrawing them.
- **Colours look washed out?** The reference may use Display P3.