CORSAIR Wallpaper Engine docs Skip to content

Web wallpaper iCUE integration

In this guide you'll learn how to add iCUE integration to your web wallpaper.

Wallpaper Engine supports all CORSAIR devices supported by the official iCUE SDK, ranging from keyboards to LED strips. With the help this guide and your own HTML/JavaScript experience you can fully sync up a CORSAIR-based lighting setup with your wallpaper.

Note: When viewing the code examples, be sure to read the comment lines in the code for extra explaination. The full resulting wallpaper will be provided at the end of the guide.

1. Prerequisites

  • This tutorial requires knowledge about HTML, JavaScript and JSON. If you have never made a web wallpaper before, check out the starter tutorial for web wallpapers here: Creating an HTML web wallpaper
  • For testing purposes you need one or more CORSAIR iCUE enabled products
  • Make sure you are running the latest version of iCUE
  • Review the iCUE SDK manual, Wallpaper Engine acts as a bridge between your web wallpaper and this SDK

Note

Although the regular iCUE SDK is made for C++, you don't need any C++ knowledge to follow this guide, in Wallpaper Engine the SDK is available through JavaScript.

2. Detect LED support in your wallpaper

If it is available, Wallpaper Engine will detect and initialize the iCUE integration. When this happens and event will fire in your wallpaper. To use iCUE we need a listener for this event:

var icueAvailable = false;

window.wallpaperPluginListener = {
    onPluginLoaded: function (name, version) {
        if (name === 'cue') {
            icueAvailable = true;
        }
    }
};

With this code we'll know that if icueAvailable is true, it's ok to use the rest of the iCUE integration. All iCUE functionality will be available in the window.cue variable.

3. Detecting iCUE supported devices

Now that iCUE is available, we want to know what kind of devices are available on the system. This is done by asking Wallpaper Engine how many devices are detected and following it up by requesting info on each detected device.

function setupDevices() {
    if (!icueAvailable) {
        return;
    }

    icueDevices = [];
    // Ask for the total amount of devices
    window.cue.getDeviceCount(function (deviceCount) {
        for (var d = 0; d < deviceCount; ++d) {
            (function (d) {
                // Get device info on each device
                window.cue.getDeviceInfo(d, function (deviceInfo) {
                    // Put the ID on the device, useful later on
                    deviceInfo.id = d;
                    // Store all our devices in an array
                    icueDevices.push(deviceInfo);
                });
            }(d));
        }
    });
}

You must call the setupDevices function yourself after you've set icueAvailable to true. A good place to do this is in the wallpaperPluginListener callback we made in the last example.

4. Per-LED lighting

With the devices detected it's now possible to get all available LEDs on the device. In the case of a keyboard there's a LED for each key. To demonstrate this we'll loop through all LEDs on the keyboard (this guide assumes you have one, you can also swap it out for a different device).

First let's define some variables we'll need each frame and create a render loop that updates the keyboard 30 times per second

var ledIndex = 0;
var colorIndex = 0;
var colors = [
    {r: 255, g: 0, b: 0},
    {r: 0, g: 255, b: 0},
    {r: 0, g: 0, b: 255},
];

function onTimerTick() {
    // Everything here is called 30 times per second this is where our LED logic will take place

    // At the end of the frame, update the variables for the next frame, fiurst advance our LED index
    ledIndex++;
    if (ledIndex > keyboard.ledPositions.length - 1) {
        // Start over and advance our color index when all LEDs are colored
        ledIndex = 0;
        colorIndex++;
        if (colorIndex > 2) {
            colorIndex = 0;
        }
    }
}

// Run at 30 frames per second
setInterval(onTimerTick, 1000 / 30);

To keep things simple we'll do all the work each frame, this isn't the most optimized solution but works well for this guide.

Each frame our script must run through the following steps:

  1. Find the keyboard's device ID
  2. Make sure the keyboard's LEDs are retrieved, if they aren't, retrieve them now and skip the frame
  3. Assign the color to the current LED, for this sample we'll loop through red, then green and finally blue
  4. Update the LED index, so the next frame repeats steps 1-4 for the next LED
  5. If all LEDs have been updated, move to the next color and start at the first LED again

4.1. Retrieving the keyboard

The first step is retrieving the keyboard. The following code will find the first device of type CTD_Keyboard. If none is found the current frame is skipped.

// Find the keyboard, it's type is CDT_Keyboard as described in the SDK manual
var keyboard = null;
icueDevices.forEach(function (device) {
    if (device.type === 'CDT_Keyboard') {
        keyboard = device;
    }
});
// If no keyboard is found, stop for now, iCUE is not ready yet.
if (!keyboard) {
    return;
}

4.2. Retrieving the keyboard's LEDs

Before we can assign the keyboard's LEDs new colors, they must be retrieved first. Since retrieving them might take a while the current frame is skipped once again.

// If there are no LED positions, get them first!
if (!keyboard.ledPositions) {
    window.cue.getLedPositionsByDeviceIndex(keyboard.id, function (ledPositions) {
        keyboard.ledPositions = ledPositions;
    });
    return;
}

4.3. Updating the color of the current LED

Now it's time to assign a color to the current LED. Since each frame updates the LED index we'll be changing a different LED every frame. The color stays the same untill all LEDs are updated.

