From 6cdc44c1f07c30cd14652b628f98c069b62bee7c Mon Sep 17 00:00:00 2001 From: bhabishnu <156663652+bhabishnu@users.noreply.github.com> Date: Wed, 14 Oct 2026 00:09:58 +0530 Subject: [PATCH] fix(strands): read loop state by flat key --- src/strands/strands_transpiler.js | 30 +++++++++++++++--------------- test/unit/webgl/p5.Shader.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/strands/strands_transpiler.js b/src/strands/strands_transpiler.js index 8269af368f..589323d8aa 100644 --- a/src/strands/strands_transpiler.js +++ b/src/strands/strands_transpiler.js @@ -383,13 +383,18 @@ function addCopyingAndReturn(functionBody, varsToReturn, sourcePrefix = null) { const tempName = `__copy_${parts.join('_')}_${blockVarCounter++}`; tempVarMap.set(varPath, tempName); - // If sourcePrefix is set (loop case), read from vars.x.y - // Otherwise (if-branch case), read directly from x.y + // In loop cases, read the flat state key from vars. + // Otherwise, read the original member path. let sourceExpr = sourcePrefix - ? { type: 'Identifier', name: sourcePrefix } + ? { + type: 'MemberExpression', + object: { type: 'Identifier', name: sourcePrefix }, + property: { type: 'Literal', value: varPath }, + computed: true + } : { type: 'Identifier', name: parts[0] }; - const pathParts = sourcePrefix ? parts : parts.slice(1); + const pathParts = sourcePrefix ? [] : parts.slice(1); for (const part of pathParts) { sourceExpr = { type: 'MemberExpression', @@ -992,7 +997,6 @@ const ASTCallbacks = { }; } - // Build right side: __block_2['inputs.color'] or __block_2['x'] const rightExpr = { type: 'MemberExpression', object: { type: 'Identifier', name: blockVar }, @@ -1348,16 +1352,12 @@ const ASTCallbacks = { }; } - // Build right side: __block_2.inputs.color or __block_2.x - let rightExpr = { type: 'Identifier', name: blockVar }; - for (const part of parts) { - rightExpr = { - type: 'MemberExpression', - object: rightExpr, - property: { type: 'Identifier', name: part }, - computed: false - }; - } + const rightExpr = { + type: 'MemberExpression', + object: { type: 'Identifier', name: blockVar }, + property: { type: 'Literal', value: varPath }, + computed: true + }; statements.push({ type: 'ExpressionStatement', diff --git a/test/unit/webgl/p5.Shader.js b/test/unit/webgl/p5.Shader.js index ec3c0c8d28..a862211727 100644 --- a/test/unit/webgl/p5.Shader.js +++ b/test/unit/webgl/p5.Shader.js @@ -2169,6 +2169,34 @@ suite('p5.Shader', function () { assert.approximately(pixelColor[2], 77, 5); }); + test('handle swizzle assignments on hook color in loops', () => { + myp5.createCanvas(50, 50, myp5.WEBGL); + + const testShader = myp5.baseMaterialShader().modify( + () => { + myp5.getPixelInputs(inputs => { + inputs.color = [0, 0, 0, 1]; + + for (let i = 0; i < 3; i++) { + inputs.color.rgb += 0.1; + } + + return inputs; + }); + }, + { myp5 } + ); + + myp5.noStroke(); + myp5.shader(testShader); + myp5.plane(myp5.width, myp5.height); + + const pixelColor = myp5.get(25, 25); + assert.approximately(pixelColor[0], 77, 5); + assert.approximately(pixelColor[1], 77, 5); + assert.approximately(pixelColor[2], 77, 5); + }); + test('handle for loop with variable as loop bound', () => { myp5.createCanvas(50, 50, myp5.WEBGL);