Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor color and add support for oklch #24

Closed
quinton-ashley opened this issue Jan 22, 2024 · 1 comment
Closed

Refactor color and add support for oklch #24

quinton-ashley opened this issue Jan 22, 2024 · 1 comment
Assignees
Labels
enhancement New feature or request

Comments

@quinton-ashley
Copy link
Collaborator

quinton-ashley commented Jan 22, 2024

I want to refactor Q5.Color and the color function to add support for HDR colors, make oklch a new color mode, and remove HSB/HSV support.

p5 devs are planning to improve how color is handled in p5.js v2. I'd like them to take a look at my goals for the color improvements I will make in q5 v1.9.3. Hopefully some of these changes can be made in p5 as well!
processing/p5.js#6680

@limzykenneth @lindapaiste @Vishal2002 @JustZambetti @davepagurek @hellonearthis @meodai

Maintain good performance

q5 is 11x faster than p5 at creating 10,000 random colors: 3ms vs 33ms.

function randomColors() {
    for (let i = 0; i < 100000; i++) {
        let c = color(random(255), random(255), random(255));
    }
}

const start = performance.now();

randomColors();

const end = performance.now();
console.log(`Execution time: ${end - start} ms`);

What kind of magic is q5 using to achieve such results? q5 simply doesn't do any unnecessary color format conversions. Since the default color mode is RGB, q5 simply stores the user's rgb values as properties in a object.

But in p5, the user's legacy rgb 0-255 range input is converted to modern 0-1 range rgba values, both of which are stored in arrays. maxes arrays for each color format are also copied into every color object, which seems unnecessary. hsba and hsla are both defined on the object as null, even if the user doesn't intended to convert the color.

Make color components easier to view and edit

If you view a p5.Color in the console, you'll probably be confused by the output! Especially if you're a beginner programmer.

{
	hsba: null,
	hsla: null,
	levels: [255, 10, 82, 255],
	maxes: {
	  hsb:  [360, 100, 100, 1],
	  hsl: [360, 100, 100, 1],
	  rgb: [255, 255, 255, 255]
	},
	mode: 'rgb',
	_array: [1, 0.0392156862745098, 0.3215686274509804, 1]
}

To try to understand why p5.Color was implemented this way, we have to study its grandaddy: Processing.

In Java Processing, the color method generated a primitive int, not an Object, and in Java ints can't have properties or methods. That's why the red, green, blue, alpha functions were necessary. Those individual color components could only be retrieved from a color int through bitwise operations, not via properties.
https://forum.processing.org/two/discussion/15923/how-to-change-alpha-without-changing-the-whole-color.html

But in p5 these functions should've only been implemented for backwards compatibility. Thankfully color.setRed() and similar functions were introduced, but why not a color.getRed() or better yet expose the color components as public properties?

To improve q5 I'm taking inspiration from the popular JS color library culori represents colors as objects with letter properties, using a single color mode per object, making them easy to view and edit.

// culori.js rgba color data representation
{
  r: 255,
  g: 10,
  b: 82,
  a: 1,
  mode: 'rgba'
}

oklch support

But just making red, green, and blue components easier to edit doesn't fix the more fundamental problems with the RGB format. As noted in the article "OKLCH in CSS: why we moved from RGB and HSL":

"RGB, hex and color(display-p3) aren’t convenient for color modifications because, for the vast majority of humans, it’s difficult to intuitively set colors by changing the amount of red, blue and green. Further, RGB and hex also can’t encode P3 colors."

I recommend reading the full article, it's great! I'm going to make separate classes for rgb and oklch that extend Q5.Color, so that instanceof p5.Color checks can still work.

Currently Q5.Color instances internally output color to ctx.fillStyle or ctx.strokeStyle via their toString method. For Q5.ColorRGBA and Q5.ColorOKLCH their toString() functions won't require any calculations.

Auto-upgrade RGB to HDR

While I do think oklch is the future, I don't really expect any Intro to Web Design class/section to teach oklch anytime soon. But I want to get people using HDR colors today!

I think the best way to do this is to create a backwards compatibility class, Q5.ColorRGBA_P3. Users can still edit colors using the default RGB colorMode but the resulting colors will be internally mapped directly to the HDR "display-p3" color space in toString using this format: color(display-p3 r g b / a).
https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color

To prevent toString from needing to do the format conversion from the legacy 0-255 range to the modern 0-1 range whenever toString is used, I'll create getter/setter properties for the purpose of watching for changes. Only when the color is changed will toString do new calculations.

Let users make colors using new Color()

p5.Color is not a class that belongs to a p5 instance but rather p5 itself. q5 mimics this implementation.

Yet,_colorMode is an instance variable, so it can't be accessed directly by the p5.Color constructor. p5 gets around it by passing p5 instances to the p5.Color constructor. Additionally, in q5 I'll need to access the canvas to get the canvas' color space. In q5, all of the color parsing code is done in the q5 instance level color function. I will maintain this structure.

Depending on the instance's current color mode and canvas color space, the q5 instance variable $.Color will be set to Q5.ColorRGBA, Q5.ColorRGBA_P3, or Q5.ColorOKLCH. These constructors will have no parsing overhead.

Remove HSB/HSV support

Support for the HSV color format will be removed in q5 v1.9.3 because it was rarely used, the amount of code required to convert between RGB and HSV was quite large, and color experts considered HSV to be flawed and outdated way back in 1997!

https://en.wikipedia.org/wiki/HSL_and_HSV#Disadvantages

@quinton-ashley quinton-ashley added the enhancement New feature or request label Jan 22, 2024
@quinton-ashley quinton-ashley self-assigned this Jan 22, 2024
@quinton-ashley quinton-ashley changed the title reimagingedcolor Upgrade color Jan 22, 2024
@quinton-ashley quinton-ashley changed the title Upgrade color Upgrade color with support for oklch Jan 22, 2024
@quinton-ashley quinton-ashley changed the title Upgrade color with support for oklch Refactor color and add support for oklch Jan 22, 2024
@quinton-ashley
Copy link
Collaborator Author

Check out my implementation of these ideas in v1.9.3!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant