Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
name: Bug report
about: Something is producing incorrect or unexpected output
labels: bug
---

## Description

<!-- What went wrong? -->

## Steps to reproduce

```go
// Minimal code sample that demonstrates the problem
```

## Expected output

<!-- What did you expect? -->

## Actual output

<!-- What did you get instead? -->

## Environment

- Go version:
- golor version / commit:
- OS:
19 changes: 19 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: Feature request
about: Propose a new function, package, or behavior
labels: enhancement
---

## What problem does this solve?

<!-- Describe the use case. What are you trying to do that golor currently can't? -->

## Proposed API

```go
// Sketch of what the function signature or usage would look like
```

## Alternatives considered

<!-- Any workarounds you've tried, or other approaches that could solve it -->
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Changelog

All notable changes to this project will be documented here.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

---

## [Unreleased]

### Added
- Core `Color` type with `RGB`, `RGBf`, and `Hex` constructors
- `convert` package: HSL, HSV, L\*a\*b\*, and LCH color space conversions
- `adjust` package: lighten, darken, saturate, desaturate, hue shift, warm, cool, tint, shade, value
- `blend` package: mix, multiply, screen, overlay, hard light, soft light, difference, luminosity
- `contrast` package: WCAG 2.1 luminance, contrast ratio, and enforcement via binary bisection
- `deltae` package: ΔE76 and CIEDE2000 color difference, EnsureDistinct palette utility
- `colorblind` package: deficiency simulation (deuteranopia, protanopia, tritanopia) and AccessiblePalette
- `harmony` package: complementary, triadic, analogous, tetradic, split-complementary, and lightness-expand generators
- `gradient` package: interpolation in RGB, HSL, L\*a\*b\*, LCH, and multi-stop variants
- `transform` package: fluent `Chain` builder for composing transformations
- CI pipeline with `golangci-lint`, `gofumpt`, `go vet`, and race-enabled tests

[Unreleased]: https://github.com/0mega24/golor/compare/main...HEAD
66 changes: 66 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Contributing to golor

Thanks for your interest in contributing. This document covers how to get set up, the conventions we follow, and how to get a change merged.

## Getting started

```sh
git clone https://github.com/0mega24/golor
cd golor
go mod download
```

### Prerequisites

| Tool | Purpose |
|---|---|
| Go 1.26+ | Build and test |
| [golangci-lint](https://golangci-lint.run/welcome/install/) | Linting |
| [gofumpt](https://github.com/mvdan/gofumpt) | Formatting |

## Development workflow

```sh
make test # go test -race -count=1 ./...
make vet # go vet ./...
make lint # golangci-lint run
make fmt # gofumpt -extra -l -w .
make fix # golangci-lint run --fix
```

All of these must pass before opening a PR. CI runs `vet`, `fmt`, and `lint` in the lint job and `test` in the test job.

## Making changes

1. Fork the repo and create a branch from `main`.
2. Branch names should follow the prefix convention: `feat/`, `fix/`, `chore/`, `docs/`.
3. Keep changes focused — one logical change per PR.
4. Add or update tests for any behavior change.
5. Ensure every new exported symbol has a doc comment and that any new package has a package-level doc comment (required by the `staticcheck` ST1000 rule).

## Commit messages

We follow the conventional commits style:

```
<type>: <short description>

<optional body>
```

Types: `feat`, `fix`, `chore`, `ci`, `docs`, `test`, `refactor`

- Use the imperative mood in the subject line ("add", not "adds" or "added")
- Keep the subject line under 72 characters
- Reference issues in the body where relevant

## Submitting a pull request

- Open a PR against `main`
- Fill in the PR template
- A PR should pass all CI checks before review
- We use **Rebase and merge** — individual commits land on `main` as-is, so keep your history clean

## Reporting issues

Please open a GitHub issue with enough detail to reproduce the problem: Go version, OS, a minimal code sample, and the actual vs expected output.
182 changes: 182 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# golor

A Go library for color manipulation, conversion, and accessibility.

```
go get github.com/0mega24/golor
```

---

## Overview

golor provides a single `Color` type (normalized sRGB) and a set of focused sub-packages for everything you might need to do with colors in Go.

| Package | What it does |
|---|---|
| `golor` | Core type, constructors, hex parsing |
| `convert` | HSL, HSV, L\*a\*b\*, LCH conversions |
| `adjust` | Lighten, darken, saturate, hue shift, warm/cool, tint, shade |
| `blend` | Blend modes: multiply, screen, overlay, soft light, and more |
| `contrast` | WCAG 2.1 contrast ratio and enforcement |
| `deltae` | Perceptual color difference (ΔE76 and CIEDE2000) |
| `colorblind` | Deficiency simulation and accessible palette generation |
| `harmony` | Complementary, triadic, analogous, tetradic, split schemes |
| `gradient` | Interpolation in RGB, HSL, L\*a\*b\*, and LCH |
| `transform` | Fluent chained transformations |

---

## Usage

### Creating colors

```go
import "github.com/0mega24/golor"

c := golor.RGB(255, 107, 53) // from 8-bit channels
c := golor.RGBf(1.0, 0.42, 0.21) // from normalized floats
c, err := golor.Hex("#ff6b35") // from hex string

fmt.Println(c) // #ff6b35
```

### Adjusting colors

```go
import "github.com/0mega24/golor/adjust"

lighter := adjust.Lighten(c, 0.1)
darker := adjust.Darken(c, 0.1)
vibrant := adjust.Saturate(c, 0.2)
muted := adjust.Desaturate(c, 0.2)
shifted := adjust.ShiftHue(c, 30)
warmer := adjust.Warm(c, 0.3)
cooler := adjust.Cool(c, 0.3)
tinted := adjust.Tint(c, 0.2) // toward white
shaded := adjust.Shade(c, 0.2) // toward black
```

### Fluent chaining

```go
import "github.com/0mega24/golor/transform"

result := transform.From(c).
Lighten(0.1).
Saturate(0.2).
Warm(0.15).
Color()
```

### Color space conversions

```go
import "github.com/0mega24/golor/convert"

hsl := convert.ToHSL(c) // HSL{H:16, S:1.0, L:0.6}
hsv := convert.ToHSV(c)
lab := convert.ToLAB(c)
lch := convert.ToLCH(c)

back := convert.FromLCH(lch) // round-trips cleanly
```

### Blend modes

```go
import "github.com/0mega24/golor/blend"

out := blend.Multiply(base, layer)
out = blend.Screen(base, layer)
out = blend.Overlay(base, layer)
out = blend.SoftLight(base, layer)
out = blend.Mix(base, layer, 0.5) // linear interpolation
```

### Contrast and accessibility

```go
import "github.com/0mega24/golor/contrast"

r := contrast.Ratio(fg, bg) // e.g. 4.87
ok := contrast.Meets(fg, bg, 4.5) // WCAG AA

// Adjust fg until it meets the threshold against bg
fg = contrast.EnforceContrast(fg, bg, 4.5)
```

### Perceptual color difference

```go
import "github.com/0mega24/golor/deltae"

d76 := deltae.DeltaE76(c1, c2) // fast, CIE 1976
d2000 := deltae.DeltaE2000(c1, c2) // accurate, CIEDE2000

// Nudge palette entries apart until each pair differs by at least minDeltaE
palette = deltae.EnsureDistinct(palette, 10.0)
```

### Colorblind simulation

```go
import "github.com/0mega24/golor/colorblind"

sim := colorblind.Simulate(c, colorblind.Deuteranopia)
sim = colorblind.Simulate(c, colorblind.Protanopia)
sim = colorblind.Simulate(c, colorblind.Tritanopia)

// Shift palette hues until distinguishable under the given deficiency
safe := colorblind.AccessiblePalette(palette, colorblind.Deuteranopia)
```

### Color harmonies

```go
import "github.com/0mega24/golor/harmony"

pair := harmony.Complementary(c) // [2]Color
triad := harmony.Triadic(c) // [3]Color
quad := harmony.Tetradic(c) // [4]Color
analog := harmony.Analogous(c) // [3]Color
split := harmony.SplitComplementary(c) // [3]Color
shades := harmony.Expand(c, 5) // []Color, lightness spread
```

### Gradients

```go
import "github.com/0mega24/golor/gradient"

steps := gradient.RGB(black, white, 10) // []Color, RGB interpolation
steps = gradient.HSL(red, blue, 10) // hue takes shortest path
steps = gradient.LCH(red, blue, 10) // perceptually uniform
steps = gradient.LAB(red, blue, 10)

// Multi-stop
stops := []golor.Color{black, red, yellow, white}
ramp := gradient.MultiStopLCH(stops, 64)
```

---

## Development

```sh
make test # run tests with race detector
make lint # run golangci-lint
make fmt # format with gofumpt
make fix # auto-fix lint issues where possible
make vet # run go vet
```

Requires [golangci-lint](https://golangci-lint.run) and [gofumpt](https://github.com/mvdan/gofumpt) to be installed for `lint` and `fmt`.

See [CONTRIBUTING.md](CONTRIBUTING.md) for full contribution guidelines.

---

## License

MIT — see [LICENSE](LICENSE).
17 changes: 17 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Security Policy

## Reporting a Vulnerability

Please **do not** open a public GitHub issue for security vulnerabilities.

Instead, email **sean@lidy.me** with:

- A description of the vulnerability and its potential impact
- Steps to reproduce or a minimal proof-of-concept
- Any suggested mitigations if you have them

You can expect an acknowledgement within 48 hours and a resolution timeline within 7 days depending on severity.

## Scope

golor is a pure computation library with no network access, file I/O, or external service calls. Security issues are most likely to involve incorrect output that could silently mislead accessibility checks (e.g. a contrast ratio reported as passing when it does not). These are treated as bugs with high priority.