CLAUDE LABJP
FORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as OctoberFORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as October
Articles/Claude Code
Claude Code/2026-05-15Intermediate

Eliminating SwiftUI Animation Guesswork with Claude Code — Prompt Patterns from a 50M Download Wallpaper App

How to use Claude Code for SwiftUI animation work — practical prompt patterns and Before/After code examples from the development of Beautiful HD Wallpapers, a 50M+ download app.

Claude Code196SwiftUI7iOS24AnimationIndie Dev22Mobile App

SwiftUI made animations more declarative and concise than UIKit, but the "why isn't this working" rabbit hole is just as deep as ever. Stacking .animation() modifiers, tweaking the scope of withAnimation, watching the preview fail in confusing ways — it still eats hours if you approach it without a clear mental model.

I've been building iOS apps independently since 2013. Beautiful HD Wallpapers, one of the apps I've maintained over those years, has crossed 50 million downloads. Wallpaper apps live or die on the quality of their scroll, zoom, and transition animations — so animation code is something I revisit regularly. Over the past year, the way I use Claude Code for this work has shifted in a few meaningful ways. Here's what's actually helped.

Why "Just Fix This" Doesn't Work Well for Animations

Dropping a Swift file into Claude Code and asking it to "improve the animation" rarely produces useful output on the first try. Animation problems are almost always an intent problem before they're a code problem. The code might be technically valid and still be completely wrong for what you're trying to communicate to the user.

Take a card-flip animation as a concrete example. If I hand Claude Code my Card.swift and say "improve the animation," it has no way to know which dimension of "improve" matters here:

  • Is the duration wrong?
  • Does the easing feel unnatural at the start?
  • Does the back face flicker during the rotation?
  • Is the timing relationship between the flip and a secondary label animation off?

Claude Code can't do that disambiguation for me. I need to bring that information to the conversation, and the quality of what comes back is almost entirely determined by the quality of what I bring.

This sounds obvious written out, but in practice there's a strong pull toward just pasting the code and hoping. The three-element structure below is what I use to resist that pull.

The Three-Element Prompt Pattern

After enough iterations, I settled on a consistent structure for animation-related prompts:

[Current] Tapping a card triggers .rotation3DEffect. Duration is 0.3s, linear.
[Expected] Fast start, eases toward the end. A brief pause after the back face appears.
[Constraint] iOS 16+, Xcode 16.x. No side effects on sibling views.

The three elements are: current state, expected behavior, and constraints.

The constraint field is what makes this structure particularly effective. Specifying the minimum iOS version filters out suggestions that would require availability guards for APIs you can't use. Specifying scope — "no side effects on sibling views" — prevents Claude Code from suggesting refactors that, while arguably cleaner, would require touching code you don't want to touch right now.

Expected behavior is where most of the value lives, though. "Feels more natural" is too vague to act on. "Fast start, eases toward the end, brief pause after back face appears" gives Claude Code something specific to optimize toward.

I didn't think in terms of structured prompts when I started building apps independently. Working with Claude Code made me notice that I'd been asking imprecise questions and blaming the tool for imprecise answers. The three-element pattern is essentially just a discipline for asking better questions.

Animation Patterns from the Wallpaper App

Paging Transition Between Wallpapers

In Beautiful HD Wallpapers, switching between wallpapers uses a custom paging transition rather than TabView's default behavior. The default cut felt abrupt — users described it as "jarring," and that description was accurate. There was no visual momentum communicating that the content was being replaced, not just updated.

The condensed prompt I used:

[Current] TabView with .page style. The cut between wallpapers feels abrupt on swipe.
[Expected] Current wallpaper slides left out of frame. Next wallpaper fades in from the right.
           easeInOut curve, approximately 0.35s.
[Constraint] iOS 16+. Wallpapers load via AsyncImage — placeholder visible while loading.
             The transition should work correctly even if the next image isn't loaded yet.

The core of what Claude Code suggested, after cleanup:

struct PageTransitionModifier: ViewModifier {
    let offset: CGFloat
    let opacity: Double
 
    func body(content: Content) -> some View {
        content
            .offset(x: offset)
            .opacity(opacity)
            .animation(.easeInOut(duration: 0.35), value: offset)
    }
}
 
// Call site
WallpaperView(wallpaper: current)
    .modifier(PageTransitionModifier(
        offset: isTransitioning ? -UIScreen.main.bounds.width : 0,
        opacity: isTransitioning ? 0 : 1
    ))

The AsyncImage constraint was the tricky part — the transition needed to feel smooth regardless of whether the next wallpaper had finished loading. Claude Code's initial suggestion handled the loaded state cleanly but treated the placeholder as an afterthought. The final implementation required two or three rounds of refinement.

That's typical. Claude Code rarely returns production-ready animation code on the first pass. What it consistently does is provide a reasonable starting shape — something to refine rather than something to figure out from scratch — which is where most of the time savings come from.

Fine-Tuning a Tap Response Animation

