p5.js icon indicating copy to clipboard operation
p5.js copied to clipboard

[2.0] Proposal: A standard mechanism for reading renderer state

Open dhowe opened this issue 1 month ago • 3 comments

As discussed with @limzykenneth, there is not currently a consistent usage pattern for reading renderer state properties. In some cases (e.g. textWeight()) calling the function with no argument returns the current setting, while in other cases (rectMode(), for example) it results in an error message.

There are many use-cases for this information (for example, writing a function which needs to adjust to the various rect-modes) and in v1.x, people have used non-API access like _renderer._rectMode. In 2.x, this info is available in _renderer.states, also not part of the API, and also not available in global mode (for example, in the editor, where one would have to do p5.instance._renderer.states.rectMode.

The proposal here is to standardise the API so that calling no-argument versions of the state-setting functions return the current values. This will require evaluating whether there are existing uses of any of the existing no-argument versions of these methods (for example, randomSeed()) as well as checking for any other problematic cases

dhowe avatar Nov 19 '25 13:11 dhowe

Drawing functions

  • [x] background
  • [x] fill
  • [x] stroke
  • [x] tint
  • [x] rectMode
  • [x] colorMode
  • [x] blendMode
  • [x] imageMode
  • [x] ellipseMode
  • [x] strokeWeight
  • [x] strokeCap
  • [x] strokeJoin
  • [x] pixelDensity
  • [x] cursor
  • [x] rotate
  • [x] translate
  • [x] scale
  • [x] bezierOrder
  • [x] splineProperty
  • [x] splineProperties
  • [x] ~noiseSeed~
  • [x] ~randomSeed~
  • [ ] shearX ?
  • [ ] shearY ?

Text functions

  • [x] textAlign
  • [x] textLeading
  • [x] textFont
  • [x] textSize
  • [x] textStyle
  • [x] textWrap
  • [x] textDirection
  • [x] textWeight
  • [x] textProperty
  • [x] textProperties

dhowe avatar Dec 09 '25 00:12 dhowe

Questions

1. what to return for the no-arg functions dealing with color (fill, stroke, etc)?

In the current implementation I simply return the full color object, but an alternative that might be more manageable for new users would be to return a 4-element array in the current color-mode. Any thoughts @limzykenneth, @davepagurek, others?

2. how to handle background() ?

Currently we don't save the background color when we set it - my suggestion is to save this in renderer.states as a color object

3. how to handle randomSeed() and noiseSeed() which already have no-arg functionality?

dhowe avatar Dec 09 '25 20:12 dhowe

Thanks for putting this together @dhowe . Just my 2 cents:

  1. I have no objections to background() returning the color, and storing that in renderer.states.
  2. If fill() stroke() background() return the Color object rather than array would allow easier use of Color utilities (for example, the contrast check). If they return the more easy-to-read array, that seems more useful for debugging. Arguably, for debugging, _renderer.states is sufficient; one benefit for standardizing renderer state reading functions is to make them more usable in program logic. From that POV, I think color object makes more sense.
  3. Re: noiseSeed() and randomSeed() - please see https://github.com/processing/p5.js/issues/7711. Per @limzykenneth:

That is not possible, when randomSeed() is not explicitly called, random() delegates to Math.random() (ie. p5.js is not randomizing the seed by default at the start), and it is not possible to retrieve the seed value of Math.random() (not to mention they use different RNG implementation depending on the browser). Changing unseeded RNG to use our own RNG implementation presents performance tradeoff, ie. Math.random() is significantly faster than our seedable RNG implementation.

On reflection after that discussion, it seems randomNoise and randomSeed without arguments would have to stay as they are.

ksen0 avatar Dec 10 '25 14:12 ksen0

In addition to adding the setters listed above (let me know if I am missing any), I've made the following changes:

  • updated paramaterData.json for functions above to accept no-argument calls
  • for getters that return an object (textAlign, scale, translate, etc.), the setter now accepts that object
  • added background (either a color or an image) to renderer.state
  • all color-related getters return p5.Color
  • no change to randomSeed() or noiseSeed() for now
  • added tests for all of these in test/unit/core/properties.js

dhowe avatar Dec 10 '25 18:12 dhowe

I would think fill(), stroke() etc to return p5.Color as it is more flexible than an array of numbers which can have ambiguities around the color mode and color range.

background() is a bit different though as it is not really a state, ie. if you have drawn on top of the background, calling background() again doesn't preserve those things drawn on top and change the background color but rather draw over the whole thing. I'm not sure utility wise and in terms of conceptual understanding whether it would make sense to have a background state.

For randomSeed() and noiseSeed() as mentioned in #7711 the behavior of calling them without arguments set a random seed is not documented and something I find rather unusual/not very useful. As such it can be argued that randomSeed() and noiseSeed() without arguments are undefined behavior that we can set a new behavior for them, eg. returning set seed value if any or null/undefined if not set.

limzykenneth avatar Dec 10 '25 18:12 limzykenneth