Note: By passing more than one LED update object to window.cue.setLedsColorsAsync you can update multiple LEDs in a high-performance way.

var color = colors[colorIndex];
var ledUpdate = {ledId: keyboard.ledPositions[ledIndex].ledId, r: color.r, g: color.g, b: color.b};
// You can send more than one LED update at once, in this example we'll stick to just one however
window.cue.setLedsColorsAsync([ledUpdate]);

When you've followed all these steps you should see your keyboard change key-by-key from black to red, from red to green and finally from green to blue.

5. Sending a canvas

As an alternative to controlling devices LED-by-LED it's possible to send an entire image to the device in the form of a canvas. There are a few pros and cons to this approach:

Pros

  • You can reuse existing canvas draw-code
  • If can use JavaScript's canvas API for easy shape drawing
  • You don't have to worry about LED positions, it's all taken care of for you

Cons

  • The canvas must be very small or performance will take a hit
  • You lose the ability to precisely color specific LEDs
  • To draw different things to different devices you need multiple canvases

To demonstrate canvas drawing we'll once again draw to a keyboard. Keyboards have the most LEDs so we can treat the keyboard like a little display. In this example we'll drawl a circle and slide it from left to right, changing it's color every time the circle reaches the end of the canvas.

We'll once again set up a render loop like so:

var circlePosition = 0;
var colorIndex = 0;
var colors = [
    {r: 255, g: 0, b: 0},
    {r: 0, g: 255, b: 0},
    {r: 0, g: 0, b: 255},
];

function onTimerTick() {
    // Everything here is called 30 times per second this is where our draw logic will take place

    // At the end of the frame, update the variables for the next frame, first advance our circle's position
    circlePosition++;
    if (circlePosition > 25) {
        // Start over and advance our color index when the circle has crossed the entire canvas
        circlePosition = 0;
        colorIndex++;
        if (colorIndex > 2) {
            colorIndex = 0;
        }
    }
}

// Run at 30 frames per second
setInterval(onTimerTick, 1000 / 30);

To keep things simple we'll do all the work each frame, this isn't the most optimized solution but works well for this guide.
Each frame our script must run through the following steps: 1. Find the keyboard's device ID 3. Draw the circle on our canvas 4. Convert the canvas to raw image data 5. Send the data to iCUE

5.1. Creating a canvas to draw to

A canvas is a DOM element which means it's usually represented in HTML and visible in the browser. In this case however we'll create the canvas in JavaScript before our render loop.

Warning

Note how it's only 25 pixels wide and 6 pixels high. This roughly represents the shape of a keyboard. Larger canvases don't necessarily look better and will cause Wallpaper Engine to use more CPU and RAM.

var canvas = document.createElement('canvas');
canvas.width = 25;
canvas.height = 6;

The code above will create a canvas element and set it's width and height.

Tip

When you've finished your wallpaper you can hide your canvas: canvas.style.display = 'none';.

5.2. Retrieving the keyboard

The first step is retrieving the keyboard. The following code will find the first device of type CTD_Keyboard. If none is found the current frame is skipped.

// Find the keyboard, it's type is CDT_Keyboard as described in the SDK manual
var keyboard = null;
icueDevices.forEach(function (device) {
    if (device.type === 'CDT_Keyboard') {
        keyboard = device;
    }
});
// If no keyboard is found, stop for now, iCUE is not ready yet.
if (!keyboard) {
    return;
}

5.3. Drawing to the canvas

The canvas we created is a regular HTML canvas and so we can use the JavaScript API to draw to it. There are plenty of resources on the internet about canvases but if you are unfamilliar with the concept, W3Schools is a good place to start.

Inside our render loop we'll draw the circle to the canvas each frame.

// Get the render context and clear the canvas
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);

// Set the color to our current color
var color = colors[colorIndex];
ctx.fillStyle = 'rgb(' + color.r + ', ' + color.g + ', ' + color.b + ')';

// Draw a circle at the current position
ctx.beginPath();
ctx.arc(3, circlePosition + 3, 6, 0, 2 * Math.PI);
ctx.fill();

5.4. Sending the canvas to the keyboard

With our canvas ready and in place it's time to send it to the keyboard. Doing so is a process that requires two steps.

Step 1. Encode the canvas to raw image data
This step turns the canvas into raw image Wallpaper Engine can understand. You can simply copy-paste this function into your code and reuse it whenever you want to convert a canvas.

function getEncodedCanvasImageData(canvas) {
    var context = canvas.getContext('2d');
    var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
    var colorArray = [];

    for (var d = 0; d < imageData.data.length; d += 4) {
        var write = d / 4 * 3;
        colorArray[write] = imageData.data[d];
        colorArray[write + 1] = imageData.data[d + 1];
        colorArray[write + 2] = imageData.data[d + 2];
    }
    return String.fromCharCode.apply(null, colorArray);
}

Step 2. Send the image data to one or more device
The second step is sending the newly converted image data to iCUE.

var encodedImageData = getEncodedCanvasImageData(canvas);
window.cue.setAllLedsColorsAsync([keyboard.id], encodedImageData, canvas.width, canvas.height);

Note

In this example we're just sending the canvas to the keyboard. You can send a canvas to multiple devices however. The more you reuse your canvas the better performance will be.

When you’ve followed all these steps you should see a circle slide across your keyboard from left to right, changing color each time it starts over.