@guinetik/gcanvas 1.0.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 (349) hide show
  1. package/.github/workflows/release.yaml +70 -0
  2. package/.jshintrc +4 -0
  3. package/.vscode/settings.json +22 -0
  4. package/CLAUDE.md +310 -0
  5. package/blackhole.jpg +0 -0
  6. package/demo.png +0 -0
  7. package/demos/CNAME +1 -0
  8. package/demos/animations.html +31 -0
  9. package/demos/basic.html +38 -0
  10. package/demos/baskara.html +31 -0
  11. package/demos/bezier.html +35 -0
  12. package/demos/beziersignature.html +29 -0
  13. package/demos/blackhole.html +28 -0
  14. package/demos/blob.html +35 -0
  15. package/demos/demos.css +289 -0
  16. package/demos/easing.html +28 -0
  17. package/demos/events.html +195 -0
  18. package/demos/fluent.html +647 -0
  19. package/demos/fractals.html +36 -0
  20. package/demos/genart.html +26 -0
  21. package/demos/gendream.html +26 -0
  22. package/demos/group.html +36 -0
  23. package/demos/home.html +587 -0
  24. package/demos/index.html +364 -0
  25. package/demos/isometric.html +34 -0
  26. package/demos/js/animations.js +452 -0
  27. package/demos/js/basic.js +204 -0
  28. package/demos/js/baskara.js +751 -0
  29. package/demos/js/bezier.js +692 -0
  30. package/demos/js/beziersignature.js +241 -0
  31. package/demos/js/blackhole/accretiondisk.obj.js +379 -0
  32. package/demos/js/blackhole/blackhole.obj.js +318 -0
  33. package/demos/js/blackhole/index.js +409 -0
  34. package/demos/js/blackhole/particle.js +56 -0
  35. package/demos/js/blackhole/starfield.obj.js +218 -0
  36. package/demos/js/blob.js +2263 -0
  37. package/demos/js/easing.js +477 -0
  38. package/demos/js/fluent.js +183 -0
  39. package/demos/js/fractals.js +931 -0
  40. package/demos/js/fractalworker.js +93 -0
  41. package/demos/js/genart.js +268 -0
  42. package/demos/js/gendream.js +209 -0
  43. package/demos/js/group.js +140 -0
  44. package/demos/js/info-toggle.js +25 -0
  45. package/demos/js/isometric.js +863 -0
  46. package/demos/js/kerr.js +1556 -0
  47. package/demos/js/lavalamp.js +590 -0
  48. package/demos/js/layout.js +354 -0
  49. package/demos/js/mondrian.js +285 -0
  50. package/demos/js/opacity.js +275 -0
  51. package/demos/js/painter.js +484 -0
  52. package/demos/js/particles-showcase.js +514 -0
  53. package/demos/js/particles.js +299 -0
  54. package/demos/js/patterns.js +397 -0
  55. package/demos/js/penrose/artifact.js +69 -0
  56. package/demos/js/penrose/blackhole.js +121 -0
  57. package/demos/js/penrose/constants.js +73 -0
  58. package/demos/js/penrose/game.js +943 -0
  59. package/demos/js/penrose/lore.js +278 -0
  60. package/demos/js/penrose/penrosescene.js +892 -0
  61. package/demos/js/penrose/ship.js +216 -0
  62. package/demos/js/penrose/sounds.js +211 -0
  63. package/demos/js/penrose/voidparticle.js +55 -0
  64. package/demos/js/penrose/voidscene.js +258 -0
  65. package/demos/js/penrose/voidship.js +144 -0
  66. package/demos/js/penrose/wormhole.js +46 -0
  67. package/demos/js/pipeline.js +555 -0
  68. package/demos/js/scene.js +304 -0
  69. package/demos/js/scenes.js +320 -0
  70. package/demos/js/schrodinger.js +410 -0
  71. package/demos/js/schwarzschild.js +1023 -0
  72. package/demos/js/shapes.js +628 -0
  73. package/demos/js/space/alien.js +171 -0
  74. package/demos/js/space/boom.js +98 -0
  75. package/demos/js/space/boss.js +353 -0
  76. package/demos/js/space/buff.js +73 -0
  77. package/demos/js/space/bullet.js +102 -0
  78. package/demos/js/space/constants.js +85 -0
  79. package/demos/js/space/game.js +1884 -0
  80. package/demos/js/space/hud.js +112 -0
  81. package/demos/js/space/laserbeam.js +179 -0
  82. package/demos/js/space/lightning.js +277 -0
  83. package/demos/js/space/minion.js +192 -0
  84. package/demos/js/space/missile.js +212 -0
  85. package/demos/js/space/player.js +430 -0
  86. package/demos/js/space/powerup.js +90 -0
  87. package/demos/js/space/starfield.js +58 -0
  88. package/demos/js/space/starpower.js +90 -0
  89. package/demos/js/spacetime.js +559 -0
  90. package/demos/js/svgtween.js +204 -0
  91. package/demos/js/tde/accretiondisk.js +418 -0
  92. package/demos/js/tde/blackhole.js +219 -0
  93. package/demos/js/tde/blackholescene.js +209 -0
  94. package/demos/js/tde/config.js +59 -0
  95. package/demos/js/tde/index.js +695 -0
  96. package/demos/js/tde/jets.js +290 -0
  97. package/demos/js/tde/lensedstarfield.js +147 -0
  98. package/demos/js/tde/tdestar.js +317 -0
  99. package/demos/js/tde/tidalstream.js +356 -0
  100. package/demos/js/tde_old/blackhole.obj.js +354 -0
  101. package/demos/js/tde_old/debris.obj.js +791 -0
  102. package/demos/js/tde_old/flare.obj.js +239 -0
  103. package/demos/js/tde_old/index.js +448 -0
  104. package/demos/js/tde_old/star.obj.js +812 -0
  105. package/demos/js/tiles.js +312 -0
  106. package/demos/js/tweendemo.js +79 -0
  107. package/demos/js/visibility.js +102 -0
  108. package/demos/kerr.html +28 -0
  109. package/demos/lavalamp.html +27 -0
  110. package/demos/layouts.html +37 -0
  111. package/demos/logo.svg +4 -0
  112. package/demos/loop.html +84 -0
  113. package/demos/mondrian.html +32 -0
  114. package/demos/og_image.png +0 -0
  115. package/demos/opacity.html +36 -0
  116. package/demos/painter.html +39 -0
  117. package/demos/particles-showcase.html +28 -0
  118. package/demos/particles.html +24 -0
  119. package/demos/patterns.html +33 -0
  120. package/demos/penrose-game.html +31 -0
  121. package/demos/pipeline.html +737 -0
  122. package/demos/scene.html +33 -0
  123. package/demos/scenes.html +96 -0
  124. package/demos/schrodinger.html +27 -0
  125. package/demos/schwarzschild.html +27 -0
  126. package/demos/shapes.html +16 -0
  127. package/demos/space.html +85 -0
  128. package/demos/spacetime.html +27 -0
  129. package/demos/svgtween.html +29 -0
  130. package/demos/tde.html +28 -0
  131. package/demos/tiles.html +28 -0
  132. package/demos/transforms.html +400 -0
  133. package/demos/tween.html +45 -0
  134. package/demos/visibility.html +33 -0
  135. package/disk_example.png +0 -0
  136. package/docs/README.md +222 -0
  137. package/docs/concepts/architecture-overview.md +204 -0
  138. package/docs/concepts/lifecycle.md +255 -0
  139. package/docs/concepts/rendering-pipeline.md +279 -0
  140. package/docs/concepts/tde-zorder.md +106 -0
  141. package/docs/concepts/two-layer-architecture.md +229 -0
  142. package/docs/getting-started/first-game.md +354 -0
  143. package/docs/getting-started/hello-world.md +269 -0
  144. package/docs/getting-started/installation.md +157 -0
  145. package/docs/modules/collision/README.md +453 -0
  146. package/docs/modules/fluent/README.md +1075 -0
  147. package/docs/modules/game/README.md +303 -0
  148. package/docs/modules/isometric-camera.md +210 -0
  149. package/docs/modules/isometric.md +275 -0
  150. package/docs/modules/painter/README.md +328 -0
  151. package/docs/modules/particle/README.md +559 -0
  152. package/docs/modules/shapes/README.md +221 -0
  153. package/docs/modules/shapes/base/euclidian.md +123 -0
  154. package/docs/modules/shapes/base/geometry2d.md +204 -0
  155. package/docs/modules/shapes/base/renderable.md +215 -0
  156. package/docs/modules/shapes/base/shape.md +262 -0
  157. package/docs/modules/shapes/base/transformable.md +243 -0
  158. package/docs/modules/shapes/hierarchy.md +218 -0
  159. package/docs/modules/state/README.md +577 -0
  160. package/docs/modules/util/README.md +99 -0
  161. package/docs/modules/util/camera3d.md +412 -0
  162. package/docs/modules/util/scene3d.md +395 -0
  163. package/index.html +17 -0
  164. package/jsdoc.json +50 -0
  165. package/package.json +55 -0
  166. package/readme.md +599 -0
  167. package/scripts/build-demo.js +69 -0
  168. package/scripts/bundle4llm.js +276 -0
  169. package/scripts/clearconsole.js +48 -0
  170. package/src/collision/collision-system.js +332 -0
  171. package/src/collision/collision.js +303 -0
  172. package/src/collision/index.js +10 -0
  173. package/src/fluent/fluent-game.js +430 -0
  174. package/src/fluent/fluent-go.js +1060 -0
  175. package/src/fluent/fluent-layer.js +152 -0
  176. package/src/fluent/fluent-scene.js +291 -0
  177. package/src/fluent/index.js +98 -0
  178. package/src/fluent/sketch.js +380 -0
  179. package/src/game/game.js +467 -0
  180. package/src/game/index.js +49 -0
  181. package/src/game/objects/go.js +220 -0
  182. package/src/game/objects/imagego.js +30 -0
  183. package/src/game/objects/index.js +54 -0
  184. package/src/game/objects/isometric-scene.js +260 -0
  185. package/src/game/objects/layoutscene.js +549 -0
  186. package/src/game/objects/scene.js +175 -0
  187. package/src/game/objects/scene3d.js +118 -0
  188. package/src/game/objects/text.js +221 -0
  189. package/src/game/objects/wrapper.js +232 -0
  190. package/src/game/pipeline.js +243 -0
  191. package/src/game/ui/button.js +396 -0
  192. package/src/game/ui/cursor.js +93 -0
  193. package/src/game/ui/fps.js +91 -0
  194. package/src/game/ui/index.js +5 -0
  195. package/src/game/ui/togglebutton.js +93 -0
  196. package/src/game/ui/tooltip.js +249 -0
  197. package/src/index.js +25 -0
  198. package/src/io/events.js +20 -0
  199. package/src/io/index.js +86 -0
  200. package/src/io/input.js +70 -0
  201. package/src/io/keys.js +152 -0
  202. package/src/io/mouse.js +61 -0
  203. package/src/io/touch.js +39 -0
  204. package/src/logger/debugtab.js +138 -0
  205. package/src/logger/index.js +3 -0
  206. package/src/logger/loggable.js +47 -0
  207. package/src/logger/logger.js +113 -0
  208. package/src/math/complex.js +37 -0
  209. package/src/math/constants.js +1 -0
  210. package/src/math/fractal.js +1271 -0
  211. package/src/math/gr.js +201 -0
  212. package/src/math/heat.js +202 -0
  213. package/src/math/index.js +12 -0
  214. package/src/math/noise.js +433 -0
  215. package/src/math/orbital.js +191 -0
  216. package/src/math/patterns.js +1339 -0
  217. package/src/math/penrose.js +259 -0
  218. package/src/math/quantum.js +115 -0
  219. package/src/math/random.js +195 -0
  220. package/src/math/tensor.js +1009 -0
  221. package/src/mixins/anchor.js +131 -0
  222. package/src/mixins/draggable.js +72 -0
  223. package/src/mixins/index.js +2 -0
  224. package/src/motion/bezier.js +132 -0
  225. package/src/motion/bounce.js +58 -0
  226. package/src/motion/easing.js +349 -0
  227. package/src/motion/float.js +130 -0
  228. package/src/motion/follow.js +125 -0
  229. package/src/motion/hop.js +52 -0
  230. package/src/motion/index.js +82 -0
  231. package/src/motion/motion.js +1124 -0
  232. package/src/motion/orbit.js +49 -0
  233. package/src/motion/oscillate.js +39 -0
  234. package/src/motion/parabolic.js +141 -0
  235. package/src/motion/patrol.js +147 -0
  236. package/src/motion/pendulum.js +48 -0
  237. package/src/motion/pulse.js +88 -0
  238. package/src/motion/shake.js +83 -0
  239. package/src/motion/spiral.js +144 -0
  240. package/src/motion/spring.js +150 -0
  241. package/src/motion/swing.js +47 -0
  242. package/src/motion/tween.js +92 -0
  243. package/src/motion/tweenetik.js +139 -0
  244. package/src/motion/waypoint.js +210 -0
  245. package/src/painter/index.js +8 -0
  246. package/src/painter/painter.colors.js +331 -0
  247. package/src/painter/painter.effects.js +230 -0
  248. package/src/painter/painter.img.js +229 -0
  249. package/src/painter/painter.js +295 -0
  250. package/src/painter/painter.lines.js +189 -0
  251. package/src/painter/painter.opacity.js +41 -0
  252. package/src/painter/painter.shapes.js +277 -0
  253. package/src/painter/painter.text.js +273 -0
  254. package/src/particle/emitter.js +124 -0
  255. package/src/particle/index.js +11 -0
  256. package/src/particle/particle-system.js +322 -0
  257. package/src/particle/particle.js +71 -0
  258. package/src/particle/updaters.js +170 -0
  259. package/src/shapes/arc.js +43 -0
  260. package/src/shapes/arrow.js +33 -0
  261. package/src/shapes/bezier.js +42 -0
  262. package/src/shapes/circle.js +62 -0
  263. package/src/shapes/clouds.js +56 -0
  264. package/src/shapes/cone.js +219 -0
  265. package/src/shapes/cross.js +70 -0
  266. package/src/shapes/cube.js +244 -0
  267. package/src/shapes/cylinder.js +254 -0
  268. package/src/shapes/diamond.js +48 -0
  269. package/src/shapes/euclidian.js +111 -0
  270. package/src/shapes/figure.js +115 -0
  271. package/src/shapes/geometry.js +220 -0
  272. package/src/shapes/group.js +375 -0
  273. package/src/shapes/heart.js +42 -0
  274. package/src/shapes/hexagon.js +26 -0
  275. package/src/shapes/image.js +192 -0
  276. package/src/shapes/index.js +111 -0
  277. package/src/shapes/line.js +29 -0
  278. package/src/shapes/pattern.js +90 -0
  279. package/src/shapes/pin.js +44 -0
  280. package/src/shapes/poly.js +31 -0
  281. package/src/shapes/prism.js +226 -0
  282. package/src/shapes/rect.js +35 -0
  283. package/src/shapes/renderable.js +333 -0
  284. package/src/shapes/ring.js +26 -0
  285. package/src/shapes/roundrect.js +95 -0
  286. package/src/shapes/shape.js +117 -0
  287. package/src/shapes/slice.js +26 -0
  288. package/src/shapes/sphere.js +314 -0
  289. package/src/shapes/sphere3d.js +537 -0
  290. package/src/shapes/square.js +15 -0
  291. package/src/shapes/star.js +99 -0
  292. package/src/shapes/svg.js +408 -0
  293. package/src/shapes/text.js +553 -0
  294. package/src/shapes/traceable.js +83 -0
  295. package/src/shapes/transform.js +357 -0
  296. package/src/shapes/transformable.js +172 -0
  297. package/src/shapes/triangle.js +26 -0
  298. package/src/sound/index.js +17 -0
  299. package/src/sound/sound.js +473 -0
  300. package/src/sound/synth.analyzer.js +149 -0
  301. package/src/sound/synth.effects.js +207 -0
  302. package/src/sound/synth.envelope.js +59 -0
  303. package/src/sound/synth.js +229 -0
  304. package/src/sound/synth.musical.js +160 -0
  305. package/src/sound/synth.noise.js +85 -0
  306. package/src/sound/synth.oscillators.js +293 -0
  307. package/src/state/index.js +10 -0
  308. package/src/state/state-machine.js +371 -0
  309. package/src/util/camera3d.js +438 -0
  310. package/src/util/index.js +6 -0
  311. package/src/util/isometric-camera.js +235 -0
  312. package/src/util/layout.js +317 -0
  313. package/src/util/position.js +147 -0
  314. package/src/util/tasks.js +47 -0
  315. package/src/util/zindex.js +287 -0
  316. package/src/webgl/index.js +9 -0
  317. package/src/webgl/shaders/sphere-shaders.js +994 -0
  318. package/src/webgl/webgl-renderer.js +388 -0
  319. package/tde.png +0 -0
  320. package/test/math/orbital.test.js +61 -0
  321. package/test/math/tensor.test.js +114 -0
  322. package/test/particle/emitter.test.js +204 -0
  323. package/test/particle/particle-system.test.js +310 -0
  324. package/test/particle/particle.test.js +116 -0
  325. package/test/particle/updaters.test.js +386 -0
  326. package/test/setup.js +120 -0
  327. package/test/shapes/euclidian.test.js +44 -0
  328. package/test/shapes/geometry.test.js +86 -0
  329. package/test/shapes/group.test.js +86 -0
  330. package/test/shapes/rectangle.test.js +64 -0
  331. package/test/shapes/transform.test.js +379 -0
  332. package/test/util/camera3d.test.js +428 -0
  333. package/test/util/scene3d.test.js +352 -0
  334. package/types/collision.d.ts +249 -0
  335. package/types/common.d.ts +155 -0
  336. package/types/game.d.ts +497 -0
  337. package/types/index.d.ts +309 -0
  338. package/types/io.d.ts +188 -0
  339. package/types/logger.d.ts +127 -0
  340. package/types/math.d.ts +268 -0
  341. package/types/mixins.d.ts +92 -0
  342. package/types/motion.d.ts +678 -0
  343. package/types/painter.d.ts +378 -0
  344. package/types/shapes.d.ts +864 -0
  345. package/types/sound.d.ts +672 -0
  346. package/types/state.d.ts +251 -0
  347. package/types/util.d.ts +253 -0
  348. package/vite.config.js +50 -0
  349. package/vitest.config.js +13 -0
