diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..b14ce9a
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,24 @@
+name: ci
+
+on: [ push, pull_request ]
+
+jobs:
+ checks:
+ runs-on: ubuntu-latest
+ steps:
+ - name: clone repository
+ uses: actions/checkout@v3
+
+ - name: install deno
+ uses: denoland/setup-deno@v1
+ with:
+ deno-version: 1.X
+
+ - name: check format
+ run: deno fmt --check
+
+ - name: check linting
+ run: deno lint
+
+ - name: run tests
+ run: deno test
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6450084
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/.npm
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..b58b603
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,5 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..a55e7a1
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/color.iml b/.idea/color.iml
new file mode 100644
index 0000000..24643cc
--- /dev/null
+++ b/.idea/color.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copyright/mit_license.xml b/.idea/copyright/mit_license.xml
new file mode 100644
index 0000000..4f96546
--- /dev/null
+++ b/.idea/copyright/mit_license.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..d984029
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deno.xml b/.idea/deno.xml
new file mode 100644
index 0000000..3b8a686
--- /dev/null
+++ b/.idea/deno.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.idea/dictionaries/mineejo.xml b/.idea/dictionaries/mineejo.xml
new file mode 100644
index 0000000..60d3b69
--- /dev/null
+++ b/.idea/dictionaries/mineejo.xml
@@ -0,0 +1,8 @@
+
+
+
+ chalkpot
+ mineejo
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..dd4c951
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..3743e72
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml
new file mode 100644
index 0000000..ed877ef
--- /dev/null
+++ b/.idea/watcherTasks.xml
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c1ad1e7
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 mineejo
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..58c0e38
--- /dev/null
+++ b/README.md
@@ -0,0 +1,34 @@
+# Color
+
+Color is a tool for creating [RGB] color by range and by HSL without leaving RGB
+space. With `additional tools`, `unlimited development` and `no dependencies`.
+
+[Read documentation, API...]
+
+[RGB]: https://en.wikipedia.org/wiki/RGB_color_model
+[Read documentation, API...]: https://deno.land/x/chalkpot_color/mod.ts
+
+## Installation
+
+`CommonJS` (script directory) and `ModuleJS` (esm directory) support for
+`Node.js`, see [NPM page] for installation command. Also support for `Yarn` and
+other package managers or CDNs like `UNPKG`. For `Deno` reference see
+[module page], or use CDN like `esm.sh`.
+
+[NPM page]: https://www.npmjs.com/package/@chalkpot/color
+[module page]: https://deno.land/x/chalkpot_color
+
+## Related
+
+- [colors](https://github.com/chalkpot/colors) - Colors is JSON with the names
+ of colors, their values and localization. Colors are based on HTML color names
+ and CSS keywords.
+
+## Contributing
+
+Pull requests are welcome. For major changes, please open an issue first to
+discuss what you would like to change.
+
+## License
+
+[MIT](https://choosealicense.com/licenses/mit/)
diff --git a/_build_npm.ts b/_build_npm.ts
new file mode 100644
index 0000000..45eee8c
--- /dev/null
+++ b/_build_npm.ts
@@ -0,0 +1,42 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { build, emptyDir } from "https://deno.land/x/dnt@0.38.1/mod.ts";
+
+const outDir = "./.npm";
+
+await emptyDir(outDir);
+
+await build({
+ entryPoints: ["./mod.ts"],
+ outDir: outDir,
+ shims: {
+ deno: true,
+ },
+ test: true,
+ package: {
+ name: "@chalkpot/color",
+ version: Deno.args[0],
+ description:
+ "Color is a tool for creating [RGB] color by range and by HSL without leaving RGB space.",
+ author: "mineejo",
+ license: "MIT",
+ homepage: "https://github.com/chalkpot/color#readme",
+ repository: {
+ type: "git",
+ url: "git+https://github.com/chalkpot/color.git",
+ },
+ bugs: {
+ url: "https://github.com/chalkpot/color/issues",
+ },
+ keywords: [
+ "chalkpot",
+ "color",
+ "rgb",
+ "hsl",
+ ],
+ },
+ postBuild() {
+ Deno.copyFileSync("LICENSE", `${outDir}/LICENSE`);
+ Deno.copyFileSync("README.md", `${outDir}/README.md`);
+ },
+});
diff --git a/advanced_color.ts b/advanced_color.ts
new file mode 100644
index 0000000..2f305ae
--- /dev/null
+++ b/advanced_color.ts
@@ -0,0 +1,131 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { Color } from "./color.ts";
+import { Rgb } from "./color/mod.ts";
+import { mixColors } from "./color_effects/mod.ts";
+import { percent } from "./util.ts";
+import { rgbColorWheel } from "./color/rgb_color_wheel.ts";
+
+/**
+ * AdvancedColor is an advanced [RGB] color.
+ * Like regular `Color`, it mimics the [HSL] model.
+ *
+ * [RGB]: https://en.wikipedia.org/wiki/RGB_color_model
+ * [HSL]: https://en.wikipedia.org/wiki/HSL_and_HSV
+ *
+ * ### Example
+ *
+ * ```ts
+ * const darkGreen = new AdvancedColor(33.33, undefined, 25);
+ * console.log(darkGreen.components); // [0, 127.8, 0]
+ *
+ * const paleRed = new AdvancedColor(100, 70, 80);
+ * console.log(paleRed.components); // [255, 173.3, 173.3]
+ * ```
+ */
+export class AdvancedColor {
+ public readonly hue: number = 0;
+ public readonly saturation: number = 0;
+ public readonly lightness: number = 0;
+ public readonly red: number = 0;
+ public readonly green: number = 0;
+ public readonly blue: number = 0;
+ public readonly components: Rgb = [0, 0, 0];
+
+ private hueColor: Color = new Color(false, ...this.components);
+ private saturationColor: Color = new Color(false, ...this.components);
+ private lightnessColor: Color = new Color(false, ...this.components);
+
+ /**
+ * @param hue
+ * Percentage value of the color wheel from `0` to `100`:
+ * - Red: `0`;
+ * - Green: `33.33`;
+ * - Blue: `66.66`;
+ * - Red: `100`;
+ *
+ * @param saturation
+ * Percentage value from `0` to `100`:
+ * - Colorless (grey color): `0`;
+ * - Hue color: `100`;
+ *
+ * @param lightness
+ * Percentage value from `0` to `100`:
+ * - Black: `0`;
+ * - Hue color: `50`;
+ * - White: `100`;
+ */
+ public constructor(
+ hue: number,
+ saturation?: number | undefined,
+ lightness?: number | undefined,
+ ) {
+ this.hue = percent(hue);
+ this.addHueColor();
+
+ if (saturation !== undefined) {
+ this.saturation = percent(saturation);
+ this.createSaturationColor();
+ }
+
+ if (lightness !== undefined) {
+ this.lightness = percent(lightness);
+ this.createLightnessColor();
+ }
+
+ this.components = this._rgbColor.components;
+ this.red = this._rgbColor.red;
+ this.green = this._rgbColor.green;
+ this.blue = this._rgbColor.blue;
+ }
+
+ private _rgbColor: Color = new Color(false, ...this.components);
+
+ get rgbColor(): Color {
+ return this._rgbColor;
+ }
+
+ private createLightnessColor(): void {
+ const lightnessValue: number = this.lightness - 0.1;
+ const ratio: number = (lightnessValue - 30.2) / (100 - 30.2);
+ const lightness: number = 255 / (100 / (ratio * 140));
+
+ const newComponents: Rgb = this._rgbColor.components.map(
+ (component: number) => component - (100 - lightness),
+ ) as Rgb;
+
+ this.lightnessColor = new Color(false, ...newComponents);
+ this._rgbColor = this.lightnessColor;
+ }
+
+ private createSaturationColor(): void {
+ const saturation: number = (
+ this._rgbColor.red +
+ this._rgbColor.green +
+ this._rgbColor.blue
+ ) / 4;
+
+ const color: Color = new Color(false, saturation, saturation, saturation);
+ const saturationValue: number = this.saturation;
+
+ this.saturationColor = mixColors(
+ this.hueColor,
+ color,
+ 100 - saturationValue,
+ );
+
+ this._rgbColor = this.saturationColor;
+ }
+
+ private addHueColor(): void {
+ const hueValue: number = this.hue;
+
+ const colorIndex: number = Math.min(
+ Math.max(rgbColorWheel.length * (hueValue / 100), 0),
+ rgbColorWheel.length - 1,
+ );
+
+ this.hueColor = new Color(false, ...rgbColorWheel[Math.floor(colorIndex)]);
+ this._rgbColor = this.hueColor;
+ }
+}
diff --git a/advanced_color_test.ts b/advanced_color_test.ts
new file mode 100644
index 0000000..5a910a9
--- /dev/null
+++ b/advanced_color_test.ts
@@ -0,0 +1,145 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { assertEquals } from "./dev_deps.ts";
+import { AdvancedColor } from "./advanced_color.ts";
+import { Rgb } from "./color/mod.ts";
+import { Color } from "./color.ts";
+
+export function truncComponents(color: AdvancedColor | Color): Rgb {
+ const [_red, _green, _blue]: Rgb = color.components;
+ return [Math.trunc(_red), Math.trunc(_green), Math.trunc(_blue)];
+}
+
+Deno.test("class contains correct fields", async (t) => {
+ const red = 31;
+ const green = 10;
+ const blue = 0;
+
+ const hue = 10;
+ const saturation = 20;
+ const lightness = 30;
+
+ const color: AdvancedColor = new AdvancedColor(hue, saturation, lightness);
+
+ assertEquals(Math.trunc(color.red), red, `"color.red"`);
+ assertEquals(Math.trunc(color.green), green, `"color.green"`);
+ assertEquals(Math.trunc(color.blue), blue, `"color.blue"`);
+
+ assertEquals(color.hue, hue, `"color.hue"`);
+ assertEquals(color.saturation, saturation, `"color.saturation"`);
+ assertEquals(color.lightness, lightness, `"color.lightness"`);
+
+ await t.step("dependent field contains correct values", () => {
+ assertEquals(
+ truncComponents(color.rgbColor),
+ [red, green, blue],
+ `"color.rgbColor"`,
+ );
+
+ assertEquals(
+ truncComponents(color),
+ [red, green, blue],
+ `"color"`,
+ );
+ });
+});
+
+Deno.test("HSL conversion of red, green and blue correct", async (t) => {
+ const red: Rgb = [255, 0, 0];
+ const green: Rgb = [0, 255, 0];
+ const blue: Rgb = [0, 0, 255];
+
+ const hue: AdvancedColor = new AdvancedColor(0);
+ assertEquals(truncComponents(hue), red, `"hue"`);
+
+ await t.step("no lightness or saturation values do not change hue", () => {
+ const hueSaturation: AdvancedColor = new AdvancedColor(0, 100);
+ assertEquals(truncComponents(hueSaturation), red, `"hueSaturation"`);
+
+ const hueLightness: AdvancedColor = new AdvancedColor(0, undefined, 50);
+ assertEquals(truncComponents(hueLightness), red, `"hueLightness"`);
+ });
+
+ await t.step("default values do not change hue", () => {
+ const hueSaturationLightness: AdvancedColor = new AdvancedColor(0, 100, 50);
+ assertEquals(
+ truncComponents(hueSaturationLightness),
+ red,
+ `"hueSaturationLightness"`,
+ );
+ });
+
+ await t.step("hue range correct", () => {
+ const startRedColor: AdvancedColor = new AdvancedColor(0);
+ assertEquals(truncComponents(startRedColor), red, `"startRedColor"`);
+
+ const greenColor: AdvancedColor = new AdvancedColor(33.33);
+ assertEquals(truncComponents(greenColor), green, `"greenColor"`);
+
+ const blueColor: AdvancedColor = new AdvancedColor(66.66);
+ assertEquals(truncComponents(blueColor), blue, `"blueColor"`);
+
+ const endRedColor: AdvancedColor = new AdvancedColor(100);
+ assertEquals(truncComponents(endRedColor), red, `"endRedColor"`);
+ });
+
+ await t.step("saturation range correct", () => {
+ const redSaturated: Rgb = [255, 0, 0];
+ const saturatedColor: AdvancedColor = new AdvancedColor(0, 100);
+ assertEquals(
+ truncComponents(saturatedColor),
+ redSaturated,
+ `"saturatedColor"`,
+ );
+
+ const redUnsaturated: Rgb = [63, 63, 63];
+ const unsaturatedColor: AdvancedColor = new AdvancedColor(0, 0);
+ assertEquals(
+ truncComponents(unsaturatedColor),
+ redUnsaturated,
+ `"unsaturatedColor"`,
+ );
+ });
+
+ await t.step("lightness range correct", () => {
+ const black: Rgb = [0, 0, 0];
+ const blackColor: AdvancedColor = new AdvancedColor(0, undefined, 0);
+ assertEquals(
+ truncComponents(blackColor),
+ black,
+ `"blackColor"`,
+ );
+
+ const white: Rgb = [255, 255, 255];
+ const whiteColor: AdvancedColor = new AdvancedColor(0, undefined, 100);
+ assertEquals(
+ truncComponents(whiteColor),
+ white,
+ `"whiteColor"`,
+ );
+ });
+});
+
+for (let i = 0; i < 100; i++) {
+ const hue = new AdvancedColor(i, 100).components.toString()
+ .replace(/,/g, ";")
+ .replace(/\.\d+/gm, "");
+
+ const saturation = new AdvancedColor(i, 0).components.toString()
+ .replace(/,/g, ";")
+ .replace(/\.\d+/gm, "");
+
+ const lighntess = new AdvancedColor(i, undefined, 80).components.toString()
+ .replace(/,/g, ";")
+ .replace(/\.\d+/gm, "");
+
+ console.log(
+ `${i}.`.padEnd(4),
+ `[${hue}]`.padEnd(11),
+ `[${saturation}]`.padEnd(13),
+ `[${lighntess}]:`.padEnd(14),
+ `\x1b[48;2;${hue}m \x1b[0m`,
+ `\x1b[48;2;${saturation}m \x1b[0m`,
+ `\x1b[48;2;${lighntess}m \x1b[0m`,
+ );
+}
diff --git a/color.ts b/color.ts
new file mode 100644
index 0000000..66cb1d3
--- /dev/null
+++ b/color.ts
@@ -0,0 +1,49 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { ColorComponent } from "./color_component.ts";
+import { Rgb } from "./color/mod.ts";
+import { percent } from "./util.ts";
+
+/**
+ * [Color] contains the components, red, green, blue.
+ *
+ * [Color]: https://en.wikipedia.org/wiki/RGB_color_model
+ *
+ * ### Example
+ *
+ * ```ts
+ * const red = new Color(false, 255, 0, 0)
+ * const blue = new Color(true, 0, 0, 100);
+ * ```
+ */
+export class Color {
+ public readonly components: Rgb = [0, 0, 0];
+ public readonly red: number = 0;
+ public readonly green: number = 0;
+ public readonly blue: number = 0;
+
+ /**
+ * @param percentage
+ * Use percentages instead of component range, if true.
+ *
+ * @param components
+ */
+ public constructor(percentage: boolean = false, ...components: Rgb) {
+ const [red, green, blue]: Rgb = percentage
+ ? this.rgbPercent(...components)
+ : components;
+
+ this.red = new ColorComponent(red).lightness;
+ this.green = new ColorComponent(green).lightness;
+ this.blue = new ColorComponent(blue).lightness;
+ this.components = [this.red, this.green, this.blue];
+ }
+
+ private rgbPercent(...components: Rgb): Rgb {
+ return [
+ (percent(components[0]) / 100) * 255,
+ (percent(components[1]) / 100) * 255,
+ (percent(components[2]) / 100) * 255,
+ ];
+ }
+}
diff --git a/color/mod.ts b/color/mod.ts
new file mode 100644
index 0000000..7cd193d
--- /dev/null
+++ b/color/mod.ts
@@ -0,0 +1,4 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+export { rgbColorWheel } from "./rgb_color_wheel.ts";
+export type { Rgb } from "./rgb.ts";
diff --git a/color/rgb.ts b/color/rgb.ts
new file mode 100644
index 0000000..e75beb7
--- /dev/null
+++ b/color/rgb.ts
@@ -0,0 +1,9 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+/**
+ * The alias describing three colors is [RGB],
+ * each of which is a component.
+ *
+ * [RGB]: https://en.wikipedia.org/wiki/RGB_color_model
+ */
+export type Rgb = [number, number, number];
diff --git a/color/rgb_color_wheel.ts b/color/rgb_color_wheel.ts
new file mode 100644
index 0000000..5229fbb
--- /dev/null
+++ b/color/rgb_color_wheel.ts
@@ -0,0 +1,1537 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { Rgb } from "./rgb.ts";
+
+export const rgbColorWheel: Rgb[] = [
+ [255, 0, 0],
+ [255, 1, 0],
+ [255, 2, 0],
+ [255, 3, 0],
+ [255, 4, 0],
+ [255, 5, 0],
+ [255, 6, 0],
+ [255, 7, 0],
+ [255, 8, 0],
+ [255, 9, 0],
+ [255, 10, 0],
+ [255, 11, 0],
+ [255, 12, 0],
+ [255, 13, 0],
+ [255, 14, 0],
+ [255, 15, 0],
+ [255, 16, 0],
+ [255, 17, 0],
+ [255, 18, 0],
+ [255, 19, 0],
+ [255, 20, 0],
+ [255, 21, 0],
+ [255, 22, 0],
+ [255, 23, 0],
+ [255, 24, 0],
+ [255, 25, 0],
+ [255, 26, 0],
+ [255, 27, 0],
+ [255, 28, 0],
+ [255, 29, 0],
+ [255, 30, 0],
+ [255, 31, 0],
+ [255, 32, 0],
+ [255, 33, 0],
+ [255, 34, 0],
+ [255, 35, 0],
+ [255, 36, 0],
+ [255, 37, 0],
+ [255, 38, 0],
+ [255, 39, 0],
+ [255, 40, 0],
+ [255, 41, 0],
+ [255, 42, 0],
+ [255, 43, 0],
+ [255, 44, 0],
+ [255, 45, 0],
+ [255, 46, 0],
+ [255, 47, 0],
+ [255, 48, 0],
+ [255, 49, 0],
+ [255, 50, 0],
+ [255, 51, 0],
+ [255, 52, 0],
+ [255, 53, 0],
+ [255, 54, 0],
+ [255, 55, 0],
+ [255, 56, 0],
+ [255, 57, 0],
+ [255, 58, 0],
+ [255, 59, 0],
+ [255, 60, 0],
+ [255, 61, 0],
+ [255, 62, 0],
+ [255, 63, 0],
+ [255, 64, 0],
+ [255, 65, 0],
+ [255, 66, 0],
+ [255, 67, 0],
+ [255, 68, 0],
+ [255, 69, 0],
+ [255, 70, 0],
+ [255, 71, 0],
+ [255, 72, 0],
+ [255, 73, 0],
+ [255, 74, 0],
+ [255, 75, 0],
+ [255, 76, 0],
+ [255, 77, 0],
+ [255, 78, 0],
+ [255, 79, 0],
+ [255, 80, 0],
+ [255, 81, 0],
+ [255, 82, 0],
+ [255, 83, 0],
+ [255, 84, 0],
+ [255, 85, 0],
+ [255, 86, 0],
+ [255, 87, 0],
+ [255, 88, 0],
+ [255, 89, 0],
+ [255, 90, 0],
+ [255, 91, 0],
+ [255, 92, 0],
+ [255, 93, 0],
+ [255, 94, 0],
+ [255, 95, 0],
+ [255, 96, 0],
+ [255, 97, 0],
+ [255, 98, 0],
+ [255, 99, 0],
+ [255, 100, 0],
+ [255, 101, 0],
+ [255, 102, 0],
+ [255, 103, 0],
+ [255, 104, 0],
+ [255, 105, 0],
+ [255, 106, 0],
+ [255, 107, 0],
+ [255, 108, 0],
+ [255, 109, 0],
+ [255, 110, 0],
+ [255, 111, 0],
+ [255, 112, 0],
+ [255, 113, 0],
+ [255, 114, 0],
+ [255, 115, 0],
+ [255, 116, 0],
+ [255, 117, 0],
+ [255, 118, 0],
+ [255, 119, 0],
+ [255, 120, 0],
+ [255, 121, 0],
+ [255, 122, 0],
+ [255, 123, 0],
+ [255, 124, 0],
+ [255, 125, 0],
+ [255, 126, 0],
+ [255, 127, 0],
+ [255, 128, 0],
+ [255, 129, 0],
+ [255, 130, 0],
+ [255, 131, 0],
+ [255, 132, 0],
+ [255, 133, 0],
+ [255, 134, 0],
+ [255, 135, 0],
+ [255, 136, 0],
+ [255, 137, 0],
+ [255, 138, 0],
+ [255, 139, 0],
+ [255, 140, 0],
+ [255, 141, 0],
+ [255, 142, 0],
+ [255, 143, 0],
+ [255, 144, 0],
+ [255, 145, 0],
+ [255, 146, 0],
+ [255, 147, 0],
+ [255, 148, 0],
+ [255, 149, 0],
+ [255, 150, 0],
+ [255, 151, 0],
+ [255, 152, 0],
+ [255, 153, 0],
+ [255, 154, 0],
+ [255, 155, 0],
+ [255, 156, 0],
+ [255, 157, 0],
+ [255, 158, 0],
+ [255, 159, 0],
+ [255, 160, 0],
+ [255, 161, 0],
+ [255, 162, 0],
+ [255, 163, 0],
+ [255, 164, 0],
+ [255, 165, 0],
+ [255, 166, 0],
+ [255, 167, 0],
+ [255, 168, 0],
+ [255, 169, 0],
+ [255, 170, 0],
+ [255, 171, 0],
+ [255, 172, 0],
+ [255, 173, 0],
+ [255, 174, 0],
+ [255, 175, 0],
+ [255, 176, 0],
+ [255, 177, 0],
+ [255, 178, 0],
+ [255, 179, 0],
+ [255, 180, 0],
+ [255, 181, 0],
+ [255, 182, 0],
+ [255, 183, 0],
+ [255, 184, 0],
+ [255, 185, 0],
+ [255, 186, 0],
+ [255, 187, 0],
+ [255, 188, 0],
+ [255, 189, 0],
+ [255, 190, 0],
+ [255, 191, 0],
+ [255, 192, 0],
+ [255, 193, 0],
+ [255, 194, 0],
+ [255, 195, 0],
+ [255, 196, 0],
+ [255, 197, 0],
+ [255, 198, 0],
+ [255, 199, 0],
+ [255, 200, 0],
+ [255, 201, 0],
+ [255, 202, 0],
+ [255, 203, 0],
+ [255, 204, 0],
+ [255, 205, 0],
+ [255, 206, 0],
+ [255, 207, 0],
+ [255, 208, 0],
+ [255, 209, 0],
+ [255, 210, 0],
+ [255, 211, 0],
+ [255, 212, 0],
+ [255, 213, 0],
+ [255, 214, 0],
+ [255, 215, 0],
+ [255, 216, 0],
+ [255, 217, 0],
+ [255, 218, 0],
+ [255, 219, 0],
+ [255, 220, 0],
+ [255, 221, 0],
+ [255, 222, 0],
+ [255, 223, 0],
+ [255, 224, 0],
+ [255, 225, 0],
+ [255, 226, 0],
+ [255, 227, 0],
+ [255, 228, 0],
+ [255, 229, 0],
+ [255, 230, 0],
+ [255, 231, 0],
+ [255, 232, 0],
+ [255, 233, 0],
+ [255, 234, 0],
+ [255, 235, 0],
+ [255, 236, 0],
+ [255, 237, 0],
+ [255, 238, 0],
+ [255, 239, 0],
+ [255, 240, 0],
+ [255, 241, 0],
+ [255, 242, 0],
+ [255, 243, 0],
+ [255, 244, 0],
+ [255, 245, 0],
+ [255, 246, 0],
+ [255, 247, 0],
+ [255, 248, 0],
+ [255, 249, 0],
+ [255, 250, 0],
+ [255, 251, 0],
+ [255, 252, 0],
+ [255, 253, 0],
+ [255, 254, 0],
+ [255, 255, 0],
+ [254, 255, 0],
+ [253, 255, 0],
+ [252, 255, 0],
+ [251, 255, 0],
+ [250, 255, 0],
+ [249, 255, 0],
+ [248, 255, 0],
+ [247, 255, 0],
+ [246, 255, 0],
+ [245, 255, 0],
+ [244, 255, 0],
+ [243, 255, 0],
+ [242, 255, 0],
+ [241, 255, 0],
+ [240, 255, 0],
+ [239, 255, 0],
+ [238, 255, 0],
+ [237, 255, 0],
+ [236, 255, 0],
+ [235, 255, 0],
+ [234, 255, 0],
+ [233, 255, 0],
+ [232, 255, 0],
+ [231, 255, 0],
+ [230, 255, 0],
+ [229, 255, 0],
+ [228, 255, 0],
+ [227, 255, 0],
+ [226, 255, 0],
+ [225, 255, 0],
+ [224, 255, 0],
+ [223, 255, 0],
+ [222, 255, 0],
+ [221, 255, 0],
+ [220, 255, 0],
+ [219, 255, 0],
+ [218, 255, 0],
+ [217, 255, 0],
+ [216, 255, 0],
+ [215, 255, 0],
+ [214, 255, 0],
+ [213, 255, 0],
+ [212, 255, 0],
+ [211, 255, 0],
+ [210, 255, 0],
+ [209, 255, 0],
+ [208, 255, 0],
+ [207, 255, 0],
+ [206, 255, 0],
+ [205, 255, 0],
+ [204, 255, 0],
+ [203, 255, 0],
+ [202, 255, 0],
+ [201, 255, 0],
+ [200, 255, 0],
+ [199, 255, 0],
+ [198, 255, 0],
+ [197, 255, 0],
+ [196, 255, 0],
+ [195, 255, 0],
+ [194, 255, 0],
+ [193, 255, 0],
+ [192, 255, 0],
+ [191, 255, 0],
+ [190, 255, 0],
+ [189, 255, 0],
+ [188, 255, 0],
+ [187, 255, 0],
+ [186, 255, 0],
+ [185, 255, 0],
+ [184, 255, 0],
+ [183, 255, 0],
+ [182, 255, 0],
+ [181, 255, 0],
+ [180, 255, 0],
+ [179, 255, 0],
+ [178, 255, 0],
+ [177, 255, 0],
+ [176, 255, 0],
+ [175, 255, 0],
+ [174, 255, 0],
+ [173, 255, 0],
+ [172, 255, 0],
+ [171, 255, 0],
+ [170, 255, 0],
+ [169, 255, 0],
+ [168, 255, 0],
+ [167, 255, 0],
+ [166, 255, 0],
+ [165, 255, 0],
+ [164, 255, 0],
+ [163, 255, 0],
+ [162, 255, 0],
+ [161, 255, 0],
+ [160, 255, 0],
+ [159, 255, 0],
+ [158, 255, 0],
+ [157, 255, 0],
+ [156, 255, 0],
+ [155, 255, 0],
+ [154, 255, 0],
+ [153, 255, 0],
+ [152, 255, 0],
+ [151, 255, 0],
+ [150, 255, 0],
+ [149, 255, 0],
+ [148, 255, 0],
+ [147, 255, 0],
+ [146, 255, 0],
+ [145, 255, 0],
+ [144, 255, 0],
+ [143, 255, 0],
+ [142, 255, 0],
+ [141, 255, 0],
+ [140, 255, 0],
+ [139, 255, 0],
+ [138, 255, 0],
+ [137, 255, 0],
+ [136, 255, 0],
+ [135, 255, 0],
+ [134, 255, 0],
+ [133, 255, 0],
+ [132, 255, 0],
+ [131, 255, 0],
+ [130, 255, 0],
+ [129, 255, 0],
+ [128, 255, 0],
+ [127, 255, 0],
+ [126, 255, 0],
+ [125, 255, 0],
+ [124, 255, 0],
+ [123, 255, 0],
+ [122, 255, 0],
+ [121, 255, 0],
+ [120, 255, 0],
+ [119, 255, 0],
+ [118, 255, 0],
+ [117, 255, 0],
+ [116, 255, 0],
+ [115, 255, 0],
+ [114, 255, 0],
+ [113, 255, 0],
+ [112, 255, 0],
+ [111, 255, 0],
+ [110, 255, 0],
+ [109, 255, 0],
+ [108, 255, 0],
+ [107, 255, 0],
+ [106, 255, 0],
+ [105, 255, 0],
+ [104, 255, 0],
+ [103, 255, 0],
+ [102, 255, 0],
+ [101, 255, 0],
+ [100, 255, 0],
+ [99, 255, 0],
+ [98, 255, 0],
+ [97, 255, 0],
+ [96, 255, 0],
+ [95, 255, 0],
+ [94, 255, 0],
+ [93, 255, 0],
+ [92, 255, 0],
+ [91, 255, 0],
+ [90, 255, 0],
+ [89, 255, 0],
+ [88, 255, 0],
+ [87, 255, 0],
+ [86, 255, 0],
+ [85, 255, 0],
+ [84, 255, 0],
+ [83, 255, 0],
+ [82, 255, 0],
+ [81, 255, 0],
+ [80, 255, 0],
+ [79, 255, 0],
+ [78, 255, 0],
+ [77, 255, 0],
+ [76, 255, 0],
+ [75, 255, 0],
+ [74, 255, 0],
+ [73, 255, 0],
+ [72, 255, 0],
+ [71, 255, 0],
+ [70, 255, 0],
+ [69, 255, 0],
+ [68, 255, 0],
+ [67, 255, 0],
+ [66, 255, 0],
+ [65, 255, 0],
+ [64, 255, 0],
+ [63, 255, 0],
+ [62, 255, 0],
+ [61, 255, 0],
+ [60, 255, 0],
+ [59, 255, 0],
+ [58, 255, 0],
+ [57, 255, 0],
+ [56, 255, 0],
+ [55, 255, 0],
+ [54, 255, 0],
+ [53, 255, 0],
+ [52, 255, 0],
+ [51, 255, 0],
+ [50, 255, 0],
+ [49, 255, 0],
+ [48, 255, 0],
+ [47, 255, 0],
+ [46, 255, 0],
+ [45, 255, 0],
+ [44, 255, 0],
+ [43, 255, 0],
+ [42, 255, 0],
+ [41, 255, 0],
+ [40, 255, 0],
+ [39, 255, 0],
+ [38, 255, 0],
+ [37, 255, 0],
+ [36, 255, 0],
+ [35, 255, 0],
+ [34, 255, 0],
+ [33, 255, 0],
+ [32, 255, 0],
+ [31, 255, 0],
+ [30, 255, 0],
+ [29, 255, 0],
+ [28, 255, 0],
+ [27, 255, 0],
+ [26, 255, 0],
+ [25, 255, 0],
+ [24, 255, 0],
+ [23, 255, 0],
+ [22, 255, 0],
+ [21, 255, 0],
+ [20, 255, 0],
+ [19, 255, 0],
+ [18, 255, 0],
+ [17, 255, 0],
+ [16, 255, 0],
+ [15, 255, 0],
+ [14, 255, 0],
+ [13, 255, 0],
+ [12, 255, 0],
+ [11, 255, 0],
+ [10, 255, 0],
+ [9, 255, 0],
+ [8, 255, 0],
+ [7, 255, 0],
+ [6, 255, 0],
+ [5, 255, 0],
+ [4, 255, 0],
+ [3, 255, 0],
+ [2, 255, 0],
+ [1, 255, 0],
+ [0, 255, 0],
+ [0, 255, 1],
+ [0, 255, 2],
+ [0, 255, 3],
+ [0, 255, 4],
+ [0, 255, 5],
+ [0, 255, 6],
+ [0, 255, 7],
+ [0, 255, 8],
+ [0, 255, 9],
+ [0, 255, 10],
+ [0, 255, 11],
+ [0, 255, 12],
+ [0, 255, 13],
+ [0, 255, 14],
+ [0, 255, 15],
+ [0, 255, 16],
+ [0, 255, 17],
+ [0, 255, 18],
+ [0, 255, 19],
+ [0, 255, 20],
+ [0, 255, 21],
+ [0, 255, 22],
+ [0, 255, 23],
+ [0, 255, 24],
+ [0, 255, 25],
+ [0, 255, 26],
+ [0, 255, 27],
+ [0, 255, 28],
+ [0, 255, 29],
+ [0, 255, 30],
+ [0, 255, 31],
+ [0, 255, 32],
+ [0, 255, 33],
+ [0, 255, 34],
+ [0, 255, 35],
+ [0, 255, 36],
+ [0, 255, 37],
+ [0, 255, 38],
+ [0, 255, 39],
+ [0, 255, 40],
+ [0, 255, 41],
+ [0, 255, 42],
+ [0, 255, 43],
+ [0, 255, 44],
+ [0, 255, 45],
+ [0, 255, 46],
+ [0, 255, 47],
+ [0, 255, 48],
+ [0, 255, 49],
+ [0, 255, 50],
+ [0, 255, 51],
+ [0, 255, 52],
+ [0, 255, 53],
+ [0, 255, 54],
+ [0, 255, 55],
+ [0, 255, 56],
+ [0, 255, 57],
+ [0, 255, 58],
+ [0, 255, 59],
+ [0, 255, 60],
+ [0, 255, 61],
+ [0, 255, 62],
+ [0, 255, 63],
+ [0, 255, 64],
+ [0, 255, 65],
+ [0, 255, 66],
+ [0, 255, 67],
+ [0, 255, 68],
+ [0, 255, 69],
+ [0, 255, 70],
+ [0, 255, 71],
+ [0, 255, 72],
+ [0, 255, 73],
+ [0, 255, 74],
+ [0, 255, 75],
+ [0, 255, 76],
+ [0, 255, 77],
+ [0, 255, 78],
+ [0, 255, 79],
+ [0, 255, 80],
+ [0, 255, 81],
+ [0, 255, 82],
+ [0, 255, 83],
+ [0, 255, 84],
+ [0, 255, 85],
+ [0, 255, 86],
+ [0, 255, 87],
+ [0, 255, 88],
+ [0, 255, 89],
+ [0, 255, 90],
+ [0, 255, 91],
+ [0, 255, 92],
+ [0, 255, 93],
+ [0, 255, 94],
+ [0, 255, 95],
+ [0, 255, 96],
+ [0, 255, 97],
+ [0, 255, 98],
+ [0, 255, 99],
+ [0, 255, 100],
+ [0, 255, 101],
+ [0, 255, 102],
+ [0, 255, 103],
+ [0, 255, 104],
+ [0, 255, 105],
+ [0, 255, 106],
+ [0, 255, 107],
+ [0, 255, 108],
+ [0, 255, 109],
+ [0, 255, 110],
+ [0, 255, 111],
+ [0, 255, 112],
+ [0, 255, 113],
+ [0, 255, 114],
+ [0, 255, 115],
+ [0, 255, 116],
+ [0, 255, 117],
+ [0, 255, 118],
+ [0, 255, 119],
+ [0, 255, 120],
+ [0, 255, 121],
+ [0, 255, 122],
+ [0, 255, 123],
+ [0, 255, 124],
+ [0, 255, 125],
+ [0, 255, 126],
+ [0, 255, 127],
+ [0, 255, 128],
+ [0, 255, 129],
+ [0, 255, 130],
+ [0, 255, 131],
+ [0, 255, 132],
+ [0, 255, 133],
+ [0, 255, 134],
+ [0, 255, 135],
+ [0, 255, 136],
+ [0, 255, 137],
+ [0, 255, 138],
+ [0, 255, 139],
+ [0, 255, 140],
+ [0, 255, 141],
+ [0, 255, 142],
+ [0, 255, 143],
+ [0, 255, 144],
+ [0, 255, 145],
+ [0, 255, 146],
+ [0, 255, 147],
+ [0, 255, 148],
+ [0, 255, 149],
+ [0, 255, 150],
+ [0, 255, 151],
+ [0, 255, 152],
+ [0, 255, 153],
+ [0, 255, 154],
+ [0, 255, 155],
+ [0, 255, 156],
+ [0, 255, 157],
+ [0, 255, 158],
+ [0, 255, 159],
+ [0, 255, 160],
+ [0, 255, 161],
+ [0, 255, 162],
+ [0, 255, 163],
+ [0, 255, 164],
+ [0, 255, 165],
+ [0, 255, 166],
+ [0, 255, 167],
+ [0, 255, 168],
+ [0, 255, 169],
+ [0, 255, 170],
+ [0, 255, 171],
+ [0, 255, 172],
+ [0, 255, 173],
+ [0, 255, 174],
+ [0, 255, 175],
+ [0, 255, 176],
+ [0, 255, 177],
+ [0, 255, 178],
+ [0, 255, 179],
+ [0, 255, 180],
+ [0, 255, 181],
+ [0, 255, 182],
+ [0, 255, 183],
+ [0, 255, 184],
+ [0, 255, 185],
+ [0, 255, 186],
+ [0, 255, 187],
+ [0, 255, 188],
+ [0, 255, 189],
+ [0, 255, 190],
+ [0, 255, 191],
+ [0, 255, 192],
+ [0, 255, 193],
+ [0, 255, 194],
+ [0, 255, 195],
+ [0, 255, 196],
+ [0, 255, 197],
+ [0, 255, 198],
+ [0, 255, 199],
+ [0, 255, 200],
+ [0, 255, 201],
+ [0, 255, 202],
+ [0, 255, 203],
+ [0, 255, 204],
+ [0, 255, 205],
+ [0, 255, 206],
+ [0, 255, 207],
+ [0, 255, 208],
+ [0, 255, 209],
+ [0, 255, 210],
+ [0, 255, 211],
+ [0, 255, 212],
+ [0, 255, 213],
+ [0, 255, 214],
+ [0, 255, 215],
+ [0, 255, 216],
+ [0, 255, 217],
+ [0, 255, 218],
+ [0, 255, 219],
+ [0, 255, 220],
+ [0, 255, 221],
+ [0, 255, 222],
+ [0, 255, 223],
+ [0, 255, 224],
+ [0, 255, 225],
+ [0, 255, 226],
+ [0, 255, 227],
+ [0, 255, 228],
+ [0, 255, 229],
+ [0, 255, 230],
+ [0, 255, 231],
+ [0, 255, 232],
+ [0, 255, 233],
+ [0, 255, 234],
+ [0, 255, 235],
+ [0, 255, 236],
+ [0, 255, 237],
+ [0, 255, 238],
+ [0, 255, 239],
+ [0, 255, 240],
+ [0, 255, 241],
+ [0, 255, 242],
+ [0, 255, 243],
+ [0, 255, 244],
+ [0, 255, 245],
+ [0, 255, 246],
+ [0, 255, 247],
+ [0, 255, 248],
+ [0, 255, 249],
+ [0, 255, 250],
+ [0, 255, 251],
+ [0, 255, 252],
+ [0, 255, 253],
+ [0, 255, 254],
+ [0, 255, 255],
+ [0, 254, 255],
+ [0, 253, 255],
+ [0, 252, 255],
+ [0, 251, 255],
+ [0, 250, 255],
+ [0, 249, 255],
+ [0, 248, 255],
+ [0, 247, 255],
+ [0, 246, 255],
+ [0, 245, 255],
+ [0, 244, 255],
+ [0, 243, 255],
+ [0, 242, 255],
+ [0, 241, 255],
+ [0, 240, 255],
+ [0, 239, 255],
+ [0, 238, 255],
+ [0, 237, 255],
+ [0, 236, 255],
+ [0, 235, 255],
+ [0, 234, 255],
+ [0, 233, 255],
+ [0, 232, 255],
+ [0, 231, 255],
+ [0, 230, 255],
+ [0, 229, 255],
+ [0, 228, 255],
+ [0, 227, 255],
+ [0, 226, 255],
+ [0, 225, 255],
+ [0, 224, 255],
+ [0, 223, 255],
+ [0, 222, 255],
+ [0, 221, 255],
+ [0, 220, 255],
+ [0, 219, 255],
+ [0, 218, 255],
+ [0, 217, 255],
+ [0, 216, 255],
+ [0, 215, 255],
+ [0, 214, 255],
+ [0, 213, 255],
+ [0, 212, 255],
+ [0, 211, 255],
+ [0, 210, 255],
+ [0, 209, 255],
+ [0, 208, 255],
+ [0, 207, 255],
+ [0, 206, 255],
+ [0, 205, 255],
+ [0, 204, 255],
+ [0, 203, 255],
+ [0, 202, 255],
+ [0, 201, 255],
+ [0, 200, 255],
+ [0, 199, 255],
+ [0, 198, 255],
+ [0, 197, 255],
+ [0, 196, 255],
+ [0, 195, 255],
+ [0, 194, 255],
+ [0, 193, 255],
+ [0, 192, 255],
+ [0, 191, 255],
+ [0, 190, 255],
+ [0, 189, 255],
+ [0, 188, 255],
+ [0, 187, 255],
+ [0, 186, 255],
+ [0, 185, 255],
+ [0, 184, 255],
+ [0, 183, 255],
+ [0, 182, 255],
+ [0, 181, 255],
+ [0, 180, 255],
+ [0, 179, 255],
+ [0, 178, 255],
+ [0, 177, 255],
+ [0, 176, 255],
+ [0, 175, 255],
+ [0, 174, 255],
+ [0, 173, 255],
+ [0, 172, 255],
+ [0, 171, 255],
+ [0, 170, 255],
+ [0, 169, 255],
+ [0, 168, 255],
+ [0, 167, 255],
+ [0, 166, 255],
+ [0, 165, 255],
+ [0, 164, 255],
+ [0, 163, 255],
+ [0, 162, 255],
+ [0, 161, 255],
+ [0, 160, 255],
+ [0, 159, 255],
+ [0, 158, 255],
+ [0, 157, 255],
+ [0, 156, 255],
+ [0, 155, 255],
+ [0, 154, 255],
+ [0, 153, 255],
+ [0, 152, 255],
+ [0, 151, 255],
+ [0, 150, 255],
+ [0, 149, 255],
+ [0, 148, 255],
+ [0, 147, 255],
+ [0, 146, 255],
+ [0, 145, 255],
+ [0, 144, 255],
+ [0, 143, 255],
+ [0, 142, 255],
+ [0, 141, 255],
+ [0, 140, 255],
+ [0, 139, 255],
+ [0, 138, 255],
+ [0, 137, 255],
+ [0, 136, 255],
+ [0, 135, 255],
+ [0, 134, 255],
+ [0, 133, 255],
+ [0, 132, 255],
+ [0, 131, 255],
+ [0, 130, 255],
+ [0, 129, 255],
+ [0, 128, 255],
+ [0, 127, 255],
+ [0, 126, 255],
+ [0, 125, 255],
+ [0, 124, 255],
+ [0, 123, 255],
+ [0, 122, 255],
+ [0, 121, 255],
+ [0, 120, 255],
+ [0, 119, 255],
+ [0, 118, 255],
+ [0, 117, 255],
+ [0, 116, 255],
+ [0, 115, 255],
+ [0, 114, 255],
+ [0, 113, 255],
+ [0, 112, 255],
+ [0, 111, 255],
+ [0, 110, 255],
+ [0, 109, 255],
+ [0, 108, 255],
+ [0, 107, 255],
+ [0, 106, 255],
+ [0, 105, 255],
+ [0, 104, 255],
+ [0, 103, 255],
+ [0, 102, 255],
+ [0, 101, 255],
+ [0, 100, 255],
+ [0, 99, 255],
+ [0, 98, 255],
+ [0, 97, 255],
+ [0, 96, 255],
+ [0, 95, 255],
+ [0, 94, 255],
+ [0, 93, 255],
+ [0, 92, 255],
+ [0, 91, 255],
+ [0, 90, 255],
+ [0, 89, 255],
+ [0, 88, 255],
+ [0, 87, 255],
+ [0, 86, 255],
+ [0, 85, 255],
+ [0, 84, 255],
+ [0, 83, 255],
+ [0, 82, 255],
+ [0, 81, 255],
+ [0, 80, 255],
+ [0, 79, 255],
+ [0, 78, 255],
+ [0, 77, 255],
+ [0, 76, 255],
+ [0, 75, 255],
+ [0, 74, 255],
+ [0, 73, 255],
+ [0, 72, 255],
+ [0, 71, 255],
+ [0, 70, 255],
+ [0, 69, 255],
+ [0, 68, 255],
+ [0, 67, 255],
+ [0, 66, 255],
+ [0, 65, 255],
+ [0, 64, 255],
+ [0, 63, 255],
+ [0, 62, 255],
+ [0, 61, 255],
+ [0, 60, 255],
+ [0, 59, 255],
+ [0, 58, 255],
+ [0, 57, 255],
+ [0, 56, 255],
+ [0, 55, 255],
+ [0, 54, 255],
+ [0, 53, 255],
+ [0, 52, 255],
+ [0, 51, 255],
+ [0, 50, 255],
+ [0, 49, 255],
+ [0, 48, 255],
+ [0, 47, 255],
+ [0, 46, 255],
+ [0, 45, 255],
+ [0, 44, 255],
+ [0, 43, 255],
+ [0, 42, 255],
+ [0, 41, 255],
+ [0, 40, 255],
+ [0, 39, 255],
+ [0, 38, 255],
+ [0, 37, 255],
+ [0, 36, 255],
+ [0, 35, 255],
+ [0, 34, 255],
+ [0, 33, 255],
+ [0, 32, 255],
+ [0, 31, 255],
+ [0, 30, 255],
+ [0, 29, 255],
+ [0, 28, 255],
+ [0, 27, 255],
+ [0, 26, 255],
+ [0, 25, 255],
+ [0, 24, 255],
+ [0, 23, 255],
+ [0, 22, 255],
+ [0, 21, 255],
+ [0, 20, 255],
+ [0, 19, 255],
+ [0, 18, 255],
+ [0, 17, 255],
+ [0, 16, 255],
+ [0, 15, 255],
+ [0, 14, 255],
+ [0, 13, 255],
+ [0, 12, 255],
+ [0, 11, 255],
+ [0, 10, 255],
+ [0, 9, 255],
+ [0, 8, 255],
+ [0, 7, 255],
+ [0, 6, 255],
+ [0, 5, 255],
+ [0, 4, 255],
+ [0, 3, 255],
+ [0, 2, 255],
+ [0, 1, 255],
+ [0, 0, 255],
+ [1, 0, 255],
+ [2, 0, 255],
+ [3, 0, 255],
+ [4, 0, 255],
+ [5, 0, 255],
+ [6, 0, 255],
+ [7, 0, 255],
+ [8, 0, 255],
+ [9, 0, 255],
+ [10, 0, 255],
+ [11, 0, 255],
+ [12, 0, 255],
+ [13, 0, 255],
+ [14, 0, 255],
+ [15, 0, 255],
+ [16, 0, 255],
+ [17, 0, 255],
+ [18, 0, 255],
+ [19, 0, 255],
+ [20, 0, 255],
+ [21, 0, 255],
+ [22, 0, 255],
+ [23, 0, 255],
+ [24, 0, 255],
+ [25, 0, 255],
+ [26, 0, 255],
+ [27, 0, 255],
+ [28, 0, 255],
+ [29, 0, 255],
+ [30, 0, 255],
+ [31, 0, 255],
+ [32, 0, 255],
+ [33, 0, 255],
+ [34, 0, 255],
+ [35, 0, 255],
+ [36, 0, 255],
+ [37, 0, 255],
+ [38, 0, 255],
+ [39, 0, 255],
+ [40, 0, 255],
+ [41, 0, 255],
+ [42, 0, 255],
+ [43, 0, 255],
+ [44, 0, 255],
+ [45, 0, 255],
+ [46, 0, 255],
+ [47, 0, 255],
+ [48, 0, 255],
+ [49, 0, 255],
+ [50, 0, 255],
+ [51, 0, 255],
+ [52, 0, 255],
+ [53, 0, 255],
+ [54, 0, 255],
+ [55, 0, 255],
+ [56, 0, 255],
+ [57, 0, 255],
+ [58, 0, 255],
+ [59, 0, 255],
+ [60, 0, 255],
+ [61, 0, 255],
+ [62, 0, 255],
+ [63, 0, 255],
+ [64, 0, 255],
+ [65, 0, 255],
+ [66, 0, 255],
+ [67, 0, 255],
+ [68, 0, 255],
+ [69, 0, 255],
+ [70, 0, 255],
+ [71, 0, 255],
+ [72, 0, 255],
+ [73, 0, 255],
+ [74, 0, 255],
+ [75, 0, 255],
+ [76, 0, 255],
+ [77, 0, 255],
+ [78, 0, 255],
+ [79, 0, 255],
+ [80, 0, 255],
+ [81, 0, 255],
+ [82, 0, 255],
+ [83, 0, 255],
+ [84, 0, 255],
+ [85, 0, 255],
+ [86, 0, 255],
+ [87, 0, 255],
+ [88, 0, 255],
+ [89, 0, 255],
+ [90, 0, 255],
+ [91, 0, 255],
+ [92, 0, 255],
+ [93, 0, 255],
+ [94, 0, 255],
+ [95, 0, 255],
+ [96, 0, 255],
+ [97, 0, 255],
+ [98, 0, 255],
+ [99, 0, 255],
+ [100, 0, 255],
+ [101, 0, 255],
+ [102, 0, 255],
+ [103, 0, 255],
+ [104, 0, 255],
+ [105, 0, 255],
+ [106, 0, 255],
+ [107, 0, 255],
+ [108, 0, 255],
+ [109, 0, 255],
+ [110, 0, 255],
+ [111, 0, 255],
+ [112, 0, 255],
+ [113, 0, 255],
+ [114, 0, 255],
+ [115, 0, 255],
+ [116, 0, 255],
+ [117, 0, 255],
+ [118, 0, 255],
+ [119, 0, 255],
+ [120, 0, 255],
+ [121, 0, 255],
+ [122, 0, 255],
+ [123, 0, 255],
+ [124, 0, 255],
+ [125, 0, 255],
+ [126, 0, 255],
+ [127, 0, 255],
+ [128, 0, 255],
+ [129, 0, 255],
+ [130, 0, 255],
+ [131, 0, 255],
+ [132, 0, 255],
+ [133, 0, 255],
+ [134, 0, 255],
+ [135, 0, 255],
+ [136, 0, 255],
+ [137, 0, 255],
+ [138, 0, 255],
+ [139, 0, 255],
+ [140, 0, 255],
+ [141, 0, 255],
+ [142, 0, 255],
+ [143, 0, 255],
+ [144, 0, 255],
+ [145, 0, 255],
+ [146, 0, 255],
+ [147, 0, 255],
+ [148, 0, 255],
+ [149, 0, 255],
+ [150, 0, 255],
+ [151, 0, 255],
+ [152, 0, 255],
+ [153, 0, 255],
+ [154, 0, 255],
+ [155, 0, 255],
+ [156, 0, 255],
+ [157, 0, 255],
+ [158, 0, 255],
+ [159, 0, 255],
+ [160, 0, 255],
+ [161, 0, 255],
+ [162, 0, 255],
+ [163, 0, 255],
+ [164, 0, 255],
+ [165, 0, 255],
+ [166, 0, 255],
+ [167, 0, 255],
+ [168, 0, 255],
+ [169, 0, 255],
+ [170, 0, 255],
+ [171, 0, 255],
+ [172, 0, 255],
+ [173, 0, 255],
+ [174, 0, 255],
+ [175, 0, 255],
+ [176, 0, 255],
+ [177, 0, 255],
+ [178, 0, 255],
+ [179, 0, 255],
+ [180, 0, 255],
+ [181, 0, 255],
+ [182, 0, 255],
+ [183, 0, 255],
+ [184, 0, 255],
+ [185, 0, 255],
+ [186, 0, 255],
+ [187, 0, 255],
+ [188, 0, 255],
+ [189, 0, 255],
+ [190, 0, 255],
+ [191, 0, 255],
+ [192, 0, 255],
+ [193, 0, 255],
+ [194, 0, 255],
+ [195, 0, 255],
+ [196, 0, 255],
+ [197, 0, 255],
+ [198, 0, 255],
+ [199, 0, 255],
+ [200, 0, 255],
+ [201, 0, 255],
+ [202, 0, 255],
+ [203, 0, 255],
+ [204, 0, 255],
+ [205, 0, 255],
+ [206, 0, 255],
+ [207, 0, 255],
+ [208, 0, 255],
+ [209, 0, 255],
+ [210, 0, 255],
+ [211, 0, 255],
+ [212, 0, 255],
+ [213, 0, 255],
+ [214, 0, 255],
+ [215, 0, 255],
+ [216, 0, 255],
+ [217, 0, 255],
+ [218, 0, 255],
+ [219, 0, 255],
+ [220, 0, 255],
+ [221, 0, 255],
+ [222, 0, 255],
+ [223, 0, 255],
+ [224, 0, 255],
+ [225, 0, 255],
+ [226, 0, 255],
+ [227, 0, 255],
+ [228, 0, 255],
+ [229, 0, 255],
+ [230, 0, 255],
+ [231, 0, 255],
+ [232, 0, 255],
+ [233, 0, 255],
+ [234, 0, 255],
+ [235, 0, 255],
+ [236, 0, 255],
+ [237, 0, 255],
+ [238, 0, 255],
+ [239, 0, 255],
+ [240, 0, 255],
+ [241, 0, 255],
+ [242, 0, 255],
+ [243, 0, 255],
+ [244, 0, 255],
+ [245, 0, 255],
+ [246, 0, 255],
+ [247, 0, 255],
+ [248, 0, 255],
+ [249, 0, 255],
+ [250, 0, 255],
+ [251, 0, 255],
+ [252, 0, 255],
+ [253, 0, 255],
+ [254, 0, 255],
+ [255, 0, 255],
+ [255, 0, 254],
+ [255, 0, 253],
+ [255, 0, 252],
+ [255, 0, 251],
+ [255, 0, 250],
+ [255, 0, 249],
+ [255, 0, 248],
+ [255, 0, 247],
+ [255, 0, 246],
+ [255, 0, 245],
+ [255, 0, 244],
+ [255, 0, 243],
+ [255, 0, 242],
+ [255, 0, 241],
+ [255, 0, 240],
+ [255, 0, 239],
+ [255, 0, 238],
+ [255, 0, 237],
+ [255, 0, 236],
+ [255, 0, 235],
+ [255, 0, 234],
+ [255, 0, 233],
+ [255, 0, 232],
+ [255, 0, 231],
+ [255, 0, 230],
+ [255, 0, 229],
+ [255, 0, 228],
+ [255, 0, 227],
+ [255, 0, 226],
+ [255, 0, 225],
+ [255, 0, 224],
+ [255, 0, 223],
+ [255, 0, 222],
+ [255, 0, 221],
+ [255, 0, 220],
+ [255, 0, 219],
+ [255, 0, 218],
+ [255, 0, 217],
+ [255, 0, 216],
+ [255, 0, 215],
+ [255, 0, 214],
+ [255, 0, 213],
+ [255, 0, 212],
+ [255, 0, 211],
+ [255, 0, 210],
+ [255, 0, 209],
+ [255, 0, 208],
+ [255, 0, 207],
+ [255, 0, 206],
+ [255, 0, 205],
+ [255, 0, 204],
+ [255, 0, 203],
+ [255, 0, 202],
+ [255, 0, 201],
+ [255, 0, 200],
+ [255, 0, 199],
+ [255, 0, 198],
+ [255, 0, 197],
+ [255, 0, 196],
+ [255, 0, 195],
+ [255, 0, 194],
+ [255, 0, 193],
+ [255, 0, 192],
+ [255, 0, 191],
+ [255, 0, 190],
+ [255, 0, 189],
+ [255, 0, 188],
+ [255, 0, 187],
+ [255, 0, 186],
+ [255, 0, 185],
+ [255, 0, 184],
+ [255, 0, 183],
+ [255, 0, 182],
+ [255, 0, 181],
+ [255, 0, 180],
+ [255, 0, 179],
+ [255, 0, 178],
+ [255, 0, 177],
+ [255, 0, 176],
+ [255, 0, 175],
+ [255, 0, 174],
+ [255, 0, 173],
+ [255, 0, 172],
+ [255, 0, 171],
+ [255, 0, 170],
+ [255, 0, 169],
+ [255, 0, 168],
+ [255, 0, 167],
+ [255, 0, 166],
+ [255, 0, 165],
+ [255, 0, 164],
+ [255, 0, 163],
+ [255, 0, 162],
+ [255, 0, 161],
+ [255, 0, 160],
+ [255, 0, 159],
+ [255, 0, 158],
+ [255, 0, 157],
+ [255, 0, 156],
+ [255, 0, 155],
+ [255, 0, 154],
+ [255, 0, 153],
+ [255, 0, 152],
+ [255, 0, 151],
+ [255, 0, 150],
+ [255, 0, 149],
+ [255, 0, 148],
+ [255, 0, 147],
+ [255, 0, 146],
+ [255, 0, 145],
+ [255, 0, 144],
+ [255, 0, 143],
+ [255, 0, 142],
+ [255, 0, 141],
+ [255, 0, 140],
+ [255, 0, 139],
+ [255, 0, 138],
+ [255, 0, 137],
+ [255, 0, 136],
+ [255, 0, 135],
+ [255, 0, 134],
+ [255, 0, 133],
+ [255, 0, 132],
+ [255, 0, 131],
+ [255, 0, 130],
+ [255, 0, 129],
+ [255, 0, 128],
+ [255, 0, 127],
+ [255, 0, 126],
+ [255, 0, 125],
+ [255, 0, 124],
+ [255, 0, 123],
+ [255, 0, 122],
+ [255, 0, 121],
+ [255, 0, 120],
+ [255, 0, 119],
+ [255, 0, 118],
+ [255, 0, 117],
+ [255, 0, 116],
+ [255, 0, 115],
+ [255, 0, 114],
+ [255, 0, 113],
+ [255, 0, 112],
+ [255, 0, 111],
+ [255, 0, 110],
+ [255, 0, 109],
+ [255, 0, 108],
+ [255, 0, 107],
+ [255, 0, 106],
+ [255, 0, 105],
+ [255, 0, 104],
+ [255, 0, 103],
+ [255, 0, 102],
+ [255, 0, 101],
+ [255, 0, 100],
+ [255, 0, 99],
+ [255, 0, 98],
+ [255, 0, 97],
+ [255, 0, 96],
+ [255, 0, 95],
+ [255, 0, 94],
+ [255, 0, 93],
+ [255, 0, 92],
+ [255, 0, 91],
+ [255, 0, 90],
+ [255, 0, 89],
+ [255, 0, 88],
+ [255, 0, 87],
+ [255, 0, 86],
+ [255, 0, 85],
+ [255, 0, 84],
+ [255, 0, 83],
+ [255, 0, 82],
+ [255, 0, 81],
+ [255, 0, 80],
+ [255, 0, 79],
+ [255, 0, 78],
+ [255, 0, 77],
+ [255, 0, 76],
+ [255, 0, 75],
+ [255, 0, 74],
+ [255, 0, 73],
+ [255, 0, 72],
+ [255, 0, 71],
+ [255, 0, 70],
+ [255, 0, 69],
+ [255, 0, 68],
+ [255, 0, 67],
+ [255, 0, 66],
+ [255, 0, 65],
+ [255, 0, 64],
+ [255, 0, 63],
+ [255, 0, 62],
+ [255, 0, 61],
+ [255, 0, 60],
+ [255, 0, 59],
+ [255, 0, 58],
+ [255, 0, 57],
+ [255, 0, 56],
+ [255, 0, 55],
+ [255, 0, 54],
+ [255, 0, 53],
+ [255, 0, 52],
+ [255, 0, 51],
+ [255, 0, 50],
+ [255, 0, 49],
+ [255, 0, 48],
+ [255, 0, 47],
+ [255, 0, 46],
+ [255, 0, 45],
+ [255, 0, 44],
+ [255, 0, 43],
+ [255, 0, 42],
+ [255, 0, 41],
+ [255, 0, 40],
+ [255, 0, 39],
+ [255, 0, 38],
+ [255, 0, 37],
+ [255, 0, 36],
+ [255, 0, 35],
+ [255, 0, 34],
+ [255, 0, 33],
+ [255, 0, 32],
+ [255, 0, 31],
+ [255, 0, 30],
+ [255, 0, 29],
+ [255, 0, 28],
+ [255, 0, 27],
+ [255, 0, 26],
+ [255, 0, 25],
+ [255, 0, 24],
+ [255, 0, 23],
+ [255, 0, 22],
+ [255, 0, 21],
+ [255, 0, 20],
+ [255, 0, 19],
+ [255, 0, 18],
+ [255, 0, 17],
+ [255, 0, 16],
+ [255, 0, 15],
+ [255, 0, 14],
+ [255, 0, 13],
+ [255, 0, 12],
+ [255, 0, 11],
+ [255, 0, 10],
+ [255, 0, 9],
+ [255, 0, 8],
+ [255, 0, 7],
+ [255, 0, 6],
+ [255, 0, 5],
+ [255, 0, 4],
+ [255, 0, 3],
+ [255, 0, 2],
+ [255, 0, 1],
+ [255, 0, 0],
+];
diff --git a/color_component.ts b/color_component.ts
new file mode 100644
index 0000000..31a2b76
--- /dev/null
+++ b/color_component.ts
@@ -0,0 +1,18 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+/**
+ * [ColorComponent] can be red, green or blue, being the lightness
+ * of that color.
+ *
+ * [ColorComponent]: https://en.wikipedia.org/wiki/RGB_color_model
+ */
+export class ColorComponent {
+ public readonly lightness: number = 0;
+
+ /**
+ * @param lightness - A numerical range from `0` to `255`.
+ */
+ public constructor(lightness: number) {
+ this.lightness = Math.min(Math.max(lightness, 0), 255);
+ }
+}
diff --git a/color_effects/discolor.ts b/color_effects/discolor.ts
new file mode 100644
index 0000000..42bd136
--- /dev/null
+++ b/color_effects/discolor.ts
@@ -0,0 +1,24 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { Color } from "../color.ts";
+
+/**
+ * ### Example
+ *
+ * ```ts
+ * const red = new Color(false, 255, 0, 0);
+ * const white = new Color(false, 255, 255, 255);
+ *
+ * const grey = discolor(red);
+ * console.log(grey.components); // [85, 85, 85]
+ *
+ * const _white = discolor(white);
+ * console.log(_white.components); // [255, 255, 255]
+ * ```
+ */
+export function discolor(color: Color): Color {
+ const grey: number = (color.red + color.green + color.blue) /
+ color.components.length;
+
+ return new Color(false, grey, grey, grey);
+}
diff --git a/color_effects/discolor_test.ts b/color_effects/discolor_test.ts
new file mode 100644
index 0000000..40cc3d8
--- /dev/null
+++ b/color_effects/discolor_test.ts
@@ -0,0 +1,21 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { assertEquals } from "../dev_deps.ts";
+import { Color } from "../color.ts";
+import { discolor } from "./discolor.ts";
+import { Rgb } from "../color/mod.ts";
+
+Deno.test("discolor function correct", () => {
+ let red: Color = new Color(false, 255, 0, 0);
+ let green: Color = new Color(false, 0, 255, 0);
+ let blue: Color = new Color(false, 0, 0, 255);
+ const grey: Rgb = [85, 85, 85];
+
+ red = discolor(red);
+ green = discolor(green);
+ blue = discolor(blue);
+
+ assertEquals(red.components, grey, `"red.components"`);
+ assertEquals(green.components, grey, `"green.components"`);
+ assertEquals(blue.components, grey, `"blue.components"`);
+});
diff --git a/color_effects/invert_color.ts b/color_effects/invert_color.ts
new file mode 100644
index 0000000..bb9bf47
--- /dev/null
+++ b/color_effects/invert_color.ts
@@ -0,0 +1,22 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { Color } from "../color.ts";
+import { Rgb } from "../color/mod.ts";
+
+/**
+ * ### Example
+ *
+ * ```ts
+ * const black = new Color(false, 0, 0, 0);
+ *
+ * const white = invertColor(black);
+ * console.log(white.components); // [255, 255, 255]
+ * ```
+ */
+export function invertColor(color: Color): Color {
+ const newComponents: Rgb = color.components.map((component: number) =>
+ 255 - component
+ ) as Rgb;
+
+ return new Color(false, ...newComponents);
+}
diff --git a/color_effects/invert_color_test.ts b/color_effects/invert_color_test.ts
new file mode 100644
index 0000000..0dc2a69
--- /dev/null
+++ b/color_effects/invert_color_test.ts
@@ -0,0 +1,19 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { assertEquals } from "../dev_deps.ts";
+import { Color } from "../color.ts";
+import { invertColor } from "./invert_color.ts";
+
+Deno.test("invert function correct", () => {
+ let red: Color = new Color(false, 255, 0, 0);
+ let black: Color = new Color(false, 0, 0, 0);
+ let white: Color = new Color(false, 255, 255, 255);
+
+ red = invertColor(red);
+ black = invertColor(black);
+ white = invertColor(white);
+
+ assertEquals(red.components, [0, 255, 255], `"red.components"`);
+ assertEquals(black.components, [255, 255, 255], `"black.components"`);
+ assertEquals(white.components, [0, 0, 0], `"white.components"`);
+});
diff --git a/color_effects/mix_colors.ts b/color_effects/mix_colors.ts
new file mode 100644
index 0000000..6b92019
--- /dev/null
+++ b/color_effects/mix_colors.ts
@@ -0,0 +1,35 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { Color } from "../color.ts";
+import { Rgb } from "../color/mod.ts";
+import { percent } from "../util.ts";
+
+/**
+ * ### Example
+ *
+ * ```ts
+ * const black = new Color(false, 0, 0, 0);
+ * const white = new Color(false, 255, 255, 255);
+ *
+ * const grey = mixColors(black, white, 50);
+ * console.log(grey.components); // [127.5, 127.5, 127.5]
+ *
+ * const _black = mixColors(black, white, 0);
+ * console.log(_black.components); // [0, 0, 0]
+ *
+ * const _white = mixColors(black, white, 100);
+ * console.log(_white.components); // [255, 255, 255]
+ * ```
+ */
+export function mixColors(
+ first: Color,
+ second: Color,
+ percentage: number,
+): Color {
+ percentage = percent(percentage) / 100;
+ const newComponents: Rgb = first.components.map((_, i: number) =>
+ first.components[i] * (1 - percentage) + second.components[i] * percentage
+ ) as Rgb;
+
+ return new Color(false, ...newComponents);
+}
diff --git a/color_effects/mix_colors_test.ts b/color_effects/mix_colors_test.ts
new file mode 100644
index 0000000..2f10210
--- /dev/null
+++ b/color_effects/mix_colors_test.ts
@@ -0,0 +1,42 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { assertEquals } from "../dev_deps.ts";
+import { truncComponents } from "../advanced_color_test.ts";
+import { Color } from "../color.ts";
+import { mixColors } from "./mix_colors.ts";
+
+Deno.test("mix function correct", async (t) => {
+ const purple: Color = mixColors(
+ new Color(false, 255, 0, 0),
+ new Color(false, 0, 0, 255),
+ 50,
+ );
+
+ assertEquals(truncComponents(purple), [127, 0, 127], `"purple"`);
+
+ await t.step("percentage correct", () => {
+ const blue: Color = mixColors(
+ new Color(false, 255, 0, 0),
+ new Color(false, 0, 0, 255),
+ 100,
+ );
+
+ assertEquals(truncComponents(blue), [0, 0, 255], `"blue"`);
+
+ const red: Color = mixColors(
+ new Color(false, 255, 0, 0),
+ new Color(false, 0, 0, 255),
+ 0,
+ );
+
+ assertEquals(truncComponents(red), [255, 0, 0], `"red"`);
+
+ const black: Color = mixColors(
+ new Color(false, 0, 0, 0),
+ new Color(false, 0, 0, 0),
+ 50,
+ );
+
+ assertEquals(truncComponents(black), [0, 0, 0], `"black"`);
+ });
+});
diff --git a/color_effects/mod.ts b/color_effects/mod.ts
new file mode 100644
index 0000000..47499c6
--- /dev/null
+++ b/color_effects/mod.ts
@@ -0,0 +1,7 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+export { discolor } from "./discolor.ts";
+export { invertColor } from "./invert_color.ts";
+export { mixColors } from "./mix_colors.ts";
+export { subtractColors } from "./subtract_colors.ts";
+export { summarizeColors } from "./summarize_colors.ts";
diff --git a/color_effects/subtract_colors.ts b/color_effects/subtract_colors.ts
new file mode 100644
index 0000000..11c91be
--- /dev/null
+++ b/color_effects/subtract_colors.ts
@@ -0,0 +1,23 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { Color } from "../color.ts";
+import { Rgb } from "../color/mod.ts";
+
+/**
+ * ### Example
+ *
+ * ```ts
+ * const purple = new Color(false, 128, 0, 128);
+ * const blue = new Color(false, 0, 0, 128);
+ *
+ * const red = subtractColors(purple, blue);
+ * console.log(red.components); // [128, 0, 0]
+ * ```
+ */
+export function subtractColors(first: Color, second: Color): Color {
+ const newComponents: Rgb = first.components.map((_, i: number) =>
+ first.components[i] - second.components[i]
+ ) as Rgb;
+
+ return new Color(false, ...newComponents);
+}
diff --git a/color_effects/subtract_colors_test.ts b/color_effects/subtract_colors_test.ts
new file mode 100644
index 0000000..88234dd
--- /dev/null
+++ b/color_effects/subtract_colors_test.ts
@@ -0,0 +1,13 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { assertEquals } from "../dev_deps.ts";
+import { Color } from "../color.ts";
+import { subtractColors } from "./subtract_colors.ts";
+
+Deno.test("subtract function correct", () => {
+ const purpleColor: Color = new Color(false, 255, 0, 255);
+ const redColor: Color = new Color(false, 255, 0, 0);
+ const blueColor: Color = subtractColors(purpleColor, redColor);
+
+ assertEquals(blueColor.components, [0, 0, 255], `"blueColor.components"`);
+});
diff --git a/color_effects/summarize_colors.ts b/color_effects/summarize_colors.ts
new file mode 100644
index 0000000..2013a68
--- /dev/null
+++ b/color_effects/summarize_colors.ts
@@ -0,0 +1,23 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { Color } from "../color.ts";
+import { Rgb } from "../color/mod.ts";
+
+/**
+ * ### Example
+ *
+ * ```ts
+ * const red = new Color(false, 128, 0, 0);
+ * const blue = new Color(false, 0, 0, 128);
+ *
+ * const purple = summarizeColors(red, blue);
+ * console.log(purple.components); // [128, 0, 128]
+ * ```
+ */
+export function summarizeColors(first: Color, second: Color): Color {
+ const newComponents: Rgb = first.components.map((_, i: number) =>
+ first.components[i] + second.components[i]
+ ) as Rgb;
+
+ return new Color(false, ...newComponents);
+}
diff --git a/color_effects/summarize_colors_test.ts b/color_effects/summarize_colors_test.ts
new file mode 100644
index 0000000..586c227
--- /dev/null
+++ b/color_effects/summarize_colors_test.ts
@@ -0,0 +1,17 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { assertEquals } from "../dev_deps.ts";
+import { Color } from "../color.ts";
+import { summarizeColors } from "./summarize_colors.ts";
+
+Deno.test("sum function correct", () => {
+ const redColor: Color = new Color(false, 255, 0, 0);
+ const blueColor: Color = new Color(false, 0, 0, 255);
+ const purpleColor: Color = summarizeColors(redColor, blueColor);
+
+ assertEquals(
+ purpleColor.components,
+ [255, 0, 255],
+ `"purpleColor.components"`,
+ );
+});
diff --git a/color_info.ts b/color_info.ts
new file mode 100644
index 0000000..40bc52b
--- /dev/null
+++ b/color_info.ts
@@ -0,0 +1,48 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { colors } from "./deps.ts";
+import { Rgb } from "./color/mod.ts";
+
+/**
+ * `ColorInfo` retrieves similar color information
+ * from HTML colors and the [Colors] dependencies.
+ *
+ * [Colors]: https://github.com/chalkpot/colors
+ *
+ * ### Example
+ *
+ * ```ts
+ * const unknownColor = new ColorInfo(255, 0, 0);
+ * console.log(unknownColor.name); // "red"
+ * console.log(unknownColor.localize("ru-RU")); // "красный"
+ * ```
+ */
+export class ColorInfo {
+ public readonly name: string | undefined;
+ public readonly localize: (localeCode: string) => string | undefined;
+
+ public constructor(...components: Rgb) {
+ let minDiff = Infinity;
+ let colorName = "";
+
+ for (const color in colors) {
+ const rgb: number[] = colors[color as keyof typeof colors].rgb;
+ const diff: number = this.colorDiff(components, rgb);
+ if (diff > minDiff) continue;
+
+ minDiff = diff;
+ colorName = color;
+ }
+
+ const color = colors[colorName as keyof typeof colors];
+ this.name = color.name;
+ this.localize = color.localize;
+ }
+
+ private colorDiff(firstRgb: number[], secondRgb: number[]) {
+ const rDiff: number = secondRgb[0] - firstRgb[0];
+ const gDiff: number = secondRgb[1] - firstRgb[1];
+ const bDiff: number = secondRgb[2] - firstRgb[2];
+ return Math.sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff);
+ }
+}
diff --git a/color_info_test.ts b/color_info_test.ts
new file mode 100644
index 0000000..1c4893e
--- /dev/null
+++ b/color_info_test.ts
@@ -0,0 +1,12 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { assertEquals } from "./dev_deps.ts";
+import { ColorInfo } from "./color_info.ts";
+
+Deno.test("getting JSON color object from module correct", () => {
+ const black: ColorInfo = new ColorInfo(0, 0, 0);
+ assertEquals(black.name, "black", `"black.name"`);
+
+ const white: ColorInfo = new ColorInfo(255, 255, 255);
+ assertEquals(white.name, "white", `"white.name"`);
+});
diff --git a/color_test.ts b/color_test.ts
new file mode 100644
index 0000000..d9e65b0
--- /dev/null
+++ b/color_test.ts
@@ -0,0 +1,31 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+import { assertEquals } from "./dev_deps.ts";
+import { Color } from "./color.ts";
+
+Deno.test("class contains correct fields", async (t) => {
+ const red = 10 as const;
+ const green = 20 as const;
+ const blue = 30 as const;
+
+ const color: Color = new Color(false, red, green, blue);
+
+ assertEquals(color.red, red, `"color.red"`);
+ assertEquals(color.green, green, `"color.green"`);
+ assertEquals(color.blue, blue, `"color.blue"`);
+
+ await t.step("dependent field contains correct values", () => {
+ assertEquals(color.components, [red, green, blue], `"color.components"`);
+ });
+});
+
+Deno.test("creating components using percentages correct", () => {
+ const black: Color = new Color(true, 0, 0, 0);
+ assertEquals(black.components, [0, 0, 0], `"black"`);
+
+ const grey: Color = new Color(true, 50, 50, 50);
+ assertEquals(grey.components, [127.5, 127.5, 127.5], `"grey"`);
+
+ const white: Color = new Color(true, 100, 100, 100);
+ assertEquals(white.components, [255, 255, 255], `"white"`);
+});
diff --git a/deno.jsonc b/deno.jsonc
new file mode 100644
index 0000000..0109217
--- /dev/null
+++ b/deno.jsonc
@@ -0,0 +1,17 @@
+{
+ "tasks": {
+ // npm publish --access public
+ "build": "deno run --allow-read --allow-write --allow-net --allow-env --allow-run _build_npm.ts"
+ },
+ "fmt": {
+ "include": [
+ "./"
+ ]
+ },
+ "exclude": [
+ "./.github",
+ "./.idea",
+ "./.git",
+ "./.npm"
+ ]
+}
diff --git a/deno.lock b/deno.lock
new file mode 100644
index 0000000..401cbed
--- /dev/null
+++ b/deno.lock
@@ -0,0 +1,111 @@
+{
+ "version": "3",
+ "remote": {
+ "https://deno.land/std@0.140.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74",
+ "https://deno.land/std@0.140.0/_util/os.ts": "3b4c6e27febd119d36a416d7a97bd3b0251b77c88942c8f16ee5953ea13e2e49",
+ "https://deno.land/std@0.140.0/bytes/bytes_list.ts": "67eb118e0b7891d2f389dad4add35856f4ad5faab46318ff99653456c23b025d",
+ "https://deno.land/std@0.140.0/bytes/equals.ts": "fc16dff2090cced02497f16483de123dfa91e591029f985029193dfaa9d894c9",
+ "https://deno.land/std@0.140.0/bytes/mod.ts": "763f97d33051cc3f28af1a688dfe2830841192a9fea0cbaa55f927b49d49d0bf",
+ "https://deno.land/std@0.140.0/fmt/colors.ts": "30455035d6d728394781c10755351742dd731e3db6771b1843f9b9e490104d37",
+ "https://deno.land/std@0.140.0/fs/_util.ts": "0fb24eb4bfebc2c194fb1afdb42b9c3dda12e368f43e8f2321f84fc77d42cb0f",
+ "https://deno.land/std@0.140.0/fs/ensure_dir.ts": "9dc109c27df4098b9fc12d949612ae5c9c7169507660dcf9ad90631833209d9d",
+ "https://deno.land/std@0.140.0/io/buffer.ts": "bd0c4bf53db4b4be916ca5963e454bddfd3fcd45039041ea161dbf826817822b",
+ "https://deno.land/std@0.140.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3",
+ "https://deno.land/std@0.140.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09",
+ "https://deno.land/std@0.140.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b",
+ "https://deno.land/std@0.140.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633",
+ "https://deno.land/std@0.140.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee",
+ "https://deno.land/std@0.140.0/path/mod.ts": "d3e68d0abb393fb0bf94a6d07c46ec31dc755b544b13144dee931d8d5f06a52d",
+ "https://deno.land/std@0.140.0/path/posix.ts": "293cdaec3ecccec0a9cc2b534302dfe308adb6f10861fa183275d6695faace44",
+ "https://deno.land/std@0.140.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9",
+ "https://deno.land/std@0.140.0/path/win32.ts": "31811536855e19ba37a999cd8d1b62078235548d67902ece4aa6b814596dd757",
+ "https://deno.land/std@0.140.0/streams/conversion.ts": "712585bfa0172a97fb68dd46e784ae8ad59d11b88079d6a4ab098ff42e697d21",
+ "https://deno.land/std@0.181.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462",
+ "https://deno.land/std@0.181.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3",
+ "https://deno.land/std@0.181.0/fs/_util.ts": "65381f341af1ff7f40198cee15c20f59951ac26e51ddc651c5293e24f9ce6f32",
+ "https://deno.land/std@0.181.0/fs/ensure_dir.ts": "dc64c4c75c64721d4e3fb681f1382f803ff3d2868f08563ff923fdd20d071c40",
+ "https://deno.land/std@0.181.0/fs/expand_glob.ts": "e4f56259a0a70fe23f05215b00de3ac5e6ba46646ab2a06ebbe9b010f81c972a",
+ "https://deno.land/std@0.181.0/fs/walk.ts": "ea95ffa6500c1eda6b365be488c056edc7c883a1db41ef46ec3bf057b1c0fe32",
+ "https://deno.land/std@0.181.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0",
+ "https://deno.land/std@0.181.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b",
+ "https://deno.land/std@0.181.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0",
+ "https://deno.land/std@0.181.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000",
+ "https://deno.land/std@0.181.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1",
+ "https://deno.land/std@0.181.0/path/mod.ts": "bf718f19a4fdd545aee1b06409ca0805bd1b68ecf876605ce632e932fe54510c",
+ "https://deno.land/std@0.181.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d",
+ "https://deno.land/std@0.181.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1",
+ "https://deno.land/std@0.181.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba",
+ "https://deno.land/std@0.182.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462",
+ "https://deno.land/std@0.182.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3",
+ "https://deno.land/std@0.182.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e",
+ "https://deno.land/std@0.182.0/fs/_util.ts": "65381f341af1ff7f40198cee15c20f59951ac26e51ddc651c5293e24f9ce6f32",
+ "https://deno.land/std@0.182.0/fs/empty_dir.ts": "c3d2da4c7352fab1cf144a1ecfef58090769e8af633678e0f3fabaef98594688",
+ "https://deno.land/std@0.182.0/fs/expand_glob.ts": "e4f56259a0a70fe23f05215b00de3ac5e6ba46646ab2a06ebbe9b010f81c972a",
+ "https://deno.land/std@0.182.0/fs/walk.ts": "920be35a7376db6c0b5b1caf1486fb962925e38c9825f90367f8f26b5e5d0897",
+ "https://deno.land/std@0.182.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0",
+ "https://deno.land/std@0.182.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b",
+ "https://deno.land/std@0.182.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0",
+ "https://deno.land/std@0.182.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000",
+ "https://deno.land/std@0.182.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1",
+ "https://deno.land/std@0.182.0/path/mod.ts": "bf718f19a4fdd545aee1b06409ca0805bd1b68ecf876605ce632e932fe54510c",
+ "https://deno.land/std@0.182.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d",
+ "https://deno.land/std@0.182.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1",
+ "https://deno.land/std@0.182.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba",
+ "https://deno.land/std@0.204.0/assert/_constants.ts": "8a9da298c26750b28b326b297316cdde860bc237533b07e1337c021379e6b2a9",
+ "https://deno.land/std@0.204.0/assert/_diff.ts": "58e1461cc61d8eb1eacbf2a010932bf6a05b79344b02ca38095f9b805795dc48",
+ "https://deno.land/std@0.204.0/assert/_format.ts": "a69126e8a469009adf4cf2a50af889aca364c349797e63174884a52ff75cf4c7",
+ "https://deno.land/std@0.204.0/assert/assert_equals.ts": "d8ec8a22447fbaf2fc9d7c3ed2e66790fdb74beae3e482855d75782218d68227",
+ "https://deno.land/std@0.204.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56",
+ "https://deno.land/std@0.204.0/assert/equal.ts": "9f1a46d5993966d2596c44e5858eec821859b45f783a5ee2f7a695dfc12d8ece",
+ "https://deno.land/std@0.204.0/fmt/colors.ts": "c51c4642678eb690dcf5ffee5918b675bf01a33fba82acf303701ae1a4f8c8d9",
+ "https://deno.land/x/chalkpot_colors@1.0.0/basic_colors.ts": "f0d4c124c3fff1f8c2f9d8d935493ff620bb21c1857478566a09ba606ffdf0b0",
+ "https://deno.land/x/chalkpot_colors@1.0.0/colors.ts": "6b42301e547574332db4eb77bb9ab70990348bea9196b2a595a1cd50fad5343f",
+ "https://deno.land/x/chalkpot_colors@1.0.0/locales/be_BY.ts": "7d93344420094eea8fa5386a8e682183c995dd18c7779d0ba447592ce6abd174",
+ "https://deno.land/x/chalkpot_colors@1.0.0/locales/en_US.ts": "7ab336fc88ee21cf5c843311e5549917e218a0ece66a3dab5c91a1589fb25a9c",
+ "https://deno.land/x/chalkpot_colors@1.0.0/locales/locale/localize_color.ts": "19960d6871d426955a4e268fbcd068b8c26b0156bc32d422b028448f9719ad1e",
+ "https://deno.land/x/chalkpot_colors@1.0.0/locales/locale/mod.ts": "86d808cb2de3cf6050ebd89e49255631eddc770af650ddd4950b2f419ff46b36",
+ "https://deno.land/x/chalkpot_colors@1.0.0/locales/locale/unformat_locale_code.ts": "24e6ad25f6b2722c96d94a3219ba2f104b8dca236130a758fd092735234be4e8",
+ "https://deno.land/x/chalkpot_colors@1.0.0/locales/mod.ts": "2339c351eeff7e47af71f0afe74b49740f81b43494afb16d3be8c1aed0ddf6d0",
+ "https://deno.land/x/chalkpot_colors@1.0.0/locales/ru_RU.ts": "a13f54cb2bbf8f0d21f79de68a2cc1515cb5e0565ea9f410df322b88eef20941",
+ "https://deno.land/x/chalkpot_colors@1.0.0/locales/uk_UA.ts": "4f6a90dfdb92360a8676ba8259c8e6d551aab17d3640b7817d7422390d848c1e",
+ "https://deno.land/x/chalkpot_colors@1.0.0/mod.ts": "6e8daa7d2e4bc1bd9c59083e07ee49a20fbb9a5a37dd675f46b3a969099752f7",
+ "https://deno.land/x/code_block_writer@12.0.0/mod.ts": "2c3448060e47c9d08604c8f40dee34343f553f33edcdfebbf648442be33205e5",
+ "https://deno.land/x/code_block_writer@12.0.0/utils/string_utils.ts": "60cb4ec8bd335bf241ef785ccec51e809d576ff8e8d29da43d2273b69ce2a6ff",
+ "https://deno.land/x/deno_cache@0.5.2/auth_tokens.ts": "5d1d56474c54a9d152e44d43ea17c2e6a398dd1e9682c69811a313567c01ee1e",
+ "https://deno.land/x/deno_cache@0.5.2/cache.ts": "92ce8511e1e5c00fdf53a41619aa77d632ea8e0fc711324322e4d5ebf8133911",
+ "https://deno.land/x/deno_cache@0.5.2/deno_dir.ts": "1ea355b8ba11c630d076b222b197cfc937dd81e5a4a260938997da99e8ff93a0",
+ "https://deno.land/x/deno_cache@0.5.2/deps.ts": "26a75905652510b76e54b6d5ef3cf824d1062031e00782efcd768978419224e7",
+ "https://deno.land/x/deno_cache@0.5.2/dirs.ts": "009c6f54e0b610914d6ce9f72f6f6ccfffd2d47a79a19061e0a9eb4253836069",
+ "https://deno.land/x/deno_cache@0.5.2/disk_cache.ts": "66a1e604a8d564b6dd0500326cac33d08b561d331036bf7272def80f2f7952aa",
+ "https://deno.land/x/deno_cache@0.5.2/file_fetcher.ts": "89616c50b6df73fb04e73d0b7cd99e5f2ed7967386913d65b9e8baa4238501f7",
+ "https://deno.land/x/deno_cache@0.5.2/http_cache.ts": "407135eaf2802809ed373c230d57da7ef8dff923c4abf205410b9b99886491fd",
+ "https://deno.land/x/deno_cache@0.5.2/lib/deno_cache_dir.generated.js": "18b6526d0c50791a73dd0eb894e99de1ac05ee79dcbd53298ff5b5b6b0757fe6",
+ "https://deno.land/x/deno_cache@0.5.2/lib/snippets/deno_cache_dir-77bed54ace8005e0/fs.js": "cbe3a976ed63c72c7cb34ef845c27013033a3b11f9d8d3e2c4aa5dda2c0c7af6",
+ "https://deno.land/x/deno_cache@0.5.2/mod.ts": "0b4d071ad095128bdc2b1bc6e5d2095222dcbae08287261690ee9757e6300db6",
+ "https://deno.land/x/deno_cache@0.5.2/util.ts": "f3f5a0cfc60051f09162942fb0ee87a0e27b11a12aec4c22076e3006be4cc1e2",
+ "https://deno.land/x/dir@1.5.1/data_local_dir/mod.ts": "91eb1c4bfadfbeda30171007bac6d85aadacd43224a5ed721bbe56bc64e9eb66",
+ "https://deno.land/x/dnt@0.38.1/lib/compiler.ts": "209ad2e1b294f93f87ec02ade9a0821f942d2e524104552d0aa8ff87021050a5",
+ "https://deno.land/x/dnt@0.38.1/lib/compiler_transforms.ts": "f21aba052f5dcf0b0595c734450842855c7f572e96165d3d34f8fed2fc1f7ba1",
+ "https://deno.land/x/dnt@0.38.1/lib/mod.deps.ts": "30367fc68bcd2acf3b7020cf5cdd26f817f7ac9ac35c4bfb6c4551475f91bc3e",
+ "https://deno.land/x/dnt@0.38.1/lib/npm_ignore.ts": "57fbb7e7b935417d225eec586c6aa240288905eb095847d3f6a88e290209df4e",
+ "https://deno.land/x/dnt@0.38.1/lib/package_json.ts": "61f35b06e374ed39ca776d29d67df4be7ee809d0bca29a8239687556c6d027c2",
+ "https://deno.land/x/dnt@0.38.1/lib/pkg/dnt_wasm.generated.js": "cfb352ae839865f5698c9b35099d4c783510195a1e3c9f9b04d94fac86394ed9",
+ "https://deno.land/x/dnt@0.38.1/lib/pkg/snippets/dnt-wasm-a15ef721fa5290c5/helpers.js": "45f74f00472b3a399bc16e5dc056966b55dcdd8fa2bd61505c6dfd2f5d33b9f4",
+ "https://deno.land/x/dnt@0.38.1/lib/shims.ts": "df1bd4d9a196dca4b2d512b1564fff64ac6c945189a273d706391f87f210d7e6",
+ "https://deno.land/x/dnt@0.38.1/lib/test_runner/get_test_runner_code.ts": "4dc7a73a13b027341c0688df2b29a4ef102f287c126f134c33f69f0339b46968",
+ "https://deno.land/x/dnt@0.38.1/lib/test_runner/test_runner.ts": "4d0da0500ec427d5f390d9a8d42fb882fbeccc92c92d66b6f2e758606dbd40e6",
+ "https://deno.land/x/dnt@0.38.1/lib/transform.deps.ts": "e42f2bdef46d098453bdba19261a67cf90b583f5d868f7fe83113c1380d9b85c",
+ "https://deno.land/x/dnt@0.38.1/lib/types.ts": "b8e228b2fac44c2ae902fbb73b1689f6ab889915bd66486c8a85c0c24255f5fb",
+ "https://deno.land/x/dnt@0.38.1/lib/utils.ts": "878b7ac7003a10c16e6061aa49dbef9b42bd43174853ebffc9b67ea47eeb11d8",
+ "https://deno.land/x/dnt@0.38.1/mod.ts": "b13349fe77847cf58e26b40bcd58797a8cec5d71b31a1ca567071329c8489de1",
+ "https://deno.land/x/dnt@0.38.1/transform.ts": "f68743a14cf9bf53bfc9c81073871d69d447a7f9e3453e0447ca2fb78926bb1d",
+ "https://deno.land/x/ts_morph@18.0.0/bootstrap/mod.ts": "b53aad517f106c4079971fcd4a81ab79fadc40b50061a3ab2b741a09119d51e9",
+ "https://deno.land/x/ts_morph@18.0.0/bootstrap/ts_morph_bootstrap.js": "6645ac03c5e6687dfa8c78109dc5df0250b811ecb3aea2d97c504c35e8401c06",
+ "https://deno.land/x/ts_morph@18.0.0/common/DenoRuntime.ts": "6a7180f0c6e90dcf23ccffc86aa8271c20b1c4f34c570588d08a45880b7e172d",
+ "https://deno.land/x/ts_morph@18.0.0/common/mod.ts": "01985d2ee7da8d1caee318a9d07664774fbee4e31602bc2bb6bb62c3489555ed",
+ "https://deno.land/x/ts_morph@18.0.0/common/ts_morph_common.js": "845671ca951073400ce142f8acefa2d39ea9a51e29ca80928642f3f8cf2b7700",
+ "https://deno.land/x/ts_morph@18.0.0/common/typescript.js": "d5c598b6a2db2202d0428fca5fd79fc9a301a71880831a805d778797d2413c59",
+ "https://deno.land/x/wasmbuild@0.15.0/cache.ts": "89eea5f3ce6035a1164b3e655c95f21300498920575ade23161421f5b01967f4",
+ "https://deno.land/x/wasmbuild@0.15.0/loader.ts": "d98d195a715f823151cbc8baa3f32127337628379a02d9eb2a3c5902dbccfc02"
+ }
+}
diff --git a/deps.ts b/deps.ts
new file mode 100644
index 0000000..b217dd5
--- /dev/null
+++ b/deps.ts
@@ -0,0 +1,3 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+export { colors } from "https://deno.land/x/chalkpot_colors@1.0.0/mod.ts";
diff --git a/dev_deps.ts b/dev_deps.ts
new file mode 100644
index 0000000..cc9ef38
--- /dev/null
+++ b/dev_deps.ts
@@ -0,0 +1,3 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+export { assertEquals } from "https://deno.land/std@0.204.0/assert/assert_equals.ts";
diff --git a/mod.ts b/mod.ts
new file mode 100644
index 0000000..91ddacd
--- /dev/null
+++ b/mod.ts
@@ -0,0 +1,7 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+export { Color } from "./color.ts";
+export { AdvancedColor } from "./advanced_color.ts";
+export { ColorComponent } from "./color_component.ts";
+
+export * from "./color_effects/mod.ts";
diff --git a/util.ts b/util.ts
new file mode 100644
index 0000000..9c64a09
--- /dev/null
+++ b/util.ts
@@ -0,0 +1,5 @@
+// Copyright 2023 mineejo. All rights reserved. MIT license.
+
+export function percent(value: number): number {
+ return Math.min(Math.max(value, 0), 100);
+}