| 441 | |
| 442 | // Global helper function for binding properties to window in global mode |
| 443 | function createBindGlobal(instance) { |
| 444 | return function bindGlobal(property) { |
| 445 | if (property === 'constructor') return; |
| 446 | |
| 447 | // Check if this property has a getter on the instance or prototype |
| 448 | const instanceDescriptor = Object.getOwnPropertyDescriptor( |
| 449 | instance, |
| 450 | property |
| 451 | ); |
| 452 | const prototypeDescriptor = Object.getOwnPropertyDescriptor( |
| 453 | p5.prototype, |
| 454 | property |
| 455 | ); |
| 456 | const hasGetter = (instanceDescriptor && instanceDescriptor.get) || |
| 457 | (prototypeDescriptor && prototypeDescriptor.get); |
| 458 | |
| 459 | // Only check if it's a function if it doesn't have a getter |
| 460 | // to avoid actually evaluating getters before things like the |
| 461 | // renderer are fully constructed |
| 462 | let isPrototypeFunction = false; |
| 463 | let isConstant = false; |
| 464 | let constantValue; |
| 465 | |
| 466 | if (!hasGetter) { |
| 467 | const prototypeValue = p5.prototype[property]; |
| 468 | isPrototypeFunction = typeof prototypeValue === 'function'; |
| 469 | |
| 470 | // Check if this is a true constant from the constants module |
| 471 | if (!isPrototypeFunction && constants[property] !== undefined) { |
| 472 | isConstant = true; |
| 473 | constantValue = prototypeValue; |
| 474 | } |
| 475 | } |
| 476 | |
| 477 | if (isPrototypeFunction) { |
| 478 | // For regular functions, cache the bound function |
| 479 | const boundFunction = p5.prototype[property].bind(instance); |
| 480 | Object.defineProperty(window, property, { |
| 481 | configurable: true, |
| 482 | enumerable: true, |
| 483 | value: boundFunction |
| 484 | }); |
| 485 | } else if (isConstant) { |
| 486 | // For constants, cache the value directly |
| 487 | Object.defineProperty(window, property, { |
| 488 | configurable: true, |
| 489 | enumerable: true, |
| 490 | value: constantValue |
| 491 | }); |
| 492 | } else if (hasGetter || !isPrototypeFunction) { |
| 493 | // For properties with getters or non-function properties, use lazy optimization |
| 494 | // On first access, determine the type and optimize subsequent accesses |
| 495 | let lastFunction = null; |
| 496 | let boundFunction = null; |
| 497 | let isFunction = null; // null = unknown, true = function, false = not function |
| 498 | |
| 499 | Object.defineProperty(window, property, { |
| 500 | configurable: true, |