Skip to content

Instantly share code, notes, and snippets.

@4Ply
Last active February 16, 2024 21:22
Show Gist options
  • Save 4Ply/f94e5be2756c50520db79bfe16b355e4 to your computer and use it in GitHub Desktop.
Save 4Ply/f94e5be2756c50520db79bfe16b355e4 to your computer and use it in GitHub Desktop.
{
"name": "rgb-controller",
"version": "1.0.0",
"description": "",
"main": "rgb.js",
"scripts": {
"start": "tsc wal.ts && node wal.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"nearest-color": "^0.4.4",
"openrgb": "^0.1.2",
"openrgb-sdk": "^0.3.1",
"sleep": "^6.3.0"
},
"devDependencies": {
"@babel/cli": "^7.12.13",
"@babel/core": "^7.12.13",
"@babel/node": "^7.12.13",
"@babel/preset-env": "^7.12.13",
"@types/node": "^14.14.25",
"@typescript-eslint/eslint-plugin": "^4.14.2",
"@typescript-eslint/parser": "^4.14.2",
"eslint": "^7.19.0",
"typescript": "^4.1.3"
}
}
#!/usr/bin/env bash
# I use nvm to manage the versions of nodejs installed locally, but if you have node > 14 instaled globally then you can replace `nvm exec 14 node` with just `node`
# Change working directory so that relative imports work from within wal.js
cd /some/path/here/rgb-controller
source /usr/share/nvm/init-nvm.sh
nvm exec 14 node wal.js

This script leverages Pywal and OpenRGB to sync the lighting of your devices (RAM, keyboard, mouse, fans, etc) to your wallpaper. See https://imgur.com/a/3Vq5SpJ for examples!

To use this script, you need to have OpenRGB (https://gitlab.com/CalcProgrammer1/OpenRGB) installed and running in server mode. Refer to the OpenRGB wiki for setup instructions as and for a list of supported devices.

openrgb --server --startminimized

Next, install https://github.com/dylanaraps/pywal which generates a colour palette from your wallpaper (this palette data is stored then in .cache/wal/colors.json and used by wal.js when configuring your RGB devices).

Finally, download run-wal.sh, package.json, and wal.ts to some location, which is from here on referred to as /some/path/here/rgb-controller/. You will need to transpile the included wal.ts file (TypeScript) to wal.js (JavaScript), which is usually done by running npm install && tsc wal.ts. You only need to do this once, but the initial setup may be tricky for those who are unfamilar with running JavaScript files. See https://www.typescriptlang.org/download to learn more.

Once wal.js exists; run the following to set a random wallpaper and then set all supported RGB components to a matching background colour: (You can just re-run this command above every time you want to rotate you wallpaper)

wal -i <path-to-wallpaper-folder> --saturate 0.7 -o /some/path/here/rgb-controller/run-wal.sh

That's it! Your devices should be synced to your wallpaper!

// This needs to be transpiled from Typescript to Javascript using tsc wal.ts
import { OpenRGBClient } from 'openrgb';
import { msleep } from 'sleep';
import { readFileSync } from 'fs';
import { homedir } from 'os';
import * as path from 'path';
import * as near from 'nearest-color';
// Source: https://stackoverflow.com/a/5624139/3614298
function hexToRgb(hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
return r + r + g + g + b + b;
});
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
const res = result ? {
red: parseInt(result[1], 16),
green: parseInt(result[2], 16),
blue: parseInt(result[3], 16)
} : null;
console.log(`HEX to RGB: ${hex} =>`, res);
return res;
}
const nearestPrimaryColor = (color) => {
const nearest = near.from(color);
console.log('Nearest primary color:', nearest);
return nearest;
};
const colorShade = (col, amt) => {
col = col.replace(/^#/, '')
if (col.length === 3) col = col[0] + col[0] + col[1] + col[1] + col[2] + col[2]
let [r, g, b] = col.match(/.{2}/g);
([r, g, b] = [parseInt(r, 16) + amt, parseInt(g, 16) + amt, parseInt(b, 16) + amt])
r = Math.max(Math.min(255, r), 0).toString(16)
g = Math.max(Math.min(255, g), 0).toString(16)
b = Math.max(Math.min(255, b), 0).toString(16)
const rr = (r.length < 2 ? '0' : '') + r
const gg = (g.length < 2 ? '0' : '') + g
const bb = (b.length < 2 ? '0' : '') + b
return `#${rr}${gg}${bb}`
}
const walColors = JSON.parse(readFileSync(path.join(homedir(), '.cache/wal/colors.json'), 'utf8'));
Object.keys(walColors.colors).forEach(c => hexToRgb(walColors.colors[c]))
const targetColor = hexToRgb(colorShade(walColors.colors.color12, -90))
declare global {
interface Array<T> {
set(string, any): Array<T>;
reset(): Array<T>;
setChar(char, any): Array<T>;
}
}
async function start() {
const client = new OpenRGBClient({
port: 6742,
host: "localhost",
name: "Wal.js",
});
await client.connect();
const controllerCount = await client.getControllerCount();
Array.prototype.set = function set(str, color = { red: 0x00, green: 0x00, blue: 0xFF}) {
for (let i = 0; i < str.length; i++) {
this.setChar(str[i], color);
}
return this;
};
Array.prototype.reset = function() {
this.fill(targetColor);
return this;
};
const tasks = [];
for (let deviceId = 0; deviceId < controllerCount; deviceId++) {
const device = await client.getDeviceController(deviceId);
console.log('Configuring device:', device.name);
const colors = Array(device.colors.length).reset();
msleep(200);
colors.reset();
tasks.push(client.updateLeds(deviceId, colors));
}
await Promise.all(tasks);
await client.disconnect();
}
start();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment