@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,131 @@
1
+ import { GameObject } from "../game/index.js";
2
+ import { Position } from "../util/position.js";
3
+
4
+ /**
5
+ * Applies anchor positioning to a game object
6
+ *
7
+ * @param {GameObject} go - The game object to anchor
8
+ * @param {Object} options - Anchor configuration options
9
+ * @param {string} [options.anchor] - Anchor position (use Position constants)
10
+ * @param {number} [options.anchorMargin=10] - Margin from the edge when anchoring
11
+ * @param {number} [options.anchorOffsetX=0] - Additional X offset to apply after anchoring
12
+ * @param {number} [options.anchorOffsetY=0] - Additional Y offset to apply after anchoring
13
+ * @param {GameObject|boolean} [options.anchorRelative=false] - Object to anchor relative to, or true to use parent
14
+ * @param {boolean} [options.anchorSetTextAlign=true] - Whether to set text alignment properties if available
15
+ * @returns {GameObject} The original game object for chaining
16
+ */
17
+ export function applyAnchor(go, options = {}) {
18
+ // Ensure we're only applying anchor to GameObjects
19
+ if (!go || !(go instanceof GameObject)) {
20
+ console.warn("applyAnchor can only be applied to GameObject instances");
21
+ return go;
22
+ }
23
+
24
+ // Store anchor properties in a separate namespace to avoid conflicts
25
+ go._anchor = {
26
+ position: options.anchor ?? null,
27
+ margin: options.anchorMargin ?? 10,
28
+ offsetX: options.anchorOffsetX ?? 0,
29
+ offsetY: options.anchorOffsetY ?? 0,
30
+ relative: options.anchorRelative ?? false,
31
+ setTextAlign: options.anchorSetTextAlign !== false,
32
+ lastUpdate: 0, // Track when we last updated positioning
33
+ };
34
+
35
+ // Keep a reference to the original update method
36
+ const originalUpdate = go.update?.bind(go);
37
+
38
+ // Override the update method
39
+ go.update = function (dt) {
40
+ //console.log("Anchor.update", go.name || go.constructor.name, go.boundsDirty);
41
+ // Skip anchor updates if bounds aren't dirty
42
+ const relativeObj =
43
+ go._anchor.relative === true && go.parent
44
+ ? go.parent
45
+ : go._anchor.relative;
46
+
47
+ // Only update positioning when bounds are dirty (geometry changed)
48
+ // or when related objects have changed
49
+ if (
50
+ go._anchor.position &&
51
+ (go.boundsDirty ||
52
+ (relativeObj && relativeObj.boundsDirty) ||
53
+ (go.parent && go.parent.boundsDirty))
54
+ ) {
55
+ // Calculate position
56
+ let position;
57
+
58
+ if (relativeObj) {
59
+ // Position relative to another object
60
+ const containerObj = {
61
+ x: relativeObj.x,
62
+ y: relativeObj.y,
63
+ width: relativeObj.width,
64
+ height: relativeObj.height,
65
+ };
66
+
67
+ position = Position.calculate(
68
+ go._anchor.position,
69
+ go,
70
+ containerObj,
71
+ go._anchor.margin,
72
+ go._anchor.offsetX,
73
+ go._anchor.offsetY
74
+ );
75
+ } else {
76
+ // Position absolute to the game canvas
77
+ position = Position.calculateAbsolute(
78
+ go._anchor.position,
79
+ go,
80
+ go.game,
81
+ go._anchor.margin,
82
+ go._anchor.offsetX,
83
+ go._anchor.offsetY
84
+ );
85
+ }
86
+ // Apply the calculated position
87
+ if (go.parent && !isPipelineRoot(go)) {
88
+ // If object has a parent AND is not directly in the pipeline
89
+ if (relativeObj === go.parent) {
90
+ // If anchored relative to parent, use local coordinates
91
+ // (parent position is already accounted for in rendering)
92
+ go.x = position.x - relativeObj.x;
93
+ go.y = position.y - relativeObj.y;
94
+ } else {
95
+ // If anchored to something else or absolutely, convert to local coordinates
96
+ go.x = position.x - go.parent.x;
97
+ go.y = position.y - go.parent.y;
98
+ }
99
+ } else {
100
+ // No parent or directly in pipeline - use absolute coordinates
101
+ go.x = position.x;
102
+ go.y = position.y;
103
+ }
104
+
105
+ // Set text alignment if applicable and enabled
106
+ if (go._anchor.setTextAlign) {
107
+ if ("align" in go) go.align = position.align;
108
+ if ("baseline" in go) go.baseline = position.baseline;
109
+ }
110
+
111
+ // Remember the time we last updated
112
+ go._anchor.lastUpdate = go.game ? go.game.lastTime : Date.now();
113
+ }
114
+
115
+ // Call the original update method
116
+ if (originalUpdate) originalUpdate(dt);
117
+ };
118
+
119
+ // Helper function to determine if an object is directly in the pipeline
120
+ function isPipelineRoot(gameObject) {
121
+ return (
122
+ gameObject.game &&
123
+ gameObject.game.pipeline &&
124
+ gameObject.game.pipeline.gameObjects &&
125
+ gameObject.game.pipeline.gameObjects.includes(gameObject)
126
+ );
127
+ }
128
+
129
+ // Return the object for chaining
130
+ return go;
131
+ }
@@ -0,0 +1,72 @@
1
+ export function applyDraggable(go, options = {}) {
2
+ const game = go.game;
3
+
4
+ // Clear any existing state to avoid duplicates
5
+ go.dragging = false;
6
+ go.dragOffset = { x: 0, y: 0 };
7
+
8
+ // Clean up any existing event handlers to prevent duplicates
9
+ if (go._dragInputMoveHandler) {
10
+ game.events.off("inputmove", go._dragInputMoveHandler);
11
+ }
12
+ if (go._dragInputUpHandler) {
13
+ game.events.off("inputup", go._dragInputUpHandler);
14
+ }
15
+
16
+ // Make sure the object is interactive
17
+ if (typeof go.enableInteractivity === 'function') {
18
+ go.enableInteractivity(go);
19
+ } else {
20
+ go.interactive = true;
21
+ }
22
+
23
+ // Define the input handlers and store them on the object to allow cleanup
24
+ go._dragInputDownHandler = (e) => {
25
+ // console.log("Drag input down", go.constructor.name);
26
+ go.dragging = true;
27
+
28
+ // Calculate offset from mouse position to object center
29
+ go.dragOffset.x = go.x - e.x;
30
+ go.dragOffset.y = go.y - e.y;
31
+
32
+ if (options.onDragStart) options.onDragStart();
33
+ };
34
+
35
+ go._dragInputMoveHandler = (e) => {
36
+ //console.log("Drag input move", go.constructor.name, "dragging:", go.dragging);
37
+ if (go.dragging) {
38
+ //console.log("Actually dragging", go.x, go.y, "to", e.x + go.dragOffset.x, e.y + go.dragOffset.y);
39
+ // Directly update position
40
+ go.x = e.x + go.dragOffset.x;
41
+ go.y = e.y + go.dragOffset.y;
42
+ }
43
+ };
44
+
45
+ go._dragInputUpHandler = (e) => {
46
+ //console.log("Drag input up", go.constructor.name, "dragging:", go.dragging);
47
+ if (!go.dragging) return;
48
+
49
+ go.dragging = false;
50
+ if (options.onDragEnd) options.onDragEnd();
51
+ };
52
+
53
+ // Bind the event handlers
54
+ go.on("inputdown", go._dragInputDownHandler);
55
+ game.events.on("inputmove", go._dragInputMoveHandler);
56
+ game.events.on("inputup", go._dragInputUpHandler);
57
+
58
+ // Return a cleanup function
59
+ return () => {
60
+ // Remove event listeners
61
+ go.off("inputdown", go._dragInputDownHandler);
62
+ game.events.off("inputmove", go._dragInputMoveHandler);
63
+ game.events.off("inputup", go._dragInputUpHandler);
64
+
65
+ // Clean up properties
66
+ delete go._dragInputDownHandler;
67
+ delete go._dragInputMoveHandler;
68
+ delete go._dragInputUpHandler;
69
+ delete go.dragging;
70
+ delete go.dragOffset;
71
+ };
72
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./draggable.js";
2
+ export * from "./anchor.js";
@@ -0,0 +1,132 @@
1
+ import { Motion } from "./motion";
2
+
3
+ /**
4
+ * Bezier curve motion animation with yoyo support
5
+ *
6
+ * @param {Array<number>} p0 - Start point [x, y]
7
+ * @param {Array<number>} p1 - Control point 1 [x, y]
8
+ * @param {Array<number>} p2 - Control point 2 [x, y]
9
+ * @param {Array<number>} p3 - End point [x, y]
10
+ * @param {number} elapsedTime - Total elapsed time in seconds
11
+ * @param {number} duration - Duration of animation in seconds
12
+ * @param {boolean} [loop=false] - Whether animation should loop
13
+ * @param {boolean} [yoyo=false] - Whether animation should return to start
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
17
+ * @returns {Object} Animation result with x, y coordinates and metadata
18
+ */
19
+ export function bezierV1(
20
+ p0,
21
+ p1,
22
+ p2,
23
+ p3,
24
+ elapsedTime,
25
+ duration,
26
+ loop = false,
27
+ yoyo = false,
28
+ easingFn = null,
29
+ callbacks = {},
30
+ state = null
31
+ ) {
32
+ // Early return for zero duration
33
+ if (duration <= 0) {
34
+ return Motion.animationResult(
35
+ { x: p3[0], y: p3[1], phase: "complete" },
36
+ 1,
37
+ false,
38
+ true
39
+ );
40
+ }
41
+
42
+ // Normalize time (0-1) within current cycle
43
+ let t = elapsedTime / duration;
44
+ let yoyoPhase = "forward";
45
+ let loopCount = 0;
46
+
47
+ // Handle looping vs. non-looping
48
+ if (loop) {
49
+ // Calculate loop count (for callbacks)
50
+ loopCount = Math.floor(t);
51
+
52
+ // Use only the fractional part for looping (0-1 repeating)
53
+ t = t % 1;
54
+
55
+ // Call onLoop callback if provided and we crossed a loop boundary
56
+ if (loopCount > 0 && callbacks.onLoop) {
57
+ callbacks.onLoop(loopCount);
58
+ }
59
+ } else {
60
+ // Clamp to 1 for non-looping animations
61
+ if (t > 1) t = 1;
62
+ }
63
+
64
+ // Call onStart callback if needed (only when animation begins)
65
+ if (t > 0 && elapsedTime <= duration && callbacks.onStart) {
66
+ callbacks.onStart();
67
+ }
68
+
69
+ // Apply easing if provided
70
+ const easedT = easingFn ? easingFn(t) : t;
71
+
72
+ // Adjust time value for yoyo behavior
73
+ let adjustedT = easedT;
74
+
75
+ if (yoyo) {
76
+ // If in the second half of the animation, we're going back
77
+ if (t >= 0.5) {
78
+ // Rescale t to 0-1 for the second half, but reversed
79
+ adjustedT = 1 - (t - 0.5) * 2;
80
+ yoyoPhase = "return";
81
+
82
+ // Call onYoyoTurn callback at the turning point
83
+ if (t >= 0.5 && t < 0.51 && callbacks.onYoyoTurn) {
84
+ callbacks.onYoyoTurn();
85
+ }
86
+ } else {
87
+ // First half of animation
88
+ adjustedT = t * 2;
89
+ yoyoPhase = "forward";
90
+ }
91
+
92
+ // Apply easing to the adjusted time if needed
93
+ adjustedT = easingFn ? easingFn(adjustedT) : adjustedT;
94
+ }
95
+
96
+ // Cubic Bezier formula
97
+ const cx = 3 * (p1[0] - p0[0]);
98
+ const bx = 3 * (p2[0] - p1[0]) - cx;
99
+ const ax = p3[0] - p0[0] - cx - bx;
100
+
101
+ const cy = 3 * (p1[1] - p0[1]);
102
+ const by = 3 * (p2[1] - p1[1]) - cy;
103
+ const ay = p3[1] - p0[1] - cy - by;
104
+
105
+ const x =
106
+ ax * Math.pow(adjustedT, 3) +
107
+ bx * Math.pow(adjustedT, 2) +
108
+ cx * adjustedT +
109
+ p0[0];
110
+ const y =
111
+ ay * Math.pow(adjustedT, 3) +
112
+ by * Math.pow(adjustedT, 2) +
113
+ cy * adjustedT +
114
+ p0[1];
115
+
116
+ // Check if non-looping animation is complete
117
+ const isDone = !loop && t >= 1;
118
+
119
+ // Call onComplete if animation has completed
120
+ if (isDone && callbacks.onComplete) {
121
+ callbacks.onComplete();
122
+ }
123
+
124
+ // Return standardized result with phase information
125
+ return Motion.animationResult(
126
+ { x, y, phase: yoyoPhase },
127
+ t,
128
+ loop,
129
+ isDone,
130
+ state
131
+ );
132
+ }
@@ -0,0 +1,58 @@
1
+ import { Motion } from "./motion";
2
+
3
+ /**
4
+ * Bounce animation - object drops and bounces with diminishing height
5
+ *
6
+ * @param {number} maxHeight - Maximum height (negative y value)
7
+ * @param {number} groundY - Ground position (positive y value)
8
+ * @param {number} bounceCount - Number of bounces to perform
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 y position and metadata
16
+ */
17
+ export function bounceV1(
18
+ maxHeight,
19
+ groundY,
20
+ bounceCount,
21
+ elapsedTime,
22
+ duration,
23
+ loop = false,
24
+ easingFn = null,
25
+ callbacks = {},
26
+ state = null
27
+ ) {
28
+ // Update animation time and apply easing
29
+ const {
30
+ t,
31
+ easedT,
32
+ completed,
33
+ state: newState,
34
+ } = Motion._frame(elapsedTime, duration, loop, easingFn, callbacks, state);
35
+
36
+ // Divide the animation into segments based on bounce count
37
+ const segmentSize = 1 / (bounceCount + 1);
38
+ const segment = Math.min(Math.floor(easedT / segmentSize), bounceCount);
39
+ const segmentT = (easedT % segmentSize) / segmentSize;
40
+
41
+ // Calculate bounce height for this segment
42
+ const bounceHeight = maxHeight * Math.pow(0.6, segment);
43
+
44
+ // Use a simple sine wave for each bounce
45
+ // Sin goes from 0 to 1 to 0, we want -maxHeight to groundY to -maxHeight
46
+ // Transform the sin function to get bounce effect
47
+ const normalized = Math.sin(segmentT * Math.PI);
48
+ const y = groundY - normalized * (groundY - bounceHeight);
49
+
50
+ // Return standardized result
51
+ return Motion.animationResult(
52
+ { y, segment, bounceHeight },
53
+ t,
54
+ loop,
55
+ completed,
56
+ newState
57
+ );
58
+ }