@nakednous/tree 0.0.16 → 0.0.18

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
@@ -84,7 +84,7 @@ Playback features: signed `rate` (negative reverses), `loop`, `bounce`, `seek(t)
84
84
  ```js
85
85
  track.add({ pos, rot, scl }) // explicit TRS — rot accepts any form below
86
86
  track.add({ pos, rot, scl, tanIn, tanOut }) // with Hermite tangents (vec3, optional)
87
- track.add({ mMatrix: mat4 }) // decompose a column-major model matrix into TRS
87
+ track.add({ mat4Model: mat4 }) // decompose a column-major model matrix into TRS
88
88
  track.add([ spec, spec, ... ]) // bulk
89
89
  ```
90
90
 
@@ -109,7 +109,7 @@ rot: { euler:[rx,ry,rz], order?:'YXZ' } // intrinsic Euler angles (radians)
109
109
  // extrinsic ABC = intrinsic CBA
110
110
  rot: { from:[x,y,z], to:[x,y,z] } // shortest-arc between directions
111
111
  rot: { mat3: Float32Array|Array } // column-major 3×3 rotation matrix
112
- rot: { eMatrix: mat4 } // rotation block of an eye matrix
112
+ rot: { mat4Eye: mat4 } // rotation block of an eye matrix
113
113
  ```
114
114
 
115
115
  ---
