I believe the tonal palettes generated by Material Design 3 are created via the HCT color space. You may get something similar to what you ask for (changing luminance of a color) by modifing the (T)one value of a color in that space.
The following tests roundtrip conversion from an sRGB hex color code to HCT color space and back, and also modifies the resulting HCT values and converts those back to sRGB hex. (Doing the roundtrip conversion first is to demonstrate consistency of the return-trip value to the original without modifying the HCT values.) It uses the npm (nodejs-installable) library @material/material-color-utilities
(which uses HCT space). My angle on doing this is demonstrating from a script invoked from CLI. I hope it might be adaptable for your purposes.
DEPENDENCIES: nodejs and the material-color-utilities package installed, either locally (from a terminal, run) : npm install -g @material/material-color-utilities
-- or locally in a project folder you make: npm install @material/material-color-utilities
For this use case I had to override the package.json
of package/@material/material-color-utilities
(where it is installed) to look like this:
{
"dependencies": {
"@material/material-color-utilities": "^0.2.7",
"type": "module"
}
}
--adding that "type": "module"
line
-- and then save the following code to a file named (e.g.) sRGB_to_HCT_to_sRGB.mjs
NOTE: the file must have the .mjs
extension for this to work.*
file/code: sRGB_to_HCT_to_sRGB.mjs
:
import { Hct } from "@material/material-color-utilities"
// Hct.fromInt will accept a hex value in format a r g b (eg 0xff4285f4) OR just rgb (e.g. 4285f4) :
var originalValue = 0x8fe5b9
console.log("original sRGB values, hex format:\t", originalValue.toString(16))
var color = Hct.fromInt(originalValue)
console.log("HCT values:")
console.log("Hue:", color.hue)
console.log("Chroma:", color.chroma)
console.log("Tone:", color.tone)
var reconstructed = Hct.from(
color.hue,
color.chroma,
color.tone,
).toInt().toString(16).slice(2)
console.log("Reconstructed sRGB values, hex format:\t", reconstructed)
// MODIFYING VALUES IN HCT SPACE:
color.hue +=1
color.chroma += 2
color.tone += 3
console.log("\nModded HCT values:")
console.log("Hue:", color.hue)
console.log("Chroma:", color.chroma)
console.log("Tone:", color.tone)
// becomes after convert back to sRGB: 91efc1:
reconstructed = Hct.from(
color.hue,
color.chroma,
color.tone,
).toInt().toString(16).slice(2)
console.log("~Modded sRGB values, hex format:\t", reconstructed)
To run the code from e.g. a terminal, open a terminal to the path with the file, and run:
node sRGB_to_HCT_to_sRGB.mjs
Output:
original sRGB values, hex format: 8fe5b9
HCT values:
Hue: 164.34413232095446
Chroma: 41.27889003143768
Tone: 84.67970676233278
Reconstructed sRGB values, hex format: 8fe5b9
Modded HCT values:
Hue: 165.11479101939187
Chroma: 43.531612419379805
Tone: 87.77714825778628
~Modded sRGB values, hex format: 91efc1
Modification of values in HCT space would probably best be done within the min/max ranges allowed for (H)ue, (C)hroma, (T)one. Wherever there is reference about that. Looking that up is my next step for my project :)
Pieced together and adapted from:
*FEEDBACK TO THE NODEJS project: it is extremely janky to make it necessary to hack a package like that just to import a module for CLI use. You should re-introduce the CLI switch lovingly and carefully begged for by many developers for this purpose, and provide CLI feedback suggesting use of that switch if you detect a user may wish to. The research and hacking effort involved just to get it working (and figure out how to!) for this very common use case (CLI script) was very excessive. You made it way too difficult.