math 0.0.3 → 0.1.0

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.
Files changed (203) hide show
  1. package/API.md +1605 -0
  2. package/LICENSE +21 -0
  3. package/README.md +197 -0
  4. package/dist/color/color.js +136 -0
  5. package/dist/color/color.js.map +1 -0
  6. package/dist/color/colorspace.js +43 -0
  7. package/dist/color/colorspace.js.map +1 -0
  8. package/dist/color/hsl.js +123 -0
  9. package/dist/color/hsl.js.map +1 -0
  10. package/dist/color/index.js +7 -0
  11. package/dist/color/index.js.map +1 -0
  12. package/dist/color/parse.js +276 -0
  13. package/dist/color/parse.js.map +1 -0
  14. package/dist/core/angle.js +43 -0
  15. package/dist/core/angle.js.map +1 -0
  16. package/dist/core/euler.js +212 -0
  17. package/dist/core/euler.js.map +1 -0
  18. package/dist/core/mat2.js +385 -0
  19. package/dist/core/mat2.js.map +1 -0
  20. package/dist/core/mat2d.js +422 -0
  21. package/dist/core/mat2d.js.map +1 -0
  22. package/dist/core/mat3.js +749 -0
  23. package/dist/core/mat3.js.map +1 -0
  24. package/dist/core/mat4.js +2197 -0
  25. package/dist/core/mat4.js.map +1 -0
  26. package/dist/core/polar.js +200 -0
  27. package/dist/core/polar.js.map +1 -0
  28. package/dist/core/quat.js +730 -0
  29. package/dist/core/quat.js.map +1 -0
  30. package/dist/core/quat2.js +883 -0
  31. package/dist/core/quat2.js.map +1 -0
  32. package/dist/core/scalar.js +112 -0
  33. package/dist/core/scalar.js.map +1 -0
  34. package/dist/core/spherical.js +248 -0
  35. package/dist/core/spherical.js.map +1 -0
  36. package/dist/core/vec2.js +597 -0
  37. package/dist/core/vec2.js.map +1 -0
  38. package/dist/core/vec3.js +916 -0
  39. package/dist/core/vec3.js.map +1 -0
  40. package/dist/core/vec4.js +573 -0
  41. package/dist/core/vec4.js.map +1 -0
  42. package/dist/geometry/circumcircle.js +39 -0
  43. package/dist/geometry/circumcircle.js.map +1 -0
  44. package/dist/geometry/index.js +6 -0
  45. package/dist/geometry/index.js.map +1 -0
  46. package/dist/geometry/polygon2-decompose.js +411 -0
  47. package/dist/geometry/polygon2-decompose.js.map +1 -0
  48. package/dist/geometry/polygon2-triangulate.js +222 -0
  49. package/dist/geometry/polygon2-triangulate.js.map +1 -0
  50. package/dist/geometry/quickhull2.js +123 -0
  51. package/dist/geometry/quickhull2.js.map +1 -0
  52. package/dist/geometry/quickhull3.js +605 -0
  53. package/dist/geometry/quickhull3.js.map +1 -0
  54. package/dist/ik/fabrik2.js +675 -0
  55. package/dist/ik/fabrik2.js.map +1 -0
  56. package/dist/ik/fabrik3.js +912 -0
  57. package/dist/ik/fabrik3.js.map +1 -0
  58. package/dist/ik/index.js +5 -0
  59. package/dist/ik/index.js.map +1 -0
  60. package/dist/index.js +27 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/noise/fractal.js +185 -0
  63. package/dist/noise/fractal.js.map +1 -0
  64. package/dist/noise/index.js +16 -0
  65. package/dist/noise/index.js.map +1 -0
  66. package/dist/noise/perlin2d.js +50 -0
  67. package/dist/noise/perlin2d.js.map +1 -0
  68. package/dist/noise/perlin3d.js +72 -0
  69. package/dist/noise/perlin3d.js.map +1 -0
  70. package/dist/noise/permutation.js +120 -0
  71. package/dist/noise/permutation.js.map +1 -0
  72. package/dist/noise/simplex2d.js +84 -0
  73. package/dist/noise/simplex2d.js.map +1 -0
  74. package/dist/noise/simplex3d.js +147 -0
  75. package/dist/noise/simplex3d.js.map +1 -0
  76. package/dist/noise/simplex4d.js +149 -0
  77. package/dist/noise/simplex4d.js.map +1 -0
  78. package/dist/noise/worley2d.js +50 -0
  79. package/dist/noise/worley2d.js.map +1 -0
  80. package/dist/noise/worley3d.js +61 -0
  81. package/dist/noise/worley3d.js.map +1 -0
  82. package/dist/random/index.js +9 -0
  83. package/dist/random/index.js.map +1 -0
  84. package/dist/random/isaac32.js +164 -0
  85. package/dist/random/isaac32.js.map +1 -0
  86. package/dist/random/isaac64.js +215 -0
  87. package/dist/random/isaac64.js.map +1 -0
  88. package/dist/random/mulberry32.js +48 -0
  89. package/dist/random/mulberry32.js.map +1 -0
  90. package/dist/random/random.js +120 -0
  91. package/dist/random/random.js.map +1 -0
  92. package/dist/shapes/box2.js +300 -0
  93. package/dist/shapes/box2.js.map +1 -0
  94. package/dist/shapes/box3.js +550 -0
  95. package/dist/shapes/box3.js.map +1 -0
  96. package/dist/shapes/circle.js +6 -0
  97. package/dist/shapes/circle.js.map +1 -0
  98. package/dist/shapes/frustum.js +662 -0
  99. package/dist/shapes/frustum.js.map +1 -0
  100. package/dist/shapes/index.js +25 -0
  101. package/dist/shapes/index.js.map +1 -0
  102. package/dist/shapes/obb3.js +557 -0
  103. package/dist/shapes/obb3.js.map +1 -0
  104. package/dist/shapes/plane3.js +267 -0
  105. package/dist/shapes/plane3.js.map +1 -0
  106. package/dist/shapes/polygon2.js +451 -0
  107. package/dist/shapes/polygon2.js.map +1 -0
  108. package/dist/shapes/raycast3.js +164 -0
  109. package/dist/shapes/raycast3.js.map +1 -0
  110. package/dist/shapes/segment2.js +82 -0
  111. package/dist/shapes/segment2.js.map +1 -0
  112. package/dist/shapes/sphere.js +23 -0
  113. package/dist/shapes/sphere.js.map +1 -0
  114. package/dist/shapes/triangle2.js +79 -0
  115. package/dist/shapes/triangle2.js.map +1 -0
  116. package/dist/shapes/triangle3.js +60 -0
  117. package/dist/shapes/triangle3.js.map +1 -0
  118. package/dist/src/color/color.d.ts +50 -0
  119. package/dist/src/color/colorspace.d.ts +15 -0
  120. package/dist/src/color/hsl.d.ts +28 -0
  121. package/dist/src/color/index.d.ts +5 -0
  122. package/dist/src/color/parse.d.ts +15 -0
  123. package/dist/src/core/angle.d.ts +29 -0
  124. package/dist/src/core/arrays.d.ts +4 -0
  125. package/dist/src/core/euler.d.ts +78 -0
  126. package/dist/src/core/index.d.ts +27 -0
  127. package/dist/src/core/mat2.d.ts +217 -0
  128. package/dist/src/core/mat2d.d.ts +218 -0
  129. package/dist/src/core/mat3.d.ts +295 -0
  130. package/dist/src/core/mat4.d.ts +667 -0
  131. package/dist/src/core/polar.d.ts +151 -0
  132. package/dist/src/core/quat.d.ts +370 -0
  133. package/dist/src/core/quat2.d.ts +344 -0
  134. package/dist/src/core/scalar.d.ts +75 -0
  135. package/dist/src/core/spherical.d.ts +165 -0
  136. package/dist/src/core/vec2.d.ts +403 -0
  137. package/dist/src/core/vec3.d.ts +493 -0
  138. package/dist/src/core/vec4.d.ts +336 -0
  139. package/dist/src/geometry/circumcircle.d.ts +9 -0
  140. package/dist/src/geometry/index.d.ts +5 -0
  141. package/dist/src/geometry/polygon2-decompose.d.ts +25 -0
  142. package/dist/src/geometry/polygon2-triangulate.d.ts +15 -0
  143. package/dist/src/geometry/quickhull2.d.ts +10 -0
  144. package/dist/src/geometry/quickhull3.d.ts +27 -0
  145. package/dist/src/ik/fabrik2.d.ts +314 -0
  146. package/dist/src/ik/fabrik3.d.ts +371 -0
  147. package/dist/src/ik/index.d.ts +2 -0
  148. package/dist/src/index.d.ts +1 -0
  149. package/dist/src/noise/fractal.d.ts +95 -0
  150. package/dist/src/noise/index.d.ts +9 -0
  151. package/dist/src/noise/perlin2d.d.ts +19 -0
  152. package/dist/src/noise/perlin3d.d.ts +20 -0
  153. package/dist/src/noise/permutation.d.ts +22 -0
  154. package/dist/src/noise/simplex2d.d.ts +19 -0
  155. package/dist/src/noise/simplex3d.d.ts +20 -0
  156. package/dist/src/noise/simplex4d.d.ts +24 -0
  157. package/dist/src/noise/worley2d.d.ts +22 -0
  158. package/dist/src/noise/worley3d.d.ts +23 -0
  159. package/dist/src/random/index.d.ts +8 -0
  160. package/dist/src/random/isaac32.d.ts +62 -0
  161. package/dist/src/random/isaac64.d.ts +75 -0
  162. package/dist/src/random/mulberry32.d.ts +43 -0
  163. package/dist/src/random/random.d.ts +67 -0
  164. package/dist/src/shapes/box2.d.ts +174 -0
  165. package/dist/src/shapes/box3.d.ts +213 -0
  166. package/dist/src/shapes/circle.d.ts +7 -0
  167. package/dist/src/shapes/frustum.d.ts +147 -0
  168. package/dist/src/shapes/index.d.ts +20 -0
  169. package/dist/src/shapes/obb3.d.ts +105 -0
  170. package/dist/src/shapes/plane3.d.ts +130 -0
  171. package/dist/src/shapes/polygon2.d.ts +155 -0
  172. package/dist/src/shapes/raycast3.d.ts +42 -0
  173. package/dist/src/shapes/segment2.d.ts +34 -0
  174. package/dist/src/shapes/sphere.d.ts +19 -0
  175. package/dist/src/shapes/triangle2.d.ts +53 -0
  176. package/dist/src/shapes/triangle3.d.ts +29 -0
  177. package/dist/src/time/easing.d.ts +21 -0
  178. package/dist/src/time/index.d.ts +6 -0
  179. package/dist/src/time/spring-core.d.ts +15 -0
  180. package/dist/src/time/spring.d.ts +36 -0
  181. package/dist/src/time/spring2.d.ts +11 -0
  182. package/dist/src/time/spring3.d.ts +11 -0
  183. package/dist/src/time/spring4.d.ts +11 -0
  184. package/dist/time/easing.js +24 -0
  185. package/dist/time/easing.js.map +1 -0
  186. package/dist/time/index.js +11 -0
  187. package/dist/time/index.js.map +1 -0
  188. package/dist/time/spring-core.js +48 -0
  189. package/dist/time/spring-core.js.map +1 -0
  190. package/dist/time/spring.js +62 -0
  191. package/dist/time/spring.js.map +1 -0
  192. package/dist/time/spring2.js +31 -0
  193. package/dist/time/spring2.js.map +1 -0
  194. package/dist/time/spring3.js +32 -0
  195. package/dist/time/spring3.js.map +1 -0
  196. package/dist/time/spring4.js +32 -0
  197. package/dist/time/spring4.js.map +1 -0
  198. package/package.json +90 -16
  199. package/skills/math/SKILL.md +140 -0
  200. package/AUTHORS +0 -1
  201. package/Cakefile +0 -28
  202. package/math.coffee +0 -112
  203. package/math.js +0 -141
