From c2afbe7fa2767f6b2899e6b27cc603256b5c583d Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Fri, 29 Aug 2025 18:33:03 +0100 Subject: [PATCH 1/2] Fix most of the eslint warnings currently generated --- rollup.config.mjs | 4 +- src/accessibility/describe.js | 8 +- src/accessibility/gridOutput.js | 3 +- src/accessibility/outputs.js | 19 +- src/app.js | 2 +- src/color/p5.Color.culori.js | 2 +- src/color/p5.Color.js | 135 +- src/color/setting.js | 56 +- src/core/environment.js | 11 +- src/core/friendly_errors/fes_core.js | 2 +- src/core/friendly_errors/param_validator.js | 77 +- src/core/friendly_errors/sketch_verifier.js | 7 +- src/core/main.js | 8 +- src/core/p5.Graphics.js | 1 - src/core/p5.Renderer.js | 28 +- src/core/p5.Renderer2D.js | 26 +- src/core/rendering.js | 8 +- src/dom/dom.js | 10 +- src/dom/p5.Element.js | 32 +- src/dom/p5.MediaElement.js | 24 +- src/events/acceleration.js | 8 +- src/events/keyboard.js | 73 +- src/events/pointer.js | 114 +- src/image/const.js | 2 +- src/image/filterRenderer2D.js | 100 +- src/image/image.js | 30 +- src/image/loading_displaying.js | 25 +- src/image/p5.Image.js | 2 +- src/io/csv.js | 196 +-- src/io/files.js | 34 +- src/io/p5.Table.js | 24 +- src/io/p5.TableRow.js | 6 +- src/io/p5.XML.js | 2 +- src/math/Matrices/Matrix.js | 34 +- src/math/Matrices/MatrixInterface.js | 68 +- src/math/Matrices/MatrixNumjs.js | 14 +- src/math/math.js | 2 +- src/math/p5.Matrix.js | 4 +- src/math/p5.Vector.js | 126 +- src/shape/2d_primitives.js | 22 +- src/shape/curves.js | 36 +- src/shape/custom_shapes.js | 596 ++++----- src/shape/vertex.js | 40 +- src/type/p5.Font.js | 466 ++++--- src/type/textCore.js | 264 ++-- src/type/unicodeRanges.js | 1318 +++++++++---------- src/webgl/3d_primitives.js | 88 +- src/webgl/GeometryBufferCache.js | 7 +- src/webgl/GeometryBuilder.js | 20 +- src/webgl/ShaderGenerator.js | 558 ++++---- src/webgl/ShapeBuilder.js | 41 +- src/webgl/light.js | 18 +- src/webgl/loading.js | 16 +- src/webgl/material.js | 22 +- src/webgl/p5.Camera.js | 46 +- src/webgl/p5.DataArray.js | 2 +- src/webgl/p5.Framebuffer.js | 2 +- src/webgl/p5.Geometry.js | 194 +-- src/webgl/p5.Quat.js | 50 +- src/webgl/p5.RenderBuffer.js | 2 +- src/webgl/p5.RendererGL.js | 727 +++++----- src/webgl/p5.Shader.js | 12 +- src/webgl/p5.Texture.js | 2 +- src/webgl/text.js | 110 +- test/unit/accessibility/outputs.js | 8 +- test/unit/color/setting.js | 12 +- test/unit/core/main.js | 6 +- test/unit/core/p5.Graphics.js | 2 +- test/unit/core/param_errors.js | 12 +- test/unit/core/sketch_overrides.js | 104 +- test/unit/core/vertex.js | 1 - test/unit/dom/dom.js | 50 +- test/unit/dom/p5.MediaElement.js | 14 +- test/unit/events/keyboard.js | 14 +- test/unit/events/touch.js | 1 - test/unit/image/downloading.js | 54 +- test/unit/image/loading.js | 8 +- test/unit/io/files.js | 3 +- test/unit/io/loadBytes.js | 6 +- test/unit/io/loadJSON.js | 8 +- test/unit/io/loadModel.js | 6 +- test/unit/io/loadShader.js | 8 +- test/unit/io/loadStrings.js | 6 +- test/unit/io/loadTable.js | 6 +- test/unit/io/loadXML.js | 8 +- test/unit/math/p5.Matrix.js | 243 ++-- test/unit/math/p5.Vector.js | 684 +++++----- test/unit/type/loading.js | 2 +- test/unit/types/generate-types.js | 221 ++-- test/unit/visual/cases/noise.js | 2 +- test/unit/visual/cases/shape_modes.js | 2 +- test/unit/visual/cases/shapes.js | 10 +- test/unit/visual/cases/typography.js | 124 +- test/unit/visual/cases/webgl.js | 53 +- test/unit/visual/visualTest.js | 148 ++- test/unit/webgl/light.js | 135 +- test/unit/webgl/p5.Camera.js | 35 +- test/unit/webgl/p5.Framebuffer.js | 10 +- test/unit/webgl/p5.RendererGL.js | 131 +- test/unit/webgl/p5.Shader.js | 20 +- utils/convert.mjs | 27 +- utils/generate-types.mjs | 12 +- utils/helper.mjs | 999 +++++++------- utils/patch.mjs | 34 +- vitest.workspace.mjs | 10 +- 105 files changed, 4922 insertions(+), 4303 deletions(-) diff --git a/rollup.config.mjs b/rollup.config.mjs index 0c48afb163..e2928ad207 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -38,7 +38,7 @@ const bundleSize = (name, sourcemap) => { const modules = ['math']; const generateModuleBuild = () => { - return modules.map((module) => { + return modules.map(module => { return { input: `src/${module}/index.js`, output: [ @@ -83,7 +83,7 @@ const generateModuleBuild = () => { }); }; -rmSync("./dist", { +rmSync('./dist', { force: true, recursive: true }); diff --git a/src/accessibility/describe.js b/src/accessibility/describe.js index 984682ee34..8a5e0a1398 100644 --- a/src/accessibility/describe.js +++ b/src/accessibility/describe.js @@ -75,11 +75,11 @@ function describe(p5, fn){ * *
* - * + * * function setup(){ * createCanvas(100, 100); * }; - * + * * function draw() { * background(200); * @@ -101,11 +101,11 @@ function describe(p5, fn){ * *
* - * + * * function setup(){ * createCanvas(100, 100); * } - * + * * function draw() { * background(200); * diff --git a/src/accessibility/gridOutput.js b/src/accessibility/gridOutput.js index a7e5513a41..ce19cb37b1 100644 --- a/src/accessibility/gridOutput.js +++ b/src/accessibility/gridOutput.js @@ -71,7 +71,8 @@ function gridOutput(p5, fn){ //if empty cell of location of shape is undefined if (!cells[ingredients[x][y].loc.locY][ingredients[x][y].loc.locX]) { //fill it with shape info - cells[ingredients[x][y].loc.locY][ingredients[x][y].loc.locX] = fill; + cells[ingredients[x][y].loc.locY][ingredients[x][y].loc.locX] = + fill; //if a shape is already in that location } else { //add it diff --git a/src/accessibility/outputs.js b/src/accessibility/outputs.js index b9abddb8a6..352d39a811 100644 --- a/src/accessibility/outputs.js +++ b/src/accessibility/outputs.js @@ -81,11 +81,11 @@ function outputs(p5, fn){ * *
* - * + * * function setup(){ * createCanvas(100, 100); * } - * + * * function draw() { * // Add the text description. * textOutput(); @@ -106,11 +106,11 @@ function outputs(p5, fn){ * *
* - * + * * function setup(){ * createCanvas(100, 100); * } - * + * * function draw() { * // Add the text description and * // display it for debugging. @@ -225,11 +225,11 @@ function outputs(p5, fn){ * *
* - * + * * function setup() { * createCanvas(100, 100); * } - * + * * function draw() { * // Add the grid description. * gridOutput(); @@ -250,11 +250,11 @@ function outputs(p5, fn){ * *
* - * + * * function setup(){ * createCanvas(100, 100); * } - * + * * function draw() { * // Add the grid description and * // display it for debugging. @@ -561,7 +561,8 @@ function outputs(p5, fn){ //gets position of shape in the canvas fn._getPos = function (x, y) { - const { x: transformedX, y: transformedY } = this.worldToScreen(new p5.Vector(x, y)); + const { x: transformedX, y: transformedY } = + this.worldToScreen(new p5.Vector(x, y)); const canvasWidth = this.width; const canvasHeight = this.height; if (transformedX < 0.4 * canvasWidth) { diff --git a/src/app.js b/src/app.js index 83129d4d30..ce3d1fcd4a 100644 --- a/src/app.js +++ b/src/app.js @@ -51,7 +51,7 @@ import webgl from './webgl'; webgl(p5); // typography -import type from './type' +import type from './type'; type(p5); import { waitForDocumentReady, waitingForTranslator, _globalInit } from './core/init'; diff --git a/src/color/p5.Color.culori.js b/src/color/p5.Color.culori.js index 0e184b13dc..12ce7e724d 100644 --- a/src/color/p5.Color.culori.js +++ b/src/color/p5.Color.culori.js @@ -1,4 +1,4 @@ -class Color { +export class Color { _color; maxes; mode; diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index b5a278f30b..8e2a9d8e82 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -59,7 +59,8 @@ class Color { Color.colorMap[mode] = definition.id; // Get colorjs maxes - Color.#colorjsMaxes[mode] = Object.values(definition.coords).reduce((acc, v) => { + Color.#colorjsMaxes[mode] = Object.values(definition.coords) + .reduce((acc, v) => { acc.push(v.refRange || v.range); return acc; }, []); @@ -87,7 +88,8 @@ class Color { Color.colorMap[colorMode] : vals.spaceId; this._color = to(vals, mode); - this.mode = colorMode || Object.entries(Color.colorMap).find(([key, val]) => { + this.mode = colorMode || Object.entries(Color.colorMap) + .find(([key, val]) => { return val === this._color.spaceId; }); @@ -114,14 +116,28 @@ class Color { if(vals.length === 4){ mappedVals = Color.mapColorRange(vals, this.mode, colorMaxes, clamp); }else if(vals.length === 3){ - mappedVals = Color.mapColorRange([vals[0], vals[1], vals[2]], this.mode, colorMaxes, clamp); + mappedVals = Color.mapColorRange( + [vals[0], vals[1], vals[2]], + this.mode, + colorMaxes, + clamp + ); mappedVals.push(1); }else if(vals.length === 2){ // Grayscale with alpha if(Color.#grayscaleMap[this.mode]){ - mappedVals = Color.#grayscaleMap[this.mode](vals[0], colorMaxes, clamp); + mappedVals = Color.#grayscaleMap[this.mode]( + vals[0], + colorMaxes, + clamp + ); }else{ - mappedVals = Color.mapColorRange([vals[0], vals[0], vals[0]], this.mode, colorMaxes, clamp); + mappedVals = Color.mapColorRange( + [vals[0], vals[0], vals[0]], + this.mode, + colorMaxes, + clamp + ); } const alphaMaxes = Array.isArray(colorMaxes[colorMaxes.length-1]) ? colorMaxes[colorMaxes.length-1] : @@ -139,9 +155,18 @@ class Color { }else if(vals.length === 1){ // Grayscale only if(Color.#grayscaleMap[this.mode]){ - mappedVals = Color.#grayscaleMap[this.mode](vals[0], colorMaxes, clamp); + mappedVals = Color.#grayscaleMap[this.mode]( + vals[0], + colorMaxes, + clamp + ); }else{ - mappedVals = Color.mapColorRange([vals[0], vals[0], vals[0]], this.mode, colorMaxes, clamp); + mappedVals = Color.mapColorRange( + [vals[0], vals[0], vals[0]], + this.mode, + colorMaxes, + clamp + ); } mappedVals.push(1); }else{ @@ -165,7 +190,7 @@ class Color { // Convert from p5 color range to color.js color range static mapColorRange(origin, mode, maxes, clamp){ - const p5Maxes = maxes.map((max) => { + const p5Maxes = maxes.map(max => { if(!Array.isArray(max)){ return [0, max]; }else{ @@ -175,14 +200,19 @@ class Color { const colorjsMaxes = Color.#colorjsMaxes[mode]; return origin.map((channel, i) => { - const newval = map(channel, p5Maxes[i][0], p5Maxes[i][1], colorjsMaxes[i][0], colorjsMaxes[i][1], clamp); + const newval = map( + channel, + p5Maxes[i][0], p5Maxes[i][1], + colorjsMaxes[i][0], colorjsMaxes[i][1], + clamp + ); return newval; }); } // Convert from color.js color range to p5 color range static unmapColorRange(origin, mode, maxes){ - const p5Maxes = maxes.map((max) => { + const p5Maxes = maxes.map(max => { if(!Array.isArray(max)){ return [0, max]; }else{ @@ -192,7 +222,11 @@ class Color { const colorjsMaxes = Color.#colorjsMaxes[mode]; return origin.map((channel, i) => { - const newval = map(channel, colorjsMaxes[i][0], colorjsMaxes[i][1], p5Maxes[i][0], p5Maxes[i][1]); + const newval = map( + channel, + colorjsMaxes[i][0], colorjsMaxes[i][1], + p5Maxes[i][0], p5Maxes[i][1] + ); return newval; }); } @@ -219,7 +253,8 @@ class Color { spaceIndex+1 < this._color.space.path.length || spaceIndex+1 < color._color.space.path.length ) && - this._color.space.path[spaceIndex+1] === color._color.space.path[spaceIndex+1] + this._color.space.path[spaceIndex+1] === + color._color.space.path[spaceIndex+1] ){ spaceIndex += 1; } @@ -279,7 +314,7 @@ class Color { *
*/ toString(format) { - const key = `${this._color.space.id}-${this._color.coords.join(",")}-${this._color.alpha}-${format}`; + const key = `${this._color.space.id}-${this._color.coords.join(',')}-${this._color.alpha}-${format}`; let colorString = serializationMap[key]; if(!colorString){ @@ -436,7 +471,7 @@ class Color { * } * *
- **/ + */ setBlue(new_blue, max=[0, 1]) { if(!Array.isArray(max)){ max = [0, max]; @@ -521,7 +556,11 @@ class Color { }); coords = coords.map((coord, i) => { - return map(coord, colorjsMaxes[i][0], colorjsMaxes[i][1], rangeMaxes[i][0], rangeMaxes[i][1]); + return map( + coord, + colorjsMaxes[i][0], colorjsMaxes[i][1], + rangeMaxes[i][0], rangeMaxes[i][1] + ); }); return coords; @@ -538,7 +577,11 @@ class Color { if(this.mode === RGB || this.mode === RGBHDR){ const colorjsMax = Color.#colorjsMaxes[this.mode][0]; - return map(this._color.coords[0], colorjsMax[0], colorjsMax[1], max[0], max[1]); + return map( + this._color.coords[0], + colorjsMax[0], colorjsMax[1], + max[0], max[1] + ); }else{ // Will do an imprecise conversion to 'srgb', not recommended const colorjsMax = Color.#colorjsMaxes[RGB][0]; @@ -558,7 +601,11 @@ class Color { if(this.mode === RGB || this.mode === RGBHDR){ const colorjsMax = Color.#colorjsMaxes[this.mode][1]; - return map(this._color.coords[1], colorjsMax[0], colorjsMax[1], max[0], max[1]); + return map( + this._color.coords[1], + colorjsMax[0], colorjsMax[1], + max[0], max[1] + ); }else{ // Will do an imprecise conversion to 'srgb', not recommended const colorjsMax = Color.#colorjsMaxes[RGB][1]; @@ -573,7 +620,11 @@ class Color { if(this.mode === RGB || this.mode === RGBHDR){ const colorjsMax = Color.#colorjsMaxes[this.mode][2]; - return map(this._color.coords[2], colorjsMax[0], colorjsMax[1], max[0], max[1]); + return map( + this._color.coords[2], + colorjsMax[0], colorjsMax[1], + max[0], max[1] + ); }else{ // Will do an imprecise conversion to 'srgb', not recommended const colorjsMax = Color.#colorjsMaxes[RGB][2]; @@ -603,7 +654,11 @@ class Color { if(this.mode === HSB || this.mode === HSL){ const colorjsMax = Color.#colorjsMaxes[this.mode][0]; - return map(this._color.coords[0], colorjsMax[0], colorjsMax[1], max[0], max[1]); + return map( + this._color.coords[0], + colorjsMax[0], colorjsMax[1], + max[0], max[1] + ); }else{ // Will do an imprecise conversion to 'HSL', not recommended const colorjsMax = Color.#colorjsMaxes[HSL][0]; @@ -623,7 +678,11 @@ class Color { if(this.mode === HSB || this.mode === HSL){ const colorjsMax = Color.#colorjsMaxes[this.mode][1]; - return map(this._color.coords[1], colorjsMax[0], colorjsMax[1], max[0], max[1]); + return map( + this._color.coords[1], + colorjsMax[0], colorjsMax[1], + max[0], max[1] + ); }else{ // Will do an imprecise conversion to 'HSL', not recommended const colorjsMax = Color.#colorjsMaxes[HSL][1]; @@ -645,7 +704,11 @@ class Color { if(this.mode === HSB){ const colorjsMax = Color.#colorjsMaxes[this.mode][2]; - return map(this._color.coords[2], colorjsMax[0], colorjsMax[1], max[0], max[1]); + return map( + this._color.coords[2], + colorjsMax[0], colorjsMax[1], + max[0], max[1] + ); }else{ // Will do an imprecise conversion to 'HSB', not recommended const colorjsMax = Color.#colorjsMaxes[HSB][2]; @@ -660,7 +723,11 @@ class Color { if(this.mode === HSL){ const colorjsMax = Color.#colorjsMaxes[this.mode][2]; - return map(this._color.coords[2], colorjsMax[0], colorjsMax[1], max[0], max[1]); + return map( + this._color.coords[2], + colorjsMax[0], colorjsMax[1], + max[0], max[1] + ); }else{ // Will do an imprecise conversion to 'HSL', not recommended const colorjsMax = Color.#colorjsMaxes[HSL][2]; @@ -701,7 +768,7 @@ function color(p5, fn, lifecycles){ sRGB.fromGray = P3.fromGray = function(val, maxes, clamp){ // Use blue max - const p5Maxes = maxes.map((max) => { + const p5Maxes = maxes.map(max => { if(!Array.isArray(max)){ return [0, max]; }else{ @@ -715,7 +782,7 @@ function color(p5, fn, lifecycles){ HSBSpace.fromGray = HSLSpace.fromGray = function(val, maxes, clamp){ // Use brightness max - const p5Maxes = maxes.map((max) => { + const p5Maxes = maxes.map(max => { if(!Array.isArray(max)){ return [0, max]; }else{ @@ -729,7 +796,7 @@ function color(p5, fn, lifecycles){ HWBSpace.fromGray = function(val, maxes, clamp){ // Use Whiteness and Blackness to create number line - const p5Maxes = maxes.map((max) => { + const p5Maxes = maxes.map(max => { if(!Array.isArray(max)){ return [0, max]; }else{ @@ -759,7 +826,7 @@ function color(p5, fn, lifecycles){ OKLCHSpace.fromGray = function(val, maxes, clamp){ // Use lightness max - const p5Maxes = maxes.map((max) => { + const p5Maxes = maxes.map(max => { if(!Array.isArray(max)){ return [0, max]; }else{ @@ -793,7 +860,7 @@ function color(p5, fn, lifecycles){ p5.Color.prototype['set' + method] = function(newval, max){ max = max || pInst?._renderer?.states?.colorMaxes?.[RGB][i]; return setCopy.call(this, newval, max); - } + }; } // Decorate get methods @@ -801,14 +868,20 @@ function color(p5, fn, lifecycles){ const getCopy = p5.Color.prototype['_get' + channel]; p5.Color.prototype['_get' + channel] = function(max){ if(Object.keys(modes).includes(this.mode)){ - max = max || pInst?._renderer?.states?.colorMaxes?.[this.mode][modes[this.mode]]; + max = max || + pInst?._renderer?.states?.colorMaxes?.[this.mode][modes[this.mode]]; }else{ const defaultMode = Object.keys(modes)[0]; - max = max || pInst?._renderer?.states?.colorMaxes?.[defaultMode][modes[defaultMode]]; + max = max || + pInst + ?._renderer + ?.states + ?.colorMaxes + ?.[defaultMode][modes[defaultMode]]; } return getCopy.call(this, max); - } + }; } decorateGet('Red', { @@ -856,7 +929,7 @@ function color(p5, fn, lifecycles){ } export default color; -export { Color } +export { Color }; if(typeof p5 !== 'undefined'){ color(p5, p5.prototype); diff --git a/src/color/setting.js b/src/color/setting.js index 70a1e38119..24b8afc035 100644 --- a/src/color/setting.js +++ b/src/color/setting.js @@ -757,7 +757,7 @@ function setting(p5, fn){ * Instead of saturation and lightness, HWB defines colors based on the percentage * of whiteness and blackness. This is the color model used by Chrome's GUI color picker. * Pure red in HWB is represented as `color(0, 0, 0)` (i.e., hue 0 with 0% whiteness and 0% blackness). - * + * * * * `LAB` - Also known as CIE Lab, this color mode defines colors with Lightness, Alpha, and Beta. @@ -777,14 +777,14 @@ function setting(p5, fn){ * p5.Color objects remember the mode that they were * created in. Changing modes doesn't affect their appearance. * - * `Single-value (Grayscale) Colors`: + * `Single-value (Grayscale) Colors`: * When a color is specified with only one parameter (e.g., `color(g)`), p5.js will interpret it * as a grayscale color. However, how that single parameter translates into a grayscale value * depends on the color mode: * - * - `RGB, HSB, and HSL`: In RGB, the single value is interpreted using the “blue” maximum - * (i.e., the single parameter is mapped to the blue channel's max). - * In HSB and HSL, the single value is mapped to Brightness and Lightness max respectively with hue=0 . + * - `RGB, HSB, and HSL`: In RGB, the single value is interpreted using the “blue” maximum + * (i.e., the single parameter is mapped to the blue channel's max). + * In HSB and HSL, the single value is mapped to Brightness and Lightness max respectively with hue=0 . * and saturation=0. * * - `LAB, LCH, OKLAB, and OKLCH`: The single value is taken to be the `lightness (L)` component, @@ -889,78 +889,78 @@ function setting(p5, fn){ * * function setup() { * createCanvas(100, 100); - * + * * // Draw a neutral gray background using the default color mode. - * background(200); - * + * background(200); + * * // Switch to HWB color mode. * // (Assuming p5.js supports HWB with a range of: * // hue: 0–360, whiteness: 0–100, blackness: 0–100.) * colorMode(HWB); - * + * * // Set fill to pure red in HWB. * // Pure red in HWB is: hue = 0°, whiteness = 0%, blackness = 0%. * fill(0, 0, 0); - * + * * // Draw a circle at the center. * circle(50, 50, 25); - * + * * describe('A gray square with a red circle at its center, drawn using HWB color mode.'); * } * *
- * + * * @example *
* * function setup() { * createCanvas(100, 100); - * + * * // Draw a neutral gray background using the default color mode. * background(200); - * + * * // Switch to LAB color mode. * // In this mode, L typically ranges from 0 to 100 while a and b span roughly -128 to 127. * colorMode(LAB); - * + * * // Set fill to pure red in LAB. * // The sRGB red (255, 0, 0) converts approximately to LAB as: * // L = 53, a = 80, b = 67. * fill(53, 80, 67); - * + * * // Draw a circle at the center. * circle(50, 50, 25); - * + * * describe('A gray square with a red circle at its center, drawn using LAB color mode.'); * } * *
- * + * * @example *
* * function setup() { * createCanvas(100, 100); - * + * * // Draw a neutral gray background. * background(200); - * + * * // Switch to LCH color mode. * // In LCH, colors are defined by Lightness, Chroma, and Hue (in degrees). * colorMode(LCH); - * + * * // Set fill to an approximation of pure red in LCH: * // Lightness ≈ 53, Chroma ≈ 104, Hue ≈ 40°. * fill(53, 104, 40); - * + * * // Draw a circle at the center. * circle(50, 50, 25); - * + * * describe('A gray square with a red circle at its center, drawn using LCH color mode.'); * } - * + * *
- * + * * @example *
* @@ -1056,7 +1056,7 @@ function setting(p5, fn){ * } * *
- * + * * @example *
* @@ -1111,7 +1111,7 @@ function setting(p5, fn){ * } * *
- * + * * @example *
* @@ -1128,7 +1128,7 @@ function setting(p5, fn){ * function draw() { * // Set color mode to RGB with range 0-255 * colorMode(RGB, 255); - * + * * // Fill with single grayscale value * fill(128); * rect(0, 0, 100, 100); diff --git a/src/core/environment.js b/src/core/environment.js index 7f117993c7..be4b9fe741 100644 --- a/src/core/environment.js +++ b/src/core/environment.js @@ -7,7 +7,7 @@ */ import * as C from './constants'; -import { Vector } from '../math/p5.Vector'; +// import { Vector } from '../math/p5.Vector'; function environment(p5, fn){ const standardCursors = [C.ARROW, C.CROSS, C.HAND, C.MOVE, C.TEXT, C.WAIT]; @@ -1383,7 +1383,7 @@ function environment(p5, fn){ * */ fn.worldToScreen = function(worldPosition) { - if (typeof worldPosition === "number") { + if (typeof worldPosition === 'number') { // We got passed numbers, convert to vector worldPosition = this.createVector(...arguments); } @@ -1436,14 +1436,14 @@ function environment(p5, fn){ * */ fn.screenToWorld = function(screenPosition) { - if (typeof screenPosition === "number") { + if (typeof screenPosition === 'number') { // We got passed numbers, convert to vector screenPosition = this.createVector(...arguments); } const matrix = this._renderer.getWorldToScreenMatrix(); - if (screenPosition.dimensions == 2) { + if (screenPosition.dimensions === 2) { // Calculate a sensible Z value for the current camera projection that // will result in 0 once converted to world coordinates let z = matrix.mat4[14] / matrix.mat4[15]; @@ -1452,7 +1452,8 @@ function environment(p5, fn){ const matrixInverse = matrix.invert(matrix); - const worldPosition = matrixInverse.multiplyAndNormalizePoint(screenPosition); + const worldPosition = matrixInverse + .multiplyAndNormalizePoint(screenPosition); return worldPosition; }; } diff --git a/src/core/friendly_errors/fes_core.js b/src/core/friendly_errors/fes_core.js index 0a7e58d4fe..41e40f2755 100644 --- a/src/core/friendly_errors/fes_core.js +++ b/src/core/friendly_errors/fes_core.js @@ -309,7 +309,7 @@ function fesCore(p5, fn){ */ p5.isPreloadSupported = function() { return false; - } + }; /** * Checks capitalization for user defined functions. diff --git a/src/core/friendly_errors/param_validator.js b/src/core/friendly_errors/param_validator.js index 915e084d96..b391150e04 100644 --- a/src/core/friendly_errors/param_validator.js +++ b/src/core/friendly_errors/param_validator.js @@ -66,7 +66,7 @@ function validateParams(p5, fn, lifecycles) { 'Integer': z.number().int(), 'Number': z.number(), 'Object': z.object({}), - 'String': z.string(), + 'String': z.string() }; const webAPIObjects = [ @@ -96,7 +96,7 @@ function validateParams(p5, fn, lifecycles) { // For mapping 0-indexed parameters to their ordinal representation, e.g. // "first" for 0, "second" for 1, "third" for 2, etc. - const ordinals = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth"]; + const ordinals = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth']; function extractFuncNameAndClass(func) { const ichDot = func.lastIndexOf('.'); @@ -124,15 +124,15 @@ function validateParams(p5, fn, lifecycles) { * * Example parameter data for function `background`: * "background": { - "overloads": [ - ["p5.Color"], - ["String", "Number?"], - ["Number", "Number?"], - ["Number", "Number", "Number", "Number?"], - ["Number[]"], - ["p5.Image", "Number?"] - ] - } + * "overloads": [ + * ["p5.Color"], + * ["String", "Number?"], + * ["Number", "Number?"], + * ["Number", "Number", "Number", "Number?"], + * ["Number[]"], + * ["p5.Image", "Number?"] + * ] + * } * Where each array in `overloads` represents a set of valid overloaded * parameters, and `?` is a shorthand for `Optional`. * @@ -230,10 +230,10 @@ function validateParams(p5, fn, lifecycles) { param = param?.replace(/^\.\.\.(.+)\[\]$/, '$1'); let schema = generateTypeSchema(param); - // Fallback to z.custom() because function types are no longer + // Fallback to z.custom() because function types are no longer // returns a Zod schema. if (schema.def.type === 'function') { - schema = z.custom(val => val instanceof Function) + schema = z.custom(val => val instanceof Function); } if (isOptional) { @@ -294,7 +294,7 @@ function validateParams(p5, fn, lifecycles) { return overloadSchemas.length === 1 ? overloadSchemas[0] : z.union(overloadSchemas); - } + }; /** * Finds the closest schema to the input arguments. @@ -326,7 +326,9 @@ function validateParams(p5, fn, lifecycles) { const numArgs = args.length; const schemaItems = schema.def.items; const numSchemaItems = schemaItems.length; - const numRequiredSchemaItems = schemaItems.filter(item => !item.isOptional()).length; + const numRequiredSchemaItems = schemaItems + .filter(item => !item.isOptional()) + .length; if (numArgs >= numRequiredSchemaItems && numArgs <= numSchemaItems) { score = 0; @@ -344,7 +346,9 @@ function validateParams(p5, fn, lifecycles) { // are received. else { score = Math.abs( - numArgs < numRequiredSchemaItems ? numRequiredSchemaItems - numArgs : numArgs - numSchemaItems + numArgs < numRequiredSchemaItems ? + numRequiredSchemaItems - numArgs : + numArgs - numSchemaItems ) * 4; } @@ -373,7 +377,7 @@ function validateParams(p5, fn, lifecycles) { }); return closestSchema; - } + }; /** * Prints a friendly error message after parameter validation, if validation @@ -395,17 +399,18 @@ function validateParams(p5, fn, lifecycles) { let currentError = zodErrorObj.issues[0]; // Helper function to build a type mismatch message. - const buildTypeMismatchMessage = (actualType, expectedTypeStr, position) => { - const positionStr = position ? `at the ${ordinals[position]} parameter` : ''; - const actualTypeStr = actualType ? `, but received ${actualType}` : ''; - return `Expected ${expectedTypeStr} ${positionStr}${actualTypeStr}`; - } + const buildTypeMismatchMessage = + (actualType, expectedTypeStr, position) => { + const positionStr = position ? `at the ${ordinals[position]} parameter` : ''; + const actualTypeStr = actualType ? `, but received ${actualType}` : ''; + return `Expected ${expectedTypeStr} ${positionStr}${actualTypeStr}`; + }; // Union errors occur when a parameter can be of multiple types but is not // of any of them. In this case, aggregate all possible types and print // a friendly error message that indicates what the expected types are at // which position (position is not 0-indexed, for accessibility reasons). - const processUnionError = (error) => { + const processUnionError = error => { const expectedTypes = new Set(); let actualType; @@ -417,19 +422,19 @@ function validateParams(p5, fn, lifecycles) { } if (issue.code === 'invalid_type') { - actualType = issue.message.split(', received ')[1] + actualType = issue.message.split(', received ')[1]; expectedTypes.add(issue.expected); } // The case for constants. Since we don't want to print out the actual // constant values in the error message, the error message will // direct users to the documentation. else if (issue.code === 'invalid_value') { - expectedTypes.add("constant (please refer to documentation for allowed values)"); - actualType = args[error.path[0]]; + expectedTypes.add('constant (please refer to documentation for allowed values)'); + actualType = args[error.path[0]]; } else if (issue.code === 'custom') { const match = issue.message.match(/Input not instance of (\w+)/); if (match) expectedTypes.add(match[1]); - actualType = undefined + actualType = undefined; } } }); @@ -444,11 +449,13 @@ function validateParams(p5, fn, lifecycles) { const expectedTypesStr = Array.from(expectedTypes).join(' or '); const position = error.path.join('.'); - message += buildTypeMismatchMessage(actualType, expectedTypesStr, position); + message += buildTypeMismatchMessage( + actualType, expectedTypesStr, position + ); } return message; - } + }; switch (currentError.code) { case 'invalid_union': { @@ -480,13 +487,13 @@ function validateParams(p5, fn, lifecycles) { // Generates a link to the documentation based on the given function name. // TODO: Check if the link is reachable before appending it to the error // message. - const generateDocumentationLink = (func) => { + const generateDocumentationLink = func => { const { funcName, funcClass } = extractFuncNameAndClass(func); const p5BaseUrl = 'https://p5js.org/reference'; const url = `${p5BaseUrl}/${funcClass}/${funcName}`; return url; - } + }; if (currentError.code === 'too_big' || currentError.code === 'too_small') { const documentationLink = generateDocumentationLink(func); @@ -499,7 +506,7 @@ function validateParams(p5, fn, lifecycles) { console.log(message); } return message; - } + }; /** * Runs parameter validation by matching the input parameters to Zod schemas @@ -526,7 +533,11 @@ function validateParams(p5, fn, lifecycles) { // theoretically allowed to stay undefined and valid, it is likely that the // user intended to call the function with non-undefined arguments. Skip // regular workflow and return a friendly error message right away. - if (Array.isArray(args) && args.length > 0 && args.every(arg => arg === undefined)) { + if ( + Array.isArray(args) && + args.length > 0 && + args.every(arg => arg === undefined) + ) { const undefinedErrorMessage = `🌸 p5.js says: All arguments for ${func}() are undefined. There is likely an error in the code.`; return { diff --git a/src/core/friendly_errors/sketch_verifier.js b/src/core/friendly_errors/sketch_verifier.js index 66b2b7027b..b8f6e70db6 100644 --- a/src/core/friendly_errors/sketch_verifier.js +++ b/src/core/friendly_errors/sketch_verifier.js @@ -42,11 +42,11 @@ export const verifierUtils = { * @method fetchScript * @param {HTMLScriptElement} script * @returns {Promise} - */ + */ fetchScript: async function (script) { if (script.src) { try { - const contents = await fetch(script.src).then((res) => res.text()); + const contents = await fetch(script.src).then(res => res.text()); return contents; } catch (error) { // TODO: Handle CORS error here. @@ -212,7 +212,8 @@ export const verifierUtils = { */ runFES: async function (p5) { const userCode = await verifierUtils.getUserCode(); - const userDefinedVariablesAndFuncs = verifierUtils.extractUserDefinedVariablesAndFuncs(userCode); + const userDefinedVariablesAndFuncs = verifierUtils + .extractUserDefinedVariablesAndFuncs(userCode); verifierUtils.checkForConstsAndFuncs(userDefinedVariablesAndFuncs, p5); } diff --git a/src/core/main.js b/src/core/main.js index e3e0075414..4fa904cb68 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -98,7 +98,7 @@ class p5 { // ensure correct reporting of window dimensions this._updateWindowSize(); - const bindGlobal = (property) => { + const bindGlobal = property => { Object.defineProperty(window, property, { configurable: true, enumerable: true, @@ -109,7 +109,7 @@ class p5 { return this[property]; } }, - set: (newValue) => { + set: newValue => { Object.defineProperty(window, property, { configurable: true, enumerable: true, @@ -120,7 +120,7 @@ class p5 { console.log(`You just changed the value of "${property}", which was a p5 global value. This could cause problems later if you're not careful.`); } } - }) + }); }; // If the user has created a global setup or draw function, // assume "global" mode and make everything global (i.e. on the window) @@ -476,7 +476,7 @@ for (const k in constants) { * to load because `loadFont()` function returns a promise, and the await * keyword means the program will wait for the promise to resolve. * This ensures that all assets are fully loaded before the sketch continues. - + * * * loading assets. * diff --git a/src/core/p5.Graphics.js b/src/core/p5.Graphics.js index 204f489bdd..b831595344 100644 --- a/src/core/p5.Graphics.js +++ b/src/core/p5.Graphics.js @@ -5,7 +5,6 @@ */ import * as constants from './constants'; -import { RGB, HSB, HSL } from '../color/creating_reading'; import primitives2D from '../shape/2d_primitives'; import attributes from '../shape/attributes'; import curves from '../shape/curves'; diff --git a/src/core/p5.Renderer.js b/src/core/p5.Renderer.js index 18573da7f5..75d01bc04c 100644 --- a/src/core/p5.Renderer.js +++ b/src/core/p5.Renderer.js @@ -6,7 +6,7 @@ /** * `pInst` may be: - * + * * The main sketch-wide `p5` instance (global canvas), or * an off-screen `p5.Graphics` wrapper. * @@ -53,7 +53,10 @@ class Renderer { textAlign: constants.LEFT, textBaseline: constants.BASELINE, bezierOrder: 3, - splineProperties: new ClonableObject({ ends: constants.INCLUDE, tightness: 0 }), + splineProperties: new ClonableObject({ + ends: constants.INCLUDE, + tightness: 0 + }), textWrap: constants.WORD, // added v2.0 @@ -63,7 +66,7 @@ class Renderer { lineHeight: constants.NORMAL, fontVariant: constants.NORMAL, direction: 'inherit' - } + }; constructor(pInst, w, h, isMainCanvas) { this._pInst = pInst; @@ -150,7 +153,8 @@ class Renderer { bezierVertex(x, y, z = 0, u = 0, v = 0) { const position = new Vector(x, y, z); - const textureCoordinates = this.getSupportedIndividualVertexProperties().textureCoordinates + const textureCoordinates = this.getSupportedIndividualVertexProperties() + .textureCoordinates ? new Vector(u, v) : undefined; this.currentShape.bezierVertex(position, textureCoordinates); @@ -178,7 +182,8 @@ class Renderer { splineVertex(x, y, z = 0, u = 0, v = 0) { const position = new Vector(x, y, z); - const textureCoordinates = this.getSupportedIndividualVertexProperties().textureCoordinates + const textureCoordinates = this.getSupportedIndividualVertexProperties() + .textureCoordinates ? new Vector(u, v) : undefined; this.currentShape.splineVertex(position, textureCoordinates); @@ -212,12 +217,13 @@ class Renderer { } drawShape(shape, count) { - throw new Error('Unimplemented') + throw new Error('Unimplemented'); } vertex(x, y, z = 0, u = 0, v = 0) { const position = new Vector(x, y, z); - const textureCoordinates = this.getSupportedIndividualVertexProperties().textureCoordinates + const textureCoordinates = this.getSupportedIndividualVertexProperties() + .textureCoordinates ? new Vector(u, v) : undefined; this.currentShape.vertex(position, textureCoordinates); @@ -345,13 +351,13 @@ class Renderer { } getCommonVertexProperties() { - return {} + return {}; } getSupportedIndividualVertexProperties() { return { - textureCoordinates: false, - } + textureCoordinates: false + }; } updateShapeProperties(modified) { @@ -365,7 +371,7 @@ class Renderer { updateShapeVertexProperties(modified) { const props = this.getCommonVertexProperties(); - if (!modified || Object.keys(modified).some((k) => k in props)) { + if (!modified || Object.keys(modified).some(k => k in props)) { const shape = this.currentShape; for (const key in props) { shape[key](props[key]); diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index f48716739f..95286b0b51 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -39,7 +39,7 @@ class Renderer2D extends Renderer { get() { return this.wrappedElt[p]; } - }) + }); } } @@ -177,7 +177,7 @@ class Renderer2D extends Renderer { // create background rect const color = this._pInst.color(...args); - // Add accessible outputs if the method exists; on success, + // Add accessible outputs if the method exists; on success, // set the accessible output background to white. if (this._pInst._addAccsOutput?.()) { this._pInst._accsBackground?.(color._getRGBA([255, 255, 255, 255])); @@ -211,8 +211,8 @@ class Renderer2D extends Renderer { const color = this.states.fillColor; this._setFill(color.toString()); - // Add accessible outputs if the method exists; on success, - // set the accessible output background to white. + // Add accessible outputs if the method exists; on success, + // set the accessible output background to white. if (this._pInst._addAccsOutput?.()) { this._pInst._accsCanvasColors?.('fill', color._getRGBA([255, 255, 255, 255])); } @@ -223,8 +223,8 @@ class Renderer2D extends Renderer { const color = this.states.strokeColor; this._setStroke(color.toString()); - // Add accessible outputs if the method exists; on success, - // set the accessible output background to white. + // Add accessible outputs if the method exists; on success, + // set the accessible output background to white. if (this._pInst._addAccsOutput?.()) { this._pInst._accsCanvasColors?.('stroke', color._getRGBA([255, 255, 255, 255])); } @@ -262,7 +262,9 @@ class Renderer2D extends Renderer { } drawShape(shape) { - const visitor = new PrimitiveToPath2DConverter({ strokeWeight: this.states.strokeWeight }); + const visitor = new PrimitiveToPath2DConverter({ + strokeWeight: this.states.strokeWeight + }); shape.accept(visitor); if (this._clipping) { this.clipPath.addPath(visitor.path); @@ -421,7 +423,11 @@ class Renderer2D extends Renderer { ctx.save(); ctx.clearRect(0, 0, img.canvas.width, img.canvas.height); - if (this.states.tint[0] < 255 || this.states.tint[1] < 255 || this.states.tint[2] < 255) { + if ( + this.states.tint[0] < 255 || + this.states.tint[1] < 255 || + this.states.tint[2] < 255 + ) { // Color tint: we need to use the multiply blend mode to change the colors. // However, the canvas implementation of this destroys the alpha channel of // the image. To accommodate, we first get a version of the image with full @@ -1057,9 +1063,9 @@ function renderer2D(p5, fn){ p5.renderers[constants.P2D] = Renderer2D; p5.renderers['p2d-hdr'] = new Proxy(Renderer2D, { construct(target, [pInst, w, h, isMainCanvas, elt]){ - return new target(pInst, w, h, isMainCanvas, elt, {colorSpace: "display-p3"}) + return new target(pInst, w, h, isMainCanvas, elt, { colorSpace: 'display-p3' }); } - }) + }); } export default renderer2D; diff --git a/src/core/rendering.js b/src/core/rendering.js index e9e9b36bff..a941c3bd1e 100644 --- a/src/core/rendering.js +++ b/src/core/rendering.js @@ -127,7 +127,7 @@ function rendering(p5, fn){ // p5._validateParameters('createCanvas', arguments); //optional: renderer, otherwise defaults to p2d - let selectedRenderer = constants.P2D + let selectedRenderer = constants.P2D; // Check third argument whether it is renderer constants if(Reflect.ownKeys(renderers).includes(renderer)){ selectedRenderer = renderer; @@ -394,9 +394,9 @@ function rendering(p5, fn){ */ fn.createGraphics = function (w, h, ...args) { /** - * args[0] is expected to be renderer - * args[1] is expected to be canvas - */ + * args[0] is expected to be renderer + * args[1] is expected to be canvas + */ if (args[0] instanceof HTMLCanvasElement) { args[1] = args[0]; args[0] = constants.P2D; diff --git a/src/dom/dom.js b/src/dom/dom.js index 3c1d812aa2..48144c9198 100644 --- a/src/dom/dom.js +++ b/src/dom/dom.js @@ -1518,7 +1518,10 @@ function dom(p5, fn){ const arg0 = args[0]; if ( arg0 instanceof Element && - (arg0.elt instanceof HTMLDivElement || arg0.elt instanceof HTMLSpanElement) + ( + arg0.elt instanceof HTMLDivElement || + arg0.elt instanceof HTMLSpanElement + ) ) { // If given argument is p5.Element of div/span type self = arg0; @@ -1755,7 +1758,10 @@ function dom(p5, fn){ inst.push(); if (value) { if (value.mode) { - inst.colorMode(value.mode, ...(value?.maxes ? value.maxes[value.mode] || [] : [])); + inst.colorMode( + value.mode, + ...(value?.maxes ? value.maxes[value.mode] || [] : []) + ); } } const c = inst.color(this.elt.value); diff --git a/src/dom/p5.Element.js b/src/dom/p5.Element.js index 0265a64c42..099b807c1c 100644 --- a/src/dom/p5.Element.js +++ b/src/dom/p5.Element.js @@ -67,23 +67,22 @@ class Element { // `_elements` array. But when an element lives inside an off-screen // `p5.Graphics` layer, `this._pInst` is that wrapper Graphics object // instead. The wrapper keeps a back–pointer (`_pInst`) to the real - // sketch but has no `_elements` array of its own. - - let sketch = this._pInst; - + // sketch but has no `_elements` array of its own. + + let sketch = this._pInst; + // If `sketch` doesn’t own an `_elements` array it means - // we’re still at the graphics-layer “wrapper”. + // we’re still at the graphics-layer “wrapper”. // Jump one level up to the real p5 sketch stored in sketch._pInst. if (sketch && !sketch._elements && sketch._pInst) { - sketch = sketch._pInst; // climb one level up + sketch = sketch._pInst; // climb one level up } - + if (sketch && sketch._elements) { // only if the array exists const i = sketch._elements.indexOf(this); if (i !== -1) sketch._elements.splice(i, 1); } - // deregister events for (let ev in this._events) { @@ -723,7 +722,9 @@ class Element { this.position(0, 0); const wOffset = Math.abs(this.parent().offsetWidth - this.elt.offsetWidth); - const hOffset = Math.abs(this.parent().offsetHeight - this.elt.offsetHeight); + const hOffset = Math.abs( + this.parent().offsetHeight - this.elt.offsetHeight + ); if (align === 'both' || align === undefined) { this.position( @@ -1033,7 +1034,10 @@ class Element { this.elt.setAttribute('height', aH * this._pInst._pixelDensity); this.elt.style.width = aW + 'px'; this.elt.style.height = aH + 'px'; - this._pInst.scale(this._pInst._pixelDensity, this._pInst._pixelDensity); + this._pInst.scale( + this._pInst._pixelDensity, + this._pInst._pixelDensity + ); for (prop in j) { this.elt.getContext('2d')[prop] = j[prop]; } @@ -1865,7 +1869,7 @@ class Element { return this; } - /** + /** * Calls a function when a file is dragged over the element. * * Calling `myElement.dragOver(false)` disables the function. @@ -2375,7 +2379,11 @@ class Element { } function closeDragElement() { - document.removeEventListener(closeDragElementEvt, closeDragElement, false); + document.removeEventListener( + closeDragElementEvt, + closeDragElement, + false + ); document.removeEventListener(elementDragEvt, elementDrag, false); } diff --git a/src/dom/p5.MediaElement.js b/src/dom/p5.MediaElement.js index f767dae229..a8afa2a6c7 100644 --- a/src/dom/p5.MediaElement.js +++ b/src/dom/p5.MediaElement.js @@ -5,6 +5,15 @@ import { Element } from './p5.Element'; +class Cue { + constructor(callback, time, id, val) { + this.callback = callback; + this.time = time; + this.id = id; + this.val = val; + } +} + class MediaElement extends Element { constructor(elt, pInst) { super(elt, pInst); @@ -1294,15 +1303,6 @@ class MediaElement extends Element { // Cue inspired by JavaScript setTimeout, and the // Tone.js Transport Timeline Event, MIT License Yotam Mann 2015 tonejs.org -// eslint-disable-next-line no-unused-vars -class Cue { - constructor(callback, time, id, val) { - this.callback = callback; - this.time = time; - this.id = id; - this.val = val; - } -} function media(p5, fn){ /** @@ -1318,7 +1318,7 @@ function media(p5, fn){ return c; } - /** VIDEO STUFF **/ + /* VIDEO STUFF */ // Helps perform similar tasks for media element methods. function createMedia(pInst, type, src, callback) { @@ -1460,7 +1460,7 @@ function media(p5, fn){ return createMedia(this, 'video', src, callback); }; - /** AUDIO STUFF **/ + /* AUDIO STUFF */ /** * Creates a hidden `<audio>` element for simple audio playback. @@ -1507,7 +1507,7 @@ function media(p5, fn){ return createMedia(this, 'audio', src, callback); }; - /** CAMERA STUFF **/ + /* CAMERA STUFF */ fn.VIDEO = 'video'; diff --git a/src/events/acceleration.js b/src/events/acceleration.js index 3b0d5d8dc7..e3b716faba 100644 --- a/src/events/acceleration.js +++ b/src/events/acceleration.js @@ -730,8 +730,12 @@ function acceleration(p5, fn){ let accelerationChangeY; // Add accelerationChangeZ if acceleration change on Z is needed if (this.pAccelerationX !== null) { - accelerationChangeX = Math.abs(this.accelerationX - this.pAccelerationX); - accelerationChangeY = Math.abs(this.accelerationY - this.pAccelerationY); + accelerationChangeX = Math.abs( + this.accelerationX - this.pAccelerationX + ); + accelerationChangeY = Math.abs( + this.accelerationY - this.pAccelerationY + ); } if (accelerationChangeX + accelerationChangeY > shake_threshold) { context.deviceShaken(); diff --git a/src/events/keyboard.js b/src/events/keyboard.js index e319903e7a..bbf350dfc8 100644 --- a/src/events/keyboard.js +++ b/src/events/keyboard.js @@ -9,7 +9,7 @@ export function isCode(input) { 'Alt', 'Shift', 'Control', - 'Meta', + 'Meta' ]; if (leftRightKeys.includes(input)) { return false; @@ -195,26 +195,26 @@ function keyboard(p5, fn){ fn.key = ''; /** - * The `code` property represents a physical key on the keyboard (as opposed - * to the character generated by pressing the key). In other words, this - * property returns a value that isn't altered by keyboard layout or the state + * The `code` property represents a physical key on the keyboard (as opposed + * to the character generated by pressing the key). In other words, this + * property returns a value that isn't altered by keyboard layout or the state * of the modifier keys. - * - * This property is useful when you want to handle keys based on their - * physical positions on the input device rather than the characters associated + * + * This property is useful when you want to handle keys based on their + * physical positions on the input device rather than the characters associated * with those keys; * - * Unlike key, the `code` property differentiates between - * physical keys that generate the same character—for example, `CtrlLeft` and + * Unlike key, the `code` property differentiates between + * physical keys that generate the same character—for example, `CtrlLeft` and * `CtrlRight`—so each can be handled independently. * Here's the MDN docs for KeyboardEvent.code - - * - * Pressing the key physically labeled “A” always yields `KeyA`, regardless - * of the current keyboard layout (QWERTY, Dvorak, AZERTY, etc.) or the character + * + * + * Pressing the key physically labeled “A” always yields `KeyA`, regardless + * of the current keyboard layout (QWERTY, Dvorak, AZERTY, etc.) or the character * that appears in a text field. - * - * The code property returns a plain string (e.g., 'ArrowRight'). You can + * + * The code property returns a plain string (e.g., 'ArrowRight'). You can * compare it directly with string literals: * ```js * if (keyIsDown(RIGHT_ARROW)) { @@ -224,11 +224,11 @@ function keyboard(p5, fn){ * if (code === 'ArrowRight') { * // … * } - * if (key === 'ArrowRight') { + * if (key === 'ArrowRight') { * // … * } * ``` - * + * * The system variables `BACKSPACE`, `DELETE`, `ENTER`, `RETURN`, `TAB`, * `ESCAPE`, `SHIFT`, `CONTROL`, `OPTION`, `ALT`, `UP_ARROW`, `DOWN_ARROW`, * `LEFT_ARROW`, and `RIGHT_ARROW` are all helpful shorthands the key codes of @@ -239,7 +239,7 @@ function keyboard(p5, fn){ * // .. * } * ``` - * + * * *

The table below summarizes how the main keyboard-related system variables changed between p5.js 1.x and 2.x.

* @@ -305,7 +305,7 @@ function keyboard(p5, fn){ * *
* - * + * * function setup() { * createCanvas(100, 100); * } @@ -336,40 +336,40 @@ function keyboard(p5, fn){ * * let x = 50; * let y = 50; - * + * * function setup() { * createCanvas(100, 100); - * + * * background(200); - * + * * describe( * 'A gray square with a black circle at its center. The circle moves when the user presses an arrow key. It leaves a trail as it moves.' * ); * } - * + * * function draw() { * // Update x and y if an arrow key is pressed. * if (keyIsPressed){ * if (keyIsDown(LEFT_ARROW)){ * x -= 1; * } - * + * * if (keyIsDown(RIGHT_ARROW)) { * x += 1; * } - * + * * if (keyIsDown(UP_ARROW)) { * y -= 1; * } - * + * * if (keyIsDown(DOWN_ARROW)) { * y += 1; * } * } - * + * * // Style the circle. * fill(0); - * + * * // Draw the circle. * circle(x, y, 5); * } @@ -404,12 +404,12 @@ function keyboard(p5, fn){ * * Use the following numeric codes for the arrow keys: * - * Up Arrow: 38 - * Down Arrow: 40 - * Left Arrow: 37 + * Up Arrow: 38 + * Down Arrow: 40 + * Left Arrow: 37 * Right Arrow: 39 * - * More key codes can be found at websites such as + * More key codes can be found at websites such as * keycode.info. * * @property {Integer} keyCode @@ -828,7 +828,7 @@ function keyboard(p5, fn){ e.preventDefault(); } } - + delete this._downKeyCodes[e.code]; delete this._downKeys[e.key]; @@ -1127,16 +1127,17 @@ function keyboard(p5, fn){ } else { return this._downKeys[input] || this._downKeyCodes[input] || false; } - } + }; + /** * The _areDownKeys function returns a boolean true if any keys pressed * and a false if no keys are currently pressed. - + * * Helps avoid instances where multiple keys are pressed simultaneously and * releasing a single key will then switch the * keyIsPressed property to true. * @private - **/ + */ fn._areDownKeys = function() { for (const key in this._downKeys) { if (this._downKeys.hasOwnProperty(key) && this._downKeys[key] === true) { diff --git a/src/events/pointer.js b/src/events/pointer.js index 44717a31d4..bd3a1ed0a1 100644 --- a/src/events/pointer.js +++ b/src/events/pointer.js @@ -6,8 +6,6 @@ * @requires constants */ -import * as constants from '../core/constants'; - function pointer(p5, fn){ /** * A `Number` system variable that tracks the mouse's horizontal movement. @@ -749,7 +747,7 @@ function pointer(p5, fn){ center: false }; - /** + /** * An `Array` of all the current touch points on a touchscreen device. * * The `touches` array is empty by default. When the user touches their @@ -832,8 +830,8 @@ function pointer(p5, fn){ * *
*/ - fn.touches = []; - fn._activePointers = new Map(); + fn.touches = []; + fn._activePointers = new Map(); /** * A `Boolean` system variable that's `true` if the mouse is pressed and @@ -900,13 +898,13 @@ function pointer(p5, fn){ const sx = canvas.scrollWidth / this.width || 1; const sy = canvas.scrollHeight / this.height || 1; - if (e.pointerType == 'touch') { - const touches = []; - for (const touch of this._activePointers.values()) { - touches.push(getTouchInfo(canvas, sx, sy, touch)); - } - this.touches = touches; - } + if (e.pointerType === 'touch') { + const touches = []; + for (const touch of this._activePointers.values()) { + touches.push(getTouchInfo(canvas, sx, sy, touch)); + } + this.touches = touches; + } const mousePos = getMouseInfo(canvas, sx, sy, e); this.movedX = e.movementX || 0; @@ -916,12 +914,12 @@ function pointer(p5, fn){ this.winMouseX = mousePos.winX; this.winMouseY = mousePos.winY; - if (!this._hasMouseInteracted) { - this._updateMouseCoords(); - this._hasMouseInteracted = true; - } + if (!this._hasMouseInteracted) { + this._updateMouseCoords(); + this._hasMouseInteracted = true; + } } - }; + }; fn._updateMouseCoords = function() { this.pmouseX = this.mouseX; @@ -934,36 +932,39 @@ function pointer(p5, fn){ function getMouseInfo(canvas, sx, sy, evt) { const rect = canvas.getBoundingClientRect(); return { - x: (evt.clientX - rect.left) / sx, - y: (evt.clientY - rect.top) / sy, - winX: evt.clientX, - winY: evt.clientY, + x: (evt.clientX - rect.left) / sx, + y: (evt.clientY - rect.top) / sy, + winX: evt.clientX, + winY: evt.clientY }; - } + } - function getTouchInfo(canvas, sx, sy, touch) { - const rect = canvas.getBoundingClientRect(); - return { - x: (touch.clientX - rect.left) / sx, - y: (touch.clientY - rect.top) / sy, - winX: touch.clientX, - winY: touch.clientY, - id: touch.pointerId, - }; -} + function getTouchInfo(canvas, sx, sy, touch) { + const rect = canvas.getBoundingClientRect(); + return { + x: (touch.clientX - rect.left) / sx, + y: (touch.clientY - rect.top) / sy, + winX: touch.clientX, + winY: touch.clientY, + id: touch.pointerId + }; + } -fn._setMouseButton = function(e) { - // Check all active touches to determine button states - this.mouseButton.left = Array.from(this._activePointers.values()).some(touch => - (touch.buttons & 1) !== 0 - ); - this.mouseButton.center = Array.from(this._activePointers.values()).some(touch => - (touch.buttons & 4) !== 0 - ); - this.mouseButton.right = Array.from(this._activePointers.values()).some(touch => - (touch.buttons & 2) !== 0 - ); -}; + fn._setMouseButton = function(e) { + // Check all active touches to determine button states + this.mouseButton.left = Array.from(this._activePointers.values()) + .some(touch => + (touch.buttons & 1) !== 0 + ); + this.mouseButton.center = Array.from(this._activePointers.values()) + .some(touch => + (touch.buttons & 4) !== 0 + ); + this.mouseButton.right = Array.from(this._activePointers.values()) + .some(touch => + (touch.buttons & 2) !== 0 + ); + }; /** * A function that's called when the mouse moves. @@ -1144,19 +1145,18 @@ fn._setMouseButton = function(e) { this._updatePointerCoords(e); this._activePointers.set(e.pointerId, e); this._setMouseButton(e); - - if (!this.mouseIsPressed && typeof context.mouseMoved === 'function') { - executeDefault = context.mouseMoved(e); - if (executeDefault === false) { - e.preventDefault(); - } - } else if (this.mouseIsPressed && typeof context.mouseDragged === 'function') { - executeDefault = context.mouseDragged(e); - if (executeDefault === false) { - e.preventDefault(); - } + if (!this.mouseIsPressed && typeof context.mouseMoved === 'function') { + executeDefault = context.mouseMoved(e); + if (executeDefault === false) { + e.preventDefault(); } + } else if (this.mouseIsPressed && typeof context.mouseDragged === 'function') { + executeDefault = context.mouseDragged(e); + if (executeDefault === false) { + e.preventDefault(); + } + } }; /** @@ -1315,7 +1315,7 @@ fn._setMouseButton = function(e) { if (executeDefault === false) { e.preventDefault(); } - } + } }; /** @@ -1470,7 +1470,7 @@ fn._setMouseButton = function(e) { this._setMouseButton(e); this._updatePointerCoords(e); - + if (typeof context.mouseReleased === 'function') { executeDefault = context.mouseReleased(e); if (executeDefault === false) { diff --git a/src/image/const.js b/src/image/const.js index 535ce66c31..c123f66f37 100644 --- a/src/image/const.js +++ b/src/image/const.js @@ -2,5 +2,5 @@ import * as constants from '../core/constants'; export const filterParamDefaults = { [constants.BLUR]: 3, [constants.POSTERIZE]: 4, - [constants.THRESHOLD]: 0.5, + [constants.THRESHOLD]: 0.5 }; diff --git a/src/image/filterRenderer2D.js b/src/image/filterRenderer2D.js index 5e2dcc3107..cd0a97fe0a 100644 --- a/src/image/filterRenderer2D.js +++ b/src/image/filterRenderer2D.js @@ -1,6 +1,6 @@ -import { Shader } from "../webgl/p5.Shader"; -import { Texture } from "../webgl/p5.Texture"; -import { Image } from "./p5.Image"; +import { Shader } from '../webgl/p5.Shader'; +import { Texture } from '../webgl/p5.Texture'; +import { Image } from './p5.Image'; import * as constants from '../core/constants'; import filterGrayFrag from '../webgl/shaders/filters/gray.frag'; @@ -12,12 +12,12 @@ import filterOpaqueFrag from '../webgl/shaders/filters/opaque.frag'; import filterInvertFrag from '../webgl/shaders/filters/invert.frag'; import filterThresholdFrag from '../webgl/shaders/filters/threshold.frag'; import filterShaderVert from '../webgl/shaders/filters/default.vert'; -import { filterParamDefaults } from "./const"; +import { filterParamDefaults } from './const'; -import filterBaseFrag from "../webgl/shaders/filters/base.frag"; -import filterBaseVert from "../webgl/shaders/filters/base.vert"; -import webgl2CompatibilityShader from "../webgl/shaders/webgl2Compatibility.glsl"; +import filterBaseFrag from '../webgl/shaders/filters/base.frag'; +import filterBaseVert from '../webgl/shaders/filters/base.vert'; +import webgl2CompatibilityShader from '../webgl/shaders/webgl2Compatibility.glsl'; class FilterRenderer2D { /** @@ -39,7 +39,7 @@ class FilterRenderer2D { this.gl = this.canvas.getContext('webgl'); } if (!this.gl) { - console.error("WebGL not supported, cannot apply filter."); + console.error('WebGL not supported, cannot apply filter.'); return; } // Minimal renderer object required by p5.Shader and p5.Texture @@ -51,7 +51,7 @@ class FilterRenderer2D { webglVersion, states: { textureWrapX: this.gl.CLAMP_TO_EDGE, - textureWrapY: this.gl.CLAMP_TO_EDGE, + textureWrapY: this.gl.CLAMP_TO_EDGE }, _arraysEqual: (a, b) => JSON.stringify(a) === JSON.stringify(b), _getEmptyTexture: () => { @@ -61,7 +61,7 @@ class FilterRenderer2D { this._emptyTexture = new Texture(this._renderer, im); } return this._emptyTexture; - }, + } }; this._baseFilterShader = undefined; @@ -75,7 +75,7 @@ class FilterRenderer2D { [constants.GRAY]: filterGrayFrag, [constants.DILATE]: filterDilateFrag, [constants.POSTERIZE]: filterPosterizeFrag, - [constants.OPAQUE]: filterOpaqueFrag, + [constants.OPAQUE]: filterOpaqueFrag }; // Store initialized shaders for each operation @@ -96,21 +96,29 @@ class FilterRenderer2D { this.texcoords = new Float32Array([0, 1, 1, 1, 0, 0, 1, 0]); // Upload vertex data once - this._bindBufferData(this.vertexBuffer, this.gl.ARRAY_BUFFER, this.vertices); + this._bindBufferData( + this.vertexBuffer, + this.gl.ARRAY_BUFFER, + this.vertices + ); // Upload texcoord data once - this._bindBufferData(this.texcoordBuffer, this.gl.ARRAY_BUFFER, this.texcoords); + this._bindBufferData( + this.texcoordBuffer, + this.gl.ARRAY_BUFFER, + this.texcoords + ); } _webGL2CompatibilityPrefix(shaderType, floatPrecision) { - let code = ""; + let code = ''; if (this._renderer.webglVersion === constants.WEBGL2) { - code += "#version 300 es\n#define WEBGL2\n"; + code += '#version 300 es\n#define WEBGL2\n'; } - if (shaderType === "vert") { - code += "#define VERTEX_SHADER\n"; - } else if (shaderType === "frag") { - code += "#define FRAGMENT_SHADER\n"; + if (shaderType === 'vert') { + code += '#define VERTEX_SHADER\n'; + } else if (shaderType === 'frag') { + code += '#define FRAGMENT_SHADER\n'; } if (floatPrecision) { code += `precision ${floatPrecision} float;\n`; @@ -122,20 +130,20 @@ class FilterRenderer2D { if (!this._baseFilterShader) { this._baseFilterShader = new Shader( this._renderer, - this._webGL2CompatibilityPrefix("vert", "highp") + + this._webGL2CompatibilityPrefix('vert', 'highp') + webgl2CompatibilityShader + filterBaseVert, - this._webGL2CompatibilityPrefix("frag", "highp") + + this._webGL2CompatibilityPrefix('frag', 'highp') + webgl2CompatibilityShader + filterBaseFrag, { - vertex: {}, - fragment: { - "vec4 getColor": `(FilterInputs inputs, in sampler2D canvasContent) { - return getTexture(canvasContent, inputs.texCoord); - }`, - }, + vertex: {}, + fragment: { + 'vec4 getColor': `(FilterInputs inputs, in sampler2D canvasContent) { + return getTexture(canvasContent, inputs.texCoord); + }` } + } ); } return this._baseFilterShader; @@ -152,7 +160,8 @@ class FilterRenderer2D { this.operation = operation; this.filterParameter = filterParameter; - let useDefaultParam = operation in filterParamDefaults && filterParameter === undefined; + let useDefaultParam = operation in filterParamDefaults && + filterParameter === undefined; if (useDefaultParam) { this.filterParameter = filterParamDefaults[operation]; } @@ -173,7 +182,7 @@ class FilterRenderer2D { } if (!this.operation) { - console.error("No operation set for FilterRenderer2D, cannot initialize shader."); + console.error('No operation set for FilterRenderer2D, cannot initialize shader.'); return; } @@ -185,12 +194,16 @@ class FilterRenderer2D { const fragShaderSrc = this.filterShaderSources[this.operation]; if (!fragShaderSrc) { - console.error("No shader available for this operation:", this.operation); + console.error('No shader available for this operation:', this.operation); return; } // Create and store the new shader - const newShader = new Shader(this._renderer, filterShaderVert, fragShaderSrc); + const newShader = new Shader( + this._renderer, + filterShaderVert, + fragShaderSrc + ); this.filterShaders[this.operation] = newShader; this._shader = newShader; } @@ -219,7 +232,8 @@ class FilterRenderer2D { _renderPass() { const gl = this.gl; this._shader.bindShader(); - const pixelDensity = this.pInst.pixelDensity ? this.pInst.pixelDensity() : 1; + const pixelDensity = this.pInst.pixelDensity ? + this.pInst.pixelDensity() : 1; const texelSize = [ 1 / (this.pInst.width * pixelDensity), @@ -235,7 +249,7 @@ class FilterRenderer2D { this._shader.setUniform('radius', Math.max(1, this.filterParameter)); this._shader.setUniform('filterParameter', this.filterParameter); this._shader.setDefaultUniforms(); - + this.pInst.states.setValue('rectMode', constants.CORNER); this.pInst.states.setValue('imageMode', constants.CORNER); this.pInst.blendMode(constants.BLEND); @@ -271,7 +285,7 @@ class FilterRenderer2D { */ applyFilter() { if (!this._shader) { - console.error("Cannot apply filter: shader not initialized."); + console.error('Cannot apply filter: shader not initialized.'); return; } this.pInst.push(); @@ -284,14 +298,22 @@ class FilterRenderer2D { // Draw the result onto itself this.pInst.clear(); - this.pInst.drawingContext.drawImage(this.canvas, 0, 0, this.pInst.width, this.pInst.height); + this.pInst.drawingContext.drawImage( + this.canvas, + 0, 0, + this.pInst.width, this.pInst.height + ); // Vertical pass this._shader.setUniform('direction', [0, 1]); this._renderPass(); this.pInst.clear(); - this.pInst.drawingContext.drawImage(this.canvas, 0, 0, this.pInst.width, this.pInst.height); + this.pInst.drawingContext.drawImage( + this.canvas, + 0, 0, + this.pInst.width, this.pInst.height + ); } else { // Single-pass filters @@ -301,7 +323,11 @@ class FilterRenderer2D { this.pInst.blendMode(constants.BLEND); - this.pInst.drawingContext.drawImage(this.canvas, 0, 0, this.pInst.width, this.pInst.height); + this.pInst.drawingContext.drawImage( + this.canvas, + 0, 0, + this.pInst.width, this.pInst.height + ); } this.pInst.pop(); } diff --git a/src/image/image.js b/src/image/image.js index dc944666ab..9879a36ef6 100644 --- a/src/image/image.js +++ b/src/image/image.js @@ -386,12 +386,13 @@ function image(p5, fn){ // Now to build the global palette // Sort all the unique palettes in descending order of their occurrence - const palettesSortedByFreq = Object.keys(paletteFreqsAndFrames).sort(function( - a, - b - ) { - return paletteFreqsAndFrames[b].freq - paletteFreqsAndFrames[a].freq; - }); + const palettesSortedByFreq = Object.keys(paletteFreqsAndFrames) + .sort(function( + a, + b + ) { + return paletteFreqsAndFrames[b].freq - paletteFreqsAndFrames[a].freq; + }); // The initial global palette is the one with the most occurrence const globalPalette = palettesSortedByFreq[0] @@ -449,7 +450,12 @@ function image(p5, fn){ loop: loopLimit, palette: new Uint32Array(globalPalette) }; - const gifWriter = new omggif.GifWriter(buffer, pImg.width, pImg.height, opts); + const gifWriter = new omggif.GifWriter( + buffer, + pImg.width, + pImg.height, + opts + ); let previousFrame = {}; // Pass 2 @@ -596,11 +602,11 @@ function image(p5, fn){ * @param {Number} duration duration in seconds to record. This parameter will be constrained to be less or equal to 15. * @param {Number} framerate number of frames to save per second. This parameter will be constrained to be less or equal to 22. * @param {function(Array)} [callback] callback function that will be executed - to handle the image data. This function - should accept an array as argument. The - array will contain the specified number of - frames of objects. Each object has three - properties: `imageData`, `filename`, and `extension`. + * to handle the image data. This function + * should accept an array as argument. The + * array will contain the specified number of + * frames of objects. Each object has three + * properties: `imageData`, `filename`, and `extension`. * @example *
* diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index a4e321f6ce..3666ac1056 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -300,7 +300,11 @@ function loadingDisplaying(p5, fn){ // get the project's framerate let _frameRate = this._targetFrameRate; // if it is undefined or some non useful value, assume it's 60 - if (_frameRate === Infinity || _frameRate === undefined || _frameRate === 0) { + if ( + _frameRate === Infinity || + _frameRate === undefined || + _frameRate === 0 + ) { _frameRate = 60; } @@ -353,7 +357,9 @@ function loadingDisplaying(p5, fn){ // if we have a WEBGL context, initialize the pixels array // and the gl context to use them inside the loop gl = this.drawingContext; - pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4); + pixels = new Uint8Array( + gl.drawingBufferWidth * gl.drawingBufferHeight * 4 + ); } // stop the loop since we are going to manually redraw @@ -796,7 +802,12 @@ function loadingDisplaying(p5, fn){ */ function _imageFit(fit, xAlign, yAlign, dx, dy, dw, dh, sx, sy, sw, sh) { if (fit === constants.COVER) { - const { x, y, w, h } = _imageCover(xAlign, yAlign, dw, dh, sx, sy, sw, sh); + const { x, y, w, h } = _imageCover( + xAlign, yAlign, + dw, dh, + sx, sy, + sw, sh + ); sx = x; sy = y; sw = w; @@ -1098,7 +1109,11 @@ function loadingDisplaying(p5, fn){ _sh *= pd; _sw *= pd; - let vals = canvas.modeAdjust(_dx, _dy, _dw, _dh, this._renderer.states.imageMode); + let vals = canvas.modeAdjust( + _dx, _dy, + _dw, _dh, + this._renderer.states.imageMode + ); vals = _imageFit( fit, xAlign, @@ -1202,7 +1217,7 @@ function loadingDisplaying(p5, fn){ *
* * let img; - ** + * * async function setup() { * // Load the image. * img = await loadImage('assets/laDefense.jpg'); diff --git a/src/image/p5.Image.js b/src/image/p5.Image.js index 0fad23a429..897e1b02d8 100644 --- a/src/image/p5.Image.js +++ b/src/image/p5.Image.js @@ -1326,7 +1326,7 @@ class Image { /** * Copies a region of pixels from another image into this one. * - * The first parameter, `srcImage`, is the + * The first parameter, `srcImage`, is the * p5.Image object to blend. * * The next four parameters, `sx`, `sy`, `sw`, and `sh` determine the region diff --git a/src/io/csv.js b/src/io/csv.js index 4b1c2924fb..1714ee2a7f 100644 --- a/src/io/csv.js +++ b/src/io/csv.js @@ -23,189 +23,189 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ export function parse (csv, options, reviver = v => v) { - const ctx = Object.create(null) - ctx.options = options || {} - ctx.reviver = reviver - ctx.value = '' - ctx.entry = [] - ctx.output = [] - ctx.col = 1 - ctx.row = 1 + const ctx = Object.create(null); + ctx.options = options || {}; + ctx.reviver = reviver; + ctx.value = ''; + ctx.entry = []; + ctx.output = []; + ctx.col = 1; + ctx.row = 1; ctx.options.delimiter = ctx.options.delimiter === undefined ? '"' : options.delimiter; if(ctx.options.delimiter.length > 1 || ctx.options.delimiter.length === 0) - throw Error(`CSVError: delimiter must be one character [${ctx.options.separator}]`) + throw Error(`CSVError: delimiter must be one character [${ctx.options.separator}]`); ctx.options.separator = ctx.options.separator === undefined ? ',' : options.separator; if(ctx.options.separator.length > 1 || ctx.options.separator.length === 0) - throw Error(`CSVError: separator must be one character [${ctx.options.separator}]`) + throw Error(`CSVError: separator must be one character [${ctx.options.separator}]`); - const lexer = new RegExp(`${escapeRegExp(ctx.options.delimiter)}|${escapeRegExp(ctx.options.separator)}|\r\n|\n|\r|[^${escapeRegExp(ctx.options.delimiter)}${escapeRegExp(ctx.options.separator)}\r\n]+`, 'y') - const isNewline = /^(\r\n|\n|\r)$/ + const lexer = new RegExp(`${escapeRegExp(ctx.options.delimiter)}|${escapeRegExp(ctx.options.separator)}|\r\n|\n|\r|[^${escapeRegExp(ctx.options.delimiter)}${escapeRegExp(ctx.options.separator)}\r\n]+`, 'y'); + const isNewline = /^(\r\n|\n|\r)$/; - let matches = [] - let match = '' - let state = 0 + let matches = []; + let match = ''; + let state = 0; while ((matches = lexer.exec(csv)) !== null) { - match = matches[0] + match = matches[0]; switch (state) { case 0: // start of entry switch (true) { case match === ctx.options.delimiter: - state = 3 - break + state = 3; + break; case match === ctx.options.separator: - state = 0 - valueEnd(ctx) - break + state = 0; + valueEnd(ctx); + break; case isNewline.test(match): - state = 0 - valueEnd(ctx) - entryEnd(ctx) - break + state = 0; + valueEnd(ctx); + entryEnd(ctx); + break; default: - ctx.value += match - state = 2 - break + ctx.value += match; + state = 2; + break; } - break + break; case 2: // un-delimited input switch (true) { case match === ctx.options.separator: - state = 0 - valueEnd(ctx) - break + state = 0; + valueEnd(ctx); + break; case isNewline.test(match): - state = 0 - valueEnd(ctx) - entryEnd(ctx) - break + state = 0; + valueEnd(ctx); + entryEnd(ctx); + break; default: - state = 4 - throw Error(`CSVError: Illegal state [row:${ctx.row}, col:${ctx.col}]`) + state = 4; + throw Error(`CSVError: Illegal state [row:${ctx.row}, col:${ctx.col}]`); } - break + break; case 3: // delimited input switch (true) { case match === ctx.options.delimiter: - state = 4 - break + state = 4; + break; default: - state = 3 - ctx.value += match - break + state = 3; + ctx.value += match; + break; } - break + break; case 4: // escaped or closing delimiter switch (true) { case match === ctx.options.delimiter: - state = 3 - ctx.value += match - break + state = 3; + ctx.value += match; + break; case match === ctx.options.separator: - state = 0 - valueEnd(ctx) - break + state = 0; + valueEnd(ctx); + break; case isNewline.test(match): - state = 0 - valueEnd(ctx) - entryEnd(ctx) - break + state = 0; + valueEnd(ctx); + entryEnd(ctx); + break; default: - throw Error(`CSVError: Illegal state [row:${ctx.row}, col:${ctx.col}]`) + throw Error(`CSVError: Illegal state [row:${ctx.row}, col:${ctx.col}]`); } - break + break; } } // flush the last value if (ctx.entry.length !== 0) { - valueEnd(ctx) - entryEnd(ctx) + valueEnd(ctx); + entryEnd(ctx); } - return ctx.output + return ctx.output; } export function stringify (array, options = {}, replacer = v => v) { - const ctx = Object.create(null) - ctx.options = options - ctx.options.eof = ctx.options.eof !== undefined ? ctx.options.eof : true - ctx.row = 1 - ctx.col = 1 - ctx.output = '' + const ctx = Object.create(null); + ctx.options = options; + ctx.options.eof = ctx.options.eof !== undefined ? ctx.options.eof : true; + ctx.row = 1; + ctx.col = 1; + ctx.output = ''; ctx.options.delimiter = ctx.options.delimiter === undefined ? '"' : options.delimiter; if(ctx.options.delimiter.length > 1 || ctx.options.delimiter.length === 0) - throw Error(`CSVError: delimiter must be one character [${ctx.options.separator}]`) + throw Error(`CSVError: delimiter must be one character [${ctx.options.separator}]`); ctx.options.separator = ctx.options.separator === undefined ? ',' : options.separator; if(ctx.options.separator.length > 1 || ctx.options.separator.length === 0) - throw Error(`CSVError: separator must be one character [${ctx.options.separator}]`) + throw Error(`CSVError: separator must be one character [${ctx.options.separator}]`); - const needsDelimiters = new RegExp(`${escapeRegExp(ctx.options.delimiter)}|${escapeRegExp(ctx.options.separator)}|\r\n|\n|\r`) + const needsDelimiters = new RegExp(`${escapeRegExp(ctx.options.delimiter)}|${escapeRegExp(ctx.options.separator)}|\r\n|\n|\r`); array.forEach((row, rIdx) => { - let entry = '' - ctx.col = 1 + let entry = ''; + ctx.col = 1; row.forEach((col, cIdx) => { if (typeof col === 'string') { - col = col.replace(new RegExp(ctx.options.delimiter, 'g'), `${ctx.options.delimiter}${ctx.options.delimiter}`) - col = needsDelimiters.test(col) ? `${ctx.options.delimiter}${col}${ctx.options.delimiter}` : col + col = col.replace(new RegExp(ctx.options.delimiter, 'g'), `${ctx.options.delimiter}${ctx.options.delimiter}`); + col = needsDelimiters.test(col) ? `${ctx.options.delimiter}${col}${ctx.options.delimiter}` : col; } - entry += replacer(col, ctx.row, ctx.col) + entry += replacer(col, ctx.row, ctx.col); if (cIdx !== row.length - 1) { - entry += ctx.options.separator + entry += ctx.options.separator; } - ctx.col++ - }) + ctx.col++; + }); switch (true) { case ctx.options.eof: case !ctx.options.eof && rIdx !== array.length - 1: - ctx.output += `${entry}\n` - break + ctx.output += `${entry}\n`; + break; default: - ctx.output += `${entry}` - break + ctx.output += `${entry}`; + break; } - ctx.row++ - }) + ctx.row++; + }); - return ctx.output + return ctx.output; } function valueEnd (ctx) { - const value = ctx.options.typed ? inferType(ctx.value) : ctx.value - ctx.entry.push(ctx.reviver(value, ctx.row, ctx.col)) - ctx.value = '' - ctx.col++ + const value = ctx.options.typed ? inferType(ctx.value) : ctx.value; + ctx.entry.push(ctx.reviver(value, ctx.row, ctx.col)); + ctx.value = ''; + ctx.col++; } function entryEnd (ctx) { - ctx.output.push(ctx.entry) - ctx.entry = [] - ctx.row++ - ctx.col = 1 + ctx.output.push(ctx.entry); + ctx.entry = []; + ctx.row++; + ctx.col = 1; } function inferType (value) { - const isNumber = /.\./ + const isNumber = /.\./; switch (true) { case value === 'true': case value === 'false': - return value === 'true' + return value === 'true'; case isNumber.test(value): - return parseFloat(value) + return parseFloat(value); case isFinite(value): - return parseInt(value) + return parseInt(value); default: - return value + return value; } } function escapeRegExp(str) { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); } diff --git a/src/io/files.js b/src/io/files.js index 2a23bb71db..a18d074a84 100644 --- a/src/io/files.js +++ b/src/io/files.js @@ -511,7 +511,13 @@ function files(p5, fn){ * *
*/ - fn.loadTable = async function (path, separator, header, successCallback, errorCallback) { + fn.loadTable = async function ( + path, + separator, + header, + successCallback, + errorCallback + ) { if(typeof arguments[arguments.length-1] === 'function'){ if(typeof arguments[arguments.length-2] === 'function'){ successCallback = arguments[arguments.length-2]; @@ -538,7 +544,7 @@ function files(p5, fn){ ret.columns = Array(data[0].length).fill(null); } - data.forEach((line) => { + data.forEach(line => { const row = new p5.TableRow(line); ret.addRow(row); }); @@ -873,7 +879,7 @@ function files(p5, fn){ * async function setup() { * // Get the most recent earthquake in the database * let url = - 'https://earthquake.usgs.gov/fdsnws/event/1/query?' + + * 'https://earthquake.usgs.gov/fdsnws/event/1/query?' + * 'format=geojson&limit=1&orderby=time'; * earthquakes = await httpGet(url, 'json'); * } @@ -1090,15 +1096,15 @@ function files(p5, fn){ * * function setup() { * createCanvas(100,100); - * + * * let url = 'https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson'; - * + * * const req = new Request(url, { * method: 'GET', * headers: {authorization: 'Bearer secretKey'} * }); - * // httpDo(path, method, datatype, success, error) - * + * // httpDo(path, method, datatype, success, error) + * * httpDo( * req, * 'GET', @@ -1111,7 +1117,7 @@ function files(p5, fn){ * } * ); * } - * + * * function draw() { * // wait until the data is loaded * if (!earthquakes || !earthquakes.features[eqFeatureIndex]) { @@ -1141,7 +1147,13 @@ function files(p5, fn){ * @param {Function} [errorCallback] * @return {Promise} */ - fn.httpDo = async function (path, method, datatype, successCallback, errorCallback) { + fn.httpDo = async function ( + path, + method, + datatype, + successCallback, + errorCallback + ) { // This behave similarly to httpGet but even more primitive. The user // will most likely want to pass in a Request to path, the only convenience // is that datatype will be taken into account to parse the response. @@ -1155,8 +1167,8 @@ function files(p5, fn){ // Try to infer data type if it is defined if(!datatype){ const extension = typeof path === 'string' ? - path.split(".").pop() : - path.url.split(".").pop(); + path.split('.').pop() : + path.url.split('.').pop(); switch(extension) { case 'json': datatype = 'json'; diff --git a/src/io/p5.Table.js b/src/io/p5.Table.js index e4dbb3978a..0cb6fa101b 100644 --- a/src/io/p5.Table.js +++ b/src/io/p5.Table.js @@ -13,10 +13,10 @@ class Table { } toString(separator=',') { - let rows = this.rows.map((row) => row.arr); + let rows = this.rows.map(row => row.arr); - if(!this.columns.some((column) => column === null)){ - rows = [this.columns, ...rows,] + if(!this.columns.some(column => column === null)){ + rows = [this.columns, ...rows]; } return stringify(rows, { @@ -132,7 +132,7 @@ class Table { * text(rowText, 18, y * 3); * y += 20; * } - * + * * describe('no image displayed'); * } *
@@ -168,7 +168,7 @@ class Table { * * // Get the row at index 1 (second row) * let row = table.getRow(1); - * + * * // Set text properties for drawing on the canvas * fill(0); // Set text color to black * textSize(12); // Set the text size @@ -400,7 +400,7 @@ class Table { * // Set text properties for drawing on the canvas * fill(0); // Text color: black * textSize(12); // Adjust text size as needed - * + * * // Display the species on the canvas * text(species, 10, 30); * @@ -525,7 +525,7 @@ class Table { * // 2,Equus zebra,Zebra * * let table; - ** + * * async function setup() { * // The table is comma separated value "csv" * // and has a header specifying the columns labels. @@ -543,8 +543,8 @@ class Table { const ret = []; if (typeof value === 'string') { for (let i = 0; i < this.rows.length; i++) { - ret.push(this.rows[i].obj[this.columns.indexOf(value)]); - } + ret.push(this.rows[i].obj[this.columns.indexOf(value)]); + } } else { for (let j = 0; j < this.rows.length; j++) { ret.push(this.rows[j].arr[value]); @@ -578,7 +578,7 @@ class Table { * * // Load the CSV file with a header row * table = await loadTable('assets/mammals.csv', ',', 'header'); - * + * * // Clear all rows from the table * table.clearRows(); * @@ -1143,7 +1143,7 @@ class Table { * * // Compute the result: id at row 1, column 0 plus 100 (i.e. 1 + 100 = 101) * let result = table.getNum(1, 0) + 100; - * + * * // Set text properties and display the result on the canvas * fill(0); // Set text color to black * textSize(12); // Adjust text size as needed @@ -1400,7 +1400,7 @@ function table(p5, fn){ * @deprecated p5.Table will be removed in a future version of p5.js to make way for a new, friendlier version :) * @for p5.Table * @name rows - */ + */ } export default table; diff --git a/src/io/p5.TableRow.js b/src/io/p5.TableRow.js index c5f1dfd4ea..02cfcd2a91 100644 --- a/src/io/p5.TableRow.js +++ b/src/io/p5.TableRow.js @@ -265,13 +265,13 @@ class TableRow { * let rows = table.getRows(); * let minId = Infinity; * let maxId = -Infinity; - * + * * for (let r = 0; r < rows.length; r++) { * let id = rows[r].getNum('id'); * minId = min(minId, id); * maxId = max(maxId, id); * } - * + * * let result = 'minimum id = ' + minId + ', maximum id = ' + maxId; * * // Set text properties and display the result on the canvas @@ -304,7 +304,7 @@ class TableRow { * title. * * @deprecated p5.Table will be removed in a future version of p5.js to make way for a new, friendlier version :) - + * * @param {String|Integer} column columnName (string) or * ID (number) * @return {String} String diff --git a/src/io/p5.XML.js b/src/io/p5.XML.js index b8abf49769..8dbc8fa55f 100644 --- a/src/io/p5.XML.js +++ b/src/io/p5.XML.js @@ -1291,7 +1291,7 @@ function xml(p5, fn){ } export default xml; -export { XML } +export { XML }; if(typeof p5 !== 'undefined'){ xml(p5, p5.prototype); diff --git a/src/math/Matrices/Matrix.js b/src/math/Matrices/Matrix.js index b4d0b7d420..eba767f33a 100644 --- a/src/math/Matrices/Matrix.js +++ b/src/math/Matrices/Matrix.js @@ -2,22 +2,22 @@ * @module Math */ -import { Vector } from "../p5.Vector"; -import { MatrixInterface } from "./MatrixInterface"; +import { Vector } from '../p5.Vector'; +import { MatrixInterface } from './MatrixInterface'; -const isPerfectSquare = (arr) => { +const isPerfectSquare = arr => { const sqDimention = Math.sqrt(Array.from(arr).length); if (sqDimention % 1 !== 0) { - throw new Error("Array length must be a perfect square."); + throw new Error('Array length must be a perfect square.'); } return true; }; export let GLMAT_ARRAY_TYPE = Array; -export let isMatrixArray = (x) => Array.isArray(x); -if (typeof Float32Array !== "undefined") { +export let isMatrixArray = x => Array.isArray(x); +if (typeof Float32Array !== 'undefined') { GLMAT_ARRAY_TYPE = Float32Array; - isMatrixArray = (x) => Array.isArray(x) || x instanceof Float32Array; + isMatrixArray = x => Array.isArray(x) || x instanceof Float32Array; } export class Matrix extends MatrixInterface { @@ -32,7 +32,7 @@ export class Matrix extends MatrixInterface { const sqDimention = Math.sqrt(Array.from(args[0]).length); this.#sqDimention = sqDimention; this.matrix = GLMAT_ARRAY_TYPE.from(args[0]); - } else if (typeof args[0] === "number") { + } else if (typeof args[0] === 'number') { this.#sqDimention = Number(args[0]); this.matrix = this.#createIdentityMatrix(args[0]); } @@ -96,7 +96,7 @@ export class Matrix extends MatrixInterface { */ add(matrix) { if (this.matrix.length !== matrix.matrix.length) { - throw new Error("Matrices must be of the same dimension to add."); + throw new Error('Matrices must be of the same dimension to add.'); } for (let i = 0; i < this.matrix.length; i++) { this.matrix[i] += matrix.matrix[i]; @@ -255,7 +255,7 @@ export class Matrix extends MatrixInterface { if (refArray.length !== this.matrix.length) { p5._friendlyError( `Expected same dimensions values but received different ${refArray.length}.`, - "p5.Matrix.set" + 'p5.Matrix.set' ); return this; } @@ -672,7 +672,7 @@ export class Matrix extends MatrixInterface { return this.#invert3x3(a); } else { throw new Error( - "Invert is not implemented for N>4 at the moment, we are working on it" + 'Invert is not implemented for N>4 at the moment, we are working on it' ); } } @@ -726,7 +726,7 @@ export class Matrix extends MatrixInterface { result.mat3[8] = this.matrix[10]; return result; } else { - throw new Error("Matrix dimension must be 4 to create a 3x3 submatrix."); + throw new Error('Matrix dimension must be 4 to create a 3x3 submatrix.'); } } @@ -767,7 +767,7 @@ export class Matrix extends MatrixInterface { */ inverseTranspose4x4({ mat4 }) { if (this.#sqDimention !== 3) { - throw new Error("This function only works with 3×3 matrices."); + throw new Error('This function only works with 3×3 matrices.'); } else { // Convert mat4 -> mat3 by extracting the top-left 3×3 portion this.matrix[0] = mat4[0]; @@ -1663,7 +1663,7 @@ export class Matrix extends MatrixInterface { return new GLMAT_ARRAY_TYPE([1, 0, 0, 0, 1, 0, 0, 0, 1]); if (dimension === 4) return new GLMAT_ARRAY_TYPE([ - 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]); const identityMatrix = new GLMAT_ARRAY_TYPE(dimension * dimension).fill(0); for (let i = 0; i < dimension; i++) { @@ -1750,7 +1750,7 @@ export class Matrix extends MatrixInterface { */ #multNxN(multMatrix) { if (multMatrix.length !== this.matrix.length) { - throw new Error("Matrices must be of the same dimension to multiply."); + throw new Error('Matrices must be of the same dimension to multiply.'); } const result = new GLMAT_ARRAY_TYPE(this.matrix.length).fill(0); for (let i = 0; i < this.#sqDimention; i++) { @@ -1829,7 +1829,7 @@ export class Matrix extends MatrixInterface { * @chainable */ #transpose4x4(a) { - console.log("====> 4x4"); + console.log('====> 4x4'); let a01, a02, a03, a12, a13, a23; if (a instanceof Matrix) { a01 = a.matrix[1]; @@ -2047,7 +2047,7 @@ export class Matrix extends MatrixInterface { #determinant4x4() { if (this.#sqDimention !== 4) { throw new Error( - "Determinant is only implemented for 4x4 matrices. We are working on it." + 'Determinant is only implemented for 4x4 matrices. We are working on it.' ); } diff --git a/src/math/Matrices/MatrixInterface.js b/src/math/Matrices/MatrixInterface.js index 4ab4a0b63a..e9778ba82a 100644 --- a/src/math/Matrices/MatrixInterface.js +++ b/src/math/Matrices/MatrixInterface.js @@ -1,8 +1,8 @@ export let GLMAT_ARRAY_TYPE = Array; -export let isMatrixArray = (x) => Array.isArray(x); -if (typeof Float32Array !== "undefined") { +export let isMatrixArray = x => Array.isArray(x); +if (typeof Float32Array !== 'undefined') { GLMAT_ARRAY_TYPE = Float32Array; - isMatrixArray = (x) => Array.isArray(x) || x instanceof Float32Array; + isMatrixArray = x => Array.isArray(x) || x instanceof Float32Array; } export class MatrixInterface { // Private field to store the matrix @@ -12,39 +12,39 @@ export class MatrixInterface { throw new Error("Class is of abstract type and can't be instantiated"); } const methods = [ - "add", - "setElement", - "reset", - "set", - "get", - "copy", - "clone", - "diagonal", - "row", - "column", - "transpose", - "mult", - "multiplyVec", - "invert", - "createSubMatrix3x3", - "inverseTranspose4x4", - "apply", - "scale", - "rotate4x4", - "translate", - "rotateX", - "rotateY", - "rotateZ", - "perspective", - "ortho", - "multiplyVec4", - "multiplyPoint", - "multiplyAndNormalizePoint", - "multiplyDirection", - "multiplyVec3", + 'add', + 'setElement', + 'reset', + 'set', + 'get', + 'copy', + 'clone', + 'diagonal', + 'row', + 'column', + 'transpose', + 'mult', + 'multiplyVec', + 'invert', + 'createSubMatrix3x3', + 'inverseTranspose4x4', + 'apply', + 'scale', + 'rotate4x4', + 'translate', + 'rotateX', + 'rotateY', + 'rotateZ', + 'perspective', + 'ortho', + 'multiplyVec4', + 'multiplyPoint', + 'multiplyAndNormalizePoint', + 'multiplyDirection', + 'multiplyVec3' ]; - methods.forEach((method) => { + methods.forEach(method => { if (this[method] === undefined) { throw new Error(`${method}() method must be implemented`); } diff --git a/src/math/Matrices/MatrixNumjs.js b/src/math/Matrices/MatrixNumjs.js index 75d731dbee..6643c10857 100644 --- a/src/math/Matrices/MatrixNumjs.js +++ b/src/math/Matrices/MatrixNumjs.js @@ -1,6 +1,6 @@ -import nj from "@d4c/numjs/build/module/numjs.min.js"; -import { Vector } from "../p5.Vector"; -import { MatrixInterface } from "./MatrixInterface"; +import nj from '@d4c/numjs/build/module/numjs.min.js'; +import { Vector } from '../p5.Vector'; +import { MatrixInterface } from './MatrixInterface'; /** * @requires constants @@ -12,10 +12,10 @@ import { MatrixInterface } from "./MatrixInterface"; */ let GLMAT_ARRAY_TYPE = Array; -let isMatrixArray = (x) => Array.isArray(x); -if (typeof Float32Array !== "undefined") { +let isMatrixArray = x => Array.isArray(x); +if (typeof Float32Array !== 'undefined') { GLMAT_ARRAY_TYPE = Float32Array; - isMatrixArray = (x) => Array.isArray(x) || x instanceof Float32Array; + isMatrixArray = x => Array.isArray(x) || x instanceof Float32Array; } /** @@ -49,7 +49,7 @@ if (typeof Float32Array !== "undefined") { export class MatrixNumjs extends MatrixInterface{ constructor(...args) { // This is default behavior when object - super(...args) + super(...args); if (args[0] === 3) { this._mat3 = Array.isArray(args[1]) ? nj.array(args[1]) : nj.identity(3); diff --git a/src/math/math.js b/src/math/math.js index de11e2889b..fe7a69af43 100644 --- a/src/math/math.js +++ b/src/math/math.js @@ -137,6 +137,6 @@ function math(p5, fn) { export default math; -if (typeof p5 !== "undefined") { +if (typeof p5 !== 'undefined') { math(p5, p5.prototype); } diff --git a/src/math/p5.Matrix.js b/src/math/p5.Matrix.js index 487a7da3de..415633ce1d 100644 --- a/src/math/p5.Matrix.js +++ b/src/math/p5.Matrix.js @@ -7,7 +7,7 @@ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/ * Reference/Global_Objects/SIMD */ -import { Matrix } from "./Matrices/Matrix"; +import { Matrix } from './Matrices/Matrix'; // import { MatrixNumjs as Matrix } from './Matrices/MatrixNumjs' function matrix(p5, fn) { @@ -111,6 +111,6 @@ function matrix(p5, fn) { export default matrix; export { Matrix }; -if (typeof p5 !== "undefined") { +if (typeof p5 !== 'undefined') { matrix(p5, p5.prototype); } diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index 97b72ab61b..a244720170 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -3,7 +3,7 @@ * @requires constants */ -import * as constants from "../core/constants"; +import * as constants from '../core/constants'; /// HELPERS FOR REMAINDER METHOD const calculateRemainder2D = function (xComponent, yComponent) { @@ -33,12 +33,12 @@ class Vector { // This is how it comes in with createVector() // This check if the first argument is a function constructor(...args) { - let values = args.map((arg) => arg || 0); - if (typeof args[0] === "function") { + let values = args.map(arg => arg || 0); + if (typeof args[0] === 'function') { this.isPInst = true; this._fromRadians = args[0]; this._toRadians = args[1]; - values = args.slice(2).map((arg) => arg || 0); + values = args.slice(2).map(arg => arg || 0); } let dimensions = values.length; // TODO: make default 3 if no arguments if (dimensions === 0) { @@ -121,8 +121,8 @@ class Vector { return this._values[index]; } else { p5._friendlyError( - "The index parameter is trying to set a value outside the bounds of the vector", - "p5.Vector.setValue" + 'The index parameter is trying to set a value outside the bounds of the vector', + 'p5.Vector.setValue' ); } } @@ -146,8 +146,8 @@ class Vector { this._values[index] = value; } else { p5._friendlyError( - "The index parameter is trying to set a value outside the bounds of the vector", - "p5.Vector.setValue" + 'The index parameter is trying to set a value outside the bounds of the vector', + 'p5.Vector.setValue' ); } } @@ -272,7 +272,7 @@ class Vector { *
*/ toString() { - return `[${this.values.join(", ")}]`; + return `[${this.values.join(', ')}]`; } /** @@ -336,9 +336,9 @@ class Vector { if (args[0] instanceof Vector) { this.values = args[0].values.slice(); } else if (Array.isArray(args[0])) { - this.values = args[0].map((arg) => arg || 0); + this.values = args[0].map(arg => arg || 0); } else { - this.values = args.map((arg) => arg || 0); + this.values = args.map(arg => arg || 0); } this.dimensions = this.values.length; return this; @@ -660,7 +660,7 @@ class Vector { ); } } else if (Array.isArray(x)) { - if (x.every((element) => Number.isFinite(element))) { + if (x.every(element => Number.isFinite(element))) { if (x.length === 2) { return calculateRemainder2D.call(this, x[0], x[1]); } @@ -677,7 +677,7 @@ class Vector { } } else if (arguments.length === 2) { const vectorComponents = [...arguments]; - if (vectorComponents.every((element) => Number.isFinite(element))) { + if (vectorComponents.every(element => Number.isFinite(element))) { if (vectorComponents.length === 2) { return calculateRemainder2D.call( this, @@ -688,7 +688,7 @@ class Vector { } } else if (arguments.length === 3) { const vectorComponents = [...arguments]; - if (vectorComponents.every((element) => Number.isFinite(element))) { + if (vectorComponents.every(element => Number.isFinite(element))) { if (vectorComponents.length === 3) { return calculateRemainder3D.call( this, @@ -1046,12 +1046,12 @@ class Vector { const v = args[0]; const maxLen = Math.min(this.values.length, v.values.length); for (let i = 0; i < maxLen; i++) { - if (Number.isFinite(v.values[i]) && typeof v.values[i] === "number") { + if (Number.isFinite(v.values[i]) && typeof v.values[i] === 'number') { this._values[i] *= v.values[i]; } else { console.warn( - "p5.Vector.prototype.mult:", - "v contains components that are either undefined or not finite numbers" + 'p5.Vector.prototype.mult:', + 'v contains components that are either undefined or not finite numbers' ); return this; } @@ -1060,19 +1060,19 @@ class Vector { const arr = args[0]; const maxLen = Math.min(this.values.length, arr.length); for (let i = 0; i < maxLen; i++) { - if (Number.isFinite(arr[i]) && typeof arr[i] === "number") { + if (Number.isFinite(arr[i]) && typeof arr[i] === 'number') { this._values[i] *= arr[i]; } else { console.warn( - "p5.Vector.prototype.mult:", - "arr contains elements that are either undefined or not finite numbers" + 'p5.Vector.prototype.mult:', + 'arr contains elements that are either undefined or not finite numbers' ); return this; } } } else if ( args.length === 1 && - typeof args[0] === "number" && + typeof args[0] === 'number' && Number.isFinite(args[0]) ) { for (let i = 0; i < this._values.length; i++) { @@ -1282,18 +1282,18 @@ class Vector { const v = args[0]; if ( v._values.every( - (val) => Number.isFinite(val) && typeof val === "number" + val => Number.isFinite(val) && typeof val === 'number' ) ) { - if (v._values.some((val) => val === 0)) { - console.warn("p5.Vector.prototype.div:", "divide by 0"); + if (v._values.some(val => val === 0)) { + console.warn('p5.Vector.prototype.div:', 'divide by 0'); return this; } this._values = this._values.map((val, i) => val / v._values[i]); } else { console.warn( - "p5.Vector.prototype.div:", - "vector contains components that are either undefined or not finite numbers" + 'p5.Vector.prototype.div:', + 'vector contains components that are either undefined or not finite numbers' ); } return this; @@ -1301,31 +1301,31 @@ class Vector { if (args.length === 1 && Array.isArray(args[0])) { const arr = args[0]; - if (arr.every((val) => Number.isFinite(val) && typeof val === "number")) { - if (arr.some((val) => val === 0)) { - console.warn("p5.Vector.prototype.div:", "divide by 0"); + if (arr.every(val => Number.isFinite(val) && typeof val === 'number')) { + if (arr.some(val => val === 0)) { + console.warn('p5.Vector.prototype.div:', 'divide by 0'); return this; } this._values = this._values.map((val, i) => val / arr[i]); } else { console.warn( - "p5.Vector.prototype.div:", - "array contains components that are either undefined or not finite numbers" + 'p5.Vector.prototype.div:', + 'array contains components that are either undefined or not finite numbers' ); } return this; } - if (args.every((val) => Number.isFinite(val) && typeof val === "number")) { - if (args.some((val) => val === 0)) { - console.warn("p5.Vector.prototype.div:", "divide by 0"); + if (args.every(val => Number.isFinite(val) && typeof val === 'number')) { + if (args.some(val => val === 0)) { + console.warn('p5.Vector.prototype.div:', 'divide by 0'); return this; } this._values = this._values.map((val, i) => val / args[0]); } else { console.warn( - "p5.Vector.prototype.div:", - "arguments contain components that are either undefined or not finite numbers" + 'p5.Vector.prototype.div:', + 'arguments contain components that are either undefined or not finite numbers' ); } @@ -3152,7 +3152,7 @@ class Vector { * */ static fromAngle(angle, length) { - if (typeof length === "undefined") { + if (typeof length === 'undefined') { length = 1; } return new Vector(length * Math.cos(angle), length * Math.sin(angle), 0); @@ -3214,7 +3214,7 @@ class Vector { * */ static fromAngles(theta, phi, length) { - if (typeof length === "undefined") { + if (typeof length === 'undefined') { length = 1; } const cosPhi = Math.cos(phi); @@ -3347,8 +3347,8 @@ class Vector { target = v1.copy(); if (arguments.length === 3) { p5._friendlyError( - "The target parameter is undefined, it should be of type p5.Vector", - "p5.Vector.add" + 'The target parameter is undefined, it should be of type p5.Vector', + 'p5.Vector.add' ); } } else { @@ -3394,8 +3394,8 @@ class Vector { target = v1.copy(); if (arguments.length === 3) { p5._friendlyError( - "The target parameter is undefined, it should be of type p5.Vector", - "p5.Vector.sub" + 'The target parameter is undefined, it should be of type p5.Vector', + 'p5.Vector.sub' ); } } else { @@ -3438,8 +3438,8 @@ class Vector { target = v.copy(); if (arguments.length === 3) { p5._friendlyError( - "The target parameter is undefined, it should be of type p5.Vector", - "p5.Vector.mult" + 'The target parameter is undefined, it should be of type p5.Vector', + 'p5.Vector.mult' ); } } else { @@ -3464,8 +3464,8 @@ class Vector { } else { if (!(target instanceof Vector)) { p5._friendlyError( - "The target parameter should be of type p5.Vector", - "p5.Vector.rotate" + 'The target parameter should be of type p5.Vector', + 'p5.Vector.rotate' ); } target.set(v); @@ -3508,8 +3508,8 @@ class Vector { if (arguments.length === 3) { p5._friendlyError( - "The target parameter is undefined, it should be of type p5.Vector", - "p5.Vector.div" + 'The target parameter is undefined, it should be of type p5.Vector', + 'p5.Vector.div' ); } } else { @@ -3576,8 +3576,8 @@ class Vector { target = v1.copy(); if (arguments.length === 4) { p5._friendlyError( - "The target parameter is undefined, it should be of type p5.Vector", - "p5.Vector.lerp" + 'The target parameter is undefined, it should be of type p5.Vector', + 'p5.Vector.lerp' ); } } else { @@ -3606,8 +3606,8 @@ class Vector { target = v1.copy(); if (arguments.length === 4) { p5._friendlyError( - "The target parameter is undefined, it should be of type p5.Vector", - "p5.Vector.slerp" + 'The target parameter is undefined, it should be of type p5.Vector', + 'p5.Vector.slerp' ); } } else { @@ -3660,8 +3660,8 @@ class Vector { } else { if (!(target instanceof Vector)) { p5._friendlyError( - "The target parameter should be of type p5.Vector", - "p5.Vector.normalize" + 'The target parameter should be of type p5.Vector', + 'p5.Vector.normalize' ); } target.set(v); @@ -3686,8 +3686,8 @@ class Vector { } else { if (!(target instanceof Vector)) { p5._friendlyError( - "The target parameter should be of type p5.Vector", - "p5.Vector.limit" + 'The target parameter should be of type p5.Vector', + 'p5.Vector.limit' ); } target.set(v); @@ -3712,8 +3712,8 @@ class Vector { } else { if (!(target instanceof Vector)) { p5._friendlyError( - "The target parameter should be of type p5.Vector", - "p5.Vector.setMag" + 'The target parameter should be of type p5.Vector', + 'p5.Vector.setMag' ); } target.set(v); @@ -3768,8 +3768,8 @@ class Vector { } else { if (!(target instanceof Vector)) { p5._friendlyError( - "The target parameter should be of type p5.Vector", - "p5.Vector.reflect" + 'The target parameter should be of type p5.Vector', + 'p5.Vector.reflect' ); } target.set(incidentVector); @@ -3809,8 +3809,8 @@ class Vector { v = new Vector().set(v1); } else { p5._friendlyError( - "The v1 parameter should be of type Array or p5.Vector", - "p5.Vector.equals" + 'The v1 parameter should be of type Array or p5.Vector', + 'p5.Vector.equals' ); } return v.equals(v2); @@ -3931,6 +3931,6 @@ function vector(p5, fn) { export default vector; export { Vector }; -if (typeof p5 !== "undefined") { +if (typeof p5 !== 'undefined') { vector(p5, p5.prototype); } diff --git a/src/shape/2d_primitives.js b/src/shape/2d_primitives.js index eca8b6e05f..3a9f38d53d 100644 --- a/src/shape/2d_primitives.js +++ b/src/shape/2d_primitives.js @@ -314,7 +314,10 @@ function primitives(p5, fn){ // if the current stroke and fill settings wouldn't result in something // visible, exit immediately - if (!this._renderer.states.strokeColor && !this._renderer.states.fillColor) { + if ( + !this._renderer.states.strokeColor && + !this._renderer.states.fillColor + ) { return this; } @@ -325,7 +328,11 @@ function primitives(p5, fn){ start = this._toRadians(start); stop = this._toRadians(stop); - const vals = canvas.modeAdjust(x, y, w, h, this._renderer.states.ellipseMode); + const vals = canvas.modeAdjust( + x, y, + w, h, + this._renderer.states.ellipseMode + ); const angles = this._normalizeArcAngles(start, stop, vals.w, vals.h, true); if (angles.correspondToSamePoint) { @@ -537,7 +544,10 @@ function primitives(p5, fn){ fn._renderEllipse = function(x, y, w, h, detailX) { // if the current stroke and fill settings wouldn't result in something // visible, exit immediately - if (!this._renderer.states.strokeColor && !this._renderer.states.fillColor) { + if ( + !this._renderer.states.strokeColor && + !this._renderer.states.fillColor + ) { return this; } @@ -546,7 +556,11 @@ function primitives(p5, fn){ h = w; } - const vals = canvas.modeAdjust(x, y, w, h, this._renderer.states.ellipseMode); + const vals = canvas.modeAdjust( + x, y, + w, h, + this._renderer.states.ellipseMode + ); this._renderer.ellipse([vals.x, vals.y, vals.w, vals.h, detailX]); //accessible Outputs diff --git a/src/shape/curves.js b/src/shape/curves.js index 0f8ab0ad8d..d4ab3271bc 100644 --- a/src/shape/curves.js +++ b/src/shape/curves.js @@ -205,7 +205,10 @@ function curves(p5, fn){ // if the current stroke and fill settings wouldn't result in something // visible, exit immediately - if (!this._renderer.states.strokeColor && !this._renderer.states.fillColor) { + if ( + !this._renderer.states.strokeColor && + !this._renderer.states.fillColor + ) { return this; } @@ -462,11 +465,11 @@ function curves(p5, fn){ /** * Draws a curve using a Catmull-Rom spline. - * + * * Spline curves can form shapes and curves that slope gently. They’re like * cables that are attached to a set of points. By default (`ends: INCLUDE`), * the curve passes through all four points you provide, in order - * `p0(x1,y1)` -> `p1(x2,y2)` -> `p2(x3,y3)` -> `p3(x4,y4)`. Think of them as + * `p0(x1,y1)` -> `p1(x2,y2)` -> `p2(x3,y3)` -> `p3(x4,y4)`. Think of them as * points on a curve. If you switch to `ends: EXCLUDE`, p0 and p3 act * like control points and only the middle span `p1->p2` is drawn. * @@ -486,7 +489,7 @@ function curves(p5, fn){ * @chainable * * @example - * + * *
* * function setup() { @@ -508,7 +511,7 @@ function curves(p5, fn){ * } * *
- * + * *
* * function setup() { @@ -518,7 +521,7 @@ function curves(p5, fn){ * * // Exclude the ends—skip the outer spans (p0→p1 and p2→p3) so only the middle span (p1→p2) is drawn. * splineProperty('ends', EXCLUDE); - * + * * // Draw a black spline curve. * noFill(); * strokeWeight(1); @@ -564,10 +567,10 @@ function curves(p5, fn){ * * function draw() { * background(200); - * + * * // Exclude the ends—skip the outer spans (p0→p1 and p2→p3) so only the middle span (p1→p2) is drawn. * splineProperty('ends', EXCLUDE); - * + * * // Draw a black spline curve. * noFill(); * strokeWeight(1); @@ -619,10 +622,10 @@ function curves(p5, fn){ * createCanvas(100, 100); * * background('skyblue'); - * + * * // Exclude the ends—skip the outer spans (p0→p1 and p2→p3) so only the middle span (p1→p2) is drawn. * splineProperty('ends', EXCLUDE); - * + * * // Draw the red balloon. * fill('red'); * spline(-150, 275, 50, 60, 50, 60, 250, 275); @@ -645,10 +648,10 @@ function curves(p5, fn){ * * function draw() { * background('skyblue'); - * + * * // Exclude the ends—skip the outer spans (p0→p1 and p2→p3) so only the middle span (p1→p2) is drawn. * splineProperty('ends', EXCLUDE); - * + * * // Rotate around the y-axis. * rotateY(frameCount * 0.01); * @@ -680,7 +683,10 @@ function curves(p5, fn){ * @chainable */ fn.spline = function(...args) { - if (!this._renderer.states.strokeColor && !this._renderer.states.fillColor) { + if ( + !this._renderer.states.strokeColor && + !this._renderer.states.fillColor + ) { return this; } this._renderer.spline(...args); @@ -822,7 +828,7 @@ function curves(p5, fn){ * `splineTangent()` calculates coordinates along a tangent line using four * points p0, p1, p2, p3. It expects points in the same order as the * spline() function. `splineTangent()` works one - * axis at a time. Passing the points' x-coordinates returns the x-component of + * axis at a time. Passing the points' x-coordinates returns the x-component of * the tangent vector; passing the points' y-coordinates returns the y-component. * The first parameter, `a`, is the coordinate of point p0. * @@ -886,7 +892,7 @@ function curves(p5, fn){ * } * *
- * + * *
* * function setup() { diff --git a/src/shape/custom_shapes.js b/src/shape/custom_shapes.js index 68805260f3..edc0ad416d 100644 --- a/src/shape/custom_shapes.js +++ b/src/shape/custom_shapes.js @@ -311,7 +311,7 @@ class SplineSegment extends Segment { this.vertices[1] : this.vertices[0]; } else { - return this.getStartVertex() + return this.getStartVertex(); } } @@ -817,7 +817,7 @@ class Shape { this.userVertexProperties[key] = dataArray.length; } this.#vertexProperties[key] = dataArray; -} + } vertexPropertyName(key) { return key.replace(/Src$/, ''); } @@ -1226,7 +1226,9 @@ class PrimitiveToVerticesConverter extends PrimitiveVisitor { arrayVertices, splineSegment._splineProperties.tightness ); - let startVertex = shape.vertexToArray(splineSegment._firstInterpolatedVertex); + let startVertex = shape.vertexToArray( + splineSegment._firstInterpolatedVertex + ); for (const array of bezierArrays) { const bezierControls = [startVertex, ...array]; const numPoints = Math.max( @@ -1281,297 +1283,297 @@ function customShapes(p5, fn) { // ---- GENERAL CLASSES ---- /** - * @private - * A class to describe a custom shape made with `beginShape()`/`endShape()`. - * - * Every `Shape` has a `kind`. The kind takes any value that - * can be passed to beginShape(): - * - * - `PATH` - * - `POINTS` - * - `LINES` - * - `TRIANGLES` - * - `QUADS` - * - `TRIANGLE_FAN` - * - `TRIANGLE_STRIP` - * - `QUAD_STRIP` - * - * A `Shape` of any kind consists of `contours`, which can be thought of as - * subshapes (shapes inside another shape). Each `contour` is built from - * basic shapes called primitives, and each primitive consists of one or more vertices. - * - * For example, a square can be made from a single path contour with four line-segment - * primitives. Each line segment contains a vertex that indicates its endpoint. A square - * with a circular hole in it contains the circle in a separate contour. - * - * By default, each vertex only has a position, but a shape's vertices may have other - * properties such as texture coordinates, a normal vector, a fill color, and a stroke color. - * The properties every vertex should have may be customized by passing `vertexProperties` to - * `createShape()`. - * - * Once a shape is created and given a name like `myShape`, it can be built up with - * methods such as `myShape.beginShape()`, `myShape.vertex()`, and `myShape.endShape()`. - * - * Vertex functions such as `vertex()` or `bezierVertex()` are used to set the `position` - * property of vertices, as well as the `textureCoordinates` property if applicable. Those - * properties only apply to a single vertex. - * - * If `vertexProperties` includes other properties, they are each set by a method of the - * same name. For example, if vertices in `myShape` have a `fill`, then that is set with - * `myShape.fill()`. In the same way that a fill() may be applied - * to one or more shapes, `myShape.fill()` may be applied to one or more vertices. - * - * @class p5.Shape - * @param {Object} [vertexProperties={position: createVector(0, 0)}] vertex properties and their initial values. - */ + * @private + * A class to describe a custom shape made with `beginShape()`/`endShape()`. + * + * Every `Shape` has a `kind`. The kind takes any value that + * can be passed to beginShape(): + * + * - `PATH` + * - `POINTS` + * - `LINES` + * - `TRIANGLES` + * - `QUADS` + * - `TRIANGLE_FAN` + * - `TRIANGLE_STRIP` + * - `QUAD_STRIP` + * + * A `Shape` of any kind consists of `contours`, which can be thought of as + * subshapes (shapes inside another shape). Each `contour` is built from + * basic shapes called primitives, and each primitive consists of one or more vertices. + * + * For example, a square can be made from a single path contour with four line-segment + * primitives. Each line segment contains a vertex that indicates its endpoint. A square + * with a circular hole in it contains the circle in a separate contour. + * + * By default, each vertex only has a position, but a shape's vertices may have other + * properties such as texture coordinates, a normal vector, a fill color, and a stroke color. + * The properties every vertex should have may be customized by passing `vertexProperties` to + * `createShape()`. + * + * Once a shape is created and given a name like `myShape`, it can be built up with + * methods such as `myShape.beginShape()`, `myShape.vertex()`, and `myShape.endShape()`. + * + * Vertex functions such as `vertex()` or `bezierVertex()` are used to set the `position` + * property of vertices, as well as the `textureCoordinates` property if applicable. Those + * properties only apply to a single vertex. + * + * If `vertexProperties` includes other properties, they are each set by a method of the + * same name. For example, if vertices in `myShape` have a `fill`, then that is set with + * `myShape.fill()`. In the same way that a fill() may be applied + * to one or more shapes, `myShape.fill()` may be applied to one or more vertices. + * + * @class p5.Shape + * @param {Object} [vertexProperties={position: createVector(0, 0)}] vertex properties and their initial values. + */ p5.Shape = Shape; /** - * @private - * A class to describe a contour made with `beginContour()`/`endContour()`. - * - * Contours may be thought of as shapes inside of other shapes. - * For example, a contour may be used to create a hole in a shape that is created - * with beginShape()/endShape(). - * Multiple contours may be included inside a single shape. - * - * Contours can have any `kind` that a shape can have: - * - * - `PATH` - * - `POINTS` - * - `LINES` - * - `TRIANGLES` - * - `QUADS` - * - `TRIANGLE_FAN` - * - `TRIANGLE_STRIP` - * - `QUAD_STRIP` - * - * By default, a contour has the same kind as the shape that contains it, but this - * may be changed by passing a different `kind` to beginContour(). - * - * A `Contour` of any kind consists of `primitives`, which are the most basic - * shapes that can be drawn. For example, if a contour is a hexagon, then - * it's made from six line-segment primitives. - * - * @class p5.Contour - */ + * @private + * A class to describe a contour made with `beginContour()`/`endContour()`. + * + * Contours may be thought of as shapes inside of other shapes. + * For example, a contour may be used to create a hole in a shape that is created + * with beginShape()/endShape(). + * Multiple contours may be included inside a single shape. + * + * Contours can have any `kind` that a shape can have: + * + * - `PATH` + * - `POINTS` + * - `LINES` + * - `TRIANGLES` + * - `QUADS` + * - `TRIANGLE_FAN` + * - `TRIANGLE_STRIP` + * - `QUAD_STRIP` + * + * By default, a contour has the same kind as the shape that contains it, but this + * may be changed by passing a different `kind` to beginContour(). + * + * A `Contour` of any kind consists of `primitives`, which are the most basic + * shapes that can be drawn. For example, if a contour is a hexagon, then + * it's made from six line-segment primitives. + * + * @class p5.Contour + */ p5.Contour = Contour; /** - * @private - * A base class to describe a shape primitive (a basic shape drawn with - * `beginShape()`/`endShape()`). - * - * Shape primitives are the most basic shapes that can be drawn with - * beginShape()/endShape(): - * - * - segment primitives: line segments, bezier segments, spline segments, and arc segments - * - isolated primitives: points, lines, triangles, and quads - * - tessellation primitives: triangle fans, triangle strips, and quad strips - * - * More complex shapes may be created by combining many primitives, possibly of different kinds, - * into a single shape. - * - * In a similar way, every shape primitive is built from one or more vertices. - * For example, a point consists of a single vertex, while a triangle consists of three vertices. - * Each type of shape primitive has a `vertexCapacity`, which may be `Infinity` (for example, a - * spline may consist of any number of vertices). A primitive's `vertexCount` is the number of - * vertices it currently contains. - * - * Each primitive can add itself to a shape with an `addToShape()` method. - * - * It can also accept visitor objects with an `accept()` method. When a primitive accepts a visitor, - * it gives the visitor access to its vertex data. For example, one visitor to a segment might turn - * the data into 2D drawing instructions. Another might find a point at a given distance - * along the segment. - * - * @class p5.ShapePrimitive - * @abstract - */ + * @private + * A base class to describe a shape primitive (a basic shape drawn with + * `beginShape()`/`endShape()`). + * + * Shape primitives are the most basic shapes that can be drawn with + * beginShape()/endShape(): + * + * - segment primitives: line segments, bezier segments, spline segments, and arc segments + * - isolated primitives: points, lines, triangles, and quads + * - tessellation primitives: triangle fans, triangle strips, and quad strips + * + * More complex shapes may be created by combining many primitives, possibly of different kinds, + * into a single shape. + * + * In a similar way, every shape primitive is built from one or more vertices. + * For example, a point consists of a single vertex, while a triangle consists of three vertices. + * Each type of shape primitive has a `vertexCapacity`, which may be `Infinity` (for example, a + * spline may consist of any number of vertices). A primitive's `vertexCount` is the number of + * vertices it currently contains. + * + * Each primitive can add itself to a shape with an `addToShape()` method. + * + * It can also accept visitor objects with an `accept()` method. When a primitive accepts a visitor, + * it gives the visitor access to its vertex data. For example, one visitor to a segment might turn + * the data into 2D drawing instructions. Another might find a point at a given distance + * along the segment. + * + * @class p5.ShapePrimitive + * @abstract + */ p5.ShapePrimitive = ShapePrimitive; /** - * @private - * A class to describe a vertex (a point on a shape), in 2D or 3D. - * - * Vertices are the basic building blocks of all `p5.Shape` objects, including - * shapes made with vertex(), arcVertex(), - * bezierVertex(), and splineVertex(). - * - * Like a point on an object in the real world, a vertex may have different properties. - * These may include coordinate properties such as `position`, `textureCoordinates`, and `normal`, - * color properties such as `fill` and `stroke`, and more. - * - * A vertex called `myVertex` with position coordinates `(2, 3, 5)` and a green stroke may be created - * like this: - * - * ```js - * let myVertex = new p5.Vertex({ - * position: createVector(2, 3, 5), - * stroke: color('green') - * }); - * ``` - * - * Any property names may be used. The `p5.Shape` class assumes that if a vertex has a - * position or texture coordinates, they are stored in `position` and `textureCoordinates` - * properties. - * - * Property values may be any - * JavaScript primitive, any - * object literal, - * or any object with an `array` property. - * - * For example, if a position is stored as a `p5.Vector` object and a stroke is stored as a `p5.Color` object, - * then the `array` properties of those objects will be used by the vertex's own `array` property, which provides - * all the vertex data in a single array. - * - * @class p5.Vertex - * @param {Object} [properties={position: createVector(0, 0)}] vertex properties. - */ + * @private + * A class to describe a vertex (a point on a shape), in 2D or 3D. + * + * Vertices are the basic building blocks of all `p5.Shape` objects, including + * shapes made with vertex(), arcVertex(), + * bezierVertex(), and splineVertex(). + * + * Like a point on an object in the real world, a vertex may have different properties. + * These may include coordinate properties such as `position`, `textureCoordinates`, and `normal`, + * color properties such as `fill` and `stroke`, and more. + * + * A vertex called `myVertex` with position coordinates `(2, 3, 5)` and a green stroke may be created + * like this: + * + * ```js + * let myVertex = new p5.Vertex({ + * position: createVector(2, 3, 5), + * stroke: color('green') + * }); + * ``` + * + * Any property names may be used. The `p5.Shape` class assumes that if a vertex has a + * position or texture coordinates, they are stored in `position` and `textureCoordinates` + * properties. + * + * Property values may be any + * JavaScript primitive, any + * object literal, + * or any object with an `array` property. + * + * For example, if a position is stored as a `p5.Vector` object and a stroke is stored as a `p5.Color` object, + * then the `array` properties of those objects will be used by the vertex's own `array` property, which provides + * all the vertex data in a single array. + * + * @class p5.Vertex + * @param {Object} [properties={position: createVector(0, 0)}] vertex properties. + */ p5.Vertex = Vertex; // ---- PATH PRIMITIVES ---- /** - * @private - * A class responsible for... - * - * @class p5.Anchor - * @extends p5.ShapePrimitive - * @param {p5.Vertex} vertex the vertex to include in the anchor. - */ + * @private + * A class responsible for... + * + * @class p5.Anchor + * @extends p5.ShapePrimitive + * @param {p5.Vertex} vertex the vertex to include in the anchor. + */ p5.Anchor = Anchor; /** - * @private - * A class responsible for... - * - * Note: When a segment is added to a shape, it's attached to an anchor or another segment. - * Adding it to another shape may result in unexpected behavior. - * - * @class p5.Segment - * @extends p5.ShapePrimitive - * @param {...p5.Vertex} vertices the vertices to include in the segment. - */ + * @private + * A class responsible for... + * + * Note: When a segment is added to a shape, it's attached to an anchor or another segment. + * Adding it to another shape may result in unexpected behavior. + * + * @class p5.Segment + * @extends p5.ShapePrimitive + * @param {...p5.Vertex} vertices the vertices to include in the segment. + */ p5.Segment = Segment; /** - * @private - * A class responsible for... - * - * @class p5.LineSegment - * @param {p5.Vertex} vertex the vertex to include in the anchor. - */ + * @private + * A class responsible for... + * + * @class p5.LineSegment + * @param {p5.Vertex} vertex the vertex to include in the anchor. + */ p5.LineSegment = LineSegment; /** - * @private - * A class responsible for... - */ + * @private + * A class responsible for... + */ p5.BezierSegment = BezierSegment; /** - * @private - * A class responsible for... - */ + * @private + * A class responsible for... + */ p5.SplineSegment = SplineSegment; // ---- ISOLATED PRIMITIVES ---- /** - * @private - * A class responsible for... - */ + * @private + * A class responsible for... + */ p5.Point = Point; /** - * @private - * A class responsible for... - * - * @class p5.Line - * @param {...p5.Vertex} vertices the vertices to include in the line. - */ + * @private + * A class responsible for... + * + * @class p5.Line + * @param {...p5.Vertex} vertices the vertices to include in the line. + */ p5.Line = Line; /** - * @private - * A class responsible for... - */ + * @private + * A class responsible for... + */ p5.Triangle = Triangle; /** - * @private - * A class responsible for... - */ + * @private + * A class responsible for... + */ p5.Quad = Quad; // ---- TESSELLATION PRIMITIVES ---- /** - * @private - * A class responsible for... - */ + * @private + * A class responsible for... + */ p5.TriangleFan = TriangleFan; /** - * @private - * A class responsible for... - */ + * @private + * A class responsible for... + */ p5.TriangleStrip = TriangleStrip; /** - * @private - * A class responsible for... - */ + * @private + * A class responsible for... + */ p5.QuadStrip = QuadStrip; // ---- PRIMITIVE VISITORS ---- /** - * @private - * A class responsible for... - */ + * @private + * A class responsible for... + */ p5.PrimitiveVisitor = PrimitiveVisitor; /** - * @private - * A class responsible for... - * - * Notes: - * 1. Assumes vertex positions are stored as p5.Vector instances. - * 2. Currently only supports position properties of vectors. - */ + * @private + * A class responsible for... + * + * Notes: + * 1. Assumes vertex positions are stored as p5.Vector instances. + * 2. Currently only supports position properties of vectors. + */ p5.PrimitiveToPath2DConverter = PrimitiveToPath2DConverter; /** - * @private - * A class responsible for... - */ + * @private + * A class responsible for... + */ p5.PrimitiveToVerticesConverter = PrimitiveToVerticesConverter; /** - * @private - * A class responsible for... - */ + * @private + * A class responsible for... + */ p5.PointAtLengthGetter = PointAtLengthGetter; @@ -1592,11 +1594,11 @@ function customShapes(p5, fn) { * one call to bezierVertex(), before * a number of `bezierVertex()` calls that is a multiple of the parameter * set by bezierOrder(...) (default 3). - * + * * Each curve of order 3 requires three calls to `bezierVertex`, so * 2 curves would need 7 calls to `bezierVertex()`: * (1 one initial anchor point, two sets of 3 curves describing the curves) - * With `bezierOrder(2)`, two curves would need 5 calls: 1 + 2 + 2. + * With `bezierOrder(2)`, two curves would need 5 calls: 1 + 2 + 2. * * Bézier curves can also be drawn in 3D using WebGL mode. * @@ -1605,7 +1607,7 @@ function customShapes(p5, fn) { * * @method bezierOrder * @param {Number} order The new order to set. Can be either 2 or 3, by default 3 - * + * * @example *
* @@ -1619,7 +1621,7 @@ function customShapes(p5, fn) { * * // Start drawing the shape. * beginShape(); - * + * * // set the order to 2 for a quadratic Bézier curve * bezierOrder(2); * @@ -1647,29 +1649,29 @@ function customShapes(p5, fn) { }; - -/** + + /** * Connects points with a smooth curve (a spline). * - * `splineVertex()` adds a curved segment to custom shapes. - * The curve it creates follows the same rules as the ones + * `splineVertex()` adds a curved segment to custom shapes. + * The curve it creates follows the same rules as the ones * made with the spline() function. - * `splineVertex()` must be called between the + * `splineVertex()` must be called between the * beginShape() and * endShape() functions. * * Spline curves can form shapes and curves that slope gently. They’re like - * cables that are attached to a set of points. `splineVertex()` draws a smooth + * cables that are attached to a set of points. `splineVertex()` draws a smooth * curve through the points you give it. * beginShape() and * endShape() in order to draw a curve: * - * - * If you provide three points, the spline will pass through them. + * + * If you provide three points, the spline will pass through them. * It works the same way with any number of points. - * - * - * + * + * + * * ```js * beginShape(); * @@ -1684,36 +1686,36 @@ function customShapes(p5, fn) { * * endShape(); * ``` - * + * * - * - * + * + * * Passing in `CLOSE` to `endShape()` closes the spline smoothly. * ```js * beginShape(); - * + * * // Add the first point. * splineVertex(25, 80); - * + * * // Add the second point. * splineVertex(20, 30); - * + * * // Add the second point. * splineVertex(85, 60); - * + * * endShape(CLOSE); * ``` - * + * * - * - * + * + * * By default (`ends: INCLUDE`), the curve passes through - * all the points you add with `splineVertex()`, similar to + * all the points you add with `splineVertex()`, similar to * the spline() function. To draw only - * the middle span p1->p2 (skipping p0->p1 and p2->p3), set + * the middle span p1->p2 (skipping p0->p1 and p2->p3), set * `splineProperty('ends', EXCLUDE)`. You don’t need to duplicate * vertices to draw those spans. - * + * * Spline curves can also be drawn in 3D using WebGL mode. The 3D version of * `splineVertex()` has three arguments because each point has x-, y-, and * z-coordinates. By default, the vertex’s z-coordinate is set to 0. @@ -1731,29 +1733,29 @@ function customShapes(p5, fn) { * * function setup() { * createCanvas(100, 100); - * + * * background(220); * noFill(); * strokeWeight(1); - * + * * beginShape(); * splineVertex(25, 80); * splineVertex(20, 30); * splineVertex(85, 60); * endShape(); - * + * * strokeWeight(5); * stroke(0); - * + * * point(25, 80); * point(20, 30); * point(85, 60); - * + * * describe( * 'On a gray background, a black spline passes through three marked points.' * ); * } - * + * * *
* @@ -1773,7 +1775,7 @@ function customShapes(p5, fn) { * 'On a gray background, a closed black spline with a white interior forms a triangular shape with smooth corners.' * ); * } - * + * * *
* @@ -1907,87 +1909,87 @@ function customShapes(p5, fn) { /** * Gets or sets a given spline property. - * - * Use `splineProperty()` to adjust the behavior of splines + * + * Use `splineProperty()` to adjust the behavior of splines * created with `splineVertex()` or `spline()`. You can control * two key aspects of a spline: its end behavior (`ends`) and * its curvature (`tightness`). - * + * * By default, the ends property is set to `INCLUDE`, which means * the spline passes through every point, including the endpoints. - * You can also set it to `EXCLUDE` i.e. `splineProperty('ends', EXCLUDE)`, + * You can also set it to `EXCLUDE` i.e. `splineProperty('ends', EXCLUDE)`, * which makes the spline pass through all points except the endpoints. - * + * * `INCLUDE` case will have the spline passing through * all points, like this: - * + * * ```js * splineProperty('ends', INCLUDE); // no need to set this, as it is the default * spline(25, 46, 93, 44, 93, 81, 35, 85); - * + * * point(25, 46); * point(93, 44); * point(93, 81); * point(35, 85); * ``` - * + * * - * - * + * + * * EXCLUDE case will have the spline passing through - * the middle points, like this: - * - * + * the middle points, like this: + * + * * ```js * splineProperty('ends', INCLUDE); * spline(25, 46, 93, 44, 93, 81, 35, 85); - * + * * point(25, 46); * point(93, 44); * point(93, 81); * point(35, 85); * ``` - * + * * - * - * By default, the tightness property is set to `0`, - * producing a smooth curve that passes evenly through + * + * By default, the tightness property is set to `0`, + * producing a smooth curve that passes evenly through * the vertices. Negative values make the curve looser, - * while positive values make it tighter. Common values - * range between -1 and 1, though values outside this + * while positive values make it tighter. Common values + * range between -1 and 1, though values outside this * range can also be used for different effects. - * - * For example, To set tightness, use `splineProperty('tightness', t)`, + * + * For example, To set tightness, use `splineProperty('tightness', t)`, * (default: t = 0). - * + * * Here's the example showing negetive value of tightness, * which creates a rounder bulge: - * + * * ```js * splineProperty('tightness', -5) * stroke(0); * strokeWeight(2); * spline(25, 46, 93, 44, 93, 81, 35, 85); * ``` - * + * * Here's the example showing positive value of tightness, * which makes the curve tighter and more angular: - * + * * ```js * splineProperty('tightness', 5) * stroke(0); * strokeWeight(2); * spline(25, 46, 93, 44, 93, 81, 35, 85); * ``` - * + * * In all cases, the splines in p5.js are cardinal splines. - * When tightness is 0, these splines are often known as + * When tightness is 0, these splines are often known as * Catmull-Rom splines - * + * * @method splineProperty * @param {String} property * @param value Value to set the given property to. - * + * * @example *
* @@ -2034,7 +2036,7 @@ function customShapes(p5, fn) { * } * *
- * + * * @example *
* @@ -2042,7 +2044,7 @@ function customShapes(p5, fn) { * createCanvas(360, 140); * background(240); * noFill(); - * + * * // Right panel: ends = INCLUDE (all spans). * push(); * translate(10, 10); @@ -2052,12 +2054,12 @@ function customShapes(p5, fn) { * textSize(11); * text('ends: INCLUDE (all spans)', 8, 16); * noFill(); - * + * * splineProperty('ends', INCLUDE); * stroke(0); * strokeWeight(2); * spline(25, 46, 93, 44, 93, 81, 35, 85); - * + * * // vertices * strokeWeight(5); * stroke(0); @@ -2066,7 +2068,7 @@ function customShapes(p5, fn) { * point(93, 81); * point(35, 85); * pop(); - * + * * // Right panel: ends = EXCLUDE (middle only). * push(); * translate(190, 10); @@ -2076,12 +2078,12 @@ function customShapes(p5, fn) { * fill(30); * text('ends: EXCLUDE ', 18, 16); * noFill(); - * + * * splineProperty('ends', EXCLUDE); * stroke(0); * strokeWeight(2); * spline(25, 46, 93, 44, 93, 81, 35, 85); - * + * * // vertices * strokeWeight(5); * stroke(0); @@ -2090,7 +2092,7 @@ function customShapes(p5, fn) { * point(93, 81); * point(35, 85); * pop(); - * + * * describe('Left panel shows spline with ends INCLUDE (three spans). Right panel shows EXCLUDE (only the middle span). Four black points mark the vertices.'); * } * @@ -2108,11 +2110,11 @@ function customShapes(p5, fn) { /** * Get or set multiple spline properties at once. - * + * * Similar to splineProperty(): * `splineProperty('tightness', t)` is the same as * `splineProperties({'tightness': t})` - * + * * @method splineProperties * @param {Object} properties An object containing key-value pairs to set. */ @@ -2291,7 +2293,7 @@ function customShapes(p5, fn) { * } * *
- * + * *
* * let vid; @@ -2299,28 +2301,28 @@ function customShapes(p5, fn) { * // Load a video and create a p5.MediaElement object. * vid = createVideo('/assets/fingers.mov'); * createCanvas(100, 100, WEBGL); - * + * * // Hide the video. * vid.hide(); - * + * * // Set the video to loop. * vid.loop(); - * + * * describe('A rectangle with video as texture'); * } - * + * * function draw() { * background(0); - * + * * // Rotate around the y-axis. * rotateY(frameCount * 0.01); - * + * * // Set the texture mode. * textureMode(NORMAL); - * + * * // Apply the video as a texture. * texture(vid); - * + * * // Draw a custom shape using uv coordinates. * beginShape(); * vertex(-40, -40, 0, 0); @@ -2473,7 +2475,7 @@ function customShapes(p5, fn) { }; /** - * Stops creating a hole within a flat shape. + * Stops creating a hole within a flat shape. * * The beginContour() and `endContour()` * functions allow for creating negative space within custom shapes that are @@ -2483,10 +2485,10 @@ function customShapes(p5, fn) { * called between beginShape() and * endShape(). * - * By default, + * By default, * the controur has an `OPEN` end, and to close it, * call `endContour(CLOSE)`. The CLOSE contour mode closes splines smoothly. - * + * * Transformations such as translate(), * rotate(), and scale() * don't work between beginContour() and diff --git a/src/shape/vertex.js b/src/shape/vertex.js index 2995f4f9a7..8ed828fd30 100644 --- a/src/shape/vertex.js +++ b/src/shape/vertex.js @@ -6,8 +6,6 @@ * @requires constants */ -import * as constants from '../core/constants'; - function vertex(p5, fn){ /** * Begins adding vertices to a custom shape. @@ -416,14 +414,14 @@ function vertex(p5, fn){ * a number of `bezierVertex()` calls that is a multiple of the parameter * set by bezierOrder(...) (default 3). * But shapes can mix different types of vertices, so if there - * are some previous vertices, then the initial anchor is not needed, - * only the multiples of 3 (or the Bézier order) calls to + * are some previous vertices, then the initial anchor is not needed, + * only the multiples of 3 (or the Bézier order) calls to * `bezierVertex` for each curve. - * + * * Each curve of order 3 requires three calls to `bezierVertex`, so * 2 curves would need 7 calls to `bezierVertex()`: * (1 one initial anchor point, two sets of 3 curves describing the curves) - * With `bezierOrder(2)`, two curves would need 5 calls: 1 + 2 + 2. + * With `bezierOrder(2)`, two curves would need 5 calls: 1 + 2 + 2. * * Bézier curves can also be drawn in 3D using WebGL mode. * @@ -610,7 +608,7 @@ function vertex(p5, fn){ * bezierVertex(80, 0); * bezierVertex(80, 75); * bezierVertex(30, 75); - * + * * bezierVertex(50, 80); * bezierVertex(60, 25); * bezierVertex(30, 20); @@ -646,11 +644,11 @@ function vertex(p5, fn){ * // Draw the first moon. * beginShape(); * bezierVertex(-20, -30, 0); - * + * * bezierVertex(30, -50, 0); * bezierVertex(30, 25, 0); * bezierVertex(-20, 25, 0); - * + * * bezierVertex(0, 30, 0); * bezierVertex(10, -25, 0); * bezierVertex(-20, -30, 0); @@ -658,17 +656,17 @@ function vertex(p5, fn){ * * // Draw the second moon. * beginShape(); - * + * * bezierVertex(-20, -30, -20); - * + * * bezierVertex(30, -50, -20); * bezierVertex(30, 25, -20); * bezierVertex(-20, 25, -20); - * + * * bezierVertex(0, 30, -20); * bezierVertex(10, -25, -20); * bezierVertex(-20, -30, -20); - * + * * endShape(); * } * @@ -688,8 +686,8 @@ function vertex(p5, fn){ }; /** - * Concludes the vertices of a custom shape. - * + * Concludes the vertices of a custom shape. + * * The beginShape() and `endShape()` functions * allow for creating custom shapes in 2D or 3D. * beginShape() begins adding vertices to a @@ -700,7 +698,7 @@ function vertex(p5, fn){ * in `endShape(CLOSE)`, then the first and last vertices will be connected. * When CLOSE mode is used for splines (with `splineVeertex()`), the shape is ended smoothly. * - * + * * The second parameter, `count`, is also optional. In WebGL mode, it’s more * efficient to draw many copies of the same shape using a technique called * instancing. @@ -761,22 +759,22 @@ function vertex(p5, fn){ * } * *
- * + * *
* * function setup() { * createCanvas(100, 100); * background(200); - * + * * beginShape(); - * + * * splineVertex(32, 91); * splineVertex(21, 17); * splineVertex(68, 19); * splineVertex(82, 91); - * + * * endShape(CLOSE); - * + * * describe( * 'A curvy four-sided slightly lopsided blob.' * ); diff --git a/src/type/p5.Font.js b/src/type/p5.Font.js index 1b088fad77..83c30fee82 100644 --- a/src/type/p5.Font.js +++ b/src/type/p5.Font.js @@ -272,7 +272,12 @@ export class Font { */ textToPoints(str, x, y, width, height, options) { // By segmenting per contour, pointAtLength becomes much faster - const contourPoints = this.textToContours(str, x, y, width, height, options); + const contourPoints = this.textToContours( + str, + x, y, + width, height, + options + ); return contourPoints.reduce((acc, next) => { acc.push(...next); return acc; @@ -356,183 +361,183 @@ export class Font { cmdContours[cmdContours.length - 1].push(cmd); } - return cmdContours.map((commands) => pathToPoints(commands, options, this)); + return cmdContours.map(commands => pathToPoints(commands, options, this)); } /** - * - * Converts text into a 3D model that can be rendered in WebGL mode. - * - * This method transforms flat text into extruded 3D geometry, allowing - * for dynamic effects like depth, warping, and custom shading. - * - * It works by taking the outlines (contours) of each character in the - * provided text string and constructing a 3D shape from them. - * - * Once your 3D text is ready, you can rotate it in 3D space using orbitControl() - * — just click and drag with your mouse to see it from all angles! - * - * Use the extrude slider to give your letters depth: slide it up, and your - * flat text turns into a solid, multi-dimensional object. - * - * You can also choose from various fonts such as "Anton", "Montserrat", or "Source Serif", - * much like selecting fancy fonts in a word processor, - * - * The generated model (a Geometry object) can be manipulated further—rotated, scaled, - * or styled with shaders—to create engaging, interactive visual art. - * - * @param {String} str The text string to convert into a 3D model. - * @param {Number} x The x-coordinate for the starting position of the text. - * @param {Number} y The y-coordinate for the starting position of the text. - * @param {Number} width Maximum width of the text block (wraps text if exceeded). - * @param {Number} height Maximum height of the text block. - * @param {Object} [options] Configuration options for the 3D text: - * @param {Number} [options.extrude=0] The depth to extrude the text. A value of 0 produces - * flat text; higher values create thicker, 3D models. - * @param {Number} [options.sampleFactor=1] A factor controlling the level of detail for the text contours. - * Higher values result in smoother curves. - * @return {p5.Geometry} A geometry object representing the 3D model of the text. - * - * @example - *
- * - * let font; - * let geom; - * - * async function setup() { - * createCanvas(200, 200, WEBGL); - * font = await loadFont('https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf'); - * - * geom = font.textToModel("Hello", 50, 0, { sampleFactor: 2 }); - * geom.clearColors(); - * geom.normalize(); - * } - * - * function draw() { - * background(255); - * orbitControl(); - * fill("red"); - * strokeWeight(4); - * scale(min(width, height) / 300); - * model(geom); - * describe('A red non-extruded "Hello" in Anton on white canvas, rotatable via mouse.'); - * } - * - *
- * - * @example - *
- * - * let font; - * let geom; - * - * async function setup() { - * createCanvas(200, 200, WEBGL); - * - * // Alternative fonts: - * // Anton: 'https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf' - * // Montserrat: 'https://fonts.gstatic.com/s/montserrat/v29/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Ew-Y3tcoqK5.ttf' - * // Source Serif: 'https://fonts.gstatic.com/s/sourceserif4/v8/vEFy2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6OAVIJmeUDygwjihdqrhxXD-wGvjU.ttf' - * - * // Using Source Serif for this example: - * font = await loadFont('https://fonts.gstatic.com/s/sourceserif4/v8/vEFy2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6OAVIJmeUDygwjihdqrhxXD-wGvjU.ttf'); - * - * geom = font.textToModel("Hello", 50, 0, { sampleFactor: 2, extrude: 5 }); - * geom.clearColors(); - * geom.normalize(); - * } - * - * function draw() { - * background(255); - * orbitControl(); - * fill("red"); - * strokeWeight(4); - * scale(min(width, height) / 300); - * model(geom); - * describe('3D red extruded "Hello" in Source Serif on white, rotatable via mouse.'); - * } - * - *
- * - * @example - *
- * - * let geom; - * let activeFont; - * let artShader; - * let lineShader; - * - * // Define parameters as simple variables - * let words = 'HELLO'; - * let warp = 1; - * let extrude = 5; - * let palette = ["#ffe03d", "#fe4830", "#d33033", "#6d358a", "#1c509e", "#00953c"]; - * - * async function setup() { - * createCanvas(200, 200, WEBGL); - * - * // Using Anton as the default font for this example: - * - * // Alternative fonts: - * // Anton: 'https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf' - * // Montserrat: 'https://fonts.gstatic.com/s/montserrat/v29/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Ew-Y3tcoqK5.ttf' - * // Source Serif: 'https://fonts.gstatic.com/s/sourceserif4/v8/vEFy2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6OAVIJmeUDygwjihdqrhxXD-wGvjU.ttf' - * activeFont = await loadFont('https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf'); - * - * geom = activeFont.textToModel(words, 0, 50, { sampleFactor: 2, extrude }); - * geom.clearColors(); - * geom.normalize(); - * - * artShader = baseMaterialShader().modify({ - * uniforms: { - * 'float time': () => millis(), - * 'float warp': () => warp, - * 'float numColors': () => palette.length, - * 'vec3[6] colors': () => palette.flatMap((c) => [red(c)/255, green(c)/255, blue(c)/255]), - * }, - * vertexDeclarations: 'out vec3 vPos;', - * fragmentDeclarations: 'in vec3 vPos;', - * 'Vertex getObjectInputs': `(Vertex inputs) { - * vPos = inputs.position; - * inputs.position.x += 5. * warp * sin(inputs.position.y * 0.1 + time * 0.001) / (1. + warp); - * inputs.position.y += 5. * warp * sin(inputs.position.x * 0.1 + time * 0.0009) / (1. + warp); - * return inputs; - * }`, - * 'vec4 getFinalColor': `(vec4 _c) { - * float x = vPos.x * 0.005; - * float a = floor(fract(x) * numColors); - * float b = a == numColors - 1. ? 0. : a + 1.; - * float t = fract(x * numColors); - * vec3 c = mix(colors[int(a)], colors[int(b)], t); - * return vec4(c, 1.); - * }` - * }); - * - * lineShader = baseStrokeShader().modify({ - * uniforms: { - * 'float time': () => millis(), - * 'float warp': () => warp, - * }, - * 'StrokeVertex getObjectInputs': `(StrokeVertex inputs) { - * inputs.position.x += 5. * warp * sin(inputs.position.y * 0.1 + time * 0.001) / (1. + warp); - * inputs.position.y += 5. * warp * sin(inputs.position.x * 0.1 + time * 0.0009) / (1. + warp); - * return inputs; - * }`, - * }); - * } - * - * function draw() { - * background(255); - * orbitControl(); - * shader(artShader); - * strokeShader(lineShader); - * strokeWeight(4); - * scale(min(width, height) / 210); - * model(geom); - * describe('3D wavy with different color sets "Hello" in Anton on white canvas, rotatable via mouse.'); - * } - * - *
- */ + * + * Converts text into a 3D model that can be rendered in WebGL mode. + * + * This method transforms flat text into extruded 3D geometry, allowing + * for dynamic effects like depth, warping, and custom shading. + * + * It works by taking the outlines (contours) of each character in the + * provided text string and constructing a 3D shape from them. + * + * Once your 3D text is ready, you can rotate it in 3D space using orbitControl() + * — just click and drag with your mouse to see it from all angles! + * + * Use the extrude slider to give your letters depth: slide it up, and your + * flat text turns into a solid, multi-dimensional object. + * + * You can also choose from various fonts such as "Anton", "Montserrat", or "Source Serif", + * much like selecting fancy fonts in a word processor, + * + * The generated model (a Geometry object) can be manipulated further—rotated, scaled, + * or styled with shaders—to create engaging, interactive visual art. + * + * @param {String} str The text string to convert into a 3D model. + * @param {Number} x The x-coordinate for the starting position of the text. + * @param {Number} y The y-coordinate for the starting position of the text. + * @param {Number} width Maximum width of the text block (wraps text if exceeded). + * @param {Number} height Maximum height of the text block. + * @param {Object} [options] Configuration options for the 3D text: + * @param {Number} [options.extrude=0] The depth to extrude the text. A value of 0 produces + * flat text; higher values create thicker, 3D models. + * @param {Number} [options.sampleFactor=1] A factor controlling the level of detail for the text contours. + * Higher values result in smoother curves. + * @return {p5.Geometry} A geometry object representing the 3D model of the text. + * + * @example + *
+ * + * let font; + * let geom; + * + * async function setup() { + * createCanvas(200, 200, WEBGL); + * font = await loadFont('https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf'); + * + * geom = font.textToModel("Hello", 50, 0, { sampleFactor: 2 }); + * geom.clearColors(); + * geom.normalize(); + * } + * + * function draw() { + * background(255); + * orbitControl(); + * fill("red"); + * strokeWeight(4); + * scale(min(width, height) / 300); + * model(geom); + * describe('A red non-extruded "Hello" in Anton on white canvas, rotatable via mouse.'); + * } + * + *
+ * + * @example + *
+ * + * let font; + * let geom; + * + * async function setup() { + * createCanvas(200, 200, WEBGL); + * + * // Alternative fonts: + * // Anton: 'https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf' + * // Montserrat: 'https://fonts.gstatic.com/s/montserrat/v29/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Ew-Y3tcoqK5.ttf' + * // Source Serif: 'https://fonts.gstatic.com/s/sourceserif4/v8/vEFy2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6OAVIJmeUDygwjihdqrhxXD-wGvjU.ttf' + * + * // Using Source Serif for this example: + * font = await loadFont('https://fonts.gstatic.com/s/sourceserif4/v8/vEFy2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6OAVIJmeUDygwjihdqrhxXD-wGvjU.ttf'); + * + * geom = font.textToModel("Hello", 50, 0, { sampleFactor: 2, extrude: 5 }); + * geom.clearColors(); + * geom.normalize(); + * } + * + * function draw() { + * background(255); + * orbitControl(); + * fill("red"); + * strokeWeight(4); + * scale(min(width, height) / 300); + * model(geom); + * describe('3D red extruded "Hello" in Source Serif on white, rotatable via mouse.'); + * } + * + *
+ * + * @example + *
+ * + * let geom; + * let activeFont; + * let artShader; + * let lineShader; + * + * // Define parameters as simple variables + * let words = 'HELLO'; + * let warp = 1; + * let extrude = 5; + * let palette = ["#ffe03d", "#fe4830", "#d33033", "#6d358a", "#1c509e", "#00953c"]; + * + * async function setup() { + * createCanvas(200, 200, WEBGL); + * + * // Using Anton as the default font for this example: + * + * // Alternative fonts: + * // Anton: 'https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf' + * // Montserrat: 'https://fonts.gstatic.com/s/montserrat/v29/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Ew-Y3tcoqK5.ttf' + * // Source Serif: 'https://fonts.gstatic.com/s/sourceserif4/v8/vEFy2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6OAVIJmeUDygwjihdqrhxXD-wGvjU.ttf' + * activeFont = await loadFont('https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf'); + * + * geom = activeFont.textToModel(words, 0, 50, { sampleFactor: 2, extrude }); + * geom.clearColors(); + * geom.normalize(); + * + * artShader = baseMaterialShader().modify({ + * uniforms: { + * 'float time': () => millis(), + * 'float warp': () => warp, + * 'float numColors': () => palette.length, + * 'vec3[6] colors': () => palette.flatMap((c) => [red(c)/255, green(c)/255, blue(c)/255]), + * }, + * vertexDeclarations: 'out vec3 vPos;', + * fragmentDeclarations: 'in vec3 vPos;', + * 'Vertex getObjectInputs': `(Vertex inputs) { + * vPos = inputs.position; + * inputs.position.x += 5. * warp * sin(inputs.position.y * 0.1 + time * 0.001) / (1. + warp); + * inputs.position.y += 5. * warp * sin(inputs.position.x * 0.1 + time * 0.0009) / (1. + warp); + * return inputs; + * }`, + * 'vec4 getFinalColor': `(vec4 _c) { + * float x = vPos.x * 0.005; + * float a = floor(fract(x) * numColors); + * float b = a == numColors - 1. ? 0. : a + 1.; + * float t = fract(x * numColors); + * vec3 c = mix(colors[int(a)], colors[int(b)], t); + * return vec4(c, 1.); + * }` + * }); + * + * lineShader = baseStrokeShader().modify({ + * uniforms: { + * 'float time': () => millis(), + * 'float warp': () => warp, + * }, + * 'StrokeVertex getObjectInputs': `(StrokeVertex inputs) { + * inputs.position.x += 5. * warp * sin(inputs.position.y * 0.1 + time * 0.001) / (1. + warp); + * inputs.position.y += 5. * warp * sin(inputs.position.x * 0.1 + time * 0.0009) / (1. + warp); + * return inputs; + * }`, + * }); + * } + * + * function draw() { + * background(255); + * orbitControl(); + * shader(artShader); + * strokeShader(lineShader); + * strokeWeight(4); + * scale(min(width, height) / 210); + * model(geom); + * describe('3D wavy with different color sets "Hello" in Anton on white canvas, rotatable via mouse.'); + * } + * + *
+ */ textToModel(str, x, y, width, height, options) { ({ width, height, options } = this._parseArgs(width, height, options)); const extrude = options?.extrude || 0; @@ -586,7 +591,7 @@ export class Font { if (extrude !== 0) { geom.computeNormals(); for (const face of geom.faces) { - if (face.every((idx) => geom.vertices[idx].z <= -extrude * 0.5 + 0.1)) { + if (face.every(idx => geom.vertices[idx].z <= -extrude * 0.5 + 0.1)) { for (const idx of face) geom.vertexNormals[idx].set(0, 0, -1); face.reverse(); } @@ -667,8 +672,8 @@ export class Font { // lineate and compute bounds for the text let { lines, bounds } = renderer._computeBounds - (textCoreConstants._FONT_BOUNDS, str, x, y, width, height, - { ignoreRectMode: true, ...options }); + (textCoreConstants._FONT_BOUNDS, str, x, y, width, height, + { ignoreRectMode: true, ...options }); // compute positions for each of the lines lines = this._position(renderer, lines, bounds, width, height); @@ -729,7 +734,7 @@ export class Font { subdivide(pts, pt1, middle, md); subdivide(pts, middle, pt2, md); } - } + }; // a point for each path-command plus line subdivisions let pts = []; @@ -739,7 +744,7 @@ export class Font { for (let i = 0; i < cmds.length; i++) { let { type, data: d } = cmds[i]; if (type !== 'Z') { - let pt = { x: d[d.length - 2], y: d[d.length - 1] } + let pt = { x: d[d.length - 2], y: d[d.length - 1] }; if (type === 'L' && pts.length && !options?.nodivide > 0) { subdivide(pts, pts[pts.length - 1], pt, maxDist); } @@ -792,7 +797,7 @@ export class Font { } } return { text, x, y }; - } + }; return lines.map(coordify); } @@ -824,7 +829,14 @@ export class Font { return positionedGlyphs; } - _singleShapeToPath(shape, { scale = 1, x = 0, y = 0, lineX = 0, lineY = 0, axs } = {}) { + _singleShapeToPath(shape, { + scale = 1, + x = 0, + y = 0, + lineX = 0, + lineY = 0, + axs + } = {}) { let font = this.data; let crdIdx = 0; let { g, ax, ay, dx, dy } = shape; @@ -872,7 +884,7 @@ export class Font { y, lineX: line.x, lineY: line.y, - axs, + axs }); paths.push(glyph); @@ -924,19 +936,23 @@ export class Font { // iterate over the path, storing each non-control point for (let c = 0, j = 0; j < cmds.length; j++) { let cmd = cmds[j], obj = { type: cmd, data: [] }; - if (cmd == "M" || cmd == "L") { + if (cmd === 'M' || cmd === 'L') { obj.data.push(x + crds[c] * scale, y + crds[c + 1] * -scale); c += 2; } - else if (cmd == "C") { + else if (cmd === 'C') { for (let i = 0; i < 6; i += 2) { - obj.data.push(x + crds[c + i] * scale, y + crds[c + i + 1] * -scale); + obj.data.push( + x + crds[c + i] * scale, y + crds[c + i + 1] * -scale + ); } c += 6; } - else if (cmd == "Q") { + else if (cmd === 'Q') { for (let i = 0; i < 4; i += 2) { - obj.data.push(x + crds[c + i] * scale, y + crds[c + i + 1] * -scale); + obj.data.push( + x + crds[c + i] * scale, y + crds[c + i + 1] * -scale + ); } c += 4; } @@ -982,7 +998,9 @@ function createFontFace(name, path, descriptors, rawFont) { if ((rawFont?.fvar?.length ?? 0) > 0) { descriptors = descriptors || {}; - for (const [tag, minVal, defaultVal, maxVal, flags, name] of rawFont.fvar[0]) { + for (const [ + tag, minVal, defaultVal, maxVal, flags, name + ] of rawFont.fvar[0]) { if (tag === 'wght') { descriptors.weight = `${minVal} ${maxVal}`; } else if (tag === 'wdth') { @@ -1047,12 +1065,12 @@ function pathToPoints(cmds, options, font) { } } return options; - } + }; const at = (v, i) => { const s = v.length; return v[i < 0 ? i % s + s : i % s]; - } + }; const simplify = (pts, angle) => { angle = angle || 0; @@ -1064,7 +1082,7 @@ function pathToPoints(cmds, options, font) { } } return num; - } + }; const path = createFromCommands(arrayCommandsToObjects(cmds)); let opts = parseOpts(options, { @@ -1072,7 +1090,10 @@ function pathToPoints(cmds, options, font) { simplifyThreshold: 0 }); - const totalPoints = Math.max(1, Math.ceil(path.getTotalLength() * opts.sampleFactor)); + const totalPoints = Math.max( + 1, + Math.ceil(path.getTotalLength() * opts.sampleFactor) + ); let points = []; const mode = font._pInst.angleMode(); @@ -1312,20 +1333,26 @@ function font(p5, fn) { *
*/ /** - * @method loadFont - * @for p5 - * @param {String} path path of the font to be loaded. - * @param {Function} [successCallback] function called with the - * p5.Font object after it - * loads. - * @param {Function} [failureCallback] function called with the error - * Event - * object if the font fails to load. - * @returns {Promise} The font. - */ - fn.loadFont = async function (...args/*path, name, onSuccess, onError, descriptors*/) { - - let { path, name, success, error, options: { sets, ...descriptors } = {} } = parseCreateArgs(...args); + * @method loadFont + * @for p5 + * @param {String} path path of the font to be loaded. + * @param {Function} [successCallback] function called with the + * p5.Font object after it + * loads. + * @param {Function} [failureCallback] function called with the error + * Event + * object if the font fails to load. + * @returns {Promise} The font. + */ + fn.loadFont = async function (...args) { + /*path, name, onSuccess, onError, descriptors*/ + let { + path, + name, + success, + error, + options: { sets, ...descriptors } = {} + } = parseCreateArgs(...args); let isCSS = path.includes('@font-face'); @@ -1334,7 +1361,7 @@ function font(p5, fn) { const isCSSFile = info.headers.get('content-type')?.startsWith('text/css'); if (isCSSFile) { isCSS = true; - path = await fetch(path).then((res) => res.text()); + path = await fetch(path).then(res => res.text()); } } @@ -1368,12 +1395,12 @@ function font(p5, fn) { if (urlMatch) { let url = urlMatch[1]; if (/^['"]/.exec(url) && url.at(0) === url.at(-1)) { - url = url.slice(1, -1) + url = url.slice(1, -1); } fontData = await fn.parseFontData(url); } } catch (_e) {} - return create(this, name, src, fontDescriptors, fontData) + return create(this, name, src, fontDescriptors, fontData); }, loadWithoutData: () => create(this, name, src, fontDescriptors) }); @@ -1386,14 +1413,14 @@ function font(p5, fn) { .map(s => s.toLowerCase()); // Grab thr named groups with names that include the requested keywords const requestedCategories = unicodeRanges - .filter((r) => requestedGroups.some( + .filter(r => requestedGroups.some( g => r.category.includes(g) && // Only include extended character sets if specifically requested r.category.includes('ext') === g.includes('ext') )); const requestedRanges = new Set( UnicodeRange.parse( - requestedCategories.map((c) => `U+${c.hexrange[0]}-${c.hexrange[1]}`) + requestedCategories.map(c => `U+${c.hexrange[0]}-${c.hexrange[1]}`) ) ); let closestRangeOverlap = 0; @@ -1423,9 +1450,12 @@ function font(p5, fn) { if ( descriptorOverlap > closestDescriptorOverlap || - (descriptorOverlap === closestDescriptorOverlap && rangeOverlap >= closestRangeOverlap) + ( + descriptorOverlap === closestDescriptorOverlap && + rangeOverlap >= closestRangeOverlap + ) ) { - closestDescriptorOverlap = descriptorOverlap + closestDescriptorOverlap = descriptorOverlap; closestRangeOverlap = rangeOverlap; closestMatch = font; } @@ -1455,7 +1485,7 @@ function font(p5, fn) { // failed to parse the font, load it as a simple FontFace let ident = name || path .substring(path.lastIndexOf('/') + 1) - .replace(/\.[^/.]+$/, ""); + .replace(/\.[^/.]+$/, ''); console.warn(`WARN: No glyph data for '${ident}', retrying as FontFace`); @@ -1471,11 +1501,11 @@ function font(p5, fn) { if (success) return success(pfont); return pfont; - } + }; }; // Convert arrays to named objects -export const arrayCommandsToObjects = (commands) => commands.map((command) => { +export const arrayCommandsToObjects = commands => commands.map(command => { const type = command[0]; switch (type) { case 'Z': { diff --git a/src/type/textCore.js b/src/type/textCore.js index 11c863d650..3a769cb73e 100644 --- a/src/type/textCore.js +++ b/src/type/textCore.js @@ -14,8 +14,8 @@ export const textCoreConstants = { _FONT_BOUNDS: '_fontBoundsSingle', HANGING: 'hanging', START: 'start', - END: 'end', -} + END: 'end' +}; function textCore(p5, fn) { const LeadingScale = 1.275; @@ -486,43 +486,43 @@ function textCore(p5, fn) { * */ -/** - * Sets the spacing between lines of text when - * text() is called. - * - * Note: Spacing is measured in pixels. - * - * Calling `textLeading()` without an argument returns the current spacing. - * - * @method textLeading - * @for p5 - * @param {Number} leading The new text leading to apply, in pixels - * @returns {Number} If no arguments are provided, the current text leading - * - * @example - *
- * - * function setup() { - * createCanvas(100, 100); - * - * background(200); - * - * // "\n" starts a new line of text. - * let lines = 'one\ntwo'; - * - * // Left. - * text(lines, 10, 25); - * - * // Right. - * textLeading(30); - * text(lines, 70, 25); - * - * describe('The words "one" and "two" written on separate lines twice. The words on the left have less vertical spacing than the words on the right.'); - * } - * - *
- */ - /* + /** + * Sets the spacing between lines of text when + * text() is called. + * + * Note: Spacing is measured in pixels. + * + * Calling `textLeading()` without an argument returns the current spacing. + * + * @method textLeading + * @for p5 + * @param {Number} leading The new text leading to apply, in pixels + * @returns {Number} If no arguments are provided, the current text leading + * + * @example + *
+ * + * function setup() { + * createCanvas(100, 100); + * + * background(200); + * + * // "\n" starts a new line of text. + * let lines = 'one\ntwo'; + * + * // Left. + * text(lines, 10, 25); + * + * // Right. + * textLeading(30); + * text(lines, 70, 25); + * + * describe('The words "one" and "two" written on separate lines twice. The words on the left have less vertical spacing than the words on the right.'); + * } + * + *
+ */ + /* * @method textLeading * @for p5 */ @@ -683,11 +683,11 @@ function textCore(p5, fn) { *
* */ - /** - * @method textSize - * @for p5 - * @returns {Number} The current text size in pixels. - */ + /** + * @method textSize + * @for p5 + * @returns {Number} The current text size in pixels. + */ /** * Sets the style for system fonts when @@ -930,11 +930,11 @@ function textCore(p5, fn) { * * */ - /** - * @method textWrap - * @for p5 - * @returns {CHAR|WORD} The current wrapping style - */ + /** + * @method textWrap + * @for p5 + * @returns {CHAR|WORD} The current wrapping style + */ /** @@ -1034,11 +1034,11 @@ function textCore(p5, fn) { * * */ - /** - * @method textDirection - * @for p5 - * @returns {String} The current text direction, either "ltr", "rtl", or "inherit" - */ + /** + * @method textDirection + * @for p5 + * @returns {String} The current text direction, either "ltr", "rtl", or "inherit" + */ /** * Sets or gets a single text property for the renderer. @@ -1090,12 +1090,12 @@ function textCore(p5, fn) { * * */ - /** - * @method textProperty - * @for p5 - * @param {String} prop - The name of the text property to set or get. - * @returns The current value of the specified text property - */ + /** + * @method textProperty + * @for p5 + * @param {String} prop - The name of the text property to set or get. + * @returns The current value of the specified text property + */ /** * Gets or sets text properties in batch, similar to calling `textProperty()` @@ -1423,17 +1423,18 @@ function textCore(p5, fn) { lineHeight: { default: fn.NORMAL, isShorthand: true }, // line-height: { default: normal | number | length | percentage } fontVariant: { default: fn.NORMAL, isShorthand: true }, // font-variant: { default: normal | small-caps } fontStyle: { default: fn.NORMAL, isShorthand: true }, // font-style: { default: normal | italic | oblique } [was 'textStyle' in v1] - direction: { default: 'inherit' }, // direction: { default: inherit | ltr | rtl } + direction: { default: 'inherit' } // direction: { default: inherit | ltr | rtl } }; // note: font must be first here otherwise it may reset other properties const ContextTextProps = ['font', 'direction', 'fontKerning', 'fontStretch', 'fontVariantCaps', 'letterSpacing', 'textAlign', 'textBaseline', 'textRendering', 'wordSpacing']; // shorthand font properties that can be set with context2d.font - const ShorthandFontProps = Object.keys(RendererTextProps).filter(p => RendererTextProps[p].isShorthand); + const ShorthandFontProps = Object.keys(RendererTextProps) + .filter(p => RendererTextProps[p].isShorthand); // allowable values for font-stretch property for context2d.font - const FontStretchKeys = ["ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "normal", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded"]; + const FontStretchKeys = ['ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded']; let contextQueue, cachedDiv; // lazy @@ -1470,7 +1471,12 @@ function textCore(p5, fn) { */ Renderer.prototype.textBounds = function (str, x, y, width, height) { // delegate to _textBoundsSingle for measuring - return this._computeBounds(textCoreConstants._TEXT_BOUNDS, str, x, y, width, height).bounds; + return this._computeBounds( + textCoreConstants._TEXT_BOUNDS, + str, + x, y, + width, height + ).bounds; }; /** @@ -1485,7 +1491,12 @@ function textCore(p5, fn) { */ Renderer.prototype.fontBounds = function (str, x, y, width, height) { // delegate to _fontBoundsSingle for measuring - return this._computeBounds(textCoreConstants._FONT_BOUNDS, str, x, y, width, height).bounds; + return this._computeBounds( + textCoreConstants._FONT_BOUNDS, + str, + x, y, + width, height + ).bounds; }; /** @@ -1571,7 +1582,7 @@ function textCore(p5, fn) { Renderer.prototype._currentTextFont = function () { return this.states.textFont.font || this.states.textFont.family; - } + }; /** * Set the font and [size] and [options] for rendering text @@ -1628,7 +1639,7 @@ function textCore(p5, fn) { } return this._applyTextProperties(); - } + }; Renderer.prototype._directSetFontString = function (font, debug = 0) { if (debug) console.log('_directSetFontString"' + font + '"'); @@ -1647,7 +1658,7 @@ function textCore(p5, fn) { }); return { family: style.fontFamily, size: style.fontSize }; - } + }; Renderer.prototype.textLeading = function (leading) { // the setter @@ -1658,7 +1669,7 @@ function textCore(p5, fn) { } // the getter return this.states.textLeading; - } + }; Renderer.prototype.textWeight = function (weight) { // the setter @@ -1676,7 +1687,7 @@ function textCore(p5, fn) { } // the getter return this.states.fontWeight; - } + }; /** * @param {*} size - the size of the text, can be a number or a css-style string @@ -1691,7 +1702,7 @@ function textCore(p5, fn) { } // the getter return this.states.textSize; - } + }; Renderer.prototype.textStyle = function (style) { @@ -1702,7 +1713,7 @@ function textCore(p5, fn) { } // the getter return this.states.fontStyle; - } + }; Renderer.prototype.textWrap = function (wrapStyle) { @@ -1818,14 +1829,20 @@ function textCore(p5, fn) { Renderer.prototype._currentTextFont = function () { return this.states.textFont.font || this.states.textFont.family; - } + }; /* Compute the bounds for a block of text based on the specified measure function, either _textBoundsSingle or _fontBoundsSingle * @private */ - Renderer.prototype._computeBounds = function (type, str, x, y, width, height, opts) { + Renderer.prototype._computeBounds = function ( + type, + str, + x, y, + width, height, + opts + ) { let context = this.textDrawingContext(); let setBaseline = context.textBaseline; @@ -1839,13 +1856,16 @@ function textCore(p5, fn) { // get the adjusted positions [x,y] for each line let boxes = lines.map((line, i) => this[type].bind(this) - (line, x, y + i * textLeading)); + (line, x, y + i * textLeading)); // adjust the bounding boxes based on horiz. text alignment if (lines.length > 1) { // Call the 2D mode version: the WebGL mode version does additional // alignment adjustments to account for how WebGL renders text. - boxes.forEach(bb => bb.x += p5.Renderer2D.prototype._xAlignOffset.call(this, textAlign, width)); + boxes.forEach(bb => + bb.x += p5.Renderer2D.prototype._xAlignOffset + .call(this, textAlign, width) + ); } // adjust the bounding boxes based on vert. text alignment @@ -1901,7 +1921,7 @@ function textCore(p5, fn) { } } return { x, y, width, height }; - } + }; /* Attempts to set a property directly on the canvas.style object @@ -1937,7 +1957,9 @@ function textCore(p5, fn) { working consistently across browsers at present * @private */ - Renderer.prototype._handleFontVariationSettings = function (value, debug = false) { + Renderer.prototype._handleFontVariationSettings = function ( + value, debug = false + ) { // check if the value is a string or an object if (typeof value === 'object') { value = Object.keys(value).map(k => k + ' ' + value[k]).join(', '); @@ -1960,19 +1982,20 @@ function textCore(p5, fn) { case 'wdth': if (0) { // attempt to map font-stretch to allowed keywords const FontStretchMap = { - "ultra-condensed": 50, - "extra-condensed": 62.5, - "condensed": 75, - "semi-condensed": 87.5, - "normal": 100, - "semi-expanded": 112.5, - "expanded": 125, - "extra-expanded": 150, - "ultra-expanded": 200, + 'ultra-condensed': 50, + 'extra-condensed': 62.5, + 'condensed': 75, + 'semi-condensed': 87.5, + 'normal': 100, + 'semi-expanded': 112.5, + 'expanded': 125, + 'extra-expanded': 150, + 'ultra-expanded': 200 }; let values = Object.values(FontStretchMap); - const indexArr = values.map(function (k) { return Math.abs(k - val) }) - const min = Math.min.apply(Math, indexArr) + const indexArr = values + .map(function (k) { return Math.abs(k - val); }); + const min = Math.min.apply(Math, indexArr); let idx = indexArr.indexOf(min); let stretch = Object.keys(FontStretchMap)[idx]; this.states.setValue('fontStretch', stretch); @@ -2054,9 +2077,11 @@ function textCore(p5, fn) { @returns {number} - the computed font-size in pixels * @private */ - Renderer.prototype._fontSizePx = function (theSize, { family } = this.states.textFont) { - - const isNumString = (num) => !isNaN(num) && num.trim() !== ''; + Renderer.prototype._fontSizePx = function ( + theSize, + { family } = this.states.textFont + ) { + const isNumString = num => !isNaN(num) && num.trim() !== ''; // check for a number in a string, eg '12' if (isNumString(theSize)) { @@ -2085,7 +2110,7 @@ function textCore(p5, fn) { cachedDiv = ele; } return cachedDiv; - } + }; /* @@ -2133,7 +2158,8 @@ function textCore(p5, fn) { let lines = this._splitOnBreaks(str.toString()); let hasLineBreaks = lines.length > 1; let hasWidth = typeof width !== 'undefined'; - let exceedsWidth = hasWidth && lines.some(l => this._textWidthSingle(l) > width); + let exceedsWidth = hasWidth && + lines.some(l => this._textWidthSingle(l) > width); let { textLeading: leading, textWrap } = this.states; //if (!hasLineBreaks && !exceedsWidth) return lines; // a single-line @@ -2180,7 +2206,7 @@ function textCore(p5, fn) { default: return 0; } - } + }; /* Align the bounding box based on the current rectMode setting @@ -2206,7 +2232,7 @@ function textCore(p5, fn) { } return bb; } - } + }; Renderer.prototype._rectModeAlignRevert = function (bb, width, height) { if (typeof width !== 'undefined') { @@ -2229,7 +2255,7 @@ function textCore(p5, fn) { } return bb; } - } + }; /* Get the (tight) width of a single line of text @@ -2314,7 +2340,12 @@ function textCore(p5, fn) { @returns {array} - the split lines of text * @private */ - Renderer.prototype._lineate = function (textWrap, lines, maxWidth = Infinity, opts = {}) { + Renderer.prototype._lineate = function ( + textWrap, + lines, + maxWidth = Infinity, + opts = {} + ) { let splitter = opts.splitChar ?? (textWrap === fn.WORD ? ' ' : ''); let line, testLine, testWidth, words, newLines = []; @@ -2376,7 +2407,14 @@ function textCore(p5, fn) { - line-height must immediately follow font-size, preceded by "/", eg 16px/3. - font-family must be the last value specified. */ - let { textFont, textSize, lineHeight, fontStyle, fontWeight, fontVariant } = this.states; + let { + textFont, + textSize, + lineHeight, + fontStyle, + fontWeight, + fontVariant + } = this.states; let drawingContext = this.textDrawingContext(); let family = this._parseFontFamily(textFont.family); @@ -2401,7 +2439,7 @@ function textCore(p5, fn) { } } return true; - } + }; /* Apply the text properties in `this.states` to the `this.textDrawingContext()` @@ -2478,7 +2516,11 @@ function textCore(p5, fn) { /* Position the lines of text based on their textAlign/textBaseline properties */ - p5.Renderer2D.prototype._positionLines = function (x, y, width, height, lines) { + p5.Renderer2D.prototype._positionLines = function ( + x, y, + width, height, + lines + ) { let { textLeading, textAlign } = this.states; let adjustedX, lineData = new Array(lines.length); @@ -2539,7 +2581,7 @@ function textCore(p5, fn) { } dataArr.forEach(ele => ele.y += yOff); return dataArr; - } + }; } if (p5.RendererGL) { @@ -2569,10 +2611,14 @@ function textCore(p5, fn) { oldRemove.call(this); }; - p5.RendererGL.prototype._positionLines = function (x, y, width, height, lines) { + p5.RendererGL.prototype._positionLines = function ( + x, y, + width, height, + lines + ) { let { textLeading, textAlign } = this.states; - const widths = lines.map((line) => this._fontWidthSingle(line)); + const widths = lines.map(line => this._fontWidthSingle(line)); let adjustedX, lineData = new Array(lines.length); let adjustedW = typeof width === 'undefined' ? Math.max(0, ...widths) : width; let adjustedH = typeof height === 'undefined' ? 0 : height; @@ -2585,7 +2631,10 @@ function textCore(p5, fn) { adjustedX = x; break; case fn.CENTER: - adjustedX = x + (adjustedW - widths[i]) / 2 - adjustedW / 2 + (width || 0) / 2; + adjustedX = x + + (adjustedW - widths[i]) / 2 - + adjustedW / 2 + + (width || 0) / 2; break; case fn.RIGHT: adjustedX = x + adjustedW - widths[i] - adjustedW + (width || 0); @@ -2607,7 +2656,8 @@ function textCore(p5, fn) { let { textLeading, textBaseline, textSize, textFont } = this.states; let yOff = 0, numLines = dataArr.length; - let totalHeight = textSize * numLines + ((textLeading - textSize) * (numLines - 1)); + let totalHeight = textSize * numLines + + ((textLeading - textSize) * (numLines - 1)); switch (textBaseline) { // drawingContext ? case fn.TOP: yOff = textSize; @@ -2627,7 +2677,7 @@ function textCore(p5, fn) { yOff += this.states.textFont.font?._verticalAlign(textSize) || 0; // Does this function exist? dataArr.forEach(ele => ele.y += yOff); return dataArr; - } + }; } } diff --git a/src/type/unicodeRanges.js b/src/type/unicodeRanges.js index 848c277554..a8ab9acf27 100644 --- a/src/type/unicodeRanges.js +++ b/src/type/unicodeRanges.js @@ -3,1319 +3,1319 @@ // names converted to lowercase ahead of time export const unicodeRanges = [ { - category: "control character", - hexrange: ["0000", "001f"], + category: 'control character', + hexrange: ['0000', '001f'] }, { - category: "basic latin", - hexrange: ["0000", "007f"], + category: 'basic latin', + hexrange: ['0000', '007f'] }, { - category: "latin-1 supplement", - hexrange: ["0080", "00ff"], + category: 'latin-1 supplement', + hexrange: ['0080', '00ff'] }, { - category: "latin extended-a", - hexrange: ["0100", "017f"], + category: 'latin extended-a', + hexrange: ['0100', '017f'] }, { - category: "latin extended-b", - hexrange: ["0180", "024f"], + category: 'latin extended-b', + hexrange: ['0180', '024f'] }, { - category: "ipa extensions", - hexrange: ["0250", "02af"], + category: 'ipa extensions', + hexrange: ['0250', '02af'] }, { - category: "spacing modifier letters", - hexrange: ["02b0", "02ff"], + category: 'spacing modifier letters', + hexrange: ['02b0', '02ff'] }, { - category: "combining diacritical marks", - hexrange: ["0300", "036f"], + category: 'combining diacritical marks', + hexrange: ['0300', '036f'] }, { - category: "greek and coptic", - hexrange: ["0370", "03ff"], + category: 'greek and coptic', + hexrange: ['0370', '03ff'] }, { - category: "cyrillic", - hexrange: ["0400", "04ff"], + category: 'cyrillic', + hexrange: ['0400', '04ff'] }, { - category: "cyrillic supplement", - hexrange: ["0500", "052f"], + category: 'cyrillic supplement', + hexrange: ['0500', '052f'] }, { - category: "armenian", - hexrange: ["0530", "058f"], + category: 'armenian', + hexrange: ['0530', '058f'] }, { - category: "hebrew", - hexrange: ["0590", "05ff"], + category: 'hebrew', + hexrange: ['0590', '05ff'] }, { - category: "arabic", - hexrange: ["0600", "06ff"], + category: 'arabic', + hexrange: ['0600', '06ff'] }, { - category: "syriac", - hexrange: ["0700", "074f"], + category: 'syriac', + hexrange: ['0700', '074f'] }, { - category: "arabic supplement", - hexrange: ["0750", "077f"], + category: 'arabic supplement', + hexrange: ['0750', '077f'] }, { - category: "thaana", - hexrange: ["0780", "07bf"], + category: 'thaana', + hexrange: ['0780', '07bf'] }, { - category: "nko", - hexrange: ["07c0", "07ff"], + category: 'nko', + hexrange: ['07c0', '07ff'] }, { - category: "samaritan", - hexrange: ["0800", "083f"], + category: 'samaritan', + hexrange: ['0800', '083f'] }, { - category: "mandaic", - hexrange: ["0840", "085f"], + category: 'mandaic', + hexrange: ['0840', '085f'] }, { - category: "syriac supplement", - hexrange: ["0860", "086f"], + category: 'syriac supplement', + hexrange: ['0860', '086f'] }, { - category: "arabic extended-b", - hexrange: ["0870", "089f"], + category: 'arabic extended-b', + hexrange: ['0870', '089f'] }, { - category: "arabic extended-a", - hexrange: ["08a0", "08ff"], + category: 'arabic extended-a', + hexrange: ['08a0', '08ff'] }, { - category: "devanagari", - hexrange: ["0900", "097f"], + category: 'devanagari', + hexrange: ['0900', '097f'] }, { - category: "bengali", - hexrange: ["0980", "09ff"], + category: 'bengali', + hexrange: ['0980', '09ff'] }, { - category: "gurmukhi", - hexrange: ["0a00", "0a7f"], + category: 'gurmukhi', + hexrange: ['0a00', '0a7f'] }, { - category: "gujarati", - hexrange: ["0a80", "0aff"], + category: 'gujarati', + hexrange: ['0a80', '0aff'] }, { - category: "oriya", - hexrange: ["0b00", "0b7f"], + category: 'oriya', + hexrange: ['0b00', '0b7f'] }, { - category: "tamil", - hexrange: ["0b80", "0bff"], + category: 'tamil', + hexrange: ['0b80', '0bff'] }, { - category: "telugu", - hexrange: ["0c00", "0c7f"], + category: 'telugu', + hexrange: ['0c00', '0c7f'] }, { - category: "kannada", - hexrange: ["0c80", "0cff"], + category: 'kannada', + hexrange: ['0c80', '0cff'] }, { - category: "malayalam", - hexrange: ["0d00", "0d7f"], + category: 'malayalam', + hexrange: ['0d00', '0d7f'] }, { - category: "sinhala", - hexrange: ["0d80", "0dff"], + category: 'sinhala', + hexrange: ['0d80', '0dff'] }, { - category: "thai", - hexrange: ["0e00", "0e7f"], + category: 'thai', + hexrange: ['0e00', '0e7f'] }, { - category: "lao", - hexrange: ["0e80", "0eff"], + category: 'lao', + hexrange: ['0e80', '0eff'] }, { - category: "tibetan", - hexrange: ["0f00", "0fff"], + category: 'tibetan', + hexrange: ['0f00', '0fff'] }, { - category: "myanmar", - hexrange: ["1000", "109f"], + category: 'myanmar', + hexrange: ['1000', '109f'] }, { - category: "georgian", - hexrange: ["10a0", "10ff"], + category: 'georgian', + hexrange: ['10a0', '10ff'] }, { - category: "hangul jamo", - hexrange: ["1100", "11ff"], + category: 'hangul jamo', + hexrange: ['1100', '11ff'] }, { - category: "ethiopic", - hexrange: ["1200", "137f"], + category: 'ethiopic', + hexrange: ['1200', '137f'] }, { - category: "ethiopic supplement", - hexrange: ["1380", "139f"], + category: 'ethiopic supplement', + hexrange: ['1380', '139f'] }, { - category: "cherokee", - hexrange: ["13a0", "13ff"], + category: 'cherokee', + hexrange: ['13a0', '13ff'] }, { - category: "unified canadian aboriginal syllabics", - hexrange: ["1400", "167f"], + category: 'unified canadian aboriginal syllabics', + hexrange: ['1400', '167f'] }, { - category: "ogham", - hexrange: ["1680", "169f"], + category: 'ogham', + hexrange: ['1680', '169f'] }, { - category: "runic", - hexrange: ["16a0", "16ff"], + category: 'runic', + hexrange: ['16a0', '16ff'] }, { - category: "tagalog", - hexrange: ["1700", "171f"], + category: 'tagalog', + hexrange: ['1700', '171f'] }, { - category: "hanunoo", - hexrange: ["1720", "173f"], + category: 'hanunoo', + hexrange: ['1720', '173f'] }, { - category: "buhid", - hexrange: ["1740", "175f"], + category: 'buhid', + hexrange: ['1740', '175f'] }, { - category: "tagbanwa", - hexrange: ["1760", "177f"], + category: 'tagbanwa', + hexrange: ['1760', '177f'] }, { - category: "khmer", - hexrange: ["1780", "17ff"], + category: 'khmer', + hexrange: ['1780', '17ff'] }, { - category: "mongolian", - hexrange: ["1800", "18af"], + category: 'mongolian', + hexrange: ['1800', '18af'] }, { - category: "unified canadian aboriginal syllabics extended", - hexrange: ["18b0", "18ff"], + category: 'unified canadian aboriginal syllabics extended', + hexrange: ['18b0', '18ff'] }, { - category: "limbu", - hexrange: ["1900", "194f"], + category: 'limbu', + hexrange: ['1900', '194f'] }, { - category: "tai le", - hexrange: ["1950", "197f"], + category: 'tai le', + hexrange: ['1950', '197f'] }, { - category: "new tai lue", - hexrange: ["1980", "19df"], + category: 'new tai lue', + hexrange: ['1980', '19df'] }, { - category: "khmer symbols", - hexrange: ["19e0", "19ff"], + category: 'khmer symbols', + hexrange: ['19e0', '19ff'] }, { - category: "buginese", - hexrange: ["1a00", "1a1f"], + category: 'buginese', + hexrange: ['1a00', '1a1f'] }, { - category: "tai tham", - hexrange: ["1a20", "1aaf"], + category: 'tai tham', + hexrange: ['1a20', '1aaf'] }, { - category: "combining diacritical marks extended", - hexrange: ["1ab0", "1aff"], + category: 'combining diacritical marks extended', + hexrange: ['1ab0', '1aff'] }, { - category: "balinese", - hexrange: ["1b00", "1b7f"], + category: 'balinese', + hexrange: ['1b00', '1b7f'] }, { - category: "sundanese", - hexrange: ["1b80", "1bbf"], + category: 'sundanese', + hexrange: ['1b80', '1bbf'] }, { - category: "batak", - hexrange: ["1bc0", "1bff"], + category: 'batak', + hexrange: ['1bc0', '1bff'] }, { - category: "lepcha", - hexrange: ["1c00", "1c4f"], + category: 'lepcha', + hexrange: ['1c00', '1c4f'] }, { - category: "ol chiki", - hexrange: ["1c50", "1c7f"], + category: 'ol chiki', + hexrange: ['1c50', '1c7f'] }, { - category: "cyrillic extended-c", - hexrange: ["1c80", "1c8f"], + category: 'cyrillic extended-c', + hexrange: ['1c80', '1c8f'] }, { - category: "georgian extended", - hexrange: ["1c90", "1cbf"], + category: 'georgian extended', + hexrange: ['1c90', '1cbf'] }, { - category: "sundanese supplement", - hexrange: ["1cc0", "1ccf"], + category: 'sundanese supplement', + hexrange: ['1cc0', '1ccf'] }, { - category: "vedic extensions", - hexrange: ["1cd0", "1cff"], + category: 'vedic extensions', + hexrange: ['1cd0', '1cff'] }, { - category: "phonetic extensions", - hexrange: ["1d00", "1d7f"], + category: 'phonetic extensions', + hexrange: ['1d00', '1d7f'] }, { - category: "phonetic extensions supplement", - hexrange: ["1d80", "1dbf"], + category: 'phonetic extensions supplement', + hexrange: ['1d80', '1dbf'] }, { - category: "combining diacritical marks supplement", - hexrange: ["1dc0", "1dff"], + category: 'combining diacritical marks supplement', + hexrange: ['1dc0', '1dff'] }, { - category: "latin extended additional", - hexrange: ["1e00", "1eff"], + category: 'latin extended additional', + hexrange: ['1e00', '1eff'] }, { - category: "greek extended", - hexrange: ["1f00", "1fff"], + category: 'greek extended', + hexrange: ['1f00', '1fff'] }, { - category: "general punctuation", - hexrange: ["2000", "206f"], + category: 'general punctuation', + hexrange: ['2000', '206f'] }, { - category: "superscripts and subscripts", - hexrange: ["2070", "209f"], + category: 'superscripts and subscripts', + hexrange: ['2070', '209f'] }, { - category: "currency symbols", - hexrange: ["20a0", "20cf"], + category: 'currency symbols', + hexrange: ['20a0', '20cf'] }, { - category: "combining diacritical marks for symbols", - hexrange: ["20d0", "20ff"], + category: 'combining diacritical marks for symbols', + hexrange: ['20d0', '20ff'] }, { - category: "letterlike symbols", - hexrange: ["2100", "214f"], + category: 'letterlike symbols', + hexrange: ['2100', '214f'] }, { - category: "number forms", - hexrange: ["2150", "218f"], + category: 'number forms', + hexrange: ['2150', '218f'] }, { - category: "arrows", - hexrange: ["2190", "21ff"], + category: 'arrows', + hexrange: ['2190', '21ff'] }, { - category: "mathematical operators", - hexrange: ["2200", "22ff"], + category: 'mathematical operators', + hexrange: ['2200', '22ff'] }, { - category: "miscellaneous technical", - hexrange: ["2300", "23ff"], + category: 'miscellaneous technical', + hexrange: ['2300', '23ff'] }, { - category: "control pictures", - hexrange: ["2400", "243f"], + category: 'control pictures', + hexrange: ['2400', '243f'] }, { - category: "optical character recognition", - hexrange: ["2440", "245f"], + category: 'optical character recognition', + hexrange: ['2440', '245f'] }, { - category: "enclosed alphanumerics", - hexrange: ["2460", "24ff"], + category: 'enclosed alphanumerics', + hexrange: ['2460', '24ff'] }, { - category: "box drawing", - hexrange: ["2500", "257f"], + category: 'box drawing', + hexrange: ['2500', '257f'] }, { - category: "block elements", - hexrange: ["2580", "259f"], + category: 'block elements', + hexrange: ['2580', '259f'] }, { - category: "geometric shapes", - hexrange: ["25a0", "25ff"], + category: 'geometric shapes', + hexrange: ['25a0', '25ff'] }, { - category: "miscellaneous symbols", - hexrange: ["2600", "26ff"], + category: 'miscellaneous symbols', + hexrange: ['2600', '26ff'] }, { - category: "dingbats", - hexrange: ["2700", "27bf"], + category: 'dingbats', + hexrange: ['2700', '27bf'] }, { - category: "miscellaneous mathematical symbols-a", - hexrange: ["27c0", "27ef"], + category: 'miscellaneous mathematical symbols-a', + hexrange: ['27c0', '27ef'] }, { - category: "supplemental arrows-a", - hexrange: ["27f0", "27ff"], + category: 'supplemental arrows-a', + hexrange: ['27f0', '27ff'] }, { - category: "braille patterns", - hexrange: ["2800", "28ff"], + category: 'braille patterns', + hexrange: ['2800', '28ff'] }, { - category: "supplemental arrows-b", - hexrange: ["2900", "297f"], + category: 'supplemental arrows-b', + hexrange: ['2900', '297f'] }, { - category: "miscellaneous mathematical symbols-b", - hexrange: ["2980", "29ff"], + category: 'miscellaneous mathematical symbols-b', + hexrange: ['2980', '29ff'] }, { - category: "supplemental mathematical operators", - hexrange: ["2a00", "2aff"], + category: 'supplemental mathematical operators', + hexrange: ['2a00', '2aff'] }, { - category: "miscellaneous symbols and arrows", - hexrange: ["2b00", "2bff"], + category: 'miscellaneous symbols and arrows', + hexrange: ['2b00', '2bff'] }, { - category: "glagolitic", - hexrange: ["2c00", "2c5f"], + category: 'glagolitic', + hexrange: ['2c00', '2c5f'] }, { - category: "latin extended-c", - hexrange: ["2c60", "2c7f"], + category: 'latin extended-c', + hexrange: ['2c60', '2c7f'] }, { - category: "coptic", - hexrange: ["2c80", "2cff"], + category: 'coptic', + hexrange: ['2c80', '2cff'] }, { - category: "georgian supplement", - hexrange: ["2d00", "2d2f"], + category: 'georgian supplement', + hexrange: ['2d00', '2d2f'] }, { - category: "tifinagh", - hexrange: ["2d30", "2d7f"], + category: 'tifinagh', + hexrange: ['2d30', '2d7f'] }, { - category: "ethiopic extended", - hexrange: ["2d80", "2ddf"], + category: 'ethiopic extended', + hexrange: ['2d80', '2ddf'] }, { - category: "cyrillic extended-a", - hexrange: ["2de0", "2dff"], + category: 'cyrillic extended-a', + hexrange: ['2de0', '2dff'] }, { - category: "supplemental punctuation", - hexrange: ["2e00", "2e7f"], + category: 'supplemental punctuation', + hexrange: ['2e00', '2e7f'] }, { - category: "cjk radicals supplement", - hexrange: ["2e80", "2eff"], + category: 'cjk radicals supplement', + hexrange: ['2e80', '2eff'] }, { - category: "kangxi radicals", - hexrange: ["2f00", "2fdf"], + category: 'kangxi radicals', + hexrange: ['2f00', '2fdf'] }, { - category: "ideographic description characters", - hexrange: ["2ff0", "2fff"], + category: 'ideographic description characters', + hexrange: ['2ff0', '2fff'] }, { - category: "cjk symbols and punctuation", - hexrange: ["3000", "303f"], + category: 'cjk symbols and punctuation', + hexrange: ['3000', '303f'] }, { - category: "hiragana", - hexrange: ["3040", "309f"], + category: 'hiragana', + hexrange: ['3040', '309f'] }, { - category: "katakana", - hexrange: ["30a0", "30ff"], + category: 'katakana', + hexrange: ['30a0', '30ff'] }, { - category: "bopomofo", - hexrange: ["3100", "312f"], + category: 'bopomofo', + hexrange: ['3100', '312f'] }, { - category: "hangul compatibility jamo", - hexrange: ["3130", "318f"], + category: 'hangul compatibility jamo', + hexrange: ['3130', '318f'] }, { - category: "kanbun", - hexrange: ["3190", "319f"], + category: 'kanbun', + hexrange: ['3190', '319f'] }, { - category: "bopomofo extended", - hexrange: ["31a0", "31bf"], + category: 'bopomofo extended', + hexrange: ['31a0', '31bf'] }, { - category: "cjk strokes", - hexrange: ["31c0", "31ef"], + category: 'cjk strokes', + hexrange: ['31c0', '31ef'] }, { - category: "katakana phonetic extensions", - hexrange: ["31f0", "31ff"], + category: 'katakana phonetic extensions', + hexrange: ['31f0', '31ff'] }, { - category: "enclosed cjk letters and months", - hexrange: ["3200", "32ff"], + category: 'enclosed cjk letters and months', + hexrange: ['3200', '32ff'] }, { - category: "cjk compatibility", - hexrange: ["3300", "33ff"], + category: 'cjk compatibility', + hexrange: ['3300', '33ff'] }, { - category: "cjk unified ideographs extension a", - hexrange: ["3400", "4dbf"], + category: 'cjk unified ideographs extension a', + hexrange: ['3400', '4dbf'] }, { - category: "yijing hexagram symbols", - hexrange: ["4dc0", "4dff"], + category: 'yijing hexagram symbols', + hexrange: ['4dc0', '4dff'] }, { - category: "cjk unified ideographs", - hexrange: ["4e00", "9fff"], + category: 'cjk unified ideographs', + hexrange: ['4e00', '9fff'] }, { - category: "yi syllables", - hexrange: ["a000", "a48f"], + category: 'yi syllables', + hexrange: ['a000', 'a48f'] }, { - category: "yi radicals", - hexrange: ["a490", "a4cf"], + category: 'yi radicals', + hexrange: ['a490', 'a4cf'] }, { - category: "lisu", - hexrange: ["a4d0", "a4ff"], + category: 'lisu', + hexrange: ['a4d0', 'a4ff'] }, { - category: "vai", - hexrange: ["a500", "a63f"], + category: 'vai', + hexrange: ['a500', 'a63f'] }, { - category: "cyrillic extended-b", - hexrange: ["a640", "a69f"], + category: 'cyrillic extended-b', + hexrange: ['a640', 'a69f'] }, { - category: "bamum", - hexrange: ["a6a0", "a6ff"], + category: 'bamum', + hexrange: ['a6a0', 'a6ff'] }, { - category: "modifier tone letters", - hexrange: ["a700", "a71f"], + category: 'modifier tone letters', + hexrange: ['a700', 'a71f'] }, { - category: "latin extended-d", - hexrange: ["a720", "a7ff"], + category: 'latin extended-d', + hexrange: ['a720', 'a7ff'] }, { - category: "syloti nagri", - hexrange: ["a800", "a82f"], + category: 'syloti nagri', + hexrange: ['a800', 'a82f'] }, { - category: "common indic number forms", - hexrange: ["a830", "a83f"], + category: 'common indic number forms', + hexrange: ['a830', 'a83f'] }, { - category: "phags-pa", - hexrange: ["a840", "a87f"], + category: 'phags-pa', + hexrange: ['a840', 'a87f'] }, { - category: "saurashtra", - hexrange: ["a880", "a8df"], + category: 'saurashtra', + hexrange: ['a880', 'a8df'] }, { - category: "devanagari extended", - hexrange: ["a8e0", "a8ff"], + category: 'devanagari extended', + hexrange: ['a8e0', 'a8ff'] }, { - category: "kayah li", - hexrange: ["a900", "a92f"], + category: 'kayah li', + hexrange: ['a900', 'a92f'] }, { - category: "rejang", - hexrange: ["a930", "a95f"], + category: 'rejang', + hexrange: ['a930', 'a95f'] }, { - category: "hangul jamo extended-a", - hexrange: ["a960", "a97f"], + category: 'hangul jamo extended-a', + hexrange: ['a960', 'a97f'] }, { - category: "javanese", - hexrange: ["a980", "a9df"], + category: 'javanese', + hexrange: ['a980', 'a9df'] }, { - category: "myanmar extended-b", - hexrange: ["a9e0", "a9ff"], + category: 'myanmar extended-b', + hexrange: ['a9e0', 'a9ff'] }, { - category: "cham", - hexrange: ["aa00", "aa5f"], + category: 'cham', + hexrange: ['aa00', 'aa5f'] }, { - category: "myanmar extended-a", - hexrange: ["aa60", "aa7f"], + category: 'myanmar extended-a', + hexrange: ['aa60', 'aa7f'] }, { - category: "tai viet", - hexrange: ["aa80", "aadf"], + category: 'tai viet', + hexrange: ['aa80', 'aadf'] }, { - category: "meetei mayek extensions", - hexrange: ["aae0", "aaff"], + category: 'meetei mayek extensions', + hexrange: ['aae0', 'aaff'] }, { - category: "ethiopic extended-a", - hexrange: ["ab00", "ab2f"], + category: 'ethiopic extended-a', + hexrange: ['ab00', 'ab2f'] }, { - category: "latin extended-e", - hexrange: ["ab30", "ab6f"], + category: 'latin extended-e', + hexrange: ['ab30', 'ab6f'] }, { - category: "cherokee supplement", - hexrange: ["ab70", "abbf"], + category: 'cherokee supplement', + hexrange: ['ab70', 'abbf'] }, { - category: "meetei mayek", - hexrange: ["abc0", "abff"], + category: 'meetei mayek', + hexrange: ['abc0', 'abff'] }, { - category: "hangul syllables", - hexrange: ["ac00", "d7af"], + category: 'hangul syllables', + hexrange: ['ac00', 'd7af'] }, { - category: "hangul jamo extended-b", - hexrange: ["d7b0", "d7ff"], + category: 'hangul jamo extended-b', + hexrange: ['d7b0', 'd7ff'] }, { - category: "high surrogates", - hexrange: ["d800", "db7f"], + category: 'high surrogates', + hexrange: ['d800', 'db7f'] }, { - category: "high private use surrogates", - hexrange: ["db80", "dbff"], + category: 'high private use surrogates', + hexrange: ['db80', 'dbff'] }, { - category: "low surrogates", - hexrange: ["dc00", "dfff"], + category: 'low surrogates', + hexrange: ['dc00', 'dfff'] }, { - category: "private use area", - hexrange: ["e000", "f8ff"], + category: 'private use area', + hexrange: ['e000', 'f8ff'] }, { - category: "cjk compatibility ideographs", - hexrange: ["f900", "faff"], + category: 'cjk compatibility ideographs', + hexrange: ['f900', 'faff'] }, { - category: "alphabetic presentation forms", - hexrange: ["fb00", "fb4f"], + category: 'alphabetic presentation forms', + hexrange: ['fb00', 'fb4f'] }, { - category: "arabic presentation forms-a", - hexrange: ["fb50", "fdff"], + category: 'arabic presentation forms-a', + hexrange: ['fb50', 'fdff'] }, { - category: "variation selectors", - hexrange: ["fe00", "fe0f"], + category: 'variation selectors', + hexrange: ['fe00', 'fe0f'] }, { - category: "vertical forms", - hexrange: ["fe10", "fe1f"], + category: 'vertical forms', + hexrange: ['fe10', 'fe1f'] }, { - category: "combining half marks", - hexrange: ["fe20", "fe2f"], + category: 'combining half marks', + hexrange: ['fe20', 'fe2f'] }, { - category: "cjk compatibility forms", - hexrange: ["fe30", "fe4f"], + category: 'cjk compatibility forms', + hexrange: ['fe30', 'fe4f'] }, { - category: "small form variants", - hexrange: ["fe50", "fe6f"], + category: 'small form variants', + hexrange: ['fe50', 'fe6f'] }, { - category: "arabic presentation forms-b", - hexrange: ["fe70", "feff"], + category: 'arabic presentation forms-b', + hexrange: ['fe70', 'feff'] }, { - category: "halfwidth and fullwidth forms", - hexrange: ["ff00", "ffef"], + category: 'halfwidth and fullwidth forms', + hexrange: ['ff00', 'ffef'] }, { - category: "specials", - hexrange: ["fff0", "ffff"], + category: 'specials', + hexrange: ['fff0', 'ffff'] }, { - category: "linear b syllabary", - hexrange: ["10000", "1007f"], + category: 'linear b syllabary', + hexrange: ['10000', '1007f'] }, { - category: "linear b ideograms", - hexrange: ["10080", "100ff"], + category: 'linear b ideograms', + hexrange: ['10080', '100ff'] }, { - category: "aegean numbers", - hexrange: ["10100", "1013f"], + category: 'aegean numbers', + hexrange: ['10100', '1013f'] }, { - category: "ancient greek numbers", - hexrange: ["10140", "1018f"], + category: 'ancient greek numbers', + hexrange: ['10140', '1018f'] }, { - category: "ancient symbols", - hexrange: ["10190", "101cf"], + category: 'ancient symbols', + hexrange: ['10190', '101cf'] }, { - category: "phaistos disc", - hexrange: ["101d0", "101ff"], + category: 'phaistos disc', + hexrange: ['101d0', '101ff'] }, { - category: "lycian", - hexrange: ["10280", "1029f"], + category: 'lycian', + hexrange: ['10280', '1029f'] }, { - category: "carian", - hexrange: ["102a0", "102df"], + category: 'carian', + hexrange: ['102a0', '102df'] }, { - category: "coptic epact numbers", - hexrange: ["102e0", "102ff"], + category: 'coptic epact numbers', + hexrange: ['102e0', '102ff'] }, { - category: "old italic", - hexrange: ["10300", "1032f"], + category: 'old italic', + hexrange: ['10300', '1032f'] }, { - category: "gothic", - hexrange: ["10330", "1034f"], + category: 'gothic', + hexrange: ['10330', '1034f'] }, { - category: "old permic", - hexrange: ["10350", "1037f"], + category: 'old permic', + hexrange: ['10350', '1037f'] }, { - category: "ugaritic", - hexrange: ["10380", "1039f"], + category: 'ugaritic', + hexrange: ['10380', '1039f'] }, { - category: "old persian", - hexrange: ["103a0", "103df"], + category: 'old persian', + hexrange: ['103a0', '103df'] }, { - category: "deseret", - hexrange: ["10400", "1044f"], + category: 'deseret', + hexrange: ['10400', '1044f'] }, { - category: "shavian", - hexrange: ["10450", "1047f"], + category: 'shavian', + hexrange: ['10450', '1047f'] }, { - category: "osmanya", - hexrange: ["10480", "104af"], + category: 'osmanya', + hexrange: ['10480', '104af'] }, { - category: "osage", - hexrange: ["104b0", "104ff"], + category: 'osage', + hexrange: ['104b0', '104ff'] }, { - category: "elbasan", - hexrange: ["10500", "1052f"], + category: 'elbasan', + hexrange: ['10500', '1052f'] }, { - category: "caucasian albanian", - hexrange: ["10530", "1056f"], + category: 'caucasian albanian', + hexrange: ['10530', '1056f'] }, { - category: "vithkuqi", - hexrange: ["10570", "105bf"], + category: 'vithkuqi', + hexrange: ['10570', '105bf'] }, { - category: "linear a", - hexrange: ["10600", "1077f"], + category: 'linear a', + hexrange: ['10600', '1077f'] }, { - category: "latin extended-f", - hexrange: ["10780", "107bf"], + category: 'latin extended-f', + hexrange: ['10780', '107bf'] }, { - category: "cypriot syllabary", - hexrange: ["10800", "1083f"], + category: 'cypriot syllabary', + hexrange: ['10800', '1083f'] }, { - category: "imperial aramaic", - hexrange: ["10840", "1085f"], + category: 'imperial aramaic', + hexrange: ['10840', '1085f'] }, { - category: "palmyrene", - hexrange: ["10860", "1087f"], + category: 'palmyrene', + hexrange: ['10860', '1087f'] }, { - category: "nabataean", - hexrange: ["10880", "108af"], + category: 'nabataean', + hexrange: ['10880', '108af'] }, { - category: "hatran", - hexrange: ["108e0", "108ff"], + category: 'hatran', + hexrange: ['108e0', '108ff'] }, { - category: "phoenician", - hexrange: ["10900", "1091f"], + category: 'phoenician', + hexrange: ['10900', '1091f'] }, { - category: "lydian", - hexrange: ["10920", "1093f"], + category: 'lydian', + hexrange: ['10920', '1093f'] }, { - category: "meroitic hieroglyphs", - hexrange: ["10980", "1099f"], + category: 'meroitic hieroglyphs', + hexrange: ['10980', '1099f'] }, { - category: "meroitic cursive", - hexrange: ["109a0", "109ff"], + category: 'meroitic cursive', + hexrange: ['109a0', '109ff'] }, { - category: "kharoshthi", - hexrange: ["10a00", "10a5f"], + category: 'kharoshthi', + hexrange: ['10a00', '10a5f'] }, { - category: "old south arabian", - hexrange: ["10a60", "10a7f"], + category: 'old south arabian', + hexrange: ['10a60', '10a7f'] }, { - category: "old north arabian", - hexrange: ["10a80", "10a9f"], + category: 'old north arabian', + hexrange: ['10a80', '10a9f'] }, { - category: "manichaean", - hexrange: ["10ac0", "10aff"], + category: 'manichaean', + hexrange: ['10ac0', '10aff'] }, { - category: "avestan", - hexrange: ["10b00", "10b3f"], + category: 'avestan', + hexrange: ['10b00', '10b3f'] }, { - category: "inscriptional parthian", - hexrange: ["10b40", "10b5f"], + category: 'inscriptional parthian', + hexrange: ['10b40', '10b5f'] }, { - category: "inscriptional pahlavi", - hexrange: ["10b60", "10b7f"], + category: 'inscriptional pahlavi', + hexrange: ['10b60', '10b7f'] }, { - category: "psalter pahlavi", - hexrange: ["10b80", "10baf"], + category: 'psalter pahlavi', + hexrange: ['10b80', '10baf'] }, { - category: "old turkic", - hexrange: ["10c00", "10c4f"], + category: 'old turkic', + hexrange: ['10c00', '10c4f'] }, { - category: "old hungarian", - hexrange: ["10c80", "10cff"], + category: 'old hungarian', + hexrange: ['10c80', '10cff'] }, { - category: "hanifi rohingya", - hexrange: ["10d00", "10d3f"], + category: 'hanifi rohingya', + hexrange: ['10d00', '10d3f'] }, { - category: "rumi numeral symbols", - hexrange: ["10e60", "10e7f"], + category: 'rumi numeral symbols', + hexrange: ['10e60', '10e7f'] }, { - category: "yezidi", - hexrange: ["10e80", "10ebf"], + category: 'yezidi', + hexrange: ['10e80', '10ebf'] }, { - category: "arabic extended-c", - hexrange: ["10ec0", "10eff"], + category: 'arabic extended-c', + hexrange: ['10ec0', '10eff'] }, { - category: "old sogdian", - hexrange: ["10f00", "10f2f"], + category: 'old sogdian', + hexrange: ['10f00', '10f2f'] }, { - category: "sogdian", - hexrange: ["10f30", "10f6f"], + category: 'sogdian', + hexrange: ['10f30', '10f6f'] }, { - category: "old uyghur", - hexrange: ["10f70", "10faf"], + category: 'old uyghur', + hexrange: ['10f70', '10faf'] }, { - category: "chorasmian", - hexrange: ["10fb0", "10fdf"], + category: 'chorasmian', + hexrange: ['10fb0', '10fdf'] }, { - category: "elymaic", - hexrange: ["10fe0", "10fff"], + category: 'elymaic', + hexrange: ['10fe0', '10fff'] }, { - category: "brahmi", - hexrange: ["11000", "1107f"], + category: 'brahmi', + hexrange: ['11000', '1107f'] }, { - category: "kaithi", - hexrange: ["11080", "110cf"], + category: 'kaithi', + hexrange: ['11080', '110cf'] }, { - category: "sora sompeng", - hexrange: ["110d0", "110ff"], + category: 'sora sompeng', + hexrange: ['110d0', '110ff'] }, { - category: "chakma", - hexrange: ["11100", "1114f"], + category: 'chakma', + hexrange: ['11100', '1114f'] }, { - category: "mahajani", - hexrange: ["11150", "1117f"], + category: 'mahajani', + hexrange: ['11150', '1117f'] }, { - category: "sharada", - hexrange: ["11180", "111df"], + category: 'sharada', + hexrange: ['11180', '111df'] }, { - category: "sinhala archaic numbers", - hexrange: ["111e0", "111ff"], + category: 'sinhala archaic numbers', + hexrange: ['111e0', '111ff'] }, { - category: "khojki", - hexrange: ["11200", "1124f"], + category: 'khojki', + hexrange: ['11200', '1124f'] }, { - category: "multani", - hexrange: ["11280", "112af"], + category: 'multani', + hexrange: ['11280', '112af'] }, { - category: "khudawadi", - hexrange: ["112b0", "112ff"], + category: 'khudawadi', + hexrange: ['112b0', '112ff'] }, { - category: "grantha", - hexrange: ["11300", "1137f"], + category: 'grantha', + hexrange: ['11300', '1137f'] }, { - category: "newa", - hexrange: ["11400", "1147f"], + category: 'newa', + hexrange: ['11400', '1147f'] }, { - category: "tirhuta", - hexrange: ["11480", "114df"], + category: 'tirhuta', + hexrange: ['11480', '114df'] }, { - category: "siddham", - hexrange: ["11580", "115ff"], + category: 'siddham', + hexrange: ['11580', '115ff'] }, { - category: "modi", - hexrange: ["11600", "1165f"], + category: 'modi', + hexrange: ['11600', '1165f'] }, { - category: "mongolian supplement", - hexrange: ["11660", "1167f"], + category: 'mongolian supplement', + hexrange: ['11660', '1167f'] }, { - category: "takri", - hexrange: ["11680", "116cf"], + category: 'takri', + hexrange: ['11680', '116cf'] }, { - category: "ahom", - hexrange: ["11700", "1174f"], + category: 'ahom', + hexrange: ['11700', '1174f'] }, { - category: "dogra", - hexrange: ["11800", "1184f"], + category: 'dogra', + hexrange: ['11800', '1184f'] }, { - category: "warang citi", - hexrange: ["118a0", "118ff"], + category: 'warang citi', + hexrange: ['118a0', '118ff'] }, { - category: "dives akuru", - hexrange: ["11900", "1195f"], + category: 'dives akuru', + hexrange: ['11900', '1195f'] }, { - category: "nandinagari", - hexrange: ["119a0", "119ff"], + category: 'nandinagari', + hexrange: ['119a0', '119ff'] }, { - category: "zanabazar square", - hexrange: ["11a00", "11a4f"], + category: 'zanabazar square', + hexrange: ['11a00', '11a4f'] }, { - category: "soyombo", - hexrange: ["11a50", "11aaf"], + category: 'soyombo', + hexrange: ['11a50', '11aaf'] }, { - category: "unified canadian aboriginal syllabics extended-a", - hexrange: ["11ab0", "11abf"], + category: 'unified canadian aboriginal syllabics extended-a', + hexrange: ['11ab0', '11abf'] }, { - category: "pau cin hau", - hexrange: ["11ac0", "11aff"], + category: 'pau cin hau', + hexrange: ['11ac0', '11aff'] }, { - category: "devanagari extended-a", - hexrange: ["11b00", "11b5f"], + category: 'devanagari extended-a', + hexrange: ['11b00', '11b5f'] }, { - category: "bhaiksuki", - hexrange: ["11c00", "11c6f"], + category: 'bhaiksuki', + hexrange: ['11c00', '11c6f'] }, { - category: "marchen", - hexrange: ["11c70", "11cbf"], + category: 'marchen', + hexrange: ['11c70', '11cbf'] }, { - category: "masaram gondi", - hexrange: ["11d00", "11d5f"], + category: 'masaram gondi', + hexrange: ['11d00', '11d5f'] }, { - category: "gunjala gondi", - hexrange: ["11d60", "11daf"], + category: 'gunjala gondi', + hexrange: ['11d60', '11daf'] }, { - category: "makasar", - hexrange: ["11ee0", "11eff"], + category: 'makasar', + hexrange: ['11ee0', '11eff'] }, { - category: "kawi", - hexrange: ["11f00", "11f5f"], + category: 'kawi', + hexrange: ['11f00', '11f5f'] }, { - category: "lisu supplement", - hexrange: ["11fb0", "11fbf"], + category: 'lisu supplement', + hexrange: ['11fb0', '11fbf'] }, { - category: "tamil supplement", - hexrange: ["11fc0", "11fff"], + category: 'tamil supplement', + hexrange: ['11fc0', '11fff'] }, { - category: "cuneiform", - hexrange: ["12000", "123ff"], + category: 'cuneiform', + hexrange: ['12000', '123ff'] }, { - category: "cuneiform numbers and punctuation", - hexrange: ["12400", "1247f"], + category: 'cuneiform numbers and punctuation', + hexrange: ['12400', '1247f'] }, { - category: "early dynastic cuneiform", - hexrange: ["12480", "1254f"], + category: 'early dynastic cuneiform', + hexrange: ['12480', '1254f'] }, { - category: "cypro-minoan", - hexrange: ["12f90", "12fff"], + category: 'cypro-minoan', + hexrange: ['12f90', '12fff'] }, { - category: "egyptian hieroglyphs", - hexrange: ["13000", "1342f"], + category: 'egyptian hieroglyphs', + hexrange: ['13000', '1342f'] }, { - category: "egyptian hieroglyph format controls", - hexrange: ["13430", "1345f"], + category: 'egyptian hieroglyph format controls', + hexrange: ['13430', '1345f'] }, { - category: "anatolian hieroglyphs", - hexrange: ["14400", "1467f"], + category: 'anatolian hieroglyphs', + hexrange: ['14400', '1467f'] }, { - category: "bamum supplement", - hexrange: ["16800", "16a3f"], + category: 'bamum supplement', + hexrange: ['16800', '16a3f'] }, { - category: "mro", - hexrange: ["16a40", "16a6f"], + category: 'mro', + hexrange: ['16a40', '16a6f'] }, { - category: "tangsa", - hexrange: ["16a70", "16acf"], + category: 'tangsa', + hexrange: ['16a70', '16acf'] }, { - category: "bassa vah", - hexrange: ["16ad0", "16aff"], + category: 'bassa vah', + hexrange: ['16ad0', '16aff'] }, { - category: "pahawh hmong", - hexrange: ["16b00", "16b8f"], + category: 'pahawh hmong', + hexrange: ['16b00', '16b8f'] }, { - category: "medefaidrin", - hexrange: ["16e40", "16e9f"], + category: 'medefaidrin', + hexrange: ['16e40', '16e9f'] }, { - category: "miao", - hexrange: ["16f00", "16f9f"], + category: 'miao', + hexrange: ['16f00', '16f9f'] }, { - category: "ideographic symbols and punctuation", - hexrange: ["16fe0", "16fff"], + category: 'ideographic symbols and punctuation', + hexrange: ['16fe0', '16fff'] }, { - category: "tangut", - hexrange: ["17000", "187ff"], + category: 'tangut', + hexrange: ['17000', '187ff'] }, { - category: "tangut components", - hexrange: ["18800", "18aff"], + category: 'tangut components', + hexrange: ['18800', '18aff'] }, { - category: "khitan small script", - hexrange: ["18b00", "18cff"], + category: 'khitan small script', + hexrange: ['18b00', '18cff'] }, { - category: "tangut supplement", - hexrange: ["18d00", "18d7f"], + category: 'tangut supplement', + hexrange: ['18d00', '18d7f'] }, { - category: "kana extended-b", - hexrange: ["1aff0", "1afff"], + category: 'kana extended-b', + hexrange: ['1aff0', '1afff'] }, { - category: "kana supplement", - hexrange: ["1b000", "1b0ff"], + category: 'kana supplement', + hexrange: ['1b000', '1b0ff'] }, { - category: "kana extended-a", - hexrange: ["1b100", "1b12f"], + category: 'kana extended-a', + hexrange: ['1b100', '1b12f'] }, { - category: "small kana extension", - hexrange: ["1b130", "1b16f"], + category: 'small kana extension', + hexrange: ['1b130', '1b16f'] }, { - category: "nushu", - hexrange: ["1b170", "1b2ff"], + category: 'nushu', + hexrange: ['1b170', '1b2ff'] }, { - category: "duployan", - hexrange: ["1bc00", "1bc9f"], + category: 'duployan', + hexrange: ['1bc00', '1bc9f'] }, { - category: "shorthand format controls", - hexrange: ["1bca0", "1bcaf"], + category: 'shorthand format controls', + hexrange: ['1bca0', '1bcaf'] }, { - category: "znamenny musical notation", - hexrange: ["1cf00", "1cfcf"], + category: 'znamenny musical notation', + hexrange: ['1cf00', '1cfcf'] }, { - category: "byzantine musical symbols", - hexrange: ["1d000", "1d0ff"], + category: 'byzantine musical symbols', + hexrange: ['1d000', '1d0ff'] }, { - category: "musical symbols", - hexrange: ["1d100", "1d1ff"], + category: 'musical symbols', + hexrange: ['1d100', '1d1ff'] }, { - category: "ancient greek musical notation", - hexrange: ["1d200", "1d24f"], + category: 'ancient greek musical notation', + hexrange: ['1d200', '1d24f'] }, { - category: "kaktovik numerals", - hexrange: ["1d2c0", "1d2df"], + category: 'kaktovik numerals', + hexrange: ['1d2c0', '1d2df'] }, { - category: "mayan numerals", - hexrange: ["1d2e0", "1d2ff"], + category: 'mayan numerals', + hexrange: ['1d2e0', '1d2ff'] }, { - category: "tai xuan jing symbols", - hexrange: ["1d300", "1d35f"], + category: 'tai xuan jing symbols', + hexrange: ['1d300', '1d35f'] }, { - category: "counting rod numerals", - hexrange: ["1d360", "1d37f"], + category: 'counting rod numerals', + hexrange: ['1d360', '1d37f'] }, { - category: "mathematical alphanumeric symbols", - hexrange: ["1d400", "1d7ff"], + category: 'mathematical alphanumeric symbols', + hexrange: ['1d400', '1d7ff'] }, { - category: "sutton signwriting", - hexrange: ["1d800", "1daaf"], + category: 'sutton signwriting', + hexrange: ['1d800', '1daaf'] }, { - category: "latin extended-g", - hexrange: ["1df00", "1dfff"], + category: 'latin extended-g', + hexrange: ['1df00', '1dfff'] }, { - category: "glagolitic supplement", - hexrange: ["1e000", "1e02f"], + category: 'glagolitic supplement', + hexrange: ['1e000', '1e02f'] }, { - category: "cyrillic extended-d", - hexrange: ["1e030", "1e08f"], + category: 'cyrillic extended-d', + hexrange: ['1e030', '1e08f'] }, { - category: "nyiakeng puachue hmong", - hexrange: ["1e100", "1e14f"], + category: 'nyiakeng puachue hmong', + hexrange: ['1e100', '1e14f'] }, { - category: "toto", - hexrange: ["1e290", "1e2bf"], + category: 'toto', + hexrange: ['1e290', '1e2bf'] }, { - category: "wancho", - hexrange: ["1e2c0", "1e2ff"], + category: 'wancho', + hexrange: ['1e2c0', '1e2ff'] }, { - category: "nag mundari", - hexrange: ["1e4d0", "1e4ff"], + category: 'nag mundari', + hexrange: ['1e4d0', '1e4ff'] }, { - category: "ethiopic extended-b", - hexrange: ["1e7e0", "1e7ff"], + category: 'ethiopic extended-b', + hexrange: ['1e7e0', '1e7ff'] }, { - category: "mende kikakui", - hexrange: ["1e800", "1e8df"], + category: 'mende kikakui', + hexrange: ['1e800', '1e8df'] }, { - category: "adlam", - hexrange: ["1e900", "1e95f"], + category: 'adlam', + hexrange: ['1e900', '1e95f'] }, { - category: "indic siyaq numbers", - hexrange: ["1ec70", "1ecbf"], + category: 'indic siyaq numbers', + hexrange: ['1ec70', '1ecbf'] }, { - category: "ottoman siyaq numbers", - hexrange: ["1ed00", "1ed4f"], + category: 'ottoman siyaq numbers', + hexrange: ['1ed00', '1ed4f'] }, { - category: "arabic mathematical alphabetic symbols", - hexrange: ["1ee00", "1eeff"], + category: 'arabic mathematical alphabetic symbols', + hexrange: ['1ee00', '1eeff'] }, { - category: "mahjong tiles", - hexrange: ["1f000", "1f02f"], + category: 'mahjong tiles', + hexrange: ['1f000', '1f02f'] }, { - category: "domino tiles", - hexrange: ["1f030", "1f09f"], + category: 'domino tiles', + hexrange: ['1f030', '1f09f'] }, { - category: "playing cards", - hexrange: ["1f0a0", "1f0ff"], + category: 'playing cards', + hexrange: ['1f0a0', '1f0ff'] }, { - category: "enclosed alphanumeric supplement", - hexrange: ["1f100", "1f1ff"], + category: 'enclosed alphanumeric supplement', + hexrange: ['1f100', '1f1ff'] }, { - category: "enclosed ideographic supplement", - hexrange: ["1f200", "1f2ff"], + category: 'enclosed ideographic supplement', + hexrange: ['1f200', '1f2ff'] }, { - category: "miscellaneous symbols and pictographs", - hexrange: ["1f300", "1f5ff"], + category: 'miscellaneous symbols and pictographs', + hexrange: ['1f300', '1f5ff'] }, { - category: "emoticons (emoji)", - hexrange: ["1f600", "1f64f"], + category: 'emoticons (emoji)', + hexrange: ['1f600', '1f64f'] }, { - category: "ornamental dingbats", - hexrange: ["1f650", "1f67f"], + category: 'ornamental dingbats', + hexrange: ['1f650', '1f67f'] }, { - category: "transport and map symbols", - hexrange: ["1f680", "1f6ff"], + category: 'transport and map symbols', + hexrange: ['1f680', '1f6ff'] }, { - category: "alchemical symbols", - hexrange: ["1f700", "1f77f"], + category: 'alchemical symbols', + hexrange: ['1f700', '1f77f'] }, { - category: "geometric shapes extended", - hexrange: ["1f780", "1f7ff"], + category: 'geometric shapes extended', + hexrange: ['1f780', '1f7ff'] }, { - category: "supplemental arrows-c", - hexrange: ["1f800", "1f8ff"], + category: 'supplemental arrows-c', + hexrange: ['1f800', '1f8ff'] }, { - category: "supplemental symbols and pictographs", - hexrange: ["1f900", "1f9ff"], + category: 'supplemental symbols and pictographs', + hexrange: ['1f900', '1f9ff'] }, { - category: "chess symbols", - hexrange: ["1fa00", "1fa6f"], + category: 'chess symbols', + hexrange: ['1fa00', '1fa6f'] }, { - category: "symbols and pictographs extended-a", - hexrange: ["1fa70", "1faff"], + category: 'symbols and pictographs extended-a', + hexrange: ['1fa70', '1faff'] }, { - category: "symbols for legacy computing", - hexrange: ["1fb00", "1fbff"], + category: 'symbols for legacy computing', + hexrange: ['1fb00', '1fbff'] }, { - category: "cjk unified ideographs extension b", - hexrange: ["20000", "2a6df"], + category: 'cjk unified ideographs extension b', + hexrange: ['20000', '2a6df'] }, { - category: "cjk unified ideographs extension c", - hexrange: ["2a700", "2b73f"], + category: 'cjk unified ideographs extension c', + hexrange: ['2a700', '2b73f'] }, { - category: "cjk unified ideographs extension d", - hexrange: ["2b740", "2b81f"], + category: 'cjk unified ideographs extension d', + hexrange: ['2b740', '2b81f'] }, { - category: "cjk unified ideographs extension e", - hexrange: ["2b820", "2ceaf"], + category: 'cjk unified ideographs extension e', + hexrange: ['2b820', '2ceaf'] }, { - category: "cjk unified ideographs extension f", - hexrange: ["2ceb0", "2ebef"], + category: 'cjk unified ideographs extension f', + hexrange: ['2ceb0', '2ebef'] }, { - category: "cjk unified ideographs extension i", - hexrange: ["2ebf0", "2ee5f"], + category: 'cjk unified ideographs extension i', + hexrange: ['2ebf0', '2ee5f'] }, { - category: "cjk compatibility ideographs supplement", - hexrange: ["2f800", "2fa1f"], + category: 'cjk compatibility ideographs supplement', + hexrange: ['2f800', '2fa1f'] }, { - category: "cjk unified ideographs extension g", - hexrange: ["30000", "3134f"], + category: 'cjk unified ideographs extension g', + hexrange: ['30000', '3134f'] }, { - category: "cjk unified ideographs extension h", - hexrange: ["31350", "323af"], + category: 'cjk unified ideographs extension h', + hexrange: ['31350', '323af'] }, { - category: "tags", - hexrange: ["e0000", "e007f"], + category: 'tags', + hexrange: ['e0000', 'e007f'] }, { - category: "variation selectors supplement", - hexrange: ["e0100", "e01ef"], + category: 'variation selectors supplement', + hexrange: ['e0100', 'e01ef'] }, { - category: "supplementary private use area-a", - hexrange: ["f0000", "fffff"], + category: 'supplementary private use area-a', + hexrange: ['f0000', 'fffff'] }, { - category: "supplementary private use area-b", - hexrange: ["100000", "10ffff"], - }, + category: 'supplementary private use area-b', + hexrange: ['100000', '10ffff'] + } ]; diff --git a/src/webgl/3d_primitives.js b/src/webgl/3d_primitives.js index 3bd2c70baf..cc07f71f78 100644 --- a/src/webgl/3d_primitives.js +++ b/src/webgl/3d_primitives.js @@ -71,7 +71,7 @@ function primitives3D(p5, fn){ * function draw() { * background(128); * strokeMode(SIMPLE); // Simplifies stroke rendering for better performance. - * + * * // Draw sphere * push(); * strokeWeight(1); @@ -105,7 +105,7 @@ function primitives3D(p5, fn){ } else { throw Error('no such parameter'); } - } + }; /** * Creates a custom p5.Geometry object from * simpler 3D shapes. @@ -1060,7 +1060,12 @@ function primitives3D(p5, fn){ this._assert3d('cylinder'); // p5._validateParameters('cylinder', arguments); - this._renderer.cylinder(radius, height, detailX, detailY, bottomCap, topCap); + this._renderer.cylinder( + radius, + height, + detailX, detailY, + bottomCap, topCap + ); return this; }; @@ -1965,7 +1970,7 @@ function primitives3D(p5, fn){ const addUVs = (x, y) => [x, y, (x - x1)/width, (y - y1)/height]; if (tr !== 0) { this.vertex(...addUVs(x2 - tr, y1)); - this.bezierVertex(...addUVs(x2, y1)) + this.bezierVertex(...addUVs(x2, y1)); this.bezierVertex(...addUVs(x2, y1 + tr)); } else { this.vertex(...addUVs(x2, y1)); @@ -1973,7 +1978,7 @@ function primitives3D(p5, fn){ if (br !== 0) { this.vertex(...addUVs(x2, y2 - br)); this.bezierVertex(...addUVs(x2, y2)); - this.bezierVertex(...addUVs(x2 - br, y2)) + this.bezierVertex(...addUVs(x2 - br, y2)); } else { this.vertex(...addUVs(x2, y2)); } @@ -1999,9 +2004,16 @@ function primitives3D(p5, fn){ return this; }; - /* eslint-disable max-len */ - RendererGL.prototype.quad = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, detailX=2, detailY=2) { - /* eslint-enable max-len */ + + RendererGL.prototype.quad = function( + x1, y1, z1, + x2, y2, z2, + x3, y3, z3, + x4, y4, z4, + detailX=2, + detailY=2 + ) { + const gid = `quad|${x1}|${y1}|${z1}|${x2}|${y2}|${z2}|${x3}|${y3}|${z3}|${x4}|${y4}|${z4}|${detailX}|${detailY}`; @@ -2390,8 +2402,12 @@ function primitives3D(p5, fn){ this.geometryBufferCache.ensureCached(planeGeom); } - this._drawGeometryScaled(this.geometryBufferCache.getGeometryByID(gid), width, height, 1); - } + this._drawGeometryScaled( + this.geometryBufferCache.getGeometryByID(gid), + width, height, + 1 + ); + }; RendererGL.prototype.box = function( width = 50, @@ -2472,8 +2488,12 @@ function primitives3D(p5, fn){ boxGeom.gid = gid; this.geometryBufferCache.ensureCached(boxGeom); } - this._drawGeometryScaled(this.geometryBufferCache.getGeometryByID(gid), width, height, depth); - } + this._drawGeometryScaled( + this.geometryBufferCache.getGeometryByID(gid), + width, height, + depth + ); + }; RendererGL.prototype.sphere = function( radius = 50, @@ -2481,7 +2501,7 @@ function primitives3D(p5, fn){ detailY = 16 ) { this.ellipsoid(radius, radius, radius, detailX, detailY); - } + }; RendererGL.prototype.ellipsoid = function( radiusX = 50, @@ -2505,7 +2525,11 @@ function primitives3D(p5, fn){ const theta = 2 * Math.PI * u; const cosTheta = Math.cos(theta); const sinTheta = Math.sin(theta); - const p = new p5.Vector(cosPhi * sinTheta, sinPhi, cosPhi * cosTheta); + const p = new p5.Vector( + cosPhi * sinTheta, + sinPhi, + cosPhi * cosTheta + ); this.vertices.push(p); this.vertexNormals.push(p); this.uvs.push(u, v); @@ -2526,8 +2550,11 @@ function primitives3D(p5, fn){ this.geometryBufferCache.ensureCached(ellipsoidGeom); } - this._drawGeometryScaled(this.geometryBufferCache.getGeometryByID(gid), radiusX, radiusY, radiusZ); - } + this._drawGeometryScaled( + this.geometryBufferCache.getGeometryByID(gid), + radiusX, radiusY, radiusZ + ); + }; RendererGL.prototype.cylinder = function( radius = 50, @@ -2564,8 +2591,13 @@ function primitives3D(p5, fn){ this.geometryBufferCache.ensureCached(cylinderGeom); } - this._drawGeometryScaled(this.geometryBufferCache.getGeometryByID(gid), radius, height, radius); - } + this._drawGeometryScaled( + this.geometryBufferCache.getGeometryByID(gid), + radius, + height, + radius + ); + }; RendererGL.prototype.cone = function( radius = 50, @@ -2600,8 +2632,13 @@ function primitives3D(p5, fn){ this.geometryBufferCache.ensureCached(coneGeom); } - this._drawGeometryScaled(this.geometryBufferCache.getGeometryByID(gid), radius, height, radius); - } + this._drawGeometryScaled( + this.geometryBufferCache.getGeometryByID(gid), + radius, + height, + radius + ); + }; RendererGL.prototype.torus = function( radius = 50, @@ -2662,8 +2699,13 @@ function primitives3D(p5, fn){ torusGeom.gid = gid; this.geometryBufferCache.ensureCached(torusGeom); } - this._drawGeometryScaled(this.geometryBufferCache.getGeometryByID(gid), radius, radius, radius); - } + this._drawGeometryScaled( + this.geometryBufferCache.getGeometryByID(gid), + radius, + radius, + radius + ); + }; /** * Sets the number of segments used to draw spline curves in WebGL mode. @@ -2691,7 +2733,7 @@ function primitives3D(p5, fn){ * * // Set the curveDetail() to 0.5 * curveDetail(0.5); - * + * * // Do not show all the vertices * splineProperty('ends', EXCLUDE) * diff --git a/src/webgl/GeometryBufferCache.js b/src/webgl/GeometryBufferCache.js index 289a1daaff..337383fd55 100644 --- a/src/webgl/GeometryBufferCache.js +++ b/src/webgl/GeometryBufferCache.js @@ -60,7 +60,12 @@ export class GeometryBufferCache { // Uint16Array const hasVertexIndicesOverMaxUInt16 = vals.some(v => v > 65535); let type = hasVertexIndicesOverMaxUInt16 ? Uint32Array : Uint16Array; - this.renderer._bindBuffer(indexBuffer, gl.ELEMENT_ARRAY_BUFFER, vals, type); + this.renderer._bindBuffer( + indexBuffer, + gl.ELEMENT_ARRAY_BUFFER, + vals, + type + ); // If we're using a Uint32Array for our indexBuffer we will need to pass a // different enum value to WebGL draw triangles. This happens in diff --git a/src/webgl/GeometryBuilder.js b/src/webgl/GeometryBuilder.js index 47912e5c94..19331f3e28 100644 --- a/src/webgl/GeometryBuilder.js +++ b/src/webgl/GeometryBuilder.js @@ -13,7 +13,12 @@ class GeometryBuilder { renderer._pInst.push(); this.identityMatrix = new Matrix(4); renderer.states.setValue('uModelMatrix', new Matrix(4)); - this.geometry = new Geometry(undefined, undefined, undefined, this.renderer); + this.geometry = new Geometry( + undefined, + undefined, + undefined, + this.renderer + ); this.geometry.gid = `_p5_GeometryBuilder_${GeometryBuilder.nextGeometryId}`; GeometryBuilder.nextGeometryId++; this.hasTransform = false; @@ -26,7 +31,9 @@ class GeometryBuilder { transformVertices(vertices) { if (!this.hasTransform) return vertices; - return vertices.map(v => this.renderer.states.uModelMatrix.multiplyPoint(v)); + return vertices.map(v => + this.renderer.states.uModelMatrix.multiplyPoint(v) + ); } /** @@ -51,7 +58,9 @@ class GeometryBuilder { .every((v, i) => v === this.identityMatrix.mat4[i]); if (this.hasTransform) { - this.renderer.scratchMat3.inverseTranspose4x4(this.renderer.states.uModelMatrix); + this.renderer.scratchMat3.inverseTranspose4x4( + this.renderer.states.uModelMatrix + ); } let startIdx = this.geometry.vertices.length; @@ -63,13 +72,14 @@ class GeometryBuilder { const inputUserVertexProps = input.userVertexProperties; const builtUserVertexProps = this.geometry.userVertexProperties; - const numPreviousVertices = this.geometry.vertices.length - input.vertices.length; + const numPreviousVertices = + this.geometry.vertices.length - input.vertices.length; for (const propName in builtUserVertexProps){ if (propName in inputUserVertexProps){ continue; } - const prop = builtUserVertexProps[propName] + const prop = builtUserVertexProps[propName]; const size = prop.getDataSize(); const numMissingValues = size * input.vertices.length; const missingValues = Array(numMissingValues).fill(0); diff --git a/src/webgl/ShaderGenerator.js b/src/webgl/ShaderGenerator.js index 67a9b72676..c3397e3aa4 100644 --- a/src/webgl/ShaderGenerator.js +++ b/src/webgl/ShaderGenerator.js @@ -1,9 +1,9 @@ /** -* @module 3D -* @submodule ShaderGenerator -* @for p5 -* @requires core -*/ + * @module 3D + * @submodule ShaderGenerator + * @for p5 + * @requires core + */ import { parse } from 'acorn'; import { ancestor } from 'acorn-walk'; import escodegen from 'escodegen'; @@ -14,7 +14,7 @@ function shadergenerator(p5, fn) { let GLOBAL_SHADER; let BRANCH; - const oldModify = p5.Shader.prototype.modify + const oldModify = p5.Shader.prototype.modify; p5.Shader.prototype.modify = function(shaderModifier, scope = {}) { if (shaderModifier instanceof Function) { @@ -40,23 +40,28 @@ function shadergenerator(p5, fn) { '__p5', ...scopeKeys, transpiledSource - .slice( - transpiledSource.indexOf('{') + 1, - transpiledSource.lastIndexOf('}') - ).replaceAll(';', '') + .slice( + transpiledSource.indexOf('{') + 1, + transpiledSource.lastIndexOf('}') + ).replaceAll(';', '') ); - generatorFunction = () => internalGeneratorFunction(p5, ...scopeKeys.map(key => scope[key])); + generatorFunction = () => + internalGeneratorFunction(p5, ...scopeKeys.map(key => scope[key])); } else { generatorFunction = shaderModifier; } - const generator = new ShaderGenerator(generatorFunction, this, options.srcLocations); + const generator = new ShaderGenerator( + generatorFunction, + this, + options.srcLocations + ); const generatedModifyArgument = generator.generate(); return oldModify.call(this, generatedModifyArgument); } else { - return oldModify.call(this, shaderModifier) + return oldModify.call(this, shaderModifier); } - } + }; // AST Transpiler Callbacks and helper functions function replaceBinaryOperator(codeSource) { @@ -97,17 +102,17 @@ function shadergenerator(p5, fn) { const signNode = { type: 'Literal', - value: node.operator, - } + value: node.operator + }; - const standardReplacement = (node) => { - node.type = 'CallExpression' - node.callee = { - type: 'Identifier', - name: '__p5.unaryNode', - } - node.arguments = [node.argument, signNode] - } + const standardReplacement = node => { + node.type = 'CallExpression'; + node.callee = { + type: 'Identifier', + name: '__p5.unaryNode' + }; + node.arguments = [node.argument, signNode]; + }; if (node.type === 'MemberExpression') { const property = node.argument.property.name; @@ -129,7 +134,7 @@ function shadergenerator(p5, fn) { type: 'Identifier', name: '__p5.unaryNode' }, - arguments: [node.argument.object, signNode], + arguments: [node.argument.object, signNode] }; node.property = { type: 'Identifier', @@ -150,14 +155,14 @@ function shadergenerator(p5, fn) { const uniformNameLiteral = { type: 'Literal', value: node.id.name - } + }; node.init.arguments.unshift(uniformNameLiteral); } if (node.init.callee && node.init.callee.name?.startsWith('varying')) { const varyingNameLiteral = { type: 'Literal', value: node.id.name - } + }; node.init.arguments.unshift(varyingNameLiteral); _state.varyings[node.id.name] = varyingNameLiteral; } @@ -178,10 +183,10 @@ function shadergenerator(p5, fn) { property: { type: 'Identifier', name: 'getValue' - }, + } }, - arguments: [], - } + arguments: [] + }; } }, // The callbacks for AssignmentExpression and BinaryExpression handle @@ -192,7 +197,7 @@ function shadergenerator(p5, fn) { node.type = 'CallExpression'; node.callee = { type: 'Identifier', - name: '__p5.dynamicNode', + name: '__p5.dynamicNode' }; node.arguments = [original]; }, @@ -207,33 +212,33 @@ function shadergenerator(p5, fn) { object: node.left, property: { type: 'Identifier', - name: methodName, - }, + name: methodName + } }, arguments: [node.right] - } - node.operator = '='; - node.right = rightReplacementNode; - } - if (_state.varyings[node.left.name]) { - node.type = 'ExpressionStatement'; - node.expression = { - type: 'CallExpression', - callee: { - type: 'MemberExpression', - object: { - type: 'Identifier', - name: node.left.name - }, - property: { - type: 'Identifier', - name: 'bridge', - } + }; + node.operator = '='; + node.right = rightReplacementNode; + } + if (_state.varyings[node.left.name]) { + node.type = 'ExpressionStatement'; + node.expression = { + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: node.left.name }, - arguments: [node.right], - } - } - }, + property: { + type: 'Identifier', + name: 'bridge' + } + }, + arguments: [node.right] + }; + } + }, BinaryExpression(node, _state, ancestors) { // Don't convert uniform default values to node methods, as // they should be evaluated at runtime, not compiled. @@ -246,10 +251,10 @@ function shadergenerator(p5, fn) { type: 'CallExpression', callee: { type: 'Identifier', - name: '__p5.dynamicNode', + name: '__p5.dynamicNode' }, arguments: [node.left] - } + }; node.left = leftReplacementNode; } // Replace the binary operator with a call expression @@ -260,12 +265,12 @@ function shadergenerator(p5, fn) { object: node.left, property: { type: 'Identifier', - name: replaceBinaryOperator(node.operator), - }, + name: replaceBinaryOperator(node.operator) + } }; node.arguments = [node.right]; - }, - } + } + }; // Javascript Node API. class BaseNode { @@ -314,14 +319,16 @@ function shadergenerator(p5, fn) { value = newValue; } } - }) + }); } } } forceTemporaryVariable() { - if (!(isFloatNode(this) && isVectorNode(this.parent)) || !isVariableNode(this)) - this.useTemp = true; + if ( + !(isFloatNode(this) && isVectorNode(this.parent)) || + !isVariableNode(this) + ) this.useTemp = true; } assertUsedInConditional(branch) { @@ -335,14 +342,21 @@ function shadergenerator(p5, fn) { } checkConditionalDependencies(context) { - context.ifs.forEach((statement) => { + context.ifs.forEach(statement => { const isUsedSatisfied = () => statement.usedInSatisfied.length >= 1; - const isDepsSatisfied = () => statement.dependsOn.length === statement.dependsOnSatisfied.length; + const isDepsSatisfied = () => + statement.dependsOn.length === statement.dependsOnSatisfied.length; if (statement.insertionPoint > -1 || !statement.usedIn.length) return; - if (statement.dependsOn.some(d => d.node === this) && !statement.dependsOnSatisfied.includes(this)) { + if ( + statement.dependsOn.some(d => d.node === this) && + !statement.dependsOnSatisfied.includes(this) + ) { statement.dependsOnSatisfied.push(this); } - if (statement.usedIn.includes(this) && !statement.usedInSatisfied.includes(this)) { + if ( + statement.usedIn.includes(this) && + !statement.usedInSatisfied.includes(this) + ) { statement.usedInSatisfied.push(this); } if (isDepsSatisfied() && isUsedSatisfied()) { @@ -361,9 +375,10 @@ function shadergenerator(p5, fn) { diff = diff > 0 ? diff : undefined; this.dependsOn.forEach(dependency => { if (dependency.isVector) { - const dependencies = dependency.originalComponents.map((component, i) => - component === dependency.currentComponents[i] - ); + const dependencies = dependency.originalComponents + .map((component, i) => + component === dependency.currentComponents[i] + ); context.updateComponents(dependency.node, diff, dependencies); } else { context.updateComponents(dependency.node, diff); @@ -372,12 +387,16 @@ function shadergenerator(p5, fn) { } else { result = this.toGLSL(context); } - this.checkConditionalDependencies(context) + this.checkConditionalDependencies(context); return result; } shouldUseTemporaryVariable() { - if (this.componentsChanged || hasTemporaryVariable(this) || this.useTemp) { return true; } + if ( + this.componentsChanged || + hasTemporaryVariable(this) || + this.useTemp + ) return true; if (this.isInternal || isVariableNode(this) || isConditionalNode(this) || this.type === 'sampler2D') { return false; } // return false; @@ -414,13 +433,13 @@ function shadergenerator(p5, fn) { enforceType(other){ if (isShaderNode(other)){ if (!isGLSLNativeType(other.type)) { - throw new TypeError (`You've tried to perform an operation on a struct of type: ${other.type}. Try accessing a member on that struct with '.'`) + throw new TypeError (`You've tried to perform an operation on a struct of type: ${other.type}. Try accessing a member on that struct with '.'`); } if (!isGLSLNativeType(other.type)) { - throw new TypeError (`You've tried to perform an operation on a struct of type: ${other.type}. Try accessing a member on that struct with '.'`) + throw new TypeError (`You've tried to perform an operation on a struct of type: ${other.type}. Try accessing a member on that struct with '.'`); } if ((isFloatType(this) || isVectorType(this)) && isIntType(other)) { - return new FloatNode(other) + return new FloatNode(other); } return other; } @@ -480,7 +499,7 @@ function shadergenerator(p5, fn) { x = x[0]; } if (_parent) { - const { parent, name } = _parent + const { parent, name } = _parent; this.name = name; this.parent = parent; } @@ -504,7 +523,9 @@ function shadergenerator(p5, fn) { class VectorNode extends BaseNode { constructor(values, type, isInternal = false) { super(isInternal, type); - this.originalValues = conformVectorParameters(values, parseInt(type.slice(3))); + this.originalValues = conformVectorParameters( + values, parseInt(type.slice(3)) + ); this.componentNames = ['x', 'y', 'z', 'w'].slice(0, this.originalValues.length); } @@ -514,7 +535,9 @@ function shadergenerator(p5, fn) { this.componentNames.forEach((componentName, i) => { const info = { name: componentName, parent: this }; - let value = isFloatNode(values[i]) ? values[i] : new FloatNode(values[i], true, info); + let value = isFloatNode(values[i]) ? + values[i] : + new FloatNode(values[i], true, info); Object.defineProperty(this, componentName, { get() { return value; @@ -524,10 +547,12 @@ function shadergenerator(p5, fn) { if (isUnaryExpressionNode(this)) { this.node.value = newValue; } else { - value = isFloatNode(newValue) ? newValue : new FloatNode(newValue, true, info); + value = isFloatNode(newValue) ? + newValue : + new FloatNode(newValue, true, info); } } - }) + }); }); this.originalValues = this.componentNames.map(name => this[name]); } @@ -547,7 +572,7 @@ function shadergenerator(p5, fn) { class FunctionCallNode extends BaseNode { constructor(name, userArgs, properties, isInternal = false) { let functionSignature; - const determineFunctionSignature = (props) => { + const determineFunctionSignature = props => { let genType; let similarity = 0; @@ -558,25 +583,26 @@ function shadergenerator(p5, fn) { if (expectedArgType === 'genType') { // We allow conversions from float -> vec if one argument is a vector. if (genType === undefined || (genType === 'float' && userType.startsWith('vec'))) { - genType = userType + genType = userType; }; expectedArgType = genType; } similarity += (userType === expectedArgType); return userType === expectedArgType || (userType === 'float' && expectedArgType.startsWith('vec')); - }) + }); - return { ...props, valid, similarity, genType } - } + return { ...props, valid, similarity, genType }; + }; if (Array.isArray(properties)) { // Check if the right number of parameters were provided - let possibleOverloads = properties.filter(o => o.args.length === userArgs.length); + let possibleOverloads = properties + .filter(o => o.args.length === userArgs.length); if (possibleOverloads.length === 0) { const argsLengthSet = new Set(); const argsLengthArr = []; - properties.forEach((p) => argsLengthSet.add(p.args.length)); - argsLengthSet.forEach((len) => argsLengthArr.push(`${len}`)); + properties.forEach(p => argsLengthSet.add(p.args.length)); + argsLengthSet.forEach(len => argsLengthArr.push(`${len}`)); const argsLengthStr = argsLengthArr.join(' or '); throw new Error(`Function '${name}' has ${properties.length} variants which expect ${argsLengthStr} arguments, but ${userArgs.length} arguments were provided.`); } @@ -587,19 +613,19 @@ function shadergenerator(p5, fn) { best = current; } return best; - } + }; functionSignature = possibleOverloads.reduce(findBestOverload, null); } else { functionSignature = determineFunctionSignature(properties); } if (!functionSignature || !functionSignature.valid) { - const argsStrJoin = (args) => `(${args.map((arg) => arg).join(', ')})`; + const argsStrJoin = args => `(${args.map(arg => arg).join(', ')})`; const expectedArgsString = Array.isArray(properties) ? properties.map(prop => argsStrJoin(prop.args)).join(' or ') : argsStrJoin(properties.args); - const providedArgsString = argsStrJoin(userArgs.map((a)=>getType(a))); - throw new Error(`Function '${name}' was called with wrong arguments. Most likely, you provided mixed lengths vectors as arguments.\nExpected argument types: ${expectedArgsString}\nProvided argument types: ${providedArgsString}\nAll of the arguments with expected type 'genType' should have a matching type. If one of those is different, try to find where it was created. + const providedArgsString = argsStrJoin(userArgs.map(a=>getType(a))); + throw new Error(`Function '${name}' was called with wrong arguments. Most likely, you provided mixed lengths vectors as arguments.\nExpected argument types: ${expectedArgsString}\nProvided argument types: ${providedArgsString}\nAll of the arguments with expected type 'genType' should have a matching type. If one of those is different, try to find where it was created. `); } @@ -615,7 +641,7 @@ function shadergenerator(p5, fn) { arg = nodeConstructors[functionSignature.genType](arg); } return arg; - }) + }); if (functionSignature.returnType === 'genType') { functionSignature.returnType = functionSignature.genType; @@ -630,7 +656,7 @@ function shadergenerator(p5, fn) { deconstructArgs(context) { let argsString = this.args.map((argNode, i) => { - if (isIntType(argNode) && this.argumentTypes[i] != 'float') { + if (isIntType(argNode) && this.argumentTypes[i] !== 'float') { argNode = argNode.toFloat(); } argNode.toGLSLBase(context); @@ -692,8 +718,10 @@ function shadergenerator(p5, fn) { let { value } = val; context.declarations.push(` ${this.name} = ${value.toGLSLBase(context)};`); if (i === values.length - 1) { - const tempName = `${this.name}_${this.tempVars++}` - snapshot = dynamicAddSwizzleTrap(new VariableNode(tempName, this.type, true)); + const tempName = `${this.name}_${this.tempVars++}`; + snapshot = dynamicAddSwizzleTrap( + new VariableNode(tempName, this.type, true) + ); context.declarations.push(` ${this.type} ${tempName} = ${this.name};`); } }); @@ -704,10 +732,10 @@ function shadergenerator(p5, fn) { bridge(value) { if (!isShaderNode(value) || this.type.startsWith('vec') && getType(value) === 'float') { - value = nodeConstructors[this.type](value) + value = nodeConstructors[this.type](value); } GLOBAL_SHADER.registerVarying(this, value); - this.timesChanged += 1 + this.timesChanged += 1; } } @@ -782,51 +810,55 @@ function shadergenerator(p5, fn) { class UnaryExpressionNode extends BaseNode { constructor(node, operator, isInternal = false) { - super(isInternal, node.type) + super(isInternal, node.type); this.node = node; this.operator = operator; } toGLSL(context) { let mainStr = this.node.toGLSLBase(context); - if (!isVariableNode(this.node) && !hasTemporaryVariable(this.node) && !isPrimitiveNode(this.node)) { - mainStr = `(${mainStr})` + if ( + !isVariableNode(this.node) && + !hasTemporaryVariable(this.node) && + !isPrimitiveNode(this.node) + ) { + mainStr = `(${mainStr})`; } - return `${this.operator}${mainStr}` + return `${this.operator}${mainStr}`; } } // Conditions and logical modifiers BaseNode.prototype.equalTo = function(other) { return binaryExpressionNodeConstructor(this, this.enforceType(other), '=='); - } + }; BaseNode.prototype.greaterThan = function(other) { return binaryExpressionNodeConstructor(this, this.enforceType(other), '>'); - } + }; BaseNode.prototype.greaterThanEqualTo = function(other) { return binaryExpressionNodeConstructor(this, this.enforceType(other), '>='); - } + }; BaseNode.prototype.lessThan = function(other) { return binaryExpressionNodeConstructor(this, this.enforceType(other), '<'); - } + }; BaseNode.prototype.lessThanEqualTo = function(other) { - return binaryExpressionNodeConstructor(this, this.enforceType(other), '<='); } + return binaryExpressionNodeConstructor(this, this.enforceType(other), '<='); }; BaseNode.prototype.not = function() { - return new UnaryExpressionNode(this.condition, '!', true); - } + return new UnaryExpressionNode(this.condition, '!', true); + }; BaseNode.prototype.or = function(other) { return new binaryExpressionNodeConstructor(this, this.enforceType(other), '||', true); - } + }; BaseNode.prototype.and = function(other) { return new binaryExpressionNodeConstructor(this, this.enforceType(other), '&&', true); - } + }; function branch(callback) { const branch = new BranchNode(); @@ -865,7 +897,7 @@ function shadergenerator(p5, fn) { else(branchCallback) { this.elseBranch = branch(branchCallback); - this.elseBranch.parent = this + this.elseBranch.parent = this; return this; } @@ -892,22 +924,22 @@ function shadergenerator(p5, fn) { let codelines = [ `\n if (${this.conditionString}) {`, `\n ${this.ifBranch.toGLSL(context)}`, - `\n }` + '\n }' ]; if (this.elseIfs.length) { - this.elseIfs.forEach((elif) => { + this.elseIfs.forEach(elif => { let { condition, elseBranch } = elif; codelines.push(` else if (${condition.toGLSL(context)}) {`); codelines.push(`\n ${elseBranch.toGLSL(context)}`); - codelines.push(`\n }`); - }) + codelines.push('\n }'); + }); } if (this.elseBranch) { - codelines.push(` else {`); + codelines.push(' else {'); codelines.push(`\n ${this.elseBranch.toGLSL(context)}`); - codelines.push(`\n }\n`); + codelines.push('\n }\n'); } codelines.push('\n'); return codelines.flat().join(''); @@ -916,10 +948,10 @@ function shadergenerator(p5, fn) { fn.assign = function(node, value) { if (!BRANCH) { - throw new error('assign() is supposed to be used inside of conditional branchs. Use the "=" operator as normal otherwise.'); + throw new error('assign() is supposed to be used inside of conditional branchs. Use the "=" operator as normal otherwise.'); } BRANCH.assign(node, value); - } + }; class BranchNode { constructor() { @@ -934,10 +966,10 @@ function shadergenerator(p5, fn) { return parent; }, set(newParent) { - newParent.dependsOn.push(...this.dependsOn) + newParent.dependsOn.push(...this.dependsOn); parent = newParent; } - }) + }); } assign(node, value) { @@ -954,7 +986,7 @@ function shadergenerator(p5, fn) { return; } node.assertUsedInConditional(this); - this.dependsOn.push(makeDependencyObject(node)) + this.dependsOn.push(makeDependencyObject(node)); if (value.shouldUseTemporaryVariable()) { value.assertUsedInConditional(this); this.dependsOn.push(makeDependencyObject(value)); @@ -983,17 +1015,17 @@ function shadergenerator(p5, fn) { statement = `${node.toGLSLBase(context)} = ${result};`; } else if (isFloatNode(node) && node.name) { - statement = `${node.parent.toGLSLBase(context)}.${node.name} = ${result};`; + statement = `${node.parent.toGLSLBase(context)}.${node.name} = ${result};`; } else { node.temporaryVariable = `temp_${context.getNextID()}`; - statement = `${node.type} ${node.toGLSLBase(context)} = ${result};` + statement = `${node.type} ${node.toGLSLBase(context)} = ${result};`; } this.statements.push(statement); - }) + }); - return this.statements.join(`\n `); + return this.statements.join('\n '); } } @@ -1030,9 +1062,9 @@ function shadergenerator(p5, fn) { length += parseInt(val.type.slice(3)); } if (![2, 3, 4].includes(length)) { - throw new Error(`You have attempted to construct a vector with ${length} values. Only vec2, vec3, and vec4 types are supported.`) + throw new Error(`You have attempted to construct a vector with ${length} values. Only vec2, vec3, and vec4 types are supported.`); } - return length + return length; } p5.dynamicNode = function (input) { @@ -1045,13 +1077,13 @@ function shadergenerator(p5, fn) { else if (Array.isArray(input)) { return nodeConstructors.dynamicVector(input); } - } + }; // For replacing unary expressions p5.unaryNode = function(input, sign) { input = p5.dynamicNode(input); return dynamicAddSwizzleTrap(new UnaryExpressionNode(input, sign)); - } + }; function isShaderNode(node) { return (node instanceof BaseNode); @@ -1082,7 +1114,7 @@ function shadergenerator(p5, fn) { } function isConditionalNode(node) { - return (node instanceof ConditionalNode || node instanceof BranchNode) + return (node instanceof ConditionalNode || node instanceof BranchNode); } function hasTemporaryVariable(node) { @@ -1090,7 +1122,11 @@ function shadergenerator(p5, fn) { } function isPrimitiveNode(node) { - return (node instanceof FloatNode || node instanceof IntNode || node instanceof VectorNode); + return ( + node instanceof FloatNode || + node instanceof IntNode || + node instanceof VectorNode + ); } function isFunctionCallNode(node) { @@ -1098,11 +1134,11 @@ function shadergenerator(p5, fn) { } function isVectorNode(node) { - return (node instanceof VectorNode) + return (node instanceof VectorNode); } function isUnaryExpressionNode(node) { - return (node instanceof UnaryExpressionNode) + return (node instanceof UnaryExpressionNode); } // Helper function to check if a type is a user defined struct or native type @@ -1125,8 +1161,8 @@ function shadergenerator(p5, fn) { this.output = { vertexDeclarations: new Set(), fragmentDeclarations: new Set(), - uniforms: {}, - } + uniforms: {} + }; this.uniformNodes = []; this.resetGLSLContext(); this.isGenerating = false; @@ -1152,38 +1188,42 @@ function shadergenerator(p5, fn) { generateHookOverrides(originalShader) { const availableHooks = { ...originalShader.hooks.vertex, - ...originalShader.hooks.fragment, - } + ...originalShader.hooks.fragment + }; const windowOverrides = {}; const fnOverrides = {}; - Object.keys(availableHooks).forEach((hookName) => { + Object.keys(availableHooks).forEach(hookName => { const hookTypes = originalShader.hookTypes(hookName); // These functions are where the user code is executed this[hookTypes.name] = function(userCallback) { // Create the initial nodes which are passed to the user callback // Also generate a string of the arguments for the code generation - const argNodes = [] + const argNodes = []; const argsArray = []; - hookTypes.parameters.forEach((parameter) => { + hookTypes.parameters.forEach(parameter => { // For hooks with structs as input we should pass an object populated with variable nodes if (!isGLSLNativeType(parameter.type.typeName)) { const structArg = {}; - parameter.type.properties.forEach((property) => { + parameter.type.properties.forEach(property => { structArg[property.name] = variableConstructor(`${parameter.name}.${property.name}`, property.type.typeName, true); }); argNodes.push(structArg); } else { argNodes.push( - variableConstructor(parameter.name, parameter.type.typeName, true) + variableConstructor( + parameter.name, + parameter.type.typeName, + true + ) ); } const qualifiers = parameter.type.qualifiers.length > 0 ? parameter.type.qualifiers.join(' ') : ''; - argsArray.push(`${qualifiers} ${parameter.type.typeName} ${parameter.name}`.trim()) - }) + argsArray.push(`${qualifiers} ${parameter.type.typeName} ${parameter.name}`.trim()); + }); let returnedValue = userCallback(...argNodes); const expectedReturnType = hookTypes.returnType; @@ -1191,26 +1231,34 @@ function shadergenerator(p5, fn) { // If the expected return type is a struct we need to evaluate each of its properties if (!isGLSLNativeType(expectedReturnType.typeName)) { - Object.entries(returnedValue).forEach(([propertyName, propertyNode]) => { - propertyNode = p5.dynamicNode(propertyNode); - toGLSLResults[propertyName] = propertyNode.toGLSLBase(this.context); - this.context.updateComponents(propertyNode); - }); + Object.entries(returnedValue) + .forEach(([propertyName, propertyNode]) => { + propertyNode = p5.dynamicNode(propertyNode); + toGLSLResults[propertyName] = propertyNode + .toGLSLBase(this.context); + this.context.updateComponents(propertyNode); + }); } else { if (!isShaderNode(returnedValue)) { - returnedValue = nodeConstructors[expectedReturnType.typeName](returnedValue) + returnedValue = + nodeConstructors[expectedReturnType.typeName](returnedValue); } else if (isFloatType(returnedValue) && expectedReturnType.typeName.startsWith('vec')) { - returnedValue = nodeConstructors[expectedReturnType.typeName](returnedValue); + returnedValue = + nodeConstructors[expectedReturnType.typeName](returnedValue); } toGLSLResults['notAProperty'] = returnedValue.toGLSLBase(this.context); this.context.updateComponents(returnedValue); } - this.context.ifs.forEach((statement) => { + this.context.ifs.forEach(statement => { if (statement.usedIn.length === 0) { return; } const lines = statement.toGLSL(this.context); - this.context.declarations.splice(statement.insertionPoint, 0, lines); - }) + this.context.declarations.splice( + statement.insertionPoint, + 0, + lines + ); + }); // Build the final GLSL string. // The order of this code is a bit confusing, we need to call toGLSLBase let codeLines = [ @@ -1221,7 +1269,7 @@ function shadergenerator(p5, fn) { Object.entries(toGLSLResults).forEach(([propertyName, result]) => { const propString = expectedReturnType.properties ? `.${propertyName}` : ''; - codeLines.push(` finalReturnValue${propString} = ${result};`) + codeLines.push(` finalReturnValue${propString} = ${result};`); }); this.context.declarations = []; @@ -1230,7 +1278,7 @@ function shadergenerator(p5, fn) { const finalVaryingAssignments = []; declArray.forEach(obj => { const { node, value } = obj; - finalVaryingAssignments.push(` ${node.name} = ${value.toGLSLBase(this.context)};`) + finalVaryingAssignments.push(` ${node.name} = ${value.toGLSLBase(this.context)};`); finalVaryingAssignments.unshift(...this.context.declarations); node.timesChanged = 0; }); @@ -1240,7 +1288,7 @@ function shadergenerator(p5, fn) { codeLines.push(' return finalReturnValue;', '}'); this.output[hookName] = codeLines.join('\n'); this.resetGLSLContext(); - } + }; windowOverrides[hookTypes.name] = window[hookTypes.name]; fnOverrides[hookTypes.name] = fn[hookTypes.name]; @@ -1274,13 +1322,13 @@ function shadergenerator(p5, fn) { } resetGLSLContext() { - this.uniformNodes.forEach((node) => { + this.uniformNodes.forEach(node => { node.usedIn = []; node.temporaryVariable = undefined; }); this.context = { id: 0, - getNextID() { return this.id++ }, + getNextID() { return this.id++; }, declarations: [], varyings: [], ifs: [], @@ -1300,22 +1348,22 @@ function shadergenerator(p5, fn) { } }); } else { - const components = node.componentNames.map((name) => { - return node[name] + const components = node.componentNames.map(name => { + return node[name]; }); const replacement = nodeConstructors[node.type](components); - const line = ` ${node.temporaryVariable} = ${replacement.toGLSLBase(this)};` + const line = ` ${node.temporaryVariable} = ${replacement.toGLSLBase(this)};`; lines.push(line); } if (_emplaceAt) { - this.declarations.splice(_emplaceAt, 0, ...lines) + this.declarations.splice(_emplaceAt, 0, ...lines); } else { this.declarations.push(...lines); } node.componentsChanged = false; } } - } + }; this.uniformNodes = []; } } @@ -1379,7 +1427,7 @@ function shadergenerator(p5, fn) { for (const set of swizzleSets) { if ([...property].every(char => set.includes(char))) { if (property.length === 1) { - return target[swizzleSets[0][set.indexOf(property[0])]] + return target[swizzleSets[0][set.indexOf(property[0])]]; } const components = [...property].map(char => { const index = set.indexOf(char); @@ -1397,11 +1445,16 @@ function shadergenerator(p5, fn) { for (const set of swizzleSets) { const propertyCharArray = [...property]; if (propertyCharArray.every(char => set.includes(char))) { - const newValues = Array.isArray(value) ? value : Array(property.length).fill(value); + const newValues = Array.isArray(value) ? + value : + Array(property.length).fill(value); propertyCharArray.forEach((char, i) => { const index = set.indexOf(char); const realProperty = swizzleSets[0][index]; - const descriptor = Object.getOwnPropertyDescriptor(target, realProperty); + const descriptor = Object.getOwnPropertyDescriptor( + target, + realProperty + ); Reflect.set(target, realProperty, newValues[i], receiver); }); return true; @@ -1409,22 +1462,22 @@ function shadergenerator(p5, fn) { } return Reflect.set(...arguments); } - } + }; } // User functions fn.If = function (condition, branch) { return new ConditionalNode(condition, branch); - } + }; fn.instanceID = function() { return variableConstructor('gl_InstanceID', 'int'); - } + }; fn.getTexture = function(...userArgs) { const props = { args: ['sampler2D', 'vec2'], returnType: 'vec4', isp5Function: true }; return fnNodeConstructor('getTexture', userArgs, props); - } + }; // Generating uniformFloat, uniformVec, createFloat, etc functions // Maps a GLSL type to the name suffix for method names @@ -1434,7 +1487,7 @@ function shadergenerator(p5, fn) { vec2: 'Vector2', vec3: 'Vector3', vec4: 'Vector4', - sampler2D: 'Texture', + sampler2D: 'Texture' }; function dynamicAddSwizzleTrap(node, _size) { @@ -1466,13 +1519,14 @@ function shadergenerator(p5, fn) { node = dynamicAddSwizzleTrap(node); node.dependsOn = makeDependencyArray(node.args); const dependsOnConditionals = node.args.map(arg => { - const conditionals = arg.usedIn.filter(n => isConditionalNode(n)).map(c => { - if (c instanceof BranchNode) { - return c.parent; - } else { - return c; - } - }); + const conditionals = arg.usedIn + .filter(n => isConditionalNode(n)).map(c => { + if (c instanceof BranchNode) { + return c.parent; + } else { + return c; + } + }); return conditionals; }).flat(); dependsOnConditionals.forEach(conditional => conditional.usedIn.push(node)); @@ -1481,15 +1535,15 @@ function shadergenerator(p5, fn) { } const nodeConstructors = { - int: (value) => new IntNode(value), - float: (value) => new FloatNode(value), - vec2: (value) => dynamicAddSwizzleTrap(new VectorNode(value, 'vec2')), - vec3: (value) => dynamicAddSwizzleTrap(new VectorNode(value, 'vec3')), - vec4: (value) => dynamicAddSwizzleTrap(new VectorNode(value, 'vec4')), + int: value => new IntNode(value), + float: value => new FloatNode(value), + vec2: value => dynamicAddSwizzleTrap(new VectorNode(value, 'vec2')), + vec3: value => dynamicAddSwizzleTrap(new VectorNode(value, 'vec3')), + vec4: value => dynamicAddSwizzleTrap(new VectorNode(value, 'vec4')), dynamicVector: function(value) { const size = computeVectorLength(value); return this[`vec${size}`](value); - }, + } }; for (const glslType in GLSLTypesToIdentifiers) { @@ -1500,7 +1554,10 @@ function shadergenerator(p5, fn) { ShaderGenerator.prototype[uniformMethodName] = function(...args) { let [name, ...defaultValue] = args; if (glslType.startsWith('vec') && !(defaultValue[0] instanceof Function)) { - defaultValue = conformVectorParameters(defaultValue, parseInt(glslType.slice(3))); + defaultValue = conformVectorParameters( + defaultValue, + parseInt(glslType.slice(3)) + ); this.output.uniforms[`${glslType} ${name}`] = defaultValue; } else { @@ -1522,7 +1579,7 @@ function shadergenerator(p5, fn) { const varyingMethodName = `varying${typeIdentifier}`; ShaderGenerator.prototype[varyingMethodName] = function(name) { return dynamicAddSwizzleTrap(new VaryingNode(name, glslType, false)); - } + }; fn[varyingMethodName] = function (name) { return GLOBAL_SHADER[varyingMethodName](name); @@ -1553,94 +1610,96 @@ function shadergenerator(p5, fn) { // https://docs.gl/el3/abs const builtInGLSLFunctions = { //////////// Trigonometry ////////// - 'acos': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'acosh': { args: ['genType'], returnType: 'genType', isp5Function: false}, - 'asin': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'asinh': { args: ['genType'], returnType: 'genType', isp5Function: false}, + 'acos': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'acosh': { args: ['genType'], returnType: 'genType', isp5Function: false }, + 'asin': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'asinh': { args: ['genType'], returnType: 'genType', isp5Function: false }, 'atan': [ - { args: ['genType'], returnType: 'genType', isp5Function: false}, - { args: ['genType', 'genType'], returnType: 'genType', isp5Function: false}, + { args: ['genType'], returnType: 'genType', isp5Function: false }, + { args: ['genType', 'genType'], returnType: 'genType', isp5Function: false } ], - 'atanh': { args: ['genType'], returnType: 'genType', isp5Function: false}, - 'cos': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'cosh': { args: ['genType'], returnType: 'genType', isp5Function: false}, - 'degrees': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'radians': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'sin': { args: ['genType'], returnType: 'genType' , isp5Function: true}, - 'sinh': { args: ['genType'], returnType: 'genType', isp5Function: false}, - 'tan': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'tanh': { args: ['genType'], returnType: 'genType', isp5Function: false}, + 'atanh': { args: ['genType'], returnType: 'genType', isp5Function: false }, + 'cos': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'cosh': { args: ['genType'], returnType: 'genType', isp5Function: false }, + 'degrees': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'radians': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'sin': { args: ['genType'], returnType: 'genType' , isp5Function: true }, + 'sinh': { args: ['genType'], returnType: 'genType', isp5Function: false }, + 'tan': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'tanh': { args: ['genType'], returnType: 'genType', isp5Function: false }, ////////// Mathematics ////////// - 'abs': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'ceil': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'clamp': { args: ['genType', 'genType', 'genType'], returnType: 'genType', isp5Function: false}, - 'dFdx': { args: ['genType'], returnType: 'genType', isp5Function: false}, - 'dFdy': { args: ['genType'], returnType: 'genType', isp5Function: false}, - 'exp': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'exp2': { args: ['genType'], returnType: 'genType', isp5Function: false}, - 'floor': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'fma': { args: ['genType', 'genType', 'genType'], returnType: 'genType', isp5Function: false}, - 'fract': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'fwidth': { args: ['genType'], returnType: 'genType', isp5Function: false}, - 'inversesqrt': { args: ['genType'], returnType: 'genType', isp5Function: true}, + 'abs': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'ceil': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'clamp': { args: ['genType', 'genType', 'genType'], returnType: 'genType', isp5Function: false }, + 'dFdx': { args: ['genType'], returnType: 'genType', isp5Function: false }, + 'dFdy': { args: ['genType'], returnType: 'genType', isp5Function: false }, + 'exp': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'exp2': { args: ['genType'], returnType: 'genType', isp5Function: false }, + 'floor': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'fma': { args: ['genType', 'genType', 'genType'], returnType: 'genType', isp5Function: false }, + 'fract': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'fwidth': { args: ['genType'], returnType: 'genType', isp5Function: false }, + 'inversesqrt': { args: ['genType'], returnType: 'genType', isp5Function: true }, // 'isinf': {}, // 'isnan': {}, - 'log': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'log2': { args: ['genType'], returnType: 'genType', isp5Function: false}, + 'log': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'log2': { args: ['genType'], returnType: 'genType', isp5Function: false }, 'max': [ - { args: ['genType', 'genType'], returnType: 'genType', isp5Function: true}, - { args: ['genType', 'float'], returnType: 'genType', isp5Function: true}, + { args: ['genType', 'genType'], returnType: 'genType', isp5Function: true }, + { args: ['genType', 'float'], returnType: 'genType', isp5Function: true } ], 'min': [ - { args: ['genType', 'genType'], returnType: 'genType', isp5Function: true}, - { args: ['genType', 'float'], returnType: 'genType', isp5Function: true}, + { args: ['genType', 'genType'], returnType: 'genType', isp5Function: true }, + { args: ['genType', 'float'], returnType: 'genType', isp5Function: true } ], 'mix': [ - { args: ['genType', 'genType', 'genType'], returnType: 'genType', isp5Function: false}, - { args: ['genType', 'genType', 'float'], returnType: 'genType', isp5Function: false}, + { args: ['genType', 'genType', 'genType'], returnType: 'genType', isp5Function: false }, + { args: ['genType', 'genType', 'float'], returnType: 'genType', isp5Function: false } ], // 'mod': {}, // 'modf': {}, - 'pow': { args: ['genType', 'genType'], returnType: 'genType', isp5Function: true}, - 'round': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'roundEven': { args: ['genType'], returnType: 'genType', isp5Function: false}, + 'pow': { args: ['genType', 'genType'], returnType: 'genType', isp5Function: true }, + 'round': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'roundEven': { args: ['genType'], returnType: 'genType', isp5Function: false }, // 'sign': {}, 'smoothstep': [ - { args: ['genType', 'genType', 'genType'], returnType: 'genType', isp5Function: false}, - { args: ['float', 'float', 'genType'], returnType: 'genType', isp5Function: false}, + { args: ['genType', 'genType', 'genType'], returnType: 'genType', isp5Function: false }, + { args: ['float', 'float', 'genType'], returnType: 'genType', isp5Function: false } ], - 'sqrt': { args: ['genType'], returnType: 'genType', isp5Function: true}, - 'step': { args: ['genType', 'genType'], returnType: 'genType', isp5Function: false}, - 'trunc': { args: ['genType'], returnType: 'genType', isp5Function: false}, + 'sqrt': { args: ['genType'], returnType: 'genType', isp5Function: true }, + 'step': { args: ['genType', 'genType'], returnType: 'genType', isp5Function: false }, + 'trunc': { args: ['genType'], returnType: 'genType', isp5Function: false }, ////////// Vector ////////// - 'cross': { args: ['vec3', 'vec3'], returnType: 'vec3', isp5Function: true}, - 'distance': { args: ['genType', 'genType'], returnType: 'float', isp5Function: true}, - 'dot': { args: ['genType', 'genType'], returnType: 'float', isp5Function: true}, + 'cross': { args: ['vec3', 'vec3'], returnType: 'vec3', isp5Function: true }, + 'distance': { args: ['genType', 'genType'], returnType: 'float', isp5Function: true }, + 'dot': { args: ['genType', 'genType'], returnType: 'float', isp5Function: true }, // 'equal': {}, - 'faceforward': { args: ['genType', 'genType', 'genType'], returnType: 'genType', isp5Function: false}, - 'length': { args: ['genType'], returnType: 'float', isp5Function: false}, - 'normalize': { args: ['genType'], returnType: 'genType', isp5Function: true}, + 'faceforward': { args: ['genType', 'genType', 'genType'], returnType: 'genType', isp5Function: false }, + 'length': { args: ['genType'], returnType: 'float', isp5Function: false }, + 'normalize': { args: ['genType'], returnType: 'genType', isp5Function: true }, // 'notEqual': {}, - 'reflect': { args: ['genType', 'genType'], returnType: 'genType', isp5Function: false}, - 'refract': { args: ['genType', 'genType', 'float'], returnType: 'genType', isp5Function: false}, + 'reflect': { args: ['genType', 'genType'], returnType: 'genType', isp5Function: false }, + 'refract': { args: ['genType', 'genType', 'float'], returnType: 'genType', isp5Function: false }, ////////// Texture sampling ////////// - 'texture': {args: ['sampler2D', 'vec2'], returnType: 'vec4', isp5Function: true}, - } + 'texture': { args: ['sampler2D', 'vec2'], returnType: 'vec4', isp5Function: true } + }; Object.entries(builtInGLSLFunctions).forEach(([functionName, properties]) => { - const isp5Function = Array.isArray(properties) ? properties[0].isp5Function : properties.isp5Function; + const isp5Function = Array.isArray(properties) ? + properties[0].isp5Function : + properties.isp5Function; if (isp5Function) { const originalFn = fn[functionName]; fn[functionName] = function (...args) { if (GLOBAL_SHADER?.isGenerating) { - return fnNodeConstructor(functionName, args, properties) + return fnNodeConstructor(functionName, args, properties); } else { return originalFn.apply(this, args); } - } + }; } else { fn[functionName] = function (...args) { if (GLOBAL_SHADER?.isGenerating) { @@ -1650,9 +1709,9 @@ function shadergenerator(p5, fn) { `It looks like you've called ${functionName} outside of a shader's modify() function.` ); } - } + }; } - }) + }); // Alias GLSL's mix function as lerp in p5.strands // Bridging p5.js lerp and GLSL mix for consistency in shader expressions const originalLerp = fn.lerp; @@ -1687,9 +1746,8 @@ function shadergenerator(p5, fn) { } - export default shadergenerator; if (typeof p5 !== 'undefined') { - p5.registerAddon(shadergenerator) + p5.registerAddon(shadergenerator); } diff --git a/src/webgl/ShapeBuilder.js b/src/webgl/ShapeBuilder.js index 41535345e7..1e61d2490d 100644 --- a/src/webgl/ShapeBuilder.js +++ b/src/webgl/ShapeBuilder.js @@ -21,7 +21,12 @@ export class ShapeBuilder { constructor(renderer) { this.renderer = renderer; this.shapeMode = constants.PATH; - this.geometry = new Geometry(undefined, undefined, undefined, this.renderer); + this.geometry = new Geometry( + undefined, + undefined, + undefined, + this.renderer + ); this.geometry.gid = '__IMMEDIATE_MODE_GEOMETRY__'; this.contourIndices = []; @@ -55,12 +60,22 @@ export class ShapeBuilder { this._useUserVertexProperties = true; for (const key in shape.userVertexProperties) { const name = shape.vertexPropertyName(key); - const prop = this.geometry._userVertexPropertyHelper(name, [], shape.userVertexProperties[key]); + const prop = this.geometry._userVertexPropertyHelper( + name, + [], + shape.userVertexProperties[key] + ); userVertexPropertyHelpers[key] = prop; this.tessyVertexSize += prop.getDataSize(); this.bufferStrides[prop.getSrcName()] = prop.getDataSize(); this.renderer.buffers.user.push( - new RenderBuffer(prop.getDataSize(), prop.getSrcName(), prop.getDstName(), name, this.renderer) + new RenderBuffer( + prop.getDataSize(), + prop.getSrcName(), + prop.getDstName(), + name, + this.renderer + ) ); } } else { @@ -90,7 +105,7 @@ export class ShapeBuilder { buffer.length - 3 * stride, buffer.length - 2 * stride ), - ...buffer.slice(buffer.length - stride, buffer.length), + ...buffer.slice(buffer.length - stride, buffer.length) ); } } @@ -98,7 +113,10 @@ export class ShapeBuilder { this.geometry.vertices.push(vertex.position); this.geometry.vertexNormals.push(vertex.normal || new Vector(0, 0, 0)); - this.geometry.uvs.push(vertex.textureCoordinates.x, vertex.textureCoordinates.y); + this.geometry.uvs.push( + vertex.textureCoordinates.x, + vertex.textureCoordinates.y + ); if (this.renderer.states.fillColor) { this.geometry.vertexColors.push(...vertex.fill.array()); } else { @@ -120,7 +138,10 @@ export class ShapeBuilder { } if (shouldProcessEdges) { - this.geometry.edges = this._calculateEdges(this.shapeMode, this.geometry.vertices); + this.geometry.edges = this._calculateEdges( + this.shapeMode, + this.geometry.vertices + ); } if (shouldProcessEdges && !this.renderer.geometryBuilder) { this.geometry._edgesToVertices(); @@ -155,7 +176,7 @@ export class ShapeBuilder { } else { return val / this.renderer.states._tex.height; } - }) + }); } } @@ -179,7 +200,7 @@ export class ShapeBuilder { */ _calculateEdges( shapeMode, - verts, + verts ) { const res = []; let i = 0; @@ -310,7 +331,9 @@ export class ShapeBuilder { j = j + this.tessyVertexSize ) { colors.push(...polyTriangles.slice(j + 5, j + 9)); - this.geometry.vertexNormals.push(new Vector(...polyTriangles.slice(j + 9, j + 12))); + this.geometry.vertexNormals.push( + new Vector(...polyTriangles.slice(j + 9, j + 12)) + ); { let offset = 12; for (const propName in this.geometry.userVertexProperties){ diff --git a/src/webgl/light.js b/src/webgl/light.js index 815dfec4d9..3aaf09e3e2 100644 --- a/src/webgl/light.js +++ b/src/webgl/light.js @@ -1461,7 +1461,7 @@ function light(p5, fn){ ); this.states.setValue('enableLighting', true); - } + }; RendererGL.prototype.specularColor = function(v1, v2, v3) { const color = this._pInst.color(...arguments); @@ -1471,7 +1471,7 @@ function light(p5, fn){ color._array[1], color._array[2] ]); - } + }; RendererGL.prototype.directionalLight = function(v1, v2, v3, x, y, z) { let color; @@ -1512,7 +1512,7 @@ function light(p5, fn){ ); this.states.setValue('enableLighting', true); - } + }; RendererGL.prototype.pointLight = function(v1, v2, v3, x, y, z) { let color; @@ -1551,20 +1551,20 @@ function light(p5, fn){ ); this.states.setValue('enableLighting', true); - } + }; RendererGL.prototype.imageLight = function(img) { // activeImageLight property is checked by _setFillUniforms // for sending uniforms to the fillshader this.states.setValue('activeImageLight', img); this.states.setValue('enableLighting', true); - } + }; RendererGL.prototype.lights = function() { const grayColor = this._pInst.color('rgb(128,128,128)'); this.ambientLight(grayColor); this.directionalLight(grayColor, 0, 0, -1); - } + }; RendererGL.prototype.lightFalloff = function( constantAttenuation, @@ -1605,7 +1605,7 @@ function light(p5, fn){ this.states.setValue('constantAttenuation', constantAttenuation); this.states.setValue('linearAttenuation', linearAttenuation); this.states.setValue('quadraticAttenuation', quadraticAttenuation); - } + }; RendererGL.prototype.spotLight = function( v1, @@ -1812,7 +1812,7 @@ function light(p5, fn){ this.states.setValue('spotLightConc', [concentration]); this.states.setValue('enableLighting', true); - } + }; RendererGL.prototype.noLights = function() { this.states.setValue('activeImageLight', null); @@ -1841,7 +1841,7 @@ function light(p5, fn){ this.states.setValue('quadraticAttenuation', 0); this.states.setValue('_useShininess', 1); this.states.setValue('_useMetalness', 0); - } + }; } export default light; diff --git a/src/webgl/loading.js b/src/webgl/loading.js index 4f7fa6af6a..e808cd4275 100755 --- a/src/webgl/loading.js +++ b/src/webgl/loading.js @@ -338,7 +338,13 @@ function loading(p5, fn){ * @param {Boolean} [options.flipV] * @return {Promise} new p5.Geometry object. */ - fn.loadModel = async function (path, fileType, normalize, successCallback, failureCallback) { + fn.loadModel = async function ( + path, + fileType, + normalize, + successCallback, + failureCallback + ) { // p5._validateParameters('loadModel', arguments); let flipU = false; @@ -494,7 +500,7 @@ function loading(p5, fn){ let currentMaterial = null; let materials = {}; - const { data } = await request(mtlPath, "text"); + const { data } = await request(mtlPath, 'text'); const lines = data.split('\n'); for (let line = 0; line < lines.length; ++line) { @@ -847,7 +853,11 @@ function loading(p5, fn){ const line = lines[iterator].trim(); const parts = line.split(' '); - for (let partsiterator = 0; partsiterator < parts.length; ++partsiterator) { + for ( + let partsiterator = 0; + partsiterator < parts.length; + ++partsiterator + ) { if (parts[partsiterator] === '') { // Ignoring multiple whitespaces parts.splice(partsiterator, 1); diff --git a/src/webgl/material.js b/src/webgl/material.js index 4fbb3c03ff..917402faae 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -136,7 +136,7 @@ function material(p5, fn){ if (successCallback) { return successCallback(loadedShader); } else { - return loadedShader + return loadedShader; } } catch(err) { if (failureCallback) { @@ -550,7 +550,11 @@ function material(p5, fn){ * @alt * A rectangle with a shader applied to it. */ - fn.loadFilterShader = async function (fragFilename, successCallback, failureCallback) { + fn.loadFilterShader = async function ( + fragFilename, + successCallback, + failureCallback + ) { // p5._validateParameters('loadFilterShader', arguments); try { // Load the fragment shader @@ -3788,25 +3792,25 @@ function material(p5, fn){ this.states.setValue('_useNormalMaterial', false); s.ensureCompiledOnContext(this); s.setDefaultUniforms(); - } + }; RendererGL.prototype.strokeShader = function(s) { this.states.setValue('userStrokeShader', s); s.ensureCompiledOnContext(this); s.setDefaultUniforms(); - } + }; RendererGL.prototype.imageShader = function(s) { this.states.setValue('userImageShader', s); s.ensureCompiledOnContext(this); s.setDefaultUniforms(); - } + }; RendererGL.prototype.resetShader = function() { this.states.setValue('userFillShader', null); this.states.setValue('userStrokeShader', null); this.states.setValue('userImageShader', null); - } + }; RendererGL.prototype.texture = function(tex) { this.states.setValue('drawMode', constants.TEXTURE); @@ -3823,7 +3827,7 @@ function material(p5, fn){ this.states.setValue('curFillColor', [1, 1, 1, 1]); this.states.setValue('fillColor', new Color([1, 1, 1])); this.states.setValue('strokeColor', null); - } + }; // RendererGL.prototype.ambientMaterial = function(v1, v2, v3) { // } @@ -3839,12 +3843,12 @@ function material(p5, fn){ shine = 1; } this.states.setValue('_useShininess', shine); - } + }; RendererGL.prototype.metalness = function(metallic) { const metalMix = 1 - Math.exp(-metallic / 100); this.states.setValue('_useMetalness', metalMix); - } + }; } export default material; diff --git a/src/webgl/p5.Camera.js b/src/webgl/p5.Camera.js index bca2efb2a2..f9b87e0dce 100644 --- a/src/webgl/p5.Camera.js +++ b/src/webgl/p5.Camera.js @@ -1235,12 +1235,10 @@ class Camera { const f = 1.0 / Math.tan(this.cameraFOV / 2); const nf = 1.0 / (this.cameraNear - this.cameraFar); - /* eslint-disable indent */ this.projMatrix.set(f / aspect, 0, 0, 0, 0, -f * this.yScale, 0, 0, 0, 0, (far + near) * nf, -1, 0, 0, (2 * far * near) * nf, 0); - /* eslint-enable indent */ if (this._isActive()) { this._renderer.states.setValue('uPMatrix', this._renderer.states.uPMatrix.clone()); @@ -1424,12 +1422,12 @@ class Camera { const ty = -(top + bottom) / h; const tz = -(far + near) / d; this.projMatrix = new Matrix(4); - /* eslint-disable indent */ + this.projMatrix.set(x, 0, 0, 0, 0, -y, 0, 0, 0, 0, z, 0, tx, ty, tz, 1); - /* eslint-enable indent */ + if (this._isActive()) { this._renderer.states.setValue('uPMatrix', this._renderer.states.uPMatrix.clone()); this._renderer.states.uPMatrix.set(this.projMatrix); @@ -1562,12 +1560,12 @@ class Camera { this.projMatrix = new Matrix(4); - /* eslint-disable indent */ + this.projMatrix.set(x, 0, 0, 0, 0, -y, 0, 0, tx, ty, tz, -1, 0, 0, z, 0); - /* eslint-enable indent */ + if (this._isActive()) { this._renderer.states.setValue('uPMatrix', this._renderer.states.uPMatrix.clone()); @@ -1599,13 +1597,11 @@ class Camera { const rotation = new Matrix(4); // TODO Maybe pass p5 rotation.rotate4x4(this._renderer._pInst._toRadians(a), x, y, z); - /* eslint-disable max-len */ const rotatedCenter = [ centerX * rotation.mat4[0] + centerY * rotation.mat4[4] + centerZ * rotation.mat4[8], centerX * rotation.mat4[1] + centerY * rotation.mat4[5] + centerZ * rotation.mat4[9], centerX * rotation.mat4[2] + centerY * rotation.mat4[6] + centerZ * rotation.mat4[10] ]; - /* eslint-enable max-len */ // add eye position back into center rotatedCenter[0] += this.eyeX; @@ -2143,12 +2139,12 @@ class Camera { // the camera affects the model view matrix, insofar as it // inverse translates the world to the eye position of the camera // and rotates it. - /* eslint-disable indent */ + this.cameraMatrix.set(local.x[0], local.y[0], local.z[0], 0, local.x[1], local.y[1], local.z[1], 0, local.x[2], local.y[2], local.z[2], 0, 0, 0, 0, 1); - /* eslint-enable indent */ + const tx = -eyeX; const ty = -eyeY; @@ -2583,16 +2579,16 @@ class Camera { // and interpolate the elements of the projection matrix. // Use logarithmic interpolation for interpolation. if (this.projMatrix.mat4[15] !== 0) { - this.projMatrix.setElement( - 0, - cam0.projMatrix.mat4[0] * + this.projMatrix.setElement( + 0, + cam0.projMatrix.mat4[0] * Math.pow(cam1.projMatrix.mat4[0] / cam0.projMatrix.mat4[0], amt) - ); - this.projMatrix.setElement( - 5, - cam0.projMatrix.mat4[5] * + ); + this.projMatrix.setElement( + 5, + cam0.projMatrix.mat4[5] * Math.pow(cam1.projMatrix.mat4[5] / cam0.projMatrix.mat4[5], amt) - ); + ); // If the camera is active, make uPMatrix reflect changes in projMatrix. if (this._isActive()) { this._renderer.states.setValue('uPMatrix', this._renderer.states.uPMatrix.clone()); @@ -3952,11 +3948,11 @@ function camera(p5, fn){ RendererGL.prototype.camera = function(...args) { this.states.curCamera.camera(...args); - } + }; RendererGL.prototype.perspective = function(...args) { this.states.curCamera.perspective(...args); - } + }; RendererGL.prototype.linePerspective = function(enable) { if (enable !== undefined) { @@ -3966,15 +3962,15 @@ function camera(p5, fn){ // If no argument is provided, return the current value return this.states.curCamera.useLinePerspective; } - } + }; RendererGL.prototype.ortho = function(...args) { this.states.curCamera.ortho(...args); - } + }; RendererGL.prototype.frustum = function(...args) { this.states.curCamera.frustum(...args); - } + }; RendererGL.prototype.createCamera = function() { // compute default camera settings, then set a default camera @@ -3983,7 +3979,7 @@ function camera(p5, fn){ _cam._setDefaultCamera(); return _cam; - } + }; RendererGL.prototype.setCamera = function(cam) { this.states.setValue('curCamera', cam); @@ -3993,7 +3989,7 @@ function camera(p5, fn){ this.states.uPMatrix.set(cam.projMatrix); this.states.setValue('uViewMatrix', this.states.uViewMatrix.clone()); this.states.uViewMatrix.set(cam.cameraMatrix); - } + }; } export default camera; diff --git a/src/webgl/p5.DataArray.js b/src/webgl/p5.DataArray.js index 00306105b1..5f55864420 100644 --- a/src/webgl/p5.DataArray.js +++ b/src/webgl/p5.DataArray.js @@ -110,7 +110,7 @@ function dataArray(p5, fn){ } export default dataArray; -export { DataArray } +export { DataArray }; if(typeof p5 !== 'undefined'){ dataArray(p5, p5.prototype); diff --git a/src/webgl/p5.Framebuffer.js b/src/webgl/p5.Framebuffer.js index 9ff75ff1fa..ad481fb586 100644 --- a/src/webgl/p5.Framebuffer.js +++ b/src/webgl/p5.Framebuffer.js @@ -1115,7 +1115,7 @@ class Framebuffer { gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.aaFramebuffer); gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.framebuffer); const partsToCopy = { - colorTexture: [gl.COLOR_BUFFER_BIT, this.colorP5Texture.glMagFilter], + colorTexture: [gl.COLOR_BUFFER_BIT, this.colorP5Texture.glMagFilter] }; if (this.useDepth) { partsToCopy.depthTexture = [ diff --git a/src/webgl/p5.Geometry.js b/src/webgl/p5.Geometry.js index d8b1f2e0b5..1efcc3d991 100644 --- a/src/webgl/p5.Geometry.js +++ b/src/webgl/p5.Geometry.js @@ -71,103 +71,103 @@ class Geometry { } /** - * Calculates the position and size of the smallest box that contains the geometry. - * - * A bounding box is the smallest rectangular prism that contains the entire - * geometry. It's defined by the box's minimum and maximum coordinates along - * each axis, as well as the size (length) and offset (center). - * - * Calling `myGeometry.calculateBoundingBox()` returns an object with four - * properties that describe the bounding box: - * - * ```js - * // Get myGeometry's bounding box. - * let bbox = myGeometry.calculateBoundingBox(); - * - * // Print the bounding box to the console. - * console.log(bbox); - * - * // { - * // // The minimum coordinate along each axis. - * // min: { x: -1, y: -2, z: -3 }, - * // - * // // The maximum coordinate along each axis. - * // max: { x: 1, y: 2, z: 3}, - * // - * // // The size (length) along each axis. - * // size: { x: 2, y: 4, z: 6}, - * // - * // // The offset (center) along each axis. - * // offset: { x: 0, y: 0, z: 0} - * // } - * ``` - * - * @returns {Object} bounding box of the geometry. - * - * @example - *
- * - * // Click and drag the mouse to view the scene from different angles. - * - * let particles; - * - * function setup() { - * createCanvas(100, 100, WEBGL); - * - * // Create a new p5.Geometry object with random spheres. - * particles = buildGeometry(createParticles); - * - * describe('Ten white spheres placed randomly against a gray background. A box encloses the spheres.'); - * } - * - * function draw() { - * background(50); - * - * // Enable orbiting with the mouse. - * orbitControl(); - * - * // Turn on the lights. - * lights(); - * - * // Style the particles. - * noStroke(); - * fill(255); - * - * // Draw the particles. - * model(particles); - * - * // Calculate the bounding box. - * let bbox = particles.calculateBoundingBox(); - * - * // Translate to the bounding box's center. - * translate(bbox.offset.x, bbox.offset.y, bbox.offset.z); - * - * // Style the bounding box. - * stroke(255); - * noFill(); - * - * // Draw the bounding box. - * box(bbox.size.x, bbox.size.y, bbox.size.z); - * } - * - * function createParticles() { - * for (let i = 0; i < 10; i += 1) { - * // Calculate random coordinates. - * let x = randomGaussian(0, 15); - * let y = randomGaussian(0, 15); - * let z = randomGaussian(0, 15); - * - * push(); - * // Translate to the particle's coordinates. - * translate(x, y, z); - * // Draw the particle. - * sphere(3); - * pop(); - * } - * } - * - *
- */ + * Calculates the position and size of the smallest box that contains the geometry. + * + * A bounding box is the smallest rectangular prism that contains the entire + * geometry. It's defined by the box's minimum and maximum coordinates along + * each axis, as well as the size (length) and offset (center). + * + * Calling `myGeometry.calculateBoundingBox()` returns an object with four + * properties that describe the bounding box: + * + * ```js + * // Get myGeometry's bounding box. + * let bbox = myGeometry.calculateBoundingBox(); + * + * // Print the bounding box to the console. + * console.log(bbox); + * + * // { + * // // The minimum coordinate along each axis. + * // min: { x: -1, y: -2, z: -3 }, + * // + * // // The maximum coordinate along each axis. + * // max: { x: 1, y: 2, z: 3}, + * // + * // // The size (length) along each axis. + * // size: { x: 2, y: 4, z: 6}, + * // + * // // The offset (center) along each axis. + * // offset: { x: 0, y: 0, z: 0} + * // } + * ``` + * + * @returns {Object} bounding box of the geometry. + * + * @example + *
+ * + * // Click and drag the mouse to view the scene from different angles. + * + * let particles; + * + * function setup() { + * createCanvas(100, 100, WEBGL); + * + * // Create a new p5.Geometry object with random spheres. + * particles = buildGeometry(createParticles); + * + * describe('Ten white spheres placed randomly against a gray background. A box encloses the spheres.'); + * } + * + * function draw() { + * background(50); + * + * // Enable orbiting with the mouse. + * orbitControl(); + * + * // Turn on the lights. + * lights(); + * + * // Style the particles. + * noStroke(); + * fill(255); + * + * // Draw the particles. + * model(particles); + * + * // Calculate the bounding box. + * let bbox = particles.calculateBoundingBox(); + * + * // Translate to the bounding box's center. + * translate(bbox.offset.x, bbox.offset.y, bbox.offset.z); + * + * // Style the bounding box. + * stroke(255); + * noFill(); + * + * // Draw the bounding box. + * box(bbox.size.x, bbox.size.y, bbox.size.z); + * } + * + * function createParticles() { + * for (let i = 0; i < 10; i += 1) { + * // Calculate random coordinates. + * let x = randomGaussian(0, 15); + * let y = randomGaussian(0, 15); + * let z = randomGaussian(0, 15); + * + * push(); + * // Translate to the particle's coordinates. + * translate(x, y, z); + * // Draw the particle. + * sphere(3); + * pop(); + * } + * } + * + *
+ */ calculateBoundingBox() { if (this.boundingBoxCache) { return this.boundingBoxCache; // Return cached result if available diff --git a/src/webgl/p5.Quat.js b/src/webgl/p5.Quat.js index 7ecb773bff..3ad8681c5b 100644 --- a/src/webgl/p5.Quat.js +++ b/src/webgl/p5.Quat.js @@ -12,16 +12,16 @@ class Quat { } /** - * Returns a Quaternion for the - * axis angle representation of the rotation - * - * @method fromAxisAngle - * @param {Number} [angle] Angle with which the points needs to be rotated - * @param {Number} [x] x component of the axis vector - * @param {Number} [y] y component of the axis vector - * @param {Number} [z] z component of the axis vector - * @chainable - */ + * Returns a Quaternion for the + * axis angle representation of the rotation + * + * @method fromAxisAngle + * @param {Number} [angle] Angle with which the points needs to be rotated + * @param {Number} [x] x component of the axis vector + * @param {Number} [y] y component of the axis vector + * @param {Number} [z] z component of the axis vector + * @chainable + */ static fromAxisAngle(angle, x, y, z) { const w = Math.cos(angle/2); const vec = new Vector(x, y, z).normalize().mult(Math.sin(angle/2)); @@ -33,20 +33,20 @@ class Quat { } /** - * Multiplies a quaternion with other quaternion. - * @method mult - * @param {p5.Quat} [quat] quaternion to multiply with the quaternion calling the method. - * @chainable - */ + * Multiplies a quaternion with other quaternion. + * @method mult + * @param {p5.Quat} [quat] quaternion to multiply with the quaternion calling the method. + * @chainable + */ multiply(quat) { - /* eslint-disable max-len */ + return new Quat( this.w * quat.w - this.vec.x * quat.vec.x - this.vec.y * quat.vec.y - this.vec.z - quat.vec.z, this.w * quat.vec.x + this.vec.x * quat.w + this.vec.y * quat.vec.z - this.vec.z * quat.vec.y, this.w * quat.vec.y - this.vec.x * quat.vec.z + this.vec.y * quat.w + this.vec.z * quat.vec.x, this.w * quat.vec.z + this.vec.x * quat.vec.y - this.vec.y * quat.vec.x + this.vec.z * quat.w ); - /* eslint-enable max-len */ + } /** @@ -65,14 +65,14 @@ class Quat { } /** - * Rotates the Quaternion by the quaternion passed - * which contains the axis of roation and angle of rotation - * - * @method rotateBy - * @param {p5.Quat} [axesQuat] axis quaternion which contains - * the axis of rotation and angle of rotation - * @chainable - */ + * Rotates the Quaternion by the quaternion passed + * which contains the axis of roation and angle of rotation + * + * @method rotateBy + * @param {p5.Quat} [axesQuat] axis quaternion which contains + * the axis of rotation and angle of rotation + * @chainable + */ rotateBy(axesQuat) { return axesQuat.multiply(this).multiply(axesQuat.conjugate()). vec.clampToZero(); diff --git a/src/webgl/p5.RenderBuffer.js b/src/webgl/p5.RenderBuffer.js index 87c80ce45b..6beaa690a5 100644 --- a/src/webgl/p5.RenderBuffer.js +++ b/src/webgl/p5.RenderBuffer.js @@ -70,6 +70,6 @@ function renderBuffer(p5, fn) { export default renderBuffer; export { RenderBuffer }; -if (typeof p5 !== "undefined") { +if (typeof p5 !== 'undefined') { renderBuffer(p5, p5.prototype); } diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js index 1304d0bb84..3705bed131 100644 --- a/src/webgl/p5.RendererGL.js +++ b/src/webgl/p5.RendererGL.js @@ -1,58 +1,58 @@ -import * as constants from "../core/constants"; -import GeometryBuilder from "./GeometryBuilder"; -import { Renderer } from "../core/p5.Renderer"; -import { Matrix } from "../math/p5.Matrix"; -import { Camera } from "./p5.Camera"; -import { Vector } from "../math/p5.Vector"; -import { RenderBuffer } from "./p5.RenderBuffer"; -import { DataArray } from "./p5.DataArray"; -import { Shader } from "./p5.Shader"; -import { Image } from "../image/p5.Image"; -import { Texture, MipmapTexture } from "./p5.Texture"; -import { Framebuffer } from "./p5.Framebuffer"; -import { Graphics } from "../core/p5.Graphics"; -import { Element } from "../dom/p5.Element"; -import { ShapeBuilder } from "./ShapeBuilder"; -import { GeometryBufferCache } from "./GeometryBufferCache"; -import { filterParamDefaults } from "../image/const"; - -import filterBaseVert from "./shaders/filters/base.vert"; -import lightingShader from "./shaders/lighting.glsl"; -import webgl2CompatibilityShader from "./shaders/webgl2Compatibility.glsl"; -import normalVert from "./shaders/normal.vert"; -import normalFrag from "./shaders/normal.frag"; -import basicFrag from "./shaders/basic.frag"; -import sphereMappingFrag from "./shaders/sphereMapping.frag"; -import lightVert from "./shaders/light.vert"; -import lightTextureFrag from "./shaders/light_texture.frag"; -import phongVert from "./shaders/phong.vert"; -import phongFrag from "./shaders/phong.frag"; -import fontVert from "./shaders/font.vert"; -import fontFrag from "./shaders/font.frag"; -import lineVert from "./shaders/line.vert"; -import lineFrag from "./shaders/line.frag"; -import pointVert from "./shaders/point.vert"; -import pointFrag from "./shaders/point.frag"; -import imageLightVert from "./shaders/imageLight.vert"; -import imageLightDiffusedFrag from "./shaders/imageLightDiffused.frag"; -import imageLightSpecularFrag from "./shaders/imageLightSpecular.frag"; - -import filterBaseFrag from "./shaders/filters/base.frag"; -import filterGrayFrag from "./shaders/filters/gray.frag"; -import filterErodeFrag from "./shaders/filters/erode.frag"; -import filterDilateFrag from "./shaders/filters/dilate.frag"; -import filterBlurFrag from "./shaders/filters/blur.frag"; -import filterPosterizeFrag from "./shaders/filters/posterize.frag"; -import filterOpaqueFrag from "./shaders/filters/opaque.frag"; -import filterInvertFrag from "./shaders/filters/invert.frag"; -import filterThresholdFrag from "./shaders/filters/threshold.frag"; -import filterShaderVert from "./shaders/filters/default.vert"; -import { PrimitiveToVerticesConverter } from "../shape/custom_shapes"; -import { Color } from "../color/p5.Color"; +import * as constants from '../core/constants'; +import GeometryBuilder from './GeometryBuilder'; +import { Renderer } from '../core/p5.Renderer'; +import { Matrix } from '../math/p5.Matrix'; +import { Camera } from './p5.Camera'; +import { Vector } from '../math/p5.Vector'; +import { RenderBuffer } from './p5.RenderBuffer'; +import { DataArray } from './p5.DataArray'; +import { Shader } from './p5.Shader'; +import { Image } from '../image/p5.Image'; +import { Texture, MipmapTexture } from './p5.Texture'; +import { Framebuffer } from './p5.Framebuffer'; +import { Graphics } from '../core/p5.Graphics'; +import { Element } from '../dom/p5.Element'; +import { ShapeBuilder } from './ShapeBuilder'; +import { GeometryBufferCache } from './GeometryBufferCache'; +import { filterParamDefaults } from '../image/const'; + +import filterBaseVert from './shaders/filters/base.vert'; +import lightingShader from './shaders/lighting.glsl'; +import webgl2CompatibilityShader from './shaders/webgl2Compatibility.glsl'; +import normalVert from './shaders/normal.vert'; +import normalFrag from './shaders/normal.frag'; +import basicFrag from './shaders/basic.frag'; +import sphereMappingFrag from './shaders/sphereMapping.frag'; +import lightVert from './shaders/light.vert'; +import lightTextureFrag from './shaders/light_texture.frag'; +import phongVert from './shaders/phong.vert'; +import phongFrag from './shaders/phong.frag'; +import fontVert from './shaders/font.vert'; +import fontFrag from './shaders/font.frag'; +import lineVert from './shaders/line.vert'; +import lineFrag from './shaders/line.frag'; +import pointVert from './shaders/point.vert'; +import pointFrag from './shaders/point.frag'; +import imageLightVert from './shaders/imageLight.vert'; +import imageLightDiffusedFrag from './shaders/imageLightDiffused.frag'; +import imageLightSpecularFrag from './shaders/imageLightSpecular.frag'; + +import filterBaseFrag from './shaders/filters/base.frag'; +import filterGrayFrag from './shaders/filters/gray.frag'; +import filterErodeFrag from './shaders/filters/erode.frag'; +import filterDilateFrag from './shaders/filters/dilate.frag'; +import filterBlurFrag from './shaders/filters/blur.frag'; +import filterPosterizeFrag from './shaders/filters/posterize.frag'; +import filterOpaqueFrag from './shaders/filters/opaque.frag'; +import filterInvertFrag from './shaders/filters/invert.frag'; +import filterThresholdFrag from './shaders/filters/threshold.frag'; +import filterShaderVert from './shaders/filters/default.vert'; +import { PrimitiveToVerticesConverter } from '../shape/custom_shapes'; +import { Color } from '../color/p5.Color'; const STROKE_CAP_ENUM = {}; const STROKE_JOIN_ENUM = {}; -let lineDefs = ""; +let lineDefs = ''; const defineStrokeCapEnum = function (key, val) { lineDefs += `#define STROKE_CAP_${key} ${val}\n`; STROKE_CAP_ENUM[constants[key]] = val; @@ -64,12 +64,12 @@ const defineStrokeJoinEnum = function (key, val) { // Define constants in line shaders for each type of cap/join, and also record // the values in JS objects -defineStrokeCapEnum("ROUND", 0); -defineStrokeCapEnum("PROJECT", 1); -defineStrokeCapEnum("SQUARE", 2); -defineStrokeJoinEnum("ROUND", 0); -defineStrokeJoinEnum("MITER", 1); -defineStrokeJoinEnum("BEVEL", 2); +defineStrokeCapEnum('ROUND', 0); +defineStrokeCapEnum('PROJECT', 1); +defineStrokeCapEnum('SQUARE', 2); +defineStrokeJoinEnum('ROUND', 0); +defineStrokeJoinEnum('MITER', 1); +defineStrokeJoinEnum('BEVEL', 2); const defaultShaders = { normalVert, @@ -90,7 +90,7 @@ const defaultShaders = { imageLightDiffusedFrag, imageLightSpecularFrag, filterBaseVert, - filterBaseFrag, + filterBaseFrag }; let sphereMapping = defaultShaders.sphereMappingFrag; for (const key in defaultShaders) { @@ -105,7 +105,7 @@ const filterShaderFrags = { [constants.POSTERIZE]: filterPosterizeFrag, [constants.OPAQUE]: filterOpaqueFrag, [constants.INVERT]: filterInvertFrag, - [constants.THRESHOLD]: filterThresholdFrag, + [constants.THRESHOLD]: filterThresholdFrag }; /** @@ -121,7 +121,7 @@ class RendererGL extends Renderer { super(pInst, w, h, isMainCanvas); // Create new canvas - this.canvas = this.elt = elt || document.createElement("canvas"); + this.canvas = this.elt = elt || document.createElement('canvas'); this._setAttributeDefaults(pInst); this._initContext(); // This redundant property is useful in reminding you that you are @@ -134,10 +134,10 @@ class RendererGL extends Renderer { this._pInst.canvas = this.canvas; } else { // hide if offscreen buffer by default - this.canvas.style.display = "none"; + this.canvas.style.display = 'none'; } - this.elt.id = "defaultCanvas0"; - this.elt.classList.add("p5Canvas"); + this.elt.id = 'defaultCanvas0'; + this.elt.classList.add('p5Canvas'); // Set and return p5.Element this.wrappedElt = new Element(this.elt, this._pInst); @@ -149,7 +149,7 @@ class RendererGL extends Renderer { get() { return this.wrappedElt[p]; } - }) + }); } } @@ -167,7 +167,7 @@ class RendererGL extends Renderer { this.elt.style.height = `${h}px`; this._origViewport = { width: this.GL.drawingBufferWidth, - height: this.GL.drawingBufferHeight, + height: this.GL.drawingBufferHeight }; this.viewport(this._origViewport.width, this._origViewport.height); @@ -177,12 +177,12 @@ class RendererGL extends Renderer { this._pInst._userNode.appendChild(this.elt); } else { //create main element - if (document.getElementsByTagName("main").length === 0) { - let m = document.createElement("main"); + if (document.getElementsByTagName('main').length === 0) { + let m = document.createElement('main'); document.body.appendChild(m); } //append canvas to main - document.getElementsByTagName("main")[0].appendChild(this.elt); + document.getElementsByTagName('main')[0].appendChild(this.elt); } this.isP3D = true; //lets us know we're in 3d mode @@ -272,7 +272,7 @@ class RendererGL extends Renderer { if (this.webglVersion === constants.WEBGL2) { this.blendExt = this.GL; } else { - this.blendExt = this.GL.getExtension("EXT_blend_minmax"); + this.blendExt = this.GL.getExtension('EXT_blend_minmax'); } this._isBlending = false; @@ -327,84 +327,84 @@ class RendererGL extends Renderer { fill: [ new RenderBuffer( 3, - "vertices", - "vertexBuffer", - "aPosition", + 'vertices', + 'vertexBuffer', + 'aPosition', this, this._vToNArray ), new RenderBuffer( 3, - "vertexNormals", - "normalBuffer", - "aNormal", + 'vertexNormals', + 'normalBuffer', + 'aNormal', this, this._vToNArray ), new RenderBuffer( 4, - "vertexColors", - "colorBuffer", - "aVertexColor", + 'vertexColors', + 'colorBuffer', + 'aVertexColor', this ), new RenderBuffer( 3, - "vertexAmbients", - "ambientBuffer", - "aAmbientColor", + 'vertexAmbients', + 'ambientBuffer', + 'aAmbientColor', this ), - new RenderBuffer(2, "uvs", "uvBuffer", "aTexCoord", this, (arr) => + new RenderBuffer(2, 'uvs', 'uvBuffer', 'aTexCoord', this, arr => arr.flat() - ), + ) ], stroke: [ new RenderBuffer( 4, - "lineVertexColors", - "lineColorBuffer", - "aVertexColor", + 'lineVertexColors', + 'lineColorBuffer', + 'aVertexColor', this ), new RenderBuffer( 3, - "lineVertices", - "lineVerticesBuffer", - "aPosition", + 'lineVertices', + 'lineVerticesBuffer', + 'aPosition', this ), new RenderBuffer( 3, - "lineTangentsIn", - "lineTangentsInBuffer", - "aTangentIn", + 'lineTangentsIn', + 'lineTangentsInBuffer', + 'aTangentIn', this ), new RenderBuffer( 3, - "lineTangentsOut", - "lineTangentsOutBuffer", - "aTangentOut", + 'lineTangentsOut', + 'lineTangentsOutBuffer', + 'aTangentOut', this ), - new RenderBuffer(1, "lineSides", "lineSidesBuffer", "aSide", this), + new RenderBuffer(1, 'lineSides', 'lineSidesBuffer', 'aSide', this) ], text: [ new RenderBuffer( 3, - "vertices", - "vertexBuffer", - "aPosition", + 'vertices', + 'vertexBuffer', + 'aPosition', this, this._vToNArray ), - new RenderBuffer(2, "uvs", "uvBuffer", "aTexCoord", this, (arr) => + new RenderBuffer(2, 'uvs', 'uvBuffer', 'aTexCoord', this, arr => arr.flat() - ), + ) ], point: this.GL.createBuffer(), - user: [], + user: [] }; this.geometryBufferCache = new GeometryBufferCache(this); @@ -439,7 +439,7 @@ class RendererGL extends Renderer { this._internalDisable = this.drawingContext.disable; // Override WebGL enable function - this.drawingContext.enable = (key) => { + this.drawingContext.enable = key => { if (key === this.drawingContext.STENCIL_TEST) { if (!this._clipping) { this._userEnabledStencil = true; @@ -449,9 +449,9 @@ class RendererGL extends Renderer { }; // Override WebGL disable function - this.drawingContext.disable = (key) => { + this.drawingContext.disable = key => { if (key === this.drawingContext.STENCIL_TEST) { - this._userEnabledStencil = false; + this._userEnabledStencil = false; } return this._internalDisable.call(this.drawingContext, key); }; @@ -487,7 +487,7 @@ class RendererGL extends Renderer { beginGeometry() { if (this.geometryBuilder) { throw new Error( - "It looks like `beginGeometry()` is being called while another p5.Geometry is already being build." + 'It looks like `beginGeometry()` is being called while another p5.Geometry is already being build.' ); } this.geometryBuilder = new GeometryBuilder(this); @@ -507,7 +507,7 @@ class RendererGL extends Renderer { endGeometry() { if (!this.geometryBuilder) { throw new Error( - "Make sure you call beginGeometry() before endGeometry()!" + 'Make sure you call beginGeometry() before endGeometry()!' ); } const geometry = this.geometryBuilder.finish(); @@ -552,13 +552,13 @@ class RendererGL extends Renderer { if (d === undefined) { return this.states.curveDetail; } else { - this.states.setValue("curveDetail", d); + this.states.setValue('curveDetail', d); } } drawShape(shape) { const visitor = new PrimitiveToVerticesConverter({ - curveDetail: this.states.curveDetail, + curveDetail: this.states.curveDetail }); shape.accept(visitor); this.shapeBuilder.constructFromContours(shape, visitor.contours); @@ -578,7 +578,7 @@ class RendererGL extends Renderer { } else { this._drawGeometry(this.shapeBuilder.geometry, { mode: this.shapeBuilder.shapeMode, - count: this.drawShapeCount, + count: this.drawShapeCount }); } } @@ -596,9 +596,9 @@ class RendererGL extends Renderer { normal(xorv, y, z) { if (xorv instanceof Vector) { - this.states.setValue("_currentNormal", xorv); + this.states.setValue('_currentNormal', xorv); } else { - this.states.setValue("_currentNormal", new Vector(xorv, y, z)); + this.states.setValue('_currentNormal', new Vector(xorv, y, z)); } this.updateShapeVertexProperties(); } @@ -653,7 +653,7 @@ class RendererGL extends Renderer { _drawGeometryScaled(model, scaleX, scaleY, scaleZ) { let originalModelMatrix = this.states.uModelMatrix; - this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone()); + this.states.setValue('uModelMatrix', this.states.uModelMatrix.clone()); try { this.states.uModelMatrix.scale(scaleX, scaleY, scaleZ); @@ -663,7 +663,7 @@ class RendererGL extends Renderer { this._drawGeometry(model); } } finally { - this.states.setValue("uModelMatrix", originalModelMatrix); + this.states.setValue('uModelMatrix', originalModelMatrix); } } @@ -729,7 +729,7 @@ class RendererGL extends Renderer { ); } catch (e) { console.log( - "🌸 p5.js says: Instancing is only supported in WebGL2 mode" + '🌸 p5.js says: Instancing is only supported in WebGL2 mode' ); } } @@ -772,12 +772,12 @@ class RendererGL extends Renderer { if (adjustedLength > geometry.vertices.length) { this._pInst.constructor._friendlyError( `One of the geometries has a custom vertex property '${prop.getName()}' with more values than vertices. This is probably caused by directly using the Geometry.vertexProperty() method.`, - "vertexProperty()" + 'vertexProperty()' ); } else if (adjustedLength < geometry.vertices.length) { this._pInst.constructor._friendlyError( `One of the geometries has a custom vertex property '${prop.getName()}' with fewer values than vertices. This is probably caused by directly using the Geometry.vertexProperty() method.`, - "vertexProperty()" + 'vertexProperty()' ); } } @@ -801,9 +801,9 @@ class RendererGL extends Renderer { this._pInst.webglVersion !== constants.WEBGL2 && glBuffers.indexBufferType === gl.UNSIGNED_INT ) { - if (!gl.getExtension("OES_element_index_uint")) { + if (!gl.getExtension('OES_element_index_uint')) { throw new Error( - "Unable to render a 3d model with > 65535 triangles. Your web browser does not support the WebGL Extension OES_element_index_uint." + 'Unable to render a 3d model with > 65535 triangles. Your web browser does not support the WebGL Extension OES_element_index_uint.' ); } } @@ -826,7 +826,7 @@ class RendererGL extends Renderer { ); } catch (e) { console.log( - "🌸 p5.js says: Instancing is only supported in WebGL2 mode" + '🌸 p5.js says: Instancing is only supported in WebGL2 mode' ); } } @@ -838,7 +838,7 @@ class RendererGL extends Renderer { gl.drawArraysInstanced(mode, 0, geometry.vertices.length, count); } catch (e) { console.log( - "🌸 p5.js says: Instancing is only supported in WebGL2 mode" + '🌸 p5.js says: Instancing is only supported in WebGL2 mode' ); } } @@ -855,7 +855,7 @@ class RendererGL extends Renderer { _setAttributeDefaults(pInst) { // See issue #3850, safer to enable AA in Safari - const applyAA = navigator.userAgent.toLowerCase().includes("safari"); + const applyAA = navigator.userAgent.toLowerCase().includes('safari'); const defaults = { alpha: true, depth: true, @@ -864,7 +864,7 @@ class RendererGL extends Renderer { premultipliedAlpha: true, preserveDrawingBuffer: true, perPixelLighting: true, - version: 2, + version: 2 }; if (pInst._glAttributes === null) { pInst._glAttributes = defaults; @@ -878,7 +878,7 @@ class RendererGL extends Renderer { if (this._pInst._glAttributes?.version !== 1) { // Unless WebGL1 is explicitly asked for, try to create a WebGL2 context this.drawingContext = this.canvas.getContext( - "webgl2", + 'webgl2', this._pInst._glAttributes ); } @@ -892,11 +892,11 @@ class RendererGL extends Renderer { // disabled via `setAttributes({ version: 1 })` or because the device // doesn't support it), fall back to a WebGL1 context this.drawingContext = - this.canvas.getContext("webgl", this._pInst._glAttributes) || - this.canvas.getContext("experimental-webgl", this._pInst._glAttributes); + this.canvas.getContext('webgl', this._pInst._glAttributes) || + this.canvas.getContext('experimental-webgl', this._pInst._glAttributes); } if (this.drawingContext === null) { - throw new Error("Error creating webgl context"); + throw new Error('Error creating webgl context'); } else { const gl = this.drawingContext; gl.enable(gl.DEPTH_TEST); @@ -931,7 +931,7 @@ class RendererGL extends Renderer { if (adjustedWidth !== width || adjustedHeight !== height) { console.warn( - "Warning: The requested width/height exceeds hardware limits. " + + 'Warning: The requested width/height exceeds hardware limits. ' + `Adjusting dimensions to width: ${adjustedWidth}, height: ${adjustedHeight}.` ); } @@ -952,14 +952,14 @@ class RendererGL extends Renderer { const prevStyle = { position: this.canvas.style.position, top: this.canvas.style.top, - left: this.canvas.style.left, + left: this.canvas.style.left }; if (isPGraphics) { // Handle PGraphics: remove and recreate the canvas const pg = this._pInst; pg.canvas.parentNode.removeChild(pg.canvas); - pg.canvas = document.createElement("canvas"); + pg.canvas = document.createElement('canvas'); const node = pg._pInst._userNode || document.body; node.appendChild(pg.canvas); Element.call(pg, pg.canvas, pg._pInst); @@ -972,7 +972,7 @@ class RendererGL extends Renderer { if (c) { c.parentNode.removeChild(c); } - c = document.createElement("canvas"); + c = document.createElement('canvas'); c.id = defaultId; // Attach the new canvas to the correct parent node if (this._pInst._userNode) { @@ -1000,7 +1000,7 @@ class RendererGL extends Renderer { renderer._applyDefaults(); - if (typeof callback === "function") { + if (typeof callback === 'function') { //setTimeout with 0 forces the task to the back of the queue, this ensures that //we finish switching out the renderer setTimeout(() => { @@ -1012,35 +1012,35 @@ class RendererGL extends Renderer { _update() { // reset model view and apply initial camera transform // (containing only look at info; no projection). - this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone()); + this.states.setValue('uModelMatrix', this.states.uModelMatrix.clone()); this.states.uModelMatrix.reset(); - this.states.setValue("uViewMatrix", this.states.uViewMatrix.clone()); + this.states.setValue('uViewMatrix', this.states.uViewMatrix.clone()); this.states.uViewMatrix.set(this.states.curCamera.cameraMatrix); // reset light data for new frame. - this.states.setValue("ambientLightColors", []); - this.states.setValue("specularColors", [1, 1, 1]); + this.states.setValue('ambientLightColors', []); + this.states.setValue('specularColors', [1, 1, 1]); - this.states.setValue("directionalLightDirections", []); - this.states.setValue("directionalLightDiffuseColors", []); - this.states.setValue("directionalLightSpecularColors", []); + this.states.setValue('directionalLightDirections', []); + this.states.setValue('directionalLightDiffuseColors', []); + this.states.setValue('directionalLightSpecularColors', []); - this.states.setValue("pointLightPositions", []); - this.states.setValue("pointLightDiffuseColors", []); - this.states.setValue("pointLightSpecularColors", []); + this.states.setValue('pointLightPositions', []); + this.states.setValue('pointLightDiffuseColors', []); + this.states.setValue('pointLightSpecularColors', []); - this.states.setValue("spotLightPositions", []); - this.states.setValue("spotLightDirections", []); - this.states.setValue("spotLightDiffuseColors", []); - this.states.setValue("spotLightSpecularColors", []); - this.states.setValue("spotLightAngle", []); - this.states.setValue("spotLightConc", []); + this.states.setValue('spotLightPositions', []); + this.states.setValue('spotLightDirections', []); + this.states.setValue('spotLightDiffuseColors', []); + this.states.setValue('spotLightSpecularColors', []); + this.states.setValue('spotLightAngle', []); + this.states.setValue('spotLightConc', []); - this.states.setValue("enableLighting", false); + this.states.setValue('enableLighting', false); //reset tint value for new frame - this.states.setValue("tint", [255, 255, 255, 255]); + this.states.setValue('tint', [255, 255, 255, 255]); //Clear depth every frame this.GL.clearStencil(0); @@ -1095,7 +1095,8 @@ class RendererGL extends Renderer { const modelViewMatrix = modelMatrix.copy().mult(viewMatrix); const modelViewProjectionMatrix = modelViewMatrix.mult(projectionMatrix); - const worldToScreenMatrix = modelViewProjectionMatrix.mult(projectedToScreenMatrix); + const worldToScreenMatrix = modelViewProjectionMatrix + .mult(projectedToScreenMatrix); return worldToScreenMatrix; } @@ -1137,10 +1138,10 @@ class RendererGL extends Renderer { //see material.js for more info on color blending in webgl // const color = fn.color.apply(this._pInst, arguments); const color = this.states.fillColor; - this.states.setValue("curFillColor", color._array); - this.states.setValue("drawMode", constants.FILL); - this.states.setValue("_useNormalMaterial", false); - this.states.setValue("_tex", null); + this.states.setValue('curFillColor', color._array); + this.states.setValue('drawMode', constants.FILL); + this.states.setValue('_useNormalMaterial', false); + this.states.setValue('_tex', null); } /** @@ -1175,7 +1176,7 @@ class RendererGL extends Renderer { stroke(...args) { super.stroke(...args); // const color = fn.color.apply(this._pInst, arguments); - this.states.setValue("curStrokeColor", this.states.strokeColor._array); + this.states.setValue('curStrokeColor', this.states.strokeColor._array); } getCommonVertexProperties() { @@ -1183,13 +1184,13 @@ class RendererGL extends Renderer { ...super.getCommonVertexProperties(), stroke: this.states.strokeColor, fill: this.states.fillColor, - normal: this.states._currentNormal, + normal: this.states._currentNormal }; } getSupportedIndividualVertexProperties() { return { - textureCoordinates: true, + textureCoordinates: true }; } @@ -1230,7 +1231,7 @@ class RendererGL extends Renderer { // use internal shader for filter constants BLUR, INVERT, etc let filterParameter = undefined; let operation = undefined; - if (typeof args[0] === "string") { + if (typeof args[0] === 'string') { operation = args[0]; let useDefaultParam = operation in filterParamDefaults && args[1] === undefined; @@ -1249,13 +1250,13 @@ class RendererGL extends Renderer { ); } this.states.setValue( - "filterShader", + 'filterShader', this.defaultFilterShaders[operation] ); } // use custom user-supplied shader else { - this.states.setValue("filterShader", args[0]); + this.states.setValue('filterShader', args[0]); } // Setting the target to the framebuffer when applying a filter to a framebuffer. @@ -1269,7 +1270,7 @@ class RendererGL extends Renderer { let texelSize = [ 1 / (target.width * target.pixelDensity()), - 1 / (target.height * target.pixelDensity()), + 1 / (target.height * target.pixelDensity()) ]; // apply blur shader with multiple passes. @@ -1280,25 +1281,25 @@ class RendererGL extends Renderer { this.matchSize(tmp, target); // setup this.push(); - this.states.setValue("strokeColor", null); + this.states.setValue('strokeColor', null); this.blendMode(constants.BLEND); // draw main to temp buffer this.shader(this.states.filterShader); - this.states.filterShader.setUniform("texelSize", texelSize); - this.states.filterShader.setUniform("canvasSize", [ + this.states.filterShader.setUniform('texelSize', texelSize); + this.states.filterShader.setUniform('canvasSize', [ target.width, - target.height, + target.height ]); this.states.filterShader.setUniform( - "radius", + 'radius', Math.max(1, filterParameter) ); // Horiz pass: draw `target` to `tmp` tmp.draw(() => { - this.states.filterShader.setUniform("direction", [1, 0]); - this.states.filterShader.setUniform("tex0", target); + this.states.filterShader.setUniform('direction', [1, 0]); + this.states.filterShader.setUniform('tex0', target); this.clear(); this.shader(this.states.filterShader); this.noLights(); @@ -1307,8 +1308,8 @@ class RendererGL extends Renderer { // Vert pass: draw `tmp` to `fbo` fbo.draw(() => { - this.states.filterShader.setUniform("direction", [0, 1]); - this.states.filterShader.setUniform("tex0", tmp); + this.states.filterShader.setUniform('direction', [0, 1]); + this.states.filterShader.setUniform('tex0', tmp); this.clear(); this.shader(this.states.filterShader); this.noLights(); @@ -1320,28 +1321,28 @@ class RendererGL extends Renderer { // every other non-blur shader uses single pass else { fbo.draw(() => { - this.states.setValue("strokeColor", null); + this.states.setValue('strokeColor', null); this.blendMode(constants.BLEND); this.shader(this.states.filterShader); - this.states.filterShader.setUniform("tex0", target); - this.states.filterShader.setUniform("texelSize", texelSize); - this.states.filterShader.setUniform("canvasSize", [ + this.states.filterShader.setUniform('tex0', target); + this.states.filterShader.setUniform('texelSize', texelSize); + this.states.filterShader.setUniform('canvasSize', [ target.width, - target.height, + target.height ]); // filterParameter uniform only used for POSTERIZE, and THRESHOLD // but shouldn't hurt to always set - this.states.filterShader.setUniform("filterParameter", filterParameter); + this.states.filterShader.setUniform('filterParameter', filterParameter); this.noLights(); this.plane(target.width, target.height); }); } // draw fbo contents onto main renderer. this.push(); - this.states.setValue("strokeColor", null); + this.states.setValue('strokeColor', null); this.clear(); this.push(); - this.states.setValue("imageMode", constants.CORNER); + this.states.setValue('imageMode', constants.CORNER); this.blendMode(constants.BLEND); target.filterCamera._resize(); this.setCamera(target.filterCamera); @@ -1387,7 +1388,7 @@ class RendererGL extends Renderer { mode === constants.MULTIPLY || mode === constants.REMOVE ) - this.states.setValue("curBlendMode", mode); + this.states.setValue('curBlendMode', mode); else if ( mode === constants.BURN || mode === constants.OVERLAY || @@ -1396,7 +1397,7 @@ class RendererGL extends Renderer { mode === constants.DODGE ) { console.warn( - "BURN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, and DODGE only work for blendMode in 2D mode." + 'BURN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, and DODGE only work for blendMode in 2D mode.' ); } } @@ -1407,19 +1408,19 @@ class RendererGL extends Renderer { this._isErasing = true; this.blendMode(constants.REMOVE); this._cachedFillStyle = this.states.curFillColor.slice(); - this.states.setValue("curFillColor", [1, 1, 1, opacityFill / 255]); + this.states.setValue('curFillColor', [1, 1, 1, opacityFill / 255]); this._cachedStrokeStyle = this.states.curStrokeColor.slice(); - this.states.setValue("curStrokeColor", [1, 1, 1, opacityStroke / 255]); + this.states.setValue('curStrokeColor', [1, 1, 1, opacityStroke / 255]); } } noErase() { if (this._isErasing) { // Restore colors - this.states.setValue("curFillColor", this._cachedFillStyle.slice()); - this.states.setValue("curStrokeColor", this._cachedStrokeStyle.slice()); + this.states.setValue('curFillColor', this._cachedFillStyle.slice()); + this.states.setValue('curStrokeColor', this._cachedStrokeStyle.slice()); // Restore blend mode - this.states.setValue("curBlendMode", this.preEraseBlend); + this.states.setValue('curBlendMode', this.preEraseBlend); this.blendMode(this.preEraseBlend); // Ensure that _applyBlendMode() sets preEraseBlend back to the original blend mode this._isErasing = false; @@ -1516,8 +1517,8 @@ class RendererGL extends Renderer { //@todo_FES if (this._pInst._glAttributes.preserveDrawingBuffer !== true) { console.log( - "loadPixels only works in WebGL when preserveDrawingBuffer " + - "is true." + 'loadPixels only works in WebGL when preserveDrawingBuffer ' + + 'is true.' ); return; } @@ -1546,7 +1547,7 @@ class RendererGL extends Renderer { this.push(); this.resetMatrix(); this.clear(); - this.states.setValue("imageMode", constants.CORNER); + this.states.setValue('imageMode', constants.CORNER); this.image( fbo, 0, @@ -1575,7 +1576,7 @@ class RendererGL extends Renderer { format: constants.UNSIGNED_BYTE, useDepth: this._pInst._glAttributes.depth, depthFormat: constants.UNSIGNED_INT, - antialias: this._pInst._glAttributes.antialias, + antialias: this._pInst._glAttributes.antialias }); } return this._tempFramebuffer; @@ -1607,7 +1608,7 @@ class RendererGL extends Renderer { const props = {}; for (const key in this.drawingContext) { const val = this.drawingContext[key]; - if (typeof val !== "object" && typeof val !== "function") { + if (typeof val !== 'object' && typeof val !== 'function') { props[key] = val; } } @@ -1625,14 +1626,14 @@ class RendererGL extends Renderer { this.canvas.style.height = `${h}px`; this._origViewport = { width: this.GL.drawingBufferWidth, - height: this.GL.drawingBufferHeight, + height: this.GL.drawingBufferHeight }; this.viewport(this._origViewport.width, this._origViewport.height); this.states.curCamera._resize(); //resize pixels buffer - if (typeof this.pixels !== "undefined") { + if (typeof this.pixels !== 'undefined') { this.pixels = new Uint8Array( this.GL.drawingBufferWidth * this.GL.drawingBufferHeight * 4 ); @@ -1699,7 +1700,7 @@ class RendererGL extends Renderer { } applyMatrix(a, b, c, d, e, f) { - this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone()); + this.states.setValue('uModelMatrix', this.states.uModelMatrix.clone()); if (arguments.length === 16) { // this.states.uModelMatrix.apply(arguments); Matrix.prototype.apply.apply(this.states.uModelMatrix, arguments); @@ -1720,7 +1721,7 @@ class RendererGL extends Renderer { e, f, 0, - 1, + 1 ]); } } @@ -1740,7 +1741,7 @@ class RendererGL extends Renderer { y = x.y; x = x.x; } - this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone()); + this.states.setValue('uModelMatrix', this.states.uModelMatrix.clone()); this.states.uModelMatrix.translate([x, y, z]); return this; } @@ -1754,16 +1755,16 @@ class RendererGL extends Renderer { * @chainable */ scale(x, y, z) { - this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone()); + this.states.setValue('uModelMatrix', this.states.uModelMatrix.clone()); this.states.uModelMatrix.scale(x, y, z); return this; } rotate(rad, axis) { - if (typeof axis === "undefined") { + if (typeof axis === 'undefined') { return this.rotateZ(rad); } - this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone()); + this.states.setValue('uModelMatrix', this.states.uModelMatrix.clone()); Matrix.prototype.rotate4x4.apply(this.states.uModelMatrix, arguments); return this; } @@ -1814,9 +1815,9 @@ class RendererGL extends Renderer { } } resetMatrix() { - this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone()); + this.states.setValue('uModelMatrix', this.states.uModelMatrix.clone()); this.states.uModelMatrix.reset(); - this.states.setValue("uViewMatrix", this.states.uViewMatrix.clone()); + this.states.setValue('uViewMatrix', this.states.uViewMatrix.clone()); this.states.uViewMatrix.set(this.states.curCamera.cameraMatrix); return this; } @@ -1846,10 +1847,10 @@ class RendererGL extends Renderer { } this.scratchMat3.inverseTranspose4x4(this.states.uViewMatrix); this.scratchMat3.invert(this.scratchMat3); // uNMMatrix is 3x3 - this.sphereMapping.setUniform("uFovY", this.states.curCamera.cameraFOV); - this.sphereMapping.setUniform("uAspect", this.states.curCamera.aspectRatio); - this.sphereMapping.setUniform("uNewNormalMatrix", this.scratchMat3.mat3); - this.sphereMapping.setUniform("uEnvMap", img); + this.sphereMapping.setUniform('uFovY', this.states.curCamera.cameraFOV); + this.sphereMapping.setUniform('uAspect', this.states.curCamera.aspectRatio); + this.sphereMapping.setUniform('uNewNormalMatrix', this.scratchMat3.mat3); + this.sphereMapping.setUniform('uEnvMap', img); return this.sphereMapping; } @@ -1896,7 +1897,7 @@ class RendererGL extends Renderer { baseMaterialShader() { if (!this._pInst._glAttributes.perPixelLighting) { throw new Error( - "The material shader does not support hooks without perPixelLighting. Try turning it back on." + 'The material shader does not support hooks without perPixelLighting. Try turning it back on.' ); } return this._getLightShader(); @@ -1907,22 +1908,22 @@ class RendererGL extends Renderer { if (this._pInst._glAttributes.perPixelLighting) { this._defaultLightShader = new Shader( this, - this._webGL2CompatibilityPrefix("vert", "highp") + + this._webGL2CompatibilityPrefix('vert', 'highp') + defaultShaders.phongVert, - this._webGL2CompatibilityPrefix("frag", "highp") + + this._webGL2CompatibilityPrefix('frag', 'highp') + defaultShaders.phongFrag, { vertex: { - "void beforeVertex": "() {}", - "Vertex getObjectInputs": "(Vertex inputs) { return inputs; }", - "Vertex getWorldInputs": "(Vertex inputs) { return inputs; }", - "Vertex getCameraInputs": "(Vertex inputs) { return inputs; }", - "void afterVertex": "() {}", + 'void beforeVertex': '() {}', + 'Vertex getObjectInputs': '(Vertex inputs) { return inputs; }', + 'Vertex getWorldInputs': '(Vertex inputs) { return inputs; }', + 'Vertex getCameraInputs': '(Vertex inputs) { return inputs; }', + 'void afterVertex': '() {}' }, fragment: { - "void beforeFragment": "() {}", - "Inputs getPixelInputs": "(Inputs inputs) { return inputs; }", - "vec4 combineColors": `(ColorComponents components) { + 'void beforeFragment': '() {}', + 'Inputs getPixelInputs': '(Inputs inputs) { return inputs; }', + 'vec4 combineColors': `(ColorComponents components) { vec4 color = vec4(0.); color.rgb += components.diffuse * components.baseColor; color.rgb += components.ambient * components.ambientColor; @@ -1931,17 +1932,17 @@ class RendererGL extends Renderer { color.a = components.opacity; return color; }`, - "vec4 getFinalColor": "(vec4 color) { return color; }", - "void afterFragment": "() {}", - }, + 'vec4 getFinalColor': '(vec4 color) { return color; }', + 'void afterFragment': '() {}' + } } ); } else { this._defaultLightShader = new Shader( this, - this._webGL2CompatibilityPrefix("vert", "highp") + + this._webGL2CompatibilityPrefix('vert', 'highp') + defaultShaders.lightVert, - this._webGL2CompatibilityPrefix("frag", "highp") + + this._webGL2CompatibilityPrefix('frag', 'highp') + defaultShaders.lightTextureFrag ); } @@ -1958,23 +1959,23 @@ class RendererGL extends Renderer { if (!this._defaultNormalShader) { this._defaultNormalShader = new Shader( this, - this._webGL2CompatibilityPrefix("vert", "mediump") + + this._webGL2CompatibilityPrefix('vert', 'mediump') + defaultShaders.normalVert, - this._webGL2CompatibilityPrefix("frag", "mediump") + + this._webGL2CompatibilityPrefix('frag', 'mediump') + defaultShaders.normalFrag, { vertex: { - "void beforeVertex": "() {}", - "Vertex getObjectInputs": "(Vertex inputs) { return inputs; }", - "Vertex getWorldInputs": "(Vertex inputs) { return inputs; }", - "Vertex getCameraInputs": "(Vertex inputs) { return inputs; }", - "void afterVertex": "() {}", + 'void beforeVertex': '() {}', + 'Vertex getObjectInputs': '(Vertex inputs) { return inputs; }', + 'Vertex getWorldInputs': '(Vertex inputs) { return inputs; }', + 'Vertex getCameraInputs': '(Vertex inputs) { return inputs; }', + 'void afterVertex': '() {}' }, fragment: { - "void beforeFragment": "() {}", - "vec4 getFinalColor": "(vec4 color) { return color; }", - "void afterFragment": "() {}", - }, + 'void beforeFragment': '() {}', + 'vec4 getFinalColor': '(vec4 color) { return color; }', + 'void afterFragment': '() {}' + } } ); } @@ -1990,23 +1991,23 @@ class RendererGL extends Renderer { if (!this._defaultColorShader) { this._defaultColorShader = new Shader( this, - this._webGL2CompatibilityPrefix("vert", "mediump") + + this._webGL2CompatibilityPrefix('vert', 'mediump') + defaultShaders.normalVert, - this._webGL2CompatibilityPrefix("frag", "mediump") + + this._webGL2CompatibilityPrefix('frag', 'mediump') + defaultShaders.basicFrag, { vertex: { - "void beforeVertex": "() {}", - "Vertex getObjectInputs": "(Vertex inputs) { return inputs; }", - "Vertex getWorldInputs": "(Vertex inputs) { return inputs; }", - "Vertex getCameraInputs": "(Vertex inputs) { return inputs; }", - "void afterVertex": "() {}", + 'void beforeVertex': '() {}', + 'Vertex getObjectInputs': '(Vertex inputs) { return inputs; }', + 'Vertex getWorldInputs': '(Vertex inputs) { return inputs; }', + 'Vertex getCameraInputs': '(Vertex inputs) { return inputs; }', + 'void afterVertex': '() {}' }, fragment: { - "void beforeFragment": "() {}", - "vec4 getFinalColor": "(vec4 color) { return color; }", - "void afterFragment": "() {}", - }, + 'void beforeFragment': '() {}', + 'vec4 getFinalColor': '(vec4 color) { return color; }', + 'void afterFragment': '() {}' + } } ); } @@ -2046,24 +2047,24 @@ class RendererGL extends Renderer { if (!this._defaultPointShader) { this._defaultPointShader = new Shader( this, - this._webGL2CompatibilityPrefix("vert", "mediump") + + this._webGL2CompatibilityPrefix('vert', 'mediump') + defaultShaders.pointVert, - this._webGL2CompatibilityPrefix("frag", "mediump") + + this._webGL2CompatibilityPrefix('frag', 'mediump') + defaultShaders.pointFrag, { vertex: { - "void beforeVertex": "() {}", - "vec3 getLocalPosition": "(vec3 position) { return position; }", - "vec3 getWorldPosition": "(vec3 position) { return position; }", - "float getPointSize": "(float size) { return size; }", - "void afterVertex": "() {}", + 'void beforeVertex': '() {}', + 'vec3 getLocalPosition': '(vec3 position) { return position; }', + 'vec3 getWorldPosition': '(vec3 position) { return position; }', + 'float getPointSize': '(float size) { return size; }', + 'void afterVertex': '() {}' }, fragment: { - "void beforeFragment": "() {}", - "vec4 getFinalColor": "(vec4 color) { return color; }", - "bool shouldDiscard": "(bool outside) { return outside; }", - "void afterFragment": "() {}", - }, + 'void beforeFragment': '() {}', + 'vec4 getFinalColor': '(vec4 color) { return color; }', + 'bool shouldDiscard': '(bool outside) { return outside; }', + 'void afterFragment': '() {}' + } } ); } @@ -2078,28 +2079,28 @@ class RendererGL extends Renderer { if (!this._defaultLineShader) { this._defaultLineShader = new Shader( this, - this._webGL2CompatibilityPrefix("vert", "mediump") + + this._webGL2CompatibilityPrefix('vert', 'mediump') + defaultShaders.lineVert, - this._webGL2CompatibilityPrefix("frag", "mediump") + + this._webGL2CompatibilityPrefix('frag', 'mediump') + defaultShaders.lineFrag, { vertex: { - "void beforeVertex": "() {}", - "StrokeVertex getObjectInputs": - "(StrokeVertex inputs) { return inputs; }", - "StrokeVertex getWorldInputs": - "(StrokeVertex inputs) { return inputs; }", - "StrokeVertex getCameraInputs": - "(StrokeVertex inputs) { return inputs; }", - "void afterVertex": "() {}", + 'void beforeVertex': '() {}', + 'StrokeVertex getObjectInputs': + '(StrokeVertex inputs) { return inputs; }', + 'StrokeVertex getWorldInputs': + '(StrokeVertex inputs) { return inputs; }', + 'StrokeVertex getCameraInputs': + '(StrokeVertex inputs) { return inputs; }', + 'void afterVertex': '() {}' }, fragment: { - "void beforeFragment": "() {}", - "Inputs getPixelInputs": "(Inputs inputs) { return inputs; }", - "vec4 getFinalColor": "(vec4 color) { return color; }", - "bool shouldDiscard": "(bool outside) { return outside; }", - "void afterFragment": "() {}", - }, + 'void beforeFragment': '() {}', + 'Inputs getPixelInputs': '(Inputs inputs) { return inputs; }', + 'vec4 getFinalColor': '(vec4 color) { return color; }', + 'bool shouldDiscard': '(bool outside) { return outside; }', + 'void afterFragment': '() {}' + } } ); } @@ -2110,13 +2111,13 @@ class RendererGL extends Renderer { _getFontShader() { if (!this._defaultFontShader) { if (this.webglVersion === constants.WEBGL) { - this.GL.getExtension("OES_standard_derivatives"); + this.GL.getExtension('OES_standard_derivatives'); } this._defaultFontShader = new Shader( this, - this._webGL2CompatibilityPrefix("vert", "highp") + + this._webGL2CompatibilityPrefix('vert', 'highp') + defaultShaders.fontVert, - this._webGL2CompatibilityPrefix("frag", "highp") + + this._webGL2CompatibilityPrefix('frag', 'highp') + defaultShaders.fontFrag ); } @@ -2127,32 +2128,32 @@ class RendererGL extends Renderer { if (!this._baseFilterShader) { this._baseFilterShader = new Shader( this, - this._webGL2CompatibilityPrefix("vert", "highp") + + this._webGL2CompatibilityPrefix('vert', 'highp') + defaultShaders.filterBaseVert, - this._webGL2CompatibilityPrefix("frag", "highp") + + this._webGL2CompatibilityPrefix('frag', 'highp') + defaultShaders.filterBaseFrag, { - vertex: {}, - fragment: { - "vec4 getColor": `(FilterInputs inputs, in sampler2D canvasContent) { + vertex: {}, + fragment: { + 'vec4 getColor': `(FilterInputs inputs, in sampler2D canvasContent) { return getTexture(canvasContent, inputs.texCoord); - }`, - }, + }` } + } ); } return this._baseFilterShader; } _webGL2CompatibilityPrefix(shaderType, floatPrecision) { - let code = ""; + let code = ''; if (this.webglVersion === constants.WEBGL2) { - code += "#version 300 es\n#define WEBGL2\n"; + code += '#version 300 es\n#define WEBGL2\n'; } - if (shaderType === "vert") { - code += "#define VERTEX_SHADER\n"; - } else if (shaderType === "frag") { - code += "#define FRAGMENT_SHADER\n"; + if (shaderType === 'vert') { + code += '#define VERTEX_SHADER\n'; + } else if (shaderType === 'frag') { + code += '#define FRAGMENT_SHADER\n'; } if (floatPrecision) { code += `precision ${floatPrecision} float;\n`; @@ -2212,7 +2213,7 @@ class RendererGL extends Renderer { newFramebuffer = new Framebuffer(this, { width, height, - density: 1, + density: 1 }); // create framebuffer is like making a new sketch, all functions on main // sketch it would be available on framebuffer @@ -2224,8 +2225,8 @@ class RendererGL extends Renderer { } newFramebuffer.draw(() => { this.shader(this.diffusedShader); - this.diffusedShader.setUniform("environmentMap", input); - this.states.setValue("strokeColor", null); + this.diffusedShader.setUniform('environmentMap', input); + this.states.setValue('strokeColor', null); this.noLights(); this.plane(width, height); }); @@ -2255,7 +2256,7 @@ class RendererGL extends Renderer { const framebuffer = new Framebuffer(this, { width: size, height: size, - density: 1, + density: 1 }); let count = Math.log(size) / Math.log(2); if (!this.specularShader) { @@ -2276,9 +2277,9 @@ class RendererGL extends Renderer { framebuffer.draw(() => { this.shader(this.specularShader); this.clear(); - this.specularShader.setUniform("environmentMap", input); - this.specularShader.setUniform("roughness", roughness); - this.states.setValue("strokeColor", null); + this.specularShader.setUniform('environmentMap', input); + this.specularShader.setUniform('roughness', roughness); + this.states.setValue('strokeColor', null); this.noLights(); this.plane(w, w); }); @@ -2311,49 +2312,49 @@ class RendererGL extends Renderer { const modelViewMatrix = modelMatrix.copy().mult(viewMatrix); shader.setUniform( - "uPerspective", + 'uPerspective', this.states.curCamera.useLinePerspective ? 1 : 0 ); - shader.setUniform("uViewMatrix", viewMatrix.mat4); - shader.setUniform("uProjectionMatrix", projectionMatrix.mat4); - shader.setUniform("uModelMatrix", modelMatrix.mat4); - shader.setUniform("uModelViewMatrix", modelViewMatrix.mat4); + shader.setUniform('uViewMatrix', viewMatrix.mat4); + shader.setUniform('uProjectionMatrix', projectionMatrix.mat4); + shader.setUniform('uModelMatrix', modelMatrix.mat4); + shader.setUniform('uModelViewMatrix', modelViewMatrix.mat4); if (shader.uniforms.uModelViewProjectionMatrix) { const modelViewProjectionMatrix = modelViewMatrix.copy(); modelViewProjectionMatrix.mult(projectionMatrix); shader.setUniform( - "uModelViewProjectionMatrix", + 'uModelViewProjectionMatrix', modelViewProjectionMatrix.mat4 ); } if (shader.uniforms.uNormalMatrix) { this.scratchMat3.inverseTranspose4x4(modelViewMatrix); - shader.setUniform("uNormalMatrix", this.scratchMat3.mat3); + shader.setUniform('uNormalMatrix', this.scratchMat3.mat3); } if (shader.uniforms.uModelNormalMatrix) { this.scratchMat3.inverseTranspose4x4(this.states.uModelMatrix); - shader.setUniform("uModelNormalMatrix", this.scratchMat3.mat3); + shader.setUniform('uModelNormalMatrix', this.scratchMat3.mat3); } if (shader.uniforms.uCameraNormalMatrix) { this.scratchMat3.inverseTranspose4x4(this.states.uViewMatrix); - shader.setUniform("uCameraNormalMatrix", this.scratchMat3.mat3); + shader.setUniform('uCameraNormalMatrix', this.scratchMat3.mat3); } if (shader.uniforms.uCameraRotation) { this.scratchMat3.inverseTranspose4x4(this.states.uViewMatrix); - shader.setUniform("uCameraRotation", this.scratchMat3.mat3); + shader.setUniform('uCameraRotation', this.scratchMat3.mat3); } - shader.setUniform("uViewport", this._viewport); + shader.setUniform('uViewport', this._viewport); } _setStrokeUniforms(strokeShader) { // set the uniform values - strokeShader.setUniform("uSimpleLines", this._simpleLines); - strokeShader.setUniform("uUseLineColor", this._useLineColor); - strokeShader.setUniform("uMaterialColor", this.states.curStrokeColor); - strokeShader.setUniform("uStrokeWeight", this.states.strokeWeight); - strokeShader.setUniform("uStrokeCap", STROKE_CAP_ENUM[this.curStrokeCap]); + strokeShader.setUniform('uSimpleLines', this._simpleLines); + strokeShader.setUniform('uUseLineColor', this._useLineColor); + strokeShader.setUniform('uMaterialColor', this.states.curStrokeColor); + strokeShader.setUniform('uStrokeWeight', this.states.strokeWeight); + strokeShader.setUniform('uStrokeCap', STROKE_CAP_ENUM[this.curStrokeCap]); strokeShader.setUniform( - "uStrokeJoin", + 'uStrokeJoin', STROKE_JOIN_ENUM[this.curStrokeJoin] ); } @@ -2371,58 +2372,58 @@ class RendererGL extends Renderer { } // TODO: optimize - fillShader.setUniform("uUseVertexColor", this._useVertexColor); - fillShader.setUniform("uMaterialColor", this.states.curFillColor); - fillShader.setUniform("isTexture", !!this.states._tex); + fillShader.setUniform('uUseVertexColor', this._useVertexColor); + fillShader.setUniform('uMaterialColor', this.states.curFillColor); + fillShader.setUniform('isTexture', !!this.states._tex); // We need to explicitly set uSampler back to an empty texture here. // In general, we record the last set texture so we can re-apply it // the next time a shader is used. However, the texture() function // 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("uHasSetAmbient", this.states._hasSetAmbient); - fillShader.setUniform("uAmbientMatColor", this.states.curAmbientColor); - fillShader.setUniform("uSpecularMatColor", this.mixedSpecularColor); - fillShader.setUniform("uEmissiveMatColor", this.states.curEmissiveColor); - fillShader.setUniform("uSpecular", this.states._useSpecularMaterial); - fillShader.setUniform("uEmissive", this.states._useEmissiveMaterial); - fillShader.setUniform("uShininess", this.states._useShininess); - fillShader.setUniform("uMetallic", this.states._useMetalness); + fillShader.setUniform('uSampler', this.states._tex || empty); + fillShader.setUniform('uTint', this.states.tint); + + fillShader.setUniform('uHasSetAmbient', this.states._hasSetAmbient); + fillShader.setUniform('uAmbientMatColor', this.states.curAmbientColor); + fillShader.setUniform('uSpecularMatColor', this.mixedSpecularColor); + fillShader.setUniform('uEmissiveMatColor', this.states.curEmissiveColor); + fillShader.setUniform('uSpecular', this.states._useSpecularMaterial); + fillShader.setUniform('uEmissive', this.states._useEmissiveMaterial); + fillShader.setUniform('uShininess', this.states._useShininess); + fillShader.setUniform('uMetallic', this.states._useMetalness); this._setImageLightUniforms(fillShader); - fillShader.setUniform("uUseLighting", this.states.enableLighting); + fillShader.setUniform('uUseLighting', this.states.enableLighting); const pointLightCount = this.states.pointLightDiffuseColors.length / 3; - fillShader.setUniform("uPointLightCount", pointLightCount); + fillShader.setUniform('uPointLightCount', pointLightCount); fillShader.setUniform( - "uPointLightLocation", + 'uPointLightLocation', this.states.pointLightPositions ); fillShader.setUniform( - "uPointLightDiffuseColors", + 'uPointLightDiffuseColors', this.states.pointLightDiffuseColors ); fillShader.setUniform( - "uPointLightSpecularColors", + 'uPointLightSpecularColors', this.states.pointLightSpecularColors ); const directionalLightCount = this.states.directionalLightDiffuseColors.length / 3; - fillShader.setUniform("uDirectionalLightCount", directionalLightCount); + fillShader.setUniform('uDirectionalLightCount', directionalLightCount); fillShader.setUniform( - "uLightingDirection", + 'uLightingDirection', this.states.directionalLightDirections ); fillShader.setUniform( - "uDirectionalDiffuseColors", + 'uDirectionalDiffuseColors', this.states.directionalLightDiffuseColors ); fillShader.setUniform( - "uDirectionalSpecularColors", + 'uDirectionalSpecularColors', this.states.directionalLightSpecularColors ); @@ -2431,39 +2432,39 @@ class RendererGL extends Renderer { this.mixedAmbientLight = [...this.states.ambientLightColors]; if (this.states._useMetalness > 0) { - this.mixedAmbientLight = this.mixedAmbientLight.map((ambientColors) => { + this.mixedAmbientLight = this.mixedAmbientLight.map(ambientColors => { let mixing = ambientColors - this.states._useMetalness; return Math.max(0, mixing); }); } - fillShader.setUniform("uAmbientLightCount", ambientLightCount); - fillShader.setUniform("uAmbientColor", this.mixedAmbientLight); + fillShader.setUniform('uAmbientLightCount', ambientLightCount); + fillShader.setUniform('uAmbientColor', this.mixedAmbientLight); const spotLightCount = this.states.spotLightDiffuseColors.length / 3; - fillShader.setUniform("uSpotLightCount", spotLightCount); - fillShader.setUniform("uSpotLightAngle", this.states.spotLightAngle); - fillShader.setUniform("uSpotLightConc", this.states.spotLightConc); + fillShader.setUniform('uSpotLightCount', spotLightCount); + fillShader.setUniform('uSpotLightAngle', this.states.spotLightAngle); + fillShader.setUniform('uSpotLightConc', this.states.spotLightConc); fillShader.setUniform( - "uSpotLightDiffuseColors", + 'uSpotLightDiffuseColors', this.states.spotLightDiffuseColors ); fillShader.setUniform( - "uSpotLightSpecularColors", + 'uSpotLightSpecularColors', this.states.spotLightSpecularColors ); - fillShader.setUniform("uSpotLightLocation", this.states.spotLightPositions); + fillShader.setUniform('uSpotLightLocation', this.states.spotLightPositions); fillShader.setUniform( - "uSpotLightDirection", + 'uSpotLightDirection', this.states.spotLightDirections ); fillShader.setUniform( - "uConstantAttenuation", + 'uConstantAttenuation', this.states.constantAttenuation ); - fillShader.setUniform("uLinearAttenuation", this.states.linearAttenuation); + fillShader.setUniform('uLinearAttenuation', this.states.linearAttenuation); fillShader.setUniform( - "uQuadraticAttenuation", + 'uQuadraticAttenuation', this.states.quadraticAttenuation ); } @@ -2471,26 +2472,26 @@ class RendererGL extends Renderer { // getting called from _setFillUniforms _setImageLightUniforms(shader) { //set uniform values - shader.setUniform("uUseImageLight", this.states.activeImageLight != null); + shader.setUniform('uUseImageLight', this.states.activeImageLight != null); // true if (this.states.activeImageLight) { // this.states.activeImageLight has image as a key // look up the texture from the diffusedTexture map let diffusedLight = this.getDiffusedTexture(this.states.activeImageLight); - shader.setUniform("environmentMapDiffused", diffusedLight); + shader.setUniform('environmentMapDiffused', diffusedLight); let specularLight = this.getSpecularTexture(this.states.activeImageLight); - shader.setUniform("environmentMapSpecular", specularLight); + shader.setUniform('environmentMapSpecular', specularLight); } } _setPointUniforms(pointShader) { // set the uniform values - pointShader.setUniform("uMaterialColor", this.states.curStrokeColor); + pointShader.setUniform('uMaterialColor', this.states.curStrokeColor); // @todo is there an instance where this isn't stroke weight? // should be they be same var? pointShader.setUniform( - "uPointSize", + 'uPointSize', this.states.strokeWeight * this._pixelDensity ); } @@ -2528,8 +2529,8 @@ class RendererGL extends Renderer { Float64Array, Int16Array, Uint16Array, - Uint32Array, - ].some((x) => arr instanceof x); + Uint32Array + ].some(x => arr instanceof x); } /** @@ -2541,7 +2542,7 @@ class RendererGL extends Renderer { * [1, 2, 3, 4, 5, 6] */ _vToNArray(arr) { - return arr.flatMap((item) => [item.x, item.y, item.z]); + return arr.flatMap(item => [item.x, item.y, item.z]); } } @@ -2702,15 +2703,15 @@ function rendererGL(p5, fn) { * @param {Object} obj object with key-value pairs */ fn.setAttributes = function (key, value) { - if (typeof this._glAttributes === "undefined") { + if (typeof this._glAttributes === 'undefined') { console.log( - "You are trying to use setAttributes on a p5.Graphics object " + - "that does not use a WEBGL renderer." + 'You are trying to use setAttributes on a p5.Graphics object ' + + 'that does not use a WEBGL renderer.' ); return; } let unchanged = true; - if (typeof value !== "undefined") { + if (typeof value !== 'undefined') { //first time modifying the attributes if (this._glAttributes === null) { this._glAttributes = {}; @@ -2735,8 +2736,8 @@ function rendererGL(p5, fn) { if (!this._setupDone) { if (this._renderer.geometryBufferCache.numCached() > 0) { p5._friendlyError( - "Sorry, Could not set the attributes, you need to call setAttributes() " + - "before calling the other drawing methods in setup()" + 'Sorry, Could not set the attributes, you need to call setAttributes() ' + + 'before calling the other drawing methods in setup()' ); return; } @@ -2866,6 +2867,6 @@ export function readPixelWebGL(gl, framebuffer, x, y, format, type, flipY) { export default rendererGL; export { RendererGL }; -if (typeof p5 !== "undefined") { +if (typeof p5 !== 'undefined') { rendererGL(p5, p5.prototype); } diff --git a/src/webgl/p5.Shader.js b/src/webgl/p5.Shader.js index 8bd38c8117..cecd7ae992 100644 --- a/src/webgl/p5.Shader.js +++ b/src/webgl/p5.Shader.js @@ -89,8 +89,8 @@ class Shader { type: { typeName, qualifiers: [], - properties: typeProperties, - }, + properties: typeProperties + } }); } } @@ -109,9 +109,9 @@ class Shader { type: { typeName, qualifiers, - properties, + properties } - } + }; }); return { @@ -536,10 +536,10 @@ class Shader { if (typeof IS_MINIFIED !== 'undefined') { console.error(glError); } else { - throw glError; p5._friendlyError( `Yikes! An error occurred compiling the vertex shader:${glError}` ); + throw glError; } return null; } @@ -554,10 +554,10 @@ class Shader { if (typeof IS_MINIFIED !== 'undefined') { console.error(glError); } else { - throw glError; p5._friendlyError( `Darn! An error occurred compiling the fragment shader:${glError}` ); + throw glError; } return null; } diff --git a/src/webgl/p5.Texture.js b/src/webgl/p5.Texture.js index c291d70022..17056f8106 100644 --- a/src/webgl/p5.Texture.js +++ b/src/webgl/p5.Texture.js @@ -64,7 +64,7 @@ class Texture { // used to determine if this texture might need constant updating // because it is a video or gif. this.isSrcMediaElement = false; - typeof MediaElement !== 'undefined' && obj instanceof MediaElement; + typeof MediaElement !== 'undefined' && obj instanceof MediaElement; this._videoPrevUpdateTime = 0; this.isSrcHTMLElement = typeof Element !== 'undefined' && diff --git a/src/webgl/text.js b/src/webgl/text.js index 7418e6cc52..3358466a8c 100644 --- a/src/webgl/text.js +++ b/src/webgl/text.js @@ -1,8 +1,8 @@ -import * as constants from "../core/constants"; -import { RendererGL } from "./p5.RendererGL"; -import { Vector } from "../math/p5.Vector"; -import { Geometry } from "./p5.Geometry"; -import { Font, arrayCommandsToObjects } from "../type/p5.Font"; +import * as constants from '../core/constants'; +import { RendererGL } from './p5.RendererGL'; +import { Vector } from '../math/p5.Vector'; +import { Geometry } from './p5.Geometry'; +import { Font, arrayCommandsToObjects } from '../type/p5.Font'; function text(p5, fn) { RendererGL.prototype.maxCachedGlyphs = function() { @@ -23,7 +23,7 @@ function text(p5, fn) { this._fontInfos[key] = val; return val; } - } + }; // Text/Typography (see src/type/textCore.js) /* @@ -79,7 +79,7 @@ function text(p5, fn) { findImage(space) { const imageSize = this.width * this.height; if (space > imageSize) - throw new Error("font is too complex to render in 3D"); + throw new Error('font is too complex to render in 3D'); // search through the list of images, looking for one with // anough unused space. @@ -101,15 +101,15 @@ function text(p5, fn) { } catch (err) { // for browsers that don't support ImageData constructors (ie IE11) // create an ImageData using the old method - let canvas = document.getElementsByTagName("canvas")[0]; + let canvas = document.getElementsByTagName('canvas')[0]; const created = !canvas; if (!canvas) { // create a temporary canvas - canvas = document.createElement("canvas"); - canvas.style.display = "none"; + canvas = document.createElement('canvas'); + canvas.style.display = 'none'; document.body.appendChild(canvas); } - const ctx = canvas.getContext("2d"); + const ctx = canvas.getContext('2d'); if (ctx) { imageData = ctx.createImageData(this.width, this.height); } @@ -166,7 +166,7 @@ function text(p5, fn) { // the bezier curve coordinates this.strokeImageInfos = new ImageInfos( strokeImageWidth, - strokeImageHeight, + strokeImageHeight ); // lists of curve indices for each row/column slice this.colDimImageInfos = new ImageInfos(gridImageWidth, gridImageHeight); @@ -193,8 +193,8 @@ function text(p5, fn) { const axs = this.axs; const { glyph: { - path: { commands }, - }, + path: { commands } + } } = this.font._singleShapeToPath(glyph.shape, { axs }); let xMin = Infinity; let xMax = -Infinity; @@ -269,22 +269,22 @@ function text(p5, fn) { const mmX = minMax(xs, 1, 0); const ixMin = Math.max( Math.floor(mmX.min * charGridWidth - cellOffset), - 0, + 0 ); const ixMax = Math.min( Math.ceil(mmX.max * charGridWidth + cellOffset), - charGridWidth, + charGridWidth ); for (let iCol = ixMin; iCol < ixMax; ++iCol) cols[iCol].push(index); const mmY = minMax(ys, 1, 0); const iyMin = Math.max( Math.floor(mmY.min * charGridHeight - cellOffset), - 0, + 0 ); const iyMax = Math.min( Math.ceil(mmY.max * charGridHeight + cellOffset), - charGridHeight, + charGridHeight ); for (let iRow = iyMin; iRow < iyMax; ++iRow) rows[iRow].push(index); } @@ -343,7 +343,7 @@ function text(p5, fn) { x1: this.p1.x, y1: this.p1.y, cx: ((this.c0.x + this.c1.x) * 3 - (this.p0.x + this.p1.x)) / 4, - cy: ((this.c0.y + this.c1.y) * 3 - (this.p0.y + this.p1.y)) / 4, + cy: ((this.c0.y + this.c1.y) * 3 - (this.p0.y + this.p1.y)) / 4 }; } @@ -357,7 +357,7 @@ function text(p5, fn) { return ( Vector.sub( Vector.sub(this.p1, this.p0), - Vector.mult(Vector.sub(this.c1, this.c0), 3), + Vector.mult(Vector.sub(this.c1, this.c0), 3) ).mag() / 2 ); } @@ -395,7 +395,7 @@ function text(p5, fn) { const b = Vector.sub(Vector.sub(this.c1, this.c0), a); const c = Vector.sub( Vector.sub(Vector.sub(this.p1, this.c1), a), - Vector.mult(b, 2), + Vector.mult(b, 2) ); const cubics = []; @@ -459,7 +459,7 @@ function text(p5, fn) { new Vector(x0, y0), new Vector(cx0, cy0), new Vector(cx1, cy1), - new Vector(x1, y1), + new Vector(x1, y1) ).splitInflections(); const qs = []; // the final list of quadratics @@ -546,25 +546,25 @@ function text(p5, fn) { if (samePoint(x0, y0, x1, y1)) continue; switch (cmd.type) { - case "M": { + case 'M': { // move xs = x1; ys = y1; break; } - case "L": { + case 'L': { // line pushLine(x0, y0, x1, y1); break; } - case "Q": { + case 'Q': { // quadratic const cx = (cmd.x1 - xMin) / gWidth; const cy = (cmd.y1 - yMin) / gHeight; push([x0, x1, cx], [y0, y1, cy], { x: x0, y: y0, cx, cy }); break; } - case "Z": { + case 'Z': { // end if (!samePoint(x0, y0, xs, ys)) { // add an extra line closing the loop, if necessary @@ -575,7 +575,7 @@ function text(p5, fn) { } break; } - case "C": { + case 'C': { // cubic const cx1 = (cmd.x1 - xMin) / gWidth; const cy1 = (cmd.y1 - yMin) / gHeight; @@ -642,7 +642,7 @@ function text(p5, fn) { cellLineIndex >> 7, cellLineIndex & 0x7f, strokeCount >> 7, - strokeCount & 0x7f, + strokeCount & 0x7f ); // for each stroke index in that slice @@ -656,7 +656,7 @@ function text(p5, fn) { return { cellImageInfo, dimOffset, - dimImageInfo, + dimImageInfo }; } @@ -667,7 +667,7 @@ function text(p5, fn) { strokeImageInfo, strokes, colInfo: layout(cols, this.colDimImageInfos, this.colCellImageInfos), - rowInfo: layout(rows, this.rowDimImageInfos, this.rowCellImageInfos), + rowInfo: layout(rows, this.rowDimImageInfos, this.rowCellImageInfos) }; gi.uGridOffset = [gi.colInfo.dimOffset, gi.rowInfo.dimOffset]; return gi; @@ -675,9 +675,9 @@ function text(p5, fn) { } RendererGL.prototype._renderText = function (line, x, y, maxY, minY) { - if (!this.states.textFont || typeof this.states.textFont === "string") { + if (!this.states.textFont || typeof this.states.textFont === 'string') { console.log( - "WEBGL: you must load and set a font before drawing text. See `loadFont` and `textFont` for more details.", + 'WEBGL: you must load and set a font before drawing text. See `loadFont` and `textFont` for more details.' ); return; } @@ -687,7 +687,7 @@ function text(p5, fn) { if (!p5.Font.hasGlyphData(this.states.textFont)) { console.log( - "WEBGL: only Opentype (.otf) and Truetype (.ttf) fonts with glyph data are supported", + 'WEBGL: only Opentype (.otf) and Truetype (.ttf) fonts with glyph data are supported' ); return; } @@ -698,14 +698,14 @@ function text(p5, fn) { const doStroke = this.states.strokeColor; const drawMode = this.states.drawMode; - this.states.setValue("strokeColor", null); - this.states.setValue("drawMode", constants.TEXTURE); + this.states.setValue('strokeColor', null); + this.states.setValue('drawMode', constants.TEXTURE); // get the cached FontInfo object const { font } = this.states.textFont; if (!font) { throw new Error( - "In WebGL mode, textFont() needs to be given the result of loadFont() instead of a font family name.", + 'In WebGL mode, textFont() needs to be given the result of loadFont() instead of a font family name.' ); } const axs = font._currentAxes(this); @@ -728,10 +728,10 @@ function text(p5, fn) { if (initializeShader) { // these are constants, really. just initialize them one-time. - sh.setUniform("uGridImageSize", [gridImageWidth, gridImageHeight]); - sh.setUniform("uCellsImageSize", [cellImageWidth, cellImageHeight]); - sh.setUniform("uStrokeImageSize", [strokeImageWidth, strokeImageHeight]); - sh.setUniform("uGridSize", [charGridWidth, charGridHeight]); + sh.setUniform('uGridImageSize', [gridImageWidth, gridImageHeight]); + sh.setUniform('uCellsImageSize', [cellImageWidth, cellImageHeight]); + sh.setUniform('uStrokeImageSize', [strokeImageWidth, strokeImageHeight]); + sh.setUniform('uGridSize', [charGridWidth, charGridHeight]); } const curFillColor = this.states.fillSet @@ -741,7 +741,7 @@ function text(p5, fn) { this._setGlobalUniforms(sh); this._applyColorBlend(curFillColor); - let g = this.geometryBufferCache.getGeometryByID("glyph"); + let g = this.geometryBufferCache.getGeometryByID('glyph'); if (!g) { // create the geometry for rendering a quad g = this._textGeom = new Geometry( @@ -755,9 +755,9 @@ function text(p5, fn) { } } }, - this, + this ); - g.gid = "glyph"; + g.gid = 'glyph'; g.computeFaces().computeNormals(); this.geometryBufferCache.ensureCached(g); } @@ -768,11 +768,11 @@ function text(p5, fn) { } this._bindBuffer( this.geometryBufferCache.cache.glyph.indexBuffer, - gl.ELEMENT_ARRAY_BUFFER, + gl.ELEMENT_ARRAY_BUFFER ); // this will have to do for now... - sh.setUniform("uMaterialColor", curFillColor); + sh.setUniform('uMaterialColor', curFillColor); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); this.glyphDataCache = this.glyphDataCache || new Set(); @@ -813,14 +813,14 @@ function text(p5, fn) { } } - sh.setUniform("uSamplerStrokes", gi.strokeImageInfo.imageData); - sh.setUniform("uSamplerRowStrokes", rowInfo.cellImageInfo.imageData); - sh.setUniform("uSamplerRows", rowInfo.dimImageInfo.imageData); - sh.setUniform("uSamplerColStrokes", colInfo.cellImageInfo.imageData); - sh.setUniform("uSamplerCols", colInfo.dimImageInfo.imageData); - sh.setUniform("uGridOffset", gi.uGridOffset); - sh.setUniform("uGlyphRect", gi.uGlyphRect); - sh.setUniform("uGlyphOffset", glyph.x); + sh.setUniform('uSamplerStrokes', gi.strokeImageInfo.imageData); + sh.setUniform('uSamplerRowStrokes', rowInfo.cellImageInfo.imageData); + sh.setUniform('uSamplerRows', rowInfo.dimImageInfo.imageData); + sh.setUniform('uSamplerColStrokes', colInfo.cellImageInfo.imageData); + sh.setUniform('uSamplerCols', colInfo.dimImageInfo.imageData); + sh.setUniform('uGridOffset', gi.uGridOffset); + sh.setUniform('uGlyphRect', gi.uGlyphRect); + sh.setUniform('uGlyphOffset', glyph.x); sh.bindTextures(); // afterwards, only textures need updating @@ -832,8 +832,8 @@ function text(p5, fn) { // clean up sh.unbindShader(); - this.states.setValue("strokeColor", doStroke); - this.states.setValue("drawMode", drawMode); + this.states.setValue('strokeColor', doStroke); + this.states.setValue('drawMode', drawMode); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); this.pop(); diff --git a/test/unit/accessibility/outputs.js b/test/unit/accessibility/outputs.js index ef0f59d822..167888bf1a 100644 --- a/test/unit/accessibility/outputs.js +++ b/test/unit/accessibility/outputs.js @@ -19,8 +19,8 @@ suite('outputs', function() { }); test('should not break for webgl', async function() { - await new Promise((res) => { - new p5((p) => { + await new Promise(res => { + new p5(p => { p.setup = function() { p.createCanvas(50, 50, p.WEBGL); p.textOutput(); @@ -32,8 +32,8 @@ suite('outputs', function() { }); test('should not break for webgl', async function() { - await new Promise((res) => { - new p5((p) => { + await new Promise(res => { + new p5(p => { p.setup = function() { p.createCanvas(50, 50, p.WEBGL); p.gridOutput(); diff --git a/test/unit/color/setting.js b/test/unit/color/setting.js index 53e86d1174..ba70afa7a0 100644 --- a/test/unit/color/setting.js +++ b/test/unit/color/setting.js @@ -70,7 +70,7 @@ suite('color/Setting', function() { } } }) - } + }; }); afterEach(() => { @@ -153,12 +153,18 @@ suite('color/Setting', function() { test('should set fill strength', function() { my3D.erase(125); - assert.deepEqual(my3D._renderer.states.curFillColor, [1, 1, 1, 125 / 255]); + assert.deepEqual( + my3D._renderer.states.curFillColor, + [1, 1, 1, 125 / 255] + ); }); test('should set stroke strength', function() { my3D.erase(255, 50); - assert.deepEqual(my3D._renderer.states.curStrokeColor, [1, 1, 1, 50 / 255]); + assert.deepEqual( + my3D._renderer.states.curStrokeColor, + [1, 1, 1, 50 / 255] + ); }); test('should set default values when no arguments', function() { diff --git a/test/unit/core/main.js b/test/unit/core/main.js index 0c166f6bab..84e9eb00da 100644 --- a/test/unit/core/main.js +++ b/test/unit/core/main.js @@ -181,7 +181,7 @@ suite('Core', function () { }); suite('millis()', () => { - let myp5 + let myp5; beforeEach(() => { vi.useFakeTimers(); @@ -195,8 +195,8 @@ suite('Core', function () { }); test('millis() starts at 0 when the draw loop begins', async () => { - const t = await new Promise((resolve) => { - myp5 = new p5((p) => { + const t = await new Promise(resolve => { + myp5 = new p5(p => { p.setup = () => { // Pretend setup takes 1s vi.advanceTimersByTime(1000); diff --git a/test/unit/core/p5.Graphics.js b/test/unit/core/p5.Graphics.js index 890e1d41f5..00961911de 100644 --- a/test/unit/core/p5.Graphics.js +++ b/test/unit/core/p5.Graphics.js @@ -124,7 +124,7 @@ suite('Graphics', function() { assert.typeOf(g.splineVertex, 'function'); }); }); - + suite('p5.Graphics.resizeCanvas', function() { let glStub; diff --git a/test/unit/core/param_errors.js b/test/unit/core/param_errors.js index 26a9efe4fb..247ae4a692 100644 --- a/test/unit/core/param_errors.js +++ b/test/unit/core/param_errors.js @@ -28,7 +28,7 @@ suite('Validate Params', function () { Graphics: function() { return 'mock p5.Graphics'; }, - _error: () => {}, + _error: () => {} }; const mockP5Prototype = {}; @@ -63,7 +63,7 @@ suite('Validate Params', function () { invalidInputs.forEach(({ input }) => { const result = mockP5Prototype.validate('p5.saturation', input); - assert.isTrue(result.error.startsWith("🌸 p5.js says: Expected Color or array or string at the first parameter, but received")); + assert.isTrue(result.error.startsWith('🌸 p5.js says: Expected Color or array or string at the first parameter, but received')); }); }); }); @@ -90,7 +90,7 @@ suite('Validate Params', function () { invalidInputs.forEach(({ name, input }) => { test(`blendMode(): ${name}`, () => { const result = mockP5Prototype.validate('p5.blendMode', [input]); - const expectedError = "🌸 p5.js says: Expected constant (please refer to documentation for allowed values) at the first parameter, but received " + input + " in p5.blendMode()."; + const expectedError = '🌸 p5.js says: Expected constant (please refer to documentation for allowed values) at the first parameter, but received ' + input + ' in p5.blendMode().'; assert.equal(result.error, expectedError); }); }); @@ -139,8 +139,8 @@ suite('Validate Params', function () { test('ambientLight(): no firendly-err-msg', function () { const result = mockP5Prototype.validate('p5.ambientLight', [new mockP5.Color()]); assert.isTrue(result.success); - }) - }) + }); + }); suite('validateParams: a few edge cases', function () { const invalidInputs = [ @@ -221,7 +221,7 @@ suite('Validate Params', function () { }); }); - test(`set() with Boolean (invalid)`, function () { + test('set() with Boolean (invalid)', function () { const result = mockP5Prototype.validate('p5.set', [0, 0, true]); assert.equal(result.error, '🌸 p5.js says: Expected number or array or object at the third parameter, but received boolean in p5.set().'); }); diff --git a/test/unit/core/sketch_overrides.js b/test/unit/core/sketch_overrides.js index 7a8f398fde..1d3893372d 100644 --- a/test/unit/core/sketch_overrides.js +++ b/test/unit/core/sketch_overrides.js @@ -9,12 +9,12 @@ suite('Sketch Verifier', function () { Vector: function () { }, prototype: { rect: function () { }, - ellipse: function () { }, + ellipse: function () { } } }; afterEach(() => { - vi.restoreAllMocks() + vi.restoreAllMocks(); vi.unstubAllGlobals(); }); @@ -46,7 +46,7 @@ suite('Sketch Verifier', function () { }); suite('getUserCode()', function () { - const userCode = "let c = p5.Color(20, 20, 20);"; + const userCode = 'let c = p5.Color(20, 20, 20);'; test('fetches the last script element', async function () { const fakeDocument = document.createElement('div'); @@ -56,7 +56,9 @@ suite('Sketch Verifier', function () { `; vi.spyOn(document, 'querySelectorAll') - .mockImplementation((...args) => fakeDocument.querySelectorAll(...args)); + .mockImplementation((...args) => + fakeDocument.querySelectorAll(...args) + ); vi.spyOn(verifierUtils, 'fetchScript') .mockImplementation(() => Promise.resolve(userCode)); @@ -82,46 +84,46 @@ suite('Sketch Verifier', function () { const result = verifierUtils.extractUserDefinedVariablesAndFuncs(code); const expectedResult = { - "functions": [ + 'functions': [ { - "line": 5, - "name": "foo", + 'line': 5, + 'name': 'foo' }, { - "line": 6, - "name": "bar", + 'line': 6, + 'name': 'bar' }, { - "line": 7, - "name": "baz", - }, + 'line': 7, + 'name': 'baz' + } ], - "variables": [ + 'variables': [ { - "line": 1, - "name": "x", + 'line': 1, + 'name': 'x' }, { - "line": 2, - "name": "y", + 'line': 2, + 'name': 'y' }, { - "line": 3, - "name": "z", + 'line': 3, + 'name': 'z' }, { - "line": 4, - "name": "v1", + 'line': 4, + 'name': 'v1' }, { - "line": 4, - "name": "v2", + 'line': 4, + 'name': 'v2' }, { - "line": 4, - "name": "v3", - }, - ], + 'line': 4, + 'name': 'v3' + } + ] }; expect(result).toEqual(expectedResult); }); @@ -149,25 +151,25 @@ suite('Sketch Verifier', function () { const result = verifierUtils.extractUserDefinedVariablesAndFuncs(code); const expectedResult = { - "functions": [], - "variables": [ + 'functions': [], + 'variables': [ { - "line": 2, - "name": "x", + 'line': 2, + 'name': 'x' }, { - "line": 6, - "name": "y", + 'line': 6, + 'name': 'y' }, { - "line": 11, - "name": "z", + 'line': 11, + 'name': 'z' }, { - "line": 13, - "name": "i", - }, - ], + 'line': 13, + 'name': 'i' + } + ] }; expect(result).toEqual(expectedResult); @@ -177,7 +179,9 @@ suite('Sketch Verifier', function () { const invalidCode = 'let x = ;'; const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { }); - const result = verifierUtils.extractUserDefinedVariablesAndFuncs(invalidCode); + const result = verifierUtils.extractUserDefinedVariablesAndFuncs( + invalidCode + ); expect(consoleSpy).toHaveBeenCalled(); expect(result).toEqual({ variables: [], functions: [] }); @@ -208,7 +212,10 @@ suite('Sketch Verifier', function () { variables: [{ name: 'PI', line: 1 }], functions: [] }; - const result = verifierUtils.checkForConstsAndFuncs(userDefinitions, MockP5); + const result = verifierUtils.checkForConstsAndFuncs( + userDefinitions, + MockP5 + ); expect(result).toBe(true); expect(consoleSpy).toHaveBeenCalledWith( @@ -223,7 +230,10 @@ suite('Sketch Verifier', function () { variables: [], functions: [{ name: 'rect', line: 2 }] }; - const result = verifierUtils.checkForConstsAndFuncs(userDefinitions, MockP5); + const result = verifierUtils.checkForConstsAndFuncs( + userDefinitions, + MockP5 + ); expect(result).toBe(true); expect(consoleSpy).toHaveBeenCalledWith( @@ -243,7 +253,10 @@ suite('Sketch Verifier', function () { ] }; - const result = verifierUtils.checkForConstsAndFuncs(userDefinitions, MockP5); + const result = verifierUtils.checkForConstsAndFuncs( + userDefinitions, + MockP5 + ); expect(result).toBe(false); expect(consoleSpy).not.toHaveBeenCalled(); @@ -255,7 +268,10 @@ suite('Sketch Verifier', function () { functions: [{ name: 'cut', line: 2 }] }; - const result = verifierUtils.checkForConstsAndFuncs(userDefinitions, MockP5); + const result = verifierUtils.checkForConstsAndFuncs( + userDefinitions, + MockP5 + ); expect(result).toBe(false); }); diff --git a/test/unit/core/vertex.js b/test/unit/core/vertex.js index 690a6dc682..24b9edca79 100644 --- a/test/unit/core/vertex.js +++ b/test/unit/core/vertex.js @@ -3,7 +3,6 @@ import { vi } from 'vitest'; suite('Vertex', function() { var myp5; - let _friendlyErrorSpy; beforeEach(function() { _friendlyErrorSpy = vi.spyOn(p5, '_friendlyError'); diff --git a/test/unit/dom/dom.js b/test/unit/dom/dom.js index 0dcf374b41..2621ac19b7 100644 --- a/test/unit/dom/dom.js +++ b/test/unit/dom/dom.js @@ -42,7 +42,7 @@ suite('DOM', function() { }); afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should return only one p5.element if match is found', function() { @@ -149,7 +149,7 @@ suite('DOM', function() { }); afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should return an array', function() { @@ -309,7 +309,7 @@ suite('DOM', function() { // Add/remove elements suite('p5.prototype.createDiv', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -331,7 +331,7 @@ suite('DOM', function() { suite('p5.prototype.createP', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -353,7 +353,7 @@ suite('DOM', function() { suite('p5.prototype.createSpan', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -377,7 +377,7 @@ suite('DOM', function() { const imagePath = '/test/unit/assets/cat.jpg'; afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -420,7 +420,7 @@ suite('DOM', function() { suite('p5.prototype.createA', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should return a p5.Element of anchor type', () => { @@ -447,7 +447,7 @@ suite('DOM', function() { suite('p5.prototype.createSlider', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should return a p5.Element of slider type', () => { @@ -476,7 +476,7 @@ suite('DOM', function() { suite('p5.prototype.createButton', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should return a p5.Element of button type', function() { @@ -499,7 +499,7 @@ suite('DOM', function() { suite('p5.prototype.createCheckbox', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); // helper functions @@ -567,7 +567,7 @@ suite('DOM', function() { suite('p5.prototype.createSelect', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); const createHTMLSelect = options => { @@ -691,7 +691,7 @@ suite('DOM', function() { suite('p5.prototype.createRadio', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); // Helper functions @@ -855,7 +855,7 @@ suite('DOM', function() { suite('p5.prototype.createColorPicker', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -900,7 +900,7 @@ suite('DOM', function() { suite('p5.prototype.createInput', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -932,7 +932,7 @@ suite('DOM', function() { suite('p5.prototype.createFileInput', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); const emptyCallback = () => {}; @@ -1003,7 +1003,7 @@ suite('DOM', function() { suite('p5.prototype.createElement', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); const testData = { @@ -1035,7 +1035,7 @@ suite('DOM', function() { suite('p5.prototype.removeElements', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should remove all elements created by p5 except Canvas', function() { @@ -1059,7 +1059,7 @@ suite('DOM', function() { // p5.Element.prototype.addClass suite('p5.Element.prototype.addClass', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -1093,7 +1093,7 @@ suite('DOM', function() { // p5.Element.prototype.removeClass suite('p5.Element.prototype.removeClass', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -1132,7 +1132,7 @@ suite('DOM', function() { // p5.Element.prototype.hasClass suite('p5.Element.prototype.hasClass', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -1165,7 +1165,7 @@ suite('DOM', function() { // p5.Element.prototype.toggleClass suite('p5.Element.prototype.toggleClass', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -1204,7 +1204,7 @@ suite('DOM', function() { // p5.Element.prototype.child suite('p5.Element.prototype.child', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -1266,7 +1266,7 @@ suite('DOM', function() { // p5.Element.prototype.center suite('p5.Element.prototype.center', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -1290,7 +1290,7 @@ suite('DOM', function() { // p5.Element.prototype.html suite('p5.Element.prototype.html', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -1347,7 +1347,7 @@ suite('DOM', function() { // p5.Element.prototype.position suite('p5.Element.prototype.position', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { diff --git a/test/unit/dom/p5.MediaElement.js b/test/unit/dom/p5.MediaElement.js index bfdb447755..38718c9821 100644 --- a/test/unit/dom/p5.MediaElement.js +++ b/test/unit/dom/p5.MediaElement.js @@ -9,7 +9,7 @@ suite('p5.MediaElement', () => { media(mockP5, mockP5Prototype); pixels(mockP5, mockP5Prototype); navigator.mediaDevices.getUserMedia = vi.fn() - .mockResolvedValue("stream-value"); + .mockResolvedValue('stream-value'); }); afterAll(() => { @@ -18,7 +18,7 @@ suite('p5.MediaElement', () => { suite('p5.prototype.createVideo', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); const mediaSources = [ @@ -153,7 +153,7 @@ suite('p5.MediaElement', () => { suite('p5.prototype.createAudio', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); const mediaSources = [ @@ -205,7 +205,7 @@ suite('p5.MediaElement', () => { suite('p5.prototype.createCapture', function() { afterEach(function() { - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should be a function', function() { @@ -238,14 +238,14 @@ suite('p5.MediaElement', () => { }); }); - suite("p5.MediaElement.copy", function () { + suite('p5.MediaElement.copy', function () { beforeAll(() => { globalThis.p5 = { prototype: mockP5Prototype }; }); afterAll(() => { delete globalThis.p5; - document.body.innerHTML = ""; + document.body.innerHTML = ''; }); test('should not throw an error', function() { @@ -254,5 +254,5 @@ suite('p5.MediaElement', () => { testElement.copy(0, 0, 10, 10, 0, 0, 10, 10); }); }); - }) + }); }); diff --git a/test/unit/events/keyboard.js b/test/unit/events/keyboard.js index 2f1d747dce..e8280dc87d 100644 --- a/test/unit/events/keyboard.js +++ b/test/unit/events/keyboard.js @@ -173,7 +173,7 @@ suite('Keyboard Events', function() { assert.isFalse(isCode({})); assert.isFalse(isCode([])); }); - + test('returns false for single non-digit and digit characters', function() { assert.isFalse(isCode('a')); assert.isFalse(isCode('Z')); @@ -181,7 +181,7 @@ suite('Keyboard Events', function() { assert.isFalse(isCode('2')); assert.isFalse(isCode(' ')); }); - + test('returns true for multi-character strings', function() { assert.isTrue(isCode('ShiftLeft')); assert.isTrue(isCode('ArrowUp')); @@ -194,7 +194,7 @@ suite('Keyboard Events', function() { assert.isTrue(isCode('AltLeft')); assert.isTrue(isCode('ShiftLeft')); }); - + test('handles edge cases correctly', function() { assert.isFalse(isCode('')); // empty string assert.isTrue(isCode('11')); // multi-digit number @@ -212,21 +212,21 @@ suite('Keyboard Events', function() { // Test single character keys window.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' })); assert.strictEqual(myp5.keyIsDown('a'), true); - + // Test digit keys window.dispatchEvent(new KeyboardEvent('keydown', { key: '1', code: 'Digit1' })); assert.strictEqual(myp5.keyIsDown('1'), true); - + // Test special keys window.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter' })); assert.strictEqual(myp5.keyIsDown('Enter'), true); }); - + test('keyIsDown should return false if key is not down', function() { // Ensure key is not down window.dispatchEvent(new KeyboardEvent('keyup')); assert.strictEqual(myp5.keyIsDown('z'), false); - + }); }); }); diff --git a/test/unit/events/touch.js b/test/unit/events/touch.js index 54677a59cc..f17eb7387a 100644 --- a/test/unit/events/touch.js +++ b/test/unit/events/touch.js @@ -1,5 +1,4 @@ import p5 from '../../../src/app.js'; -import { parallelSketches } from '../../js/p5_helpers'; suite('Touch Events', function() { let myp5; diff --git a/test/unit/image/downloading.js b/test/unit/image/downloading.js index d2bdd4a794..717c6f7944 100644 --- a/test/unit/image/downloading.js +++ b/test/unit/image/downloading.js @@ -9,50 +9,50 @@ import p5Image from '../../../src/image/p5.Image'; vi.mock('file-saver'); expect.extend({ - tobeGif: (received) => { + tobeGif: received => { if (received.type === 'image/gif') { return { message: 'expect blob to have type image/gif', pass: true - } + }; } else { return { message: 'expect blob to have type image/gif', pass: false - } + }; } }, - tobePng: (received) => { + tobePng: received => { if (received.type === 'image/png') { return { message: 'expect blob to have type image/png', pass: true - } + }; } else { return { message: 'expect blob to have type image/png', pass: false - } + }; } }, - tobeJpg: (received) => { + tobeJpg: received => { if (received.type === 'image/jpeg') { return { message: 'expect blob to have type image/jpeg', pass: true - } + }; } else { return { message: 'expect blob to have type image/jpeg', pass: false - } + }; } } }); -const wait = async (time) => { +const wait = async time => { return new Promise(resolve => setTimeout(resolve, time)); -} +}; suite('Downloading', () => { beforeAll(async function() { @@ -107,10 +107,10 @@ suite('Downloading', () => { await wait(100); expect(fileSaver.saveAs).toHaveBeenCalledTimes(1); expect(fileSaver.saveAs) - .toHaveBeenCalledWith( - expect.tobePng(), - 'untitled.png' - ); + .toHaveBeenCalledWith( + expect.tobePng(), + 'untitled.png' + ); }); test('should download a jpg file I', async () => { @@ -118,10 +118,10 @@ suite('Downloading', () => { await wait(100); expect(fileSaver.saveAs).toHaveBeenCalledTimes(1); expect(fileSaver.saveAs) - .toHaveBeenCalledWith( - expect.tobeJpg(), - 'filename.jpg' - ); + .toHaveBeenCalledWith( + expect.tobeJpg(), + 'filename.jpg' + ); }); test('should download a jpg file II', async () => { @@ -129,10 +129,10 @@ suite('Downloading', () => { await wait(100); expect(fileSaver.saveAs).toHaveBeenCalledTimes(1); expect(fileSaver.saveAs) - .toHaveBeenCalledWith( - expect.tobeJpg(), - 'filename.jpg' - ); + .toHaveBeenCalledWith( + expect.tobeJpg(), + 'filename.jpg' + ); }); }); @@ -190,10 +190,10 @@ suite('Downloading', () => { await mockP5Prototype.saveGif('myGif', 3, 2); expect(fileSaver.saveAs).toHaveBeenCalledTimes(1); expect(fileSaver.saveAs) - .toHaveBeenCalledWith( - expect.tobeGif(), - 'myGif.gif' - ); + .toHaveBeenCalledWith( + expect.tobeGif(), + 'myGif.gif' + ); }); }); }); diff --git a/test/unit/image/loading.js b/test/unit/image/loading.js index 801705294e..55bbc98f9c 100644 --- a/test/unit/image/loading.js +++ b/test/unit/image/loading.js @@ -45,7 +45,7 @@ suite('loading images', function() { beforeAll(async function() { loadingDisplaying(mockP5, mockP5Prototype); image(mockP5, mockP5Prototype); - await httpMock.start({quiet: true}); + await httpMock.start({ quiet: true }); }); test('throws error when encountering HTTP errors', async () => { @@ -57,7 +57,7 @@ suite('loading images', function() { test('error callback is called', async () => { await new Promise((resolve, reject) => { mockP5Prototype.loadImage(invalidFile, () => { - reject("Success callback executed"); + reject('Success callback executed'); }, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); @@ -70,7 +70,7 @@ suite('loading images', function() { mockP5Prototype.loadImage(imagePath, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); - }, (err) => { + }, err => { reject(`Error callback called: ${err.toString()}`); }); }); @@ -83,7 +83,7 @@ suite('loading images', function() { }); test('passes an object with correct data to success callback', async () => { - await mockP5Prototype.loadImage(imagePath, (pImg) => { + await mockP5Prototype.loadImage(imagePath, pImg => { assert.ok(pImg, 'cat.jpg loaded'); assert.isTrue(pImg instanceof mockP5.Image); }); diff --git a/test/unit/io/files.js b/test/unit/io/files.js index bde79ddf91..ad5e87565a 100644 --- a/test/unit/io/files.js +++ b/test/unit/io/files.js @@ -133,7 +133,8 @@ suite('Files', function() { test('should call saveCanvas', async () => { mockP5Prototype.save(); expect(mockP5Prototype.saveCanvas).toHaveBeenCalledTimes(1); - expect(mockP5Prototype.saveCanvas).toHaveBeenCalledWith(mockP5Prototype.elt); + expect(mockP5Prototype.saveCanvas) + .toHaveBeenCalledWith(mockP5Prototype.elt); }); test('should call saveCanvas with filename', async () => { diff --git a/test/unit/io/loadBytes.js b/test/unit/io/loadBytes.js index 34efe595a2..e5e95b464c 100644 --- a/test/unit/io/loadBytes.js +++ b/test/unit/io/loadBytes.js @@ -19,7 +19,7 @@ suite('loadBytes', function() { test('error callback is called', async () => { await new Promise((resolve, reject) => { mockP5Prototype.loadBytes(invalidFile, () => { - reject("Success callback executed"); + reject('Success callback executed'); }, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); @@ -32,7 +32,7 @@ suite('loadBytes', function() { mockP5Prototype.loadBytes(validFile, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); - }, (err) => { + }, err => { reject(`Error callback called: ${err.toString()}`); }); }); @@ -54,7 +54,7 @@ suite('loadBytes', function() { }); test('passes athe correct object to success callback', async () => { - await mockP5Prototype.loadBytes(validFile, (data) => { + await mockP5Prototype.loadBytes(validFile, data => { assert.instanceOf(data, Uint8Array); // Validate data diff --git a/test/unit/io/loadJSON.js b/test/unit/io/loadJSON.js index 333695b042..ea57d28d33 100644 --- a/test/unit/io/loadJSON.js +++ b/test/unit/io/loadJSON.js @@ -20,7 +20,7 @@ suite('loadJSON', function() { test('error callback is called', async () => { await new Promise((resolve, reject) => { mockP5Prototype.loadJSON(invalidFile, () => { - reject("Success callback executed"); + reject('Success callback executed'); }, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); @@ -33,7 +33,7 @@ suite('loadJSON', function() { mockP5Prototype.loadJSON(jsonObjectFile, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); - }, (err) => { + }, err => { reject(`Error callback called: ${err.toString()}`); }); }); @@ -46,7 +46,7 @@ suite('loadJSON', function() { }); test('passes an object to success callback for object JSON.', async () => { - await mockP5Prototype.loadJSON(jsonObjectFile, (data) => { + await mockP5Prototype.loadJSON(jsonObjectFile, data => { assert.isObject(data); }); }); @@ -58,7 +58,7 @@ suite('loadJSON', function() { }); test('passes an array to success callback for array JSON.', async function() { - await mockP5Prototype.loadJSON(jsonArrayFile, (data) => { + await mockP5Prototype.loadJSON(jsonArrayFile, data => { assert.isArray(data); assert.lengthOf(data, 3); }); diff --git a/test/unit/io/loadModel.js b/test/unit/io/loadModel.js index 694f87e37f..5b6a718f8f 100644 --- a/test/unit/io/loadModel.js +++ b/test/unit/io/loadModel.js @@ -25,7 +25,7 @@ suite('loadModel', function() { test('error callback is called', async () => { await new Promise((resolve, reject) => { mockP5Prototype.loadModel(invalidFile, () => { - reject("Success callback executed"); + reject('Success callback executed'); }, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); @@ -38,7 +38,7 @@ suite('loadModel', function() { mockP5Prototype.loadModel(validFile, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); - }, (err) => { + }, err => { reject(`Error callback called: ${err.toString()}`); }); }); @@ -96,7 +96,7 @@ suite('loadModel', function() { }); test('passes an object with correct data to callback', async function() { - await mockP5Prototype.loadModel(validFile, (model) => { + await mockP5Prototype.loadModel(validFile, model => { assert.instanceOf(model, Geometry); }); }); diff --git a/test/unit/io/loadShader.js b/test/unit/io/loadShader.js index 51aef19716..7894f54b39 100644 --- a/test/unit/io/loadShader.js +++ b/test/unit/io/loadShader.js @@ -27,7 +27,7 @@ suite('loadShader', function() { test('error callback is called for vert shader', async () => { await new Promise((resolve, reject) => { mockP5Prototype.loadShader(invalidFile, fragFile, () => { - reject("Success callback executed"); + reject('Success callback executed'); }, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); @@ -38,7 +38,7 @@ suite('loadShader', function() { test('error callback is called for frag shader', async () => { await new Promise((resolve, reject) => { mockP5Prototype.loadShader(vertFile, invalidFile, () => { - reject("Success callback executed"); + reject('Success callback executed'); }, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); @@ -51,7 +51,7 @@ suite('loadShader', function() { mockP5Prototype.loadShader(vertFile, fragFile, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); - }, (err) => { + }, err => { reject(`Error callback called: ${err.toString()}`); }); }); @@ -63,7 +63,7 @@ suite('loadShader', function() { }); test('passes an object with correct data to callback', async function() { - await mockP5Prototype.loadShader(vertFile, fragFile, (shader) => { + await mockP5Prototype.loadShader(vertFile, fragFile, shader => { assert.instanceOf(shader, Shader); }); }); diff --git a/test/unit/io/loadStrings.js b/test/unit/io/loadStrings.js index b8db23cb53..c8916b97a0 100644 --- a/test/unit/io/loadStrings.js +++ b/test/unit/io/loadStrings.js @@ -21,7 +21,7 @@ suite('loadStrings', function() { test('error callback is called', async () => { await new Promise((resolve, reject) => { mockP5Prototype.loadStrings(invalidFile, () => { - reject("Success callback executed"); + reject('Success callback executed'); }, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); @@ -34,7 +34,7 @@ suite('loadStrings', function() { mockP5Prototype.loadStrings(validFile, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); - }, (err) => { + }, err => { reject(`Error callback called: ${err.toString()}`); }); }); @@ -49,7 +49,7 @@ suite('loadStrings', function() { }); test('passes an array to success callback', async () => { - await mockP5Prototype.loadStrings(validFile, (strings) => { + await mockP5Prototype.loadStrings(validFile, strings => { assert.isArray(strings); for(let string of strings){ assert.isString(string); diff --git a/test/unit/io/loadTable.js b/test/unit/io/loadTable.js index 171d12f7c3..c18adf788d 100644 --- a/test/unit/io/loadTable.js +++ b/test/unit/io/loadTable.js @@ -23,7 +23,7 @@ suite('loadTable', function() { test('error callback is called', async () => { await new Promise((resolve, reject) => { mockP5Prototype.loadTable(invalidFile, () => { - reject("Success callback executed"); + reject('Success callback executed'); }, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); @@ -36,7 +36,7 @@ suite('loadTable', function() { mockP5Prototype.loadTable(validFile, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); - }, (err) => { + }, err => { reject(`Error callback called: ${err.toString()}`); }); }); @@ -50,7 +50,7 @@ suite('loadTable', function() { }); test('passes an object with correct data to success callback', async () => { - await mockP5Prototype.loadTable(validFile, (table) => { + await mockP5Prototype.loadTable(validFile, table => { assert.equal(table.getRowCount(), 4); assert.strictEqual(table.getRow(1).getString(0), 'David'); assert.strictEqual(table.getRow(1).getNum(1), 31); diff --git a/test/unit/io/loadXML.js b/test/unit/io/loadXML.js index 9ed8109e68..2715d22d4c 100644 --- a/test/unit/io/loadXML.js +++ b/test/unit/io/loadXML.js @@ -21,8 +21,8 @@ suite('loadXML', function() { test('error callback is called', async () => { await new Promise((resolve, reject) => { mockP5Prototype.loadXML(invalidFile, () => { - console.log("here"); - reject("Success callback executed"); + console.log('here'); + reject('Success callback executed'); }, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); @@ -35,7 +35,7 @@ suite('loadXML', function() { mockP5Prototype.loadXML(validFile, () => { // Wait a bit so that if both callbacks are executed we will get an error. setTimeout(resolve, 50); - }, (err) => { + }, err => { reject(`Error callback called: ${err.toString()}`); }); }); @@ -49,7 +49,7 @@ suite('loadXML', function() { }); test('passes an object with correct data to success callback', async () => { - await mockP5Prototype.loadXML(validFile, (xml) => { + await mockP5Prototype.loadXML(validFile, xml => { assert.isObject(xml); const children = xml.getChildren('book'); assert.lengthOf(children, 12); diff --git a/test/unit/math/p5.Matrix.js b/test/unit/math/p5.Matrix.js index 88b31d5b27..acce52506c 100644 --- a/test/unit/math/p5.Matrix.js +++ b/test/unit/math/p5.Matrix.js @@ -1,16 +1,20 @@ -import { describe, it, expect, beforeAll, afterAll, test } from "vitest"; -import p5 from "../../../src/app.js"; +import { describe, it, expect, beforeAll, afterAll, test } from 'vitest'; +import p5 from '../../../src/app.js'; -const toArray = (typedArray) => Array.from(typedArray); -/* eslint-disable indent */ -var mat4 = Float32Array.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); +const toArray = typedArray => Array.from(typedArray); -var other = Float32Array.from([1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]); +var mat4 = Float32Array.from([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 +]); + +var other = Float32Array.from([ + 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16 +]); var mat3 = Float32Array.from([1, 2, 3, 4, 5, 6, 7, 8, 9]); -/* eslint-enable indent */ -suite("p5.Matrix", function () { + +suite('p5.Matrix', function () { var myp5; beforeAll(function () { @@ -25,87 +29,89 @@ suite("p5.Matrix", function () { myp5.remove(); }); - suite("construction", function () { - test("new p5.Matrix(4)", function () { + suite('construction', function () { + test('new p5.Matrix(4)', function () { var m = new p5.Matrix(4); assert.instanceOf(m, p5.Matrix); assert.isUndefined(m.mat3); - /* eslint-disable indent */ + assert.deepEqual( [].slice.call(m.mat4), [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] ); - /* eslint-enable indent */ + }); - test("new p5.Matrix(array)", function () { + test('new p5.Matrix(array)', function () { var m = new p5.Matrix(mat4); assert.instanceOf(m, p5.Matrix); assert.isUndefined(m.mat3); expect(m.mat4).toEqual(mat4); }); - test("new p5.Matrix(mat3)", function () { + test('new p5.Matrix(mat3)', function () { var m = new p5.Matrix(mat3); assert.instanceOf(m, p5.Matrix); assert.isUndefined(m.mat4); assert.deepEqual(m.mat3, mat3); }); - test("identity()", function () { + test('identity()', function () { var m = new p5.Matrix(4); assert.instanceOf(m, p5.Matrix); assert.isUndefined(m.mat3); - /* eslint-disable indent */ + expect(toArray(m.mat4)).toEqual([ - 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]); - /* eslint-enable indent */ + }); }); - describe("reset", function () { - it("should reset a 4x4 matrix to the identity matrix", function () { + describe('reset', function () { + it('should reset a 4x4 matrix to the identity matrix', function () { const m = new p5.Matrix([ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]); m.reset(); expect(toArray(m.mat4)).toEqual([ - 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]); }); - it("should reset a 3x3 matrix to the identity matrix", function () { + it('should reset a 3x3 matrix to the identity matrix', function () { const m = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); m.reset(); expect(toArray(m.mat3)).toEqual([1, 0, 0, 0, 1, 0, 0, 0, 1]); }); }); - suite("set", function () { - test("p5.Matrix", function () { + suite('set', function () { + test('p5.Matrix', function () { var m = new p5.Matrix(4); m.set(new p5.Matrix(mat4)); expect(m.mat4).toEqual(mat4); // assert.deepEqual([].slice.call(m.mat4), mat4); }); - test("array", function () { + test('array', function () { var m = new p5.Matrix(4); m.set(mat4); assert.deepEqual(m.mat4, mat4); }); - test("arguments", function () { + test('arguments', function () { var m = new p5.Matrix(4); m.set(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6); - expect(Array.from(m.mat4)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6]); + expect(Array.from(m.mat4)).toEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 + ]); }); }); - it("should clone a 4x4 matrix correctly", () => { + it('should clone a 4x4 matrix correctly', () => { const original = new p5.Matrix([ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]); const clone = original.clone(); @@ -113,7 +119,7 @@ suite("p5.Matrix", function () { expect(toArray(clone.mat4)).toEqual(toArray(original.mat4)); }); - it("should clone a 3x3 matrix correctly", () => { + it('should clone a 3x3 matrix correctly', () => { const original = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); const clone = original.clone(); @@ -121,7 +127,7 @@ suite("p5.Matrix", function () { expect(clone.mat3).toEqual(original.mat3); }); - it("should clone an identity matrix correctly", () => { + it('should clone an identity matrix correctly', () => { const original = new p5.Matrix(4); const clone = original.clone(); @@ -129,14 +135,14 @@ suite("p5.Matrix", function () { expect(toArray(clone.mat4)).toEqual(toArray(original.mat4)); }); - suite("get / copy", function () { - test("get", function () { + suite('get / copy', function () { + test('get', function () { var m = new p5.Matrix(mat4); var m2 = m.get(); assert.notEqual(m, m2); expect(m.mat4).toEqual(m2.mat4); }); - test("copy", function () { + test('copy', function () { var m = new p5.Matrix(mat4); var m2 = m.copy(); assert.notEqual(m, m2); @@ -145,99 +151,99 @@ suite("p5.Matrix", function () { }); }); - suite.todo("add", () => {}); + suite.todo('add', () => {}); + + suite('mult', function () { - suite("mult", function () { - /* eslint-disable indent */ var mm = [ 30, 70, 110, 150, 70, 174, 278, 382, 110, 278, 446, 614, 150, 382, 614, - 846, + 846 ]; - /* eslint-enable indent */ - test("self", function () { + + test('self', function () { var m = new p5.Matrix(mat4.slice()); m.mult(m); - /* eslint-disable indent */ + assert.deepEqual( [].slice.call(m.mat4), [ 90, 100, 110, 120, 202, 228, 254, 280, 314, 356, 398, 440, 426, 484, - 542, 600, + 542, 600 ] ); - /* eslint-enable indent */ + }); - test("p5.Matrix", function () { + test('p5.Matrix', function () { var m1 = new p5.Matrix(mat4.slice()); var m2 = new p5.Matrix(other); m1.mult(m2); assert.deepEqual([].slice.call(m1.mat4), mm); }); - test("array", function () { + test('array', function () { var m = new p5.Matrix(mat4.slice()); m.mult(other); assert.deepEqual([].slice.call(m.mat4), mm); }); - test.todo("arguments", function () { + test.todo('arguments', function () { var m = new p5.Matrix(mat4.slice()); m.mult.apply(m, other); assert.deepEqual([].slice.call(m.mat4), mm); }); }); - suite("apply", function () { - /* eslint-disable indent */ + suite('apply', function () { + var am = [ 276, 304, 332, 360, 304, 336, 368, 400, 332, 368, 404, 440, 360, 400, 440, - 480, + 480 ]; - /* eslint-enable indent */ - test("self", function () { + + test('self', function () { var m = new p5.Matrix(mat4.slice()); m.apply(m); - /* eslint-disable indent */ + assert.deepEqual( [].slice.call(m.mat4), [ 90, 100, 110, 120, 202, 228, 254, 280, 314, 356, 398, 440, 426, 484, - 542, 600, + 542, 600 ] ); - /* eslint-enable indent */ + }); - test("p5.Matrix", function () { + test('p5.Matrix', function () { var m1 = new p5.Matrix(mat4.slice()); var m2 = new p5.Matrix(other); m1.apply(m2); assert.deepEqual([].slice.call(m1.mat4), am); }); - test("array", function () { + test('array', function () { var m = new p5.Matrix(mat4.slice()); m.apply(other); assert.deepEqual([].slice.call(m.mat4), am); }); - test("arguments", function () { + test('arguments', function () { var m = new p5.Matrix(mat4.slice()); m.apply.apply(m, other); assert.deepEqual([].slice.call(m.mat4), am); }); }); - suite("scale", function () { - /* eslint-disable indent */ + suite('scale', function () { + var sm = [2, 4, 6, 8, 15, 18, 21, 24, 45, 50, 55, 60, 13, 14, 15, 16]; - /* eslint-enable indent */ + var mat4 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; - test("p5.Vector", function () { + test('p5.Vector', function () { var m = new p5.Matrix(mat4.slice()); var v = myp5.createVector(2, 3, 5); m.scale(v); @@ -245,14 +251,14 @@ suite("p5.Matrix", function () { assert.deepEqual([].slice.call(m.mat4), sm); }); - test("array", function () { + test('array', function () { var m = new p5.Matrix(mat4.slice()); m.scale([2, 3, 5]); assert.notEqual(m.mat4, mat4); assert.deepEqual([].slice.call(m.mat4), sm); }); - test("arguments", function () { + test('arguments', function () { var m = new p5.Matrix(mat4.slice()); m.scale(2, 3, 5); assert.notEqual(m.mat4, mat4); @@ -260,38 +266,38 @@ suite("p5.Matrix", function () { }); }); - suite("rotate", function () { - /* eslint-disable max-len */ + suite('rotate', function () { + var rm = Float32Array.from([ 1.433447866601989, 2.5241247073503885, 3.6148015480987885, 4.7054783888471885, 6.460371405020393, 7.054586073938033, 7.648800742855675, 8.243015411773316, 7.950398010346969, - 9.157598472697025, 10.36479893504708, 11.571999397397136, 13, 14, 15, 16, + 9.157598472697025, 10.36479893504708, 11.571999397397136, 13, 14, 15, 16 ]); - /* eslint-enable max-len */ - test("p5.Vector", function () { + + test('p5.Vector', function () { var m = new p5.Matrix(mat4.slice()); var v = myp5.createVector(2, 3, 5); m.rotate4x4(45 * myp5.DEG_TO_RAD, v); assert.deepEqual(m.mat4, rm); }); - test("array", function () { + test('array', function () { var m = new p5.Matrix(mat4.slice()); m.rotate4x4(45 * myp5.DEG_TO_RAD, [2, 3, 5]); assert.deepEqual(m.mat4, rm); }); - test("arguments", function () { + test('arguments', function () { var m = new p5.Matrix(mat4.slice()); m.rotate4x4(45 * myp5.DEG_TO_RAD, 2, 3, 5); assert.deepEqual([].slice.call(m.mat4), Array.from(rm)); }); }); - suite("p5.Matrix3x3", function () { - test("apply copy() to 3x3Matrix", function () { + suite('p5.Matrix3x3', function () { + test('apply copy() to 3x3Matrix', function () { const m = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); const mCopy = m.copy(); @@ -302,7 +308,7 @@ suite("p5.Matrix", function () { // The matrix created by copying has the same elements as the original matrix assert.deepEqual([].slice.call(m.mat3), [].slice.call(mCopy.mat3)); }); - test("transpose()", function () { + test('transpose()', function () { const m = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); const mTp = new p5.Matrix([1, 4, 7, 2, 5, 8, 3, 6, 9]); @@ -318,7 +324,7 @@ suite("p5.Matrix", function () { ); }); - test("mult a 3x3 matrix with matrix as argument", function () { + test('mult a 3x3 matrix with matrix as argument', function () { const m = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); const multMatrix = new p5.Matrix([1, 1, 1, 0, 1, 1, 1, 0, 1]); // When taking a matrix as an argument @@ -326,19 +332,19 @@ suite("p5.Matrix", function () { expect(toArray(m.mat3)).toEqual([ 4, 3, 6, 10, 9, 15, 16, 15, 24 ]); }); - test("mult a 3x3 matrix with array as argument", function () { + test('mult a 3x3 matrix with array as argument', function () { const m = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); - m.mult([1, 1, 1, 0, 1, 1, 1, 0, 1]) + m.mult([1, 1, 1, 0, 1, 1, 1, 0, 1]); expect(toArray(m.mat3)).toEqual([ 4, 3, 6, 10, 9, 15, 16, 15, 24 ]); }); - test("mult a 3x3 matrix with arguments non array", function () { + test('mult a 3x3 matrix with arguments non array', function () { const m = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); - m.mult(1, 1, 1, 0, 1, 1, 1, 0, 1) + m.mult(1, 1, 1, 0, 1, 1, 1, 0, 1); expect(toArray(m.mat3)).toEqual([ 4, 3, 6, 10, 9, 15, 16, 15, 24 ]); }); - test("column() and row()", function () { + test('column() and row()', function () { // The matrix data is stored column-major, so each line below is // a column rather than a row. Imagine you are looking at the // transpose of the matrix in the source code. @@ -356,15 +362,15 @@ suite("p5.Matrix", function () { expect(row1.array()).toStrictEqual([2, 5, 8]); expect(row2.array()).toStrictEqual([3, 6, 9]); }); - test("diagonal()", function () { + test('diagonal()', function () { const m = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); const m4x4 = new p5.Matrix([ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]); assert.deepEqual(m.diagonal(), [1, 5, 9]); assert.deepEqual(m4x4.diagonal(), [1, 6, 11, 16]); }); - test("multiplyVec version 3", function () { + test('multiplyVec version 3', function () { const m = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); const multVector = new p5.Vector(3, 2, 1); const result = m.multiplyVec(multVector); @@ -374,9 +380,9 @@ suite("p5.Matrix", function () { m.multiplyVec(multVector, target); assert.deepEqual(target.array(), [18, 24, 30]); }); - test("createSubMatrix3x3", function () { + test('createSubMatrix3x3', function () { const m4x4 = new p5.Matrix([ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]); const result = new p5.Matrix([1, 2, 3, 5, 6, 7, 9, 10, 11]); const subMatrix3x3 = m4x4.createSubMatrix3x3(); @@ -388,40 +394,40 @@ suite("p5.Matrix", function () { }); /// - describe("transpose", () => { - it("should transpose a 4x4 matrix correctly", () => { + describe('transpose', () => { + it('should transpose a 4x4 matrix correctly', () => { const mat = new p5.Matrix([ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]); mat.transpose(mat); expect(toArray(mat.mat4)).toEqual([ - 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16, + 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16 ]); }); - it("should transpose a 4x4 matrix from an array correctly", () => { + it('should transpose a 4x4 matrix from an array correctly', () => { const mat = new p5.Matrix([ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]); mat.transpose([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); expect(toArray(mat.mat4)).toEqual([ - 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16, + 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16 ]); }); // TODO: matrix transpose This needs to be added to the legacy tests - it.skip("should transpose a 3x3 matrix correctly", () => { + it.skip('should transpose a 3x3 matrix correctly', () => { const mat = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); mat.transpose(mat); expect(mat.mat3).toEqual([1, 4, 7, 2, 5, 8, 3, 6, 9]); }); // TODO: matrix transpose This needs to be added to the legacy tests - it.skip("should transpose a 3x3 matrix from an array correctly", () => { + it.skip('should transpose a 3x3 matrix from an array correctly', () => { const mat = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); mat.transpose([1, 2, 3, 4, 5, 6, 7, 8, 9]); @@ -429,40 +435,40 @@ suite("p5.Matrix", function () { expect(mat.mat3).toEqual([1, 4, 7, 2, 5, 8, 3, 6, 9]); }); }); - describe.skip("Determinant", () => { // TODO: Cristian, when this is public we'll add tests - it("should calculate the determinant of a 4x4 matrix", () => { + describe.skip('Determinant', () => { // TODO: Cristian, when this is public we'll add tests + it('should calculate the determinant of a 4x4 matrix', () => { const mat4 = new p5.Matrix([ - 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]); const det = mat4.determinant4x4(); expect(det).toBeCloseTo(1); }); - it("should return 0 for a singular 4x4 matrix", () => { + it('should return 0 for a singular 4x4 matrix', () => { const mat4 = new p5.Matrix([ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]); const det = mat4.determinant4x4(); expect(det).toBeCloseTo(0); }); }); - describe("invert", () => { - it("should correctly invert a 4x4 matrix", () => { + describe('invert', () => { + it('should correctly invert a 4x4 matrix', () => { const matrix = new p5.Matrix([ - 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]); const invertedMatrix = matrix.invert(matrix); expect(toArray(invertedMatrix.mat4)).toEqual([ - 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]); }); - it("should return null for a non-invertible matrix", () => { + it('should return null for a non-invertible matrix', () => { const matrix = new p5.Matrix([ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]); const invertedMatrix = matrix.invert(matrix); @@ -470,35 +476,36 @@ suite("p5.Matrix", function () { expect(invertedMatrix).toBeNull(); }); - it("should correctly invert a non-identity 4x4 matrix", () => { + it('should correctly invert a non-identity 4x4 matrix', () => { const matrix = new p5.Matrix([ - 1, 1, 1, 1, 1, -1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, + 1, 1, 1, 1, 1, -1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0 ]); const invertedMatrix = matrix.invert(matrix); expect(toArray(invertedMatrix.mat4)).toEqual([ - 0, 0, 0, 1, 0, 0, 1, -1, 0, 1, 1, -2, 1, -1, -2, 2, + 0, 0, 0, 1, 0, 0, 1, -1, 0, 1, 1, -2, 1, -1, -2, 2 ]); }); }); // - describe("invert", () => { - it("should correctly invert a 3x3 matrix", () => { + describe('invert', () => { + it('should correctly invert a 3x3 matrix', () => { const matrix = new p5.Matrix([1, 2, 3, 0, 1, 4, 5, 6, 0]); const invertedMatrix = matrix.invert(); - expect(toArray(invertedMatrix.mat3)).toEqual([-24, 18, 5, 20, -15, -4, -5, 4, 1]); + expect(toArray(invertedMatrix.mat3)) + .toEqual([-24, 18, 5, 20, -15, -4, -5, 4, 1]); }); - it("should return null for a non-invertible 3x3 matrix", () => { + it('should return null for a non-invertible 3x3 matrix', () => { const matrix = new p5.Matrix([1, 2, 3, 4, 5, 6, 7, 8, 9]); const invertedMatrix = matrix.invert(); expect(invertedMatrix).toBeNull(); }); - it("should return the identity matrix when inverting the identity matrix", () => { + it('should return the identity matrix when inverting the identity matrix', () => { const matrix = new p5.Matrix([1, 0, 0, 0, 1, 0, 0, 0, 1]); const invertedMatrix = matrix.invert(); @@ -506,19 +513,19 @@ suite("p5.Matrix", function () { }); }); - describe("mat set element", () => { - it("should set element of mat4 matrix", () => { + describe('mat set element', () => { + it('should set element of mat4 matrix', () => { const matrix = new p5.Matrix([ - 1, 2, 3, 5, 0, 1, 4, 5, 5, 6, 0, 5, 5, 6, 0, 5, + 1, 2, 3, 5, 0, 1, 4, 5, 5, 6, 0, 5, 5, 6, 0, 5 ]); const invertedMatrix = matrix.setElement(2, 0); expect(toArray(invertedMatrix.mat4)).toEqual([ - 1, 2, 0, 5, 0, 1, 4, 5, 5, 6, 0, 5, 5, 6, 0, 5, + 1, 2, 0, 5, 0, 1, 4, 5, 5, 6, 0, 5, 5, 6, 0, 5 ]); }); - it("should set element of mat3 matrix", () => { + it('should set element of mat3 matrix', () => { const matrix = new p5.Matrix([1, 2, 3, 0, 1, 4, 5, 6, 0]); const invertedMatrix = matrix.setElement(2, 0); diff --git a/test/unit/math/p5.Vector.js b/test/unit/math/p5.Vector.js index 81090c21e9..8e2dcf157d 100644 --- a/test/unit/math/p5.Vector.js +++ b/test/unit/math/p5.Vector.js @@ -1,11 +1,11 @@ -import vector from "../../../src/math/p5.Vector.js"; -import { vi } from "vitest"; +import vector from '../../../src/math/p5.Vector.js'; +import { vi } from 'vitest'; -suite("p5.Vector", function () { +suite('p5.Vector', function () { var v; const mockP5 = { - _validateParameters: vi.fn(), + _validateParameters: vi.fn() }; const mockP5Prototype = {}; @@ -15,117 +15,117 @@ suite("p5.Vector", function () { afterEach(function () {}); - suite.todo("p5.prototype.setHeading() RADIANS", function () { + suite.todo('p5.prototype.setHeading() RADIANS', function () { beforeEach(function () { mockP5Prototype.angleMode(mockP5.RADIANS); v = mockP5Prototype.createVector(1, 1); v.setHeading(1); }); - test("should have heading() value of 1 (RADIANS)", function () { + test('should have heading() value of 1 (RADIANS)', function () { assert.closeTo(v.heading(), 1, 0.001); }); }); - suite.todo("p5.prototype.setHeading() DEGREES", function () { + suite.todo('p5.prototype.setHeading() DEGREES', function () { beforeEach(function () { mockP5Prototype.angleMode(mockP5.DEGREES); v = mockP5Prototype.createVector(1, 1); v.setHeading(1); }); - test("should have heading() value of 1 (DEGREES)", function () { + test('should have heading() value of 1 (DEGREES)', function () { assert.closeTo(v.heading(), 1, 0.001); }); }); // NOTE: test this in a separate file or move `createVector` to p5.Vector file // Prefer latter - suite.todo("p5.prototype.createVector()", function () { + suite.todo('p5.prototype.createVector()', function () { beforeEach(function () { v = mockP5Prototype.createVector(); }); - test("should create instance of p5.Vector", function () { + test('should create instance of p5.Vector', function () { assert.instanceOf(v, mockP5.Vector); }); - test("should have x, y, z be initialized to 0", function () { + test('should have x, y, z be initialized to 0', function () { assert.equal(v.x, 0); assert.equal(v.y, 0); assert.equal(v.z, 0); }); - test("should have dimensions initialized to 2", function () { + test('should have dimensions initialized to 2', function () { assert.equal(v.dimensions, 2); }); }); - suite.todo("p5.prototype.createVector(1, 2, 3)", function () { + suite.todo('p5.prototype.createVector(1, 2, 3)', function () { beforeEach(function () { v = mockP5Prototype.createVector(1, 2, 3); }); - test("should have x, y, z be initialized to 1,2,3", function () { + test('should have x, y, z be initialized to 1,2,3', function () { assert.equal(v.x, 1); assert.equal(v.y, 2); assert.equal(v.z, 3); }); - test("should have dimensions initialized to 3", function () { + test('should have dimensions initialized to 3', function () { assert.equal(v.dimensions, 3); }); }); - suite("new p5.Vector()", function () { + suite('new p5.Vector()', function () { beforeEach(function () { v = new mockP5.Vector(); }); - test("should set constant to DEGREES", function () { + test('should set constant to DEGREES', function () { assert.instanceOf(v, mockP5.Vector); }); - test("should have x, y, z be initialized to 0", function () { + test('should have x, y, z be initialized to 0', function () { assert.equal(v.x, 0); assert.equal(v.y, 0); assert.equal(v.z, 0); }); }); - suite("new p5.Vector(1, 2, 3)", function () { + suite('new p5.Vector(1, 2, 3)', function () { beforeEach(function () { v = new mockP5.Vector(1, 2, 3); }); - test("should have x, y, z be initialized to 1,2,3", function () { + test('should have x, y, z be initialized to 1,2,3', function () { assert.equal(v.x, 1); assert.equal(v.y, 2); assert.equal(v.z, 3); }); }); - suite("new p5.Vector(1,2,undefined)", function () { + suite('new p5.Vector(1,2,undefined)', function () { beforeEach(function () { v = new mockP5.Vector(1, 2, undefined); }); - test("should have x, y, z be initialized to 1,2,0", function () { + test('should have x, y, z be initialized to 1,2,0', function () { assert.equal(v.x, 1); assert.equal(v.y, 2); assert.equal(v.z, 0); }); }); - suite("rotate", function () { - suite("p5.Vector.prototype.rotate() [INSTANCE]", function () { - test("should return the same object", function () { + suite('rotate', function () { + suite('p5.Vector.prototype.rotate() [INSTANCE]', function () { + test('should return the same object', function () { v = new mockP5.Vector(0, 1); expect(v.rotate(Math.PI)).to.eql(v); }); - suite.todo("radians", function () { + suite.todo('radians', function () { beforeEach(function () { mockP5Prototype.angleMode(mockP5.RADIANS); }); - test("should rotate the vector [0, 1, 0] by pi radians to [0, -1, 0]", function () { + test('should rotate the vector [0, 1, 0] by pi radians to [0, -1, 0]', function () { v = mockP5Prototype.createVector(0, 1, 0); v.rotate(Math.PI); expect(v.x).to.be.closeTo(0, 0.01); @@ -133,7 +133,7 @@ suite("p5.Vector", function () { expect(v.z).to.be.closeTo(0, 0.01); }); - test("should rotate the vector [1, 0, 0] by -pi/2 radians to [0, -1, 0]", function () { + test('should rotate the vector [1, 0, 0] by -pi/2 radians to [0, -1, 0]', function () { v = mockP5Prototype.createVector(1, 0, 0); v.rotate(-Math.PI / 2); expect(v.x).to.be.closeTo(0, 0.01); @@ -141,7 +141,7 @@ suite("p5.Vector", function () { expect(v.z).to.be.closeTo(0, 0.01); }); - test("should rotate the vector [1, 0, 0] by pi radians to [-1, 0, 0]", function () { + test('should rotate the vector [1, 0, 0] by pi radians to [-1, 0, 0]', function () { v = mockP5Prototype.createVector(1, 0, 0); v.rotate(Math.PI); expect(v.x).to.be.closeTo(-1, 0.01); @@ -150,12 +150,12 @@ suite("p5.Vector", function () { }); }); - suite.todo("degrees", function () { + suite.todo('degrees', function () { beforeEach(function () { mockP5Prototype.angleMode(mockP5.DEGREES); }); - test("should rotate the vector [0, 1, 0] by 180 degrees to [0, -1, 0]", function () { + test('should rotate the vector [0, 1, 0] by 180 degrees to [0, -1, 0]', function () { v = mockP5Prototype.createVector(0, 1, 0); v.rotate(180); expect(v.x).to.be.closeTo(0, 0.01); @@ -163,7 +163,7 @@ suite("p5.Vector", function () { expect(v.z).to.be.closeTo(0, 0.01); }); - test("should rotate the vector [1, 0, 0] by -90 degrees to [0, -1, 0]", function () { + test('should rotate the vector [1, 0, 0] by -90 degrees to [0, -1, 0]', function () { v = mockP5Prototype.createVector(1, 0, 0); v.rotate(-90); expect(v.x).to.be.closeTo(0, 0.01); @@ -173,12 +173,12 @@ suite("p5.Vector", function () { }); }); - suite.todo("p5.Vector.rotate() [CLASS]", function () { + suite.todo('p5.Vector.rotate() [CLASS]', function () { beforeEach(function () { mockP5Prototype.angleMode(mockP5.RADIANS); }); - test("should not change the original object", function () { + test('should not change the original object', function () { v = mockP5Prototype.createVector(1, 0, 0); mockP5.Vector.rotate(v, Math.PI / 2); expect(v.x).to.equal(1); @@ -186,7 +186,7 @@ suite("p5.Vector", function () { expect(v.z).to.equal(0); }); - test("should rotate the vector [0, 1, 0] by pi radians to [0, -1, 0]", function () { + test('should rotate the vector [0, 1, 0] by pi radians to [0, -1, 0]', function () { v = mockP5Prototype.createVector(0, 1, 0); const v1 = mockP5.Vector.rotate(v, Math.PI); expect(v1.x).to.be.closeTo(0, 0.01); @@ -194,7 +194,7 @@ suite("p5.Vector", function () { expect(v1.z).to.be.closeTo(0, 0.01); }); - test("should rotate the vector [1, 0, 0] by -pi/2 radians to [0, -1, 0]", function () { + test('should rotate the vector [1, 0, 0] by -pi/2 radians to [0, -1, 0]', function () { v = mockP5Prototype.createVector(1, 0, 0); const v1 = mockP5.Vector.rotate(v, -Math.PI / 2); expect(v1.x).to.be.closeTo(0, 0.01); @@ -204,20 +204,20 @@ suite("p5.Vector", function () { }); }); - suite("angleBetween", function () { + suite('angleBetween', function () { let v1, v2; beforeEach(function () { v1 = new mockP5.Vector(1, 0, 0); v2 = new mockP5.Vector(2, 2, 0); }); - suite("p5.Vector.prototype.angleBetween() [INSTANCE]", function () { - test("should return a Number", function () { + suite('p5.Vector.prototype.angleBetween() [INSTANCE]', function () { + test('should return a Number', function () { const res = v1.angleBetween(v2); - expect(typeof res).to.eql("number"); + expect(typeof res).to.eql('number'); }); - test("should not trip on rounding issues in 2D space", function () { + test('should not trip on rounding issues in 2D space', function () { v1 = new mockP5.Vector(-11, -20); v2 = new mockP5.Vector(-5.5, -10); const v3 = new mockP5.Vector(5.5, 10); @@ -226,20 +226,20 @@ suite("p5.Vector", function () { expect(v1.angleBetween(v3)).to.be.closeTo(Math.PI, 0.00001); }); - test("should not trip on rounding issues in 3D space", function () { + test('should not trip on rounding issues in 3D space', function () { v1 = new mockP5.Vector(1, 1.1, 1.2); v2 = new mockP5.Vector(2, 2.2, 2.4); expect(v1.angleBetween(v2)).to.be.closeTo(0, 0.00001); }); - test("should return NaN for zero vector", function () { + test('should return NaN for zero vector', function () { v1 = new mockP5.Vector(0, 0, 0); v2 = new mockP5.Vector(2, 3, 4); expect(v1.angleBetween(v2)).to.be.NaN; expect(v2.angleBetween(v1)).to.be.NaN; }); - test.todo("between [1,0,0] and [1,0,0] should be 0 degrees", function () { + test.todo('between [1,0,0] and [1,0,0] should be 0 degrees', function () { mockP5Prototype.angleMode(mockP5.DEGREES); v1 = new mockP5.Vector(1, 0, 0); v2 = new mockP5.Vector(1, 0, 0); @@ -247,7 +247,7 @@ suite("p5.Vector", function () { }); test.todo( - "between [0,3,0] and [0,-3,0] should be 180 degrees", + 'between [0,3,0] and [0,-3,0] should be 180 degrees', function () { mockP5Prototype.angleMode(mockP5.DEGREES); v1 = new mockP5.Vector(0, 3, 0); @@ -256,20 +256,20 @@ suite("p5.Vector", function () { } ); - test("between [1,0,0] and [2,2,0] should be 1/4 PI radians", function () { + test('between [1,0,0] and [2,2,0] should be 1/4 PI radians', function () { v1 = new mockP5.Vector(1, 0, 0); v2 = new mockP5.Vector(2, 2, 0); expect(v1.angleBetween(v2)).to.be.closeTo(Math.PI / 4, 0.01); expect(v2.angleBetween(v1)).to.be.closeTo((-1 * Math.PI) / 4, 0.01); }); - test("between [2,0,0] and [-2,0,0] should be PI radians", function () { + test('between [2,0,0] and [-2,0,0] should be PI radians', function () { v1 = new mockP5.Vector(2, 0, 0); v2 = new mockP5.Vector(-2, 0, 0); expect(v1.angleBetween(v2)).to.be.closeTo(Math.PI, 0.01); }); - test("between [2,0,0] and [-2,-2,0] should be -3/4 PI radians ", function () { + test('between [2,0,0] and [-2,-2,0] should be -3/4 PI radians ', function () { v1 = new mockP5.Vector(2, 0, 0); v2 = new mockP5.Vector(-2, -2, 0); expect(v1.angleBetween(v2)).to.be.closeTo( @@ -278,7 +278,7 @@ suite("p5.Vector", function () { ); }); - test("between [-2,-2,0] and [2,0,0] should be 3/4 PI radians", function () { + test('between [-2,-2,0] and [2,0,0] should be 3/4 PI radians', function () { v1 = new mockP5.Vector(-2, -2, 0); v2 = new mockP5.Vector(2, 0, 0); expect(v1.angleBetween(v2)).to.be.closeTo( @@ -287,21 +287,21 @@ suite("p5.Vector", function () { ); }); - test("For the same vectors, the angle between them should always be 0.", function () { + test('For the same vectors, the angle between them should always be 0.', function () { v1 = new mockP5.Vector(288, 814); v2 = new mockP5.Vector(288, 814); expect(v1.angleBetween(v2)).to.equal(0); }); - test("The angle between vectors pointing in opposite is always PI.", function () { + test('The angle between vectors pointing in opposite is always PI.', function () { v1 = new mockP5.Vector(219, 560); v2 = new mockP5.Vector(-219, -560); expect(v1.angleBetween(v2)).to.be.closeTo(Math.PI, 0.0000001); }); }); - suite("p5.Vector.angleBetween() [CLASS]", function () { - test("should return NaN for zero vector", function () { + suite('p5.Vector.angleBetween() [CLASS]', function () { + test('should return NaN for zero vector', function () { v1 = new mockP5.Vector(0, 0, 0); v2 = new mockP5.Vector(2, 3, 4); expect(mockP5.Vector.angleBetween(v1, v2)).to.be.NaN; @@ -309,7 +309,7 @@ suite("p5.Vector", function () { }); test.todo( - "between [1,0,0] and [0,-1,0] should be -90 degrees", + 'between [1,0,0] and [0,-1,0] should be -90 degrees', function () { mockP5Prototype.angleMode(mockP5.DEGREES); v1 = new mockP5.Vector(1, 0, 0); @@ -318,7 +318,7 @@ suite("p5.Vector", function () { } ); - test("between [0,3,0] and [0,-3,0] should be PI radians", function () { + test('between [0,3,0] and [0,-3,0] should be PI radians', function () { v1 = new mockP5.Vector(0, 3, 0); v2 = new mockP5.Vector(0, -3, 0); expect(mockP5.Vector.angleBetween(v1, v2)).to.be.closeTo(Math.PI, 0.01); @@ -326,8 +326,8 @@ suite("p5.Vector", function () { }); }); - suite("set()", function () { - suite("with p5.Vector", function () { + suite('set()', function () { + suite('with p5.Vector', function () { test("should have x, y, z be initialized to the vector's x, y, z", function () { v.set(new mockP5.Vector(2, 5, 6)); expect(v.x).to.eql(2); @@ -336,8 +336,8 @@ suite("p5.Vector", function () { }); }); - suite("with Array", function () { - test("[2,4] should set x === 2, y === 4, z === 0", function () { + suite('with Array', function () { + test('[2,4] should set x === 2, y === 4, z === 0', function () { v.set([2, 4]); expect(v.x).to.eql(2); expect(v.y).to.eql(4); @@ -352,8 +352,8 @@ suite("p5.Vector", function () { }); }); - suite("set(1,2,3)", function () { - test("should have x, y, z be initialized to the 1, 2, 3", function () { + suite('set(1,2,3)', function () { + test('should have x, y, z be initialized to the 1, 2, 3', function () { v.set(1, 2, 3); expect(v.x).to.eql(1); expect(v.y).to.eql(2); @@ -362,13 +362,13 @@ suite("p5.Vector", function () { }); }); - suite("copy", function () { + suite('copy', function () { beforeEach(function () { v = new mockP5.Vector(2, 3, 4); }); - suite("p5.Vector.prototype.copy() [INSTANCE]", function () { - test("should not return the same instance", function () { + suite('p5.Vector.prototype.copy() [INSTANCE]', function () { + test('should not return the same instance', function () { var newObject = v.copy(); expect(newObject).to.not.equal(v); }); @@ -381,8 +381,8 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.copy() [CLASS]", function () { - test("should not return the same instance", function () { + suite('p5.Vector.copy() [CLASS]', function () { + test('should not return the same instance', function () { var newObject = mockP5.Vector.copy(v); expect(newObject).to.not.equal(v); }); @@ -396,13 +396,13 @@ suite("p5.Vector", function () { }); }); - suite("add()", function () { + suite('add()', function () { beforeEach(function () { v = new mockP5.Vector(); }); - suite("with p5.Vector", function () { - test("should add x, y, z from the vector argument", function () { + suite('with p5.Vector', function () { + test('should add x, y, z from the vector argument', function () { v.add(new mockP5.Vector(1, 5, 6)); expect(v.x).to.eql(1); expect(v.y).to.eql(5); @@ -410,9 +410,9 @@ suite("p5.Vector", function () { }); }); - suite("with Array", function () { - suite("add([2, 4])", function () { - test("should add the x and y components", function () { + suite('with Array', function () { + suite('add([2, 4])', function () { + test('should add the x and y components', function () { v.add([2, 4]); expect(v.x).to.eql(2); expect(v.y).to.eql(4); @@ -428,8 +428,8 @@ suite("p5.Vector", function () { }); }); - suite("add(3,5)", function () { - test("should add the x and y components", function () { + suite('add(3,5)', function () { + test('should add the x and y components', function () { v.add(3, 5); expect(v.x).to.eql(3); expect(v.y).to.eql(5); @@ -437,8 +437,8 @@ suite("p5.Vector", function () { }); }); - suite("add(2,3,4)", function () { - test("should add the x, y, z components", function () { + suite('add(2,3,4)', function () { + test('should add the x, y, z components', function () { v.add(5, 5, 5); expect(v.x).to.eql(5); expect(v.y).to.eql(5); @@ -446,15 +446,15 @@ suite("p5.Vector", function () { }); }); - suite("add(2,3,4)", function () { - test("should add the x, y, z components", function () { + suite('add(2,3,4)', function () { + test('should add the x, y, z components', function () { v.add([1, 2, 3]); expect(v.x).to.eql(1); expect(v.y).to.eql(2); }); }); - suite("p5.Vector.add(v1, v2)", function () { + suite('p5.Vector.add(v1, v2)', function () { var v1, v2, res; beforeEach(function () { v1 = new mockP5.Vector(2, 0, 3); @@ -462,12 +462,12 @@ suite("p5.Vector", function () { res = mockP5.Vector.add(v1, v2); }); - test("should return neither v1 nor v2", function () { + test('should return neither v1 nor v2', function () { expect(res).to.not.eql(v1); expect(res).to.not.eql(v2); }); - test("should be sum of the two p5.Vectors", function () { + test('should be sum of the two p5.Vectors', function () { expect(res.x).to.eql(v1.x + v2.x); expect(res.y).to.eql(v1.y + v2.y); expect(res.z).to.eql(v1.z + v2.z); @@ -475,62 +475,62 @@ suite("p5.Vector", function () { }); }); - suite("rem()", function () { + suite('rem()', function () { beforeEach(function () { v = new mockP5.Vector(3, 4, 5); }); - test("should give same vector if nothing passed as parameter", function () { + test('should give same vector if nothing passed as parameter', function () { v.rem(); expect(v.x).to.eql(3); expect(v.y).to.eql(4); expect(v.z).to.eql(5); }); - test("should give correct output if passed only one numeric value", function () { + test('should give correct output if passed only one numeric value', function () { v.rem(2); expect(v.x).to.eql(1); expect(v.y).to.eql(0); expect(v.z).to.eql(1); }); - test("should give correct output if passed two numeric value", function () { + test('should give correct output if passed two numeric value', function () { v.rem(2, 3); expect(v.x).to.eql(1); expect(v.y).to.eql(1); expect(v.z).to.eql(5); }); - test("should give correct output if passed three numeric value", function () { + test('should give correct output if passed three numeric value', function () { v.rem(2, 3, 4); expect(v.x).to.eql(1); expect(v.y).to.eql(1); expect(v.z).to.eql(1); }); - suite("with p5.Vector", function () { - test("should return correct output if only one component is non-zero", function () { + suite('with p5.Vector', function () { + test('should return correct output if only one component is non-zero', function () { v.rem(new mockP5.Vector(0, 0, 4)); expect(v.x).to.eql(3); expect(v.y).to.eql(4); expect(v.z).to.eql(1); }); - test("should return correct output if x component is zero", () => { + test('should return correct output if x component is zero', () => { v.rem(new mockP5.Vector(0, 3, 4)); expect(v.x).to.eql(3); expect(v.y).to.eql(1); expect(v.z).to.eql(1); }); - test("should return correct output if all components are non-zero", () => { + test('should return correct output if all components are non-zero', () => { v.rem(new mockP5.Vector(2, 3, 4)); expect(v.x).to.eql(1); expect(v.y).to.eql(1); expect(v.z).to.eql(1); }); - test("should return same vector if all components are zero", () => { + test('should return same vector if all components are zero', () => { v.rem(new mockP5.Vector(0, 0, 0)); expect(v.x).to.eql(3); expect(v.y).to.eql(4); @@ -538,12 +538,12 @@ suite("p5.Vector", function () { }); }); - suite("with negative vectors", function () { + suite('with negative vectors', function () { let v; beforeEach(function () { v = new mockP5.Vector(-15, -5, -2); }); - test("should return correct output", () => { + test('should return correct output', () => { v.rem(new mockP5.Vector(2, 3, 3)); expect(v.x).to.eql(-1); expect(v.y).to.eql(-2); @@ -551,28 +551,28 @@ suite("p5.Vector", function () { }); }); - suite("with Arrays", function () { - test("should return remainder of vector components for 3D vector", function () { + suite('with Arrays', function () { + test('should return remainder of vector components for 3D vector', function () { v.rem([2, 3, 0]); expect(v.x).to.eql(1); expect(v.y).to.eql(1); expect(v.z).to.eql(5); }); - test("should return remainder of vector components for 2D vector", function () { + test('should return remainder of vector components for 2D vector', function () { v.rem([2, 3]); expect(v.x).to.eql(1); expect(v.y).to.eql(1); expect(v.z).to.eql(5); }); - test("should return correct output if x,y components are zero for 2D vector", () => { + test('should return correct output if x,y components are zero for 2D vector', () => { v.rem([0, 0]); expect(v.x).to.eql(3); expect(v.y).to.eql(4); expect(v.z).to.eql(5); }); - test("should return same vector if any vector component is non-finite number", () => { + test('should return same vector if any vector component is non-finite number', () => { v.rem([2, 3, Infinity]); expect(v.x).to.eql(3); expect(v.y).to.eql(4); @@ -580,7 +580,7 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.rem(v1,v2)", function () { + suite('p5.Vector.rem(v1,v2)', function () { let v1, v2, res; beforeEach(function () { v1 = new mockP5.Vector(2, 3, 4); @@ -588,12 +588,12 @@ suite("p5.Vector", function () { res = mockP5.Vector.rem(v1, v2); }); - test("should return neither v1 nor v2", function () { + test('should return neither v1 nor v2', function () { expect(res).to.not.eql(v1); expect(res).to.not.eql(v2); }); - test("should be v1 % v2", function () { + test('should be v1 % v2', function () { expect(res.x).to.eql(v1.x % v2.x); expect(res.y).to.eql(v1.y % v2.y); expect(res.z).to.eql(v1.z % v2.z); @@ -601,14 +601,14 @@ suite("p5.Vector", function () { }); }); - suite("sub()", function () { + suite('sub()', function () { beforeEach(function () { v.x = 0; v.y = 0; v.z = 0; }); - suite("with p5.Vector", function () { - test("should sub x, y, z from the vector argument", function () { + suite('with p5.Vector', function () { + test('should sub x, y, z from the vector argument', function () { v.sub(new mockP5.Vector(2, 5, 6)); expect(v.x).to.eql(-2); expect(v.y).to.eql(-5); @@ -616,9 +616,9 @@ suite("p5.Vector", function () { }); }); - suite("with Array", function () { - suite("sub([2, 4])", function () { - test("should sub the x and y components", function () { + suite('with Array', function () { + suite('sub([2, 4])', function () { + test('should sub the x and y components', function () { v.sub([2, 4]); expect(v.x).to.eql(-2); expect(v.y).to.eql(-4); @@ -634,8 +634,8 @@ suite("p5.Vector", function () { }); }); - suite("sub(3,5)", function () { - test("should subtract the x and y components", function () { + suite('sub(3,5)', function () { + test('should subtract the x and y components', function () { v.sub(3, 5); expect(v.x).to.eql(-3); expect(v.y).to.eql(-5); @@ -643,8 +643,8 @@ suite("p5.Vector", function () { }); }); - suite("sub(2,3,4)", function () { - test("should subtract the x, y, z components", function () { + suite('sub(2,3,4)', function () { + test('should subtract the x, y, z components', function () { v.sub(5, 5, 5); expect(v.x).to.eql(-5); expect(v.y).to.eql(-5); @@ -652,7 +652,7 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.sub(v1, v2)", function () { + suite('p5.Vector.sub(v1, v2)', function () { var v1, v2, res; beforeEach(function () { v1 = new mockP5.Vector(2, 0, 3); @@ -660,12 +660,12 @@ suite("p5.Vector", function () { res = mockP5.Vector.sub(v1, v2); }); - test("should return neither v1 nor v2", function () { + test('should return neither v1 nor v2', function () { expect(res).to.not.eql(v1); expect(res).to.not.eql(v2); }); - test("should be v1 - v2", function () { + test('should be v1 - v2', function () { expect(res.x).to.eql(v1.x - v2.x); expect(res.y).to.eql(v1.y - v2.y); expect(res.z).to.eql(v1.z - v2.z); @@ -673,31 +673,31 @@ suite("p5.Vector", function () { }); }); - suite("mult()", function () { + suite('mult()', function () { beforeEach(function () { v = new mockP5.Vector(1, 1, 1); }); - test("should return the same object", function () { + test('should return the same object', function () { expect(v.mult(1)).to.eql(v); }); - test("should not change x, y, z if no argument is given", function () { + test('should not change x, y, z if no argument is given', function () { v.mult(); expect(v.x).to.eql(1); expect(v.y).to.eql(1); expect(v.z).to.eql(1); }); - test("should not change x, y, z if n is not a finite number", function () { + test('should not change x, y, z if n is not a finite number', function () { v.mult(NaN); expect(v.x).to.eql(1); expect(v.y).to.eql(1); expect(v.z).to.eql(1); }); - suite("with scalar", function () { - test("multiply the x, y, z with the scalar", function () { + suite('with scalar', function () { + test('multiply the x, y, z with the scalar', function () { v.mult(2); expect(v.x).to.eql(2); expect(v.y).to.eql(2); @@ -705,7 +705,7 @@ suite("p5.Vector", function () { }); }); - suite("v0.mult(v1)", function () { + suite('v0.mult(v1)', function () { var v0, v1; beforeEach(function () { v0 = new mockP5.Vector(1, 2, 3); @@ -713,14 +713,14 @@ suite("p5.Vector", function () { v0.mult(v1); }); - test("should do component wise multiplication", function () { + test('should do component wise multiplication', function () { expect(v0.x).to.eql(2); expect(v0.y).to.eql(6); expect(v0.z).to.eql(12); }); }); - suite("v0.mult(arr)", function () { + suite('v0.mult(arr)', function () { var v0, arr; beforeEach(function () { v0 = new mockP5.Vector(1, 2, 3); @@ -728,32 +728,32 @@ suite("p5.Vector", function () { v0.mult(arr); }); - test("should do component wise multiplication from an array", function () { + test('should do component wise multiplication from an array', function () { expect(v0.x).to.eql(2); expect(v0.y).to.eql(6); expect(v0.z).to.eql(12); }); }); - suite("p5.Vector.mult(v, n)", function () { + suite('p5.Vector.mult(v, n)', function () { var v, res; beforeEach(function () { v = new mockP5.Vector(1, 2, 3); res = mockP5.Vector.mult(v, 4); }); - test("should return a new p5.Vector", function () { + test('should return a new p5.Vector', function () { expect(res).to.not.eql(v); }); - test("should multiply the scalar", function () { + test('should multiply the scalar', function () { expect(res.x).to.eql(4); expect(res.y).to.eql(8); expect(res.z).to.eql(12); }); }); - suite("p5.Vector.mult(v, v", function () { + suite('p5.Vector.mult(v, v', function () { var v0, v1, res; beforeEach(function () { v0 = new mockP5.Vector(1, 2, 3); @@ -761,14 +761,14 @@ suite("p5.Vector", function () { res = mockP5.Vector.mult(v0, v1); }); - test("should return new vector from component wise multiplication", function () { + test('should return new vector from component wise multiplication', function () { expect(res.x).to.eql(2); expect(res.y).to.eql(6); expect(res.z).to.eql(12); }); }); - suite("p5.Vector.mult(v, arr", function () { + suite('p5.Vector.mult(v, arr', function () { var v0, arr, res; beforeEach(function () { v0 = new mockP5.Vector(1, 2, 3); @@ -776,7 +776,7 @@ suite("p5.Vector", function () { res = mockP5.Vector.mult(v0, arr); }); - test("should return new vector from component wise multiplication with an array", function () { + test('should return new vector from component wise multiplication with an array', function () { expect(res.x).to.eql(2); expect(res.y).to.eql(6); expect(res.z).to.eql(12); @@ -784,38 +784,38 @@ suite("p5.Vector", function () { }); }); - suite("div()", function () { + suite('div()', function () { beforeEach(function () { v = new mockP5.Vector(1, 1, 1); }); - test("should return the same object", function () { + test('should return the same object', function () { expect(v.div(1)).to.eql(v); }); - test("should not change x, y, z if no argument is given", function () { + test('should not change x, y, z if no argument is given', function () { v.div(); expect(v.x).to.eql(1); expect(v.y).to.eql(1); expect(v.z).to.eql(1); }); - test("should not change x, y, z if n is not a finite number", function () { + test('should not change x, y, z if n is not a finite number', function () { v.div(NaN); expect(v.x).to.eql(1); expect(v.y).to.eql(1); expect(v.z).to.eql(1); }); - suite("with scalar", function () { - test("divide the x, y, z with the scalar", function () { + suite('with scalar', function () { + test('divide the x, y, z with the scalar', function () { v.div(2); expect(v.x).to.be.closeTo(0.5, 0.01); expect(v.y).to.be.closeTo(0.5, 0.01); expect(v.z).to.be.closeTo(0.5, 0.01); }); - test("should not change x, y, z if n is 0", function () { + test('should not change x, y, z if n is 0', function () { v.div(0); expect(v.x).to.eql(1); expect(v.y).to.eql(1); @@ -823,29 +823,29 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.div(v, n)", function () { + suite('p5.Vector.div(v, n)', function () { var v, res; beforeEach(function () { v = new mockP5.Vector(1, 1, 1); res = mockP5.Vector.div(v, 4); }); - test("should not be undefined", function () { + test('should not be undefined', function () { expect(res).to.not.eql(undefined); }); - test("should return a new p5.Vector", function () { + test('should return a new p5.Vector', function () { expect(res).to.not.eql(v); }); - test("should divide the scalar", function () { + test('should divide the scalar', function () { expect(res.x).to.eql(0.25); expect(res.y).to.eql(0.25); expect(res.z).to.eql(0.25); }); }); - suite("v0.div(v1)", function () { + suite('v0.div(v1)', function () { var v0, v1, v2, v3; beforeEach(function () { v0 = new mockP5.Vector(2, 6, 9); @@ -856,20 +856,20 @@ suite("p5.Vector", function () { v0.div(v1); }); - test("should do component wise division", function () { + test('should do component wise division', function () { expect(v0.x).to.eql(1); expect(v0.y).to.eql(3); expect(v0.z).to.eql(3); }); - test("should not change x, y, z if v3 is all 0", function () { + test('should not change x, y, z if v3 is all 0', function () { v2.div(v3); expect(v2.x).to.eql(1); expect(v2.y).to.eql(1); expect(v2.z).to.eql(1); }); - test("should work on 2D vectors", function () { + test('should work on 2D vectors', function () { const v = new mockP5.Vector(1, 1); const divisor = new mockP5.Vector(2, 2); v.div(divisor); @@ -878,7 +878,7 @@ suite("p5.Vector", function () { expect(v.z).to.eql(0); }); - test("should work when the dividend has 0", function () { + test('should work when the dividend has 0', function () { const v = new mockP5.Vector(1, 0); const divisor = new mockP5.Vector(2, 2); v.div(divisor); @@ -887,7 +887,7 @@ suite("p5.Vector", function () { expect(v.z).to.eql(0); }); - test("should do nothing when the divisor has 0", function () { + test('should do nothing when the divisor has 0', function () { const v = new mockP5.Vector(1, 1); const divisor = new mockP5.Vector(0, 2); v.div(divisor); @@ -897,7 +897,7 @@ suite("p5.Vector", function () { }); }); - suite("v0.div(arr)", function () { + suite('v0.div(arr)', function () { var v0, v1, arr; beforeEach(function () { v0 = new mockP5.Vector(2, 6, 9); @@ -906,13 +906,13 @@ suite("p5.Vector", function () { v0.div(arr); }); - test("should do component wise division with an array", function () { + test('should do component wise division with an array', function () { expect(v0.x).to.eql(1); expect(v0.y).to.eql(3); expect(v0.z).to.eql(3); }); - test("should not change x, y, z if array contains 0", function () { + test('should not change x, y, z if array contains 0', function () { v1.div([0, 0, 0]); expect(v1.x).to.eql(1); expect(v1.y).to.eql(1); @@ -920,7 +920,7 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.div(v, v", function () { + suite('p5.Vector.div(v, v', function () { var v0, v1, res; beforeEach(function () { v0 = new mockP5.Vector(2, 6, 9); @@ -928,14 +928,14 @@ suite("p5.Vector", function () { res = mockP5.Vector.div(v0, v1); }); - test("should return new vector from component wise division", function () { + test('should return new vector from component wise division', function () { expect(res.x).to.eql(1); expect(res.y).to.eql(3); expect(res.z).to.eql(3); }); }); - suite("p5.Vector.div(v, arr", function () { + suite('p5.Vector.div(v, arr', function () { var v0, arr, res; beforeEach(function () { v0 = new mockP5.Vector(2, 6, 9); @@ -943,7 +943,7 @@ suite("p5.Vector", function () { res = mockP5.Vector.div(v0, arr); }); - test("should return new vector from component wise division with an array", function () { + test('should return new vector from component wise division with an array', function () { expect(res.x).to.eql(1); expect(res.y).to.eql(3); expect(res.z).to.eql(3); @@ -951,34 +951,34 @@ suite("p5.Vector", function () { }); }); - suite("dot", function () { + suite('dot', function () { beforeEach(function () { v.x = 1; v.y = 1; v.z = 1; }); - test("should return a number", function () { - expect(typeof v.dot(new mockP5.Vector()) === "number").to.eql(true); + test('should return a number', function () { + expect(typeof v.dot(new mockP5.Vector()) === 'number').to.eql(true); }); - suite("with p5.Vector", function () { - test("should be the dot product of the vector", function () { + suite('with p5.Vector', function () { + test('should be the dot product of the vector', function () { expect(v.dot(new mockP5.Vector(2, 2))).to.eql(4); }); }); - suite("with x, y, z", function () { - test("should be the dot product with x, y", function () { + suite('with x, y, z', function () { + test('should be the dot product with x, y', function () { expect(v.dot(2, 2)).to.eql(4); }); - test("should be the dot product with x, y, z", function () { + test('should be the dot product with x, y, z', function () { expect(v.dot(2, 2, 2)).to.eql(6); }); }); - suite("p5.Vector.dot(v, n)", function () { + suite('p5.Vector.dot(v, n)', function () { var v1, v2, res; beforeEach(function () { v1 = new mockP5.Vector(1, 1, 1); @@ -986,17 +986,17 @@ suite("p5.Vector", function () { res = mockP5.Vector.dot(v1, v2); }); - test("should return a number", function () { - expect(typeof res === "number").to.eql(true); + test('should return a number', function () { + expect(typeof res === 'number').to.eql(true); }); - test("should be the dot product of the two vectors", function () { + test('should be the dot product of the two vectors', function () { expect(res).to.eql(9); }); }); }); - suite("cross", function () { + suite('cross', function () { var res; beforeEach(function () { v.x = 1; @@ -1004,12 +1004,12 @@ suite("p5.Vector", function () { v.z = 1; }); - test("should return a new product", function () { + test('should return a new product', function () { expect(v.cross(new mockP5.Vector())).to.not.eql(v); }); - suite("with p5.Vector", function () { - test("should cross x, y, z from the vector argument", function () { + suite('with p5.Vector', function () { + test('should cross x, y, z from the vector argument', function () { res = v.cross(new mockP5.Vector(2, 5, 6)); expect(res.x).to.eql(1); //this.y * v.z - this.z * v.y expect(res.y).to.eql(-4); //this.z * v.x - this.x * v.z @@ -1017,7 +1017,7 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.cross(v1, v2)", function () { + suite('p5.Vector.cross(v1, v2)', function () { var v1, v2, res; beforeEach(function () { v1 = new mockP5.Vector(3, 6, 9); @@ -1025,16 +1025,16 @@ suite("p5.Vector", function () { res = mockP5.Vector.cross(v1, v2); }); - test("should not be undefined", function () { + test('should not be undefined', function () { expect(res).to.not.eql(undefined); }); - test("should return neither v1 nor v2", function () { + test('should return neither v1 nor v2', function () { expect(res).to.not.eql(v1); expect(res).to.not.eql(v2); }); - test("should the cross product of v1 and v2", function () { + test('should the cross product of v1 and v2', function () { expect(res.x).to.eql(-3); expect(res.y).to.eql(6); expect(res.z).to.eql(-3); @@ -1042,7 +1042,7 @@ suite("p5.Vector", function () { }); }); - suite("dist", function () { + suite('dist', function () { var b, c; beforeEach(function () { v = new mockP5.Vector(0, 0, 1); @@ -1050,50 +1050,50 @@ suite("p5.Vector", function () { c = new mockP5.Vector(3, 4, 1); }); - test("should return a number", function () { - expect(typeof v.dist(b) === "number").to.eql(true); + test('should return a number', function () { + expect(typeof v.dist(b) === 'number').to.eql(true); }); - test("should return distance between two vectors", function () { + test('should return distance between two vectors', function () { expect(v.dist(b)).to.eql(4); }); - test("should return distance between two vectors", function () { + test('should return distance between two vectors', function () { expect(v.dist(c)).to.eql(5); }); - test("should be commutative", function () { + test('should be commutative', function () { expect(b.dist(c)).to.eql(c.dist(b)); }); }); - suite("p5.Vector.dist(v1, v2)", function () { + suite('p5.Vector.dist(v1, v2)', function () { var v1, v2; beforeEach(function () { v1 = new mockP5.Vector(0, 0, 0); v2 = new mockP5.Vector(0, 3, 4); }); - test("should return a number", function () { - expect(typeof mockP5.Vector.dist(v1, v2) === "number").to.eql(true); + test('should return a number', function () { + expect(typeof mockP5.Vector.dist(v1, v2) === 'number').to.eql(true); }); - test("should be commutative", function () { + test('should be commutative', function () { expect(mockP5.Vector.dist(v1, v2)).to.eql(mockP5.Vector.dist(v2, v1)); }); }); - suite("normalize", function () { - suite("p5.Vector.prototype.normalize() [INSTANCE]", function () { + suite('normalize', function () { + suite('p5.Vector.prototype.normalize() [INSTANCE]', function () { beforeEach(function () { v = new mockP5.Vector(1, 1, 1); }); - test("should return the same object", function () { + test('should return the same object', function () { expect(v.normalize()).to.eql(v); }); - test("unit vector should not change values", function () { + test('unit vector should not change values', function () { v.x = 1; v.y = 0; v.z = 0; @@ -1103,7 +1103,7 @@ suite("p5.Vector", function () { expect(v.z).to.eql(0); }); - test("2,2,1 should normalize to ~0.66,0.66,0.33", function () { + test('2,2,1 should normalize to ~0.66,0.66,0.33', function () { v.x = 2; v.y = 2; v.z = 1; @@ -1114,28 +1114,28 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.normalize(v) [CLASS]", function () { + suite('p5.Vector.normalize(v) [CLASS]', function () { var res; beforeEach(function () { v = new mockP5.Vector(1, 0, 0); res = mockP5.Vector.normalize(v); }); - test("should not be undefined", function () { + test('should not be undefined', function () { expect(res).to.not.eql(undefined); }); - test("should not return same object v", function () { + test('should not return same object v', function () { expect(res).to.not.equal(v); }); - test("unit vector 1,0,0 should normalize to 1,0,0", function () { + test('unit vector 1,0,0 should normalize to 1,0,0', function () { expect(res.x).to.eql(1); expect(res.y).to.eql(0); expect(res.z).to.eql(0); }); - test("2,2,1 should normalize to ~0.66,0.66,0.33", function () { + test('2,2,1 should normalize to ~0.66,0.66,0.33', function () { v.x = 2; v.y = 2; v.z = 1; @@ -1147,20 +1147,20 @@ suite("p5.Vector", function () { }); }); - suite("limit", function () { + suite('limit', function () { let v; beforeEach(function () { v = new mockP5.Vector(5, 5, 5); }); - suite("p5.Vector.prototype.limit() [INSTANCE]", function () { - test("should return the same object", function () { + suite('p5.Vector.prototype.limit() [INSTANCE]', function () { + test('should return the same object', function () { expect(v.limit()).to.equal(v); }); - suite("with a vector larger than the limit", function () { - test("should limit the vector", function () { + suite('with a vector larger than the limit', function () { + test('should limit the vector', function () { v.limit(1); expect(v.x).to.be.closeTo(0.5773, 0.01); expect(v.y).to.be.closeTo(0.5773, 0.01); @@ -1168,8 +1168,8 @@ suite("p5.Vector", function () { }); }); - suite("with a vector smaller than the limit", function () { - test("should not limit the vector", function () { + suite('with a vector smaller than the limit', function () { + test('should not limit the vector', function () { v.limit(8.67); expect(v.x).to.eql(5); expect(v.y).to.eql(5); @@ -1178,13 +1178,13 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.limit() [CLASS]", function () { - test("should not return the same object", function () { + suite('p5.Vector.limit() [CLASS]', function () { + test('should not return the same object', function () { expect(mockP5.Vector.limit(v)).to.not.equal(v); }); - suite("with a vector larger than the limit", function () { - test("should limit the vector", function () { + suite('with a vector larger than the limit', function () { + test('should limit the vector', function () { const res = mockP5.Vector.limit(v, 1); expect(res.x).to.be.closeTo(0.5773, 0.01); expect(res.y).to.be.closeTo(0.5773, 0.01); @@ -1192,8 +1192,8 @@ suite("p5.Vector", function () { }); }); - suite("with a vector smaller than the limit", function () { - test("should not limit the vector", function () { + suite('with a vector smaller than the limit', function () { + test('should not limit the vector', function () { const res = mockP5.Vector.limit(v, 8.67); expect(res.x).to.eql(5); expect(res.y).to.eql(5); @@ -1201,8 +1201,8 @@ suite("p5.Vector", function () { }); }); - suite("when given a target vector", function () { - test("should store limited vector in the target", function () { + suite('when given a target vector', function () { + test('should store limited vector in the target', function () { const target = new mockP5.Vector(0, 0, 0); mockP5.Vector.limit(v, 1, target); expect(target.x).to.be.closeTo(0.5773, 0.01); @@ -1213,26 +1213,26 @@ suite("p5.Vector", function () { }); }); - suite("setMag", function () { + suite('setMag', function () { let v; beforeEach(function () { v = new mockP5.Vector(1, 0, 0); }); - suite("p5.Vector.setMag() [INSTANCE]", function () { - test("should return the same object", function () { + suite('p5.Vector.setMag() [INSTANCE]', function () { + test('should return the same object', function () { expect(v.setMag(2)).to.equal(v); }); - test("should set the magnitude of the vector", function () { + test('should set the magnitude of the vector', function () { v.setMag(4); expect(v.x).to.eql(4); expect(v.y).to.eql(0); expect(v.z).to.eql(0); }); - test("should set the magnitude of the vector", function () { + test('should set the magnitude of the vector', function () { v.x = 2; v.y = 3; v.z = -6; @@ -1243,19 +1243,19 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.prototype.setMag() [CLASS]", function () { - test("should not return the same object", function () { + suite('p5.Vector.prototype.setMag() [CLASS]', function () { + test('should not return the same object', function () { expect(mockP5.Vector.setMag(v, 2)).to.not.equal(v); }); - test("should set the magnitude of the vector", function () { + test('should set the magnitude of the vector', function () { const res = mockP5.Vector.setMag(v, 4); expect(res.x).to.eql(4); expect(res.y).to.eql(0); expect(res.z).to.eql(0); }); - test("should set the magnitude of the vector", function () { + test('should set the magnitude of the vector', function () { v.x = 2; v.y = 3; v.z = -6; @@ -1265,8 +1265,8 @@ suite("p5.Vector", function () { expect(res.z).to.eql(-12); }); - suite("when given a target vector", function () { - test("should set the magnitude on the target", function () { + suite('when given a target vector', function () { + test('should set the magnitude on the target', function () { const target = new mockP5.Vector(0, 1, 0); const res = mockP5.Vector.setMag(v, 4, target); expect(target).to.equal(res); @@ -1278,57 +1278,57 @@ suite("p5.Vector", function () { }); }); - suite("heading", function () { + suite('heading', function () { beforeEach(function () { v = new mockP5.Vector(); }); - suite("p5.Vector.prototype.heading() [INSTANCE]", function () { - test("should return a number", function () { - expect(typeof v.heading() === "number").to.eql(true); + suite('p5.Vector.prototype.heading() [INSTANCE]', function () { + test('should return a number', function () { + expect(typeof v.heading() === 'number').to.eql(true); }); - test("heading for vector pointing right is 0", function () { + test('heading for vector pointing right is 0', function () { v.x = 1; v.y = 0; v.z = 0; expect(v.heading()).to.be.closeTo(0, 0.01); }); - test("heading for vector pointing down is PI/2", function () { + test('heading for vector pointing down is PI/2', function () { v.x = 0; v.y = 1; v.z = 0; expect(v.heading()).to.be.closeTo(Math.PI / 2, 0.01); }); - test("heading for vector pointing left is PI", function () { + test('heading for vector pointing left is PI', function () { v.x = -1; v.y = 0; v.z = 0; expect(v.heading()).to.be.closeTo(Math.PI, 0.01); }); - suite.todo("with `angleMode(DEGREES)`", function () { + suite.todo('with `angleMode(DEGREES)`', function () { beforeEach(function () { mockP5Prototype.angleMode(mockP5.DEGREES); }); - test("heading for vector pointing right is 0", function () { + test('heading for vector pointing right is 0', function () { v.x = 1; v.y = 0; v.z = 0; expect(v.heading()).to.equal(0); }); - test("heading for vector pointing down is 90", function () { + test('heading for vector pointing down is 90', function () { v.x = 0; v.y = 1; v.z = 0; expect(v.heading()).to.equal(90); }); - test("heading for vector pointing left is 180", function () { + test('heading for vector pointing left is 180', function () { v.x = -1; v.y = 0; v.z = 0; @@ -1337,26 +1337,26 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.heading() [CLASS]", function () { - test("should return a number", function () { - expect(typeof mockP5.Vector.heading(v) === "number").to.eql(true); + suite('p5.Vector.heading() [CLASS]', function () { + test('should return a number', function () { + expect(typeof mockP5.Vector.heading(v) === 'number').to.eql(true); }); - test("heading for vector pointing right is 0", function () { + test('heading for vector pointing right is 0', function () { v.x = 1; v.y = 0; v.z = 0; expect(mockP5.Vector.heading(v)).to.be.closeTo(0, 0.01); }); - test("heading for vector pointing down is PI/2", function () { + test('heading for vector pointing down is PI/2', function () { v.x = 0; v.y = 1; v.z = 0; expect(mockP5.Vector.heading(v)).to.be.closeTo(Math.PI / 2, 0.01); }); - test("heading for vector pointing left is PI", function () { + test('heading for vector pointing left is PI', function () { v.x = -1; v.y = 0; v.z = 0; @@ -1365,8 +1365,8 @@ suite("p5.Vector", function () { }); }); - suite("lerp", function () { - test("should return the same object", function () { + suite('lerp', function () { + test('should return the same object', function () { expect(v.lerp()).to.eql(v); }); @@ -1379,7 +1379,7 @@ suite("p5.Vector", function () { // }); // }); - suite("with x, y, z, amt", function () { + suite('with x, y, z, amt', function () { beforeEach(function () { v.x = 0; v.y = 0; @@ -1387,21 +1387,21 @@ suite("p5.Vector", function () { v.lerp(2, 2, 2, 0.5); }); - test("should lerp x by amt", function () { + test('should lerp x by amt', function () { expect(v.x).to.eql(1); }); - test("should lerp y by amt", function () { + test('should lerp y by amt', function () { expect(v.y).to.eql(1); }); - test("should lerp z by amt", function () { + test('should lerp z by amt', function () { expect(v.z).to.eql(1); }); }); - suite("with no amt", function () { - test("should assume 0 amt", function () { + suite('with no amt', function () { + test('should assume 0 amt', function () { v.x = 0; v.y = 0; v.z = 0; @@ -1413,7 +1413,7 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.lerp(v1, v2, amt)", function () { + suite('p5.Vector.lerp(v1, v2, amt)', function () { var res, v1, v2; beforeEach(function () { v1 = new mockP5.Vector(0, 0, 0); @@ -1421,48 +1421,48 @@ suite("p5.Vector", function () { res = mockP5.Vector.lerp(v1, v2, 0.5); }); - test("should not be undefined", function () { + test('should not be undefined', function () { expect(res).to.not.eql(undefined); }); - test("should be a p5.Vector", function () { + test('should be a p5.Vector', function () { expect(res).to.be.an.instanceof(mockP5.Vector); }); - test("should return neither v1 nor v2", function () { + 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 [1, 1, 1]", function () { + test('should res to be [1, 1, 1]', function () { expect(res.x).to.eql(1); expect(res.y).to.eql(1); expect(res.z).to.eql(1); }); }); - suite("v.slerp(w, amt)", function () { + suite('v.slerp(w, amt)', function () { var w; beforeEach(function () { v.set(1, 2, 3); w = new mockP5.Vector(4, 6, 8); }); - test("if amt is 0, returns original vector", function () { + test('if amt is 0, returns original vector', function () { v.slerp(w, 0); expect(v.x).to.eql(1); expect(v.y).to.eql(2); expect(v.z).to.eql(3); }); - test("if amt is 1, returns argument vector", function () { + test('if amt is 1, returns argument vector', function () { v.slerp(w, 1); expect(v.x).to.eql(4); expect(v.y).to.eql(6); expect(v.z).to.eql(8); }); - test("if both v and w are 2D, then result will also be 2D.", function () { + test('if both v and w are 2D, then result will also be 2D.', function () { v.set(2, 3, 0); w.set(3, -2, 0); v.slerp(w, 0.3); @@ -1474,7 +1474,7 @@ suite("p5.Vector", function () { expect(v.z).to.eql(0); }); - test("if one side is a zero vector, linearly interpolate.", function () { + test('if one side is a zero vector, linearly interpolate.', function () { v.set(0, 0, 0); w.set(2, 4, 6); v.slerp(w, 0.5); @@ -1483,7 +1483,7 @@ suite("p5.Vector", function () { expect(v.z).to.eql(3); }); - test("If they are pointing in the same direction, linearly interpolate.", function () { + test('If they are pointing in the same direction, linearly interpolate.', function () { v.set(5, 11, 16); w.set(15, 33, 48); v.slerp(w, 0.5); @@ -1493,7 +1493,7 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.slerp(v1, v2, amt)", function () { + suite('p5.Vector.slerp(v1, v2, amt)', function () { var res, v1, v2; beforeEach(function () { v1 = new mockP5.Vector(1, 0, 0); @@ -1501,33 +1501,33 @@ suite("p5.Vector", function () { res = mockP5.Vector.slerp(v1, v2, 1 / 3); }); - test("should not be undefined", function () { + test('should not be undefined', function () { expect(res).to.not.eql(undefined); }); - test("should be a p5.Vector", function () { + test('should be a p5.Vector', function () { expect(res).to.be.an.instanceof(mockP5.Vector); }); - test("should return neither v1 nor v2", function () { + test('should return neither v1 nor v2', function () { expect(res).to.not.eql(v1); expect(res).to.not.eql(v2); }); - test("Make sure the interpolation in 1/3 is correct", function () { + test('Make sure the interpolation in 1/3 is correct', function () { expect(res.x).to.be.closeTo(Math.cos(Math.PI / 6), 0.00001); expect(res.y).to.be.closeTo(0, 0.00001); expect(res.z).to.be.closeTo(Math.sin(Math.PI / 6), 0.00001); }); - test("Make sure the interpolation in -1/3 is correct", function () { + test('Make sure the interpolation in -1/3 is correct', function () { mockP5.Vector.slerp(v1, v2, -1 / 3, res); expect(res.x).to.be.closeTo(Math.cos(-Math.PI / 6), 0.00001); expect(res.y).to.be.closeTo(0, 0.00001); expect(res.z).to.be.closeTo(Math.sin(-Math.PI / 6), 0.00001); }); - test("Make sure the interpolation in 5/3 is correct", function () { + test('Make sure the interpolation in 5/3 is correct', function () { mockP5.Vector.slerp(v1, v2, 5 / 3, res); expect(res.x).to.be.closeTo(Math.cos((5 * Math.PI) / 6), 0.00001); expect(res.y).to.be.closeTo(0, 0.00001); @@ -1535,68 +1535,68 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.fromAngle(angle)", function () { + suite('p5.Vector.fromAngle(angle)', function () { var res, angle; beforeEach(function () { angle = Math.PI / 2; res = mockP5.Vector.fromAngle(angle); }); - test("should be a p5.Vector with values (0,1)", function () { + test('should be a p5.Vector with values (0,1)', function () { expect(res.x).to.be.closeTo(0, 0.01); expect(res.y).to.be.closeTo(1, 0.01); }); }); - suite("p5.Vector.random2D()", function () { + suite('p5.Vector.random2D()', function () { var res; beforeEach(function () { res = mockP5.Vector.random2D(); }); - test("should be a unit p5.Vector", function () { + test('should be a unit p5.Vector', function () { expect(res.mag()).to.be.closeTo(1, 0.01); }); }); - suite("p5.Vector.random3D()", function () { + suite('p5.Vector.random3D()', function () { var res; beforeEach(function () { res = mockP5.Vector.random3D(); }); - test("should be a unit p5.Vector", function () { + test('should be a unit p5.Vector', function () { expect(res.mag()).to.be.closeTo(1, 0.01); }); }); - suite("array", function () { + suite('array', function () { beforeEach(function () { v = new mockP5.Vector(1, 23, 4); }); - suite("p5.Vector.prototype.array() [INSTANCE]", function () { - test("should return an array", function () { + suite('p5.Vector.prototype.array() [INSTANCE]', function () { + test('should return an array', function () { expect(v.array()).to.be.instanceof(Array); }); - test("should return an with the x y and z components", function () { + test('should return an with the x y and z components', function () { expect(v.array()).to.eql([1, 23, 4]); }); }); - suite("p5.Vector.array() [CLASS]", function () { - test("should return an array", function () { + suite('p5.Vector.array() [CLASS]', function () { + test('should return an array', function () { expect(mockP5.Vector.array(v)).to.be.instanceof(Array); }); - test("should return an with the x y and z components", function () { + test('should return an with the x y and z components', function () { expect(mockP5.Vector.array(v)).to.eql([1, 23, 4]); }); }); }); - suite("reflect", function () { - suite("p5.Vector.prototype.reflect() [INSTANCE]", function () { + suite('reflect', function () { + suite('p5.Vector.prototype.reflect() [INSTANCE]', function () { let incoming_x, incoming_y, incoming_z, original_incoming; let x_normal, y_normal, z_normal; let x_bounce_incoming, @@ -1641,35 +1641,35 @@ suite("p5.Vector", function () { z_bounce_outgoing = z_bounce_incoming.reflect(z_normal); }); - test("should return a p5.Vector", function () { + test('should return a p5.Vector', function () { expect(x_bounce_incoming).to.be.an.instanceof(mockP5.Vector); expect(y_bounce_incoming).to.be.an.instanceof(mockP5.Vector); expect(z_bounce_incoming).to.be.an.instanceof(mockP5.Vector); }); - test("should update this", function () { + test('should update this', function () { assert.equal(x_bounce_incoming, x_bounce_outgoing); assert.equal(y_bounce_incoming, y_bounce_outgoing); assert.equal(z_bounce_incoming, z_bounce_outgoing); }); - test("x-normal should flip incoming x component and maintain y,z components", function () { + test('x-normal should flip incoming x component and maintain y,z components', function () { expect(x_bounce_outgoing.x).to.be.closeTo(-1, 0.01); expect(x_bounce_outgoing.y).to.be.closeTo(1, 0.01); expect(x_bounce_outgoing.z).to.be.closeTo(1, 0.01); }); - test("y-normal should flip incoming y component and maintain x,z components", function () { + test('y-normal should flip incoming y component and maintain x,z components', function () { expect(y_bounce_outgoing.x).to.be.closeTo(1, 0.01); expect(y_bounce_outgoing.y).to.be.closeTo(-1, 0.01); expect(y_bounce_outgoing.z).to.be.closeTo(1, 0.01); }); - test("z-normal should flip incoming z component and maintain x,y components", function () { + test('z-normal should flip incoming z component and maintain x,y components', function () { expect(z_bounce_outgoing.x).to.be.closeTo(1, 0.01); expect(z_bounce_outgoing.y).to.be.closeTo(1, 0.01); expect(z_bounce_outgoing.z).to.be.closeTo(-1, 0.01); }); - test("angle of incidence should match angle of reflection", function () { + test('angle of incidence should match angle of reflection', function () { expect( Math.abs(x_normal.angleBetween(original_incoming)) ).to.be.closeTo( @@ -1689,7 +1689,7 @@ suite("p5.Vector", function () { 0.01 ); }); - test("should not update surface normal", function () { + test('should not update surface normal', function () { const tolerance = 0.001; assert.closeTo(x_normal.x, 3, tolerance); assert.closeTo(x_normal.y, 0, tolerance); @@ -1705,7 +1705,7 @@ suite("p5.Vector", function () { }); }); - suite("p5.Vector.reflect() [CLASS]", function () { + suite('p5.Vector.reflect() [CLASS]', function () { let incoming_x, incoming_y, incoming_z, original_incoming; let x_target, y_target, z_target; let x_normal, y_normal, z_normal; @@ -1767,19 +1767,19 @@ suite("p5.Vector", function () { ); }); - test("should return a p5.Vector", function () { + test('should return a p5.Vector', function () { expect(x_bounce_incoming).to.be.an.instanceof(mockP5.Vector); expect(y_bounce_incoming).to.be.an.instanceof(mockP5.Vector); expect(z_bounce_incoming).to.be.an.instanceof(mockP5.Vector); }); - test("should not update this", function () { + test('should not update this', function () { expect(x_bounce_incoming).to.not.equal(x_bounce_outgoing); expect(y_bounce_incoming).to.not.equal(y_bounce_outgoing); expect(z_bounce_incoming).to.not.equal(z_bounce_outgoing); }); - test("should not update surface normal", function () { + test('should not update surface normal', function () { const tolerance = 0.001; assert.closeTo(x_normal.x, 3, tolerance); assert.closeTo(x_normal.y, 0, tolerance); @@ -1794,29 +1794,29 @@ suite("p5.Vector", function () { assert.closeTo(z_normal.z, 3, tolerance); }); - test("should update target", function () { + test('should update target', function () { assert.equal(x_target, x_bounce_outgoing); assert.equal(y_target, y_bounce_outgoing); assert.equal(z_target, z_bounce_outgoing); }); - test("x-normal should flip incoming x component and maintain y,z components", function () { + test('x-normal should flip incoming x component and maintain y,z components', function () { expect(x_bounce_outgoing.x).to.be.closeTo(-1, 0.01); expect(x_bounce_outgoing.y).to.be.closeTo(1, 0.01); expect(x_bounce_outgoing.z).to.be.closeTo(1, 0.01); }); - test("y-normal should flip incoming y component and maintain x,z components", function () { + test('y-normal should flip incoming y component and maintain x,z components', function () { expect(y_bounce_outgoing.x).to.be.closeTo(1, 0.01); expect(y_bounce_outgoing.y).to.be.closeTo(-1, 0.01); expect(y_bounce_outgoing.z).to.be.closeTo(1, 0.01); }); - test("z-normal should flip incoming z component and maintain x,y components", function () { + test('z-normal should flip incoming z component and maintain x,y components', function () { expect(z_bounce_outgoing.x).to.be.closeTo(1, 0.01); expect(z_bounce_outgoing.y).to.be.closeTo(1, 0.01); expect(z_bounce_outgoing.z).to.be.closeTo(-1, 0.01); }); - test("angle of incidence should match angle of reflection", function () { + test('angle of incidence should match angle of reflection', function () { expect( Math.abs(x_normal.angleBetween(original_incoming)) ).to.be.closeTo( @@ -1839,7 +1839,7 @@ suite("p5.Vector", function () { }); }); - suite("mag", function () { + suite('mag', function () { const MAG = 3.7416573867739413; // sqrt(1*1 + 2*2 + 3*3) let v0; @@ -1850,22 +1850,22 @@ suite("p5.Vector", function () { v1 = new mockP5.Vector(1, 2, 3); }); - suite("p5.Vector.prototype.mag() [INSTANCE]", function () { - test("should return the magnitude of the vector", function () { + suite('p5.Vector.prototype.mag() [INSTANCE]', function () { + test('should return the magnitude of the vector', function () { expect(v0.mag()).to.eql(0); expect(v1.mag()).to.eql(MAG); }); }); - suite("p5.Vector.mag() [CLASS]", function () { - test("should return the magnitude of the vector", function () { + suite('p5.Vector.mag() [CLASS]', function () { + test('should return the magnitude of the vector', function () { expect(mockP5.Vector.mag(v0)).to.eql(0); expect(mockP5.Vector.mag(v1)).to.eql(MAG); }); }); }); - suite("magSq", function () { + suite('magSq', function () { const MAG = 14; // 1*1 + 2*2 + 3*3 let v0; @@ -1876,24 +1876,24 @@ suite("p5.Vector", function () { v1 = new mockP5.Vector(1, 2, 3); }); - suite("p5.Vector.prototype.magSq() [INSTANCE]", function () { - test("should return the magnitude of the vector", function () { + suite('p5.Vector.prototype.magSq() [INSTANCE]', function () { + test('should return the magnitude of the vector', function () { expect(v0.magSq()).to.eql(0); expect(v1.magSq()).to.eql(MAG); }); }); - suite("p5.Vector.magSq() [CLASS]", function () { - test("should return the magnitude of the vector", function () { + suite('p5.Vector.magSq() [CLASS]', function () { + test('should return the magnitude of the vector', function () { expect(mockP5.Vector.magSq(v0)).to.eql(0); expect(mockP5.Vector.magSq(v1)).to.eql(MAG); }); }); }); - suite("equals", function () { - suite("p5.Vector.prototype.equals() [INSTANCE]", function () { - test("should return false for parameters inequal to the vector", function () { + suite('equals', function () { + suite('p5.Vector.prototype.equals() [INSTANCE]', function () { + test('should return false for parameters inequal to the vector', function () { const v1 = new mockP5.Vector(0, -1, 1); const v2 = new mockP5.Vector(1, 2, 3); const a2 = [1, 2, 3]; @@ -1902,26 +1902,26 @@ suite("p5.Vector", function () { expect(v1.equals(1, 2, 3)).to.be.false; }); - test("should return true for equal vectors", function () { + test('should return true for equal vectors', function () { const v1 = new mockP5.Vector(0, -1, 1); const v2 = new mockP5.Vector(0, -1, 1); expect(v1.equals(v2)).to.be.true; }); - test("should return true for arrays equal to the vector", function () { + test('should return true for arrays equal to the vector', function () { const v1 = new mockP5.Vector(0, -1, 1); const a1 = [0, -1, 1]; expect(v1.equals(a1)).to.be.true; }); - test("should return true for arguments equal to the vector", function () { + test('should return true for arguments equal to the vector', function () { const v1 = new mockP5.Vector(0, -1, 1); expect(v1.equals(0, -1, 1)).to.be.true; }); }); - suite("p5.Vector.equals() [CLASS]", function () { - test("should return false for inequal parameters", function () { + suite('p5.Vector.equals() [CLASS]', function () { + test('should return false for inequal parameters', function () { const v1 = new mockP5.Vector(0, -1, 1); const v2 = new mockP5.Vector(1, 2, 3); const a2 = [1, 2, 3]; @@ -1930,20 +1930,20 @@ suite("p5.Vector", function () { expect(mockP5.Vector.equals(a2, v1)).to.be.false; }); - test("should return true for equal vectors", function () { + test('should return true for equal vectors', function () { const v1 = new mockP5.Vector(0, -1, 1); const v2 = new mockP5.Vector(0, -1, 1); expect(mockP5.Vector.equals(v1, v2)).to.be.true; }); - test("should return true for equal vectors and arrays", function () { + test('should return true for equal vectors and arrays', function () { const v1 = new mockP5.Vector(0, -1, 1); const a1 = [0, -1, 1]; expect(mockP5.Vector.equals(v1, a1)).to.be.true; expect(mockP5.Vector.equals(a1, v1)).to.be.true; }); - test("should return true for equal arrays", function () { + test('should return true for equal arrays', function () { const a1 = [0, -1, 1]; const a2 = [0, -1, 1]; expect(mockP5.Vector.equals(a1, a2)).to.be.true; @@ -1951,12 +1951,12 @@ suite("p5.Vector", function () { }); }); - suite("set values", function () { + suite('set values', function () { beforeEach(function () { v = new mockP5.Vector(); }); - test("should set values to [0,0,0] if values array is empty", function () { + test('should set values to [0,0,0] if values array is empty', function () { v.values = []; assert.equal(v.x, 0); assert.equal(v.y, 0); @@ -1964,8 +1964,8 @@ suite("p5.Vector", function () { assert.equal(v.dimensions, 2); }); }); - suite("get value", function () { - test("should return element in range of a non empty vector", function () { + suite('get value', function () { + test('should return element in range of a non empty vector', function () { let vect = new mockP5.Vector(1, 2, 3, 4); assert.equal(vect.getValue(0), 1); assert.equal(vect.getValue(1), 2); @@ -1974,7 +1974,7 @@ suite("p5.Vector", function () { }); test.fails( - "should throw friendly error if attempting to get element outside lenght", + 'should throw friendly error if attempting to get element outside lenght', function () { let vect = new mockP5.Vector(1, 2, 3, 4); assert.equal(vect.getValue(5), 1); @@ -1982,8 +1982,8 @@ suite("p5.Vector", function () { ); }); - suite("set value", function () { - test("should set value of element in range", function () { + suite('set value', function () { + test('should set value of element in range', function () { let vect = new mockP5.Vector(1, 2, 3, 4); vect.setValue(0, 7); assert.equal(vect.getValue(0), 7); @@ -1993,7 +1993,7 @@ suite("p5.Vector", function () { }); test.fails( - "should throw friendly error if attempting to set element outside lenght", + 'should throw friendly error if attempting to set element outside lenght', function () { let vect = new mockP5.Vector(1, 2, 3, 4); vect.setValue(100, 7); @@ -2001,20 +2001,20 @@ suite("p5.Vector", function () { ); }); - describe("get w", () => { - it("should return the w component of the vector", () => { + describe('get w', () => { + it('should return the w component of the vector', () => { v = new mockP5.Vector(1, 2, 3, 4); expect(v.w).toBe(4); }); - it("should return 0 if w component is not set", () => { + it('should return 0 if w component is not set', () => { v = new mockP5.Vector(1, 2, 3); expect(v.w).toBe(0); }); }); - describe("set w", () => { - it("should set 4th dimension of vector to w value if it exists", () => { + describe('set w', () => { + it('should set 4th dimension of vector to w value if it exists', () => { v = new mockP5.Vector(1, 2, 3, 4); v.w = 7; expect(v.x).toBe(1); @@ -2023,7 +2023,7 @@ suite("p5.Vector", function () { expect(v.w).toBe(7); }); - it("should throw error if trying to set w if vector dimensions is less than 4", () => { + it('should throw error if trying to set w if vector dimensions is less than 4', () => { v = new mockP5.Vector(1, 2); v.w = 5; console.log(v); @@ -2032,15 +2032,15 @@ suite("p5.Vector", function () { }); }); - describe("vector to string", () => { - it("should return the string version of a vector", () => { + describe('vector to string', () => { + it('should return the string version of a vector', () => { v = new mockP5.Vector(1, 2, 3, 4); - expect(v.toString()).toBe("[1, 2, 3, 4]"); + expect(v.toString()).toBe('[1, 2, 3, 4]'); }); }); - describe("set heading", () => { - it("should rotate a 2D vector by specified angle without changing magnitude", () => { + describe('set heading', () => { + it('should rotate a 2D vector by specified angle without changing magnitude', () => { v = new mockP5.Vector(0, 2); const mag = v.mag(); expect(v.setHeading(2 * Math.PI).mag()).toBe(mag); @@ -2049,27 +2049,27 @@ suite("p5.Vector", function () { }); }); - describe("clamp to zero", () => { - it("should clamp values cloze to zero to zero, with Number.epsilon value", () => { + describe('clamp to zero', () => { + it('should clamp values cloze to zero to zero, with Number.epsilon value', () => { v = new mockP5.Vector(0, 1, 0.5, 0.1, 0.0000000000000001); expect(v.clampToZero().values).toEqual([0, 1, 0.5, 0.1, 0]); }); }); - suite("p5.Vector.fromAngles()", function () { - it("should create a v3ctor froma pair of ISO spherical angles", () => { + suite('p5.Vector.fromAngles()', function () { + it('should create a v3ctor froma pair of ISO spherical angles', () => { let vect = mockP5.Vector.fromAngles(0, 0); expect(vect.values).toEqual([0, -1, 0]); }); }); - suite("p5.Vector.rotate()", function () { - it("should rotate the vector (only 2D vectors) by the given angle; magnitude remains the same.", () => { + suite('p5.Vector.rotate()', function () { + it('should rotate the vector (only 2D vectors) by the given angle; magnitude remains the same.', () => { v = new mockP5.Vector(0, 1, 2); let target = new mockP5.Vector(); mockP5.Vector.rotate(v, 1 * Math.PI, target); expect(target.values).toEqual([ - -4.10759023698152e-16, -2.23606797749979, 2, + -4.10759023698152e-16, -2.23606797749979, 2 ]); }); }); diff --git a/test/unit/type/loading.js b/test/unit/type/loading.js index dbbef1ebe2..a1c0b174af 100644 --- a/test/unit/type/loading.js +++ b/test/unit/type/loading.js @@ -41,7 +41,7 @@ suite('Loading Fonts', function () { })); test.skip('loadFont.callback', async () => new Promise(done => { - myp5.loadFont(fontFile, (pFont) => { + myp5.loadFont(fontFile, pFont => { assert.ok(pFont, 'acmesa.ttf loaded'); assert.equal(pFont.name, 'A.C.M.E. Secret Agent'); assert.isTrue(pFont instanceof p5.Font); diff --git a/test/unit/types/generate-types.js b/test/unit/types/generate-types.js index 88d19b5e1a..47fa5b1f81 100644 --- a/test/unit/types/generate-types.js +++ b/test/unit/types/generate-types.js @@ -11,180 +11,180 @@ import { // Move absFuncDoc to the top level const absFuncDoc = { - "description": { - "type": "root", - "children": [ + 'description': { + 'type': 'root', + 'children': [ { - "type": "paragraph", - "children": [ + 'type': 'paragraph', + 'children': [ { - "type": "text", - "value": "Calculates the absolute value of a number." + 'type': 'text', + 'value': 'Calculates the absolute value of a number.' } ] }, { - "type": "paragraph", - "children": [ + 'type': 'paragraph', + 'children': [ { - "type": "text", - "value": "A number's absolute value is its distance from zero on the number line.\n-5 and 5 are both five units away from zero, so calling " + 'type': 'text', + 'value': "A number's absolute value is its distance from zero on the number line.\n-5 and 5 are both five units away from zero, so calling " }, { - "type": "inlineCode", - "value": "abs(-5)" + 'type': 'inlineCode', + 'value': 'abs(-5)' }, { - "type": "text", - "value": " and\n" + 'type': 'text', + 'value': ' and\n' }, { - "type": "inlineCode", - "value": "abs(5)" + 'type': 'inlineCode', + 'value': 'abs(5)' }, { - "type": "text", - "value": " both return 5. The absolute value of a number is always positive." + 'type': 'text', + 'value': ' both return 5. The absolute value of a number is always positive.' } ] } ] }, - "tags": [ + 'tags': [ { - "title": "method", - "description": null, - "lineNumber": 7, - "name": "abs" + 'title': 'method', + 'description': null, + 'lineNumber': 7, + 'name': 'abs' }, { - "title": "param", - "description": "number to compute.", - "lineNumber": 8, - "type": { - "type": "NameExpression", - "name": "Number" + 'title': 'param', + 'description': 'number to compute.', + 'lineNumber': 8, + 'type': { + 'type': 'NameExpression', + 'name': 'Number' }, - "name": "n" + 'name': 'n' }, { - "title": "return", - "description": "absolute value of given number.", - "lineNumber": 9, - "type": { - "type": "NameExpression", - "name": "Number" + 'title': 'return', + 'description': 'absolute value of given number.', + 'lineNumber': 9, + 'type': { + 'type': 'NameExpression', + 'name': 'Number' } }, { - "title": "example", - "description": "
\n\nfunction setup() {\n createCanvas(100, 100);\n\n describe('A gray square with a vertical black line that divides it in half. A white rectangle gets taller when the user moves the mouse away from the line.');\n}\n\nfunction draw() {\n background(200);\n\n // Divide the canvas.\n line(50, 0, 50, 100);\n\n // Calculate the mouse's distance from the middle.\n let h = abs(mouseX - 50);\n\n // Draw a rectangle based on the mouse's distance\n // from the middle.\n rect(0, 100 - h, 100, h);\n}\n\n
", - "lineNumber": 11 + 'title': 'example', + 'description': "
\n\nfunction setup() {\n createCanvas(100, 100);\n\n describe('A gray square with a vertical black line that divides it in half. A white rectangle gets taller when the user moves the mouse away from the line.');\n}\n\nfunction draw() {\n background(200);\n\n // Divide the canvas.\n line(50, 0, 50, 100);\n\n // Calculate the mouse's distance from the middle.\n let h = abs(mouseX - 50);\n\n // Draw a rectangle based on the mouse's distance\n // from the middle.\n rect(0, 100 - h, 100, h);\n}\n\n
", + 'lineNumber': 11 } ], - "loc": { - "start": { - "line": 9, - "column": 2, - "index": 112 + 'loc': { + 'start': { + 'line': 9, + 'column': 2, + 'index': 112 }, - "end": { - "line": 44, - "column": 5, - "index": 1167 + 'end': { + 'line': 44, + 'column': 5, + 'index': 1167 } }, - "context": { - "loc": { - "start": { - "line": 45, - "column": 2, - "index": 1170 + 'context': { + 'loc': { + 'start': { + 'line': 45, + 'column': 2, + 'index': 1170 }, - "end": { - "line": 45, - "column": 20, - "index": 1188 + 'end': { + 'line': 45, + 'column': 20, + 'index': 1188 } }, - "file": "C:\\Users\\diyas\\Documents\\p5.js\\src\\math\\calculation.js" + 'file': 'C:\\Users\\diyas\\Documents\\p5.js\\src\\math\\calculation.js' }, - "augments": [], - "examples": [ + 'augments': [], + 'examples': [ { - "description": "
\n\nfunction setup() {\n createCanvas(100, 100);\n\n describe('A gray square with a vertical black line that divides it in half. A white rectangle gets taller when the user moves the mouse away from the line.');\n}\n\nfunction draw() {\n background(200);\n\n // Divide the canvas.\n line(50, 0, 50, 100);\n\n // Calculate the mouse's distance from the middle.\n let h = abs(mouseX - 50);\n\n // Draw a rectangle based on the mouse's distance\n // from the middle.\n rect(0, 100 - h, 100, h);\n}\n\n
" + 'description': "
\n\nfunction setup() {\n createCanvas(100, 100);\n\n describe('A gray square with a vertical black line that divides it in half. A white rectangle gets taller when the user moves the mouse away from the line.');\n}\n\nfunction draw() {\n background(200);\n\n // Divide the canvas.\n line(50, 0, 50, 100);\n\n // Calculate the mouse's distance from the middle.\n let h = abs(mouseX - 50);\n\n // Draw a rectangle based on the mouse's distance\n // from the middle.\n rect(0, 100 - h, 100, h);\n}\n\n
" } ], - "implements": [], - "params": [ + 'implements': [], + 'params': [ { - "title": "param", - "name": "n", - "lineNumber": 8, - "description": { - "type": "root", - "children": [ + 'title': 'param', + 'name': 'n', + 'lineNumber': 8, + 'description': { + 'type': 'root', + 'children': [ { - "type": "paragraph", - "children": [ + 'type': 'paragraph', + 'children': [ { - "type": "text", - "value": "number to compute." + 'type': 'text', + 'value': 'number to compute.' } ] } ] }, - "type": { - "type": "NameExpression", - "name": "Number" + 'type': { + 'type': 'NameExpression', + 'name': 'Number' } } ], - "properties": [], - "returns": [ + 'properties': [], + 'returns': [ { - "description": { - "type": "root", - "children": [ + 'description': { + 'type': 'root', + 'children': [ { - "type": "paragraph", - "children": [ + 'type': 'paragraph', + 'children': [ { - "type": "text", - "value": "absolute value of given number." + 'type': 'text', + 'value': 'absolute value of given number.' } ] } ] }, - "title": "returns", - "type": { - "type": "NameExpression", - "name": "Number" + 'title': 'returns', + 'type': { + 'type': 'NameExpression', + 'name': 'Number' } } ], - "sees": [], - "throws": [], - "todos": [], - "yields": [], - "kind": "function", - "name": "abs", - "members": { - "global": [], - "inner": [], - "instance": [], - "events": [], - "static": [] + 'sees': [], + 'throws': [], + 'todos': [], + 'yields': [], + 'kind': 'function', + 'name': 'abs', + 'members': { + 'global': [], + 'inner': [], + 'instance': [], + 'events': [], + 'static': [] }, - "path": [ + 'path': [ { - "name": "abs", - "kind": "function" + 'name': 'abs', + 'kind': 'function' } ], - "namespace": "abs" + 'namespace': 'abs' }; suite('normalizeClassName', () => { @@ -317,7 +317,6 @@ suite('generateMethodDeclarations', () => { class: 'p5.Shader', module: 'p5', submodule: null, - class: 'p5.Shader', isStatic: false, overloads: undefined }; @@ -371,10 +370,10 @@ suite('generateTypeDefinitions', () => { const filePath = 'C:\\Users\\diyas\\Documents\\p5.js\\src\\math\\calculation.js'; // Helper function to normalize whitespace and newlines - const normalizeString = (str) => + const normalizeString = str => str.replace(/\s+/g, ' ') - .replace(/\n\s*/g, '\n') - .trim(); + .replace(/\n\s*/g, '\n') + .trim(); // Compare normalized strings expect( diff --git a/test/unit/visual/cases/noise.js b/test/unit/visual/cases/noise.js index ccc4738a42..11e64ef06f 100644 --- a/test/unit/visual/cases/noise.js +++ b/test/unit/visual/cases/noise.js @@ -18,7 +18,7 @@ visualSuite('Noise', function() { visualTest('Drawn in a shader', function(p5, screenshot) { p5.createCanvas(50, 50, p5.WEBGL); const shader = p5.baseFilterShader().modify(() => { - p5.getColor((inputs) => { + p5.getColor(inputs => { const value = p5.clamp(p5.noise(inputs.texCoord * 4) * 2, 0, 1); return [value, value, value, 1]; }); diff --git a/test/unit/visual/cases/shape_modes.js b/test/unit/visual/cases/shape_modes.js index b4020ac8b6..692ab48100 100644 --- a/test/unit/visual/cases/shape_modes.js +++ b/test/unit/visual/cases/shape_modes.js @@ -1,4 +1,4 @@ -import { visualSuite, visualTest } from "../visualTest"; +import { visualSuite, visualTest } from '../visualTest'; /* Helper function that draws a shape using the specified shape mode diff --git a/test/unit/visual/cases/shapes.js b/test/unit/visual/cases/shapes.js index 222097f68d..4fc38b97ea 100644 --- a/test/unit/visual/cases/shapes.js +++ b/test/unit/visual/cases/shapes.js @@ -3,7 +3,7 @@ import { visualSuite, visualTest } from '../visualTest'; visualSuite('Shape drawing', function() { for (const mode of ['2D', 'WebGL']) { visualSuite(`${mode} mode`, function() { - const setup = (p5) => { + const setup = p5 => { p5.createCanvas(50, 50, mode === '2D' ? p5.P2D : p5.WEBGL); if (mode !== '2D') { p5.translate(-p5.width / 2, -p5.height / 2); @@ -11,7 +11,7 @@ visualSuite('Shape drawing', function() { p5.background(200); p5.fill(255); p5.stroke(0); - } + }; visualTest('Drawing polylines', function(p5, screenshot) { setup(p5); @@ -33,7 +33,7 @@ visualSuite('Shape drawing', function() { const angle = p5.map(i, 0, 12, 0, p5.TWO_PI) * direction; p5.vertex(x + r * p5.cos(angle), y + r * p5.sin(angle)); } - } + }; p5.beginShape(); vertexCircle(15, 15, 10, 1); @@ -199,8 +199,8 @@ visualSuite('Shape drawing', function() { p5.bezierVertex(15, 40); p5.bezierVertex(40, 35); - p5.bezierVertex(25, 15) - p5.bezierVertex(15, 25) + p5.bezierVertex(25, 15); + p5.bezierVertex(15, 25); p5.bezierVertex(15, 25); p5.endShape(); screenshot(); diff --git a/test/unit/visual/cases/typography.js b/test/unit/visual/cases/typography.js index 09cc2d311c..cbba56b477 100644 --- a/test/unit/visual/cases/typography.js +++ b/test/unit/visual/cases/typography.js @@ -1,21 +1,21 @@ -import { visualSuite, visualTest } from "../visualTest"; +import { visualSuite, visualTest } from '../visualTest'; -visualSuite("Typography", function () { - visualSuite("textFont", function () { - visualTest("with the default font", function (p5, screenshot) { +visualSuite('Typography', function () { + visualSuite('textFont', function () { + visualTest('with the default font', function (p5, screenshot) { p5.createCanvas(50, 50); p5.textSize(20); p5.textAlign(p5.LEFT, p5.TOP); - p5.text("test", 0, 0); + p5.text('test', 0, 0); screenshot(); }); - visualTest("with the default monospace font", function (p5, screenshot) { + visualTest('with the default monospace font', function (p5, screenshot) { p5.createCanvas(50, 50); p5.textSize(20); - p5.textFont("monospace"); + p5.textFont('monospace'); p5.textAlign(p5.LEFT, p5.TOP); - p5.text("test", 0, 0); + p5.text('test', 0, 0); screenshot(); }); @@ -57,7 +57,7 @@ visualSuite("Typography", function () { visualTest('with a directly set font string', async function (p5, screenshot) { p5.createCanvas(100, 100); - p5.textFont(`italic bold 32px serif`); + p5.textFont('italic bold 32px serif'); p5.text('p5*js', 0, 10, p5.width); screenshot(); }); @@ -112,7 +112,7 @@ visualSuite("Typography", function () { visualTest('can control variable fonts from files', async function (p5, screenshot) { p5.createCanvas(100, 100); const font = await p5.loadFont( - '/unit/assets/BricolageGrotesque-Variable.ttf', + '/unit/assets/BricolageGrotesque-Variable.ttf' ); for (let weight = 400; weight <= 800; weight += 100) { p5.background(255); @@ -128,7 +128,7 @@ visualSuite("Typography", function () { visualTest('can control variable fonts from files in WebGL', async function (p5, screenshot) { p5.createCanvas(100, 100, p5.WEBGL); const font = await p5.loadFont( - '/unit/assets/BricolageGrotesque-Variable.ttf', + '/unit/assets/BricolageGrotesque-Variable.ttf' ); for (let weight = 400; weight <= 800; weight += 100) { p5.push(); @@ -145,10 +145,10 @@ visualSuite("Typography", function () { }); }); - visualSuite("textAlign", function () { + visualSuite('textAlign', function () { for (const mode of ['2d', 'webgl']) { visualSuite(`${mode} mode`, () => { - visualTest("all alignments with single word", async function (p5, screenshot) { + visualTest('all alignments with single word', async function (p5, screenshot) { const alignments = [ { alignX: p5.LEFT, alignY: p5.TOP }, { alignX: p5.CENTER, alignY: p5.TOP }, @@ -158,7 +158,7 @@ visualSuite("Typography", function () { { alignX: p5.RIGHT, alignY: p5.CENTER }, { alignX: p5.LEFT, alignY: p5.BOTTOM }, { alignX: p5.CENTER, alignY: p5.BOTTOM }, - { alignX: p5.RIGHT, alignY: p5.BOTTOM }, + { alignX: p5.RIGHT, alignY: p5.BOTTOM } ]; p5.createCanvas(300, 300, mode === 'webgl' ? p5.WEBGL : undefined); @@ -168,21 +168,21 @@ visualSuite("Typography", function () { '/unit/assets/Inconsolata-Bold.ttf' ); p5.textFont(font); - alignments.forEach((alignment) => { + alignments.forEach(alignment => { p5.background(255); p5.textAlign(alignment.alignX, alignment.alignY); - p5.text("Single Line", p5.width / 2, p5.height / 2); - const bb = p5.textBounds("Single Line", p5.width / 2, p5.height / 2); + p5.text('Single Line', p5.width / 2, p5.height / 2); + const bb = p5.textBounds('Single Line', p5.width / 2, p5.height / 2); p5.push(); p5.noFill(); - p5.stroke("red"); + p5.stroke('red'); p5.rect(bb.x, bb.y, bb.w, bb.h); p5.pop(); screenshot(); - }) + }); }); - visualTest("all alignments with single line", async function (p5, screenshot) { + visualTest('all alignments with single line', async function (p5, screenshot) { const alignments = [ { alignX: p5.LEFT, alignY: p5.TOP }, { alignX: p5.CENTER, alignY: p5.TOP }, @@ -192,7 +192,7 @@ visualSuite("Typography", function () { { alignX: p5.RIGHT, alignY: p5.CENTER }, { alignX: p5.LEFT, alignY: p5.BOTTOM }, { alignX: p5.CENTER, alignY: p5.BOTTOM }, - { alignX: p5.RIGHT, alignY: p5.BOTTOM }, + { alignX: p5.RIGHT, alignY: p5.BOTTOM } ]; p5.createCanvas(300, 300, mode === 'webgl' ? p5.WEBGL : undefined); @@ -202,21 +202,21 @@ visualSuite("Typography", function () { '/unit/assets/Inconsolata-Bold.ttf' ); p5.textFont(font); - alignments.forEach((alignment) => { + alignments.forEach(alignment => { p5.background(255); p5.textAlign(alignment.alignX, alignment.alignY); - p5.text("Single Line", p5.width / 2, p5.height / 2); - const bb = p5.textBounds("Single Line", p5.width / 2, p5.height / 2); + p5.text('Single Line', p5.width / 2, p5.height / 2); + const bb = p5.textBounds('Single Line', p5.width / 2, p5.height / 2); p5.push(); p5.noFill(); - p5.stroke("red"); + p5.stroke('red'); p5.rect(bb.x, bb.y, bb.w, bb.h); p5.pop(); screenshot(); }); }); - visualTest("all alignments with multi-lines and wrap word", + visualTest('all alignments with multi-lines and wrap word', async function (p5, screenshot) { const alignments = [ { alignX: p5.LEFT, alignY: p5.TOP }, @@ -227,7 +227,7 @@ visualSuite("Typography", function () { { alignX: p5.RIGHT, alignY: p5.CENTER }, { alignX: p5.LEFT, alignY: p5.BOTTOM }, { alignX: p5.CENTER, alignY: p5.BOTTOM }, - { alignX: p5.RIGHT, alignY: p5.BOTTOM }, + { alignX: p5.RIGHT, alignY: p5.BOTTOM } ]; p5.createCanvas(150, 100, mode === 'webgl' ? p5.WEBGL : undefined); @@ -257,21 +257,21 @@ visualSuite("Typography", function () { p5.fill(0); p5.noStroke(); p5.text( - "A really long text that should wrap automatically as it reaches the end of the box", + 'A really long text that should wrap automatically as it reaches the end of the box', xPos, yPos, boxWidth, boxHeight ); const bb = p5.textBounds( - "A really long text that should wrap automatically as it reaches the end of the box", + 'A really long text that should wrap automatically as it reaches the end of the box', xPos, yPos, boxWidth, boxHeight ); p5.noFill(); - p5.stroke("red"); + p5.stroke('red'); p5.rect(bb.x, bb.y, bb.w, bb.h); p5.pop(); @@ -281,7 +281,7 @@ visualSuite("Typography", function () { ); visualTest( - "all alignments with multi-lines and wrap char", + 'all alignments with multi-lines and wrap char', async function (p5, screenshot) { const alignments = [ { alignX: p5.LEFT, alignY: p5.TOP }, @@ -292,7 +292,7 @@ visualSuite("Typography", function () { { alignX: p5.RIGHT, alignY: p5.CENTER }, { alignX: p5.LEFT, alignY: p5.BOTTOM }, { alignX: p5.CENTER, alignY: p5.BOTTOM }, - { alignX: p5.RIGHT, alignY: p5.BOTTOM }, + { alignX: p5.RIGHT, alignY: p5.BOTTOM } ]; p5.createCanvas(150, 100, mode === 'webgl' ? p5.WEBGL : undefined); @@ -322,21 +322,21 @@ visualSuite("Typography", function () { p5.fill(0); p5.noStroke(); p5.text( - "A really long text that should wrap automatically as it reaches the end of the box", + 'A really long text that should wrap automatically as it reaches the end of the box', xPos, yPos, boxWidth, boxHeight ); const bb = p5.textBounds( - "A really long text that should wrap automatically as it reaches the end of the box", + 'A really long text that should wrap automatically as it reaches the end of the box', xPos, yPos, boxWidth, boxHeight ); p5.noFill(); - p5.stroke("red"); + p5.stroke('red'); p5.rect(bb.x, bb.y, bb.w, bb.h); p5.pop(); @@ -346,7 +346,7 @@ visualSuite("Typography", function () { ); visualTest( - "all alignments with multi-line manual text", + 'all alignments with multi-line manual text', async function (p5, screenshot) { const alignments = [ { alignX: p5.LEFT, alignY: p5.TOP }, @@ -357,7 +357,7 @@ visualSuite("Typography", function () { { alignX: p5.RIGHT, alignY: p5.CENTER }, { alignX: p5.LEFT, alignY: p5.BOTTOM }, { alignX: p5.CENTER, alignY: p5.BOTTOM }, - { alignX: p5.RIGHT, alignY: p5.BOTTOM }, + { alignX: p5.RIGHT, alignY: p5.BOTTOM } ]; p5.createCanvas(150, 100, mode === 'webgl' ? p5.WEBGL : undefined); @@ -386,16 +386,16 @@ visualSuite("Typography", function () { p5.fill(0); p5.noStroke(); - p5.text("Line 1\nLine 2\nLine 3", xPos, yPos, boxWidth, boxHeight); + p5.text('Line 1\nLine 2\nLine 3', xPos, yPos, boxWidth, boxHeight); const bb = p5.textBounds( - "Line 1\nLine 2\nLine 3", + 'Line 1\nLine 2\nLine 3', xPos, yPos, boxWidth, boxHeight ); p5.noFill(); - p5.stroke("red"); + p5.stroke('red'); p5.rect(bb.x, bb.y, bb.w, bb.h); p5.pop(); @@ -407,8 +407,8 @@ visualSuite("Typography", function () { } }); - visualSuite("textStyle", function () { - visualTest("all text styles", async function (p5, screenshot) { + visualSuite('textStyle', function () { + visualTest('all text styles', async function (p5, screenshot) { p5.createCanvas(150, 150); const font = await p5.loadFont( 'https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap' @@ -417,27 +417,27 @@ visualSuite("Typography", function () { p5.textFont(font); p5.textAlign(p5.LEFT, p5.TOP); - p5.text("Regular Text", 0, 0); + p5.text('Regular Text', 0, 0); p5.textStyle(p5.BOLD); - p5.text("Bold Text", 0, 30); + p5.text('Bold Text', 0, 30); p5.textStyle(p5.ITALIC); - p5.text("Italic Text", 0, 60); + p5.text('Italic Text', 0, 60); p5.textStyle(p5.BOLDITALIC); - p5.text("Bold Italic Text", 0, 90); + p5.text('Bold Italic Text', 0, 90); screenshot(); }); }); - visualSuite("textSize", function () { - const units = ["px"]; + visualSuite('textSize', function () { + const units = ['px']; const sizes = [12, 16, 20, 24, 30]; - visualTest("text sizes comparison", function (p5, screenshot) { + visualTest('text sizes comparison', function (p5, screenshot) { p5.createCanvas(300, 200); let yOffset = 0; - units.forEach((unit) => { - sizes.forEach((size) => { + units.forEach(unit => { + sizes.forEach(size => { p5.textSize(size); p5.textAlign(p5.LEFT, p5.TOP); p5.text(`Size: ${size}${unit}`, 0, yOffset); @@ -448,8 +448,8 @@ visualSuite("Typography", function () { }); }); - visualSuite("textLeading", function () { - visualTest("text leading with different values", function (p5, screenshot) { + visualSuite('textLeading', function () { + visualTest('text leading with different values', function (p5, screenshot) { p5.createCanvas(300, 200); const leadingValues = [10, 20, 30]; let yOffset = 0; @@ -457,26 +457,26 @@ visualSuite("Typography", function () { p5.textSize(20); p5.textAlign(p5.LEFT, p5.TOP); - leadingValues.forEach((leading) => { + leadingValues.forEach(leading => { p5.textLeading(leading); p5.text(`Leading: ${leading}`, 0, yOffset); - p5.text("This is a line of text.", 0, yOffset + 30); - p5.text("This is another line of text.", 0, yOffset + 30 + leading); + p5.text('This is a line of text.', 0, yOffset + 30); + p5.text('This is another line of text.', 0, yOffset + 30 + leading); yOffset += 30 + leading; }); screenshot(); }); }); - visualSuite("textWidth", function () { - visualTest("verify width of a string", function (p5, screenshot) { + visualSuite('textWidth', function () { + visualTest('verify width of a string', function (p5, screenshot) { p5.createCanvas(100, 100); p5.textSize(20); - const text = "Width Test"; + const text = 'Width Test'; const width = p5.textWidth(text); p5.text(text, 0, 30); p5.noFill(); - p5.stroke("red"); + p5.stroke('red'); p5.rect(0, 30 - 20, width, 20); screenshot(); }); @@ -550,7 +550,7 @@ visualSuite("Typography", function () { p5.background(200); p5.strokeWeight(2); p5.textSize(50); - const contours = font.textToContours('p5*js', 0, 50, { sampleFactor: 0.5 }) + const contours = font.textToContours('p5*js', 0, 50, { sampleFactor: 0.5 }); p5.beginShape(); for (const pts of contours) { p5.beginContour(); @@ -571,7 +571,7 @@ visualSuite("Typography", function () { p5.background(200); p5.strokeWeight(2); p5.textSize(50); - const cmds = font.textToPaths('p5*js', 0, 50) + const cmds = font.textToPaths('p5*js', 0, 50); p5.drawingContext.beginPath(); for (const [type, ...args] of cmds) { if (type === 'M') { diff --git a/test/unit/visual/cases/webgl.js b/test/unit/visual/cases/webgl.js index a670d34387..ebe79e82c2 100644 --- a/test/unit/visual/cases/webgl.js +++ b/test/unit/visual/cases/webgl.js @@ -1,6 +1,5 @@ -import { vi, beforeEach, afterEach } from 'vitest'; +import { vi, afterEach } from 'vitest'; import { visualSuite, visualTest } from '../visualTest'; -import { RendererGL } from '../../../../src/webgl/p5.RendererGL'; visualSuite('WebGL', function() { visualSuite('Camera', function() { @@ -217,7 +216,7 @@ visualSuite('WebGL', function() { p5.createCanvas(50, 50, p5.WEBGL); p5.background('white'); const myShader = p5.createShader(vertSrc, fragSrc); - p5.shader(myShader) + p5.shader(myShader); p5.beginShape(p5.QUADS); p5.noStroke(); p5.translate(-25,-25); @@ -253,18 +252,18 @@ visualSuite('WebGL', function() { p5.sphere(5); p5.pop(); p5.beginShape(p5.TRIANGLES); - p5.vertexProperty('aCol', [1,0,0]) + p5.vertexProperty('aCol', [1,0,0]); p5.vertex(-5, 5, 0); - p5.vertexProperty('aCol', [0,1,0]) + p5.vertexProperty('aCol', [0,1,0]); p5.vertex(5, 5, 0); - p5.vertexProperty('aCol', [0,0,1]) + p5.vertexProperty('aCol', [0,0,1]); p5.vertex(0, -5, 0); p5.endShape(p5.CLOSE); p5.push(); p5.translate(-15,10,0); p5.box(10); p5.pop(); - }) + }); p5.model(shape); screenshot(); } @@ -370,8 +369,8 @@ visualSuite('WebGL', function() { p5.rotateY(p5.PI/4); p5.box(30); screenshot(); - }) - }) + }); + }); visualSuite('Opacity', function() { visualTest('Basic colors have opacity applied correctly', (p5, screenshot) => { @@ -398,7 +397,7 @@ visualSuite('WebGL', function() { inputs.color = vec4(1., 0.4, 0.4, 100./255.); return inputs; }` - }) + }); p5.background(255); p5.shader(myShader); p5.circle(0, 0, 50); @@ -495,26 +494,26 @@ visualSuite('WebGL', function() { visualTest('Combined vs split matrices', (p5, screenshot) => { p5.createCanvas(50, 50, p5.WEBGL); - for (const space of ['Object', 'World', 'Camera']) { - const myShader = p5[base]().modify({ - [`Vertex get${space}Inputs`]: `(Vertex inputs) { + for (const space of ['Object', 'World', 'Camera']) { + const myShader = p5[base]().modify({ + [`Vertex get${space}Inputs`]: `(Vertex inputs) { // No-op return inputs; }` - }); - p5.background(255); - p5.push(); - p5.lights(); - p5.fill('red'); - p5.noStroke(); - p5.translate(20, -10, 5); - p5.rotate(p5.PI * 0.1); - p5.camera(-800, 0, 0, 0, 0, 0); - p5.shader(myShader); - p5.box(30); - p5.pop(); - screenshot(); - } + }); + p5.background(255); + p5.push(); + p5.lights(); + p5.fill('red'); + p5.noStroke(); + p5.translate(20, -10, 5); + p5.rotate(p5.PI * 0.1); + p5.camera(-800, 0, 0, 0, 0, 0); + p5.shader(myShader); + p5.box(30); + p5.pop(); + screenshot(); + } }); }); } diff --git a/test/unit/visual/visualTest.js b/test/unit/visual/visualTest.js index 120ce79565..2fe9da334b 100644 --- a/test/unit/visual/visualTest.js +++ b/test/unit/visual/visualTest.js @@ -1,7 +1,7 @@ import p5 from '../../../src/app.js'; -import { server } from '@vitest/browser/context' +import { server } from '@vitest/browser/context'; import { THRESHOLD, DIFFERENCE, ERODE } from '../../../src/core/constants.js'; -const { readFile, writeFile } = server.commands +const { readFile, writeFile } = server.commands; import pixelmatch from 'pixelmatch'; // By how much can each color channel value (0-255) differ before @@ -62,7 +62,7 @@ export function visualSuite( suiteFn = suiteFn.skip; } suiteFn(name, () => { - let lastShiftThreshold + let lastShiftThreshold; let lastPrefix; let lastDeviceRatio = window.devicePixelRatio; beforeAll(() => { @@ -70,14 +70,14 @@ export function visualSuite( namePrefix += escapeName(name) + '/'; lastShiftThreshold = shiftThreshold; if (newShiftThreshold !== undefined) { - shiftThreshold = newShiftThreshold + shiftThreshold = newShiftThreshold; } // Force everything to be 1x window.devicePixelRatio = 1; - }) + }); - callback() + callback(); afterAll(() => { namePrefix = lastPrefix; @@ -89,43 +89,43 @@ export function visualSuite( /** * Image Diff Algorithm for p5.js Visual Tests - * + * * This algorithm addresses the challenge of cross-platform rendering differences in p5.js visual tests. * Different operating systems and browsers render graphics with subtle variations, particularly with * anti-aliasing, text rendering, and sub-pixel positioning. This can cause false negatives in tests * when the visual differences are acceptable rendering variations rather than actual bugs. - * + * * Key components of the approach: - * + * * 1. Initial pixel-by-pixel comparison: * - Uses pixelmatch to identify differences between expected and actual images * - Sets a moderate threshold (0.5) to filter out minor color/intensity variations * - Produces a diff image with red pixels marking differences - * + * * 2. Cluster identification using BFS (Breadth-First Search): * - Groups connected difference pixels into clusters * - Uses a queue-based BFS algorithm to find all connected pixels * - Defines connectivity based on 8-way adjacency (all surrounding pixels) - * + * * 3. Cluster categorization by type: * - Analyzes each pixel's neighborhood characteristics * - Specifically identifies "line shift" clusters - differences that likely represent * the same visual elements shifted by 1px due to platform rendering differences * - Line shifts are identified when >80% of pixels in a cluster have ≤2 neighboring diff pixels - * + * * 4. Intelligent failure criteria: * - Filters out clusters smaller than MIN_CLUSTER_SIZE pixels (noise reduction) * - Applies different thresholds for regular differences vs. line shifts * - Considers both the total number of significant pixels and number of distinct clusters - * - * This approach balances the need to catch genuine visual bugs (like changes to shape geometry, + * + * This approach balances the need to catch genuine visual bugs (like changes to shape geometry, * colors, or positioning) while tolerating acceptable cross-platform rendering variations. - * + * * Parameters: * - MIN_CLUSTER_SIZE: Minimum size for a cluster to be considered significant (default: 4) * - MAX_TOTAL_DIFF_PIXELS: Maximum allowed non-line-shift difference pixels (default: 40) * Note: These can be adjusted for further updation - * + * * Note for contributors: When running tests locally, you may not see these differences as they * mainly appear when tests run on different operating systems or browser rendering engines. * However, the same code may produce slightly different renderings on CI environments, particularly @@ -140,7 +140,7 @@ export async function checkMatch(actual, expected, p5) { if (narrow) { scale *= 2; } - + for (const img of [actual, expected]) { img.resize( Math.ceil(img.width * scale), @@ -151,28 +151,28 @@ export async function checkMatch(actual, expected, p5) { // Ensure both images have the same dimensions const width = expected.width; const height = expected.height; - + // Create canvases with background color const actualCanvas = p5.createGraphics(width, height); const expectedCanvas = p5.createGraphics(width, height); actualCanvas.pixelDensity(1); expectedCanvas.pixelDensity(1); - + actualCanvas.background(BG); expectedCanvas.background(BG); - + actualCanvas.image(actual, 0, 0); expectedCanvas.image(expected, 0, 0); - + // Load pixel data actualCanvas.loadPixels(); expectedCanvas.loadPixels(); - + // Create diff output canvas const diffCanvas = p5.createGraphics(width, height); diffCanvas.pixelDensity(1); diffCanvas.loadPixels(); - + // Run pixelmatch const diffCount = pixelmatch( actualCanvas.pixels, @@ -180,13 +180,13 @@ export async function checkMatch(actual, expected, p5) { diffCanvas.pixels, width, height, - { + { threshold: 0.5, includeAA: false, alpha: 0.1 } ); - + // If no differences, return early if (diffCount === 0) { actualCanvas.remove(); @@ -194,59 +194,67 @@ export async function checkMatch(actual, expected, p5) { diffCanvas.updatePixels(); return { ok: true, diff: diffCanvas }; } - + // Post-process to identify and filter out isolated differences const visited = new Set(); const clusterSizes = []; - + for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { const pos = (y * width + x) * 4; - + // If this is a diff pixel (red in pixelmatch output) and not yet visited if ( - diffCanvas.pixels[pos] === 255 && - diffCanvas.pixels[pos + 1] === 0 && + diffCanvas.pixels[pos] === 255 && + diffCanvas.pixels[pos + 1] === 0 && diffCanvas.pixels[pos + 2] === 0 && !visited.has(pos) ) { // Find the connected cluster size using BFS - const clusterSize = findClusterSize(diffCanvas.pixels, x, y, width, height, 1, visited); + const clusterSize = findClusterSize( + diffCanvas.pixels, + x, y, + width, height, + 1, + visited + ); clusterSizes.push(clusterSize); } } } - + // Define significance thresholds const MIN_CLUSTER_SIZE = 4; // Minimum pixels in a significant cluster const MAX_TOTAL_DIFF_PIXELS = 40; // Maximum total different pixels // Determine if the differences are significant - const nonLineShiftClusters = clusterSizes.filter(c => !c.isLineShift && c.size >= MIN_CLUSTER_SIZE); - + const nonLineShiftClusters = clusterSizes + .filter(c => !c.isLineShift && c.size >= MIN_CLUSTER_SIZE); + // Calculate significant differences excluding line shifts - const significantDiffPixels = nonLineShiftClusters.reduce((sum, c) => sum + c.size, 0); + const significantDiffPixels = nonLineShiftClusters + .reduce((sum, c) => sum + c.size, 0); // Update the diff canvas diffCanvas.updatePixels(); - + // Clean up canvases actualCanvas.remove(); expectedCanvas.remove(); - + // Determine test result const ok = ( - diffCount === 0 || + diffCount === 0 || ( - significantDiffPixels === 0 || + significantDiffPixels === 0 || ( - (significantDiffPixels <= MAX_TOTAL_DIFF_PIXELS) && + (significantDiffPixels <= MAX_TOTAL_DIFF_PIXELS) && (nonLineShiftClusters.length <= 2) // Not too many significant clusters ) ) ); - return { + return { ok, diff: diffCanvas, details: { @@ -260,39 +268,49 @@ export async function checkMatch(actual, expected, p5) { /** * Find the size of a connected cluster of diff pixels using BFS */ -function findClusterSize(pixels, startX, startY, width, height, radius, visited) { - const queue = [{x: startX, y: startY}]; +function findClusterSize( + pixels, + startX, startY, + width, height, + radius, + visited +) { + const queue = [{ x: startX, y: startY }]; let size = 0; const clusterPixels = []; - + while (queue.length > 0) { - const {x, y} = queue.shift(); + const { x, y } = queue.shift(); const pos = (y * width + x) * 4; - + // Skip if already visited if (visited.has(pos)) continue; - + // Skip if not a diff pixel - if (pixels[pos] !== 255 || pixels[pos + 1] !== 0 || pixels[pos + 2] !== 0) continue; - + if ( + pixels[pos] !== 255 || + pixels[pos + 1] !== 0 || + pixels[pos + 2] !== 0 + ) continue; + // Mark as visited visited.add(pos); size++; - clusterPixels.push({x, y}); - + clusterPixels.push({ x, y }); + // Add neighbors to queue for (let dy = -radius; dy <= radius; dy++) { for (let dx = -radius; dx <= radius; dx++) { const nx = x + dx; const ny = y + dy; - + // Skip if out of bounds if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue; - + // Skip if already visited const npos = (ny * width + nx) * 4; if (!visited.has(npos)) { - queue.push({x: nx, y: ny}); + queue.push({ x: nx, y: ny }); } } } @@ -302,34 +320,38 @@ function findClusterSize(pixels, startX, startY, width, height, radius, visited) if (clusterPixels.length > 0) { // Count pixels with limited neighbors (line-like characteristic) let linelikePixels = 0; - - for (const {x, y} of clusterPixels) { + + for (const { x, y } of clusterPixels) { // Count neighbors let neighbors = 0; for (let dy = -1; dy <= 1; dy++) { for (let dx = -1; dx <= 1; dx++) { if (dx === 0 && dy === 0) continue; // Skip self - + const nx = x + dx; const ny = y + dy; - + // Skip if out of bounds if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue; - + const npos = (ny * width + nx) * 4; // Check if neighbor is a diff pixel - if (pixels[npos] === 255 && pixels[npos + 1] === 0 && pixels[npos + 2] === 0) { + if ( + pixels[npos] === 255 && + pixels[npos + 1] === 0 && + pixels[npos + 2] === 0 + ) { neighbors++; } } } - + // Line-like pixels typically have 1-2 neighbors if (neighbors <= 2) { linelikePixels++; } } - + // If most pixels (>80%) in the cluster have ≤2 neighbors, it's likely a line shift isLineShift = linelikePixels / clusterPixels.length > 0.8; } @@ -447,7 +469,7 @@ export function visualTest( throw new Error( `Screenshots do not match! Expected:\n${toBase64(expected[i])}\n\nReceived:\n${toBase64(actual[i])}\n\nDiff:\n${toBase64(result.diff)}\n\n` + 'If this is unexpected, paste these URLs into your browser to inspect them.\n\n' + - `If this change is expected, please delete the screenshots/${name} folder and run tests again to generate a new screenshot.`, + `If this change is expected, please delete the screenshots/${name} folder and run tests again to generate a new screenshot.` ); } } else { diff --git a/test/unit/webgl/light.js b/test/unit/webgl/light.js index 3f8785a5c9..add543c058 100644 --- a/test/unit/webgl/light.js +++ b/test/unit/webgl/light.js @@ -29,12 +29,18 @@ suite('light', function() { test('specularColor is initialised and set properly', function() { assert.deepEqual(myp5._renderer.states.specularColors, [1, 1, 1]); assert.deepEqual(myp5._renderer.states.pointLightSpecularColors, []); - assert.deepEqual(myp5._renderer.states.directionalLightSpecularColors, []); + assert.deepEqual( + myp5._renderer.states.directionalLightSpecularColors, + [] + ); myp5.specularColor(255, 0, 0); assert.deepEqual(myp5._renderer.states.specularColors, [1, 0, 0]); myp5.pointLight(255, 0, 0, 1, 0, 0); myp5.directionalLight(255, 0, 0, 0, 0, 0); - assert.deepEqual(myp5._renderer.states.pointLightSpecularColors, [1, 0, 0]); + assert.deepEqual( + myp5._renderer.states.pointLightSpecularColors, + [1, 0, 0] + ); assert.deepEqual(myp5._renderer.states.directionalLightSpecularColors, [ 1, 0, @@ -55,7 +61,10 @@ suite('light', function() { assert.deepEqual([], myp5._renderer.states.pointLightSpecularColors); assert.deepEqual([], myp5._renderer.states.pointLightPositions); assert.deepEqual([], myp5._renderer.states.directionalLightDiffuseColors); - assert.deepEqual([], myp5._renderer.states.directionalLightSpecularColors); + assert.deepEqual( + [], + myp5._renderer.states.directionalLightSpecularColors + ); assert.deepEqual([], myp5._renderer.states.directionalLightDirections); assert.deepEqual([1, 1, 1], myp5._renderer.states.specularColors); assert.deepEqual([], myp5._renderer.states.spotLightDiffuseColors); @@ -86,7 +95,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(color, positions, directions); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [defaultAngle]); @@ -98,7 +110,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(color, positions, directions, angle); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -110,7 +125,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(color, positions, directions, angle, conc); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -121,7 +139,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(255, 0, 255, positions, directions); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [defaultAngle]); @@ -132,7 +153,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(color, 1, 2, 3, directions); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [defaultAngle]); @@ -143,7 +167,10 @@ suite('light', function() { let positions = new p5.Vector(1, 2, 3); myp5.spotLight(color, positions, 0, 1, 0); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [defaultAngle]); @@ -154,7 +181,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(255, 0, 255, positions, directions, angle); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -165,7 +195,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(color, 1, 2, 3, directions, angle); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -176,7 +209,10 @@ suite('light', function() { let positions = new p5.Vector(1, 2, 3); myp5.spotLight(color, positions, 0, 1, 0, angle); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -187,7 +223,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(255, 0, 255, positions, directions, angle, conc); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -198,7 +237,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(color, 1, 2, 3, directions, angle, conc); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -209,7 +251,10 @@ suite('light', function() { let positions = new p5.Vector(1, 2, 3); myp5.spotLight(color, positions, 0, 1, 0, angle, conc); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -219,7 +264,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(255, 0, 255, 1, 2, 3, directions); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [defaultAngle]); @@ -229,7 +277,10 @@ suite('light', function() { let positions = new p5.Vector(1, 2, 3); myp5.spotLight(255, 0, 255, positions, 0, 1, 0); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [defaultAngle]); @@ -239,7 +290,10 @@ suite('light', function() { let color = myp5.color(255, 0, 255); myp5.spotLight(color, 1, 2, 3, 0, 1, 0); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [defaultAngle]); @@ -249,7 +303,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(255, 0, 255, 1, 2, 3, directions, angle); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -259,7 +316,10 @@ suite('light', function() { let positions = new p5.Vector(1, 2, 3); myp5.spotLight(255, 0, 255, positions, 0, 1, 0, angle); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -269,7 +329,10 @@ suite('light', function() { let color = myp5.color(255, 0, 255); myp5.spotLight(color, 1, 2, 3, 0, 1, 0, angle); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -279,7 +342,10 @@ suite('light', function() { let directions = new p5.Vector(0, 1, 0); myp5.spotLight(255, 0, 255, 1, 2, 3, directions, angle, conc); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -289,7 +355,10 @@ suite('light', function() { let positions = new p5.Vector(1, 2, 3); myp5.spotLight(255, 0, 255, positions, 0, 1, 0, angle, conc); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -299,7 +368,10 @@ suite('light', function() { let color = myp5.color(255, 0, 255); myp5.spotLight(color, 1, 2, 3, 0, 1, 0, angle, conc); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -308,7 +380,10 @@ suite('light', function() { test('c1,c2,c3,p1,p2,p3,r1,r2,r3', function() { myp5.spotLight(255, 0, 255, 1, 2, 3, 0, 1, 0); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [defaultAngle]); @@ -317,7 +392,10 @@ suite('light', function() { test('c1,c2,c3,p1,p2,p3,r1,r2,r3,angle', function() { myp5.spotLight(255, 0, 255, 1, 2, 3, 0, 1, 0, angle); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); @@ -326,7 +404,10 @@ suite('light', function() { test('c1,c2,c3,p1,p2,p3,r1,r2,r3,angle,conc', function() { myp5.spotLight(255, 0, 255, 1, 2, 3, 0, 1, 0, angle, 7); assert.deepEqual(myp5._renderer.states.spotLightDiffuseColors, [1, 0, 1]); - assert.deepEqual(myp5._renderer.states.spotLightSpecularColors, [1, 1, 1]); + assert.deepEqual( + myp5._renderer.states.spotLightSpecularColors, + [1, 1, 1] + ); assert.deepEqual(myp5._renderer.states.spotLightPositions, [1, 2, 3]); assert.deepEqual(myp5._renderer.states.spotLightDirections, [0, 1, 0]); assert.deepEqual(myp5._renderer.states.spotLightAngle, [cosAngle]); diff --git a/test/unit/webgl/p5.Camera.js b/test/unit/webgl/p5.Camera.js index f3e6e24850..92cfe69962 100644 --- a/test/unit/webgl/p5.Camera.js +++ b/test/unit/webgl/p5.Camera.js @@ -725,20 +725,23 @@ suite('p5.Camera', function() { test('ortho() sets renderer uPMatrix', function() { myCam.ortho(-10, 10, -10, 10, 0, 100); - assert.deepCloseTo(myCam.projMatrix.mat4, myp5._renderer.states.uPMatrix.mat4); + assert.deepCloseTo( + myCam.projMatrix.mat4, + myp5._renderer.states.uPMatrix.mat4 + ); }); test('ortho() sets projection matrix correctly', function() { // expectedMatrix array needs to match Float32Array type of // p5.Camera projMatrix's mat4 array for deepCloseTo to work - /* eslint-disable indent */ + var expectedMatrix = new Float32Array([ - 1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, -1, 0, + 1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, -1, 0, -0, -0, -1, 1 ]); - /* eslint-enable indent */ + myCam.ortho(-1, 1, -1, 1, 0, 2); @@ -765,7 +768,10 @@ suite('p5.Camera', function() { test('perspective() sets renderer uPMatrix', function() { myCam.perspective(Math.PI / 3.0, 1, 1, 100); - assert.deepCloseTo(myCam.projMatrix.mat4, myp5._renderer.states.uPMatrix.mat4); + assert.deepCloseTo( + myCam.projMatrix.mat4, + myp5._renderer.states.uPMatrix.mat4 + ); }); test('perspective() sets projection matrix correctly', function() { var expectedMatrix = new Float32Array([ @@ -802,17 +808,20 @@ suite('p5.Camera', function() { test('frustum() sets renderer uPMatrix', function() { myCam.frustum(-10, 10, -20, 20, -100, 100); - assert.deepCloseTo(myCam.projMatrix.mat4, myp5._renderer.states.uPMatrix.mat4); + assert.deepCloseTo( + myCam.projMatrix.mat4, + myp5._renderer.states.uPMatrix.mat4 + ); }); test('frustum() sets projection matrix correctly', function() { - /* eslint-disable indent */ + var expectedMatrix = new Float32Array([ -2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, -0, -1, - 0, 0, 2, 0 + 0, 2, 0, 0, + 0, 0, -0, -1, + 0, 0, 2, 0 ]); - /* eslint-enable indent */ + myCam.frustum(-1, 1, -1, 1, -2, 2); diff --git a/test/unit/webgl/p5.Framebuffer.js b/test/unit/webgl/p5.Framebuffer.js index 8d52a1668c..57799b7dc5 100644 --- a/test/unit/webgl/p5.Framebuffer.js +++ b/test/unit/webgl/p5.Framebuffer.js @@ -4,17 +4,17 @@ import * as fileSaver from 'file-saver'; vi.mock('file-saver'); expect.extend({ - tobePng: (received) => { + tobePng: received => { if (received.type === 'image/png') { return { message: 'expect blob to have type image/png', pass: true - } + }; } else { return { message: 'expect blob to have type image/png', pass: false - } + }; } } }); @@ -674,6 +674,6 @@ suite('p5.Framebuffer', function() { expect.tobePng(), 'untitled.png' ); - }) - }) + }); + }); }); diff --git a/test/unit/webgl/p5.RendererGL.js b/test/unit/webgl/p5.RendererGL.js index 93d66c790a..7b84728695 100644 --- a/test/unit/webgl/p5.RendererGL.js +++ b/test/unit/webgl/p5.RendererGL.js @@ -1,7 +1,7 @@ import { suite } from 'vitest'; import p5 from '../../../src/app.js'; import '../../js/chai_helpers'; -const toArray = (typedArray) => Array.from(typedArray); +const toArray = typedArray => Array.from(typedArray); suite('p5.RendererGL', function() { var myp5; @@ -96,13 +96,13 @@ suite('p5.RendererGL', function() { const myShader = myp5.baseMaterialShader().modify({ uniforms: { - 'sampler2D myTex': undefined, + 'sampler2D myTex': undefined }, 'Inputs getPixelInputs': `(Inputs inputs) { inputs.color = texture(myTex, inputs.texCoord); return inputs; }` - }) + }); // Make a red texture const tex = myp5.createFramebuffer(); @@ -110,11 +110,11 @@ suite('p5.RendererGL', function() { console.log(tex.get().canvas.toDataURL()); myp5.shader(myShader); - myp5.fill('red') + myp5.fill('red'); myp5.noStroke(); myShader.setUniform('myTex', tex); - myp5.rectMode(myp5.CENTER) + myp5.rectMode(myp5.CENTER); myp5.rect(0, 0, myp5.width, myp5.height); // It should be red @@ -127,7 +127,7 @@ suite('p5.RendererGL', function() { const myShader = myp5.baseMaterialShader().modify({ uniforms: { - 'sampler2D myTex': undefined, + 'sampler2D myTex': undefined }, 'Inputs getPixelInputs': `(Inputs inputs) { inputs.color = texture(myTex, inputs.texCoord); @@ -168,7 +168,7 @@ suite('p5.RendererGL', function() { tex.draw(() => myp5.background('red')); myp5.shader(myShader); - const uSampler = myShader.samplers.find((s) => s.name === 'uSampler'); + const uSampler = myShader.samplers.find(s => s.name === 'uSampler'); myp5.push(); myp5.texture(tex); @@ -228,8 +228,8 @@ suite('p5.RendererGL', function() { }; const getPixel = (colors, x, y) => { - const idx = (y * 20 + x) * 4 - return colors.slice(idx, idx + 4) + const idx = (y * 20 + x) * 4; + return colors.slice(idx, idx + 4); }; const colors2D = getColors(myp5.P2D); @@ -741,7 +741,10 @@ suite('p5.RendererGL', function() { // Check if both the model and view matrices are restored after popping assert.deepEqual(modelMatrixBefore.mat4, myp5._renderer.states.uModelMatrix.mat4); - assert.deepEqual(viewMatrixBefore.mat4, myp5._renderer.states.uViewMatrix.mat4); + assert.deepEqual( + viewMatrixBefore.mat4, + myp5._renderer.states.uViewMatrix.mat4 + ); }); test('push/pop and directionalLight() works', function() { @@ -797,8 +800,10 @@ suite('p5.RendererGL', function() { test('push/pop and pointLight() works', function() { myp5.createCanvas(100, 100, myp5.WEBGL); myp5.pointLight(255, 0, 0, 0, 0, 0); - var pointDiffuseColors = myp5._renderer.states.pointLightDiffuseColors.slice(); - var pointSpecularColors = myp5._renderer.states.pointLightSpecularColors.slice(); + var pointDiffuseColors = + myp5._renderer.states.pointLightDiffuseColors.slice(); + var pointSpecularColors = + myp5._renderer.states.pointLightSpecularColors.slice(); var pointLocs = myp5._renderer.states.pointLightPositions.slice(); myp5.push(); myp5.pointLight(0, 0, 255, 0, 10, 5); @@ -842,7 +847,8 @@ suite('p5.RendererGL', function() { let spotLightSpecularColors = myp5._renderer.states.spotLightSpecularColors.slice(); let spotLightPositions = myp5._renderer.states.spotLightPositions.slice(); - let spotLightDirections = myp5._renderer.states.spotLightDirections.slice(); + let spotLightDirections = + myp5._renderer.states.spotLightDirections.slice(); let spotLightAngle = myp5._renderer.states.spotLightAngle.slice(); let spotLightConc = myp5._renderer.states.spotLightConc.slice(); myp5.push(); @@ -855,8 +861,14 @@ suite('p5.RendererGL', function() { spotLightSpecularColors, myp5._renderer.states.spotLightSpecularColors ); - assert.notEqual(spotLightPositions, myp5._renderer.states.spotLightPositions); - assert.notEqual(spotLightDirections, myp5._renderer.states.spotLightDirections); + assert.notEqual( + spotLightPositions, + myp5._renderer.states.spotLightPositions + ); + assert.notEqual( + spotLightDirections, + myp5._renderer.states.spotLightDirections + ); assert.notEqual(spotLightAngle, myp5._renderer.states.spotLightAngle); assert.notEqual(spotLightConc, myp5._renderer.states.spotLightConc); myp5.pop(); @@ -868,8 +880,14 @@ suite('p5.RendererGL', function() { spotLightSpecularColors, myp5._renderer.states.spotLightSpecularColors ); - assert.deepEqual(spotLightPositions, myp5._renderer.states.spotLightPositions); - assert.deepEqual(spotLightDirections, myp5._renderer.states.spotLightDirections); + assert.deepEqual( + spotLightPositions, + myp5._renderer.states.spotLightPositions + ); + assert.deepEqual( + spotLightDirections, + myp5._renderer.states.spotLightDirections + ); assert.deepEqual(spotLightAngle, myp5._renderer.states.spotLightAngle); assert.deepEqual(spotLightConc, myp5._renderer.states.spotLightConc); }); @@ -975,7 +993,10 @@ suite('p5.RendererGL', function() { // cam1 is applied right now so technically this is redundant myp5.setCamera(cam1); const cam1Matrix = cam1.cameraMatrix.copy(); - assert.deepEqual(toArray(myp5._renderer.states.uViewMatrix.mat4), toArray(cam1Matrix.mat4)); + assert.deepEqual( + toArray(myp5._renderer.states.uViewMatrix.mat4), + toArray(cam1Matrix.mat4) + ); // Translation only changes the model matrix myp5.translate(100, 0, 0); @@ -983,13 +1004,22 @@ suite('p5.RendererGL', function() { myp5._renderer.states.uModelMatrix.mat4, origModelMatrix.mat4 ); - assert.deepEqual(toArray(myp5._renderer.states.uViewMatrix.mat4), toArray(cam1Matrix.mat4)); + assert.deepEqual( + toArray(myp5._renderer.states.uViewMatrix.mat4), + toArray(cam1Matrix.mat4) + ); // Switchnig cameras only changes the view matrix const transformedModel = myp5._renderer.states.uModelMatrix.copy(); myp5.setCamera(cam2); - assert.deepEqual(toArray(myp5._renderer.states.uModelMatrix.mat4), toArray(transformedModel.mat4)); - assert.notDeepEqual(myp5._renderer.states.uViewMatrix.mat4, cam1Matrix.mat4); + assert.deepEqual( + toArray(myp5._renderer.states.uModelMatrix.mat4), + toArray(transformedModel.mat4) + ); + assert.notDeepEqual( + myp5._renderer.states.uViewMatrix.mat4, + cam1Matrix.mat4 + ); }); }); @@ -1347,7 +1377,7 @@ suite('p5.RendererGL', function() { target.fill(colorB); target.rect(0, 0, target.width, target.height); target.pop(); - console.log(`${colorA} ${mode} ${colorB}: ` + target.canvas.toDataURL()) + console.log(`${colorA} ${mode} ${colorB}: ` + target.canvas.toDataURL()); return target.get(0, 0); }; @@ -1696,19 +1726,19 @@ suite('p5.RendererGL', function() { myp5.beginShape(myp5.PATH); myp5.fill(255, 255, 255); myp5.normal(-1, -1, 1); - myp5.vertexProperty('aCustom', [1, 1, 1]) + myp5.vertexProperty('aCustom', [1, 1, 1]); myp5.vertex(-10, -10, 0, 0); myp5.fill(255, 0, 0); myp5.normal(1, -1, 1); - myp5.vertexProperty('aCustom', [1, 0, 0]) + myp5.vertexProperty('aCustom', [1, 0, 0]); myp5.vertex(10, -10, 1, 0); myp5.fill(0, 255, 0); myp5.normal(1, 1, 1); - myp5.vertexProperty('aCustom', [0, 1, 0]) + myp5.vertexProperty('aCustom', [0, 1, 0]); myp5.vertex(10, 10, 1, 1); myp5.fill(0, 0, 255); myp5.normal(-1, 1, 1); - myp5.vertexProperty('aCustom', [0, 0, 1]) + myp5.vertexProperty('aCustom', [0, 0, 1]); myp5.vertex(-10, 10, 0, 1); myp5.endShape(myp5.CLOSE); @@ -1765,13 +1795,13 @@ suite('p5.RendererGL', function() { ); assert.deepEqual(renderer.shapeBuilder.geometry.aCustomSrc, [ - 1, 0, 0, - 0, 0, 1, - 1, 1, 1, - 0, 0, 1, - 1, 0, 0, - 0, 1, 0 - ]); + 1, 0, 0, + 0, 0, 1, + 1, 1, 1, + 0, 0, 1, + 1, 0, 0, + 0, 1, 0 + ]); assert.deepEqual(renderer.shapeBuilder.geometry.vertexColors, [ 1, 0, 0, 1, @@ -1814,7 +1844,7 @@ suite('p5.RendererGL', function() { 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, - 1, 1, 1, 1, + 1, 1, 1, 1 ]); }); @@ -2569,12 +2599,16 @@ suite('p5.RendererGL', function() { myp5.vertex(1,1,0); myp5.endShape(); - expect(myp5._renderer.shapeBuilder.geometry.userVertexProperties.aCustom).to.containSubset({ + expect( + myp5._renderer.shapeBuilder.geometry.userVertexProperties.aCustom + ).to.containSubset({ name: 'aCustom', currentData: [1], dataSize: 1 }); - expect(myp5._renderer.shapeBuilder.geometry.userVertexProperties.aCustomVec3).to.containSubset({ + expect( + myp5._renderer.shapeBuilder.geometry.userVertexProperties.aCustomVec3 + ).to.containSubset({ name: 'aCustomVec3', currentData: [1, 2, 3], dataSize: 3 @@ -2595,7 +2629,10 @@ suite('p5.RendererGL', function() { myp5.endShape(); assert.isUndefined(myp5._renderer.shapeBuilder.geometry.aCustomSrc); assert.isUndefined(myp5._renderer.shapeBuilder.geometry.aCustomVec3Src); - assert.deepEqual(myp5._renderer.shapeBuilder.geometry.userVertexProperties, {}); + assert.deepEqual( + myp5._renderer.shapeBuilder.geometry.userVertexProperties, + {} + ); assert.deepEqual(myp5._renderer.buffers.user, []); } ); @@ -2628,18 +2665,18 @@ suite('p5.RendererGL', function() { size: 1, src: 'aCustomSrc', dst: 'aCustomBuffer', - attr: 'aCustom', + attr: 'aCustom' }, { size: 3, src: 'aCustomVec3Src', dst: 'aCustomVec3Buffer', - attr: 'aCustomVec3', + attr: 'aCustomVec3' } ]); prevDrawFills.apply(this, args); - } + }; try { const myGeo = myp5.buildGeometry(() => { @@ -2782,7 +2819,7 @@ suite('p5.RendererGL', function() { const gl = myp5._renderer.GL; gl.enable(gl.STENCIL_TEST); - assert.equal(gl.isEnabled(gl.STENCIL_TEST), true) + assert.equal(gl.isEnabled(gl.STENCIL_TEST), true); myp5.redraw(); assert.equal(gl.isEnabled(gl.STENCIL_TEST), true); @@ -2803,7 +2840,7 @@ suite('p5.RendererGL', function() { myp5.clip(() => { myp5.rect(0, 0, 10, 10); }); - assert.equal(gl.isEnabled(gl.STENCIL_TEST), true) + assert.equal(gl.isEnabled(gl.STENCIL_TEST), true); myp5.pop(); assert.equal(myp5._renderer._userEnabledStencil, true); @@ -2823,7 +2860,7 @@ suite('p5.RendererGL', function() { myp5.clip(() => { myp5.rect(0, 0, 10, 10); }); - assert.equal(gl.isEnabled(gl.STENCIL_TEST), true) + assert.equal(gl.isEnabled(gl.STENCIL_TEST), true); myp5.pop(); myp5.redraw(); @@ -2847,7 +2884,7 @@ suite('p5.RendererGL', function() { 5, 0, 0, 1 ] ); - } + }; }); myp5.createCanvas(50, 50, myp5.WEBGL); myp5.translate(5, 0); @@ -2867,7 +2904,7 @@ suite('p5.RendererGL', function() { 0, 0, -500, 1 ] ); - } + }; }); myp5.createCanvas(50, 50, myp5.WEBGL); myp5.translate(5, 0); @@ -2887,7 +2924,7 @@ suite('p5.RendererGL', function() { 5, 0, -500, 1 ] ); - } + }; }); myp5.createCanvas(50, 50, myp5.WEBGL); myp5.translate(5, 0); @@ -2907,7 +2944,7 @@ suite('p5.RendererGL', function() { 0, 0, -161.6161651611328, 0 ] ); - } + }; }); myp5.createCanvas(50, 50, myp5.WEBGL); myp5.checkPMatrix(); diff --git a/test/unit/webgl/p5.Shader.js b/test/unit/webgl/p5.Shader.js index 9683999d9b..d4e74efa36 100644 --- a/test/unit/webgl/p5.Shader.js +++ b/test/unit/webgl/p5.Shader.js @@ -122,7 +122,7 @@ suite('p5.Shader', function() { var expectedUniforms = [ 'uModelViewMatrix', - 'uProjectionMatrix', + 'uProjectionMatrix' ]; testShader( @@ -342,7 +342,7 @@ suite('p5.Shader', function() { test('framebuffer textures are unbound when you draw to the framebuffer', function() { const sh = myp5.baseMaterialShader().modify({ uniforms: { - 'sampler2D myTex': null, + 'sampler2D myTex': null }, 'vec4 getFinalColor': `(vec4 c) { return getTexture(myTex, vec2(0.,0.)); @@ -370,7 +370,7 @@ suite('p5.Shader', function() { returnType: { typeName: 'vec4', qualifiers: [], - properties: undefined, + properties: undefined }, parameters: [ { @@ -384,7 +384,7 @@ suite('p5.Shader', function() { type: { typeName: 'vec2', qualifiers: [], - properties: undefined, + properties: undefined } }, { @@ -392,7 +392,7 @@ suite('p5.Shader', function() { type: { typeName: 'vec2', qualifiers: [], - properties: undefined, + properties: undefined } }, { @@ -400,10 +400,10 @@ suite('p5.Shader', function() { type: { typeName: 'vec2', qualifiers: [], - properties: undefined, + properties: undefined } - }, - ], + } + ] } }, { @@ -411,7 +411,7 @@ suite('p5.Shader', function() { type: { typeName: 'sampler2D', qualifiers: ['in'], - properties: undefined, + properties: undefined } } ] @@ -424,7 +424,7 @@ suite('p5.Shader', function() { myp5.createCanvas(5, 5, myp5.WEBGL); const myShader = myp5.baseMaterialShader().modify(() => { const size = myp5.uniformVector2(() => [myp5.width, myp5.height]); - myp5.getPixelInputs((inputs) => { + myp5.getPixelInputs(inputs => { inputs.color = [ size / 1000, 0, diff --git a/utils/convert.mjs b/utils/convert.mjs index 9fb921c2a2..ba56c59df0 100644 --- a/utils/convert.mjs +++ b/utils/convert.mjs @@ -135,7 +135,10 @@ function deprecationInfo(node) { return {}; } - return { deprecated: true, deprecationMessage: descriptionString(node.deprecated) }; + return { + deprecated: true, + deprecationMessage: descriptionString(node.deprecated) + }; } function getExample(node) { @@ -232,13 +235,14 @@ function getParams(entry) { // string, so we match these params to the Documentation.js-provided `params` // array and grab the description from those. return (entry.tags || []) - + // Filter out the nested parameters (eg. options.extrude), // to be treated as part of parent parameters (eg. options) // and not separate entries - .filter(t => t.title === 'param' && !t.name.includes('.')) + .filter(t => t.title === 'param' && !t.name.includes('.')) .map(node => { - const param = (entry.params || []).find(param => param.name === node.name); + const param = (entry.params || []) + .find(param => param.name === node.name); return { ...node, description: param?.description || { @@ -522,7 +526,7 @@ function cleanUpClassItems(data) { return Object.values(overload.params).map(param => processParam(param)); } return overload; - } + }; // To simplify `parameterData.json`, instead of having a separate field for // optional parameters, we'll add a ? to the end of parameter type to @@ -536,7 +540,7 @@ function cleanUpClassItems(data) { type = `...${type}[]`; } return type; - } + }; // In some cases, even when the arguments are intended to mean different // things, their types and order are identical. Since the exact meaning @@ -549,7 +553,7 @@ function cleanUpClassItems(data) { } uniqueOverloads.add(overloadString); return true; - } + }; for (const [key, value] of Object.entries(funcObj)) { if (value && typeof value === 'object' && value.overloads) { @@ -557,7 +561,9 @@ function cleanUpClassItems(data) { result[key] = { overloads: Object.values(value.overloads) .map(overload => processOverload(overload)) - .filter(overload => removeDuplicateOverloads(overload, uniqueOverloads)) + .filter(overload => + removeDuplicateOverloads(overload, uniqueOverloads) + ) }; } else { result[key] = value; @@ -585,7 +591,10 @@ function buildParamDocs(docs) { // If `classitem` doesn't have overloads, then it's not a function—skip processing in this case if (classitem.name && classitem.class && classitem.hasOwnProperty('overloads')) { // Skip if the item already exists in newClassItems - if (newClassItems[classitem.class] && newClassItems[classitem.class][classitem.name]) { + if ( + newClassItems[classitem.class] && + newClassItems[classitem.class][classitem.name] + ) { continue; } diff --git a/utils/generate-types.mjs b/utils/generate-types.mjs index 51921bf040..5c5c05a7f1 100644 --- a/utils/generate-types.mjs +++ b/utils/generate-types.mjs @@ -3,7 +3,7 @@ import path from 'path'; import { fileURLToPath } from 'url'; import { generateTypeDefinitions -} from "./helper.mjs"; +} from './helper.mjs'; // Fix for __dirname equivalent in ES modules const __filename = fileURLToPath(import.meta.url); @@ -19,7 +19,7 @@ function findDtsFiles(dir, files = []) { } const entries = fs.readdirSync(dir, { withFileTypes: true }); - + for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { @@ -36,7 +36,11 @@ function findDtsFiles(dir, files = []) { } export function generateAllDeclarationFiles() { - const { p5Types: rawP5Types, globalTypes, fileTypes } = generateTypeDefinitions(data); + const { + p5Types: rawP5Types, + globalTypes, + fileTypes + } = generateTypeDefinitions(data); const typesDir = path.join(process.cwd(), 'types'); fs.mkdirSync(typesDir, { recursive: true }); @@ -44,7 +48,7 @@ export function generateAllDeclarationFiles() { fileTypes.forEach((content, filePath) => { const parsedPath = path.parse(filePath); const relativePath = path.relative( - path.join(__dirname, "../src"), + path.join(__dirname, '../src'), filePath ); const dtsPath = path.join( diff --git a/utils/helper.mjs b/utils/helper.mjs index 6c340bc1df..5506363692 100644 --- a/utils/helper.mjs +++ b/utils/helper.mjs @@ -28,594 +28,599 @@ export function generateTypeDefinitions(data) { }; } function generateP5TypeDefinitions(organizedData) { - let output = '// This file is auto-generated from JSDoc documentation\n\n'; - - output += `declare class p5 {\n`; - output += ` constructor(sketch?: (p: p5) => void, node?: HTMLElement, sync?: boolean);\n\n`; - const instanceItems = organizedData.classitems.filter(item => - item.class === 'p5' && !item.isStatic - ); - instanceItems.forEach(item => { - output += generateMethodDeclarations(item, false); - }); - - const staticItems = organizedData.classitems.filter(item => - item.class === 'p5' && item.isStatic - ); - staticItems.forEach(item => { - output += generateMethodDeclarations(item, true); - }); - - Object.values(organizedData.consts).forEach(constData => { - if (constData.class === 'p5') { - if (constData.description) { - output += ` /**\n * ${constData.description}\n */\n`; - } - if (constData.kind === 'constant') { - output += ` readonly ${constData.name.toUpperCase()}: ${constData.type};\n\n`; - } else { - output += ` static ${constData.name}: ${constData.type};\n\n`; - } + let output = '// This file is auto-generated from JSDoc documentation\n\n'; + + output += 'declare class p5 {\n'; + output += ' constructor(sketch?: (p: p5) => void, node?: HTMLElement, sync?: boolean);\n\n'; + const instanceItems = organizedData.classitems.filter(item => + item.class === 'p5' && !item.isStatic + ); + instanceItems.forEach(item => { + output += generateMethodDeclarations(item, false); + }); + + const staticItems = organizedData.classitems.filter(item => + item.class === 'p5' && item.isStatic + ); + staticItems.forEach(item => { + output += generateMethodDeclarations(item, true); + }); + + Object.values(organizedData.consts).forEach(constData => { + if (constData.class === 'p5') { + if (constData.description) { + output += ` /**\n * ${constData.description}\n */\n`; } - }); + if (constData.kind === 'constant') { + output += ` readonly ${constData.name.toUpperCase()}: ${constData.type};\n\n`; + } else { + output += ` static ${constData.name}: ${constData.type};\n\n`; + } + } + }); - output += `}\n\n`; + output += '}\n\n'; - output += `declare namespace p5 {\n`; + output += 'declare namespace p5 {\n'; - Object.values(organizedData.consts).forEach(constData => { - if (constData.kind === 'typedef') { - if (constData.description) { - output += ` /**\n * ${constData.description}\n */\n`; - } - output += ` type ${constData.name} = ${constData.type};\n\n`; + Object.values(organizedData.consts).forEach(constData => { + if (constData.kind === 'typedef') { + if (constData.description) { + output += ` /**\n * ${constData.description}\n */\n`; } - }); + output += ` type ${constData.name} = ${constData.type};\n\n`; + } + }); - Object.values(organizedData.classes).forEach(classDoc => { - if (classDoc.name !== 'p5') { - output += generateClassDeclaration(classDoc, organizedData); - } - }); - output += `}\n\n`; + Object.values(organizedData.classes).forEach(classDoc => { + if (classDoc.name !== 'p5') { + output += generateClassDeclaration(classDoc, organizedData); + } + }); + output += '}\n\n'; - output += `export default p5;\n`; - output += `export as namespace p5;\n`; + output += 'export default p5;\n'; + output += 'export as namespace p5;\n'; - return output; - } + return output; +} function generateGlobalTypeDefinitions(organizedData) { - let output = '// This file is auto-generated from JSDoc documentation\n\n'; - output += `import p5 from 'p5';\n\n`; - output += `declare global {\n`; - - const instanceItems = organizedData.classitems.filter(item => - item.class === 'p5' && !item.isStatic - ); - instanceItems.forEach(item => { - if (item.kind === 'function') { - if (item.description) { - output += ` /**\n${formatJSDocComment(item.description, 2)}\n */\n`; - } - - if (item.overloads?.length > 0) { - item.overloads.forEach(overload => { - const params = (overload.params || []) - .map(param => generateParamDeclaration(param)) - .join(', '); - const returnType = overload.returns?.[0]?.type - ? generateTypeFromTag(overload.returns[0]) - : 'void'; - output += ` function ${item.name}(${params}): ${returnType};\n`; - }); - } - - const params = (item.params || []) - .map(param => generateParamDeclaration(param)) - .join(', '); - output += ` function ${item.name}(${params}): ${item.returnType};\n\n`; + let output = '// This file is auto-generated from JSDoc documentation\n\n'; + output += 'import p5 from \'p5\';\n\n'; + output += 'declare global {\n'; + + const instanceItems = organizedData.classitems.filter(item => + item.class === 'p5' && !item.isStatic + ); + instanceItems.forEach(item => { + if (item.kind === 'function') { + if (item.description) { + output += ` /**\n${formatJSDocComment(item.description, 2)}\n */\n`; } - }); - Object.values(organizedData.consts).forEach(constData => { - if (constData.kind === 'constant') { - if (constData.description) { - output += ` /**\n${formatJSDocComment(constData.description, 2)}\n */\n`; - } - output += ` const ${constData.name.toUpperCase()}: p5.${constData.name.toUpperCase()};\n\n`; + if (item.overloads?.length > 0) { + item.overloads.forEach(overload => { + const params = (overload.params || []) + .map(param => generateParamDeclaration(param)) + .join(', '); + const returnType = overload.returns?.[0]?.type + ? generateTypeFromTag(overload.returns[0]) + : 'void'; + output += ` function ${item.name}(${params}): ${returnType};\n`; + }); } - }); - output += ` interface Window {\n`; + const params = (item.params || []) + .map(param => generateParamDeclaration(param)) + .join(', '); + output += ` function ${item.name}(${params}): ${item.returnType};\n\n`; + } + }); - instanceItems.forEach(item => { - if (item.kind === 'function') { - output += ` ${item.name}: typeof ${item.name};\n`; + Object.values(organizedData.consts).forEach(constData => { + if (constData.kind === 'constant') { + if (constData.description) { + output += ` /**\n${formatJSDocComment(constData.description, 2)}\n */\n`; } - }); + output += ` const ${constData.name.toUpperCase()}: p5.${constData.name.toUpperCase()};\n\n`; + } + }); - Object.values(organizedData.consts).forEach(constData => { - if (constData.kind === 'constant') { - if (constData.description) { - output += ` /**\n * ${constData.description}\n */\n`; - } - output += ` readonly ${constData.name.toUpperCase()}: typeof ${constData.name.toUpperCase()};\n`; + output += ' interface Window {\n'; + + instanceItems.forEach(item => { + if (item.kind === 'function') { + output += ` ${item.name}: typeof ${item.name};\n`; + } + }); + + Object.values(organizedData.consts).forEach(constData => { + if (constData.kind === 'constant') { + if (constData.description) { + output += ` /**\n * ${constData.description}\n */\n`; } - }); + output += ` readonly ${constData.name.toUpperCase()}: typeof ${constData.name.toUpperCase()};\n`; + } + }); - output += ` }\n`; - output += `}\n\n`; - output += `export {};\n`; + output += ' }\n'; + output += '}\n\n'; + output += 'export {};\n'; - return output; - } + return output; +} function generateFileTypeDefinitions(organizedData, data) { - const fileDefinitions = new Map(); - const fileGroups = groupByFile(getAllEntries(data)); + const fileDefinitions = new Map(); + const fileGroups = groupByFile(getAllEntries(data)); - fileGroups.forEach((items, filePath) => { - const declarationContent = generateDeclarationFile(items, organizedData); - fileDefinitions.set(filePath, declarationContent); - }); + fileGroups.forEach((items, filePath) => { + const declarationContent = generateDeclarationFile(items, organizedData); + fileDefinitions.set(filePath, declarationContent); + }); - return fileDefinitions; - } - const organized = { - modules: {}, - classes: {}, - classitems: [], - consts: {} - }; + return fileDefinitions; +} +const organized = { + modules: {}, + classes: {}, + classitems: [], + consts: {} +}; function generateDeclarationFile(items, organizedData) { - let output = '// This file is auto-generated from JSDoc documentation\n\n'; - const imports = new Set([`import p5 from 'p5';`]); - const hasColorDependency = items.some(item => { - const typeName = item.type?.name; - const desc = extractDescription(item.description); - return typeName === 'Color' || (typeof desc === 'string' && desc.includes('Color')); - }); - - const hasVectorDependency = items.some(item => { - const typeName = item.type?.name; - const desc = extractDescription(item.description); - return typeName === 'Vector' || (typeof desc === 'string' && desc.includes('Vector')); - }); + let output = '// This file is auto-generated from JSDoc documentation\n\n'; + const imports = new Set(['import p5 from \'p5\';']); + const hasColorDependency = items.some(item => { + const typeName = item.type?.name; + const desc = extractDescription(item.description); + return typeName === 'Color' || (typeof desc === 'string' && desc.includes('Color')); + }); + + const hasVectorDependency = items.some(item => { + const typeName = item.type?.name; + const desc = extractDescription(item.description); + return typeName === 'Vector' || (typeof desc === 'string' && desc.includes('Vector')); + }); + + const hasConstantsDependency = items.some(item => + item.tags?.some(tag => tag.title === 'requires' && tag.description === 'constants') + ); + + if (hasColorDependency) { + imports.add('import { Color } from \'../color/p5.Color\';'); + } + if (hasVectorDependency) { + imports.add('import { Vector } from \'../math/p5.Vector\';'); + } + if (hasConstantsDependency) { + imports.add('import * as constants from \'../core/constants\';'); + } - const hasConstantsDependency = items.some(item => - item.tags?.some(tag => tag.title === 'requires' && tag.description === 'constants') - ); + output += Array.from(imports).join('\n') + '\n\n'; + output += 'declare module \'p5\' {\n'; - if (hasColorDependency) { - imports.add(`import { Color } from '../color/p5.Color';`); - } - if (hasVectorDependency) { - imports.add(`import { Vector } from '../math/p5.Vector';`); - } - if (hasConstantsDependency) { - imports.add(`import * as constants from '../core/constants';`); + const classDoc = items.find(item => item.kind === 'class'); + if (classDoc) { + const fullClassName = normalizeClassName(classDoc.name); + const classDocName = fullClassName.replace('p5.', ''); + let parentClass = classDoc.tags?.find(tag => tag.title === 'extends')?.name; + if (parentClass) { + parentClass = parentClass.replace('p5.', ''); } + const extendsClause = parentClass ? ` extends ${parentClass}` : ''; - output += Array.from(imports).join('\n') + '\n\n'; - output += `declare module 'p5' {\n`; - - const classDoc = items.find(item => item.kind === 'class'); - if (classDoc) { - const fullClassName = normalizeClassName(classDoc.name); - const classDocName = fullClassName.replace('p5.', ''); - let parentClass = classDoc.tags?.find(tag => tag.title === 'extends')?.name; - if (parentClass) { - parentClass = parentClass.replace('p5.', ''); - } - const extendsClause = parentClass ? ` extends ${parentClass}` : ''; - - output += ` class ${classDocName}${extendsClause} {\n`; + output += ` class ${classDocName}${extendsClause} {\n`; - if (classDoc.params?.length > 0) { - output += ' constructor('; - output += classDoc.params - .map(param => generateParamDeclaration(param)) - .join(', '); - output += ');\n\n'; - } + if (classDoc.params?.length > 0) { + output += ' constructor('; + output += classDoc.params + .map(param => generateParamDeclaration(param)) + .join(', '); + output += ');\n\n'; + } - const classItems = organizedData.classitems.filter(item => - item.class === fullClassName || + const classItems = organizedData.classitems.filter(item => + item.class === fullClassName || item.class === fullClassName.replace('p5.', '') - ); + ); - const staticItems = classItems.filter(item => item.isStatic); - const instanceItems = classItems.filter(item => !item.isStatic); - staticItems.forEach(item => { - output += generateMethodDeclarations(item, true); - }); - instanceItems.forEach(item => { - output += generateMethodDeclarations(item, false); - }); - output += ' }\n\n'; - } + const staticItems = classItems.filter(item => item.isStatic); + const instanceItems = classItems.filter(item => !item.isStatic); + staticItems.forEach(item => { + output += generateMethodDeclarations(item, true); + }); + instanceItems.forEach(item => { + output += generateMethodDeclarations(item, false); + }); + output += ' }\n\n'; + } - items.forEach(item => { - if (item.kind !== 'class' && (!item.memberof || item.memberof !== classDoc?.name)) { - switch (item.kind) { - case 'function': - output += generateFunctionDeclaration(item); - break; - case 'constant': - case 'typedef': - const constData = organizedData.consts[item.name]; - if (constData) { - if (constData.description) { - output += ` /**\n * ${constData.description}\n */\n`; - } - if (constData.kind === 'constant') { - output += ` const ${constData.name}: ${constData.type};\n\n`; - } else { - output += ` type ${constData.name} = ${constData.type};\n\n`; - } + items.forEach(item => { + if (item.kind !== 'class' && (!item.memberof || item.memberof !== classDoc?.name)) { + switch (item.kind) { + case 'function': + output += generateFunctionDeclaration(item); + break; + case 'constant': + case 'typedef': + const constData = organizedData.consts[item.name]; + if (constData) { + if (constData.description) { + output += ` /**\n * ${constData.description}\n */\n`; } - break; - } + if (constData.kind === 'constant') { + output += ` const ${constData.name}: ${constData.type};\n\n`; + } else { + output += ` type ${constData.name} = ${constData.type};\n\n`; + } + } + break; } - }); + } + }); - output += '}\n\n'; + output += '}\n\n'; - return output; - } + return output; +} - export function organizeData(data) { - const allData = getAllEntries(data); - - organized.modules = {}; - organized.classes = {}; - organized.classitems = []; - organized.consts = {}; - - allData.forEach(entry => { - const { module, submodule, forEntry } = getModuleInfo(entry); - const className = normalizeClassName(forEntry || entry.memberof || 'p5'); - - switch(entry.kind) { - case 'class': - organized.classes[className] = { - name: entry.name, - description: extractDescription(entry.description), - params: (entry.params || []).map(param => ({ - name: param.name, - type: generateTypeFromTag(param), - optional: param.type?.type === 'OptionalType' - })), - module, - submodule, - extends: entry.tags?.find(tag => tag.title === 'extends')?.name || null - }; break; - case 'function': - case 'property': - const overloads = entry.overloads?.map(overload => ({ - params: overload.params, - returns: overload.returns, - description: extractDescription(overload.description) - })); - - organized.classitems.push({ - name: entry.name, - kind: entry.kind, - description: extractDescription(entry.description), - params: (entry.params || []).map(param => ({ - name: param.name, - type: generateTypeFromTag(param), - optional: param.type?.type === 'OptionalType' - })), - returnType: entry.returns?.[0] ? generateTypeFromTag(entry.returns[0]) : 'void', - module, - submodule, - class: className, - isStatic: entry.path?.[0]?.scope === 'static', - overloads - }); break; - case 'constant': - case 'typedef': - organized.consts[entry.name] = { - name: entry.name, - kind: entry.kind, - description: extractDescription(entry.description), - type: entry.kind === 'constant' ? `P5.${entry.name.toUpperCase()}` : (entry.type ? generateTypeFromTag(entry) : 'any'), - module, - submodule, - class: forEntry || 'p5' - }; break; - } - }); - return organized; - } +export function organizeData(data) { + const allData = getAllEntries(data); + + organized.modules = {}; + organized.classes = {}; + organized.classitems = []; + organized.consts = {}; + + allData.forEach(entry => { + const { module, submodule, forEntry } = getModuleInfo(entry); + const className = normalizeClassName(forEntry || entry.memberof || 'p5'); + + switch(entry.kind) { + case 'class': + organized.classes[className] = { + name: entry.name, + description: extractDescription(entry.description), + params: (entry.params || []).map(param => ({ + name: param.name, + type: generateTypeFromTag(param), + optional: param.type?.type === 'OptionalType' + })), + module, + submodule, + extends: entry.tags?.find(tag => tag.title === 'extends')?.name || null + }; break; + case 'function': + case 'property': + const overloads = entry.overloads?.map(overload => ({ + params: overload.params, + returns: overload.returns, + description: extractDescription(overload.description) + })); + + organized.classitems.push({ + name: entry.name, + kind: entry.kind, + description: extractDescription(entry.description), + params: (entry.params || []).map(param => ({ + name: param.name, + type: generateTypeFromTag(param), + optional: param.type?.type === 'OptionalType' + })), + returnType: entry.returns?.[0] ? generateTypeFromTag(entry.returns[0]) : 'void', + module, + submodule, + class: className, + isStatic: entry.path?.[0]?.scope === 'static', + overloads + }); break; + case 'constant': + case 'typedef': + organized.consts[entry.name] = { + name: entry.name, + kind: entry.kind, + description: extractDescription(entry.description), + type: entry.kind === 'constant' ? `P5.${entry.name.toUpperCase()}` : (entry.type ? generateTypeFromTag(entry) : 'any'), + module, + submodule, + class: forEntry || 'p5' + }; break; + } + }); + return organized; +} - export function getModuleInfo(entry) { - return { - module: entry.tags?.find(tag => tag.title === 'module')?.name || 'p5', - submodule: entry.tags?.find(tag => tag.title === 'submodule')?.description || null, - forEntry: entry.tags?.find(tag => tag.title === 'for')?.description || entry.memberof - }; +export function getModuleInfo(entry) { + return { + module: entry.tags?.find(tag => tag.title === 'module')?.name || 'p5', + submodule: entry.tags?.find(tag => tag.title === 'submodule')?.description || null, + forEntry: entry.tags?.find(tag => tag.title === 'for')?.description || entry.memberof + }; } export function extractDescription(desc) { - if (!desc) return ''; - if (typeof desc === 'string') return desc; - if (desc.children) { - return desc.children.map(child => { - if (child.type === 'text') return child.value; - if (child.type === 'paragraph') return extractDescription(child); - if (child.type === 'inlineCode' || child.type === 'code') return `\`${child.value}\``; - return ''; - }) - .join('').trim().replace(/\n{3,}/g, '\n\n'); - } - return ''; + if (!desc) return ''; + if (typeof desc === 'string') return desc; + if (desc.children) { + return desc.children.map(child => { + if (child.type === 'text') return child.value; + if (child.type === 'paragraph') return extractDescription(child); + if (child.type === 'inlineCode' || child.type === 'code') return `\`${child.value}\``; + return ''; + }) + .join('').trim().replace(/\n{3,}/g, '\n\n'); } + return ''; +} export function generateTypeFromTag(param) { - if (!param || !param.type) return 'any'; - - switch (param.type.type) { - case 'NameExpression': - return normalizeTypeName(param.type.name); - case 'TypeApplication': { - const baseType = normalizeTypeName(param.type.expression.name); - - if (baseType === 'Array') { - const innerType = param.type.applications[0]; - const innerTypeStr = generateTypeFromTag({ type: innerType }); - return `${innerTypeStr}[]`; - } - - const typeParams = param.type.applications - .map(app => generateTypeFromTag({ type: app })) - .join(', '); - return `${baseType}<${typeParams}>`; - } - case 'UnionType': - const unionTypes = param.type.elements - .map(el => generateTypeFromTag({ type: el })) - .join(' | '); - return unionTypes; - case 'OptionalType': - return generateTypeFromTag({ type: param.type.expression }); - case 'AllLiteral': - return 'any'; - case 'RecordType': - return 'object'; - case 'StringLiteralType': - return `'${param.type.value}'`; - case 'UndefinedLiteralType': - return 'undefined'; - case 'ArrayType': { - const innerTypeStrs = param.type.elements.map(e => generateTypeFromTag({ type: e })); - return `[${innerTypeStrs.join(', ')}]`; + if (!param || !param.type) return 'any'; + + switch (param.type.type) { + case 'NameExpression': + return normalizeTypeName(param.type.name); + case 'TypeApplication': { + const baseType = normalizeTypeName(param.type.expression.name); + + if (baseType === 'Array') { + const innerType = param.type.applications[0]; + const innerTypeStr = generateTypeFromTag({ type: innerType }); + return `${innerTypeStr}[]`; } - case 'RestType': - return `${generateTypeFromTag({ type: param.type.expression })}[]`; - default: - return 'any'; + + const typeParams = param.type.applications + .map(app => generateTypeFromTag({ type: app })) + .join(', '); + return `${baseType}<${typeParams}>`; } + case 'UnionType': + const unionTypes = param.type.elements + .map(el => generateTypeFromTag({ type: el })) + .join(' | '); + return unionTypes; + case 'OptionalType': + return generateTypeFromTag({ type: param.type.expression }); + case 'AllLiteral': + return 'any'; + case 'RecordType': + return 'object'; + case 'StringLiteralType': + return `'${param.type.value}'`; + case 'UndefinedLiteralType': + return 'undefined'; + case 'ArrayType': { + const innerTypeStrs = param.type.elements + .map(e => generateTypeFromTag({ type: e })); + return `[${innerTypeStrs.join(', ')}]`; + } + case 'RestType': + return `${generateTypeFromTag({ type: param.type.expression })}[]`; + default: + return 'any'; } +} - export function normalizeTypeName(type) { - if (!type) return 'any'; - - if (type === '[object Object]') return 'any'; +export function normalizeTypeName(type) { + if (!type) return 'any'; - const primitiveTypes = { - 'String': 'string', - 'Number': 'number', - 'Integer': 'number', - 'Boolean': 'boolean', - 'Void': 'void', - 'Object': 'object', - 'Array': 'Array', - 'Function': 'Function' - }; + if (type === '[object Object]') return 'any'; - return primitiveTypes[type] || type; - } + const primitiveTypes = { + 'String': 'string', + 'Number': 'number', + 'Integer': 'number', + 'Boolean': 'boolean', + 'Void': 'void', + 'Object': 'object', + 'Array': 'Array', + 'Function': 'Function' + }; - export function generateParamDeclaration(param) { - if (!param) return 'any'; - - let type = param.type; - let prefix = ''; - const isOptional = param.type?.type === 'OptionalType'; - if (typeof type === 'string') { - type = normalizeTypeName(type); - } else if (param.type?.type) { - type = generateTypeFromTag(param); - } else { - type = 'any'; - } + return primitiveTypes[type] || type; +} - if (param.type?.type === 'RestType') { - prefix = '...'; - } +export function generateParamDeclaration(param) { + if (!param) return 'any'; + + let type = param.type; + let prefix = ''; + const isOptional = param.type?.type === 'OptionalType'; + if (typeof type === 'string') { + type = normalizeTypeName(type); + } else if (param.type?.type) { + type = generateTypeFromTag(param); + } else { + type = 'any'; + } - return `${prefix}${param.name}${isOptional ? '?' : ''}: ${type}`; + if (param.type?.type === 'RestType') { + prefix = '...'; } - export function generateFunctionDeclaration(funcDoc) { + return `${prefix}${param.name}${isOptional ? '?' : ''}: ${type}`; +} - let output = ''; +export function generateFunctionDeclaration(funcDoc) { - if (funcDoc.description || funcDoc.tags?.length > 0) { - output += '/**\n'; - const description = extractDescription(funcDoc.description); + let output = ''; + + if (funcDoc.description || funcDoc.tags?.length > 0) { + output += '/**\n'; + const description = extractDescription(funcDoc.description); + if (description) { + output += formatJSDocComment(description) + '\n'; + } + if (funcDoc.tags) { if (description) { - output += formatJSDocComment(description) + '\n'; + output += ' *\n'; } - if (funcDoc.tags) { - if (description) { - output += ' *\n'; + funcDoc.tags.forEach(tag => { + if (tag.description) { + const tagDesc = extractDescription(tag.description); + output += formatJSDocComment(`@${tag.title} ${tagDesc}`, 0) + '\n'; } - funcDoc.tags.forEach(tag => { - if (tag.description) { - const tagDesc = extractDescription(tag.description); - output += formatJSDocComment(`@${tag.title} ${tagDesc}`, 0) + '\n'; - } - }); - } - output += ' */\n'; + }); } + output += ' */\n'; + } - const params = (funcDoc.params || []) - .map(param => generateParamDeclaration(param)) - .join(', '); + const params = (funcDoc.params || []) + .map(param => generateParamDeclaration(param)) + .join(', '); - const returnType = funcDoc.returns?.[0]?.type - ? generateTypeFromTag(funcDoc.returns[0]) - : 'void'; + const returnType = funcDoc.returns?.[0]?.type + ? generateTypeFromTag(funcDoc.returns[0]) + : 'void'; - output += `function ${funcDoc.name}(${params}): ${returnType};\n\n`; - return output; - } - - export function generateMethodDeclarations(item, isStatic = false, isGlobal = false) { - let output = ''; + output += `function ${funcDoc.name}(${params}): ${returnType};\n\n`; + return output; +} - if (item.description) { - output += ' /**\n'; - const itemDesc = extractDescription(item.description); - output += formatJSDocComment(itemDesc, 2) + '\n'; - if (item.params?.length > 0) { - output += ' *\n'; - item.params.forEach(param => { - const paramDesc = extractDescription(param.description); - output += formatJSDocComment(`@param ${paramDesc}`, 2) + '\n'; - }); - } - if (item.returns) { - output += ' *\n'; - const returnDesc = extractDescription(item.returns[0]?.description); - output += formatJSDocComment(`@return ${returnDesc}`, 2) + '\n'; - } - output += ' */\n'; +export function generateMethodDeclarations( + item, + isStatic = false, + isGlobal = false +) { + let output = ''; + + if (item.description) { + output += ' /**\n'; + const itemDesc = extractDescription(item.description); + output += formatJSDocComment(itemDesc, 2) + '\n'; + if (item.params?.length > 0) { + output += ' *\n'; + item.params.forEach(param => { + const paramDesc = extractDescription(param.description); + output += formatJSDocComment(`@param ${paramDesc}`, 2) + '\n'; + }); } + if (item.returns) { + output += ' *\n'; + const returnDesc = extractDescription(item.returns[0]?.description); + output += formatJSDocComment(`@return ${returnDesc}`, 2) + '\n'; + } + output += ' */\n'; + } - if (item.kind === 'function') { - const staticPrefix = isStatic ? 'static ' : ''; - - if (item.overloads?.length > 0) { - item.overloads.forEach(overload => { - const params = (overload.params || []) - .map(param => generateParamDeclaration(param)) - .join(', '); - const returnType = overload.returns?.[0]?.type - ? generateTypeFromTag(overload.returns[0]) - : 'void'; - output += ` ${staticPrefix}${item.name}(${params}): ${returnType};\n`; - }); - } + if (item.kind === 'function') { + const staticPrefix = isStatic ? 'static ' : ''; - const params = (item.params || []) - .map(param => generateParamDeclaration(param)) - .join(', '); - output += ` ${staticPrefix}${item.name}(${params}): ${item.returnType};\n\n`; - } else { - const staticPrefix = isStatic ? 'static ' : ''; - output += ` ${staticPrefix}${item.name}: ${item.returnType};\n\n`; + if (item.overloads?.length > 0) { + item.overloads.forEach(overload => { + const params = (overload.params || []) + .map(param => generateParamDeclaration(param)) + .join(', '); + const returnType = overload.returns?.[0]?.type + ? generateTypeFromTag(overload.returns[0]) + : 'void'; + output += ` ${staticPrefix}${item.name}(${params}): ${returnType};\n`; + }); } - return output; + const params = (item.params || []) + .map(param => generateParamDeclaration(param)) + .join(', '); + output += ` ${staticPrefix}${item.name}(${params}): ${item.returnType};\n\n`; + } else { + const staticPrefix = isStatic ? 'static ' : ''; + output += ` ${staticPrefix}${item.name}: ${item.returnType};\n\n`; } + return output; +} + export function generateClassDeclaration(classDoc, organizedData) { - let output = ''; + let output = ''; - if (classDoc.description || classDoc.tags?.length > 0) { - output += '/**\n'; - const description = extractDescription(classDoc.description); + if (classDoc.description || classDoc.tags?.length > 0) { + output += '/**\n'; + const description = extractDescription(classDoc.description); + if (description) { + output += formatJSDocComment(description) + '\n'; + } + if (classDoc.tags) { if (description) { - output += formatJSDocComment(description) + '\n'; + output += ' *\n'; } - if (classDoc.tags) { - if (description) { - output += ' *\n'; + classDoc.tags.forEach(tag => { + if (tag.description) { + const tagDesc = extractDescription(tag.description); + output += formatJSDocComment(`@${tag.title} ${tagDesc}`, 0) + '\n'; } - classDoc.tags.forEach(tag => { - if (tag.description) { - const tagDesc = extractDescription(tag.description); - output += formatJSDocComment(`@${tag.title} ${tagDesc}`, 0) + '\n'; - } - }); - } - output += ' */\n'; + }); } + output += ' */\n'; + } - const parentClass = classDoc.extends; - const extendsClause = parentClass ? ` extends ${parentClass}` : ''; + const parentClass = classDoc.extends; + const extendsClause = parentClass ? ` extends ${parentClass}` : ''; - const fullClassName = normalizeClassName(classDoc.name); - const classDocName = fullClassName.replace('p5.', ''); - output += `class ${classDocName}${extendsClause} {\n`; + const fullClassName = normalizeClassName(classDoc.name); + const classDocName = fullClassName.replace('p5.', ''); + output += `class ${classDocName}${extendsClause} {\n`; - if (classDoc.params?.length > 0) { - output += ' constructor('; - output += classDoc.params - .map(param => generateParamDeclaration(param)) - .join(', '); - output += ');\n\n'; - } + if (classDoc.params?.length > 0) { + output += ' constructor('; + output += classDoc.params + .map(param => generateParamDeclaration(param)) + .join(', '); + output += ');\n\n'; + } - const classItems = organizedData.classitems.filter(item => - item.class === fullClassName || + const classItems = organizedData.classitems.filter(item => + item.class === fullClassName || item.class === fullClassName.replace('p5.', '') - ); - const staticItems = classItems.filter(item => item.isStatic); - const instanceItems = classItems.filter(item => !item.isStatic); + ); + const staticItems = classItems.filter(item => item.isStatic); + const instanceItems = classItems.filter(item => !item.isStatic); - staticItems.forEach(item => { - output += generateMethodDeclarations(item, true); - }); + staticItems.forEach(item => { + output += generateMethodDeclarations(item, true); + }); - instanceItems.forEach(item => { - output += generateMethodDeclarations(item, false); - }); + instanceItems.forEach(item => { + output += generateMethodDeclarations(item, false); + }); - output += '}\n\n'; - return output; - } + output += '}\n\n'; + return output; +} function formatJSDocComment(text, indentLevel = 0) { - if (!text) return ''; - const indent = ' '.repeat(indentLevel); - - const lines = text - .split('\n') - .map(line => line.trim()) - .reduce((acc, line) => { - // If we're starting and line is empty, skip it - if (acc.length === 0 && line === '') return acc; - // If we have content and hit an empty line, keep one empty line - if (acc.length > 0 && line === '' && acc[acc.length - 1] === '') return acc; - acc.push(line); - return acc; - }, []) - .filter((line, i, arr) => i < arr.length - 1 || line !== ''); // Remove trailing empty line - - return lines - .map(line => `${indent} * ${line}`) - .join('\n'); - } - function groupByFile(items) { - const fileGroups = new Map(); + if (!text) return ''; + const indent = ' '.repeat(indentLevel); + + const lines = text + .split('\n') + .map(line => line.trim()) + .reduce((acc, line) => { + // If we're starting and line is empty, skip it + if (acc.length === 0 && line === '') return acc; + // If we have content and hit an empty line, keep one empty line + if (acc.length > 0 && line === '' && acc[acc.length - 1] === '') return acc; + acc.push(line); + return acc; + }, []) + .filter((line, i, arr) => i < arr.length - 1 || line !== ''); // Remove trailing empty line + + return lines + .map(line => `${indent} * ${line}`) + .join('\n'); +} +function groupByFile(items) { + const fileGroups = new Map(); - items.forEach(item => { - if (!item.context || !item.context.file) return; + items.forEach(item => { + if (!item.context || !item.context.file) return; - const filePath = item.context.file; - if (!fileGroups.has(filePath)) { - fileGroups.set(filePath, []); - } - fileGroups.get(filePath).push(item); - }); + const filePath = item.context.file; + if (!fileGroups.has(filePath)) { + fileGroups.set(filePath, []); + } + fileGroups.get(filePath).push(item); + }); - return fileGroups; - } + return fileGroups; +} diff --git a/utils/patch.mjs b/utils/patch.mjs index d70f983006..9aeee1b6d0 100644 --- a/utils/patch.mjs +++ b/utils/patch.mjs @@ -1,26 +1,26 @@ import fs from 'fs'; const replace = (path, src, dest) => { - try { - const data = fs - .readFileSync(path, { encoding: 'utf-8' }) - .replace(src, dest); - fs.writeFileSync(path, data); - } catch (err) { - console.error(err); - } + try { + const data = fs + .readFileSync(path, { encoding: 'utf-8' }) + .replace(src, dest); + fs.writeFileSync(path, data); + } catch (err) { + console.error(err); + } }; replace( - "./types/core/structure.d.ts", - "function p5(sketch: object, node: string | HTMLElement): void;", - "function p5: typeof p5" + './types/core/structure.d.ts', + 'function p5(sketch: object, node: string | HTMLElement): void;', + 'function p5: typeof p5' ); replace( - "./types/webgl/p5.Geometry.d.ts", - "constructor(detailX?: number, detailY?: number, callback?: function);", - `constructor( + './types/webgl/p5.Geometry.d.ts', + 'constructor(detailX?: number, detailY?: number, callback?: function);', + `constructor( detailX?: number, detailY?: number, callback?: (this: { @@ -33,9 +33,9 @@ replace( // https://github.com/p5-types/p5.ts/issues/31 replace( - "./types/math/random.d.ts", - "function random(choices: Array): any;", - "function random(choices: T[]): T;" + './types/math/random.d.ts', + 'function random(choices: Array): any;', + 'function random(choices: T[]): T;' ); diff --git a/vitest.workspace.mjs b/vitest.workspace.mjs index 767c67f90b..3b8cc242f7 100644 --- a/vitest.workspace.mjs +++ b/vitest.workspace.mjs @@ -18,18 +18,18 @@ export default defineWorkspace([ root: './', include: [ './test/bench/**/*.js' - ], + ] }, test: { name: 'unit', root: './', include: [ - './test/unit/**/*.js', + './test/unit/**/*.js' ], exclude: [ './test/unit/spec.js', './test/unit/assets/**/*', - './test/unit/visual/visualTest.js', + './test/unit/visual/visualTest.js' ], testTimeout: 1000, globals: true, @@ -40,8 +40,8 @@ export default defineWorkspace([ screenshotFailures: false }, fakeTimers: { - toFake: [...(configDefaults.fakeTimers.toFake ?? []), 'performance'], - }, + toFake: [...(configDefaults.fakeTimers.toFake ?? []), 'performance'] + } } } ]); \ No newline at end of file From f9334953590877ae00295fdbe9ca979aa8b85e61 Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Tue, 2 Sep 2025 19:42:05 +0100 Subject: [PATCH 2/2] Fix unit test referencing undefined variable --- test/unit/core/vertex.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/core/vertex.js b/test/unit/core/vertex.js index 24b9edca79..357d1e7ab6 100644 --- a/test/unit/core/vertex.js +++ b/test/unit/core/vertex.js @@ -5,7 +5,6 @@ suite('Vertex', function() { var myp5; beforeEach(function() { - _friendlyErrorSpy = vi.spyOn(p5, '_friendlyError'); new p5(function(p) { p.setup = function() { myp5 = p;