◉CLAUDE LABJP
●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/Claude Code
⟐ Claude Code/2026-06-30Advanced

Fixing Blurry Wallpapers on New iPhones with Claude Code: Safely Growing a Per-Device Resolution Map

Why wallpapers go blurry or letterboxed on brand-new iPhones, and how to collapse scattered device branches into a single source of truth you can extend in one line — walked through as a real Claude Code refactor with before/after code.

Claude Code264iOS26Swift5wallpaper apprefactoring4indie developer21

✦ Premium Article

The weekend a new iPhone shipped, I got a report on my wallpaper app, Beautiful HD Wallpapers, that one new device showed a faint band above and below the image. Reproducing it in the simulator confirmed it: on the new model only, the wallpaper sat centered with the background color filling the top and bottom. The cause was mundane — the code that decides each device's resolution didn't know the new screen size, so it fell back to "the nearest old device" and served an image whose aspect ratio didn't match.

A wallpaper app lives or dies on one thing: serving the exactly correct pixel resolution for each device. Get the aspect ratio even slightly wrong and you either upscale into softness or letterbox into empty bands. Yet after years of updates, that decision had scattered itself across the codebase. Here's how I collapsed that sprawl into a single table with Claude Code, so a new device now takes one line — with the actual code along the way.


Why "nearest height" quietly breaks

Start with the precise root cause. An iOS screen is two-layered: logical points and physical pixels. UIScreen.main.bounds returns points; the real pixel count is that multiplied by nativeScale (3.0 on most recent devices). A wallpaper image has to line up with those physical pixels, or the system rescales it and softens the result.

In my app, the branch that picks an image size or layout constant per device had been appended to, screen by screen, with every new model — ending up as 29 ternary expressions. The typical shape:

// ❌ Before: matching by screen "height" alone
// branches like this multiplied across the app with each new device
func wallpaperPixelHeight() -> CGFloat {
    let h = UIScreen.main.bounds.height
    if h >= 932 {          // meant to be "Pro Max class"
        return 2796
    } else if h >= 852 {   // meant to be "standard Pro"
        return 2556
    } else if h >= 844 {
        return 2532
    } else {
        return 2436        // fall back to older devices
    }
}

This has two weaknesses. First, when a new model's height lands in a gap between thresholds, it gets sucked into an unintended branch. Second, the only axis is height, so a device with a different aspect ratio gets treated as identical to a same-height device. For wallpapers the second one is fatal: even a few points of width difference at the same height means the image is slightly stretched or letterboxed.

The band on the new iPhone was exactly that — a device "close in height but different in width" was handled as an old device.


First, have Claude Code list every branch

The plan is clear: gather the scattered branches into one place, switch the axis from height to the screen's point size (a width/height pair), and change selection from "nearest height" to "exact size match, then closest aspect ratio." But rewriting blind would miss one of the 29 sites. The first job is to know the full set precisely.

This is where Claude Code helps. Asking it to find the branches semantically is faster and leakier than hand-grepping. I asked:

List every place in this repo that branches on UIScreen.main.bounds
height/width or UIDevice model name. Give me a table of file path,
line number, and what each branch switches (image size / inset /
font etc.). Do not make any changes yet.

The "do not make any changes yet" matters. Claude Code will happily rewrite everything at once, but a refactor is safer in the order understand → design → replace → verify. The returned list showed that of the 29 sites, 6 switched image size and the rest were insets or safe-area constants. That told me to carve out the image-size decision first.


✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Understand why wallpapers go soft or letterboxed only on new iPhones, and ship a fix that matches by aspect ratio instead of nearest height in your own app
✦Learn how to safely fold 20–30 scattered device-branching ternaries into one source-of-truth table using Claude Code, with before/after Swift
✦Rebuild the logic so a new device takes a single new line, and catch any miss with a snapshot test that fails loudly
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⟐ Claude Code2026-04-15
Building StoreKit 2 × SwiftUI Purchases with Claude Code — The Minimum That Passes Review
Build a StoreKit 2 × SwiftUI purchase flow end to end with Claude Code as your design partner — PurchaseManager, server-side validation, and paywall UI — plus the operational traps Apple's docs skip, like Ask to Buy and late-arriving transactions.
⟐ Claude Code2026-10-12
After Moving to SPM, My App Died the Moment It Launched — Reading One dyld Line with Claude Code
Right after moving from CocoaPods to Swift Package Manager, the build passed but the app died on launch. Here is how I traced one dyld line to its cause, the fix, and how to verify it.
⟐ Claude Code2026-09-04
The One File I Keep Out of Claude Code's Reach: project.pbxproj
With Xcode project files, the breakage that still opens costs far more than the breakage that refuses to open. Here is what I measured before moving every edit behind a script, and where the line sits today.