@OPEN-KAPPA/COLORS
    Preparing search index...

    TUTORIAL: Getting Started with @open-kappa/colors

    This comprehensive guide covers everything from basic color manipulation to advanced HDR tone mapping and accessibility analysis using @open-kappa/colors.

    • Node.js 18+ or Bun 1.3.5+
    • TypeScript 5.9.3+ (recommended for type safety)
    • Basic understanding of color theory concepts
    npm install @open-kappa/colors
    # or
    bun add @open-kappa/colors
    import {
    Harmony,
    Oklch,
    Rgb,
    Wcag
    } from "@open-kappa/colors"

    // 1. Create a color (Standard sRGB)
    const red = Rgb.fromComponents([255, 0, 0, 1])

    // 2. Convert to a perceptual space (Oklch)
    const oklch = red.to(Oklch)

    // 3. Generate a color harmony (Analogous palette)
    const palette = Harmony.analogous(red, 5)

    // 4. Check accessibility against transparent white
    const contrast = Wcag.contrast(
    red,
    Rgb.fromComponents([255, 255, 255, 0])
    )

    Before diving deeper, understanding these five fundamental principles is crucial:

    1. Immutability: All color objects are immutable. Calling a setter (e.g., setR()) returns a new instance; the original remains unchanged.
    2. The XYZ Hub: All color spaces implement conversion to/from CIE XYZ. Any conversion between two distinct spaces passes through XYZ as an intermediate step (e.g., Rgb -> Xyz -> Hsl).
    3. Geometric Conversions: Standard conversions (to()) are mathematical. They do not perform automatic gamut mapping or tone mapping unless explicitly requested via specific APIs.
    4. Metadata: All colors possess attached metadata (ColorMeta), enabling powerful manipulations even without knowing the specific color space type at compile time.
    5. HDR by Default: The library supports High Dynamic Range (HDR) values beyond the traditional 0-1 range. Values are generally not automatically clipped, except for Alpha (0-1) and degrees (0-360).

    You can create colors using type-safe static methods, component arrays, factories, or by parsing standard string formats.

    import {
    Hsl,
    Oklch,
    P3,
    Rgb
    } from "@open-kappa/colors"

    // RGB (0-255)
    const red = Rgb.fromComponents([255, 0, 0, 1])

    // HSL (H: 0-360, S: 0-100, L: 0-100)
    const blue = Hsl.fromComponents([240, 100, 50, 1])

    // OKLCH (L: 0-1, C: 0-0.4, H: 0-360)
    const perceptual = Oklch.fromComponents([0.6, 0.2, 180, 1])

    // Display P3 using a JSON object (explicit keys)
    const p3Color = P3.fromJSON({
    "alpha": 1, "b": 0, "g": 1, "r": 0
    })
    import {
    Css,
    Hex,
    Standards
    } from "@open-kappa/colors"

    // From Hex string
    const fromHex = Hex.fromRgbHexString("#ff0000")

    // From CSS functional notation
    const fromCss = Css.fromCssString("rgb(255 0 0 / 0.5)")

    // From Named Colors
    const fromName = Standards.fromName("cornflowerblue")

    Useful when the color space is determined at runtime.

    import {ColorFactory} from "@open-kappa/colors"

    const factoryColor = ColorFactory.fromColorSpace("lab", [50, -20, 20, 1])

    Convert easily between color spaces. The library handles the math via the XYZ hub.

    import {
    Base,
    Lab,
    Oklch,
    Rgb
    } from "@open-kappa/colors"

    const rgb = Rgb.fromComponents([255, 0, 0, 1])

    // 1. Standard Geometric Conversion
    const oklch = rgb.to(Oklch)
    const lab = rgb.to(Lab)

    console.log(oklch.components)
    // Output: ~[0.62, 0.25, 29.2, 1] (Lightness, Chroma, Hue, Alpha)

    // 2. Advanced Conversion (White Balance & Tone Mapping)
    // Use Base.convert for fine-grained control
    const sophisticated = Base.convert(rgb, Oklch, {
    "toneMapping": "agX",
    "whiteBalance": "cat02"
    })

    // 3. Range Checks
    const isSdr = rgb.isInSdr() // True
    const isHdr = rgb.isInHdr() // False
    const clipped = rgb.clipSdr() // Clamps values to valid range

    Traditional spaces like RGB or HSL are not perceptually uniform.

    • Problem: Darkening RGB often turns colors gray/muddy. Changing HSL Hue alters perceived lightness.
    • Solution: Use Oklch or Oklab for intuitive adjustments.
    import {
    Oklch,
    Rgb,
    Saturation
    } from "@open-kappa/colors"

    const rgb = Rgb.fromComponents([255, 0, 0, 1])

    // ❌ BAD (RGB): Linearly scaling RGB channels desaturates the color
    const muddyDark = rgb.setR(127).setG(0)
    .setB(0)

    // ✅ GOOD (Oklch): Adjusting Lightness preserves Chroma and Hue
    const color = rgb.to(Oklch)
    const niceDark = color.setL(0.5)

    // Adjust Chroma (Vibrancy)
    const vibrant = color.setC(0.3)
    const muted = Saturation.decrease(color, 0.5)

    // Shift Hue (Complementary palette example)
    const complementary = color.setH(color.h + 180)

    Linear interpolation in RGB creates "dead zones" (gray areas). Perceptual interpolation maintains vibrancy.

    import {
    Generator,
    Interpolation,
    Oklab,
    Oklch,
    Rgb
    } from "@open-kappa/colors"

    const start = Rgb.fromComponents([0, 0, 255, 1]) // Blue
    const end = Rgb.fromComponents([255, 255, 0, 1]) // Yellow

    // 1. Gradient Generation
    // Uses Oklab for a vibrant mix passing through neutral tones correctly
    const gradient = Generator.gradient(
    100,
    start.to(Oklab),
    end.to(Oklab),
    Interpolation.linear
    )

    // 2. Direct Interpolation
    const midPoint = Interpolation.bezier(
    start.to(Oklab),
    end.to(Oklab),
    0.5
    )

    // 3. Data Visualization Scales
    // Generate distinct colors for charts using Golden Ratio
    const chartColors = Generator.distinct(10, {
    "chroma": 0.14,
    "useGoldenRatio": true
    })

    High Dynamic Range (HDR) colors often exceed the visible range of standard monitors. Tone mapping compresses this range smoothly (cinematographic approach) rather than clipping it harshly.

    import {
    LinearRgb,
    Oklch,
    Rec2020,
    ToneMapper
    } from "@open-kappa/colors"

    // An HDR color (e.g., sun reflection, 10x brighter than white)
    const sun = Rec2020.fromComponents([10, 10, 8, 1])

    // ❌ Naive Clipping: Destroys details in bright areas
    const sdrBad = sun.clipSdr()

    // ✅ Reinhard: Compresses light softly (General purpose)
    const sdrReinhard = ToneMapper.reinhard(sun.to(Oklch))

    // ✅ ACES Filmic: Standard cinematic look (Narkowicz curve)
    const sdrFilmic = ToneMapper.acesRgb(sun.to(LinearRgb))

    // ✅ AgX: Next-gen photorealistic tone mapping (prevents hue skews)
    const sdrAgx = ToneMapper.agX(sun.to(LinearRgb), 1.0, "punchy")

    Ensure your UI meets accessibility standards and simulates how users with color vision deficiencies see your content.

    import {
    ColorDifference,
    Cvd,
    Lab,
    LinearRgb,
    Rgb,
    Wcag
    } from "@open-kappa/colors"

    const text = Rgb.fromComponents([0, 0, 0, 1]).toXyz()
    const bg = Rgb.fromComponents([255, 255, 255, 1]).toXyz()

    // 1. Contrast Ratio & WCAG Compliance
    const ratio = Wcag.contrast(bg, text) // 21:1
    const meetsAA = Wcag.isReadable(ratio, {"level": "AA", "size": "normal"})
    const meetsAAA = Wcag.isReadable(ratio, {"level": "AAA"})

    // 2. Advanced Distance (DeltaE 2000)
    // Measures perceived difference between colors
    const deltaE = ColorDifference.deltaE2000(text.to(Lab), bg.to(Lab))

    // 3. Color Vision Deficiency (Color Blindness) Simulation
    const source = Rgb.fromComponents([255, 0, 0, 1]).to(LinearRgb)

    // Simulate Protanopia (Red-blind)
    const simulated = Cvd.simulate(source, "protanopia")

    // Attempt to correct colors for Deuteranopia (Green-blind)
    const corrected = Cvd.correct(source, "deuteranopia")

    Extract palettes from raw image data using K-Means clustering.

    import {
    Extraction,
    Hsl,
    Palette,
    Rgb
    } from "@open-kappa/colors"

    // Assume imageData is a Uint8ClampedArray from a Canvas or Image Buffer
    const imageData: Uint8ClampedArray = new Uint8ClampedArray([/* ... */])

    // Extract 5 dominant colors
    const clusters = Extraction.kMeansClustering(
    imageData,
    {"count": 5}
    )

    // Generate a dynamic palette from the primary dominant color
    const primaryDom = clusters[0]
    const uiPalette = Palette.dynamic(primaryDom.to(Hsl))

    If you need to work with colors generically (e.g., a UI component handling any color space), you can use the Metadata API.

    import {
    type Color,
    Rgb
    } from "@open-kappa/colors"

    function adjustLightnessGeneric(color: Color, amount: number): Color
    {
    // Check if the color space supports Lightness
    if (color.lightnessIndex !== null)
    {
    // TrySetLightness returns a new instance of the same type
    return color.trySetLightness(amount)
    }

    // Fallback: Convert to a space that definitely has lightness
    // (Note: This changes the type of the color)
    const rgb = color.to(Rgb)
    // Rgb doesn't have direct lightness, so we might convert
    // to HSL or Oklch here...
    return rgb
    }

    // Inspect component names
    const myColor = Rgb.fromComponents([0, 0, 0, 1])
    console.log(myColor.meta.componentNames()) // ["r", "g", "b", "alpha"]