## Audio + haptic sync (CoreHaptics audio events)

- Use case: A confirmation that is heard and felt as one event — haptic and sound scheduled on the same clock.
- Feel: A click you hear and feel at the exact same instant. Scheduling both in one pattern removes all drift.
- APIs: CHHapticEvent(.audioContinuous / .audioCustom), registerAudioResource
- Minimum OS: iOS 13+

### Core Haptics

```swift
import CoreHaptics

func playClickWithSound(engine: CHHapticEngine) throws {
    // Register a bundled sound once (cache the ID in real code)
    guard let url = Bundle.main.url(forResource: "click",
                                    withExtension: "wav") else { return }
    let audioID = try engine.registerAudioResource(url)

    let haptic = CHHapticEvent(eventType: .hapticTransient, parameters: [
        CHHapticEventParameter(parameterID: .hapticIntensity, value: 0.9),
        CHHapticEventParameter(parameterID: .hapticSharpness, value: 0.8),
    ], relativeTime: 0)

    let sound = CHHapticEvent(audioResourceID: audioID, parameters: [
        CHHapticEventParameter(parameterID: .audioVolume, value: 0.8),
    ], relativeTime: 0)

    let pattern = try CHHapticPattern(events: [haptic, sound], parameters: [])
    let player = try engine.makePlayer(with: pattern)
    try engine.start()
    try player.start(atTime: CHHapticTimeImmediate)
}
```

### Notes
- This is how system sounds like keyboard clicks stay perfectly aligned with their haptics.
- Unregister audio resources you no longer need to free engine memory.
