milestone-celebration
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.
Best use case
milestone-celebration is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
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.
Teams using milestone-celebration should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/milestone-celebration/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How milestone-celebration Compares
| Feature / Agent | milestone-celebration | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
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.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# 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
## 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 engagementRelated Skills
watchOS
watchOS development guidance including SwiftUI for Watch, Watch Connectivity, complications, and watch-specific UI patterns. Use for watchOS code review, best practices, or Watch app development.
visionos-widgets
visionOS widget patterns including mounting styles, glass/paper textures, proximity-aware layouts, and spatial widget families. Use when creating or adapting widgets for visionOS.
test-data-factory
Generate test fixture factories for your models. Builder pattern and static factories for zero-boilerplate test data. Use when tests need sample data setup.
test-contract
Generate protocol/interface test suites that any implementation must pass. Define the contract once, test every implementation. Use when designing protocols or swapping implementations.
tdd-refactor-guard
Pre-refactor safety checklist. Verifies test coverage exists before AI modifies existing code. Use before asking AI to refactor anything.
tdd-feature
Red-green-refactor scaffold for building new features with TDD. Write failing tests first, then implement to pass. Use when building new features test-first.
tdd-bug-fix
Fix bugs using red-green-refactor — reproduce the bug as a failing test first, then fix it. Use when fixing bugs to ensure they never regress.
snapshot-test-setup
Set up SwiftUI visual regression testing with swift-snapshot-testing. Generates snapshot test boilerplate and CI configuration. Use for UI regression prevention.
integration-test-scaffold
Generate cross-module test harness with mock servers, in-memory stores, and test configuration. Use when testing networking + persistence + business logic together.
characterization-test-generator
Generates tests that capture current behavior of existing code before refactoring. Use when you need a safety net before AI-assisted refactoring or modifying legacy code.
testing
TDD and testing skills for iOS/macOS apps. Covers characterization tests, TDD workflows, test contracts, snapshot tests, and test infrastructure. Use for test-driven development, adding tests to existing code, or building test infrastructure.
webkit-integration
WebKit integration in SwiftUI using WebView and WebPage for embedding web content, navigation, JavaScript interop, and customization. Use when embedding web content in SwiftUI apps.