@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
package/src/math/gr.js ADDED
@@ -0,0 +1,201 @@
1
+ /**
2
+ * General Relativity utilities for spacetime visualization.
3
+ * Complements the Tensor class with higher-level embedding and coordinate functions.
4
+ *
5
+ * @example
6
+ * import { flammEmbedding, flammEmbeddingHeight } from './gr.js';
7
+ *
8
+ * // Raw Flamm's paraboloid height
9
+ * const z = flammEmbedding(10, 2, 1); // r=10, rs=2, M=1
10
+ *
11
+ * // Inverted for visualization (well goes "down")
12
+ * const height = flammEmbeddingHeight(10, 2, 1, 20, 25);
13
+ */
14
+
15
+ // ─────────────────────────────────────────────────────────────────────────────
16
+ // EMBEDDING FUNCTIONS
17
+ // ─────────────────────────────────────────────────────────────────────────────
18
+
19
+ /**
20
+ * Flamm's paraboloid embedding for Schwarzschild/Kerr spacetime.
21
+ *
22
+ * The formula z = sqrt(8M(r - r_horizon)) gives the proper embedding
23
+ * of the spatial geometry into 3D Euclidean space.
24
+ *
25
+ * @param {number} r - Radial coordinate
26
+ * @param {number} rHorizon - Event horizon radius (rs for Schwarzschild, r+ for Kerr)
27
+ * @param {number} M - Mass parameter (in geometrized units G=c=1)
28
+ * @returns {number} Embedding height z (positive)
29
+ */
30
+ export function flammEmbedding(r, rHorizon, M) {
31
+ if (r <= rHorizon) return 0;
32
+ return Math.sqrt(8 * M * (r - rHorizon));
33
+ }
34
+
35
+ /**
36
+ * Inverted embedding height for visualization.
37
+ *
38
+ * Returns a height value where:
39
+ * - Far from the black hole: height approaches 0 (flat)
40
+ * - Near the horizon: height increases (deep well)
41
+ *
42
+ * This is what you typically want for rendering the "gravity well" visualization.
43
+ *
44
+ * @param {number} r - Radial coordinate
45
+ * @param {number} rHorizon - Event horizon radius
46
+ * @param {number} M - Mass parameter
47
+ * @param {number} rMax - Maximum radius for normalization (typically grid size)
48
+ * @param {number} scale - Visual scale factor for the well depth
49
+ * @returns {number} Height value for rendering (larger = deeper in well)
50
+ */
51
+ export function flammEmbeddingHeight(r, rHorizon, M, rMax, scale) {
52
+ // Clamp to just outside horizon
53
+ const rClamped = Math.max(r, rHorizon + 0.01);
54
+
55
+ // Flamm's paraboloid: z = sqrt(8M(r - r_horizon))
56
+ const z = flammEmbedding(rClamped, rHorizon, M);
57
+ const zMax = flammEmbedding(rMax, rHorizon, M);
58
+
59
+ // Invert so well goes "down", normalize by zMax
60
+ // This gives proper curvature behavior: steep near horizon, flat far away
61
+ return ((zMax - z) * scale) / zMax;
62
+ }
63
+
64
+ // ─────────────────────────────────────────────────────────────────────────────
65
+ // COORDINATE TRANSFORMATIONS
66
+ // ─────────────────────────────────────────────────────────────────────────────
67
+
68
+ /**
69
+ * Convert Cartesian coordinates to spherical coordinates.
70
+ *
71
+ * @param {number} x - Cartesian x
72
+ * @param {number} y - Cartesian y
73
+ * @param {number} z - Cartesian z
74
+ * @returns {{ r: number, theta: number, phi: number }} Spherical coordinates
75
+ */
76
+ export function cartesianToSpherical(x, y, z) {
77
+ const r = Math.sqrt(x * x + y * y + z * z);
78
+ const theta = r > 0 ? Math.acos(z / r) : 0;
79
+ const phi = Math.atan2(y, x);
80
+ return { r, theta, phi };
81
+ }
82
+
83
+ /**
84
+ * Convert spherical coordinates to Cartesian coordinates.
85
+ *
86
+ * @param {number} r - Radial distance
87
+ * @param {number} theta - Polar angle (0 to π)
88
+ * @param {number} phi - Azimuthal angle (0 to 2π)
89
+ * @returns {{ x: number, y: number, z: number }} Cartesian coordinates
90
+ */
91
+ export function sphericalToCartesian(r, theta, phi) {
92
+ const sinTheta = Math.sin(theta);
93
+ return {
94
+ x: r * sinTheta * Math.cos(phi),
95
+ y: r * sinTheta * Math.sin(phi),
96
+ z: r * Math.cos(theta),
97
+ };
98
+ }
99
+
100
+ /**
101
+ * Convert polar coordinates (r, phi) to Cartesian (x, z) in the equatorial plane.
102
+ * Commonly used for orbital visualization where y is the "height" axis.
103
+ *
104
+ * @param {number} r - Radial distance
105
+ * @param {number} phi - Azimuthal angle
106
+ * @returns {{ x: number, z: number }} Cartesian coordinates in equatorial plane
107
+ */
108
+ export function polarToCartesian(r, phi) {
109
+ return {
110
+ x: r * Math.cos(phi),
111
+ z: r * Math.sin(phi),
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Convert Cartesian (x, z) to polar (r, phi) in the equatorial plane.
117
+ *
118
+ * @param {number} x - Cartesian x
119
+ * @param {number} z - Cartesian z
120
+ * @returns {{ r: number, phi: number }} Polar coordinates
121
+ */
122
+ export function cartesianToPolar(x, z) {
123
+ return {
124
+ r: Math.sqrt(x * x + z * z),
125
+ phi: Math.atan2(z, x),
126
+ };
127
+ }
128
+
129
+ // ─────────────────────────────────────────────────────────────────────────────
130
+ // GRAVITATIONAL LENSING
131
+ // ─────────────────────────────────────────────────────────────────────────────
132
+
133
+ /**
134
+ * Calculate gravitational lensing displacement for a point near a massive object.
135
+ *
136
+ * Light passing near a massive object is deflected, causing background objects
137
+ * to appear displaced radially outward from the lens center. This creates the
138
+ * "Einstein ring" effect where objects directly behind the lens form a ring.
139
+ *
140
+ * This is a simplified screen-space approximation suitable for real-time rendering.
141
+ * True lensing would require ray-tracing through curved spacetime.
142
+ *
143
+ * @param {number} screenDist - Distance from lens center in screen pixels
144
+ * @param {number} effectRadius - Maximum radius of lensing effect in pixels
145
+ * @param {number} strength - Displacement strength (higher = more dramatic)
146
+ * @param {number} falloff - Exponential falloff rate (higher = tighter effect)
147
+ * @param {number} minDist - Minimum distance to apply lensing (avoids singularity)
148
+ * @returns {number} Radial displacement in pixels (0 if outside effect radius)
149
+ *
150
+ * @example
151
+ * // Calculate displacement for a star 100px from black hole center
152
+ * const displacement = gravitationalLensing(100, 500, 200, 0.008, 5);
153
+ * // Apply: newRadius = screenDist + displacement
154
+ */
155
+ export function gravitationalLensing(screenDist, effectRadius, strength, falloff, minDist = 5) {
156
+ if (screenDist <= minDist || screenDist >= effectRadius) {
157
+ return 0;
158
+ }
159
+
160
+ // Exponential falloff: stronger closer to lens center
161
+ const lensFactor = Math.exp(-screenDist * falloff);
162
+
163
+ return lensFactor * strength;
164
+ }
165
+
166
+ /**
167
+ * Apply gravitational lensing to screen coordinates.
168
+ *
169
+ * Takes a point's screen position (relative to lens center) and returns
170
+ * the displaced position after lensing.
171
+ *
172
+ * @param {number} x - X coordinate relative to lens center
173
+ * @param {number} y - Y coordinate relative to lens center
174
+ * @param {number} effectRadius - Maximum radius of lensing effect
175
+ * @param {number} strength - Displacement strength
176
+ * @param {number} falloff - Exponential falloff rate
177
+ * @param {number} minDist - Minimum distance for lensing
178
+ * @returns {{ x: number, y: number, displacement: number }} Displaced coordinates and displacement amount
179
+ *
180
+ * @example
181
+ * const result = applyGravitationalLensing(50, 30, 500, 200, 0.008);
182
+ * ctx.drawImage(star, centerX + result.x, centerY + result.y, ...);
183
+ */
184
+ export function applyGravitationalLensing(x, y, effectRadius, strength, falloff, minDist = 5) {
185
+ const dist = Math.sqrt(x * x + y * y);
186
+
187
+ if (dist <= minDist || dist >= effectRadius) {
188
+ return { x, y, displacement: 0 };
189
+ }
190
+
191
+ const displacement = gravitationalLensing(dist, effectRadius, strength, falloff, minDist);
192
+
193
+ // Radial displacement: push point outward from center
194
+ const ratio = (dist + displacement) / dist;
195
+
196
+ return {
197
+ x: x * ratio,
198
+ y: y * ratio,
199
+ displacement
200
+ };
201
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Heat Dynamics Module
3
+ *
4
+ * Particle-based heat physics functions for simulating thermal behavior:
5
+ * - Zone-based temperature changes (heating/cooling regions)
6
+ * - Buoyancy forces from temperature differentials
7
+ * - Heat transfer between particles
8
+ *
9
+ * Designed for lava lamp, fluid simulations, and particle systems.
10
+ *
11
+ * @see Easing.smoothstep, Easing.lerp in src/motion/easing.js for interpolation utilities
12
+ */
13
+
14
+ import { Easing } from "../motion/easing.js";
15
+
16
+ // ─────────────────────────────────────────────────────────────────────────────
17
+ // TEMPERATURE FUNCTIONS
18
+ // ─────────────────────────────────────────────────────────────────────────────
19
+
20
+ /**
21
+ * Attempt ot use this as smoothstep with edge parameters (wrapper for Easing.smoothstep).
22
+ * @private
23
+ */
24
+ function smoothstep(edge0, edge1, x) {
25
+ const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
26
+ return Easing.smoothstep(t);
27
+ }
28
+
29
+ /**
30
+ * Calculate temperature change based on position in thermal zones.
31
+ * Uses smooth transitions between zones instead of hard boundaries.
32
+ *
33
+ * Zone layout (normalized y: 0 = top, 1 = bottom):
34
+ * - Cool zone: y < coolZone (temperature approaches 0)
35
+ * - Middle zone: between coolZone and heatZone (temperature approaches y position)
36
+ * - Heat zone: y > heatZone (temperature approaches 1)
37
+ *
38
+ * @param {number} position - Normalized position [0, 1] (typically y coordinate)
39
+ * @param {number} currentTemp - Current temperature [0, 1]
40
+ * @param {Object} config - Zone configuration
41
+ * @param {number} config.heatZone - Y position where heating begins (e.g., 0.92)
42
+ * @param {number} config.coolZone - Y position where cooling begins (e.g., 0.2)
43
+ * @param {number} config.rate - Base temperature change rate
44
+ * @param {number} [config.heatMultiplier=1.5] - Heating rate multiplier
45
+ * @param {number} [config.coolMultiplier=1.5] - Cooling rate multiplier
46
+ * @param {number} [config.middleMultiplier=0.05] - Middle zone rate multiplier
47
+ * @param {number} [config.transitionWidth=0.1] - Width of smooth transition zones
48
+ * @returns {number} New temperature value [0, 1]
49
+ *
50
+ * @example
51
+ * const temp = zoneTemperature(0.95, 0.5, {
52
+ * heatZone: 0.92, coolZone: 0.2, rate: 0.0055
53
+ * });
54
+ */
55
+ export function zoneTemperature(position, currentTemp, config) {
56
+ const {
57
+ heatZone,
58
+ coolZone,
59
+ rate,
60
+ heatMultiplier = 1.5,
61
+ coolMultiplier = 1.5,
62
+ middleMultiplier = 0.05,
63
+ transitionWidth = 0.1,
64
+ } = config;
65
+
66
+ // Calculate zone influence using smoothstep for soft transitions
67
+ // Heat zone influence: ramps up as position exceeds heatZone
68
+ const heatInfluence = smoothstep(heatZone - transitionWidth, heatZone + transitionWidth * 0.5, position);
69
+
70
+ // Cool zone influence: ramps up as position goes below coolZone
71
+ const coolInfluence = 1 - smoothstep(coolZone - transitionWidth * 0.5, coolZone + transitionWidth, position);
72
+
73
+ // Middle zone is whatever's left
74
+ const middleInfluence = 1 - heatInfluence - coolInfluence;
75
+
76
+ // Calculate target temperatures and rates for each zone
77
+ let deltaTemp = 0;
78
+
79
+ // Heat zone: temperature approaches 1.0
80
+ if (heatInfluence > 0) {
81
+ deltaTemp += (1.0 - currentTemp) * rate * heatMultiplier * heatInfluence;
82
+ }
83
+
84
+ // Cool zone: temperature approaches 0.0
85
+ if (coolInfluence > 0) {
86
+ deltaTemp += (0.0 - currentTemp) * rate * coolMultiplier * coolInfluence;
87
+ }
88
+
89
+ // Middle zone: temperature approaches position (linear gradient)
90
+ if (middleInfluence > 0) {
91
+ deltaTemp += (position - currentTemp) * rate * middleMultiplier * middleInfluence;
92
+ }
93
+
94
+ // Apply and clamp
95
+ return Math.max(0, Math.min(1, currentTemp + deltaTemp));
96
+ }
97
+
98
+ // ─────────────────────────────────────────────────────────────────────────────
99
+ // BUOYANCY FUNCTIONS
100
+ // ─────────────────────────────────────────────────────────────────────────────
101
+
102
+ /**
103
+ * Calculate buoyancy force from temperature differential.
104
+ * Hot particles rise (negative velocity), cold particles sink (positive velocity).
105
+ *
106
+ * Based on simplified Archimedes principle where temperature acts as
107
+ * inverse density: hotter = less dense = more buoyant.
108
+ *
109
+ * @param {number} temperature - Particle temperature [0, 1]
110
+ * @param {number} neutralTemp - Temperature at which buoyancy is zero (typically 0.5)
111
+ * @param {number} strength - Buoyancy force strength coefficient
112
+ * @returns {number} Velocity adjustment (negative = rise, positive = sink)
113
+ *
114
+ * @example
115
+ * // Hot particle rises
116
+ * const lift = thermalBuoyancy(0.9, 0.5, 0.00018); // negative value
117
+ * particle.vy -= lift; // subtracting negative = rising
118
+ *
119
+ * // Cold particle sinks
120
+ * const sink = thermalBuoyancy(0.2, 0.5, 0.00018); // positive value
121
+ */
122
+ export function thermalBuoyancy(temperature, neutralTemp, strength) {
123
+ return (temperature - neutralTemp) * strength;
124
+ }
125
+
126
+ /**
127
+ * Calculate weight-adjusted gravity force.
128
+ * Larger particles experience more gravitational pull.
129
+ *
130
+ * @param {number} radius - Particle radius
131
+ * @param {number} baseRadius - Reference radius for weight = 1
132
+ * @param {number} gravity - Base gravity coefficient
133
+ * @returns {number} Gravity force to add to vertical velocity
134
+ *
135
+ * @example
136
+ * const weight = thermalGravity(0.06, 0.04, 0.000052);
137
+ * particle.vy += weight;
138
+ */
139
+ export function thermalGravity(radius, baseRadius, gravity) {
140
+ const weight = radius / baseRadius;
141
+ return gravity * weight;
142
+ }
143
+
144
+ // ─────────────────────────────────────────────────────────────────────────────
145
+ // HEAT TRANSFER FUNCTIONS
146
+ // ─────────────────────────────────────────────────────────────────────────────
147
+
148
+ /**
149
+ * Calculate heat transfer between two particles.
150
+ * Uses Newton's law of cooling: heat flows from hot to cold proportionally
151
+ * to the temperature difference.
152
+ *
153
+ * @param {number} temp1 - Temperature of first particle [0, 1]
154
+ * @param {number} temp2 - Temperature of second particle [0, 1]
155
+ * @param {number} distance - Distance between particle centers
156
+ * @param {number} maxDistance - Maximum distance for heat transfer
157
+ * @param {number} rate - Heat transfer rate coefficient
158
+ * @returns {number} Temperature change for particle 1 (add to temp1)
159
+ *
160
+ * @example
161
+ * const dist = Math.sqrt(dx*dx + dy*dy);
162
+ * const maxDist = (blob1.r + blob2.r) * 1.5;
163
+ * const delta = heatTransfer(blob1.temp, blob2.temp, dist, maxDist, 0.0022);
164
+ * blob1.temp += delta;
165
+ */
166
+ export function heatTransfer(temp1, temp2, distance, maxDistance, rate) {
167
+ if (distance >= maxDistance) return 0;
168
+
169
+ // Heat flows from hot to cold
170
+ const heatDiff = temp2 - temp1;
171
+
172
+ // Optional: scale transfer by proximity (closer = faster transfer)
173
+ // const proximity = 1 - (distance / maxDistance);
174
+ // return heatDiff * rate * proximity;
175
+
176
+ return heatDiff * rate;
177
+ }
178
+
179
+ /**
180
+ * Calculate heat transfer with distance falloff.
181
+ * Transfer rate decreases with distance for more realistic behavior.
182
+ *
183
+ * @param {number} temp1 - Temperature of first particle [0, 1]
184
+ * @param {number} temp2 - Temperature of second particle [0, 1]
185
+ * @param {number} distance - Distance between particle centers
186
+ * @param {number} maxDistance - Maximum distance for heat transfer
187
+ * @param {number} rate - Base heat transfer rate coefficient
188
+ * @param {number} [falloff=1] - Distance falloff exponent (1 = linear, 2 = quadratic)
189
+ * @returns {number} Temperature change for particle 1
190
+ *
191
+ * @example
192
+ * // Quadratic falloff for more localized heat transfer
193
+ * const delta = heatTransferFalloff(t1, t2, dist, maxDist, 0.003, 2);
194
+ */
195
+ export function heatTransferFalloff(temp1, temp2, distance, maxDistance, rate, falloff = 1) {
196
+ if (distance >= maxDistance) return 0;
197
+
198
+ const heatDiff = temp2 - temp1;
199
+ const proximity = Math.pow(1 - distance / maxDistance, falloff);
200
+
201
+ return heatDiff * rate * proximity;
202
+ }
@@ -0,0 +1,12 @@
1
+ export {Random} from "./random.js";
2
+ export {Complex} from "./complex.js";
3
+ export {Fractals} from "./fractal.js";
4
+ export {Patterns} from "./patterns.js";
5
+ export {Noise} from "./noise.js";
6
+ export {Tensor} from "./tensor.js";
7
+
8
+ // Physics modules
9
+ export * from "./gr.js";
10
+ export * from "./orbital.js";
11
+ export * from "./quantum.js";
12
+ export * from "./heat.js";