Other haptic runtime APIs
Updated: Nov 11, 2025
While
Haptics Studio and
Haptics SDK are the recommended path for haptics on Quest, there are a number of other haptics APIs available in the runtime. These provide lower-level control to your application and may be useful in some specific contexts. You may consider these APIs when building custom middleware integrations, or when you need features not supported by the Haptics SDK, such as haptics generated on-the-fly, or when employing controller-specific APIs, like adding localized haptics on Meta Quest Touch Pro controllers.
To trigger high-fidelity haptic effects that allow varying the vibration frequency, use the parametric haptics or PCM haptics API. Varying vibration frequency is supported for controllers with a VCM (Voice Coil Motor), which is Meta Quest Touch Pro, Touch Plus and later. Out of the two APIs, parametric haptics is recommended for most use cases due to its ease of use and device-agnostic data format.
With the simple haptics API, you can trigger a vibration with a specified intensity. The controller vibrates at that intensity until you call the API again with a different intensity. By calling the API repeatedly at different times, such as once per frame, you trigger a vibration with an intensity that changes over time. The vibration will automatically stop after 2 seconds after your last call, or when you call the API with an amplitude of 0.
To start, update, or end a vibration, call SetControllerVibration() at the time when you want to make the change:
public static void OVRInput.SetControllerVibration(
float frequency,
float amplitude,
Controller controllerMask)
Expected values for amplitude are any value between zero and one, inclusive. The greater the amplitude, the stronger the vibration in the controller. Frequency should be set to 1 to enable haptics.
Note on Frequency:
Frequency should be set to 1 to enable haptics, but this value will have no further impact on the actual frequency at which the controller vibrates. The only way to dynamically change the frequency of the motor is by using Haptics SDK or PCM haptics as your haptics API.
// starts vibration on the right Touch controller
OVRInput.SetControllerVibration(1, 1, OVRInput.Controller.RTouch);
The Meta Quest Touch Pro controller has three haptic actuators: two LRAs (Linear Resonant Actuators) for thumb and trigger, and one VCM (Voice Coil Motor). You can use the localized haptics API to trigger vibrations on any actuator, including the two LRAs. All other haptic APIs trigger a vibration on the VCM only.
To start, update, or end a vibration on any actuator, call SetControllerLocalizedVibration():
public static void SetControllerLocalizedVibration(
HapticsLocation hapticsLocationMask,
float frequency,
float amplitude,
Controller controllerMask = Controller.Active)
Apart from allowing triggering vibrations on the two LRAs (the thumb and trigger locations), this function behaves the same as SetControllerVibration().
hapticsLocationMask represents the location where the effect will be played:
public enum HapticsLocation
{
None = OVRPlugin.HapticsLocation.None,
Hand = OVRPlugin.HapticsLocation.Hand, // main haptics location with VCM
Thumb = OVRPlugin.HapticsLocation.Thumb, // haptics location on the thumb with LRA
Index = OVRPlugin.HapticsLocation.Index, // haptics location on the trigger with LRA
}
Experimental API
The parametric haptics API is being released as an experimental feature. The Meta Quest Store will not accept any products that incorporate experimental features. These features are provided on an "as-is" basis, subject to all applicable terms set forth in the Meta Platform Technologies SDK License Agreement.
Using any experimental feature requires you to configure your app and Quest device. See the Manage experimental features page for enabling experimental features on the Quest device, and the Use Link for App Development page for enabling experimental features on Quest Link (Windows PCVR). With the parametric haptics API, you can trigger a high-fidelity vibration with an intensity and frequency that vary over time. The vibration is described in a device-agnostic format.
For an example of how to use the API, you can look at the code snippet below or at the sample scene and its script in the Samples/Haptics/ folder.
Parametric haptics is supported on Quest 2 and later devices.
A parametric haptics vibration is described by a series of amplitude points, frequency points, and transients.
The amplitude points describe how the intensity of the vibration changes over time.
The frequency points describe how the frequency of the vibration changes over time, which is supported by Meta Quest Touch Pro, Touch Plus and later controllers. Frequency points are ignored for older controllers.
A transient is a short burst that has a strong and “clicky” characteristic. Transients are useful for adding a layer of distinct, discernible, and emphasized points to the resulting vibration.
The parametric haptics data is translated to a signal that drives the haptic motor. Meta Quest Touch Pro, Touch Plus and later controllers have a voice coil motor (VCM), which is driven by a PCM waveform. Previous controllers like the Meta Quest Touch have a linear resonant actuator (LRA), which is driven by stepped amplitude changes. On these controllers, the frequency points are ignored, as they vibrate at a fixed frequency.
Triggering a parametric haptics vibration
You can trigger a parametric haptics vibration by making one call to the SetControllerHapticsParametric() function and passing the amplitude points, frequency points, and transients of the entire vibration:
using static OVRInput;
[..]
HapticsParametricPoint[] amplitudePoints = new HapticsParametricPoint[]
{
new HapticsParametricPoint { Time = 0, Value = 0.0f },
new HapticsParametricPoint { Time = 4000000000, Value = 1.0f },
new HapticsParametricPoint { Time = 10000000000, Value = 1.0f },
};
HapticsParametricPoint[] frequencyPoints = new HapticsParametricPoint[]
{
new HapticsParametricPoint { Time = 0, Value = 1.0f },
new HapticsParametricPoint { Time = 6000000000, Value = 1.0f },
new HapticsParametricPoint { Time = 10000000000, Value = 0.0f },
};
HapticsParametricTransient[] transients = new HapticsParametricTransient[]
{
new HapticsParametricTransient { Time = 3000000000, Amplitude = 1.0f, Frequency = 1.0f },
};
HapticsParametricVibration hapticsVibration = new HapticsParametricVibration();
hapticsVibration.AmplitudePoints = amplitudePoints;
hapticsVibration.FrequencyPoints = frequencyPoints;
hapticsVibration.Transients = transients;
hapticsVibration.MinFrequencyHz =
(int)OVRPlugin.HapticsConstants.ParametricHapticsUnspecifiedFrequency;
hapticsVibration.MaxFrequencyHz =
(int)OVRPlugin.HapticsConstants.ParametricHapticsUnspecifiedFrequency;
hapticsVibration.StreamFrameType = HapticsParametricStreamFrameType.None;
SetControllerHapticsParametric(hapticsVibration, Controller.RTouch);
The values for amplitude points, frequency points, and transients range from 0.0 to 1.0. The time values for these points are in nanoseconds since the start of the haptic vibration. The first amplitude point needs to be at time 0ns. Frequency points and transients are optional.
You can either define the amplitude points, frequency points, and transients in code, or use
Meta Haptics Studio, export the haptic clip as a
.haptic JSON file, and then read the data from that file.
While you can trigger a vibration by passing the entire data upfront in one call to SetControllerHapticsParametric(), in some cases you need multiple calls to SetControllerHapticsParametric() over time, in which the data is passed piece-by-piece. This is called streaming. Streaming is needed in these cases:
- When not all of the haptic data is known upfront, and is generated on-the-fly instead.
- When the haptic data contains more than the maximum of 500 amplitude points, frequency points, or transients.
The haptic data passed in one API call is called a haptic frame. In the initial call to the API, you pass the first frame of haptic data. Before that frame has been fully played out, you call the API again with a new frame of haptic data. The first frame needs to contain at least two amplitude points, later frames need to contain at least one. For each call, set StreamFrameType to the appropriate frame type. The example code above does not use streaming, so the frame type is set to HapticsParametricStreamFrameType.None.
Call the GetControllerParametricProperties() function to query the minimum duration the first frame needs to have, as well as the optimal timing interval for sending subsequent frames:
HapticsParametricProperties rightControllerParametricProperties =
OVRInput.GetControllerParametricProperties(Controller.RTouch);
The minimum duration the first frame needs to have is available in HapticsParametricProperties.MinimumFirstFrameDuration, and the optimal timing interval for sending subsequent frames is available in HapticsParametricProperties.IdealFrameSubmissionRate.
The amplitude and frequency values range from 0.0 to 1.0, which are automatically mapped to the full intensity and frequency range supported by the controller.
For frequencies, you can also specify the absolute frequency range in Hertz. The absolute frequency range is specified in the first frame, and used for the entire haptic vibration. To specify the absolute frequency range, set MinFrequencyHz and MaxFrequencyHz to the respective values. The example code above uses the maximum frequency range supported by the controller, so both values are set to ParametricHapticsUnspecifiedFrequency.
To query the maximum frequency range supported by the controller, call GetControllerParametricProperties(). The supported frequency range is available in the MinFrequencyHz and MaxFrequencyHz members of HapticsParametricProperties.
Amplitude envelope haptics
With the amplitude envelope haptics API, you can trigger a vibration with an intensity that varies over time. How the intensity changes over time is described in the amplitude envelope that is passed upfront in a single API call.
Consider the following complex analog signal.
The amplitude envelope of a signal is a smooth curve outlining its extremes. The amplitude envelope for the above signal would look like this:
To start an amplitude envelope vibration, call SetControllerHapticsAmplitudeEnvelope():
public static void SetControllerHapticsAmplitudeEnvelope(
HapticsAmplitudeEnvelopeVibration hapticsVibration,
Controller controllerMask = Controller.Active)
If an effect is already playing when this function is called, the new effect will begin playing immediately.
The HapticsAmplitudeEnvelopeVibration parameter contains the description of the effect:
public struct HapticsAmplitudeEnvelopeVibration
{
public int SamplesCount;
public float[] Samples;
public float Duration;
}
The fields are described as follows:
| Field | Description |
|---|
Samples
| A float array representing the amplitude envelope values. |
SamplesCount
| The number of elements in the Samples array. |
Duration
| A float value representing the duration of the haptic effect in seconds. |
With the PCM haptics API, you can trigger a vibration that is described by a PCM (Pulse Code Modulation) waveform. For controllers with a VCM (Meta Quest Touch Pro, Touch Plus and later), the PCM waveform directly drives the haptic motor. For other controllers (Meta Quest Touch and earlier), an equivalent haptic effect is played.
To start a PCM haptics vibration, call SetControllerHapticsPcm():
public static int SetControllerHapticsPcm(
HapticsPcmVibration hapticsVibration,
Controller controllerMask = Controller.Active)
If an effect is already playing when this function is called, the new effect will begin playing immediately.
The HapticsPcmVibration parameter contains the description of the effect:
public struct HapticsPcmVibration
{
public int SamplesCount;
public float[] Samples;
public float SampleRateHz;
public bool Append;
}
The fields are described as follows:
| Field | Description |
|---|
Samples
| A float array. Represents the haptic feedback samples. If you consider the haptic effect as a sampled analog audio, then this buffer will contain the samples representing that effect. |
SamplesCount
| The number of samples in the Samples array. |
SampleRateHz
| A float value representing the number of samples to be played from Samples per second. This is used to determine the duration of the effect. |
Append
| To support long haptic effects, set this flag to true, which means that the effect will be played after the currently-playing effect is finished. If Append is false, then the provided effect will begin playing immediately. |
The system resamples the waveform to the sample rate of the controller. If you prefer to match the signal sample rate to that of the controller (saving the system the need to resample), use the sample rate returned by the GetControllerSampleRateHz function to generate the haptic data:
public static float GetControllerSampleRateHz(Controller controllerMask = Controller.Active)