@@ -160,7 +160,7 @@ track.add({ eye, center?, up?, fov?, halfHeight?,
160
160
  track.add([ spec, spec, ... ]) // bulk
161
161
  ```
162
162
 
163
- For matrix-based capture use `PoseTrack.add({ mMatrix: eMatrix })` for full-fidelity TRS including roll, or `cam.capturePose()` (p5.tree bridge) for lookat-style capture.
163
+ For matrix-based capture use `track.add({ mat4Model: mat4Eye })` for full-fidelity TRS including roll, or `cam.capturePose()` (p5.tree bridge) for lookat-style capture.
164
164
 
165
165
  `fov` and `halfHeight` are lerped between keyframes only when both adjacent keyframes carry a non-null value for that field. Mixed or null entries pass `null` through — the bridge leaves the projection unchanged.
166
166
 
@@ -320,11 +320,14 @@ mat4Eye — eye matrix (eye→world) from lookat params
320
320
  mat4FromTRS — column-major mat4 from flat TRS scalars
321
321
  mat4FromTranslation — translation-only mat4
322
322
  mat4FromScale — scale-only mat4
323
- mat4Perspective — perspective projection (ndcZMin, ndcYSign)
324
- mat4Ortho — orthographic projection (ndcZMin, ndcYSign)
325
- mat4Frustum — off-centre perspective (ndcZMin, ndcYSign)
323
+ mat4Persp — perspective projection, general frustum (ndcZMin, ndcYSign)
324
+ mat4Ortho — orthographic projection (ndcZMin, ndcYSign)
326
325
  mat4Bias — NDC→texture/UV remap [0,1] for shadow mapping
327
326
  mat4Reflect — reflection across a plane
327
+ ```
328
+
329
+ **Mat4 decomposition** (`query.js`):
330
+ ```
328
331
  mat4ToTranslation — extract translation (col 3)
329
332
  mat4ToScale — extract scale (column lengths)
330
333
  mat4ToRotation — extract rotation as unit quaternion
package/dist/index.js CHANGED
@@ -346,7 +346,7 @@ function mat4Eye(out, ex,ey,ez, cx,cy,cz, ux,uy,uz) {
346
346
  *
347
347
  * @param {Float32Array|number[]} out 16-element destination.
348
348
  * @param {number} tx,ty,tz Translation.
349
- * @param {number} qx,qy,qz,qw Rotation quaternion [x,y,z,w].
349
+ * @param {number} qx,qy,qz,qw Rotation quaternion [x,y,z,w].
350
350
  * @param {number} sx,sy,sz Scale.
351
351
  */
352
352
  function mat4FromTRS(out, tx,ty,tz, qx,qy,qz,qw, sx,sy,sz) {
@@ -390,30 +390,6 @@ function mat4FromScale(out, sx,sy,sz) {
390
390
  // Projection construction
391
391
  // =========================================================================
392
392
 
393
- /**
394
- * Perspective projection matrix.
395
- *
396
- * @param {Float32Array|number[]} out 16-element destination.
397
- * @param {number} fov Vertical field of view (radians).
398
- * @param {number} aspect Width / height.
399
- * @param {number} near Near plane distance (positive).
400
- * @param {number} far Far plane distance (positive, > near).
401
- * @param {number} ndcZMin −1 (WEBGL) or 0 (WEBGPU).
402
- * @param {number} [ndcYSign=1] +1 = NDC y-up (default); −1 = NDC y-down (native Vulkan).
403
- */
404
- function mat4Perspective(out, fov, aspect, near, far, ndcZMin, ndcYSign=1) {
405
- const f = 1 / Math.tan(fov * 0.5);
406
- out[0]=f/aspect; out[1]=0; out[2]=0; out[3]=0;
407
- out[4]=0; out[5]=ndcYSign*f; out[6]=0; out[7]=0;
408
- out[8]=0; out[9]=0;
409
- out[10]=(ndcZMin*near-far)/(far-near);
410
- out[11]=-1;
411
- out[12]=0; out[13]=0;
412
- out[14]=(ndcZMin-1)*far*near/(far-near);
413
- out[15]=0;
414
- return out;
415
- }
416
-
417
393
  /**
418
394
  * Orthographic projection matrix.
419
395
  *
@@ -435,15 +411,18 @@ function mat4Ortho(out, left, right, bottom, top, near, far, ndcZMin, ndcYSign=1
435
411
  }
436
412
 
437
413
  /**
438
- * Frustum (off-centre perspective) projection matrix.
414
+ * Perspective projection matrix (general / off-centre frustum).
415
+ * Symmetric case: left=-right, bottom=-top — derive from fov+aspect in user space:
416
+ * top = near * Math.tan(fov / 2); right = top * aspect
417
+ * mat4Persp(out, -right, right, -top, top, near, far, ndcZMin)
439
418
  *
440
419
  * @param {Float32Array|number[]} out 16-element destination.
441
- * @param {number} left,right,bottom,top Near-plane extents.
420
+ * @param {number} left,right,bottom,top Near-plane extents (signed, y-up: top>0, bottom<0).
442
421
  * @param {number} near,far Clip plane distances (positive).
443
422
  * @param {number} ndcZMin −1 (WEBGL) or 0 (WEBGPU).
444
423
  * @param {number} [ndcYSign=1] +1 = NDC y-up (default); −1 = NDC y-down (native Vulkan).
445
424
  */
446
- function mat4Frustum(out, left, right, bottom, top, near, far, ndcZMin, ndcYSign=1) {
425
+ function mat4Persp(out, left, right, bottom, top, near, far, ndcZMin, ndcYSign=1) {
447
426
  const rl=1/(right-left), tb=1/(top-bottom);
448
427
  out[0]=2*near*rl; out[1]=0; out[2]=0; out[3]=0;
449
428
  out[4]=0; out[5]=ndcYSign*2*near*tb; out[6]=0; out[7]=0;
@@ -503,49 +482,6 @@ function mat4Reflect(out, nx,ny,nz,d) {
503
482
  return out;
504
483
  }
505
484
 
506
- // =========================================================================
507
- // Partial decomposition (mat4To___ mirrors mat4From___)
508
- // =========================================================================
509
-
510
- /**
511
- * Extract translation from a column-major mat4 (column 3).
512
- * @param {Float32Array|number[]} out3 3-element destination.
513
- * @param {Float32Array|number[]} m 16-element source.
514
- */
515
- function mat4ToTranslation(out3, m) {
516
- out3[0]=m[12]; out3[1]=m[13]; out3[2]=m[14];
517
- return out3;
518
- }
519
-
520
- /**
521
- * Extract scale from a column-major mat4 (column lengths of the rotation block).
522
- * Assumes no shear.
523
- * @param {Float32Array|number[]} out3 3-element destination.
524
- * @param {Float32Array|number[]} m 16-element source.
525
- */
526
- function mat4ToScale(out3, m) {
527
- out3[0]=Math.sqrt(m[0]*m[0]+m[1]*m[1]+m[2]*m[2]);
528
- out3[1]=Math.sqrt(m[4]*m[4]+m[5]*m[5]+m[6]*m[6]);
529
- out3[2]=Math.sqrt(m[8]*m[8]+m[9]*m[9]+m[10]*m[10]);
530
- return out3;
531
- }
532
-
533
- /**
534
- * Extract rotation as a unit quaternion from a column-major mat4.
535
- * Scale is factored out from each column. Assumes no shear.
536
- * @param {number[]} out4 4-element [x,y,z,w] destination.
537
- * @param {Float32Array|number[]} m 16-element source.
538
- */
539
- function mat4ToRotation(out4, m) {
540
- const sx=Math.sqrt(m[0]*m[0]+m[1]*m[1]+m[2]*m[2])||1;
541
- const sy=Math.sqrt(m[4]*m[4]+m[5]*m[5]+m[6]*m[6])||1;
542
- const sz=Math.sqrt(m[8]*m[8]+m[9]*m[9]+m[10]*m[10])||1;
543
- return qFromRotMat3x3(out4,
544
- m[0]/sx, m[4]/sy, m[8]/sz,
545
- m[1]/sx, m[5]/sy, m[9]/sz,
546
- m[2]/sx, m[6]/sy, m[10]/sz);
547
- }
548
-
549
485
  /**
550
486
  * @file Matrix arithmetic, space-transform dispatch, and projection queries.
551
487
  * @module tree/query
@@ -763,10 +699,30 @@ function mat4MV(out, model, view) { return mat4Mul(out, view, model); }
763
699
 
764
700
  /**
765
701
  * Location transform between frames: out = inv(to) · from.
702
+ * Assumes both matrices are affine (bottom row [0,0,0,1]).
766
703
  * @returns {ArrayLike<number>|null} out, or null if `to` is singular.
767
704
  */
768
705
  function mat4Location(out, from, to) {
769
- return mat4Invert(out, to) && mat4Mul(out, out, from);
706
+ // Same as: return mat4Invert(out, to) && mat4Mul(out, out, from);
707
+ const a00=to[0],a01=to[1],a02=to[2],
708
+ a10=to[4],a11=to[5],a12=to[6],
709
+ a20=to[8],a21=to[9],a22=to[10];
710
+ const b01=a22*a11-a12*a21, b11=a12*a20-a22*a10, b21=a21*a10-a11*a20;
711
+ let det=a00*b01+a01*b11+a02*b21;
712
+ if (Math.abs(det) < 1e-12) return null;
713
+ det=1/det;
714
+ const i00=b01*det, i01=(a02*a21-a22*a01)*det, i02=(a12*a01-a02*a11)*det;
715
+ const i10=b11*det, i11=(a22*a00-a02*a20)*det, i12=(a02*a10-a12*a00)*det;
716
+ const i20=b21*det, i21=(a01*a20-a21*a00)*det, i22=(a11*a00-a01*a10)*det;
717
+ const f00=from[0],f01=from[1],f02=from[2],
718
+ f10=from[4],f11=from[5],f12=from[6],
719
+ f20=from[8],f21=from[9],f22=from[10];
720
+ out[0]=i00*f00+i01*f01+i02*f02; out[1]=i10*f00+i11*f01+i12*f02; out[2]=i20*f00+i21*f01+i22*f02; out[3]=0;
721
+ out[4]=i00*f10+i01*f11+i02*f12; out[5]=i10*f10+i11*f11+i12*f12; out[6]=i20*f10+i21*f11+i22*f12; out[7]=0;
722
+ out[8]=i00*f20+i01*f21+i02*f22; out[9]=i10*f20+i11*f21+i12*f22; out[10]=i20*f20+i21*f21+i22*f22; out[11]=0;
723
+ const dx=from[12]-to[12], dy=from[13]-to[13], dz=from[14]-to[14];
724
+ out[12]=i00*dx+i01*dy+i02*dz; out[13]=i10*dx+i11*dy+i12*dz; out[14]=i20*dx+i21*dy+i22*dz; out[15]=1;
725
+ return out;
770
726
  }
771
727
 
772
728
  /**
@@ -1149,6 +1105,49 @@ function mat4Pick(proj, px, py, vp) {
1149
1105
  }
1150
1106
  }
1151
1107
 
1108
+ // =========================================================================
1109
+ // Decomposition
1110
+ // =========================================================================
1111
+
1112
+ /**
1113
+ * Extract translation from a column-major mat4 (column 3).
1114
+ * @param {Float32Array|number[]} out3 3-element destination.
1115
+ * @param {Float32Array|number[]} m 16-element source.
1116
+ */
1117
+ function mat4ToTranslation(out3, m) {
1118
+ out3[0]=m[12]; out3[1]=m[13]; out3[2]=m[14];
1119
+ return out3;
1120
+ }
1121
+
1122
+ /**
1123
+ * Extract scale from a column-major mat4 (column lengths of the rotation block).
1124
+ * Assumes no shear.
1125
+ * @param {Float32Array|number[]} out3 3-element destination.
1126
+ * @param {Float32Array|number[]} m 16-element source.
1127
+ */
1128
+ function mat4ToScale(out3, m) {
1129
+ out3[0]=Math.sqrt(m[0]*m[0]+m[1]*m[1]+m[2]*m[2]);
1130
+ out3[1]=Math.sqrt(m[4]*m[4]+m[5]*m[5]+m[6]*m[6]);
1131
+ out3[2]=Math.sqrt(m[8]*m[8]+m[9]*m[9]+m[10]*m[10]);
1132
+ return out3;
1133
+ }
1134
+
1135
+ /**
1136
+ * Extract rotation as a unit quaternion from a column-major mat4.
1137
+ * Scale is factored out from each column. Assumes no shear.
1138
+ * @param {number[]} out4 4-element [x,y,z,w] destination.
1139
+ * @param {Float32Array|number[]} m 16-element source.
1140
+ */
1141
+ function mat4ToRotation(out4, m) {
1142
+ const sx=Math.sqrt(m[0]*m[0]+m[1]*m[1]+m[2]*m[2])||1;
1143
+ const sy=Math.sqrt(m[4]*m[4]+m[5]*m[5]+m[6]*m[6])||1;
1144
+ const sz=Math.sqrt(m[8]*m[8]+m[9]*m[9]+m[10]*m[10])||1;
1145
+ return qFromRotMat3x3(out4,
1146
+ m[0]/sx, m[4]/sy, m[8]/sz,
1147
+ m[1]/sx, m[5]/sy, m[9]/sz,
1148
+ m[2]/sx, m[6]/sy, m[10]/sz);
1149
+ }
1150
+
1152
1151
  /**
1153
1152
  * @file Spline math and keyframe animation state machines.
1154
1153
  * @module tree/track
@@ -1260,13 +1259,13 @@ const hermiteVec3 = (out, p0, m0, p1, m1, t) => {
1260
1259
  };
1261
1260
 
1262
1261
  // Centripetal CR outgoing tangent at p1 for segment p1→p2, scaled by dt1.
1263
- const _crTanOut = (out, p0, p1, p2, p3) => {
1262
+ const _crTanOut = (out, p0, p1, p2) => {
1264
1263
  const dt0=Math.pow(_dist3(p0,p1),0.5)||1, dt1=Math.pow(_dist3(p1,p2),0.5)||1;
1265
1264
  for (let i=0;i<3;i++) out[i]=((p1[i]-p0[i])/dt0-(p2[i]-p0[i])/(dt0+dt1)+(p2[i]-p1[i])/dt1)*dt1;
1266
1265
  return out;
1267
1266
  };
1268
1267
 
1269
- const _crTanIn = (out, p0, p1, p2, p3) => {
1268
+ const _crTanIn = (out, p1, p2, p3) => {
1270
1269
  const dt1=Math.pow(_dist3(p1,p2),0.5)||1, dt2=Math.pow(_dist3(p2,p3),0.5)||1;
1271
1270
  for (let i=0;i<3;i++) out[i]=((p2[i]-p1[i])/dt1-(p3[i]-p1[i])/(dt1+dt2)+(p3[i]-p2[i])/dt2)*dt1;
1272
1271
  return out;
@@ -1940,13 +1939,13 @@ class PoseTrack extends Track {
1940
1939
  lerpVec3(out.pos, k0.pos, k1.pos, t);
1941
1940
  } else {
1942
1941
  const p0 = seg > 0 ? this.keyframes[seg - 1].pos : k0.pos;
1943
- const p3 = seg + 2 < n ? this.keyframes[seg + 2].pos : k1.pos;
1942
+ seg + 2 < n ? this.keyframes[seg + 2].pos : k1.pos;
1944
1943
  const m0 = k0.tanOut != null ? k0.tanOut
1945
1944
  : k0.tanIn != null ? k0.tanIn
1946
1945
  : _crTanOut(_m0, p0, k0.pos, k1.pos);
1947
1946
  const m1 = k1.tanIn != null ? k1.tanIn
1948
1947
  : k1.tanOut != null ? k1.tanOut
1949
- : _crTanIn(_m1, p0, k0.pos, k1.pos, p3);
1948
+ : _crTanIn(_m1, p0, k0.pos, k1.pos);
1950
1949
  hermiteVec3(out.pos, k0.pos, m0, k1.pos, m1, t);
1951
1950
  }
1952
1951
 
@@ -2091,13 +2090,13 @@ class CameraTrack extends Track {
2091
2090
  lerpVec3(out.eye, k0.eye, k1.eye, t);
2092
2091
  } else {
2093
2092
  const p0 = seg > 0 ? this.keyframes[seg - 1].eye : k0.eye;
2094
- const p3 = seg + 2 < n ? this.keyframes[seg + 2].eye : k1.eye;
2093
+ seg + 2 < n ? this.keyframes[seg + 2].eye : k1.eye;
2095
2094
  const m0 = k0.eyeTanOut != null ? k0.eyeTanOut
2096
2095
  : k0.eyeTanIn != null ? k0.eyeTanIn
2097
2096
  : _crTanOut(_m0, p0, k0.eye, k1.eye);
2098
2097
  const m1 = k1.eyeTanIn != null ? k1.eyeTanIn
2099
2098
  : k1.eyeTanOut != null ? k1.eyeTanOut
2100
- : _crTanIn(_m1, p0, k0.eye, k1.eye, p3);
2099
+ : _crTanIn(_m1, p0, k0.eye, k1.eye);
2101
2100
  hermiteVec3(out.eye, k0.eye, m0, k1.eye, m1, t);
2102
2101
  }
2103
2102
 
@@ -2106,13 +2105,13 @@ class CameraTrack extends Track {
2106
2105
  out.center[0]=k0.center[0]; out.center[1]=k0.center[1]; out.center[2]=k0.center[2];
2107
2106
  } else if (this.centerInterp === 'hermite') {
2108
2107
  const c0 = seg > 0 ? this.keyframes[seg - 1].center : k0.center;
2109
- const c3 = seg + 2 < n ? this.keyframes[seg + 2].center : k1.center;
2108
+ seg + 2 < n ? this.keyframes[seg + 2].center : k1.center;
2110
2109
  const m0 = k0.centerTanOut != null ? k0.centerTanOut
2111
2110
  : k0.centerTanIn != null ? k0.centerTanIn
2112
2111
  : _crTanOut(_m0, c0, k0.center, k1.center);
2113
2112
  const m1 = k1.centerTanIn != null ? k1.centerTanIn
2114
2113
  : k1.centerTanOut != null ? k1.centerTanOut
2115
- : _crTanIn(_m1, c0, k0.center, k1.center, c3);
2114
+ : _crTanIn(_m1, c0, k0.center, k1.center);
2116
2115
  hermiteVec3(out.center, k0.center, m0, k1.center, m1, t);
2117
2116
  } else {
2118
2117
  lerpVec3(out.center, k0.center, k1.center, t);
@@ -2293,5 +2292,5 @@ function boxVisibility(planes, x0, y0, z0, x1, y1, z1) {
2293
2292
  return allIn ? VISIBLE : SEMIVISIBLE;
2294
2293
  }
2295
2294
 
2296
- export { CameraTrack, EYE, INVISIBLE, MATRIX, MODEL, NDC, ORIGIN, PLANE_BOTTOM, PLANE_FAR, PLANE_LEFT, PLANE_NEAR, PLANE_RIGHT, PLANE_TOP, PoseTrack, SCREEN, SEMIVISIBLE, VISIBLE, WEBGL, WEBGPU, WORLD, _i, _j, _k, boxVisibility, distanceToPlane, frustumPlanes, hermiteVec3, i, j, k, lerpVec3, mapDirection, mapLocation, mat3Direction, mat3NormalFromMat4, mat4Bias, mat4Eye, mat4FromBasis, mat4FromScale, mat4FromTRS, mat4FromTranslation, mat4Frustum, mat4Invert, mat4Location, mat4MV, mat4Mul, mat4MulDir, mat4MulPoint, mat4Ortho, mat4PV, mat4Perspective, mat4Pick, mat4Reflect, mat4ToRotation, mat4ToScale, mat4ToTransform, mat4ToTranslation, mat4View, pixelRatio, pointVisibility, projBottom, projFar, projFov, projHfov, projIsOrtho, projLeft, projNear, projRight, projTop, qCopy, qDot, qFromAxisAngle, qFromLookDir, qFromMat4, qFromRotMat3x3, qMul, qNegate, qNlerp, qNormalize, qSet, qSlerp, qToMat4, quatToAxisAngle, sphereVisibility, transformToMat4 };
2295
+ export { CameraTrack, EYE, INVISIBLE, MATRIX, MODEL, NDC, ORIGIN, PLANE_BOTTOM, PLANE_FAR, PLANE_LEFT, PLANE_NEAR, PLANE_RIGHT, PLANE_TOP, PoseTrack, SCREEN, SEMIVISIBLE, VISIBLE, WEBGL, WEBGPU, WORLD, _i, _j, _k, boxVisibility, distanceToPlane, frustumPlanes, hermiteVec3, i, j, k, lerpVec3, mapDirection, mapLocation, mat3Direction, mat3NormalFromMat4, mat4Bias, mat4Eye, mat4FromBasis, mat4FromScale, mat4FromTRS, mat4FromTranslation, mat4Invert, mat4Location, mat4MV, mat4Mul, mat4MulDir, mat4MulPoint, mat4Ortho, mat4PV, mat4Persp, mat4Pick, mat4Reflect, mat4ToRotation, mat4ToScale, mat4ToTransform, mat4ToTranslation, mat4View, pixelRatio, pointVisibility, projBottom, projFar, projFov, projHfov, projIsOrtho, projLeft, projNear, projRight, projTop, qCopy, qDot, qFromAxisAngle, qFromLookDir, qFromMat4, qFromRotMat3x3, qMul, qNegate, qNlerp, qNormalize, qSet, qSlerp, qToMat4, quatToAxisAngle, sphereVisibility, transformToMat4 };
2297
2296
  //# sourceMappingURL=index.js.map