divoom-timesgate-sdk 0.1.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.
@@ -0,0 +1,279 @@
1
+ import { Sharp } from 'sharp';
2
+ import { F as FetchLike, P as PanelIndex } from '../common-D8oHDNi6.cjs';
3
+
4
+ /**
5
+ * Types for the image pipeline (`divoom-timesgate-sdk/image`).
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
10
+ /**
11
+ * Anything the image helpers can turn into a panel frame:
12
+ * - a file path (`"./cover.png"`),
13
+ * - an `http(s)` URL (downloaded automatically),
14
+ * - raw encoded bytes (`Buffer` / `Uint8Array`), or
15
+ * - an existing `sharp` pipeline.
16
+ */
17
+ type ImageSource = string | Buffer | Uint8Array | Sharp;
18
+ /** Output encoding for a panel frame. */
19
+ type EncodedFormat = 'jpeg' | 'png';
20
+ /** Resize strategies, mirroring sharp's `fit` options. */
21
+ type ResizeFit = 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
22
+ /** A fully-encoded frame, ready to hand to the device's draw commands. */
23
+ interface EncodedFrame {
24
+ /**
25
+ * Base64-encoded image data — drop this straight into the `picData`
26
+ * argument of {@link DrawCommands.sendImage} (the device's `PicData` field).
27
+ */
28
+ data: string;
29
+ /** The raw encoded bytes. */
30
+ buffer: Buffer;
31
+ /** The container format the bytes are encoded in. */
32
+ format: EncodedFormat;
33
+ /** Frame width in pixels (square frames: equal to {@link EncodedFrame.height}). */
34
+ width: number;
35
+ /** Frame height in pixels. */
36
+ height: number;
37
+ }
38
+ /** Common encoding options shared by most image helpers. */
39
+ interface EncodeOptions {
40
+ /** Output edge length in pixels. Defaults to `128` (one panel). */
41
+ size?: number;
42
+ /** Output format. Defaults to `"jpeg"` (smaller, what the device expects). */
43
+ format?: EncodedFormat;
44
+ /** JPEG quality, `1`–`100`. Defaults to `95`. */
45
+ quality?: number;
46
+ /** JPEG chroma subsampling. Defaults to `"4:4:4"` for crisp edges. */
47
+ chromaSubsampling?: string;
48
+ /** Background used when flattening transparency for JPEG. Defaults to black. */
49
+ background?: string;
50
+ }
51
+ /** Options for {@link encodePanel}. */
52
+ interface EncodePanelOptions extends EncodeOptions {
53
+ /** How the source is fitted into the square frame. Defaults to `"cover"`. */
54
+ fit?: ResizeFit;
55
+ /** Resampling kernel. Defaults to `"lanczos3"` for the sharpest downscale. */
56
+ kernel?: 'nearest' | 'cubic' | 'mitchell' | 'lanczos2' | 'lanczos3';
57
+ }
58
+
59
+ /**
60
+ * Turns any {@link ImageSource} into a `sharp` pipeline.
61
+ *
62
+ * @remarks
63
+ * **Trust model.** A `string` source is treated as an `http(s)` URL when it
64
+ * starts with that scheme, and otherwise as a **local file path**. Do not pass
65
+ * untrusted/attacker-influenced strings here: a URL can trigger a server-side
66
+ * request (SSRF) and a path can read arbitrary local files. URL downloads are
67
+ * bounded by a timeout and a maximum size, but callers handling untrusted input
68
+ * should validate/allowlist the source themselves (and prefer passing a
69
+ * `Buffer` you fetched under your own controls).
70
+ *
71
+ * @packageDocumentation
72
+ */
73
+
74
+ /** Options controlling how URL image sources are downloaded. */
75
+ interface LoadImageOptions {
76
+ /** Per-download timeout in milliseconds (URL sources only). Defaults to `15000`. */
77
+ timeoutMs?: number;
78
+ /** Maximum bytes to download before aborting (URL sources only). Defaults to 64 MiB. */
79
+ maxBytes?: number;
80
+ /** A custom `fetch` for URL sources. Defaults to the global `fetch`. */
81
+ fetch?: FetchLike;
82
+ }
83
+ /**
84
+ * Resolves an {@link ImageSource} to a `sharp` pipeline. Existing pipelines are
85
+ * cloned so callers can reuse the original safely.
86
+ *
87
+ * @param source - A file path, an `http(s)` URL, raw bytes, or a `sharp` instance.
88
+ * See the module-level note on the URL/path trust model before passing
89
+ * untrusted input.
90
+ * @param options - Download controls for URL sources (timeout, size cap, fetch).
91
+ * @throws {@link DivoomValidationError} for unsupported sources or oversized downloads.
92
+ * @throws {@link DivoomConnectionError} when a URL cannot be downloaded.
93
+ * @throws {@link DivoomTimeoutError} when a download exceeds `timeoutMs`.
94
+ */
95
+ declare function loadImage(source: ImageSource, options?: LoadImageOptions): Promise<Sharp>;
96
+
97
+ /**
98
+ * Frame encoding: resize-and-encode any source to a panel-ready
99
+ * {@link EncodedFrame}, plus a helper for solid-color frames.
100
+ *
101
+ * @packageDocumentation
102
+ */
103
+
104
+ /**
105
+ * Encodes an already-sized `sharp` pipeline into an {@link EncodedFrame},
106
+ * applying the SDK's default high-quality JPEG settings (q95, 4:4:4 chroma).
107
+ *
108
+ * @internal Shared by the higher-level helpers; exported for advanced use.
109
+ */
110
+ declare function finalizeFrame(pipeline: Sharp, options: EncodeOptions & {
111
+ size: number;
112
+ }): Promise<EncodedFrame>;
113
+ /**
114
+ * Resizes and encodes any {@link ImageSource} into a single square panel frame.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * const frame = await encodePanel('./album.jpg'); // 128×128 JPEG, q95
119
+ * await client.draw.sendImage(0, frame.data);
120
+ * ```
121
+ */
122
+ declare function encodePanel(source: ImageSource, options?: EncodePanelOptions): Promise<EncodedFrame>;
123
+ /**
124
+ * Produces a solid-color panel frame — handy for clearing a panel or showing a
125
+ * status color.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * await client.draw.sendImage(1, (await solidFrame('#000000')).data); // blank
130
+ * ```
131
+ */
132
+ declare function solidFrame(color: string, options?: EncodeOptions): Promise<EncodedFrame>;
133
+
134
+ /**
135
+ * Color helpers: hex⇄RGB conversion, mixing, and accent extraction from
136
+ * artwork (used to tint the now-playing panels).
137
+ *
138
+ * @packageDocumentation
139
+ */
140
+
141
+ /** An `[r, g, b]` triple with each channel in `0`–`255`. */
142
+ type Rgb = [number, number, number];
143
+ /** Parses a `#RGB` or `#RRGGBB` hex string into an {@link Rgb} triple. */
144
+ declare function hexToRgb(hex: string): Rgb;
145
+ /** Formats an {@link Rgb} triple as an uppercase `#RRGGBB` string. */
146
+ declare function rgbToHex([r, g, b]: Rgb): string;
147
+ /** Linearly interpolates between two colors (`t` in `0`–`1`). */
148
+ declare function mixRgb(a: Rgb, b: Rgb, t: number): Rgb;
149
+ /** Scales every channel of a color by `factor`. */
150
+ declare function scaleRgb([r, g, b]: Rgb, factor: number): Rgb;
151
+ /**
152
+ * Extracts a vivid accent color from artwork — the most saturated reasonably
153
+ * bright pixel — for tinting backgrounds and progress bars. Mirrors the proven
154
+ * heuristic from the reference now-playing app.
155
+ *
156
+ * @param source - The artwork to sample.
157
+ * @param fallback - Returned when no saturated pixel is found. Defaults to
158
+ * Spotify green (`#1DB954`).
159
+ */
160
+ declare function getAccentColor(source: ImageSource, fallback?: string): Promise<string>;
161
+
162
+ /**
163
+ * Album-art styling — the two looks from the reference now-playing app:
164
+ * a crisp "smooth" treatment and a chunky "pixel" treatment.
165
+ *
166
+ * @packageDocumentation
167
+ */
168
+
169
+ /** Visual treatment applied by {@link prepareAlbumArt}. */
170
+ type AlbumArtStyle = 'smooth' | 'pixel';
171
+ /** Options for {@link prepareAlbumArt}. */
172
+ interface PrepareAlbumArtOptions extends EncodeOptions {
173
+ /**
174
+ * `"smooth"` (default) gently boosts saturation/contrast and unsharp-masks for
175
+ * a clean look; `"pixel"` downsamples to 32×32 nearest-neighbour for a retro,
176
+ * blocky aesthetic.
177
+ */
178
+ style?: AlbumArtStyle;
179
+ }
180
+ /**
181
+ * Prepares album/cover artwork for a panel, matching the look of the reference
182
+ * Spotify app.
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * const art = await prepareAlbumArt(coverUrl, { style: 'smooth' });
187
+ * await client.draw.sendImage(0, art.data);
188
+ * ```
189
+ */
190
+ declare function prepareAlbumArt(source: ImageSource, options?: PrepareAlbumArtOptions): Promise<EncodedFrame>;
191
+
192
+ /**
193
+ * Split one image across several panels to create a single wide (or tall)
194
+ * canvas spanning the Times Gate.
195
+ *
196
+ * @packageDocumentation
197
+ */
198
+
199
+ /** A frame paired with the panel it belongs on. */
200
+ interface PanelFrame {
201
+ /** The target panel index. */
202
+ panel: PanelIndex;
203
+ /** The encoded frame for that panel. */
204
+ frame: EncodedFrame;
205
+ }
206
+ /** Options for {@link splitImageAcrossPanels}. */
207
+ interface SplitOptions extends EncodeOptions {
208
+ /** Panels to span, in visual order. Defaults to all five (`[0,1,2,3,4]`). */
209
+ panels?: PanelIndex[];
210
+ /**
211
+ * `"horizontal"` (default) lays the image out left-to-right across panels;
212
+ * `"vertical"` stacks top-to-bottom.
213
+ */
214
+ layout?: 'horizontal' | 'vertical';
215
+ }
216
+ /**
217
+ * Slices a single image into one square frame per panel, so a panorama spans
218
+ * the whole device.
219
+ *
220
+ * @example
221
+ * ```ts
222
+ * const tiles = await splitImageAcrossPanels('./wide-banner.png');
223
+ * for (const { panel, frame } of tiles) {
224
+ * await client.draw.sendImage(panel, frame.data);
225
+ * }
226
+ * ```
227
+ */
228
+ declare function splitImageAcrossPanels(source: ImageSource, options?: SplitOptions): Promise<PanelFrame[]>;
229
+
230
+ /**
231
+ * Renders a designed "now-playing"-style text panel: a tinted gradient
232
+ * background, an optional eyebrow with a play glyph, an auto-fitted title, a
233
+ * subtitle, and an optional progress bar. Text is rendered with Pango (via
234
+ * sharp) for crisp, properly-wrapped output that doesn't depend on the host's
235
+ * system fonts the way the original Python reference did.
236
+ *
237
+ * @packageDocumentation
238
+ */
239
+
240
+ /** Options for {@link renderTextPanel}. */
241
+ interface RenderTextPanelOptions extends EncodeOptions {
242
+ /** The headline text (e.g. a track title). Auto-sized to fit. */
243
+ title: string;
244
+ /** Secondary text below the title (e.g. an artist). Optional. */
245
+ subtitle?: string;
246
+ /** Small uppercase label above the title (e.g. `"NOW PLAYING"`). Optional. */
247
+ eyebrow?: string;
248
+ /** Accent color (hex) used for the tint, eyebrow, subtitle and bar. Defaults to `#1DB954`. */
249
+ accent?: string;
250
+ /** Progress fraction `0`–`1`. When set, a progress bar is drawn. */
251
+ progress?: number;
252
+ /**
253
+ * Background style: `"gradient"` (default, an accent-tinted vertical fade),
254
+ * `"solid"` (a flat accent), or any hex string for a custom flat color.
255
+ */
256
+ background?: 'gradient' | 'solid' | string;
257
+ /** Pango font family. Defaults to `"DejaVu Sans"`. */
258
+ font?: string;
259
+ }
260
+ /**
261
+ * Renders a designed now-playing-style panel and returns an
262
+ * {@link EncodedFrame} ready for a panel. Overly long titles/subtitles are
263
+ * shrunk to fit rather than overflowing the panel.
264
+ *
265
+ * @example
266
+ * ```ts
267
+ * const panel = await renderTextPanel({
268
+ * eyebrow: 'Now Playing',
269
+ * title: 'Bohemian Rhapsody',
270
+ * subtitle: 'Queen',
271
+ * accent: '#E94F37',
272
+ * progress: 0.42,
273
+ * });
274
+ * await client.draw.sendImage(1, panel.data);
275
+ * ```
276
+ */
277
+ declare function renderTextPanel(options: RenderTextPanelOptions): Promise<EncodedFrame>;
278
+
279
+ export { type AlbumArtStyle, type EncodeOptions, type EncodePanelOptions, type EncodedFormat, type EncodedFrame, type ImageSource, type LoadImageOptions, type PanelFrame, type PrepareAlbumArtOptions, type RenderTextPanelOptions, type ResizeFit, type Rgb, type SplitOptions, encodePanel, finalizeFrame, getAccentColor, hexToRgb, loadImage, mixRgb, prepareAlbumArt, renderTextPanel, rgbToHex, scaleRgb, solidFrame, splitImageAcrossPanels };
@@ -0,0 +1,279 @@
1
+ import { Sharp } from 'sharp';
2
+ import { F as FetchLike, P as PanelIndex } from '../common-D8oHDNi6.js';
3
+
4
+ /**
5
+ * Types for the image pipeline (`divoom-timesgate-sdk/image`).
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
10
+ /**
11
+ * Anything the image helpers can turn into a panel frame:
12
+ * - a file path (`"./cover.png"`),
13
+ * - an `http(s)` URL (downloaded automatically),
14
+ * - raw encoded bytes (`Buffer` / `Uint8Array`), or
15
+ * - an existing `sharp` pipeline.
16
+ */
17
+ type ImageSource = string | Buffer | Uint8Array | Sharp;
18
+ /** Output encoding for a panel frame. */
19
+ type EncodedFormat = 'jpeg' | 'png';
20
+ /** Resize strategies, mirroring sharp's `fit` options. */
21
+ type ResizeFit = 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
22
+ /** A fully-encoded frame, ready to hand to the device's draw commands. */
23
+ interface EncodedFrame {
24
+ /**
25
+ * Base64-encoded image data — drop this straight into the `picData`
26
+ * argument of {@link DrawCommands.sendImage} (the device's `PicData` field).
27
+ */
28
+ data: string;
29
+ /** The raw encoded bytes. */
30
+ buffer: Buffer;
31
+ /** The container format the bytes are encoded in. */
32
+ format: EncodedFormat;
33
+ /** Frame width in pixels (square frames: equal to {@link EncodedFrame.height}). */
34
+ width: number;
35
+ /** Frame height in pixels. */
36
+ height: number;
37
+ }
38
+ /** Common encoding options shared by most image helpers. */
39
+ interface EncodeOptions {
40
+ /** Output edge length in pixels. Defaults to `128` (one panel). */
41
+ size?: number;
42
+ /** Output format. Defaults to `"jpeg"` (smaller, what the device expects). */
43
+ format?: EncodedFormat;
44
+ /** JPEG quality, `1`–`100`. Defaults to `95`. */
45
+ quality?: number;
46
+ /** JPEG chroma subsampling. Defaults to `"4:4:4"` for crisp edges. */
47
+ chromaSubsampling?: string;
48
+ /** Background used when flattening transparency for JPEG. Defaults to black. */
49
+ background?: string;
50
+ }
51
+ /** Options for {@link encodePanel}. */
52
+ interface EncodePanelOptions extends EncodeOptions {
53
+ /** How the source is fitted into the square frame. Defaults to `"cover"`. */
54
+ fit?: ResizeFit;
55
+ /** Resampling kernel. Defaults to `"lanczos3"` for the sharpest downscale. */
56
+ kernel?: 'nearest' | 'cubic' | 'mitchell' | 'lanczos2' | 'lanczos3';
57
+ }
58
+
59
+ /**
60
+ * Turns any {@link ImageSource} into a `sharp` pipeline.
61
+ *
62
+ * @remarks
63
+ * **Trust model.** A `string` source is treated as an `http(s)` URL when it
64
+ * starts with that scheme, and otherwise as a **local file path**. Do not pass
65
+ * untrusted/attacker-influenced strings here: a URL can trigger a server-side
66
+ * request (SSRF) and a path can read arbitrary local files. URL downloads are
67
+ * bounded by a timeout and a maximum size, but callers handling untrusted input
68
+ * should validate/allowlist the source themselves (and prefer passing a
69
+ * `Buffer` you fetched under your own controls).
70
+ *
71
+ * @packageDocumentation
72
+ */
73
+
74
+ /** Options controlling how URL image sources are downloaded. */
75
+ interface LoadImageOptions {
76
+ /** Per-download timeout in milliseconds (URL sources only). Defaults to `15000`. */
77
+ timeoutMs?: number;
78
+ /** Maximum bytes to download before aborting (URL sources only). Defaults to 64 MiB. */
79
+ maxBytes?: number;
80
+ /** A custom `fetch` for URL sources. Defaults to the global `fetch`. */
81
+ fetch?: FetchLike;
82
+ }
83
+ /**
84
+ * Resolves an {@link ImageSource} to a `sharp` pipeline. Existing pipelines are
85
+ * cloned so callers can reuse the original safely.
86
+ *
87
+ * @param source - A file path, an `http(s)` URL, raw bytes, or a `sharp` instance.
88
+ * See the module-level note on the URL/path trust model before passing
89
+ * untrusted input.
90
+ * @param options - Download controls for URL sources (timeout, size cap, fetch).
91
+ * @throws {@link DivoomValidationError} for unsupported sources or oversized downloads.
92
+ * @throws {@link DivoomConnectionError} when a URL cannot be downloaded.
93
+ * @throws {@link DivoomTimeoutError} when a download exceeds `timeoutMs`.
94
+ */
95
+ declare function loadImage(source: ImageSource, options?: LoadImageOptions): Promise<Sharp>;
96
+
97
+ /**
98
+ * Frame encoding: resize-and-encode any source to a panel-ready
99
+ * {@link EncodedFrame}, plus a helper for solid-color frames.
100
+ *
101
+ * @packageDocumentation
102
+ */
103
+
104
+ /**
105
+ * Encodes an already-sized `sharp` pipeline into an {@link EncodedFrame},
106
+ * applying the SDK's default high-quality JPEG settings (q95, 4:4:4 chroma).
107
+ *
108
+ * @internal Shared by the higher-level helpers; exported for advanced use.
109
+ */
110
+ declare function finalizeFrame(pipeline: Sharp, options: EncodeOptions & {
111
+ size: number;
112
+ }): Promise<EncodedFrame>;
113
+ /**
114
+ * Resizes and encodes any {@link ImageSource} into a single square panel frame.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * const frame = await encodePanel('./album.jpg'); // 128×128 JPEG, q95
119
+ * await client.draw.sendImage(0, frame.data);
120
+ * ```
121
+ */
122
+ declare function encodePanel(source: ImageSource, options?: EncodePanelOptions): Promise<EncodedFrame>;
123
+ /**
124
+ * Produces a solid-color panel frame — handy for clearing a panel or showing a
125
+ * status color.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * await client.draw.sendImage(1, (await solidFrame('#000000')).data); // blank
130
+ * ```
131
+ */
132
+ declare function solidFrame(color: string, options?: EncodeOptions): Promise<EncodedFrame>;
133
+
134
+ /**
135
+ * Color helpers: hex⇄RGB conversion, mixing, and accent extraction from
136
+ * artwork (used to tint the now-playing panels).
137
+ *
138
+ * @packageDocumentation
139
+ */
140
+
141
+ /** An `[r, g, b]` triple with each channel in `0`–`255`. */
142
+ type Rgb = [number, number, number];
143
+ /** Parses a `#RGB` or `#RRGGBB` hex string into an {@link Rgb} triple. */
144
+ declare function hexToRgb(hex: string): Rgb;
145
+ /** Formats an {@link Rgb} triple as an uppercase `#RRGGBB` string. */
146
+ declare function rgbToHex([r, g, b]: Rgb): string;
147
+ /** Linearly interpolates between two colors (`t` in `0`–`1`). */
148
+ declare function mixRgb(a: Rgb, b: Rgb, t: number): Rgb;
149
+ /** Scales every channel of a color by `factor`. */
150
+ declare function scaleRgb([r, g, b]: Rgb, factor: number): Rgb;
151
+ /**
152
+ * Extracts a vivid accent color from artwork — the most saturated reasonably
153
+ * bright pixel — for tinting backgrounds and progress bars. Mirrors the proven
154
+ * heuristic from the reference now-playing app.
155
+ *
156
+ * @param source - The artwork to sample.
157
+ * @param fallback - Returned when no saturated pixel is found. Defaults to
158
+ * Spotify green (`#1DB954`).
159
+ */
160
+ declare function getAccentColor(source: ImageSource, fallback?: string): Promise<string>;
161
+
162
+ /**
163
+ * Album-art styling — the two looks from the reference now-playing app:
164
+ * a crisp "smooth" treatment and a chunky "pixel" treatment.
165
+ *
166
+ * @packageDocumentation
167
+ */
168
+
169
+ /** Visual treatment applied by {@link prepareAlbumArt}. */
170
+ type AlbumArtStyle = 'smooth' | 'pixel';
171
+ /** Options for {@link prepareAlbumArt}. */
172
+ interface PrepareAlbumArtOptions extends EncodeOptions {
173
+ /**
174
+ * `"smooth"` (default) gently boosts saturation/contrast and unsharp-masks for
175
+ * a clean look; `"pixel"` downsamples to 32×32 nearest-neighbour for a retro,
176
+ * blocky aesthetic.
177
+ */
178
+ style?: AlbumArtStyle;
179
+ }
180
+ /**
181
+ * Prepares album/cover artwork for a panel, matching the look of the reference
182
+ * Spotify app.
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * const art = await prepareAlbumArt(coverUrl, { style: 'smooth' });
187
+ * await client.draw.sendImage(0, art.data);
188
+ * ```
189
+ */
190
+ declare function prepareAlbumArt(source: ImageSource, options?: PrepareAlbumArtOptions): Promise<EncodedFrame>;
191
+
192
+ /**
193
+ * Split one image across several panels to create a single wide (or tall)
194
+ * canvas spanning the Times Gate.
195
+ *
196
+ * @packageDocumentation
197
+ */
198
+
199
+ /** A frame paired with the panel it belongs on. */
200
+ interface PanelFrame {
201
+ /** The target panel index. */
202
+ panel: PanelIndex;
203
+ /** The encoded frame for that panel. */
204
+ frame: EncodedFrame;
205
+ }
206
+ /** Options for {@link splitImageAcrossPanels}. */
207
+ interface SplitOptions extends EncodeOptions {
208
+ /** Panels to span, in visual order. Defaults to all five (`[0,1,2,3,4]`). */
209
+ panels?: PanelIndex[];
210
+ /**
211
+ * `"horizontal"` (default) lays the image out left-to-right across panels;
212
+ * `"vertical"` stacks top-to-bottom.
213
+ */
214
+ layout?: 'horizontal' | 'vertical';
215
+ }
216
+ /**
217
+ * Slices a single image into one square frame per panel, so a panorama spans
218
+ * the whole device.
219
+ *
220
+ * @example
221
+ * ```ts
222
+ * const tiles = await splitImageAcrossPanels('./wide-banner.png');
223
+ * for (const { panel, frame } of tiles) {
224
+ * await client.draw.sendImage(panel, frame.data);
225
+ * }
226
+ * ```
227
+ */
228
+ declare function splitImageAcrossPanels(source: ImageSource, options?: SplitOptions): Promise<PanelFrame[]>;
229
+
230
+ /**
231
+ * Renders a designed "now-playing"-style text panel: a tinted gradient
232
+ * background, an optional eyebrow with a play glyph, an auto-fitted title, a
233
+ * subtitle, and an optional progress bar. Text is rendered with Pango (via
234
+ * sharp) for crisp, properly-wrapped output that doesn't depend on the host's
235
+ * system fonts the way the original Python reference did.
236
+ *
237
+ * @packageDocumentation
238
+ */
239
+
240
+ /** Options for {@link renderTextPanel}. */
241
+ interface RenderTextPanelOptions extends EncodeOptions {
242
+ /** The headline text (e.g. a track title). Auto-sized to fit. */
243
+ title: string;
244
+ /** Secondary text below the title (e.g. an artist). Optional. */
245
+ subtitle?: string;
246
+ /** Small uppercase label above the title (e.g. `"NOW PLAYING"`). Optional. */
247
+ eyebrow?: string;
248
+ /** Accent color (hex) used for the tint, eyebrow, subtitle and bar. Defaults to `#1DB954`. */
249
+ accent?: string;
250
+ /** Progress fraction `0`–`1`. When set, a progress bar is drawn. */
251
+ progress?: number;
252
+ /**
253
+ * Background style: `"gradient"` (default, an accent-tinted vertical fade),
254
+ * `"solid"` (a flat accent), or any hex string for a custom flat color.
255
+ */
256
+ background?: 'gradient' | 'solid' | string;
257
+ /** Pango font family. Defaults to `"DejaVu Sans"`. */
258
+ font?: string;
259
+ }
260
+ /**
261
+ * Renders a designed now-playing-style panel and returns an
262
+ * {@link EncodedFrame} ready for a panel. Overly long titles/subtitles are
263
+ * shrunk to fit rather than overflowing the panel.
264
+ *
265
+ * @example
266
+ * ```ts
267
+ * const panel = await renderTextPanel({
268
+ * eyebrow: 'Now Playing',
269
+ * title: 'Bohemian Rhapsody',
270
+ * subtitle: 'Queen',
271
+ * accent: '#E94F37',
272
+ * progress: 0.42,
273
+ * });
274
+ * await client.draw.sendImage(1, panel.data);
275
+ * ```
276
+ */
277
+ declare function renderTextPanel(options: RenderTextPanelOptions): Promise<EncodedFrame>;
278
+
279
+ export { type AlbumArtStyle, type EncodeOptions, type EncodePanelOptions, type EncodedFormat, type EncodedFrame, type ImageSource, type LoadImageOptions, type PanelFrame, type PrepareAlbumArtOptions, type RenderTextPanelOptions, type ResizeFit, type Rgb, type SplitOptions, encodePanel, finalizeFrame, getAccentColor, hexToRgb, loadImage, mixRgb, prepareAlbumArt, renderTextPanel, rgbToHex, scaleRgb, solidFrame, splitImageAcrossPanels };