Skip to main content

WYVRN Haptics Configuration

The WYVRN configuration supports Haptic effect playback. Haptic effect files (.haps) contain the data for playing haptics on Razer Sensa HD Haptics devices.

Tools

The main tools for creating the haptic part of the WYVRN folder are:

  • Haptic Composer: creation and design of the haptic files
  • Synesthesia App: debug console intercepting the WYVRN SDK API calls: InitSDK, SetEventName and UninitSDK (seen in the Synesthesia app as load; play and unload).

The Haptic Composer is a powerful design tool for creating high-definition haptic experiences that can be deployed across multiple platforms and devices. With an intuitive graphical interface, it allows designers to create, edit, and test haptic effects through a familiar timeline-based workflow.

The Synesthesia Console makes creating the WYVRN (Chroma - haptics) configuration for game integration super easy. The Synesthesia engine integrates the WYVRN enabled games with various Razer Chroma RGB and Sensa haptic devices to provide a synchronized gaming experience that involves dynamic chroma and haptic feedback based on in-game events. It can be downloaded from the following link: https://github.com/WyvrnOfficial/RazerSensa_DevKit/tree/master

The Synesthesia Console app can be found in the folder ReleaseConsole from this repository. The console version is provided for testing and QA purposes. The HapticFolders can also be found in the Synesthesia app folder under HapticFolders. The latest version of this folder can be found in C:\Program Files (x86)\Interhaptics\HapticFolders when Razer Chroma is installed together with Razer Synapse 4.

To use the console version instead of the production version of Synesthesia (included in Synapse/Chroma 4 as the HapticService background service) follow the steps below.

  1. Open Razer Chroma and open the Sensa HD Haptics tab. Check that Haptic Source is Sensa HD Games. If it is Audio-to-Haptics switch it to Sensa HD Games.

Razer Chroma Sensa HD Haptics tab

  1. Open Task Manager. Look for the Haptic Service background process and check if it is active. Restart it if it is not active.

Haptic Service Background Process

  1. Open the Synesthesia app downloaded from https://github.com/Interhaptics/RazerSensa_DevKit and test the setup with WYVRNFakeClient, or any WYVRN enabled game (i.e. Marvek Rivals) and the following commands load; active; play which will appear when starting the app.

When the application launches and initializes Chroma, the command to load the haptic configuration file is sent. When the SetEventName WYVRN API is called, the play command is sent.

Example:

Command Received: "load;Marvel Rivals"
Command Received: "play;Effect1"
...
Command Received: "unload;Marvel Rivals"

Haptic Folders and Files

The system uses a specific folder structure to manage haptic assets. Each game or application has a dedicated folder, named with a <Game_ID>, which contains all the necessary files for its haptic and Chroma effects.

  • Haptic Folder: The folder's name serves as the Game_ID used in external commands.
  • Configuration File: Each haptic folder must contain a single configuration file with a .config extension. This file, structured in JSON format, defines the links between external command IDs and the corresponding haptic or Chroma events.
  • Haptic and Chroma Files: These files have .haps and .chroma extensions, respectively. They contain the haptic or Chroma effect data and are created using the Haptic Composer or Chroma Studio. These files are triggered via the .config file.

External Commands

Communication with the Synesthesia process is handled through a series of simple, semicolon-separated commands. This allows the game to load, play, and stop haptic effects dynamically.

The general format for a command is: [COMMAND ID];[ARGUMENT_1];[ARGUMENT_2]

Four main commands are available for haptic control:

CommandCommand IDArgument 1Argument 2
Load game haptic effectsloadGame_ID
Unload game haptic effectsunloadGame_ID
Play haptic eventplayGame_IDExternal_Command_ID
Stop haptics eventstopGame_IDExternal_Command_ID

Load

The load command pre-loads all haptic effects for a game, preventing runtime delays when an effect is triggered for the first time. This should be called when the game launches. load;[Game_ID]

Unload

The unload command is used to free up resources by unloading a game's haptic effects. This should be called when the game is closed or the user navigates away from it. unload;[Game_ID]

Play

The play command triggers a specific haptic event defined in the game's .config file. If the corresponding game's configuration is not already loaded, the system will load it first. play;[Game_ID];[External_Command_ID]

Stop

The stop command halts haptic events. Its behavior varies based on the arguments provided:

  • stop;[Game_ID];[External_Command_ID]: Stops the specified event for the given game.
  • stop;[Game_ID]: Stops all currently playing haptic effects related to that game.
  • stop;: Stops all haptic effects from any game on all devices.

Configuration File

The .config file is a JSON file that acts as the brain for your game's haptic integration. It maps the External_Command_ID sent from the game to one or more haptic events.

ExternalCommands

The ExternalCommands array is the primary component of the configuration. Each entry links an External_Command_ID from the game to a corresponding set of Haptic_Events.

Example:

{
"ExternalCommands": [
{
"External_Command_ID": "PlayerRunning",
"Haptic_Events": [
...
]
}
]
}

Haptic Event Properties

Each haptic event can be customized with several properties that control its playback behavior.

{
"Haptic_Effect": "footsteps",
"Mixing": "Merge",
"Priority": "Medium",
"Loop": "infinity",
"Targeting": [
...
]
}
  • Haptic_Effect: The name of the .haps file to play (without the extension).
  • Loop: The number of times the effect should be played. Use an integer for a specific count or "infinity" for an endless loop. The default is 1.
  • Priority: Determines which effects are rendered when multiple events are active. Only the event with the highest priority will play. The levels are VeryHigh, High, Medium (default), Low, and VeryLow.
  • Mixing: Used when two events of the same priority are active. Override (default) stops all other effects on the target, while Merge allows both to play simultaneously.
  • Targeting: An array specifying which body parts should play the effect and with what modifications.

