From 1be7b20bc5c0402ec98b5ab1cd731619e05b1c98 Mon Sep 17 00:00:00 2001 From: dhowe Date: Mon, 8 Dec 2025 21:31:31 +0000 Subject: [PATCH 01/21] implemented first 10 getters --- src/color/setting.js | 8 +++----- src/core/p5.Renderer.js | 17 +++++++++++------ src/core/p5.Renderer2D.js | 27 ++++++++++++++++++++++++++- src/image/loading_displaying.js | 6 ++++++ src/shape/attributes.js | 15 +++++++++++++-- 5 files changed, 59 insertions(+), 14 deletions(-) diff --git a/src/color/setting.js b/src/color/setting.js index e60af75c3f..7e1d92b995 100644 --- a/src/color/setting.js +++ b/src/color/setting.js @@ -1470,8 +1470,7 @@ function setting(p5, fn){ * @chainable */ fn.fill = function(...args) { - this._renderer.fill(...args); - return this; + return this._renderer.fill(...args); }; /** @@ -1839,8 +1838,7 @@ function setting(p5, fn){ * @chainable */ fn.stroke = function(...args) { - this._renderer.stroke(...args); - return this; + return this._renderer.stroke(...args); }; /** @@ -2443,7 +2441,7 @@ function setting(p5, fn){ ); mode = constants.BLEND; } - this._renderer.blendMode(mode); + return this._renderer.blendMode(mode); }; } diff --git a/src/core/p5.Renderer.js b/src/core/p5.Renderer.js index 75d01bc04c..f2d60f4dac 100644 --- a/src/core/p5.Renderer.js +++ b/src/core/p5.Renderer.js @@ -323,9 +323,12 @@ class Renderer { } fill(...args) { - this.states.setValue('fillSet', true); - this.states.setValue('fillColor', this._pInst.color(...args)); - this.updateShapeVertexProperties(); + if (args.length > 0) { + this.states.setValue('fillSet', true); + this.states.setValue('fillColor', this._pInst.color(...args)); + this.updateShapeVertexProperties(); + } + return this.states.fillColor; } noFill() { @@ -333,14 +336,16 @@ class Renderer { } strokeWeight(w) { - if (w === undefined) { + if (typeof w === 'undefined') { return this.states.strokeWeight; - } else { - this.states.setValue('strokeWeight', w); } + this.states.setValue('strokeWeight', w); } stroke(...args) { + if (args.length === 0) { + return this.states.strokeColor; + } this.states.setValue('strokeSet', true); this.states.setValue('strokeColor', this._pInst.color(...args)); this.updateShapeVertexProperties(); diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index b9a7e12d00..635218080f 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -213,6 +213,9 @@ class Renderer2D extends Renderer { fill(...args) { super.fill(...args); const color = this.states.fillColor; + if (args.length === 0) { + return color; // getter + } this._setFill(color.toString()); // Add accessible outputs if the method exists; on success, @@ -225,6 +228,9 @@ class Renderer2D extends Renderer { stroke(...args) { super.stroke(...args); const color = this.states.strokeColor; + if (args.length === 0) { + return color; // getter + } this._setStroke(color.toString()); // Add accessible outputs if the method exists; on success, @@ -475,6 +481,9 @@ class Renderer2D extends Renderer { ////////////////////////////////////////////// blendMode(mode) { + if (typeof mode === 'undefined') { // getter + return this._cachedBlendMode; + } if (mode === constants.SUBTRACT) { console.warn('blendMode(SUBTRACT) only works in WEBGL mode.'); } else if ( @@ -921,6 +930,9 @@ class Renderer2D extends Renderer { ////////////////////////////////////////////// strokeCap(cap) { + if (typeof cap === 'undefined') { // getter + return this.drawingContext.lineCap; + } if ( cap === constants.ROUND || cap === constants.SQUARE || @@ -932,6 +944,9 @@ class Renderer2D extends Renderer { } strokeJoin(join) { + if (typeof join === 'undefined') { // getter + return this.drawingContext.lineJoin; + } if ( join === constants.ROUND || join === constants.BEVEL || @@ -944,7 +959,10 @@ class Renderer2D extends Renderer { strokeWeight(w) { super.strokeWeight(w); - if (typeof w === 'undefined' || w === 0) { + if (typeof w === 'undefined') { + return this.states.strokeWeight; + } + if (w === 0) { // hack because lineWidth 0 doesn't work this.drawingContext.lineWidth = 0.0001; } else { @@ -1006,7 +1024,14 @@ class Renderer2D extends Renderer { } rotate(rad) { + if (typeof rad === 'undefined') { + const matrix = ctx.getTransform(); + console.log(matrix); + const rad = Math.atan2(/*-*/matrix.b, matrix.a); + return rad >= 0 ? rad : rad + Math.PI * 2; // angle > Math.PI } + } this.drawingContext.rotate(rad); + return this; } scale(x, y) { diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 8487dde0a5..017b452517 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1291,6 +1291,9 @@ function loadingDisplaying(p5, fn){ */ fn.tint = function(...args) { // p5._validateParameters('tint', args); + if (args.length === 0) { + return this._renderer.states.tint; // getter + } const c = this.color(...args); this._renderer.states.setValue('tint', c._getRGBA([255, 255, 255, 255])); }; @@ -1437,6 +1440,9 @@ function loadingDisplaying(p5, fn){ */ fn.imageMode = function(m) { // p5._validateParameters('imageMode', arguments); + if (typeof m === 'undefined') { // getter + return this._renderer.states.imageMode; + } if ( m === constants.CORNER || m === constants.CORNERS || diff --git a/src/shape/attributes.js b/src/shape/attributes.js index 5669c5d32e..18188618a6 100644 --- a/src/shape/attributes.js +++ b/src/shape/attributes.js @@ -86,6 +86,9 @@ function attributes(p5, fn){ */ fn.ellipseMode = function(m) { // p5._validateParameters('ellipseMode', arguments); + if (typeof m === 'undefined') { // getter + return this._renderer?.states.ellipseMode; + } if ( m === constants.CORNER || m === constants.CORNERS || @@ -286,6 +289,9 @@ function attributes(p5, fn){ */ fn.rectMode = function(m) { // p5._validateParameters('rectMode', arguments); + if (typeof m === 'undefined') { // getter + return this._renderer?.states.ellipseMode; + } if ( m === constants.CORNER || m === constants.CORNERS || @@ -424,6 +430,9 @@ function attributes(p5, fn){ */ fn.strokeCap = function(cap) { // p5._validateParameters('strokeCap', arguments); + if (typeof cap === 'undefined') { // getter + return this._renderer.strokeCap(); + } if ( cap === constants.ROUND || cap === constants.SQUARE || @@ -523,6 +532,9 @@ function attributes(p5, fn){ */ fn.strokeJoin = function(join) { // p5._validateParameters('strokeJoin', arguments); + if (typeof join === 'undefined') { // getter + return this._renderer.strokeJoin(); + } if ( join === constants.ROUND || join === constants.BEVEL || @@ -590,8 +602,7 @@ function attributes(p5, fn){ */ fn.strokeWeight = function(w) { // p5._validateParameters('strokeWeight', arguments); - this._renderer.strokeWeight(w); - return this; + return this._renderer.strokeWeight(w); }; } From ae9af3040f05ad2f9c15545da14797a109824667 Mon Sep 17 00:00:00 2001 From: dhowe Date: Tue, 9 Dec 2025 20:13:31 +0000 Subject: [PATCH 02/21] more getters --- src/color/setting.js | 3 +-- src/core/environment.js | 4 ++++ src/core/p5.Renderer2D.js | 22 ++++++++++++++++---- src/core/transform.js | 43 ++++++++++++++++++++++++++------------- src/math/trigonometry.js | 30 ++++++++++++++++++++++++++- 5 files changed, 81 insertions(+), 21 deletions(-) diff --git a/src/color/setting.js b/src/color/setting.js index 7e1d92b995..9509f9dd3f 100644 --- a/src/color/setting.js +++ b/src/color/setting.js @@ -668,8 +668,7 @@ function setting(p5, fn){ * @chainable */ fn.background = function(...args) { - this._renderer.background(...args); - return this; + return this._renderer.background(...args); }; /** diff --git a/src/core/environment.js b/src/core/environment.js index a3226aa77b..ab4575d9bb 100644 --- a/src/core/environment.js +++ b/src/core/environment.js @@ -314,6 +314,10 @@ function environment(p5, fn, lifecycles){ fn.cursor = function(type, x, y) { let cursor = 'auto'; const canvas = this._curElement.elt; + if (typeof type === 'undefined') { + let curstr = canvas.style.cursor; + return curstr.length ? curstr : 'default'; + } if (standardCursors.includes(type)) { // Standard css cursor cursor = type; diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index 635218080f..9561c91b73 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -1025,27 +1025,41 @@ class Renderer2D extends Renderer { rotate(rad) { if (typeof rad === 'undefined') { - const matrix = ctx.getTransform(); - console.log(matrix); - const rad = Math.atan2(/*-*/matrix.b, matrix.a); - return rad >= 0 ? rad : rad + Math.PI * 2; // angle > Math.PI } + const matrix = this.drawingContext.getTransform(); + let angle = this._pInst.decomposeMatrix(matrix).rotation; + if (angle < 0) { + angle += Math.PI * 2; // ensure a positive angle + } + if (this._pInst._angleMode === this._pInst.DEGREES) { + angle *= constants.RAD_TO_DEG; // to degrees + } + return Math.abs(angle); } this.drawingContext.rotate(rad); return this; } scale(x, y) { + if (typeof x === 'undefined' && typeof y === 'undefined') { + const matrix = this.drawingContext.getTransform(); + return this._pInst.decomposeMatrix(matrix).scale; + } this.drawingContext.scale(x, y); return this; } translate(x, y) { + if (typeof x === 'undefined' && typeof y === 'undefined') { + const matrix = this.drawingContext.getTransform(); + return this._pInst.decomposeMatrix(matrix).translation; + } // support passing a vector as the 1st parameter if (x instanceof p5.Vector) { y = x.y; x = x.x; } this.drawingContext.translate(x, y); + console.log('MAT:',this.drawingContext.getTransform()); return this; } diff --git a/src/core/transform.js b/src/core/transform.js index 8832d3a4ee..7db3cf8e46 100644 --- a/src/core/transform.js +++ b/src/core/transform.js @@ -462,8 +462,7 @@ function transform(p5, fn){ */ fn.rotate = function(angle, axis) { // p5._validateParameters('rotate', arguments); - this._renderer.rotate(this._toRadians(angle), axis); - return this; + return this._renderer.rotate(this._toRadians(angle), axis); }; /** @@ -598,8 +597,7 @@ function transform(p5, fn){ fn.rotateX = function(angle) { this._assert3d('rotateX'); // p5._validateParameters('rotateX', arguments); - this._renderer.rotateX(this._toRadians(angle)); - return this; + return this._renderer.rotateX(this._toRadians(angle)); }; /** @@ -734,8 +732,7 @@ function transform(p5, fn){ fn.rotateY = function(angle) { this._assert3d('rotateY'); // p5._validateParameters('rotateY', arguments); - this._renderer.rotateY(this._toRadians(angle)); - return this; + return this._renderer.rotateY(this._toRadians(angle)); }; /** @@ -870,8 +867,7 @@ function transform(p5, fn){ fn.rotateZ = function(angle) { this._assert3d('rotateZ'); // p5._validateParameters('rotateZ', arguments); - this._renderer.rotateZ(this._toRadians(angle)); - return this; + return this._renderer.rotateZ(this._toRadians(angle)); }; /** @@ -1060,9 +1056,7 @@ function transform(p5, fn){ z = 1; } - this._renderer.scale(x, y, z); - - return this; + return this._renderer.scale(x, y, z); }; /** @@ -1137,6 +1131,17 @@ function transform(p5, fn){ */ fn.shearX = function(angle) { // p5._validateParameters('shearX', arguments); + if (typeof angle === 'undefined') { + let matrix = this._renderer.drawingContext.getTransform(); + let rad = this.decomposeMatrix(matrix).skew.x; + if (rad < 0) { + rad += Math.PI * 2; // ensure a positive angle + } + if (fn._angleMode === fn.DEGREES) { + rad *= fn.RAD_TO_DEG; // to degrees + } + return rad; + } const rad = this._toRadians(angle); this._renderer.applyMatrix(1, 0, Math.tan(rad), 1, 0, 0); return this; @@ -1214,6 +1219,17 @@ function transform(p5, fn){ */ fn.shearY = function(angle) { // p5._validateParameters('shearY', arguments); + if (typeof angle === 'undefined') { + let matrix = this._renderer.drawingContext.getTransform(); + let rad = this.decomposeMatrix(matrix).skew.y; + if (rad < 0) { + rad += Math.PI * 2; // ensure a positive angle + } + if (fn._angleMode === fn.DEGREES) { + rad *= fn.RAD_TO_DEG; // to degrees + } + return rad; + } const rad = this._toRadians(angle); this._renderer.applyMatrix(1, Math.tan(rad), 0, 1, 0, 0); return this; @@ -1398,11 +1414,10 @@ function transform(p5, fn){ fn.translate = function(x, y, z) { // p5._validateParameters('translate', arguments); if (this._renderer.isP3D) { - this._renderer.translate(x, y, z); + return this._renderer.translate(x, y, z); } else { - this._renderer.translate(x, y); + return this._renderer.translate(x, y); } - return this; }; /** diff --git a/src/math/trigonometry.js b/src/math/trigonometry.js index 608ac60743..e3e2fa12bc 100644 --- a/src/math/trigonometry.js +++ b/src/math/trigonometry.js @@ -226,6 +226,33 @@ function trigonometry(p5, fn){ return this._fromRadians(Math.asin(ratio)); }; + fn.decomposeMatrix = function(mat) { + // adapted from https://frederic-wang.fr/2013/12/01/decomposition-of-2d-transform-matrices/ + let { a, b, c, d, e, f } = mat; + let delta = a * d - b * c; + let result = { + translation: { x: e, y: f }, + scale: { x: 0, y: 0 }, + skew: { x: 0, y: 0 }, + rotation: 0 + }; + if (a !== 0 || b !== 0) { + let r = Math.sqrt(a * a + b * b); + result.rotation = b > 0 ? Math.acos(a / r) : -Math.acos(a / r); + result.scale = { x: r, y: delta / r }; + result.skew = { x: Math.atan((a * c + b * d) / (r * r)), y: 0 }; + } else if (c !== 0 || d !== 0) { + let s = Math.sqrt(c * c + d * d); + result.rotation = Math.PI / 2 - + (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s)); + result.scale = { x: delta / s, y: s }; + result.skew = { x: 0, y: Math.atan((a * c + b * d) / (s * s)) }; + } else { + // a = b = c = d = 0 + } + return result; + }; + /** * Calculates the arc tangent of a number. * @@ -864,7 +891,8 @@ function trigonometry(p5, fn){ * @returns {Number} */ fn._toRadians = function(angle) { - if (this._angleMode === DEGREES) { + // returns undefined if no argument + if (typeof angle !== 'undefined' && this._angleMode === DEGREES) { return angle * constants.DEG_TO_RAD; } return angle; From 8f7a431ff4f18a1623cf99d1fe600fa2872d77dd Mon Sep 17 00:00:00 2001 From: dhowe Date: Wed, 10 Dec 2025 17:38:48 +0000 Subject: [PATCH 03/21] complete first set of getters --- src/core/p5.Renderer.js | 15 +++++++-------- src/core/p5.Renderer2D.js | 23 +++++++++++++++-------- src/core/transform.js | 10 ++-------- src/image/loading_displaying.js | 2 +- src/math/trigonometry.js | 6 +++--- src/type/textCore.js | 7 +++++++ 6 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/core/p5.Renderer.js b/src/core/p5.Renderer.js index f2d60f4dac..87c5241e75 100644 --- a/src/core/p5.Renderer.js +++ b/src/core/p5.Renderer.js @@ -35,6 +35,7 @@ class ClonableObject { class Renderer { static states = { + background: null, strokeColor: null, strokeSet: false, fillColor: null, @@ -45,6 +46,11 @@ class Renderer { rectMode: constants.CORNER, ellipseMode: constants.CENTER, strokeWeight: 1, + bezierOrder: 3, + splineProperties: new ClonableObject({ + ends: constants.INCLUDE, + tightness: 0 + }), textFont: { family: 'sans-serif' }, textLeading: 15, @@ -52,15 +58,8 @@ class Renderer { textSize: 12, textAlign: constants.LEFT, textBaseline: constants.BASELINE, - bezierOrder: 3, - splineProperties: new ClonableObject({ - ends: constants.INCLUDE, - tightness: 0 - }), textWrap: constants.WORD, - - // added v2.0 - fontStyle: constants.NORMAL, // v1: textStyle + fontStyle: constants.NORMAL, // v1: was textStyle fontStretch: constants.NORMAL, fontWeight: constants.NORMAL, lineHeight: constants.NORMAL, diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index 9561c91b73..ad92ec5e71 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -167,16 +167,18 @@ class Renderer2D extends Renderer { background(...args) { this.push(); this.resetMatrix(); - + if (args.length === 0) { + // getter (#8278) + return this.states.background; + } if (args[0] instanceof Image) { + const img = args[0]; if (args[1] >= 0) { // set transparency of background - const img = args[0]; this.drawingContext.globalAlpha = args[1] / 255; - this._pInst.image(img, 0, 0, this.width, this.height); - } else { - this._pInst.image(args[0], 0, 0, this.width, this.height); } + this._pInst.image(img, 0, 0, this.width, this.height); + this.states.background = img; // save for getter (#8278) } else { // create background rect const color = this._pInst.color(...args); @@ -199,6 +201,7 @@ class Renderer2D extends Renderer { if (this._isErasing) { this._pInst.erase(); } + this.states.background = color; // save for getter (#8278) } this.pop(); } @@ -1044,6 +1047,11 @@ class Renderer2D extends Renderer { const matrix = this.drawingContext.getTransform(); return this._pInst.decomposeMatrix(matrix).scale; } + // support passing objects with x,y properties (including p5.Vector) + if (typeof x === 'object' && 'x' in x && 'y' in x) { + y = x.y; + x = x.x; + } this.drawingContext.scale(x, y); return this; } @@ -1053,13 +1061,12 @@ class Renderer2D extends Renderer { const matrix = this.drawingContext.getTransform(); return this._pInst.decomposeMatrix(matrix).translation; } - // support passing a vector as the 1st parameter - if (x instanceof p5.Vector) { + // support passing objects with x,y properties (including p5.Vector) + if (typeof x === 'object' && 'x' in x && 'y' in x) { y = x.y; x = x.x; } this.drawingContext.translate(x, y); - console.log('MAT:',this.drawingContext.getTransform()); return this; } diff --git a/src/core/transform.js b/src/core/transform.js index 7db3cf8e46..133a9da9cc 100644 --- a/src/core/transform.js +++ b/src/core/transform.js @@ -1133,10 +1133,7 @@ function transform(p5, fn){ // p5._validateParameters('shearX', arguments); if (typeof angle === 'undefined') { let matrix = this._renderer.drawingContext.getTransform(); - let rad = this.decomposeMatrix(matrix).skew.x; - if (rad < 0) { - rad += Math.PI * 2; // ensure a positive angle - } + let rad = this.decomposeMatrix(matrix).shear.x; if (fn._angleMode === fn.DEGREES) { rad *= fn.RAD_TO_DEG; // to degrees } @@ -1221,10 +1218,7 @@ function transform(p5, fn){ // p5._validateParameters('shearY', arguments); if (typeof angle === 'undefined') { let matrix = this._renderer.drawingContext.getTransform(); - let rad = this.decomposeMatrix(matrix).skew.y; - if (rad < 0) { - rad += Math.PI * 2; // ensure a positive angle - } + let rad = this.decomposeMatrix(matrix).shear.y; if (fn._angleMode === fn.DEGREES) { rad *= fn.RAD_TO_DEG; // to degrees } diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 017b452517..9617b2ce3c 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1292,7 +1292,7 @@ function loadingDisplaying(p5, fn){ fn.tint = function(...args) { // p5._validateParameters('tint', args); if (args.length === 0) { - return this._renderer.states.tint; // getter + return this.color(this._renderer.states.tint); // getter } const c = this.color(...args); this._renderer.states.setValue('tint', c._getRGBA([255, 255, 255, 255])); diff --git a/src/math/trigonometry.js b/src/math/trigonometry.js index e3e2fa12bc..28fe4fcf3a 100644 --- a/src/math/trigonometry.js +++ b/src/math/trigonometry.js @@ -233,20 +233,20 @@ function trigonometry(p5, fn){ let result = { translation: { x: e, y: f }, scale: { x: 0, y: 0 }, - skew: { x: 0, y: 0 }, + shear: { x: 0, y: 0 }, rotation: 0 }; if (a !== 0 || b !== 0) { let r = Math.sqrt(a * a + b * b); result.rotation = b > 0 ? Math.acos(a / r) : -Math.acos(a / r); result.scale = { x: r, y: delta / r }; - result.skew = { x: Math.atan((a * c + b * d) / (r * r)), y: 0 }; + result.shear = { x: Math.atan((a * c + b * d) / (r * r)), y: 0 }; } else if (c !== 0 || d !== 0) { let s = Math.sqrt(c * c + d * d); result.rotation = Math.PI / 2 - (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s)); result.scale = { x: delta / s, y: s }; - result.skew = { x: 0, y: Math.atan((a * c + b * d) / (s * s)) }; + result.shear = { x: 0, y: Math.atan((a * c + b * d) / (s * s)) }; } else { // a = b = c = d = 0 } diff --git a/src/type/textCore.js b/src/type/textCore.js index 70c05cf927..4f6e555601 100644 --- a/src/type/textCore.js +++ b/src/type/textCore.js @@ -1611,7 +1611,14 @@ function textCore(p5, fn) { // the setter if (typeof h !== 'undefined') { + // accept what is returned from the getter + if (h.hasOwnProperty('horizontal')) { + h = h.horizontal; + } this.states.setValue('textAlign', h); + if (h.hasOwnProperty('vertical') && typeof v === 'undefined') { + v = h.vertical; + } if (typeof v !== 'undefined') { if (v === fn.CENTER) { v = textCoreConstants._CTX_MIDDLE; From 039ef43bc08ddf32981092fc93c88508ba6c6c8f Mon Sep 17 00:00:00 2001 From: dhowe Date: Wed, 10 Dec 2025 21:58:29 +0000 Subject: [PATCH 04/21] update parameter json, add tests for getters --- docs/parameterData.json | 52 +++++++++++++++++++-------- src/core/p5.Renderer2D.js | 14 ++++---- src/shape/attributes.js | 2 +- test/unit/core/properties.js | 69 ++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 22 deletions(-) create mode 100644 test/unit/core/properties.js diff --git a/docs/parameterData.json b/docs/parameterData.json index ab5f651595..543787aa80 100644 --- a/docs/parameterData.json +++ b/docs/parameterData.json @@ -162,6 +162,7 @@ }, "background": { "overloads": [ + [], [ "p5.Color" ], @@ -201,6 +202,7 @@ }, "colorMode": { "overloads": [ + [], [ "RGB|HSB|HSL|RGBHDR|HWB|LAB|LCH|OKLAB|OKLCH", "Number?" @@ -217,6 +219,7 @@ }, "fill": { "overloads": [ + [], [ "Number", "Number", @@ -250,6 +253,7 @@ }, "stroke": { "overloads": [ + [], [ "Number", "Number", @@ -286,6 +290,7 @@ }, "blendMode": { "overloads": [ + [], [ "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|REMOVE|SUBTRACT" ] @@ -303,6 +308,7 @@ }, "cursor": { "overloads": [ + [], [ "ARROW|CROSS|HAND|MOVE|TEXT|WAIT|String", "Number?", @@ -528,28 +534,32 @@ [ "Number", "p5.Vector|Number[]?" - ] + ], + [] ] }, "rotateX": { "overloads": [ [ "Number" - ] + ], + [] ] }, "rotateY": { "overloads": [ [ "Number" - ] + ], + [] ] }, "rotateZ": { "overloads": [ [ "Number" - ] + ], + [] ] }, "scale": { @@ -561,21 +571,24 @@ ], [ "p5.Vector|Number[]" - ] + ], + [] ] }, "shearX": { "overloads": [ [ "Number" - ] + ], + [] ] }, "shearY": { "overloads": [ [ "Number" - ] + ], + [] ] }, "translate": { @@ -587,7 +600,8 @@ ], [ "p5.Vector" - ] + ], + [] ] }, "push": { @@ -1014,7 +1028,8 @@ ], [ "p5.Color" - ] + ], + [] ] }, "noTint": { @@ -1026,7 +1041,8 @@ "overloads": [ [ "CORNER|CORNERS|CENTER" - ] + ], + [] ] }, "blend": { @@ -1748,7 +1764,8 @@ "overloads": [ [ "CENTER|RADIUS|CORNER|CORNERS" - ] + ], + [] ] }, "noSmooth": { @@ -1758,6 +1775,7 @@ }, "rectMode": { "overloads": [ + [], [ "CENTER|RADIUS|CORNER|CORNERS" ] @@ -1772,21 +1790,24 @@ "overloads": [ [ "ROUND|SQUARE|PROJECT" - ] + ], + [] ] }, "strokeJoin": { "overloads": [ [ "MITER|BEVEL|ROUND" - ] + ], + [] ] }, "strokeWeight": { "overloads": [ [ "Number" - ] + ], + [] ] }, "bezier": { @@ -2108,7 +2129,8 @@ [ "LEFT|CENTER|RIGHT?", "TOP|BOTTOM|CENTER|BASELINE?" - ] + ], + [] ] }, "textAscent": { diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index ad92ec5e71..e75a108a7a 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -165,12 +165,12 @@ class Renderer2D extends Renderer { ////////////////////////////////////////////// background(...args) { - this.push(); - this.resetMatrix(); if (args.length === 0) { - // getter (#8278) - return this.states.background; + return this.states.background; // getter (#8278) } + let bgForState = null; + this.push(); + this.resetMatrix(); if (args[0] instanceof Image) { const img = args[0]; if (args[1] >= 0) { @@ -178,7 +178,7 @@ class Renderer2D extends Renderer { this.drawingContext.globalAlpha = args[1] / 255; } this._pInst.image(img, 0, 0, this.width, this.height); - this.states.background = img; // save for getter (#8278) + bgForState = img; // save for getter (#8278) } else { // create background rect const color = this._pInst.color(...args); @@ -201,9 +201,11 @@ class Renderer2D extends Renderer { if (this._isErasing) { this._pInst.erase(); } - this.states.background = color; // save for getter (#8278) + bgForState = color; // save for getter (#8278) } this.pop(); + + this.states.setValue('background', bgForState); // set state (#8278) } clear() { diff --git a/src/shape/attributes.js b/src/shape/attributes.js index 18188618a6..7ac2a8618e 100644 --- a/src/shape/attributes.js +++ b/src/shape/attributes.js @@ -290,7 +290,7 @@ function attributes(p5, fn){ fn.rectMode = function(m) { // p5._validateParameters('rectMode', arguments); if (typeof m === 'undefined') { // getter - return this._renderer?.states.ellipseMode; + return this._renderer?.states.rectMode; } if ( m === constants.CORNER || diff --git a/test/unit/core/properties.js b/test/unit/core/properties.js new file mode 100644 index 0000000000..8c58a73e2f --- /dev/null +++ b/test/unit/core/properties.js @@ -0,0 +1,69 @@ +import p5 from '../../../src/app.js'; + +suite('Set/get properties', function() { + + let p = new p5(function (sketch) { + sketch.setup = function () { }; + sketch.draw = function () { }; + }); + + /*beforeEach(function () { + myp5 = new p5(function (p) { + p.setup = function () { }; + p.draw = function () { }; + }); + }); + afterEach(function () { + myp5.remove(); + });*/ + + let getters = { + background: new p5.Color([100, 100, 50]), + fill: new p5.Color([100, 200, 50]), + stroke: new p5.Color([200, 100, 50, 100]), + tint: new p5.Color([100, 140, 50]), + + rectMode: p.CENTER, + colorMode: p.HSB, + blendMode: 'source-over', + imageMode: p.CORNER, + ellipseMode: p.CORNER, + + strokeWeight: 6, + strokeCap: p.ROUND, + strokeJoin: p.MITER, + pixelDensity: 1, + cursor: 'pointer', + + rotate: p.PI, + translate: { x: 1, y: 2 }, + scale: { x: 1, y: 2 }, + + textAlign: { horizontal: p.CENTER, vertical: p.CENTER }, + textLeading: 18, + textFont: 'arial', + textSize: 1, + textStyle: 1, + textWrap: p.WORD, + textDirection: 1, + textWeight: 1 + }; + + Object.keys(getters).forEach(prop => { + let arg = getters[prop]; + test(`${prop}()`, function() { + // setter + if (typeof arg === 'object' && !(arg instanceof p5.Color)) { + p[prop](...Object.values(arg)); // set with object + } + else if (Array.isArray(arg)) { + p[prop](...arg); // set with array + } + else { + p[prop](arg); // set with primitive + } + // getter + assert.strictEqual(p[prop]().toString(), arg.toString(), `${arg.toString()}`); + }); + }); +}); From ece3986450895c152612193a835485ce903ce22b Mon Sep 17 00:00:00 2001 From: dhowe Date: Wed, 10 Dec 2025 22:13:39 +0000 Subject: [PATCH 05/21] add bezierOrder and splineProperties to tests --- test/unit/core/properties.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unit/core/properties.js b/test/unit/core/properties.js index 8c58a73e2f..10bcce9162 100644 --- a/test/unit/core/properties.js +++ b/test/unit/core/properties.js @@ -38,7 +38,8 @@ suite('Set/get properties', function() { rotate: p.PI, translate: { x: 1, y: 2 }, scale: { x: 1, y: 2 }, - + bezierOrder: 2, + splineProperties: { ends: p.EXCLUDE, tightness: -5 }, textAlign: { horizontal: p.CENTER, vertical: p.CENTER }, textLeading: 18, textFont: 'arial', @@ -52,6 +53,7 @@ suite('Set/get properties', function() { Object.keys(getters).forEach(prop => { let arg = getters[prop]; test(`${prop}()`, function() { + // setter if (typeof arg === 'object' && !(arg instanceof p5.Color)) { p[prop](...Object.values(arg)); // set with object From 255af5a3f1cc5a311db486cdafbf7048a10f3af4 Mon Sep 17 00:00:00 2001 From: dhowe Date: Sun, 1 Feb 2026 13:02:14 +0000 Subject: [PATCH 06/21] remove getters for matrix transforms: shear, rotate, translate, scale --- docs/parameterData.json | 21 +++++++-------------- src/core/p5.Renderer2D.js | 19 ------------------- src/core/transform.js | 16 ---------------- 3 files changed, 7 insertions(+), 49 deletions(-) diff --git a/docs/parameterData.json b/docs/parameterData.json index 199d8f66c1..bb83f10368 100644 --- a/docs/parameterData.json +++ b/docs/parameterData.json @@ -534,32 +534,28 @@ [ "Number", "p5.Vector|Number[]?" - ], - [] + ] ] }, "rotateX": { "overloads": [ [ "Number" - ], - [] + ] ] }, "rotateY": { "overloads": [ [ "Number" - ], - [] + ] ] }, "rotateZ": { "overloads": [ [ "Number" - ], - [] + ] ] }, "scale": { @@ -571,24 +567,21 @@ ], [ "p5.Vector|Number[]" - ], - [] + ] ] }, "shearX": { "overloads": [ [ "Number" - ], - [] + ] ] }, "shearY": { "overloads": [ [ "Number" - ], - [] + ] ] }, "translate": { diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index 6012751ad2..e95d81e93d 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -1030,26 +1030,11 @@ class Renderer2D extends Renderer { } rotate(rad) { - if (typeof rad === 'undefined') { - const matrix = this.drawingContext.getTransform(); - let angle = this._pInst.decomposeMatrix(matrix).rotation; - if (angle < 0) { - angle += Math.PI * 2; // ensure a positive angle - } - if (this._pInst._angleMode === this._pInst.DEGREES) { - angle *= constants.RAD_TO_DEG; // to degrees - } - return Math.abs(angle); - } this.drawingContext.rotate(rad); return this; } scale(x, y) { - if (typeof x === 'undefined' && typeof y === 'undefined') { - const matrix = this.drawingContext.getTransform(); - return this._pInst.decomposeMatrix(matrix).scale; - } // support passing objects with x,y properties (including p5.Vector) if (typeof x === 'object' && 'x' in x && 'y' in x) { y = x.y; @@ -1060,10 +1045,6 @@ class Renderer2D extends Renderer { } translate(x, y) { - if (typeof x === 'undefined' && typeof y === 'undefined') { - const matrix = this.drawingContext.getTransform(); - return this._pInst.decomposeMatrix(matrix).translation; - } // support passing objects with x,y properties (including p5.Vector) if (typeof x === 'object' && 'x' in x && 'y' in x) { y = x.y; diff --git a/src/core/transform.js b/src/core/transform.js index 133a9da9cc..e5ab7277ac 100644 --- a/src/core/transform.js +++ b/src/core/transform.js @@ -1131,14 +1131,6 @@ function transform(p5, fn){ */ fn.shearX = function(angle) { // p5._validateParameters('shearX', arguments); - if (typeof angle === 'undefined') { - let matrix = this._renderer.drawingContext.getTransform(); - let rad = this.decomposeMatrix(matrix).shear.x; - if (fn._angleMode === fn.DEGREES) { - rad *= fn.RAD_TO_DEG; // to degrees - } - return rad; - } const rad = this._toRadians(angle); this._renderer.applyMatrix(1, 0, Math.tan(rad), 1, 0, 0); return this; @@ -1216,14 +1208,6 @@ function transform(p5, fn){ */ fn.shearY = function(angle) { // p5._validateParameters('shearY', arguments); - if (typeof angle === 'undefined') { - let matrix = this._renderer.drawingContext.getTransform(); - let rad = this.decomposeMatrix(matrix).shear.y; - if (fn._angleMode === fn.DEGREES) { - rad *= fn.RAD_TO_DEG; // to degrees - } - return rad; - } const rad = this._toRadians(angle); this._renderer.applyMatrix(1, Math.tan(rad), 0, 1, 0, 0); return this; From f26eff61d6e6a41c11f7dd7dcf28f9a335465888 Mon Sep 17 00:00:00 2001 From: dhowe Date: Sun, 1 Feb 2026 13:15:41 +0000 Subject: [PATCH 07/21] remove translate, rotate, scale from getter tests --- src/image/loading_displaying.js | 2 ++ test/unit/core/properties.js | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 9617b2ce3c..fb914ff379 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1296,6 +1296,7 @@ function loadingDisplaying(p5, fn){ } const c = this.color(...args); this._renderer.states.setValue('tint', c._getRGBA([255, 255, 255, 255])); + return this; }; /** @@ -1333,6 +1334,7 @@ function loadingDisplaying(p5, fn){ */ fn.noTint = function() { this._renderer.states.setValue('tint', null); + return this; }; /** diff --git a/test/unit/core/properties.js b/test/unit/core/properties.js index 10bcce9162..34bb499114 100644 --- a/test/unit/core/properties.js +++ b/test/unit/core/properties.js @@ -35,9 +35,9 @@ suite('Set/get properties', function() { pixelDensity: 1, cursor: 'pointer', - rotate: p.PI, - translate: { x: 1, y: 2 }, - scale: { x: 1, y: 2 }, + // rotate: p.PI, + // translate: { x: 1, y: 2 }, + // scale: { x: 1, y: 2 }, bezierOrder: 2, splineProperties: { ends: p.EXCLUDE, tightness: -5 }, textAlign: { horizontal: p.CENTER, vertical: p.CENTER }, From be4de9813a83456ba4599486743830498a690f6a Mon Sep 17 00:00:00 2001 From: dhowe Date: Sun, 1 Feb 2026 14:15:21 +0000 Subject: [PATCH 08/21] re-implemented tint, plus textureWrap and textureMode --- src/color/p5.Color.js | 2 +- src/core/p5.Renderer2D.js | 4 +++- src/image/loading_displaying.js | 6 ++++-- src/webgl/material.js | 21 +++++++++++++++++++-- test/unit/core/properties.js | 17 ++++++++++++----- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index 3622bb4b9c..fb901e9ec4 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -675,7 +675,7 @@ class Color { if(!Array.isArray(v)){ return [0, v]; }else{ - return v + return v; } }); diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index e95d81e93d..87a008009c 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -167,7 +167,8 @@ class Renderer2D extends Renderer { background(...args) { if (args.length === 0) { - return this.states.background; // getter (#8278) + return this;// setter with no args does nothing + //return this.states.background; // getter (#8278) } let bgForState = null; this.push(); @@ -207,6 +208,7 @@ class Renderer2D extends Renderer { this.pop(); this.states.setValue('background', bgForState); // set state (#8278) + return this; } clear() { diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index fb914ff379..d080e2fb4a 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1294,8 +1294,10 @@ function loadingDisplaying(p5, fn){ if (args.length === 0) { return this.color(this._renderer.states.tint); // getter } - const c = this.color(...args); - this._renderer.states.setValue('tint', c._getRGBA([255, 255, 255, 255])); + if (args && args.length) { + const c = this.color(...args); + this._renderer.states.setValue('tint', c._getRGBA([255, 255, 255, 255])); + } return this; }; diff --git a/src/webgl/material.js b/src/webgl/material.js index 60f01a3969..ed4a1b7a99 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -2563,6 +2563,9 @@ function material(p5, fn){ * */ fn.textureMode = function (mode) { + if (typeof mode === 'undefined') { // getter + return this._renderer.states.textureMode; + } if (mode !== constants.IMAGE && mode !== constants.NORMAL) { console.warn( `You tried to set ${mode} textureMode only supports IMAGE & NORMAL ` @@ -2839,12 +2842,26 @@ function material(p5, fn){ * */ fn.textureWrap = function (wrapX, wrapY = wrapX) { + if (typeof wrapX === 'undefined') { // getter + return { + x: this._renderer.states.textureWrapX, + y: this._renderer.states.textureWrapY + }; + } + // accept what is returned from the getter + if (wrapX.hasOwnProperty('x') && wrapX.hasOwnProperty('y')) { + wrapX = wrapX.x; + wrapY = wrapX.y; + } this._renderer.states.setValue('textureWrapX', wrapX); this._renderer.states.setValue('textureWrapY', wrapY); - for (const texture of this._renderer.textures.values()) { - texture.setWrapMode(wrapX, wrapY); + if (this._renderer.textures) { + for (const texture of this._renderer.textures.values()) { + texture.setWrapMode(wrapX, wrapY); + } } + return this; }; /** diff --git a/test/unit/core/properties.js b/test/unit/core/properties.js index 34bb499114..04e44b3978 100644 --- a/test/unit/core/properties.js +++ b/test/unit/core/properties.js @@ -18,7 +18,6 @@ suite('Set/get properties', function() { });*/ let getters = { - background: new p5.Color([100, 100, 50]), fill: new p5.Color([100, 200, 50]), stroke: new p5.Color([200, 100, 50, 100]), tint: new p5.Color([100, 140, 50]), @@ -28,6 +27,7 @@ suite('Set/get properties', function() { blendMode: 'source-over', imageMode: p.CORNER, ellipseMode: p.CORNER, + angleMode: p.DEGREES, strokeWeight: 6, strokeCap: p.ROUND, @@ -35,11 +35,12 @@ suite('Set/get properties', function() { pixelDensity: 1, cursor: 'pointer', - // rotate: p.PI, - // translate: { x: 1, y: 2 }, - // scale: { x: 1, y: 2 }, bezierOrder: 2, splineProperties: { ends: p.EXCLUDE, tightness: -5 }, + + textureMode: p.IMAGE, // 3D only + textureWrap: { x: p.REPEAT, y: p.MIRROR }, // 3D only + textAlign: { horizontal: p.CENTER, vertical: p.CENTER }, textLeading: 18, textFont: 'arial', @@ -48,6 +49,12 @@ suite('Set/get properties', function() { textWrap: p.WORD, textDirection: 1, textWeight: 1 + + // rotate: p.PI, see #8278 + // translate: { x: 1, y: 2 }, + // scale: { x: 1, y: 2 }, + // background: new p5.Color([100, 100, 50]), + }; Object.keys(getters).forEach(prop => { @@ -62,7 +69,7 @@ suite('Set/get properties', function() { p[prop](...arg); // set with array } else { - p[prop](arg); // set with primitive + p[prop](arg); // set with primitive or p5.Color } // getter assert.strictEqual(p[prop]().toString(), arg.toString(), `${arg.toString()}`); From f87df11565fce36d530950d5a9e2a37f0927f763 Mon Sep 17 00:00:00 2001 From: dhowe Date: Sun, 1 Feb 2026 14:17:09 +0000 Subject: [PATCH 09/21] update fes data --- docs/parameterData.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/parameterData.json b/docs/parameterData.json index bb83f10368..6de82636f3 100644 --- a/docs/parameterData.json +++ b/docs/parameterData.json @@ -162,7 +162,6 @@ }, "background": { "overloads": [ - [], [ "p5.Color" ], @@ -2969,7 +2968,8 @@ "overloads": [ [ "IMAGE|NORMAL" - ] + ], + [] ] }, "textureWrap": { @@ -2977,7 +2977,8 @@ [ "CLAMP|REPEAT|MIRROR", "CLAMP|REPEAT|MIRROR?" - ] + ], + [] ] }, "normalMaterial": { From 67bd05b55e90bcca0afd0d5111434bf1be544a06 Mon Sep 17 00:00:00 2001 From: dhowe Date: Mon, 16 Feb 2026 16:56:49 +0000 Subject: [PATCH 10/21] fix to #8469 in dev-2.0 --- src/type/textCore.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/type/textCore.js b/src/type/textCore.js index 345267fa4c..c1f13531b8 100644 --- a/src/type/textCore.js +++ b/src/type/textCore.js @@ -1790,6 +1790,11 @@ function textCore(p5, fn) { return { bounds, lines }; }; + Renderer.prototype._trimEnd = function (str) { + // trim trailing linebreaks and whitespace only + return str.replace(/[\s\n]+$/, ''); + }; + /* Adjust width, height of bounds based on current rectMode * @private @@ -2247,13 +2252,13 @@ function textCore(p5, fn) { testLine = `${line + words[widx]}` + splitter; testWidth = this._textWidthSingle(testLine); if (line.length > 0 && testWidth > maxWidth) { - newLines.push(line.trim()); + newLines.push(this._trimEnd(line)); line = `${words[widx]}` + splitter; } else { line = testLine; } } - newLines.push(line.trim()); + newLines.push(this._trimEnd(line)); } return newLines; }; From 0f82b9b4b5edbe22dbb9495f692290a3edfeaaa0 Mon Sep 17 00:00:00 2001 From: dhowe Date: Mon, 16 Feb 2026 16:59:47 +0000 Subject: [PATCH 11/21] Revert "fix to #8469 in dev-2.0" This reverts commit 67bd05b55e90bcca0afd0d5111434bf1be544a06. --- src/type/textCore.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/type/textCore.js b/src/type/textCore.js index c1f13531b8..345267fa4c 100644 --- a/src/type/textCore.js +++ b/src/type/textCore.js @@ -1790,11 +1790,6 @@ function textCore(p5, fn) { return { bounds, lines }; }; - Renderer.prototype._trimEnd = function (str) { - // trim trailing linebreaks and whitespace only - return str.replace(/[\s\n]+$/, ''); - }; - /* Adjust width, height of bounds based on current rectMode * @private @@ -2252,13 +2247,13 @@ function textCore(p5, fn) { testLine = `${line + words[widx]}` + splitter; testWidth = this._textWidthSingle(testLine); if (line.length > 0 && testWidth > maxWidth) { - newLines.push(this._trimEnd(line)); + newLines.push(line.trim()); line = `${words[widx]}` + splitter; } else { line = testLine; } } - newLines.push(this._trimEnd(line)); + newLines.push(line.trim()); } return newLines; }; From 3559fadd4d9279336fbd39285464da1fb5dad145 Mon Sep 17 00:00:00 2001 From: dhowe Date: Mon, 23 Mar 2026 16:13:41 +0000 Subject: [PATCH 12/21] fix to bug with color in tint --- src/image/loading_displaying.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 3f6548032a..1ad7a9c80a 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1249,7 +1249,7 @@ function loadingDisplaying(p5, fn){ } if (args && args.length) { const c = this.color(...args); - this._renderer.states.setValue('tint', c._getRGBA([255, 255, 255, 255])); + this._renderer.states.setValue('tint', c); } return this; }; From 4c51317f82106221d6b55c8d0b3c7023152b3287 Mon Sep 17 00:00:00 2001 From: dhowe Date: Mon, 23 Mar 2026 17:14:58 +0000 Subject: [PATCH 13/21] merge from dev2.0 --- docs/parameterData.json | 38 +++++++++++++++++++++++--------- test/unit/core/properties.js | 20 +++++------------ test/unit/webgl/p5.RendererGL.js | 33 ++++++++++++++++++--------- 3 files changed, 56 insertions(+), 35 deletions(-) diff --git a/docs/parameterData.json b/docs/parameterData.json index 6cf76f3c4a..41da80e4ab 100644 --- a/docs/parameterData.json +++ b/docs/parameterData.json @@ -305,6 +305,7 @@ }, "ellipseMode": { "overloads": [ + [], [ "CENTER|RADIUS|CORNER|CORNERS" ] @@ -808,6 +809,7 @@ }, "rectMode": { "overloads": [ + [], [ "CENTER|RADIUS|CORNER|CORNERS" ] @@ -878,7 +880,8 @@ "ARROW|CROSS|HAND|MOVE|TEXT|WAIT|String", "Number?", "Number?" - ] + ], + [] ] }, "createElement": { @@ -1086,7 +1089,8 @@ "overloads": [ [ "ROUND|SQUARE|PROJECT" - ] + ], + [] ] }, "lerp": { @@ -1292,7 +1296,8 @@ "overloads": [ [ "MITER|BEVEL|ROUND" - ] + ], + [] ] }, "noCursor": { @@ -1391,7 +1396,8 @@ "overloads": [ [ "Number" - ] + ], + [] ] }, "degrees": { @@ -2268,6 +2274,7 @@ }, "colorMode": { "overloads": [ + [], [ "RGB|HSB|HSL|RGBHDR|HWB|LAB|LCH|OKLAB|OKLCH", "Number?" @@ -2492,6 +2499,7 @@ }, "tint": { "overloads": [ + [], [ "Number", "Number", @@ -2631,6 +2639,7 @@ }, "fill": { "overloads": [ + [], [ "Number", "Number", @@ -2680,7 +2689,8 @@ [ "LEFT|CENTER|RIGHT?", "TOP|BOTTOM|CENTER|BASELINE?" - ] + ], + [] ] }, "textAscent": { @@ -2701,7 +2711,8 @@ "overloads": [ [ "Number?" - ] + ], + [] ] }, "textFont": { @@ -2709,7 +2720,8 @@ [ "p5.Font|String|Object?", "Number?" - ] + ], + [] ] }, "textSize": { @@ -2854,6 +2866,7 @@ }, "imageMode": { "overloads": [ + [], [ "CORNER|CORNERS|CENTER" ] @@ -2983,6 +2996,7 @@ }, "stroke": { "overloads": [ + [], [ "Number", "Number", @@ -3227,6 +3241,7 @@ }, "blendMode": { "overloads": [ + [], [ "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|REMOVE|SUBTRACT" ] @@ -3298,7 +3313,8 @@ "overloads": [ [ "Object" - ] + ], + [] ] }, "linePerspective": { @@ -3387,7 +3403,8 @@ "overloads": [ [ "IMAGE|NORMAL" - ] + ], + [] ] }, "setCamera": { @@ -3409,7 +3426,8 @@ [ "CLAMP|REPEAT|MIRROR", "CLAMP|REPEAT|MIRROR?" - ] + ], + [] ] }, "normalMaterial": { diff --git a/test/unit/core/properties.js b/test/unit/core/properties.js index 04e44b3978..e7def6900e 100644 --- a/test/unit/core/properties.js +++ b/test/unit/core/properties.js @@ -7,16 +7,6 @@ suite('Set/get properties', function() { sketch.draw = function () { }; }); - /*beforeEach(function () { - myp5 = new p5(function (p) { - p.setup = function () { }; - p.draw = function () { }; - }); - }); - afterEach(function () { - myp5.remove(); - });*/ - let getters = { fill: new p5.Color([100, 200, 50]), stroke: new p5.Color([200, 100, 50, 100]), @@ -24,7 +14,7 @@ suite('Set/get properties', function() { rectMode: p.CENTER, colorMode: p.HSB, - blendMode: 'source-over', + blendMode: p.BLEND, imageMode: p.CORNER, ellipseMode: p.CORNER, angleMode: p.DEGREES, @@ -32,8 +22,8 @@ suite('Set/get properties', function() { strokeWeight: 6, strokeCap: p.ROUND, strokeJoin: p.MITER, + cursor: p.HAND, pixelDensity: 1, - cursor: 'pointer', bezierOrder: 2, splineProperties: { ends: p.EXCLUDE, tightness: -5 }, @@ -50,11 +40,11 @@ suite('Set/get properties', function() { textDirection: 1, textWeight: 1 - // rotate: p.PI, see #8278 + // see #8278 + // rotate: p.PI, // translate: { x: 1, y: 2 }, // scale: { x: 1, y: 2 }, - // background: new p5.Color([100, 100, 50]), - + // background: new p5.Color([100, 100, 50]) }; Object.keys(getters).forEach(prop => { diff --git a/test/unit/webgl/p5.RendererGL.js b/test/unit/webgl/p5.RendererGL.js index b42562051f..5cb1c7f82d 100644 --- a/test/unit/webgl/p5.RendererGL.js +++ b/test/unit/webgl/p5.RendererGL.js @@ -1495,28 +1495,41 @@ suite('p5.RendererGL', function() { assert.deepEqual(myp5._renderer.states.tint, [255, 255, 255, 255]); }); + + test('tint value is modified correctly when tint() is called', function() { + + function assertDeepEqualColor(actual, expected) { + if (typeof actual === 'string' && typeof expected === 'string') { + assert.equal(actual, expected); + } else { + assert.equal(actual.toString(), myp5.color(expected).toString()); + } + } myp5.createCanvas(100, 100, myp5.WEBGL); myp5.tint(0, 153, 204, 126); - assert.deepEqual(myp5._renderer.states.tint, [0, 153, 204, 126]); + assertDeepEqualColor(myp5._renderer.states.tint, [0, 153, 204, 126]); myp5.tint(100, 120, 140); - assert.deepEqual(myp5._renderer.states.tint, [100, 120, 140, 255]); + assertDeepEqualColor(myp5._renderer.states.tint, [100, 120, 140, 255]); myp5.tint('violet'); - assert.deepEqual(myp5._renderer.states.tint, [238, 130, 238, 255]); + // Note that in WEBGL mode, we don't convert color strings to arrays until the shader, + // so the tint state is still the string 'violet' at this point, not the array [238, 130, 238, 255]. + //assertDeepEqualColor(myp5._renderer.states.tint, [238, 130, 238, 255]); + assertDeepEqualColor(myp5._renderer.states.tint, 'violet'); myp5.tint(100); - assert.deepEqual(myp5._renderer.states.tint, [100, 100, 100, 255]); + assertDeepEqualColor(myp5._renderer.states.tint, [100, 100, 100, 255]); myp5.tint(100, 126); - assert.deepEqual(myp5._renderer.states.tint, [100, 100, 100, 126]); + assertDeepEqualColor(myp5._renderer.states.tint, [100, 100, 100, 126]); myp5.tint([100, 126, 0, 200]); - assert.deepEqual(myp5._renderer.states.tint, [100, 126, 0, 200]); + assertDeepEqualColor(myp5._renderer.states.tint, [100, 126, 0, 200]); myp5.tint([100, 126, 0]); - assert.deepEqual(myp5._renderer.states.tint, [100, 126, 0, 255]); + assertDeepEqualColor(myp5._renderer.states.tint, [100, 126, 0, 255]); myp5.tint([100]); - assert.deepEqual(myp5._renderer.states.tint, [100, 100, 100, 255]); + assertDeepEqualColor(myp5._renderer.states.tint, [100, 100, 100, 255]); myp5.tint([100, 126]); - assert.deepEqual(myp5._renderer.states.tint, [100, 100, 100, 126]); + assertDeepEqualColor(myp5._renderer.states.tint, [100, 100, 100, 126]); myp5.tint(myp5.color(255, 204, 0)); - assert.deepEqual(myp5._renderer.states.tint, [255, 204, 0, 255]); + assertDeepEqualColor(myp5._renderer.states.tint, [255, 204, 0, 255]); }); test('tint should be reset after draw loop', function() { From d22cd36fa7e381f0800f6db067aa8a97fce539ce Mon Sep 17 00:00:00 2001 From: dhowe Date: Mon, 23 Mar 2026 23:02:13 +0000 Subject: [PATCH 14/21] using 255 range for tint in shaders --- src/core/p5.Renderer3D.js | 8 ++++---- src/image/loading_displaying.js | 6 ++---- test/unit/webgl/p5.RendererGL.js | 26 ++++++++++++++------------ 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/core/p5.Renderer3D.js b/src/core/p5.Renderer3D.js index 4241a56157..129d40df84 100644 --- a/src/core/p5.Renderer3D.js +++ b/src/core/p5.Renderer3D.js @@ -132,7 +132,7 @@ export class Renderer3D extends Renderer { this.states._useShininess = 1; this.states._useMetalness = 0; - this.states.tint = [255, 255, 255, 255]; + this.states.tint = new Color([255, 255, 255, 255]); this.states.constantAttenuation = 1; this.states.linearAttenuation = 0; @@ -721,10 +721,10 @@ export class Renderer3D extends Renderer { this.states.setValue("enableLighting", false); //reset tint value for new frame - this.states.setValue("tint", [255, 255, 255, 255]); + this.states.setValue("tint", new Color([255, 255, 255, 255])); //Clear depth every frame - this._resetBuffersBeforeDraw() + this._resetBuffersBeforeDraw(); } background(...args) { @@ -1486,7 +1486,7 @@ export class Renderer3D extends Renderer { // works differently and is global p5 state. If the p5 state has // been cleared, we also need to clear the value in uSampler to match. fillShader.setUniform("uSampler", this.states._tex || empty); - fillShader.setUniform("uTint", this.states.tint); + fillShader.setUniform("uTint", this.states.tint.array().map(v => v * 255)); fillShader.setUniform("uHasSetAmbient", this.states._hasSetAmbient); fillShader.setUniform("uAmbientMatColor", this.states.curAmbientColor); diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 1ad7a9c80a..60c5e5d045 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1243,13 +1243,11 @@ function loadingDisplaying(p5, fn){ * @param {p5.Color} color the tint color */ fn.tint = function(...args) { - // p5._validateParameters('tint', args); if (args.length === 0) { - return this.color(this._renderer.states.tint); // getter + return this._renderer.states.tint; // getter } if (args && args.length) { - const c = this.color(...args); - this._renderer.states.setValue('tint', c); + this._renderer.states.setValue('tint', this.color(...args)); } return this; }; diff --git a/test/unit/webgl/p5.RendererGL.js b/test/unit/webgl/p5.RendererGL.js index 5cb1c7f82d..a2e29f76ce 100644 --- a/test/unit/webgl/p5.RendererGL.js +++ b/test/unit/webgl/p5.RendererGL.js @@ -1492,7 +1492,7 @@ suite('p5.RendererGL', function() { suite('tint() in WEBGL mode', function() { test('default tint value is set and not null', function() { myp5.createCanvas(100, 100, myp5.WEBGL); - assert.deepEqual(myp5._renderer.states.tint, [255, 255, 255, 255]); + assert.deepEqual(myp5._renderer.states.tint.array(), [255, 255, 255, 255]); }); @@ -1508,28 +1508,30 @@ suite('p5.RendererGL', function() { } myp5.createCanvas(100, 100, myp5.WEBGL); myp5.tint(0, 153, 204, 126); - assertDeepEqualColor(myp5._renderer.states.tint, [0, 153, 204, 126]); + assertDeepEqualColor(myp5._renderer.states.tint.array(), [0, 153, 204, 126]); myp5.tint(100, 120, 140); - assertDeepEqualColor(myp5._renderer.states.tint, [100, 120, 140, 255]); + assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 120, 140, 255]); + myp5.tint('violet'); // Note that in WEBGL mode, we don't convert color strings to arrays until the shader, // so the tint state is still the string 'violet' at this point, not the array [238, 130, 238, 255]. - //assertDeepEqualColor(myp5._renderer.states.tint, [238, 130, 238, 255]); - assertDeepEqualColor(myp5._renderer.states.tint, 'violet'); + //assertDeepEqualColor(myp5._renderer.states.tint.array(), [238, 130, 238, 255]); + assertDeepEqualColor(myp5._renderer.states.tint.array(), 'violet'); + myp5.tint(100); - assertDeepEqualColor(myp5._renderer.states.tint, [100, 100, 100, 255]); + assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 100, 100, 255]); myp5.tint(100, 126); - assertDeepEqualColor(myp5._renderer.states.tint, [100, 100, 100, 126]); + assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 100, 100, 126]); myp5.tint([100, 126, 0, 200]); - assertDeepEqualColor(myp5._renderer.states.tint, [100, 126, 0, 200]); + assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 126, 0, 200]); myp5.tint([100, 126, 0]); - assertDeepEqualColor(myp5._renderer.states.tint, [100, 126, 0, 255]); + assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 126, 0, 255]); myp5.tint([100]); - assertDeepEqualColor(myp5._renderer.states.tint, [100, 100, 100, 255]); + assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 100, 100, 255]); myp5.tint([100, 126]); - assertDeepEqualColor(myp5._renderer.states.tint, [100, 100, 100, 126]); + assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 100, 100, 126]); myp5.tint(myp5.color(255, 204, 0)); - assertDeepEqualColor(myp5._renderer.states.tint, [255, 204, 0, 255]); + assertDeepEqualColor(myp5._renderer.states.tint.array(), [255, 204, 0, 255]); }); test('tint should be reset after draw loop', function() { From f9460f4a560266ee93a38d79595e78eba58e4f2f Mon Sep 17 00:00:00 2001 From: dhowe Date: Mon, 23 Mar 2026 23:26:01 +0000 Subject: [PATCH 15/21] fix tint-related gl tests --- src/core/p5.Renderer3D.js | 4 ++-- test/unit/webgl/p5.RendererGL.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/p5.Renderer3D.js b/src/core/p5.Renderer3D.js index 129d40df84..5f29e7a60c 100644 --- a/src/core/p5.Renderer3D.js +++ b/src/core/p5.Renderer3D.js @@ -132,7 +132,7 @@ export class Renderer3D extends Renderer { this.states._useShininess = 1; this.states._useMetalness = 0; - this.states.tint = new Color([255, 255, 255, 255]); + this.states.tint = new Color([1, 1, 1, 1]); this.states.constantAttenuation = 1; this.states.linearAttenuation = 0; @@ -721,7 +721,7 @@ export class Renderer3D extends Renderer { this.states.setValue("enableLighting", false); //reset tint value for new frame - this.states.setValue("tint", new Color([255, 255, 255, 255])); + this.states.setValue("tint", new Color([1,1,1,1])); //Clear depth every frame this._resetBuffersBeforeDraw(); diff --git a/test/unit/webgl/p5.RendererGL.js b/test/unit/webgl/p5.RendererGL.js index a2e29f76ce..10976c6b51 100644 --- a/test/unit/webgl/p5.RendererGL.js +++ b/test/unit/webgl/p5.RendererGL.js @@ -1492,7 +1492,7 @@ suite('p5.RendererGL', function() { suite('tint() in WEBGL mode', function() { test('default tint value is set and not null', function() { myp5.createCanvas(100, 100, myp5.WEBGL); - assert.deepEqual(myp5._renderer.states.tint.array(), [255, 255, 255, 255]); + assert.deepEqual(myp5._renderer.states.tint.array(), [1,1,1,1]); }); @@ -1503,7 +1503,7 @@ suite('p5.RendererGL', function() { if (typeof actual === 'string' && typeof expected === 'string') { assert.equal(actual, expected); } else { - assert.equal(actual.toString(), myp5.color(expected).toString()); + assert.deepEqual(actual, myp5.color(expected).array()); } } myp5.createCanvas(100, 100, myp5.WEBGL); @@ -1548,7 +1548,7 @@ suite('p5.RendererGL', function() { }; }); }).then(function(_tint) { - assert.deepEqual(_tint, [255, 255, 255, 255]); + assert.deepEqual(_tint.array(), [1, 1, 1, 1]); }); }); }); From 19c68510d2f2d34c292bb0abf2b82f4f14709862 Mon Sep 17 00:00:00 2001 From: dhowe Date: Tue, 24 Mar 2026 16:28:26 +0000 Subject: [PATCH 16/21] first pass at updating jsdocs for setters --- src/color/setting.js | 12 ++++++++++++ src/image/loading_displaying.js | 10 ++++++++++ src/shape/attributes.js | 6 ++++++ 3 files changed, 28 insertions(+) diff --git a/src/color/setting.js b/src/color/setting.js index 35181f9b19..84fab6182c 100644 --- a/src/color/setting.js +++ b/src/color/setting.js @@ -1095,6 +1095,8 @@ function setting(p5, fn){ * or `HSLA` colors, depending on the current colorMode(). The last parameter * sets the alpha (transparency) value. * + * Calling `fill()` without an argument returns the current fill as a p5.Color object. + * * @method fill * @param {Number} v1 red value if color mode is RGB or hue value if color mode is HSB. * @param {Number} v2 green value if color mode is RGB or saturation value if color mode is HSB. @@ -1283,6 +1285,10 @@ function setting(p5, fn){ * @param {p5.Color} color the fill color. * @chainable */ + /** + * @method fill + * @return {p5.Color} the current fill color. + */ fn.fill = function(...args) { return this._renderer.fill(...args); }; @@ -1413,6 +1419,8 @@ function setting(p5, fn){ * or HSLA colors, depending on the current `colorMode()`. The last parameter * sets the alpha (transparency) value. * + * Calling `stroke()` without an argument returns the current stroke as a p5.Color object. + * * @method stroke * @param {Number} v1 red value if color mode is RGB or hue value if color mode is HSB. * @param {Number} v2 green value if color mode is RGB or saturation value if color mode is HSB. @@ -1599,6 +1607,10 @@ function setting(p5, fn){ * @param {p5.Color} color the stroke color. * @chainable */ + /** + * @method stroke + * @return {p5.Color} the current stroke color. + */ fn.stroke = function(...args) { return this._renderer.stroke(...args); }; diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 60c5e5d045..1e068964b7 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1138,6 +1138,12 @@ function loadingDisplaying(p5, fn){ * sets the alpha value. For example, `tint(255, 0, 0, 100)` will give images * a red tint and make them transparent. * + * Calling `tint()` without an argument returns the current tint as a p5.Color object. + * + * @method frameRate + * @param {Number} fps number of frames to draw per second. + * @chainable + * * @method tint * @param {Number} v1 red or hue value. * @param {Number} v2 green or saturation value. @@ -1242,6 +1248,10 @@ function loadingDisplaying(p5, fn){ * @method tint * @param {p5.Color} color the tint color */ + /** + * @method tint + * @return {p5.Color} the current tint color + */ fn.tint = function(...args) { if (args.length === 0) { return this._renderer.states.tint; // getter diff --git a/src/shape/attributes.js b/src/shape/attributes.js index e8a942d08f..77ac58ce0c 100644 --- a/src/shape/attributes.js +++ b/src/shape/attributes.js @@ -189,6 +189,8 @@ function attributes(p5, fn){ * constants `CENTER`, `RADIUS`, `CORNER`, and `CORNERS` are defined this way. * JavaScript is a case-sensitive language. * + * Calling `rectMode()` without an argument returns the current rectMode, either `CORNER`, `CORNERS`, `CENTER`, or `RADIUS`. + * * @method rectMode * @param {(CENTER|RADIUS|CORNER|CORNERS)} mode either CORNER, CORNERS, CENTER, or RADIUS * @chainable @@ -257,6 +259,10 @@ function attributes(p5, fn){ * describe('A small gray square drawn at the center of a white square.'); * } */ + /** + * @method rectMode + * @return {(CENTER|RADIUS|CORNER|CORNERS)} the current rectMode. + */ fn.rectMode = function(m) { // p5._validateParameters('rectMode', arguments); if (typeof m === 'undefined') { // getter From 85d6cccdaf270d617d126d5555cf22592b38aef2 Mon Sep 17 00:00:00 2001 From: dhowe Date: Tue, 24 Mar 2026 17:25:59 +0000 Subject: [PATCH 17/21] updated inline jsdocs for all setters that have them --- src/color/setting.js | 6 ++++++ src/core/environment.js | 6 ++++++ src/image/loading_displaying.js | 6 ++++++ src/shape/attributes.js | 18 ++++++++++++++++++ src/shape/custom_shapes.js | 2 ++ src/webgl/material.js | 13 +++++++++++++ 6 files changed, 51 insertions(+) diff --git a/src/color/setting.js b/src/color/setting.js index 84fab6182c..cae961600b 100644 --- a/src/color/setting.js +++ b/src/color/setting.js @@ -1777,6 +1777,8 @@ function setting(p5, fn){ * EXCLUSION, SCREEN, REPLACE, OVERLAY, HARD_LIGHT, * SOFT_LIGHT, DODGE, BURN, ADD, REMOVE or SUBTRACT * + * Calling `blendMode()` without an argument returns the current blendMode. + * * @example * function setup() { * createCanvas(100, 100); @@ -2145,6 +2147,10 @@ function setting(p5, fn){ * describe('A yellow line and a turquoise line form an X on a gray background. The area where they overlap is green.'); * } */ + /** + * @method blendMode + * @return {(BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|REMOVE|SUBTRACT)} the current blend mode. + */ fn.blendMode = function (mode) { // p5._validateParameters('blendMode', arguments); if (mode === constants.NORMAL) { diff --git a/src/core/environment.js b/src/core/environment.js index de036e0218..6fffe81973 100644 --- a/src/core/environment.js +++ b/src/core/environment.js @@ -215,6 +215,8 @@ function environment(p5, fn, lifecycles){ * cursor, `x` and `y` set the location pointed to within the image. They are * both 0 by default, so the cursor points to the image's top-left corner. `x` * and `y` must be less than the image's width and height, respectively. + * + * Calling `cursor()` without an argument returns the current cursor type as a string. * * @method cursor * @param {(ARROW|CROSS|HAND|MOVE|TEXT|WAIT|String)} type Built-in: either ARROW, CROSS, HAND, MOVE, TEXT, or WAIT. @@ -281,6 +283,10 @@ function environment(p5, fn, lifecycles){ * } * } */ + /** + * @method cursor + * @return {(ARROW|CROSS|HAND|MOVE|TEXT|WAIT|String)} the current cursor type + */ fn.cursor = function(type, x, y) { let cursor = 'auto'; const canvas = this._curElement.elt; diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 1e068964b7..bc199c1544 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1325,6 +1325,8 @@ function loadingDisplaying(p5, fn){ * image() as the x- and y-coordinates of the image's * center. The next parameters are its width and height. * + * Calling `imageMode()` without an argument returns the current image mode, either `CORNER`, `CORNERS`, or `CENTER`. + * * @method imageMode * @param {(CORNER|CORNERS|CENTER)} mode either CORNER, CORNERS, or CENTER. * @@ -1388,6 +1390,10 @@ function loadingDisplaying(p5, fn){ * describe('A square image of a brick wall is drawn on a gray square.'); * } */ + /** + * @method imageMode + * @return {(CORNER|CORNERS|CENTER)} the current image mode + */ fn.imageMode = function(m) { // p5._validateParameters('imageMode', arguments); if (typeof m === 'undefined') { // getter diff --git a/src/shape/attributes.js b/src/shape/attributes.js index 77ac58ce0c..812159267f 100644 --- a/src/shape/attributes.js +++ b/src/shape/attributes.js @@ -35,6 +35,8 @@ function attributes(p5, fn){ * the constants `CENTER`, `RADIUS`, `CORNER`, and `CORNERS` are defined this * way. JavaScript is a case-sensitive language. * + * Calling `ellipseMode()` without an argument returns the current ellipseMode, either `CENTER`, `RADIUS`, `CORNER`, or `CORNERS`. + * * @method ellipseMode * @param {(CENTER|RADIUS|CORNER|CORNERS)} mode either CENTER, RADIUS, CORNER, or CORNERS * @chainable @@ -77,6 +79,10 @@ function attributes(p5, fn){ * describe('A white circle with a gray circle at its top-left corner. Both circles have black outlines.'); * } */ + /** + * @method ellipseMode + * @return {(CENTER|RADIUS|CORNER|CORNERS)} the current ellipseMode. + */ fn.ellipseMode = function(m) { // p5._validateParameters('ellipseMode', arguments); if (typeof m === 'undefined') { // getter @@ -416,6 +422,8 @@ function attributes(p5, fn){ * the constants `MITER`, `BEVEL`, and `ROUND` are defined this way. * JavaScript is a case-sensitive language. * + * Calling `strokeJoin()` without an argument returns the current stroke join style, either `MITER`, `BEVEL`, or `ROUND`. + * * @method strokeJoin * @param {(MITER|BEVEL|ROUND)} join either MITER, BEVEL, or ROUND * @chainable @@ -482,6 +490,10 @@ function attributes(p5, fn){ * describe('A right-facing arrowhead shape with a rounded tip in center of canvas.'); * } */ + /** + * @method strokeJoin + * @return {(MITER|BEVEL|ROUND)} the current stroke join style. + */ fn.strokeJoin = function(join) { // p5._validateParameters('strokeJoin', arguments); if (typeof join === 'undefined') { // getter @@ -503,6 +515,8 @@ function attributes(p5, fn){ * * Note: `strokeWeight()` is affected by transformations, especially calls to * scale(). + * + * Calling `strokeWeight()` without an argument returns the current stroke weight as a number. * * @method strokeWeight * @param {Number} weight the weight of the stroke (in pixels). @@ -545,6 +559,10 @@ function attributes(p5, fn){ * describe('Two horizontal black lines. The top line is thin and the bottom is five times thicker than the top.'); * } */ + /** + * @method strokeWeight + * @return {Number} the current stroke weight. + */ fn.strokeWeight = function(w) { // p5._validateParameters('strokeWeight', arguments); return this._renderer.strokeWeight(w); diff --git a/src/shape/custom_shapes.js b/src/shape/custom_shapes.js index 3a09200f75..f287a4823e 100644 --- a/src/shape/custom_shapes.js +++ b/src/shape/custom_shapes.js @@ -1611,6 +1611,8 @@ function customShapes(p5, fn) { * Note: `bezierVertex()` won’t work when an argument is passed to * beginShape(). * + * Calling `bezierOrder()` without an argument returns the current Bézier order. + * * @method bezierOrder * @param {Number} order The new order to set. Can be either 2 or 3, by default 3 * diff --git a/src/webgl/material.js b/src/webgl/material.js index 8b0664eca1..3d0378e26e 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -2652,6 +2652,8 @@ function material(p5, fn) { * * Note: `textureMode()` can only be used in WebGL mode. * + * Calling `textureMode()` with no arguments returns the current texture mode. + * * @method textureMode * @param {(IMAGE|NORMAL)} mode either IMAGE or NORMAL. * @@ -2714,6 +2716,10 @@ function material(p5, fn) { * endShape(); * } */ + /** + * @method textureMode + * @return {(IMAGE|NORMAL)} The current texture mode, either IMAGE or NORMAL. + */ fn.textureMode = function (mode) { if (typeof mode === 'undefined') { // getter return this._renderer.states.textureMode; @@ -2825,6 +2831,9 @@ function material(p5, fn) { * * Note: `textureWrap()` can only be used in WebGL mode. * + * Calling `textureWrap()` with no arguments returns an object with the current + * mode for x and y directions, as in `{ wrapX: CLAMP, wrapY: REPEAT }`. + * * @method textureWrap * @param {(CLAMP|REPEAT|MIRROR)} wrapX either CLAMP, REPEAT, or MIRROR * @param {(CLAMP|REPEAT|MIRROR)} [wrapY=wrapX] either CLAMP, REPEAT, or MIRROR @@ -2980,6 +2989,10 @@ function material(p5, fn) { * endShape(); * } */ + /** + * @method textureWrap + * @return {{x: (CLAMP|REPEAT|MIRROR), y: (CLAMP|REPEAT|MIRROR)}} The current texture wrapping for x and y. + */ fn.textureWrap = function (wrapX, wrapY = wrapX) { if (typeof wrapX === 'undefined') { // getter return { From 1a408afb327b04e1ebedefbabf49225e0ca4067e Mon Sep 17 00:00:00 2001 From: dhowe Date: Tue, 24 Mar 2026 17:27:31 +0000 Subject: [PATCH 18/21] remove no-longer used decomposeMatrix function --- src/math/trigonometry.js | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/src/math/trigonometry.js b/src/math/trigonometry.js index eb3b20efa9..d2c5491b7d 100644 --- a/src/math/trigonometry.js +++ b/src/math/trigonometry.js @@ -204,33 +204,6 @@ function trigonometry(p5, fn){ return this._fromRadians(Math.asin(ratio)); }; - fn.decomposeMatrix = function(mat) { - // adapted from https://frederic-wang.fr/2013/12/01/decomposition-of-2d-transform-matrices/ - let { a, b, c, d, e, f } = mat; - let delta = a * d - b * c; - let result = { - translation: { x: e, y: f }, - scale: { x: 0, y: 0 }, - shear: { x: 0, y: 0 }, - rotation: 0 - }; - if (a !== 0 || b !== 0) { - let r = Math.sqrt(a * a + b * b); - result.rotation = b > 0 ? Math.acos(a / r) : -Math.acos(a / r); - result.scale = { x: r, y: delta / r }; - result.shear = { x: Math.atan((a * c + b * d) / (r * r)), y: 0 }; - } else if (c !== 0 || d !== 0) { - let s = Math.sqrt(c * c + d * d); - result.rotation = Math.PI / 2 - - (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s)); - result.scale = { x: delta / s, y: s }; - result.shear = { x: 0, y: Math.atan((a * c + b * d) / (s * s)) }; - } else { - // a = b = c = d = 0 - } - return result; - }; - /** * Calculates the arc tangent of a number. * From acc319a4253cd59ed399fd3e4c0846f4ce6df99d Mon Sep 17 00:00:00 2001 From: dhowe Date: Wed, 25 Mar 2026 01:18:27 +0000 Subject: [PATCH 19/21] fixes from reviewer --- src/core/p5.Renderer.js | 1 - src/core/p5.Renderer2D.js | 5 ---- src/image/loading_displaying.js | 7 ++--- src/type/textCore.js | 42 ++++++++++++++++----------- test/unit/webgl/p5.RendererGL.js | 49 ++++++++++++++++++-------------- 5 files changed, 55 insertions(+), 49 deletions(-) diff --git a/src/core/p5.Renderer.js b/src/core/p5.Renderer.js index ce8b1f2b06..f9caac7793 100644 --- a/src/core/p5.Renderer.js +++ b/src/core/p5.Renderer.js @@ -35,7 +35,6 @@ class ClonableObject { class Renderer { static states = { - background: null, strokeColor: null, strokeSet: false, fillColor: null, diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index 459802a44b..a98f60f339 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -168,9 +168,7 @@ class Renderer2D extends Renderer { background(...args) { if (args.length === 0) { return this;// setter with no args does nothing - //return this.states.background; // getter (#8278) } - let bgForState = null; this.push(); this.resetMatrix(); if (args[0] instanceof Image) { @@ -180,7 +178,6 @@ class Renderer2D extends Renderer { this.drawingContext.globalAlpha = args[1] / 255; } this._pInst.image(img, 0, 0, this.width, this.height); - bgForState = img; // save for getter (#8278) } else { // create background rect const color = this._pInst.color(...args); @@ -203,11 +200,9 @@ class Renderer2D extends Renderer { if (this._isErasing) { this._pInst.erase(); } - bgForState = color; // save for getter (#8278) } this.pop(); - this.states.setValue('background', bgForState); // set state (#8278) return this; } diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index bc199c1544..e15ee286df 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1138,11 +1138,8 @@ function loadingDisplaying(p5, fn){ * sets the alpha value. For example, `tint(255, 0, 0, 100)` will give images * a red tint and make them transparent. * - * Calling `tint()` without an argument returns the current tint as a p5.Color object. - * - * @method frameRate - * @param {Number} fps number of frames to draw per second. - * @chainable + * Calling `tint()` without an argument returns the current tint as a + * p5.Color object. * * @method tint * @param {Number} v1 red or hue value. diff --git a/src/type/textCore.js b/src/type/textCore.js index 64ceb4d6e1..909609ef0c 100644 --- a/src/type/textCore.js +++ b/src/type/textCore.js @@ -1459,29 +1459,37 @@ function textCore(p5, fn) { Renderer.prototype.textAlign = function (h, v) { - // the setter - if (typeof h !== 'undefined') { - // accept what is returned from the getter + if (arguments.length === 0) { // the getter + return { + horizontal: this.states.textAlign, + vertical: this.states.textBaseline + }; + } + + // allow an object with horizontal and vertical properties + if (typeof h === 'object' && h !== null) { + if (h.hasOwnProperty('vertical')) { + v = h.vertical; + } if (h.hasOwnProperty('horizontal')) { h = h.horizontal; } + } + + // horizontal value as separate argument + if (typeof h === 'string' || h instanceof String) { this.states.setValue('textAlign', h); - if (h.hasOwnProperty('vertical') && typeof v === 'undefined') { - v = h.vertical; - } - if (typeof v !== 'undefined') { - if (v === fn.CENTER) { - v = textCoreConstants._CTX_MIDDLE; - } - this.states.setValue('textBaseline', v); + } + + // vertical value as separate argument + if (typeof v === 'string' || v instanceof String) { + if (v === fn.CENTER) { + v = textCoreConstants._CTX_MIDDLE; } - return this._applyTextProperties(); + this.states.setValue('textBaseline', v); } - // the getter - return { - horizontal: this.states.textAlign, - vertical: this.states.textBaseline - }; + + return this._applyTextProperties(); }; Renderer.prototype._currentTextFont = function () { diff --git a/test/unit/webgl/p5.RendererGL.js b/test/unit/webgl/p5.RendererGL.js index 10976c6b51..4d3eaaf7aa 100644 --- a/test/unit/webgl/p5.RendererGL.js +++ b/test/unit/webgl/p5.RendererGL.js @@ -1492,46 +1492,52 @@ suite('p5.RendererGL', function() { suite('tint() in WEBGL mode', function() { test('default tint value is set and not null', function() { myp5.createCanvas(100, 100, myp5.WEBGL); - assert.deepEqual(myp5._renderer.states.tint.array(), [1,1,1,1]); + assert.deepEqual(myp5._renderer.states.tint + ._getRGBA([255, 255, 255, 255]), [255, 255, 255, 255]); }); test('tint value is modified correctly when tint() is called', function() { - function assertDeepEqualColor(actual, expected) { - if (typeof actual === 'string' && typeof expected === 'string') { - assert.equal(actual, expected); - } else { - assert.deepEqual(actual, myp5.color(expected).array()); - } + function assertColorEq(tint, colArray) { + assert.deepEqual(tint._getRGBA([255, 255, 255, 255]), colArray); } + myp5.createCanvas(100, 100, myp5.WEBGL); + myp5.tint(0, 153, 204, 126); - assertDeepEqualColor(myp5._renderer.states.tint.array(), [0, 153, 204, 126]); + assertColorEq(myp5._renderer.states.tint, [0, 153, 204, 126]); + myp5.tint(100, 120, 140); - assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 120, 140, 255]); - + assertColorEq(myp5._renderer.states.tint, [100, 120, 140, 255]); + myp5.tint('violet'); - // Note that in WEBGL mode, we don't convert color strings to arrays until the shader, + // Note that in WEBGL mode, we don't convert color strings to arrays until the shader, // so the tint state is still the string 'violet' at this point, not the array [238, 130, 238, 255]. - //assertDeepEqualColor(myp5._renderer.states.tint.array(), [238, 130, 238, 255]); - assertDeepEqualColor(myp5._renderer.states.tint.array(), 'violet'); + //assertDeepEqualColor(myp5._renderer.states.tint, [238, 130, 238, 255]); + assert.equal(myp5._renderer.states.tint, 'violet'); myp5.tint(100); - assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 100, 100, 255]); + assertColorEq(myp5._renderer.states.tint, [100, 100, 100, 255]); + myp5.tint(100, 126); - assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 100, 100, 126]); + assertColorEq(myp5._renderer.states.tint, [100, 100, 100, 126]); + myp5.tint([100, 126, 0, 200]); - assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 126, 0, 200]); + assertColorEq(myp5._renderer.states.tint, [100, 126, 0, 200]); + myp5.tint([100, 126, 0]); - assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 126, 0, 255]); + assertColorEq(myp5._renderer.states.tint, [100, 126, 0, 255]); + myp5.tint([100]); - assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 100, 100, 255]); + assertColorEq(myp5._renderer.states.tint, [100, 100, 100, 255]); + myp5.tint([100, 126]); - assertDeepEqualColor(myp5._renderer.states.tint.array(), [100, 100, 100, 126]); + assertColorEq(myp5._renderer.states.tint, [100, 100, 100, 126]); + myp5.tint(myp5.color(255, 204, 0)); - assertDeepEqualColor(myp5._renderer.states.tint.array(), [255, 204, 0, 255]); + assertColorEq(myp5._renderer.states.tint, [255, 204, 0, 255]); }); test('tint should be reset after draw loop', function() { @@ -1548,7 +1554,8 @@ suite('p5.RendererGL', function() { }; }); }).then(function(_tint) { - assert.deepEqual(_tint.array(), [1, 1, 1, 1]); + assert.deepEqual(_tint._getRGBA([255, 255, 255, 255]), + [255, 255, 255, 255]); }); }); }); From 3d4d45e07895f6638c6b5ecff281a9f5d92543fe Mon Sep 17 00:00:00 2001 From: dhowe Date: Wed, 25 Mar 2026 01:22:08 +0000 Subject: [PATCH 20/21] fix to tint argument handling --- src/image/loading_displaying.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index e15ee286df..28149c4412 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1253,10 +1253,10 @@ function loadingDisplaying(p5, fn){ if (args.length === 0) { return this._renderer.states.tint; // getter } - if (args && args.length) { + else { this._renderer.states.setValue('tint', this.color(...args)); + return this; } - return this; }; /** From 0bf343a3cea8f906cf11474d6fb4e8805d347ce6 Mon Sep 17 00:00:00 2001 From: dhowe Date: Thu, 26 Mar 2026 18:06:59 +0000 Subject: [PATCH 21/21] fix to tint in Renderer3D --- src/core/p5.Renderer3D.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/p5.Renderer3D.js b/src/core/p5.Renderer3D.js index 5f29e7a60c..b98cb19178 100644 --- a/src/core/p5.Renderer3D.js +++ b/src/core/p5.Renderer3D.js @@ -1486,7 +1486,7 @@ export class Renderer3D extends Renderer { // works differently and is global p5 state. If the p5 state has // been cleared, we also need to clear the value in uSampler to match. fillShader.setUniform("uSampler", this.states._tex || empty); - fillShader.setUniform("uTint", this.states.tint.array().map(v => v * 255)); + fillShader.setUniform("uTint", this.states.tint._getRGBA([255, 255, 255, 255])); fillShader.setUniform("uHasSetAmbient", this.states._hasSetAmbient); fillShader.setUniform("uAmbientMatColor", this.states.curAmbientColor);