@@ -30,7 +30,11 @@ function strands(p5, fn) {
3030 //////////////////////////////////////////////
3131 // Global Runtime
3232 //////////////////////////////////////////////
33- function initStrandsContext ( ctx , backend , { active = false , renderer = null , baseShader = null } = { } ) {
33+ function initStrandsContext (
34+ ctx ,
35+ backend ,
36+ { active = false , renderer = null , baseShader = null } = { } ,
37+ ) {
3438 ctx . dag = createDirectedAcyclicGraph ( ) ;
3539 ctx . cfg = createControlFlowGraph ( ) ;
3640 ctx . uniforms = [ ] ;
@@ -78,11 +82,8 @@ function strands(p5, fn) {
7882
7983 const prev = { } ;
8084 for ( const key of Object . getOwnPropertyNames ( fn ) ) {
81- const descriptor = Object . getOwnPropertyDescriptor (
82- fn ,
83- key
84- ) ;
85- if ( descriptor && ! descriptor . get && typeof fn [ key ] === 'function' ) {
85+ const descriptor = Object . getOwnPropertyDescriptor ( fn , key ) ;
86+ if ( descriptor && ! descriptor . get && typeof fn [ key ] === "function" ) {
8687 prev [ key ] = window [ key ] ;
8788 window [ key ] = fn [ key ] . bind ( pInst ) ;
8889 }
@@ -104,7 +105,10 @@ function strands(p5, fn) {
104105
105106 p5 . Shader . prototype . modify = function ( shaderModifier , scope = { } ) {
106107 try {
107- if ( shaderModifier instanceof Function || typeof shaderModifier === 'string' ) {
108+ if (
109+ shaderModifier instanceof Function ||
110+ typeof shaderModifier === "string"
111+ ) {
108112 // Reset the context object every time modify is called;
109113 // const backend = glslBackend;
110114 initStrandsContext ( strandsContext , this . _renderer . strandsBackend , {
@@ -121,9 +125,10 @@ function strands(p5, fn) {
121125 if ( options . parser ) {
122126 // #7955 Wrap function declaration code in brackets so anonymous functions are not top level statements, which causes an error in acorn when parsing
123127 // https://github.com/acornjs/acorn/issues/1385
124- const sourceString = typeof shaderModifier === 'string'
125- ? `(${ shaderModifier } )`
126- : `(${ shaderModifier . toString ( ) } )` ;
128+ const sourceString =
129+ typeof shaderModifier === "string"
130+ ? `(${ shaderModifier } )`
131+ : `(${ shaderModifier . toString ( ) } )` ;
127132 strandsCallback = transpileStrandsToJS (
128133 p5 ,
129134 sourceString ,
@@ -275,6 +280,100 @@ if (typeof p5 !== "undefined") {
275280 * </div>
276281 */
277282
283+ /**
284+ * @method smoothstep
285+ * @description
286+ * A shader function that performs smooth Hermite interpolation between `0.0`
287+ * and `1.0`.
288+ *
289+ * This function is equivalent to the GLSL built-in
290+ * `smoothstep(edge0, edge1, x)` and is available inside p5.strands shader
291+ * callbacks. It is commonly used to create soft transitions, smooth edges,
292+ * fades, and anti-aliased effects.
293+ *
294+ * Smoothstep is useful when a threshold or cutoff is needed, but with a
295+ * gradual transition instead of a hard edge.
296+ *
297+ * - Returns `0.0` when `x` is less than or equal to `edge0`
298+ * - Returns `1.0` when `x` is greater than or equal to `edge1`
299+ * - Smoothly interpolates between `0.0` and `1.0` when `x` is between them
300+ *
301+ * @param {Number } edge0
302+ * Lower edge of the transition
303+ * @param {Number } edge1
304+ * Upper edge of the transition
305+ * @param {Number } x
306+ * Input value to interpolate
307+ *
308+ * @returns {Number }
309+ * A value between `0.0` and `1.0`
310+ *
311+ * @example
312+ * <div modernizr="webgl">
313+ * <code>
314+ * // Example 1: A soft vertical fade using smoothstep (no uniforms)
315+ *
316+ * let fadeShader;
317+ *
318+ * function fadeCallback() {
319+ * getColor((inputs) => {
320+ * // x goes from 0 → 1 across the canvas
321+ * let x = inputs.texCoord.x;
322+ *
323+ * // smoothstep creates a soft transition instead of a hard edge
324+ * let t = smoothstep(0.25, 0.35, x);
325+ *
326+ * // Use t directly as brightness
327+ * return [t, t, t, 1];
328+ * });
329+ * }
330+ *
331+ * function setup() {
332+ * createCanvas(300, 200, WEBGL);
333+ * fadeShader = baseFilterShader().modify(fadeCallback);
334+ * }
335+ *
336+ * function draw() {
337+ * background(0);
338+ * filter(fadeShader);
339+ * }
340+ * </code>
341+ * </div>
342+ *
343+ * @example
344+ * <div modernizr="webgl">
345+ * <code>
346+ * // Example 2: Animate the smooth transition using a uniform
347+ *
348+ * let animatedShader;
349+ *
350+ * function animatedFadeCallback() {
351+ * const time = uniformFloat(() => millis() * 0.001);
352+ *
353+ * getColor((inputs) => {
354+ * let x = inputs.texCoord.x;
355+ *
356+ * // Move the smoothstep band back and forth over time
357+ * let center = 0.5 + 0.25 * sin(time);
358+ * let t = smoothstep(center - 0.05, center + 0.05, x);
359+ *
360+ * return [t, t, t, 1];
361+ * });
362+ * }
363+ *
364+ * function setup() {
365+ * createCanvas(300, 200, WEBGL);
366+ * animatedShader = baseFilterShader().modify(animatedFadeCallback);
367+ * }
368+ *
369+ * function draw() {
370+ * background(0);
371+ * filter(animatedShader);
372+ * }
373+ * </code>
374+ * </div>
375+ */
376+
278377/**
279378 * @method beforeVertex
280379 * @private
0 commit comments