wallpaper-engine 1.0.1 → 1.0.3

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.
Files changed (2) hide show
  1. package/README.md +337 -0
  2. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,337 @@
1
+ <div align="center">
2
+
3
+ # wallpaper-engine
4
+
5
+ TypeScript type definitions, a Vite plugin, and runtime helpers for building [Wallpaper Engine](https://www.wallpaperengine.io/) web wallpapers.
6
+
7
+ [![npm](https://img.shields.io/npm/v/wallpaper-engine)](https://www.npmjs.com/package/wallpaper-engine)
8
+ [![Build Status](https://github.com/ShadowNineX/wallpaper-engine/actions/workflows/test_and_deploy.yml/badge.svg)](https://github.com/ShadowNineX/wallpaper-engine/actions)
9
+ [![codecov](https://codecov.io/gh/ShadowNineX/wallpaper-engine/branch/main/graph/badge.svg)](https://codecov.io/gh/ShadowNineX/wallpaper-engine)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
+
12
+ [:package: Installation](#installation) · [:electric_plug: Vite Plugin](#vite-plugin) · [:muscle: Strong Typing](#strong-property-typing) · [:wrench: Helpers](#helpers) · [:window: Window Augmentation](#window-augmentation) · [:books: Type Reference](#full-type-reference)
13
+
14
+ </div>
15
+
16
+ - **Full type coverage** for the entire Wallpaper Engine Web API — property listeners, media integration, audio, iCUE/LED plugins, and `window` augmentation
17
+ - **Vite plugin** that auto-generates `project.json` at build time with full IntelliSense on your property definitions
18
+ - **Strong inference** — define your properties once and TypeScript automatically types every key in `applyUserProperties`
19
+ - **Tree-shakeable helpers** for color conversion, audio processing, file URLs, LED encoding, and FPS-limited animation loops
20
+
21
+ ---
22
+
23
+ ## <a id="installation"></a>:package: Installation
24
+
25
+ ```bash
26
+ bun add wallpaper-engine
27
+ # or
28
+ npm install wallpaper-engine
29
+ # or
30
+ pnpm add wallpaper-engine
31
+ ```
32
+
33
+ Vite is an optional peer dependency, required only if you use `wallpaper-engine/plugin`:
34
+
35
+ ```bash
36
+ bun add -d vite
37
+ ```
38
+
39
+ ---
40
+
41
+ ## <a id="package-exports"></a>:inbox_tray: Package Exports
42
+
43
+ | Import path | Contents |
44
+ |---|---|
45
+ | `wallpaper-engine` | All TypeScript types + `window` augmentation |
46
+ | `wallpaper-engine/plugin` | Vite plugin, property builders, `WallpaperUserPropertiesOf<T>` |
47
+ | `wallpaper-engine/helpers` | Runtime utility functions |
48
+
49
+ ---
50
+
51
+ ## <a id="vite-plugin"></a>:electric_plug: Vite Plugin
52
+
53
+ The plugin emits a `project.json` asset alongside your build so Wallpaper Engine can load the wallpaper without any manual file maintenance.
54
+
55
+ ### Basic setup
56
+
57
+ ```ts
58
+ // vite.config.ts
59
+ import { defineConfig } from 'vite';
60
+ import { wallpaperEnginePlugin, colorProperty, sliderProperty, boolProperty } from 'wallpaper-engine/plugin';
61
+
62
+ export default defineConfig({
63
+ plugins: [
64
+ wallpaperEnginePlugin({
65
+ title: 'My Wallpaper',
66
+ supportsAudioProcessing: true,
67
+ properties: {
68
+ bgcolor: colorProperty({ text: 'Background Color', value: '1 1 1' }),
69
+ speed: sliderProperty({ text: 'Speed', value: 1, min: 0, max: 10 }),
70
+ showClock: boolProperty({ text: 'Show Clock', value: true }),
71
+ },
72
+ }),
73
+ ],
74
+ });
75
+ ```
76
+
77
+ This outputs a `project.json` alongside your build:
78
+
79
+ ```json
80
+ {
81
+ "file": "index.html",
82
+ "title": "My Wallpaper",
83
+ "type": "web",
84
+ "supportsaudioprocessing": true,
85
+ "general": {
86
+ "properties": {
87
+ "bgcolor": { "type": "color", "text": "Background Color", "value": "1 1 1", "index": 0, "order": 0 },
88
+ "speed": { "type": "slider", "text": "Speed", "value": 1, "index": 1, "order": 1, "min": 0, "max": 10 },
89
+ "showClock": { "type": "bool", "text": "Show Clock", "value": true, "index": 2, "order": 2 }
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ ### Property builder reference
96
+
97
+ | Builder | Property type | Runtime value |
98
+ |---|---|---|
99
+ | `colorProperty` | Color picker | `WallpaperColorValue` — `value: "R G B"` (0–1 per channel) |
100
+ | `sliderProperty` | Numeric slider | `WallpaperSliderValue` — `value: number` |
101
+ | `boolProperty` | Checkbox | `WallpaperBoolValue` — `value: boolean` |
102
+ | `comboProperty` | Dropdown | `WallpaperComboValue` — `value: string` (hidden key), `text: string` (label) |
103
+ | `textInputProperty` | Text input | `WallpaperTextValue` — `value: string` |
104
+ | `fileProperty` | File picker | `WallpaperFileValue` — `value: string` (path, prefix with `file:///`) |
105
+ | `directoryProperty` | Directory picker | `WallpaperDirectoryValue` — `value: string` (path) |
106
+
107
+ ### Localization
108
+
109
+ Property labels starting with `ui_` are resolved against the localization map:
110
+
111
+ ```ts
112
+ wallpaperEnginePlugin({
113
+ title: 'My Wallpaper',
114
+ properties: {
115
+ bgcolor: colorProperty({ text: 'ui_bgcolor', value: '0 0 0' }),
116
+ },
117
+ localization: {
118
+ 'en-us': { 'ui_bgcolor': 'Background Color' },
119
+ 'de-de': { 'ui_bgcolor': 'Hintergrundfarbe' },
120
+ },
121
+ });
122
+ ```
123
+
124
+ ---
125
+
126
+ ## <a id="strong-property-typing"></a>:muscle: Strong Property Typing
127
+
128
+ Define your properties in a dedicated file, then import it in both `vite.config.ts` and your wallpaper source. `WallpaperUserPropertiesOf<T>` maps each definition to its exact runtime value type automatically.
129
+
130
+ ```ts
131
+ // src/properties.ts
132
+ import { colorProperty, sliderProperty, boolProperty } from 'wallpaper-engine/plugin';
133
+
134
+ export const myProperties = {
135
+ bgcolor: colorProperty({ text: 'Background Color', value: '0 0 0' }),
136
+ speed: sliderProperty({ text: 'Speed', value: 1, min: 0, max: 5 }),
137
+ showClock: boolProperty({ text: 'Show Clock', value: true }),
138
+ };
139
+ ```
140
+
141
+ ```ts
142
+ // vite.config.ts
143
+ import { wallpaperEnginePlugin } from 'wallpaper-engine/plugin';
144
+ import { myProperties } from './src/properties';
145
+
146
+ export default defineConfig({
147
+ plugins: [wallpaperEnginePlugin({ title: 'My Wallpaper', properties: myProperties })],
148
+ });
149
+ ```
150
+
151
+ ```ts
152
+ // src/wallpaper.ts
153
+ import type { WallpaperUserPropertiesOf } from 'wallpaper-engine/plugin';
154
+ import type { myProperties } from './properties';
155
+ import { wallpaperColorToRgb } from 'wallpaper-engine/helpers';
156
+
157
+ type MyProps = WallpaperUserPropertiesOf<typeof myProperties>;
158
+ // → { bgcolor: WallpaperColorValue; speed: WallpaperSliderValue; showClock: WallpaperBoolValue }
159
+
160
+ window.wallpaperPropertyListener = {
161
+ applyUserProperties(props: Partial<MyProps>) {
162
+ if (props.bgcolor) document.body.style.background = wallpaperColorToRgb(props.bgcolor.value);
163
+ if (props.speed) setSpeed(props.speed.value); // inferred as number ✓
164
+ if (props.showClock) toggle(props.showClock.value); // inferred as boolean ✓
165
+ },
166
+ };
167
+ ```
168
+
169
+ ---
170
+
171
+ ## <a id="helpers"></a>:wrench: Helpers
172
+
173
+ All helpers are side-effect-free and individually tree-shakeable.
174
+
175
+ ```ts
176
+ import {
177
+ parseWallpaperColor,
178
+ wallpaperColorToRgb,
179
+ wallpaperColorToHex,
180
+ toFileUrl,
181
+ clampAudio,
182
+ leftChannel,
183
+ rightChannel,
184
+ encodeCanvasForLed,
185
+ createFpsLimiter,
186
+ } from 'wallpaper-engine/helpers';
187
+ ```
188
+
189
+ ### Color
190
+
191
+ ```ts
192
+ // "R G B" string (0–1 per channel) → { r, g, b } (0–255)
193
+ const { r, g, b } = parseWallpaperColor(props.bgcolor.value);
194
+
195
+ // → CSS "rgb(255,128,0)"
196
+ el.style.color = wallpaperColorToRgb(props.bgcolor.value);
197
+
198
+ // → CSS "#ff8000"
199
+ el.style.color = wallpaperColorToHex(props.bgcolor.value);
200
+ ```
201
+
202
+ ### Files
203
+
204
+ ```ts
205
+ // Prefix a WE path with file:/// before using it as an <img> or <video> src
206
+ img.src = toFileUrl(props.myimage.value);
207
+ ```
208
+
209
+ ### Audio
210
+
211
+ ```ts
212
+ window.wallpaperRegisterAudioListener((raw) => {
213
+ const audio = clampAudio(raw); // clamp all 128 values to 0–1
214
+ const left = leftChannel(audio); // indices 0–63 (bass → treble)
215
+ const right = rightChannel(audio); // indices 64–127 (bass → treble)
216
+ renderBars(left, right);
217
+ });
218
+ ```
219
+
220
+ > [!IMPORTANT]
221
+ > **Always use `window.wallpaperRegisterAudioListener`, not `globalThis.`.**
222
+ > Wallpaper Engine scans your compiled JS for this exact call to detect that the wallpaper uses audio and automatically sets `"supportsaudioprocessing": true` in its internal `project.json`. Without that flag, WE will **not** send audio data in live desktop mode (the editor preview always sends audio regardless, which can mask the problem).
223
+ >
224
+ > If audio works in the WE editor but not as a live wallpaper, open the wallpaper in the WE editor and click **Edit → Save** to force WE to write the updated `project.json`. After saving, re-apply the wallpaper as your desktop background.
225
+
226
+ ### LED / RGB
227
+
228
+ ```ts
229
+ // Encode a canvas as the RGB byte string expected by setAllDevicesByImageData
230
+ const canvas = document.getElementById('RGBCanvas') as HTMLCanvasElement;
231
+ const encoded = encodeCanvasForLed(canvas);
232
+ window.wpPlugins.led.setAllDevicesByImageData(encoded, canvas.width, canvas.height);
233
+ ```
234
+
235
+ ### FPS-limited animation loop
236
+
237
+ Mirrors the FPS cap delivered by `applyGeneralProperties`. Pass `0` for unlimited.
238
+
239
+ ```ts
240
+ const loop = createFpsLimiter((dt) => renderFrame(dt));
241
+
242
+ window.wallpaperPropertyListener = {
243
+ applyGeneralProperties(props) {
244
+ if (props.fps !== undefined) loop.setLimit(props.fps);
245
+ },
246
+ };
247
+
248
+ window.onload = () => loop.start();
249
+ ```
250
+
251
+ ---
252
+
253
+ ## <a id="window-augmentation"></a>:window: Window Augmentation
254
+
255
+ If you're not using Vite or don't need the plugin, the main `wallpaper-engine` entry is all you need. A single side-effect import augments the global `Window` interface so every WE API is fully typed — no manual `declare` blocks, no runtime cost.
256
+
257
+ ```ts
258
+ import 'wallpaper-engine';
259
+
260
+ // All of these are now fully typed:
261
+ window.wallpaperPropertyListener = { ... };
262
+ window.wallpaperRegisterAudioListener((audio) => { ... });
263
+ window.wallpaperRequestRandomFileForProperty('mydir');
264
+ window.wallpaperPluginListener = { onPluginLoaded(name, version) { ... } };
265
+ window.wpPlugins.led.setAllDevicesByImageData(encoded, w, h);
266
+ window.cue.setLedsColorsAsync(deviceIndex, leds);
267
+
268
+ // Media integration
269
+ window.wallpaperRegisterMediaPropertiesListener((e) => { /* e.title, e.artist, ... */ });
270
+ window.wallpaperRegisterMediaPlaybackListener((e) => { /* e.state */ });
271
+ window.wallpaperRegisterMediaThumbnailListener((e) => { /* e.thumbnail (base64 PNG) */ });
272
+ ```
273
+
274
+ The import is erased at compile time — nothing is added to your bundle.
275
+
276
+ Two alternatives that also work without an `import` in your source:
277
+
278
+ **`tsconfig.json`** — applies the augmentation project-wide, no import needed anywhere:
279
+ ```json
280
+ {
281
+ "compilerOptions": {
282
+ "types": ["wallpaper-engine"]
283
+ }
284
+ }
285
+ ```
286
+
287
+ **Triple-slash reference** — per-file, useful if you only want types in specific files:
288
+ ```ts
289
+ /// <reference types="wallpaper-engine" />
290
+ ```
291
+
292
+ ---
293
+
294
+ ## <a id="full-type-reference"></a>:books: Full Type Reference
295
+
296
+ All types are exported from `wallpaper-engine` (main entry).
297
+
298
+ ### Property definition types (`project.json`)
299
+
300
+ `WallpaperColorProperty` · `WallpaperSliderProperty` · `WallpaperBoolProperty` · `WallpaperComboProperty` · `WallpaperTextInputProperty` · `WallpaperFileProperty` · `WallpaperDirectoryProperty` · `WallpaperPropertyDefinition` · `WallpaperProject` · `WallpaperProjectGeneral` · `WallpaperLocalization`
301
+
302
+ ### Runtime value types (`applyUserProperties`)
303
+
304
+ `WallpaperColorValue` · `WallpaperSliderValue` · `WallpaperBoolValue` · `WallpaperComboValue` · `WallpaperTextValue` · `WallpaperFileValue` · `WallpaperDirectoryValue` · `WallpaperUserProperties` · `WallpaperGeneralProperties`
305
+
306
+ ### Listener interfaces
307
+
308
+ `WallpaperPropertyListener` · `WallpaperPluginListener`
309
+
310
+ ### Media integration
311
+
312
+ `WallpaperMediaStatusEvent` · `WallpaperMediaPropertiesEvent` · `WallpaperMediaThumbnailEvent` · `WallpaperMediaPlaybackEvent` · `WallpaperMediaPlaybackState` · `WallpaperMediaTimelineEvent`
313
+
314
+ ### iCUE / LED
315
+
316
+ `WallpaperCuePlugin` · `WallpaperLedPlugin` · `CueDeviceInfo` · `CueLedColor` · `CueLedPosition` · `CueProtocolDetails`
317
+
318
+ ---
319
+
320
+ ## <a id="building"></a>:building_construction: Building
321
+
322
+ ```bash
323
+ bun run build # production build (ESM + CJS + .d.ts)
324
+ bun run dev # watch mode
325
+ bun run typecheck # type-check without emitting
326
+ ```
327
+
328
+ Output goes to `dist/` with the following structure:
329
+
330
+ ```
331
+ dist/
332
+ index.js / index.cjs / index.d.ts
333
+ helpers.js / helpers.cjs / helpers.d.ts
334
+ plugin/
335
+ index.js / index.cjs / index.d.ts
336
+ ```
337
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wallpaper-engine",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "TypeScript types, Vite plugin, and runtime helpers for Wallpaper Engine web wallpapers",
5
5
  "keywords": [
6
6
  "wallpaper-engine",
@@ -51,7 +51,7 @@
51
51
  "typecheck": "tsc --noEmit",
52
52
  "test": "vitest",
53
53
  "test:run": "vitest run",
54
- "prepublishOnly": "bun run --cwd ../.. build"
54
+ "prepublishOnly": "bun run --cwd ../.. build && node -e \"require('fs').copyFileSync('../../README.md', 'README.md')\""
55
55
  },
56
56
  "peerDependencies": {
57
57
  "vite": ">=5.0.0"