What an AHAP file is
AHAP is the file format behind Core Haptics. Instead of building CHHapticEvent objects in Swift, you describe the same pattern in JSON and ship it as a resource in your app bundle. The format covers:
- Haptic events: transient taps and continuous vibrations, each with intensity and sharpness.
- Audio events: custom audio files or generated tones that play in sync with the haptics.
- Dynamic parameters and curves: values that change the feel of events over time, such as a fade-out.
Because it is data, not code, an AHAP file can be reviewed, versioned, swapped per device or loaded from a server like any other asset.
The structure of an AHAP file
At the top level there are three keys:
| Key | Required | Purpose |
|---|---|---|
Version | Yes | Format version, 1.0 |
Metadata | No | Free-form info such as project name or description |
Pattern | Yes | An array of entries, each wrapped in Event, Parameter or ParameterCurve |
Event entries
Each Event dictionary has:
Time: start time in seconds, relative to the start of the pattern.EventType:HapticTransient,HapticContinuous,AudioContinuousorAudioCustom.EventDuration: length in seconds. Continuous events need it; transients do not.EventParameters: an array of{ "ParameterID": ..., "ParameterValue": ... }pairs. For haptic events the two you will use most areHapticIntensityandHapticSharpness, both from 0 to 1.
AudioCustom events point at a sound file through EventWaveformPath, which is how a pattern can carry its own audio.
Parameter and ParameterCurve entries
These change things while the pattern plays. A Parameter sets a value at a moment in time. A ParameterCurve interpolates between control points listed in ParameterCurveControlPoints. Both use the control IDs, such as HapticIntensityControl and HapticSharpnessControl, not the plain event IDs. Mixing those up is a frequent mistake in hand-written files.
A small AHAP example
This pattern plays a sharp tap, then a half-second rumble that fades out:
{
"Version": 1.0,
"Pattern": [
{ "Event": { "Time": 0.0, "EventType": "HapticTransient",
"EventParameters": [
{ "ParameterID": "HapticIntensity", "ParameterValue": 1.0 },
{ "ParameterID": "HapticSharpness", "ParameterValue": 0.8 } ] } },
{ "Event": { "Time": 0.1, "EventType": "HapticContinuous", "EventDuration": 0.5,
"EventParameters": [
{ "ParameterID": "HapticIntensity", "ParameterValue": 0.7 },
{ "ParameterID": "HapticSharpness", "ParameterValue": 0.2 } ] } },
{ "ParameterCurve": { "ParameterID": "HapticIntensityControl", "Time": 0.1,
"ParameterCurveControlPoints": [
{ "Time": 0.0, "ParameterValue": 1.0 },
{ "Time": 0.5, "ParameterValue": 0.0 } ] } }
]
}
Note that control point times are relative to the curve’s own Time.
How to play an AHAP file in your app
The short version in Swift:
- Check
CHHapticEngine.capabilitiesForHardware().supportsHaptics. If it is false (iPad, Mac, Simulator), skip haptics quietly. - Create a
CHHapticEngineand callstart(). - Call
engine.playPattern(from: url)with the URL of the.ahapfile in your bundle.
For more control, build a CHHapticPattern from the file’s contents and create a player from it, which lets you start, stop and send dynamic parameters at runtime. Set the engine’s stoppedHandler and resetHandler too: the system can stop the engine (for example when the app goes to the background), and you need to restart it before the next pattern. Apple’s Core Haptics documentation covers the full API.
Common mistakes in hand-written AHAP files
- Using
HapticIntensityinside aParameterCurveinstead ofHapticIntensityControl. - Forgetting
EventDurationon a continuous event. - Values outside 0 to 1 for intensity or sharpness.
- Trailing commas or comments, which are not valid JSON.
- Testing only in the Simulator, where nothing plays, and assuming the file is fine.
Editing AHAP files visually with Haptic Forge
Reading JSON tells you what a pattern contains, not how it feels. Haptic Forge, my Core Haptics editor for iPhone, iPad and Mac, treats AHAP as its exchange format:
- Import any standard
.ahapfile, including ones written by hand or by other tools. Its events become editable layers on a single timeline. - Edit transient and continuous layers by dragging, or type exact intensity and sharpness values.
- Export a standard
.ahapfile that stays valid for any app that reads AHAP, so nothing in your project depends on the editor.
On Mac and iPad, where Core Haptics cannot play, you pair an iPhone and feel each edit there. That workflow is described in testing haptics on iPhone from your Mac. If you are still deciding which event type a moment needs, start with transient vs continuous haptics.