Another case from Beautiful HD Wallpapers: tapping a wallpaper thumbnail to open a detail view. The thumbnail needed to feel like it was being "selected" — a subtle scale-up to confirm the tap before the transition plays.

The first version used a simple .spring() without parameters. It worked, but the spring felt slightly overdamped — a small bounce at the end that I wanted to eliminate.

[Current] .spring() modifier on scaleEffect. Slight bounce at the end feels off.
[Expected] Scale from 1.0 to 1.05 quickly, no bounce, hold briefly, then transition.
           Should feel like physical pressure, not a trampoline.
[Constraint] iOS 16+. Transition to detail view follows immediately — timing needs to coordinate.

The key adjustment Claude Code suggested was using spring(response:dampingFraction:) with a high damping fraction instead of the parameterless .spring():

withAnimation(.spring(response: 0.2, dampingFraction: 0.9)) {
    isSelected = true
}

A dampingFraction close to 1.0 eliminates the oscillation. The response parameter controls how quickly it reaches the target. This is the kind of parameter relationship that's documented but easy to forget in practice — having it surfaced by Claude Code during a review saved me the trip to the documentation.

Using Claude Code as a Reviewer

One of the more useful patterns is treating Claude Code as a code reviewer rather than a code generator. Hand it existing code and ask for critique instead of asking it to write from scratch. This surfaces issues that accumulate when you've been inside a codebase long enough to stop noticing them.

Before:

Button(action: { showDetail = true }) {
    Image(uiImage: wallpaper.thumbnail)
        .resizable()
        .scaledToFill()
}
.animation(.spring(), value: showDetail)

I asked: "Point out any animation-related issues in this code."

Claude Code flagged three things:

  1. Attaching .animation() to the Button propagates it to all child views. Any view inside the button that depends on showDetail will animate, whether or not that's the intent.
  2. The animated property isn't explicit — it's not clear which visual attribute is supposed to change when showDetail becomes true.
  3. .spring() without parameters has version-dependent defaults. Explicit parameters are more predictable across iOS versions.

After:

Button(action: {
    withAnimation(.spring(response: 0.35, dampingFraction: 0.7)) {
        showDetail = true
    }
}) {
    Image(uiImage: wallpaper.thumbnail)
        .resizable()
        .scaledToFill()
        .scaleEffect(showDetail ? 1.05 : 1.0)
}

The scaleEffect makes the animated property explicit. The withAnimation block scopes the animation to the state change, not the view hierarchy.

As an indie developer maintaining multiple apps without a team, getting targeted feedback like this isn't something that happens naturally. Code review is a collaboration I mostly do with Claude Code now, and for animation issues specifically, it's been reliable enough that I use it consistently before any change goes into a release branch.

First-Pass Performance Diagnosis

High-resolution image apps put pressure on memory and the rendering pipeline. When animation performance degrades on older devices — frame drops, stuttering during transitions — the cause is often not the animation itself but something nearby: image decoding happening synchronously on the main thread, heavy operations inside onAppear, or excessive view invalidation on each animation frame.

Before opening Instruments, I pass the suspicious section to Claude Code with this kind of request: "Identify patterns in this code that are likely to cause animation performance problems on older devices."

It won't catch everything. Instruments is still the right tool for confirming and measuring. But as a first pass — something to do before the 15-minute setup of a proper profiling session — Claude Code consistently identifies the most common culprits. It's narrowed my Instruments sessions from "find the problem" to "confirm the problem I already suspect."

Where to Start

If there's animation code in your project that's been "good enough for now" for a while — timing that never quite felt right, a transition that's slightly off but not broken enough to prioritize — pick one instance and write the three elements: current state, expected behavior, constraints.

The act of writing those three elements often clarifies what the problem actually is before Claude Code even responds. And the habit of writing them transfers well beyond AI tools: PR descriptions, inline comments, technical conversations — structured intent makes all of those better too.

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 →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Claude Code2026-05-28
Claude Code × Xcode Cloud — A One-Week Migration of ci_scripts and TestFlight Auto-Delivery
Notes from migrating a long-running indie iOS CI from Fastlane to Xcode Cloud in one week, with the three ci_scripts/ hook scripts in full, TestFlight automation, and dSYM upload — all paired with Claude Code.
Claude Code2026-05-24
Automating iOS Crashlytics Triage with Claude Code — A Production Pipeline from dSYM Symbolication to Draft PR
How I rebuilt iOS crash triage at our 50M+ download app studio: Firebase Crashlytics issues flow into a Cloud Functions + Claude Code pipeline that handles dSYM symbolication, blast-radius estimation, and a draft fix PR in under 90 seconds. Real numbers, real code, real lessons.
Claude Code2026-04-18
Claude Code for Mobile App Development in 2026: A Practical SwiftUI & Kotlin Workflow
How to actually integrate Claude Code into iOS (SwiftUI) and Android (Kotlin) development. Real patterns from an indie developer maintaining multiple apps.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →