@xivdyetools/color-blending 1.0.0
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.
- package/README.md +100 -0
- package/dist/blending.d.ts +26 -0
- package/dist/blending.d.ts.map +1 -0
- package/dist/blending.js +143 -0
- package/dist/blending.js.map +1 -0
- package/dist/conversions.d.ts +43 -0
- package/dist/conversions.d.ts.map +1 -0
- package/dist/conversions.js +229 -0
- package/dist/conversions.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# @xivdyetools/color-blending
|
|
2
|
+
|
|
3
|
+
> Six color blending algorithms (RGB, LAB, OKLAB, RYB, HSL, Spectral/Kubelka-Munk) for the XIV Dye Tools ecosystem.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@xivdyetools/color-blending)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
`@xivdyetools/color-blending` provides six distinct color blending algorithms, each producing different results for the same pair of colors. Used by the Mixer command and gradient interpolation in XIV Dye Tools bots.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @xivdyetools/color-blending
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Blending Modes
|
|
19
|
+
|
|
20
|
+
| Mode | Name | Description |
|
|
21
|
+
|------|------|-------------|
|
|
22
|
+
| `rgb` | RGB | Simple additive channel averaging (default) |
|
|
23
|
+
| `lab` | LAB | Perceptually uniform CIELAB blending |
|
|
24
|
+
| `oklab` | OKLAB | Modern perceptual — fixes LAB's blue→purple issue |
|
|
25
|
+
| `ryb` | RYB | Traditional artist's color wheel (blue + yellow = green) |
|
|
26
|
+
| `hsl` | HSL | Hue-Saturation-Lightness interpolation |
|
|
27
|
+
| `spectral` | Spectral | Kubelka-Munk physics simulation (paint-like mixing) |
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { blendColors, BLENDING_MODES, isValidBlendingMode } from '@xivdyetools/color-blending';
|
|
33
|
+
|
|
34
|
+
// Blend two colors (equal 50/50 mix)
|
|
35
|
+
const result = blendColors('#FF0000', '#0000FF', 'oklab');
|
|
36
|
+
console.log(result.hex); // → '#C2007E' (perceptually balanced purple)
|
|
37
|
+
console.log(result.rgb); // → { r: 194, g: 0, b: 126 }
|
|
38
|
+
|
|
39
|
+
// Adjust blend ratio (0.0 = all first, 1.0 = all second)
|
|
40
|
+
const mostly_red = blendColors('#FF0000', '#0000FF', 'oklab', 0.25);
|
|
41
|
+
|
|
42
|
+
// Compare all modes
|
|
43
|
+
for (const mode of BLENDING_MODES) {
|
|
44
|
+
const blend = blendColors('#FF0000', '#FFFF00', mode.value);
|
|
45
|
+
console.log(`${mode.name}: ${blend.hex} — ${mode.description}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Validate user input
|
|
49
|
+
if (isValidBlendingMode(userInput)) {
|
|
50
|
+
const result = blendColors(color1, color2, userInput);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Why Different Modes Produce Different Results
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
Red (#FF0000) + Blue (#0000FF):
|
|
58
|
+
RGB: #7F007F (dark purple — channel averaging)
|
|
59
|
+
LAB: #CA0088 (magenta — perceptual, but blue bias)
|
|
60
|
+
OKLAB: #C2007E (magenta — perceptual, corrected)
|
|
61
|
+
RYB: #800080 (purple — artist color wheel)
|
|
62
|
+
HSL: #FF00FF (bright magenta — hue rotation)
|
|
63
|
+
Spectral: #6A1B9A (deep purple — physics-based paint mixing)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## API
|
|
67
|
+
|
|
68
|
+
### Core
|
|
69
|
+
|
|
70
|
+
- `blendColors(hex1, hex2, mode, ratio?)` — Blend two colors. Returns `BlendResult` (`{ hex, rgb }`).
|
|
71
|
+
- `getBlendingModeDescription(mode)` — Returns human-readable description for a mode.
|
|
72
|
+
|
|
73
|
+
### Validation
|
|
74
|
+
|
|
75
|
+
- `isValidBlendingMode(mode)` — Type guard: checks if a string is a valid `BlendingMode`.
|
|
76
|
+
- `BLENDING_MODES` — Array of `{ value, name, description }` for all modes.
|
|
77
|
+
|
|
78
|
+
### Color Conversions
|
|
79
|
+
|
|
80
|
+
- `rgbToLab(rgb)` — Convert RGB to CIELAB color space.
|
|
81
|
+
|
|
82
|
+
### Types
|
|
83
|
+
|
|
84
|
+
| Type | Description |
|
|
85
|
+
|------|-------------|
|
|
86
|
+
| `BlendingMode` | `'rgb' \| 'lab' \| 'oklab' \| 'ryb' \| 'hsl' \| 'spectral'` |
|
|
87
|
+
| `BlendResult` | `{ hex: string; rgb: RGB }` |
|
|
88
|
+
| `RGB` | `{ r: number; g: number; b: number }` (0–255) |
|
|
89
|
+
| `LAB` | `{ l: number; a: number; b: number }` (CIELAB) |
|
|
90
|
+
| `HSL` | `{ h: number; s: number; l: number }` (0–360, 0–1, 0–1) |
|
|
91
|
+
|
|
92
|
+
## Dependencies
|
|
93
|
+
|
|
94
|
+
| Package | Purpose |
|
|
95
|
+
|---------|---------|
|
|
96
|
+
| `@xivdyetools/core` | `ColorService` for hex↔RGB conversions |
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
MIT
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color Blending — Six algorithms for mixing two colors.
|
|
3
|
+
*
|
|
4
|
+
* Blending Modes:
|
|
5
|
+
* - RGB: Simple additive channel averaging
|
|
6
|
+
* - LAB: Perceptually uniform CIELAB blending
|
|
7
|
+
* - OKLAB: Modern perceptual (fixes LAB blue→purple issue)
|
|
8
|
+
* - RYB: Traditional artist's color wheel
|
|
9
|
+
* - HSL: Hue-Saturation-Lightness interpolation
|
|
10
|
+
* - Spectral: Kubelka-Munk physics simulation
|
|
11
|
+
*/
|
|
12
|
+
import type { BlendResult, BlendingMode } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Blend two colors using the specified blending mode.
|
|
15
|
+
*
|
|
16
|
+
* @param hex1 - First color hex code (with or without #)
|
|
17
|
+
* @param hex2 - Second color hex code (with or without #)
|
|
18
|
+
* @param mode - Blending algorithm to use
|
|
19
|
+
* @param ratio - 0.0 = all hex1, 0.5 = equal mix, 1.0 = all hex2
|
|
20
|
+
*/
|
|
21
|
+
export declare function blendColors(hex1: string, hex2: string, mode: BlendingMode, ratio?: number): BlendResult;
|
|
22
|
+
/**
|
|
23
|
+
* Get a human-readable description of a blending mode.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getBlendingModeDescription(mode: BlendingMode): string;
|
|
26
|
+
//# sourceMappingURL=blending.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blending.d.ts","sourceRoot":"","sources":["../src/blending.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAiB,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAqB3E;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,YAAY,EAClB,KAAK,GAAE,MAAY,GAClB,WAAW,CAkCb;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAUrE"}
|
package/dist/blending.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color Blending — Six algorithms for mixing two colors.
|
|
3
|
+
*
|
|
4
|
+
* Blending Modes:
|
|
5
|
+
* - RGB: Simple additive channel averaging
|
|
6
|
+
* - LAB: Perceptually uniform CIELAB blending
|
|
7
|
+
* - OKLAB: Modern perceptual (fixes LAB blue→purple issue)
|
|
8
|
+
* - RYB: Traditional artist's color wheel
|
|
9
|
+
* - HSL: Hue-Saturation-Lightness interpolation
|
|
10
|
+
* - Spectral: Kubelka-Munk physics simulation
|
|
11
|
+
*/
|
|
12
|
+
import { ColorService } from '@xivdyetools/core';
|
|
13
|
+
import { rgbToLab, labToRgb, rgbToOklab, oklabToRgb, rgbToRyb, rybToRgb, rgbToHsl, hslToRgb, rgbToReflectance, reflectanceToRgb, reflectanceToKS, ksToReflectance, rgbToHex, } from './conversions.js';
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// Public API
|
|
16
|
+
// ============================================================================
|
|
17
|
+
/**
|
|
18
|
+
* Blend two colors using the specified blending mode.
|
|
19
|
+
*
|
|
20
|
+
* @param hex1 - First color hex code (with or without #)
|
|
21
|
+
* @param hex2 - Second color hex code (with or without #)
|
|
22
|
+
* @param mode - Blending algorithm to use
|
|
23
|
+
* @param ratio - 0.0 = all hex1, 0.5 = equal mix, 1.0 = all hex2
|
|
24
|
+
*/
|
|
25
|
+
export function blendColors(hex1, hex2, mode, ratio = 0.5) {
|
|
26
|
+
const h1 = hex1.startsWith('#') ? hex1 : `#${hex1}`;
|
|
27
|
+
const h2 = hex2.startsWith('#') ? hex2 : `#${hex2}`;
|
|
28
|
+
const t = Math.max(0, Math.min(1, ratio));
|
|
29
|
+
const rgb1 = ColorService.hexToRgb(h1);
|
|
30
|
+
const rgb2 = ColorService.hexToRgb(h2);
|
|
31
|
+
let blendedRgb;
|
|
32
|
+
switch (mode) {
|
|
33
|
+
case 'rgb':
|
|
34
|
+
blendedRgb = blendRGB(rgb1, rgb2, t);
|
|
35
|
+
break;
|
|
36
|
+
case 'lab':
|
|
37
|
+
blendedRgb = blendLAB(rgb1, rgb2, t);
|
|
38
|
+
break;
|
|
39
|
+
case 'oklab':
|
|
40
|
+
blendedRgb = blendOKLAB(rgb1, rgb2, t);
|
|
41
|
+
break;
|
|
42
|
+
case 'ryb':
|
|
43
|
+
blendedRgb = blendRYB(rgb1, rgb2, t);
|
|
44
|
+
break;
|
|
45
|
+
case 'hsl':
|
|
46
|
+
blendedRgb = blendHSL(rgb1, rgb2, t);
|
|
47
|
+
break;
|
|
48
|
+
case 'spectral':
|
|
49
|
+
blendedRgb = blendSpectral(rgb1, rgb2, t);
|
|
50
|
+
break;
|
|
51
|
+
default:
|
|
52
|
+
blendedRgb = blendRGB(rgb1, rgb2, t);
|
|
53
|
+
}
|
|
54
|
+
return { hex: rgbToHex(blendedRgb), rgb: blendedRgb };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get a human-readable description of a blending mode.
|
|
58
|
+
*/
|
|
59
|
+
export function getBlendingModeDescription(mode) {
|
|
60
|
+
const descriptions = {
|
|
61
|
+
rgb: 'Simple additive channel averaging',
|
|
62
|
+
lab: 'Perceptually uniform CIELAB blending',
|
|
63
|
+
oklab: 'Modern perceptual (fixes LAB blue→purple)',
|
|
64
|
+
ryb: "Traditional artist's color wheel",
|
|
65
|
+
hsl: 'Hue-Saturation-Lightness interpolation',
|
|
66
|
+
spectral: 'Kubelka-Munk pigment simulation',
|
|
67
|
+
};
|
|
68
|
+
return descriptions[mode];
|
|
69
|
+
}
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// Blend Implementations
|
|
72
|
+
// ============================================================================
|
|
73
|
+
function blendRGB(rgb1, rgb2, t) {
|
|
74
|
+
return {
|
|
75
|
+
r: Math.round(rgb1.r * (1 - t) + rgb2.r * t),
|
|
76
|
+
g: Math.round(rgb1.g * (1 - t) + rgb2.g * t),
|
|
77
|
+
b: Math.round(rgb1.b * (1 - t) + rgb2.b * t),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function blendLAB(rgb1, rgb2, t) {
|
|
81
|
+
const lab1 = rgbToLab(rgb1);
|
|
82
|
+
const lab2 = rgbToLab(rgb2);
|
|
83
|
+
const blended = {
|
|
84
|
+
l: lab1.l * (1 - t) + lab2.l * t,
|
|
85
|
+
a: lab1.a * (1 - t) + lab2.a * t,
|
|
86
|
+
b: lab1.b * (1 - t) + lab2.b * t,
|
|
87
|
+
};
|
|
88
|
+
return labToRgb(blended);
|
|
89
|
+
}
|
|
90
|
+
function blendOKLAB(rgb1, rgb2, t) {
|
|
91
|
+
const ok1 = rgbToOklab(rgb1);
|
|
92
|
+
const ok2 = rgbToOklab(rgb2);
|
|
93
|
+
return oklabToRgb({
|
|
94
|
+
L: ok1.L * (1 - t) + ok2.L * t,
|
|
95
|
+
a: ok1.a * (1 - t) + ok2.a * t,
|
|
96
|
+
b: ok1.b * (1 - t) + ok2.b * t,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function blendRYB(rgb1, rgb2, t) {
|
|
100
|
+
const ryb1 = rgbToRyb(rgb1);
|
|
101
|
+
const ryb2 = rgbToRyb(rgb2);
|
|
102
|
+
return rybToRgb({
|
|
103
|
+
r: ryb1.r * (1 - t) + ryb2.r * t,
|
|
104
|
+
y: ryb1.y * (1 - t) + ryb2.y * t,
|
|
105
|
+
b: ryb1.b * (1 - t) + ryb2.b * t,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function blendHSL(rgb1, rgb2, t) {
|
|
109
|
+
const hsl1 = rgbToHsl(rgb1);
|
|
110
|
+
const hsl2 = rgbToHsl(rgb2);
|
|
111
|
+
// Shortest-arc hue interpolation
|
|
112
|
+
let hueDiff = hsl2.h - hsl1.h;
|
|
113
|
+
if (hueDiff > 180)
|
|
114
|
+
hueDiff -= 360;
|
|
115
|
+
if (hueDiff < -180)
|
|
116
|
+
hueDiff += 360;
|
|
117
|
+
let blendedH = hsl1.h + hueDiff * t;
|
|
118
|
+
if (blendedH < 0)
|
|
119
|
+
blendedH += 360;
|
|
120
|
+
if (blendedH >= 360)
|
|
121
|
+
blendedH -= 360;
|
|
122
|
+
const blended = {
|
|
123
|
+
h: blendedH,
|
|
124
|
+
s: hsl1.s * (1 - t) + hsl2.s * t,
|
|
125
|
+
l: hsl1.l * (1 - t) + hsl2.l * t,
|
|
126
|
+
};
|
|
127
|
+
return hslToRgb(blended);
|
|
128
|
+
}
|
|
129
|
+
function blendSpectral(rgb1, rgb2, t) {
|
|
130
|
+
const ref1 = rgbToReflectance(rgb1);
|
|
131
|
+
const ref2 = rgbToReflectance(rgb2);
|
|
132
|
+
return reflectanceToRgb({
|
|
133
|
+
r: kubelkaMunkMix(ref1.r, ref2.r, t),
|
|
134
|
+
g: kubelkaMunkMix(ref1.g, ref2.g, t),
|
|
135
|
+
b: kubelkaMunkMix(ref1.b, ref2.b, t),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
function kubelkaMunkMix(r1, r2, t) {
|
|
139
|
+
const ks1 = reflectanceToKS(r1);
|
|
140
|
+
const ks2 = reflectanceToKS(r2);
|
|
141
|
+
return ksToReflectance(ks1 * (1 - t) + ks2 * t);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=blending.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blending.js","sourceRoot":"","sources":["../src/blending.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { RGB, LAB, HSL } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* RGB to CIELAB conversion.
|
|
4
|
+
* Exported for use in SVG generators that display LAB values.
|
|
5
|
+
*/
|
|
6
|
+
export declare function rgbToLab(rgb: RGB): LAB;
|
|
7
|
+
export declare function labToRgb(lab: LAB): RGB;
|
|
8
|
+
export declare function rgbToOklab(rgb: RGB): {
|
|
9
|
+
L: number;
|
|
10
|
+
a: number;
|
|
11
|
+
b: number;
|
|
12
|
+
};
|
|
13
|
+
export declare function oklabToRgb(oklab: {
|
|
14
|
+
L: number;
|
|
15
|
+
a: number;
|
|
16
|
+
b: number;
|
|
17
|
+
}): RGB;
|
|
18
|
+
export declare function rgbToRyb(rgb: RGB): {
|
|
19
|
+
r: number;
|
|
20
|
+
y: number;
|
|
21
|
+
b: number;
|
|
22
|
+
};
|
|
23
|
+
export declare function rybToRgb(ryb: {
|
|
24
|
+
r: number;
|
|
25
|
+
y: number;
|
|
26
|
+
b: number;
|
|
27
|
+
}): RGB;
|
|
28
|
+
export declare function rgbToHsl(rgb: RGB): HSL;
|
|
29
|
+
export declare function hslToRgb(hsl: HSL): RGB;
|
|
30
|
+
export declare function rgbToReflectance(rgb: RGB): {
|
|
31
|
+
r: number;
|
|
32
|
+
g: number;
|
|
33
|
+
b: number;
|
|
34
|
+
};
|
|
35
|
+
export declare function reflectanceToRgb(ref: {
|
|
36
|
+
r: number;
|
|
37
|
+
g: number;
|
|
38
|
+
b: number;
|
|
39
|
+
}): RGB;
|
|
40
|
+
export declare function reflectanceToKS(r: number): number;
|
|
41
|
+
export declare function ksToReflectance(ks: number): number;
|
|
42
|
+
export declare function rgbToHex(rgb: RGB): string;
|
|
43
|
+
//# sourceMappingURL=conversions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversions.d.ts","sourceRoot":"","sources":["../src/conversions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAMhD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CAyBtC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CA8BtC;AAMD,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBxE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,GAAG,CAuB1E;AAMD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBtE;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,GAAG,CA0BtE;AAMD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CA8BtC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CA2BtC;AAMD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAE9E;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,GAAG,CAM9E;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAGlD;AAMD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAGzC"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// CIELAB (D65 illuminant)
|
|
3
|
+
// ============================================================================
|
|
4
|
+
/**
|
|
5
|
+
* RGB to CIELAB conversion.
|
|
6
|
+
* Exported for use in SVG generators that display LAB values.
|
|
7
|
+
*/
|
|
8
|
+
export function rgbToLab(rgb) {
|
|
9
|
+
let r = rgb.r / 255;
|
|
10
|
+
let g = rgb.g / 255;
|
|
11
|
+
let b = rgb.b / 255;
|
|
12
|
+
// sRGB to linear
|
|
13
|
+
r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
|
|
14
|
+
g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
|
|
15
|
+
b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
|
|
16
|
+
// Convert to XYZ (D65 illuminant)
|
|
17
|
+
let x = (r * 0.4124564 + g * 0.3575761 + b * 0.1804375) / 0.95047;
|
|
18
|
+
let y = r * 0.2126729 + g * 0.7151522 + b * 0.072175;
|
|
19
|
+
let z = (r * 0.0193339 + g * 0.119192 + b * 0.9503041) / 1.08883;
|
|
20
|
+
// XYZ to LAB
|
|
21
|
+
x = x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787 * x + 16 / 116;
|
|
22
|
+
y = y > 0.008856 ? Math.pow(y, 1 / 3) : 7.787 * y + 16 / 116;
|
|
23
|
+
z = z > 0.008856 ? Math.pow(z, 1 / 3) : 7.787 * z + 16 / 116;
|
|
24
|
+
return {
|
|
25
|
+
l: 116 * y - 16,
|
|
26
|
+
a: 500 * (x - y),
|
|
27
|
+
b: 200 * (y - z),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function labToRgb(lab) {
|
|
31
|
+
let y = (lab.l + 16) / 116;
|
|
32
|
+
let x = lab.a / 500 + y;
|
|
33
|
+
let z = y - lab.b / 200;
|
|
34
|
+
const y3 = y * y * y;
|
|
35
|
+
const x3 = x * x * x;
|
|
36
|
+
const z3 = z * z * z;
|
|
37
|
+
y = y3 > 0.008856 ? y3 : (y - 16 / 116) / 7.787;
|
|
38
|
+
x = x3 > 0.008856 ? x3 : (x - 16 / 116) / 7.787;
|
|
39
|
+
z = z3 > 0.008856 ? z3 : (z - 16 / 116) / 7.787;
|
|
40
|
+
x *= 0.95047;
|
|
41
|
+
z *= 1.08883;
|
|
42
|
+
let r = x * 3.2404542 + y * -1.5371385 + z * -0.4985314;
|
|
43
|
+
let g = x * -0.969266 + y * 1.8760108 + z * 0.041556;
|
|
44
|
+
let b = x * 0.0556434 + y * -0.2040259 + z * 1.0572252;
|
|
45
|
+
// Linear to sRGB
|
|
46
|
+
r = r > 0.0031308 ? 1.055 * Math.pow(r, 1 / 2.4) - 0.055 : 12.92 * r;
|
|
47
|
+
g = g > 0.0031308 ? 1.055 * Math.pow(g, 1 / 2.4) - 0.055 : 12.92 * g;
|
|
48
|
+
b = b > 0.0031308 ? 1.055 * Math.pow(b, 1 / 2.4) - 0.055 : 12.92 * b;
|
|
49
|
+
return {
|
|
50
|
+
r: Math.round(Math.max(0, Math.min(255, r * 255))),
|
|
51
|
+
g: Math.round(Math.max(0, Math.min(255, g * 255))),
|
|
52
|
+
b: Math.round(Math.max(0, Math.min(255, b * 255))),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// ============================================================================
|
|
56
|
+
// OKLAB (Björn Ottosson, 2020)
|
|
57
|
+
// ============================================================================
|
|
58
|
+
export function rgbToOklab(rgb) {
|
|
59
|
+
let r = rgb.r / 255;
|
|
60
|
+
let g = rgb.g / 255;
|
|
61
|
+
let b = rgb.b / 255;
|
|
62
|
+
// sRGB to linear
|
|
63
|
+
r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
|
|
64
|
+
g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
|
|
65
|
+
b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
|
|
66
|
+
// Linear RGB to LMS
|
|
67
|
+
const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
|
|
68
|
+
const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
|
|
69
|
+
const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
|
|
70
|
+
const l_ = Math.cbrt(l);
|
|
71
|
+
const m_ = Math.cbrt(m);
|
|
72
|
+
const s_ = Math.cbrt(s);
|
|
73
|
+
return {
|
|
74
|
+
L: 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,
|
|
75
|
+
a: 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,
|
|
76
|
+
b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export function oklabToRgb(oklab) {
|
|
80
|
+
const l_ = oklab.L + 0.3963377774 * oklab.a + 0.2158037573 * oklab.b;
|
|
81
|
+
const m_ = oklab.L - 0.1055613458 * oklab.a - 0.0638541728 * oklab.b;
|
|
82
|
+
const s_ = oklab.L - 0.0894841775 * oklab.a - 1.291485548 * oklab.b;
|
|
83
|
+
const l = l_ * l_ * l_;
|
|
84
|
+
const m = m_ * m_ * m_;
|
|
85
|
+
const s = s_ * s_ * s_;
|
|
86
|
+
let r = +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
|
|
87
|
+
let g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
|
|
88
|
+
let b = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;
|
|
89
|
+
// Linear to sRGB
|
|
90
|
+
r = r > 0.0031308 ? 1.055 * Math.pow(r, 1 / 2.4) - 0.055 : 12.92 * r;
|
|
91
|
+
g = g > 0.0031308 ? 1.055 * Math.pow(g, 1 / 2.4) - 0.055 : 12.92 * g;
|
|
92
|
+
b = b > 0.0031308 ? 1.055 * Math.pow(b, 1 / 2.4) - 0.055 : 12.92 * b;
|
|
93
|
+
return {
|
|
94
|
+
r: Math.round(Math.max(0, Math.min(255, r * 255))),
|
|
95
|
+
g: Math.round(Math.max(0, Math.min(255, g * 255))),
|
|
96
|
+
b: Math.round(Math.max(0, Math.min(255, b * 255))),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// RYB (Red-Yellow-Blue, approximate)
|
|
101
|
+
// ============================================================================
|
|
102
|
+
export function rgbToRyb(rgb) {
|
|
103
|
+
const r = rgb.r / 255;
|
|
104
|
+
const g = rgb.g / 255;
|
|
105
|
+
const b = rgb.b / 255;
|
|
106
|
+
const w = Math.min(r, g, b);
|
|
107
|
+
const r_ = r - w;
|
|
108
|
+
const g_ = g - w;
|
|
109
|
+
const b_ = b - w;
|
|
110
|
+
const mg = Math.max(r_, g_, b_);
|
|
111
|
+
const y = Math.min(r_, g_);
|
|
112
|
+
const r__ = r_ - y;
|
|
113
|
+
const b__ = (b_ + (g_ - y)) / 2;
|
|
114
|
+
const n = Math.max(r__, y, b__) / Math.max(mg, 0.001);
|
|
115
|
+
return {
|
|
116
|
+
r: r__ / Math.max(n, 0.001) + w,
|
|
117
|
+
y: y / Math.max(n, 0.001) + w,
|
|
118
|
+
b: b__ / Math.max(n, 0.001) + w,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export function rybToRgb(ryb) {
|
|
122
|
+
const r = ryb.r;
|
|
123
|
+
const y = ryb.y;
|
|
124
|
+
const b = ryb.b;
|
|
125
|
+
const w = Math.min(r, y, b);
|
|
126
|
+
const r_ = r - w;
|
|
127
|
+
const y_ = y - w;
|
|
128
|
+
const b_ = b - w;
|
|
129
|
+
const my = Math.max(r_, y_, b_);
|
|
130
|
+
let g = Math.min(y_, b_);
|
|
131
|
+
const y__ = y_ - g;
|
|
132
|
+
const b__ = b_ - g;
|
|
133
|
+
const r__ = r_ + y__;
|
|
134
|
+
g = g + y__;
|
|
135
|
+
const n = Math.max(r__, g, b__) / Math.max(my, 0.001);
|
|
136
|
+
return {
|
|
137
|
+
r: Math.round(Math.max(0, Math.min(255, (r__ / Math.max(n, 0.001) + w) * 255))),
|
|
138
|
+
g: Math.round(Math.max(0, Math.min(255, (g / Math.max(n, 0.001) + w) * 255))),
|
|
139
|
+
b: Math.round(Math.max(0, Math.min(255, (b__ / Math.max(n, 0.001) + w) * 255))),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// ============================================================================
|
|
143
|
+
// HSL
|
|
144
|
+
// ============================================================================
|
|
145
|
+
export function rgbToHsl(rgb) {
|
|
146
|
+
const r = rgb.r / 255;
|
|
147
|
+
const g = rgb.g / 255;
|
|
148
|
+
const b = rgb.b / 255;
|
|
149
|
+
const max = Math.max(r, g, b);
|
|
150
|
+
const min = Math.min(r, g, b);
|
|
151
|
+
const l = (max + min) / 2;
|
|
152
|
+
if (max === min) {
|
|
153
|
+
return { h: 0, s: 0, l };
|
|
154
|
+
}
|
|
155
|
+
const d = max - min;
|
|
156
|
+
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
157
|
+
let h = 0;
|
|
158
|
+
switch (max) {
|
|
159
|
+
case r:
|
|
160
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
161
|
+
break;
|
|
162
|
+
case g:
|
|
163
|
+
h = ((b - r) / d + 2) / 6;
|
|
164
|
+
break;
|
|
165
|
+
case b:
|
|
166
|
+
h = ((r - g) / d + 4) / 6;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
return { h: h * 360, s, l };
|
|
170
|
+
}
|
|
171
|
+
export function hslToRgb(hsl) {
|
|
172
|
+
const h = hsl.h / 360;
|
|
173
|
+
const s = hsl.s;
|
|
174
|
+
const l = hsl.l;
|
|
175
|
+
if (s === 0) {
|
|
176
|
+
const v = Math.round(l * 255);
|
|
177
|
+
return { r: v, g: v, b: v };
|
|
178
|
+
}
|
|
179
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
180
|
+
const p = 2 * l - q;
|
|
181
|
+
const hue2rgb = (p, q, t) => {
|
|
182
|
+
if (t < 0)
|
|
183
|
+
t += 1;
|
|
184
|
+
if (t > 1)
|
|
185
|
+
t -= 1;
|
|
186
|
+
if (t < 1 / 6)
|
|
187
|
+
return p + (q - p) * 6 * t;
|
|
188
|
+
if (t < 1 / 2)
|
|
189
|
+
return q;
|
|
190
|
+
if (t < 2 / 3)
|
|
191
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
192
|
+
return p;
|
|
193
|
+
};
|
|
194
|
+
return {
|
|
195
|
+
r: Math.round(hue2rgb(p, q, h + 1 / 3) * 255),
|
|
196
|
+
g: Math.round(hue2rgb(p, q, h) * 255),
|
|
197
|
+
b: Math.round(hue2rgb(p, q, h - 1 / 3) * 255),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
// ============================================================================
|
|
201
|
+
// Kubelka-Munk (Spectral)
|
|
202
|
+
// ============================================================================
|
|
203
|
+
export function rgbToReflectance(rgb) {
|
|
204
|
+
return { r: rgb.r / 255, g: rgb.g / 255, b: rgb.b / 255 };
|
|
205
|
+
}
|
|
206
|
+
export function reflectanceToRgb(ref) {
|
|
207
|
+
return {
|
|
208
|
+
r: Math.round(Math.max(0, Math.min(255, ref.r * 255))),
|
|
209
|
+
g: Math.round(Math.max(0, Math.min(255, ref.g * 255))),
|
|
210
|
+
b: Math.round(Math.max(0, Math.min(255, ref.b * 255))),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
export function reflectanceToKS(r) {
|
|
214
|
+
// K/S = (1-R)² / (2R)
|
|
215
|
+
const R = Math.max(0.001, Math.min(0.999, r));
|
|
216
|
+
return ((1 - R) * (1 - R)) / (2 * R);
|
|
217
|
+
}
|
|
218
|
+
export function ksToReflectance(ks) {
|
|
219
|
+
// R = 1 + K/S - √((K/S)² + 2·K/S)
|
|
220
|
+
return 1 + ks - Math.sqrt(ks * ks + 2 * ks);
|
|
221
|
+
}
|
|
222
|
+
// ============================================================================
|
|
223
|
+
// Utility
|
|
224
|
+
// ============================================================================
|
|
225
|
+
export function rgbToHex(rgb) {
|
|
226
|
+
const toHex = (n) => n.toString(16).padStart(2, '0');
|
|
227
|
+
return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`;
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=conversions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversions.js","sourceRoot":"","sources":["../src/conversions.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { RGB, LAB, HSL, BlendResult, BlendingMode } from './types.js';
|
|
2
|
+
export { BLENDING_MODES, isValidBlendingMode } from './types.js';
|
|
3
|
+
export { blendColors, getBlendingModeDescription } from './blending.js';
|
|
4
|
+
export { rgbToLab } from './conversions.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Available color blending algorithms.
|
|
3
|
+
*/
|
|
4
|
+
export type BlendingMode = 'rgb' | 'lab' | 'oklab' | 'ryb' | 'hsl' | 'spectral';
|
|
5
|
+
/**
|
|
6
|
+
* All blending modes with display metadata.
|
|
7
|
+
*/
|
|
8
|
+
export declare const BLENDING_MODES: Array<{
|
|
9
|
+
value: BlendingMode;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Type guard: check if a string is a valid blending mode.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isValidBlendingMode(mode: string): mode is BlendingMode;
|
|
17
|
+
export interface RGB {
|
|
18
|
+
r: number;
|
|
19
|
+
g: number;
|
|
20
|
+
b: number;
|
|
21
|
+
}
|
|
22
|
+
export interface LAB {
|
|
23
|
+
l: number;
|
|
24
|
+
a: number;
|
|
25
|
+
b: number;
|
|
26
|
+
}
|
|
27
|
+
export interface HSL {
|
|
28
|
+
h: number;
|
|
29
|
+
s: number;
|
|
30
|
+
l: number;
|
|
31
|
+
}
|
|
32
|
+
export interface BlendResult {
|
|
33
|
+
hex: string;
|
|
34
|
+
rgb: RGB;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,UAAU,CAAC;AAEhF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAO5F,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,YAAY,CAEtE;AAMD,MAAM,WAAW,GAAG;IAClB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,GAAG;IAClB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,GAAG;IAClB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,GAAG,CAAC;CACV"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Blending Mode
|
|
3
|
+
// ============================================================================
|
|
4
|
+
/**
|
|
5
|
+
* All blending modes with display metadata.
|
|
6
|
+
*/
|
|
7
|
+
export const BLENDING_MODES = [
|
|
8
|
+
{ value: 'rgb', name: 'RGB', description: 'Additive channel averaging (default)' },
|
|
9
|
+
{ value: 'lab', name: 'LAB', description: 'Perceptually uniform CIELAB blending' },
|
|
10
|
+
{ value: 'oklab', name: 'OKLAB', description: 'Modern perceptual (fixes LAB blue→purple)' },
|
|
11
|
+
{ value: 'ryb', name: 'RYB', description: "Traditional artist's color wheel" },
|
|
12
|
+
{ value: 'hsl', name: 'HSL', description: 'Hue-Saturation-Lightness interpolation' },
|
|
13
|
+
{ value: 'spectral', name: 'Spectral', description: 'Kubelka-Munk physics simulation' },
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* Type guard: check if a string is a valid blending mode.
|
|
17
|
+
*/
|
|
18
|
+
export function isValidBlendingMode(mode) {
|
|
19
|
+
return BLENDING_MODES.some((m) => m.value === mode);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,gBAAgB;AAChB,+EAA+E;AAO/E;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAsE;IAC/F,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,sCAAsC,EAAE;IAClF,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,sCAAsC,EAAE;IAClF,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,2CAA2C,EAAE;IAC3F,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,kCAAkC,EAAE;IAC9E,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,wCAAwC,EAAE;IACpF,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,iCAAiC,EAAE;CACxF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;AACtD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xivdyetools/color-blending",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Six color blending algorithms (RGB, LAB, OKLAB, RYB, HSL, Spectral/Kubelka-Munk) for the XIV Dye Tools ecosystem",
|
|
5
|
+
"author": "XIV Dye Tools",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@xivdyetools/core": "1.17.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
26
|
+
"vitest": "^4.0.18"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18.0.0"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"xivdyetools",
|
|
33
|
+
"color",
|
|
34
|
+
"blending",
|
|
35
|
+
"kubelka-munk",
|
|
36
|
+
"oklab",
|
|
37
|
+
"typescript"
|
|
38
|
+
],
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/FlashGalatine/xivdyetools.git",
|
|
42
|
+
"directory": "packages/color-blending"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc -p tsconfig.build.json",
|
|
46
|
+
"type-check": "tsc --noEmit",
|
|
47
|
+
"clean": "rimraf dist coverage",
|
|
48
|
+
"lint": "eslint src",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"test:watch": "vitest",
|
|
51
|
+
"test:coverage": "vitest run --coverage"
|
|
52
|
+
}
|
|
53
|
+
}
|