bagistoplus/couleur
Couleur is a lightweight color utility for Laravel and PHP, offering helpers to define, convert, and format colors for use in views, CSS, and dynamic theming. A small, dependency-free addition for projects that need consistent color handling.
Where color logic runs: server or browser. CSS handles the in-browser happy path, but a meaningful share of product surfaces never touch a stylesheet — transactional email, PDF invoices, OG/social images, Slack and webhook card payloads, server-rendered theme variables, chart images. Each of those needs a backend color engine. This package reframes "we'll hand-roll hex helpers eventually" as a small, reversible infrastructure decision.
White-label theming as a self-serve onboarding step. Once a customer supplies a brand hex, "use it as-is" is no longer acceptable — you need derived hover, active, muted, on-brand, focus-ring, and disabled tokens that stay legible. A server-side color library turns tenant theming from a design-services engagement into a form field, which is a packaging, pricing-tier, and expansion-revenue decision as much as an engineering one.
Accessibility as a save-time gate rather than a review cycle. If the backend can compute contrast ratios, we can reject a brand color the instant it is entered ("fails WCAG AA against white text") instead of discovering it in design QA or a customer complaint. Where the constraint lives — form validation, review checklist, or nowhere — is a PM call; this package is what makes the form-validation option cheap enough to be the default.
Build vs. buy vs. keep accumulating helpers. The true comparison is not "this package or nothing." It is "this package or the 150–400 lines of hex parsing and naive lighten/darken math already scattered across the codebase, each with different rounding and no shared tests." Consolidation is a maintainability bet, and it only pays off if it replaces real code rather than adding a fourth dialect of color handling.
Roadmap sequencing for theming and design-system work. Because the scope is narrow (create, convert, manipulate, check contrast) and installation is a single composer require with no service provider, facade, config, or migrations, this can be trialed inside a single sprint on a non-critical surface — an admin color input or a branded email layout — without a platform commitment or a migration plan.
Reversibility as a budgeting input. Wrapped behind a thin application-owned adapter, the exit cost is one composer require and roughly 200 lines of reimplementation. That changes the risk conversation: we are not betting the design system on an unproven dependency, we are renting a small utility with a known, capped swap cost.
Consider it when:
color-mix() is unavailable.Look elsewhere or wait when:
none channels, percentage alpha, and deg/rad/turn hues. These cannot be answered from the README; read the source before committing.For executives — one paragraph. We have a small, low-cost opportunity to make customer-supplied brand colors a self-serve feature instead of a services engagement, and to enforce accessibility at the moment a color is entered instead of months later in QA. The candidate is a narrowly scoped PHP library that converts between color formats, derives tints, shades, and palettes, and computes contrast ratios. It installs with one command, has no configuration or migration footprint, and is cheap to remove. The honest framing is that this is an unproven single-maintainer package: we are not adopting a platform, we are renting a utility behind a wrapper we own. The recommendation is a one-surface pilot — validation on an admin color field, or a branded email layout — with a go/no-go before any broader rollout.
For engineering. The scope is deliberately bounded: create, convert, manipulate, check contrast. No service provider, no facade, no config to publish, no migrations — if composer require succeeds, it is installed. Three conditions make this safe: (1) a thin application-owned adapter from the first commit, so vendor value objects never appear in domain models, API resources, event payloads, or Blade templates; (2) color math happens at write time in a theme compiler and is persisted as tokens or a CSS artifact, never recomputed per request or per render; (3) an exact pinned version plus golden-file tests covering ~20 real brand colors — achromatic gray, near-gamut-edge saturated, translucent, malformed, 3-digit and 8-digit hex — asserting lossless parse/serialize round-trips, browser-matched serialized output, and independently computed contrast ratios.
For design and accessibility. Two things to flag up front. First, derived shades will not match our existing lighten()/darken() helpers pixel for pixel — that is expected, because those helpers produced uneven perceptual ramps; screenshot-diff generated themes per tenant behind a flag before cutover and plan for sign-off rather than a silent refactor. Second, contrast checks here are WCAG 2.x ratios unless proven otherwise, and translucent colors must be composited against a known background before the ratio is meaningful. If our published accessibility commitment moves to APCA, that is a re-evaluation trigger, not an assumption.
The risk, stated plainly. Zero stars, zero dependents, one maintainer, no stack-overflow corpus, no issue history, and no documented semver policy. Two unknowns are genuine go/no-go questions that only reading the source can answer: whether out-of-gamut values are mapped with proper chroma reduction or naively clipped, and whether Lab/LCH conversions assume the white point our design tooling assumes. Everything in the plan — the adapter, the compiler, the validation rule, the golden files — exists so that if this package is abandoned, forked, or turns out to be subtly wrong, we delete one line from composer.json and reimplement behind an interface that never moved. Given the size of the bet, that isolation is the price of admission, not over-engineering.
How can I help you explore Laravel packages today?