@guinetik/gcanvas 1.0.4 → 2.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 (261) hide show
  1. package/dist/CNAME +1 -0
  2. package/dist/aizawa.html +27 -0
  3. package/dist/animations.html +31 -0
  4. package/dist/basic.html +38 -0
  5. package/dist/baskara.html +31 -0
  6. package/dist/bezier.html +35 -0
  7. package/dist/beziersignature.html +29 -0
  8. package/dist/blackhole.html +28 -0
  9. package/dist/blob.html +35 -0
  10. package/dist/clifford.html +25 -0
  11. package/dist/cmb.html +24 -0
  12. package/dist/coordinates.html +698 -0
  13. package/dist/cube3d.html +23 -0
  14. package/dist/dadras.html +26 -0
  15. package/dist/dejong.html +25 -0
  16. package/dist/demos.css +303 -0
  17. package/dist/dino.html +42 -0
  18. package/dist/easing.html +28 -0
  19. package/dist/events.html +195 -0
  20. package/dist/fluent.html +647 -0
  21. package/dist/fluid-simple.html +22 -0
  22. package/dist/fluid.html +37 -0
  23. package/dist/fractals.html +36 -0
  24. package/dist/gameobjects.html +626 -0
  25. package/dist/gcanvas.es.js +14368 -9093
  26. package/dist/gcanvas.es.min.js +1 -1
  27. package/dist/gcanvas.umd.js +1 -1
  28. package/dist/gcanvas.umd.min.js +1 -1
  29. package/dist/genart.html +26 -0
  30. package/dist/gendream.html +26 -0
  31. package/dist/group.html +36 -0
  32. package/dist/halvorsen.html +27 -0
  33. package/dist/home.html +587 -0
  34. package/dist/hyperbolic001.html +23 -0
  35. package/dist/hyperbolic002.html +23 -0
  36. package/dist/hyperbolic003.html +23 -0
  37. package/dist/hyperbolic004.html +23 -0
  38. package/dist/hyperbolic005.html +22 -0
  39. package/dist/index.html +446 -0
  40. package/dist/isometric.html +34 -0
  41. package/dist/js/aizawa.js +425 -0
  42. package/dist/js/animations.js +452 -0
  43. package/dist/js/basic.js +204 -0
  44. package/dist/js/baskara.js +751 -0
  45. package/dist/js/bezier.js +692 -0
  46. package/dist/js/beziersignature.js +241 -0
  47. package/dist/js/blackhole/accretiondisk.obj.js +379 -0
  48. package/dist/js/blackhole/blackhole.obj.js +318 -0
  49. package/dist/js/blackhole/index.js +409 -0
  50. package/dist/js/blackhole/particle.js +56 -0
  51. package/dist/js/blackhole/starfield.obj.js +218 -0
  52. package/dist/js/blob.js +2276 -0
  53. package/dist/js/clifford.js +236 -0
  54. package/dist/js/cmb.js +594 -0
  55. package/dist/js/coordinates.js +840 -0
  56. package/dist/js/cube3d.js +789 -0
  57. package/dist/js/dadras.js +405 -0
  58. package/dist/js/dejong.js +257 -0
  59. package/dist/js/dino.js +1420 -0
  60. package/dist/js/easing.js +477 -0
  61. package/dist/js/fluent.js +183 -0
  62. package/dist/js/fluid-simple.js +253 -0
  63. package/dist/js/fluid.js +527 -0
  64. package/dist/js/fractals.js +932 -0
  65. package/dist/js/fractalworker.js +93 -0
  66. package/dist/js/gameobjects.js +176 -0
  67. package/dist/js/genart.js +268 -0
  68. package/dist/js/gendream.js +209 -0
  69. package/dist/js/group.js +140 -0
  70. package/dist/js/halvorsen.js +405 -0
  71. package/dist/js/hyperbolic001.js +310 -0
  72. package/dist/js/hyperbolic002.js +388 -0
  73. package/dist/js/hyperbolic003.js +319 -0
  74. package/dist/js/hyperbolic004.js +345 -0
  75. package/dist/js/hyperbolic005.js +340 -0
  76. package/dist/js/info-toggle.js +25 -0
  77. package/dist/js/isometric.js +851 -0
  78. package/dist/js/kerr.js +1547 -0
  79. package/dist/js/lavalamp.js +590 -0
  80. package/dist/js/layout.js +354 -0
  81. package/dist/js/lorenz.js +425 -0
  82. package/dist/js/mondrian.js +285 -0
  83. package/dist/js/opacity.js +275 -0
  84. package/dist/js/painter.js +484 -0
  85. package/dist/js/particles-showcase.js +514 -0
  86. package/dist/js/particles.js +299 -0
  87. package/dist/js/patterns.js +397 -0
  88. package/dist/js/penrose/artifact.js +69 -0
  89. package/dist/js/penrose/blackhole.js +121 -0
  90. package/dist/js/penrose/constants.js +73 -0
  91. package/dist/js/penrose/game.js +943 -0
  92. package/dist/js/penrose/lore.js +278 -0
  93. package/dist/js/penrose/penrosescene.js +892 -0
  94. package/dist/js/penrose/ship.js +216 -0
  95. package/dist/js/penrose/sounds.js +211 -0
  96. package/dist/js/penrose/voidparticle.js +55 -0
  97. package/dist/js/penrose/voidscene.js +258 -0
  98. package/dist/js/penrose/voidship.js +144 -0
  99. package/dist/js/penrose/wormhole.js +46 -0
  100. package/dist/js/pipeline.js +555 -0
  101. package/dist/js/plane3d.js +256 -0
  102. package/dist/js/platformer.js +1579 -0
  103. package/dist/js/rossler.js +480 -0
  104. package/dist/js/scene.js +304 -0
  105. package/dist/js/scenes.js +320 -0
  106. package/dist/js/schrodinger.js +706 -0
  107. package/dist/js/schwarzschild.js +1015 -0
  108. package/dist/js/shapes.js +628 -0
  109. package/dist/js/space/alien.js +171 -0
  110. package/dist/js/space/boom.js +98 -0
  111. package/dist/js/space/boss.js +353 -0
  112. package/dist/js/space/buff.js +73 -0
  113. package/dist/js/space/bullet.js +102 -0
  114. package/dist/js/space/constants.js +85 -0
  115. package/dist/js/space/game.js +1884 -0
  116. package/dist/js/space/hud.js +112 -0
  117. package/dist/js/space/laserbeam.js +179 -0
  118. package/dist/js/space/lightning.js +277 -0
  119. package/dist/js/space/minion.js +192 -0
  120. package/dist/js/space/missile.js +212 -0
  121. package/dist/js/space/player.js +430 -0
  122. package/dist/js/space/powerup.js +90 -0
  123. package/dist/js/space/starfield.js +58 -0
  124. package/dist/js/space/starpower.js +90 -0
  125. package/dist/js/spacetime.js +559 -0
  126. package/dist/js/sphere3d.js +229 -0
  127. package/dist/js/sprite.js +473 -0
  128. package/dist/js/starfaux/config.js +118 -0
  129. package/dist/js/starfaux/enemy.js +353 -0
  130. package/dist/js/starfaux/hud.js +78 -0
  131. package/dist/js/starfaux/index.js +482 -0
  132. package/dist/js/starfaux/laser.js +182 -0
  133. package/dist/js/starfaux/player.js +468 -0
  134. package/dist/js/starfaux/terrain.js +560 -0
  135. package/dist/js/study001.js +275 -0
  136. package/dist/js/study002.js +366 -0
  137. package/dist/js/study003.js +331 -0
  138. package/dist/js/study004.js +389 -0
  139. package/dist/js/study005.js +209 -0
  140. package/dist/js/study006.js +194 -0
  141. package/dist/js/study007.js +192 -0
  142. package/dist/js/study008.js +413 -0
  143. package/dist/js/svgtween.js +204 -0
  144. package/dist/js/tde/accretiondisk.js +471 -0
  145. package/dist/js/tde/blackhole.js +219 -0
  146. package/dist/js/tde/blackholescene.js +209 -0
  147. package/dist/js/tde/config.js +59 -0
  148. package/dist/js/tde/index.js +820 -0
  149. package/dist/js/tde/jets.js +290 -0
  150. package/dist/js/tde/lensedstarfield.js +154 -0
  151. package/dist/js/tde/tdestar.js +297 -0
  152. package/dist/js/tde/tidalstream.js +372 -0
  153. package/dist/js/tde_old/blackhole.obj.js +354 -0
  154. package/dist/js/tde_old/debris.obj.js +791 -0
  155. package/dist/js/tde_old/flare.obj.js +239 -0
  156. package/dist/js/tde_old/index.js +448 -0
  157. package/dist/js/tde_old/star.obj.js +812 -0
  158. package/dist/js/tetris/config.js +157 -0
  159. package/dist/js/tetris/grid.js +286 -0
  160. package/dist/js/tetris/index.js +1195 -0
  161. package/dist/js/tetris/renderer.js +634 -0
  162. package/dist/js/tetris/tetrominos.js +280 -0
  163. package/dist/js/thomas.js +394 -0
  164. package/dist/js/tiles.js +312 -0
  165. package/dist/js/tweendemo.js +79 -0
  166. package/dist/js/visibility.js +102 -0
  167. package/dist/kerr.html +28 -0
  168. package/dist/lavalamp.html +27 -0
  169. package/dist/layouts.html +37 -0
  170. package/dist/logo.svg +4 -0
  171. package/dist/loop.html +84 -0
  172. package/dist/lorenz.html +27 -0
  173. package/dist/mondrian.html +32 -0
  174. package/dist/og_image.png +0 -0
  175. package/dist/opacity.html +36 -0
  176. package/dist/painter.html +39 -0
  177. package/dist/particles-showcase.html +28 -0
  178. package/dist/particles.html +24 -0
  179. package/dist/patterns.html +33 -0
  180. package/dist/penrose-game.html +31 -0
  181. package/dist/pipeline.html +737 -0
  182. package/dist/plane3d.html +24 -0
  183. package/dist/platformer.html +43 -0
  184. package/dist/rossler.html +27 -0
  185. package/dist/scene-interactivity-test.html +220 -0
  186. package/dist/scene.html +33 -0
  187. package/dist/scenes.html +96 -0
  188. package/dist/schrodinger.html +27 -0
  189. package/dist/schwarzschild.html +27 -0
  190. package/dist/shapes.html +16 -0
  191. package/dist/space.html +85 -0
  192. package/dist/spacetime.html +27 -0
  193. package/dist/sphere3d.html +24 -0
  194. package/dist/sprite.html +18 -0
  195. package/dist/starfaux.html +22 -0
  196. package/dist/study001.html +23 -0
  197. package/dist/study002.html +23 -0
  198. package/dist/study003.html +23 -0
  199. package/dist/study004.html +23 -0
  200. package/dist/study005.html +22 -0
  201. package/dist/study006.html +24 -0
  202. package/dist/study007.html +24 -0
  203. package/dist/study008.html +22 -0
  204. package/dist/svgtween.html +29 -0
  205. package/dist/tde.html +28 -0
  206. package/dist/tetris3d.html +25 -0
  207. package/dist/thomas.html +27 -0
  208. package/dist/tiles.html +28 -0
  209. package/dist/transforms.html +400 -0
  210. package/dist/tween.html +45 -0
  211. package/dist/visibility.html +33 -0
  212. package/package.json +1 -1
  213. package/readme.md +30 -22
  214. package/src/game/objects/go.js +7 -0
  215. package/src/game/objects/index.js +2 -0
  216. package/src/game/objects/isometric-scene.js +53 -3
  217. package/src/game/objects/layoutscene.js +57 -0
  218. package/src/game/objects/mask.js +241 -0
  219. package/src/game/objects/scene.js +19 -0
  220. package/src/game/objects/wrapper.js +14 -2
  221. package/src/game/pipeline.js +17 -0
  222. package/src/game/ui/button.js +101 -16
  223. package/src/game/ui/theme.js +0 -6
  224. package/src/game/ui/togglebutton.js +25 -14
  225. package/src/game/ui/tooltip.js +12 -4
  226. package/src/index.js +3 -0
  227. package/src/io/gesture.js +409 -0
  228. package/src/io/index.js +4 -1
  229. package/src/io/keys.js +9 -1
  230. package/src/io/screen.js +476 -0
  231. package/src/math/attractors.js +664 -0
  232. package/src/math/heat.js +106 -0
  233. package/src/math/index.js +1 -0
  234. package/src/mixins/draggable.js +15 -19
  235. package/src/painter/painter.shapes.js +11 -5
  236. package/src/particle/particle-system.js +165 -1
  237. package/src/physics/index.js +26 -0
  238. package/src/physics/physics-updaters.js +333 -0
  239. package/src/physics/physics.js +375 -0
  240. package/src/shapes/image.js +5 -5
  241. package/src/shapes/index.js +2 -0
  242. package/src/shapes/parallelogram.js +147 -0
  243. package/src/shapes/righttriangle.js +115 -0
  244. package/src/shapes/svg.js +281 -100
  245. package/src/shapes/text.js +22 -6
  246. package/src/shapes/transformable.js +5 -0
  247. package/src/sound/effects.js +807 -0
  248. package/src/sound/index.js +13 -0
  249. package/src/webgl/index.js +7 -0
  250. package/src/webgl/shaders/clifford-point-shaders.js +131 -0
  251. package/src/webgl/shaders/dejong-point-shaders.js +131 -0
  252. package/src/webgl/shaders/point-sprite-shaders.js +152 -0
  253. package/src/webgl/webgl-clifford-renderer.js +477 -0
  254. package/src/webgl/webgl-dejong-renderer.js +472 -0
  255. package/src/webgl/webgl-line-renderer.js +391 -0
  256. package/src/webgl/webgl-particle-renderer.js +410 -0
  257. package/types/index.d.ts +30 -2
  258. package/types/io.d.ts +217 -0
  259. package/types/physics.d.ts +299 -0
  260. package/types/shapes.d.ts +8 -0
  261. package/types/webgl.d.ts +188 -109
