## Core Haptics engine setup

- Use case: Boilerplate for custom haptic patterns: capability check, engine creation, and auto-restart handlers.
- Feel: N/A — infrastructure required by every custom pattern in this library.
- APIs: CHHapticEngine, CHHapticEvent, CHHapticPattern
- Minimum OS: iOS 13+

### Core Haptics

```swift
import CoreHaptics

/// Owns a CHHapticEngine and keeps it alive across app lifecycle events.
final class HapticEngine {
    static let shared = HapticEngine()
    private var engine: CHHapticEngine?

    /// True on iPhone 8 and later. Always gate custom patterns on this.
    var supportsHaptics: Bool {
        CHHapticEngine.capabilitiesForHardware().supportsHaptics
    }

    private init() {
        guard supportsHaptics else { return }
        do {
            engine = try CHHapticEngine()
            // Restart automatically if the system stops the engine
            // (audio session interruption, backgrounding, etc.)
            engine?.resetHandler = { [weak self] in
                try? self?.engine?.start()
            }
            engine?.stoppedHandler = { reason in
                print("Haptic engine stopped: \(reason)")
            }
            try engine?.start()
        } catch {
            print("Haptic engine failed to start: \(error)")
        }
    }

    /// Plays an array of events as a one-shot pattern.
    func play(_ events: [CHHapticEvent]) {
        guard supportsHaptics, let engine else { return }
        do {
            let pattern = try CHHapticPattern(events: events, parameters: [])
            let player = try engine.makePlayer(with: pattern)
            try engine.start() // no-op if already running
            try player.start(atTime: CHHapticTimeImmediate)
        } catch {
            print("Failed to play pattern: \(error)")
        }
    }
}
```

### Notes
- Two building blocks: .hapticTransient (a tick — like a drum hit) and .hapticContinuous (a sustained buzz with a duration).
- Two parameters shape every event: hapticIntensity (strength, 0–1) and hapticSharpness (0 = round/dull thud, 1 = crisp/precise click).
- Restart the engine in sceneDidBecomeActive if you play haptics right after foregrounding.