@@ -0,0 +1,48 @@
1
+ // Internal: the damped-harmonic-oscillator solver shared by every spring
2
+ // dimension. `coefficients` recomputes the step's 2×2 linear map into `coef`
3
+ // (module scratch, zero-allocation); each `spring*` namespace then applies those
4
+ // four coefficients per component.
5
+ // coefficients of the step's 2×2 map, recomputed per call into shared scratch:
6
+ // displacement' = coef.pp·displacement + coef.pv·velocity
7
+ // velocity' = coef.vp·displacement + coef.vv·velocity
8
+ const coef = { pp: 1, pv: 0, vp: 0, vv: 1 };
9
+ function coefficients(smoothTime, dampingRatio, delta) {
10
+ const omega = 2 / Math.max(0.0001, smoothTime);
11
+ if (Math.abs(dampingRatio - 1) < 1e-4) {
12
+ // critically damped — a double root at -omega
13
+ const e = Math.exp(-omega * delta);
14
+ coef.pp = e * (1 + omega * delta);
15
+ coef.pv = e * delta;
16
+ coef.vp = -e * omega * omega * delta;
17
+ coef.vv = e * (1 - omega * delta);
18
+ }
19
+ else if (dampingRatio < 1) {
20
+ // under-damped — complex roots, oscillates and overshoots
21
+ const za = -omega * dampingRatio;
22
+ const wd = omega * Math.sqrt(1 - dampingRatio * dampingRatio);
23
+ const e = Math.exp(za * delta);
24
+ const c = Math.cos(wd * delta);
25
+ const s = Math.sin(wd * delta);
26
+ coef.pp = e * (c - (za * s) / wd);
27
+ coef.pv = (e * s) / wd;
28
+ coef.vp = (-e * omega * omega * s) / wd;
29
+ coef.vv = e * (c + (za * s) / wd);
30
+ }
31
+ else {
32
+ // over-damped — two real roots, no overshoot
33
+ const za = -omega * dampingRatio;
34
+ const zb = omega * Math.sqrt(dampingRatio * dampingRatio - 1);
35
+ const r1 = za - zb;
36
+ const r2 = za + zb;
37
+ const den = r1 - r2;
38
+ const e1 = Math.exp(r1 * delta);
39
+ const e2 = Math.exp(r2 * delta);
40
+ coef.pp = (r1 * e2 - r2 * e1) / den;
41
+ coef.pv = (e1 - e2) / den;
42
+ coef.vp = (omega * omega * (e2 - e1)) / den; // r1·r2 = omega²
43
+ coef.vv = (r1 * e1 - r2 * e2) / den;
44
+ }
45
+ }
46
+
47
+ export { coef, coefficients };
48
+ //# sourceMappingURL=spring-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring-core.js","sources":["../../src/time/spring-core.ts"],"sourcesContent":["// Internal: the damped-harmonic-oscillator solver shared by every spring\n// dimension. `coefficients` recomputes the step's 2×2 linear map into `coef`\n// (module scratch, zero-allocation); each `spring*` namespace then applies those\n// four coefficients per component.\n\n/**\n * Spring state: a `value` and its `velocity`, of matching rank\n * (`number`, `Vec2`, `Vec3`, or `Vec4`). Allocate once, mutate each frame.\n */\nexport type Spring<T> = { value: T; velocity: T };\n\n// coefficients of the step's 2×2 map, recomputed per call into shared scratch:\n// displacement' = coef.pp·displacement + coef.pv·velocity\n// velocity' = coef.vp·displacement + coef.vv·velocity\nexport const coef = { pp: 1, pv: 0, vp: 0, vv: 1 };\n\nexport function coefficients(smoothTime: number, dampingRatio: number, delta: number): void {\n const omega = 2 / Math.max(0.0001, smoothTime);\n\n if (Math.abs(dampingRatio - 1) < 1e-4) {\n // critically damped — a double root at -omega\n const e = Math.exp(-omega * delta);\n coef.pp = e * (1 + omega * delta);\n coef.pv = e * delta;\n coef.vp = -e * omega * omega * delta;\n coef.vv = e * (1 - omega * delta);\n } else if (dampingRatio < 1) {\n // under-damped — complex roots, oscillates and overshoots\n const za = -omega * dampingRatio;\n const wd = omega * Math.sqrt(1 - dampingRatio * dampingRatio);\n const e = Math.exp(za * delta);\n const c = Math.cos(wd * delta);\n const s = Math.sin(wd * delta);\n coef.pp = e * (c - (za * s) / wd);\n coef.pv = (e * s) / wd;\n coef.vp = (-e * omega * omega * s) / wd;\n coef.vv = e * (c + (za * s) / wd);\n } else {\n // over-damped — two real roots, no overshoot\n const za = -omega * dampingRatio;\n const zb = omega * Math.sqrt(dampingRatio * dampingRatio - 1);\n const r1 = za - zb;\n const r2 = za + zb;\n const den = r1 - r2;\n const e1 = Math.exp(r1 * delta);\n const e2 = Math.exp(r2 * delta);\n coef.pp = (r1 * e2 - r2 * e1) / den;\n coef.pv = (e1 - e2) / den;\n coef.vp = (omega * omega * (e2 - e1)) / den; // r1·r2 = omega²\n coef.vv = (r1 * e1 - r2 * e2) / den;\n }\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AAQA;AACA;AACA;MACa,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;SAEhC,YAAY,CAAC,UAAkB,EAAE,YAAoB,EAAE,KAAa,EAAA;AAChF,IAAA,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC;IAE9C,IAAI,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE;;QAEnC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC;AAClC,QAAA,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC;AACjC,QAAA,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK;QACnB,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK;AACpC,QAAA,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC;IACrC;AAAO,SAAA,IAAI,YAAY,GAAG,CAAC,EAAE;;AAEzB,QAAA,MAAM,EAAE,GAAG,CAAC,KAAK,GAAG,YAAY;AAChC,QAAA,MAAM,EAAE,GAAG,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,YAAY,GAAG,YAAY,CAAC;QAC7D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC;AAC9B,QAAA,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE;AACtB,QAAA,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,GAAG,CAAC,IAAI,EAAE;AACvC,QAAA,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;IACrC;SAAO;;AAEH,QAAA,MAAM,EAAE,GAAG,CAAC,KAAK,GAAG,YAAY;AAChC,QAAA,MAAM,EAAE,GAAG,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,YAAY,GAAG,CAAC,CAAC;AAC7D,QAAA,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE;AAClB,QAAA,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE;AAClB,QAAA,MAAM,GAAG,GAAG,EAAE,GAAG,EAAE;QACnB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC;QAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC;AAC/B,QAAA,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,GAAG;QACnC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,IAAI,GAAG;AACzB,QAAA,IAAI,CAAC,EAAE,GAAG,CAAC,KAAK,GAAG,KAAK,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC;AAC5C,QAAA,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,GAAG;IACvC;AACJ;;;;"}
@@ -0,0 +1,62 @@
1
+ import { deltaAngle } from '../core/angle.js';
2
+ import { coef, coefficients } from './spring-core.js';
3
+
4
+ // A scalar spring (damped harmonic oscillator), integrated with the exact
5
+ // analytic solution — unconditionally stable at any frame delta, and
6
+ // behaviourally equivalent to Unity SmoothDamp / OG maath `damp` for the
7
+ // critical case. Two dials:
8
+ // smoothTime — roughly how long to reach the target; omega = 2 / smoothTime
9
+ // dampingRatio — the character: 1 = critical (no overshoot), <1 bouncy, >1 sluggish
10
+ // `damp` is `update` pinned to dampingRatio = 1.
11
+ //
12
+ // State lives in a `Spring<number>` the caller allocates once and passes back
13
+ // each frame; `update`/`damp` mutate `value` and `velocity` in place.
14
+ /** Creates a scalar spring at `value`, at rest. */
15
+ const create = (value = 0) => ({ value, velocity: 0 });
16
+ /**
17
+ * Springs `state.value` toward `target`, mutating `state` in place. Returns it.
18
+ *
19
+ * @param state spring state, mutated in place
20
+ * @param target goal value
21
+ * @param smoothTime approximate time to reach the target; smaller is faster
22
+ * @param dampingRatio 1 = critically damped (no overshoot), <1 bouncy, >1 sluggish
23
+ * @param delta frame delta, for refresh-rate independence
24
+ * @returns state
25
+ */
26
+ function update(state, target, smoothTime, dampingRatio, delta) {
27
+ coefficients(smoothTime, dampingRatio, delta);
28
+ const d = state.value - target;
29
+ const v = state.velocity;
30
+ state.value = target + coef.pp * d + coef.pv * v;
31
+ state.velocity = coef.vp * d + coef.vv * v;
32
+ return state;
33
+ }
34
+ /**
35
+ * Critically-damped {@link update} (dampingRatio = 1): moves toward `target` as
36
+ * fast as possible without overshooting.
37
+ */
38
+ function damp(state, target, smoothTime, delta) {
39
+ return update(state, target, smoothTime, 1, delta);
40
+ }
41
+ /**
42
+ * Like {@link damp}, but takes the shortest angular path to `target` (radians),
43
+ * wrapping across the ±π seam rather than unwinding the long way around.
44
+ */
45
+ function dampAngle(state, target, smoothTime, delta) {
46
+ return damp(state, state.value + deltaAngle(state.value, target), smoothTime, delta);
47
+ }
48
+ /**
49
+ * Converts a SwiftUI-style `response` — the spring's natural period, in seconds
50
+ * — to the `smoothTime` that `update`/`damp` consume. `dampingRatio` is the
51
+ * orthogonal second dial and is passed to `update` unchanged.
52
+ *
53
+ * Yields the same stiffness/damping as SwiftUI's `Spring(response:dampingFraction:)`:
54
+ *
55
+ * ```ts
56
+ * spring3.update(state, target, spring.fromResponse(0.5), 0.3, delta); // bouncy, ~0.5s period
57
+ * ```
58
+ */
59
+ const fromResponse = (response) => response / Math.PI;
60
+
61
+ export { create, damp, dampAngle, fromResponse, update };
62
+ //# sourceMappingURL=spring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring.js","sources":["../../src/time/spring.ts"],"sourcesContent":["import { deltaAngle } from '../core/angle';\nimport { coef, coefficients, type Spring } from './spring-core';\n\n// A scalar spring (damped harmonic oscillator), integrated with the exact\n// analytic solution — unconditionally stable at any frame delta, and\n// behaviourally equivalent to Unity SmoothDamp / OG maath `damp` for the\n// critical case. Two dials:\n// smoothTime — roughly how long to reach the target; omega = 2 / smoothTime\n// dampingRatio — the character: 1 = critical (no overshoot), <1 bouncy, >1 sluggish\n// `damp` is `update` pinned to dampingRatio = 1.\n//\n// State lives in a `Spring<number>` the caller allocates once and passes back\n// each frame; `update`/`damp` mutate `value` and `velocity` in place.\n\n/** Creates a scalar spring at `value`, at rest. */\nexport const create = (value = 0): Spring<number> => ({ value, velocity: 0 });\n\n/**\n * Springs `state.value` toward `target`, mutating `state` in place. Returns it.\n *\n * @param state spring state, mutated in place\n * @param target goal value\n * @param smoothTime approximate time to reach the target; smaller is faster\n * @param dampingRatio 1 = critically damped (no overshoot), <1 bouncy, >1 sluggish\n * @param delta frame delta, for refresh-rate independence\n * @returns state\n */\nexport function update(\n state: Spring<number>,\n target: number,\n smoothTime: number,\n dampingRatio: number,\n delta: number,\n): Spring<number> {\n coefficients(smoothTime, dampingRatio, delta);\n const d = state.value - target;\n const v = state.velocity;\n state.value = target + coef.pp * d + coef.pv * v;\n state.velocity = coef.vp * d + coef.vv * v;\n return state;\n}\n\n/**\n * Critically-damped {@link update} (dampingRatio = 1): moves toward `target` as\n * fast as possible without overshooting.\n */\nexport function damp(state: Spring<number>, target: number, smoothTime: number, delta: number): Spring<number> {\n return update(state, target, smoothTime, 1, delta);\n}\n\n/**\n * Like {@link damp}, but takes the shortest angular path to `target` (radians),\n * wrapping across the ±π seam rather than unwinding the long way around.\n */\nexport function dampAngle(state: Spring<number>, target: number, smoothTime: number, delta: number): Spring<number> {\n return damp(state, state.value + deltaAngle(state.value, target), smoothTime, delta);\n}\n\n/**\n * Converts a SwiftUI-style `response` — the spring's natural period, in seconds\n * — to the `smoothTime` that `update`/`damp` consume. `dampingRatio` is the\n * orthogonal second dial and is passed to `update` unchanged.\n *\n * Yields the same stiffness/damping as SwiftUI's `Spring(response:dampingFraction:)`:\n *\n * ```ts\n * spring3.update(state, target, spring.fromResponse(0.5), 0.3, delta); // bouncy, ~0.5s period\n * ```\n */\nexport const fromResponse = (response: number): number => response / Math.PI;\n"],"names":[],"mappings":";;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;MACa,MAAM,GAAG,CAAC,KAAK,GAAG,CAAC,MAAsB,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE;AAE5E;;;;;;;;;AASG;AACG,SAAU,MAAM,CAClB,KAAqB,EACrB,MAAc,EACd,UAAkB,EAClB,YAAoB,EACpB,KAAa,EAAA;AAEb,IAAA,YAAY,CAAC,UAAU,EAAE,YAAY,EAAE,KAAK,CAAC;AAC7C,IAAA,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,MAAM;AAC9B,IAAA,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ;AACxB,IAAA,KAAK,CAAC,KAAK,GAAG,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;AAChD,IAAA,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;AAC1C,IAAA,OAAO,KAAK;AAChB;AAEA;;;AAGG;AACG,SAAU,IAAI,CAAC,KAAqB,EAAE,MAAc,EAAE,UAAkB,EAAE,KAAa,EAAA;AACzF,IAAA,OAAO,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,CAAC;AACtD;AAEA;;;AAGG;AACG,SAAU,SAAS,CAAC,KAAqB,EAAE,MAAc,EAAE,UAAkB,EAAE,KAAa,EAAA;IAC9F,OAAO,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC;AACxF;AAEA;;;;;;;;;;AAUG;AACI,MAAM,YAAY,GAAG,CAAC,QAAgB,KAAa,QAAQ,GAAG,IAAI,CAAC;;;;"}
@@ -0,0 +1,31 @@
1
+ import { coefficients, coef } from './spring-core.js';
2
+
3
+ // A Vec2 spring. See `spring` (scalar) for the model; the same four coefficients
4
+ // are applied to each component. `damp` is `update` pinned to dampingRatio = 1.
5
+ /** Creates a Vec2 spring at `value` (copied), at rest. */
6
+ const create = (value = [0, 0]) => ({ value: [value[0], value[1]], velocity: [0, 0] });
7
+ /**
8
+ * Springs `state.value` toward `target`, mutating `state` in place. Returns it.
9
+ * @param dampingRatio 1 = critically damped (no overshoot), <1 bouncy, >1 sluggish
10
+ */
11
+ function update(state, target, smoothTime, dampingRatio, delta) {
12
+ coefficients(smoothTime, dampingRatio, delta);
13
+ const val = state.value;
14
+ const vel = state.velocity;
15
+ let d = val[0] - target[0];
16
+ let v = vel[0];
17
+ val[0] = target[0] + coef.pp * d + coef.pv * v;
18
+ vel[0] = coef.vp * d + coef.vv * v;
19
+ d = val[1] - target[1];
20
+ v = vel[1];
21
+ val[1] = target[1] + coef.pp * d + coef.pv * v;
22
+ vel[1] = coef.vp * d + coef.vv * v;
23
+ return state;
24
+ }
25
+ /** Critically-damped Vec2 spring (dampingRatio = 1). See {@link update}. */
26
+ function damp(state, target, smoothTime, delta) {
27
+ return update(state, target, smoothTime, 1, delta);
28
+ }
29
+
30
+ export { create, damp, update };
31
+ //# sourceMappingURL=spring2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring2.js","sources":["../../src/time/spring2.ts"],"sourcesContent":["import type { Vec2 } from '../core';\nimport { coef, coefficients, type Spring } from './spring-core';\n\n// A Vec2 spring. See `spring` (scalar) for the model; the same four coefficients\n// are applied to each component. `damp` is `update` pinned to dampingRatio = 1.\n\n/** Creates a Vec2 spring at `value` (copied), at rest. */\nexport const create = (value: Vec2 = [0, 0]): Spring<Vec2> => ({ value: [value[0], value[1]], velocity: [0, 0] });\n\n/**\n * Springs `state.value` toward `target`, mutating `state` in place. Returns it.\n * @param dampingRatio 1 = critically damped (no overshoot), <1 bouncy, >1 sluggish\n */\nexport function update(state: Spring<Vec2>, target: Vec2, smoothTime: number, dampingRatio: number, delta: number): Spring<Vec2> {\n coefficients(smoothTime, dampingRatio, delta);\n const val = state.value;\n const vel = state.velocity;\n let d = val[0] - target[0];\n let v = vel[0];\n val[0] = target[0] + coef.pp * d + coef.pv * v;\n vel[0] = coef.vp * d + coef.vv * v;\n d = val[1] - target[1];\n v = vel[1];\n val[1] = target[1] + coef.pp * d + coef.pv * v;\n vel[1] = coef.vp * d + coef.vv * v;\n return state;\n}\n\n/** Critically-damped Vec2 spring (dampingRatio = 1). See {@link update}. */\nexport function damp(state: Spring<Vec2>, target: Vec2, smoothTime: number, delta: number): Spring<Vec2> {\n return update(state, target, smoothTime, 1, delta);\n}\n"],"names":[],"mappings":";;AAGA;AACA;AAEA;AACO,MAAM,MAAM,GAAG,CAAC,QAAc,CAAC,CAAC,EAAE,CAAC,CAAC,MAAoB,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;AAEhH;;;AAGG;AACG,SAAU,MAAM,CAAC,KAAmB,EAAE,MAAY,EAAE,UAAkB,EAAE,YAAoB,EAAE,KAAa,EAAA;AAC7G,IAAA,YAAY,CAAC,UAAU,EAAE,YAAY,EAAE,KAAK,CAAC;AAC7C,IAAA,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK;AACvB,IAAA,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ;IAC1B,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAC1B,IAAA,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACd,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;AAC9C,IAAA,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;IAClC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AACtB,IAAA,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACV,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;AAC9C,IAAA,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;AAClC,IAAA,OAAO,KAAK;AAChB;AAEA;AACM,SAAU,IAAI,CAAC,KAAmB,EAAE,MAAY,EAAE,UAAkB,EAAE,KAAa,EAAA;AACrF,IAAA,OAAO,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,CAAC;AACtD;;;;"}
@@ -0,0 +1,32 @@
1
+ import { coefficients, coef } from './spring-core.js';
2
+
3
+ // A Vec3 spring. See `spring` (scalar) for the model. `damp` is `update` pinned
4
+ // to dampingRatio = 1.
5
+ /** Creates a Vec3 spring at `value` (copied), at rest. */
6
+ const create = (value = [0, 0, 0]) => ({
7
+ value: [value[0], value[1], value[2]],
8
+ velocity: [0, 0, 0],
9
+ });
10
+ /**
11
+ * Springs `state.value` toward `target`, mutating `state` in place. Returns it.
12
+ * @param dampingRatio 1 = critically damped (no overshoot), <1 bouncy, >1 sluggish
13
+ */
14
+ function update(state, target, smoothTime, dampingRatio, delta) {
15
+ coefficients(smoothTime, dampingRatio, delta);
16
+ const val = state.value;
17
+ const vel = state.velocity;
18
+ for (let i = 0; i < 3; i++) {
19
+ const d = val[i] - target[i];
20
+ const v = vel[i];
21
+ val[i] = target[i] + coef.pp * d + coef.pv * v;
22
+ vel[i] = coef.vp * d + coef.vv * v;
23
+ }
24
+ return state;
25
+ }
26
+ /** Critically-damped Vec3 spring (dampingRatio = 1). See {@link update}. */
27
+ function damp(state, target, smoothTime, delta) {
28
+ return update(state, target, smoothTime, 1, delta);
29
+ }
30
+
31
+ export { create, damp, update };
32
+ //# sourceMappingURL=spring3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring3.js","sources":["../../src/time/spring3.ts"],"sourcesContent":["import type { Vec3 } from '../core';\nimport { coef, coefficients, type Spring } from './spring-core';\n\n// A Vec3 spring. See `spring` (scalar) for the model. `damp` is `update` pinned\n// to dampingRatio = 1.\n\n/** Creates a Vec3 spring at `value` (copied), at rest. */\nexport const create = (value: Vec3 = [0, 0, 0]): Spring<Vec3> => ({\n value: [value[0], value[1], value[2]],\n velocity: [0, 0, 0],\n});\n\n/**\n * Springs `state.value` toward `target`, mutating `state` in place. Returns it.\n * @param dampingRatio 1 = critically damped (no overshoot), <1 bouncy, >1 sluggish\n */\nexport function update(state: Spring<Vec3>, target: Vec3, smoothTime: number, dampingRatio: number, delta: number): Spring<Vec3> {\n coefficients(smoothTime, dampingRatio, delta);\n const val = state.value;\n const vel = state.velocity;\n for (let i = 0; i < 3; i++) {\n const d = val[i] - target[i];\n const v = vel[i];\n val[i] = target[i] + coef.pp * d + coef.pv * v;\n vel[i] = coef.vp * d + coef.vv * v;\n }\n return state;\n}\n\n/** Critically-damped Vec3 spring (dampingRatio = 1). See {@link update}. */\nexport function damp(state: Spring<Vec3>, target: Vec3, smoothTime: number, delta: number): Spring<Vec3> {\n return update(state, target, smoothTime, 1, delta);\n}\n"],"names":[],"mappings":";;AAGA;AACA;AAEA;AACO,MAAM,MAAM,GAAG,CAAC,QAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,MAAoB;AAC9D,IAAA,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;AACrC,IAAA,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACtB,CAAA;AAED;;;AAGG;AACG,SAAU,MAAM,CAAC,KAAmB,EAAE,MAAY,EAAE,UAAkB,EAAE,YAAoB,EAAE,KAAa,EAAA;AAC7G,IAAA,YAAY,CAAC,UAAU,EAAE,YAAY,EAAE,KAAK,CAAC;AAC7C,IAAA,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK;AACvB,IAAA,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ;AAC1B,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;QACxB,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAC5B,QAAA,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAChB,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;AAC9C,QAAA,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;IACtC;AACA,IAAA,OAAO,KAAK;AAChB;AAEA;AACM,SAAU,IAAI,CAAC,KAAmB,EAAE,MAAY,EAAE,UAAkB,EAAE,KAAa,EAAA;AACrF,IAAA,OAAO,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,CAAC;AACtD;;;;"}
@@ -0,0 +1,32 @@
1
+ import { coefficients, coef } from './spring-core.js';
2
+
3
+ // A Vec4 spring. See `spring` (scalar) for the model. `damp` is `update` pinned
4
+ // to dampingRatio = 1.
5
+ /** Creates a Vec4 spring at `value` (copied), at rest. */
6
+ const create = (value = [0, 0, 0, 0]) => ({
7
+ value: [value[0], value[1], value[2], value[3]],
8
+ velocity: [0, 0, 0, 0],
9
+ });
10
+ /**
11
+ * Springs `state.value` toward `target`, mutating `state` in place. Returns it.
12
+ * @param dampingRatio 1 = critically damped (no overshoot), <1 bouncy, >1 sluggish
13
+ */
14
+ function update(state, target, smoothTime, dampingRatio, delta) {
15
+ coefficients(smoothTime, dampingRatio, delta);
16
+ const val = state.value;
17
+ const vel = state.velocity;
18
+ for (let i = 0; i < 4; i++) {
19
+ const d = val[i] - target[i];
20
+ const v = vel[i];
21
+ val[i] = target[i] + coef.pp * d + coef.pv * v;
22
+ vel[i] = coef.vp * d + coef.vv * v;
23
+ }
24
+ return state;
25
+ }
26
+ /** Critically-damped Vec4 spring (dampingRatio = 1). See {@link update}. */
27
+ function damp(state, target, smoothTime, delta) {
28
+ return update(state, target, smoothTime, 1, delta);
29
+ }
30
+
31
+ export { create, damp, update };
32
+ //# sourceMappingURL=spring4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring4.js","sources":["../../src/time/spring4.ts"],"sourcesContent":["import type { Vec4 } from '../core';\nimport { coef, coefficients, type Spring } from './spring-core';\n\n// A Vec4 spring. See `spring` (scalar) for the model. `damp` is `update` pinned\n// to dampingRatio = 1.\n\n/** Creates a Vec4 spring at `value` (copied), at rest. */\nexport const create = (value: Vec4 = [0, 0, 0, 0]): Spring<Vec4> => ({\n value: [value[0], value[1], value[2], value[3]],\n velocity: [0, 0, 0, 0],\n});\n\n/**\n * Springs `state.value` toward `target`, mutating `state` in place. Returns it.\n * @param dampingRatio 1 = critically damped (no overshoot), <1 bouncy, >1 sluggish\n */\nexport function update(state: Spring<Vec4>, target: Vec4, smoothTime: number, dampingRatio: number, delta: number): Spring<Vec4> {\n coefficients(smoothTime, dampingRatio, delta);\n const val = state.value;\n const vel = state.velocity;\n for (let i = 0; i < 4; i++) {\n const d = val[i] - target[i];\n const v = vel[i];\n val[i] = target[i] + coef.pp * d + coef.pv * v;\n vel[i] = coef.vp * d + coef.vv * v;\n }\n return state;\n}\n\n/** Critically-damped Vec4 spring (dampingRatio = 1). See {@link update}. */\nexport function damp(state: Spring<Vec4>, target: Vec4, smoothTime: number, delta: number): Spring<Vec4> {\n return update(state, target, smoothTime, 1, delta);\n}\n"],"names":[],"mappings":";;AAGA;AACA;AAEA;AACO,MAAM,MAAM,GAAG,CAAC,KAAA,GAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,MAAoB;IACjE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/C,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACzB,CAAA;AAED;;;AAGG;AACG,SAAU,MAAM,CAAC,KAAmB,EAAE,MAAY,EAAE,UAAkB,EAAE,YAAoB,EAAE,KAAa,EAAA;AAC7G,IAAA,YAAY,CAAC,UAAU,EAAE,YAAY,EAAE,KAAK,CAAC;AAC7C,IAAA,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK;AACvB,IAAA,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ;AAC1B,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;QACxB,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAC5B,QAAA,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAChB,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;AAC9C,QAAA,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;IACtC;AACA,IAAA,OAAO,KAAK;AAChB;AAEA;AACM,SAAU,IAAI,CAAC,KAAmB,EAAE,MAAY,EAAE,UAAkB,EAAE,KAAa,EAAA;AACrF,IAAA,OAAO,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,CAAC;AACtD;;;;"}
package/package.json CHANGED
@@ -1,20 +1,94 @@
1
1
  {
2
- "author": "Kaleb Hornsby <kaleb@hornsby.ws> (kaleb.hornsby.ws)",
3
2
  "name": "math",
4
- "description": "Mathematical Functions",
5
- "version": "0.0.3",
6
- "repository": {
7
- "type": "git",
8
- "url": "git://github.com/kaleb/js-math.git"
3
+ "version": "0.1.0",
4
+ "author": "Isaac Mason <isaac@isaacmason.com>",
5
+ "description": "a collection of math helpers for graphics and simulations",
6
+ "keywords": [
7
+ "math",
8
+ "vector",
9
+ "matrix",
10
+ "quaternion",
11
+ "euler",
12
+ "random",
13
+ "noise"
14
+ ],
15
+ "license": "MIT",
16
+ "repository": "github:pmndrs/math",
17
+ "homepage": "https://github.com/pmndrs/math",
18
+ "bugs": {
19
+ "url": "https://github.com/pmndrs/math/issues"
9
20
  },
10
- "main": "math.js",
11
- "engines": {
12
- "node": "> 0.0.0"
21
+ "type": "module",
22
+ "main": "dist/index.js",
23
+ "types": "dist/src/index.d.ts",
24
+ "sideEffects": false,
25
+ "exports": {
26
+ ".": {
27
+ "import": "./dist/index.js",
28
+ "types": "./dist/src/index.d.ts"
29
+ },
30
+ "./shapes": {
31
+ "import": "./dist/shapes/index.js",
32
+ "types": "./dist/src/shapes/index.d.ts"
33
+ },
34
+ "./geometry": {
35
+ "import": "./dist/geometry/index.js",
36
+ "types": "./dist/src/geometry/index.d.ts"
37
+ },
38
+ "./time": {
39
+ "import": "./dist/time/index.js",
40
+ "types": "./dist/src/time/index.d.ts"
41
+ },
42
+ "./random": {
43
+ "import": "./dist/random/index.js",
44
+ "types": "./dist/src/random/index.d.ts"
45
+ },
46
+ "./noise": {
47
+ "import": "./dist/noise/index.js",
48
+ "types": "./dist/src/noise/index.d.ts"
49
+ },
50
+ "./color": {
51
+ "import": "./dist/color/index.js",
52
+ "types": "./dist/src/color/index.d.ts"
53
+ },
54
+ "./ik": {
55
+ "import": "./dist/ik/index.js",
56
+ "types": "./dist/src/ik/index.d.ts"
57
+ }
13
58
  },
14
- "dependencies": {},
15
- "devDependencies": {},
16
- "homepage": "kaleb.hornsby.ws/js-math",
17
- "contributors": [
18
- "Kaleb Hornsby <kaleb@hornsby.ws> (kaleb.hornsby.ws)"
19
- ]
20
- }
59
+ "files": [
60
+ "dist",
61
+ "skills",
62
+ "LICENSE",
63
+ "README.md",
64
+ "API.md"
65
+ ],
66
+ "scripts": {
67
+ "build": "rm -rf ./dist && pnpm run build:bundle && pnpm run build:dts",
68
+ "build:bundle": "rollup --config rollup.config.mjs",
69
+ "build:dts": "tsc -p tsconfig.build.json && node scripts/add-js-extensions-dts.mjs",
70
+ "build:examples": "pnpm --filter math-examples build",
71
+ "dev:examples": "pnpm --filter math-examples dev",
72
+ "build:website": "pnpm --filter website build",
73
+ "format": "biome format --write src/. tst/.",
74
+ "lint": "biome lint --write src/. tst/.",
75
+ "test": "vitest run ./tst",
76
+ "bench": "pnpm --filter benches exec labs",
77
+ "typecheck-docs": "tsc --project docs/tsconfig.json --noEmit",
78
+ "docs": "(cd docs && node ./build.js)",
79
+ "typedoc": "typedoc --tsconfig ./tsconfig.json --name \"math docs\" --out ./dist-typedoc ./src/index.ts ./src/shapes/index.ts ./src/geometry/index.ts ./src/time/index.ts ./src/random/index.ts ./src/noise/index.ts ./src/color/index.ts ./src/ik/index.ts",
80
+ "build:docs": "pnpm run docs && pnpm run typedoc",
81
+ "release": "pnpm run build && pnpm run test && pnpm run build:examples && pnpm run build:docs && pnpm run build:website"
82
+ },
83
+ "packageManager": "pnpm@11.22.0",
84
+ "devDependencies": {
85
+ "@biomejs/biome": "^2.5.6",
86
+ "@rollup/plugin-node-resolve": "^16",
87
+ "@rollup/plugin-typescript": "^12",
88
+ "rollup": "^4",
89
+ "tslib": "^2.8.1",
90
+ "typedoc": "^0.28.16",
91
+ "typescript": "^5.9.2",
92
+ "vitest": "^3.2.4"
93
+ }
94
+ }
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: math
3
+ description: Use when writing or reviewing geometry, simulation, collision, navigation, culling, procedural generation, transforms, or other performance-sensitive algorithms with the npm `math` package, or when the user invokes /math. Not for routine arithmetic or textbook explanations.
4
+ ---
5
+
6
+ # math
7
+
8
+ Write data-oriented TypeScript on top of the npm `math` package: plain data, free functions, no classes, no allocation in hot paths.
9
+
10
+ API docs are in `API.md` — every export with its signature, grouped by module and flat enough to grep. Find it at `node_modules/math/API.md` in a consuming project, or at the repo root when working on `math` itself.
11
+
12
+ ## Types
13
+
14
+ Every type is a plain fixed-length tuple of numbers — no classes, no wrappers, and not a typed array:
15
+
16
+ - `Vec2` `[x, y]`, `Vec3` `[x, y, z]`, `Vec4` `[x, y, z, w]`
17
+ - `Quat` `[x, y, z, w]`, `Quat2` `[x, y, z, w, x2, y2, z2, w2]`
18
+ - `Euler` `[x, y, z, order?]`, radians, order defaulting to `'xyz'`
19
+ - `Mat2` (4), `Mat2d` (6), `Mat3` (9), `Mat4` (16) — contiguous and column-major, with `Mat4` translation in `m[12]`, `m[13]`, `m[14]`
20
+ - `Polar` `[r, theta]`, `Spherical` `[r, theta, phi]`
21
+
22
+ ## Style
23
+
24
+ - **Functions over data.** Export `function` declarations that take typed data and operate on it. Never classes for data, never closures that hold state. The one exception is a small fixed set of classes implementing a single structural type — a collector handed to a query to receive its hits, say — where the call site is polymorphic and a stable hidden class keeps it fast.
25
+ - **`out` first, return `out`** for composite results: `fn(out: Vec3, a: Vec3, b: Vec3): Vec3`. Scalars and booleans return directly.
26
+ - **Use result objects and `out` params over returning new objects.** When a result doesn't fit a vector, define a result type with a `createXResult()` factory beside it; report failure with a boolean or status enum rather than `out | null`.
27
+ - **Assume the caller aliases** — the same array may arrive as both `out` and an input, as in `vec3.normalize(v, v)` or `vec3.cross(a, a, b)`. Read every input component into a local before the first write to `out`, so a write can't clobber an input still needed.
28
+ - **Caller-owned state.** Long-lived state is plain data the caller allocates and owns. Functions receive it, mutate it in place, and return it. The library never owns the data lifecycle, so allocation happens once, ownership is explicit, and the object keeps one stable shape. Naming and file layout are up to the codebase. One common shape:
29
+
30
+ ```ts
31
+ export function createWorld(capacity: number) {
32
+ return { capacity, count: 0, positions: new Float32Array(capacity * 3) };
33
+ }
34
+ export type World = ReturnType<typeof createWorld>;
35
+
36
+ export function stepWorld(world: World, delta: number): World { /* mutate, return world */ }
37
+ export function getWorldPosition(out: Vec3, world: World, i: number): Vec3 { /* write out, return it */ }
38
+ ```
39
+
40
+ - **Monomorphic state.** Build the object with the same keys in the same order every time. No optional fields, no keys added later.
41
+ - **Allocate at creation, never per call.** Preallocate flat or typed arrays to capacity. When full, return a count, sentinel, or status rather than growing inside a hot loop.
42
+ - **Compose `math` primitives** (`vec3`, `mat4`, `quat`, and the `math/shapes`, `math/geometry`, `math/noise`, `math/random`, `math/time` subpaths).
43
+ - **Hoist invariants out of loops**
44
+
45
+ ## Gotchas
46
+
47
+ - Module-level scratch is named `_owner_purpose`. Grow-once buffers carry an explicit size counter rather than `push`/`pop`/`length = 0`.
48
+ - Module-level scratch variables are not reentrant. Pass caller-owned workspace for recursive, nested, or worker code.
49
+ - One epsilon does not fit every operation or scale. Choose each tolerance and say why.
50
+ - Define behavior for empty input, zero-length vectors, degenerate geometry, NaN, and exact boundary contact.
51
+ - Compare squared distances; reach for `squaredLength` / `squaredDistance` over their square-rooted pairs.
52
+ - Integers in the range [-2^30, 2^30) are stored in the pointer itself (V8 Smi), with no heap object. Use them for indices, handles, packed IDs, bitmasks, and counts.
53
+ - Where possible avoid plain array element kind transitions (small integers, doubles, array with holes). Especially avoid unnecessary SMI or PACKED_DOUBLE to holey transitions when holey arrays are not desired.
54
+ - Don't assume a typed array is faster. A packed plain array is already unboxed and can still grow. Typed arrays buy footprint, a fixed layout, and zero-copy interop with workers, Wasm, and the GPU; they cost a capacity fixed up front and, for `Float32Array`, a narrowing conversion on every write. Choose one for interop or memory, not on a hunch about speed.
55
+ - In a **library**, annotate module-level factory calls `/* @__PURE__ */` so a consumer's bundler can drop the scratch when the function is tree-shaken out. Application code does not need it.
56
+
57
+ Deliver the implementation with its assumptions, complexity, edge cases, and focused tests.
58
+
59
+ ## Working with other libs
60
+
61
+ Marshal in, compute, marshal out — and allocate on neither crossing. Keep the scratch `math` types at module scope, fill them from the other library's values, run the algorithm as plain `math` calls, then write the results back. The seam is a few lines at each end of a function; everything between them is flat data.
62
+
63
+ - **A `Float32Array` is not a `Vec3`.** The tuple types don't accept one, and casting past that gets you a value the rest of the codebase can't rely on. Marshal across the boundary instead.
64
+ - **Marshal with whatever writes into memory you already own.** For flat buffers — an instanced attribute, a packed particle array — that's `vec3.fromBuffer(out, buffer, i * 3)` and `vec3.toBuffer(buffer, v, i * 3)` (also on `vec2`, `vec4`, `quat`), or `buffer.set(m, i * 16)` for a whole matrix, since `TypedArray.set` takes any array-like.
65
+ - **State that crosses a worker, Wasm, or GPU boundary lives in a typed array from the start.** A plain-array `Vec3` can't be transferred or shared, so back the long-lived data with `Float32Array` / `SharedArrayBuffer` at creation and marshal at the edges.
66
+
67
+ ### three.js
68
+
69
+ `Vector3`, `Quaternion`, `Matrix4`, and `Euler` all marshal through `toArray(target)` and `fromArray(source)`, and the component order matches `math`'s in every case. Always pass your scratch to `toArray` — called bare, it allocates a fresh array.
70
+
71
+ **Orbit camera.** The camera's state is a `Spherical` and a target the caller owns; three only ever sees the resulting position.
72
+
73
+ ```ts
74
+ import { spherical, vec3 } from 'math';
75
+ import type { Camera } from 'three';
76
+
77
+ const MIN_RADIUS = 1;
78
+ const MAX_RADIUS = 100;
79
+
80
+ export function createOrbit() {
81
+ return { target: vec3.create(), orbit: spherical.fromValues(10, 0, Math.PI / 3) };
82
+ }
83
+ export type Orbit = ReturnType<typeof createOrbit>;
84
+
85
+ const _orbit_position = vec3.create();
86
+
87
+ /** Apply a drag in radians and a zoom factor, then place the camera. */
88
+ export function updateOrbit(camera: Camera, orbit: Orbit, dragX: number, dragY: number, zoom: number): void {
89
+ const s = orbit.orbit;
90
+
91
+ s[0] = Math.min(MAX_RADIUS, Math.max(MIN_RADIUS, s[0] * zoom));
92
+ s[1] -= dragX;
93
+ s[2] -= dragY;
94
+ spherical.makeSafe(s, s); // keeps phi off the poles, where the frame degenerates
95
+
96
+ vec3.add(_orbit_position, spherical.toVec3(_orbit_position, s), orbit.target);
97
+
98
+ camera.position.fromArray(_orbit_position);
99
+ camera.lookAt(orbit.target[0], orbit.target[1], orbit.target[2]);
100
+ }
101
+ ```
102
+
103
+ **Camera-relative character move.** Takes the yaw straight from that orbit state, so stick-forward means away-from-camera.
104
+
105
+ ```ts
106
+ import { quat, vec3, type Vec3 } from 'math';
107
+ import type { Object3D } from 'three';
108
+
109
+ const UP: Vec3 = [0, 1, 0];
110
+ const TURN_RATE = 15;
111
+ const DEADZONE_SQ = 0.01;
112
+
113
+ const _move_yaw = quat.create();
114
+ const _move_facing = quat.create();
115
+ const _move_rotation = quat.create();
116
+ const _move_position = vec3.create();
117
+ const _move_direction = vec3.create();
118
+
119
+ /** Move `character` by `inputX` / `inputZ` (a stick, in [-1, 1]) relative to a camera at `yaw`. */
120
+ export function moveCharacter(character: Object3D, inputX: number, inputZ: number, yaw: number, speed: number, delta: number): void {
121
+ vec3.set(_move_direction, inputX, 0, inputZ);
122
+ if (vec3.squaredLength(_move_direction) < DEADZONE_SQ) return; // idle: leave the facing alone
123
+
124
+ // swing the stick into camera space, then step along it
125
+ quat.setAxisAngle(_move_yaw, UP, yaw);
126
+ vec3.transformQuat(_move_direction, _move_direction, _move_yaw);
127
+ vec3.normalize(_move_direction, _move_direction);
128
+
129
+ character.position.toArray(_move_position);
130
+ vec3.scaleAndAdd(_move_position, _move_position, _move_direction, speed * delta);
131
+
132
+ // turn toward travel, rather than snapping
133
+ character.quaternion.toArray(_move_rotation);
134
+ quat.setAxisAngle(_move_facing, UP, Math.atan2(_move_direction[0], _move_direction[2]));
135
+ quat.slerp(_move_rotation, _move_rotation, _move_facing, 1 - TURN_RATE ** -delta);
136
+
137
+ character.position.fromArray(_move_position);
138
+ character.quaternion.fromArray(_move_rotation);
139
+ }
140
+ ```
package/AUTHORS DELETED
@@ -1 +0,0 @@
1
- Kaleb Hornsby <kaleb@hornsby.ws> (kaleb.hornsby.ws)
package/Cakefile DELETED
@@ -1,28 +0,0 @@
1
- {exec, spawn} = require 'child_process'
2
- path = require 'path'
3
-
4
- repo = 'git' # or 'hg
5
-
6
- getVersion = -> spawn 'npm', ['--version'], (err, stdout, stderr) ->
7
- [err, stdout, stderr]
8
-
9
- task 'edit', 'Edit the Cakefile', (options) ->
10
- console.log 'Not implemented', options
11
-
12
- task 'version', 'Display the package version.', (options) ->
13
- exec 'npm --version', (error, stdout, stderr) ->
14
- version = stdout.split('.')
15
- console.log version[2]
16
-
17
- task 'ci', 'commit', (options) ->
18
- console.dir(options)
19
- exec "#{repo} commit", (error, stdout, stderr) ->
20
- console.log stdout
21
-
22
- task 'co',
23
-
24
- task 'push'
25
-
26
- task 'pull'
27
-
28
- option '-m', '--message', 'Message'
package/math.coffee DELETED
@@ -1,112 +0,0 @@
1
- module?.exports &&= Math
2
-
3
- ###*
4
- * @return wheter a Number x, has the same sign as another Number, y.
5
- * @example
6
- * Math.samesign(1,2)
7
- * //-> true
8
- * Math.samesign(-3, 4)
9
- * //-> false
10
- * @test
11
- * Math.samesign(5, 6)
12
- * //-> false
13
- * Math.samesign(-7, -8)
14
- * //-> true
15
- ###
16
- Math.samesign = (x, y) -> (x >= 0) != (y < 0)
17
-
18
- ###*
19
- * @return {Number} a copy of Number x with the same sign of Number y.
20
- * @example
21
- * Math.copysign(1, -2)
22
- * //-> -1
23
- * @test
24
- * Math.copysign(-3, 4)
25
- * //-> 3
26
- * Math.copysign(5, 6)
27
- * //-> 5
28
- * Math.copysign(-7, -8)
29
- * //-> -7
30
- ###
31
- Math.copysign = (x, y) -> if Math.samesign x, y then x else -x
32
-
33
- ###*
34
- * @return {Number} sum of two Numbers.
35
- * @example
36
- * Math.add(1, 2)
37
- * //-> 3
38
- * @test
39
- * Math.add('three', 4)
40
- * //-> NaN
41
- ###
42
- Math.add = (a, b) -> (+a) + (+b)
43
-
44
- ###*
45
- * @return {Number} sum of an Array of Numbers.
46
- * @example
47
- * Math.sum([1, 2, 3])
48
- * //-> 6
49
- ###
50
- Math.sum = (nums) -> nums.reduce Math.add
51
-
52
- ###*
53
- * @return {Number} product of two Numbers.
54
- * @example
55
- * Math.(2, 3)
56
- * //-> 6
57
- ###
58
- Math.mul = (a, b) -> a * b
59
-
60
- ###*
61
- * @return {Number} product of an Array of Numbers.
62
- * @example
63
- * Math.prod(2, 3, 4)
64
- * //-> 24
65
- ###
66
- Math.prod = (nums) -> nums.reduce Math.mul
67
-
68
- ###*
69
- * @return {Number} factorial of a Number.
70
- * @example
71
- * Math.factorial(4)
72
- * //-> 24
73
- * @test
74
- * Math.factorial(3)
75
- * //-> 6
76
- * Math.factorial(2)
77
- * //-> 2
78
- * Math.factorial(1)
79
- * //-> 1
80
- * Math.factorial(0)
81
- * //-> 1
82
- * Math.factorial(-1)
83
- * //-> Infinity
84
- ###
85
- Math.factorial = (n) ->
86
- if n < 0 then Infinity
87
- else if n == 0 then 1
88
- else Math.prod.apply null, [1..n]
89
-
90
- ###*
91
- * Greatest Common Multipler
92
- * @return {Number} greatest common multipler of two Numbers.
93
- * @example
94
- * Math.gcd(493, 289)
95
- * //-> 17
96
- * @test
97
- * Math.gcd(493, -289)
98
- * //-> 17
99
- ###
100
- Math.gcd = (a, b) -> [a, b] = [b, a % b] while b; a
101
-
102
- ###*
103
- * Least Common Multiplier
104
- * @return {Number} least common multiplier of two numbers.
105
- * @example
106
- * Math.lcm(4, 12)
107
- * //-> 12
108
- * @test
109
- * Math.lcm(6, 7)
110
- * //-> 42
111
- ###
112
- Math.lcm = (a, b) -> a / Math.gcd(a, b) * b