@@ -0,0 +1,664 @@
1
+ /**
2
+ * @module math/attractors
3
+ * @description Strange attractor functions for chaotic dynamical systems.
4
+ *
5
+ * Provides pure mathematical functions for computing attractor dynamics.
6
+ * Each attractor returns both the new position and velocity (derivatives)
7
+ * for use in visualization, coloring, and analysis.
8
+ *
9
+ * @example
10
+ * import { Attractors } from '@guinetik/gcanvas';
11
+ *
12
+ * // Use default parameters
13
+ * const { position, velocity } = Attractors.lorenz.step({ x: 1, y: 1, z: 1 }, 0.01);
14
+ *
15
+ * // Custom parameters
16
+ * const step = Attractors.lorenz.createStepper({ sigma: 10, rho: 28, beta: 8/3 });
17
+ * const result = step({ x: 1, y: 1, z: 1 }, 0.01);
18
+ *
19
+ * // Get just derivatives (for advanced use)
20
+ * const { dx, dy, dz } = Attractors.lorenz.derivatives({ x: 1, y: 1, z: 1 });
21
+ */
22
+
23
+ /**
24
+ * Attractor types
25
+ */
26
+ export const AttractorType = {
27
+ CONTINUOUS: "continuous", // Uses dt for integration
28
+ ITERATIVE: "iterative", // Direct mapping (no dt)
29
+ };
30
+
31
+ /**
32
+ * Attractor dimensions
33
+ */
34
+ export const AttractorDimension = {
35
+ TWO_D: 2,
36
+ THREE_D: 3,
37
+ };
38
+
39
+ // ─────────────────────────────────────────────────────────────────────────────
40
+ // LORENZ ATTRACTOR
41
+ // ─────────────────────────────────────────────────────────────────────────────
42
+
43
+ /**
44
+ * Lorenz Attractor (1963)
45
+ *
46
+ * The classic "butterfly effect" attractor discovered by Edward Lorenz
47
+ * while studying atmospheric convection.
48
+ *
49
+ * Equations:
50
+ * dx/dt = σ(y - x)
51
+ * dy/dt = x(ρ - z) - y
52
+ * dz/dt = xy - βz
53
+ *
54
+ * Default parameters: σ=10, ρ=28, β=8/3
55
+ */
56
+ const lorenz = {
57
+ name: "Lorenz",
58
+ type: AttractorType.CONTINUOUS,
59
+ dimension: AttractorDimension.THREE_D,
60
+
61
+ equations: [
62
+ "dx/dt = σ(y - x)",
63
+ "dy/dt = x(ρ - z) - y",
64
+ "dz/dt = xy - βz",
65
+ ],
66
+
67
+ defaultParams: {
68
+ sigma: 10,
69
+ rho: 28,
70
+ beta: 8 / 3,
71
+ },
72
+
73
+ defaultDt: 0.01,
74
+
75
+ /**
76
+ * Compute derivatives at a point
77
+ * @param {Object} point - { x, y, z }
78
+ * @param {Object} [params] - { sigma, rho, beta }
79
+ * @returns {Object} { dx, dy, dz }
80
+ */
81
+ derivatives(point, params = this.defaultParams) {
82
+ const { sigma, rho, beta } = { ...this.defaultParams, ...params };
83
+ const { x, y, z } = point;
84
+
85
+ return {
86
+ dx: sigma * (y - x),
87
+ dy: x * (rho - z) - y,
88
+ dz: x * y - beta * z,
89
+ };
90
+ },
91
+
92
+ /**
93
+ * Perform one integration step (Euler method)
94
+ * @param {Object} point - { x, y, z }
95
+ * @param {number} [dt] - Time step
96
+ * @param {Object} [params] - Attractor parameters
97
+ * @returns {Object} { position: {x,y,z}, velocity: {dx,dy,dz}, speed }
98
+ */
99
+ step(point, dt = this.defaultDt, params = this.defaultParams) {
100
+ const d = this.derivatives(point, params);
101
+ const speed = Math.sqrt(d.dx * d.dx + d.dy * d.dy + d.dz * d.dz);
102
+
103
+ return {
104
+ position: {
105
+ x: point.x + d.dx * dt,
106
+ y: point.y + d.dy * dt,
107
+ z: point.z + d.dz * dt,
108
+ },
109
+ velocity: d,
110
+ speed,
111
+ };
112
+ },
113
+
114
+ /**
115
+ * Create a stepper function with fixed parameters
116
+ * @param {Object} [params] - Attractor parameters
117
+ * @returns {Function} (point, dt) => result
118
+ */
119
+ createStepper(params = this.defaultParams) {
120
+ const mergedParams = { ...this.defaultParams, ...params };
121
+ return (point, dt = this.defaultDt) => this.step(point, dt, mergedParams);
122
+ },
123
+ };
124
+
125
+ // ─────────────────────────────────────────────────────────────────────────────
126
+ // DADRAS ATTRACTOR
127
+ // ─────────────────────────────────────────────────────────────────────────────
128
+
129
+ /**
130
+ * Dadras Attractor (2010)
131
+ *
132
+ * A chaotic system with multiple scrolls and wings, discovered by
133
+ * Sara Dadras and Hamid Reza Momeni. Features complex folding dynamics
134
+ * due to nonlinear coupling terms.
135
+ *
136
+ * Equations:
137
+ * dx/dt = y - ax + byz
138
+ * dy/dt = cy - xz + z
139
+ * dz/dt = dxy - ez
140
+ *
141
+ * Default parameters: a=3, b=2.7, c=1.7, d=2, e=9
142
+ */
143
+ const dadras = {
144
+ name: "Dadras",
145
+ type: AttractorType.CONTINUOUS,
146
+ dimension: AttractorDimension.THREE_D,
147
+
148
+ equations: [
149
+ "dx/dt = y - ax + byz",
150
+ "dy/dt = cy - xz + z",
151
+ "dz/dt = dxy - ez",
152
+ ],
153
+
154
+ defaultParams: {
155
+ a: 3,
156
+ b: 2.7,
157
+ c: 1.7,
158
+ d: 2,
159
+ e: 9,
160
+ },
161
+
162
+ defaultDt: 0.005,
163
+
164
+ derivatives(point, params = this.defaultParams) {
165
+ const { a, b, c, d, e } = { ...this.defaultParams, ...params };
166
+ const { x, y, z } = point;
167
+
168
+ return {
169
+ dx: y - a * x + b * y * z,
170
+ dy: c * y - x * z + z,
171
+ dz: d * x * y - e * z,
172
+ };
173
+ },
174
+
175
+ step(point, dt = this.defaultDt, params = this.defaultParams) {
176
+ const d = this.derivatives(point, params);
177
+ const speed = Math.sqrt(d.dx * d.dx + d.dy * d.dy + d.dz * d.dz);
178
+
179
+ return {
180
+ position: {
181
+ x: point.x + d.dx * dt,
182
+ y: point.y + d.dy * dt,
183
+ z: point.z + d.dz * dt,
184
+ },
185
+ velocity: d,
186
+ speed,
187
+ };
188
+ },
189
+
190
+ createStepper(params = this.defaultParams) {
191
+ const mergedParams = { ...this.defaultParams, ...params };
192
+ return (point, dt = this.defaultDt) => this.step(point, dt, mergedParams);
193
+ },
194
+ };
195
+
196
+ // ─────────────────────────────────────────────────────────────────────────────
197
+ // AIZAWA ATTRACTOR
198
+ // ─────────────────────────────────────────────────────────────────────────────
199
+
200
+ /**
201
+ * Aizawa Attractor
202
+ *
203
+ * A 3D chaotic system with intricate folding structure, named after
204
+ * Japanese mathematician Tomohiko Aizawa.
205
+ *
206
+ * Equations:
207
+ * dx/dt = (z - b)x - dy
208
+ * dy/dt = dx + (z - b)y
209
+ * dz/dt = c + az - z³/3 - (x² + y²)(1 + ez) + fzx³
210
+ *
211
+ * Default parameters: a=0.95, b=0.7, c=0.6, d=3.5, e=0.25, f=0.1
212
+ */
213
+ const aizawa = {
214
+ name: "Aizawa",
215
+ type: AttractorType.CONTINUOUS,
216
+ dimension: AttractorDimension.THREE_D,
217
+
218
+ equations: [
219
+ "dx/dt = (z - b)x - dy",
220
+ "dy/dt = dx + (z - b)y",
221
+ "dz/dt = c + az - z³/3 - (x² + y²)(1 + ez) + fzx³",
222
+ ],
223
+
224
+ defaultParams: {
225
+ a: 0.95,
226
+ b: 0.7,
227
+ c: 0.6,
228
+ d: 3.5,
229
+ e: 0.25,
230
+ f: 0.1,
231
+ },
232
+
233
+ defaultDt: 0.01,
234
+
235
+ derivatives(point, params = this.defaultParams) {
236
+ const { a, b, c, d, e, f } = { ...this.defaultParams, ...params };
237
+ const { x, y, z } = point;
238
+
239
+ return {
240
+ dx: (z - b) * x - d * y,
241
+ dy: d * x + (z - b) * y,
242
+ dz:
243
+ c +
244
+ a * z -
245
+ (z * z * z) / 3 -
246
+ (x * x + y * y) * (1 + e * z) +
247
+ f * z * x * x * x,
248
+ };
249
+ },
250
+
251
+ step(point, dt = this.defaultDt, params = this.defaultParams) {
252
+ const d = this.derivatives(point, params);
253
+ const speed = Math.sqrt(d.dx * d.dx + d.dy * d.dy + d.dz * d.dz);
254
+
255
+ return {
256
+ position: {
257
+ x: point.x + d.dx * dt,
258
+ y: point.y + d.dy * dt,
259
+ z: point.z + d.dz * dt,
260
+ },
261
+ velocity: d,
262
+ speed,
263
+ };
264
+ },
265
+
266
+ createStepper(params = this.defaultParams) {
267
+ const mergedParams = { ...this.defaultParams, ...params };
268
+ return (point, dt = this.defaultDt) => this.step(point, dt, mergedParams);
269
+ },
270
+ };
271
+
272
+ // ─────────────────────────────────────────────────────────────────────────────
273
+ // THOMAS ATTRACTOR
274
+ // ─────────────────────────────────────────────────────────────────────────────
275
+
276
+ /**
277
+ * Thomas' Cyclically Symmetric Attractor (1999)
278
+ *
279
+ * Discovered by René Thomas. Features elegant symmetry and smooth
280
+ * cyclical motion with a simple sinusoidal structure.
281
+ *
282
+ * Equations:
283
+ * dx/dt = sin(y) - bx
284
+ * dy/dt = sin(z) - by
285
+ * dz/dt = sin(x) - bz
286
+ *
287
+ * Default parameter: b=0.208186
288
+ */
289
+ const thomas = {
290
+ name: "Thomas",
291
+ type: AttractorType.CONTINUOUS,
292
+ dimension: AttractorDimension.THREE_D,
293
+
294
+ equations: ["dx/dt = sin(y) - bx", "dy/dt = sin(z) - by", "dz/dt = sin(x) - bz"],
295
+
296
+ defaultParams: {
297
+ b: 0.208186,
298
+ },
299
+
300
+ defaultDt: 0.1,
301
+
302
+ derivatives(point, params = this.defaultParams) {
303
+ const { b } = { ...this.defaultParams, ...params };
304
+ const { x, y, z } = point;
305
+
306
+ return {
307
+ dx: Math.sin(y) - b * x,
308
+ dy: Math.sin(z) - b * y,
309
+ dz: Math.sin(x) - b * z,
310
+ };
311
+ },
312
+
313
+ step(point, dt = this.defaultDt, params = this.defaultParams) {
314
+ const d = this.derivatives(point, params);
315
+ const speed = Math.sqrt(d.dx * d.dx + d.dy * d.dy + d.dz * d.dz);
316
+
317
+ return {
318
+ position: {
319
+ x: point.x + d.dx * dt,
320
+ y: point.y + d.dy * dt,
321
+ z: point.z + d.dz * dt,
322
+ },
323
+ velocity: d,
324
+ speed,
325
+ };
326
+ },
327
+
328
+ createStepper(params = this.defaultParams) {
329
+ const mergedParams = { ...this.defaultParams, ...params };
330
+ return (point, dt = this.defaultDt) => this.step(point, dt, mergedParams);
331
+ },
332
+ };
333
+
334
+ // ─────────────────────────────────────────────────────────────────────────────
335
+ // CLIFFORD ATTRACTOR
336
+ // ─────────────────────────────────────────────────────────────────────────────
337
+
338
+ /**
339
+ * Clifford Attractor
340
+ *
341
+ * A 2D iterative attractor that creates intricate fractal patterns
342
+ * using simple trigonometric functions. Unlike continuous attractors,
343
+ * this is a discrete map (no dt required).
344
+ *
345
+ * Equations:
346
+ * x_{n+1} = sin(a·y_n) + c·cos(a·x_n)
347
+ * y_{n+1} = sin(b·x_n) + d·cos(b·y_n)
348
+ *
349
+ * Default parameters: a=-1.4, b=1.6, c=1.0, d=0.7
350
+ */
351
+ const clifford = {
352
+ name: "Clifford",
353
+ type: AttractorType.ITERATIVE,
354
+ dimension: AttractorDimension.TWO_D,
355
+
356
+ equations: [
357
+ "x_{n+1} = sin(a·y_n) + c·cos(a·x_n)",
358
+ "y_{n+1} = sin(b·x_n) + d·cos(b·y_n)",
359
+ ],
360
+
361
+ defaultParams: {
362
+ a: -1.4,
363
+ b: 1.6,
364
+ c: 1.0,
365
+ d: 0.7,
366
+ },
367
+
368
+ /**
369
+ * Compute next position (iterative, no derivatives)
370
+ * @param {Object} point - { x, y }
371
+ * @param {Object} [params] - { a, b, c, d }
372
+ * @returns {Object} { x, y }
373
+ */
374
+ next(point, params = this.defaultParams) {
375
+ const { a, b, c, d } = { ...this.defaultParams, ...params };
376
+ const { x, y } = point;
377
+
378
+ return {
379
+ x: Math.sin(a * y) + c * Math.cos(a * x),
380
+ y: Math.sin(b * x) + d * Math.cos(b * y),
381
+ };
382
+ },
383
+
384
+ /**
385
+ * Step function for consistency with other attractors
386
+ * For iterative attractors, dt is ignored
387
+ * @param {Object} point - { x, y }
388
+ * @param {number} [_dt] - Ignored for iterative attractors
389
+ * @param {Object} [params] - Attractor parameters
390
+ * @returns {Object} { position: {x,y}, velocity: {dx,dy}, speed }
391
+ */
392
+ step(point, _dt, params = this.defaultParams) {
393
+ const newPos = this.next(point, params);
394
+
395
+ // Compute velocity as difference (for coloring consistency)
396
+ const dx = newPos.x - point.x;
397
+ const dy = newPos.y - point.y;
398
+ const speed = Math.sqrt(dx * dx + dy * dy);
399
+
400
+ return {
401
+ position: newPos,
402
+ velocity: { dx, dy, dz: 0 },
403
+ speed,
404
+ };
405
+ },
406
+
407
+ createStepper(params = this.defaultParams) {
408
+ const mergedParams = { ...this.defaultParams, ...params };
409
+ return (point, _dt) => this.step(point, _dt, mergedParams);
410
+ },
411
+ };
412
+
413
+ // ─────────────────────────────────────────────────────────────────────────────
414
+ // ROSSLER ATTRACTOR
415
+ // ─────────────────────────────────────────────────────────────────────────────
416
+
417
+ /**
418
+ * Rössler Attractor (1976)
419
+ *
420
+ * Discovered by Otto Rössler. One of the simplest chaotic attractors,
421
+ * featuring a single spiral that folds back on itself.
422
+ *
423
+ * Equations:
424
+ * dx/dt = -y - z
425
+ * dy/dt = x + ay
426
+ * dz/dt = b + z(x - c)
427
+ *
428
+ * Default parameters: a=0.2, b=0.2, c=5.7
429
+ */
430
+ const rossler = {
431
+ name: "Rössler",
432
+ type: AttractorType.CONTINUOUS,
433
+ dimension: AttractorDimension.THREE_D,
434
+
435
+ equations: ["dx/dt = -y - z", "dy/dt = x + ay", "dz/dt = b + z(x - c)"],
436
+
437
+ defaultParams: {
438
+ a: 0.2,
439
+ b: 0.2,
440
+ c: 5.7,
441
+ },
442
+
443
+ defaultDt: 0.01,
444
+
445
+ derivatives(point, params = this.defaultParams) {
446
+ const { a, b, c } = { ...this.defaultParams, ...params };
447
+ const { x, y, z } = point;
448
+
449
+ return {
450
+ dx: -y - z,
451
+ dy: x + a * y,
452
+ dz: b + z * (x - c),
453
+ };
454
+ },
455
+
456
+ step(point, dt = this.defaultDt, params = this.defaultParams) {
457
+ const d = this.derivatives(point, params);
458
+ const speed = Math.sqrt(d.dx * d.dx + d.dy * d.dy + d.dz * d.dz);
459
+
460
+ return {
461
+ position: {
462
+ x: point.x + d.dx * dt,
463
+ y: point.y + d.dy * dt,
464
+ z: point.z + d.dz * dt,
465
+ },
466
+ velocity: d,
467
+ speed,
468
+ };
469
+ },
470
+
471
+ createStepper(params = this.defaultParams) {
472
+ const mergedParams = { ...this.defaultParams, ...params };
473
+ return (point, dt = this.defaultDt) => this.step(point, dt, mergedParams);
474
+ },
475
+ };
476
+
477
+ // ─────────────────────────────────────────────────────────────────────────────
478
+ // HALVORSEN ATTRACTOR
479
+ // ─────────────────────────────────────────────────────────────────────────────
480
+
481
+ /**
482
+ * Halvorsen Attractor
483
+ *
484
+ * A symmetric chaotic attractor with three-fold rotational symmetry.
485
+ *
486
+ * Equations:
487
+ * dx/dt = -ax - 4y - 4z - y²
488
+ * dy/dt = -ay - 4z - 4x - z²
489
+ * dz/dt = -az - 4x - 4y - x²
490
+ *
491
+ * Default parameter: a=1.89
492
+ */
493
+ const halvorsen = {
494
+ name: "Halvorsen",
495
+ type: AttractorType.CONTINUOUS,
496
+ dimension: AttractorDimension.THREE_D,
497
+
498
+ equations: [
499
+ "dx/dt = -ax - 4y - 4z - y²",
500
+ "dy/dt = -ay - 4z - 4x - z²",
501
+ "dz/dt = -az - 4x - 4y - x²",
502
+ ],
503
+
504
+ defaultParams: {
505
+ a: 1.89,
506
+ },
507
+
508
+ defaultDt: 0.005,
509
+
510
+ derivatives(point, params = this.defaultParams) {
511
+ const { a } = { ...this.defaultParams, ...params };
512
+ const { x, y, z } = point;
513
+
514
+ return {
515
+ dx: -a * x - 4 * y - 4 * z - y * y,
516
+ dy: -a * y - 4 * z - 4 * x - z * z,
517
+ dz: -a * z - 4 * x - 4 * y - x * x,
518
+ };
519
+ },
520
+
521
+ step(point, dt = this.defaultDt, params = this.defaultParams) {
522
+ const d = this.derivatives(point, params);
523
+ const speed = Math.sqrt(d.dx * d.dx + d.dy * d.dy + d.dz * d.dz);
524
+
525
+ return {
526
+ position: {
527
+ x: point.x + d.dx * dt,
528
+ y: point.y + d.dy * dt,
529
+ z: point.z + d.dz * dt,
530
+ },
531
+ velocity: d,
532
+ speed,
533
+ };
534
+ },
535
+
536
+ createStepper(params = this.defaultParams) {
537
+ const mergedParams = { ...this.defaultParams, ...params };
538
+ return (point, dt = this.defaultDt) => this.step(point, dt, mergedParams);
539
+ },
540
+ };
541
+
542
+ // ─────────────────────────────────────────────────────────────────────────────
543
+ // DE JONG ATTRACTOR
544
+ // ─────────────────────────────────────────────────────────────────────────────
545
+
546
+ /**
547
+ * De Jong Attractor (Peter de Jong)
548
+ *
549
+ * A 2D iterative attractor similar to Clifford, creating beautiful
550
+ * swirling patterns.
551
+ *
552
+ * Equations:
553
+ * x_{n+1} = sin(a·y_n) - cos(b·x_n)
554
+ * y_{n+1} = sin(c·x_n) - cos(d·y_n)
555
+ *
556
+ * Default parameters: a=-2.24, b=-0.65, c=-0.43, d=-2.43
557
+ */
558
+ const deJong = {
559
+ name: "De Jong",
560
+ type: AttractorType.ITERATIVE,
561
+ dimension: AttractorDimension.TWO_D,
562
+
563
+ equations: [
564
+ "x_{n+1} = sin(a·y_n) - cos(b·x_n)",
565
+ "y_{n+1} = sin(c·x_n) - cos(d·y_n)",
566
+ ],
567
+
568
+ defaultParams: {
569
+ a: -2.24,
570
+ b: -0.65,
571
+ c: -0.43,
572
+ d: -2.43,
573
+ },
574
+
575
+ next(point, params = this.defaultParams) {
576
+ const { a, b, c, d } = { ...this.defaultParams, ...params };
577
+ const { x, y } = point;
578
+
579
+ return {
580
+ x: Math.sin(a * y) - Math.cos(b * x),
581
+ y: Math.sin(c * x) - Math.cos(d * y),
582
+ };
583
+ },
584
+
585
+ step(point, _dt, params = this.defaultParams) {
586
+ const newPos = this.next(point, params);
587
+ const dx = newPos.x - point.x;
588
+ const dy = newPos.y - point.y;
589
+ const speed = Math.sqrt(dx * dx + dy * dy);
590
+
591
+ return {
592
+ position: newPos,
593
+ velocity: { dx, dy, dz: 0 },
594
+ speed,
595
+ };
596
+ },
597
+
598
+ createStepper(params = this.defaultParams) {
599
+ const mergedParams = { ...this.defaultParams, ...params };
600
+ return (point, _dt) => this.step(point, _dt, mergedParams);
601
+ },
602
+ };
603
+
604
+ // ─────────────────────────────────────────────────────────────────────────────
605
+ // EXPORTS
606
+ // ─────────────────────────────────────────────────────────────────────────────
607
+
608
+ /**
609
+ * Collection of all attractor functions
610
+ */
611
+ export const Attractors = {
612
+ lorenz,
613
+ dadras,
614
+ aizawa,
615
+ thomas,
616
+ clifford,
617
+ rossler,
618
+ halvorsen,
619
+ deJong,
620
+ };
621
+
622
+ /**
623
+ * Get list of all available attractor names
624
+ * @returns {string[]}
625
+ */
626
+ export function getAttractorNames() {
627
+ return Object.keys(Attractors);
628
+ }
629
+
630
+ /**
631
+ * Get attractor by name
632
+ * @param {string} name - Attractor name
633
+ * @returns {Object|null}
634
+ */
635
+ export function getAttractor(name) {
636
+ return Attractors[name] || null;
637
+ }
638
+
639
+ /**
640
+ * Get all 3D attractors
641
+ * @returns {Object}
642
+ */
643
+ export function get3DAttractors() {
644
+ return Object.fromEntries(
645
+ Object.entries(Attractors).filter(
646
+ ([, attr]) => attr.dimension === AttractorDimension.THREE_D
647
+ )
648
+ );
649
+ }
650
+
651
+ /**
652
+ * Get all 2D attractors
653
+ * @returns {Object}
654
+ */
655
+ export function get2DAttractors() {
656
+ return Object.fromEntries(
657
+ Object.entries(Attractors).filter(
658
+ ([, attr]) => attr.dimension === AttractorDimension.TWO_D
659
+ )
660
+ );
661
+ }
662
+
663
+ // Default export
664
+ export default Attractors;