- From: Kearwood Gilbert <notifications@github.com>
- Date: Wed, 14 Sep 2016 18:07:02 -0700
- To: w3c/gamepad <gamepad@noreply.github.com>
- Message-ID: <w3c/gamepad/pull/32/c247204121@github.com>
I have given this a bit of thought and iterated on some WebIDL for an interface that makes the easy "pulse" effects simple while enabling high frequency buffered haptic effects.
Here is a rough draft of proposed WebIDL:
```
// Each value is normalized to a range between 0.0 and 1.0
// The actuator type determines the force applied for a given
// "value" in GamepadHapticActuatorBuffer or GamepadHapticActuator
enum GamepadHapticActuatorType {
// Vibration is a rumbling effect often implemented as an offset weight
// driven on a rotational axis.
// The "value" of a vibration force determines the frequency of the rumble
// effect and is normalized between 0.0 and 1.0
"vibration",
// Linear actuators shift a weight to an absolute position, changing the
// center of gravity of the controller and resulting in an opposing force
// that can be felt by the holder.
// The "value" of a linear force is the absolute position of the actuator
// relative to its center position and is normalized between -1.0 and 1.0
"linear",
// XXX - Angular force (steering wheels), springs, dampeners, and other
// actuators should be defined as separate GamepadHapticActuatorType's
// here instead of being mapped to "vibration" or "linear".
};
// Each GamepadHapticActuator corresponds to a motor or other actuator that can
// apply a force for the purposes of haptic feedback. In some cases, the
// physical arrangement of devices may be represented as a simpler model to this
// api. For example, a device with multiple degrees of freedom may process
// the actuator values passed into the api with inverse kinematics to determine
// the position required for the physical actuators.
dictionary GamepadHapticActuator {
// type determines the range and effect of the "value"
// passed to pulse() and within the GamepadHapticActuatorBuffer.
readonly attribute GamepadHapticActuatorType type;
// Pulse applies a value to the actuator for duration milliseconds.
// If any GamepadHapticEffect is playing, the value passed to pulse()
// is applied additively, clamped to limits defined by the actuator type.
// The returned promise will resolve true once the pulse has completed.
Promise<void> pulse(float value, float duration);
};
// GamepadHapticBuffer represents a timeline of values to drive a
// GamepadActuator.
dictionary GamepadHapticBuffer {
// actuator identifies the actuator that will be driven by the
// effect. If multiple GamepadHapticBuffer are driving the same
// actuator, the values are combined additively and clamped within the
// range defined by the actuator type.
GamepadHapticActuator actuator;
// It is recommended to normalize these values, as they can
// be attenuated by setting GamepadHapticEffect.gain
sequence<float> values = [ ];
// Durations are expressed in milliseconds
sequence<float> durations = [ ];
// The number of iterations to repeat the set of values.
// If iterations is 0, then repeat infinitely.
attribute unsigned long iterations;
};
// GamepadHapticEffect describes any haptic effect that is more complex than
// a simple pulse.
interface GamepadHapticEffect {
// buffers defines which actuators are being driven and with which pattern of
// values.
// A GamepadHapticEffect can affect a single or multiple Gamepads.
// GamepadHapticEffect is associated to a Gamepad through
// GamepadHapticBuffer.actuator
// If multiple effects or pulses are playing simultaneously, the values of each
// actuator are combined additively.
attribute bool sequence<GamepadHapticBuffer> buffers;
// When GamepadHapticEffect is playing, IsPlaying is true.
// The GamepadHapticEffect does not begin playing until play() is called.
readonly attribute bool IsPlaying;
// play() starts playing the GamepadHapticEffect.
// The returned promise will resolve true once the effect is completed or
// stop() is called.
// If any of the buffers have iterations set to 0 (infinite), the promise
// will not resolve true until stop() is called.
// Changes to the buffers are not reflected in a playing haptic effect and
// will only be applied once the effect is played again.
// If the haptic effect is already playing, play() will not interrupt
// the haptic effect and will resolve fail the returned promise.
// If you wish to play multiple of the same effect additively, multiple
// GamepadHapticEffect's should be created, but can share GamepadHapticBuffer's.
[Throws]
Promise<void> play();
// stop() ends playback of the effect and returns the values of the actuators
// to the neutral value as defined by the actuator type.
// It is not necessary to call stop() if all of the buffers have non-zero
// iterations.
void stop();
// XXX Do we wish to have a pause() function?
// gain is a 0.0 - 1.0 attenuation of HapticBuffer values.
// Unlike changes to buffers, changes to gain are effective immediately on
// a playing haptic effect.
// Simple dynamic collision effects can be modelled with a set of short,
// infinitely repeating HapticBuffer's and an ADSR envelope applied with the
// gain attribute.
attribute float gain;
};
partial interface Gamepad {
// hapticActuators enumerates haptic feedback actuators such as rumble motors.
readonly attribute GamepadHapticActuator[] hapticActuators;
// playingHapticEffects includes any GamepadHapticEffect that are playing
// and driving any actuator in this Gamepad.
readonly attribute GamepadHapticEffect[] playingHapticEffects;
};
```
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/gamepad/pull/32#issuecomment-247204121
Received on Thursday, 15 September 2016 01:07:34 UTC