Docs
Feedback

Status Morph

One stroke that spins while loading, then closes into a ring and draws a check on success or a cross on failure.

$npx swiftpieces add StatusMorph
Free · MIT + Commons ClauseiOS 17.0+Liquid Glassstatusloadingsuccessfailuretrimhapticupload
Type
StatusMorph
Files
StatusMorph.swift
Depends on
Nothing (Apple frameworks only)
Version
2.2.0
In a full screen · SwiftPieces ProAgent TaskAn agent task screen with a live timeline of tool calls, durations and expandable results.

Idle, loading, success, and failure in one ring that lands as a solid block, with an optional caption on a glass pill.

Notes

  • Loading is a 72% arc in ink turned by a TimelineView clock, so nothing runs while idle or settled. Each spin starts from rest wherever the stroke lies and reaches full speed within about half a second.
  • On success or failure the arc keeps its angle and coasts to rest at the speed it was turning, never swinging back, while it closes into a ring. A beat later the ring floods inward into a solid block (sage for success, the brand red for failure), and a beat after that the check or cross draws in dark ink. The stroke and the block are the content, so they stay solid.
  • The outcome lands as the block closes solid, about half a second after the change, while the mark finishes drawing: success plays the .success haptic and, with pops, a soft pop; failure plays the .error haptic and a short shake sized to the ring, on the same beat.
  • captions puts the caption on a liquid glass pill just under the ring. A changed caption morphs letter by letter: letters the two words share hold still and the rest blur through, so "Saving" becomes "Saved" in place, and the pill eases to its new width. An outcome's word changes two beats after the state, so it lands with the mark it names. With nothing to bud from, a caption that appears rises in on its own and one that goes sinks away; the slot keeps its height, so the ring never moves. The caption is quiet while working and full ink once settled, all in semibold.
  • Retrying from a settled state runs the morph in reverse: the mark un-draws, the arc turns back to ink and opens as it starts to turn, and the block drains outward into it in its own color. Going straight from success to failure recolors the ring, then the block a beat later, and swaps the check for the cross. Draining, the marks show only through what is left of the block, so ink never shows over the open center. Drawing in, they see the whole block, so the cross's first stroke never breaks as it crosses the closing center.
  • Each mark thins to nothing over the first few percent of its stroke, like a pen landing and lifting, so an un-drawn check never leaves its round cap behind.
  • A change that arrives mid-morph retargets from wherever the ring is, and a landing from an earlier state never plays late. An outcome left for idle before it lands still plays its haptic at once, without the pop or shake. A retry or the other outcome replaces one that hasn't landed, so only the newer outcome is felt. If the haptic matters, keep the view on screen until the outcome lands, for example before dismissing a sheet on success.
  • Style holds the two blocks, the ink, the arc and track colors and the caption colors, with house palette defaults that adapt to light and dark. tint still works and overrides the success block.
  • The check and cross are one Shape stroked to a progress, so the cross draws its two lines in order.
  • A view that appears already settled shows its final block and caption without replaying the morph or its haptic.
  • size is a @ScaledMetric, so the ring grows with Dynamic Type alongside its caption.
  • Before iOS 26 the caption pill draws on a frosted material with a light rim; under Reduce Transparency it is solid.
  • Under Reduce Motion the arc does not turn: while loading it holds still and breathes slowly in opacity, so it still reads as work in progress without a caption. Each change lands in one short beat with no rotation, pop or shake, and the mark shows through the block as it fills. The color, the mark, a crossfaded caption and the haptics still carry the outcome.
  • For a full agent task screen with a live tool timeline, see the Pro Agent Task screen.

Usage

StatusMorphExample()

Parameters

ParameterDescription
state.idle, .loading, .success, or .failure.
captionsOptional caption per state, on a glass pill under the ring. A changed caption morphs letter by letter, so "Saving" becomes "Saved" in place; a caption that appears rises in, and one that goes sinks away. Use .saving for "Saving / Saved / Failed".
sizeRing diameter in points; scales with Dynamic Type.
lineWidthStroke width for the ring, check, and cross.
tintOverrides the success block color. Defaults to style.success.
popsSoft scale pop when success lands.
styleBlock, stroke and caption colors. .standard lands sage for success and the brand red for failure, with dark ink marks.

Install

Pick one. Run it from the folder that contains your .xcodeproj and the files land inside your app.

Terminal

$npx swiftpieces add StatusMorph

Or ask your coding agent · Claude Code, Cursor or Xcode, once the MCP server is connected

>Add the SwiftPieces "Status Morph" piece to my app

Or copy the source above into your app.

New to SwiftUI?If you know React, CSS or Tailwind, SwiftUI is easier to pick up than it looks.Try real app patterns first

Building a whole app? See SwiftPieces Pro →

All feedback →

Build it yourself: SwiftUI loading states guide · SwiftUI haptics guide

On this page

SwiftPiecesPro

Build the whole app with one library.

Production-ready screens, whole flows, complete app templates, a Build Kit your agent follows and Pro remixing.

54 screens · 46 patterns · 48 flows · 12 templates · 31 Build Kit skills

Explore Pro