@@ -371,6 +371,97 @@ export function initGlobalStrandsAPI(p5, fn, strandsContext) {
371371 return p5 . strandsNode ( args [ 0 ] ) . w ;
372372 } ) ;
373373
374+ // HSB/HSL accessors — inject conversion helpers and extract channel
375+ const _hsbSnippet = `vec3 _p5_rgb2hsb(vec3 c) {
376+ vec4 K = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);
377+ vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
378+ vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
379+ float d = q.x - min(q.w, q.y);
380+ float e = 1.0e-10;
381+ return vec3(abs(q.z+(q.w-q.y)/(6.0*d+e)), d/(q.x+e), q.x);
382+ }` ;
383+
384+ const _hslSnippet = `vec3 _p5_rgb2hsl(vec3 c) {
385+ float maxC = max(c.r, max(c.g, c.b));
386+ float minC = min(c.r, min(c.g, c.b));
387+ float l = (maxC + minC) / 2.0;
388+ float d = maxC - minC;
389+ float s = d < 1e-10 ? 0.0 : d/(1.0-abs(2.0*l-1.0));
390+ float h = 0.0;
391+ if (d > 1e-10) {
392+ if (maxC == c.r) h = mod((c.g-c.b)/d, 6.0)/6.0;
393+ else if (maxC == c.g) h = ((c.b-c.r)/d+2.0)/6.0;
394+ else h = ((c.r-c.g)/d+4.0)/6.0;
395+ }
396+ return vec3(h, s, l);
397+ }` ;
398+
399+ function _injectSnippet ( snippet ) {
400+ strandsContext . vertexDeclarations . add ( snippet ) ;
401+ strandsContext . fragmentDeclarations . add ( snippet ) ;
402+ strandsContext . computeDeclarations . add ( snippet ) ;
403+ }
404+
405+ const originalHue = fn . hue ;
406+ augmentFn ( fn , p5 , 'hue' , function ( ...args ) {
407+ if ( ! strandsContext . active ) {
408+ return originalHue . apply ( this , args ) ;
409+ }
410+ _injectSnippet ( _hslSnippet ) ;
411+ const colorNode = p5 . strandsNode ( args [ 0 ] ) ;
412+ const { id, dimension } = build . functionCallNode (
413+ strandsContext , '_p5_rgb2hsl' ,
414+ [ fn . vec3 ( colorNode . x , colorNode . y , colorNode . z ) ] ,
415+ { overloads : [ { params : [ DataType . float3 ] , returnType : DataType . float3 } ] }
416+ ) ;
417+ return createStrandsNode ( id , dimension , strandsContext ) . x ;
418+ } ) ;
419+
420+ const originalSaturation = fn . saturation ;
421+ augmentFn ( fn , p5 , 'saturation' , function ( ...args ) {
422+ if ( ! strandsContext . active ) {
423+ return originalSaturation . apply ( this , args ) ;
424+ }
425+ _injectSnippet ( _hslSnippet ) ;
426+ const colorNode = p5 . strandsNode ( args [ 0 ] ) ;
427+ const { id, dimension } = build . functionCallNode (
428+ strandsContext , '_p5_rgb2hsl' ,
429+ [ fn . vec3 ( colorNode . x , colorNode . y , colorNode . z ) ] ,
430+ { overloads : [ { params : [ DataType . float3 ] , returnType : DataType . float3 } ] }
431+ ) ;
432+ return createStrandsNode ( id , dimension , strandsContext ) . y ;
433+ } ) ;
434+
435+ const originalBrightness = fn . brightness ;
436+ augmentFn ( fn , p5 , 'brightness' , function ( ...args ) {
437+ if ( ! strandsContext . active ) {
438+ return originalBrightness . apply ( this , args ) ;
439+ }
440+ _injectSnippet ( _hsbSnippet ) ;
441+ const colorNode = p5 . strandsNode ( args [ 0 ] ) ;
442+ const { id, dimension } = build . functionCallNode (
443+ strandsContext , '_p5_rgb2hsb' ,
444+ [ fn . vec3 ( colorNode . x , colorNode . y , colorNode . z ) ] ,
445+ { overloads : [ { params : [ DataType . float3 ] , returnType : DataType . float3 } ] }
446+ ) ;
447+ return createStrandsNode ( id , dimension , strandsContext ) . z ;
448+ } ) ;
449+
450+ const originalLightness = fn . lightness ;
451+ augmentFn ( fn , p5 , 'lightness' , function ( ...args ) {
452+ if ( ! strandsContext . active ) {
453+ return originalLightness . apply ( this , args ) ;
454+ }
455+ _injectSnippet ( _hslSnippet ) ;
456+ const colorNode = p5 . strandsNode ( args [ 0 ] ) ;
457+ const { id, dimension } = build . functionCallNode (
458+ strandsContext , '_p5_rgb2hsl' ,
459+ [ fn . vec3 ( colorNode . x , colorNode . y , colorNode . z ) ] ,
460+ { overloads : [ { params : [ DataType . float3 ] , returnType : DataType . float3 } ] }
461+ ) ;
462+ return createStrandsNode ( id , dimension , strandsContext ) . z ;
463+ } ) ;
464+
374465 augmentFn ( fn , p5 , 'getTexture' , function ( ...rawArgs ) {
375466 if ( strandsContext . active ) {
376467 const { id, dimension } = strandsContext . backend . createGetTextureCall ( strandsContext , rawArgs ) ;
0 commit comments