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

[p5.strands]: Abstract away `varying` and allow passing data between hooks in the same shader stage

Open davepagurek opened this issue 4 months ago • 3 comments

Increasing access

Currently there isn't a way in p5.strands to pass data between one hook in e.g. the vertex shader and another hook in the vertex shader. You can do it between vertex/fragment with a varying, but this requires users to Just Know which is which, but this is not documented anywhere, and is a new concept for them to learn. It seems feasible that we could do all this for you under the hood to reduce the incoming knowledge users have to have to be able to use p5.strands.

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 enhancement details

Currently, you can pass variables between vertex/fragment like this:

baseMaterialShader.modify(() => {
  let pos = varyingVec3()

  getObjectInputs((inputs) => {
    pos = inputs.position
    return inputs
  })

  getPixelInputs((inputs) => {
    // Do something with pos
  })
})

I propose that we take out the varyingVec3(), so it just looks like this:

baseMaterialShader.modify(() => {
  let pos

  getObjectInputs((inputs) => {
    pos = inputs.position
    return inputs
  })

  getPixelInputs((inputs) => {
    // Do something with pos
  })
})

We already detect when assigning from inside a hook to a variable in an outer scope, and when we do so, we can lazily create a variable as needed. Once we have that setup, this also lets us potentially support this:

baseMaterialShader.modify(() => {
  let pos

  getObjectInputs((inputs) => {
    pos = inputs.position
    return inputs
  })

  // Also in the vertex shader!
  getCameraInputs((inputs) => {
    inputs.color = mix([1, 0, 0, 1], [0, 0, 1, 1], length(inputs.position - pos))
    return inputs
  })
})

So instead of lazily creating a varying variable, we'd lazily create a generic global variable. This generic global does not yet know if it's a varying or a regular global. Only after we we run all the hooks, and we know where it's used, we would decide:

  • Output GLSL where it's a varying like we currently do if it's used in both a vertex shader hook and a fragment shader hook
  • Output a regular global variable if it's just used in vertex hooks or just used in fragment hooks

This would also require us to maybe track usage a little differently. Currently we do keep track of nodes that reference another node iirc, but we may want to check what shader a node is used in based on whether it gets referenced from the output of a hook and what stage that hook is for.

davepagurek avatar Jul 27 '25 17:07 davepagurek

@davepagurek @alexpls I’d like to work on this issue. Could you please assign it to me?

Satish-Medar avatar Aug 24 '25 06:08 Satish-Medar

Hi @Satish-Medar, I've noticed a few requests for contributions on different topics - and I've also seen you've been working on some PRs already. Thank you for your enthusiasm! However, in the future, I'd recommend focusing on one or two issues at a time. Also, before asking to contribute, be sure to read through the issue itself (and discussion if there is any). In this case, this is not yet an accepted proposal, there is still discussion that has to take place before implementation - so this issue is not ready to be assigned for work. You are welcome to share your ideas on any feature requests, how they can be improved, and how they can be implemented, though!

ksen0 avatar Sep 02 '25 17:09 ksen0

hey !@davepagurek This proposal sounds really promising in terms of reducing the cognitive load for users working with shader hooks. Automatically inferring whether a variable should be a varying or a global — based on usage across hooks — feels aligned with p5.js’s philosophy of accessibility and ease of use.

I especially appreciate the idea of removing the need for varyingVec3() in simple cases. That kind of abstraction could make shader logic much more approachable for beginners, while still allowing advanced users to reason about what's happening under the hood.

If this task is open, I’d love to take it on and explore how hook stage tracking and variable inference could be implemented. Happy to discuss edge cases or implementation details further.

Most appropriate sub-area: WebGL

Ayaan005-sudo avatar Nov 13 '25 14:11 Ayaan005-sudo