p5.tree 0.0.1 → 0.0.3

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.
package/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # p5.tree
2
+ [![npm version](https://img.shields.io/npm/v/p5.tree)](https://www.npmjs.com/package/p5.tree)
2
3
 
3
4
  Shader development, camera keyframes interpolation and space transformations for [WEBGL](https://p5js.org/reference/#/p5/WEBGL) / WebGPU-ready [p5.js v2](https://beta.p5js.org/).
4
5
 
@@ -188,8 +189,8 @@ This section covers matrix operations, matrix/frustum queries, and coordinate sp
188
189
 
189
190
  ## Coordinate space conversions
190
191
 
191
- 1. `transformPosition(point = p5.Tree.ORIGIN, [{ [from = p5.Tree.EYE], [to = p5.Tree.WORLD], [pMatrix], [vMatrix], [eMatrix], [pvMatrix], [ipvMatrix] }])`
192
- 2. `transformDirection(vector = p5.Tree._k, [{ [from = p5.Tree.EYE], [to = p5.Tree.WORLD], [vMatrix], [eMatrix], [pMatrix] }])`
192
+ 1. `mapLocation(point = p5.Tree.ORIGIN, [{ [from = p5.Tree.EYE], [to = p5.Tree.WORLD], [pMatrix], [vMatrix], [eMatrix], [pvMatrix], [ipvMatrix] }])`
193
+ 2. `mapDirection(vector = p5.Tree._k, [{ [from = p5.Tree.EYE], [to = p5.Tree.WORLD], [vMatrix], [eMatrix], [pMatrix] }])`
193
194
 
194
195
  Pass matrix parameters when you have **cached** those matrices (see [Matrix queries](#matrix-queries)) to speed up repeated conversions:
195
196
 
@@ -200,8 +201,8 @@ function draw() {
200
201
  cachedPVI = ipvMatrix() // compute once per frame
201
202
 
202
203
  // many fast conversions using the cached matrix
203
- const a = transformPosition([0, 0, 0], { from: p5.Tree.WORLD, to: p5.Tree.SCREEN, ipvMatrix: cachedPVI })
204
- const b = transformPosition([100, 0, 0], { from: p5.Tree.WORLD, to: p5.Tree.SCREEN, ipvMatrix: cachedPVI })
204
+ const a = mapLocation([0, 0, 0], { from: p5.Tree.WORLD, to: p5.Tree.SCREEN, ipvMatrix: cachedPVI })
205
+ const b = mapLocation([100, 0, 0], { from: p5.Tree.WORLD, to: p5.Tree.SCREEN, ipvMatrix: cachedPVI })
205
206
  // ...
206
207
  }
207
208
  ```
@@ -222,7 +223,7 @@ function draw() {
222
223
  pop()
223
224
 
224
225
  // screen projection of the model origin
225
- const s = transformPosition(p5.Tree.ORIGIN, { from: model, to: p5.Tree.SCREEN })
226
+ const s = mapLocation(p5.Tree.ORIGIN, { from: model, to: p5.Tree.SCREEN })
226
227
  beginHUD()
227
228
  bullsEye({ x: s.x, y: s.y, size: 30 })
228
229
  endHUD()
@@ -234,8 +235,8 @@ function draw() {
234
235
  1. Returned vectors are `p5.Vector` instances.
235
236
  2. `from` and `to` may be matrices or any of: `p5.Tree.WORLD`, `p5.Tree.EYE`, `p5.Tree.SCREEN`, `p5.Tree.NDC`, `p5.Tree.MODEL`.
236
237
  3. When no matrix params are passed, current renderer values are used.
237
- 4. The default `transformPosition()` call (i.e. eye → world at origin) returns the camera world position.
238
- 5. The default `transformDirection()` call returns the normalized camera viewing direction.
238
+ 4. The default `mapLocation()` call (i.e. eye → world at origin) returns the camera world position.
239
+ 5. The default `mapDirection()` call returns the normalized camera viewing direction.
239
240
  6. Useful vector constants: `p5.Tree.ORIGIN`, `p5.Tree._k`, `p5.Tree.i`, `p5.Tree.j`, `p5.Tree.k`, `p5.Tree._i`, `p5.Tree._j`.
240
241
 
241
242
  ## Heads Up Display
@@ -265,43 +266,97 @@ A small collection of helpers commonly needed in interactive 3D sketches:
265
266
  Debug / teaching primitives for visualizing common 3D concepts:
266
267
 
267
268
  1. `axes({ size, colors, bits })`
268
- 2. `grid({ size, subdivisions, style })`
269
+ 2. `grid({ size, subdivisions })`
269
270
  3. `cross({ mMatrix, x, y, size, ... })`
270
271
  4. `bullsEye({ mMatrix, x, y, size, shape, ... })`
271
272
  5. `viewFrustum({ pg, bits, viewer, eMatrix, pMatrix, vMatrix })`
272
273
 
273
274
  ---
274
275
 
275
- # Installation
276
+ # Releases
276
277
 
277
- Link `p5.tree.js` after you have linked in `p5.js`. For example:
278
+ - **Latest (v0.0.3):**
279
+ These links always point to the latest published version on npm.
280
+ - [p5.tree.js (unminified, IIFE)](https://cdn.jsdelivr.net/npm/p5.tree/dist/p5.tree.js)
281
+ - [p5.tree.min.js (minified, IIFE)](https://cdn.jsdelivr.net/npm/p5.tree/dist/p5.tree.min.js)
282
+ - [p5.tree.esm.js (ES module)](https://cdn.jsdelivr.net/npm/p5.tree/dist/p5.tree.esm.js)
283
+ - [npm package](https://www.npmjs.com/package/p5.tree)
278
284
 
279
- ```html
280
- <!doctype html>
281
- <html>
282
- <head>
283
- <script src="p5.js"></script>
284
- <script src="p5.sound.js"></script>
285
- <script src=https://cdn.jsdelivr.net/gh/VisualComputing/p5.tree/p5.tree.js></script>
286
- <script src="sketch.js"></script>
287
- </head>
288
- <body>
289
- </body>
290
- </html>
291
- ```
285
+ - **Current tagged version (v0.0.3):**
286
+ Use these if you want to lock to a specific version.
287
+ - [p5.tree@0.0.3.js (unminified, IIFE)](https://cdn.jsdelivr.net/npm/p5.tree@0.0.3/dist/p5.tree.js)
288
+ - [p5.tree@0.0.3.min.js (minified, IIFE)](https://cdn.jsdelivr.net/npm/p5.tree@0.0.3/dist/p5.tree.min.js)
289
+ - [p5.tree@0.0.3.esm.js (ES module)](https://cdn.jsdelivr.net/npm/p5.tree@0.0.3/dist/p5.tree.esm.js)
290
+ - [npm package (v0.0.3)](https://www.npmjs.com/package/p5.tree/v/0.0.3)
291
+
292
+ ---
293
+
294
+ # Usage
295
+
296
+ The library works in two setups:
297
+
298
+ - **[CDN](#cdn)**: Use the [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) (Immediately Invoked Function Expression) format with `<script>` tags directly in the browser, along with [p5.js](https://beta.p5js.org/).
299
+ - **[npm](#npm-esm)**: Use the [ES module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) version in modern projects with [Vite](https://vitejs.dev/) or another bundler.
300
+
301
+ ## CDN
292
302
 
293
- To include the minified build (when available):
303
+ Include both libraries using `<script>` tags, which run in both [global](https://github.com/processing/p5.js/wiki/Global-and-instance-mode) and [instance mode](https://github.com/processing/p5.js/wiki/Global-and-instance-mode).
294
304
 
295
305
  ```html
296
- <script src=https://cdn.jsdelivr.net/gh/VisualComputing/p5.tree/p5.tree.min.js></script>
306
+ <!-- index.html -->
307
+ <!-- Load p5.js first (required by p5.tree) -->
308
+ <script src="https://cdn.jsdelivr.net/npm/p5/lib/p5.min.js"></script>
309
+
310
+ <!-- Load p5.tree (latest stable version) -->
311
+ <script src="https://cdn.jsdelivr.net/npm/p5.tree/dist/p5.tree.js"></script>
312
+
313
+ <script>
314
+ function setup() {
315
+ createCanvas(600, 400, WEBGL)
316
+
317
+ // Example: draw world axes
318
+ axes(100)
319
+ }
320
+
321
+ function draw() {
322
+ background(0.15)
323
+ orbitControl()
324
+ }
325
+ </script>
326
+ ````
327
+
328
+ You can run the example, which uses global mode, by opening the `index.html` file in a browser, or by using [VSCodium](https://vscodium.com/) (recommended) or [Visual Studio Code](https://code.visualstudio.com/) with the [Live Server extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer).
329
+
330
+ ## npm (ESM)
331
+
332
+ Install both [`p5`](https://www.npmjs.com/package/p5) and [`p5.tree`](https://www.npmjs.com/package/p5.tree) as dependencies:
333
+
334
+ ```bash
335
+ npm i p5 p5.tree
297
336
  ```
298
337
 
299
- # [vs-code](https://code.visualstudio.com/) & [vs-codium](https://vscodium.com/) & [gitpod](https://www.gitpod.io/) hacking instructions
338
+ Then import them in your project’s entry file (e.g. `main.js`) using a modern bundler like [Vite](https://vitejs.dev/), which runs in [instance mode](https://github.com/processing/p5.js/wiki/Global-and-instance-mode) only:
300
339
 
301
- Clone the repo (`git clone https://github.com/VisualComputing/p5.tree`) and open it with your favorite editor.
340
+ ```js
341
+ // main.js
342
+ import p5 from 'p5'
343
+ import 'p5.tree'
344
+
345
+ const sketch = p => {
346
+ p.setup = () => {
347
+ p.createCanvas(600, 400, p.WEBGL)
348
+
349
+ // Example: draw world axes
350
+ p.axes(100)
351
+ }
352
+
353
+ p.draw = () => {
354
+ p.background(0.15)
355
+ p.orbitControl()
356
+ }
357
+ }
302
358
 
303
- If you are developing against p5 v2, keep an eye on:
359
+ new p5(sketch)
360
+ ```
304
361
 
305
- 1. [Creating libraries](https://beta.p5js.org/contribute/creating_libraries/)
306
- 2. [p5.js source architecture](https://github.com/processing/p5.js/blob/main/src/core/README.md)
307
- 3. [WEBGL mode architecture](https://github.com/processing/p5.js/blob/main/contributor_docs/webgl_mode_architecture.md)
362
+ This approach provides full modularity, clean instance isolation, and compatibility with modern JavaScript tooling.
@@ -2,7 +2,7 @@ import p5 from 'p5';
2
2
 
3
3
  /**
4
4
  * @file Adds Tree rendering functions to the p5 prototype.
5
- * @version 0.0.1
5
+ * @version 0.0.3
6
6
  * @author JP Charalambos
7
7
  * @license GPL-3.0-only
8
8
  *
@@ -38,7 +38,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
38
38
  const CONST = value => ({ value, writable: false, enumerable: true, configurable: false });
39
39
 
40
40
  Object.defineProperties(p5.Tree, {
41
- VERSION: CONST('0.0.1'),
41
+ VERSION: CONST('0.0.3'),
42
42
 
43
43
  NONE: CONST(0),
44
44
 
@@ -48,6 +48,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
48
48
  NDC: CONST('NDC'),
49
49
  SCREEN: CONST('SCREEN'),
50
50
  MODEL: CONST('MODEL'),
51
+ OBJECT: CONST('MODEL'), // alias of MODEL (shader terminology)
51
52
 
52
53
  // Points and vectors
53
54
  ORIGIN: CONST(Object.freeze([0, 0, 0])),
@@ -68,9 +69,6 @@ p5.registerAddon((p5, fn, lifecycles) => {
68
69
  Z: CONST(1 << 4),
69
70
  _Z: CONST(1 << 5),
70
71
  LABELS: CONST(1 << 6),
71
-
72
- DOTS: CONST(0),
73
- SOLID: CONST(1),
74
72
 
75
73
  // bullsEye
76
74
  CIRCLE: CONST(0),
@@ -815,7 +813,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
815
813
 
816
814
  /**
817
815
  * Interpolate camera pose at normalized global t in [0..1] along the whole path.
818
- * Also updates internal seg/f so playPath resumes from that location.
816
+ * Also updates internal seg/f so playPath resumes from that position.
819
817
  */
820
818
  const seekGlobal = function (cam, t) {
821
819
  const path = ensurePath(cam);
@@ -1441,7 +1439,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
1441
1439
  };
1442
1440
 
1443
1441
  // ---------------------------------------------------------------------------
1444
- // Space transforms: transformPosition / transformDirection
1442
+ // Space transforms: mapLocation / mapDirection
1445
1443
  // ---------------------------------------------------------------------------
1446
1444
 
1447
1445
  p5.RendererGL.prototype._parseTransformArgs = function (defaultMainArg, ...args) {
@@ -1461,8 +1459,8 @@ p5.registerAddon((p5, fn, lifecycles) => {
1461
1459
  // Points (positions)
1462
1460
  // ---------------------------------------------------------------------------
1463
1461
 
1464
- fn.transformPosition = function (...args) {
1465
- return _rendererGL(this)?.transformPosition(...args);
1462
+ fn.mapLocation = function (...args) {
1463
+ return _rendererGL(this)?.mapLocation(...args);
1466
1464
  };
1467
1465
 
1468
1466
  /**
@@ -1479,12 +1477,12 @@ p5.registerAddon((p5, fn, lifecycles) => {
1479
1477
  * @param {p5.Matrix} [opts.ipvMatrix]
1480
1478
  * @returns {p5.Vector}
1481
1479
  */
1482
- p5.RendererGL.prototype.transformPosition = function (...args) {
1480
+ p5.RendererGL.prototype.mapLocation = function (...args) {
1483
1481
  const { mainArg, options } = this._parseTransformArgs(p5.Tree.ORIGIN, ...args);
1484
- return this._position(mainArg, options);
1482
+ return this._location(mainArg, options);
1485
1483
  };
1486
1484
 
1487
- p5.RendererGL.prototype._position = function (
1485
+ p5.RendererGL.prototype._location = function (
1488
1486
  point = p5.Tree.ORIGIN,
1489
1487
  {
1490
1488
  from = p5.Tree.EYE,
@@ -1506,25 +1504,25 @@ p5.registerAddon((p5, fn, lifecycles) => {
1506
1504
  to = this.mMatrix({ eMatrix });
1507
1505
  }
1508
1506
  if ((from == p5.Tree.WORLD) && (to == p5.Tree.SCREEN)) {
1509
- return this._worldToScreenPosition({ point, pMatrix, vMatrix, pvMatrix });
1507
+ return this._worldToScreenLocation({ point, pMatrix, vMatrix, pvMatrix });
1510
1508
  }
1511
1509
  if ((from == p5.Tree.SCREEN) && (to == p5.Tree.WORLD)) {
1512
- return this._screenToWorldPosition({ point, pMatrix, vMatrix, pvMatrix, ipvMatrix });
1510
+ return this._screenToWorldLocation({ point, pMatrix, vMatrix, pvMatrix, ipvMatrix });
1513
1511
  }
1514
1512
  if (from == p5.Tree.SCREEN && to == p5.Tree.NDC) {
1515
- return this._screenToNDCPosition(point);
1513
+ return this._screenToNDCLocation(point);
1516
1514
  }
1517
1515
  if (from == p5.Tree.NDC && to == p5.Tree.SCREEN) {
1518
- return this._ndcToScreenPosition(point);
1516
+ return this._ndcToScreenLocation(point);
1519
1517
  }
1520
1518
  if (from == p5.Tree.WORLD && to == p5.Tree.NDC) {
1521
- return this._screenToNDCPosition(
1522
- this._worldToScreenPosition({ point, pMatrix, vMatrix, pvMatrix })
1519
+ return this._screenToNDCLocation(
1520
+ this._worldToScreenLocation({ point, pMatrix, vMatrix, pvMatrix })
1523
1521
  );
1524
1522
  }
1525
1523
  if (from == p5.Tree.NDC && to == p5.Tree.WORLD) {
1526
- return this._screenToWorldPosition({
1527
- point: this._ndcToScreenPosition(point),
1524
+ return this._screenToWorldLocation({
1525
+ point: this._ndcToScreenLocation(point),
1528
1526
  pMatrix,
1529
1527
  vMatrix,
1530
1528
  pvMatrix,
@@ -1536,8 +1534,8 @@ p5.registerAddon((p5, fn, lifecycles) => {
1536
1534
  ? (vMatrix ?? this.vMatrix())
1537
1535
  : to.copy().invert(to)
1538
1536
  ).mult4(
1539
- this._screenToWorldPosition({
1540
- point: this._ndcToScreenPosition(point),
1537
+ this._screenToWorldLocation({
1538
+ point: this._ndcToScreenLocation(point),
1541
1539
  pMatrix,
1542
1540
  vMatrix,
1543
1541
  pvMatrix,
@@ -1546,8 +1544,8 @@ p5.registerAddon((p5, fn, lifecycles) => {
1546
1544
  );
1547
1545
  }
1548
1546
  if ((from instanceof p5.Matrix || from == p5.Tree.EYE) && to == p5.Tree.NDC) {
1549
- return this._screenToNDCPosition(
1550
- this._worldToScreenPosition({
1547
+ return this._screenToNDCLocation(
1548
+ this._worldToScreenLocation({
1551
1549
  point: (from == p5.Tree.EYE
1552
1550
  ? (eMatrix ?? this.eMatrix())
1553
1551
  : from
@@ -1578,11 +1576,11 @@ p5.registerAddon((p5, fn, lifecycles) => {
1578
1576
  ? (vMatrix ?? this.vMatrix())
1579
1577
  : to.copy().invert(to)
1580
1578
  ).mult4(
1581
- this._screenToWorldPosition({ point, pMatrix, vMatrix, pvMatrix, ipvMatrix })
1579
+ this._screenToWorldLocation({ point, pMatrix, vMatrix, pvMatrix, ipvMatrix })
1582
1580
  );
1583
1581
  }
1584
1582
  if ((from instanceof p5.Matrix || from == p5.Tree.EYE) && to == p5.Tree.SCREEN) {
1585
- return this._worldToScreenPosition({
1583
+ return this._worldToScreenLocation({
1586
1584
  point: (from == p5.Tree.EYE
1587
1585
  ? (eMatrix ?? this.eMatrix())
1588
1586
  : from
@@ -1598,11 +1596,11 @@ p5.registerAddon((p5, fn, lifecycles) => {
1598
1596
  if (from == p5.Tree.EYE && to instanceof p5.Matrix) {
1599
1597
  return to.copy().invert(to).mult4((eMatrix ?? this.eMatrix()).mult4(point));
1600
1598
  }
1601
- console.error('couldn\'t parse your transformPosition query!');
1599
+ console.error('couldn\'t parse your mapLocation query!');
1602
1600
  return point;
1603
1601
  };
1604
1602
 
1605
- p5.RendererGL.prototype._ndcToScreenPosition = function (point) {
1603
+ p5.RendererGL.prototype._ndcToScreenLocation = function (point) {
1606
1604
  return new p5.Vector(
1607
1605
  p5.prototype.map(point.x, -1, 1, 0, this.width),
1608
1606
  p5.prototype.map(point.y, -1, 1, 0, this.height),
@@ -1610,7 +1608,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
1610
1608
  );
1611
1609
  };
1612
1610
 
1613
- p5.RendererGL.prototype._screenToNDCPosition = function (point) {
1611
+ p5.RendererGL.prototype._screenToNDCLocation = function (point) {
1614
1612
  return new p5.Vector(
1615
1613
  p5.prototype.map(point.x, 0, this.width, -1, 1),
1616
1614
  p5.prototype.map(point.y, 0, this.height, -1, 1),
@@ -1618,7 +1616,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
1618
1616
  );
1619
1617
  };
1620
1618
 
1621
- p5.RendererGL.prototype._worldToScreenPosition = function ({
1619
+ p5.RendererGL.prototype._worldToScreenLocation = function ({
1622
1620
  point = new p5.Vector(0, 0, 0.5),
1623
1621
  pMatrix,
1624
1622
  vMatrix,
@@ -1641,7 +1639,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
1641
1639
  return new p5.Vector(target[0], target[1], target[2]);
1642
1640
  };
1643
1641
 
1644
- p5.RendererGL.prototype._screenToWorldPosition = function ({
1642
+ p5.RendererGL.prototype._screenToWorldLocation = function ({
1645
1643
  point = new p5.Vector(this.width / 2, this.height / 2, 0.5),
1646
1644
  pMatrix,
1647
1645
  vMatrix,
@@ -1670,8 +1668,8 @@ p5.registerAddon((p5, fn, lifecycles) => {
1670
1668
  // Directions (vector displacements)
1671
1669
  // ---------------------------------------------------------------------------
1672
1670
 
1673
- fn.transformDirection = function (...args) {
1674
- return _rendererGL(this)?.transformDirection(...args);
1671
+ fn.mapDirection = function (...args) {
1672
+ return _rendererGL(this)?.mapDirection(...args);
1675
1673
  };
1676
1674
 
1677
1675
  /**
@@ -1686,7 +1684,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
1686
1684
  * @param {p5.Matrix} [opts.pMatrix]
1687
1685
  * @returns {p5.Vector}
1688
1686
  */
1689
- p5.RendererGL.prototype.transformDirection = function (...args) {
1687
+ p5.RendererGL.prototype.mapDirection = function (...args) {
1690
1688
  const { mainArg, options } = this._parseTransformArgs(p5.Tree._k, ...args);
1691
1689
  return this._direction(mainArg, options);
1692
1690
  };
@@ -1781,7 +1779,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
1781
1779
  this._screenToWorldDirection(this._ndcToScreenDirection(vector), pMatrix)
1782
1780
  );
1783
1781
  }
1784
- console.error('[p5.tree] transformDirection: could not parse query.');
1782
+ console.error('[p5.tree] mapDirection: could not parse query.');
1785
1783
  return vector;
1786
1784
  };
1787
1785
 
@@ -1792,7 +1790,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
1792
1790
  let dy = eyeVector.y;
1793
1791
  const perspective = pMatrix.mat4[15] === 0;
1794
1792
  if (perspective) {
1795
- const zEye = this._position(p5.Tree.ORIGIN, { from: p5.Tree.WORLD, to: p5.Tree.EYE }).z;
1793
+ const zEye = this._location(p5.Tree.ORIGIN, { from: p5.Tree.WORLD, to: p5.Tree.EYE }).z;
1796
1794
  const k = Math.abs(zEye * Math.tan(pMatrix.fov() / 2));
1797
1795
  dx /= 2 * k / this.height;
1798
1796
  dy /= 2 * k / this.height;
@@ -1814,7 +1812,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
1814
1812
 
1815
1813
  const perspective = pMatrix.mat4[15] === 0;
1816
1814
  if (perspective) {
1817
- const zEye = this._position(p5.Tree.ORIGIN, { from: p5.Tree.WORLD, to: p5.Tree.EYE }).z;
1815
+ const zEye = this._location(p5.Tree.ORIGIN, { from: p5.Tree.WORLD, to: p5.Tree.EYE }).z;
1818
1816
  const k = Math.abs(zEye * Math.tan(pMatrix.fov() / 2));
1819
1817
  dx *= 2 * k / this.height;
1820
1818
  dy *= 2 * k / this.height;
@@ -1869,7 +1867,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
1869
1867
  return this.isOrtho()
1870
1868
  ? Math.abs(this.tPlane() - this.bPlane()) / this.height
1871
1869
  : 2 * Math.abs(
1872
- this.transformPosition(point, { from: p5.Tree.WORLD, to: p5.Tree.EYE }).z
1870
+ this.mapLocation(point, { from: p5.Tree.WORLD, to: p5.Tree.EYE }).z
1873
1871
  ) * Math.tan(this.fov() / 2) / this.height;
1874
1872
  };
1875
1873
 
@@ -1965,6 +1963,49 @@ p5.registerAddon((p5, fn, lifecycles) => {
1965
1963
  return this;
1966
1964
  };
1967
1965
 
1966
+ /**
1967
+ * Draws 3D reference axes (X, Y, Z) centered at the origin in model space.
1968
+ *
1969
+ * Each axis can be enabled independently using bitwise flags, and optional
1970
+ * axis labels (X, Y, Z) can be rendered near the positive ends.
1971
+ *
1972
+ * This is a WEBGL-only utility intended for debugging, teaching, and spatial
1973
+ * orientation. Axes are drawn on the current Z=0 plane using the current
1974
+ * stroke settings.
1975
+ *
1976
+ * @method axes
1977
+ * @for p5.RendererGL
1978
+ * @param {Object} [opts] Axes options.
1979
+ * @param {Number} [opts.size=100] Length of each axis in world units.
1980
+ * @param {Array<String>} [opts.colors=['Red','Lime','DodgerBlue']]
1981
+ * Stroke colors for X, Y, and Z axes respectively.
1982
+ * @param {Number} [opts.bits=p5.Tree.LABELS | p5.Tree.X | p5.Tree.Y | p5.Tree.Z]
1983
+ * Bitmask controlling which axes and labels are drawn.
1984
+ *
1985
+ * @example
1986
+ * function draw() {
1987
+ * background(30);
1988
+ * orbitControl();
1989
+ * axes({ size: 300 });
1990
+ * }
1991
+ *
1992
+ * @example
1993
+ * // Draw only X and Z axes, no labels
1994
+ * axes({
1995
+ * size: 200,
1996
+ * bits: p5.Tree.X | p5.Tree.Z
1997
+ * });
1998
+ *
1999
+ * @example
2000
+ * // Draw full axes in both positive and negative directions
2001
+ * axes({
2002
+ * size: 150,
2003
+ * bits: p5.Tree.X | p5.Tree._X |
2004
+ * p5.Tree.Y | p5.Tree._Y |
2005
+ * p5.Tree.Z | p5.Tree._Z |
2006
+ * p5.Tree.LABELS
2007
+ * });
2008
+ */
1968
2009
  p5.RendererGL.prototype.axes = function ({
1969
2010
  size = 100,
1970
2011
  colors = ['Red', 'Lime', 'DodgerBlue'],
@@ -2014,47 +2055,38 @@ p5.registerAddon((p5, fn, lifecycles) => {
2014
2055
  return this;
2015
2056
  };
2016
2057
 
2058
+ /**
2059
+ * Draws a simple X/Y reference grid on the Z=0 plane in the current model space.
2060
+ *
2061
+ * The grid is centered at the origin and spans from `-size` to `+size` on both X and Y.
2062
+ * It draws `subdivisions + 1` lines in each direction (including the borders).
2063
+ *
2064
+ * This is a WEBGL-only utility intended for debugging and spatial reference.
2065
+ *
2066
+ * @method grid
2067
+ * @for p5.RendererGL
2068
+ * @param {Object} [opts] Grid options.
2069
+ * @param {Number} [opts.size=100] Half-extent of the grid in world units.
2070
+ * @param {Number} [opts.subdivisions=10] Number of subdivisions per side (must be >= 1).
2071
+ * @example
2072
+ * function draw() {
2073
+ * background(30);
2074
+ * orbitControl();
2075
+ * grid({ size: 300, subdivisions: 20 });
2076
+ * }
2077
+ */
2017
2078
  p5.RendererGL.prototype.grid = function ({
2018
2079
  size = 100,
2019
- subdivisions = 10,
2020
- style = p5.Tree.SOLID,
2021
- weight = 1,
2022
- minorSubdivisions = 5
2080
+ subdivisions = 10
2023
2081
  } = {}) {
2024
2082
  const p = this._pInst;
2025
- if (!p) return;
2083
+ if (!p) return;
2084
+ subdivisions = Math.max(1, subdivisions);
2026
2085
  p.push();
2027
- if (style === p5.Tree.DOTS) {
2028
- let posi = 0;
2029
- let posj = 0;
2030
- p.strokeWeight(weight * 2);
2031
- p.beginShape(p.POINTS);
2032
- for (let i = 0; i <= subdivisions; ++i) {
2033
- posi = size * (2.0 * i / subdivisions - 1.0);
2034
- for (let j = 0; j <= subdivisions; ++j) {
2035
- posj = size * (2.0 * j / subdivisions - 1.0);
2036
- p.vertex(posi, posj, 0);
2037
- }
2038
- }
2039
- p.endShape();
2040
- const internalSub = Math.max(1, minorSubdivisions | 0);
2041
- const subSubdivisions = subdivisions * internalSub;
2042
- p.strokeWeight(weight);
2043
- p.beginShape(p.POINTS);
2044
- for (let i = 0; i <= subSubdivisions; ++i) {
2045
- posi = size * (2.0 * i / subSubdivisions - 1.0);
2046
- for (let j = 0; j <= subSubdivisions; ++j) {
2047
- posj = size * (2.0 * j / subSubdivisions - 1.0);
2048
- ((i % internalSub) !== 0 || (j % internalSub) !== 0) && p.vertex(posi, posj, 0);
2049
- }
2050
- }
2051
- p.endShape();
2052
- } else {
2053
- for (let i = 0; i <= subdivisions; ++i) {
2054
- const pos = size * (2.0 * i / subdivisions - 1.0);
2055
- p.line(pos, -size, 0, pos, +size, 0);
2056
- p.line(-size, pos, 0, size, pos, 0);
2057
- }
2086
+ for (let i = 0; i <= subdivisions; ++i) {
2087
+ const pos = size * (2.0 * i / subdivisions - 1.0);
2088
+ p.line(pos, -size, 0, pos, +size, 0);
2089
+ p.line(-size, pos, 0, +size, pos, 0);
2058
2090
  }
2059
2091
  p.pop();
2060
2092
  };
@@ -2158,10 +2190,10 @@ p5.registerAddon((p5, fn, lifecycles) => {
2158
2190
  // If target screen position not provided, derive it from mMatrix.
2159
2191
  // In that case, treat `size` as world units and convert to pixels locally.
2160
2192
  if (x == null || y == null) {
2161
- const screen = this.transformPosition({ from: mMatrix, to: p5.Tree.SCREEN, pMatrix, vMatrix, pvMatrix });
2193
+ const screen = this.mapLocation({ from: mMatrix, to: p5.Tree.SCREEN, pMatrix, vMatrix, pvMatrix });
2162
2194
  x = screen.x;
2163
2195
  y = screen.y;
2164
- const world = this.transformPosition({ from: mMatrix, to: p5.Tree.WORLD, eMatrix });
2196
+ const world = this.mapLocation({ from: mMatrix, to: p5.Tree.WORLD, eMatrix });
2165
2197
  size = size / this.pixelRatio(world);
2166
2198
  }
2167
2199
  const r = size / 2.0;
@@ -2262,10 +2294,10 @@ p5.registerAddon((p5, fn, lifecycles) => {
2262
2294
  if (!p) return;
2263
2295
 
2264
2296
  if (x == null || y == null) {
2265
- const screen = this.transformPosition({ from: mMatrix, to: p5.Tree.SCREEN, pMatrix, vMatrix, pvMatrix });
2297
+ const screen = this.mapLocation({ from: mMatrix, to: p5.Tree.SCREEN, pMatrix, vMatrix, pvMatrix });
2266
2298
  x = screen.x;
2267
2299
  y = screen.y;
2268
- const world = this.transformPosition({ from: mMatrix, to: p5.Tree.WORLD, eMatrix });
2300
+ const world = this.mapLocation({ from: mMatrix, to: p5.Tree.WORLD, eMatrix });
2269
2301
  size = size / this.pixelRatio(world);
2270
2302
  }
2271
2303
  const half = size / 2.0;
@@ -2315,10 +2347,10 @@ p5.registerAddon((p5, fn, lifecycles) => {
2315
2347
  const p = this._pInst;
2316
2348
  if (!p) return;
2317
2349
  if (x == null || y == null) {
2318
- const screen = this.transformPosition({ from: mMatrix, to: p5.Tree.SCREEN, pMatrix, vMatrix, pvMatrix });
2350
+ const screen = this.mapLocation({ from: mMatrix, to: p5.Tree.SCREEN, pMatrix, vMatrix, pvMatrix });
2319
2351
  x = screen.x;
2320
2352
  y = screen.y;
2321
- const world = this.transformPosition({ from: mMatrix, to: p5.Tree.WORLD, eMatrix });
2353
+ const world = this.mapLocation({ from: mMatrix, to: p5.Tree.WORLD, eMatrix });
2322
2354
  size = size / this.pixelRatio(world);
2323
2355
  }
2324
2356
  const half = size / 2.0;
@@ -2666,7 +2698,7 @@ p5.registerAddon((p5, fn, lifecycles) => {
2666
2698
  const normals = Array(6);
2667
2699
  const distances = Array(6);
2668
2700
  // Camera position and basis in world space.
2669
- const pos = this._position([0, 0, 0], { from: p5.Tree.EYE, to: p5.Tree.WORLD, eMatrix });
2701
+ const pos = this._location([0, 0, 0], { from: p5.Tree.EYE, to: p5.Tree.WORLD, eMatrix });
2670
2702
  const viewDir = this._direction([0, 0, -1], { from: p5.Tree.EYE, to: p5.Tree.WORLD, vMatrix });
2671
2703
  const up = this._direction([0, 1, 0], { from: p5.Tree.EYE, to: p5.Tree.WORLD, vMatrix });
2672
2704
  const right = this._direction([1, 0, 0], { from: p5.Tree.EYE, to: p5.Tree.WORLD, vMatrix });