Skip to content

fix: round Hex4/Hex8 alpha with ALPHA_PRECISION, not a hardcoded 2 - #159

Closed
afonsojanu wants to merge 1 commit into
omgovich:masterfrom
afonsojanu:fix/hex-alpha-precision
Closed

afonsojanu wants to merge 1 commit into
omgovich:masterfrom
afonsojanu:fix/hex-alpha-precision

Conversation

@afonsojanu

Copy link
Copy Markdown

What

parseHex rounded the alpha channel of Hex4/Hex8 colors to 2 decimal places, while every other color model in the library (rgb, hsl, hsv, hwb, lab, lch, cmyk, xyz) rounds alpha to ALPHA_PRECISION (3). That constant was bumped from 2 to 3 a while back specifically because 2 digits weren't accurate enough (see the comment on it in constants.ts), but hex.ts still had the old value hardcoded in two places.

Since an alpha byte only has 256 possible values, I checked how many of them survive a round trip through a decimal string at each precision:

  • precision 2: 155 out of 256 bytes don't round-trip
  • precision 3 (ALPHA_PRECISION): 0 out of 256 fail

Concretely, this is issue #97:

colord("#cc88").toRgbString();
// "rgba(204, 204, 136, 0.53)"   <- alpha rounded to 2 digits

colord("rgba(204, 204, 136, 0.53)").toHex();
// "#cccc8887", not "#cccc8888"  <- 0x88 became 0x87

Fix

Both places in parseHex (Hex4 and Hex8) now round with ALPHA_PRECISION instead of a hardcoded 2, matching every other color model.

colord("#cc88").toRgbString();
// "rgba(204, 204, 136, 0.533)"

colord("rgba(204, 204, 136, 0.533)").toHex();
// "#cccc8888"  <- round-trips exactly now

Behavior change (called out per AGENTS.md)

This is a deliberate behavior change: parsing a Hex4/Hex8 string now resolves alpha to 3 decimal digits instead of 2 (e.g. #80 -> 0.502 instead of 0.5). toHex() output and the rounded RGB byte values are unchanged; only the decimal alpha exposed by toRgb()/toRgbString() and anything derived from it (lab/lch/cmyk/hwb conversions) gains a digit for alpha bytes that weren't exactly representable at 2 digits. I updated the existing test expectations affected by this (a handful of #...80/#...ed-style fixtures in tests/colord.test.ts and tests/plugins.test.ts) and added a dedicated round-trip regression test covering all 256 alpha bytes for both Hex4 and Hex8.

Testing

  • npm run lint, npm run check-types, npm run test (103/103 passing, 100% line coverage), npm run size all pass locally.
  • Added tests/colord.test.ts: "Round-trips every Hex4/Hex8 alpha byte through RGB without drift".

Closes #97.

parseHex rounded the alpha channel of Hex4/Hex8 colors to 2 decimal
places while every other color model (rgb, hsl, hsv, hwb, lab, lch,
cmyk, xyz) rounds alpha to ALPHA_PRECISION (3), a constant that was
raised from 2 to 3 specifically because 2 digits weren't accurate
enough. hex.ts kept the old hardcoded value.

Since a channel only has 256 possible values, this makes 155 of the
256 possible alpha bytes fail to round-trip through a string format:

  colord("#cc88").toRgbString()        // "rgba(204, 204, 136, 0.53)"
  colord("rgba(204, 204, 136, 0.53)").toHex()  // "#cccc8887", not ...88

Rounding to 3 digits instead makes every one of the 256 alpha bytes
round-trip exactly (verified by brute force), matching the precision
used by every other color model in the library.

This is an intentional behavior change: parsing "#xxxxxxYY" now
resolves alpha to 3 decimal digits instead of 2 (e.g. 0x80 -> 0.502
instead of 0.5). Hex output (toHex()) and RGB byte values are
unaffected; only the decimal alpha exposed by toRgb()/toRgbString()
and downstream conversions (lab, lch, cmyk, hwb) gains a digit for
alpha bytes that weren't exactly representable at 2 digits.

Fixes #97.
Copilot AI balanced review requested due to automatic review settings September 29, 2026 22:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@afonsojanu afonsojanu closed this Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrectly parse hexa to rgba to hexa

2 participants