Skip to content

fix(color): round channel bytes in default color hex serialization - #9185

Open
Pcmhacker-piro wants to merge 1 commit into
processing:mainfrom
Pcmhacker-piro:fix/color-hex-rounding-serialization
Open

Pcmhacker-piro wants to merge 1 commit into
processing:mainfrom
Pcmhacker-piro:fix/color-hex-rounding-serialization

Conversation

@Pcmhacker-piro

@Pcmhacker-piro Pcmhacker-piro commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Resolves #9124

Changes:

In p5.js 2.x, toHexComponent in src/color/p5.Color.js used bitwise NOT truncation (const vInt = ~~(v * 255);) to convert normalized channel values to hex bytes.

Because truncation drops the fractional part toward zero:

  • Any color channel producing a fractional byte (such as colorMode(RGB, 100); color(50, 0, 0), where 0.5 * 255 = 127.5) was truncated to 127 (#7f0000) instead of 128 (#800000).
  • The cached default string returned by c.toString() (which p5.Renderer2D feeds into canvas ctx.fillStyle and ctx.strokeStyle) disagreed with c.toString('#rrggbb') on the exact same color object, because the #rrggbb formatting path goes through colorjs.io serialization and rounds to the nearest integer.
  • Canvas rendering for colors with fractional channel bytes rendered one code point darker than expected.

This PR:

  • Updates toHexComponent in src/color/p5.Color.js to use Math.round(v * 255).
  • Adds unit tests in test/unit/color/p5.Color.js verifying that default c.toString() rounds fractional channel values correctly across custom color mode ranges (RGB, 100), standard 255 range (127.5), and alpha channels (127.5), ensuring strict consistency with c.toString('#rrggbb').

Verification:

1. Animated Demo Video (Terminal & Test Run)

Terminal Verification Demo

2. Terminal Output & Verification

Terminal Output


PR Checklist

@Pcmhacker-piro

Copy link
Copy Markdown
Contributor Author

Hi @limzykenneth (Color area steward) and @ksen0! 👋

Could you please take a look at this PR when you get a chance?

It addresses issue #9124 by updating toHexComponent from bitwise NOT truncation (~~) to standard rounding (Math.round), ensuring c.toString() strictly matches c.toString('#rrggbb') for fractional channel values.

  • All 100 color unit tests are passing (including 3 new tests added for fractional RGB and alpha byte rounding).
  • npm run lint exits clean with 0 errors.
  • Terminal proof screenshot and animated workflow demonstration are included in the description.

Thank you so much!

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.

[p5.js 2.0+ Bug Report]: default color serialization truncates channel bytes, disagreeing with #rrggbb on the same color

2 participants