@pixl-app/sdk 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +18 -3
- package/dist/api-types/device-apps.d.ts +1 -1
- package/dist/api-types/index.d.ts +3 -0
- package/dist/api-types/modules.d.ts +1 -1
- package/dist/api-types/payloads.d.ts +389 -0
- package/dist/api-types/templates.d.ts +6 -0
- package/dist/api-types/widgets.d.ts +555 -0
- package/dist/bindings.d.ts +22 -0
- package/dist/chat.d.ts +1 -1
- package/dist/client.d.ts +127 -164
- package/dist/errors.d.ts +17 -0
- package/dist/events.d.ts +41 -0
- package/dist/feed.d.ts +21 -29
- package/dist/fonts.d.ts +19 -0
- package/dist/frame.d.ts +2 -0
- package/dist/index-nb1y5rx1.js +1932 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.js +38 -873
- package/dist/live-value.d.ts +18 -0
- package/dist/pixl-ui.js +278 -0
- package/dist/pixl.js +4 -4
- package/dist/spotify.d.ts +22 -0
- package/dist/stream.d.ts +30 -0
- package/dist/streamelements.d.ts +14 -0
- package/dist/tts.d.ts +18 -9
- package/dist/twitch.d.ts +68 -0
- package/dist/ui/checkbox.d.ts +27 -0
- package/dist/ui/define.d.ts +2 -0
- package/dist/ui/dialog.d.ts +15 -0
- package/dist/ui/dropdown-helpers.d.ts +48 -0
- package/dist/ui/dropdown.d.ts +65 -0
- package/dist/ui/field.d.ts +48 -0
- package/dist/ui/index.d.ts +14 -0
- package/dist/ui/index.js +1919 -0
- package/dist/ui/inputs.d.ts +29 -0
- package/dist/ui/list.d.ts +31 -0
- package/dist/ui/runtime.d.ts +18 -0
- package/dist/ui/section.d.ts +13 -0
- package/dist/ui/styles.d.ts +6 -0
- package/dist/widget.d.ts +141 -0
- package/package.json +13 -5
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eine Aktion für den gewählten Eintrag einer Liste am Stream Deck. Dieselben Operationen wie
|
|
3
|
+
* bei `widget.batch` für ein Feld eines Eintrags, ohne `name` und `update`: `toggle` (boolean),
|
|
4
|
+
* `add` (number), `next` (enum), jeweils mit `field`, oder `patch` (feste Werte für Felder)
|
|
5
|
+
*/
|
|
6
|
+
export type StreamDeckItemAction = {
|
|
7
|
+
label: string;
|
|
8
|
+
field: string;
|
|
9
|
+
toggle: true;
|
|
10
|
+
} | {
|
|
11
|
+
label: string;
|
|
12
|
+
field: string;
|
|
13
|
+
add: number;
|
|
14
|
+
} | {
|
|
15
|
+
label: string;
|
|
16
|
+
field: string;
|
|
17
|
+
next: true;
|
|
18
|
+
} | {
|
|
19
|
+
label: string;
|
|
20
|
+
patch: Record<string, unknown>;
|
|
21
|
+
};
|
|
22
|
+
/** Grenzen für `streamdeck.actions` an Listen */
|
|
23
|
+
export declare const STREAMDECK_ACTION_LIMITS: {
|
|
24
|
+
readonly actions: 10;
|
|
25
|
+
readonly labelLength: 30;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Stream Deck an einem Feld: nur bei Listen die Aktionen. Wie Tasten und Regler aussehen,
|
|
29
|
+
* bestimmt immer pixl (einheitliche Symbole), eigene Bilder für Felder gibt es nicht. Nur die
|
|
30
|
+
* Einträge einer Liste dürfen eigene Bilder haben (`itemImage`, `item(ctx)` in streamdeck.js)
|
|
31
|
+
*/
|
|
32
|
+
export type StreamDeckDisplay = {
|
|
33
|
+
/**
|
|
34
|
+
* Nur `list`: was Taste und Regler mit dem gewählten Eintrag tun können, die erste ist der
|
|
35
|
+
* Standard. Ohne `actions` erscheint die Liste nicht am Stream Deck
|
|
36
|
+
*/
|
|
37
|
+
actions?: StreamDeckItemAction[];
|
|
38
|
+
};
|
|
39
|
+
type FieldBase = {
|
|
40
|
+
label: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
/** Abschnitt auf der Steuer-Seite bzw. im Formular */
|
|
43
|
+
group?: string;
|
|
44
|
+
/** Nur per SDK setzbar, nicht im Dashboard und nicht am Stream Deck */
|
|
45
|
+
hidden?: boolean;
|
|
46
|
+
/** Stream Deck: bei Listen die Aktionen für einen Eintrag */
|
|
47
|
+
streamdeck?: StreamDeckDisplay;
|
|
48
|
+
};
|
|
49
|
+
/** Ja oder nein (Schalter) */
|
|
50
|
+
export type BooleanField = FieldBase & {
|
|
51
|
+
type: "boolean";
|
|
52
|
+
default?: boolean;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Zahl. `step` wie bei HTML: Standard 1, also ganze Zahlen, für Kommazahlen z.B. `0.1`. Im Dashboard
|
|
56
|
+
* Plus und Minus, mit `slider` ein Schieberegler (dann sind `min` und `max` Pflicht)
|
|
57
|
+
*/
|
|
58
|
+
export type NumberField = FieldBase & {
|
|
59
|
+
type: "number";
|
|
60
|
+
min?: number;
|
|
61
|
+
max?: number;
|
|
62
|
+
step?: number;
|
|
63
|
+
default?: number;
|
|
64
|
+
slider?: boolean;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Text, mit `multiline` mehrzeilig. Mit `sensitive` ein Geheimnis wie ein API-Schlüssel: im Dashboard
|
|
68
|
+
* verdeckt, den Wert bekommen nur das Widget selbst und wer Widgets verwaltet. Nur direkt unter
|
|
69
|
+
* `settings`, immer einzeilig, ohne `default` (pixl.json liegt offen im Bundle)
|
|
70
|
+
*/
|
|
71
|
+
export type StringField = FieldBase & {
|
|
72
|
+
type: "string";
|
|
73
|
+
maxLength?: number;
|
|
74
|
+
multiline?: boolean;
|
|
75
|
+
sensitive?: boolean;
|
|
76
|
+
default?: string;
|
|
77
|
+
};
|
|
78
|
+
/** Farbe als `#RRGGBB` oder `#RRGGBBAA` */
|
|
79
|
+
export type ColorField = FieldBase & {
|
|
80
|
+
type: "color";
|
|
81
|
+
default?: string;
|
|
82
|
+
};
|
|
83
|
+
/** Eine von festen Optionen */
|
|
84
|
+
export type EnumField = FieldBase & {
|
|
85
|
+
type: "enum";
|
|
86
|
+
options: string[];
|
|
87
|
+
default?: string;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Datei aus den Uploads des Kanals (`/files/…`) oder eine https-URL. `accept` wie beim HTML-Attribut:
|
|
91
|
+
* MIME-Typen (`image/png`), Gruppen (`image/*`) und Endungen (`.mp3`), mit Komma getrennt
|
|
92
|
+
*/
|
|
93
|
+
export type FileField = FieldBase & {
|
|
94
|
+
type: "file";
|
|
95
|
+
accept: string;
|
|
96
|
+
default?: string;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Schriftart als Name der Familie (`"Open Sans"`). Das Dashboard schlägt Google Fonts vor, eigene
|
|
100
|
+
* Namen gehen auch (z.B. eine in OBS installierte Schrift). Leer = Schrift des Widgets.
|
|
101
|
+
* Gehostete Widgets laden den Wert über das SDK von selbst (Bunny Fonts, gleiche Schriften wie Google Fonts)
|
|
102
|
+
*/
|
|
103
|
+
export type FontField = FieldBase & {
|
|
104
|
+
type: "font";
|
|
105
|
+
default?: string;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* TTS-Stimme als ID wie bei `POST /api/v1/tts` (`"polly:hans"`, `"fish:<uuid>"`). Das Dashboard
|
|
109
|
+
* zeigt die Stimmen des Kanals mit Namen zur Auswahl. Leer = die Stimme aus den TTS-Einstellungen
|
|
110
|
+
* des Kanals, der Wert lässt sich also immer direkt als `voice` übergeben. `default` nur mit einer
|
|
111
|
+
* festen Standardstimme (`polly:…`), Katalog- und eigene Stimmen haben in jedem Kanal andere IDs
|
|
112
|
+
*/
|
|
113
|
+
export type VoiceField = FieldBase & {
|
|
114
|
+
type: "voice";
|
|
115
|
+
default?: string;
|
|
116
|
+
};
|
|
117
|
+
/** Kein Wert, sondern ein Ereignis: das Widget bekommt `widget.action`. Nur unter `controls` */
|
|
118
|
+
export type TriggerField = FieldBase & {
|
|
119
|
+
type: "trigger";
|
|
120
|
+
};
|
|
121
|
+
/** Felder, die ein Eintrag einer Liste haben kann */
|
|
122
|
+
export type ListItemField = BooleanField | NumberField | StringField | ColorField | EnumField | FileField | FontField | VoiceField;
|
|
123
|
+
export type ListItemFieldType = ListItemField["type"];
|
|
124
|
+
/** Liste von Einträgen mit den Feldern aus `item`, jeder Eintrag bekommt vom Server eine feste `id` */
|
|
125
|
+
export type ListField = FieldBase & {
|
|
126
|
+
type: "list";
|
|
127
|
+
item: Record<string, ListItemField>;
|
|
128
|
+
/** Höchstens so viele Einträge */
|
|
129
|
+
max?: number;
|
|
130
|
+
/** Feld, das Dashboard und Stream Deck als Namen eines Eintrags zeigen */
|
|
131
|
+
itemLabel?: string;
|
|
132
|
+
/** `file`-Feld mit dem Bild eines Eintrags */
|
|
133
|
+
itemImage?: string;
|
|
134
|
+
};
|
|
135
|
+
export type WidgetField = ListItemField | TriggerField | ListField;
|
|
136
|
+
export type WidgetFieldType = WidgetField["type"];
|
|
137
|
+
/** Einstellungen: alles außer `trigger` */
|
|
138
|
+
export type SettingField = Exclude<WidgetField, TriggerField>;
|
|
139
|
+
/** Inhalt von pixl.json */
|
|
140
|
+
export type WidgetManifest = {
|
|
141
|
+
name?: string;
|
|
142
|
+
/** Größe in Pixeln, so groß legt man die Browserquelle in OBS an (Vorschau im Dashboard ebenso) */
|
|
143
|
+
width?: number;
|
|
144
|
+
height?: number;
|
|
145
|
+
/** Aussehen und Verhalten, selten geändert, nur im Dashboard */
|
|
146
|
+
settings?: Record<string, SettingField>;
|
|
147
|
+
/** Für den laufenden Stream, im Dashboard und am Stream Deck */
|
|
148
|
+
controls?: Record<string, WidgetField>;
|
|
149
|
+
/**
|
|
150
|
+
* Eigene Steuer-Seiten im Bundle. Eine als Pfad (`"control.html"`) oder mehrere als Reiter
|
|
151
|
+
* im Dashboard (`[{ "label": "Aufgaben", "page": "control.html" }, …]`)
|
|
152
|
+
*/
|
|
153
|
+
control?: string | WidgetControlPage[];
|
|
154
|
+
/** Eigene Bilder für Einträge von Listen am Stream Deck (Skript im Bundle) */
|
|
155
|
+
streamdeck?: StreamDeckWidget;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Stream Deck auf oberster Ebene der pixl.json. `script`: Pfad im Bundle (z.B. `"streamdeck.js"`),
|
|
159
|
+
* ein ES-Modul mit `item(ctx)`, das das Bild eines Listeneintrags zeichnet (Kachel im Karussell
|
|
160
|
+
* am Regler). Alles andere zeichnet immer pixl, ohne Skript auch die Einträge (`itemImage`).
|
|
161
|
+
*/
|
|
162
|
+
export type StreamDeckWidget = {
|
|
163
|
+
script?: string;
|
|
164
|
+
};
|
|
165
|
+
/** Eine eigene Steuer-Seite, im Dashboard ein Reiter */
|
|
166
|
+
export type WidgetControlPage = {
|
|
167
|
+
label: string;
|
|
168
|
+
page: string;
|
|
169
|
+
};
|
|
170
|
+
/** Ein Eintrag einer Liste, `id` vergibt der Server */
|
|
171
|
+
export type ListItem = {
|
|
172
|
+
id: string;
|
|
173
|
+
[field: string]: unknown;
|
|
174
|
+
};
|
|
175
|
+
/** Werte, Name des Felds → Wert */
|
|
176
|
+
export type WidgetValues = Record<string, unknown>;
|
|
177
|
+
/**
|
|
178
|
+
* Änderung an einem Feld. Listen immer über die `id` des Eintrags. Auf ein Feld eines Eintrags
|
|
179
|
+
* wirken dieselben Operationen wie auf ein Feld oben, dazu `update` (id) und `field` (Name)
|
|
180
|
+
*/
|
|
181
|
+
export type WidgetOperation =
|
|
182
|
+
/** Wert setzen (alle Typen außer `trigger`, bei `list` die ganze Liste) */
|
|
183
|
+
{
|
|
184
|
+
name: string;
|
|
185
|
+
set: unknown;
|
|
186
|
+
}
|
|
187
|
+
/** `number`: um `add` ändern, bleibt in `min`/`max` */
|
|
188
|
+
| {
|
|
189
|
+
name: string;
|
|
190
|
+
add: number;
|
|
191
|
+
}
|
|
192
|
+
/** `boolean`: umschalten */
|
|
193
|
+
| {
|
|
194
|
+
name: string;
|
|
195
|
+
toggle: true;
|
|
196
|
+
}
|
|
197
|
+
/** `enum`: nächste Option, nach der letzten wieder die erste */
|
|
198
|
+
| {
|
|
199
|
+
name: string;
|
|
200
|
+
next: true;
|
|
201
|
+
}
|
|
202
|
+
/** `trigger`: auslösen */
|
|
203
|
+
| {
|
|
204
|
+
name: string;
|
|
205
|
+
press: true;
|
|
206
|
+
} | {
|
|
207
|
+
name: string;
|
|
208
|
+
insert: Record<string, unknown>;
|
|
209
|
+
at?: number;
|
|
210
|
+
} | {
|
|
211
|
+
name: string;
|
|
212
|
+
update: string;
|
|
213
|
+
patch: Record<string, unknown>;
|
|
214
|
+
} | {
|
|
215
|
+
name: string;
|
|
216
|
+
update: string;
|
|
217
|
+
field: string;
|
|
218
|
+
add: number;
|
|
219
|
+
} | {
|
|
220
|
+
name: string;
|
|
221
|
+
update: string;
|
|
222
|
+
field: string;
|
|
223
|
+
toggle: true;
|
|
224
|
+
} | {
|
|
225
|
+
name: string;
|
|
226
|
+
update: string;
|
|
227
|
+
field: string;
|
|
228
|
+
next: true;
|
|
229
|
+
} | {
|
|
230
|
+
name: string;
|
|
231
|
+
remove: string;
|
|
232
|
+
} | {
|
|
233
|
+
name: string;
|
|
234
|
+
move: string;
|
|
235
|
+
to: number;
|
|
236
|
+
};
|
|
237
|
+
/** Wo ein Feld liegt */
|
|
238
|
+
export type WidgetFieldScope = "settings" | "controls";
|
|
239
|
+
/** Was sich durch eine Operation geändert hat, so kommt es live an */
|
|
240
|
+
export type WidgetChange = {
|
|
241
|
+
scope: WidgetFieldScope;
|
|
242
|
+
name: string;
|
|
243
|
+
value: unknown;
|
|
244
|
+
} | {
|
|
245
|
+
scope: WidgetFieldScope;
|
|
246
|
+
name: string;
|
|
247
|
+
inserted: ListItem;
|
|
248
|
+
at: number;
|
|
249
|
+
} | {
|
|
250
|
+
scope: WidgetFieldScope;
|
|
251
|
+
name: string;
|
|
252
|
+
updated: ListItem;
|
|
253
|
+
} | {
|
|
254
|
+
scope: WidgetFieldScope;
|
|
255
|
+
name: string;
|
|
256
|
+
removed: string;
|
|
257
|
+
} | {
|
|
258
|
+
scope: WidgetFieldScope;
|
|
259
|
+
name: string;
|
|
260
|
+
moved: string;
|
|
261
|
+
to: number;
|
|
262
|
+
};
|
|
263
|
+
/** Stand eines Widgets beim Verbinden */
|
|
264
|
+
export type WidgetState = {
|
|
265
|
+
id: string;
|
|
266
|
+
name: string;
|
|
267
|
+
version: string | null;
|
|
268
|
+
manifest: WidgetManifest | null;
|
|
269
|
+
settings: WidgetValues;
|
|
270
|
+
values: WidgetValues;
|
|
271
|
+
};
|
|
272
|
+
/** Werte oder Einstellungen haben sich geändert */
|
|
273
|
+
export type StreamWidgetChanged = {
|
|
274
|
+
type: "widget.changed";
|
|
275
|
+
changes: WidgetChange[];
|
|
276
|
+
};
|
|
277
|
+
/** Ein `trigger` wurde ausgelöst */
|
|
278
|
+
export type StreamWidgetAction = {
|
|
279
|
+
type: "widget.action";
|
|
280
|
+
name: string;
|
|
281
|
+
};
|
|
282
|
+
/** Eine andere Code-Version ist aktiv, gehostete Widgets laden neu */
|
|
283
|
+
export type StreamWidgetVersion = {
|
|
284
|
+
type: "widget.version";
|
|
285
|
+
version: string | null;
|
|
286
|
+
};
|
|
287
|
+
export type StreamWidgetMessage = StreamWidgetChanged | StreamWidgetAction | StreamWidgetVersion;
|
|
288
|
+
/**
|
|
289
|
+
* Ein Widget, wie es eine verbundene App (Stream Deck) bekommt:
|
|
290
|
+
* GET /api/v1/channels/<kanal>/widgets. Nie mit Schlüssel, OBS-Adresse oder Einstellungen.
|
|
291
|
+
* Bildverweise auflösen: beginnt mit `https://` oder `http://` → so nehmen, beginnt mit
|
|
292
|
+
* `/files/` → `files` davor, sonst → `assets` davor (fehlt die Basis, gibt es kein Bild).
|
|
293
|
+
*/
|
|
294
|
+
export type DeviceWidget = {
|
|
295
|
+
id: string;
|
|
296
|
+
name: string;
|
|
297
|
+
version: string | null;
|
|
298
|
+
/** `controls` aus pixl.json ohne `hidden`-Felder, `{}` ohne Manifest */
|
|
299
|
+
controls: Record<string, WidgetField>;
|
|
300
|
+
/** Aktuelle Werte genau dieser Steuerelemente */
|
|
301
|
+
values: WidgetValues;
|
|
302
|
+
/** Absolute Basis-URL der aktiven Version mit `/` am Ende, null ohne Version oder Widget-Adresse */
|
|
303
|
+
assets: string | null;
|
|
304
|
+
/** Widget-Adresse ohne `/` am Ende, für Werte wie `/files/…`, null ohne Widget-Adresse */
|
|
305
|
+
files: string | null;
|
|
306
|
+
/**
|
|
307
|
+
* Absolute URL von `streamdeck.script` in der aktiven Version (`assets` + Pfad), null ohne
|
|
308
|
+
* Skript, Version oder Widget-Adresse. Bei `widget.version` neu laden.
|
|
309
|
+
*/
|
|
310
|
+
script: string | null;
|
|
311
|
+
};
|
|
312
|
+
/** Erste Nachricht auf GET /api/v1/channels/<kanal>/stream?topics=widgets */
|
|
313
|
+
export type DeviceStreamConnected = {
|
|
314
|
+
type: "connected";
|
|
315
|
+
channel: string;
|
|
316
|
+
};
|
|
317
|
+
/** Steuerelemente eines Widgets haben sich geändert. Mit `refetch` den Stand neu laden */
|
|
318
|
+
export type DeviceWidgetChanged = {
|
|
319
|
+
type: "widget.changed";
|
|
320
|
+
widgetId: string;
|
|
321
|
+
changes: WidgetChange[];
|
|
322
|
+
refetch?: true;
|
|
323
|
+
};
|
|
324
|
+
/** Andere Code-Version aktiv: Widgets neu laden (Felder und Bilder können anders sein) */
|
|
325
|
+
export type DeviceWidgetVersion = {
|
|
326
|
+
type: "widget.version";
|
|
327
|
+
widgetId: string;
|
|
328
|
+
version: string | null;
|
|
329
|
+
};
|
|
330
|
+
/** Widget angelegt, umbenannt oder gelöscht: Widgets neu laden */
|
|
331
|
+
export type DeviceWidgetsUpdated = {
|
|
332
|
+
type: "widgets.updated";
|
|
333
|
+
widgetId: string;
|
|
334
|
+
};
|
|
335
|
+
export type DeviceStreamMessage = DeviceStreamConnected | DeviceWidgetChanged | DeviceWidgetVersion | DeviceWidgetsUpdated;
|
|
336
|
+
/** Grenzen für pixl.json */
|
|
337
|
+
export declare const WIDGET_LIMITS: {
|
|
338
|
+
readonly fields: 50;
|
|
339
|
+
readonly listItems: 200;
|
|
340
|
+
readonly nameLength: 64;
|
|
341
|
+
readonly labelLength: 80;
|
|
342
|
+
readonly textLength: 2000;
|
|
343
|
+
readonly controlPages: 5;
|
|
344
|
+
/** Länge des Namens einer Schriftart (`font`) */
|
|
345
|
+
readonly fontLength: 100;
|
|
346
|
+
};
|
|
347
|
+
/**
|
|
348
|
+
* Was `item(ctx)` in streamdeck.js bekommt: ein Eintrag einer Liste, gezeichnet als Kachel im
|
|
349
|
+
* Karussell am Regler. Nur Daten, alles JSON. Das Plugin ruft die Funktion neu auf, wenn sich der
|
|
350
|
+
* Eintrag ändert oder er gewählt bzw. nicht mehr gewählt ist, und merkt sich das Ergebnis sonst.
|
|
351
|
+
*/
|
|
352
|
+
export type StreamDeckItemContext = {
|
|
353
|
+
/** Immer `"item"` */
|
|
354
|
+
kind: "item";
|
|
355
|
+
/** Größe der Kachel in Pixeln (quadratisch). Nachbarn verkleinert und abgedunkelt pixl selbst */
|
|
356
|
+
size: number;
|
|
357
|
+
widget: {
|
|
358
|
+
id: string;
|
|
359
|
+
name: string;
|
|
360
|
+
};
|
|
361
|
+
/** Name der Liste in `controls` */
|
|
362
|
+
name: string;
|
|
363
|
+
/** Die Liste aus pixl.json */
|
|
364
|
+
field: ListField;
|
|
365
|
+
/** Der Eintrag mit seiner `id` */
|
|
366
|
+
item: ListItem;
|
|
367
|
+
/** Stelle in der Liste (ab 0) und Anzahl der Einträge */
|
|
368
|
+
index: number;
|
|
369
|
+
count: number;
|
|
370
|
+
/** Gerade gewählt (die Kachel in der Mitte) */
|
|
371
|
+
selected: boolean;
|
|
372
|
+
/** Feld der Einträge, das die eingestellte Aktion aus `streamdeck.actions` ändert (z.B. `"done"`). Fehlt bei `patch` */
|
|
373
|
+
itemField?: string;
|
|
374
|
+
/** Ob dieses Feld an ist (z.B. erledigt). Nur, wenn es ein `boolean` ist */
|
|
375
|
+
done?: boolean;
|
|
376
|
+
};
|
|
377
|
+
/**
|
|
378
|
+
* Das Modul streamdeck.js mit `item(ctx)`. Ein String ist ein vollständiges SVG-Dokument für die
|
|
379
|
+
* Kachel (`ctx.size` × `ctx.size`, z.B. mit `pixl.svg`), `null`/`undefined` (oder ein Fehler)
|
|
380
|
+
* heißt: pixl zeichnet die Kachel selbst (Bild aus `itemImage`, Name, Haken)
|
|
381
|
+
*/
|
|
382
|
+
export type StreamDeckScript = {
|
|
383
|
+
item?: (ctx: StreamDeckItemContext) => string | null | undefined;
|
|
384
|
+
};
|
|
385
|
+
/** Eine Kachel in `pixl.carousel` */
|
|
386
|
+
export type StreamDeckSlot = {
|
|
387
|
+
/** Index des Eintrags */
|
|
388
|
+
index: number;
|
|
389
|
+
/**
|
|
390
|
+
* Abstand zur angezeigten Stelle, 0 = Mitte, negativ = links. Beim Blättern mit
|
|
391
|
+
* Nachkommastellen (z.B. `-0.4`)
|
|
392
|
+
*/
|
|
393
|
+
offset: number;
|
|
394
|
+
/** Linke obere Ecke der Kachel */
|
|
395
|
+
x: number;
|
|
396
|
+
y: number;
|
|
397
|
+
/** Kantenlänge der Kachel */
|
|
398
|
+
size: number;
|
|
399
|
+
/** Helligkeit wie früher als Deckkraft (1 = Mitte), nur noch zur Info */
|
|
400
|
+
opacity: number;
|
|
401
|
+
/**
|
|
402
|
+
* Abdunkelung der Kachel, 0 = hell (Mitte) bis 1 = schwarz. Innerhalb von `render` dunkeln
|
|
403
|
+
* pixl.img, pixl.image, pixl.rect und pixl.text von selbst um diesen Wert ab
|
|
404
|
+
*/
|
|
405
|
+
shade: number;
|
|
406
|
+
/** Ist das die Kachel, die der Mitte am nächsten ist? */
|
|
407
|
+
center: boolean;
|
|
408
|
+
};
|
|
409
|
+
export type StreamDeckTextOptions = {
|
|
410
|
+
x: number;
|
|
411
|
+
y: number;
|
|
412
|
+
/** Schriftgröße, Standard 14 */
|
|
413
|
+
size?: number;
|
|
414
|
+
/** Standard `"#fff"` */
|
|
415
|
+
color?: string;
|
|
416
|
+
/** Standard `"middle"` */
|
|
417
|
+
anchor?: "start" | "middle" | "end";
|
|
418
|
+
/** Standard `"normal"` */
|
|
419
|
+
weight?: "normal" | "bold" | number;
|
|
420
|
+
/** Standard 1 */
|
|
421
|
+
opacity?: number;
|
|
422
|
+
};
|
|
423
|
+
export type StreamDeckImageOptions = {
|
|
424
|
+
x: number;
|
|
425
|
+
y: number;
|
|
426
|
+
width: number;
|
|
427
|
+
height: number;
|
|
428
|
+
opacity?: number;
|
|
429
|
+
};
|
|
430
|
+
export type StreamDeckRectOptions = {
|
|
431
|
+
x: number;
|
|
432
|
+
y: number;
|
|
433
|
+
width: number;
|
|
434
|
+
height: number;
|
|
435
|
+
/** Eckenradius, Standard 0 */
|
|
436
|
+
rx?: number;
|
|
437
|
+
fill?: string;
|
|
438
|
+
opacity?: number;
|
|
439
|
+
stroke?: string;
|
|
440
|
+
strokeWidth?: number;
|
|
441
|
+
};
|
|
442
|
+
export type StreamDeckBarOptions = {
|
|
443
|
+
x: number;
|
|
444
|
+
y: number;
|
|
445
|
+
width: number;
|
|
446
|
+
height: number;
|
|
447
|
+
color?: string;
|
|
448
|
+
background?: string;
|
|
449
|
+
};
|
|
450
|
+
export type StreamDeckDotsOptions = {
|
|
451
|
+
/** Mitte der Punkte, Standard 100 (Mitte am Regler). Auf Tasten `ctx.width / 2` */
|
|
452
|
+
x?: number;
|
|
453
|
+
y: number;
|
|
454
|
+
/** Abstand der Punkte, Standard 9 */
|
|
455
|
+
gap?: number;
|
|
456
|
+
/** Höchstens so viele Punkte, bei mehr Einträgen wandert das Fenster mit. Standard 9 */
|
|
457
|
+
max?: number;
|
|
458
|
+
color?: string;
|
|
459
|
+
activeColor?: string;
|
|
460
|
+
};
|
|
461
|
+
export type StreamDeckCarouselOptions = {
|
|
462
|
+
/** Anzahl Einträge */
|
|
463
|
+
count: number;
|
|
464
|
+
/**
|
|
465
|
+
* Stelle in der Mitte. Darf Nachkommastellen haben, dann liegen die Kacheln dazwischen und
|
|
466
|
+
* Größe und Deckkraft gehen fließend über. Am Regler `ctx.position ?? ctx.selected` übergeben,
|
|
467
|
+
* dann gleitet das Karussell beim Drehen
|
|
468
|
+
*/
|
|
469
|
+
selected: number;
|
|
470
|
+
/** Fläche, Standard 200 × 100 */
|
|
471
|
+
width?: number;
|
|
472
|
+
height?: number;
|
|
473
|
+
/** Senkrechte Mitte der Kacheln, Standard height / 2 */
|
|
474
|
+
y?: number;
|
|
475
|
+
/** Kantenlänge der mittleren Kachel, Standard 70 */
|
|
476
|
+
size?: number;
|
|
477
|
+
/** Abstand zwischen den Kacheln, negativ = überlappend wie in Elgatos Aktionsrad, Standard -12 */
|
|
478
|
+
gap?: number;
|
|
479
|
+
/** Größe der Nachbarn im Verhältnis zur Mitte, Standard 0.8 */
|
|
480
|
+
sideScale?: number;
|
|
481
|
+
/** Helligkeit der Nachbarn (gleich für alle, nicht durchsichtig), Standard 0.75. img, rect und text in `render` dunkeln von selbst ab (PNG und JPEG Pixel für Pixel, SVG nicht) */
|
|
482
|
+
fade?: number;
|
|
483
|
+
/** Im Kreis: nach dem letzten Eintrag kommt der erste, Standard true */
|
|
484
|
+
wrap?: boolean;
|
|
485
|
+
/** So viele Nachbarn je Seite, Standard 1 wie bei Elgato. Beim Gleiten kommt außen der nächste herein */
|
|
486
|
+
radius?: number;
|
|
487
|
+
/** Inhalt einer Kachel als SVG-Fragment */
|
|
488
|
+
render: (index: number, slot: StreamDeckSlot) => string;
|
|
489
|
+
};
|
|
490
|
+
/** Farben von pixl, `pixl.colors` */
|
|
491
|
+
export type StreamDeckColors = {
|
|
492
|
+
bg: string;
|
|
493
|
+
fg: string;
|
|
494
|
+
text: string;
|
|
495
|
+
muted: string;
|
|
496
|
+
ok: string;
|
|
497
|
+
warn: string;
|
|
498
|
+
};
|
|
499
|
+
/**
|
|
500
|
+
* Das globale Objekt `pixl` in streamdeck.js. Alle Funktionen liefern SVG als Text,
|
|
501
|
+
* Texte werden darin schon maskiert.
|
|
502
|
+
*/
|
|
503
|
+
export type StreamDeckPresets = {
|
|
504
|
+
/**
|
|
505
|
+
* Adresse für ein Bild: Pfad im Bundle (relativ zur Version), `/files/…` aus den Uploads oder
|
|
506
|
+
* https-URL. Liefert einen Platzhalter, den das Plugin nach dem Zeichnen durch das Bild ersetzt.
|
|
507
|
+
* Ist das Bild noch nicht geladen, kommt `""` und das Plugin zeichnet neu, sobald es da ist.
|
|
508
|
+
* Höchstens 64 verschiedene Bilder pro Aufruf.
|
|
509
|
+
*/
|
|
510
|
+
image(ref: string): string;
|
|
511
|
+
/** Text für SVG maskieren (`&`, `<`, `>`, `"`, `'`) */
|
|
512
|
+
esc(text: unknown): string;
|
|
513
|
+
/** Kürzen mit `…` am Ende, höchstens `max` Zeichen */
|
|
514
|
+
truncate(text: unknown, max: number): string;
|
|
515
|
+
/** Vollständiges `<svg>` mit `xmlns` und `xmlns:xlink` */
|
|
516
|
+
svg(width: number, height: number, body: string): string;
|
|
517
|
+
/** `<text>`, der Text wird maskiert */
|
|
518
|
+
text(str: unknown, options: StreamDeckTextOptions): string;
|
|
519
|
+
/**
|
|
520
|
+
* `<image>` mit `href` und `xlink:href`, `""` solange das Bild nicht geladen ist. Das Stream Deck
|
|
521
|
+
* kennt kein `preserveAspectRatio`, Bilder werden auf Breite und Höhe gestreckt.
|
|
522
|
+
*/
|
|
523
|
+
img(ref: string, options: StreamDeckImageOptions): string;
|
|
524
|
+
rect(options: StreamDeckRectOptions): string;
|
|
525
|
+
/** Fortschrittsbalken, `fraction` von 0 bis 1 */
|
|
526
|
+
bar(fraction: number, options: StreamDeckBarOptions): string;
|
|
527
|
+
/** Punkte für die Position in einer Liste, `selected` darf Nachkommastellen haben (hervorgehoben wird der nächste) */
|
|
528
|
+
dots(count: number, selected: number, options: StreamDeckDotsOptions): string;
|
|
529
|
+
/** Karussell: ruft `render` für die sichtbaren Einträge um `selected` auf (auch zwischen zwei Einträgen) */
|
|
530
|
+
carousel(options: StreamDeckCarouselOptions): string;
|
|
531
|
+
colors: StreamDeckColors;
|
|
532
|
+
/** Hex-Farbe um `amount` (0 bis 1) Richtung Schwarz, für eigene Farben auf abgedunkelten Kacheln */
|
|
533
|
+
darken(color: string, amount: number): string;
|
|
534
|
+
/** Das SVG, das das Plugin ohne Skript für diesen Aufruf zeichnen würde */
|
|
535
|
+
default(): string;
|
|
536
|
+
};
|
|
537
|
+
/** Grenzen für streamdeck.js */
|
|
538
|
+
export declare const STREAMDECK_SCRIPT_LIMITS: {
|
|
539
|
+
/** Größe des Skripts in Byte */
|
|
540
|
+
readonly sourceBytes: number;
|
|
541
|
+
/** Rechenzeit pro Aufruf von item in ms */
|
|
542
|
+
readonly callMs: 50;
|
|
543
|
+
/** Rechenzeit für das Laden des Moduls in ms */
|
|
544
|
+
readonly evalMs: 200;
|
|
545
|
+
readonly memoryBytes: number;
|
|
546
|
+
/** Klein genug, dass QuickJS vor dem Stack von Node aufgibt */
|
|
547
|
+
readonly stackBytes: number;
|
|
548
|
+
/** Länge des zurückgegebenen SVG in Byte */
|
|
549
|
+
readonly outputBytes: number;
|
|
550
|
+
/** Verschiedene Bilder pro Aufruf */
|
|
551
|
+
readonly images: 64;
|
|
552
|
+
/** So viele Fehler hintereinander, dann bleibt das Skript bis zur nächsten Version aus */
|
|
553
|
+
readonly failures: 5;
|
|
554
|
+
};
|
|
555
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { WidgetField, WidgetState } from "./api-types/index.js";
|
|
2
|
+
type Bindable = Exclude<WidgetField, {
|
|
3
|
+
type: "list" | "trigger" | "voice";
|
|
4
|
+
}>;
|
|
5
|
+
/** Name des Felds als CSS-Variable: `accentColor` → `--pixl-accent-color` */
|
|
6
|
+
export declare function cssVarName(name: string): string;
|
|
7
|
+
/** Wert eines Felds als CSS-Wert, null = Variable entfernen */
|
|
8
|
+
export declare function cssValue(field: WidgetField, value: unknown, fileUrl: (path: string) => string): string | null;
|
|
9
|
+
/** Alle Felder, die in die Seite dürfen, Name → Feld und Wert (Steuerelemente vor Einstellungen) */
|
|
10
|
+
export declare function bindableFields(state: WidgetState): Map<string, {
|
|
11
|
+
field: Bindable;
|
|
12
|
+
value: unknown;
|
|
13
|
+
}>;
|
|
14
|
+
/** Hält die CSS-Variablen auf dem Stand des Widgets, `apply` nach jeder Änderung aufrufen */
|
|
15
|
+
export declare class PageBindings {
|
|
16
|
+
private readonly doc;
|
|
17
|
+
private readonly fileUrl;
|
|
18
|
+
private vars;
|
|
19
|
+
constructor(doc: Document, fileUrl: (path: string) => string);
|
|
20
|
+
apply(state: WidgetState): void;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
package/dist/chat.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export declare class PixlChat {
|
|
|
41
41
|
badgesHtml(badges?: ChatBadge[]): string;
|
|
42
42
|
/** CSS für einen Namen mit 7TV-Paint (siehe `paintCss`) */
|
|
43
43
|
paintCss(paint: SevenTvPaint, fallback?: string): string;
|
|
44
|
-
/** HTML einer Nachricht
|
|
44
|
+
/** HTML einer Nachricht, wie `data.html` bei `twitch.chat_message`, aber z.B. in anderer Größe */
|
|
45
45
|
html(text: string, emotes?: Record<string, ChatEmote>, options?: ChatHtmlOptions): string;
|
|
46
46
|
/** Alle Emotes des Kanals (7TV, BTTV, FFZ, Kanal und global), Gewinner bei gleichem Namen zuerst */
|
|
47
47
|
emotes(): Promise<ChatEmote[]>;
|