@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,628 @@
1
+ import {
2
+ Game,
3
+ GameObject,
4
+ FPSCounter,
5
+ Text,
6
+ Tween,
7
+ Painter,
8
+ Scene,
9
+ ShapeGOFactory,
10
+ TileLayout,
11
+ Motion,
12
+ Tweenetik,
13
+ Easing,
14
+ Line,
15
+ Rectangle,
16
+ Square,
17
+ RoundedRectangle,
18
+ Diamond,
19
+ Triangle,
20
+ Hexagon,
21
+ Polygon,
22
+ Star,
23
+ PieSlice,
24
+ Circle,
25
+ Arc,
26
+ BezierShape,
27
+ Ring,
28
+ Cube,
29
+ Prism,
30
+ Cylinder,
31
+ Cone,
32
+ Sphere,
33
+ Arrow,
34
+ Pin,
35
+ Cross,
36
+ StickFigure,
37
+ Heart,
38
+ Group,
39
+ TextShape,
40
+ applyAnchor,
41
+ Position,
42
+ } from "../../src/index";
43
+
44
+ const CONFIG = {
45
+ headerHeight: 80, // Space reserved for title + subtitle (30px title offset + 60px subtitle offset + spacing)
46
+ margin: 40, // Horizontal/vertical margins for viewport calculation
47
+ bottomMargin: 70, // Space reserved for FPS counter at bottom (with margin above it)
48
+ };
49
+
50
+ class ShapeGalleryGame extends Game {
51
+ constructor(canvas) {
52
+ super(canvas);
53
+ this.backgroundColor = "#fff";
54
+ this.enableFluidSize();
55
+ this.cellSize = 120;
56
+ this.maxColumns = 5;
57
+ }
58
+
59
+ /**
60
+ * Get viewport dimensions for scrolling based on available space.
61
+ * Accounts for header (title + subtitle), bottom margin (FPS counter), and margins.
62
+ * @returns {{width: number, height: number}} Viewport dimensions
63
+ */
64
+ getViewportDimensions() {
65
+ const availableHeight = this.canvas.height - CONFIG.headerHeight - CONFIG.bottomMargin - CONFIG.margin;
66
+ const availableWidth = this.canvas.width - CONFIG.margin * 2;
67
+ return {
68
+ width: Math.max(200, availableWidth),
69
+ height: Math.max(200, availableHeight),
70
+ };
71
+ }
72
+
73
+ init() {
74
+ super.init();
75
+ this.shapeEntries = [
76
+ {
77
+ name: "Cube",
78
+ class: Cube,
79
+ args: [50],
80
+ options: {
81
+ y: -10,
82
+ opacity: 0.8,
83
+ scaleX: 0.7,
84
+ scaleY: 0.7,
85
+ faceTopColor: Painter.colors.randomColorHSL(),
86
+ faceLeftColor: Painter.colors.randomColorHSL(),
87
+ faceRightColor: Painter.colors.randomColorHSL(),
88
+ faceFrontColor: Painter.colors.randomColorHSL(),
89
+ faceBackColor: Painter.colors.randomColorHSL(),
90
+ faceBottomColor: Painter.colors.randomColorHSL(),
91
+ strokeColor: "black",
92
+ lineWidth: 1,
93
+ },
94
+ },
95
+ {
96
+ name: "Sphere",
97
+ class: Sphere,
98
+ args: [25],
99
+ options: {
100
+ y: -10,
101
+ width: 50,
102
+ height: 50,
103
+ color: Painter.colors.randomColorHSL(),
104
+ highlightColor: "white",
105
+ hSegments: 16, // Fewer segments for wireframe
106
+ vSegments: 16,
107
+ wireframe: true, // Wireframe rendering
108
+ stroke: "#CCC",
109
+ lineWidth: 1,
110
+ rotationX: Math.PI / 8,
111
+ rotationY: 0,
112
+ rotationZ: 0,
113
+ },
114
+ },
115
+ {
116
+ name: "Cone",
117
+ class: Cone,
118
+ args: [20, 40],
119
+ options: {
120
+ x: -2,
121
+ y: -10,
122
+ bottomColor: "#FF00FF",
123
+ sideColor: "#00FF00",
124
+ segments: 16, // Higher for smoother appearance
125
+ stroke: "#333",
126
+ lineWidth: 1,
127
+ },
128
+ },
129
+ {
130
+ name: "Cylinder",
131
+ class: Cylinder,
132
+ args: [10],
133
+ options: {
134
+ y: -10,
135
+ width: 40,
136
+ height: 60,
137
+ topColor: Painter.colors.randomColorHSL(),
138
+ bottomColor: Painter.colors.randomColorHSL(),
139
+ sideColor: Painter.colors.randomColorHSL(),
140
+ rotationX: -45,
141
+ segments: 16, // Higher number for smoother curve
142
+ stroke: "black",
143
+ lineWidth: 1,
144
+ },
145
+ },
146
+ {
147
+ name: "Prism",
148
+ class: Prism,
149
+ args: [50],
150
+ options: {
151
+ y: -20,
152
+ width: 50,
153
+ height: 50,
154
+ scaleX: 0.7,
155
+ scaleY: 0.7,
156
+ faceFrontColor: "#6495ED",
157
+ faceBackColor: "#4169E1",
158
+ faceBottomColor: "#1E90FF",
159
+ faceLeftColor: "#00BFFF",
160
+ faceRightColor: "#87CEFA",
161
+ stroke: "#000",
162
+ lineWidth: 1,
163
+ },
164
+ },
165
+ {
166
+ name: "Line",
167
+ class: Line,
168
+ args: [40],
169
+ options: { stroke: "black", lineWidth: 3 },
170
+ },
171
+ {
172
+ name: "Bezier",
173
+ class: BezierShape,
174
+ args: [
175
+ [
176
+ ["M", -40, 0],
177
+ ["C", -30, -30, -10, -30, 0, 0],
178
+ ["C", 10, 30, 30, 30, 40, 0],
179
+ ],
180
+ ],
181
+ options: {
182
+ y: -10,
183
+ color: Painter.colors.randomColorHSL(),
184
+ stroke: Painter.colors.randomColorHSL(),
185
+ lineWidth: 3,
186
+ },
187
+ },
188
+ {
189
+ name: "Bezier (Filled)",
190
+ class: BezierShape,
191
+ args: [
192
+ [
193
+ ["M", -60, 0],
194
+ ["C", -60, -20, -20, -20, 0, 0],
195
+ ["C", 20, 20, 60, 20, 60, 0],
196
+ ["C", 60, -20, 20, -20, 0, 0],
197
+ ["C", -20, 20, -60, 20, -60, 0],
198
+ ["Z"],
199
+ ],
200
+ ],
201
+ options: {
202
+ scaleX: 0.7,
203
+ scaleY: 0.7,
204
+ y: -10,
205
+ color: Painter.colors.randomColorHSL(),
206
+ stroke: Painter.colors.randomColorHSL(),
207
+ lineWidth: 3,
208
+ },
209
+ },
210
+ {
211
+ name: "Pin",
212
+ class: Pin,
213
+ args: [16],
214
+ options: {
215
+ color: Painter.colors.randomColorHSL(),
216
+ stroke: "black",
217
+ lineWidth: 2,
218
+ scaleX: 0.9,
219
+ scaleY: 0.9,
220
+ y: -20,
221
+ },
222
+ },
223
+ {
224
+ name: "Heart",
225
+ class: Heart,
226
+ args: [],
227
+ options: {
228
+ width: 50,
229
+ height: 50,
230
+ color: Painter.colors.randomColorHSL(),
231
+ stroke: "black",
232
+ lineWidth: 2,
233
+ y: -35,
234
+ },
235
+ },
236
+ {
237
+ name: "Rounded Rect",
238
+ class: RoundedRectangle,
239
+ args: [10],
240
+ options: {
241
+ width: 50,
242
+ height: 50,
243
+ y: -10,
244
+ color: Painter.colors.randomColorHSL(),
245
+ stroke: "black",
246
+ lineWidth: 2,
247
+ crisp: true,
248
+ },
249
+ },
250
+ {
251
+ name: "Rectangle",
252
+ class: Rectangle,
253
+ args: [],
254
+ options: {
255
+ width: 70,
256
+ height: 50,
257
+ y: -5,
258
+ color: Painter.colors.randomColorHSL(),
259
+ stroke: "black",
260
+ lineWidth: 2,
261
+ crisp: true,
262
+ },
263
+ },
264
+ {
265
+ name: "Square",
266
+ class: Square,
267
+ args: [50],
268
+ options: {
269
+ y: -5,
270
+ color: Painter.colors.randomColorHSL(),
271
+ stroke: "black",
272
+ lineWidth: 2,
273
+ crisp: true,
274
+ },
275
+ },
276
+ {
277
+ name: "Diamond",
278
+ class: Diamond,
279
+ args: [],
280
+ options: {
281
+ y: -10,
282
+ width: 60,
283
+ height: 60,
284
+ color: Painter.colors.randomColorHSL(),
285
+ stroke: "black",
286
+ lineWidth: 2,
287
+ },
288
+ },
289
+
290
+ {
291
+ name: "Triangle",
292
+ class: Triangle,
293
+ args: [50],
294
+ options: {
295
+ y: -10,
296
+ color: Painter.colors.randomColorHSL(),
297
+ stroke: "black",
298
+ lineWidth: 2,
299
+ },
300
+ },
301
+ {
302
+ name: "Hexagon",
303
+ class: Hexagon,
304
+ args: [30],
305
+ options: {
306
+ y: -10,
307
+ color: Painter.colors.randomColorHSL(),
308
+ stroke: "black",
309
+ lineWidth: 2,
310
+ },
311
+ },
312
+ {
313
+ name: "Polygon",
314
+ class: Polygon,
315
+ args: [9, 30],
316
+ options: {
317
+ y: -10,
318
+ color: Painter.colors.randomColorHSL(),
319
+ stroke: "black",
320
+ lineWidth: 2,
321
+ },
322
+ },
323
+ {
324
+ name: "Star",
325
+ class: Star,
326
+ args: [30, 5, 0.5],
327
+ options: {
328
+ y: -10,
329
+ color: Painter.colors.randomColorHSL(),
330
+ stroke: "black",
331
+ lineWidth: 2,
332
+ },
333
+ },
334
+ {
335
+ name: "Circle",
336
+ class: Circle,
337
+ args: [30],
338
+ options: {
339
+ color: Painter.colors.randomColorHSL(),
340
+ stroke: "black",
341
+ lineWidth: 2,
342
+ y: -10,
343
+ },
344
+ },
345
+ {
346
+ name: "PieSlice",
347
+ class: PieSlice,
348
+ args: [30, 0, Math.PI * 1.5],
349
+ options: {
350
+ color: Painter.colors.randomColorHSL(),
351
+ stroke: "black",
352
+ lineWidth: 2,
353
+ y: -10,
354
+ },
355
+ },
356
+ {
357
+ name: "Arc",
358
+ class: Arc,
359
+ args: [28, 0, Math.PI * 1.5],
360
+ options: {
361
+ y: -10,
362
+ stroke: Painter.colors.randomColorHSL(),
363
+ lineWidth: 10,
364
+ },
365
+ },
366
+ {
367
+ name: "Ring",
368
+ class: Ring,
369
+ args: [30, 20],
370
+ options: {
371
+ color: Painter.colors.randomColorHSL(),
372
+ y: -10,
373
+ },
374
+ },
375
+ {
376
+ name: "Arrow",
377
+ class: Arrow,
378
+ args: [60],
379
+ options: {
380
+ width: 20,
381
+ height: 25,
382
+ color: Painter.colors.randomColorHSL(),
383
+ stroke: "black",
384
+ lineWidth: 2,
385
+ x: -5,
386
+ y: -10,
387
+ },
388
+ },
389
+ {
390
+ name: "Cross",
391
+ class: Cross,
392
+ args: [50, 10],
393
+ options: {
394
+ color: Painter.colors.randomColorHSL(),
395
+ stroke: "black",
396
+ lineWidth: 2,
397
+ y: -10,
398
+ },
399
+ },
400
+ {
401
+ name: "StickFigure",
402
+ class: StickFigure,
403
+ args: [0.5],
404
+ options: {
405
+ y: -10,
406
+ strokeColor: "#111",
407
+ headColor: Painter.colors.randomColorHSL(),
408
+ jointColor: "#111",
409
+ lineWidth: 2,
410
+ showJoints: false,
411
+ },
412
+ },
413
+ ];
414
+ // FPS Counter
415
+ this.pipeline.add(
416
+ new FPSCounter(this, { color: "black", anchor: "bottom-right" })
417
+ );
418
+ // Title
419
+ this.pipeline.add(
420
+ applyAnchor(new Text(this, "GCanvas Shape Gallery", {
421
+ font: "bold 24px monospace",
422
+ color: "#222",
423
+ }), { anchor: Position.TOP_CENTER, anchorOffsetY: 30 })
424
+ );
425
+
426
+ // Subtitle
427
+ this.pipeline.add(
428
+ applyAnchor(new Text(this, "Mouse over any shape to rotate or animate it", {
429
+ font: "16px monospace",
430
+ color: "#666",
431
+ }), { anchor: Position.TOP_CENTER, anchorOffsetY: 60 })
432
+ );
433
+ this.events.on("click", (e) => {
434
+ this.gallery.children.forEach((go) => {
435
+ go.entry.shape.color = Painter.colors.randomColorHSL();
436
+ if (
437
+ go.entry.class.name === "BezierShape" ||
438
+ go.entry.class.name == "Arc" ||
439
+ go.entry.class.name == "StickFigure"
440
+ ) {
441
+ go.entry.shape.headColor = Painter.colors.randomColorHSL();
442
+ go.entry.shape.stroke = Painter.colors.randomColorHSL();
443
+ }
444
+ if (
445
+ go.entry.name === "Sphere" ||
446
+ go.entry.name == "Cube" ||
447
+ go.entry.name === "Prism" ||
448
+ go.entry.name === "Cylinder" ||
449
+ go.entry.name === "Cone"
450
+ ) {
451
+ go.entry.shape.faceTopColor = Painter.colors.randomColorHSL();
452
+ go.entry.shape.faceBottomColor = Painter.colors.randomColorHSL();
453
+ go.entry.shape.faceLeftColor = Painter.colors.randomColorHSL();
454
+ go.entry.shape.faceRightColor = Painter.colors.randomColorHSL();
455
+ go.entry.shape.faceFrontColor = Painter.colors.randomColorHSL();
456
+ go.entry.shape.faceBackColor = Painter.colors.randomColorHSL();
457
+ go.entry.shape.topColor = Painter.colors.randomColorHSL();
458
+ go.entry.shape.bottomColor = Painter.colors.randomColorHSL();
459
+ go.entry.shape.sideColor = Painter.colors.randomColorHSL();
460
+ }
461
+ });
462
+ });
463
+ this.createGallery();
464
+ this.onResize();
465
+ }
466
+
467
+ onResize() {
468
+ if (this.gallery) {
469
+ // Calculate responsive columns based on available width
470
+ const availableWidth = this.canvas.width - CONFIG.margin;
471
+ const columns = Math.min(this.maxColumns, Math.max(1, Math.floor(availableWidth / this.cellSize)));
472
+
473
+ if (this.gallery.columns !== columns) {
474
+ this.gallery.columns = columns;
475
+ // Trigger layout update
476
+ this.gallery.markBoundsDirty();
477
+ }
478
+
479
+ // Update viewport dimensions for scrolling
480
+ const viewport = this.getViewportDimensions();
481
+ this.gallery._viewportWidth = viewport.width;
482
+ this.gallery._viewportHeight = viewport.height;
483
+
484
+ // Update anchor offset to position gallery below header
485
+ this.gallery.anchorOffsetY = CONFIG.headerHeight / 2 + 20; // Position below header with spacing
486
+
487
+ // Mark bounds dirty to trigger layout recalculation
488
+ this.gallery.markBoundsDirty();
489
+ }
490
+ }
491
+
492
+ createGallery() {
493
+ const cellSize = this.cellSize;
494
+ const initialColumns = Math.min(this.maxColumns, Math.max(1, Math.floor((this.canvas.width - CONFIG.margin) / cellSize)));
495
+ const viewport = this.getViewportDimensions();
496
+
497
+ const gallery = new TileLayout(this, {
498
+ debug: true,
499
+ debugColor: "grey",
500
+ columns: initialColumns,
501
+ spacing: 10,
502
+ // Enable scrolling with responsive viewport
503
+ scrollable: true,
504
+ viewportWidth: viewport.width,
505
+ viewportHeight: viewport.height,
506
+ // Use anchor positioning instead of manual transform.position()
507
+ anchor: Position.CENTER,
508
+ anchorOffsetY: CONFIG.headerHeight / 2 + 20, // Position below header with spacing
509
+ autoSize: true,
510
+ });
511
+
512
+ this.shapeEntries.forEach((entry, index) => {
513
+ //const col = index % cols;
514
+ //const row = Math.floor(index / cols);
515
+ //const x = originX + col * (cellSize + spacing) + cellSize / 2;
516
+ //const y = originY + row * (cellSize + spacing) + cellSize / 2;
517
+ //
518
+ const group = new Group();
519
+ // Use Transform API to set group dimensions
520
+ group.transform.size(cellSize, cellSize);
521
+ const bg = new Rectangle({
522
+ width: cellSize - 10,
523
+ height: cellSize - 10,
524
+ stroke: "rgba(0,0,0,0.1)",
525
+ lineWidth: 1,
526
+ });
527
+ const shape = new entry.class(...entry.args, entry.options);
528
+ entry.shape = shape;
529
+ const label = new TextShape(entry.name, {
530
+ x: 0,
531
+ y: (cellSize - 10) / 2 - 12,
532
+ font: "12px monospace",
533
+ color: "#333",
534
+ align: "center",
535
+ baseline: "bottom",
536
+ });
537
+ group.add(bg);
538
+ group.add(shape);
539
+ group.add(label);
540
+ //
541
+ //
542
+ const go = ShapeGOFactory.create(this, group, {
543
+ interactive: true,
544
+ name: entry.name,
545
+ width: cellSize,
546
+ height: cellSize,
547
+ scaleX: 1,
548
+ scaleY: 1,
549
+ });
550
+ go.entry = entry;
551
+ // Use Transform API for initial state
552
+ go.transform
553
+ .rotation(0)
554
+ .size(cellSize, cellSize);
555
+ go.rotationVelocity = 0;
556
+ go.startTime = 0;
557
+ go.tweening = false;
558
+ const game = this;
559
+ go.on("mouseover", () => {
560
+ // Use Transform API to reset scale
561
+ go.transform.scale(1);
562
+ game.canvas.style.cursor = "pointer";
563
+ Tweenetik.to(
564
+ group,
565
+ { scaleX: 1.3, scaleY: 1.3 },
566
+ 1, // duration
567
+ Easing.easeOutElastic,
568
+ { onComplete: () => (go.tweening = false) }
569
+ );
570
+ go.tweening = true;
571
+ });
572
+ go.on("mouseout", () => {
573
+ game.canvas.style.cursor = "default";
574
+ Tweenetik.to(
575
+ group, // the shape to scale
576
+ { scaleX: 1, scaleY: 1 },
577
+ 1, // duration
578
+ Easing.easeOutElastic
579
+ );
580
+ });
581
+ function update(dt) {
582
+ if (go.entry.name === "Hexagon") {
583
+ //console.log(go.scaleX, go.scaleY);
584
+ }
585
+ if (
586
+ go.entry.name === "Sphere" ||
587
+ go.entry.name == "Cube" ||
588
+ go.entry.name === "Prism" ||
589
+ go.entry.name === "Cylinder" ||
590
+ go.entry.name === "Cone"
591
+ ) {
592
+ const entry = go.entry;
593
+ const game = go.game;
594
+ //console.log(e);
595
+ function animate() {
596
+ if (!go.startTime) go.startTime = game.lastTime;
597
+ const elapsed = game.lastTime - go.startTime;
598
+ // Calculate rotation angles
599
+ // Calculate rotation angles (convert to radians)
600
+ const rotationSpeed = 0.001;
601
+ const xRotation = (Math.sin(elapsed * 0.0005) * Math.PI) / 4;
602
+ const yRotation =
603
+ (elapsed * rotationSpeed * 0.0005) % (Math.PI * 2);
604
+ const zRotation = (Math.cos(elapsed * 0.0003) * Math.PI) / 6;
605
+
606
+ // Apply rotations
607
+ entry.shape.setRotation(xRotation, yRotation, zRotation);
608
+ }
609
+ animate();
610
+ }
611
+ }
612
+ gallery.add(go);
613
+ go.onUpdate = update;
614
+ });
615
+ this.gallery = gallery;
616
+ this.pipeline.add(this.gallery);
617
+ }
618
+ }
619
+
620
+ window.addEventListener("load", () => {
621
+ const canvas = document.getElementById("game");
622
+ const game = new ShapeGalleryGame(canvas);
623
+ game.setFPS(60);
624
+ game.enablePauseOnBlur(true);
625
+ //game.enableLogging();
626
+ game.start();
627
+ //setTimeout(game.stop.bind(game), 10000);
628
+ });