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

Add a function for interpolating between multiple colors #6959

Open
1 of 17 tasks
RandomGamingDev opened this issue Apr 11, 2024 · 9 comments · May be fixed by #6960
Open
1 of 17 tasks

Add a function for interpolating between multiple colors #6959

RandomGamingDev opened this issue Apr 11, 2024 · 9 comments · May be fixed by #6960

Comments

@RandomGamingDev
Copy link
Contributor

Increasing access

While interpolating between 2 colors is easy with the lerpColor() function, interpolating between multiple can be annoying, and very difficult for beginners, especially for how commonly used and popular this feature is.

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • Build process
  • Unit testing
  • Internationalization
  • Friendly errors
  • Other (specify if possible)

Feature request details

Create a function that accepts a list of colors and a value to interpolate between all of them.

@RandomGamingDev RandomGamingDev linked a pull request Apr 11, 2024 that will close this issue
3 tasks
@davepagurek
Copy link
Contributor

Sorry for the delay on this! I'm going to tag the color stewards, what are your thoughts? @paulaxisabel, @SoundaryaKoutharapu, @mrbrack, @TJ723, @Zarkv, @SkylerW99, @ramya202000, @hannahvy, @robin-haxx, @hiddenenigma

Also @limzykenneth, since you've been looking into color module things

@limzykenneth
Copy link
Member

I'm thinking it may be more useful to have a gradient implementation that gives extra flexibility for the placement of intermediate colors. With lerp, it is not really defined how lerping with multiple colors should work so I wouldn't necessarily try to invite something here. I had a look at Unity and it also only does the straightforward two colors lerp only, would be great to see how other tools/libraries handle this if they do it at all.

@davepagurek
Copy link
Contributor

One piece of inspiration: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createLinearGradient

They don't have an API for getting a specific color along the gradient, so this API is for something somewhat different, but they have one for specifying color stops at different locations.

@RandomGamingDev
Copy link
Contributor Author

I'm thinking it may be more useful to have a gradient implementation that gives extra flexibility for the placement of intermediate colors

If the user's already specifying specific positions for each of the colors then using an if ... else ... chain would be more than easily enough for their task. The main issue that paletteLerp's trying to solve is when people want them equally spaced out without having to type out a bunch of extra code just to achieve the same result, especially if they don't have much coding experience and want a solution that works with a list of any size. I think that, while less flexible, paletteLerp still provides significant advantages and the users that require a more flexible solution already have that easily taken care of as well, with even beginners able to do it.

@davepagurek
Copy link
Contributor

I think stops are at least worth considering for the future. At least personally, probably half of the gradients I've done with more than two colors have had non-evenly-spaced stops in order to get the visual effect I'm looking for, and it's probably a concept familiar to people who start in digital design software and then get into coding via p5.

If the colors aren't evenly spaced out, e.g. white at 0, red at 5%, green at 25%, blue at 100%, doing a lookup could look something like this:

let c
if (mix < 0.5) {
  c = lerpColor(white, red, map(mix, 0, 0.05, 0, 1, true))
} else if (mix < 0.25) {
  c = lerpColor(red, green, map(mix, 0.05, 0.25, 0, 1, true))
} else {
  c = lerpColor(green, blue, map(mix, 0.25, 1, 0, 1, true))
}

I could see how having to jump from just lerpPalette([white, red, green, blue], mix) to the above would be a big jump for some, where people might request the ability to specify color stops. I think it's not a bad idea to think ahead about whether or not there could be an easy way in the future to extend it to that so that we aren't locking ourselves in.

One way could be to have overloads like:

lerpPalette(palette: p5.Color[], mix: number)
lerpPalette(palette: p5.Color[], stops: number[], mix: number)

...and default to an even spacing. Do you think something like that would be a good balance of achieving the evenly-spaced use case while letting us grow into the non-even use case? If so, we could start with the simpler one, and move into the latter whenever someone has the bandwidth to implement it.

@limzykenneth
Copy link
Member

Also in terms of implementation, instead of a new function, perhaps we can just implement overloading on lerpColor instead so if the first argument is an array, it lerps between all of them.

@RandomGamingDev
Copy link
Contributor Author

Do you think something like that would be a good balance of achieving the evenly-spaced use case while letting us grow into the non-even use case? If so, we could start with the simpler one, and move into the latter whenever someone has the bandwidth to implement it.

That sounds like a great idea although we might want to play around with the parameters being used a bit since it might be annoying for beginners to have 2 separate arrays that are connected to one another only through their index values especially since it can result in hard to debug bugs.

Also in terms of implementation, instead of a new function, perhaps we can just implement overloading on lerpColor instead so if the first argument is an array, it lerps between all of them.

That could be another possibility, but that would depend on which one p5.js prefers. Personally, I prefer having a separate function made for doing this, but making it an overload instead would be fine as well.

@davepagurek
Copy link
Contributor

That sounds like a great idea although we might want to play around with the parameters being used a bit since it might be annoying for beginners to have 2 separate arrays that are connected to one another only through their index values especially since it can result in hard to debug bugs.

Agreed about keeping the two array indices in sync being hard. One option could be to allow something like:

// evenly spaced
lerpPalette([white, red, green, blue], mix)

// with stops
lerpPalette([
  { color: white, stop: 0 },
  { color: red, stop: 0.05 },
  { color: green, stop: 0.25 },
  { color: blue, stop: 1 }
], mix)

I don't think we have array-of-object parameters for anything else just yet? but for this maybe it's worth trading the argument complexity for the potential bugs in keeping two arrays in sync?

@RandomGamingDev
Copy link
Contributor Author

That sounds like a great idea although we might want to play around with the parameters being used a bit since it might be annoying for beginners to have 2 separate arrays that are connected to one another only through their index values especially since it can result in hard to debug bugs.

Agreed about keeping the two array indices in sync being hard. One option could be to allow something like:

// evenly spaced
lerpPalette([white, red, green, blue], mix)

// with stops
lerpPalette([
  { color: white, stop: 0 },
  { color: red, stop: 0.05 },
  { color: green, stop: 0.25 },
  { color: blue, stop: 1 }
], mix)

I don't think we have array-of-object parameters for anything else just yet? but for this maybe it's worth trading the argument complexity for the potential bugs in keeping two arrays in sync?

I think that it'd probably be better to do something like this:

lerpPalette(
  red, 0.1,
  orange, 0.2,
  yellow, 0.4,
  green, 0.8,
  blue, 1.0,
  lerpVal
);

What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants