<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://mbwiki.stairwaygames.work/w/index.php?action=history&amp;feed=atom&amp;title=Module%3AColors</id>
	<title>Module:Colors - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://mbwiki.stairwaygames.work/w/index.php?action=history&amp;feed=atom&amp;title=Module%3AColors"/>
	<link rel="alternate" type="text/html" href="https://mbwiki.stairwaygames.work/w/index.php?title=Module:Colors&amp;action=history"/>
	<updated>2026-04-07T16:27:03Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://mbwiki.stairwaygames.work/w/index.php?title=Module:Colors&amp;diff=5685&amp;oldid=prev</id>
		<title>Admin coral island: Created page with &quot;--- Colors library for embedded color processing in the FANDOM environment. --  It ports and extends functionality in the Colors JS library written by --  Pecoes. The module supports HSL, RGB and hexadecimal web --  colors. --   --  The module offers numerous features: --   * Color parameter support in Lua modules. --   * Color parameter insertion in wiki templates. --   * Color variable parsing for style templating. --   * Color item creation and convers...&quot;</title>
		<link rel="alternate" type="text/html" href="https://mbwiki.stairwaygames.work/w/index.php?title=Module:Colors&amp;diff=5685&amp;oldid=prev"/>
		<updated>2023-08-04T02:26:04Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;--- Colors library for embedded color processing in the FANDOM environment. --  It ports and extends functionality in the Colors JS library written by --  &lt;a href=&quot;/w/index.php?title=User:Pecoes&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;User:Pecoes (page does not exist)&quot;&gt;Pecoes&lt;/a&gt;. The module supports HSL, RGB and hexadecimal web --  colors. --   --  The module offers numerous features: --   * Color parameter support in Lua modules. --   * Color parameter insertion in wiki templates. --   * Color variable parsing for style templating. --   * Color item creation and convers...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--- Colors library for embedded color processing in the FANDOM environment.&lt;br /&gt;