@@ -0,0 +1,349 @@
1
+ export class Easing {
2
+ // =========================================================================
3
+ // EASING FUNCTIONS
4
+ // =========================================================================
5
+
6
+ static lerp(a, b, t) {
7
+ return a + (b - a) * t;
8
+ }
9
+
10
+ /**
11
+ * Linear - no easing, straight line
12
+ * @param {number} t - Input (0-1)
13
+ * @returns {number} Same value as input
14
+ */
15
+ static linear(t) {
16
+ return t;
17
+ }
18
+
19
+ /**
20
+ * Smoothstep - classic shader S-curve interpolation
21
+ * Smooth start and end with zero first derivative at endpoints
22
+ * @param {number} t - Input (0-1)
23
+ * @returns {number} Eased value
24
+ */
25
+ static smoothstep(t) {
26
+ return t * t * (3 - 2 * t);
27
+ }
28
+
29
+ /**
30
+ * Smootherstep - Ken Perlin's improved smoothstep
31
+ * Even smoother with zero first AND second derivatives at endpoints
32
+ * @param {number} t - Input (0-1)
33
+ * @returns {number} Eased value
34
+ */
35
+ static smootherstep(t) {
36
+ return t * t * t * (t * (t * 6 - 15) + 10);
37
+ }
38
+
39
+ /**
40
+ * Quadratic ease-in
41
+ * @param {number} t - Input (0-1)
42
+ * @returns {number} Eased value
43
+ */
44
+ static easeInQuad(t) {
45
+ return t * t;
46
+ }
47
+
48
+ /**
49
+ * Quadratic ease-out
50
+ * @param {number} t - Input (0-1)
51
+ * @returns {number} Eased value
52
+ */
53
+ static easeOutQuad(t) {
54
+ return t * (2 - t);
55
+ }
56
+
57
+ /**
58
+ * Quadratic ease-in-out
59
+ * @param {number} t - Input (0-1)
60
+ * @returns {number} Eased value
61
+ */
62
+ static easeInOutQuad(t) {
63
+ return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
64
+ }
65
+
66
+ /**
67
+ * Cubic ease-in
68
+ * @param {number} t - Input (0-1)
69
+ * @returns {number} Eased value
70
+ */
71
+ static easeInCubic(t) {
72
+ return t * t * t;
73
+ }
74
+
75
+ /**
76
+ * Cubic ease-out
77
+ * @param {number} t - Input (0-1)
78
+ * @returns {number} Eased value
79
+ */
80
+ static easeOutCubic(t) {
81
+ return --t * t * t + 1;
82
+ }
83
+
84
+ /**
85
+ * Cubic ease-in-out
86
+ * @param {number} t - Input (0-1)
87
+ * @returns {number} Eased value
88
+ */
89
+ static easeInOutCubic(t) {
90
+ return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
91
+ }
92
+
93
+ /**
94
+ * Quartic ease-in
95
+ * @param {number} t - Input (0-1)
96
+ * @returns {number} Eased value
97
+ */
98
+ static easeInQuart(t) {
99
+ return t * t * t * t;
100
+ }
101
+
102
+ /**
103
+ * Quartic ease-out
104
+ * @param {number} t - Input (0-1)
105
+ * @returns {number} Eased value
106
+ */
107
+ static easeOutQuart(t) {
108
+ return 1 - --t * t * t * t;
109
+ }
110
+
111
+ /**
112
+ * Quartic ease-in-out
113
+ * @param {number} t - Input (0-1)
114
+ * @returns {number} Eased value
115
+ */
116
+ static easeInOutQuart(t) {
117
+ return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
118
+ }
119
+
120
+ /**
121
+ * Sine ease-in
122
+ * @param {number} t - Input (0-1)
123
+ * @returns {number} Eased value
124
+ */
125
+ static easeInSine(t) {
126
+ return 1 - Math.cos((t * Math.PI) / 2);
127
+ }
128
+
129
+ /**
130
+ * Sine ease-out
131
+ * @param {number} t - Input (0-1)
132
+ * @returns {number} Eased value
133
+ */
134
+ static easeOutSine(t) {
135
+ return Math.sin((t * Math.PI) / 2);
136
+ }
137
+
138
+ /**
139
+ * Sine ease-in-out
140
+ * @param {number} t - Input (0-1)
141
+ * @returns {number} Eased value
142
+ */
143
+ static easeInOutSine(t) {
144
+ return -(Math.cos(Math.PI * t) - 1) / 2;
145
+ }
146
+
147
+ /**
148
+ * Exponential ease-in
149
+ * @param {number} t - Input (0-1)
150
+ * @returns {number} Eased value
151
+ */
152
+ static easeInExpo(t) {
153
+ return t === 0 ? 0 : Math.pow(2, 10 * (t - 1));
154
+ }
155
+
156
+ /**
157
+ * Exponential ease-out
158
+ * @param {number} t - Input (0-1)
159
+ * @returns {number} Eased value
160
+ */
161
+ static easeOutExpo(t) {
162
+ return t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
163
+ }
164
+
165
+ /**
166
+ * Exponential ease-in-out
167
+ * @param {number} t - Input (0-1)
168
+ * @returns {number} Eased value
169
+ */
170
+ static easeInOutExpo(t) {
171
+ if (t === 0 || t === 1) return t;
172
+ if (t < 0.5) {
173
+ return 0.5 * Math.pow(2, 20 * t - 10);
174
+ } else {
175
+ return 0.5 * (2 - Math.pow(2, -20 * t + 10));
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Circular ease-in
181
+ * @param {number} t - Input (0-1)
182
+ * @returns {number} Eased value
183
+ */
184
+ static easeInCirc(t) {
185
+ return 1 - Math.sqrt(1 - t * t);
186
+ }
187
+
188
+ /**
189
+ * Circular ease-out
190
+ * @param {number} t - Input (0-1)
191
+ * @returns {number} Eased value
192
+ */
193
+ static easeOutCirc(t) {
194
+ return Math.sqrt(1 - --t * t);
195
+ }
196
+
197
+ /**
198
+ * Circular ease-in-out
199
+ * @param {number} t - Input (0-1)
200
+ * @returns {number} Eased value
201
+ */
202
+ static easeInOutCirc(t) {
203
+ return t < 0.5
204
+ ? 0.5 * (1 - Math.sqrt(1 - 4 * t * t))
205
+ : 0.5 * (Math.sqrt(-(2 * t - 3) * (2 * t - 1)) + 1);
206
+ }
207
+
208
+ /**
209
+ * Elastic ease-in
210
+ * @param {number} t - Input (0-1)
211
+ * @param {number} [amplitude=1] - Amplitude
212
+ * @param {number} [period=0.3] - Period
213
+ * @returns {number} Eased value
214
+ */
215
+ static easeInElastic(t, amplitude = 1, period = 0.3) {
216
+ if (t === 0 || t === 1) return t;
217
+
218
+ const s = (period / (2 * Math.PI)) * Math.asin(1 / amplitude);
219
+ return -(
220
+ amplitude *
221
+ Math.pow(2, 10 * (t - 1)) *
222
+ Math.sin(((t - 1 - s) * (2 * Math.PI)) / period)
223
+ );
224
+ }
225
+
226
+ /**
227
+ * Elastic ease-out
228
+ * @param {number} t - Input (0-1)
229
+ * @param {number} [amplitude=1] - Amplitude
230
+ * @param {number} [period=0.3] - Period
231
+ * @returns {number} Eased value
232
+ */
233
+ static easeOutElastic(t, amplitude = 1, period = 0.3) {
234
+ if (t === 0 || t === 1) return t;
235
+
236
+ const s = (period / (2 * Math.PI)) * Math.asin(1 / amplitude);
237
+ return (
238
+ amplitude *
239
+ Math.pow(2, -10 * t) *
240
+ Math.sin(((t - s) * (2 * Math.PI)) / period) +
241
+ 1
242
+ );
243
+ }
244
+
245
+ /**
246
+ * Elastic ease-in-out
247
+ * @param {number} t - Input (0-1)
248
+ * @param {number} [amplitude=1] - Amplitude
249
+ * @param {number} [period=0.3] - Period
250
+ * @returns {number} Eased value
251
+ */
252
+ static easeInOutElastic(t, amplitude = 1, period = 0.3) {
253
+ if (t === 0 || t === 1) return t;
254
+
255
+ const s = (period / (2 * Math.PI)) * Math.asin(1 / amplitude);
256
+
257
+ if (t < 0.5) {
258
+ return (
259
+ -0.5 *
260
+ (amplitude *
261
+ Math.pow(2, 10 * (2 * t - 1)) *
262
+ Math.sin(((2 * t - 1 - s) * (2 * Math.PI)) / period))
263
+ );
264
+ } else {
265
+ return (
266
+ amplitude *
267
+ Math.pow(2, -10 * (2 * t - 1)) *
268
+ Math.sin(((2 * t - 1 - s) * (2 * Math.PI)) / period) *
269
+ 0.5 +
270
+ 1
271
+ );
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Back ease-in
277
+ * @param {number} t - Input (0-1)
278
+ * @param {number} [overshoot=1.70158] - Overshoot amount
279
+ * @returns {number} Eased value
280
+ */
281
+ static easeInBack(t, overshoot = 1.70158) {
282
+ return t * t * ((overshoot + 1) * t - overshoot);
283
+ }
284
+
285
+ /**
286
+ * Back ease-out
287
+ * @param {number} t - Input (0-1)
288
+ * @param {number} [overshoot=1.70158] - Overshoot amount
289
+ * @returns {number} Eased value
290
+ */
291
+ static easeOutBack(t, overshoot = 1.70158) {
292
+ return --t * t * ((overshoot + 1) * t + overshoot) + 1;
293
+ }
294
+
295
+ /**
296
+ * Back ease-in-out
297
+ * @param {number} t - Input (0-1)
298
+ * @param {number} [overshoot=1.70158] - Overshoot amount
299
+ * @returns {number} Eased value
300
+ */
301
+ static easeInOutBack(t, overshoot = 1.70158) {
302
+ const s = overshoot * 1.525;
303
+
304
+ if (t < 0.5) {
305
+ return 0.5 * (2 * t) * (2 * t) * ((s + 1) * 2 * t - s);
306
+ } else {
307
+ return (
308
+ 0.5 * ((2 * t - 2) * (2 * t - 2) * ((s + 1) * (2 * t - 2) + s) + 2)
309
+ );
310
+ }
311
+ }
312
+
313
+ /**
314
+ * Bounce ease-out
315
+ * @param {number} t - Input (0-1)
316
+ * @returns {number} Eased value
317
+ */
318
+ static easeOutBounce(t) {
319
+ if (t < 1 / 2.75) {
320
+ return 7.5625 * t * t;
321
+ } else if (t < 2 / 2.75) {
322
+ return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
323
+ } else if (t < 2.5 / 2.75) {
324
+ return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
325
+ } else {
326
+ return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Bounce ease-in
332
+ * @param {number} t - Input (0-1)
333
+ * @returns {number} Eased value
334
+ */
335
+ static easeInBounce(t) {
336
+ return 1 - Easing.easeOutBounce(1 - t);
337
+ }
338
+
339
+ /**
340
+ * Bounce ease-in-out
341
+ * @param {number} t - Input (0-1)
342
+ * @returns {number} Eased value
343
+ */
344
+ static easeInOutBounce(t) {
345
+ return t < 0.5
346
+ ? Easing.easeInBounce(t * 2) * 0.5
347
+ : Easing.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
348
+ }
349
+ }
@@ -0,0 +1,130 @@
1
+ import { Motion } from "./motion";
2
+
3
+ /**
4
+ * Patrol animation - creates movement around an area with natural pausing
5
+ * Perfect for characters patrolling or objects drifting within bounds
6
+ *
7
+ * @param {Object} target - Object with x,y properties defining the center point
8
+ * @param {number} elapsedTime - Total elapsed time in seconds
9
+ * @param {number} duration - Duration of one full float cycle in seconds
10
+ * @param {number} speed - Movement speed multiplier (0.1-2.0 recommended)
11
+ * @param {number} randomness - How random/unpredictable the float path is (0-1)
12
+ * @param {number} radius - Radius of float area (object will move within -radius to +radius)
13
+ * @param {boolean} [loop=true] - Whether animation should loop
14
+ * @param {Function} [easingFn=null] - Optional easing function to apply
15
+ * @param {Object} [callbacks] - Optional callback functions
16
+ * @param {Object} [state] - Internal state tracking for callbacks and initial position
17
+ * @returns {Object} Animation result with x, y coordinates and metadata
18
+ */
19
+ export function floatV1(
20
+ target,
21
+ elapsedTime,
22
+ duration,
23
+ speed,
24
+ randomness,
25
+ radius,
26
+ loop = true,
27
+ easingFn = null,
28
+ callbacks = {},
29
+ state = null
30
+ ) {
31
+ // Early return for zero duration
32
+ if (duration <= 0) {
33
+ return Motion.animationResult(
34
+ { x: target.x, y: target.y, moving: false },
35
+ 1,
36
+ false,
37
+ true
38
+ );
39
+ }
40
+ // Initialize state if not provided, capturing initial position
41
+ if (!state) {
42
+ state = {
43
+ initialX: target.x,
44
+ initialY: target.y,
45
+ started: false,
46
+ completed: false,
47
+ loopCount: 0,
48
+ };
49
+ }
50
+ // Use initialX and initialY from state as the center point
51
+ const centerX = state.initialX;
52
+ const centerY = state.initialY;
53
+ // Update animation time and apply easing if needed
54
+ const {
55
+ t,
56
+ easedT,
57
+ completed,
58
+ state: timeState,
59
+ } = Motion._frame(elapsedTime, duration, loop, easingFn, callbacks, state);
60
+ // Update state with time tracking info
61
+ state = {
62
+ ...state,
63
+ ...timeState,
64
+ };
65
+ // Scale time by speed (higher speed = faster oscillations)
66
+ const scaledTime = elapsedTime * speed;
67
+ // Clamp randomness to valid range (0-1)
68
+ const clampedRandomness = Math.max(0, Math.min(1, randomness));
69
+ // Multi-layered sinusoidal movements with different frequencies
70
+ // to create patrol-like motion with natural pauses
71
+
72
+ // Primary motion (large, slow)
73
+ const baseFreqX = 0.7;
74
+ const baseFreqY = 0.9; // Slightly different to avoid perfect circles
75
+ // Secondary motion (direction changes)
76
+ const secondFreqX = 2.3;
77
+ const secondFreqY = 1.9;
78
+ // Calculate combined motion patterns
79
+ const dx =
80
+ Math.sin(scaledTime * baseFreqX) +
81
+ clampedRandomness * 0.4 * Math.sin(scaledTime * secondFreqX + 0.5);
82
+ const dy =
83
+ Math.cos(scaledTime * baseFreqY) +
84
+ clampedRandomness * 0.4 * Math.cos(scaledTime * secondFreqY + 0.7);
85
+ // Scale by radius - the multiplier is 0.5 because we want values to range from -radius to +radius
86
+ // This properly centers the patrol area around the initial position
87
+ const x = centerX + dx * radius;
88
+ const y = centerY + dy * radius;
89
+ //this.logger.log(x, y, centerX, centerY);
90
+ // Calculate if currently moving or paused
91
+ // Object "pauses" when velocity is low (near turning points of sine waves)
92
+ const dxdt =
93
+ baseFreqX * Math.cos(scaledTime * baseFreqX) +
94
+ clampedRandomness *
95
+ 0.4 *
96
+ secondFreqX *
97
+ Math.cos(scaledTime * secondFreqX + 0.5);
98
+ const dydt =
99
+ -baseFreqY * Math.sin(scaledTime * baseFreqY) +
100
+ clampedRandomness *
101
+ 0.4 *
102
+ -secondFreqY *
103
+ Math.sin(scaledTime * secondFreqY + 0.7);
104
+ // Calculate velocity magnitude
105
+ const velocity = Math.sqrt(dxdt * dxdt + dydt * dydt);
106
+ // Determine if moving or paused (using a threshold)
107
+ const isMoving = velocity > 0.8;
108
+ // Calculate distance from center
109
+ const distanceFromCenter = Math.sqrt(
110
+ (x - centerX) * (x - centerX) + (y - centerY) * (y - centerY)
111
+ );
112
+ // Return standardized result with patrol-specific metadata
113
+ return Motion.animationResult(
114
+ {
115
+ x,
116
+ y,
117
+ centerX,
118
+ centerY,
119
+ offsetX: x - centerX,
120
+ offsetY: y - centerY,
121
+ distance: distanceFromCenter,
122
+ moving: isMoving,
123
+ velocity: velocity,
124
+ },
125
+ t,
126
+ loop,
127
+ completed,
128
+ state
129
+ );
130
+ }
@@ -0,0 +1,125 @@
1
+ import { Motion } from "./motion";
2
+ import { Tween } from "./tween";
3
+
4
+ /**
5
+ * Follow path animation along a series of points
6
+ *
7
+ * @param {Array<Array<number>>} points - Array of points as [x, y] coordinates
8
+ * @param {boolean} [closed=false] - Whether path is closed (connects back to start)
9
+ * @param {number} elapsedTime - Total elapsed time in seconds
10
+ * @param {number} duration - Duration of animation in seconds
11
+ * @param {boolean} [loop=false] - Whether animation should loop
12
+ * @param {Function} [easingFn=null] - Optional easing function to apply
13
+ * @param {Object} [callbacks] - Optional callback functions
14
+ * @param {Object} [state] - Internal state tracking for callbacks
15
+ * @returns {Object} Animation result with x, y coordinates and metadata
16
+ */
17
+ export function followPath(
18
+ points,
19
+ closed = false,
20
+ elapsedTime,
21
+ duration,
22
+ loop = false,
23
+ easingFn = null,
24
+ callbacks = {},
25
+ state = null
26
+ ) {
27
+ // Need at least 2 points
28
+ if (!points || points.length < 2) {
29
+ return this._createResult({ x: 0, y: 0 }, 0, loop, false);
30
+ }
31
+ // Update animation time and apply easing
32
+ const {
33
+ t,
34
+ easedT,
35
+ completed,
36
+ state: newState,
37
+ } = Motion._frame(elapsedTime, duration, loop, easingFn, callbacks, state);
38
+
39
+ // Calculate total path length and segment lengths
40
+ if (!state || !state.pathData) {
41
+ const pathData = {
42
+ segmentLengths: [],
43
+ totalLength: 0,
44
+ points: [...points],
45
+ };
46
+
47
+ // Calculate length of each segment
48
+ for (let i = 0; i < points.length - 1; i++) {
49
+ const p1 = points[i];
50
+ const p2 = points[i + 1];
51
+ const dx = p2[0] - p1[0];
52
+ const dy = p2[1] - p1[1];
53
+ const length = Math.sqrt(dx * dx + dy * dy);
54
+
55
+ pathData.segmentLengths.push(length);
56
+ pathData.totalLength += length;
57
+ }
58
+
59
+ // If closed, add final segment back to start
60
+ if (closed) {
61
+ const p1 = points[points.length - 1];
62
+ const p2 = points[0];
63
+ const dx = p2[0] - p1[0];
64
+ const dy = p2[1] - p1[1];
65
+ const length = Math.sqrt(dx * dx + dy * dy);
66
+
67
+ pathData.segmentLengths.push(length);
68
+ pathData.totalLength += length;
69
+ }
70
+
71
+ newState.pathData = pathData;
72
+ }
73
+
74
+ // Get path data
75
+ const { segmentLengths, totalLength, points: pathPoints } = newState.pathData;
76
+
77
+ // Calculate distance along path
78
+ const targetDistance = easedT * totalLength;
79
+
80
+ // Find which segment we're on and the progress through it
81
+ let distanceTraveled = 0;
82
+ let segmentIndex = 0;
83
+
84
+ for (let i = 0; i < segmentLengths.length; i++) {
85
+ if (distanceTraveled + segmentLengths[i] >= targetDistance) {
86
+ segmentIndex = i;
87
+ break;
88
+ }
89
+ distanceTraveled += segmentLengths[i];
90
+ }
91
+
92
+ // Calculate progress through current segment
93
+ const segmentProgress =
94
+ (targetDistance - distanceTraveled) / segmentLengths[segmentIndex];
95
+
96
+ // Get points for current segment
97
+ const p1 = pathPoints[segmentIndex];
98
+ const p2 =
99
+ segmentIndex < pathPoints.length - 1
100
+ ? pathPoints[segmentIndex + 1]
101
+ : pathPoints[0]; // Wrap to start if closed
102
+
103
+ // Interpolate between points
104
+ const x = Tween.lerp(p1[0], p2[0], segmentProgress);
105
+ const y = Tween.lerp(p1[1], p2[1], segmentProgress);
106
+
107
+ // Calculate angle of current segment (for rotation if needed)
108
+ const angle = Math.atan2(p2[1] - p1[1], p2[0] - p1[0]);
109
+
110
+ // Return standardized result
111
+ return Motion.animationResult(
112
+ {
113
+ x,
114
+ y,
115
+ angle,
116
+ segmentIndex,
117
+ segmentProgress,
118
+ pathProgress: easedT,
119
+ },
120
+ t,
121
+ loop,
122
+ completed,
123
+ newState
124
+ );
125
+ }
@@ -0,0 +1,52 @@
1
+ import { Motion } from "./motion";
2
+
3
+ /**
4
+ * Hop animation - makes the object jump up and down rhythmically
5
+ *
6
+ * @param {number} baseY - The ground/base Y position
7
+ * @param {number} hopHeight - Maximum height (negative Y offset)
8
+ * @param {number} elapsedTime - Elapsed time in seconds
9
+ * @param {number} duration - Duration of one hop (up and down)
10
+ * @param {boolean} [loop=true] - Whether the hop repeats
11
+ * @param {boolean} [yoyo=true] - Whether the hop repeats
12
+ * @param {Function} [easingFn=null] - Optional easing for jump arc
13
+ * @param {Object} [callbacks={}] - Optional callback functions
14
+ * @param {Object} [state=null] - Internal state
15
+ * @returns {Object} Animation result with y position
16
+ */
17
+ export function hopV1(
18
+ baseY,
19
+ hopHeight,
20
+ elapsedTime,
21
+ duration,
22
+ loop = true,
23
+ yoyo = true,
24
+ easingFn = null,
25
+ callbacks = {},
26
+ state = null
27
+ ) {
28
+ const {
29
+ t,
30
+ easedT,
31
+ completed,
32
+ state: newState,
33
+ } = Motion._frame(elapsedTime, duration, loop, easingFn, callbacks, state, yoyo);
34
+
35
+ let arc = 0;
36
+
37
+ if (!loop && !yoyo) {
38
+ // One-shot up only: freeze at peak when done
39
+ arc = completed ? 1 : Math.sin(Math.min(t, 1) * Math.PI * 0.5); // sin(π/2 * t) = 0 → 1
40
+ } else if (yoyo) {
41
+ // Full up/down cycle using easedT (symmetric)
42
+ arc = Math.sin(easedT * Math.PI); // 0 → 1 → 0
43
+ } else {
44
+ // Looping up-only arc (snap to origin after)
45
+ arc = Math.sin(Math.min(t, 1) * Math.PI * 0.5); // sin(π/2 * t)
46
+ }
47
+
48
+ const y = baseY - hopHeight * arc;
49
+
50
+ return Motion.animationResult({ y }, t, loop, completed, newState);
51
+ }
52
+