From b9b22360e8e69b8437f60c1ad59abfeeb2c4f659 Mon Sep 17 00:00:00 2001 From: mawerb Date: Mon, 20 Jul 2026 09:32:35 +0300 Subject: [PATCH 1/9] generalize lerp() to N dimensions --- src/math/p5.Vector.js | 23 +++++++++++++++++------ test/unit/math/p5.Vector.js | 18 ++++++++++-------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index e7a90d4218..ec527c174e 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -2420,13 +2420,24 @@ class Vector { * @param {Number} amt * @chainable */ - lerp(x, y, z, amt) { - if (x instanceof Vector) { - return this.lerp(x.x, x.y, x.z, y); + lerp(...args) { + let amt = args.pop(); + let values; + + if (args[0] instanceof Vector) { + values = args[0].values; + } else if (Array.isArray(args[0])) { + values = args[0]; + } else { + values = args; + } + + const minDimension = prioritizeSmallerDimension(this.dimensions, values); + + for (let i = 0; i < minDimension; i++) { + this.values[i] += + (values[i] - this.values[i]) * amt; } - this.x += (x - this.x) * amt || 0; - this.y += (y - this.y) * amt || 0; - this.z += (z - this.z) * amt || 0; return this; } diff --git a/test/unit/math/p5.Vector.js b/test/unit/math/p5.Vector.js index df694d71a6..cb17b2fc9a 100644 --- a/test/unit/math/p5.Vector.js +++ b/test/unit/math/p5.Vector.js @@ -1488,10 +1488,11 @@ suite('p5.Vector', function () { }); suite('with p5.Vector', function() { - test('should call lerp with 4 arguments', function() { + test('should call lerp with 2 arguments', function() { + const v2 = new Vector(1,2,3) vi.spyOn(v, 'lerp'); - v.lerp(new Vector(1,2,3), 1); - expect(v.lerp).toHaveBeenCalledWith(1, 2, 3, 1); + v.lerp(v2, 1); + expect(v.lerp).toHaveBeenCalledWith(v2, 1); }); }); @@ -1517,11 +1518,12 @@ suite('p5.Vector', function () { }); suite('with no amt', function () { - test('should assume 0 amt', function () { - v.x = 0; - v.y = 0; - v.z = 0; - v.lerp(2, 2, 2); + test('should handle missing amt according to validation behavior', function () { + const target = new Vector(2, 2, 2); + + v.set(0, 0, 0); + v.lerp(target); + expect(v.x).to.eql(0); expect(v.y).to.eql(0); expect(v.z).to.eql(0); From 997089d41712c91cae9bdce6d70b309e07079867 Mon Sep 17 00:00:00 2001 From: mawerb Date: Mon, 20 Jul 2026 10:01:08 +0300 Subject: [PATCH 2/9] Updated function documentation to match new behaviour --- src/math/p5.Vector.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index ec527c174e..90778503ef 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -2314,7 +2314,7 @@ class Vector { } /** - * Calculates new `x`, `y`, and `z` components that are proportionally the + * Calculates new vector components that are proportionally the * same distance between two vectors. * * The `amt` parameter is the amount to interpolate between the old vector and @@ -2325,13 +2325,13 @@ class Vector { * returns a new p5.Vector object and doesn't change * the original. * - * @param {Number} x x component. - * @param {Number} y y component. - * @param {Number} z z component. - * @param {Number} amt amount of interpolation between 0.0 (old vector) - * and 1.0 (new vector). 0.5 is halfway between. + * + * @param {...Number} values target vector components + * @param {Number} amt amount of interpolation between 0.0 (old vector) + * and 1.0 (new vector). 0.5 is halfway between. * @chainable * + * * @example * // META:norender * function setup() { @@ -2415,6 +2415,11 @@ class Vector { * pop(); * } */ + /** + * @param {Number[]} arr array to lerp towards. + * @param {Number} amt + * @chainable + */ /** * @param {p5.Vector} v p5.Vector to lerp toward. * @param {Number} amt From 64bf39f2f7a0c0ae19f5fd7255a31d05899633b8 Mon Sep 17 00:00:00 2001 From: mawerb Date: Mon, 20 Jul 2026 10:01:37 +0300 Subject: [PATCH 3/9] Added unit test to handle case mentioned in issue ticket --- test/unit/math/p5.Vector.js | 57 ++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/test/unit/math/p5.Vector.js b/test/unit/math/p5.Vector.js index cb17b2fc9a..74ab622778 100644 --- a/test/unit/math/p5.Vector.js +++ b/test/unit/math/p5.Vector.js @@ -1489,7 +1489,7 @@ suite('p5.Vector', function () { suite('with p5.Vector', function() { test('should call lerp with 2 arguments', function() { - const v2 = new Vector(1,2,3) + const v2 = new Vector(1,2,3); vi.spyOn(v, 'lerp'); v.lerp(v2, 1); expect(v.lerp).toHaveBeenCalledWith(v2, 1); @@ -1517,6 +1517,32 @@ suite('p5.Vector', function () { }); }); + suite('with x, y, z, w, amt', function () { + beforeEach(function () { + v.x = 0; + v.y = 0; + v.z = 0; + v.values[3] = 0; + v.lerp(2, 2, 2, 2, 0.5); + }); + + test('should lerp x by amt', function () { + expect(v.x).to.eql(1); + }); + + test('should lerp y by amt', function () { + expect(v.y).to.eql(1); + }); + + test('should lerp z by amt', function () { + expect(v.z).to.eql(1); + }); + + test('should lerp w by amt', function () { + expect(v.values[3]).to.eql(1); + }); + }); + suite('with no amt', function () { test('should handle missing amt according to validation behavior', function () { const target = new Vector(2, 2, 2); @@ -1559,6 +1585,35 @@ suite('p5.Vector', function () { }); }); + suite('p5.Vector.lerp(v2, amt) on 4 dimensions', function () { + var res, v1, v2; + beforeEach(function () { + let v1 = new Vector(0, 1, 0, 1); + let v2 = new Vector(1, 0, 1, 0); + res = v1.lerp(v2, 0.5); + }); + + test('should not be undefined', function () { + expect(res).to.not.eql(undefined); + }); + + test('should be a p5.Vector', function () { + expect(res).to.be.an.instanceof(Vector); + }); + + test('should return neither v1 nor v2', function () { + expect(res).to.not.eql(v1); + expect(res).to.not.eql(v2); + }); + + test('should res to be [0.5, 0.5, 0.5, 0.5]', function () { + expect(res.values[0]).to.eql(0.5); + expect(res.values[1]).to.eql(0.5); + expect(res.values[2]).to.eql(0.5); + expect(res.values[3]).to.eql(0.5); + }); + }); + suite('v.slerp(w, amt)', function () { var w; beforeEach(function () { From e708de4b1b79032ae4e8506803585cd70db7677f Mon Sep 17 00:00:00 2001 From: mawerb Date: Mon, 20 Jul 2026 10:14:30 +0300 Subject: [PATCH 4/9] Added 4d example of lerp to function documentation --- src/math/p5.Vector.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index 90778503ef..4d1dc627c9 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -2374,6 +2374,20 @@ class Vector { * } * * @example + * // META:norender + * function setup() { + * // Create p5.Vector objects. + * let v0 = createVector(0, 1, 0, 1); + * let v1 = createVector(1, 0, 1, 0); + * + * // Interpolate. + * v0.lerp(v1, 0.5); + * + * // Prints "p5.Vector Object : [0.5, 0.5, 0.5, 0.5]" to the console. + * print(v1.toString()); + * } + * + * @example * function setup() { * createCanvas(100, 100); * From 30bd6ad8326636a4209179f9036608e384cfb11b Mon Sep 17 00:00:00 2001 From: mawerb Date: Mon, 20 Jul 2026 10:56:03 +0300 Subject: [PATCH 5/9] Modified _validatedVectorOperation to take in trailing arguments for lerp() --- src/math/p5.Vector.js | 19 ++------- src/math/patch-vector.js | 91 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 91 insertions(+), 19 deletions(-) diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index 4d1dc627c9..d774bd9ba7 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -2439,23 +2439,12 @@ class Vector { * @param {Number} amt * @chainable */ - lerp(...args) { - let amt = args.pop(); - let values; - - if (args[0] instanceof Vector) { - values = args[0].values; - } else if (Array.isArray(args[0])) { - values = args[0]; - } else { - values = args; - } - + lerp(values, amt) { const minDimension = prioritizeSmallerDimension(this.dimensions, values); + shrinkToDimension(this.values, minDimension); - for (let i = 0; i < minDimension; i++) { - this.values[i] += - (values[i] - this.values[i]) * amt; + for (let i = 0; i < this.values.length; i++) { + this.values[i] += (values[i] - this.values[i]) * amt; } return this; } diff --git a/src/math/patch-vector.js b/src/math/patch-vector.js index d2121101f5..879a8a00d4 100644 --- a/src/math/patch-vector.js +++ b/src/math/patch-vector.js @@ -25,17 +25,99 @@ export function _defaultEmptyVector(target){ /** * @private * @internal + * @param {Boolean} expectsSoloNumberArgument whether a single number scales + * every component (mult/div/rem) + * @param {Number} [trailingArgCount=0] number of trailing args to peel off + * before treating the rest as vector components (e.g. 1 for lerp's amt) + * @param {Number[]} [trailingDefaults] if provided, used when only component + * values are passed (no trailing args), e.g. `[0]` so `v.lerp(other)` uses amt 0 */ -export function _validatedVectorOperation(expectsSoloNumberArgument){ +export function _validatedVectorOperation( + expectsSoloNumberArgument, + trailingArgCount = 0, + trailingDefaults +){ return function(target){ return function (...args) { - if (args.length === 0) { + const trailing = []; + + if (trailingArgCount > 0) { + const onlyValues = + args.length === 1 && + (args[0] instanceof Vector || Array.isArray(args[0])); + + if (onlyValues && trailingDefaults) { + for (let i = 0; i < trailingDefaults.length; i++) { + trailing.push(trailingDefaults[i]); + } + } else if (args.length < trailingArgCount) { + if (trailingDefaults && args.length === 0) { + // No arguments? No action (same as other vector ops) + return this; + } + if (!this.friendlyErrorsDisabled()) { + this._friendlyError( + 'Requires valid arguments', + 'p5.Vector' + ); + } + return this; + } else { + for (let i = 0; i < trailingArgCount; i++) { + trailing.unshift(args.pop()); + } + + for (let i = 0; i < trailing.length; i++) { + const t = trailing[i]; + if (typeof t !== 'number' || !Number.isFinite(t)) { + if (!this.friendlyErrorsDisabled()) { + this._friendlyError( + 'Arguments contain non-finite numbers', + 'p5.Vector' + ); + } + return this; + } + } + + if (args.length === 0) { + if (!this.friendlyErrorsDisabled()) { + this._friendlyError( + 'Requires valid arguments', + 'p5.Vector' + ); + } + return this; + } + } + } else if (args.length === 0) { // No arguments? No action return this; - } else if (args[0] instanceof Vector) { + } + + if (args[0] instanceof Vector) { + // Do not allow extra args after a vector when trailing args are used + if (trailingArgCount > 0 && args.length > 1) { + if (!this.friendlyErrorsDisabled()) { + this._friendlyError( + 'Requires valid arguments', + 'p5.Vector' + ); + } + return this; + } // First argument is a vector? Make it an array args = args[0].values; } else if (Array.isArray(args[0])) { + if (trailingArgCount > 0 && args.length > 1) { + if (!this.friendlyErrorsDisabled()) { + this._friendlyError( + 'Requires valid arguments', + 'p5.Vector' + ); + } + return this; + } // First argument is an array? Great, keep it! args = args[0]; } else if (args.length === 1){ @@ -70,7 +152,7 @@ export function _validatedVectorOperation(expectsSoloNumberArgument){ } } - return target.call(this, args); + return target.call(this, args, ...trailing); }; }; } @@ -90,5 +172,6 @@ export default function vectorValidation(p5, fn, lifecycles){ p5.registerDecorator('p5.Vector.prototype.div', _validatedVectorOperation(true)); p5.registerDecorator('p5.Vector.prototype.add', _validatedVectorOperation(false)); p5.registerDecorator('p5.Vector.prototype.sub', _validatedVectorOperation(false)); + p5.registerDecorator('p5.Vector.prototype.lerp', _validatedVectorOperation(false, 1, [0])); } From 1eb935827b835096d4bd175bb9ff779d3b74d27a Mon Sep 17 00:00:00 2001 From: mawerb Date: Mon, 20 Jul 2026 15:51:56 +0300 Subject: [PATCH 6/9] Update tests to properly test edge cases mentioned in issue ticket for lerp() --- test/unit/math/p5.Vector.js | 152 +++++++++++++++++++++++++++--------- 1 file changed, 117 insertions(+), 35 deletions(-) diff --git a/test/unit/math/p5.Vector.js b/test/unit/math/p5.Vector.js index 74ab622778..61425fbbc6 100644 --- a/test/unit/math/p5.Vector.js +++ b/test/unit/math/p5.Vector.js @@ -1,7 +1,6 @@ import { default as vector, Vector } from '../../../src/math/p5.Vector.js'; import { default as math } from '../../../src/math/math.js'; import { _defaultEmptyVector, _validatedVectorOperation } from '../../../src/math/patch-vector.js'; -import { vi } from 'vitest'; suite('p5.Vector', function () { @@ -35,6 +34,10 @@ suite('p5.Vector', function () { Vector.prototype.mult = _validatedVectorOperation(true)(Vector.prototype.mult, options); Vector.prototype.rem = _validatedVectorOperation(true)(Vector.prototype.rem, options); Vector.prototype.div = _validatedVectorOperation(true)(Vector.prototype.div, options); + Vector.prototype.lerp = _validatedVectorOperation(false, 1, [0])( + Vector.prototype.lerp, + options + ); }); afterEach(function () {}); @@ -1066,6 +1069,14 @@ suite('p5.Vector', function () { assert.deepEqual(v3.rem(v2).values, [0, 2]); expect(v3.rem(v2).dimensions).to.eql(2); }); + + test('should be prioritized in lerp()', function () { + assert.deepEqual(v1.lerp(v2, 0.5).values, [1.5]); + expect(v1.dimensions).to.eql(1); + + assert.deepEqual(v3.lerp(v2, 0.5).values, [3, 4]); + expect(v3.dimensions).to.eql(2); + }); }); suite('dot', function () { @@ -1483,24 +1494,24 @@ suite('p5.Vector', function () { }); suite('lerp', function () { + beforeEach(function () { + v = new Vector(0, 0, 0); + }); + test('should return the same object', function () { expect(v.lerp()).to.eql(v); }); suite('with p5.Vector', function() { - test('should call lerp with 2 arguments', function() { - const v2 = new Vector(1,2,3); - vi.spyOn(v, 'lerp'); - v.lerp(v2, 1); - expect(v.lerp).toHaveBeenCalledWith(v2, 1); + test('should lerp toward the vector by amt', function() { + const v2 = new Vector(2, 2, 2); + v.lerp(v2, 0.5); + expect(v.values).to.eql([1, 1, 1]); }); }); suite('with x, y, z, amt', function () { beforeEach(function () { - v.x = 0; - v.y = 0; - v.z = 0; v.lerp(2, 2, 2, 0.5); }); @@ -1519,10 +1530,7 @@ suite('p5.Vector', function () { suite('with x, y, z, w, amt', function () { beforeEach(function () { - v.x = 0; - v.y = 0; - v.z = 0; - v.values[3] = 0; + v = new Vector(0, 0, 0, 0); v.lerp(2, 2, 2, 2, 0.5); }); @@ -1543,16 +1551,70 @@ suite('p5.Vector', function () { }); }); - suite('with no amt', function () { - test('should handle missing amt according to validation behavior', function () { - const target = new Vector(2, 2, 2); + suite('with array', function () { + test('should lerp toward array components by amt', function () { + v.lerp([2, 2, 2], 0.5); + expect(v.values).to.eql([1, 1, 1]); + }); + }); + + suite('with 2D numeric components', function () { + test('should treat the last argument as amt', function () { + v = new Vector(1, 1); + v.lerp(3, 3, 0.5); + expect(v.values).to.eql([2, 2]); + }); + }); + + suite('with amt outside 0 to 1', function () { + test('should extrapolate when amt is greater than 1', function () { + v.lerp(2, 2, 2, 2); + expect(v.values).to.eql([4, 4, 4]); + }); + test('should extrapolate when amt is less than 0', function () { + v.lerp(2, 2, 2, -1); + expect(v.values).to.eql([-2, -2, -2]); + }); + }); + + suite('with invalid arguments', function () { + test('should assume amt of 0 when only a vector is passed', function () { + const target = new Vector(2, 2, 2); + FESCalled = false; v.set(0, 0, 0); v.lerp(target); + expect(FESCalled).to.eql(false); + expect(v.values).to.eql([0, 0, 0]); + }); - expect(v.x).to.eql(0); - expect(v.y).to.eql(0); - expect(v.z).to.eql(0); + test('should assume amt of 0 when only an array is passed', function () { + FESCalled = false; + v.lerp([2, 2, 2]); + expect(FESCalled).to.eql(false); + expect(v.values).to.eql([0, 0, 0]); + }); + + test('should not change vector when amt is non-finite', function () { + FESCalled = false; + v.lerp(2, 2, 2, NaN); + expect(FESCalled).to.eql(true); + expect(v.values).to.eql([0, 0, 0]); + }); + + test('should not change vector when components are non-finite', function () { + FESCalled = false; + v.lerp(2, NaN, 2, 0.5); + expect(FESCalled).to.eql(true); + expect(v.values).to.eql([0, 0, 0]); + }); + + test('should not change vector with extra args after a vector', function () { + const target = new Vector(2, 2, 2); + FESCalled = false; + v.lerp(target, 1, 0.5); + expect(FESCalled).to.eql(true); + expect(v.values).to.eql([0, 0, 0]); }); }); }); @@ -1574,8 +1636,13 @@ suite('p5.Vector', function () { }); test('should return neither v1 nor v2', function () { - expect(res).to.not.eql(v1); - expect(res).to.not.eql(v2); + expect(res).to.not.equal(v1); + expect(res).to.not.equal(v2); + }); + + test('should not mutate v1 or v2', function () { + expect(v1.values).to.eql([0, 0, 0]); + expect(v2.values).to.eql([2, 2, 2]); }); test('should res to be [1, 1, 1]', function () { @@ -1585,32 +1652,47 @@ suite('p5.Vector', function () { }); }); - suite('p5.Vector.lerp(v2, amt) on 4 dimensions', function () { + suite('v.lerp(v2, amt) on 4 dimensions', function () { var res, v1, v2; beforeEach(function () { - let v1 = new Vector(0, 1, 0, 1); - let v2 = new Vector(1, 0, 1, 0); + v1 = new Vector(0, 1, 0, 1); + v2 = new Vector(1, 0, 1, 0); res = v1.lerp(v2, 0.5); }); - test('should not be undefined', function () { - expect(res).to.not.eql(undefined); + test('should return this', function () { + expect(res).to.equal(v1); }); - test('should be a p5.Vector', function () { - expect(res).to.be.an.instanceof(Vector); + test('should not mutate the argument vector', function () { + expect(v2.values).to.eql([1, 0, 1, 0]); + }); + + test('should lerp all components', function () { + expect(res.values).to.eql([0.5, 0.5, 0.5, 0.5]); + }); + }); + + suite('p5.Vector.lerp(v1, v2, amt) on 4 dimensions', function () { + var res, v1, v2; + beforeEach(function () { + v1 = new Vector(0, 1, 0, 1); + v2 = new Vector(1, 0, 1, 0); + res = Vector.lerp(v1, v2, 0.5); }); test('should return neither v1 nor v2', function () { - expect(res).to.not.eql(v1); - expect(res).to.not.eql(v2); + expect(res).to.not.equal(v1); + expect(res).to.not.equal(v2); + }); + + test('should not mutate v1 or v2', function () { + expect(v1.values).to.eql([0, 1, 0, 1]); + expect(v2.values).to.eql([1, 0, 1, 0]); }); - test('should res to be [0.5, 0.5, 0.5, 0.5]', function () { - expect(res.values[0]).to.eql(0.5); - expect(res.values[1]).to.eql(0.5); - expect(res.values[2]).to.eql(0.5); - expect(res.values[3]).to.eql(0.5); + test('should lerp all components', function () { + expect(res.values).to.eql([0.5, 0.5, 0.5, 0.5]); }); }); From 14246f29b5b136c6208271c6a93355a69eb7245c Mon Sep 17 00:00:00 2001 From: mawerb Date: Mon, 20 Jul 2026 15:52:05 +0300 Subject: [PATCH 7/9] updated documentation to match new structure of lerp() --- src/math/p5.Vector.js | 44 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index d774bd9ba7..5f38d9278c 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -2317,21 +2317,31 @@ class Vector { * Calculates new vector components that are proportionally the * same distance between two vectors. * + * `lerp()` can use separate numbers, as in `v.lerp(3, 3, 0.5)`, another + * p5.Vector object, as in `v.lerp(v2, 0.5)`, or an + * array of numbers, as in `v.lerp([3, 3], 0.5)`. When using numbers, the last + * argument is always the interpolation amount. + * * The `amt` parameter is the amount to interpolate between the old vector and * the new vector. 0.0 keeps all components equal to the old vector's, 0.5 is * halfway between, and 1.0 sets all components equal to the new vector's. + * Values of `amt` outside the range 0 to 1 are allowed and extrapolate beyond + * the target. + * + * This method supports N-dimensional vectors. You should interpolate vectors + * only when they are the same size. When two vectors of different sizes are + * used, the smaller dimension will be used, and any additional values of the + * longer vector will be ignored. * * The static version of `lerp()`, as in `p5.Vector.lerp(v0, v1, 0.5)`, * returns a new p5.Vector object and doesn't change - * the original. - * + * the originals. * * @param {...Number} values target vector components * @param {Number} amt amount of interpolation between 0.0 (old vector) * and 1.0 (new vector). 0.5 is halfway between. * @chainable * - * * @example * // META:norender * function setup() { @@ -2350,6 +2360,32 @@ class Vector { * // META:norender * function setup() { * // Create a p5.Vector object. + * let v = createVector(1, 1); + * + * // Interpolate with numbers. The last argument is the amount. + * v.lerp(3, 3, 0.5); + * + * // Prints "p5.Vector Object : [2, 2]" to the console. + * print(v.toString()); + * } + * + * @example + * // META:norender + * function setup() { + * // Create a p5.Vector object. + * let v = createVector(1, 1, 1); + * + * // Interpolate with an array. + * v.lerp([3, 3, 3], 0.5); + * + * // Prints "p5.Vector Object : [2, 2, 2]" to the console. + * print(v.toString()); + * } + * + * @example + * // META:norender + * function setup() { + * // Create a p5.Vector object. * let v = createVector(1, 1, 1); * * // Interpolate. @@ -2384,7 +2420,7 @@ class Vector { * v0.lerp(v1, 0.5); * * // Prints "p5.Vector Object : [0.5, 0.5, 0.5, 0.5]" to the console. - * print(v1.toString()); + * print(v0.toString()); * } * * @example From 9c203262f76aea6d2ec238e96b9755b8be108e47 Mon Sep 17 00:00:00 2001 From: mawerb Date: Tue, 21 Jul 2026 13:38:00 +0300 Subject: [PATCH 8/9] refactored patch vector error checks into a helper function --- src/math/patch-vector.js | 64 ++++++++++------------------------------ 1 file changed, 15 insertions(+), 49 deletions(-) diff --git a/src/math/patch-vector.js b/src/math/patch-vector.js index 879a8a00d4..1bf7348c41 100644 --- a/src/math/patch-vector.js +++ b/src/math/patch-vector.js @@ -1,5 +1,13 @@ import { Vector } from './p5.Vector.js'; +function _vectorError(instance, message = 'Requires valid arguments') { + if (!instance.friendlyErrorsDisabled()) { + instance._friendlyError(message, 'p5.Vector'); + } + + return instance; +} + /** * @private * @internal @@ -55,13 +63,7 @@ export function _validatedVectorOperation( // No arguments? No action (same as other vector ops) return this; } - if (!this.friendlyErrorsDisabled()) { - this._friendlyError( - 'Requires valid arguments', - 'p5.Vector' - ); - } - return this; + return _vectorError(this); } else { for (let i = 0; i < trailingArgCount; i++) { trailing.unshift(args.pop()); @@ -70,24 +72,12 @@ export function _validatedVectorOperation( for (let i = 0; i < trailing.length; i++) { const t = trailing[i]; if (typeof t !== 'number' || !Number.isFinite(t)) { - if (!this.friendlyErrorsDisabled()) { - this._friendlyError( - 'Arguments contain non-finite numbers', - 'p5.Vector' - ); - } - return this; + return _vectorError(this, 'Arguments contain non-finite numbers'); } } if (args.length === 0) { - if (!this.friendlyErrorsDisabled()) { - this._friendlyError( - 'Requires valid arguments', - 'p5.Vector' - ); - } - return this; + return _vectorError(this); } } } else if (args.length === 0) { @@ -98,25 +88,13 @@ export function _validatedVectorOperation( if (args[0] instanceof Vector) { // Do not allow extra args after a vector when trailing args are used if (trailingArgCount > 0 && args.length > 1) { - if (!this.friendlyErrorsDisabled()) { - this._friendlyError( - 'Requires valid arguments', - 'p5.Vector' - ); - } - return this; + return _vectorError(this); } // First argument is a vector? Make it an array args = args[0].values; } else if (Array.isArray(args[0])) { if (trailingArgCount > 0 && args.length > 1) { - if (!this.friendlyErrorsDisabled()) { - this._friendlyError( - 'Requires valid arguments', - 'p5.Vector' - ); - } - return this; + return _vectorError(this); } // First argument is an array? Great, keep it! args = args[0]; @@ -131,24 +109,12 @@ export function _validatedVectorOperation( for (let i = 0; i < args.length; i++) { const v = args[i]; if (typeof v !== 'number' || !Number.isFinite(v)) { - if (!this.friendlyErrorsDisabled()) { - this._friendlyError( - 'Arguments contain non-finite numbers', - 'p5.Vector' - ); - } - return this; + return _vectorError(this, 'Arguments contain non-finite numbers'); } } } else { if (typeof args !== 'number' || !Number.isFinite(args)) { - if (!this.friendlyErrorsDisabled()) { - this._friendlyError( - 'Arguments contain non-finite numbers', - 'p5.Vector' - ); - } - return this; + return _vectorError(this, 'Arguments contain non-finite numbers'); } } From ec211205b80f6cc65c3680ef1b861ee59be14a67 Mon Sep 17 00:00:00 2001 From: mawerb Date: Wed, 22 Jul 2026 18:47:10 +0300 Subject: [PATCH 9/9] refactored lerp() examples to output results with print() to text() --- src/math/p5.Vector.js | 72 ++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index 5f38d9278c..efa7a02b62 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -2343,8 +2343,11 @@ class Vector { * @chainable * * @example - * // META:norender * function setup() { + * createCanvas(100, 100); + * + * background(200); + * * // Create a p5.Vector object. * let v0 = createVector(1, 1, 1); * let v1 = createVector(3, 3, 3); @@ -2352,52 +2355,76 @@ class Vector { * // Interpolate. * v0.lerp(v1, 0.5); * - * // Prints "p5.Vector Object : [2, 2, 2]" to the console. - * print(v0.toString()); + * // Display the result. + * textAlign(CENTER, CENTER); + * text(v0.toString(), 0, 0, width, height); + * + * describe('The text "p5.Vector Object : [2, 2, 2]" written on a gray square.'); * } * * @example - * // META:norender * function setup() { + * createCanvas(100, 100); + * + * background(200); + * * // Create a p5.Vector object. * let v = createVector(1, 1); * * // Interpolate with numbers. The last argument is the amount. * v.lerp(3, 3, 0.5); * - * // Prints "p5.Vector Object : [2, 2]" to the console. - * print(v.toString()); + * // Display the result. + * textAlign(CENTER, CENTER); + * text(v.toString(), 0, 0, width, height); + * + * describe('The text "p5.Vector Object : [2, 2]" written on a gray square.'); * } * * @example - * // META:norender * function setup() { + * createCanvas(100, 100); + * + * background(200); + * * // Create a p5.Vector object. * let v = createVector(1, 1, 1); * * // Interpolate with an array. * v.lerp([3, 3, 3], 0.5); * - * // Prints "p5.Vector Object : [2, 2, 2]" to the console. - * print(v.toString()); + * // Display the result. + * textAlign(CENTER, CENTER); + * text(v.toString(), 0, 0, width, height); + * + * describe('The text "p5.Vector Object : [2, 2, 2]" written on a gray square.'); * } * * @example - * // META:norender * function setup() { + * createCanvas(100, 100); + * + * background(200); + * * // Create a p5.Vector object. * let v = createVector(1, 1, 1); * * // Interpolate. * v.lerp(3, 3, 3, 0.5); * - * // Prints "p5.Vector Object : [2, 2, 2]" to the console. - * print(v.toString()); + * // Display the result. + * textAlign(CENTER, CENTER); + * text(v.toString(), 0, 0, width, height); + * + * describe('The text "p5.Vector Object : [2, 2, 2]" written on a gray square.'); * } * * @example - * // META:norender * function setup() { + * createCanvas(100, 100); + * + * background(200); + * * // Create p5.Vector objects. * let v0 = createVector(1, 1, 1); * let v1 = createVector(3, 3, 3); @@ -2405,13 +2432,19 @@ class Vector { * // Interpolate. * let v2 = p5.Vector.lerp(v0, v1, 0.5); * - * // Prints "p5.Vector Object : [2, 2, 2]" to the console. - * print(v2.toString()); + * // Display the result. + * textAlign(CENTER, CENTER); + * text(v2.toString(), 0, 0, width, height); + * + * describe('The text "p5.Vector Object : [2, 2, 2]" written on a gray square.'); * } * * @example - * // META:norender * function setup() { + * createCanvas(100, 100); + * + * background(200); + * * // Create p5.Vector objects. * let v0 = createVector(0, 1, 0, 1); * let v1 = createVector(1, 0, 1, 0); @@ -2419,8 +2452,11 @@ class Vector { * // Interpolate. * v0.lerp(v1, 0.5); * - * // Prints "p5.Vector Object : [0.5, 0.5, 0.5, 0.5]" to the console. - * print(v0.toString()); + * // Display the result. + * textAlign(CENTER, CENTER); + * text(v0.toString(), 0, 0, width, height); + * + * describe('The text "p5.Vector Object : [0.5, 0.5, 0.5, 0.5]" written on a gray square.'); * } * * @example