From ed13cb63b5202bafbda01869c9490a9c4f50fde8 Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Sat, 21 Feb 2026 15:21:09 -0500 Subject: [PATCH 1/4] Handle booleans used as temp variables --- src/strands/ir_builders.js | 21 ++++++++++++++++++--- src/strands/ir_types.js | 24 ++++++++++++++---------- src/webgpu/strands_wgslBackend.js | 22 ++++++++++++---------- test/unit/webgl/p5.Shader.js | 29 +++++++++++++++++++++++++++++ test/unit/webgpu/p5.Shader.js | 29 +++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 23 deletions(-) diff --git a/src/strands/ir_builders.js b/src/strands/ir_builders.js index d6d2f46cce..097210b68a 100644 --- a/src/strands/ir_builders.js +++ b/src/strands/ir_builders.js @@ -1,7 +1,7 @@ import * as DAG from './ir_dag' import * as CFG from './ir_cfg' import * as FES from './strands_FES' -import { NodeType, OpCode, BaseType, DataType, BasePriority, OpCodeToSymbol, typeEquals, } from './ir_types'; +import { NodeType, OpCode, BaseType, DataType, BasePriority, OpCodeToSymbol, typeEquals, booleanOpCode } from './ir_types'; import { createStrandsNode, StrandsNode } from './strands_node'; import { strandsBuiltinFunctions } from './strands_builtins'; @@ -50,12 +50,22 @@ export function unaryOpNode(strandsContext, nodeOrValue, opCode) { node = createStrandsNode(id, dimension, strandsContext); } dependsOn = [node.id]; + + const typeInfo = { + baseType: dag.baseTypes[node.id], + dimension: node.dimension + }; + if (booleanOpCode[opCode]) { + typeInfo.baseType = BaseType.BOOL; + typeInfo.dimension = 1; + } + const nodeData = DAG.createNodeData({ nodeType: NodeType.OPERATION, opCode, dependsOn, - baseType: dag.baseTypes[node.id], - dimension: node.dimension + baseType: typeInfo.baseType, + dimension: typeInfo.dimension }) const id = DAG.getOrCreateNode(dag, nodeData); CFG.recordInBasicBlock(cfg, cfg.currentBlock, id); @@ -137,6 +147,11 @@ export function binaryOpNode(strandsContext, leftStrandsNode, rightArg, opCode) } } + if (booleanOpCode[opCode]) { + cast.toType.baseType = BaseType.BOOL; + cast.toType.dimension = 1; + } + const nodeData = DAG.createNodeData({ nodeType: NodeType.OPERATION, opCode, diff --git a/src/strands/ir_types.js b/src/strands/ir_types.js index 91c33e7e8e..a95cc8c907 100644 --- a/src/strands/ir_types.js +++ b/src/strands/ir_types.js @@ -137,7 +137,7 @@ export const OpCode = { } }; export const OperatorTable = [ - { arity: "unary", name: "not", symbol: "!", opCode: OpCode.Unary.LOGICAL_NOT }, + { arity: "unary", boolean: true, name: "not", symbol: "!", opCode: OpCode.Unary.LOGICAL_NOT }, { arity: "unary", name: "neg", symbol: "-", opCode: OpCode.Unary.NEGATE }, { arity: "unary", name: "plus", symbol: "+", opCode: OpCode.Unary.PLUS }, { arity: "binary", name: "add", symbol: "+", opCode: OpCode.Binary.ADD }, @@ -145,14 +145,14 @@ export const OperatorTable = [ { arity: "binary", name: "mult", symbol: "*", opCode: OpCode.Binary.MULTIPLY }, { arity: "binary", name: "div", symbol: "/", opCode: OpCode.Binary.DIVIDE }, { arity: "binary", name: "mod", symbol: "%", opCode: OpCode.Binary.MODULO }, - { arity: "binary", name: "equalTo", symbol: "==", opCode: OpCode.Binary.EQUAL }, - { arity: "binary", name: "notEqual", symbol: "!=", opCode: OpCode.Binary.NOT_EQUAL }, - { arity: "binary", name: "greaterThan", symbol: ">", opCode: OpCode.Binary.GREATER_THAN }, - { arity: "binary", name: "greaterEqual", symbol: ">=", opCode: OpCode.Binary.GREATER_EQUAL }, - { arity: "binary", name: "lessThan", symbol: "<", opCode: OpCode.Binary.LESS_THAN }, - { arity: "binary", name: "lessEqual", symbol: "<=", opCode: OpCode.Binary.LESS_EQUAL }, - { arity: "binary", name: "and", symbol: "&&", opCode: OpCode.Binary.LOGICAL_AND }, - { arity: "binary", name: "or", symbol: "||", opCode: OpCode.Binary.LOGICAL_OR }, + { arity: "binary", boolean: true, name: "equalTo", symbol: "==", opCode: OpCode.Binary.EQUAL }, + { arity: "binary", boolean: true, name: "notEqual", symbol: "!=", opCode: OpCode.Binary.NOT_EQUAL }, + { arity: "binary", boolean: true, name: "greaterThan", symbol: ">", opCode: OpCode.Binary.GREATER_THAN }, + { arity: "binary", boolean: true, name: "greaterEqual", symbol: ">=", opCode: OpCode.Binary.GREATER_EQUAL }, + { arity: "binary", boolean: true, name: "lessThan", symbol: "<", opCode: OpCode.Binary.LESS_THAN }, + { arity: "binary", boolean: true, name: "lessEqual", symbol: "<=", opCode: OpCode.Binary.LESS_EQUAL }, + { arity: "binary", boolean: true, name: "and", symbol: "&&", opCode: OpCode.Binary.LOGICAL_AND }, + { arity: "binary", boolean: true, name: "or", symbol: "||", opCode: OpCode.Binary.LOGICAL_OR }, ]; export const ConstantFolding = { [OpCode.Binary.ADD]: (a, b) => a + b, @@ -173,7 +173,8 @@ export const ConstantFolding = { export const OpCodeToSymbol = {}; export const UnarySymbolToName = {}; export const BinarySymbolToName = {}; -for (const { symbol, opCode, name, arity } of OperatorTable) { +export const booleanOpCode = {}; +for (const { symbol, opCode, name, arity, boolean } of OperatorTable) { // SymbolToOpCode[symbol] = opCode; OpCodeToSymbol[opCode] = symbol; if (arity === 'unary') { @@ -182,6 +183,9 @@ for (const { symbol, opCode, name, arity } of OperatorTable) { if (arity === 'binary') { BinarySymbolToName[symbol] = name; } + if (boolean) { + booleanOpCode[opCode] = true; + } } export const BlockType = { GLOBAL: 'global', diff --git a/src/webgpu/strands_wgslBackend.js b/src/webgpu/strands_wgslBackend.js index cca83be343..4394210414 100644 --- a/src/webgpu/strands_wgslBackend.js +++ b/src/webgpu/strands_wgslBackend.js @@ -73,10 +73,10 @@ const cfgHandlers = { // Initialize with default value - WGSL requires initialization let defaultValue; if (T.dimension === 1) { - defaultValue = T.baseType === 'float' ? '0.0' : '0'; + defaultValue = this.defaultScalarValue(T.baseType); } else { // For vector types, use constructor with repeated scalar values - const scalarDefault = T.baseType === 'float' ? '0.0' : '0'; + const scalarDefault = this.defaultScalarValue(T.baseType); const components = Array(T.dimension).fill(scalarDefault).join(', '); defaultValue = `${typeName}(${components})`; } @@ -85,6 +85,15 @@ const cfgHandlers = { } this[BlockType.DEFAULT](blockID, strandsContext, generationContext); }, + defaultScalarValue(baseType) { + if (baseType === BaseType.FLOAT) { + return '0.0'; + } else if (baseType === BaseType.BOOL) { + return 'false'; + } else { + return '0'; + } + }, [BlockType.IF_COND](blockID, strandsContext, generationContext) { const { dag, cfg } = strandsContext; const conditionID = cfg.blockConditions[blockID]; @@ -464,14 +473,7 @@ export const wgslBackend = { if (validInputs.length > 0) { return this.generateExpression(generationContext, dag, validInputs[0]); } else { - throw new Error(`No valid inputs for node`) - // Fallback: create a default value - const typeName = this.getTypeName(node.baseType, node.dimension); - if (node.dimension === 1) { - return node.baseType === BaseType.FLOAT ? '0.0' : '0'; - } else { - return `${typeName}(0.0)`; - } + throw new Error('No valid inputs for node'); } } case NodeType.ASSIGNMENT: diff --git a/test/unit/webgl/p5.Shader.js b/test/unit/webgl/p5.Shader.js index 3003037011..78319791c0 100644 --- a/test/unit/webgl/p5.Shader.js +++ b/test/unit/webgl/p5.Shader.js @@ -1113,6 +1113,35 @@ test('returns numbers for builtin globals outside hooks and a strandNode when ca assert.approximately(pixelColor[1], 0, 5); assert.approximately(pixelColor[2], 0, 5); }); + + test('using boolean intermediate variables', () => { + myp5.createCanvas(50, 50, myp5.WEBGL); + + const testShader = myp5.baseFilterShader().modify(() => { + myp5.getColor((inputs, canvasContent) => { + let value = 1; + let condition = 1 > 2; + + if (value < 0.5) { + condition = 0.5 < 2; + } + + if (condition) { + return [1, 0, 0, 1] + } + + return [0.4, 0, 0, 1]; + }); + }, { myp5 }); + + myp5.background(255, 255, 255); + myp5.filter(testShader); + + const pixelColor = myp5.get(25, 25); + assert.approximately(pixelColor[0], 0.4 * 255, 5); + assert.approximately(pixelColor[1], 0, 5); + assert.approximately(pixelColor[2], 0, 5); + }); }); suite('for loop statements', () => { diff --git a/test/unit/webgpu/p5.Shader.js b/test/unit/webgpu/p5.Shader.js index 32e7030973..06ba700ee2 100644 --- a/test/unit/webgpu/p5.Shader.js +++ b/test/unit/webgpu/p5.Shader.js @@ -411,6 +411,35 @@ suite('WebGPU p5.Shader', function() { assert.approximately(pixelColor[1], 127, 5); // Green channel should be ~127 assert.approximately(pixelColor[2], 127, 5); // Blue channel should be ~127 }); + + test('using boolean intermediate variables', async () => { + await myp5.createCanvas(50, 50, myp5.WEBGPU); + + const testShader = myp5.baseFilterShader().modify(() => { + myp5.getColor((inputs, canvasContent) => { + let value = 1; + let condition = 1 > 2; + + if (value < 0.5) { + condition = 0.5 < 2; + } + + if (condition) { + return [1, 0, 0, 1] + } + + return [0.4, 0, 0, 1]; + }); + }, { myp5 }); + + myp5.background(255, 255, 255); + myp5.filter(testShader); + + const pixelColor = await myp5.get(25, 25); + assert.approximately(pixelColor[0], 0.4 * 255, 5); + assert.approximately(pixelColor[1], 0, 5); + assert.approximately(pixelColor[2], 0, 5); + }); }); suite('for loop statements', () => { From 1e8e8d25194a8d93fef6840ed1a92c10742ed202 Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Sat, 21 Feb 2026 17:56:52 -0500 Subject: [PATCH 2/4] Fix usage of if statements in helper functions --- src/strands/ir_builders.js | 18 ++- src/strands/ir_types.js | 3 + src/strands/strands_api.js | 17 ++- src/strands/strands_phi_utils.js | 15 ++- src/strands/strands_transpiler.js | 177 +++++++++++++++++++++++++++++- test/unit/webgl/p5.Shader.js | 60 ++++++++++ test/unit/webgpu/p5.Shader.js | 60 ++++++++++ 7 files changed, 340 insertions(+), 10 deletions(-) diff --git a/src/strands/ir_builders.js b/src/strands/ir_builders.js index 097210b68a..7aef73058c 100644 --- a/src/strands/ir_builders.js +++ b/src/strands/ir_builders.js @@ -239,6 +239,17 @@ function mapPrimitiveDepsToIDs(strandsContext, typeInfo, dependsOn) { calculatedDimensions += dimension; continue; } + else if (typeof dep === 'boolean') { + // Handle boolean literals - convert to bool type + const { id, dimension } = scalarLiteralNode(strandsContext, { dimension: 1, baseType: BaseType.BOOL }, dep); + mappedDependencies.push(id); + calculatedDimensions += dimension; + // Update baseType to BOOL if it was inferred + if (baseType !== BaseType.BOOL) { + baseType = BaseType.BOOL; + } + continue; + } else { FES.userError('type error', `You've tried to construct a scalar or vector type with a non-numeric value: ${dep}`); } @@ -289,7 +300,12 @@ export function primitiveConstructorNode(strandsContext, typeInfo, dependsOn) { const { mappedDependencies, inferredTypeInfo } = mapPrimitiveDepsToIDs(strandsContext, typeInfo, dependsOn); const finalType = { - baseType: typeInfo.baseType, + // We might have inferred a non numeric type. Currently this is + // just used for booleans. Maybe this needs to be something more robust + // if we ever want to support inference of e.g. int vectors? + baseType: inferredTypeInfo.baseType === BaseType.BOOL + ? BaseType.BOOL + : typeInfo.baseType, dimension: inferredTypeInfo.dimension }; diff --git a/src/strands/ir_types.js b/src/strands/ir_types.js index a95cc8c907..9f480d5c9d 100644 --- a/src/strands/ir_types.js +++ b/src/strands/ir_types.js @@ -37,6 +37,7 @@ export const BaseType = { BOOL: "bool", MAT: "mat", DEFER: "defer", + ASSIGN_ON_USE: "assign_on_use", SAMPLER2D: "sampler2D", SAMPLER: "sampler", }; @@ -46,6 +47,7 @@ export const BasePriority = { [BaseType.BOOL]: 1, [BaseType.MAT]: 0, [BaseType.DEFER]: -1, + [BaseType.ASSIGN_ON_USE]: -2, [BaseType.SAMPLER2D]: -10, [BaseType.SAMPLER]: -11, }; @@ -66,6 +68,7 @@ export const DataType = { mat3: { fnName: "mat3x3", baseType: BaseType.MAT, dimension:3, priority: 0, }, mat4: { fnName: "mat4x4", baseType: BaseType.MAT, dimension:4, priority: 0, }, defer: { fnName: null, baseType: BaseType.DEFER, dimension: null, priority: -1 }, + assign_on_use: { fnName: null, baseType: BaseType.ASSIGN_ON_USE, dimension: null, priority: -2 }, sampler2D: { fnName: "sampler2D", baseType: BaseType.SAMPLER2D, dimension: 1, priority: -10 }, sampler: { fnName: "sampler", baseType: BaseType.SAMPLER, dimension: 1, priority: -11 }, } diff --git a/src/strands/strands_api.js b/src/strands/strands_api.js index be63791041..29e597b584 100644 --- a/src/strands/strands_api.js +++ b/src/strands/strands_api.js @@ -198,7 +198,20 @@ export function initGlobalStrandsAPI(p5, fn, strandsContext) { if (args.length > 4) { FES.userError("type error", "It looks like you've tried to construct a p5.strands node implicitly, with more than 4 components. This is currently not supported.") } - const { id, dimension } = build.primitiveConstructorNode(strandsContext, { baseType: BaseType.FLOAT, dimension: null }, args.flat()); + // Filter out undefined/null values + const flatArgs = args.flat(); + const definedArgs = flatArgs.filter(a => a !== undefined && a !== null); + + // If all args are undefined, this is likely a `let myVar` at the + // start of an if statement and it will be assigned within the branches. + // For that, we use an assign-on-use node, meaning we'll take the type of the + // values assigned to it. + if (definedArgs.length === 0) { + const { id, dimension } = build.primitiveConstructorNode(strandsContext, { baseType: BaseType.ASSIGN_ON_USE, dimension: null }, [0]); + return createStrandsNode(id, dimension, strandsContext); + } + + const { id, dimension } = build.primitiveConstructorNode(strandsContext, { baseType: BaseType.FLOAT, dimension: null }, definedArgs); return createStrandsNode(id, dimension, strandsContext);//new StrandsNode(id, dimension, strandsContext); } ////////////////////////////////////////////// @@ -337,7 +350,7 @@ export function initGlobalStrandsAPI(p5, fn, strandsContext) { // variant or also one more directly translated from GLSL, or to be more compatible with // APIs we documented at the release of 2.x and have to continue supporting. for (const type in DataType) { - if (type === BaseType.DEFER || type === 'sampler') { + if (type === BaseType.DEFER || type === BaseType.ASSIGN_ON_USE || type === 'sampler') { continue; } const typeInfo = DataType[type]; diff --git a/src/strands/strands_phi_utils.js b/src/strands/strands_phi_utils.js index 1437e75b8d..e88804f649 100644 --- a/src/strands/strands_phi_utils.js +++ b/src/strands/strands_phi_utils.js @@ -1,6 +1,6 @@ import * as CFG from './ir_cfg'; import * as DAG from './ir_dag'; -import { NodeType } from './ir_types'; +import { NodeType, BaseType } from './ir_types'; export function createPhiNode(strandsContext, phiInputs, varName) { // Determine the proper dimension and baseType from the inputs @@ -8,13 +8,16 @@ export function createPhiNode(strandsContext, phiInputs, varName) { if (validInputs.length === 0) { throw new Error(`No valid inputs for phi node for variable ${varName}`); } - // Get dimension and baseType from first valid input - let firstInput = validInputs - .map((input) => DAG.getNodeDataFromID(strandsContext.dag, input.value.id)) - .find((input) => input.dimension) ?? - DAG.getNodeDataFromID(strandsContext.dag, validInputs[0].value.id); + + // Get dimension and baseType from first valid input, skipping ASSIGN_ON_USE nodes + const inputNodes = validInputs.map((input) => DAG.getNodeDataFromID(strandsContext.dag, input.value.id)); + let firstInput = inputNodes.find((input) => input.baseType !== BaseType.ASSIGN_ON_USE && input.dimension) ?? + inputNodes.find((input) => input.baseType !== BaseType.ASSIGN_ON_USE) ?? + inputNodes[0]; + const dimension = firstInput.dimension; const baseType = firstInput.baseType; + const nodeData = { nodeType: NodeType.PHI, dimension, diff --git a/src/strands/strands_transpiler.js b/src/strands/strands_transpiler.js index 91a46d2597..90cd03203c 100644 --- a/src/strands/strands_transpiler.js +++ b/src/strands/strands_transpiler.js @@ -1142,6 +1142,177 @@ const ASTCallbacks = { return replaceInNode(node); } } + + // Helper function to check if a function body contains return statements in control flow + function functionHasEarlyReturns(functionNode) { + let hasEarlyReturn = false; + let inControlFlow = 0; + + const checkForEarlyReturns = { + IfStatement(node, state, c) { + inControlFlow++; + if (node.test) c(node.test, state); + if (node.consequent) c(node.consequent, state); + if (node.alternate) c(node.alternate, state); + inControlFlow--; + }, + ForStatement(node, state, c) { + inControlFlow++; + if (node.init) c(node.init, state); + if (node.test) c(node.test, state); + if (node.update) c(node.update, state); + if (node.body) c(node.body, state); + inControlFlow--; + }, + ReturnStatement(node) { + if (inControlFlow > 0) { + hasEarlyReturn = true; + } + } + }; + + if (functionNode.body && functionNode.body.type === 'BlockStatement') { + recursive(functionNode.body, {}, checkForEarlyReturns); + } + + return hasEarlyReturn; + } + + // Helper function to check if an if-statement's consequent contains a return + function blockContainsReturn(block) { + let hasReturn = false; + const findReturn = { + ReturnStatement() { + hasReturn = true; + } + }; + if (block) { + recursive(block, {}, findReturn); + } + return hasReturn; + } + + // Transform a helper function to use __returnValue pattern instead of early returns + function transformHelperFunction(functionNode) { + // 1. Add __returnValue declaration at the start of function body + const returnValueDecl = { + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { type: 'Identifier', name: '__returnValue' }, + init: null + }], + kind: 'let' + }; + + if (!functionNode.body || functionNode.body.type !== 'BlockStatement') { + return; // Can't transform arrow functions with expression bodies + } + + functionNode.body.body.unshift(returnValueDecl); + + // 2. Restructure if statements: move siblings after if with return into else block + function restructureIfStatements(statements) { + for (let i = 0; i < statements.length; i++) { + const stmt = statements[i]; + + if (stmt.type === 'IfStatement' && blockContainsReturn(stmt.consequent) && !stmt.alternate) { + // Find all subsequent statements + const subsequentStatements = statements.slice(i + 1); + + if (subsequentStatements.length > 0) { + // Create else block with subsequent statements + stmt.alternate = { + type: 'BlockStatement', + body: subsequentStatements + }; + + // Remove the subsequent statements from this level + statements.splice(i + 1); + + // Recursively process the new else block + restructureIfStatements(stmt.alternate.body); + } + } + + // Recursively process nested blocks + if (stmt.type === 'IfStatement') { + if (stmt.consequent && stmt.consequent.type === 'BlockStatement') { + restructureIfStatements(stmt.consequent.body); + } + if (stmt.alternate && stmt.alternate.type === 'BlockStatement') { + restructureIfStatements(stmt.alternate.body); + } + } else if (stmt.type === 'ForStatement' && stmt.body && stmt.body.type === 'BlockStatement') { + restructureIfStatements(stmt.body.body); + } else if (stmt.type === 'BlockStatement') { + restructureIfStatements(stmt.body); + } + } + } + + restructureIfStatements(functionNode.body.body); + + // 3. Transform all return statements to assignments + const transformReturns = { + ReturnStatement(node) { + // Convert return statement to assignment + node.type = 'ExpressionStatement'; + node.expression = { + type: 'AssignmentExpression', + operator: '=', + left: { type: 'Identifier', name: '__returnValue' }, + right: node.argument || { type: 'Identifier', name: 'undefined' } + }; + delete node.argument; + } + }; + + recursive(functionNode.body, {}, transformReturns); + + // 4. Add final return statement + const finalReturn = { + type: 'ReturnStatement', + argument: { type: 'Identifier', name: '__returnValue' } + }; + + functionNode.body.body.push(finalReturn); + } + + // Main transformation pass: find and transform helper functions with early returns + function transformHelperFunctionEarlyReturns(ast) { + const helperFunctionsToTransform = []; + + // Collect helper functions that need transformation + const collectHelperFunctions = { + VariableDeclarator(node, ancestors) { + const init = node.init; + if (init && (init.type === 'ArrowFunctionExpression' || init.type === 'FunctionExpression')) { + if (functionHasEarlyReturns(init)) { + helperFunctionsToTransform.push(init); + } + } + }, + FunctionDeclaration(node, ancestors) { + if (functionHasEarlyReturns(node)) { + helperFunctionsToTransform.push(node); + } + }, + // Don't transform functions that are direct arguments to call expressions + CallExpression(node, ancestors) { + // Arguments to CallExpressions are base callbacks, not helpers + // We skip them by not adding them to the transformation list + } + }; + + ancestor(ast, collectHelperFunctions); + + // Transform each collected helper function + for (const funcNode of helperFunctionsToTransform) { + transformHelperFunction(funcNode); + } + } + export function transpileStrandsToJS(p5, sourceString, srcLocations, scope) { // Reset counters at the start of each transpilation blockVarCounter = 0; @@ -1156,7 +1327,11 @@ const ASTCallbacks = { delete nonControlFlowCallbacks.IfStatement; delete nonControlFlowCallbacks.ForStatement; ancestor(ast, nonControlFlowCallbacks, undefined, { varyings: {} }); - // Second pass: transform if/for statements in post-order using recursive traversal + + // Second pass: transform helper functions with early returns to use __returnValue pattern + transformHelperFunctionEarlyReturns(ast); + + // Third pass: transform if/for statements in post-order using recursive traversal const postOrderControlFlowTransform = { IfStatement(node, state, c) { state.inControlFlow++; diff --git a/test/unit/webgl/p5.Shader.js b/test/unit/webgl/p5.Shader.js index 78319791c0..6241c88973 100644 --- a/test/unit/webgl/p5.Shader.js +++ b/test/unit/webgl/p5.Shader.js @@ -1142,6 +1142,66 @@ test('returns numbers for builtin globals outside hooks and a strandNode when ca assert.approximately(pixelColor[1], 0, 5); assert.approximately(pixelColor[2], 0, 5); }); + + test('using boolean intermediate variables in functions', () => { + myp5.createCanvas(50, 50, myp5.WEBGL); + + const testShader = myp5.baseFilterShader().modify(() => { + const conditionMet = () => { + let condition = 1 > 2; + let value = 1; + if (value < 0.5) { + condition = 0.5 < 2; + } + return !condition + } + myp5.getColor((inputs, canvasContent) => { + if (conditionMet()) { + return [1, 0, 0, 1] + } + + return [0.4, 0, 0, 1]; + }); + }, { myp5 }); + + myp5.background(255, 255, 255); + myp5.filter(testShader); + + const pixelColor = myp5.get(25, 25); + assert.approximately(pixelColor[0], 255, 5); + assert.approximately(pixelColor[1], 0, 5); + assert.approximately(pixelColor[2], 0, 5); + }); + + test('using boolean intermediate variables in functions with early returns', () => { + myp5.createCanvas(50, 50, myp5.WEBGL); + + const testShader = myp5.baseFilterShader().modify(() => { + const conditionMet = () => { + let value = 1; + if (value < 0.5) { + return true + } + return false + } + myp5.getColor((inputs, canvasContent) => { + if (conditionMet()) { + return [1, 0, 0, 1] + } + + return [0.4, 0, 0, 1]; + }); + }, { myp5 }); + console.log(testShader.fragSrc()) + + myp5.background(255, 255, 255); + myp5.filter(testShader); + + const pixelColor = myp5.get(25, 25); + assert.approximately(pixelColor[0], 102, 5); + assert.approximately(pixelColor[1], 0, 5); + assert.approximately(pixelColor[2], 0, 5); + }); }); suite('for loop statements', () => { diff --git a/test/unit/webgpu/p5.Shader.js b/test/unit/webgpu/p5.Shader.js index 06ba700ee2..ba3bcd6bdc 100644 --- a/test/unit/webgpu/p5.Shader.js +++ b/test/unit/webgpu/p5.Shader.js @@ -440,6 +440,66 @@ suite('WebGPU p5.Shader', function() { assert.approximately(pixelColor[1], 0, 5); assert.approximately(pixelColor[2], 0, 5); }); + + test('using boolean intermediate variables in functions', async () => { + await myp5.createCanvas(50, 50, myp5.WEBGPU); + + const testShader = myp5.baseFilterShader().modify(() => { + const conditionMet = () => { + let condition = 1 > 2; + let value = 1; + if (value < 0.5) { + condition = 0.5 < 2; + } + return !condition + } + myp5.getColor((inputs, canvasContent) => { + if (conditionMet()) { + return [1, 0, 0, 1] + } + + return [0.4, 0, 0, 1]; + }); + }, { myp5 }); + + myp5.background(255, 255, 255); + myp5.filter(testShader); + + const pixelColor = await myp5.get(25, 25); + assert.approximately(pixelColor[0], 255, 5); + assert.approximately(pixelColor[1], 0, 5); + assert.approximately(pixelColor[2], 0, 5); + }); + + test('using boolean intermediate variables in functions with early returns', async () => { + await myp5.createCanvas(50, 50, myp5.WEBGPU); + + const testShader = myp5.baseFilterShader().modify(() => { + const conditionMet = () => { + let value = 1; + if (value < 0.5) { + return true + } + return false + } + myp5.getColor((inputs, canvasContent) => { + if (conditionMet()) { + return [1, 0, 0, 1] + } + + return [0.4, 0, 0, 1]; + }); + }, { myp5 }); + console.log(testShader.fragSrc()) + + myp5.background(255, 255, 255); + myp5.filter(testShader); + + const pixelColor = await myp5.get(25, 25); + assert.approximately(pixelColor[0], 102, 5); + assert.approximately(pixelColor[1], 0, 5); + assert.approximately(pixelColor[2], 0, 5); + }); }); suite('for loop statements', () => { From 5ee5f0aa82f4169b2edddaae126c70f5ba3f8a0b Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Sat, 21 Feb 2026 17:57:37 -0500 Subject: [PATCH 3/4] Fix indentation --- src/strands/strands_transpiler.js | 1939 +++++++++++++++-------------- 1 file changed, 973 insertions(+), 966 deletions(-) diff --git a/src/strands/strands_transpiler.js b/src/strands/strands_transpiler.js index 90cd03203c..fce1f961f2 100644 --- a/src/strands/strands_transpiler.js +++ b/src/strands/strands_transpiler.js @@ -281,65 +281,103 @@ const ASTCallbacks = { Identifier(node, _state, ancestors) { if (ancestors.some(nodeIsUniform)) { return; } if (_state.varyings[node.name] - && !ancestors.some(a => a.type === 'AssignmentExpression' && a.left === node)) { - node.type = 'CallExpression'; - node.callee = { + && !ancestors.some(a => a.type === 'AssignmentExpression' && a.left === node) + ) { + node.type = 'CallExpression'; + node.callee = { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: node.name + }, + property: { + type: 'Identifier', + name: 'getValue' + }, + }; + node.arguments = []; + } + }, + // The callbacks for AssignmentExpression and BinaryExpression handle + // operator overloading including +=, *= assignment expressions + ArrayExpression(node, _state, ancestors) { + if (ancestors.some(nodeIsUniform)) { return; } + const original = JSON.parse(JSON.stringify(node)); + node.type = 'CallExpression'; + node.callee = { + type: 'Identifier', + name: '__p5.strandsNode', + }; + node.arguments = [original]; + }, + AssignmentExpression(node, _state, ancestors) { + if (ancestors.some(nodeIsUniform)) { return; } + const unsafeTypes = ['Literal', 'ArrayExpression', 'Identifier']; + if (node.operator !== '=') { + const methodName = replaceBinaryOperator(node.operator.replace('=','')); + const rightReplacementNode = { + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: unsafeTypes.includes(node.left.type) + ? { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: '__p5.strandsNode', + }, + arguments: [node.left] + } + : node.left, + property: { + type: 'Identifier', + name: methodName, + }, + }, + arguments: [node.right] + } + node.operator = '='; + node.right = rightReplacementNode; + } + // Handle direct varying variable assignment: myVarying = value + if (_state.varyings[node.left.name]) { + node.type = 'ExpressionStatement'; + node.expression = { + type: 'CallExpression', + callee: { type: 'MemberExpression', object: { type: 'Identifier', - name: node.name + name: node.left.name }, property: { type: 'Identifier', - name: 'getValue' - }, - }; - node.arguments = []; + name: 'bridge', + } + }, + arguments: [node.right], } - }, - // The callbacks for AssignmentExpression and BinaryExpression handle - // operator overloading including +=, *= assignment expressions - ArrayExpression(node, _state, ancestors) { - if (ancestors.some(nodeIsUniform)) { return; } - const original = JSON.parse(JSON.stringify(node)); - node.type = 'CallExpression'; - node.callee = { - type: 'Identifier', - name: '__p5.strandsNode', - }; - node.arguments = [original]; - }, - AssignmentExpression(node, _state, ancestors) { - if (ancestors.some(nodeIsUniform)) { return; } - const unsafeTypes = ['Literal', 'ArrayExpression', 'Identifier']; - if (node.operator !== '=') { - const methodName = replaceBinaryOperator(node.operator.replace('=','')); - const rightReplacementNode = { - type: 'CallExpression', - callee: { - type: 'MemberExpression', - object: unsafeTypes.includes(node.left.type) - ? { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: '__p5.strandsNode', - }, - arguments: [node.left] - } - : node.left, - property: { - type: 'Identifier', - name: methodName, - }, - }, - arguments: [node.right] - } - node.operator = '='; - node.right = rightReplacementNode; + } + // Handle swizzle assignment to varying variable: myVarying.xyz = value + // Note: node.left.object might be worldPos.getValue() due to prior Identifier transformation + else if (node.left.type === 'MemberExpression') { + let varyingName = null; + + // Check if it's a direct identifier: myVarying.xyz + if (node.left.object.type === 'Identifier' && _state.varyings[node.left.object.name]) { + varyingName = node.left.object.name; + } + // Check if it's a getValue() call: myVarying.getValue().xyz + else if (node.left.object.type === 'CallExpression' && + node.left.object.callee?.type === 'MemberExpression' && + node.left.object.callee.property?.name === 'getValue' && + node.left.object.callee.object?.type === 'Identifier' && + _state.varyings[node.left.object.callee.object.name]) { + varyingName = node.left.object.callee.object.name; } - // Handle direct varying variable assignment: myVarying = value - if (_state.varyings[node.left.name]) { + + if (varyingName) { + const swizzlePattern = node.left.property.name; node.type = 'ExpressionStatement'; node.expression = { type: 'CallExpression', @@ -347,1062 +385,1031 @@ const ASTCallbacks = { type: 'MemberExpression', object: { type: 'Identifier', - name: node.left.name + name: varyingName }, property: { type: 'Identifier', - name: 'bridge', + name: 'bridgeSwizzle', } }, - arguments: [node.right], - } - } - // Handle swizzle assignment to varying variable: myVarying.xyz = value - // Note: node.left.object might be worldPos.getValue() due to prior Identifier transformation - else if (node.left.type === 'MemberExpression') { - let varyingName = null; - - // Check if it's a direct identifier: myVarying.xyz - if (node.left.object.type === 'Identifier' && _state.varyings[node.left.object.name]) { - varyingName = node.left.object.name; - } - // Check if it's a getValue() call: myVarying.getValue().xyz - else if (node.left.object.type === 'CallExpression' && - node.left.object.callee?.type === 'MemberExpression' && - node.left.object.callee.property?.name === 'getValue' && - node.left.object.callee.object?.type === 'Identifier' && - _state.varyings[node.left.object.callee.object.name]) { - varyingName = node.left.object.callee.object.name; - } - - if (varyingName) { - const swizzlePattern = node.left.property.name; - node.type = 'ExpressionStatement'; - node.expression = { - type: 'CallExpression', - callee: { - type: 'MemberExpression', - object: { - type: 'Identifier', - name: varyingName - }, - property: { - type: 'Identifier', - name: 'bridgeSwizzle', - } + arguments: [ + { + type: 'Literal', + value: swizzlePattern }, - arguments: [ - { - type: 'Literal', - value: swizzlePattern - }, - node.right - ], - } + node.right + ], } } - }, - BinaryExpression(node, _state, ancestors) { - // Don't convert uniform default values to node methods, as - // they should be evaluated at runtime, not compiled. - if (ancestors.some(nodeIsUniform)) { return; } - // If the left hand side of an expression is one of these types, - // we should construct a node from it. - const unsafeTypes = ['Literal', 'ArrayExpression', 'Identifier']; - if (unsafeTypes.includes(node.left.type)) { - const leftReplacementNode = { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: '__p5.strandsNode', - }, - arguments: [node.left] - } - node.left = leftReplacementNode; - } - // Replace the binary operator with a call expression - // in other words a call to BaseNode.mult(), .div() etc. - node.type = 'CallExpression'; - node.callee = { - type: 'MemberExpression', - object: node.left, - property: { + } + }, + BinaryExpression(node, _state, ancestors) { + // Don't convert uniform default values to node methods, as + // they should be evaluated at runtime, not compiled. + if (ancestors.some(nodeIsUniform)) { return; } + // If the left hand side of an expression is one of these types, + // we should construct a node from it. + const unsafeTypes = ['Literal', 'ArrayExpression', 'Identifier']; + if (unsafeTypes.includes(node.left.type)) { + const leftReplacementNode = { + type: 'CallExpression', + callee: { type: 'Identifier', - name: replaceBinaryOperator(node.operator), + name: '__p5.strandsNode', }, - }; - node.arguments = [node.right]; - }, - LogicalExpression(node, _state, ancestors) { - // Don't convert uniform default values to node methods, as - // they should be evaluated at runtime, not compiled. - if (ancestors.some(nodeIsUniform)) { return; } - // If the left hand side of an expression is one of these types, - // we should construct a node from it. - const unsafeTypes = ['Literal', 'ArrayExpression', 'Identifier']; - if (unsafeTypes.includes(node.left.type)) { - const leftReplacementNode = { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: '__p5.strandsNode', - }, - arguments: [node.left] - } - node.left = leftReplacementNode; + arguments: [node.left] } - // Replace the logical operator with a call expression - // in other words a call to BaseNode.or(), .and() etc. - node.type = 'CallExpression'; - node.callee = { - type: 'MemberExpression', - object: node.left, - property: { + node.left = leftReplacementNode; + } + // Replace the binary operator with a call expression + // in other words a call to BaseNode.mult(), .div() etc. + node.type = 'CallExpression'; + node.callee = { + type: 'MemberExpression', + object: node.left, + property: { + type: 'Identifier', + name: replaceBinaryOperator(node.operator), + }, + }; + node.arguments = [node.right]; + }, + LogicalExpression(node, _state, ancestors) { + // Don't convert uniform default values to node methods, as + // they should be evaluated at runtime, not compiled. + if (ancestors.some(nodeIsUniform)) { return; } + // If the left hand side of an expression is one of these types, + // we should construct a node from it. + const unsafeTypes = ['Literal', 'ArrayExpression', 'Identifier']; + if (unsafeTypes.includes(node.left.type)) { + const leftReplacementNode = { + type: 'CallExpression', + callee: { type: 'Identifier', - name: replaceBinaryOperator(node.operator), + name: '__p5.strandsNode', }, + arguments: [node.left] + } + node.left = leftReplacementNode; + } + // Replace the logical operator with a call expression + // in other words a call to BaseNode.or(), .and() etc. + node.type = 'CallExpression'; + node.callee = { + type: 'MemberExpression', + object: node.left, + property: { + type: 'Identifier', + name: replaceBinaryOperator(node.operator), + }, + }; + node.arguments = [node.right]; + }, + IfStatement(node, _state, ancestors) { + if (ancestors.some(nodeIsUniform)) { return; } + // Transform if statement into strandsIf() call + // The condition is evaluated directly, not wrapped in a function + const condition = node.test; + // Create the then function + const thenFunction = { + type: 'ArrowFunctionExpression', + params: [], + body: node.consequent.type === 'BlockStatement' ? node.consequent : { + type: 'BlockStatement', + body: [node.consequent] + } + }; + // Start building the call chain: __p5.strandsIf(condition, then) + let callExpression = { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: '__p5.strandsIf' + }, + arguments: [condition, thenFunction] + }; + // Always chain .Else() even if there's no explicit else clause + // This ensures the conditional completes and returns phi nodes + let elseFunction; + if (node.alternate) { + elseFunction = { + type: 'ArrowFunctionExpression', + params: [], + body: node.alternate.type === 'BlockStatement' ? node.alternate : { + type: 'BlockStatement', + body: [node.alternate] + } }; - node.arguments = [node.right]; - }, - IfStatement(node, _state, ancestors) { - if (ancestors.some(nodeIsUniform)) { return; } - // Transform if statement into strandsIf() call - // The condition is evaluated directly, not wrapped in a function - const condition = node.test; - // Create the then function - const thenFunction = { + } else { + // Create an empty else function + elseFunction = { type: 'ArrowFunctionExpression', params: [], - body: node.consequent.type === 'BlockStatement' ? node.consequent : { + body: { type: 'BlockStatement', - body: [node.consequent] + body: [] } }; - // Start building the call chain: __p5.strandsIf(condition, then) - let callExpression = { - type: 'CallExpression', - callee: { + } + callExpression = { + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: callExpression, + property: { type: 'Identifier', - name: '__p5.strandsIf' - }, - arguments: [condition, thenFunction] - }; - // Always chain .Else() even if there's no explicit else clause - // This ensures the conditional completes and returns phi nodes - let elseFunction; - if (node.alternate) { - elseFunction = { - type: 'ArrowFunctionExpression', - params: [], - body: node.alternate.type === 'BlockStatement' ? node.alternate : { - type: 'BlockStatement', - body: [node.alternate] - } - }; - } else { - // Create an empty else function - elseFunction = { - type: 'ArrowFunctionExpression', - params: [], - body: { - type: 'BlockStatement', - body: [] - } - }; - } - callExpression = { - type: 'CallExpression', - callee: { - type: 'MemberExpression', - object: callExpression, - property: { - type: 'Identifier', - name: 'Else' - } - }, - arguments: [elseFunction] - }; + name: 'Else' + } + }, + arguments: [elseFunction] + }; - // Analyze which outer scope variables are assigned in any branch - const assignedVars = new Set(); - - const analyzeBranch = (functionBody) => { - // First pass: collect all variable declarations in the branch - const localVars = new Set(); - ancestor(functionBody, { - VariableDeclarator(node, ancestors) { - // Skip if we're inside a block that contains strands control flow - if (ancestors.some(statementContainsStrandsControlFlow)) return; - if (node.id.type === 'Identifier') { - localVars.add(node.id.name); - } + // Analyze which outer scope variables are assigned in any branch + const assignedVars = new Set(); + + const analyzeBranch = (functionBody) => { + // First pass: collect all variable declarations in the branch + const localVars = new Set(); + ancestor(functionBody, { + VariableDeclarator(node, ancestors) { + // Skip if we're inside a block that contains strands control flow + if (ancestors.some(statementContainsStrandsControlFlow)) return; + if (node.id.type === 'Identifier') { + localVars.add(node.id.name); } - }); + } + }); - // Second pass: find assignments to non-local variables using acorn-walk - ancestor(functionBody, { - AssignmentExpression(node, ancestors) { - // Skip if we're inside a block that contains strands control flow - if (ancestors.some(statementContainsStrandsControlFlow)) return; - - const left = node.left; - if (left.type === 'Identifier') { - // Direct variable assignment: x = value - if (!localVars.has(left.name)) { - assignedVars.add(left.name); - } - } else if (left.type === 'MemberExpression') { - // Property assignment: obj.prop = value or obj.a.b = value - const propertyPath = buildPropertyPath(left); - if (propertyPath) { - const baseName = propertyPath.split('.')[0]; - if (!localVars.has(baseName)) { - assignedVars.add(propertyPath); - } + // Second pass: find assignments to non-local variables using acorn-walk + ancestor(functionBody, { + AssignmentExpression(node, ancestors) { + // Skip if we're inside a block that contains strands control flow + if (ancestors.some(statementContainsStrandsControlFlow)) return; + + const left = node.left; + if (left.type === 'Identifier') { + // Direct variable assignment: x = value + if (!localVars.has(left.name)) { + assignedVars.add(left.name); + } + } else if (left.type === 'MemberExpression') { + // Property assignment: obj.prop = value or obj.a.b = value + const propertyPath = buildPropertyPath(left); + if (propertyPath) { + const baseName = propertyPath.split('.')[0]; + if (!localVars.has(baseName)) { + assignedVars.add(propertyPath); } } } - }); - }; + } + }); + }; - // Analyze all branches for assignments to outer scope variables - analyzeBranch(thenFunction.body); - analyzeBranch(elseFunction.body); - if (assignedVars.size > 0) { - // Add copying, reference replacement, and return statements to branch functions - const addCopyingAndReturn = (functionBody, varsToReturn) => { - if (functionBody.type === 'BlockStatement') { - // Create temporary variables and copy statements - const tempVarMap = new Map(); // property path -> temp name - const copyStatements = []; - for (const varPath of varsToReturn) { - const parts = varPath.split('.'); - const tempName = `__copy_${parts.join('_')}_${blockVarCounter++}`; - tempVarMap.set(varPath, tempName); - - // Build the member expression for the property path - let sourceExpr = { type: 'Identifier', name: parts[0] }; - for (let i = 1; i < parts.length; i++) { - sourceExpr = { - type: 'MemberExpression', - object: sourceExpr, - property: { type: 'Identifier', name: parts[i] }, - computed: false - }; - } + // Analyze all branches for assignments to outer scope variables + analyzeBranch(thenFunction.body); + analyzeBranch(elseFunction.body); + if (assignedVars.size > 0) { + // Add copying, reference replacement, and return statements to branch functions + const addCopyingAndReturn = (functionBody, varsToReturn) => { + if (functionBody.type === 'BlockStatement') { + // Create temporary variables and copy statements + const tempVarMap = new Map(); // property path -> temp name + const copyStatements = []; + for (const varPath of varsToReturn) { + const parts = varPath.split('.'); + const tempName = `__copy_${parts.join('_')}_${blockVarCounter++}`; + tempVarMap.set(varPath, tempName); - // let tempName = propertyPath.copy() - copyStatements.push({ - type: 'VariableDeclaration', - declarations: [{ - type: 'VariableDeclarator', - id: { type: 'Identifier', name: tempName }, - init: { - type: 'CallExpression', - callee: { - type: 'MemberExpression', - object: sourceExpr, - property: { type: 'Identifier', name: 'copy' }, - computed: false - }, - arguments: [] - } - }], - kind: 'let' - }); + // Build the member expression for the property path + let sourceExpr = { type: 'Identifier', name: parts[0] }; + for (let i = 1; i < parts.length; i++) { + sourceExpr = { + type: 'MemberExpression', + object: sourceExpr, + property: { type: 'Identifier', name: parts[i] }, + computed: false + }; } - // Apply reference replacement to all statements - functionBody.body.forEach(node => replaceReferences(node, tempVarMap)); - // Insert copy statements at the beginning - functionBody.body.unshift(...copyStatements); - // Add return statement with flat object using property paths as keys - const returnObj = { - type: 'ObjectExpression', - properties: Array.from(varsToReturn).map(varPath => ({ - type: 'Property', - key: { type: 'Literal', value: varPath }, - value: { type: 'Identifier', name: tempVarMap.get(varPath) }, - kind: 'init', - computed: false, - shorthand: false - })) - }; - functionBody.body.push({ - type: 'ReturnStatement', - argument: returnObj - }); - } - }; - addCopyingAndReturn(thenFunction.body, assignedVars); - addCopyingAndReturn(elseFunction.body, assignedVars); - // Create a block variable to capture the return value - const blockVar = `__block_${blockVarCounter++}`; - // Replace with a block statement - const statements = []; - // Make sure every assigned variable starts as a node - for (const varPath of assignedVars) { - const parts = varPath.split('.'); - // Build left side: inputs.color or just x - let leftExpr = { type: 'Identifier', name: parts[0] }; - for (let i = 1; i < parts.length; i++) { - leftExpr = { - type: 'MemberExpression', - object: leftExpr, - property: { type: 'Identifier', name: parts[i] }, - computed: false - }; - } - - // Build right side - same as left for strandsNode wrapping - let rightArgExpr = { type: 'Identifier', name: parts[0] }; - for (let i = 1; i < parts.length; i++) { - rightArgExpr = { - type: 'MemberExpression', - object: rightArgExpr, - property: { type: 'Identifier', name: parts[i] }, - computed: false - }; + // let tempName = propertyPath.copy() + copyStatements.push({ + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { type: 'Identifier', name: tempName }, + init: { + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: sourceExpr, + property: { type: 'Identifier', name: 'copy' }, + computed: false + }, + arguments: [] + } + }], + kind: 'let' + }); } - - statements.push({ - type: 'ExpressionStatement', - expression: { - type: 'AssignmentExpression', - operator: '=', - left: leftExpr, - right: { - type: 'CallExpression', - callee: { type: 'Identifier', name: '__p5.strandsNode' }, - arguments: [rightArgExpr], - } - } + // Apply reference replacement to all statements + functionBody.body.forEach(node => replaceReferences(node, tempVarMap)); + // Insert copy statements at the beginning + functionBody.body.unshift(...copyStatements); + // Add return statement with flat object using property paths as keys + const returnObj = { + type: 'ObjectExpression', + properties: Array.from(varsToReturn).map(varPath => ({ + type: 'Property', + key: { type: 'Literal', value: varPath }, + value: { type: 'Identifier', name: tempVarMap.get(varPath) }, + kind: 'init', + computed: false, + shorthand: false + })) + }; + functionBody.body.push({ + type: 'ReturnStatement', + argument: returnObj }); } - statements.push({ - type: 'VariableDeclaration', - declarations: [{ - type: 'VariableDeclarator', - id: { type: 'Identifier', name: blockVar }, - init: callExpression - }], - kind: 'const' - }); - // 2. Assignments for each modified variable - for (const varPath of assignedVars) { - const parts = varPath.split('.'); - - // Build left side: inputs.color or just x - let leftExpr = { type: 'Identifier', name: parts[0] }; - for (let i = 1; i < parts.length; i++) { - leftExpr = { - type: 'MemberExpression', - object: leftExpr, - property: { type: 'Identifier', name: parts[i] }, - computed: false - }; - } + }; + addCopyingAndReturn(thenFunction.body, assignedVars); + addCopyingAndReturn(elseFunction.body, assignedVars); + // Create a block variable to capture the return value + const blockVar = `__block_${blockVarCounter++}`; + // Replace with a block statement + const statements = []; + // Make sure every assigned variable starts as a node + for (const varPath of assignedVars) { + const parts = varPath.split('.'); + + // Build left side: inputs.color or just x + let leftExpr = { type: 'Identifier', name: parts[0] }; + for (let i = 1; i < parts.length; i++) { + leftExpr = { + type: 'MemberExpression', + object: leftExpr, + property: { type: 'Identifier', name: parts[i] }, + computed: false + }; + } - // Build right side: __block_2['inputs.color'] or __block_2['x'] - const rightExpr = { + // Build right side - same as left for strandsNode wrapping + let rightArgExpr = { type: 'Identifier', name: parts[0] }; + for (let i = 1; i < parts.length; i++) { + rightArgExpr = { type: 'MemberExpression', - object: { type: 'Identifier', name: blockVar }, - property: { type: 'Literal', value: varPath }, - computed: true + object: rightArgExpr, + property: { type: 'Identifier', name: parts[i] }, + computed: false }; + } - statements.push({ - type: 'ExpressionStatement', - expression: { - type: 'AssignmentExpression', - operator: '=', - left: leftExpr, - right: rightExpr + statements.push({ + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: leftExpr, + right: { + type: 'CallExpression', + callee: { type: 'Identifier', name: '__p5.strandsNode' }, + arguments: [rightArgExpr], } - }); - } - // Replace the if statement with a block statement - node.type = 'BlockStatement'; - node.body = statements; - } else { - // No assignments, just replace with the call expression - node.type = 'ExpressionStatement'; - node.expression = callExpression; + } + }); } - delete node.test; - delete node.consequent; - delete node.alternate; - }, - UpdateExpression(node, _state, ancestors) { - if (ancestors.some(nodeIsUniform)) { return; } - - // Transform ++var, var++, --var, var-- into assignment expressions - let operator; - if (node.operator === '++') { - operator = '+'; - } else if (node.operator === '--') { - operator = '-'; - } else { - return; // Unknown update operator + statements.push({ + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { type: 'Identifier', name: blockVar }, + init: callExpression + }], + kind: 'const' + }); + // 2. Assignments for each modified variable + for (const varPath of assignedVars) { + const parts = varPath.split('.'); + + // Build left side: inputs.color or just x + let leftExpr = { type: 'Identifier', name: parts[0] }; + for (let i = 1; i < parts.length; i++) { + leftExpr = { + type: 'MemberExpression', + object: leftExpr, + property: { type: 'Identifier', name: parts[i] }, + computed: false + }; + } + + // Build right side: __block_2['inputs.color'] or __block_2['x'] + const rightExpr = { + type: 'MemberExpression', + object: { type: 'Identifier', name: blockVar }, + property: { type: 'Literal', value: varPath }, + computed: true + }; + + statements.push({ + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: leftExpr, + right: rightExpr + } + }); } + // Replace the if statement with a block statement + node.type = 'BlockStatement'; + node.body = statements; + } else { + // No assignments, just replace with the call expression + node.type = 'ExpressionStatement'; + node.expression = callExpression; + } + delete node.test; + delete node.consequent; + delete node.alternate; + }, + UpdateExpression(node, _state, ancestors) { + if (ancestors.some(nodeIsUniform)) { return; } - // Convert to: var = var + 1 or var = var - 1 - const assignmentExpr = { - type: 'AssignmentExpression', - operator: '=', + // Transform ++var, var++, --var, var-- into assignment expressions + let operator; + if (node.operator === '++') { + operator = '+'; + } else if (node.operator === '--') { + operator = '-'; + } else { + return; // Unknown update operator + } + + // Convert to: var = var + 1 or var = var - 1 + const assignmentExpr = { + type: 'AssignmentExpression', + operator: '=', + left: node.argument, + right: { + type: 'BinaryExpression', + operator: operator, left: node.argument, right: { - type: 'BinaryExpression', - operator: operator, - left: node.argument, - right: { - type: 'Literal', - value: 1 - } + type: 'Literal', + value: 1 } - }; + } + }; - // Replace the update expression with the assignment expression - Object.assign(node, assignmentExpr); - delete node.prefix; - this.BinaryExpression(node.right, _state, [...ancestors, node]); - this.AssignmentExpression(node, _state, ancestors); - }, - ForStatement(node, _state, ancestors) { - if (ancestors.some(nodeIsUniform)) { return; } + // Replace the update expression with the assignment expression + Object.assign(node, assignmentExpr); + delete node.prefix; + this.BinaryExpression(node.right, _state, [...ancestors, node]); + this.AssignmentExpression(node, _state, ancestors); + }, + ForStatement(node, _state, ancestors) { + if (ancestors.some(nodeIsUniform)) { return; } + + // Transform for statement into strandsFor() call + // for (init; test; update) body -> strandsFor(initCb, conditionCb, updateCb, bodyCb, initialVars) - // Transform for statement into strandsFor() call - // for (init; test; update) body -> strandsFor(initCb, conditionCb, updateCb, bodyCb, initialVars) + // Generate unique loop variable name + const uniqueLoopVar = `loopVar${loopVarCounter++}`; - // Generate unique loop variable name - const uniqueLoopVar = `loopVar${loopVarCounter++}`; + // Create the initial callback from the for loop's init + let initialFunction; + if (node.init && node.init.type === 'VariableDeclaration') { + // Handle: for (let i = 0; ...) + const declaration = node.init.declarations[0]; + let initValue = declaration.init; - // Create the initial callback from the for loop's init - let initialFunction; - if (node.init && node.init.type === 'VariableDeclaration') { - // Handle: for (let i = 0; ...) - const declaration = node.init.declarations[0]; - let initValue = declaration.init; + const initAst = { type: 'Program', body: [{ type: 'ExpressionStatement', expression: initValue }] }; + initValue = initAst.body[0].expression; + + initialFunction = { + type: 'ArrowFunctionExpression', + params: [], + body: { + type: 'BlockStatement', + body: [{ + type: 'ReturnStatement', + argument: initValue + }] + } + }; + } else { + // Handle other cases - return a default value + initialFunction = { + type: 'ArrowFunctionExpression', + params: [], + body: { + type: 'BlockStatement', + body: [{ + type: 'ReturnStatement', + argument: { + type: 'Literal', + value: 0 + } + }] + } + }; + } - const initAst = { type: 'Program', body: [{ type: 'ExpressionStatement', expression: initValue }] }; - initValue = initAst.body[0].expression; + // Create the condition callback + let conditionBody = node.test || { type: 'Literal', value: true }; + // Replace loop variable references with the parameter + if (node.init?.type === 'VariableDeclaration') { + const loopVarName = node.init.declarations[0].id.name; + conditionBody = this.replaceIdentifierReferences(conditionBody, loopVarName, uniqueLoopVar); + } + const conditionAst = { type: 'Program', body: [{ type: 'ExpressionStatement', expression: conditionBody }] }; + conditionBody = conditionAst.body[0].expression; - initialFunction = { - type: 'ArrowFunctionExpression', - params: [], - body: { - type: 'BlockStatement', - body: [{ - type: 'ReturnStatement', - argument: initValue - }] - } - }; - } else { - // Handle other cases - return a default value - initialFunction = { - type: 'ArrowFunctionExpression', - params: [], - body: { - type: 'BlockStatement', - body: [{ - type: 'ReturnStatement', - argument: { - type: 'Literal', - value: 0 - } - }] - } - }; - } + const conditionFunction = { + type: 'ArrowFunctionExpression', + params: [{ type: 'Identifier', name: uniqueLoopVar }], + body: conditionBody + }; - // Create the condition callback - let conditionBody = node.test || { type: 'Literal', value: true }; + // Create the update callback + let updateFunction; + if (node.update) { + let updateExpr = node.update; // Replace loop variable references with the parameter if (node.init?.type === 'VariableDeclaration') { const loopVarName = node.init.declarations[0].id.name; - conditionBody = this.replaceIdentifierReferences(conditionBody, loopVarName, uniqueLoopVar); + updateExpr = this.replaceIdentifierReferences(updateExpr, loopVarName, uniqueLoopVar); } - const conditionAst = { type: 'Program', body: [{ type: 'ExpressionStatement', expression: conditionBody }] }; - conditionBody = conditionAst.body[0].expression; + const updateAst = { type: 'Program', body: [{ type: 'ExpressionStatement', expression: updateExpr }] }; + updateExpr = updateAst.body[0].expression; - const conditionFunction = { + updateFunction = { type: 'ArrowFunctionExpression', params: [{ type: 'Identifier', name: uniqueLoopVar }], - body: conditionBody + body: { + type: 'BlockStatement', + body: [{ + type: 'ReturnStatement', + argument: updateExpr + }] + } }; - - // Create the update callback - let updateFunction; - if (node.update) { - let updateExpr = node.update; - // Replace loop variable references with the parameter - if (node.init?.type === 'VariableDeclaration') { - const loopVarName = node.init.declarations[0].id.name; - updateExpr = this.replaceIdentifierReferences(updateExpr, loopVarName, uniqueLoopVar); + } else { + updateFunction = { + type: 'ArrowFunctionExpression', + params: [{ type: 'Identifier', name: uniqueLoopVar }], + body: { + type: 'BlockStatement', + body: [{ + type: 'ReturnStatement', + argument: { type: 'Identifier', name: uniqueLoopVar } + }] } - const updateAst = { type: 'Program', body: [{ type: 'ExpressionStatement', expression: updateExpr }] }; - updateExpr = updateAst.body[0].expression; + }; + } - updateFunction = { - type: 'ArrowFunctionExpression', - params: [{ type: 'Identifier', name: uniqueLoopVar }], - body: { - type: 'BlockStatement', - body: [{ - type: 'ReturnStatement', - argument: updateExpr - }] - } - }; - } else { - updateFunction = { - type: 'ArrowFunctionExpression', - params: [{ type: 'Identifier', name: uniqueLoopVar }], - body: { - type: 'BlockStatement', - body: [{ - type: 'ReturnStatement', - argument: { type: 'Identifier', name: uniqueLoopVar } - }] - } - }; - } + // Create the body callback + let bodyBlock = node.body.type === 'BlockStatement' ? node.body : { + type: 'BlockStatement', + body: [node.body] + }; - // Create the body callback - let bodyBlock = node.body.type === 'BlockStatement' ? node.body : { - type: 'BlockStatement', - body: [node.body] - }; + // Replace loop variable references in the body + if (node.init?.type === 'VariableDeclaration') { + const loopVarName = node.init.declarations[0].id.name; + bodyBlock = this.replaceIdentifierReferences(bodyBlock, loopVarName, uniqueLoopVar); + } - // Replace loop variable references in the body - if (node.init?.type === 'VariableDeclaration') { - const loopVarName = node.init.declarations[0].id.name; - bodyBlock = this.replaceIdentifierReferences(bodyBlock, loopVarName, uniqueLoopVar); - } + const bodyFunction = { + type: 'ArrowFunctionExpression', + params: [ + { type: 'Identifier', name: uniqueLoopVar }, + { type: 'Identifier', name: 'vars' } + ], + body: bodyBlock + }; - const bodyFunction = { - type: 'ArrowFunctionExpression', - params: [ - { type: 'Identifier', name: uniqueLoopVar }, - { type: 'Identifier', name: 'vars' } - ], - body: bodyBlock - }; + // Analyze which outer scope variables are assigned in the loop body + const assignedVars = new Set(); - // Analyze which outer scope variables are assigned in the loop body - const assignedVars = new Set(); + // First pass: collect all variable declarations in the body + const localVars = new Set(); + ancestor(bodyFunction.body, { + VariableDeclarator(node, ancestors) { + // Skip if we're inside a block that contains strands control flow + if (ancestors.some(statementContainsStrandsControlFlow)) return; + if (node.id.type === 'Identifier') { + localVars.add(node.id.name); + } + } + }); - // First pass: collect all variable declarations in the body - const localVars = new Set(); - ancestor(bodyFunction.body, { - VariableDeclarator(node, ancestors) { - // Skip if we're inside a block that contains strands control flow - if (ancestors.some(statementContainsStrandsControlFlow)) return; - if (node.id.type === 'Identifier') { - localVars.add(node.id.name); - } + // Second pass: find assignments to non-local variables using acorn-walk + ancestor(bodyFunction.body, { + AssignmentExpression(node, ancestors) { + // Skip if we're inside a block that contains strands control flow + if (ancestors.some(statementContainsStrandsControlFlow)) { + return } - }); - // Second pass: find assignments to non-local variables using acorn-walk - ancestor(bodyFunction.body, { - AssignmentExpression(node, ancestors) { - // Skip if we're inside a block that contains strands control flow - if (ancestors.some(statementContainsStrandsControlFlow)) { - return + const left = node.left; + if (left.type === 'Identifier') { + // Direct variable assignment: x = value + if (!localVars.has(left.name)) { + assignedVars.add(left.name); } - - const left = node.left; - if (left.type === 'Identifier') { - // Direct variable assignment: x = value - if (!localVars.has(left.name)) { - assignedVars.add(left.name); - } - } else if (left.type === 'MemberExpression') { - // Property assignment: obj.prop = value or obj.a.b = value - const propertyPath = buildPropertyPath(left); - if (propertyPath) { - const baseName = propertyPath.split('.')[0]; - if (!localVars.has(baseName)) { - assignedVars.add(propertyPath); - } + } else if (left.type === 'MemberExpression') { + // Property assignment: obj.prop = value or obj.a.b = value + const propertyPath = buildPropertyPath(left); + if (propertyPath) { + const baseName = propertyPath.split('.')[0]; + if (!localVars.has(baseName)) { + assignedVars.add(propertyPath); } } } - }); + } + }); - if (assignedVars.size > 0) { - // Add copying, reference replacement, and return statements similar to if statements - const addCopyingAndReturn = (functionBody, varsToReturn) => { - if (functionBody.type === 'BlockStatement') { - const tempVarMap = new Map(); - const copyStatements = []; - - for (const varPath of varsToReturn) { - const parts = varPath.split('.'); - const tempName = `__copy_${parts.join('_')}_${blockVarCounter++}`; - tempVarMap.set(varPath, tempName); - - // Build the member expression for vars.propertyPath - // e.g., vars.inputs.color or vars.x - let sourceExpr = { type: 'Identifier', name: 'vars' }; - for (const part of parts) { - sourceExpr = { - type: 'MemberExpression', - object: sourceExpr, - property: { type: 'Identifier', name: part }, - computed: false - }; - } + if (assignedVars.size > 0) { + // Add copying, reference replacement, and return statements similar to if statements + const addCopyingAndReturn = (functionBody, varsToReturn) => { + if (functionBody.type === 'BlockStatement') { + const tempVarMap = new Map(); + const copyStatements = []; - copyStatements.push({ - type: 'VariableDeclaration', - declarations: [{ - type: 'VariableDeclarator', - id: { type: 'Identifier', name: tempName }, - init: { - type: 'CallExpression', - callee: { - type: 'MemberExpression', - object: sourceExpr, - property: { type: 'Identifier', name: 'copy' }, - computed: false - }, - arguments: [] - } - }], - kind: 'let' - }); + for (const varPath of varsToReturn) { + const parts = varPath.split('.'); + const tempName = `__copy_${parts.join('_')}_${blockVarCounter++}`; + tempVarMap.set(varPath, tempName); + + // Build the member expression for vars.propertyPath + // e.g., vars.inputs.color or vars.x + let sourceExpr = { type: 'Identifier', name: 'vars' }; + for (const part of parts) { + sourceExpr = { + type: 'MemberExpression', + object: sourceExpr, + property: { type: 'Identifier', name: part }, + computed: false + }; } - functionBody.body.forEach(node => replaceReferences(node, tempVarMap)); - functionBody.body.unshift(...copyStatements); - - // Add return statement with flat object using property paths as keys - const returnObj = { - type: 'ObjectExpression', - properties: Array.from(varsToReturn).map(varPath => ({ - type: 'Property', - key: { type: 'Literal', value: varPath }, - value: { type: 'Identifier', name: tempVarMap.get(varPath) }, - kind: 'init', - computed: false, - shorthand: false - })) - }; - - functionBody.body.push({ - type: 'ReturnStatement', - argument: returnObj + copyStatements.push({ + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { type: 'Identifier', name: tempName }, + init: { + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: sourceExpr, + property: { type: 'Identifier', name: 'copy' }, + computed: false + }, + arguments: [] + } + }], + kind: 'let' }); } - }; - addCopyingAndReturn(bodyFunction.body, assignedVars); + functionBody.body.forEach(node => replaceReferences(node, tempVarMap)); + functionBody.body.unshift(...copyStatements); - // Create block variable and assignments similar to if statements - const blockVar = `__block_${blockVarCounter++}`; - const statements = []; - - const initialVarsObject = { - type: 'ObjectExpression', - properties: Array.from(assignedVars).map(varPath => { - const parts = varPath.split('.'); - let expr = { type: 'Identifier', name: parts[0] }; - for (let i = 1; i < parts.length; i++) { - expr = { - type: 'MemberExpression', - object: expr, - property: { type: 'Identifier', name: parts[i] }, - computed: false - }; - } - const wrappedExpr = { - type: 'CallExpression', - callee: { type: 'Identifier', name: '__p5.strandsNode' }, - arguments: [expr] - }; - return { + // Add return statement with flat object using property paths as keys + const returnObj = { + type: 'ObjectExpression', + properties: Array.from(varsToReturn).map(varPath => ({ type: 'Property', key: { type: 'Literal', value: varPath }, - value: wrappedExpr, + value: { type: 'Identifier', name: tempVarMap.get(varPath) }, kind: 'init', computed: false, shorthand: false - }; - }) - }; + })) + }; - // Create the strandsFor call - const callExpression = { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: '__p5.strandsFor' - }, - arguments: [initialFunction, conditionFunction, updateFunction, bodyFunction, initialVarsObject] - }; + functionBody.body.push({ + type: 'ReturnStatement', + argument: returnObj + }); + } + }; - statements.push({ - type: 'VariableDeclaration', - declarations: [{ - type: 'VariableDeclarator', - id: { type: 'Identifier', name: blockVar }, - init: callExpression - }], - kind: 'const' - }); + addCopyingAndReturn(bodyFunction.body, assignedVars); - // Add assignments back to original variables - for (const varPath of assignedVars) { - const parts = varPath.split('.'); + // Create block variable and assignments similar to if statements + const blockVar = `__block_${blockVarCounter++}`; + const statements = []; - // Build left side: inputs.color or just x - let leftExpr = { type: 'Identifier', name: parts[0] }; + const initialVarsObject = { + type: 'ObjectExpression', + properties: Array.from(assignedVars).map(varPath => { + const parts = varPath.split('.'); + let expr = { type: 'Identifier', name: parts[0] }; for (let i = 1; i < parts.length; i++) { - leftExpr = { + expr = { type: 'MemberExpression', - object: leftExpr, + object: expr, property: { type: 'Identifier', name: parts[i] }, computed: false }; } + const wrappedExpr = { + type: 'CallExpression', + callee: { type: 'Identifier', name: '__p5.strandsNode' }, + arguments: [expr] + }; + return { + type: 'Property', + key: { type: 'Literal', value: varPath }, + value: wrappedExpr, + kind: 'init', + computed: false, + shorthand: false + }; + }) + }; - // 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 - }; - } + // Create the strandsFor call + const callExpression = { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: '__p5.strandsFor' + }, + arguments: [initialFunction, conditionFunction, updateFunction, bodyFunction, initialVarsObject] + }; - statements.push({ - type: 'ExpressionStatement', - expression: { - type: 'AssignmentExpression', - operator: '=', - left: leftExpr, - right: rightExpr - } - }); + statements.push({ + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { type: 'Identifier', name: blockVar }, + init: callExpression + }], + kind: 'const' + }); + + // Add assignments back to original variables + for (const varPath of assignedVars) { + const parts = varPath.split('.'); + + // Build left side: inputs.color or just x + let leftExpr = { type: 'Identifier', name: parts[0] }; + for (let i = 1; i < parts.length; i++) { + leftExpr = { + type: 'MemberExpression', + object: leftExpr, + property: { type: 'Identifier', name: parts[i] }, + computed: false + }; } - node.type = 'BlockStatement'; - node.body = statements; - } else { - // No assignments, just replace with call expression - node.type = 'ExpressionStatement'; - node.expression = { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: '__p5.strandsFor' - }, - arguments: [initialFunction, conditionFunction, updateFunction, bodyFunction, { - type: 'ObjectExpression', - properties: [] - }] - }; + // 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 + }; + } + + statements.push({ + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: leftExpr, + right: rightExpr + } + }); } - delete node.init; - delete node.test; - delete node.update; - }, + node.type = 'BlockStatement'; + node.body = statements; + } else { + // No assignments, just replace with call expression + node.type = 'ExpressionStatement'; + node.expression = { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: '__p5.strandsFor' + }, + arguments: [initialFunction, conditionFunction, updateFunction, bodyFunction, { + type: 'ObjectExpression', + properties: [] + }] + }; + } - // Helper method to replace identifier references in AST nodes - replaceIdentifierReferences(node, oldName, newName) { - if (!node || typeof node !== 'object') return node; + delete node.init; + delete node.test; + delete node.update; + }, - const replaceInNode = (n) => { - if (!n || typeof n !== 'object') return n; + // Helper method to replace identifier references in AST nodes + replaceIdentifierReferences(node, oldName, newName) { + if (!node || typeof node !== 'object') return node; - if (n.type === 'Identifier' && n.name === oldName) { - return { ...n, name: newName }; - } + const replaceInNode = (n) => { + if (!n || typeof n !== 'object') return n; - // Create a copy and recursively process properties - const newNode = { ...n }; - for (const key in n) { - if (n.hasOwnProperty(key) && key !== 'parent') { - if (Array.isArray(n[key])) { - newNode[key] = n[key].map(replaceInNode); - } else if (typeof n[key] === 'object') { - newNode[key] = replaceInNode(n[key]); - } + if (n.type === 'Identifier' && n.name === oldName) { + return { ...n, name: newName }; + } + + // Create a copy and recursively process properties + const newNode = { ...n }; + for (const key in n) { + if (n.hasOwnProperty(key) && key !== 'parent') { + if (Array.isArray(n[key])) { + newNode[key] = n[key].map(replaceInNode); + } else if (typeof n[key] === 'object') { + newNode[key] = replaceInNode(n[key]); } } - return newNode; - }; + } + return newNode; + }; - return replaceInNode(node); - } + return replaceInNode(node); } +} - // Helper function to check if a function body contains return statements in control flow - function functionHasEarlyReturns(functionNode) { - let hasEarlyReturn = false; - let inControlFlow = 0; - - const checkForEarlyReturns = { - IfStatement(node, state, c) { - inControlFlow++; - if (node.test) c(node.test, state); - if (node.consequent) c(node.consequent, state); - if (node.alternate) c(node.alternate, state); - inControlFlow--; - }, - ForStatement(node, state, c) { - inControlFlow++; - if (node.init) c(node.init, state); - if (node.test) c(node.test, state); - if (node.update) c(node.update, state); - if (node.body) c(node.body, state); - inControlFlow--; - }, - ReturnStatement(node) { - if (inControlFlow > 0) { - hasEarlyReturn = true; - } +// Helper function to check if a function body contains return statements in control flow +function functionHasEarlyReturns(functionNode) { + let hasEarlyReturn = false; + let inControlFlow = 0; + + const checkForEarlyReturns = { + IfStatement(node, state, c) { + inControlFlow++; + if (node.test) c(node.test, state); + if (node.consequent) c(node.consequent, state); + if (node.alternate) c(node.alternate, state); + inControlFlow--; + }, + ForStatement(node, state, c) { + inControlFlow++; + if (node.init) c(node.init, state); + if (node.test) c(node.test, state); + if (node.update) c(node.update, state); + if (node.body) c(node.body, state); + inControlFlow--; + }, + ReturnStatement(node) { + if (inControlFlow > 0) { + hasEarlyReturn = true; } - }; - - if (functionNode.body && functionNode.body.type === 'BlockStatement') { - recursive(functionNode.body, {}, checkForEarlyReturns); } + }; - return hasEarlyReturn; + if (functionNode.body && functionNode.body.type === 'BlockStatement') { + recursive(functionNode.body, {}, checkForEarlyReturns); } - // Helper function to check if an if-statement's consequent contains a return - function blockContainsReturn(block) { - let hasReturn = false; - const findReturn = { - ReturnStatement() { - hasReturn = true; - } - }; - if (block) { - recursive(block, {}, findReturn); + return hasEarlyReturn; +} + +// Helper function to check if a block contains a return anywhere in it +function blockContainsReturn(block) { + let hasReturn = false; + const findReturn = { + ReturnStatement() { + hasReturn = true; } - return hasReturn; + }; + if (block) { + recursive(block, {}, findReturn); } + return hasReturn; +} - // Transform a helper function to use __returnValue pattern instead of early returns - function transformHelperFunction(functionNode) { - // 1. Add __returnValue declaration at the start of function body - const returnValueDecl = { - type: 'VariableDeclaration', - declarations: [{ - type: 'VariableDeclarator', - id: { type: 'Identifier', name: '__returnValue' }, - init: null - }], - kind: 'let' - }; +// Transform a helper function to use __returnValue pattern instead of early returns. +// This is necessary because we evaluate helper function *in javascript* rather than +// converting them to functions in GLSL (which is hard because we don't know the types +// of function parameters upfront, and they may change from use to use.) So they act +// like macros, all contributing to build up a single function overall. An early return +// in a helper should not be an early return of the entire hook function. Instead, we +// just make sure helper functions always evaluate to a single value. +function transformHelperFunction(functionNode) { + // 1. Add __returnValue declaration at the start of function body + const returnValueDecl = { + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { type: 'Identifier', name: '__returnValue' }, + init: null + }], + kind: 'let' + }; - if (!functionNode.body || functionNode.body.type !== 'BlockStatement') { - return; // Can't transform arrow functions with expression bodies - } + if (!functionNode.body || functionNode.body.type !== 'BlockStatement') { + return; // Can't transform arrow functions with expression bodies + } - functionNode.body.body.unshift(returnValueDecl); + functionNode.body.body.unshift(returnValueDecl); - // 2. Restructure if statements: move siblings after if with return into else block - function restructureIfStatements(statements) { - for (let i = 0; i < statements.length; i++) { - const stmt = statements[i]; + // 2. Restructure if statements: move siblings after if with return into else block + function restructureIfStatements(statements) { + for (let i = 0; i < statements.length; i++) { + const stmt = statements[i]; - if (stmt.type === 'IfStatement' && blockContainsReturn(stmt.consequent) && !stmt.alternate) { - // Find all subsequent statements - const subsequentStatements = statements.slice(i + 1); + if (stmt.type === 'IfStatement' && blockContainsReturn(stmt.consequent) && !stmt.alternate) { + // Find all subsequent statements + const subsequentStatements = statements.slice(i + 1); - if (subsequentStatements.length > 0) { - // Create else block with subsequent statements - stmt.alternate = { - type: 'BlockStatement', - body: subsequentStatements - }; + if (subsequentStatements.length > 0) { + // Create else block with subsequent statements + stmt.alternate = { + type: 'BlockStatement', + body: subsequentStatements + }; - // Remove the subsequent statements from this level - statements.splice(i + 1); + // Remove the subsequent statements from this level + statements.splice(i + 1); - // Recursively process the new else block - restructureIfStatements(stmt.alternate.body); - } + // Recursively process the new else block + restructureIfStatements(stmt.alternate.body); } + } - // Recursively process nested blocks - if (stmt.type === 'IfStatement') { - if (stmt.consequent && stmt.consequent.type === 'BlockStatement') { - restructureIfStatements(stmt.consequent.body); - } - if (stmt.alternate && stmt.alternate.type === 'BlockStatement') { - restructureIfStatements(stmt.alternate.body); - } - } else if (stmt.type === 'ForStatement' && stmt.body && stmt.body.type === 'BlockStatement') { - restructureIfStatements(stmt.body.body); - } else if (stmt.type === 'BlockStatement') { - restructureIfStatements(stmt.body); + // Recursively process nested blocks + if (stmt.type === 'IfStatement') { + if (stmt.consequent && stmt.consequent.type === 'BlockStatement') { + restructureIfStatements(stmt.consequent.body); + } + if (stmt.alternate && stmt.alternate.type === 'BlockStatement') { + restructureIfStatements(stmt.alternate.body); } + } else if (stmt.type === 'ForStatement' && stmt.body && stmt.body.type === 'BlockStatement') { + restructureIfStatements(stmt.body.body); + } else if (stmt.type === 'BlockStatement') { + restructureIfStatements(stmt.body); } } + } - restructureIfStatements(functionNode.body.body); - - // 3. Transform all return statements to assignments - const transformReturns = { - ReturnStatement(node) { - // Convert return statement to assignment - node.type = 'ExpressionStatement'; - node.expression = { - type: 'AssignmentExpression', - operator: '=', - left: { type: 'Identifier', name: '__returnValue' }, - right: node.argument || { type: 'Identifier', name: 'undefined' } - }; - delete node.argument; - } - }; + restructureIfStatements(functionNode.body.body); - recursive(functionNode.body, {}, transformReturns); + // 3. Transform all return statements to assignments + const transformReturns = { + ReturnStatement(node) { + // Convert return statement to assignment + node.type = 'ExpressionStatement'; + node.expression = { + type: 'AssignmentExpression', + operator: '=', + left: { type: 'Identifier', name: '__returnValue' }, + right: node.argument || { type: 'Identifier', name: 'undefined' } + }; + delete node.argument; + } + }; - // 4. Add final return statement - const finalReturn = { - type: 'ReturnStatement', - argument: { type: 'Identifier', name: '__returnValue' } - }; + recursive(functionNode.body, {}, transformReturns); - functionNode.body.body.push(finalReturn); - } + // 4. Add final return statement + const finalReturn = { + type: 'ReturnStatement', + argument: { type: 'Identifier', name: '__returnValue' } + }; - // Main transformation pass: find and transform helper functions with early returns - function transformHelperFunctionEarlyReturns(ast) { - const helperFunctionsToTransform = []; + functionNode.body.body.push(finalReturn); +} - // Collect helper functions that need transformation - const collectHelperFunctions = { - VariableDeclarator(node, ancestors) { - const init = node.init; - if (init && (init.type === 'ArrowFunctionExpression' || init.type === 'FunctionExpression')) { - if (functionHasEarlyReturns(init)) { - helperFunctionsToTransform.push(init); - } +// Main transformation pass: find and transform helper functions with early returns +function transformHelperFunctionEarlyReturns(ast) { + const helperFunctionsToTransform = []; + + // Collect helper functions that need transformation + const collectHelperFunctions = { + VariableDeclarator(node, ancestors) { + const init = node.init; + if (init && (init.type === 'ArrowFunctionExpression' || init.type === 'FunctionExpression')) { + if (functionHasEarlyReturns(init)) { + helperFunctionsToTransform.push(init); } - }, - FunctionDeclaration(node, ancestors) { - if (functionHasEarlyReturns(node)) { - helperFunctionsToTransform.push(node); - } - }, - // Don't transform functions that are direct arguments to call expressions - CallExpression(node, ancestors) { - // Arguments to CallExpressions are base callbacks, not helpers - // We skip them by not adding them to the transformation list } - }; + }, + FunctionDeclaration(node, ancestors) { + if (functionHasEarlyReturns(node)) { + helperFunctionsToTransform.push(node); + } + }, + // Don't transform functions that are direct arguments to call expressions + CallExpression(node, ancestors) { + // Arguments to CallExpressions are base callbacks, not helpers + // We skip them by not adding them to the transformation list + } + }; - ancestor(ast, collectHelperFunctions); + ancestor(ast, collectHelperFunctions); - // Transform each collected helper function - for (const funcNode of helperFunctionsToTransform) { - transformHelperFunction(funcNode); - } + // Transform each collected helper function + for (const funcNode of helperFunctionsToTransform) { + transformHelperFunction(funcNode); } +} - export function transpileStrandsToJS(p5, sourceString, srcLocations, scope) { - // Reset counters at the start of each transpilation - blockVarCounter = 0; - loopVarCounter = 0; - - const ast = parse(sourceString, { - ecmaVersion: 2021, - locations: srcLocations - }); - // First pass: transform everything except if/for statements using normal ancestor traversal - const nonControlFlowCallbacks = { ...ASTCallbacks }; - delete nonControlFlowCallbacks.IfStatement; - delete nonControlFlowCallbacks.ForStatement; - ancestor(ast, nonControlFlowCallbacks, undefined, { varyings: {} }); - - // Second pass: transform helper functions with early returns to use __returnValue pattern - transformHelperFunctionEarlyReturns(ast); - - // Third pass: transform if/for statements in post-order using recursive traversal - const postOrderControlFlowTransform = { - IfStatement(node, state, c) { - state.inControlFlow++; - // First recursively process children - if (node.test) c(node.test, state); - if (node.consequent) c(node.consequent, state); - if (node.alternate) c(node.alternate, state); - // Then apply the transformation to this node - ASTCallbacks.IfStatement(node, state, []); - state.inControlFlow--; - }, - ForStatement(node, state, c) { - state.inControlFlow++; - // First recursively process children - if (node.init) c(node.init, state); - if (node.test) c(node.test, state); - if (node.update) c(node.update, state); - if (node.body) c(node.body, state); - // Then apply the transformation to this node - ASTCallbacks.ForStatement(node, state, []); - state.inControlFlow--; - }, - ReturnStatement(node, state, c) { - if (!state.inControlFlow) return; - // Convert return statement to strandsEarlyReturn call - node.type = 'ExpressionStatement'; - node.expression = { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: '__p5.strandsEarlyReturn' - }, - arguments: node.argument ? [node.argument] : [] - }; - delete node.argument; - } - }; - recursive(ast, { varyings: {}, inControlFlow: 0 }, postOrderControlFlowTransform); - const transpiledSource = escodegen.generate(ast); - const scopeKeys = Object.keys(scope); - const match = /\(?\s*(?:function)?\s*\w*\s*\(([^)]*)\)\s*(?:=>)?\s*{((?:.|\n)*)}\s*;?\s*\)?/ - .exec(transpiledSource); - if (!match) { - console.log(transpiledSource); - throw new Error('Could not parse p5.strands function!'); - } - const params = match[1].split(/,\s*/).filter(param => !!param.trim()); - let paramVals, paramNames; - if (params.length > 0) { - paramNames = params; - paramVals = [scope]; - } else { - paramNames = scopeKeys; - paramVals = scopeKeys.map(key => scope[key]); - } - const body = match[2]; - try { - const internalStrandsCallback = new Function( - // Create a parameter called __p5, not just p5, because users of instance mode - // may pass in a variable called p5 as a scope variable. If we rely on a variable called - // p5, then the scope variable called p5 might accidentally override internal function - // calls to p5 static methods. - '__p5', - ...paramNames, - body, - ); - return () => internalStrandsCallback(p5, ...paramVals); - } catch (e) { - console.error(e); - console.log(paramNames); - console.log(body); - throw new Error('Error transpiling p5.strands callback!'); +export function transpileStrandsToJS(p5, sourceString, srcLocations, scope) { + // Reset counters at the start of each transpilation + blockVarCounter = 0; + loopVarCounter = 0; + + const ast = parse(sourceString, { + ecmaVersion: 2021, + locations: srcLocations + }); + // First pass: transform everything except if/for statements using normal ancestor traversal + const nonControlFlowCallbacks = { ...ASTCallbacks }; + delete nonControlFlowCallbacks.IfStatement; + delete nonControlFlowCallbacks.ForStatement; + ancestor(ast, nonControlFlowCallbacks, undefined, { varyings: {} }); + + // Second pass: transform helper functions with early returns to use __returnValue pattern + transformHelperFunctionEarlyReturns(ast); + + // Third pass: transform if/for statements in post-order using recursive traversal + const postOrderControlFlowTransform = { + IfStatement(node, state, c) { + state.inControlFlow++; + // First recursively process children + if (node.test) c(node.test, state); + if (node.consequent) c(node.consequent, state); + if (node.alternate) c(node.alternate, state); + // Then apply the transformation to this node + ASTCallbacks.IfStatement(node, state, []); + state.inControlFlow--; + }, + ForStatement(node, state, c) { + state.inControlFlow++; + // First recursively process children + if (node.init) c(node.init, state); + if (node.test) c(node.test, state); + if (node.update) c(node.update, state); + if (node.body) c(node.body, state); + // Then apply the transformation to this node + ASTCallbacks.ForStatement(node, state, []); + state.inControlFlow--; + }, + ReturnStatement(node, state, c) { + if (!state.inControlFlow) return; + // Convert return statement to strandsEarlyReturn call + node.type = 'ExpressionStatement'; + node.expression = { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: '__p5.strandsEarlyReturn' + }, + arguments: node.argument ? [node.argument] : [] + }; + delete node.argument; } + }; + recursive(ast, { varyings: {}, inControlFlow: 0 }, postOrderControlFlowTransform); + const transpiledSource = escodegen.generate(ast); + const scopeKeys = Object.keys(scope); + const match = /\(?\s*(?:function)?\s*\w*\s*\(([^)]*)\)\s*(?:=>)?\s*{((?:.|\n)*)}\s*;?\s*\)?/ + .exec(transpiledSource); + if (!match) { + console.log(transpiledSource); + throw new Error('Could not parse p5.strands function!'); + } + const params = match[1].split(/,\s*/).filter(param => !!param.trim()); + let paramVals, paramNames; + if (params.length > 0) { + paramNames = params; + paramVals = [scope]; + } else { + paramNames = scopeKeys; + paramVals = scopeKeys.map(key => scope[key]); + } + const body = match[2]; + try { + const internalStrandsCallback = new Function( + // Create a parameter called __p5, not just p5, because users of instance mode + // may pass in a variable called p5 as a scope variable. If we rely on a variable called + // p5, then the scope variable called p5 might accidentally override internal function + // calls to p5 static methods. + '__p5', + ...paramNames, + body, + ); + return () => internalStrandsCallback(p5, ...paramVals); + } catch (e) { + console.error(e); + console.log(paramNames); + console.log(body); + throw new Error('Error transpiling p5.strands callback!'); } +} From 5eb6f08f78cb30afc95b0b2e40b27819dc71eb65 Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Sat, 21 Feb 2026 18:06:27 -0500 Subject: [PATCH 4/4] Fix ts type generation --- docs/parameterData.json | 4292 ++++++++++++++++++++------------------- utils/typescript.mjs | 2 +- 2 files changed, 2159 insertions(+), 2135 deletions(-) diff --git a/docs/parameterData.json b/docs/parameterData.json index 567ba1b3ea..6cf76f3c4a 100644 --- a/docs/parameterData.json +++ b/docs/parameterData.json @@ -1,508 +1,594 @@ { - "p5": { - "describe": { + "p5.Image": { + "pixelDensity": { "overloads": [ [ - "String", - "FALLBACK|LABEL?" + "Number?" ] ] }, - "describeElement": { + "loadPixels": { "overloads": [ - [ - "String", - "String", - "FALLBACK|LABEL?" - ] + [] ] }, - "textOutput": { + "updatePixels": { "overloads": [ [ - "FALLBACK|LABEL?" + "Integer?", + "Integer?", + "Integer?", + "Integer?" ] ] }, - "gridOutput": { + "get": { "overloads": [ [ - "FALLBACK|LABEL?" + "Number", + "Number", + "Number", + "Number" + ], + [], + [ + "Number", + "Number" ] ] }, - "remove": { + "set": { "overloads": [ - [] + [ + "Number", + "Number", + "Number|Number[]|Object" + ] ] }, - "p5": { + "resize": { "overloads": [ [ - "Object", - "String|HTMLElement" + "Number", + "Number" ] ] }, - "color": { + "copy": { "overloads": [ [ - "Number", - "Number?" - ], - [ - "Number", - "Number", - "Number", - "Number?" - ], - [ - "String" - ], - [ - "Number[]" + "p5.Image|p5.Element", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer" ], [ - "p5.Color" + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer" ] ] }, - "red": { + "mask": { "overloads": [ [ - "p5.Color|Number[]|String" + "p5.Image" ] ] }, - "green": { + "filter": { "overloads": [ [ - "p5.Color|Number[]|String" + "THRESHOLD|GRAY|OPAQUE|INVERT|POSTERIZE|ERODE|DILATE|BLUR", + "Number?" ] ] }, - "blue": { + "blend": { "overloads": [ [ - "p5.Color|Number[]|String" + "p5.Image", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|NORMAL" + ], + [ + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|NORMAL" ] ] }, - "alpha": { + "save": { "overloads": [ [ - "p5.Color|Number[]|String" + "String", + "String?" ] ] }, - "hue": { + "reset": { "overloads": [ - [ - "p5.Color|Number[]|String" - ] + [] ] }, - "saturation": { + "getCurrentFrame": { + "overloads": [ + [] + ] + }, + "setFrame": { "overloads": [ [ - "p5.Color|Number[]|String" + "Number" ] ] }, - "brightness": { + "numFrames": { + "overloads": [ + [] + ] + }, + "play": { + "overloads": [ + [] + ] + }, + "pause": { + "overloads": [ + [] + ] + }, + "delay": { "overloads": [ [ - "p5.Color|Number[]|String" + "Number", + "Number?" ] ] - }, - "lightness": { + } + }, + "p5.Color": { + "toString": { "overloads": [ [ - "p5.Color|Number[]|String" + "String?" ] ] }, - "lerpColor": { + "contrast": { "overloads": [ [ - "p5.Color", - "p5.Color", - "Number" + "Color" ] ] }, - "paletteLerp": { + "setRed": { "overloads": [ [ - "[p5.Color|String|Number|Number[], Number][]", "Number" ] ] }, - "beginClip": { + "setGreen": { "overloads": [ [ - "Object?" + "Number" ] ] }, - "endClip": { + "setBlue": { "overloads": [ - [] + [ + "Number" + ] ] }, - "clip": { + "setAlpha": { "overloads": [ [ - "Function", - "Object?" + "Number" ] ] + } + }, + "p5": { + "remove": { + "overloads": [ + [] + ] }, - "background": { + "p5": { "overloads": [ [ - "p5.Color" - ], - [ - "String", - "Number?" - ], - [ - "Number", - "Number?" - ], - [ - "Number", - "Number", - "Number", - "Number?" - ], - [ - "Number[]" - ], - [ - "p5.Image", - "Number?" + "Object", + "String|HTMLElement" ] ] }, - "clear": { + "fromAxisAngle": { "overloads": [ [ "Number?", "Number?", "Number?", "Number?" - ], + ] + ] + }, + "day": { + "overloads": [ [] ] }, - "colorMode": { + "abs": { "overloads": [ [ - "RGB|HSB|HSL|RGBHDR|HWB|LAB|LCH|OKLAB|OKLCH", - "Number?" - ], + "Number" + ] + ] + }, + "mult": { + "overloads": [ [ - "RGB|HSB|HSL|RGBHDR|HWB|LAB|LCH|OKLAB|OKLCH", - "Number", - "Number", - "Number", - "Number?" - ], - [] + "p5.Quat?" + ] ] }, - "fill": { + "print": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number?" + "Any" ], [ - "String" - ], - [ - "Number", - "Number?" - ], - [ - "Number[]" - ], - [ - "p5.Color" + "String|Number|Array" ] ] }, - "noFill": { + "hour": { "overloads": [ [] ] }, - "noStroke": { + "randomSeed": { "overloads": [ - [] + [ + "Number" + ] ] }, - "stroke": { + "float": { "overloads": [ - [ - "Number", - "Number", - "Number", - "Number?" - ], [ "String" ], [ - "Number", - "Number?" - ], - [ - "Number[]" - ], - [ - "p5.Color" + "String[]" ] ] }, - "erase": { + "rotateBy": { "overloads": [ [ - "Number?", - "Number?" + "p5.Quat?" ] ] }, - "noErase": { + "ceil": { "overloads": [ - [] + [ + "Number" + ] ] }, - "blendMode": { + "ellipseMode": { "overloads": [ [ - "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|REMOVE|SUBTRACT" + "CENTER|RADIUS|CORNER|CORNERS" ] ] }, - "print": { + "nf": { "overloads": [ [ - "Any" + "Number|String", + "Integer|String?", + "Integer|String?" ], [ - "String|Number|Array" + "Number[]", + "Integer|String?", + "Integer|String?" ] ] }, - "cursor": { + "strokeMode": { "overloads": [ [ - "ARROW|CROSS|HAND|MOVE|TEXT|WAIT|String", - "Number?", - "Number?" + "String" ] ] }, - "frameRate": { + "select": { "overloads": [ [ - "Number" - ], - [] + "String", + "String|p5.Element|HTMLElement?" + ] ] }, - "getTargetFrameRate": { + "loadImage": { + "overloads": [ + [ + "String|Request", + "function(p5.Image)?", + "function(Event)?" + ] + ] + }, + "createVector": { + "overloads": [ + [ + "...Number[]" + ] + ] + }, + "minute": { "overloads": [ [] ] }, - "noCursor": { + "noLoop": { "overloads": [ [] ] }, - "windowResized": { + "describe": { "overloads": [ [ - "Event?" + "String", + "FALLBACK|LABEL?" ] ] }, - "fullscreen": { + "storeItem": { "overloads": [ [ - "Boolean?" + "String", + "String|Number|Boolean|Object|Array" ] ] }, - "pixelDensity": { + "createCanvas": { "overloads": [ [ - "Number?" + "Number?", + "Number?", + "P2D|WEBGL|P2DHDR|WEBGPU?", + "HTMLCanvasElement?" ], - [] - ] - }, - "displayDensity": { - "overloads": [ - [] + [ + "Number?", + "Number?", + "HTMLCanvasElement?" + ] ] }, - "getURL": { + "textOutput": { "overloads": [ - [] + [ + "FALLBACK|LABEL?" + ] ] }, - "getURLPath": { + "blend": { "overloads": [ - [] + [ + "p5.Image", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|NORMAL" + ], + [ + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|NORMAL" + ] ] }, - "getURLParams": { + "loadShader": { "overloads": [ - [] + [ + "String|Request", + "String|Request", + "Function?", + "Function?" + ] ] }, - "worldToScreen": { + "constrain": { "overloads": [ [ - "Number|p5.Vector", "Number", - "Number?" + "Number", + "Number" ] ] }, - "screenToWorld": { + "createImage": { "overloads": [ [ - "Number|p5.Vector", - "Number", - "Number?" + "Integer", + "Integer" ] ] }, - "setup": { + "acos": { "overloads": [ - [] + [ + "Number" + ] ] }, - "draw": { + "noSmooth": { "overloads": [ [] ] }, - "registerAddon": { + "orbitControl": { "overloads": [ [ - "Function" + "Number?", + "Number?", + "Number?", + "Object?" ] ] }, - "createCanvas": { + "beginClip": { "overloads": [ [ - "Number?", - "Number?", - "P2D|WEBGL|P2DHDR|WEBGPU?", - "HTMLCanvasElement?" - ], - [ - "Number?", - "Number?", - "HTMLCanvasElement?" + "Object?" ] ] }, - "resizeCanvas": { + "smoothstep": { "overloads": [ [ "Number", "Number", - "Boolean?" + "Number" ] ] }, - "noCanvas": { - "overloads": [ - [] - ] - }, - "createGraphics": { + "getTexture": { "overloads": [ [ - "Number", - "Number", - "P2D|WEBGL?", - "HTMLCanvasElement?" - ], - [ - "Number", - "Number", - "HTMLCanvasElement?" + null, + null ] ] }, - "createFramebuffer": { + "getWorldInputs": { "overloads": [ [ - "Object?" + "Function" ] ] }, - "clearDepth": { + "getPixelInputs": { "overloads": [ [ - "Number?" + "Function" ] ] }, - "noLoop": { + "getFinalColor": { "overloads": [ - [] + [ + "Function" + ] ] }, - "loop": { + "getColor": { "overloads": [ - [] + [ + "Function" + ] ] }, - "isLooping": { + "getObjectInputs": { "overloads": [ - [] + [ + "Function" + ] ] }, - "redraw": { + "getCameraInputs": { "overloads": [ [ - "Integer?" + "Function" ] ] }, - "applyMatrix": { + "ambientLight": { "overloads": [ - [ - "Number[]" - ], [ "Number", "Number", "Number", + "Number?" + ], + [ "Number", - "Number", - "Number" + "Number?" ], [ + "String" + ], + [ + "Number[]" + ], + [ + "p5.Color" + ] + ] + }, + "selectAll": { + "overloads": [ + [ + "String", + "String|p5.Element|HTMLElement?" + ] + ] + }, + "bezier": { + "overloads": [ + [ + "Number", + "Number", + "Number", "Number", "Number", "Number", "Number", + "Number" + ], + [ "Number", "Number", "Number", @@ -518,75 +604,132 @@ ] ] }, - "resetMatrix": { + "int": { + "overloads": [ + [ + "String|Boolean|Number" + ], + [ + "Array" + ] + ] + }, + "endClip": { "overloads": [ [] ] }, - "rotate": { + "copy": { "overloads": [ [ - "Number", - "p5.Vector|Number[]?" + "p5.Image|p5.Element", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer" + ], + [ + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer", + "Integer" ] ] }, - "rotateX": { + "loop": { "overloads": [ - [ - "Number" - ] + [] ] }, - "rotateY": { + "dist": { "overloads": [ [ + "Number", + "Number", + "Number", + "Number" + ], + [ + "Number", + "Number", + "Number", + "Number", + "Number", "Number" ] ] }, - "rotateZ": { + "asin": { "overloads": [ [ "Number" ] ] }, - "scale": { + "millis": { + "overloads": [ + [] + ] + }, + "nfc": { "overloads": [ [ - "Number|p5.Vector|Number[]", - "Number?", - "Number?" + "Number|String", + "Integer|String?" ], [ - "p5.Vector|Number[]" + "Number[]", + "Integer|String?" ] ] }, - "shearX": { + "applyMatrix": { "overloads": [ [ + "Number[]" + ], + [ + "Number", + "Number", + "Number", + "Number", + "Number", "Number" - ] - ] - }, - "shearY": { - "overloads": [ + ], [ + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", "Number" ] ] }, - "translate": { + "resizeCanvas": { "overloads": [ [ "Number", "Number", - "Number?" - ], - [ - "p5.Vector" + "Boolean?" ] ] }, @@ -595,127 +738,150 @@ [] ] }, - "pop": { + "noise": { "overloads": [ - [] + [ + "Number", + "Number?", + "Number?" + ] ] }, - "storeItem": { + "describeElement": { "overloads": [ [ "String", - "String|Number|Boolean|Object|Array" + "String", + "FALLBACK|LABEL?" ] ] }, - "getItem": { + "saveGif": { "overloads": [ [ - "String" + "String", + "Number", + "Object?" ] ] }, - "clearStorage": { + "month": { "overloads": [ [] ] }, - "removeItem": { + "random": { "overloads": [ [ - "String" + "Number?", + "Number?" + ], + [ + "Array" ] ] }, - "select": { + "isLooping": { + "overloads": [ + [] + ] + }, + "gridOutput": { "overloads": [ [ - "String", - "String|p5.Element|HTMLElement?" + "FALLBACK|LABEL?" ] ] }, - "selectAll": { + "saveCanvas": { "overloads": [ [ - "String", - "String|p5.Element|HTMLElement?" + "p5.Framebuffer|p5.Element|HTMLCanvasElement", + "String?", + "String?" + ], + [ + "String?", + "String?" ] ] }, - "createElement": { + "rectMode": { "overloads": [ [ - "String", - "String?" + "CENTER|RADIUS|CORNER|CORNERS" ] ] }, - "removeElements": { + "atan": { + "overloads": [ + [ + "Number" + ] + ] + }, + "noCanvas": { "overloads": [ [] ] }, - "addElement": { + "resetMatrix": { "overloads": [ [] ] }, - "createDiv": { + "getItem": { "overloads": [ [ - "String?" + "String" ] ] }, - "createP": { + "exp": { "overloads": [ [ - "String?" + "Number" ] ] }, - "createSpan": { + "second": { "overloads": [ - [ - "String?" - ] + [] ] }, - "createImg": { + "loadJSON": { "overloads": [ [ - "String", - "String" - ], - [ - "String", - "String", - "String?", + "String|Request", + "Function?", "Function?" ] ] }, - "createA": { + "arc": { "overloads": [ [ - "String", - "String", - "String?" + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "CHORD|PIE|OPEN?", + "Integer?" ] ] }, - "createSlider": { + "cursor": { "overloads": [ [ - "Number", - "Number", + "ARROW|CROSS|HAND|MOVE|TEXT|WAIT|String", "Number?", "Number?" ] ] }, - "createButton": { + "createElement": { "overloads": [ [ "String", @@ -723,278 +889,325 @@ ] ] }, - "createCheckbox": { + "year": { "overloads": [ - [ - "String?", - "Boolean?" - ] + [] ] }, - "createSelect": { + "floor": { "overloads": [ [ - "Boolean?" - ], - [ - "Object" + "Number" ] ] }, - "createRadio": { - "overloads": [ - [ - "Object?" - ], - [ - "String?" - ], - [] - ] - }, - "createColorPicker": { + "str": { "overloads": [ [ - "String|p5.Color?" + "String|Boolean|Number" ] ] }, - "createInput": { + "byte": { "overloads": [ [ - "String?", - "String?" + "String|Boolean|Number" ], [ - "String?" + "Array" ] ] }, - "createFileInput": { + "bezierPoint": { "overloads": [ [ - "Function", - "Boolean?" + "Number", + "Number", + "Number", + "Number", + "Number" ] ] }, - "createVideo": { + "buildGeometry": { "overloads": [ [ - "String|String[]?", - "Function?" + "Function" ] ] }, - "createAudio": { + "loadModel": { "overloads": [ [ - "String|String[]?", - "Function?" + "String|Request", + "String?", + "Boolean?", + "function(p5.Geometry)?", + "function(Event)?" + ], + [ + "String|Request", + "String?", + "function(p5.Geometry)?", + "function(Event)?" + ], + [ + "String|Request", + "Object?" ] ] }, - "createCapture": { + "randomGaussian": { "overloads": [ [ - "AUDIO|VIDEO|Object?", - "Object?", - "Function?" + "Number?", + "Number?" ] ] }, - "setMoveThreshold": { + "redraw": { "overloads": [ [ - "Number" + "Integer?" ] ] }, - "setShakeThreshold": { + "atan2": { "overloads": [ [ + "Number", "Number" ] ] }, - "deviceMoved": { + "smooth": { "overloads": [ [] ] }, - "deviceTurned": { + "clearStorage": { "overloads": [ [] ] }, - "deviceShaken": { + "nfp": { + "overloads": [ + [ + "Number", + "Integer?", + "Integer?" + ], + [ + "Number[]", + "Integer?", + "Integer?" + ] + ] + }, + "removeElements": { "overloads": [ [] ] }, - "keyPressed": { + "beginShape": { "overloads": [ [ - "KeyboardEvent?" + "POINTS|LINES|TRIANGLES|TRIANGLE_FAN|TRIANGLE_STRIP|QUADS|QUAD_STRIP|PATH?" ] ] }, - "keyReleased": { + "saveObj": { "overloads": [ [ - "KeyboardEvent?" + "String?" ] ] }, - "keyTyped": { + "addElement": { "overloads": [ - [ - "KeyboardEvent?" - ] + [] ] }, - "keyIsDown": { + "color": { "overloads": [ [ - "Number|String" + "Number", + "Number?" + ], + [ + "Number", + "Number", + "Number", + "Number?" + ], + [ + "String" + ], + [ + "Number[]" + ], + [ + "p5.Color" ] ] }, - "mouseMoved": { + "clip": { "overloads": [ [ - "MouseEvent?" + "Function", + "Object?" ] ] }, - "mouseDragged": { + "noiseDetail": { "overloads": [ [ - "MouseEvent?" + "Number", + "Number?" ] ] }, - "mousePressed": { + "createGraphics": { "overloads": [ [ - "MouseEvent?" + "Number", + "Number", + "P2D|WEBGL?", + "HTMLCanvasElement?" + ], + [ + "Number", + "Number", + "HTMLCanvasElement?" ] ] }, - "mouseReleased": { + "strokeCap": { "overloads": [ [ - "MouseEvent?" + "ROUND|SQUARE|PROJECT" ] ] }, - "mouseClicked": { + "lerp": { "overloads": [ [ - "MouseEvent?" + "Number", + "Number", + "Number" ] ] }, - "doubleClicked": { + "frameRate": { "overloads": [ [ - "MouseEvent?" - ] + "Number" + ], + [] ] }, - "mouseWheel": { + "cos": { "overloads": [ [ - "WheelEvent?" + "Number" ] ] }, - "requestPointerLock": { + "specularColor": { "overloads": [ - [] + [ + "Number", + "Number", + "Number" + ], + [ + "Number" + ], + [ + "String" + ], + [ + "Number[]" + ], + [ + "p5.Color" + ] ] }, - "exitPointerLock": { + "createDiv": { "overloads": [ - [] + [ + "String?" + ] ] }, - "createImage": { + "loadStrings": { "overloads": [ [ - "Integer", - "Integer" + "String|Request", + "Function?", + "Function?" ] ] }, - "saveCanvas": { + "boolean": { "overloads": [ [ - "p5.Framebuffer|p5.Element|HTMLCanvasElement", - "String?", - "String?" + "String|Boolean|Number" ], [ - "String?", - "String?" + "Array" ] ] }, - "saveFrames": { + "removeItem": { + "overloads": [ + [ + "String" + ] + ] + }, + "rotate": { "overloads": [ [ - "String", - "String", - "Number", "Number", - "function(Array)?" + "p5.Vector|Number[]?" ] ] }, - "loadImage": { + "freeGeometry": { "overloads": [ [ - "String|Request", - "function(p5.Image)?", - "function(Event)?" + "p5.Geometry" ] ] }, - "saveGif": { + "setMoveThreshold": { "overloads": [ [ - "String", - "Number", - "Object?" + "Number" ] ] }, - "image": { + "bezierTangent": { "overloads": [ [ - "p5.Image|p5.Element|p5.Texture|p5.Framebuffer|p5.FramebufferTexture|p5.Renderer|p5.Graphics", "Number", "Number", - "Number?", - "Number?" - ], - [ - "p5.Image|p5.Element|p5.Texture|p5.Framebuffer|p5.FramebufferTexture", - "Number", "Number", "Number", - "Number", - "Number", - "Number", - "Number?", - "Number?", - "CONTAIN|COVER?", - "LEFT|RIGHT|CENTER?", - "TOP|BOTTOM|CENTER?" + "Number" ] ] }, - "tint": { + "noiseSeed": { + "overloads": [ + [ + "Number" + ] + ] + }, + "ellipse": { "overloads": [ [ "Number", @@ -1002,337 +1215,269 @@ "Number", "Number?" ], - [ - "String" - ], [ "Number", - "Number?" - ], - [ - "Number[]" - ], - [ - "p5.Color" + "Number", + "Number", + "Number", + "Integer?" ] ] }, - "noTint": { + "log": { "overloads": [ - [] + [ + "Number" + ] ] }, - "imageMode": { + "createP": { "overloads": [ [ - "CORNER|CORNERS|CENTER" + "String?" ] ] }, - "blend": { + "createShader": { "overloads": [ [ - "p5.Image", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|NORMAL" - ], - [ - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|NORMAL" + "String", + "String", + "Object?" ] ] }, - "copy": { + "getTargetFrameRate": { + "overloads": [ + [] + ] + }, + "nfs": { "overloads": [ [ - "p5.Image|p5.Element", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer" + "Number", + "Integer?", + "Integer?" ], [ - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer" + "Array", + "Integer?", + "Integer?" ] ] }, - "filter": { + "setShakeThreshold": { "overloads": [ [ - "THRESHOLD|GRAY|OPAQUE|INVERT|POSTERIZE|BLUR|ERODE|DILATE|BLUR", - "Number?", - "Boolean?" - ], + "Number" + ] + ] + }, + "saveStl": { + "overloads": [ [ - "p5.Shader" + "String?", + "Object?" ] ] }, - "get": { + "sin": { "overloads": [ [ - "Number", - "Number", - "Number", "Number" - ], - [], + ] + ] + }, + "strokeJoin": { + "overloads": [ [ - "Number", - "Number" + "MITER|BEVEL|ROUND" ] ] }, - "loadPixels": { + "noCursor": { "overloads": [ [] ] }, - "set": { + "circle": { "overloads": [ [ "Number", "Number", - "Number|Number[]|Object" + "Number" ] ] }, - "updatePixels": { + "mag": { "overloads": [ [ - "Number?", - "Number?", - "Number?", - "Number?" - ], - [] + "Number", + "Number" + ] ] }, - "loadJSON": { + "loadTable": { "overloads": [ [ "String|Request", + "String?", + "String?", "Function?", "Function?" ] ] }, - "loadStrings": { + "red": { "overloads": [ [ - "String|Request", - "Function?", - "Function?" + "p5.Color|Number[]|String" ] ] }, - "loadTable": { + "filter": { "overloads": [ [ - "String|Request", - "String?", - "String?", - "Function?", - "Function?" + "THRESHOLD|GRAY|OPAQUE|INVERT|POSTERIZE|BLUR|ERODE|DILATE|BLUR", + "Number?", + "Boolean?" + ], + [ + "p5.Shader" ] ] }, - "loadXML": { + "tan": { "overloads": [ [ - "String|Request", - "Function?", - "Function?" + "Number" ] ] }, - "loadBytes": { + "createSpan": { "overloads": [ [ - "String|Request", - "Function?", - "Function?" + "String?" ] ] }, - "loadBlob": { + "loadFilterShader": { "overloads": [ [ - "String|Request", + "String", "Function?", "Function?" ] ] }, - "httpGet": { + "plane": { "overloads": [ [ - "String|Request", - "String?", - "Function?", - "Function?" - ], - [ - "String|Request", - "Function", - "Function?" + "Number?", + "Number?", + "Integer?", + "Integer?" ] ] }, - "httpPost": { + "createFramebuffer": { "overloads": [ [ - "String|Request", - "Object|Boolean?", - "String?", - "Function?", - "Function?" - ], - [ - "String|Request", - "Object|Boolean", - "Function?", - "Function?" - ], - [ - "String|Request", - "Function?", - "Function?" + "Object?" ] ] }, - "httpDo": { + "strokeWeight": { "overloads": [ [ - "String|Request", - "String?", - "String?", - "Object?", - "Function?", - "Function?" - ], - [ - "String|Request", - "Function?", - "Function?" + "Number" ] ] }, - "createWriter": { + "degrees": { "overloads": [ [ - "String", - "String?" + "Number" ] ] }, - "write": { + "rotateX": { "overloads": [ [ - "String|Number|Array" + "Number" ] ] }, - "close": { + "setup": { "overloads": [ [] ] }, - "save": { + "draw": { + "overloads": [ + [] + ] + }, + "registerAddon": { "overloads": [ [ - "Object|String?", - "String?", - "Boolean|String?" + "Function" ] ] }, - "saveJSON": { + "map": { "overloads": [ [ - "Array|Object", - "String", + "Number", + "Number", + "Number", + "Number", + "Number", "Boolean?" ] ] }, - "saveStrings": { + "createImg": { "overloads": [ [ - "String[]", + "String", + "String" + ], + [ + "String", "String", "String?", - "Boolean?" + "Function?" ] ] }, - "saveTable": { + "radians": { "overloads": [ [ - "p5.Table", - "String", - "String?" + "Number" ] ] }, - "setContent": { + "deviceMoved": { "overloads": [ - [ - "String" - ] + [] ] }, - "abs": { + "deviceTurned": { "overloads": [ - [ - "Number" - ] + [] ] }, - "ceil": { + "deviceShaken": { "overloads": [ - [ - "Number" - ] + [] ] }, - "constrain": { + "directionalLight": { "overloads": [ [ "Number", "Number", - "Number" - ] - ] - }, - "dist": { - "overloads": [ - [ "Number", "Number", "Number", @@ -1342,74 +1487,78 @@ "Number", "Number", "Number", + "p5.Vector" + ], + [ + "p5.Color|Number[]|String", "Number", "Number", "Number" - ] - ] - }, - "exp": { - "overloads": [ + ], [ - "Number" + "p5.Color|Number[]|String", + "p5.Vector" ] ] }, - "floor": { + "background": { "overloads": [ [ - "Number" - ] - ] - }, - "lerp": { - "overloads": [ + "p5.Color" + ], + [ + "String", + "Number?" + ], + [ + "Number", + "Number?" + ], [ "Number", "Number", - "Number" + "Number", + "Number?" + ], + [ + "Number[]" + ], + [ + "p5.Image", + "Number?" ] ] }, - "log": { + "clearDepth": { "overloads": [ [ - "Number" + "Number?" ] ] }, - "mag": { + "splitTokens": { "overloads": [ [ - "Number", - "Number" + "String", + "String?" ] ] }, - "map": { + "keyPressed": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Boolean?" + "KeyboardEvent?" ] ] }, - "max": { + "green": { "overloads": [ [ - "Number", - "Number" - ], - [ - "Number[]" + "p5.Color|Number[]|String" ] ] }, - "min": { + "max": { "overloads": [ [ "Number", @@ -1420,173 +1569,247 @@ ] ] }, - "norm": { + "bezierVertex": { "overloads": [ [ "Number", "Number", - "Number" - ] - ] - }, - "pow": { - "overloads": [ + "Number?", + "Number?" + ], [ "Number", - "Number" - ] - ] - }, - "round": { - "overloads": [ - [ "Number", + "Number", + "Number?", "Number?" ] ] }, - "sq": { + "createA": { "overloads": [ [ - "Number" + "String", + "String", + "String?" ] ] }, - "sqrt": { + "saveFrames": { "overloads": [ [ - "Number" + "String", + "String", + "Number", + "Number", + "function(Array)?" ] ] }, - "fract": { + "line": { "overloads": [ [ + "Number", + "Number", + "Number", + "Number" + ], + [ + "Number", + "Number", + "Number", + "Number", + "Number", "Number" ] ] }, - "createVector": { + "clear": { "overloads": [ [ - "...Number[]" - ] + "Number?", + "Number?", + "Number?", + "Number?" + ], + [] ] }, - "noise": { + "box": { "overloads": [ [ - "Number", "Number?", - "Number?" + "Number?", + "Number?", + "Integer?", + "Integer?" ] ] }, - "noiseDetail": { + "char": { "overloads": [ [ - "Number" + "String|Number" ], [ - "Number", - "Number" - ] - ] -}, - "noiseSeed": { - "overloads": [ - [ - "Number" + "Array" ] ] }, - "randomSeed": { + "rotateY": { "overloads": [ [ "Number" ] ] }, - "random": { + "debugMode": { "overloads": [ + [], + [ + "GRID|AXES" + ], [ + "GRID|AXES", + "Number?", + "Number?", + "Number?", "Number?", "Number?" ], [ - "Array" - ] - ] - }, - "randomGaussian": { - "overloads": [ + "GRID|AXES", + "Number?", + "Number?", + "Number?", + "Number?" + ], [ + "Number?", + "Number?", + "Number?", + "Number?", + "Number?", + "Number?", + "Number?", "Number?", "Number?" ] ] }, - "acos": { + "roll": { "overloads": [ [ "Number" ] ] }, - "asin": { + "spline": { "overloads": [ [ + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", "Number" - ] - ] - }, - "atan": { - "overloads": [ + ], [ + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", "Number" ] ] }, - "atan2": { + "loadXML": { + "overloads": [ + [ + "String|Request", + "Function?", + "Function?" + ] + ] + }, + "get": { "overloads": [ + [ + "Number", + "Number", + "Number", + "Number" + ], + [], [ "Number", "Number" ] ] }, - "cos": { + "min": { "overloads": [ [ + "Number", "Number" + ], + [ + "Number[]" ] ] }, - "sin": { + "windowResized": { "overloads": [ [ - "Number" + "Event?" ] ] }, - "tan": { + "shuffle": { "overloads": [ [ - "Number" + "Array", + "Boolean?" ] ] }, - "degrees": { + "loadBytes": { "overloads": [ [ - "Number" + "String|Request", + "Function?", + "Function?" ] ] }, - "radians": { + "noDebugMode": { + "overloads": [ + [] + ] + }, + "blue": { "overloads": [ [ - "Number" + "p5.Color|Number[]|String" + ] + ] + }, + "unchar": { + "overloads": [ + [ + "String" + ], + [ + "String[]" ] ] }, @@ -1598,77 +1821,90 @@ [] ] }, - "arc": { + "loadPixels": { + "overloads": [ + [] + ] + }, + "buildFilterShader": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "CHORD|PIE|OPEN?", - "Integer?" + "Function", + "Object?" + ], + [ + "Object", + "Object?" ] ] }, - "ellipse": { + "createSlider": { "overloads": [ [ "Number", "Number", - "Number", + "Number?", "Number?" - ], + ] + ] + }, + "norm": { + "overloads": [ [ "Number", "Number", - "Number", - "Number", + "Number" + ] + ] + }, + "sphere": { + "overloads": [ + [ + "Number?", + "Integer?", "Integer?" ] ] }, - "circle": { + "keyReleased": { "overloads": [ [ - "Number", - "Number", - "Number" + "KeyboardEvent?" ] ] }, - "line": { + "rotateZ": { "overloads": [ [ - "Number", - "Number", - "Number", "Number" - ], + ] + ] + }, + "loadBlob": { + "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Number" + "String|Request", + "Function?", + "Function?" ] ] }, - "point": { + "pow": { "overloads": [ [ "Number", - "Number", - "Number?" - ], + "Number" + ] + ] + }, + "fullscreen": { + "overloads": [ [ - "p5.Vector" + "Boolean?" ] ] }, - "quad": { + "pointLight": { "overloads": [ [ "Number", @@ -1676,142 +1912,100 @@ "Number", "Number", "Number", - "Number", - "Number", - "Number", - "Integer?", - "Integer?" + "Number" ], [ "Number", "Number", "Number", + "p5.Vector" + ], + [ + "p5.Color|Number[]|String", "Number", "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Integer?", - "Integer?" + "Number" + ], + [ + "p5.Color|Number[]|String", + "p5.Vector" ] ] }, - "rect": { + "point": { "overloads": [ [ "Number", "Number", - "Number", - "Number?", - "Number?", - "Number?", - "Number?", "Number?" ], [ - "Number", - "Number", - "Number", - "Number", - "Integer?", - "Integer?" + "p5.Vector" ] ] }, - "square": { + "alpha": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number?", - "Number?", - "Number?", - "Number?" + "p5.Color|Number[]|String" ] ] }, - "triangle": { + "createButton": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Number" + "String", + "String?" ] ] }, - "ellipseMode": { + "createFilterShader": { "overloads": [ [ - "CENTER|RADIUS|CORNER|CORNERS" + "String" ] ] }, - "noSmooth": { - "overloads": [ - [] - ] - }, - "rectMode": { + "endShape": { "overloads": [ [ - "CENTER|RADIUS|CORNER|CORNERS" + "CLOSE?", + "Integer?" ] ] }, - "smooth": { - "overloads": [ - [] - ] - }, - "strokeCap": { + "set": { "overloads": [ [ - "ROUND|SQUARE|PROJECT" + "Number", + "Number", + "Number|Number[]|Object" ] ] }, - "strokeJoin": { + "round": { "overloads": [ [ - "MITER|BEVEL|ROUND" + "Number", + "Number?" ] ] }, - "strokeWeight": { + "hex": { "overloads": [ [ - "Number" + "Number", + "Number?" + ], + [ + "Number[]", + "Number?" ] ] }, - "bezier": { + "splinePoint": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number" - ], - [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", "Number", "Number", "Number", @@ -1820,1112 +2014,1009 @@ ] ] }, - "bezierPoint": { + "httpGet": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number" + "String|Request", + "String?", + "Function?", + "Function?" + ], + [ + "String|Request", + "Function", + "Function?" ] ] }, - "bezierTangent": { + "pixelDensity": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number" - ] + "Number?" + ], + [] ] }, - "spline": { + "imageLight": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number" - ], - [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number" + "p5.Image" ] ] }, - "splinePoint": { + "updatePixels": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number" - ] + "Number?", + "Number?", + "Number?", + "Number?" + ], + [] ] }, - "splineTangent": { + "sq": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", "Number" ] ] }, - "bezierOrder": { + "displayDensity": { "overloads": [ - [ - "Number" - ], [] ] }, - "splineVertex": { + "panorama": { "overloads": [ [ - "Number", - "Number" - ], - [ - "Number", - "Number", - "Number?" - ], - [ - "Number", - "Number", - "Number?", - "Number?" - ], - [ - "Number", - "Number", - "Number", - "Number?", - "Number?" + "p5.Image" ] ] }, - "splineProperty": { + "createCheckbox": { "overloads": [ [ - "String", - null - ], - [ - "String" + "String?", + "Boolean?" ] ] }, - "splineProperties": { + "keyTyped": { "overloads": [ [ - "Object" + "KeyboardEvent?" ] ] }, - "vertex": { + "hue": { "overloads": [ [ - "Number", - "Number" - ], + "p5.Color|Number[]|String" + ] + ] + }, + "scale": { + "overloads": [ [ - "Number", - "Number", + "Number|p5.Vector|Number[]", "Number?", "Number?" ], [ - "Number", - "Number", - "Number", - "Number?", - "Number?" + "p5.Vector|Number[]" ] ] }, - "beginContour": { - "overloads": [ - [] - ] - }, - "endContour": { + "httpPost": { "overloads": [ [ - "OPEN|CLOSE?" + "String|Request", + "Object|Boolean?", + "String?", + "Function?", + "Function?" + ], + [ + "String|Request", + "Object|Boolean", + "Function?", + "Function?" + ], + [ + "String|Request", + "Function?", + "Function?" ] ] }, - "beginShape": { + "unhex": { "overloads": [ [ - "POINTS|LINES|TRIANGLES|TRIANGLE_FAN|TRIANGLE_STRIP|QUADS|QUAD_STRIP|PATH?" + "String" + ], + [ + "String[]" ] ] }, - "bezierVertex": { + "quad": { "overloads": [ [ "Number", "Number", - "Number?", - "Number?" + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Integer?", + "Integer?" ], [ "Number", "Number", "Number", - "Number?", - "Number?" - ] - ] - }, - "endShape": { - "overloads": [ - [ - "CLOSE?", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Integer?", "Integer?" ] ] }, - "normal": { + "sqrt": { "overloads": [ [ - "p5.Vector" - ], - [ - "Number", - "Number", "Number" ] ] }, - "vertexProperty": { + "cylinder": { "overloads": [ [ - "String", - "Number|Number[]" + "Number?", + "Number?", + "Integer?", + "Integer?", + "Boolean?", + "Boolean?" ] ] }, - "getWorldInputs": { + "getURL": { "overloads": [ - [ - "Function" - ] + [] ] }, - "getPixelInputs": { + "lights": { "overloads": [ - [ - "Function" - ] + [] ] }, - "getFinalColor": { + "fract": { "overloads": [ [ - "Function" + "Number" ] ] }, - "getColor": { + "getURLPath": { "overloads": [ - [ - "Function" - ] + [] ] }, - "getObjectInputs": { + "splineTangent": { "overloads": [ [ - "Function" + "Number", + "Number", + "Number", + "Number", + "Number" ] ] }, - "getCameraInputs": { + "normal": { "overloads": [ [ - "Function" + "p5.Vector" + ], + [ + "Number", + "Number", + "Number" ] ] }, - "loadFont": { + "image": { "overloads": [ [ - "String", - "String?", - "Object?", - "Function?", - "Function?" + "p5.Image|p5.Element|p5.Texture|p5.Framebuffer|p5.FramebufferTexture|p5.Renderer|p5.Graphics", + "Number", + "Number", + "Number?", + "Number?" ], [ - "String", - "Function?", - "Function?" + "p5.Image|p5.Element|p5.Texture|p5.Framebuffer|p5.FramebufferTexture", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number?", + "Number?", + "CONTAIN|COVER?", + "LEFT|RIGHT|CENTER?", + "TOP|BOTTOM|CENTER?" ] ] }, - "text": { + "getURLParams": { + "overloads": [ + [] + ] + }, + "colorMode": { "overloads": [ [ - "String|Object|Array|Number|Boolean", + "RGB|HSB|HSL|RGBHDR|HWB|LAB|LCH|OKLAB|OKLCH", + "Number?" + ], + [ + "RGB|HSB|HSL|RGBHDR|HWB|LAB|LCH|OKLAB|OKLCH", + "Number", "Number", "Number", - "Number?", "Number?" - ] + ], + [] ] }, - "textAlign": { + "shearX": { "overloads": [ [ - "LEFT|CENTER|RIGHT?", - "TOP|BOTTOM|CENTER|BASELINE?" + "Number" ] ] }, - "textAscent": { + "lightFalloff": { "overloads": [ [ - "String?" + "Number", + "Number", + "Number" ] ] }, - "textDescent": { + "mouseMoved": { "overloads": [ [ - "String?" + "MouseEvent?" ] ] }, - "textLeading": { + "mouseDragged": { "overloads": [ [ - "Number?" + "MouseEvent?" ] ] }, - "textFont": { + "keyIsDown": { "overloads": [ [ - "p5.Font|String|Object?", - "Number?" + "Number|String" ] ] }, - "textSize": { + "shader": { "overloads": [ [ - "Number" - ], - [] + "p5.Shader" + ] ] }, - "textStyle": { + "model": { "overloads": [ [ - "NORMAL|ITALIC|BOLD|BOLDITALIC" - ], - [] + "p5.Geometry", + "Number?" + ] ] }, - "textWidth": { + "setContent": { "overloads": [ [ "String" ] ] }, - "textWrap": { + "httpDo": { "overloads": [ [ - "WORD|CHAR" + "String|Request", + "String?", + "String?", + "Object?", + "Function?", + "Function?" ], - [] + [ + "String|Request", + "Function?", + "Function?" + ] ] }, - "textBounds": { + "rect": { "overloads": [ [ - "String", + "Number", "Number", "Number", "Number?", + "Number?", + "Number?", + "Number?", "Number?" + ], + [ + "Number", + "Number", + "Number", + "Number", + "Integer?", + "Integer?" ] ] }, - "textDirection": { + "shearY": { "overloads": [ [ - "String" - ], - [] + "Number" + ] ] }, - "textProperty": { + "saturation": { "overloads": [ [ - "String", - null - ], - [ - "String" + "p5.Color|Number[]|String" ] ] }, - "textProperties": { + "createSelect": { "overloads": [ [ - "Object" + "Boolean?" ], - [] + [ + "Object" + ] ] }, - "fontBounds": { + "worldToScreen": { "overloads": [ [ - "String", - "Number", + "Number|p5.Vector", "Number", - "Number?", "Number?" ] ] }, - "fontWidth": { + "cone": { "overloads": [ [ - "String" + "Number?", + "Number?", + "Integer?", + "Integer?", + "Boolean?" ] ] }, - "fontAscent": { - "overloads": [ - [] - ] - }, - "fontDescent": { - "overloads": [ - [] - ] - }, - "textWeight": { + "createModel": { "overloads": [ [ - "Number" + "String", + "String?", + "Boolean?", + "function(p5.Geometry)?", + "function(Event)?" ], - [] - ] - }, - "float": { - "overloads": [ [ - "String" + "String", + "String?", + "function(p5.Geometry)?", + "function(Event)?" ], [ - "String[]" + "String", + "String?", + "Object?" ] ] }, - "int": { + "vertexProperty": { "overloads": [ [ - "String|Boolean|Number" - ], - [ - "Array" + "String", + "Number|Number[]" ] ] }, - "str": { + "square": { "overloads": [ [ - "String|Boolean|Number" + "Number", + "Number", + "Number", + "Number?", + "Number?", + "Number?", + "Number?" ] ] }, - "boolean": { + "screenToWorld": { "overloads": [ [ - "String|Boolean|Number" - ], - [ - "Array" + "Number|p5.Vector", + "Number", + "Number?" ] ] }, - "byte": { + "mousePressed": { "overloads": [ [ - "String|Boolean|Number" - ], - [ - "Array" + "MouseEvent?" ] ] }, - "char": { + "strokeShader": { "overloads": [ [ - "String|Number" - ], - [ - "Array" + "p5.Shader" ] ] }, - "unchar": { + "tint": { "overloads": [ [ - "String" + "Number", + "Number", + "Number", + "Number?" ], [ - "String[]" - ] - ] - }, - "hex": { - "overloads": [ + "String" + ], [ "Number", "Number?" ], [ - "Number[]", - "Number?" + "Number[]" + ], + [ + "p5.Color" ] ] }, - "unhex": { + "brightness": { "overloads": [ [ - "String" - ], - [ - "String[]" + "p5.Color|Number[]|String" ] ] }, - "day": { + "createWriter": { "overloads": [ - [] + [ + "String", + "String?" + ] ] }, - "hour": { - "overloads": [ - [] - ] - }, - "minute": { - "overloads": [ - [] - ] - }, - "millis": { - "overloads": [ - [] - ] - }, - "month": { - "overloads": [ - [] - ] - }, - "second": { - "overloads": [ - [] - ] - }, - "year": { - "overloads": [ - [] - ] - }, - "nf": { + "spotLight": { "overloads": [ [ - "Number|String", - "Integer|String?", - "Integer|String?" + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number?", + "Number?" ], [ - "Number[]", - "Integer|String?", - "Integer|String?" - ] - ] - }, - "nfc": { - "overloads": [ + "p5.Color|Number[]|String", + "p5.Vector", + "p5.Vector", + "Number?", + "Number?" + ], [ - "Number|String", - "Integer|String?" + "Number", + "Number", + "Number", + "p5.Vector", + "p5.Vector", + "Number?", + "Number?" ], [ - "Number[]", - "Integer|String?" - ] - ] - }, - "nfp": { - "overloads": [ + "p5.Color|Number[]|String", + "Number", + "Number", + "Number", + "p5.Vector", + "Number?", + "Number?" + ], [ + "p5.Color|Number[]|String", + "p5.Vector", "Number", - "Integer?", - "Integer?" + "Number", + "Number", + "Number?", + "Number?" ], [ - "Number[]", - "Integer?", - "Integer?" - ] - ] - }, - "nfs": { - "overloads": [ + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "p5.Vector", + "Number?", + "Number?" + ], [ "Number", - "Integer?", - "Integer?" + "Number", + "Number", + "p5.Vector", + "Number", + "Number", + "Number", + "Number?", + "Number?" ], [ - "Array", - "Integer?", - "Integer?" + "p5.Color|Number[]|String", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number", + "Number?", + "Number?" ] ] }, - "splitTokens": { + "translate": { "overloads": [ [ - "String", - "String?" + "Number", + "Number", + "Number?" + ], + [ + "p5.Vector" ] ] }, - "shuffle": { + "noTint": { "overloads": [ - [ - "Array", - "Boolean?" - ] + [] ] }, - "strokeMode": { + "fill": { "overloads": [ + [ + "Number", + "Number", + "Number", + "Number?" + ], [ "String" - ] - ] - }, - "buildGeometry": { - "overloads": [ + ], [ - "Function" - ] - ] - }, - "freeGeometry": { - "overloads": [ + "Number", + "Number?" + ], [ - "p5.Geometry" + "Number[]" + ], + [ + "p5.Color" ] ] }, - "plane": { + "triangle": { "overloads": [ [ - "Number?", - "Number?", - "Integer?", - "Integer?" + "Number", + "Number", + "Number", + "Number", + "Number", + "Number" ] ] }, - "box": { + "text": { "overloads": [ [ + "String|Object|Array|Number|Boolean", + "Number", + "Number", "Number?", - "Number?", - "Number?", - "Integer?", - "Integer?" + "Number?" ] ] }, - "sphere": { + "textAlign": { "overloads": [ [ - "Number?", - "Integer?", - "Integer?" + "LEFT|CENTER|RIGHT?", + "TOP|BOTTOM|CENTER|BASELINE?" ] ] }, - "cylinder": { + "textAscent": { "overloads": [ [ - "Number?", - "Number?", - "Integer?", - "Integer?", - "Boolean?", - "Boolean?" + "String?" ] ] }, - "cone": { + "textDescent": { "overloads": [ [ - "Number?", - "Number?", - "Integer?", - "Integer?", - "Boolean?" + "String?" ] ] }, - "ellipsoid": { + "textLeading": { "overloads": [ [ - "Number?", - "Number?", - "Number?", - "Integer?", - "Integer?" + "Number?" ] ] }, - "torus": { + "textFont": { "overloads": [ [ - "Number?", - "Number?", - "Integer?", - "Integer?" + "p5.Font|String|Object?", + "Number?" ] ] }, - "curveDetail": { + "textSize": { "overloads": [ [ "Number" - ] + ], + [] ] }, - "orbitControl": { + "textStyle": { "overloads": [ [ - "Number?", - "Number?", - "Number?", - "Object?" - ] + "NORMAL|ITALIC|BOLD|BOLDITALIC" + ], + [] ] }, - "debugMode": { + "textWidth": { "overloads": [ - [], - [ - "GRID|AXES" - ], - [ - "GRID|AXES", - "Number?", - "Number?", - "Number?", - "Number?", - "Number?" - ], - [ - "GRID|AXES", - "Number?", - "Number?", - "Number?", - "Number?" - ], [ - "Number?", - "Number?", - "Number?", - "Number?", - "Number?", - "Number?", - "Number?", - "Number?", - "Number?" + "String" ] ] }, - "noDebugMode": { + "textWrap": { "overloads": [ + [ + "WORD|CHAR" + ], [] ] }, - "ambientLight": { + "textBounds": { "overloads": [ [ + "String", "Number", "Number", - "Number", - "Number?" - ], - [ - "Number", + "Number?", "Number?" - ], - [ - "String" - ], - [ - "Number[]" - ], - [ - "p5.Color" ] ] }, - "specularColor": { + "textDirection": { "overloads": [ - [ - "Number", - "Number", - "Number" - ], - [ - "Number" - ], [ "String" ], - [ - "Number[]" - ], - [ - "p5.Color" - ] + [] ] }, - "directionalLight": { + "textProperty": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Number" - ], - [ - "Number", - "Number", - "Number", - "p5.Vector" - ], - [ - "p5.Color|Number[]|String", - "Number", - "Number", - "Number" + "String", + null ], [ - "p5.Color|Number[]|String", - "p5.Vector" + "String" ] ] }, - "pointLight": { + "textProperties": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Number" - ], - [ - "Number", - "Number", - "Number", - "p5.Vector" - ], - [ - "p5.Color|Number[]|String", - "Number", - "Number", - "Number" + "Object" ], - [ - "p5.Color|Number[]|String", - "p5.Vector" - ] + [] ] }, - "imageLight": { + "fontBounds": { "overloads": [ [ - "p5.Image" + "String", + "Number", + "Number", + "Number?", + "Number?" ] ] }, - "panorama": { + "fontWidth": { "overloads": [ [ - "p5.Image" + "String" ] ] }, - "lights": { + "fontAscent": { "overloads": [ [] ] }, - "lightFalloff": { + "fontDescent": { "overloads": [ - [ - "Number", - "Number", - "Number" - ] + [] ] }, - "spotLight": { + "textWeight": { "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number?", - "Number?" - ], - [ - "p5.Color|Number[]|String", - "p5.Vector", - "p5.Vector", - "Number?", - "Number?" - ], - [ - "Number", - "Number", - "Number", - "p5.Vector", - "p5.Vector", - "Number?", - "Number?" - ], - [ - "p5.Color|Number[]|String", - "Number", - "Number", - "Number", - "p5.Vector", - "Number?", - "Number?" - ], - [ - "p5.Color|Number[]|String", - "p5.Vector", - "Number", - "Number", - "Number", - "Number?", - "Number?" + "Number" ], + [] + ] + }, + "ellipsoid": { + "overloads": [ [ - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", - "p5.Vector", "Number?", - "Number?" - ], - [ - "Number", - "Number", - "Number", - "p5.Vector", - "Number", - "Number", - "Number", "Number?", - "Number?" - ], - [ - "p5.Color|Number[]|String", - "Number", - "Number", - "Number", - "Number", - "Number", - "Number", "Number?", - "Number?" + "Integer?", + "Integer?" ] ] }, + "noFill": { + "overloads": [ + [] + ] + }, "noLights": { "overloads": [ [] ] }, - "loadModel": { + "write": { "overloads": [ [ - "String|Request", - "String?", - "Boolean?", - "function(p5.Geometry)?", - "function(Event)?" - ], + "String|Number|Array" + ] + ] + }, + "lightness": { + "overloads": [ [ - "String|Request", - "String?", - "function(p5.Geometry)?", - "function(Event)?" - ], + "p5.Color|Number[]|String" + ] + ] + }, + "imageMode": { + "overloads": [ [ - "String|Request", - "Object?" + "CORNER|CORNERS|CENTER" ] ] }, - "model": { + "mouseReleased": { "overloads": [ [ - "p5.Geometry", - "Number?" + "MouseEvent?" ] ] }, - "createModel": { + "imageShader": { "overloads": [ [ - "String", - "String?", - "Boolean?", - "function(p5.Geometry)?", - "function(Event)?" + "p5.Shader" + ] + ] + }, + "noStroke": { + "overloads": [ + [] + ] + }, + "createRadio": { + "overloads": [ + [ + "Object?" ], [ - "String", - "String?", - "function(p5.Geometry)?", - "function(Event)?" + "String?" ], + [] + ] + }, + "createVideo": { + "overloads": [ [ - "String", - "String?", - "Object?" + "String|String[]?", + "Function?" ] ] }, - "loadShader": { + "loadFont": { "overloads": [ [ - "String|Request", - "String|Request", + "String", + "String?", + "Object?", + "Function?", + "Function?" + ], + [ + "String", "Function?", "Function?" ] ] }, - "createShader": { + "lerpColor": { "overloads": [ [ - "String", - "String", - "Object?" + "p5.Color", + "p5.Color", + "Number" ] ] }, - "loadFilterShader": { + "createAudio": { "overloads": [ [ - "String", - "Function?", + "String|String[]?", "Function?" ] ] }, - "buildFilterShader": { + "paletteLerp": { "overloads": [ [ - "Function" - ], - [ - "Object" + "[p5.Color|String|Number|Number[], Number][]", + "Number" ] ] }, - "createFilterShader": { + "torus": { "overloads": [ [ - "String" + "Number?", + "Number?", + "Integer?", + "Integer?" ] ] }, - "shader": { + "close": { + "overloads": [ + [] + ] + }, + "mouseClicked": { "overloads": [ [ - "p5.Shader" + "MouseEvent?" ] ] }, - "strokeShader": { + "buildMaterialShader": { "overloads": [ [ - "p5.Shader" + "Function", + "Object?" + ], + [ + "Object", + "Object?" ] ] }, - "imageShader": { + "createCapture": { "overloads": [ [ - "p5.Shader" + "AUDIO|VIDEO|Object?", + "Object?", + "Function?" ] ] }, - "buildMaterialShader": { + "stroke": { "overloads": [ [ - "Function" + "Number", + "Number", + "Number", + "Number?" ], [ - "Object" + "String" + ], + [ + "Number", + "Number?" + ], + [ + "Number[]" + ], + [ + "p5.Color" + ] + ] + }, + "createColorPicker": { + "overloads": [ + [ + "String|p5.Color?" + ] + ] + }, + "save": { + "overloads": [ + [ + "Object|String?", + "String?", + "Boolean|String?" ] ] }, @@ -2938,75 +3029,102 @@ ] ] }, + "bezierOrder": { + "overloads": [ + [ + "Number" + ], + [] + ] + }, + "doubleClicked": { + "overloads": [ + [ + "MouseEvent?" + ] + ] + }, "baseMaterialShader": { "overloads": [ [] ] }, + "erase": { + "overloads": [ + [ + "Number?", + "Number?" + ] + ] + }, "baseFilterShader": { "overloads": [ [] ] }, - "buildNormalShader": { + "noErase": { + "overloads": [ + [] + ] + }, + "createInput": { "overloads": [ [ - "Function" + "String?", + "String?" ], [ - "Object" + "String?" ] ] }, - "loadNormalShader": { + "saveJSON": { "overloads": [ [ + "Array|Object", "String", - "Function?", - "Function?" + "Boolean?" ] ] }, - "baseNormalShader": { - "overloads": [ - [] - ] - }, - "buildColorShader": { + "buildNormalShader": { "overloads": [ [ - "Function" + "Function", + "Object?" ], [ - "Object" + "Object", + "Object?" ] ] }, - "loadColorShader": { + "mouseWheel": { "overloads": [ [ - "String", - "Function?", - "Function?" + "WheelEvent?" ] ] }, - "baseColorShader": { + "pop": { "overloads": [ [] ] }, - "buildStrokeShader": { + "createFileInput": { "overloads": [ [ - "Function" - ], - [ - "Object" + "Function", + "Boolean?" ] ] }, - "loadStrokeShader": { + "requestPointerLock": { + "overloads": [ + [] + ] + }, + "loadNormalShader": { "overloads": [ [ "String", @@ -3015,109 +3133,102 @@ ] ] }, - "baseStrokeShader": { + "baseNormalShader": { "overloads": [ [] ] }, - "resetShader": { + "exitPointerLock": { "overloads": [ [] ] }, - "texture": { + "saveStrings": { "overloads": [ [ - "p5.Image|p5.MediaElement|p5.Graphics|p5.Texture|p5.Framebuffer|p5.FramebufferTexture" + "String[]", + "String", + "String?", + "Boolean?" ] ] }, - "textureMode": { + "buildColorShader": { "overloads": [ [ - "IMAGE|NORMAL" - ] - ] - }, - "textureWrap": { - "overloads": [ + "Function", + "Object?" + ], [ - "CLAMP|REPEAT|MIRROR", - "CLAMP|REPEAT|MIRROR?" + "Object", + "Object?" ] ] }, - "normalMaterial": { - "overloads": [ - [] - ] - }, - "ambientMaterial": { + "splineVertex": { "overloads": [ [ "Number", - "Number", - "Number" - ], - [ "Number" ], - [ - "p5.Color|Number[]|String" - ] - ] - }, - "emissiveMaterial": { - "overloads": [ [ - "Number", "Number", "Number", "Number?" ], [ - "Number" - ], - [ - "p5.Color|Number[]|String" - ] - ] - }, - "specularMaterial": { - "overloads": [ - [ "Number", + "Number", + "Number?", "Number?" ], [ "Number", "Number", "Number", + "Number?", "Number?" - ], + ] + ] + }, + "saveTable": { + "overloads": [ [ - "p5.Color|Number[]|String" + "p5.Table", + "String", + "String?" ] ] }, - "shininess": { + "loadColorShader": { "overloads": [ [ - "Number" + "String", + "Function?", + "Function?" ] ] }, - "metalness": { + "baseColorShader": { + "overloads": [ + [] + ] + }, + "setAttributes": { "overloads": [ [ - "Number" + "String", + "Boolean" + ], + [ + "Object" ] ] }, - "roll": { + "blendMode": { "overloads": [ [ - "Number" + "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|REMOVE|SUBTRACT" ] ] }, @@ -3136,29 +3247,32 @@ ] ] }, - "perspective": { + "buildStrokeShader": { "overloads": [ [ - "Number?", - "Number?", - "Number?", - "Number?" + "Function", + "Object?" + ], + [ + "Object", + "Object?" ] ] }, - "linePerspective": { + "splineProperty": { "overloads": [ [ - "Boolean" + "String", + null ], - [] + [ + "String" + ] ] }, - "ortho": { + "perspective": { "overloads": [ [ - "Number?", - "Number?", "Number?", "Number?", "Number?", @@ -3166,140 +3280,202 @@ ] ] }, - "frustum": { + "loadStrokeShader": { "overloads": [ [ - "Number?", - "Number?", - "Number?", - "Number?", - "Number?", - "Number?" + "String", + "Function?", + "Function?" ] ] }, - "createCamera": { + "baseStrokeShader": { "overloads": [ [] ] }, - "setCamera": { + "splineProperties": { "overloads": [ [ - "p5.Camera" + "Object" ] ] }, - "saveObj": { + "linePerspective": { "overloads": [ [ - "String?" + "Boolean" + ], + [] + ] + }, + "resetShader": { + "overloads": [ + [] + ] + }, + "ortho": { + "overloads": [ + [ + "Number?", + "Number?", + "Number?", + "Number?", + "Number?", + "Number?" ] ] }, - "saveStl": { + "texture": { "overloads": [ [ - "String?", - "Object?" + "p5.Image|p5.MediaElement|p5.Graphics|p5.Texture|p5.Framebuffer|p5.FramebufferTexture" ] ] }, - "fromAxisAngle": { + "vertex": { "overloads": [ [ + "Number", + "Number" + ], + [ + "Number", + "Number", "Number?", - "Number?", + "Number?" + ], + [ + "Number", + "Number", + "Number", "Number?", "Number?" ] ] }, - "mult": { + "frustum": { "overloads": [ [ - "p5.Quat?" + "Number?", + "Number?", + "Number?", + "Number?", + "Number?", + "Number?" ] ] }, - "rotateBy": { + "curveDetail": { "overloads": [ [ - "p5.Quat?" + "Number" ] ] }, - "setAttributes": { + "createCamera": { + "overloads": [ + [] + ] + }, + "beginContour": { + "overloads": [ + [] + ] + }, + "textureMode": { "overloads": [ [ - "String", - "Boolean" - ], + "IMAGE|NORMAL" + ] + ] + }, + "setCamera": { + "overloads": [ [ - "Object" + "p5.Camera" ] ] - } - }, - "p5.Color": { - "toString": { + }, + "endContour": { "overloads": [ [ - "String?" + "OPEN|CLOSE?" ] ] }, - "contrast": { + "textureWrap": { "overloads": [ [ - "Color" + "CLAMP|REPEAT|MIRROR", + "CLAMP|REPEAT|MIRROR?" ] ] }, - "setRed": { + "normalMaterial": { + "overloads": [ + [] + ] + }, + "ambientMaterial": { "overloads": [ + [ + "Number", + "Number", + "Number" + ], [ "Number" + ], + [ + "p5.Color|Number[]|String" ] ] }, - "setGreen": { + "emissiveMaterial": { "overloads": [ + [ + "Number", + "Number", + "Number", + "Number?" + ], [ "Number" + ], + [ + "p5.Color|Number[]|String" ] ] }, - "setBlue": { + "specularMaterial": { "overloads": [ [ - "Number" + "Number", + "Number?" + ], + [ + "Number", + "Number", + "Number", + "Number?" + ], + [ + "p5.Color|Number[]|String" ] ] }, - "setAlpha": { + "shininess": { "overloads": [ [ "Number" ] ] - } - }, - "p5.Graphics": { - "reset": { - "overloads": [ - [] - ] - }, - "remove": { - "overloads": [ - [] - ] }, - "createFramebuffer": { + "metalness": { "overloads": [ [ - "Object?" + "Number" ] ] } @@ -3550,926 +3726,918 @@ ] } }, - "p5.MediaElement": { - "play": { + "p5.XML": { + "getParent": { "overloads": [ [] ] }, - "stop": { + "getName": { "overloads": [ [] ] }, - "pause": { + "setName": { "overloads": [ - [] + [ + "String" + ] ] }, - "loop": { + "hasChildren": { "overloads": [ [] ] }, - "noLoop": { + "listChildren": { "overloads": [ [] ] }, - "autoplay": { + "getChildren": { "overloads": [ [ - "Boolean?" + "String?" ] ] }, - "volume": { + "getChild": { "overloads": [ - [], [ - "Number" + "String|Integer" ] ] }, - "speed": { + "addChild": { "overloads": [ - [], [ - "Number" + "p5.XML" ] ] }, - "time": { + "removeChild": { "overloads": [ [ - "Number?" + "String|Integer" ] ] }, - "duration": { + "getAttributeCount": { "overloads": [ [] ] }, - "onended": { + "listAttributes": { + "overloads": [ + [] + ] + }, + "hasAttribute": { "overloads": [ [ - "Function" + "String" ] ] }, - "connect": { + "getNum": { "overloads": [ [ - "AudioNode|Object" + "String", + "Number?" ] ] }, - "disconnect": { + "getString": { "overloads": [ - [] + [ + "String", + "Number?" + ] ] }, - "showControls": { + "setAttribute": { "overloads": [ - [] + [ + "String", + "Number|String|Boolean" + ] ] }, - "hideControls": { + "getContent": { + "overloads": [ + [ + "String?" + ] + ] + }, + "serialize": { "overloads": [ [] ] + } + }, + "p5.TableRow": { + "set": { + "overloads": [ + [ + "String|Integer", + "String|Number" + ] + ] }, - "addCue": { + "setNum": { "overloads": [ [ - "Number", - "Function", - "Object?" + "String|Integer", + "Number|String" ] ] }, - "removeCue": { + "setString": { "overloads": [ [ - "Number" + "String|Integer", + "String|Number|Boolean|Object" ] ] }, - "clearCues": { + "get": { "overloads": [ - [] + [ + "String|Integer" + ] + ] + }, + "getNum": { + "overloads": [ + [ + "String|Integer" + ] + ] + }, + "getString": { + "overloads": [ + [ + "String|Integer" + ] ] } }, - "p5.Image": { - "pixelDensity": { + "p5.Vector": { + "getValue": { + "overloads": [ + [ + "Number" + ] + ] + }, + "setValue": { + "overloads": [ + [ + "Number", + "Number" + ] + ] + }, + "set": { "overloads": [ [ + "Number?", + "Number?", "Number?" + ], + [ + "p5.Vector|Number[]" ] ] }, - "loadPixels": { + "copy": { "overloads": [ [] ] }, - "updatePixels": { + "add": { "overloads": [ [ - "Integer?", - "Integer?", - "Integer?", - "Integer?" + "Number|Array", + "Number?", + "Number?" + ], + [ + "p5.Vector|Number[]" ] ] }, - "get": { + "rem": { "overloads": [ [ - "Number", "Number", "Number", "Number" ], - [], [ - "Number", - "Number" + "p5.Vector|Number[]" ] ] }, - "set": { + "sub": { "overloads": [ [ "Number", - "Number", - "Number|Number[]|Object" + "Number?", + "Number?" + ], + [ + "p5.Vector|Number[]" ] ] }, - "resize": { + "mult": { "overloads": [ [ - "Number", "Number" + ], + [ + "Number", + "Number", + "Number?" + ], + [ + "Number[]" + ], + [ + "p5.Vector" ] ] }, - "copy": { + "div": { "overloads": [ [ - "p5.Image|p5.Element", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer" + "Number" + ], + [ + "Number", + "Number", + "Number?" + ], + [ + "Number[]" ], [ - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer" + "p5.Vector" ] ] }, - "mask": { + "mag": { "overloads": [ - [ - "p5.Image" - ] + [] ] }, - "filter": { + "magSq": { "overloads": [ - [ - "THRESHOLD|GRAY|OPAQUE|INVERT|POSTERIZE|ERODE|DILATE|BLUR", - "Number?" - ] + [] ] }, - "blend": { + "dot": { "overloads": [ [ - "p5.Image", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|NORMAL" + "Number", + "Number?", + "Number?" ], [ - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "Integer", - "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|NORMAL" + "p5.Vector" ] ] }, - "save": { + "cross": { "overloads": [ [ - "String", - "String?" + "p5.Vector" ] ] }, - "reset": { + "dist": { "overloads": [ - [] + [ + "p5.Vector" + ] ] }, - "getCurrentFrame": { + "normalize": { "overloads": [ [] ] }, - "setFrame": { + "limit": { "overloads": [ [ "Number" ] ] }, - "numFrames": { - "overloads": [ - [] - ] - }, - "play": { + "setMag": { "overloads": [ - [] + [ + "Number" + ] ] }, - "pause": { + "heading": { "overloads": [ [] ] }, - "delay": { + "setHeading": { "overloads": [ [ - "Number", - "Number?" + "Number" ] ] - } - }, - "p5.Table": { - "addRow": { + }, + "rotate": { "overloads": [ [ - "p5.TableRow?" + "Number" ] ] }, - "removeRow": { + "angleBetween": { "overloads": [ [ - "Integer" + "p5.Vector" ] ] }, - "getRow": { + "lerp": { "overloads": [ [ - "Integer" + "Number", + "Number", + "Number", + "Number" + ], + [ + "p5.Vector", + "Number" ] ] }, - "getRows": { - "overloads": [ - [] - ] - }, - "findRow": { + "slerp": { "overloads": [ [ - "String", - "Integer|String" + "p5.Vector", + "Number" ] ] }, - "findRows": { + "reflect": { "overloads": [ [ - "String", - "Integer|String" + "p5.Vector" ] ] }, - "matchRow": { + "array": { "overloads": [ - [ - "String|RegExp", - "String|Integer" - ] + [] ] }, - "matchRows": { + "equals": { "overloads": [ [ - "String", - "String|Integer?" + "Number?", + "Number?", + "Number?" + ], + [ + "p5.Vector|Array" ] ] }, - "getColumn": { + "clampToZero": { "overloads": [ - [ - "String|Number" - ] + [] ] }, - "clearRows": { + "fromAngle": { "overloads": [ - [] + [ + "Number", + "Number?" + ] ] }, - "addColumn": { + "fromAngles": { "overloads": [ [ - "String?" + "Number", + "Number", + "Number?" ] ] }, - "getColumnCount": { + "random2D": { "overloads": [ [] ] }, - "getRowCount": { + "random3D": { "overloads": [ [] ] - }, - "removeTokens": { + } + }, + "p5.Font": { + "textToPaths": { "overloads": [ [ "String", - "String|Integer?" + "Number", + "Number", + "Number?", + "Number?" ] ] }, - "trim": { + "textToPoints": { "overloads": [ [ - "String|Integer?" + "String", + "Number", + "Number", + "Object?" ] ] }, - "removeColumn": { + "textToContours": { "overloads": [ [ - "String|Integer" + "String", + "Number", + "Number", + "Object?" ] ] }, - "set": { + "textToModel": { "overloads": [ [ - "Integer", - "String|Integer", - "String|Number" + "String", + "Number", + "Number", + "Number", + "Number", + "Object?" ] ] - }, - "setNum": { + } + }, + "p5.Shader": { + "version": { "overloads": [ - [ - "Integer", - "String|Integer", - "Number" - ] + [] ] }, - "setString": { + "inspectHooks": { "overloads": [ - [ - "Integer", - "String|Integer", - "String" - ] + [] ] }, - "get": { + "modify": { "overloads": [ [ - "Integer", - "String|Integer" + "Function", + "Object?" + ], + [ + "Object?" ] ] }, - "getNum": { + "copyToContext": { "overloads": [ [ - "Integer", - "String|Integer" + "p5|p5.Graphics" ] ] }, - "getString": { + "setUniform": { "overloads": [ [ - "Integer", - "String|Integer" + "String", + "Boolean|Number|Number[]|p5.Image|p5.Graphics|p5.MediaElement|p5.Texture" ] ] - }, - "getObject": { + } + }, + "p5.Table": { + "addRow": { "overloads": [ [ - "String?" + "p5.TableRow?" ] ] }, - "getArray": { - "overloads": [ - [] - ] - } - }, - "p5.TableRow": { - "set": { + "removeRow": { "overloads": [ - [ - "String|Integer", - "String|Number" + [ + "Integer" ] ] }, - "setNum": { + "getRow": { "overloads": [ [ - "String|Integer", - "Number|String" + "Integer" ] ] }, - "setString": { + "getRows": { + "overloads": [ + [] + ] + }, + "findRow": { "overloads": [ [ - "String|Integer", - "String|Number|Boolean|Object" + "String", + "Integer|String" ] ] }, - "get": { + "findRows": { "overloads": [ [ - "String|Integer" + "String", + "Integer|String" ] ] }, - "getNum": { + "matchRow": { "overloads": [ [ + "String|RegExp", "String|Integer" ] ] }, - "getString": { + "matchRows": { "overloads": [ [ - "String|Integer" + "String", + "String|Integer?" ] ] - } - }, - "p5.XML": { - "getParent": { + }, + "getColumn": { "overloads": [ - [] + [ + "String|Number" + ] ] }, - "getName": { + "clearRows": { "overloads": [ [] ] }, - "setName": { + "addColumn": { "overloads": [ [ - "String" + "String?" ] ] }, - "hasChildren": { + "getColumnCount": { "overloads": [ [] ] }, - "listChildren": { + "getRowCount": { "overloads": [ [] ] }, - "getChildren": { + "removeTokens": { "overloads": [ [ - "String?" + "String", + "String|Integer?" ] ] }, - "getChild": { + "trim": { "overloads": [ [ - "String|Integer" + "String|Integer?" ] ] }, - "addChild": { + "removeColumn": { "overloads": [ [ - "p5.XML" + "String|Integer" ] ] }, - "removeChild": { + "set": { "overloads": [ [ - "String|Integer" + "Integer", + "String|Integer", + "String|Number" ] ] }, - "getAttributeCount": { - "overloads": [ - [] - ] - }, - "listAttributes": { + "setNum": { "overloads": [ - [] + [ + "Integer", + "String|Integer", + "Number" + ] ] }, - "hasAttribute": { + "setString": { "overloads": [ [ + "Integer", + "String|Integer", "String" ] ] }, - "getNum": { + "get": { "overloads": [ [ - "String", - "Number?" + "Integer", + "String|Integer" ] ] }, - "getString": { + "getNum": { "overloads": [ [ - "String", - "Number?" + "Integer", + "String|Integer" ] ] }, - "setAttribute": { + "getString": { "overloads": [ [ - "String", - "Number|String|Boolean" + "Integer", + "String|Integer" ] ] }, - "getContent": { + "getObject": { "overloads": [ [ "String?" ] ] }, - "serialize": { + "getArray": { "overloads": [ [] ] } }, - "p5.Vector": { - "getValue": { + "p5.MediaElement": { + "play": { "overloads": [ - [ - "Number" - ] + [] ] }, - "setValue": { + "stop": { "overloads": [ - [ - "Number", - "Number" - ] + [] ] }, - "set": { + "pause": { "overloads": [ - [ - "Number?", - "Number?", - "Number?" - ], - [ - "p5.Vector|Number[]" - ] + [] ] }, - "copy": { + "loop": { "overloads": [ [] ] }, - "add": { + "noLoop": { "overloads": [ - [ - "Number|Array", - "Number?", - "Number?" - ], - [ - "p5.Vector|Number[]" - ] + [] ] }, - "rem": { + "autoplay": { "overloads": [ [ - "Number", - "Number", - "Number" - ], - [ - "p5.Vector|Number[]" + "Boolean?" ] ] }, - "sub": { + "volume": { "overloads": [ + [], [ - "Number", - "Number?", - "Number?" - ], - [ - "p5.Vector|Number[]" + "Number" ] ] }, - "mult": { + "speed": { "overloads": [ + [], [ "Number" - ], - [ - "Number", - "Number", - "Number?" - ], - [ - "Number[]" - ], - [ - "p5.Vector" ] ] }, - "div": { + "time": { "overloads": [ [ - "Number" - ], - [ - "Number", - "Number", "Number?" - ], - [ - "Number[]" - ], - [ - "p5.Vector" ] ] }, - "mag": { + "duration": { "overloads": [ [] ] }, - "magSq": { + "onended": { "overloads": [ - [] + [ + "Function" + ] ] }, - "dot": { + "connect": { "overloads": [ [ - "Number", - "Number?", - "Number?" - ], - [ - "p5.Vector" + "AudioNode|Object" ] ] }, - "cross": { + "disconnect": { "overloads": [ - [ - "p5.Vector" - ] + [] ] }, - "dist": { + "showControls": { "overloads": [ - [ - "p5.Vector" - ] + [] ] }, - "normalize": { + "hideControls": { "overloads": [ [] ] }, - "limit": { + "addCue": { "overloads": [ [ - "Number" + "Number", + "Function", + "Object?" ] ] }, - "setMag": { + "removeCue": { "overloads": [ [ "Number" ] ] }, - "heading": { + "clearCues": { "overloads": [ [] ] - }, - "setHeading": { + } + }, + "p5.Geometry": { + "calculateBoundingBox": { "overloads": [ - [ - "Number" - ] + [] ] }, - "rotate": { + "clearColors": { "overloads": [ - [ - "Number" - ] + [] ] }, - "angleBetween": { + "flipU": { "overloads": [ - [ - "p5.Vector" - ] + [] ] }, - "lerp": { + "computeFaces": { "overloads": [ - [ - "Number", - "Number", - "Number", - "Number" - ], - [ - "p5.Vector", - "Number" - ] + [] ] }, - "slerp": { + "computeNormals": { "overloads": [ [ - "p5.Vector", - "Number" + "FLAT|SMOOTH?", + "Object?" ] ] }, - "reflect": { + "makeEdgesFromFaces": { "overloads": [ - [ - "p5.Vector" - ] + [] ] }, - "array": { + "normalize": { "overloads": [ [] ] }, - "equals": { + "vertexProperty": { "overloads": [ [ - "Number?", - "Number?", + "String", + "Number|Number[]", "Number?" - ], - [ - "p5.Vector|Array" ] ] }, - "clampToZero": { + "flipV": { "overloads": [ [] ] - }, - "fromAngle": { + } + }, + "p5.Framebuffer": { + "resize": { "overloads": [ [ "Number", - "Number?" + "Number" ] ] }, - "fromAngles": { + "pixelDensity": { "overloads": [ [ - "Number", - "Number", "Number?" ] ] }, - "random2D": { + "autoSized": { + "overloads": [ + [ + "Boolean?" + ] + ] + }, + "createCamera": { "overloads": [ [] ] }, - "random3D": { + "remove": { "overloads": [ [] ] - } - }, - "p5.Font": { - "textToPaths": { + }, + "begin": { "overloads": [ - [ - "String", - "Number", - "Number", - "Number?", - "Number?" - ] + [] ] }, - "textToPoints": { + "end": { "overloads": [ - [ - "String", - "Number", - "Number", - "Object?" - ] + [] ] }, - "textToContours": { + "draw": { "overloads": [ [ - "String", - "Number", - "Number", - "Object?" + "Function" ] ] }, - "textToModel": { + "loadPixels": { + "overloads": [ + [] + ] + }, + "get": { "overloads": [ [ - "String", "Number", "Number", "Number", + "Number" + ], + [], + [ "Number", - "Object?" + "Number" ] ] } @@ -4582,30 +4750,8 @@ ] } }, - "p5.Framebuffer": { - "resize": { - "overloads": [ - [ - "Number", - "Number" - ] - ] - }, - "pixelDensity": { - "overloads": [ - [ - "Number?" - ] - ] - }, - "autoSized": { - "overloads": [ - [ - "Boolean?" - ] - ] - }, - "createCamera": { + "p5.Graphics": { + "reset": { "overloads": [ [] ] @@ -4615,134 +4761,12 @@ [] ] }, - "begin": { - "overloads": [ - [] - ] - }, - "end": { - "overloads": [ - [] - ] - }, - "draw": { - "overloads": [ - [ - "Function" - ] - ] - }, - "loadPixels": { - "overloads": [ - [] - ] - }, - "get": { - "overloads": [ - [ - "Number", - "Number", - "Number", - "Number" - ], - [], - [ - "Number", - "Number" - ] - ] - } - }, - "p5.Geometry": { - "calculateBoundingBox": { - "overloads": [ - [] - ] - }, - "clearColors": { - "overloads": [ - [] - ] - }, - "flipU": { - "overloads": [ - [] - ] - }, - "computeFaces": { - "overloads": [ - [] - ] - }, - "computeNormals": { - "overloads": [ - [ - "FLAT|SMOOTH?", - "Object?" - ] - ] - }, - "makeEdgesFromFaces": { - "overloads": [ - [] - ] - }, - "normalize": { - "overloads": [ - [] - ] - }, - "vertexProperty": { - "overloads": [ - [ - "String", - "Number|Number[]", - "Number?" - ] - ] - }, - "flipV": { - "overloads": [ - [] - ] - } - }, - "p5.Shader": { - "version": { - "overloads": [ - [] - ] - }, - "inspectHooks": { - "overloads": [ - [] - ] - }, - "modify": { + "createFramebuffer": { "overloads": [ - [ - "Function", - "Object?" - ], [ "Object?" ] ] - }, - "copyToContext": { - "overloads": [ - [ - "p5|p5.Graphics" - ] - ] - }, - "setUniform": { - "overloads": [ - [ - "String", - "Boolean|Number|Number[]|p5.Image|p5.Graphics|p5.MediaElement|p5.Texture" - ] - ] } } } \ No newline at end of file diff --git a/utils/typescript.mjs b/utils/typescript.mjs index d89ffd5653..88d5a93c21 100644 --- a/utils/typescript.mjs +++ b/utils/typescript.mjs @@ -103,7 +103,7 @@ function processStrandsFunctions() { // Add uniform functions: uniformFloat, uniformVec2, etc. const typeMethods = []; for (const type in DataType) { - if (type === 'defer') { + if (type === 'defer' || type === 'assign_on_use') { continue; }