Targeting Properties

The Targeting object defines where and how a haptic effect is applied.

{
"Target": "Leg",
"Spatialization": "Global",
"Gain": 0.5
}
  • Target: The body part(s) to send the effect to. The available targets are extensive, including All, Arm, Hand, Leg, Foot, Chest, and more. Targeting a parent group (e.g., Arm) will also activate its subgroups (Upper_arm, Lower_arm, Hand).
  • Spatialization: Sets the position of the effect. Can be Left, Right, or Global (default).
  • Gain: A normalized multiplier for the effect's intensity, from 0 (0%) to 1 (100%). The default is 1.

Advanced Interruption Control

You can manage complex interactions between effects using InterruptCommands and Groups.

  • InterruptCommands: This property, placed within an ExternalCommand object, lists other External_Command_IDs that should be stopped immediately when this command is triggered.
  • Groups: The Groups feature allows you to bundle multiple External_Command_IDs under a single group ID. This group ID can then be used in an InterruptCommands list, making it easy to stop a whole category of effects at once.

Example of using Groups and InterruptCommands:

{
"Groups": [
{
"ID": "AllMotor",
"Members": [
"Engine_Start",
"MotorRPM_Heavy",
"MotorRPM_Light",
"MotorRPM_Medium"
]
}
],
"ExternalCommands": [
{
"External_Command_ID": "Engine_Stop",
"Interrupts_Commands": [
"AllMotor"
],
"Haptic_Events": [...]
}
]
}

Fallback Commands

The WYVRN configuration provides additional flexibility through fallbacks and aliases, which apply to both haptics and Chroma.

  • SetEventName Fallback: The API call itself can include a fallback. SetEventName("EVENT_A;fallback=EVENT_B") will first search for EVENT_A, and if no match is found, it will then search for EVENT_B.

Configuration File

###General Structure

{
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Synesthesia.GameConfiguration",
"description": “List links between external commands and haptic events",
"type": "object",
"properties": {
"Groups": {
"description": "Group of externalCommand you can re-use in interruptCommand",
"type": "array",
"items": {
"type": "object",
"$ref": "Synesthesia.Groups.schema.json"
}
},
"ExternalCommands": {
"description": “List of links between external commands and haptic events",
"type": "array",
"items": {
"type": "object",
"$ref": "Synesthesia.ExternalCommand.schema.json"
}
}
}
}

Configuration File - Group

{
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Synesthesia.Groups",
"description": "Group of externalCommand you can re-use in interruptCommands",
"type": "object",
"properties": {
"ID": {
"description": “ID of the group you can use in interruptCommands",
"type": “string"
},
"Members": {
"description": “List of the actual interruptCommands contained in the group",
"type": "array",
"items": {
"type": "string"
}
}
}
}

External Command - Substructure

{
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Synesthesia.ExternalCommand",
"description": "a link between an external command and haptic events",
"type": "object",
"properties": {
"External_Command_ID": {
"description": "External command ID that will trigger the following haptic events",
"type": "string"
},
"Haptic_events": {
"description": "List of haptic events to triggers",
"type": "array",
"items": {
"type": "object",
"$ref": "Synesthesia.HapticEvent.schema.json"
},
"InteruptCommands": {
"description": "List commands to trigger, must match existing External_Command_ID",
"OneOf": [
{
"type": "enum",
"enum": ["All"]
},
{
"type": "array",
"items": {"type": “string"}
}
]
}
}
}
}

Haptic Event - Substructure

{
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Synesthesia.HapticEvent",
"description": "a link between an external command and haptic events",
"type": "object",
"properties": {
"Haptic_Effect": {
"description": "Name of the haptic effect to play. Should be the same as the related .haps file",
"type": "string"
},
"Mixing": {
"description": "Used mixing strategy for this event. Override will stop all haptic events on the given targets before playing",
"type": "string",
"enum": ["Override", "Merge"],
"default" : "Override"
},
"Priority": {
"description": “Priority of this event. Only the event with the higher priority are rendered, even before looking at mixing strategy.",
"type": "string",
"enum": ["VeryLow", "Low", "Medium", "High", "VeryHigh"],
"default" : "Medium"
},
“Loop": {
"description": “Number of time the effect must be played. Use a negative value or “infinity” for a infinity loop.",
"type": “integer“ (or “infinity”)
"default" : 1
},

"Targeting": {
"description": "List of targets to deploy the effect",
"type": "array",
"items": {
"type": "object",
"$ref": "Synesthesia.Targeting.schema.json"
}
}
}
}

Targeting Data - Target Enum Complete

Targeting a group will play an effect on all devices labelled in the given groups. Some groups are a combination of multiple ones and will activate all subgoups (as ex. «Leg» will activate «Upper_leg» and «Lower_leg».

All, Top, Down, Arm, Head, Chest, Waist, Leg, Upper_arm, Lower_arm, Hand, Skull, Neck, Upper_leg, Lower_leg, Foot, Palm, Finger, Sole, Toe, Thumb, Index, Middle, Ring, Pinky, Hallux, Index_toe, Middle_toe, Ring_toe, Pinky_toe, First, Second, Third