Generates achievement celebration UI with confetti animations, badge unlocks, progress milestones, haptic feedback, and optional share-to-social. Use when user wants to celebrate achievements, show confetti, display milestone badges, or trigger rewards on key thresholds.
Scanned 9/6/2026
Install to Claude Code
npx -y skills add rshankras/claude-code-apple-skills --skill milestone-celebration --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Milestone Celebration?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/rshankras-milestone-celebration)More formats (shields.io, HTML) on the badges page.
---
name: milestone-celebration
description: Generates achievement celebration UI with confetti animations, badge unlocks, progress milestones, haptic feedback, and optional share-to-social. Use when user wants to celebrate achievements, show confetti, display milestone badges, or trigger rewards on key thresholds.
allowed-tools: [Read, Write, Edit, Glob, Grep, Bash, AskUserQuestion]
last_verified: 2026-07-16
review_by: 2027-06-22
os_version: iOS 27 / macOS 27
---
# Milestone Celebration Generator
Generate a production milestone celebration system with confetti particle animations via `CAEmitterLayer`, achievement badge views with locked/unlocked states, a celebration overlay with spring animations, haptic feedback, and optional shareable achievement cards — all triggered automatically when users hit key thresholds.
## When This Skill Activates
Use this skill when the user:
- Asks to "add celebrations" or "celebrate achievements"
- Wants "confetti animation" or "particle effects for milestones"
- Mentions "achievement badges" or "badge unlock animation"
- Asks about "milestone rewards" or "progress milestones"
- Wants to "celebrate achievement" or "trigger celebration on threshold"
- Asks about "level-up animation" or "gamification celebrations"
## Pre-Generation Checks
### 1. Project Context Detection
- [ ] Check Swift version (requires Swift 5.9+)
- [ ] Check deployment target (iOS 17+ / macOS 14+ for `@Observable`, spring animations, `sensoryFeedback`)
- [ ] Check for `UIKit` availability (iOS — `CAEmitterLayer` for confetti, haptics)
- [ ] Identify source file locations
### 2. Conflict Detection
Search for existing celebration/animation code:
```
Glob: **/*Confetti*.swift, **/*Celebration*.swift, **/*Achievement*.swift, **/*Milestone*.swift, **/*Badge*.swift
Grep: "CAEmitterLayer" or "CAEmitterCell" or "UINotificationFeedbackGenerator" or "confetti" or "celebration"
```
If existing celebration or gamification library found (e.g., custom confetti, third-party particle libraries):
- Ask if user wants to replace or integrate with it
- If keeping, advise on best practices instead of generating
### 3. Platform Detection
Determine if generating for iOS (UIKit-based confetti + haptics) or macOS (Core Animation confetti, no haptics) or both (cross-platform with feature gates).
## Configuration Questions
Ask user via AskUserQuestion:
1. **Celebration type?** (multi-select)
- Confetti burst (full-screen particle animation)
- Badge unlock (icon reveal with glow animation)
- Level-up (progress ring fill + title transition)
- Custom (user defines their own celebration style)
2. **Haptic feedback?**
- Yes — success haptic on celebration trigger (recommended)
- No — silent celebrations only
3. **Shareable achievement card?**
- Yes — render achievement as image for social sharing via `ShareLink`
- No — in-app celebration only
4. **Sound effects?**
- Yes — play system sound or bundled audio on celebration
- No — visual only
## Generation Process
### Step 1: Read Templates
Read `templates.md` for production Swift code.
### Step 2: Create Core Files
Generate these files:
1. `Milestone.swift` — Model with id, title, description, threshold, icon, unlock state. `Codable` + `Sendable`.
2. `MilestoneTracker.swift` — `@Observable` class tracking progress toward milestones, checking thresholds, triggering celebrations. Persists unlock state via `UserDefaults` or file storage.
3. `ConfettiView.swift` — `UIViewRepresentable` wrapping `CAEmitterLayer` for confetti particle animation. Configurable colors, duration, density. Respects Reduce Motion.
### Step 3: Create UI Files
4. `CelebrationOverlay.swift` — Full-screen overlay combining confetti + badge reveal + congratulations message. Auto-dismisses after configurable duration. Uses `withAnimation(.spring)`.
5. `MilestoneBadgeView.swift` — Individual badge view with locked/unlocked states, SF Symbol icon, progress ring for partial progress.
6. `MilestoneCollectionView.swift` — Grid layout of all milestones showing locked/unlocked state with progress indicators.
### Step 4: Create Optional Files
Based on configuration:
- `HapticManager.swift` — If haptic feedback selected (thin wrapper around `UINotificationFeedbackGenerator` / `UIImpactFeedbackGenerator`)
- `ShareableMilestoneCard.swift` — If shareable selected (renders milestone as image via `ImageRenderer` + `ShareLink`)
### Step 5: Determine File Location
Check project structure:
- If `Sources/` exists -> `Sources/MilestoneCelebration/`
- If `App/` exists -> `App/MilestoneCelebration/`
- Otherwise -> `MilestoneCelebration/`
## Output Format
After generation, provide:
### Files Created
```
MilestoneCelebration/
├── Milestone.swift # Model with threshold, icon, unlock state
├── MilestoneTracker.swift # @Observable tracker with persistence
├── ConfettiView.swift # CAEmitterLayer confetti animation
├── CelebrationOverlay.swift # Full-screen celebration overlay
├── MilestoneBadgeView.swift # Badge with locked/unlocked + progress ring
├── MilestoneCollectionView.swift # Grid of all milestones
├── HapticManager.swift # Celebration haptics (optional)
└── ShareableMilestoneCard.swift # Achievement share card (optional)
```
### Integration Steps
**Trigger celebration on threshold:**
```swift
struct WorkoutCompleteView: View {
@State private var tracker = MilestoneTracker()
@State private var celebratingMilestone: Milestone?
var body: some View {
VStack {
// ... workout summary content ...
Button("Save Workout") {
saveWorkout()
let newCount = totalWorkouts + 1
if let milestone = tracker.checkThreshold(value: newCount, category: .workouts) {
celebratingMilestone = milestone
}
}
}
.overlay {
if let milestone = celebratingMilestone {
CelebrationOverlay(milestone: milestone) {
celebratingMilestone = nil
}
}
}
}
}
```
**Badge collection screen:**
```swift
struct ProfileView: View {
@State private var tracker = MilestoneTracker()
var body: some View {
NavigationStack {
ScrollView {
MilestoneCollectionView(
milestones: tracker.allMilestones,
columns: 3
)
}
.navigationTitle("Achievements")
}
}
}
```
**Share an achievement:**
```swift
struct MilestoneDetailView: View {
let milestone: Milestone
@State private var showShareCard = false
var body: some View {
VStack {
MilestoneBadgeView(milestone: milestone, size: .large)
Text(milestone.title).font(.title2.bold())
Text(milestone.milestoneDescription).foregroundStyle(.secondary)
if milestone.isUnlocked {
Button("Share Achievement") {
showShareCard = true
}
.buttonStyle(.borderedProminent)
}
}
.sheet(isPresented: $showShareCard) {
ShareableMilestoneCard(milestone: milestone, brandName: "FitApp")
}
}
}
```
### Testing
```swift
@Test
func milestoneUnlocksAtThreshold() {
let tracker = MilestoneTracker(store: InMemoryMilestoneStore())
let milestone = Milestone(
id: "first-10",
title: "First 10",
milestoneDescription: "Complete 10 workouts",
threshold: 10,
iconName: "flame.fill"
)
tracker.register(milestone)
let result = tracker.checkThreshold(value: 10, for: milestone.id)
#expect(result != nil)
#expect(result?.isUnlocked == true)
#expect(result?.unlockedDate != nil)
}
@Test
func milestoneDoesNotUnlockBelowThreshold() {
let tracker = MilestoneTracker(store: InMemoryMilestoneStore())
let milestone = Milestone(
id: "first-10",
title: "First 10",
milestoneDescription: "Complete 10 workouts",
threshold: 10,
iconName: "flame.fill"
)
tracker.register(milestone)
let result = tracker.checkThreshold(value: 9, for: milestone.id)
#expect(result == nil)
}
@Test
func confettiRespectsReduceMotion() {
// When Reduce Motion is enabled, ConfettiView should not emit particles
let config = ConfettiConfiguration(reduceMotionOverride: true)
#expect(config.shouldAnimate == false)
}
@Test
func celebrationOverlayAutoDismisses() async throws {
// Verify overlay dismisses after the configured duration
let expectation = XCTestExpectation(description: "Dismissed")
let duration: TimeInterval = 0.5
// Test that the onDismiss callback fires after duration
}
```
## Common Patterns
### Trigger Celebration on Threshold
Best for: fitness, learning, productivity apps.
- Define milestones with numeric thresholds (10 workouts, 100 pages read, 7-day streak)
- `MilestoneTracker` checks values against registered milestones
- Celebration fires only on the first crossing — subsequent calls are no-ops
- Persist unlock state so celebrations do not repeat
### Badge Collection View
Best for: gamification, loyalty, progression systems.
- Grid of all milestones: locked ones are dimmed/grayscale, unlocked ones are vibrant
- Progress ring shows how close user is to unlocking each badge
- Tapping a badge shows detail view with full description and share option
- Counter showing "12 of 20 unlocked" at the top
### Share Achievement
Best for: social apps, fitness, competitions.
- Render the unlocked badge + title + metric as a shareable image
- Use `ImageRenderer` at `@2x` scale for Retina quality
- Include app branding and optional QR code for deep linking
- Integrate with `ShareLink` for native share sheet
## Gotchas
### CAEmitterLayer Performance on Older Devices
- Confetti with many particles (200+) can drop frames on A11 and older chips
- Cap `birthRate` at 50-80 for smooth 60fps on most devices
- Use `emitterCells` with only 3-5 distinct shapes to reduce GPU draw calls
- Stop emission after burst duration — do not leave the emitter running indefinitely
- Profile with Instruments (Core Animation template) if users report frame drops
### Reduce Motion Accessibility
- Always check `UIAccessibility.isReduceMotionEnabled` before starting particle animations
- When Reduce Motion is on: skip confetti, show a static badge reveal or a simple fade-in instead
- Use `@Environment(\.accessibilityReduceMotion)` in SwiftUI for reactive updates
- Provide an equally rewarding experience without animation — the badge reveal and message still appear
### Haptic Feedback on Non-Supporting Devices
- `UINotificationFeedbackGenerator` is a no-op on devices without a Taptic Engine (e.g., iPod touch, iPad)
- Always guard with `CHHapticEngine.capabilitiesForHardware().supportsHaptics` before preparing generators
- On macOS, haptics are not available — gate with `#if canImport(UIKit)` and `#if os(iOS)`
- Use `.sensoryFeedback(.success, trigger:)` modifier on iOS 17+ for a simpler SwiftUI-native approach
### Sound Effect Considerations
- Use `AudioServicesPlaySystemSound` for lightweight celebration sounds (no audio session needed)
- Respect the device silent/mute switch — `AudioServicesPlaySystemSound` honors it automatically
- For custom sounds, keep files under 30 seconds and use CAF or WAV format
- Do not play sounds when Reduce Motion is enabled (some users enable it for sensory reasons)
### Persistence Edge Cases
- If the app is terminated between unlocking a milestone and persisting it, the user may see the celebration again
- Use `UserDefaults` for simple unlock flags or a lightweight JSON file for full milestone state
- For `SwiftData` or `CoreData` apps, consider storing unlock state alongside the user's data model
- Sync unlock state via CloudKit if the app supports multiple devices
### App Store Guidelines
- **Guideline 4.5.4**: Milestone-announcement pushes ("you're 1 away from a badge!") are promotional — explicit opt-in consent and an in-app opt-out are required.
- **Guideline 2.3.1**: Screenshots showing badges and achievements must reflect what the app actually awards — aspirational metadata is a rejection risk.
- **Guideline 4.3 (Spam)**: Celebrations don't differentiate a thin app. If this is one of several similar apps on your account, run `app-store/originality-check` before submitting.
## References
- **templates.md** — All production Swift templates
- Related: `generators/streak-tracker` — Streak tracking pairs naturally with milestone celebrations
- Related: `generators/share-card` — Shareable achievement card rendering and social sharing
- Related: `generators/variable-rewards` — Variable reward schedules for deeper engagement
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!