Files, LED & Frames Helpers
import { createFpsLimiter, encodeCanvasForLed, toFileUrl,} from 'wallpaper-engine/helpers';File URLs
Section titled “File URLs”toFileUrl(path) converts host filesystem values without breaking browser-ready URLs:
| Input | Output |
|---|---|
'' |
'' |
C:/Images/background.png |
file:///C:/Images/background.png |
C%3A/Images/native%20%23%20cover.jpg |
file:///C:/Images/native%20%23%20cover.jpg |
C:\\Images\\cover #1.png |
file:///C:/Images/cover%20%231.png |
//server/share/cover.png or \\\\server\\share\\cover.png |
file://server/share/cover.png |
/assets/background.png |
Preserved |
https://…, http://…, data:…, blob:…, file:… |
Preserved, case-insensitively by scheme |
image.src = toFileUrl(property.value);Raw filesystem paths normalize backslashes and encode filename characters such as spaces, #, and %. Wallpaper Engine’s encoded-drive form (C%3A/...) is decoded exactly once before conversion; malformed escapes in that form throw URIError. Percent sequences in raw drive paths (C:/...) stay literal, so a filename containing %20 remains distinct from a space. Browser-ready URLs and single-slash asset paths are preserved. The helper performs no filesystem lookup. See Files & Directories for host paths and simulator-owned object URLs.
LED canvas encoding
Section titled “LED canvas encoding”encodeCanvasForLed(canvas) reads the full 2D canvas and returns the concatenated RGB byte string expected by both hardware surfaces:
const encoded = encodeCanvasForLed(canvas);window.wpPlugins?.led?.setAllDevicesByImageData( encoded, canvas.width, canvas.height,);For every pixel, the output contains three code points in row-major order:
canvas RGBA bytes: R G B A | R G B A | …encoded string: R G B | R G B | …Alpha is discarded. The result length is canvas.width * canvas.height * 3. The helper allocates the browser’s ImageData and builds a new string, so use a small canvas such as 100×20 rather than the full wallpaper frame.
Both dimensions must be at least 2 pixels when sending the result to the native
LED APIs. The simulator rejects smaller frames with RangeError.
If canvas.getContext('2d') returns null, the helper throws Error('Could not get 2D context from canvas'). Errors from getImageData(), including a tainted canvas, propagate.
Wait for hardware readiness
Section titled “Wait for hardware readiness”Do not call hardware APIs before the host reports their plugin:
window.wallpaperPluginListener = { onPluginLoaded(name) { if (name === 'led') { sendGeneralLedFrame(); } if (name === 'cue') { sendAdvancedCueFrame(); } },};Use window.wpPlugins.led.setAllDevicesByImageData() for general RGB hardware. Use window.cue.setLedColorsByImageData() only after the cue plugin loads and direct Corsair iCUE access is required. The helper only encodes bytes; it does not check readiness or send data.
The container and plugin APIs are optional in the type declarations. Guard window.wpPlugins?.led or window.cue when sending; the plugin-name callback alone does not narrow an unrelated global property for TypeScript.
Frame limiting
Section titled “Frame limiting”createFpsLimiter(draw) owns one requestAnimationFrame chain and passes elapsed seconds to each allowed draw:
const loop = createFpsLimiter((dt) => { updateSimulation(dt); renderFrame();});
window.wallpaperPropertyListener = { applyGeneralProperties(properties) { if (properties.fps !== undefined) { loop.setLimit(properties.fps); } }, setPaused(paused) { if (paused) { loop.stop(); } else { loop.start(); } },};
loop.start();Lifecycle
Section titled “Lifecycle”| Method | Behavior |
|---|---|
start() |
Cancels an existing scheduled frame, resets timing and the cap accumulator, then schedules a fresh frame |
stop() |
Cancels the scheduled frame and becomes a no-op when already stopped |
setLimit(fps) |
Updates the cap for the next frame; changing the value resets accumulated threshold time |
A limit greater than 0 caps drawing; 0 is unlimited. Negative limits throw
RangeError, and non-finite limits throw TypeError without changing the active
cap.
Elapsed time and stalls
Section titled “Elapsed time and stalls”dtis seconds since the last allowed draw, clamped to 0–1.- Backward or duplicate timestamps therefore produce
0, not a negative step. - Long background-tab stalls produce at most
1second of simulation progress on the next draw, avoiding a spiral of death. - Under a cap, elapsed tick time accumulates until a frame duration is reached; the remainder is retained to reduce drift.
- Restarting after pause resets both timing baselines, so paused wall-clock time is not delivered as
dt.
The limiter controls draw frequency, not browser animation-frame scheduling. It maintains one RAF callback while running and skips draw calls that arrive before the cap threshold.
Related audio and media helpers
Section titled “Related audio and media helpers”Use the dedicated Audio guide for clampAudio(), leftChannel(), and rightChannel(). Use the Media guide for getMediaPlaybackStatus(). Those pages include the host callbacks that make the helpers meaningful.
Source
Section titled “Source”All functions on this page are implemented in src/helpers.ts.
Next steps
Section titled “Next steps”Connect the simulator’s Runtime tab in Development Simulation and check exact signatures in Helpers API.