@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,555 @@
1
+ /**
2
+ * Pipeline Demo Initializations
3
+ *
4
+ * Each function creates a demo on a specific canvas element,
5
+ * showcasing different layers of the rendering pipeline.
6
+ */
7
+
8
+ import {
9
+ Game,
10
+ Rectangle,
11
+ Circle,
12
+ Triangle,
13
+ TextShape,
14
+ Group,
15
+ Line,
16
+ Painter,
17
+ Motion,
18
+ Easing,
19
+ GameObject,
20
+ } from '../../src/index.js';
21
+
22
+ // ─────────────────────────────────────────────────────────
23
+ // Demo 1: Euclidian - Basic positioning (point in space)
24
+ // ─────────────────────────────────────────────────────────
25
+
26
+ function initEuclidianDemo() {
27
+ const canvas = document.getElementById('euclidian-canvas');
28
+ if (!canvas) return;
29
+
30
+ const game = new Game(canvas);
31
+ game.backgroundColor = '#000';
32
+ game.enableFluidSize(canvas.parentElement);
33
+ game.init();
34
+
35
+ // Grid GameObject that renders the cartesian plane
36
+ class GridGameObject extends GameObject {
37
+ constructor(game, options = {}) {
38
+ super(game, options);
39
+ this.zIndex = -1000; // Render grid first (lowest z-index)
40
+ this.game = game;
41
+ }
42
+
43
+ draw() {
44
+ super.draw();
45
+ Painter.useCtx((ctx) => {
46
+ const width = this.game.width;
47
+ const height = this.game.height;
48
+ const centerX = width / 2;
49
+ const centerY = height / 2;
50
+
51
+ // Draw grid lines (thin, 1px) - subtle grey
52
+ ctx.strokeStyle = '#1a1a1a';
53
+ ctx.lineWidth = 1;
54
+
55
+ // Vertical lines
56
+ for (let x = 0; x <= width; x += 5) {
57
+ ctx.beginPath();
58
+ ctx.moveTo(x, 0);
59
+ ctx.lineTo(x, height);
60
+ ctx.stroke();
61
+ }
62
+
63
+ // Horizontal lines
64
+ for (let y = 0; y <= height; y += 5) {
65
+ ctx.beginPath();
66
+ ctx.moveTo(0, y);
67
+ ctx.lineTo(width, y);
68
+ ctx.stroke();
69
+ }
70
+
71
+ // Draw center axes (terminal green)
72
+ ctx.strokeStyle = '#0f0';
73
+ ctx.lineWidth = 1;
74
+ ctx.beginPath();
75
+ // Vertical axis
76
+ ctx.moveTo(centerX, 0);
77
+ ctx.lineTo(centerX, height);
78
+ // Horizontal axis
79
+ ctx.moveTo(0, centerY);
80
+ ctx.lineTo(width, centerY);
81
+ ctx.stroke();
82
+ });
83
+ }
84
+ }
85
+
86
+ // Create a point (circle) representing the Euclidian position
87
+ const point = new Circle(6, {
88
+ x: 100,
89
+ y: 100,
90
+ color: '#333',
91
+ stroke: '#0f0',
92
+ lineWidth: 1
93
+ });
94
+
95
+ // Create text labels showing coordinates
96
+ const coordLabel = new TextShape('(100, 100)', {
97
+ x: 100,
98
+ y: 100,
99
+ color: '#0f0',
100
+ font: '12px monospace',
101
+ align: 'center',
102
+ baseline: 'top',
103
+ opacity: 0.9
104
+ });
105
+
106
+ // Create and add grid to pipeline
107
+ const grid = new GridGameObject(game);
108
+
109
+ // Animate the point moving around
110
+ let animTime = 0;
111
+ const originalUpdate = game.update.bind(game);
112
+
113
+ game.update = function(dt) {
114
+ originalUpdate(dt);
115
+ animTime += dt;
116
+
117
+ const centerX = game.width / 2;
118
+ const centerY = game.height / 2;
119
+
120
+ // Move point in a circular pattern
121
+ const radius = Math.min(game.width, game.height) * 0.2;
122
+ point.x = centerX + Math.cos(animTime * 0.8) * radius;
123
+ point.y = centerY + Math.sin(animTime * 0.8) * radius;
124
+
125
+ // Update coordinate label
126
+ coordLabel.x = point.x;
127
+ coordLabel.y = point.y + 15; // Position below the point
128
+ coordLabel.text = `(${Math.round(point.x)}, ${Math.round(point.y)})`;
129
+ };
130
+
131
+ // Add objects to pipeline (grid first so it renders behind)
132
+ game.pipeline.add(grid);
133
+ game.pipeline.add(point);
134
+ game.pipeline.add(coordLabel);
135
+ game.start();
136
+ }
137
+
138
+ // ─────────────────────────────────────────────────────────
139
+ // Demo 2: Geometry2d - Bounds and constraints
140
+ // ─────────────────────────────────────────────────────────
141
+
142
+ function initGeometry2dDemo() {
143
+ const canvas = document.getElementById('geometry2d-canvas');
144
+ if (!canvas) return;
145
+
146
+ const game = new Game(canvas);
147
+ game.backgroundColor = '#000';
148
+ game.enableFluidSize(canvas.parentElement);
149
+ game.init();
150
+
151
+ let animTime = 0;
152
+ const originalUpdate = game.update.bind(game);
153
+
154
+ // Create a constrained shape (positioned relative to game center)
155
+ let constrainedShape, constraintBounds;
156
+
157
+ game.update = function(dt) {
158
+ originalUpdate(dt);
159
+
160
+ // Initialize shapes on first update when game dimensions are available
161
+ if (!constrainedShape) {
162
+ const centerX = game.width / 2;
163
+ const centerY = game.height / 2;
164
+ const constraintSize = Math.min(game.width, game.height) * 0.3;
165
+
166
+ constrainedShape = new Rectangle({
167
+ x: centerX,
168
+ y: centerY,
169
+ width: 50,
170
+ height: 30,
171
+ minX: centerX - constraintSize / 2,
172
+ maxX: centerX + constraintSize / 2,
173
+ minY: centerY - constraintSize / 2,
174
+ maxY: centerY + constraintSize / 2,
175
+ crisp: true,
176
+ color: '#333',
177
+ stroke: '#0f0',
178
+ lineWidth: 1,
179
+ debug: false
180
+ });
181
+
182
+ constraintBounds = new Rectangle({
183
+ x: centerX,
184
+ y: centerY,
185
+ width: constraintSize,
186
+ height: constraintSize,
187
+ color: null,
188
+ stroke: '#0f0',
189
+ lineWidth: 1,
190
+ debug: false
191
+ });
192
+
193
+ game.pipeline.add(constraintBounds);
194
+ game.pipeline.add(constrainedShape);
195
+ }
196
+
197
+ animTime += dt;
198
+ const centerX = game.width / 2;
199
+ const centerY = game.height / 2;
200
+ const constraintSize = Math.min(game.width, game.height) * 0.3;
201
+
202
+ // Update constraints dynamically
203
+ constrainedShape.minX = centerX - constraintSize / 2;
204
+ constrainedShape.maxX = centerX + constraintSize / 2;
205
+ constrainedShape.minY = centerY - constraintSize / 2;
206
+ constrainedShape.maxY = centerY + constraintSize / 2;
207
+
208
+ // Try to move outside constraints - will be constrained
209
+ const radius = constraintSize * 0.6;
210
+ constrainedShape.x = centerX + Math.sin(animTime * 0.5) * radius;
211
+ constrainedShape.y = centerY + Math.cos(animTime * 0.5) * radius;
212
+ constrainedShape.update(); // Apply constraints
213
+
214
+ // Update constraint bounds visualization
215
+ constraintBounds.x = centerX;
216
+ constraintBounds.y = centerY;
217
+ constraintBounds.width = constraintSize;
218
+ constraintBounds.height = constraintSize;
219
+
220
+ // Show actual bounds of the constrained shape
221
+ const bounds = constrainedShape.getBounds();
222
+ // Convert top-left bounds to center coordinates for Rectangle
223
+ constraintBounds.x = bounds.x + bounds.width / 2;
224
+ constraintBounds.y = bounds.y + bounds.height / 2;
225
+ constraintBounds.width = bounds.width;
226
+ constraintBounds.height = bounds.height;
227
+ };
228
+
229
+ game.start();
230
+ }
231
+
232
+ // ─────────────────────────────────────────────────────────
233
+ // Demo 3: Renderable - Opacity and shadows
234
+ // ─────────────────────────────────────────────────────────
235
+
236
+ function initRenderableDemo() {
237
+ const canvas = document.getElementById('renderable-canvas');
238
+ if (!canvas) return;
239
+
240
+ const game = new Game(canvas);
241
+ game.backgroundColor = '#000';
242
+ game.enableFluidSize(canvas.parentElement);
243
+ game.init();
244
+
245
+ let shape1, shape2, shape3;
246
+ let animTime = 0;
247
+ const originalUpdate = game.update.bind(game);
248
+
249
+ game.update = function(dt) {
250
+ originalUpdate(dt);
251
+
252
+ // Initialize shapes on first update when game dimensions are available
253
+ if (!shape1) {
254
+ const centerX = game.width / 2;
255
+ const centerY = game.height / 2;
256
+ const spacing = Math.min(game.width, game.height) * 0.25;
257
+
258
+ shape1 = new Rectangle({
259
+ x: centerX - spacing,
260
+ y: centerY,
261
+ width: 50,
262
+ height: 30,
263
+ visible: true,
264
+ opacity: 0.8,
265
+ shadowColor: 'rgba(0,255,0,0.3)',
266
+ shadowBlur: 8,
267
+ shadowOffsetX: 2,
268
+ shadowOffsetY: 2,
269
+ color: '#1a1a1a',
270
+ stroke: '#0f0',
271
+ lineWidth: 1
272
+ });
273
+
274
+ shape2 = new Circle(25, {
275
+ x: centerX,
276
+ y: centerY,
277
+ opacity: 0.7,
278
+ shadowColor: 'rgba(0,255,0,0.3)',
279
+ shadowBlur: 10,
280
+ shadowOffsetX: 3,
281
+ shadowOffsetY: 3,
282
+ color: '#2a2a2a',
283
+ stroke: '#0f0',
284
+ lineWidth: 1
285
+ });
286
+
287
+ shape3 = new Triangle({
288
+ x: centerX + spacing,
289
+ y: centerY,
290
+ size: 30,
291
+ opacity: 0.9,
292
+ shadowColor: 'rgba(0,255,0,0.3)',
293
+ shadowBlur: 8,
294
+ shadowOffsetX: -2,
295
+ shadowOffsetY: 2,
296
+ color: '#1a1a1a',
297
+ stroke: '#0f0',
298
+ lineWidth: 1
299
+ });
300
+
301
+ game.pipeline.add(shape1);
302
+ game.pipeline.add(shape2);
303
+ game.pipeline.add(shape3);
304
+ }
305
+
306
+ animTime += dt;
307
+ shape1.opacity = 0.5 + Math.sin(animTime * 2) * 0.3;
308
+ shape2.opacity = 0.3 + Math.cos(animTime * 1.5) * 0.4;
309
+ shape3.opacity = 0.7 + Math.sin(animTime * 1.8) * 0.2;
310
+ };
311
+ game.start();
312
+ }
313
+
314
+ // ─────────────────────────────────────────────────────────
315
+ // Demo 4: Transformable - Rotation and scaling
316
+ // ─────────────────────────────────────────────────────────
317
+
318
+ function initTransformableDemo() {
319
+ const canvas = document.getElementById('transformable-canvas');
320
+ if (!canvas) return;
321
+
322
+ const game = new Game(canvas);
323
+ game.backgroundColor = '#000';
324
+ game.enableFluidSize(canvas.parentElement);
325
+ game.init();
326
+
327
+ let shape1, shape2, shape3;
328
+ let animTime = 0;
329
+ const originalUpdate = game.update.bind(game);
330
+
331
+ game.update = function(dt) {
332
+ originalUpdate(dt);
333
+
334
+ // Initialize shapes on first update when game dimensions are available
335
+ if (!shape1) {
336
+ const centerX = game.width / 2;
337
+ const centerY = game.height / 2;
338
+ const spacing = Math.min(game.width, game.height) * 0.25;
339
+
340
+ shape1 = new Rectangle({
341
+ x: centerX - spacing,
342
+ y: centerY,
343
+ width: 50,
344
+ height: 30,
345
+ rotation: Math.PI / 4, // 45 degrees
346
+ scaleX: 1.5,
347
+ scaleY: 0.8,
348
+ color: '#1a1a1a',
349
+ stroke: '#0f0',
350
+ lineWidth: 1
351
+ });
352
+
353
+ shape2 = new Circle(20, {
354
+ x: centerX,
355
+ y: centerY,
356
+ rotation: 0,
357
+ scaleX: 1.2,
358
+ scaleY: 1.2,
359
+ color: '#2a2a2a',
360
+ stroke: '#0f0',
361
+ lineWidth: 1
362
+ });
363
+
364
+ shape3 = new Triangle({
365
+ x: centerX + spacing,
366
+ y: centerY,
367
+ size: 25,
368
+ rotation: Math.PI / 6, // 30 degrees
369
+ scaleX: 2.0,
370
+ scaleY: 2.0,
371
+ color: '#1a1a1a',
372
+ stroke: '#0f0',
373
+ lineWidth: 1
374
+ });
375
+
376
+ game.pipeline.add(shape1);
377
+ game.pipeline.add(shape2);
378
+ game.pipeline.add(shape3);
379
+ }
380
+
381
+ animTime += dt;
382
+ shape1.rotation = Math.PI / 4 + Math.sin(animTime) * 0.3;
383
+ shape1.scaleX = 1.5 + Math.sin(animTime * 2) * 0.3;
384
+ shape1.scaleY = 0.8 + Math.cos(animTime * 2) * 0.2;
385
+
386
+ shape2.rotation = animTime * 0.5;
387
+ shape2.scaleX = 1.2 + Math.sin(animTime * 1.5) * 0.3;
388
+ shape2.scaleY = 1.2 + Math.sin(animTime * 1.5) * 0.3;
389
+
390
+ shape3.rotation = Math.PI / 6 + animTime * 0.8;
391
+ shape3.scaleX = 2.0 + Math.cos(animTime * 1.2) * 0.4;
392
+ shape3.scaleY = 2.0 + Math.cos(animTime * 1.2) * 0.4;
393
+ };
394
+ game.start();
395
+ }
396
+
397
+ // ─────────────────────────────────────────────────────────
398
+ // Demo 5: Shape - Styling properties (fill, stroke)
399
+ // ─────────────────────────────────────────────────────────
400
+
401
+ function initShapeDemo() {
402
+ const canvas = document.getElementById('shape-canvas');
403
+ if (!canvas) return;
404
+
405
+ const game = new Game(canvas);
406
+ game.backgroundColor = '#000';
407
+ game.enableFluidSize(canvas.parentElement);
408
+ game.init();
409
+
410
+ let rect, circle, triangle;
411
+ const originalUpdate = game.update.bind(game);
412
+
413
+ game.update = function(dt) {
414
+ originalUpdate(dt);
415
+
416
+ // Initialize shapes on first update when game dimensions are available
417
+ if (!rect) {
418
+ const centerX = game.width / 2;
419
+ const centerY = game.height / 2;
420
+ const spacing = Math.min(game.width, game.height) * 0.25;
421
+
422
+ rect = new Rectangle({
423
+ x: centerX - spacing,
424
+ y: centerY,
425
+ width: 50,
426
+ height: 30,
427
+ color: '#1a1a1a',
428
+ stroke: '#0f0',
429
+ lineWidth: 1,
430
+ lineJoin: 'miter',
431
+ lineCap: 'butt'
432
+ });
433
+
434
+ circle = new Circle(25, {
435
+ x: centerX,
436
+ y: centerY,
437
+ color: '#2a2a2a',
438
+ stroke: '#0f0',
439
+ lineWidth: 1,
440
+ lineJoin: 'round',
441
+ lineCap: 'round'
442
+ });
443
+
444
+ triangle = new Triangle({
445
+ x: centerX + spacing,
446
+ y: centerY,
447
+ size: 30,
448
+ color: '#1a1a1a',
449
+ stroke: '#0f0',
450
+ lineWidth: 1,
451
+ lineJoin: 'miter',
452
+ lineCap: 'butt'
453
+ });
454
+
455
+ game.pipeline.add(rect);
456
+ game.pipeline.add(circle);
457
+ game.pipeline.add(triangle);
458
+ }
459
+ };
460
+ game.start();
461
+ }
462
+
463
+ // ─────────────────────────────────────────────────────────
464
+ // Demo 6: Group - Composing shapes together
465
+ // ─────────────────────────────────────────────────────────
466
+
467
+ function initGroupDemo() {
468
+ const canvas = document.getElementById('group-canvas');
469
+ if (!canvas) return;
470
+
471
+ const game = new Game(canvas);
472
+ game.backgroundColor = '#000';
473
+ game.enableFluidSize(canvas.parentElement);
474
+ game.init();
475
+
476
+ let group;
477
+ let animTime = 0;
478
+ const originalUpdate = game.update.bind(game);
479
+
480
+ game.update = function(dt) {
481
+ originalUpdate(dt);
482
+
483
+ // Initialize group on first update when game dimensions are available
484
+ if (!group) {
485
+ const centerX = game.width / 2;
486
+ const centerY = game.height / 2;
487
+
488
+ // Create a Group to hold multiple shapes
489
+ group = new Group({
490
+ x: centerX,
491
+ y: centerY
492
+ });
493
+
494
+ // Add shapes to the group - organized geometrically
495
+ const rect = new Rectangle({
496
+ width: 100,
497
+ height: 50,
498
+ color: '#1a1a1a',
499
+ stroke: '#0f0',
500
+ lineWidth: 1
501
+ });
502
+
503
+ const circle = new Circle(25, {
504
+ x: 50,
505
+ y: 0,
506
+ color: '#2a2a2a',
507
+ stroke: '#0f0',
508
+ lineWidth: 1
509
+ });
510
+
511
+ const text = new TextShape('GROUP', {
512
+ x: 0,
513
+ y: 0,
514
+ color: '#0f0',
515
+ align: 'center',
516
+ baseline: 'middle',
517
+ font: '14px monospace'
518
+ });
519
+
520
+ // Add shapes to the group
521
+ group.add(rect);
522
+ group.add(circle);
523
+ group.add(text);
524
+
525
+ // Set initial transformations
526
+ group.rotation = Math.PI / 6; // 30 degrees
527
+ group.scaleX = 1.5;
528
+ group.scaleY = 1.5;
529
+ group.opacity = 0.7;
530
+
531
+ game.pipeline.add(group);
532
+ }
533
+
534
+ animTime += dt;
535
+ group.rotation = Math.PI / 6 + Math.sin(animTime * 0.5) * 0.3;
536
+ group.scaleX = 1.5 + Math.sin(animTime * 1.2) * 0.2;
537
+ group.scaleY = 1.5 + Math.sin(animTime * 1.2) * 0.2;
538
+ group.opacity = 0.7 + Math.cos(animTime * 0.8) * 0.2;
539
+ };
540
+ game.start();
541
+ }
542
+
543
+ // ─────────────────────────────────────────────────────────
544
+ // Initialize all demos on page load
545
+ // ─────────────────────────────────────────────────────────
546
+
547
+ window.addEventListener('load', () => {
548
+ initEuclidianDemo();
549
+ initGeometry2dDemo();
550
+ initRenderableDemo();
551
+ initTransformableDemo();
552
+ initShapeDemo();
553
+ initGroupDemo();
554
+ });
555
+