@retrovm/color 0.1.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/LICENSE +21 -0
- package/README.md +92 -0
- package/package.json +32 -0
- package/src/color.ts +589 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Juan Carlos González Amestoy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# @retrovm/color
|
|
2
|
+
|
|
3
|
+
Immutable and mutable RGB color classes with HSV conversion, ANSI terminal output, and a full set of named CSS colors.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
bun add @retrovm/color
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Color, MutableColor } from "@retrovm/color"
|
|
15
|
+
|
|
16
|
+
// From hex string
|
|
17
|
+
const red = new Color("#ff0000")
|
|
18
|
+
|
|
19
|
+
// From RGB components (0.0 – 1.0)
|
|
20
|
+
const green = new Color(0, 1, 0, 1)
|
|
21
|
+
|
|
22
|
+
// Named colors
|
|
23
|
+
const blue = Color.blue
|
|
24
|
+
const white = Color.white
|
|
25
|
+
|
|
26
|
+
// From HSV
|
|
27
|
+
const hsvColor = Color.fromHSV(0.6, 0.8, 1.0)
|
|
28
|
+
|
|
29
|
+
// Operations (return new Color)
|
|
30
|
+
const mixed = red.interpolate(blue, 0.5)
|
|
31
|
+
const brighter = red.mul(1.2)
|
|
32
|
+
|
|
33
|
+
// ANSI terminal output
|
|
34
|
+
console.log(red.toAnsiRGB() + "Hello" + "\x1b[0m")
|
|
35
|
+
console.log(red.toAnsiBackgroundRGB() + "Hello" + "\x1b[0m")
|
|
36
|
+
|
|
37
|
+
// Convert to hex string
|
|
38
|
+
console.log(red.toString()) // "#ff0000ff"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## MutableColor
|
|
42
|
+
|
|
43
|
+
`MutableColor` extends `Color` with setters and in-place operations:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
const c = new MutableColor(1, 0, 0)
|
|
47
|
+
c.r = 0.5
|
|
48
|
+
c.addIn(Color.blue)
|
|
49
|
+
c.mulIn(0.8)
|
|
50
|
+
c.interpolateIn(Color.white, 0.2)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## API
|
|
54
|
+
|
|
55
|
+
### `new Color(hex: string)`
|
|
56
|
+
### `new Color(r, g, b, a?)`
|
|
57
|
+
|
|
58
|
+
Components are in the `0.0 – 1.0` range.
|
|
59
|
+
|
|
60
|
+
### Properties (read-only on `Color`)
|
|
61
|
+
|
|
62
|
+
| Property | Description |
|
|
63
|
+
|----------|-------------|
|
|
64
|
+
| `r, g, b, a` | RGBA components |
|
|
65
|
+
| `h, s, v` | HSV components (computed lazily) |
|
|
66
|
+
|
|
67
|
+
### Methods
|
|
68
|
+
|
|
69
|
+
| Method | Description |
|
|
70
|
+
|--------|-------------|
|
|
71
|
+
| `add(c)` | Add two colors |
|
|
72
|
+
| `sub(c)` | Subtract two colors |
|
|
73
|
+
| `mul(n)` | Multiply by scalar |
|
|
74
|
+
| `div(n)` | Divide by scalar |
|
|
75
|
+
| `interpolate(c, t)` | Interpolate toward `c` by factor `t` |
|
|
76
|
+
| `interpolateIn(c, t)` | Interpolate in place |
|
|
77
|
+
| `toAnsiRGB()` | ANSI foreground escape sequence |
|
|
78
|
+
| `toAnsiBackgroundRGB()` | ANSI background escape sequence |
|
|
79
|
+
| `toString()` | Hex string `#rrggbbaa` |
|
|
80
|
+
|
|
81
|
+
### Static
|
|
82
|
+
|
|
83
|
+
| | Description |
|
|
84
|
+
|-|-------------|
|
|
85
|
+
| `Color.fromHSV(h, s, v, a?)` | Construct from HSV |
|
|
86
|
+
| `Color.names` | Array of all named color names |
|
|
87
|
+
| `Color.colors` | Object map of all named colors |
|
|
88
|
+
| `Color.red`, `Color.blue`, … | 140+ named CSS colors |
|
|
89
|
+
|
|
90
|
+
## License
|
|
91
|
+
|
|
92
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@retrovm/color",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Immutable and mutable RGB color classes with HSV, ANSI, and named color support",
|
|
5
|
+
"author": "Juan Carlos González Amestoy",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"module": "src/color.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./src/color.ts"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"src",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"keywords": [
|
|
17
|
+
"color",
|
|
18
|
+
"rgb",
|
|
19
|
+
"hsv",
|
|
20
|
+
"ansi",
|
|
21
|
+
"terminal"
|
|
22
|
+
],
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/bun": "latest"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"typescript": "^5"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/color.ts
ADDED
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
/*Copyright (c) 2026 Juan Carlos González Amestoy
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.*/
|
|
20
|
+
|
|
21
|
+
let _colors: { [key: string]: Color } | undefined
|
|
22
|
+
|
|
23
|
+
const fract = (x: number): number => {
|
|
24
|
+
return x - Math.floor(x)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const interpolate = (a: number, b: number, t: number): number => {
|
|
28
|
+
return a + (b - a) * t
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const clamp = (x: number, min: number=0, max: number=1): number => {
|
|
32
|
+
const c = x > min ? x : min
|
|
33
|
+
return max < c ? max : c
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class Color {
|
|
37
|
+
protected _r: number
|
|
38
|
+
protected _g: number
|
|
39
|
+
protected _b: number
|
|
40
|
+
protected _a: number
|
|
41
|
+
|
|
42
|
+
protected _h: number | undefined
|
|
43
|
+
protected _s: number | undefined
|
|
44
|
+
protected _v: number | undefined
|
|
45
|
+
|
|
46
|
+
// Cached ANSI escape sequences. Populated lazily by toAnsiRGB() and
|
|
47
|
+
// toAnsiBackgroundRGB() and reset to undefined by any code that mutates
|
|
48
|
+
// _r/_g/_b (see interpolateIn here, and the setters/*In methods in
|
|
49
|
+
// MutableColor). For the static readonly named colors these are computed
|
|
50
|
+
// once per process and reused forever.
|
|
51
|
+
protected _ansiFg: string | undefined
|
|
52
|
+
protected _ansiBg: string | undefined
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Construct a color from a string or RGB components
|
|
56
|
+
* @param s A color string in the format #RRGGBB
|
|
57
|
+
*/
|
|
58
|
+
constructor(s: string)
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Construct a color from RGB components
|
|
62
|
+
* @param r The red component
|
|
63
|
+
* @param g The green component
|
|
64
|
+
* @param b The blue component
|
|
65
|
+
* @param a The alpha component defaults to 1.0
|
|
66
|
+
*/
|
|
67
|
+
constructor(r: number, g: number, b: number, a: number)
|
|
68
|
+
constructor(r: number, g: number, b: number)
|
|
69
|
+
|
|
70
|
+
constructor(rs: number | string, g?: number, b?: number, a: number = 1.0) {
|
|
71
|
+
if (typeof rs === 'number' && g !== undefined && b !== undefined) {
|
|
72
|
+
this._r = rs
|
|
73
|
+
this._g = g
|
|
74
|
+
this._b = b
|
|
75
|
+
this._a = a
|
|
76
|
+
} else if (typeof rs === 'string') {
|
|
77
|
+
const match = rs.match(/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i)
|
|
78
|
+
|
|
79
|
+
if (match) {
|
|
80
|
+
this._r = parseInt(match[1]!, 16) / 255
|
|
81
|
+
this._g = parseInt(match[2]!, 16) / 255
|
|
82
|
+
this._b = parseInt(match[3]!, 16) / 255
|
|
83
|
+
this._a = match[4] ? parseInt(match[4], 16) / 255 : 1.0
|
|
84
|
+
} else {
|
|
85
|
+
const match = rs.match(/^#?([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?$/i)
|
|
86
|
+
|
|
87
|
+
if (match) {
|
|
88
|
+
this._r = parseInt(match[1]!, 16) / 15
|
|
89
|
+
this._g = parseInt(match[2]!, 16) / 15
|
|
90
|
+
this._b = parseInt(match[3]!, 16) / 15
|
|
91
|
+
this._a = match[4] ? parseInt(match[4], 16) / 15 : 1.0
|
|
92
|
+
} else {
|
|
93
|
+
throw new Error('Invalid color string')
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
throw new Error('Invalid arguments')
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get the red component
|
|
103
|
+
* @returns {number}
|
|
104
|
+
* @readonly
|
|
105
|
+
*/
|
|
106
|
+
get r() {
|
|
107
|
+
return this._r
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get the green component
|
|
112
|
+
* @returns {number}
|
|
113
|
+
* @readonly
|
|
114
|
+
*/
|
|
115
|
+
get g() {
|
|
116
|
+
return this._g
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get the blue component
|
|
121
|
+
* @returns {number}
|
|
122
|
+
* @readonly
|
|
123
|
+
*/
|
|
124
|
+
get b() {
|
|
125
|
+
return this._b
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get the alpha component
|
|
130
|
+
* @returns {number}
|
|
131
|
+
* @readonly
|
|
132
|
+
*/
|
|
133
|
+
get a() {
|
|
134
|
+
return this._a
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get the hue component
|
|
139
|
+
* @returns {number}
|
|
140
|
+
* @readonly
|
|
141
|
+
*/
|
|
142
|
+
get h() {
|
|
143
|
+
if (this._h === undefined) {
|
|
144
|
+
const M = Math.max(this._r, this._g, this._b)
|
|
145
|
+
const m = Math.min(this._r, this._g, this._b)
|
|
146
|
+
const c = M - m
|
|
147
|
+
|
|
148
|
+
if (c === 0) {
|
|
149
|
+
this._h = 0
|
|
150
|
+
} else if (M === this._r) {
|
|
151
|
+
this._h = ((this._g - this._b) / c) % 6
|
|
152
|
+
} else if (M === this._g) {
|
|
153
|
+
this._h = (this._b - this._r) / c + 2
|
|
154
|
+
} else {
|
|
155
|
+
this._h = (this._r - this._g) / c + 4
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this._h *= 60
|
|
159
|
+
|
|
160
|
+
if (this._h < 0) {
|
|
161
|
+
this._h += 360
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return this._h / 360
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Get the saturation component
|
|
170
|
+
* @returns {number}
|
|
171
|
+
* @readonly
|
|
172
|
+
*/
|
|
173
|
+
get s() {
|
|
174
|
+
if (this._s === undefined) {
|
|
175
|
+
const M = Math.max(this._r, this._g, this._b)
|
|
176
|
+
const m = Math.min(this._r, this._g, this._b)
|
|
177
|
+
this._s = M !== 0 ? (M - m) / M : 0
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return this._s
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get the value component
|
|
185
|
+
* @returns {number}
|
|
186
|
+
* @readonly
|
|
187
|
+
*/
|
|
188
|
+
get v() {
|
|
189
|
+
if (this._v === undefined) {
|
|
190
|
+
this._v = Math.max(this._r, this._g, this._b)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return this._v
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Add two colors together and return a new color
|
|
198
|
+
* @param {Color} c color to add
|
|
199
|
+
* @returns {Color}
|
|
200
|
+
*/
|
|
201
|
+
add(c: Color): Color {
|
|
202
|
+
return new Color(this._r + c._r, this._g + c._g, this._b + c._b, this._a + c._a)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Subtract two colors and return a new color
|
|
207
|
+
* @param {Color} c Color to subtract
|
|
208
|
+
* @returns {Color}
|
|
209
|
+
*/
|
|
210
|
+
sub(c: Color): Color {
|
|
211
|
+
return new Color(this._r - c._r, this._g - c._g, this._b - c._b, this._a - c._a)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Multiply a color by a scalar and return a new color
|
|
216
|
+
* @param {number} n Scalar to multiply
|
|
217
|
+
* @returns {Color}
|
|
218
|
+
*/
|
|
219
|
+
mul(n: number): Color {
|
|
220
|
+
return new Color(this._r * n, this._g * n, this._b * n, this._a * n)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Divide a color by a scalar and return a new color
|
|
225
|
+
* @param {number} n Scalar to divide
|
|
226
|
+
* @returns {Color}
|
|
227
|
+
*/
|
|
228
|
+
div(n: number): Color {
|
|
229
|
+
return new Color(this._r / n, this._g / n, this._b / n, this._a / n)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Interpolate between two colors and return a new color
|
|
234
|
+
* @param {Color} c Color to interpolate to
|
|
235
|
+
* @param {number} t Interpolation factor
|
|
236
|
+
* @returns {Color}
|
|
237
|
+
*/
|
|
238
|
+
interpolate(c: Color, t: number): Color {
|
|
239
|
+
return new Color(this._r + (c._r - this._r) * t, this._g + (c._g - this._g) * t, this._b + (c._b - this._b) * t, this._a + (c._a - this._a) * t)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Interpolate between two colors and modify the current color
|
|
244
|
+
* @param {Color} c Color to interpolate to
|
|
245
|
+
* @param {number} t Interpolation factor
|
|
246
|
+
* @returns {Color}
|
|
247
|
+
*/
|
|
248
|
+
interpolateIn(c: Color, t: number): Color {
|
|
249
|
+
this._r += (c._r - this._r) * t
|
|
250
|
+
this._g += (c._g - this._g) * t
|
|
251
|
+
this._b += (c._b - this._b) * t
|
|
252
|
+
this._a += (c._a - this._a) * t
|
|
253
|
+
this._invalidateCaches()
|
|
254
|
+
return this
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Clears all derived caches (HSV and ANSI). Must be called by any code
|
|
259
|
+
* that mutates _r/_g/_b/_a after construction.
|
|
260
|
+
*/
|
|
261
|
+
protected _invalidateCaches(): void {
|
|
262
|
+
this._h = undefined
|
|
263
|
+
this._s = undefined
|
|
264
|
+
this._v = undefined
|
|
265
|
+
this._ansiFg = undefined
|
|
266
|
+
this._ansiBg = undefined
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Return a string representation of the color
|
|
271
|
+
* @returns {string}
|
|
272
|
+
*/
|
|
273
|
+
toString() {
|
|
274
|
+
return `#${Math.round(this._r * 255)
|
|
275
|
+
.toString(16)
|
|
276
|
+
.padStart(2, '0')}${Math.round(this._g * 255)
|
|
277
|
+
.toString(16)
|
|
278
|
+
.padStart(2, '0')}${Math.round(this._b * 255)
|
|
279
|
+
.toString(16)
|
|
280
|
+
.padStart(2, '0')}${Math.round(this._a * 255)
|
|
281
|
+
.toString(16)
|
|
282
|
+
.padStart(2, '0')}`
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Converts the current color to an ANSI escape sequence for styling text color in the terminal.
|
|
287
|
+
* @returns {string} The ANSI escape sequence representing the RGB color of the text.
|
|
288
|
+
*/
|
|
289
|
+
toAnsiRGB() {
|
|
290
|
+
return this._ansiFg ??= `\x1b[38;2;${Math.floor(this._r * 255)};${Math.floor(this._g * 255)};${Math.floor(this._b * 255)}m`
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Converts the current color to an ANSI escape sequence for styling background color of the text in the terminal.
|
|
295
|
+
* @returns {string} The ANSI escape sequence representing the RGB color of the text background.
|
|
296
|
+
*/
|
|
297
|
+
toAnsiBackgroundRGB() {
|
|
298
|
+
return this._ansiBg ??= `\x1b[48;2;${Math.floor(this._r * 255)};${Math.floor(this._g * 255)};${Math.floor(this._b * 255)}m`
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
//Static methods
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Create a color from hue, saturation, and value
|
|
305
|
+
* @param {number} h Hue
|
|
306
|
+
* @param {number} s Saturation
|
|
307
|
+
* @param {number} v Value
|
|
308
|
+
* @param {number} a Alpha defaults to 1.0
|
|
309
|
+
* @returns {Color}
|
|
310
|
+
*/
|
|
311
|
+
static fromHSV(h: number, s: number, v: number, a: number = 1.0): Color {
|
|
312
|
+
let r = h + 1
|
|
313
|
+
let g = h + 2 / 3
|
|
314
|
+
let b = h + 1 / 3
|
|
315
|
+
|
|
316
|
+
r = Math.abs(fract(r) * 6 - 3)
|
|
317
|
+
g = Math.abs(fract(g) * 6 - 3)
|
|
318
|
+
b = Math.abs(fract(b) * 6 - 3)
|
|
319
|
+
|
|
320
|
+
r = v * interpolate(1, clamp(r - 1), s)
|
|
321
|
+
g = v * interpolate(1, clamp(g - 1), s)
|
|
322
|
+
b = v * interpolate(1, clamp(b - 1), s)
|
|
323
|
+
|
|
324
|
+
r = Math.round(r * 10000) / 10000
|
|
325
|
+
g = Math.round(g * 10000) / 10000
|
|
326
|
+
b = Math.round(b * 10000) / 10000
|
|
327
|
+
|
|
328
|
+
return new Color(r, g, b, a)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// #region Named colors
|
|
332
|
+
static readonly aliceBlue = new Color(0.941176, 0.972549, 1.0, 1.0)
|
|
333
|
+
static readonly antiqueWhite = new Color(0.980392, 0.921569, 0.843137, 1.0)
|
|
334
|
+
static readonly aqua = new Color(0.0, 1.0, 1.0, 1.0)
|
|
335
|
+
static readonly aquamarine = new Color(0.498039, 1.0, 0.831373, 1.0)
|
|
336
|
+
static readonly azure = new Color(0.941176, 1.0, 1.0, 1.0)
|
|
337
|
+
static readonly beige = new Color(0.960784, 0.960784, 0.862745, 1.0)
|
|
338
|
+
static readonly bisque = new Color(1.0, 0.894118, 0.768627, 1.0)
|
|
339
|
+
static readonly black = new Color(0.0, 0.0, 0.0, 1.0)
|
|
340
|
+
static readonly blanchedAlmond = new Color(1.0, 0.921569, 0.803922, 1.0)
|
|
341
|
+
static readonly blue = new Color(0.0, 0.0, 1.0, 1.0)
|
|
342
|
+
static readonly blueViolet = new Color(0.541176, 0.168627, 0.886275, 1.0)
|
|
343
|
+
static readonly brown = new Color(0.647059, 0.164706, 0.164706, 1.0)
|
|
344
|
+
static readonly burlyWood = new Color(0.870588, 0.721569, 0.529412, 1.0)
|
|
345
|
+
static readonly cadetBlue = new Color(0.372549, 0.619608, 0.627451, 1.0)
|
|
346
|
+
static readonly chartreuse = new Color(0.498039, 1.0, 0.0, 1.0)
|
|
347
|
+
static readonly chocolate = new Color(0.823529, 0.411765, 0.117647, 1.0)
|
|
348
|
+
static readonly coral = new Color(1.0, 0.498039, 0.313725, 1.0)
|
|
349
|
+
static readonly cornflowerBlue = new Color(0.392157, 0.584314, 0.929412, 1.0)
|
|
350
|
+
static readonly cornsilk = new Color(0.882353, 0.972549, 0.862745, 1.0)
|
|
351
|
+
static readonly crimson = new Color(0.862745, 0.078431, 0.235294, 1.0)
|
|
352
|
+
static readonly cyan = new Color(0.0, 1.0, 1.0, 1.0)
|
|
353
|
+
static readonly darkBlue = new Color(0.0, 0.0, 0.545098, 1.0)
|
|
354
|
+
static readonly darkCyan = new Color(0.0, 0.545098, 0.545098, 1.0)
|
|
355
|
+
static readonly darkGoldenrod = new Color(0.721569, 0.52549, 0.043137, 1.0)
|
|
356
|
+
static readonly darkGray = new Color(0.662745, 0.662745, 0.662745, 1.0)
|
|
357
|
+
static readonly darkGreen = new Color(0.0, 0.392157, 0.0, 1.0)
|
|
358
|
+
static readonly darkKhaki = new Color(0.741176, 0.717647, 0.419608, 1.0)
|
|
359
|
+
static readonly darkMagenta = new Color(0.545098, 0.0, 0.545098, 1.0)
|
|
360
|
+
static readonly darkOliveGreen = new Color(0.333333, 0.419608, 0.184314, 1.0)
|
|
361
|
+
static readonly darkOrange = new Color(1.0, 0.54902, 0.0, 1.0)
|
|
362
|
+
static readonly darkOrchid = new Color(0.6, 0.196078, 0.8, 1.0)
|
|
363
|
+
static readonly darkRed = new Color(0.545098, 0.0, 0.0, 1.0)
|
|
364
|
+
static readonly darkSalmon = new Color(0.913725, 0.588235, 0.478431, 1.0)
|
|
365
|
+
static readonly darkSeaGreen = new Color(0.560784, 0.737255, 0.560784, 1.0)
|
|
366
|
+
static readonly darkSlateBlue = new Color(0.282353, 0.239216, 0.545098, 1.0)
|
|
367
|
+
static readonly darkSlateGray = new Color(0.184314, 0.309804, 0.309804, 1.0)
|
|
368
|
+
static readonly darkTurquoise = new Color(0.0, 0.807843, 0.819608, 1.0)
|
|
369
|
+
static readonly darkViolet = new Color(0.580392, 0.0, 0.827451, 1.0)
|
|
370
|
+
static readonly deepPink = new Color(1.0, 0.078431, 0.576471, 1.0)
|
|
371
|
+
static readonly deepSkyBlue = new Color(0.0, 0.74902, 1.0, 1.0)
|
|
372
|
+
static readonly dimGray = new Color(0.411765, 0.411765, 0.411765, 1.0)
|
|
373
|
+
static readonly dodgerBlue = new Color(0.117647, 0.564706, 1.0, 1.0)
|
|
374
|
+
static readonly fireBrick = new Color(0.698039, 0.133333, 0.133333, 1.0)
|
|
375
|
+
static readonly floralWhite = new Color(1.0, 0.980392, 0.941176, 1.0)
|
|
376
|
+
static readonly forestGreen = new Color(0.133333, 0.545098, 0.133333, 1.0)
|
|
377
|
+
static readonly fuchsia = new Color(1.0, 0.0, 1.0, 1.0)
|
|
378
|
+
static readonly gainsboro = new Color(0.862745, 0.862745, 0.862745, 1.0)
|
|
379
|
+
static readonly ghostWhite = new Color(0.972549, 0.972549, 1.0, 1.0)
|
|
380
|
+
static readonly gold = new Color(1.0, 0.843137, 0.0, 1.0)
|
|
381
|
+
static readonly goldenrod = new Color(0.854902, 0.647059, 0.12549, 1.0)
|
|
382
|
+
static readonly gray = new Color(0.501961, 0.501961, 0.501961, 1.0)
|
|
383
|
+
static readonly green = new Color(0.0, 0.501961, 0.0, 1.0)
|
|
384
|
+
static readonly greenYellow = new Color(0.678431, 1.0, 0.184314, 1.0)
|
|
385
|
+
static readonly honeydew = new Color(0.941176, 1.0, 0.941176, 1.0)
|
|
386
|
+
static readonly hotPink = new Color(1.0, 0.411765, 0.705882, 1.0)
|
|
387
|
+
static readonly indianRed = new Color(0.803922, 0.360784, 0.360784, 1.0)
|
|
388
|
+
static readonly indigo = new Color(0.294118, 0.0, 0.509804, 1.0)
|
|
389
|
+
static readonly ivory = new Color(1.0, 1.0, 0.941176, 1.0)
|
|
390
|
+
static readonly khaki = new Color(0.941176, 0.901961, 0.54902, 1.0)
|
|
391
|
+
static readonly lavender = new Color(0.901961, 0.901961, 0.980392, 1.0)
|
|
392
|
+
static readonly lavenderBlush = new Color(1.0, 0.941176, 0.960784, 1.0)
|
|
393
|
+
static readonly lawnGreen = new Color(0.486275, 0.988235, 0.0, 1.0)
|
|
394
|
+
static readonly lemonChiffon = new Color(1.0, 0.980392, 0.803922, 1.0)
|
|
395
|
+
static readonly lightBlue = new Color(0.678431, 0.847059, 0.901961, 1.0)
|
|
396
|
+
static readonly lightCoral = new Color(0.941176, 0.501961, 0.501961, 1.0)
|
|
397
|
+
static readonly lightCyan = new Color(0.878431, 1.0, 1.0, 1.0)
|
|
398
|
+
static readonly lightGoldenrodYellow = new Color(0.980392, 0.980392, 0.823529, 1.0)
|
|
399
|
+
static readonly lightGreen = new Color(0.564706, 0.933333, 0.564706, 1.0)
|
|
400
|
+
static readonly lightGrey = new Color(0.827451, 0.827451, 0.827451, 1.0)
|
|
401
|
+
static readonly lightPink = new Color(1.0, 0.713725, 0.756863, 1.0)
|
|
402
|
+
static readonly lightSalmon = new Color(1.0, 0.627451, 0.478431, 1.0)
|
|
403
|
+
static readonly lightSeaGreen = new Color(0.12549, 0.698039, 0.666667, 1.0)
|
|
404
|
+
static readonly lightSkyBlue = new Color(0.529412, 0.807843, 0.980392, 1.0)
|
|
405
|
+
static readonly lightSlateGray = new Color(0.466667, 0.533333, 0.6, 1.0)
|
|
406
|
+
static readonly lightSteelBlue = new Color(0.690196, 0.768627, 0.870588, 1.0)
|
|
407
|
+
static readonly lightYellow = new Color(1.0, 1.0, 0.878431, 1.0)
|
|
408
|
+
static readonly lime = new Color(0.0, 1.0, 0.0, 1.0)
|
|
409
|
+
static readonly limeGreen = new Color(0.196078, 0.803922, 0.196078, 1.0)
|
|
410
|
+
static readonly linen = new Color(0.980392, 0.941176, 0.901961, 1.0)
|
|
411
|
+
static readonly magenta = new Color(1.0, 0.0, 1.0, 1.0)
|
|
412
|
+
static readonly maroon = new Color(0.501961, 0.0, 0.0, 1.0)
|
|
413
|
+
static readonly mediumAquamarine = new Color(0.4, 0.803922, 0.666667, 1.0)
|
|
414
|
+
static readonly mediumBlue = new Color(0.0, 0.0, 0.803922, 1.0)
|
|
415
|
+
static readonly mediumOrchid = new Color(0.729412, 0.333333, 0.827451, 1.0)
|
|
416
|
+
static readonly mediumPurple = new Color(0.576471, 0.439216, 0.858824, 1.0)
|
|
417
|
+
static readonly mediumSeaGreen = new Color(0.235294, 0.701961, 0.443137, 1.0)
|
|
418
|
+
static readonly mediumSlateBlue = new Color(0.482353, 0.407843, 0.933333, 1.0)
|
|
419
|
+
static readonly mediumSpringGreen = new Color(0.0, 0.980392, 0.603922, 1.0)
|
|
420
|
+
static readonly mediumTurquoise = new Color(0.282353, 0.819608, 0.8, 1.0)
|
|
421
|
+
static readonly mediumVioletRed = new Color(0.780392, 0.082353, 0.521569, 1.0)
|
|
422
|
+
static readonly midnightBlue = new Color(0.098039, 0.098039, 0.439216, 1.0)
|
|
423
|
+
static readonly mintCream = new Color(0.960784, 1.0, 0.980392, 1.0)
|
|
424
|
+
static readonly mistyRose = new Color(1.0, 0.894118, 0.882353, 1.0)
|
|
425
|
+
static readonly moccasin = new Color(1.0, 0.894118, 0.709804, 1.0)
|
|
426
|
+
static readonly navajoWhite = new Color(1.0, 0.870588, 0.678431, 1.0)
|
|
427
|
+
static readonly navy = new Color(0.0, 0.0, 0.501961, 1.0)
|
|
428
|
+
static readonly oldLace = new Color(0.992157, 0.960784, 0.901961, 1.0)
|
|
429
|
+
static readonly olive = new Color(0.501961, 0.501961, 0.0, 1.0)
|
|
430
|
+
static readonly oliveDrab = new Color(0.419608, 0.556863, 0.137255, 1.0)
|
|
431
|
+
static readonly orange = new Color(1.0, 0.647059, 0.0, 1.0)
|
|
432
|
+
static readonly orangeRed = new Color(1.0, 0.270588, 0.0, 1.0)
|
|
433
|
+
static readonly orchid = new Color(0.854902, 0.439216, 0.839216, 1.0)
|
|
434
|
+
static readonly paleGoldenrod = new Color(0.933333, 0.909804, 0.666667, 1.0)
|
|
435
|
+
static readonly paleGreen = new Color(0.596078, 0.984314, 0.596078, 1.0)
|
|
436
|
+
static readonly paleTurquoise = new Color(0.686275, 0.933333, 0.933333, 1.0)
|
|
437
|
+
static readonly paleVioletRed = new Color(0.858824, 0.439216, 0.576471, 1.0)
|
|
438
|
+
static readonly papayaWhip = new Color(1.0, 0.937255, 0.835294, 1.0)
|
|
439
|
+
static readonly peachPuff = new Color(1.0, 0.854902, 0.72549, 1.0)
|
|
440
|
+
static readonly peru = new Color(0.803922, 0.521569, 0.247059, 1.0)
|
|
441
|
+
static readonly pink = new Color(1.0, 0.752941, 0.796078, 1.0)
|
|
442
|
+
static readonly plum = new Color(0.866667, 0.627451, 0.866667, 1.0)
|
|
443
|
+
static readonly powderBlue = new Color(0.690196, 0.878431, 0.901961, 1.0)
|
|
444
|
+
static readonly purple = new Color(0.501961, 0.0, 0.501961, 1.0)
|
|
445
|
+
static readonly red = new Color(1.0, 0.0, 0.0, 1.0)
|
|
446
|
+
static readonly rosyBrown = new Color(0.737255, 0.560784, 0.560784, 1.0)
|
|
447
|
+
static readonly royalBlue = new Color(0.254902, 0.411765, 0.882353, 1.0)
|
|
448
|
+
static readonly saddleBrown = new Color(0.545098, 0.270588, 0.07451, 1.0)
|
|
449
|
+
static readonly salmon = new Color(0.980392, 0.501961, 0.447059, 1.0)
|
|
450
|
+
static readonly sandyBrown = new Color(0.956863, 0.643137, 0.376471, 1.0)
|
|
451
|
+
static readonly seaGreen = new Color(0.180392, 0.545098, 0.380392, 1.0)
|
|
452
|
+
static readonly seashell = new Color(1.0, 0.960784, 0.933333, 1.0)
|
|
453
|
+
static readonly sienna = new Color(0.627451, 0.321569, 0.176471, 1.0)
|
|
454
|
+
static readonly silver = new Color(0.752941, 0.752941, 0.752941, 1.0)
|
|
455
|
+
static readonly skyBlue = new Color(0.529412, 0.807843, 0.921569, 1.0)
|
|
456
|
+
static readonly slateBlue = new Color(0.415686, 0.352941, 0.803922, 1.0)
|
|
457
|
+
static readonly slateGray = new Color(0.466667, 0.533333, 0.6, 1.0)
|
|
458
|
+
static readonly snow = new Color(1.0, 0.980392, 0.980392, 1.0)
|
|
459
|
+
static readonly springGreen = new Color(0.0, 1.0, 0.498039, 1.0)
|
|
460
|
+
static readonly steelBlue = new Color(0.27451, 0.509804, 0.705882, 1.0)
|
|
461
|
+
static readonly tan = new Color(0.823529, 0.705882, 0.54902, 1.0)
|
|
462
|
+
static readonly teal = new Color(0.0, 0.501961, 0.501961, 1.0)
|
|
463
|
+
static readonly thistle = new Color(0.847059, 0.74902, 0.847059, 1.0)
|
|
464
|
+
static readonly tomato = new Color(1.0, 0.388235, 0.278431, 1.0)
|
|
465
|
+
static readonly transparent = new Color(0.0, 0.0, 0.0, 0.0)
|
|
466
|
+
static readonly turquoise = new Color(0.25098, 0.878431, 0.815686, 1.0)
|
|
467
|
+
static readonly violet = new Color(0.933333, 0.509804, 0.933333, 1.0)
|
|
468
|
+
static readonly wheat = new Color(0.960784, 0.870588, 0.701961, 1.0)
|
|
469
|
+
static readonly white = new Color(1.0, 1.0, 1.0, 1.0)
|
|
470
|
+
static readonly whiteSmoke = new Color(0.960784, 0.960784, 0.960784, 1.0)
|
|
471
|
+
static readonly yellow = new Color(1.0, 1.0, 0.0, 1.0)
|
|
472
|
+
static readonly yellowGreen = new Color(0.603922, 0.803922, 0.196078, 1.0)
|
|
473
|
+
|
|
474
|
+
static readonly names: string[] = ['aliceBlue', 'antiqueWhite', 'aqua', 'aquamarine', 'azure', 'beige', 'bisque', 'black', 'blanchedAlmond', 'blue', 'blueViolet', 'brown', 'burlyWood', 'cadetBlue', 'chartreuse', 'chocolate', 'coral', 'cornflowerBlue', 'cornsilk', 'crimson', 'cyan', 'darkBlue', 'darkCyan', 'darkGoldenrod', 'darkGray', 'darkGreen', 'darkKhaki', 'darkMagenta', 'darkOliveGreen', 'darkOrange', 'darkOrchid', 'darkRed', 'darkSalmon', 'darkSeaGreen', 'darkSlateBlue', 'darkSlateGray', 'darkTurquoise', 'darkViolet', 'deepPink', 'deepSkyBlue', 'dimGray', 'dodgerBlue', 'fireBrick', 'floralWhite', 'forestGreen', 'fuchsia', 'gainsboro', 'ghostWhite', 'gold', 'goldenrod', 'gray', 'green', 'greenYellow', 'honeydew', 'hotPink', 'indianRed', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderBlush', 'lawnGreen', 'lemonChiffon', 'lightBlue', 'lightCoral', 'lightCyan', 'lightGoldenrodYellow', 'lightGreen', 'lightGrey', 'lightPink', 'lightSalmon', 'lightSeaGreen', 'lightSkyBlue', 'lightSlateGray', 'lightSteelBlue', 'lightYellow', 'lime', 'limeGreen', 'linen', 'magenta', 'maroon', 'mediumAquamarine', 'mediumBlue', 'mediumOrchid', 'mediumPurple', 'mediumSeaGreen', 'mediumSlateBlue', 'mediumSpringGreen', 'mediumTurquoise', 'mediumVioletRed', 'midnightBlue', 'mintCream', 'mistyRose', 'moccasin', 'navajoWhite', 'navy', 'oldLace', 'olive', 'oliveDrab', 'orange', 'orangeRed', 'orchid', 'paleGoldenrod', 'paleGreen', 'paleTurquoise', 'paleVioletRed', 'papayaWhip', 'peachPuff', 'peru', 'pink', 'plum', 'powderBlue', 'purple', 'red', 'rosyBrown', 'royalBlue', 'saddleBrown', 'salmon', 'sandyBrown', 'seaGreen', 'seashell', 'sienna', 'silver', 'skyBlue', 'slateBlue', 'slateGray', 'snow', 'springGreen', 'steelBlue', 'tan', 'teal', 'thistle', 'tomato', 'transparent', 'turquoise', 'violet', 'wheat', 'white', 'whiteSmoke', 'yellow', 'yellowGreen']
|
|
475
|
+
|
|
476
|
+
static get colors() {
|
|
477
|
+
if(_colors === undefined) {
|
|
478
|
+
_colors = {}
|
|
479
|
+
const _c=_colors as any
|
|
480
|
+
const o=Color as any
|
|
481
|
+
|
|
482
|
+
Color.names.forEach(name => {
|
|
483
|
+
_c[name] = o[name]
|
|
484
|
+
})
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return _colors
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// #endregion
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export class MutableColor extends Color {
|
|
494
|
+
constructor(r: number, g: number, b: number, a: number = 1.0) {
|
|
495
|
+
super(r, g, b, a)
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
override get r() {
|
|
499
|
+
return this._r
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
override set r(r: number) {
|
|
503
|
+
this._r = r
|
|
504
|
+
this._invalidateCaches()
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
override get g() {
|
|
508
|
+
return this._g
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
override set g(g: number) {
|
|
512
|
+
this._g = g
|
|
513
|
+
this._invalidateCaches()
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
override get b() {
|
|
517
|
+
return this._b
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
override set b(b: number) {
|
|
521
|
+
this._b = b
|
|
522
|
+
this._invalidateCaches()
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
override get a() {
|
|
526
|
+
return this._a
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
override set a(a: number) {
|
|
530
|
+
this._a = a
|
|
531
|
+
this._invalidateCaches()
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Add two colors together and modify the current color
|
|
536
|
+
* @param {Color} c Color to add
|
|
537
|
+
* @returns {Color}
|
|
538
|
+
*/
|
|
539
|
+
addIn(c: Color): Color {
|
|
540
|
+
this._r += c.r
|
|
541
|
+
this._g += c.g
|
|
542
|
+
this._b += c.b
|
|
543
|
+
this._a += c.a
|
|
544
|
+
this._invalidateCaches()
|
|
545
|
+
return this
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Subtract two colors and modify the current color
|
|
550
|
+
* @param {Color} c Color to subtract
|
|
551
|
+
* @returns {Color}
|
|
552
|
+
*/
|
|
553
|
+
subIn(c: Color): Color {
|
|
554
|
+
this._r -= c.r
|
|
555
|
+
this._g -= c.g
|
|
556
|
+
this._b -= c.b
|
|
557
|
+
this._a -= c.a
|
|
558
|
+
this._invalidateCaches()
|
|
559
|
+
return this
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Multiply a color by a scalar and modify the current color
|
|
564
|
+
* @param {number} n Scalar to multiply
|
|
565
|
+
* @returns {Color}
|
|
566
|
+
*/
|
|
567
|
+
mulIn(n: number): Color {
|
|
568
|
+
this._r *= n
|
|
569
|
+
this._g *= n
|
|
570
|
+
this._b *= n
|
|
571
|
+
this._a *= n
|
|
572
|
+
this._invalidateCaches()
|
|
573
|
+
return this
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Divide a color by a scalar and modify the current color
|
|
578
|
+
* @param {number} n Scalar to divide
|
|
579
|
+
* @returns {Color}
|
|
580
|
+
*/
|
|
581
|
+
divIn(n: number): Color {
|
|
582
|
+
this._r /= n
|
|
583
|
+
this._g /= n
|
|
584
|
+
this._b /= n
|
|
585
|
+
this._a /= n
|
|
586
|
+
this._invalidateCaches()
|
|
587
|
+
return this
|
|
588
|
+
}
|
|
589
|
+
}
|