@labcat2020/p5.audioreactive 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,71 @@
1
+ import p5 from 'p5';
2
+
3
+ // p5.polygon.js
4
+ // A polygon drawing library for p5.js
5
+
6
+ /**
7
+ * Helper function to draw any regular polygon
8
+ * @param {Number} x - x-coordinate of the polygon
9
+ * @param {Number} y - y-coordinate of the polygon
10
+ * @param {Number} radius - radius of the polygon
11
+ * @param {Number} sides - number of sides
12
+ * @param {Number} startAngle - starting angle (optional)
13
+ */
14
+ p5.prototype.polygon = function(x, y, radius, sides, startAngle = 0) {
15
+ this.angleMode(this.RADIANS);
16
+ const angle = this.TWO_PI / sides;
17
+ this.beginShape();
18
+ for (let a = startAngle; a < this.TWO_PI + startAngle; a += angle) {
19
+ let sx = x + this.cos(a) * radius;
20
+ let sy = y + this.sin(a) * radius;
21
+ this.vertex(sx, sy);
22
+ }
23
+ this.endShape(this.CLOSE);
24
+ };
25
+
26
+ /**
27
+ * Draw a pentagon shape
28
+ * @param {Number} x - x-coordinate of the pentagon
29
+ * @param {Number} y - y-coordinate of the pentagon
30
+ * @param {Number} width - width of the pentagon
31
+ * @param {Number} height - height of the pentagon (optional, defaults to width)
32
+ */
33
+ p5.prototype.pentagon = function(x, y, width, height = width) {
34
+ // Fixed: Remove the radius division by 2 since we're already providing the full width/height
35
+ // Fixed: Adjust starting angle to point upward (-PI/2 or -90 degrees)
36
+ const radius = Math.min(width, height) / 2;
37
+ this.polygon(x, y, radius, 5, -this.PI/2);
38
+ };
39
+
40
+ /**
41
+ * Draw a hexagon shape
42
+ * @param {Number} x - x-coordinate of the hexagon
43
+ * @param {Number} y - y-coordinate of the hexagon
44
+ * @param {Number} radius - radius of the hexagon
45
+ */
46
+ p5.prototype.hexagon = function(x, y, radius) {
47
+ // For consistency, also remove the radius division here
48
+ this.polygon(x, y, radius / 2, 6, 0);
49
+ };
50
+
51
+ /**
52
+ * Draw an octagon shape
53
+ * @param {Number} x - x-coordinate of the octagon
54
+ * @param {Number} y - y-coordinate of the octagon
55
+ * @param {Number} radius - radius of the octagon
56
+ */
57
+ p5.prototype.octagon = function(x, y, radius) {
58
+ // For consistency, also remove the radius division here
59
+ this.polygon(x, y, radius / 2, 8, this.TWO_PI / 16);
60
+ };
61
+
62
+ /**
63
+ * Draw an equilateral triangle shape
64
+ * @param {Number} x - x-coordinate of the triangle
65
+ * @param {Number} y - y-coordinate of the triangle
66
+ * @param {Number} radius - radius of the triangle
67
+ */
68
+ p5.prototype.equilateral = function(x, y, radius) {
69
+ // Match the exact same pattern as pentagon, hexagon, and octagon
70
+ this.polygon(x, y, radius / 2, 3, -this.PI/2);
71
+ };
@@ -0,0 +1,95 @@
1
+ # p5.randomColor
2
+
3
+ A p5.js library for generating attractive random colors. A p5-aware port of [randomColor](https://randomcolor.lllllllllllllllll.com) by David Merfield (CC0).
4
+
5
+ This library augments `p5.prototype` with a `randomColor()` method that uses p5's RNG and returns a `p5.Color` object.
6
+
7
+ ## Installation
8
+
9
+ Include the script in your HTML file after p5.js:
10
+
11
+ ```html
12
+ <script src="p5.js"></script>
13
+ <script src="p5.randomColor.js"></script>
14
+ ```
15
+
16
+ ## Basic Usage
17
+
18
+ ```javascript
19
+ function setup() {
20
+ createCanvas(400, 400);
21
+
22
+ // Generate a random attractive color
23
+ let c = randomColor();
24
+ fill(c);
25
+ rect(0, 0, width, height);
26
+ }
27
+ ```
28
+
29
+ ## Options
30
+
31
+ You can pass an options object to influence the type of color it produces:
32
+
33
+ **`hue`** – Controls the hue of the generated color. You can pass a string representing a color name: `red`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink` and `monochrome` are currently supported.
34
+
35
+ **`luminosity`** – Controls the luminosity of the generated color. You can specify a string containing `bright`, `light`, `dark`, or `random`.
36
+
37
+ **`count`** – An integer which specifies the number of colors to generate. Returns an array of `p5.Color` objects.
38
+
39
+ **`alpha`** – A decimal between 0 and 1. Controls the alpha channel of the generated color.
40
+
41
+ **Note:** This library always returns a `p5.Color` object. There is no `format` option. Seeding is handled by p5's `randomSeed()` function, not through options.
42
+
43
+ ## Examples
44
+
45
+ ```javascript
46
+ // Returns a random attractive color
47
+ let color = randomColor();
48
+
49
+ // Returns an array of ten green colors
50
+ let greens = randomColor({
51
+ count: 10,
52
+ hue: 'green'
53
+ });
54
+
55
+ // Returns a light blue color
56
+ let lightBlue = randomColor({
57
+ luminosity: 'light',
58
+ hue: 'blue'
59
+ });
60
+
61
+ // Returns a bright color
62
+ let bright = randomColor({
63
+ luminosity: 'bright'
64
+ });
65
+
66
+ // Returns a dark color with alpha
67
+ let dark = randomColor({
68
+ luminosity: 'dark',
69
+ alpha: 0.8
70
+ });
71
+
72
+ // Returns a 'truly random' color
73
+ let random = randomColor({
74
+ luminosity: 'random',
75
+ hue: 'random'
76
+ });
77
+
78
+ // Using with p5's randomSeed for reproducible results
79
+ function setup() {
80
+ randomSeed(42);
81
+ let color1 = randomColor({ hue: 'blue' });
82
+
83
+ randomSeed(42);
84
+ let color2 = randomColor({ hue: 'blue' });
85
+ // color1 and color2 will be the same
86
+ }
87
+ ```
88
+
89
+ ## Differences from vanilla randomColor
90
+
91
+ - Always returns a `p5.Color` object (no hex strings or format options)
92
+ - Uses p5's RNG (use `randomSeed()` for seeding, not a `seed` option)
93
+ - Works seamlessly with p5's color system
94
+ - Only intended for use within p5 sketches
95
+
@@ -0,0 +1,302 @@
1
+ import p5 from 'p5';
2
+
3
+ /**
4
+ * @fileoverview p5.randomColor.js
5
+ * A p5-aware port of randomColor (original by David Merfield, CC0)
6
+ * This module augments p5.prototype with `randomColor(options)` which
7
+ * mirrors the original API but uses p5's RNG and returns a p5.Color.
8
+ */
9
+ const colorDictionary = {};
10
+ const colorRanges = [];
11
+
12
+ loadColorBounds();
13
+
14
+ /**
15
+ * Generates a random color using p5's RNG
16
+ * @param {Object} options - Configuration options
17
+ * @param {string|number} [options.hue] - Hue range (color name or 0-360)
18
+ * @param {string} [options.luminosity] - "bright", "light", "dark", or "random"
19
+ * @param {number} [options.alpha] - Alpha value (0-1)
20
+ * @param {number} [options.count] - Number of colors to generate
21
+ * @returns {p5.Color|p5.Color[]} A p5.Color or array of p5.Colors
22
+ */
23
+ p5.prototype.randomColor = function (options) {
24
+ const p = this;
25
+ options = options || {};
26
+
27
+ function generateOne() {
28
+ const H = pickHueForP(p, options);
29
+ const S = pickSaturation(H, options, p);
30
+ const B = pickBrightness(H, S, options, p);
31
+ return colorFromHSV([H, S, B], options, p);
32
+ }
33
+
34
+ if (options.count !== null && options.count !== undefined) {
35
+ const totalColors = options.count;
36
+ const colors = [];
37
+ for (let i = 0; i < totalColors; i++) colorRanges.push(false);
38
+ const singleOptions = { ...options };
39
+ delete singleOptions.count;
40
+ while (colors.length < totalColors) colors.push(p.randomColor(singleOptions));
41
+ return colors;
42
+ }
43
+
44
+ return generateOne();
45
+ };
46
+
47
+ /**
48
+ * Picks a hue value based on options
49
+ * @param {p5} p - p5 instance
50
+ * @param {Object} options - Options object
51
+ * @returns {number} Hue value (0-360)
52
+ * @private
53
+ */
54
+ function pickHueForP(p, options) {
55
+ if (colorRanges.length > 0) {
56
+ let hueRange = getRealHueRange(options.hue);
57
+ let hue = p.random(hueRange[0], hueRange[1]);
58
+
59
+ const step = (hueRange[1] - hueRange[0]) / colorRanges.length;
60
+ let j = parseInt((hue - hueRange[0]) / step);
61
+
62
+ if (colorRanges[j] === true) {
63
+ j = (j + 2) % colorRanges.length;
64
+ } else {
65
+ colorRanges[j] = true;
66
+ }
67
+
68
+ const min = (hueRange[0] + j * step) % 359;
69
+ const max = (hueRange[0] + (j + 1) * step) % 359;
70
+ hueRange = [min, max];
71
+
72
+ hue = p.random(hueRange[0], hueRange[1]);
73
+ if (hue < 0) hue = 360 + hue;
74
+ return hue;
75
+ } else {
76
+ const hueRange = getHueRange(options.hue);
77
+ let hue = p.random(hueRange[0], hueRange[1]);
78
+ if (hue < 0) hue = 360 + hue;
79
+ return hue;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Picks a saturation value based on hue and options
85
+ * @param {number} hue - Hue value
86
+ * @param {Object} options - Options object
87
+ * @param {p5} p - p5 instance
88
+ * @returns {number} Saturation value (0-100)
89
+ * @private
90
+ */
91
+ function pickSaturation(hue, options, p) {
92
+ if (options && options.hue === "monochrome") return 0;
93
+ if (options && options.luminosity === "random") return p.random(0, 100);
94
+
95
+ const saturationRange = getSaturationRange(hue);
96
+ let sMin = saturationRange[0], sMax = saturationRange[1];
97
+
98
+ switch (options && options.luminosity) {
99
+ case "bright":
100
+ sMin = 55;
101
+ break;
102
+ case "dark":
103
+ sMin = sMax - 10;
104
+ break;
105
+ case "light":
106
+ sMax = 55;
107
+ break;
108
+ }
109
+
110
+ return p.random(sMin, sMax);
111
+ }
112
+
113
+ /**
114
+ * Picks a brightness value based on hue, saturation, and options
115
+ * @param {number} H - Hue value
116
+ * @param {number} S - Saturation value
117
+ * @param {Object} options - Options object
118
+ * @param {p5} p - p5 instance
119
+ * @returns {number} Brightness value (0-100)
120
+ * @private
121
+ */
122
+ function pickBrightness(H, S, options, p) {
123
+ let bMin = getMinimumBrightness(H, S), bMax = 100;
124
+ switch (options && options.luminosity) {
125
+ case "dark":
126
+ bMax = bMin + 20;
127
+ break;
128
+ case "light":
129
+ bMin = (bMax + bMin) / 2;
130
+ break;
131
+ case "random":
132
+ bMin = 0;
133
+ bMax = 100;
134
+ break;
135
+ }
136
+ return p.random(bMin, bMax);
137
+ }
138
+
139
+ /**
140
+ * Creates a p5.Color from HSB values
141
+ * @param {number[]} hsv - Array of [H, S, B] values
142
+ * @param {Object} options - Options object
143
+ * @param {p5} p - p5 instance
144
+ * @returns {p5.Color} p5.Color object
145
+ * @private
146
+ */
147
+ function colorFromHSV(hsv, options, p) {
148
+ options = options || {};
149
+ const H = hsv[0];
150
+ const S = hsv[1];
151
+ const B = hsv[2];
152
+ const alpha = options.alpha === undefined ? 1 : Math.max(0, Math.min(1, options.alpha));
153
+ p.push();
154
+ p.colorMode(p.HSB, 360, 100, 100, 1);
155
+ const c = p.color(H, S, B, alpha);
156
+ p.pop();
157
+ return c;
158
+ }
159
+
160
+ /**
161
+ * Calculates minimum brightness for a given hue and saturation
162
+ * @param {number} H - Hue value
163
+ * @param {number} S - Saturation value
164
+ * @returns {number} Minimum brightness value
165
+ * @private
166
+ */
167
+ function getMinimumBrightness(H, S) {
168
+ const lowerBounds = getColorInfo(H).lowerBounds;
169
+ for (let i = 0; i < lowerBounds.length - 1; i++) {
170
+ const s1 = lowerBounds[i][0], v1 = lowerBounds[i][1];
171
+ const s2 = lowerBounds[i + 1][0], v2 = lowerBounds[i + 1][1];
172
+ if (S >= s1 && S <= s2) {
173
+ const m = (v2 - v1) / (s2 - s1), b = v1 - m * s1;
174
+ return m * S + b;
175
+ }
176
+ }
177
+ return 0;
178
+ }
179
+
180
+ /**
181
+ * Gets hue range for a color input
182
+ * @param {string|number} colorInput - Color name or hue value
183
+ * @returns {number[]} Array of [min, max] hue range
184
+ * @private
185
+ */
186
+ function getHueRange(colorInput) {
187
+ if (!isNaN(parseInt(colorInput))) {
188
+ const number = parseInt(colorInput);
189
+ if (number < 360 && number > 0) return [number, number];
190
+ }
191
+ if (typeof colorInput === "string") {
192
+ if (colorDictionary[colorInput]) {
193
+ const color = colorDictionary[colorInput];
194
+ if (color.hueRange) return color.hueRange;
195
+ }
196
+ }
197
+ return [0, 360];
198
+ }
199
+
200
+ /**
201
+ * Gets saturation range for a hue value
202
+ * @param {number} hue - Hue value
203
+ * @returns {number[]} Array of [min, max] saturation range
204
+ * @private
205
+ */
206
+ function getSaturationRange(hue) {
207
+ return getColorInfo(hue).saturationRange;
208
+ }
209
+
210
+ /**
211
+ * Gets color information for a hue value
212
+ * @param {number} hue - Hue value
213
+ * @returns {Object} Color info with hueRange, lowerBounds, saturationRange, brightnessRange
214
+ * @private
215
+ */
216
+ function getColorInfo(hue) {
217
+ if (hue >= 334 && hue <= 360) hue -= 360;
218
+ for (const colorName in colorDictionary) {
219
+ const color = colorDictionary[colorName];
220
+ if (
221
+ color.hueRange &&
222
+ hue >= color.hueRange[0] &&
223
+ hue <= color.hueRange[1]
224
+ ) {
225
+ return colorDictionary[colorName];
226
+ }
227
+ }
228
+ return { lowerBounds: [[0,0]], saturationRange: [0,100] };
229
+ }
230
+
231
+ /**
232
+ * Defines a color in the color dictionary
233
+ * @param {string} name - Color name
234
+ * @param {number[]|null} hueRange - Hue range array or null
235
+ * @param {number[][]} lowerBounds - Array of [saturation, brightness] pairs
236
+ * @private
237
+ */
238
+ function defineColor(name, hueRange, lowerBounds) {
239
+ const sMin = lowerBounds[0][0], sMax = lowerBounds[lowerBounds.length - 1][0];
240
+ const bMin = lowerBounds[lowerBounds.length - 1][1], bMax = lowerBounds[0][1];
241
+ colorDictionary[name] = {
242
+ hueRange: hueRange,
243
+ lowerBounds: lowerBounds,
244
+ saturationRange: [sMin, sMax],
245
+ brightnessRange: [bMin, bMax],
246
+ };
247
+ }
248
+
249
+ /**
250
+ * Loads color bounds into the color dictionary
251
+ * @private
252
+ */
253
+ function loadColorBounds() {
254
+ defineColor("monochrome", null, [ [0,0], [100,0] ]);
255
+
256
+ defineColor("red", [-26, 18], [
257
+ [20,100],[30,92],[40,89],[50,85],[60,78],[70,70],[80,60],[90,55],[100,50]
258
+ ]);
259
+
260
+ defineColor("orange", [18,46], [
261
+ [20,100],[30,93],[40,88],[50,86],[60,85],[70,70],[100,70]
262
+ ]);
263
+
264
+ defineColor("yellow", [46,62], [
265
+ [25,100],[40,94],[50,89],[60,86],[70,84],[80,82],[90,80],[100,75]
266
+ ]);
267
+
268
+ defineColor("green", [62,178], [
269
+ [30,100],[40,90],[50,85],[60,81],[70,74],[80,64],[90,50],[100,40]
270
+ ]);
271
+
272
+ defineColor("blue", [178,257], [
273
+ [20,100],[30,86],[40,80],[50,74],[60,60],[70,52],[80,44],[90,39],[100,35]
274
+ ]);
275
+
276
+ defineColor("purple", [257,282], [
277
+ [20,100],[30,87],[40,79],[50,70],[60,65],[70,59],[80,52],[90,45],[100,42]
278
+ ]);
279
+
280
+ defineColor("pink", [282,334], [
281
+ [20,100],[30,90],[40,86],[60,84],[80,80],[90,75],[100,73]
282
+ ]);
283
+ }
284
+
285
+ /**
286
+ * Gets the real hue range when generating multiple colors
287
+ * @param {string|number} colorHue - Color name or hue value
288
+ * @returns {number[]} Array of [min, max] hue range
289
+ * @private
290
+ */
291
+ function getRealHueRange(colorHue) {
292
+ if (!isNaN(colorHue)) {
293
+ const number = parseInt(colorHue);
294
+ if (number < 360 && number > 0) return getColorInfo(colorHue).hueRange;
295
+ } else if (typeof colorHue === 'string') {
296
+ if (colorDictionary[colorHue]) {
297
+ const color = colorDictionary[colorHue];
298
+ if (color.hueRange) return color.hueRange;
299
+ }
300
+ }
301
+ return [0,360];
302
+ }
@@ -0,0 +1,3 @@
1
+ import p5 from 'p5';
2
+
3
+ globalThis.p5 = p5;
@@ -0,0 +1,2 @@
1
+ import './p5.setGlobalP5.js';
2
+ import 'p5.sound/dist/p5.sound.js';
@@ -0,0 +1,198 @@
1
+ import p5 from 'p5';
2
+
3
+ // Sacred Geometry Library
4
+ // Shared functions for drawing sacred geometry patterns using p5.Polar
5
+ /**
6
+ * Draws the vesica piscis pattern
7
+ * @param {string} currentShapeType - Current shape type being used
8
+ * @param {number} size - Size of the pattern
9
+ */
10
+ p5.prototype.drawVesicaPiscis = function(currentShapeType, size) {
11
+ if (currentShapeType === 'polarEllipse') {
12
+ this.polarEllipse(0, size, size);
13
+ this.polarEllipse(0, size / 2, size /2);
14
+ this.polarEllipse(0, size / 4 * 3, size / 4 * 3, size / 4);
15
+ this.polarEllipse(0, size / 4 * 3, size / 4 * 3, -size / 4);
16
+ } else {
17
+ this[currentShapeType](0, size);
18
+ this[currentShapeType](0, size / 2);
19
+ this[currentShapeType](0, size / 4 * 3, -size / 4);
20
+ this[currentShapeType](180, size / 4 * 3, -size / 4);
21
+ }
22
+ };
23
+
24
+ /**
25
+ * Draws the seed of life pattern
26
+ * @param {string} currentShapeType - Current shape type being used
27
+ * @param {number} size - Size of the pattern
28
+ */
29
+ p5.prototype.drawSeedOfLife = function(currentShapeType, size) {
30
+ const shapeSize = size / 2;
31
+ if (currentShapeType === 'polarEllipse') {
32
+ this.polarEllipse(0, shapeSize, shapeSize);
33
+ this.polarEllipses(6, shapeSize, shapeSize, shapeSize);
34
+ }
35
+ else {
36
+ this[currentShapeType](0, shapeSize);
37
+ this[`${currentShapeType}s`](6, shapeSize, shapeSize);
38
+ }
39
+ };
40
+
41
+ /**
42
+ * Draws the egg of life pattern
43
+ * @param {string} currentShapeType - Current shape type being used
44
+ * @param {number} size - Size of the pattern
45
+ */
46
+ p5.prototype.drawEggOfLife = function(currentShapeType, size) {
47
+ const shapeSize = size / 3;
48
+ if (currentShapeType === 'polarEllipse') {
49
+ this.polarEllipse(0, shapeSize, shapeSize);
50
+ this.polarEllipses(6, shapeSize, shapeSize, shapeSize * 2);
51
+ }
52
+ else {
53
+ this[currentShapeType](0, shapeSize);
54
+ this[`${currentShapeType}s`](6, shapeSize, shapeSize * 2);
55
+ }
56
+ };
57
+
58
+ /**
59
+ * Draws the flower of life pattern
60
+ * @param {string} currentShapeType - Current shape type being used
61
+ * @param {number} size - Size of the pattern
62
+ */
63
+ p5.prototype.drawFlowerOfLife = function(currentShapeType, size) {
64
+ const shapeSize = size / 3;
65
+ if (currentShapeType === 'polarEllipse') {
66
+ this.polarEllipse(0, size, size);
67
+ this.polarEllipse(0, shapeSize, shapeSize);
68
+ this.polarEllipses(6, shapeSize, shapeSize, shapeSize);
69
+ this.polarEllipses(12, shapeSize, shapeSize, shapeSize * 2);
70
+ }
71
+ else {
72
+ this[currentShapeType](0, size);
73
+ this[currentShapeType](0, shapeSize);
74
+ this[`${currentShapeType}s`](6, shapeSize, shapeSize);
75
+ this[`${currentShapeType}s`](12, shapeSize, shapeSize * 2);
76
+ }
77
+ };
78
+
79
+ /**
80
+ * Draws the fruit of life pattern
81
+ * @param {string} currentShapeType - Current shape type being used
82
+ * @param {number} size - Size of the pattern
83
+ */
84
+ p5.prototype.drawFruitOfLife = function(currentShapeType, size) {
85
+ const shapeSize = size / 5;
86
+ if (currentShapeType === 'polarEllipse') {
87
+ this.polarEllipse(0, shapeSize, shapeSize);
88
+ this.polarEllipses(6, shapeSize, shapeSize, shapeSize * 2);
89
+ this.polarEllipses(6, shapeSize, shapeSize, shapeSize * 4);
90
+ }
91
+ else {
92
+ this[currentShapeType](0, shapeSize);
93
+ this[`${currentShapeType}s`](6, shapeSize, shapeSize * 2);
94
+ this[`${currentShapeType}s`](6, shapeSize, shapeSize * 4);
95
+ }
96
+ };
97
+
98
+ /**
99
+ * Draws Metatrons Cube pattern
100
+ * @param {string} currentShapeType - Current shape type being used
101
+ * @param {number} size - Size of the pattern
102
+ */
103
+ p5.prototype.drawMetatronsCube = function(currentShapeType, size) {
104
+ const shapeSize = size / 5;
105
+ if (currentShapeType === 'polarEllipse') {
106
+ this.polarEllipse(0, shapeSize, shapeSize);
107
+ this.polarEllipses(6, shapeSize, shapeSize, shapeSize * 2);
108
+ this.polarEllipses(6, shapeSize, shapeSize, shapeSize * 4);
109
+ }
110
+ else {
111
+ this[currentShapeType](0, shapeSize);
112
+ this[`${currentShapeType}s`](6, shapeSize, shapeSize * 2);
113
+ this[`${currentShapeType}s`](6, shapeSize, shapeSize * 4);
114
+ }
115
+
116
+ const originalStrokeWeight = this.drawingContext.lineWidth;
117
+ this.strokeWeight(originalStrokeWeight / 4);
118
+
119
+ const linePositions = [];
120
+ for (let i = 0; i < 6; i++) {
121
+ const angle = this.TWO_PI / 6 * i + this.PI / 6;
122
+ linePositions.push({
123
+ x: this.cos(angle) * shapeSize * 2,
124
+ y: this.sin(angle) * shapeSize * 2
125
+ });
126
+ linePositions.push({
127
+ x: this.cos(angle) * shapeSize * 4,
128
+ y: this.sin(angle) * shapeSize * 4
129
+ });
130
+ }
131
+
132
+ for (let i = 0; i < linePositions.length; i++) {
133
+ for (let j = i + 1; j < linePositions.length; j++) {
134
+ this.line(linePositions[i].x, linePositions[i].y, linePositions[j].x, linePositions[j].y);
135
+ }
136
+ }
137
+ this.strokeWeight(originalStrokeWeight);
138
+ };
139
+
140
+ /**
141
+ * Draws the tree of life pattern
142
+ * @param {string} currentShapeType - Current shape type being used
143
+ * @param {number} size - Size of the pattern
144
+ */
145
+ p5.prototype.drawTreeOfLife = function(currentShapeType, size) {
146
+ const shapeSize = size / 2;
147
+ const points = [];
148
+
149
+ for (let i = 0; i < 6; i++) {
150
+ const angle = (i * 60 + 30) * Math.PI / 180;
151
+ const x = Math.cos(angle) * shapeSize;
152
+ const y = Math.sin(angle) * shapeSize - shapeSize;
153
+ points.push({x, y});
154
+ }
155
+
156
+ for (let i = 0; i < 6; i++) {
157
+ if (i === 0 || i === 2) continue;
158
+ const angle = (i * 60 + 30) * Math.PI / 180;
159
+ const x = Math.cos(angle) * shapeSize;
160
+ const y = Math.sin(angle) * shapeSize + shapeSize;
161
+ points.push({x, y});
162
+ }
163
+
164
+ points.push({x: 0, y: shapeSize});
165
+
166
+ points.forEach((point, index) => {
167
+ this.push();
168
+ this.translate(point.x, point.y);
169
+ if (currentShapeType === 'polarEllipse') {
170
+ this.polarEllipse(0, shapeSize / 3, shapeSize / 3);
171
+ } else {
172
+ this[currentShapeType](0, shapeSize / 3);
173
+ }
174
+ this.pop();
175
+ });
176
+
177
+ const connections = [
178
+ // Top triangle (Supernal Triad)
179
+ [3, 4], [4, 5], [5, 3],
180
+ // Vertical paths from top triangle
181
+ [5, 0], [3, 2],
182
+ // Connections to bottom ring
183
+ [0, 9], [2, 7],
184
+ // Horizontal connections
185
+ [0, 2],
186
+ // Vertical central trunk
187
+ [4, 8], [8, 10], [10, 6],
188
+ // Bottom formation connections
189
+ [7, 8], [8, 9], [9, 10], [10, 7]
190
+ ];
191
+
192
+ connections.forEach(([from, to]) => {
193
+ if (points[from] && points[to]) {
194
+ this.line(points[from].x, points[from].y, points[to].x, points[to].y);
195
+ }
196
+ });
197
+
198
+ };