--  It ports and extends functionality in the Colors JS library written by&lt;br /&gt;
--  [[User:Pecoes|Pecoes]]. The module supports HSL, RGB and hexadecimal web&lt;br /&gt;
--  colors.&lt;br /&gt;
--  &lt;br /&gt;
--  The module offers numerous features:&lt;br /&gt;
--   * Color parameter support in Lua modules.&lt;br /&gt;
--   * Color parameter insertion in wiki templates.&lt;br /&gt;
--   * Color variable parsing for style templating.&lt;br /&gt;
--   * Color item creation and conversion utilities.&lt;br /&gt;
--   * A vast array of color processing methods.&lt;br /&gt;
--   * Alpha and boolean support for flexible color logic.&lt;br /&gt;
--  &lt;br /&gt;
--  **This module will not work as expected on UCP wikis.**&lt;br /&gt;
--  &lt;br /&gt;
--  @module             colors&lt;br /&gt;
--  @alias              p&lt;br /&gt;
--  @release            unmaintained&lt;br /&gt;
--  @author             [[User:Speedit|Speedit]]&lt;br /&gt;
--  @version            2.5.2&lt;br /&gt;
--  @require            Module:I18n&lt;br /&gt;
--  @require            Module:Yesno&lt;br /&gt;
--  @require            Module:Entrypoint&lt;br /&gt;
--  &amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
-- Module package.&lt;br /&gt;
local p, utils, Color = {}, {}&lt;br /&gt;
&lt;br /&gt;
-- Module utilites, configuration/cache variables.&lt;br /&gt;
local yesno = require(&amp;#039;Dev:Yesno&amp;#039;)&lt;br /&gt;
local entrypoint = require(&amp;#039;Dev:Entrypoint&amp;#039;)&lt;br /&gt;
local sassParams = mw.site.sassParams or {}&lt;br /&gt;
&lt;br /&gt;
-- Web color RGB presets.&lt;br /&gt;
local presets = mw.loadData(&amp;#039;Dev:Colors/presets&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
-- Error message data.&lt;br /&gt;
local i18n = require(&amp;#039;Dev:I18n&amp;#039;).loadMessages(&amp;#039;Colors&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
-- Validation ranges for color types and number formats.&lt;br /&gt;
local ranges = {&lt;br /&gt;
    rgb         = {    0, 255 },&lt;br /&gt;
    hsl         = {    0,   1 },&lt;br /&gt;
    hue         = {    0, 360 },&lt;br /&gt;
    percentage  = { -100, 100 },&lt;br /&gt;
    prop        = {    0, 100 },&lt;br /&gt;
    degree      = { -360, 360 }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Internal color utilities.&lt;br /&gt;
&lt;br /&gt;
--- Boundary validation for color types.&lt;br /&gt;
--  @function           utils.check&lt;br /&gt;
--  @param              {string} t Range type.&lt;br /&gt;
--  @param              {number} n Number to validate.&lt;br /&gt;
--  @error[65]          {string} &amp;#039;invalid color value input: type($n) &amp;quot;$n&amp;quot;&amp;#039;&lt;br /&gt;
--  @error[67]          {string} &amp;#039;color value $n out of $t bounds&amp;#039;&lt;br /&gt;
--  @return             {boolean} Validity of number.&lt;br /&gt;
--  @local&lt;br /&gt;
function utils.check(t, n)&lt;br /&gt;
    local min = ranges[t][1] -- Boundary variables&lt;br /&gt;
    local max = ranges[t][2]&lt;br /&gt;
&lt;br /&gt;
    if type(n) ~= &amp;#039;number&amp;#039; then&lt;br /&gt;
        error(i18n:msg(&amp;#039;invalid-value&amp;#039;, type(n), tostring(n)))&lt;br /&gt;
    elseif n &amp;lt; min or n &amp;gt; max then&lt;br /&gt;
        error(i18n:msg(&amp;#039;out-of-bounds&amp;#039;, n, t))&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Rounding utility for color tuples.&lt;br /&gt;
--  @function           utils.round&lt;br /&gt;
--  @param              {number} tup Color tuple.&lt;br /&gt;
--  @param[opt]         {number} dec Number of decimal places.&lt;br /&gt;
--  @return             {number} Rounded tuple value.&lt;br /&gt;
--  @local&lt;br /&gt;
function utils.round(tup, dec)&lt;br /&gt;
    local ord = 10^(dec or 0)&lt;br /&gt;
    return math.floor(tup * ord + 0.5) / ord&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Cloning utility for color items.&lt;br /&gt;
--  @function           utils.clone&lt;br /&gt;
--  @param              {table} clr Color instance.&lt;br /&gt;
--  @param              {string} typ Color type of clone.&lt;br /&gt;
--  @return             {table} New (clone) color instance.&lt;br /&gt;
--  @local&lt;br /&gt;
function utils.clone(clr, typ)&lt;br /&gt;
    local c = Color:new( clr.tup, clr.typ, clr.alp ) -- new color&lt;br /&gt;
    utils.convert(c, typ) -- conversion&lt;br /&gt;
    return c -- output&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Range limiter for color processing.&lt;br /&gt;
--  @function           utils.limit&lt;br /&gt;
--  @param              {number} val Numeric value to limit.&lt;br /&gt;
--  @param              {number} max Maximum value for limit boundary.&lt;br /&gt;
--  @return             {number} Limited value.&lt;br /&gt;
--  @local&lt;br /&gt;
function utils.limit(val, max)&lt;br /&gt;
    return math.max(0, math.min(val, max))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Circular spatial processing for ranges.&lt;br /&gt;
--  @function           utils.circle&lt;br /&gt;
--  @param              {number} val Numeric value to cycle.&lt;br /&gt;
--  @param              {number} max Maximum value for cycle boundary.&lt;br /&gt;
--  @return             {number} Cyclical positive value below max.&lt;br /&gt;
--  @local&lt;br /&gt;
function utils.circle(val, max)&lt;br /&gt;
    if val &amp;lt; 0 then        -- negative; below cycle minimum&lt;br /&gt;
        val = val + max&lt;br /&gt;
    elseif val &amp;gt; max then  -- exceeds cycle maximum&lt;br /&gt;
        val = val - max&lt;br /&gt;
    end&lt;br /&gt;
    return val -- output&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color space converter.&lt;br /&gt;
--  @function           utils.convert&lt;br /&gt;
--  @param              {table} clr Color instance.&lt;br /&gt;
--  @param              {string} typ Color type to output.&lt;br /&gt;
--  @return             {table} Converted color instance.&lt;br /&gt;
--  @local&lt;br /&gt;
function utils.convert(clr, typ)&lt;br /&gt;
    if clr.typ ~= typ then&lt;br /&gt;
        clr.typ   = typ&lt;br /&gt;
        if typ == &amp;#039;rgb&amp;#039; then&lt;br /&gt;
            clr.tup = utils.hslToRgb(clr.tup)&lt;br /&gt;
        else&lt;br /&gt;
            clr.tup = utils.rgbToHsl(clr.tup)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    for i, t in ipairs(clr.tup) do&lt;br /&gt;
        if clr.typ == &amp;#039;rgb&amp;#039; then&lt;br /&gt;
            clr.tup[i] = utils.round(clr.tup[i], 0)&lt;br /&gt;
        elseif clr.typ == &amp;#039;hsl&amp;#039; then&lt;br /&gt;
            clr.tup[i] = i == 1&lt;br /&gt;
                and utils.round(clr.tup[i], 0)&lt;br /&gt;
                or  utils.round(clr.tup[i], 2)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- RGB-HSL tuple converter.&lt;br /&gt;
--  @function           utils.rgbToHsl&lt;br /&gt;
--  @param              {table} rgb Tuple table of RGB values.&lt;br /&gt;
--  @return             {table} Tuple table of HSL values.&lt;br /&gt;
--  @see                http://www.easyrgb.com/en/math.php#m_rgb_hsl&lt;br /&gt;
--  @local&lt;br /&gt;
function utils.rgbToHsl(rgb)&lt;br /&gt;
    for i, t in ipairs(rgb) do&lt;br /&gt;
        rgb[i] = t/255&lt;br /&gt;
    end&lt;br /&gt;
    local r,g,b = rgb[1], rgb[2], rgb[3]&lt;br /&gt;
&lt;br /&gt;
    local min = math.min(r, g, b)&lt;br /&gt;
    local max = math.max(r, g, b)&lt;br /&gt;
    local d = max - min&lt;br /&gt;
&lt;br /&gt;
    local h, s, l = 0, 0, ((min + max) / 2)&lt;br /&gt;
&lt;br /&gt;
    if d &amp;gt; 0 then&lt;br /&gt;
        s = l &amp;lt; 0.5 and d / (max + min) or d / (2 - max - min)&lt;br /&gt;
&lt;br /&gt;
        h = max == r and (g - b) / d or&lt;br /&gt;
            max == g and 2 + (b - r)/d or&lt;br /&gt;
            max == b and 4 + (r - g)/d&lt;br /&gt;
        h = utils.circle(h/6, 1)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return { h * 360, s, l }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- HSL component conversion subroutine to RGB.&lt;br /&gt;
--  @function           utils.hueToRgb&lt;br /&gt;
--  @param              {number} p Temporary variable 1.&lt;br /&gt;
--  @param              {number} q Temporary variable 2.&lt;br /&gt;
--  @param              {number} t Modifier for primary color.&lt;br /&gt;
--  @return             {number} HSL component.&lt;br /&gt;
--  @see                http://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/&lt;br /&gt;
--  @local&lt;br /&gt;
function utils.hueToRgb(p, q, t)&lt;br /&gt;
    if t &amp;lt; 0 then&lt;br /&gt;
        t = t + 1&lt;br /&gt;
    elseif t &amp;gt; 1 then&lt;br /&gt;
        t = t - 1&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if t &amp;lt; 1/6 then&lt;br /&gt;
        return p + (q - p) * 6 * t&lt;br /&gt;
    elseif t &amp;lt; 1/2 then&lt;br /&gt;
        return q&lt;br /&gt;
    elseif t &amp;lt; 2/3 then&lt;br /&gt;
        return p + (q - p) * (2/3 - t) * 6&lt;br /&gt;
    else&lt;br /&gt;
        return p&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- HSL-RGB tuple converter.&lt;br /&gt;
--  @function           utils.hslToRgb&lt;br /&gt;
--  @param              {table} hsl Tuple table of HSL values.&lt;br /&gt;
--  @return             {table} Tuple table of RGB values.&lt;br /&gt;
--  @local&lt;br /&gt;
function utils.hslToRgb(hsl)&lt;br /&gt;
    local h, s, l = hsl[1]/360, hsl[2], hsl[3]&lt;br /&gt;
    local r&lt;br /&gt;
    local g&lt;br /&gt;
    local b&lt;br /&gt;
    local p&lt;br /&gt;
    local q&lt;br /&gt;
&lt;br /&gt;
    if s == 0 then&lt;br /&gt;
        r, g, b = l, l, l&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
        q = l &amp;lt; 0.5 and l * (1 + s) or l + s - l * s&lt;br /&gt;
&lt;br /&gt;
        p = 2 * l - q&lt;br /&gt;
&lt;br /&gt;
        r = utils.hueToRgb(p, q, h + 1/3)&lt;br /&gt;
        g = utils.hueToRgb(p, q, h)&lt;br /&gt;
        b = utils.hueToRgb(p, q, h - 1/3)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return { r * 255, g * 255, b * 255 }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Percentage-number conversion utility.&lt;br /&gt;
--  @function       utils.np&lt;br /&gt;
--  @param          {string} str Number string.&lt;br /&gt;
--  @param          {number} mul Upper bound number multiplier.&lt;br /&gt;
--  @return         {number} Bounded number.&lt;br /&gt;
--  @local&lt;br /&gt;
function utils.np(str, mul)&lt;br /&gt;
    str = str:match(&amp;#039;^%s*([^%%]+)%%%s*$&amp;#039;)&lt;br /&gt;
    local pct = tonumber(str)&lt;br /&gt;
    return pct * mul&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- CSS color functional notation parser.&lt;br /&gt;
--  @function       utils.parseColorSpace&lt;br /&gt;
--  @param          {string} str Color string.&lt;br /&gt;
--  @param          {string} spc Color function name.&lt;br /&gt;
--  @param          {table} mul Tuple color multipliers.&lt;br /&gt;
--  @return         {table} Color space tuple.&lt;br /&gt;
--  @return         {table} Color alpha value.&lt;br /&gt;
--  @local&lt;br /&gt;
function utils.parseColorSpace(str, spc, mul)&lt;br /&gt;
    local PTN = &amp;#039;^&amp;#039; .. spc .. &amp;#039;a?%(([%d%s%%.,]+)%)$&amp;#039;&lt;br /&gt;
    local tup = mw.text.split(str:match(PTN), &amp;#039;[%s,]+&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
    tup[4] = tup[4] or &amp;#039;1&amp;#039;&lt;br /&gt;
    local alp = tup[4]:find(&amp;#039;%%$&amp;#039;)&lt;br /&gt;
        and utils.np(tup[4], 1/100)&lt;br /&gt;
        or  tonumber(tup[4])&lt;br /&gt;
    table.remove(tup, 4)&lt;br /&gt;
&lt;br /&gt;
    for i, t in ipairs(tup) do&lt;br /&gt;
        tup[i] = t:find(&amp;#039;%%$&amp;#039;)&lt;br /&gt;
            and utils.np(t, mul[i])&lt;br /&gt;
            or  tonumber(t)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return tup, alp&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color item class, used for color processing.&lt;br /&gt;
--  The class provides color prop getter-setters, procedures for color computation,&lt;br /&gt;
--  compositing methods and serialisation into CSS color formats.&lt;br /&gt;
--  @type               Color&lt;br /&gt;
Color = {}&lt;br /&gt;
Color.__index = Color&lt;br /&gt;
Color.__tostring = function() return &amp;#039;Color&amp;#039; end&lt;br /&gt;
&lt;br /&gt;
--- Color tuple.&lt;br /&gt;
--  @table              Color.tup&lt;br /&gt;
Color.tup = {}&lt;br /&gt;
&lt;br /&gt;
--- Color space type.&lt;br /&gt;
--  @member             {string} Color.typ&lt;br /&gt;
Color.typ = &amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
--- Color alpha channel value.&lt;br /&gt;
--  @member             {number} Color.alp&lt;br /&gt;
Color.alp = 1&lt;br /&gt;
&lt;br /&gt;
--- Color instance constructor.&lt;br /&gt;
--  @function           Color:new&lt;br /&gt;
--  @param              {string} typ Color space type (`&amp;#039;hsl&amp;#039;` or `&amp;#039;rgb&amp;#039;`).&lt;br /&gt;
--  @param              {table} tup Color tuple in HSL or RGB&lt;br /&gt;
--  @param              {number} alp Alpha value range (`0` - `1`).&lt;br /&gt;
--  @error[304]         {string} &amp;#039;no color data provided&amp;#039;&lt;br /&gt;
--  @error[309]         {string} &amp;#039;invalid color type &amp;quot;$1&amp;quot; specified&amp;#039;&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
function Color:new(tup, typ, alp)&lt;br /&gt;
    local o = {}&lt;br /&gt;
    setmetatable(o, self)&lt;br /&gt;
&lt;br /&gt;
    -- is color tuple valid?&lt;br /&gt;
    if type(tup) ~= &amp;#039;table&amp;#039; or #tup ~= 3 then&lt;br /&gt;
        error(i18n:msg(&amp;#039;no-data&amp;#039;))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- is color type valid?&lt;br /&gt;
    if typ ~= &amp;#039;rgb&amp;#039; and typ ~= &amp;#039;hsl&amp;#039; then&lt;br /&gt;
        error(i18n:msg(&amp;#039;invalid-type&amp;#039;, typ))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- are color tuple entries valid?&lt;br /&gt;
    for n = 1, 3 do&lt;br /&gt;
        utils.check( (n == 1 and typ == &amp;#039;hsl&amp;#039;) and &amp;#039;hue&amp;#039; or typ, tup[n])&lt;br /&gt;
    end&lt;br /&gt;
    utils.check(&amp;#039;hsl&amp;#039;, alp)&lt;br /&gt;
&lt;br /&gt;
    o.tup = tup&lt;br /&gt;
    o.typ = typ&lt;br /&gt;
    o.alp = alp&lt;br /&gt;
    return o&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color string default output.&lt;br /&gt;
--  @function           Color:string&lt;br /&gt;
--  @return             {string} Hexadecimal 6-digit or HSLA color string.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;hsl(214, 15%, 30%)&amp;#039;):string() == &amp;#039;#404a57&amp;#039;&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#404a5780&amp;#039;):string() == &amp;#039;hsl(214, 15%, 30%, 0.5)&amp;#039;&lt;br /&gt;
function Color:string()&lt;br /&gt;
    return self.alp ~= 1 and self:hsl() or self:hex()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color hexadecimal string output.&lt;br /&gt;
--  @function           Color:hex&lt;br /&gt;
--  @return             {string} Hexadecimal color string.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;hsl(214, 15%, 30%)&amp;#039;):hex() == &amp;#039;#404a57&amp;#039;&lt;br /&gt;
function Color:hex()&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;rgb&amp;#039;)&lt;br /&gt;
    local hex = &amp;#039;#&amp;#039;&lt;br /&gt;
&lt;br /&gt;
    for i, t in ipairs(this.tup) do&lt;br /&gt;
        -- Hexadecimal conversion.&lt;br /&gt;
        hex = #string.format(&amp;#039;%x&amp;#039;, t) == 1 -- leftpad&lt;br /&gt;
            and hex .. &amp;#039;0&amp;#039; .. string.format(&amp;#039;%x&amp;#039;, t)&lt;br /&gt;
            or hex .. string.format(&amp;#039;%x&amp;#039;, t)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local alp = string.format(&amp;#039;%x&amp;#039;, this.alp * 255)&lt;br /&gt;
    if alp ~= &amp;#039;ff&amp;#039; then&lt;br /&gt;
        hex = #alp == 1 and hex .. &amp;#039;0&amp;#039; .. alp or hex .. alp&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return hex&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- RGBA functional color string output.&lt;br /&gt;
--  @function           Color:rgb&lt;br /&gt;
--  @return             {string} RGBA color string.&lt;br /&gt;
--  @see                https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#rgb()_and_rgba()&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;hsl(214, 15%, 30%)&amp;#039;):rgb() == &amp;#039;rgb(64, 74, 87)&amp;#039;&lt;br /&gt;
function Color:rgb()&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;rgb&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
    return this.alp ~= 1&lt;br /&gt;
        and &amp;#039;rgba(&amp;#039; .. table.concat(this.tup, &amp;#039;, &amp;#039;) .. &amp;#039;, &amp;#039; .. this.alp .. &amp;#039;)&amp;#039;&lt;br /&gt;
        or  &amp;#039;rgb(&amp;#039; .. table.concat(this.tup, &amp;#039;, &amp;#039;) .. &amp;#039;)&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- HSL functional color string output.&lt;br /&gt;
--  @function           Color:hsl&lt;br /&gt;
--  @return             {string} HSLA color string.&lt;br /&gt;
--  @see                https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#hsl()_and_hsla()&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;rgb(64, 74, 87)&amp;#039;):hsl() == &amp;#039;hsl(214, 15%, 30%)&amp;#039;&lt;br /&gt;
function Color:hsl()&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;hsl&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
    for i, t in ipairs(this.tup) do&lt;br /&gt;
        if i == 2 or i == 3 then&lt;br /&gt;
            this.tup[i] = tostring(t*100) .. &amp;#039;%&amp;#039;&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return this.alp ~= 1&lt;br /&gt;
        and &amp;#039;hsla(&amp;#039; .. table.concat(this.tup, &amp;#039;, &amp;#039;) .. &amp;#039;, &amp;#039; .. this.alp .. &amp;#039;)&amp;#039;&lt;br /&gt;
        or  &amp;#039;hsl(&amp;#039; .. table.concat(this.tup, &amp;#039;, &amp;#039;) .. &amp;#039;)&amp;#039; &lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Red color property getter-setter.&lt;br /&gt;
--  @function           Color:red&lt;br /&gt;
--  @param[opt]         {number} val Red value to set (`1` - `255`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#000000&amp;#039;):red(255):string() == &amp;#039;#ff0000&amp;#039;&lt;br /&gt;
function Color:red(val)&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;rgb&amp;#039;)&lt;br /&gt;
    if val then&lt;br /&gt;
        utils.check(&amp;#039;rgb&amp;#039;, val)&lt;br /&gt;
&lt;br /&gt;
        this.tup[1] = val&lt;br /&gt;
        return this -- chainable&lt;br /&gt;
    else&lt;br /&gt;
        return this.tup[1]&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Green color property getter-setter.&lt;br /&gt;
--  @function           Color:green&lt;br /&gt;
--  @param[opt]         {number} val Green value to set (`1` - `255`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ffffff&amp;#039;):green(1):string() == &amp;#039;#ff00ff&amp;#039;&lt;br /&gt;
function Color:green(val)&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;rgb&amp;#039;)&lt;br /&gt;
    if val then&lt;br /&gt;
        utils.check(&amp;#039;rgb&amp;#039;, val)&lt;br /&gt;
&lt;br /&gt;
        this.tup[2] = val&lt;br /&gt;
        return this -- chainable&lt;br /&gt;
    else&lt;br /&gt;
        return this.tup[2]&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Blue color property getter-setter.&lt;br /&gt;
--  @function           Color:blue&lt;br /&gt;
--  @param[opt]         {number} val Blue value to set (`1` - `255`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#00ff00&amp;#039;):blue(255):string() == &amp;#039;#00ffff&amp;#039;&lt;br /&gt;
function Color:blue(val)&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;rgb&amp;#039;)&lt;br /&gt;
    if val then&lt;br /&gt;
        utils.check(&amp;#039;rgb&amp;#039;, val)&lt;br /&gt;
&lt;br /&gt;
        this.tup[3] = val&lt;br /&gt;
        return this -- chainable&lt;br /&gt;
    else&lt;br /&gt;
        return this.tup[3]&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Hue color property getter-setter.&lt;br /&gt;
--  @function           Color:hue&lt;br /&gt;
--  @param[opt]         {number} val Hue value to set (`0` - `360`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ff0000&amp;#039;):hue(180):string() == &amp;#039;#00ffff&amp;#039;&lt;br /&gt;
function Color:hue(val) &lt;br /&gt;
    local this = utils.clone(self, &amp;#039;hsl&amp;#039;)&lt;br /&gt;
    if val then&lt;br /&gt;
        utils.check(&amp;#039;hue&amp;#039;, val)&lt;br /&gt;
&lt;br /&gt;
        this.tup[1] = val&lt;br /&gt;
        return this -- chainable&lt;br /&gt;
    else&lt;br /&gt;
        return this.tup[1]&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Saturation color property getter-setter.&lt;br /&gt;
--  @function           Color:sat&lt;br /&gt;
--  @param[opt]         {number} val Saturation value to set (`0` - `100`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ff0000&amp;#039;):sat(0):string() == &amp;#039;#808080&amp;#039;&lt;br /&gt;
function Color:sat(val)&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;hsl&amp;#039;)&lt;br /&gt;
    if val then&lt;br /&gt;
        val = val / 100&lt;br /&gt;
        utils.check(&amp;#039;hsl&amp;#039;, val)&lt;br /&gt;
&lt;br /&gt;
        this.tup[2] = val&lt;br /&gt;
        return this -- chainable&lt;br /&gt;
    else&lt;br /&gt;
        return this.tup[2]&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Lightness color property getter-setter.&lt;br /&gt;
--  @function           Color:lum&lt;br /&gt;
--  @param[opt]         {number} val Luminosity value to set (`0` - `100`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ff0000&amp;#039;):lum(0):string() == &amp;#039;#000000&amp;#039;&lt;br /&gt;
function Color:lum(val)&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;hsl&amp;#039;)&lt;br /&gt;
    if val then&lt;br /&gt;
        val = val / 100&lt;br /&gt;
        utils.check(&amp;#039;hsl&amp;#039;, val)&lt;br /&gt;
&lt;br /&gt;
        this.tup[3] = val&lt;br /&gt;
        return this -- chainable&lt;br /&gt;
    else&lt;br /&gt;
        return this.tup[3]&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Alpha getter-setter for color compositing.&lt;br /&gt;
--  @function           Color:alpha&lt;br /&gt;
--  @param              {number} val Modifier 0 - 100.&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ffffff&amp;#039;):alpha(0):string() == &amp;#039;hsla(0, 0%, 0%, 0)&amp;#039;&lt;br /&gt;
function Color:alpha(val)&lt;br /&gt;
    if val then&lt;br /&gt;
        utils.check(&amp;#039;prop&amp;#039;, val)&lt;br /&gt;
        self.alp = val / 100&lt;br /&gt;
&lt;br /&gt;
        return self&lt;br /&gt;
    else&lt;br /&gt;
        return self.alp&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Post-processing operator for color hue rotation.&lt;br /&gt;
--  @function           Color:rotate&lt;br /&gt;
--  @param              {number} mod Modifier (`-360` - `360`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ff0000&amp;#039;):rotate(60):string() == &amp;#039;#ffff00&amp;#039;&lt;br /&gt;
function Color:rotate(mod) &lt;br /&gt;
    utils.check(&amp;#039;degree&amp;#039;, mod)&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;hsl&amp;#039;)&lt;br /&gt;
    this.tup[1] = utils.circle(this.tup[1] + mod, 360)&lt;br /&gt;
    return this&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Post-processing operator for web color saturation.&lt;br /&gt;
--  @function           Color:saturate&lt;br /&gt;
--  @param              {number} mod Modifier (`-100` - `100`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ff0000&amp;#039;):saturate(-25):string() == &amp;#039;#df2020&amp;#039;&lt;br /&gt;
function Color:saturate(mod)&lt;br /&gt;
    utils.check(&amp;#039;percentage&amp;#039;, mod)&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;hsl&amp;#039;)&lt;br /&gt;
    this.tup[2] = utils.limit(this.tup[2] + (mod / 100), 1)&lt;br /&gt;
    return this&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Post-processing operator for web color lightness.&lt;br /&gt;
--  @function           Color:lighten&lt;br /&gt;
--  @param              {number} mod Modifier (`-100` - `100`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ff0000&amp;#039;):lighten(25):string() == &amp;#039;#ff8080&amp;#039;&lt;br /&gt;
function Color:lighten(mod)&lt;br /&gt;
    utils.check(&amp;#039;percentage&amp;#039;, mod)&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;hsl&amp;#039;)&lt;br /&gt;
    this.tup[3] = utils.limit(this.tup[3] + (mod / 100), 1)&lt;br /&gt;
    return this&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Opacification utility for color compositing.&lt;br /&gt;
--  @function           Color:opacify&lt;br /&gt;
--  @param              {number} mod Modifier (`-100` - `100`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ffffff&amp;#039;):opacify(-25):string() == &amp;#039;hsla(0, 0%, 100%, 0.75)&amp;#039;&lt;br /&gt;
function Color:opacify(mod)&lt;br /&gt;
    utils.check(&amp;#039;percentage&amp;#039;, mod)&lt;br /&gt;
    self.alp = utils.limit(self.alp + (mod / 100), 1)&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color additive mixing utility.&lt;br /&gt;
--  @function           Color:mix&lt;br /&gt;
--  @param              {string|table} other Module-compatible color string or instance.&lt;br /&gt;
--  @param[opt]         {number} weight Color weight of original (`0` - `100`). Default: `50`.&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#fff&amp;#039;):mix(&amp;#039;#000&amp;#039;, 80):hex() == &amp;#039;#cccccc&amp;#039;&lt;br /&gt;
function Color:mix(other, weight)&lt;br /&gt;
    if not p.instance(other) then&lt;br /&gt;
        other = p.parse(other)&lt;br /&gt;
        utils.convert(other, &amp;#039;rgb&amp;#039;)&lt;br /&gt;
    else&lt;br /&gt;
        other = utils.clone(other, &amp;#039;rgb&amp;#039;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    weight = weight or 50&lt;br /&gt;
    utils.check(&amp;#039;prop&amp;#039;, weight)&lt;br /&gt;
    weight = weight/100&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;rgb&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
    for i, t in ipairs(this.tup) do&lt;br /&gt;
        this.tup[i] = t * weight + other.tup[i] * (1 - weight)&lt;br /&gt;
        this.tup[i] = utils.limit(this.tup[i], 255)&lt;br /&gt;
    end&lt;br /&gt;
    return this&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color inversion utility.&lt;br /&gt;
--  @function           Color:invert&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ffffff&amp;#039;):invert():hex() == &amp;#039;#000000&amp;#039;&lt;br /&gt;
function Color:invert()&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;rgb&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
    for i, t in ipairs(this.tup) do&lt;br /&gt;
        this.tup[i] = 255 - t&lt;br /&gt;
    end&lt;br /&gt;
    return this&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Complementary color utility.&lt;br /&gt;
--  @function           Color:complement&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ff8000&amp;#039;):complement():hex() == &amp;#039;#0080ff&amp;#039;&lt;br /&gt;
function Color:complement()&lt;br /&gt;
    return self:rotate(180)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color brightness status testing.&lt;br /&gt;
--  @function           Color:bright&lt;br /&gt;
--  @param[opt]         {number} lim Luminosity threshold. Default: `50`.&lt;br /&gt;
--  @return             {boolean} Boolean for tone beyond threshold.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ff8000&amp;#039;):bright() == true&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ff8000&amp;#039;):bright(60) == false&lt;br /&gt;
function Color:bright(lim)&lt;br /&gt;
    lim = lim and tonumber(lim)/100 or 0.5&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;hsl&amp;#039;)&lt;br /&gt;
    return this.tup[3] &amp;gt;= lim&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color luminance status testing.&lt;br /&gt;
--  @function            Color:luminant&lt;br /&gt;
--  @param[opt]          {number} lim Luminance threshold. Default: `50`.&lt;br /&gt;
--  @return              {boolean} Boolean for luminance beyond threshold.&lt;br /&gt;
--  @see                 [[wikipedia:Relative luminance|Relative luminance (Wikipedia)]]&lt;br /&gt;
--  @usage               colors.parse(&amp;#039;#ffff00&amp;#039;):luminant() == true&lt;br /&gt;
--  @usage               colors.parse(&amp;#039;#ffff00&amp;#039;):luminant(95) == false&lt;br /&gt;
function Color:luminant(lim)&lt;br /&gt;
    lim = lim and tonumber(lim)/100 or 0.5&lt;br /&gt;
    utils.check(&amp;#039;hsl&amp;#039;, lim)&lt;br /&gt;
&lt;br /&gt;
    local hsl = utils.clone(self, &amp;#039;hsl&amp;#039;)&lt;br /&gt;
    local sat = hsl.tup[2]&lt;br /&gt;
    local lum = hsl.tup[3]&lt;br /&gt;
    local rgb = utils.clone(self, &amp;#039;rgb&amp;#039;).tup&lt;br /&gt;
&lt;br /&gt;
    for i, t in ipairs(rgb) do&lt;br /&gt;
        rgb[i] = t &amp;gt; 0.4045 and&lt;br /&gt;
            math.pow(((t + 0.05) / 1.055), 2.4) or&lt;br /&gt;
            t / 12.92&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local rel =&lt;br /&gt;
        rgb[1] * 0.2126 +&lt;br /&gt;
        rgb[2] * 0.7152 +&lt;br /&gt;
        rgb[3] * 0.0722&lt;br /&gt;
&lt;br /&gt;
    local quo = sat * (0.2038 * (rel - 0.5) / 0.5)&lt;br /&gt;
&lt;br /&gt;
    return (lum &amp;gt;= (lim - quo))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color saturation and visibility status testing.&lt;br /&gt;
--  @function           Color:chromatic&lt;br /&gt;
--  @return             {boolean} Boolean for color status.&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ffff00&amp;#039;):chromatic() == true&lt;br /&gt;
function Color:chromatic()&lt;br /&gt;
    local this = utils.clone(self, &amp;#039;hsl&amp;#039;)&lt;br /&gt;
    return this.tup[2] ~= 0 and -- sat   = not 0&lt;br /&gt;
           this.tup[3] ~= 0 and -- lum   = not 0&lt;br /&gt;
           this.alp ~= 0        -- alpha = not 0&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Package methods and members.&lt;br /&gt;
&lt;br /&gt;
--- Creation of RGB color instances.&lt;br /&gt;
--  @function           p.fromRgb&lt;br /&gt;
--  @param              {number} r Red value (`0` - `255`).&lt;br /&gt;
--  @param              {number} g Green value (`0` - `255`).&lt;br /&gt;
--  @param              {number} b Blue (`0` - `255`).&lt;br /&gt;
--  @param[opt]         {number} a Alpha value (`0` - `1`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.fromRgb(255, 255, 255, 0.2)&lt;br /&gt;
--  @see                Color:new&lt;br /&gt;
function p.fromRgb(r, g, b, a)&lt;br /&gt;
    return Color:new({ r, g, b }, &amp;#039;rgb&amp;#039;, a or 1);&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Creation of HSL color instances.&lt;br /&gt;
--  @function           p.fromHsl&lt;br /&gt;
--  @param              {number} h Hue value (`0` - `360`)&lt;br /&gt;
--  @param              {number} s Saturation value (`0` - `1`). &lt;br /&gt;
--  @param              {number} l Luminance value (`0` - `1`).&lt;br /&gt;
--  @param[opt]         {number} a Alpha channel (`0` - `1`).&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @usage              colors.fromHsl(0, 0, 1, 0.2)&lt;br /&gt;
--  @see                Color:new&lt;br /&gt;
function p.fromHsl(h, s, l, a)&lt;br /&gt;
    return Color:new({ h, s, l }, &amp;#039;hsl&amp;#039;, a or 1);&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Parsing logic for color strings.&lt;br /&gt;
--  @function           p.parse&lt;br /&gt;
--  @param              {string} str Valid color string.&lt;br /&gt;
--  @error[756]         {string} &amp;#039;cannot parse $str&amp;#039;&lt;br /&gt;
--  @return             {Color} Color instance.&lt;br /&gt;
--  @see                Color:new&lt;br /&gt;
--  @usage              colors.parse(&amp;#039;#ffffff&amp;#039;)&lt;br /&gt;
function p.parse(str)&lt;br /&gt;
    local typ&lt;br /&gt;
    local tup = {}&lt;br /&gt;
    local alp = 1&lt;br /&gt;
    str = mw.text.trim(str)&lt;br /&gt;
&lt;br /&gt;
    local VAR_PTN = &amp;#039;^%$([%w-]+)$&amp;#039;&lt;br /&gt;
    if p.params and p.params[str:match(VAR_PTN) or &amp;#039;&amp;#039;] then&lt;br /&gt;
        str = p.params[str:match(VAR_PTN)]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Hexadecimal color patterns.&lt;br /&gt;
    local HEX_PTN_3 = &amp;#039;^%#(%x)(%x)(%x)$&amp;#039;&lt;br /&gt;
    local HEX_PTN_4 = &amp;#039;^%#(%x)(%x)(%x)(%x)$&amp;#039;&lt;br /&gt;
    local HEX_PTN_6 = &amp;#039;^%#(%x%x)(%x%x)(%x%x)$&amp;#039;&lt;br /&gt;
    local HEX_PTN_8 = &amp;#039;^%#(%x%x)(%x%x)(%x%x)(%x%x)$&amp;#039;&lt;br /&gt;
&lt;br /&gt;
    -- Hexadecimal color parsing.&lt;br /&gt;
    if&lt;br /&gt;
        str:match(&amp;#039;^%#[%x]+$&amp;#039;)  and&lt;br /&gt;
        (#str == 4 or #str == 5 or -- #xxxx?&lt;br /&gt;
        #str == 7 or #str == 9)    -- #xxxxxxx?x?&lt;br /&gt;
    then&lt;br /&gt;
        if #str == 4 then&lt;br /&gt;
            tup[1], tup[2], tup[3] = str:match(HEX_PTN_3)&lt;br /&gt;
        elseif #str == 5 then&lt;br /&gt;
            tup[1], tup[2], tup[3], alp = str:match(HEX_PTN_4)&lt;br /&gt;
            alp = alp .. alp&lt;br /&gt;
        elseif #str == 7 then&lt;br /&gt;
            tup[1], tup[2], tup[3] = str:match(HEX_PTN_6)&lt;br /&gt;
            alp = 1&lt;br /&gt;
        elseif #str == 9 then&lt;br /&gt;
            tup[1], tup[2], tup[3], alp = str:match(HEX_PTN_8)&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        for i, t in ipairs(tup) do&lt;br /&gt;
            tup[i] = tonumber(#t == 2 and t or t .. t, 16)&lt;br /&gt;
        end&lt;br /&gt;
        if #str == 5 or #str == 9 then&lt;br /&gt;
            alp = tonumber(alp, 16)&lt;br /&gt;
        end&lt;br /&gt;
        typ = &amp;#039;rgb&amp;#039;&lt;br /&gt;
&lt;br /&gt;
    -- Color functional notation parsing.&lt;br /&gt;
    elseif str:find(&amp;#039;rgba?%([%d%s,.%%]+%)&amp;#039;) then&lt;br /&gt;
        tup, alp = utils.parseColorSpace(str, &amp;#039;rgb&amp;#039;, { 255, 255, 255 })&lt;br /&gt;
        typ = &amp;#039;rgb&amp;#039;&lt;br /&gt;
&lt;br /&gt;
    elseif str:find(&amp;#039;hsla?%([%d%s,.%%]+%)&amp;#039;) then&lt;br /&gt;
        tup, alp = utils.parseColorSpace(str, &amp;#039;hsl&amp;#039;, { 360, .01, .01 })&lt;br /&gt;
        typ = &amp;#039;hsl&amp;#039;&lt;br /&gt;
&lt;br /&gt;
    -- Named color parsing.&lt;br /&gt;
    elseif presets[str] then&lt;br /&gt;
        local p = presets[str]&lt;br /&gt;
        tup = { p[1], p[2], p[3] }&lt;br /&gt;
        typ = &amp;#039;rgb&amp;#039;&lt;br /&gt;
&lt;br /&gt;
    -- Transparent color parsing.&lt;br /&gt;
    elseif str == &amp;#039;transparent&amp;#039; then&lt;br /&gt;
        tup = {    0,    0,    0 }&lt;br /&gt;
        typ = &amp;#039;rgb&amp;#039;&lt;br /&gt;
        alp = 0&lt;br /&gt;
&lt;br /&gt;
    else error(i18n:msg(&amp;#039;unparse&amp;#039;, (str or &amp;#039;&amp;#039;))) end&lt;br /&gt;
&lt;br /&gt;
    return Color:new(tup, typ, alp)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Instance test function for colors.&lt;br /&gt;
--  @function           p.instance&lt;br /&gt;
--  @param              {Color|string} item Color item or string.&lt;br /&gt;
--  @return             {boolean} Whether the color item was instantiated.&lt;br /&gt;
--  @usage              colors.instance(&amp;#039;#ffffff&amp;#039;)&lt;br /&gt;
function p.instance(item)&lt;br /&gt;
    return tostring(item) == &amp;#039;Color&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color SASS parameter access utility for templating.&lt;br /&gt;
--  @function           p.wikia&lt;br /&gt;
--  @param              {table} frame Frame invocation object.&lt;br /&gt;
--  @error[778]         {string} &amp;#039;invalid SASS parameter name supplied&amp;#039;&lt;br /&gt;
--  @return             {string} Color string aligning with parameter.&lt;br /&gt;
--  @usage              {{colors|wikia|key}}&lt;br /&gt;
function p.wikia(frame)&lt;br /&gt;
    if not frame or not frame.args[1] then&lt;br /&gt;
        error(i18n:msg(&amp;#039;invalid-param&amp;#039;))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local key = mw.text.trim(frame.args[1])&lt;br /&gt;
    local val = p.params[key]&lt;br /&gt;
        and p.params[key]&lt;br /&gt;
        or  &amp;#039;&amp;lt;Dev:Colors: &amp;#039; .. i18n:msg(&amp;#039;invalid-param&amp;#039;) .. &amp;#039;&amp;gt;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
    return mw.text.trim(val)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color parameter parser for inline styling.&lt;br /&gt;
--  @function           p.css&lt;br /&gt;
--  @param              {table} frame Frame invocation object.&lt;br /&gt;
--  @param              {string} frame.args[1] Inline CSS stylesheet.&lt;br /&gt;
--  @error[799]         {string} &amp;#039;no styling supplied&amp;#039;&lt;br /&gt;
--  @return             {string} CSS styling with $parameters from&lt;br /&gt;
--                      @{colors.params}.&lt;br /&gt;
--  @usage              {{colors|css|styling}}&lt;br /&gt;
function p.css(frame)&lt;br /&gt;
    if not frame.args[1] then&lt;br /&gt;
        error(i18n:msg(&amp;#039;no-style&amp;#039;))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local styles = mw.text.trim(frame.args[1])&lt;br /&gt;
&lt;br /&gt;
    local o = styles:gsub(&amp;#039;%$([%w-]+)&amp;#039;, p.params)&lt;br /&gt;
&lt;br /&gt;
    return o&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Color generator for high-contrast text.&lt;br /&gt;
--  @function           p.text&lt;br /&gt;
--  @param              {table} frame Frame invocation object.&lt;br /&gt;
--  @param              {string} frame.args[1] Color to process.&lt;br /&gt;
--  @param[opt]         {string} frame.args[2] Dark color to return.&lt;br /&gt;
--  @param[opt]         {string} frame.args[3] Light color to return.&lt;br /&gt;
--  @param[opt]         {string} frame.args.lum Whether luminance is used.&lt;br /&gt;
--  @error[822]         {string} &amp;#039;no color supplied&amp;#039;&lt;br /&gt;
--  @return             {string} Color string `&amp;#039;#000000&amp;#039;`/$2 or&lt;br /&gt;
--                      `&amp;#039;#ffffff&amp;#039;`/$3.&lt;br /&gt;
--  @usage              {{colors|text|bg|dark color|light color}}&lt;br /&gt;
function p.text(frame)&lt;br /&gt;
    if not frame or not frame.args[1] then&lt;br /&gt;
        error(i18n:msg(&amp;#039;no-color&amp;#039;))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local str = mw.text.trim(frame.args[1])&lt;br /&gt;
    local clr = {&lt;br /&gt;
        (mw.text.trim(frame.args[2] or &amp;#039;#000000&amp;#039;)),&lt;br /&gt;
        (mw.text.trim(frame.args[3] or &amp;#039;#ffffff&amp;#039;)),&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    local b = yesno(frame.args.lum, false)&lt;br /&gt;
        and p.parse(str):luminant()&lt;br /&gt;
        or  p.parse(str):bright()&lt;br /&gt;
&lt;br /&gt;
    return b and clr[1] or clr[2]&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- SASS color parameter table for Lua modules.&lt;br /&gt;
--  These can be accessed elsewhere in the module:&lt;br /&gt;
--   * @{colors.wikia} acts as a template getter.&lt;br /&gt;
--   * @{colors.css}, @{colors.text} &amp;amp; @{colors.parse} accept&lt;br /&gt;
--  `$parameter` syntax.&lt;br /&gt;
--  @table              p.params&lt;br /&gt;
--  @field              {string} background-dynamic Whether the background is split. Default: `&amp;#039;false&amp;#039;`.&lt;br /&gt;
--  @field              {string} background-image Background image URL. Default: `&amp;#039;&amp;#039;`.&lt;br /&gt;
--  @field              {string} background-image-height Background image height. Default: `0`.&lt;br /&gt;
--  @field              {string} background-image-width Background image width. Default: `0`.&lt;br /&gt;
--  @field              {string} color-body Background color.&lt;br /&gt;
--  @field              {string} color-body-middle Background split color.&lt;br /&gt;
--  @field              {string} color-buttons Button color.&lt;br /&gt;
--  @field              {string} color-community-header Community header color.&lt;br /&gt;
--  @field              {string} color-header Legacy wiki header color.&lt;br /&gt;
--  @field              {string} color-links Wiki link color.&lt;br /&gt;
--  @field              {string} color-page Page color.&lt;br /&gt;
--  @field              {string} color-text Page text color.&lt;br /&gt;
--  @field              {string} color-contrast Page contrast color.&lt;br /&gt;
--  @field              {string} color-page-border In-page border color.&lt;br /&gt;
--  @field              {string} color-button-highlight Button highlight color.&lt;br /&gt;
--  @field              {string} color-button-text Button text color.&lt;br /&gt;
--  @field              {string} infobox-background Infobox background color.&lt;br /&gt;
--  @field              {string} infobox-section-header-background Infobox section header color.&lt;br /&gt;
--  @field              {string} color-community-header-text Infobox section header color.&lt;br /&gt;
--  @field              {string} dropdown-background-color Dropdown background color.&lt;br /&gt;
--  @field              {string} dropdown-menu-highlight Dropdown menu highlight color.&lt;br /&gt;
--  @field              {string} is-dark-wiki Whether the wiki has a dark theme (`&amp;#039;true&amp;#039;` or `&amp;#039;false&amp;#039;`).&lt;br /&gt;
--  @usage              colors.params[&amp;#039;key&amp;#039;]&lt;br /&gt;
p.params = {&lt;br /&gt;
    [&amp;#039;background-dynamic&amp;#039;] = sassParams[&amp;#039;background-dynamic&amp;#039;] or &amp;#039;false&amp;#039;,&lt;br /&gt;
    [&amp;#039;background-image&amp;#039;] = sassParams[&amp;#039;background-image&amp;#039;] or &amp;#039;&amp;#039;,&lt;br /&gt;
    [&amp;#039;background-image-height&amp;#039;] = sassParams[&amp;#039;background-image-height&amp;#039;] or &amp;#039;0&amp;#039;,&lt;br /&gt;
    [&amp;#039;background-image-width&amp;#039;] = sassParams[&amp;#039;background-image-width&amp;#039;] or &amp;#039;0&amp;#039;,&lt;br /&gt;
    [&amp;#039;color-body&amp;#039;] = sassParams[&amp;#039;color-body&amp;#039;] or &amp;#039;#f6f6f6&amp;#039;,&lt;br /&gt;
    [&amp;#039;color-body-middle&amp;#039;] = sassParams[&amp;#039;color-body-middle&amp;#039;] or &amp;#039;#f6f6f6&amp;#039;,&lt;br /&gt;
    [&amp;#039;color-buttons&amp;#039;] = sassParams[&amp;#039;color-buttons&amp;#039;] or &amp;#039;#a7d7f9&amp;#039;,&lt;br /&gt;
    [&amp;#039;color-community-header&amp;#039;] = sassParams[&amp;#039;color-community-header&amp;#039;] or &amp;#039;#f6f6f6&amp;#039;,&lt;br /&gt;
    [&amp;#039;color-header&amp;#039;] = sassParams[&amp;#039;color-header&amp;#039;] or &amp;#039;#f6f6f6&amp;#039;,&lt;br /&gt;
    [&amp;#039;color-links&amp;#039;] = sassParams[&amp;#039;color-links&amp;#039;] or &amp;#039;#0b0080&amp;#039;,&lt;br /&gt;
    [&amp;#039;color-page&amp;#039;] = sassParams[&amp;#039;color-page&amp;#039;] or &amp;#039;#ffffff&amp;#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Theme Designer color variables.&lt;br /&gt;
&lt;br /&gt;
-- Brightness conditionals (post-processing).&lt;br /&gt;
local page_bright = p.parse(&amp;#039;$color-page&amp;#039;):bright()&lt;br /&gt;
local page_bright_90 = p.parse(&amp;#039;$color-page&amp;#039;):bright(90)&lt;br /&gt;
local header_bright = p.parse(&amp;#039;$color-community-header&amp;#039;):bright()&lt;br /&gt;
local buttons_bright = p.parse(&amp;#039;$color-buttons&amp;#039;):bright()&lt;br /&gt;
&lt;br /&gt;
-- Derived opacity values.&lt;br /&gt;
local pi_bg_o = page_bright and 90 or 85&lt;br /&gt;
&lt;br /&gt;
-- Derived colors and variables.&lt;br /&gt;
&lt;br /&gt;
-- Main derived parameters.&lt;br /&gt;
p.params[&amp;#039;color-text&amp;#039;] = page_bright and &amp;#039;#3a3a3a&amp;#039; or &amp;#039;#d5d4d4&amp;#039;&lt;br /&gt;
p.params[&amp;#039;color-contrast&amp;#039;] = page_bright and &amp;#039;#000000&amp;#039; or &amp;#039;#ffffff&amp;#039;&lt;br /&gt;
p.params[&amp;#039;color-page-border&amp;#039;] = page_bright&lt;br /&gt;
    and p.parse(&amp;#039;$color-page&amp;#039;):mix(&amp;#039;#000&amp;#039;, 80):string()&lt;br /&gt;
    or  p.parse(&amp;#039;$color-page&amp;#039;):mix(&amp;#039;#fff&amp;#039;, 80):string()&lt;br /&gt;
p.params[&amp;#039;color-button-highlight&amp;#039;] = buttons_bright&lt;br /&gt;
    and p.parse(&amp;#039;$color-buttons&amp;#039;):mix(&amp;#039;#000&amp;#039;, 80):string()&lt;br /&gt;
    or  p.parse(&amp;#039;$color-buttons&amp;#039;):mix(&amp;#039;#fff&amp;#039;, 80):string()&lt;br /&gt;
p.params[&amp;#039;color-button-text&amp;#039;] = buttons_bright and &amp;#039;#000000&amp;#039; or &amp;#039;#ffffff&amp;#039;&lt;br /&gt;
&lt;br /&gt;
-- PortableInfobox color parameters.&lt;br /&gt;
local is_fandom = mw.site.server:match(&amp;#039;%.fandom%.com$&amp;#039;)&lt;br /&gt;
p.params[&amp;#039;infobox-background&amp;#039;] = is_fandom&lt;br /&gt;
    and p.parse(&amp;#039;$color-page&amp;#039;):mix(&amp;#039;$color-links&amp;#039;, pi_bg_o):string()&lt;br /&gt;
    or  &amp;#039;#f8f9fa&amp;#039;&lt;br /&gt;
p.params[&amp;#039;infobox-section-header-background&amp;#039;] = is_fandom&lt;br /&gt;
    and p.parse(&amp;#039;$color-page&amp;#039;):mix(&amp;#039;$color-links&amp;#039;, 75):string()&lt;br /&gt;
    or  &amp;#039;#eaecf0&amp;#039;&lt;br /&gt;
&lt;br /&gt;
-- CommunityHeader color parameters.&lt;br /&gt;
p.params[&amp;#039;color-community-header-text&amp;#039;] = header_bright&lt;br /&gt;
    and &amp;#039;#000000&amp;#039;&lt;br /&gt;
    or  &amp;#039;#ffffff&amp;#039;&lt;br /&gt;
p.params[&amp;#039;dropdown-background-color&amp;#039;] = (function(clr)&lt;br /&gt;
    if page_bright_90 then&lt;br /&gt;
        return &amp;#039;#ffffff&amp;#039;&lt;br /&gt;
    elseif page_bright then&lt;br /&gt;
        return clr:mix(&amp;#039;#fff&amp;#039;, 90):string()&lt;br /&gt;
    else&lt;br /&gt;
        return clr:mix(&amp;#039;#000&amp;#039;, 90):string()&lt;br /&gt;
    end&lt;br /&gt;
end)(p.parse(&amp;#039;$color-page&amp;#039;))&lt;br /&gt;
p.params[&amp;#039;dropdown-menu-highlight&amp;#039;] = p.parse(&amp;#039;$color-links&amp;#039;):alpha(10):rgb()&lt;br /&gt;
&lt;br /&gt;
-- Custom SASS parameters.&lt;br /&gt;
p.params[&amp;#039;is-dark-wiki&amp;#039;] = tostring(not page_bright)&lt;br /&gt;
&lt;br /&gt;
--- Template entrypoint for [[Template:Colors]] access.&lt;br /&gt;
--  @function           p.main&lt;br /&gt;
--  @param              {table} f Frame object in module (child) context.&lt;br /&gt;
--  @return             {string} Module output in template (parent) context.&lt;br /&gt;
--  @usage              {{#invoke:colors|main}}&lt;br /&gt;
p.main = entrypoint(p)&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Admin coral island</name></author>
	</entry>
</feed>