A typescript sdk to create plugins for the elgato streamdeck.
The goal of this sdk is to make all the events (sent and received to / from the streamdeck) and their paylods typesafe.
Features:
If you want to start writing your plugin right away you might want to look at the streamdeck-ts-template package.
It will help you with:
See UPGRADE.md for details about the upgrade process for new major versions.
yarn add @rweich/streamdeck-ts
or
npm install @rweich/streamdeck-ts
import { Streamdeck } from '@rweich/streamdeck-ts';
// Create plugin instance
const plugin = new Streamdeck().plugin();
// Add event listeners
plugin.on('keyDown', ({ row, column }) => {
console.log(`key pressed on row ${row} and column ${column}`);
});
// Sending events:
// For some events you'll need to set a context (the "button-id").
// It's sent along most events received from the streamdeck.
plugin.on('willAppear', ({ context }) => {
plugin.setTitle('new Title', context);
});
let keypresses = 0;
plugin.on('keyDown', ({ context }) => {
plugin.setTitle(`key pressed ${++keypresses} times`, context);
});
// same for the property inspector
const pi = new Streamdeck().propertyinspector();
pi.on('didReceiveSettings', ({ settings }) => console.log('got settings', settings));
The Streamdeck needs a globally accessible connectElgatoStreamDeckSocket
method to register the plugin and propertyinspector.
Both, the plugin and pi instances can be exposed to the streamdeck by binding their createStreamdeckConnector
method to the connectElgatoStreamDeckSocket
. E.g.:
window.connectElgatoStreamDeckSocket = plugin.createStreamdeckConnector();
:information_source: See the streamdeck-ts-template for a real example how to do that.
The Plugin / Propertyinspector can listen to the following events sent by the streamdeck.
For detailled information see the official docs for events received from the streamdeck.
Triggered when an application - specified in the manifest.json
- was launched.
Event-Payload:
event: { application: string; }
Example:
plugin.on('applicationDidLaunch', ({ application }) => console.log(`${application} was launched!`));
Triggered when an application - specified in the manifest.json
- was terminated.
Event-Payload:
event: { application: string; }
Example:
plugin.on('applicationDidTerminate', ({ application }) => console.log(`${application} was terminated!`));
Triggered when a streamdeck device gets plugged to the computer.
Event-Payload:
event: {
device: string;
name: string;
type: DeviceType; // enum { StreamDeck, StreamDeckMini, StreamDeckXL, StreamDeckMobile, CorsairGKeys }
columns: number;
rows: number;
}
Example:
plugin.on('deviceDidConnect', ({ name }) => console.log(`device ${name} was plugged in`));
Triggered when a streamdeck device gets unplugged from the computer.
Event-Payload:
event: {
device: string;
}
Example:
plugin.on('deviceDidDisconnect', ({ device }) => console.log(`device with id ${device} was unplugged`));
[Stream Deck 6.1.0+ Required]
Triggered when a user presses a dial on a Stream Deck +.
Event-Payload:
event: {
row: number | undefined;
column: number | undefined;
action: string;
context: string;
device: string;
settings: unknown;
controller: ControllerType; // String enum, but guaranteed to be "Encoder".
}
Example:
plugin.on('dialDown', ({ column }) => console.log(`dial ${column} was pressed`));
[Stream Deck 6.0.0+ Required] [Deprecated in 6.1.0+]
Triggered when a user presses or releases the dial on a Stream Deck +.
This event was deprecated in Version 6.1 of the Stream Deck SDK and will eventually be removed.
Developers are encouraged to consume the dialUp
and dialDown
events instead. While the API
is in its transitional phase, both events will be sent to plugins.
Event-Payload:
event: {
row: number | undefined;
column: number | undefined;
action: string;
context: string;
device: string;
settings: unknown;
controller: ControllerType; // String enum, but guaranteed to be "Encoder".
pressed: boolean;
}
Example:
plugin.on('dialPress', ({ pressed }) => {
console.log(`a dial was ${pressed ? 'pressed' : 'released'}`);
});
[Stream Deck 6.0.0+ Required]
Triggered when a user rotates a dial on a Stream Deck +. Note that a dial may be pressed and rotated simultaneously.
Event-Payload:
event: {
row: number | undefined;
column: number | undefined;
action: string;
context: string;
device: string;
settings: unknown;
controller: ControllerType; // String enum, but guaranteed to be "Encoder".
pressed: boolean;
ticks: number;
}
Example:
plugin.on('dialRotate', ({ ticks, pressed }) => {
console.log(`a dial was rotated ${ticks} ticks. It ${pressed ? 'was' : 'was not'} pressed.`);
});
[Stream Deck 6.1.0+ Required]
Triggered when a user releases a dial on a Stream Deck +.
Event-Payload:
event: {
row: number | undefined;
column: number | undefined;
action: string;
context: string;
device: string;
settings: unknown;
controller: ControllerType; // String enum, but guaranteed to be "Encoder".
}
Example:
plugin.on('dialUp', ({ column }) => console.log(`dial ${column} was released`));
Triggered after a GetGlobalSettingsEvent was sent to the streamdeck.
Event-Payload:
event: { settings: unknown }
Example:
plugin.on('didReceiveGlobalSettings', ({ settings }) => console.log('got settings', settings));
Triggered after a GetSettingsEvent was sent to the streamdeck.
Event-Payload:
event: {
settings: unknown;
row: numbe | undefinedr;
column: number | undefined;
isInMultiAction: boolean;
state: number | undefined;
action: string;
context: string;
device: string;
}
Example:
plugin.on('didReceiveSettings', ({ row, column, settings }) =>
console.log(`got settings for button ${row} / ${column}`, settings),
);
Triggered when the button gets pressed.
Event-Payload:
event: {
row: number | undefined;
column: number | undefined;
isInMultiAction: boolean;
state: number | undefined;
userDesiredState: number | undefined;
action: string;
context: string;
device: string;
settings: unknown;
}
Example:
plugin.on('keyDown', ({ row, column }) => console.log(`key down on ${row} / ${column}`));
Triggered when the button gets released.
Event-Payload:
event: {
row: number | undefined;
column: number | undefined;
isInMultiAction: boolean;
state: number | undefined;
userDesiredState: number | undefined;
action: string;
context: string;
device: string;
settings: unknown;
}
Example:
plugin.on('keyUp', ({ row, column }) => console.log(`key up on ${row} / ${column}`));
Triggered when the property inspector appears.
Event-Payload:
event: {
action: string;
context: string;
device: string;
}
Example:
plugin.on('propertyInspectorDidAppear', () => console.log(`the propertyinspector appeared!`));
Triggered when the property inspector appears.
Event-Payload:
event: {
action: string;
context: string;
device: string;
}
Example:
plugin.on('propertyInspectorDidDisappear', () => console.log(`the propertyinspector disappeared!`));
Triggered when the propertyinspector sends a SendToPluginEvent.
Event-Payload:
event: {
action: string;
context: string;
payload: Record<string, unknown>;
}
Example:
plugin.on('sendToPlugin', ({ payload }) => console.log(`the pi sent some data:`, payload));
Triggered when the plugin sends a SendToPropertyInspectorEvent.
Event-Payload:
event: {
action: string;
context: string;
payload: Record<string, unknown>;
}
Example:
pi.on('sendToPropertyInspector', ({ payload }) => console.log(`the plugin sent some data:`, payload));
Triggered when the computer is wake up.
Event-Payload:
no payload
Example:
plugin.on('systemDidWakeUp', () => console.log(`system did wake up!`));
Triggered on an interval based on your manifest configuration.
⚠️ Beware: This event is undocumented and might be removed on newer Streamdeck software versions without prior notice!
Event-Payload:
no payload
Example:
Add the TimerInterval
configuration on the root level of your manifest.json
. The interval is in milliseconds.
{ "TimerInterval": 10000 }
plugin.on('timerUpdate', () => console.log(`got update!`));
Triggered when the user changes the title or title parameters.
Event-Payload:
event: {
action: string;
context: string;
device: string;
row: number;
column: number;
settings: unknown;
state: number;
title: string;
fontFamily: string
fontSize: number
fontStyle: string
fontUnderline: boolean
showTitle: boolean
titleAlignment: string
titleColor: string
}
Example:
plugin.on('titleParametersDidChange', ({ fontSize }) => console.log(`new title/params with size ${fontSize}!`));
Triggered when a user touches the touch screen on a Stream Deck +. A hold
happens when the user keeps their finger in place for approximately 500
milliseconds.
Event-Payload:
event: {
row: number | undefined;
column: number | undefined;
action: string;
context: string;
device: string;
settings: unknown;
controller: ControllerType; // String enum, but guaranteed to be "Encoder".
tapPos: [number, number]; // X, Y
hold: boolean;
}
Example:
plugin.on('touchTap', ({ hold, tapPos }) => {
console.log(`touch screen tapped at (${tapPos[0]}, ${tapPos[1]}), ${hold ? 'was' : 'was not'} held!`);
});
Triggered when the websocket to the streamdeck was successfully opened.
Event-Payload:
event: {
uuid: string;
info: string;
}
Example:
plugin.on('websocketOpen', ({ uuid }) => console.log(`websocket opened for uuid/context: ${uuid}`));
Triggered when the plugin / button gets displayed on the streamdeck.
Event-Payload:
event: {
settings: unknown;
row: number | undefined;
column: number | undefined;
isInMultiAction: boolean;
state: number | undefined;
action: string;
context: string;
device: string;
}
Example:
plugin.on('willAppear', ({ row, column }) => console.log(`the button appeared on ${row} / ${column}`));
Triggered when the plugin / button is no longer displayed on the streamdeck.
Event-Payload:
event: {
settings: unknown;
row: number | undefined;
column: number | undefined;
isInMultiAction: boolean;
state: number | undefined;
action: string;
context: string;
device: string;
}
Example:
plugin.on('willDisappear', ({ row, column }) => console.log(`the button disappeared from ${row} / ${column}`));
The plugin and propertyinspector can send the following events to the streamdeck:
For detailled information see the official docs for events sent to the streamdeck.
Requests the settings globally stored for all buttons using this plugin / pi.
Triggers the didReceiveGlobalSettings event.
getGlobalSettings(context: string): void
Example:
plugin.getGlobalSettings('context');
Requests the settings stored for the button instance.
Triggers the didReceiveSettings event.
getSettings(context: string): void
Example:
plugin.getSettings('context');
Makes the streamdeck write the log message to a debug log file.
logMessage(message: string): void
Example:
plugin.logMessage('the message');
Makes the streamdeck open the url in a browser.
openUrl(url: string): void
Example:
plugin.openUrl('the url');
Sends data to the plugin. Triggers the sendToPlugin event.
sendToPlugin(context: string, payload: Record<string, unknown>, action: string): void
Example:
pi.sendToPlugin('context', { some: 'data' }, 'action');
Sends data to the propertyinspector. Triggers the sendToPropertyInspector event.
sendToPropertyInspector(context: string, payload: Record<string, unknown>): void
Example:
plugin.sendToPropertyInspector('context', { some: 'data' });
[Stream Deck 6.0.0+ Required]
Sends a command to the Stream Deck to update the Feedback displayed for a
specific dial. Feedback payloads must conform to (at least) the
GenericLayoutFeedback
type for any updates, but stricter types are accepted so
long as they also satisfy the requirements of this type.
Consult the streamdeck-events
project for more information about feedback and
how it behaves, including valid values for particular keys.
setFeedback(payload: LayoutFeedback | GenericLayoutFeedback, context: string): void
Example:
plugin.setFeedback({ title: 'Hello, world!' }, 'context');
[Stream Deck 6.0.0+ Required]
Sends a command to the Stream Deck to update the Feedback Layout for a specific dial. Layouts may either be a hardcoded layout ID or a path (relative to plugin root) to a layout JSON. This library will perform no validation whether a specific layout is valid or not.
Consult the streamdeck-events
project for more information about feedback and
how it behaves, including built-in layouts.
setFeedbackLayout(layout: LayoutFeedbackKey | string, context: string): void
Example:
plugin.setFeedbackLayout("layouts/layoutv2.json", 'context');
Changes the image of the button.
setImage(image: string, context: string, options: { target?: 'hardware' | 'software' | 'both'; state?: number }): void
Example:
plugin.setImage('imagedataAsBase64', 'context');
Persists the data globally (not just for the current button).
Triggers the didReceiveGlobalSettings event for the plugin (if sent by pi) and for the pi (if sent by plugin).
setGlobalSettings(context: string, settings: unknown): void
Example:
plugin.setGlobalSettings('context', { your: 'new-global-settings' });
Persists the settings for the current button.
Triggers the didReceiveSettings event for the plugin (if sent by pi) and for the pi (if sent by plugin).
setSettings(context: string, eventPayload: unknown): void
Example:
plugin.setSettings('context', { your: 'new-settings' });
Changes the state of the button if it supports multiple states.
setState(state: number, context: string): void
Example:
plugin.setState(1, 'context');
Changes the title of the button.
setTitle(title: string, context: string, options: { target?: 'hardware' | 'software' | 'both'; state?: number }): void
Example:
plugin.setTitle('the new title', 'context');
Will show an alert icon on the button.
showAlert(context: string): void
Example:
plugin.showAlert('context');
Will show an ok checkmark on the button.
showOk(context: string): void
Example:
plugin.showOk('context');
Makes the streamdeck switch to the preconfigured readonly profile.
switchToProfile(profilename: string, context: string, device: string): void
Example:
plugin.switchToProfile('profilename', 'context', 'device');