aboutsummaryrefslogtreecommitdiff
path: root/aoc2023/build/packages/gleam_community_colour
diff options
context:
space:
mode:
Diffstat (limited to 'aoc2023/build/packages/gleam_community_colour')
-rw-r--r--aoc2023/build/packages/gleam_community_colour/LICENCE190
-rw-r--r--aoc2023/build/packages/gleam_community_colour/README.md36
-rw-r--r--aoc2023/build/packages/gleam_community_colour/gleam.toml11
-rw-r--r--aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Hsla.hrl1
-rw-r--r--aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Rgba.hrl1
-rw-r--r--aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour.gleam1126
-rw-r--r--aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam173
-rw-r--r--aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour.erl511
-rw-r--r--aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl73
-rw-r--r--aoc2023/build/packages/gleam_community_colour/src/gleam_community_colour.app.src9
10 files changed, 2131 insertions, 0 deletions
diff --git a/aoc2023/build/packages/gleam_community_colour/LICENCE b/aoc2023/build/packages/gleam_community_colour/LICENCE
new file mode 100644
index 0000000..a84f0ec
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/LICENCE
@@ -0,0 +1,190 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright 2023 Gleam Community Contributors
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. \ No newline at end of file
diff --git a/aoc2023/build/packages/gleam_community_colour/README.md b/aoc2023/build/packages/gleam_community_colour/README.md
new file mode 100644
index 0000000..0eccdd7
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/README.md
@@ -0,0 +1,36 @@
+# gleam-community/colour
+
+A package for a standard Colour type, conversions, and other utilities.
+
+[![Package Version](https://img.shields.io/hexpm/v/gleam_community_colour)](https://hex.pm/packages/gleam_community_colour)
+[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/gleam_community_colour/)
+
+✨ This project is written in pure Gleam so you can use it anywhere Gleam runs: Erlang, Elixir, Node, Deno, and the browser!
+
+---
+
+## Quickstart
+
+```gleam
+import gleam_community/colour
+import gleam_community/colour/accessibility
+
+pub fn main() {
+ let foreground = colour.from_hsl(h: 0.858, s: 1.0, l: 0.843)
+
+ let background_options = [colour.light_grey, colour.dark_grey]
+
+ let background = accessibility.maximum_contrast(foreground, background_options)
+}
+```
+
+## Installation
+
+`gleam_community` packages are published to [hex.pm](https://hex.pm/packages/gleam_community_colour)
+with the prefix `gleam_community_`. You can add them to your Gleam projects directly:
+
+```sh
+gleam add gleam_community_colour
+```
+
+The docs can be found over at [hexdocs.pm](https://hexdocs.pm/gleam_community_colour).
diff --git a/aoc2023/build/packages/gleam_community_colour/gleam.toml b/aoc2023/build/packages/gleam_community_colour/gleam.toml
new file mode 100644
index 0000000..07a81bf
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/gleam.toml
@@ -0,0 +1,11 @@
+name = "gleam_community_colour"
+version = "1.2.0"
+licences = ["Apache-2.0"]
+description = "Colour types, conversions, and other utilities"
+repository = { type = "github", user = "gleam-community", repo = "colour" }
+
+[dependencies]
+gleam_stdlib = "~> 0.32"
+
+[dev-dependencies]
+gleeunit = "~> 0.11"
diff --git a/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Hsla.hrl b/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Hsla.hrl
new file mode 100644
index 0000000..06116df
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Hsla.hrl
@@ -0,0 +1 @@
+-record(hsla, {h :: float(), s :: float(), l :: float(), a :: float()}).
diff --git a/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Rgba.hrl b/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Rgba.hrl
new file mode 100644
index 0000000..fff139e
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Rgba.hrl
@@ -0,0 +1 @@
+-record(rgba, {r :: float(), g :: float(), b :: float(), a :: float()}).
diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour.gleam b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour.gleam
new file mode 100644
index 0000000..1f5872f
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour.gleam
@@ -0,0 +1,1126 @@
+////
+//// - **Types**
+//// - [`Colour`](#Colour)
+//// - [`Color`](#Color)
+//// - **Constructors**
+//// - [`from_rgb255`](#from_rgb255)
+//// - [`from_rgb`](#from_rgb)
+//// - [`from_rgba`](#from_rgba)
+//// - [`from_hsl`](#from_hsl)
+//// - [`from_hsla`](#from_hsla)
+//// - [`from_rgb_hex`](#from_rgb_hex)
+//// - [`from_rgba_hex`](#from_rgba_hex)
+//// - [`from_rgb_hex_string`](#from_rgb_hex_string)
+//// - [`from_rgba_hex_string`](#from_rgba_hex_string)
+//// - **Conversions**
+//// - [`to_rgba`](#to_rgba)
+//// - [`to_hsla`](#hsla)
+//// - [`to_css_rgba_string`](#to_css_rgba_string)
+//// - [`to_rgba_hex_string`](#to_rgba_hex_string)
+//// - [`to_rgb_hex_string`](#to_rgb_hex_string)
+//// - [`to_rgba_hex`](#to_rgba_hex)
+//// - [`to_rgb_hex`](#to_rgb_hex)
+//// - **Colours**
+//// - [`light_red`](#light_red)
+//// - [`red`](#red)
+//// - [`dark_red`](#dark_red)
+//// - [`light_orange`](#light_orange)
+//// - [`orange`](#orange)
+//// - [`dark_orange`](#dark_orange)
+//// - [`light_yellow`](#light_yellow)
+//// - [`yellow`](#yellow)
+//// - [`dark_yellow`](#dark_yellow)
+//// - [`light_green`](#light_green)
+//// - [`green`](#green)
+//// - [`dark_green`](#dark_green)
+//// - [`light_blue`](#light_blue)
+//// - [`blue`](#blue)
+//// - [`dark_blue`](#dark_blue)
+//// - [`light_purple`](#light_purple)
+//// - [`purple`](#purple)
+//// - [`dark_purple`](#dark_purple)
+//// - [`light_brown`](#light_brown)
+//// - [`brown`](#brown)
+//// - [`dark_brown`](#dark_brown)
+//// - [`black`](#black)
+//// - [`white`](#white)
+//// - [`light_grey`](#light_grey)
+//// - [`grey`](#grey)
+//// - [`dark_grey`](#dark_grey)
+//// - [`light_gray`](#light_gray)
+//// - [`gray`](#gray)
+//// - [`dark_gray`](#dark_gray)
+//// - [`light_charcoal`](#light_charcoal)
+//// - [`charcoal`](#charcoal)
+//// - [`dark_charcoal`](#dark_charcoal)
+//// - [`pink`](#pink)
+////
+//// ---
+////
+//// This package was heavily inspired by the `elm-color` module.
+//// The original source code can be found
+//// <a href="https://github.com/avh4/elm-color/">here</a>.
+////
+//// <details>
+//// <summary>The license of that package is produced below:</summary>
+////
+////
+//// > MIT License
+////
+//// > Copyright 2018 Aaron VonderHaar
+////
+//// > Redistribution and use in source and binary forms, with or without modification,
+//// are permitted provided that the following conditions are met:
+////
+//// 1. Redistributions of source code must retain the above copyright notice,
+//// this list of conditions and the following disclaimer.
+////
+//// 2. Redistributions in binary form must reproduce the above copyright notice,
+//// this list of conditions and the following disclaimer in the documentation
+//// and/or other materials provided with the distribution.
+////
+//// 3. Neither the name of the copyright holder nor the names of its contributors
+//// may be used to endorse or promote products derived from this software without
+//// specific prior written permission.
+////
+//// > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+//// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+//// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+//// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+//// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+//// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+//// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+////
+//// > The above copyright notice and this permission notice shall be included in all
+//// copies or substantial portions of the Software.
+//// </details>
+////
+
+// Just in case we decide in the future to no longer include the above reference
+// and license, this package was initially a port of the `elm-color` module:
+//
+// https://github.com/avh4/elm-color/
+//
+
+// IMPORTS --------------------------------------------------------------------
+
+import gleam/int
+import gleam/float
+import gleam/result
+import gleam/string
+import gleam/list
+
+// TYPES ----------------------------------------------------------------------
+
+/// A representation of a colour that can be converted to RGBA or HSLA format.
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+/// </br>
+///
+pub opaque type Colour {
+ Rgba(r: Float, g: Float, b: Float, a: Float)
+ Hsla(h: Float, s: Float, l: Float, a: Float)
+}
+
+/// Type alias for `Colour`
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+/// </br>
+///
+pub type Color =
+ Colour
+
+// UTILITY --------------------------------------------------------------------
+
+fn valid_colour_value(c: Float) -> Result(Float, Nil) {
+ case c >. 1.0 || c <. 0.0 {
+ True -> Error(Nil)
+ False -> Ok(c)
+ }
+}
+
+fn hue_to_rgb(hue: Float, m1: Float, m2: Float) -> Float {
+ let h = case hue {
+ _ if hue <. 0.0 -> hue +. 1.0
+ _ if hue >. 1.0 -> hue -. 1.0
+ _ -> hue
+ }
+
+ let h_t_6 = h *. 6.0
+ let h_t_2 = h *. 2.0
+ let h_t_3 = h *. 3.0
+
+ case h {
+ _ if h_t_6 <. 1.0 -> m1 +. { m2 -. m1 } *. h *. 6.0
+ _ if h_t_2 <. 1.0 -> m2
+ _ if h_t_3 <. 2.0 -> m1 +. { m2 -. m1 } *. { 2.0 /. 3.0 -. h } *. 6.0
+ _ -> m1
+ }
+}
+
+fn hex_string_to_int(hex_string: String) -> Result(Int, Nil) {
+ let hex = case hex_string {
+ "#" <> hex_number -> hex_number
+ "0x" <> hex_number -> hex_number
+ _ -> hex_string
+ }
+
+ hex
+ |> string.lowercase()
+ |> string.to_graphemes()
+ |> list.reverse()
+ |> list.index_fold(
+ Ok(0),
+ fn(total, char, index) {
+ case total {
+ Error(Nil) -> Error(Nil)
+ Ok(v) -> {
+ use num <- result.then(case char {
+ "a" -> Ok(10)
+ "b" -> Ok(11)
+ "c" -> Ok(12)
+ "d" -> Ok(13)
+ "e" -> Ok(14)
+ "f" -> Ok(15)
+ _ -> int.parse(char)
+ })
+ use base <- result.then(int.power(16, int.to_float(index)))
+ Ok(v + float.round(int.to_float(num) *. base))
+ }
+ }
+ },
+ )
+}
+
+fn hsla_to_rgba(
+ h: Float,
+ s: Float,
+ l: Float,
+ a: Float,
+) -> #(Float, Float, Float, Float) {
+ let m2 = case l <=. 0.5 {
+ True -> l *. { s +. 1.0 }
+ False -> l +. s -. l *. s
+ }
+
+ let m1 = l *. 2.0 -. m2
+
+ let r = hue_to_rgb(h +. 1.0 /. 3.0, m1, m2)
+ let g = hue_to_rgb(h, m1, m2)
+ let b = hue_to_rgb(h -. 1.0 /. 3.0, m1, m2)
+
+ #(r, g, b, a)
+}
+
+fn rgba_to_hsla(
+ r: Float,
+ g: Float,
+ b: Float,
+ a: Float,
+) -> #(Float, Float, Float, Float) {
+ let min_colour = float.min(r, float.min(g, b))
+
+ let max_colour = float.max(r, float.max(g, b))
+
+ let h1 = case True {
+ _ if max_colour == r -> float.divide(g -. b, max_colour -. min_colour)
+ _ if max_colour == g ->
+ float.divide(b -. r, max_colour -. min_colour)
+ |> result.then(fn(d) { Ok(2.0 +. d) })
+ _ ->
+ float.divide(r -. g, max_colour -. min_colour)
+ |> result.then(fn(d) { Ok(4.0 +. d) })
+ }
+
+ let h2 = case h1 {
+ Ok(v) -> Ok(v *. { 1.0 /. 6.0 })
+ _ -> h1
+ }
+
+ let h3 = case h2 {
+ Ok(v) if v <. 0.0 -> v +. 1.0
+ Ok(v) -> v
+ _ -> 0.0
+ }
+
+ let l = { min_colour +. max_colour } /. 2.0
+
+ let s = case True {
+ _ if min_colour == max_colour -> 0.0
+ _ if l <. 0.5 ->
+ { max_colour -. min_colour } /. { max_colour +. min_colour }
+ _ -> { max_colour -. min_colour } /. { 2.0 -. max_colour -. min_colour }
+ }
+
+ #(h3, s, l, a)
+}
+
+// CONSTRUCTORS ---------------------------------------------------------------
+
+/// Returns a `Result(Colour)` created from the given 8 bit RGB values.
+///
+/// Returns `Error(Nil)` if the supplied RGB values are greater than 255 or less than 0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb255(255, 0, 0)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgb255(r red: Int, g green: Int, b blue: Int) -> Result(Colour, Nil) {
+ use r <- result.then(
+ red
+ |> int.to_float()
+ |> float.divide(255.0)
+ |> result.then(valid_colour_value),
+ )
+
+ use g <- result.then(
+ green
+ |> int.to_float()
+ |> float.divide(255.0)
+ |> result.then(valid_colour_value),
+ )
+
+ use b <- result.then(
+ blue
+ |> int.to_float()
+ |> float.divide(255.0)
+ |> result.then(valid_colour_value),
+ )
+
+ Ok(Rgba(r: r, g: g, b: b, a: 1.0))
+}
+
+/// Returns `Result(Colour)` created from the given RGB values.
+///
+/// If the supplied RGB values are greater than 1.0 or less than 0.0 returns `Error(Nil)`
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb(1.0, 0.0, 0.0)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgb(
+ r red: Float,
+ g green: Float,
+ b blue: Float,
+) -> Result(Colour, Nil) {
+ use r <- result.then(valid_colour_value(red))
+ use g <- result.then(valid_colour_value(green))
+ use b <- result.then(valid_colour_value(blue))
+
+ Ok(Rgba(r: r, g: g, b: b, a: 1.0))
+}
+
+/// Returns `Result(Colour)` created from the given RGBA values.
+///
+/// Returns `Error(Nil)` if the supplied RGBA values are greater than 1.0 or less than 0.0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red_half_opacity) = from_rbga(1.0, 0.0, 0.0, 0.5)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgba(
+ r red: Float,
+ g green: Float,
+ b blue: Float,
+ a alpha: Float,
+) -> Result(Colour, Nil) {
+ use r <- result.then(valid_colour_value(red))
+ use g <- result.then(valid_colour_value(green))
+ use b <- result.then(valid_colour_value(blue))
+ use a <- result.then(valid_colour_value(alpha))
+
+ Ok(Rgba(r: r, g: g, b: b, a: a))
+}
+
+/// Returns `Result(Colour)` created from the given HSLA values.
+///
+/// Returns `Error(Nil)`f the supplied HSLA values are greater than 1.0 or less than 0.0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red_half_opacity) = from_hsla(0.0, 1.0, 0.5, 0.5)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_hsla(
+ h hue: Float,
+ s saturation: Float,
+ l lightness: Float,
+ a alpha: Float,
+) -> Result(Colour, Nil) {
+ use h <- result.then(valid_colour_value(hue))
+ use s <- result.then(valid_colour_value(saturation))
+ use l <- result.then(valid_colour_value(lightness))
+ use a <- result.then(valid_colour_value(alpha))
+
+ Ok(Hsla(h: h, s: s, l: l, a: a))
+}
+
+/// Returns `Result(Colour)` created from the given HSL values.
+///
+/// Returns `Error(Nil)` if the supplied HSL values are greater than 1.0 or less than 0.0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_hsla(0.0, 1.0, 0.5)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_hsl(
+ h hue: Float,
+ s saturation: Float,
+ l lightness: Float,
+) -> Result(Colour, Nil) {
+ from_hsla(hue, saturation, lightness, 1.0)
+}
+
+/// Returns a `Result(Colour)` created from the given hex `Int`.
+///
+/// Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffff or less than 0x0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb_hex(0xff0000)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgb_hex(hex: Int) -> Result(Colour, Nil) {
+ case hex > 0xffffff || hex < 0 {
+ True -> Error(Nil)
+ False -> {
+ let r =
+ int.bitwise_shift_right(hex, 16)
+ |> int.bitwise_and(0xff)
+ let g =
+ int.bitwise_shift_right(hex, 8)
+ |> int.bitwise_and(0xff)
+ let b = int.bitwise_and(hex, 0xff)
+ from_rgb255(r, g, b)
+ }
+ }
+}
+
+/// Returns a `Result(Colour)` created from the given RGB hex `String`.
+///
+/// Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `"#ffffff" or less than `"#0"`
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb_hex_string("#ff0000")
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgb_hex_string(hex_string: String) -> Result(Colour, Nil) {
+ use hex_int <- result.then(hex_string_to_int(hex_string))
+
+ from_rgb_hex(hex_int)
+}
+
+/// Returns a `Result(Colour)` created from the given RGBA hex `String`.
+///
+/// Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `"#ffffffff" or less than `"#0"`
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red_half_opacity) = from_rgba_hex_string("#ff00007f")
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgba_hex_string(hex_string: String) -> Result(Colour, Nil) {
+ use hex_int <- result.then(hex_string_to_int(hex_string))
+
+ from_rgba_hex(hex_int)
+}
+
+/// Returns a `Result(Colour)` created from the given hex `Int`.
+///
+/// Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffffff or less than 0x0.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red_half_opacity) = from_rgba_hex(0xff00007f)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn from_rgba_hex(hex: Int) -> Result(Colour, Nil) {
+ case hex > 0xffffffff || hex < 0 {
+ True -> Error(Nil)
+ False -> {
+ // This won't fail because we are always dividing by 255.0
+ let assert Ok(r) =
+ int.bitwise_shift_right(hex, 24)
+ |> int.bitwise_and(0xff)
+ |> int.to_float()
+ |> float.divide(255.0)
+ // This won't fail because we are always dividing by 255.0
+ let assert Ok(g) =
+ int.bitwise_shift_right(hex, 16)
+ |> int.bitwise_and(0xff)
+ |> int.to_float()
+ |> float.divide(255.0)
+ // This won't fail because we are always dividing by 255.0
+ let assert Ok(b) =
+ int.bitwise_shift_right(hex, 8)
+ |> int.bitwise_and(0xff)
+ |> int.to_float()
+ |> float.divide(255.0)
+ // This won't fail because we are always dividing by 255.0
+ let assert Ok(a) =
+ int.bitwise_and(hex, 0xff)
+ |> int.to_float()
+ |> float.divide(255.0)
+ from_rgba(r, g, b, a)
+ }
+ }
+}
+
+// CONVERSIONS ----------------------------------------------------------------
+
+/// Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s
+/// R, G, B, and A values respectively.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb255(255, 0, 0)
+/// let #(r, g, b, a) = to_rgba(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_rgba(colour: Colour) -> #(Float, Float, Float, Float) {
+ case colour {
+ Rgba(r, g, b, a) -> #(r, g, b, a)
+ Hsla(h, s, l, a) -> hsla_to_rgba(h, s, l, a)
+ }
+}
+
+/// Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s
+/// H, S, L, and A values respectively.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb255(255, 0, 0)
+/// let #(h, s, l, a) = to_hsla(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_hsla(colour: Colour) -> #(Float, Float, Float, Float) {
+ case colour {
+ Hsla(h, s, l, a) -> #(h, s, l, a)
+ Rgba(r, g, b, a) -> rgba_to_hsla(r, g, b, a)
+ }
+}
+
+/// Returns an rgba formatted CSS `String` created from the given `Colour`.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgb255(255, 0, 0)
+/// let css_red = to_css_rgba_string(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_css_rgba_string(colour: Colour) -> String {
+ let #(r, g, b, a) = to_rgba(colour)
+
+ let percent = fn(x: Float) -> Float {
+ // This won't fail because we are always dividing by 100.0
+ let assert Ok(p) =
+ x
+ |> float.multiply(10_000.0)
+ |> float.round()
+ |> int.to_float()
+ |> float.divide(100.0)
+
+ p
+ }
+
+ let round_to = fn(x: Float) -> Float {
+ // This won't fail because we are always dividing by 1000.0
+ let assert Ok(r) =
+ x
+ |> float.multiply(1000.0)
+ |> float.round()
+ |> int.to_float()
+ |> float.divide(1000.0)
+
+ r
+ }
+
+ string.join(
+ [
+ "rgba(",
+ float.to_string(percent(r)) <> "%,",
+ float.to_string(percent(g)) <> "%,",
+ float.to_string(percent(b)) <> "%,",
+ float.to_string(round_to(a)),
+ ")",
+ ],
+ "",
+ )
+}
+
+/// Returns an rgba hex formatted `String` created from the given `Colour`.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0)
+/// let red_hex = to_rgba_hex_string(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_rgba_hex_string(colour: Colour) -> String {
+ to_rgba_hex(colour)
+ |> int.to_base16()
+}
+
+/// Returns an rgb hex formatted `String` created from the given `Colour`.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgba(255, 0, 0)
+/// let red_hex = to_rgb_hex_string(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_rgb_hex_string(colour: Colour) -> String {
+ to_rgb_hex(colour)
+ |> int.to_base16()
+}
+
+/// Returns an hex `Int` created from the given `Colour`.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0)
+/// let red_hex_int = to_rgba_hex(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_rgba_hex(colour: Colour) -> Int {
+ let #(r, g, b, a) = to_rgba(colour)
+
+ let red =
+ r *. 255.0
+ |> float.round()
+ |> int.bitwise_shift_left(24)
+
+ let green =
+ g *. 255.0
+ |> float.round()
+ |> int.bitwise_shift_left(16)
+
+ let blue =
+ b *. 255.0
+ |> float.round()
+ |> int.bitwise_shift_left(8)
+
+ let alpha =
+ a *. 255.0
+ |> float.round()
+
+ red + green + blue + alpha
+}
+
+/// Returns a rgb hex `Int` created from the given `Colour`.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// assert Ok(red) = from_rgba(255, 0, 0)
+/// let red_hex_int = to_rgb_hex(red)
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn to_rgb_hex(colour: Colour) -> Int {
+ let #(r, g, b, _) = to_rgba(colour)
+
+ let red =
+ r *. 255.0
+ |> float.round()
+ |> int.bitwise_shift_left(16)
+
+ let green =
+ g *. 255.0
+ |> float.round()
+ |> int.bitwise_shift_left(8)
+
+ let blue =
+ b *. 255.0
+ |> float.round()
+
+ red + green + blue
+}
+
+// COLOURS --------------------------------------------------------------------
+
+/// A `Colour` reprsenting the colour RGBA(239, 41, 41, 1.0)
+pub const light_red = Rgba(
+ r: 0.9372549019607843,
+ g: 0.1607843137254902,
+ b: 0.1607843137254902,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(204, 0, 0, 1.0)
+pub const red = Rgba(r: 0.8, g: 0.0, b: 0.0, a: 1.0)
+
+/// A `Colour` reprsenting the colour RGBA(164, 0, 0, 1.0)
+pub const dark_red = Rgba(r: 0.6431372549019608, g: 0.0, b: 0.0, a: 1.0)
+
+/// A `Colour` reprsenting the colour RGBA(252, 175, 62, 1.0)
+pub const light_orange = Rgba(
+ r: 0.9882352941176471,
+ g: 0.6862745098039216,
+ b: 0.24313725490196078,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(245, 121, 0, 1.0)
+pub const orange = Rgba(
+ r: 0.9607843137254902,
+ g: 0.4745098039215686,
+ b: 0.0,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(206, 92, 0, 1.0)
+pub const dark_orange = Rgba(
+ r: 0.807843137254902,
+ g: 0.3607843137254902,
+ b: 0.0,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(255, 233, 79, 1.0)
+pub const light_yellow = Rgba(
+ r: 1.0,
+ g: 0.9137254901960784,
+ b: 0.30980392156862746,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(237, 212, 0, 1.0)
+pub const yellow = Rgba(
+ r: 0.9294117647058824,
+ g: 0.8313725490196079,
+ b: 0.0,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(196, 160, 0, 1.0)
+pub const dark_yellow = Rgba(
+ r: 0.7686274509803922,
+ g: 0.6274509803921569,
+ b: 0.0,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(138, 226, 52, 1.0)
+pub const light_green = Rgba(
+ r: 0.5411764705882353,
+ g: 0.8862745098039215,
+ b: 0.20392156862745098,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(115, 210, 22, 1.0)
+pub const green = Rgba(
+ r: 0.45098039215686275,
+ g: 0.8235294117647058,
+ b: 0.08627450980392157,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(78, 154, 6, 1.0)
+pub const dark_green = Rgba(
+ r: 0.3058823529411765,
+ g: 0.6039215686274509,
+ b: 0.023529411764705882,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(114, 159, 207, 1.0)
+pub const light_blue = Rgba(
+ r: 0.4470588235294118,
+ g: 0.6235294117647059,
+ b: 0.8117647058823529,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(52, 101, 164, 1.0)
+pub const blue = Rgba(
+ r: 0.20392156862745098,
+ g: 0.396078431372549,
+ b: 0.6431372549019608,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(32, 74, 135, 1.0)
+pub const dark_blue = Rgba(
+ r: 0.12549019607843137,
+ g: 0.2901960784313726,
+ b: 0.5294117647058824,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(173, 127, 168, 1.0)
+pub const light_purple = Rgba(
+ r: 0.6784313725490196,
+ g: 0.4980392156862745,
+ b: 0.6588235294117647,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(117, 80, 123, 1.0)
+pub const purple = Rgba(
+ r: 0.4588235294117647,
+ g: 0.3137254901960784,
+ b: 0.4823529411764706,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(92, 53, 102, 1.0)
+pub const dark_purple = Rgba(
+ r: 0.3607843137254902,
+ g: 0.20784313725490197,
+ b: 0.4,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(233, 185, 110, 1.0)
+pub const light_brown = Rgba(
+ r: 0.9137254901960784,
+ g: 0.7254901960784313,
+ b: 0.43137254901960786,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(193, 125, 17, 1.0)
+pub const brown = Rgba(
+ r: 0.7568627450980392,
+ g: 0.49019607843137253,
+ b: 0.06666666666666667,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(143, 89, 2, 1.0)
+pub const dark_brown = Rgba(
+ r: 0.5607843137254902,
+ g: 0.34901960784313724,
+ b: 0.00784313725490196,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(0, 0, 0, 1.0)
+pub const black = Rgba(r: 0.0, g: 0.0, b: 0.0, a: 1.0)
+
+/// A `Colour` reprsenting the colour RGBA(255, 255, 255, 1.0)
+pub const white = Rgba(r: 1.0, g: 1.0, b: 1.0, a: 1.0)
+
+/// A `Colour` reprsenting the colour RGBA(238, 238, 236, 1.0)
+pub const light_grey = Rgba(
+ r: 0.9333333333333333,
+ g: 0.9333333333333333,
+ b: 0.9254901960784314,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(211, 215, 207, 1.0)
+pub const grey = Rgba(
+ r: 0.8274509803921568,
+ g: 0.8431372549019608,
+ b: 0.8117647058823529,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(186, 189, 182, 1.0)
+pub const dark_grey = Rgba(
+ r: 0.7294117647058823,
+ g: 0.7411764705882353,
+ b: 0.7137254901960784,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(238, 238, 236, 1.0)
+pub const light_gray = Rgba(
+ r: 0.9333333333333333,
+ g: 0.9333333333333333,
+ b: 0.9254901960784314,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(211, 215, 207, 1.0)
+pub const gray = Rgba(
+ r: 0.8274509803921568,
+ g: 0.8431372549019608,
+ b: 0.8117647058823529,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(186, 189, 182, 1.0)
+pub const dark_gray = Rgba(
+ r: 0.7294117647058823,
+ g: 0.7411764705882353,
+ b: 0.7137254901960784,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(136, 138, 133, 1.0)
+pub const light_charcoal = Rgba(
+ r: 0.5333333333333333,
+ g: 0.5411764705882353,
+ b: 0.5215686274509804,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(85, 87, 83, 1.0)
+pub const charcoal = Rgba(
+ r: 0.3333333333333333,
+ g: 0.3411764705882353,
+ b: 0.3254901960784314,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(46, 52, 54, 1.0)
+pub const dark_charcoal = Rgba(
+ r: 0.1803921568627451,
+ g: 0.20392156862745098,
+ b: 0.21176470588235294,
+ a: 1.0,
+)
+
+/// A `Colour` reprsenting the colour RGBA(255, 175, 243, 1.0)
+pub const pink = Rgba(
+ r: 1.0,
+ g: 0.6862745098039216,
+ b: 0.9529411764705882,
+ a: 1.0,
+)
diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam
new file mode 100644
index 0000000..54f75e4
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam
@@ -0,0 +1,173 @@
+////
+//// - **Accessibility**
+//// - [`luminance`](#luminance)
+//// - [`contrast_ratio`](#contrast_ratio)
+//// - [`maximum_contrast`](#maximum_contrast)
+////
+//// ---
+////
+//// This package was heavily inspired by the `elm-color-extra` module.
+//// The original source code can be found
+//// <a href="https://github.com/noahzgordon/elm-color-extra">here</a>.
+////
+//// <details>
+//// <summary>The license of that package is produced below:</summary>
+////
+////
+//// > MIT License
+////
+//// > Copyright (c) 2016 Andreas Köberle
+////
+//// > 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.
+////
+//// </details>
+////
+
+// Just in case we decide in the future to no longer include the above reference
+// and license, this package was initially a port of the `elm-color-extra` module:
+//
+// https://github.com/noahzgordon/elm-color-extra
+//
+
+// IMPORTS --------------------------------------------------------------------
+
+import gleam/float
+import gleam/list
+import gleam_community/colour.{type Colour}
+
+// UTILITIES ------------------------------------------------------------------
+
+fn intensity(colour_value: Float) -> Float {
+ // Calculation taken from https://www.w3.org/TR/WCAG20/#relativeluminancedef
+ case True {
+ _ if colour_value <=. 0.03928 -> colour_value /. 12.92
+ _ -> {
+ // Is this guaranteed to be `OK`?
+ let assert Ok(i) = float.power({ colour_value +. 0.055 } /. 1.055, 2.4)
+ i
+ }
+ }
+}
+
+// ACCESSIBILITY --------------------------------------------------------------
+
+/// Returns the relative brightness of the given `Colour` as a `Float` between
+/// 0.0, and 1.0 with 0.0 being the darkest possible colour and 1.0 being the lightest.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// luminance(colour.white) // 1.0
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn luminance(colour: Colour) -> Float {
+ // Calculation taken from https://www.w3.org/TR/WCAG20/#relativeluminancedef
+ let #(r, g, b, _) = colour.to_rgba(colour)
+
+ let r_intensity = intensity(r)
+ let g_intensity = intensity(g)
+ let b_intensity = intensity(b)
+
+ 0.2126 *. r_intensity +. 0.7152 *. g_intensity +. 0.0722 *. b_intensity
+}
+
+/// Returns the contrast between two `Colour` values as a `Float` between 1.0,
+/// and 21.0 with 1.0 being no contrast and, 21.0 being the highest possible contrast.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// contrast_ratio(between: colour.white, and: colour.black) // 21.0
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn contrast_ratio(between colour_a: Colour, and colour_b: Colour) -> Float {
+ // Calculation taken from https://www.w3.org/TR/WCAG20/#contrast-ratiodef
+ let luminance_a = luminance(colour_a) +. 0.05
+ let luminance_b = luminance(colour_b) +. 0.05
+
+ case luminance_a >. luminance_b {
+ True -> luminance_a /. luminance_b
+ False -> luminance_b /. luminance_a
+ }
+}
+
+/// Returns the `Colour` with the highest contrast between the base `Colour`,
+/// and and the other provided `Colour` values.
+///
+/// <details>
+/// <summary>Example:</summary>
+///
+/// ```gleam
+/// fn example() {
+/// maximum_contrast(
+/// colour.yellow,
+/// [colour.white, colour.dark_blue, colour.green],
+/// )
+/// }
+/// ```
+/// </details>
+///
+/// <div style="position: relative;">
+/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
+/// <small>Spot a typo? Open an issue!</small>
+/// </a>
+/// <a style="position: absolute; right: 0;" href="#">
+/// <small>Back to top ↑</small>
+/// </a>
+/// </div>
+///
+pub fn maximum_contrast(
+ base: Colour,
+ colours: List(Colour),
+) -> Result(Colour, Nil) {
+ colours
+ |> list.sort(fn(colour_a, colour_b) {
+ let contrast_a = contrast_ratio(base, colour_a)
+ let contrast_b = contrast_ratio(base, colour_b)
+
+ float.compare(contrast_b, contrast_a)
+ })
+ |> list.first()
+}
diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour.erl b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour.erl
new file mode 100644
index 0000000..21e4c81
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour.erl
@@ -0,0 +1,511 @@
+-module(gleam_community@colour).
+-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
+
+-export([from_rgb255/3, from_rgb/3, from_rgba/4, from_hsla/4, from_hsl/3, from_rgb_hex/1, from_rgb_hex_string/1, from_rgba_hex/1, from_rgba_hex_string/1, to_rgba/1, to_hsla/1, to_css_rgba_string/1, to_rgba_hex/1, to_rgba_hex_string/1, to_rgb_hex/1, to_rgb_hex_string/1]).
+-export_type([colour/0]).
+
+-opaque colour() :: {rgba, float(), float(), float(), float()} |
+ {hsla, float(), float(), float(), float()}.
+
+-spec valid_colour_value(float()) -> {ok, float()} | {error, nil}.
+valid_colour_value(C) ->
+ case (C > 1.0) orelse (C < +0.0) of
+ true ->
+ {error, nil};
+
+ false ->
+ {ok, C}
+ end.
+
+-spec hue_to_rgb(float(), float(), float()) -> float().
+hue_to_rgb(Hue, M1, M2) ->
+ H = case Hue of
+ _ when Hue < +0.0 ->
+ Hue + 1.0;
+
+ _ when Hue > 1.0 ->
+ Hue - 1.0;
+
+ _ ->
+ Hue
+ end,
+ H_t_6 = H * 6.0,
+ H_t_2 = H * 2.0,
+ H_t_3 = H * 3.0,
+ case H of
+ _ when H_t_6 < 1.0 ->
+ M1 + (((M2 - M1) * H) * 6.0);
+
+ _ when H_t_2 < 1.0 ->
+ M2;
+
+ _ when H_t_3 < 2.0 ->
+ M1 + (((M2 - M1) * ((2.0 / 3.0) - H)) * 6.0);
+
+ _ ->
+ M1
+ end.
+
+-spec hex_string_to_int(binary()) -> {ok, integer()} | {error, nil}.
+hex_string_to_int(Hex_string) ->
+ Hex = case Hex_string of
+ <<"#"/utf8, Hex_number/binary>> ->
+ Hex_number;
+
+ <<"0x"/utf8, Hex_number@1/binary>> ->
+ Hex_number@1;
+
+ _ ->
+ Hex_string
+ end,
+ _pipe = Hex,
+ _pipe@1 = gleam@string:lowercase(_pipe),
+ _pipe@2 = gleam@string:to_graphemes(_pipe@1),
+ _pipe@3 = gleam@list:reverse(_pipe@2),
+ gleam@list:index_fold(
+ _pipe@3,
+ {ok, 0},
+ fun(Total, Char, Index) -> case Total of
+ {error, nil} ->
+ {error, nil};
+
+ {ok, V} ->
+ gleam@result:then(case Char of
+ <<"a"/utf8>> ->
+ {ok, 10};
+
+ <<"b"/utf8>> ->
+ {ok, 11};
+
+ <<"c"/utf8>> ->
+ {ok, 12};
+
+ <<"d"/utf8>> ->
+ {ok, 13};
+
+ <<"e"/utf8>> ->
+ {ok, 14};
+
+ <<"f"/utf8>> ->
+ {ok, 15};
+
+ _ ->
+ gleam@int:parse(Char)
+ end, fun(Num) ->
+ gleam@result:then(
+ gleam@int:power(16, gleam@int:to_float(Index)),
+ fun(Base) ->
+ {ok,
+ V + gleam@float:round(
+ gleam@int:to_float(Num) * Base
+ )}
+ end
+ )
+ end)
+ end end
+ ).
+
+-spec hsla_to_rgba(float(), float(), float(), float()) -> {float(),
+ float(),
+ float(),
+ float()}.
+hsla_to_rgba(H, S, L, A) ->
+ M2 = case L =< 0.5 of
+ true ->
+ L * (S + 1.0);
+
+ false ->
+ (L + S) - (L * S)
+ end,
+ M1 = (L * 2.0) - M2,
+ R = hue_to_rgb(H + (1.0 / 3.0), M1, M2),
+ G = hue_to_rgb(H, M1, M2),
+ B = hue_to_rgb(H - (1.0 / 3.0), M1, M2),
+ {R, G, B, A}.
+
+-spec rgba_to_hsla(float(), float(), float(), float()) -> {float(),
+ float(),
+ float(),
+ float()}.
+rgba_to_hsla(R, G, B, A) ->
+ Min_colour = gleam@float:min(R, gleam@float:min(G, B)),
+ Max_colour = gleam@float:max(R, gleam@float:max(G, B)),
+ H1 = case true of
+ _ when Max_colour =:= R ->
+ gleam@float:divide(G - B, Max_colour - Min_colour);
+
+ _ when Max_colour =:= G ->
+ _pipe = gleam@float:divide(B - R, Max_colour - Min_colour),
+ gleam@result:then(_pipe, fun(D) -> {ok, 2.0 + D} end);
+
+ _ ->
+ _pipe@1 = gleam@float:divide(R - G, Max_colour - Min_colour),
+ gleam@result:then(_pipe@1, fun(D@1) -> {ok, 4.0 + D@1} end)
+ end,
+ H2 = case H1 of
+ {ok, V} ->
+ {ok, V * (1.0 / 6.0)};
+
+ _ ->
+ H1
+ end,
+ H3 = case H2 of
+ {ok, V@1} when V@1 < +0.0 ->
+ V@1 + 1.0;
+
+ {ok, V@2} ->
+ V@2;
+
+ _ ->
+ +0.0
+ end,
+ L = (Min_colour + Max_colour) / 2.0,
+ S = case true of
+ _ when Min_colour =:= Max_colour ->
+ +0.0;
+
+ _ when L < 0.5 ->
+ case (Max_colour + Min_colour) of
+ 0.0 -> 0.0;
+ Gleam@denominator -> (Max_colour - Min_colour) / Gleam@denominator
+ end;
+
+ _ ->
+ case ((2.0 - Max_colour) - Min_colour) of
+ 0.0 -> 0.0;
+ Gleam@denominator@1 -> (Max_colour - Min_colour) / Gleam@denominator@1
+ end
+ end,
+ {H3, S, L, A}.
+
+-spec from_rgb255(integer(), integer(), integer()) -> {ok, colour()} |
+ {error, nil}.
+from_rgb255(Red, Green, Blue) ->
+ gleam@result:then(
+ begin
+ _pipe = Red,
+ _pipe@1 = gleam@int:to_float(_pipe),
+ _pipe@2 = gleam@float:divide(_pipe@1, 255.0),
+ gleam@result:then(_pipe@2, fun valid_colour_value/1)
+ end,
+ fun(R) ->
+ gleam@result:then(
+ begin
+ _pipe@3 = Green,
+ _pipe@4 = gleam@int:to_float(_pipe@3),
+ _pipe@5 = gleam@float:divide(_pipe@4, 255.0),
+ gleam@result:then(_pipe@5, fun valid_colour_value/1)
+ end,
+ fun(G) ->
+ gleam@result:then(
+ begin
+ _pipe@6 = Blue,
+ _pipe@7 = gleam@int:to_float(_pipe@6),
+ _pipe@8 = gleam@float:divide(_pipe@7, 255.0),
+ gleam@result:then(_pipe@8, fun valid_colour_value/1)
+ end,
+ fun(B) -> {ok, {rgba, R, G, B, 1.0}} end
+ )
+ end
+ )
+ end
+ ).
+
+-spec from_rgb(float(), float(), float()) -> {ok, colour()} | {error, nil}.
+from_rgb(Red, Green, Blue) ->
+ gleam@result:then(
+ valid_colour_value(Red),
+ fun(R) ->
+ gleam@result:then(
+ valid_colour_value(Green),
+ fun(G) ->
+ gleam@result:then(
+ valid_colour_value(Blue),
+ fun(B) -> {ok, {rgba, R, G, B, 1.0}} end
+ )
+ end
+ )
+ end
+ ).
+
+-spec from_rgba(float(), float(), float(), float()) -> {ok, colour()} |
+ {error, nil}.
+from_rgba(Red, Green, Blue, Alpha) ->
+ gleam@result:then(
+ valid_colour_value(Red),
+ fun(R) ->
+ gleam@result:then(
+ valid_colour_value(Green),
+ fun(G) ->
+ gleam@result:then(
+ valid_colour_value(Blue),
+ fun(B) ->
+ gleam@result:then(
+ valid_colour_value(Alpha),
+ fun(A) -> {ok, {rgba, R, G, B, A}} end
+ )
+ end
+ )
+ end
+ )
+ end
+ ).
+
+-spec from_hsla(float(), float(), float(), float()) -> {ok, colour()} |
+ {error, nil}.
+from_hsla(Hue, Saturation, Lightness, Alpha) ->
+ gleam@result:then(
+ valid_colour_value(Hue),
+ fun(H) ->
+ gleam@result:then(
+ valid_colour_value(Saturation),
+ fun(S) ->
+ gleam@result:then(
+ valid_colour_value(Lightness),
+ fun(L) ->
+ gleam@result:then(
+ valid_colour_value(Alpha),
+ fun(A) -> {ok, {hsla, H, S, L, A}} end
+ )
+ end
+ )
+ end
+ )
+ end
+ ).
+
+-spec from_hsl(float(), float(), float()) -> {ok, colour()} | {error, nil}.
+from_hsl(Hue, Saturation, Lightness) ->
+ from_hsla(Hue, Saturation, Lightness, 1.0).
+
+-spec from_rgb_hex(integer()) -> {ok, colour()} | {error, nil}.
+from_rgb_hex(Hex) ->
+ case (Hex > 16#ffffff) orelse (Hex < 0) of
+ true ->
+ {error, nil};
+
+ false ->
+ R = begin
+ _pipe = erlang:'bsr'(Hex, 16),
+ erlang:'band'(_pipe, 16#ff)
+ end,
+ G = begin
+ _pipe@1 = erlang:'bsr'(Hex, 8),
+ erlang:'band'(_pipe@1, 16#ff)
+ end,
+ B = erlang:'band'(Hex, 16#ff),
+ from_rgb255(R, G, B)
+ end.
+
+-spec from_rgb_hex_string(binary()) -> {ok, colour()} | {error, nil}.
+from_rgb_hex_string(Hex_string) ->
+ gleam@result:then(
+ hex_string_to_int(Hex_string),
+ fun(Hex_int) -> from_rgb_hex(Hex_int) end
+ ).
+
+-spec from_rgba_hex(integer()) -> {ok, colour()} | {error, nil}.
+from_rgba_hex(Hex) ->
+ case (Hex > 16#ffffffff) orelse (Hex < 0) of
+ true ->
+ {error, nil};
+
+ false ->
+ _assert_subject = begin
+ _pipe = erlang:'bsr'(Hex, 24),
+ _pipe@1 = erlang:'band'(_pipe, 16#ff),
+ _pipe@2 = gleam@int:to_float(_pipe@1),
+ gleam@float:divide(_pipe@2, 255.0)
+ end,
+ {ok, R} = case _assert_subject of
+ {ok, _} -> _assert_subject;
+ _assert_fail ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"from_rgba_hex"/utf8>>,
+ line => 588})
+ end,
+ _assert_subject@1 = begin
+ _pipe@3 = erlang:'bsr'(Hex, 16),
+ _pipe@4 = erlang:'band'(_pipe@3, 16#ff),
+ _pipe@5 = gleam@int:to_float(_pipe@4),
+ gleam@float:divide(_pipe@5, 255.0)
+ end,
+ {ok, G} = case _assert_subject@1 of
+ {ok, _} -> _assert_subject@1;
+ _assert_fail@1 ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail@1,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"from_rgba_hex"/utf8>>,
+ line => 594})
+ end,
+ _assert_subject@2 = begin
+ _pipe@6 = erlang:'bsr'(Hex, 8),
+ _pipe@7 = erlang:'band'(_pipe@6, 16#ff),
+ _pipe@8 = gleam@int:to_float(_pipe@7),
+ gleam@float:divide(_pipe@8, 255.0)
+ end,
+ {ok, B} = case _assert_subject@2 of
+ {ok, _} -> _assert_subject@2;
+ _assert_fail@2 ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail@2,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"from_rgba_hex"/utf8>>,
+ line => 600})
+ end,
+ _assert_subject@3 = begin
+ _pipe@9 = erlang:'band'(Hex, 16#ff),
+ _pipe@10 = gleam@int:to_float(_pipe@9),
+ gleam@float:divide(_pipe@10, 255.0)
+ end,
+ {ok, A} = case _assert_subject@3 of
+ {ok, _} -> _assert_subject@3;
+ _assert_fail@3 ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail@3,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"from_rgba_hex"/utf8>>,
+ line => 606})
+ end,
+ from_rgba(R, G, B, A)
+ end.
+
+-spec from_rgba_hex_string(binary()) -> {ok, colour()} | {error, nil}.
+from_rgba_hex_string(Hex_string) ->
+ gleam@result:then(
+ hex_string_to_int(Hex_string),
+ fun(Hex_int) -> from_rgba_hex(Hex_int) end
+ ).
+
+-spec to_rgba(colour()) -> {float(), float(), float(), float()}.
+to_rgba(Colour) ->
+ case Colour of
+ {rgba, R, G, B, A} ->
+ {R, G, B, A};
+
+ {hsla, H, S, L, A@1} ->
+ hsla_to_rgba(H, S, L, A@1)
+ end.
+
+-spec to_hsla(colour()) -> {float(), float(), float(), float()}.
+to_hsla(Colour) ->
+ case Colour of
+ {hsla, H, S, L, A} ->
+ {H, S, L, A};
+
+ {rgba, R, G, B, A@1} ->
+ rgba_to_hsla(R, G, B, A@1)
+ end.
+
+-spec to_css_rgba_string(colour()) -> binary().
+to_css_rgba_string(Colour) ->
+ {R, G, B, A} = to_rgba(Colour),
+ Percent = fun(X) ->
+ _assert_subject = begin
+ _pipe = X,
+ _pipe@1 = gleam@float:multiply(_pipe, 10000.0),
+ _pipe@2 = gleam@float:round(_pipe@1),
+ _pipe@3 = gleam@int:to_float(_pipe@2),
+ gleam@float:divide(_pipe@3, 100.0)
+ end,
+ {ok, P} = case _assert_subject of
+ {ok, _} -> _assert_subject;
+ _assert_fail ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"to_css_rgba_string"/utf8>>,
+ line => 704})
+ end,
+ P
+ end,
+ Round_to = fun(X@1) ->
+ _assert_subject@1 = begin
+ _pipe@4 = X@1,
+ _pipe@5 = gleam@float:multiply(_pipe@4, 1000.0),
+ _pipe@6 = gleam@float:round(_pipe@5),
+ _pipe@7 = gleam@int:to_float(_pipe@6),
+ gleam@float:divide(_pipe@7, 1000.0)
+ end,
+ {ok, R@1} = case _assert_subject@1 of
+ {ok, _} -> _assert_subject@1;
+ _assert_fail@1 ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail@1,
+ module => <<"gleam_community/colour"/utf8>>,
+ function => <<"to_css_rgba_string"/utf8>>,
+ line => 716})
+ end,
+ R@1
+ end,
+ gleam@string:join(
+ [<<"rgba("/utf8>>,
+ <<(gleam@float:to_string(Percent(R)))/binary, "%,"/utf8>>,
+ <<(gleam@float:to_string(Percent(G)))/binary, "%,"/utf8>>,
+ <<(gleam@float:to_string(Percent(B)))/binary, "%,"/utf8>>,
+ gleam@float:to_string(Round_to(A)),
+ <<")"/utf8>>],
+ <<""/utf8>>
+ ).
+
+-spec to_rgba_hex(colour()) -> integer().
+to_rgba_hex(Colour) ->
+ {R, G, B, A} = to_rgba(Colour),
+ Red = begin
+ _pipe = R * 255.0,
+ _pipe@1 = gleam@float:round(_pipe),
+ erlang:'bsl'(_pipe@1, 24)
+ end,
+ Green = begin
+ _pipe@2 = G * 255.0,
+ _pipe@3 = gleam@float:round(_pipe@2),
+ erlang:'bsl'(_pipe@3, 16)
+ end,
+ Blue = begin
+ _pipe@4 = B * 255.0,
+ _pipe@5 = gleam@float:round(_pipe@4),
+ erlang:'bsl'(_pipe@5, 8)
+ end,
+ Alpha = begin
+ _pipe@6 = A * 255.0,
+ gleam@float:round(_pipe@6)
+ end,
+ ((Red + Green) + Blue) + Alpha.
+
+-spec to_rgba_hex_string(colour()) -> binary().
+to_rgba_hex_string(Colour) ->
+ _pipe = to_rgba_hex(Colour),
+ gleam@int:to_base16(_pipe).
+
+-spec to_rgb_hex(colour()) -> integer().
+to_rgb_hex(Colour) ->
+ {R, G, B, _} = to_rgba(Colour),
+ Red = begin
+ _pipe = R * 255.0,
+ _pipe@1 = gleam@float:round(_pipe),
+ erlang:'bsl'(_pipe@1, 16)
+ end,
+ Green = begin
+ _pipe@2 = G * 255.0,
+ _pipe@3 = gleam@float:round(_pipe@2),
+ erlang:'bsl'(_pipe@3, 8)
+ end,
+ Blue = begin
+ _pipe@4 = B * 255.0,
+ gleam@float:round(_pipe@4)
+ end,
+ (Red + Green) + Blue.
+
+-spec to_rgb_hex_string(colour()) -> binary().
+to_rgb_hex_string(Colour) ->
+ _pipe = to_rgb_hex(Colour),
+ gleam@int:to_base16(_pipe).
diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl
new file mode 100644
index 0000000..64d37bf
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl
@@ -0,0 +1,73 @@
+-module(gleam_community@colour@accessibility).
+-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
+
+-export([luminance/1, contrast_ratio/2, maximum_contrast/2]).
+
+-spec intensity(float()) -> float().
+intensity(Colour_value) ->
+ case true of
+ _ when Colour_value =< 0.03928 ->
+ Colour_value / 12.92;
+
+ _ ->
+ _assert_subject = gleam@float:power(
+ (Colour_value + 0.055) / 1.055,
+ 2.4
+ ),
+ {ok, I} = case _assert_subject of
+ {ok, _} -> _assert_subject;
+ _assert_fail ->
+ erlang:error(#{gleam_error => let_assert,
+ message => <<"Assertion pattern match failed"/utf8>>,
+ value => _assert_fail,
+ module => <<"gleam_community/colour/accessibility"/utf8>>,
+ function => <<"intensity"/utf8>>,
+ line => 62})
+ end,
+ I
+ end.
+
+-spec luminance(gleam_community@colour:colour()) -> float().
+luminance(Colour) ->
+ {R, G, B, _} = gleam_community@colour:to_rgba(Colour),
+ R_intensity = intensity(R),
+ G_intensity = intensity(G),
+ B_intensity = intensity(B),
+ ((0.2126 * R_intensity) + (0.7152 * G_intensity)) + (0.0722 * B_intensity).
+
+-spec contrast_ratio(
+ gleam_community@colour:colour(),
+ gleam_community@colour:colour()
+) -> float().
+contrast_ratio(Colour_a, Colour_b) ->
+ Luminance_a = luminance(Colour_a) + 0.05,
+ Luminance_b = luminance(Colour_b) + 0.05,
+ case Luminance_a > Luminance_b of
+ true ->
+ case Luminance_b of
+ 0.0 -> 0.0;
+ Gleam@denominator -> Luminance_a / Gleam@denominator
+ end;
+
+ false ->
+ case Luminance_a of
+ 0.0 -> 0.0;
+ Gleam@denominator@1 -> Luminance_b / Gleam@denominator@1
+ end
+ end.
+
+-spec maximum_contrast(
+ gleam_community@colour:colour(),
+ list(gleam_community@colour:colour())
+) -> {ok, gleam_community@colour:colour()} | {error, nil}.
+maximum_contrast(Base, Colours) ->
+ _pipe = Colours,
+ _pipe@1 = gleam@list:sort(
+ _pipe,
+ fun(Colour_a, Colour_b) ->
+ Contrast_a = contrast_ratio(Base, Colour_a),
+ Contrast_b = contrast_ratio(Base, Colour_b),
+ gleam@float:compare(Contrast_b, Contrast_a)
+ end
+ ),
+ gleam@list:first(_pipe@1).
diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community_colour.app.src b/aoc2023/build/packages/gleam_community_colour/src/gleam_community_colour.app.src
new file mode 100644
index 0000000..a327650
--- /dev/null
+++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community_colour.app.src
@@ -0,0 +1,9 @@
+{application, gleam_community_colour, [
+ {vsn, "1.2.0"},
+ {applications, [gleam_stdlib,
+ gleeunit]},
+ {description, "Colour types, conversions, and other utilities"},
+ {modules, [gleam_community@colour,
+ gleam_community@colour@accessibility]},
+ {registered, []}
+]}.