Companion to the liquid-glass skill (~/.claude/skills/liquid-glass/). Same tag system:
[verified] / [apple] / [multi] / [single] / [version-pinned] — see that skill's
SKILL.md. Composed 2026-08 and verified against Apple documentation and SDK interfaces.
Operating rules
- Before generating code, ALWAYS read the availability firewall in the companion
liquid-glass skill (installed alongside this one):
references/availability-and-sdk27.md. Motion code trips the same SDK-27 breakages (.ifban,@ContentBuilder, renames). - Load references on demand via the router — one topic, one file.
- The motion model: Liquid Glass and its motion were designed together. Glass does not fade — it materializes by modulating lensing; when glass grows, its material gets thicker (deeper shadow, stronger lensing). Size change is a material change, which is why morphs must be the system animation, never hand-faked.
- Verify motion claims against
references/before repeating them — circulating write-ups get several of these facts wrong; the corrected facts live in these files. - Profiling evidence beats reasoning: record an Instruments trace with
xctracebefore optimizing, and never trust the iOS Simulator for the SwiftUI instrument — seereferences/performance-and-instrumentation.md.
Hard rules (the short list)
- Never animate glass with
.opacity/ fades — useglassEffectTransition(.materializeis the sanctioned fade-like option). [multi] - Morphing silently no-ops unless ALL four hold: same
GlassEffectContainer;glassEffectIDper element in one shared@Namespace; the change is view insertion/removal (not a value change); the state change is insidewithAnimation. Plus geometry: nearest edges within the container'sspacing. [multi] - The interactive "squish" is one boolean —
.interactive(). No public spring/damping/ stiffness knobs exist; do not promise tunable jelly. [multi] - Gate every glass animation on
accessibilityReduceMotion— the default morph is a kinetic effect, and reduce-motion users have experienced it as flickering. The system does NOT gate yourwithAnimationfor you. [multi] - One animation source per property — never mix implicit
.animation,withAnimation, and scroll-driven updates on the same property. Implicit later in the view tree silently wins over explicit. [multi] - The animation context must live OUTSIDE a conditional — an
.animation()inside theifis destroyed with the view and removal never animates. [multi] - Prefer renderer-side motion for scroll:
scrollTransition/visualEffect(in:)over observable scroll-offset plumbing. [apple] - Animate transforms first (scale/offset/rotation), frames second, identity changes last. [multi]
Topic router
| Topic | Reference |
|---|---|
| Springs, curves, precedence, Transaction, @Animatable, CA bridge | references/animation-fundamentals.md |
| Glass morphing, glassEffectID, union, glassEffectTransition | references/morphing.md |
| Navigation zoom, custom Transition, sheets, touch-vs-trackpad | references/transitions-and-navigation.md |
| Scroll-driven motion, scrollTransition, visualEffect, chrome interplay | references/scroll-driven.md |
| PhaseAnimator, KeyframeAnimator, symbol effects | references/phase-and-keyframe.md |
| Reduce Motion gating, replacement tables | references/reduce-motion.md |
| Metal shaders with/under/instead-of glass | references/metal-and-glass.md |
| Performance model, xctrace profiling | references/performance-and-instrumentation.md |
| Static glass, availability, toolbars, platform APIs, a11y of the material | liquid-glass skill |
| Choosing the actual spring/damping/duration values | apple-motion-feel skill |
Scripts
scripts/record_trace.py and scripts/analyze_trace.py (+ instruments_parser/) — vendored
from Antoine van der Lee's SwiftUI-Agent-Skill (MIT; licence ships beside them as
scripts/LICENSE-AvdLee-SwiftUI-Agent-Skill). Record and parse Instruments traces (Time
Profiler, Hangs, Animation Hitches, SwiftUI lanes) into JSON/markdown. Usage and interpretation:
references/performance-and-instrumentation.md.