@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,232 @@
1
+ import { applyAnchor } from "../../mixins";
2
+ import { GameObject } from "./go";
3
+
4
+ /**
5
+ * ShapeGOFactory
6
+ * --------------
7
+ *
8
+ * Utility factory for creating GameObjects from Shapes.
9
+ */
10
+ export class ShapeGOFactory {
11
+ /**
12
+ * Creates a GameObject wrapper around a Shape
13
+ *
14
+ * @param {Game} game - Game instance
15
+ * @param {Shape} shape - Shape to wrap
16
+ * @param {Object} opts - Additional options
17
+ * @returns {GameObjectShapeWrapper} - The created wrapper
18
+ */
19
+ static create(game, shape, opts = {}) {
20
+ // Create wrapper with combined options
21
+ const combinedOpts = {
22
+ // Default position & size from shape
23
+ x: shape?.x ?? 0,
24
+ y: shape?.y ?? 0,
25
+ width: shape?.width ?? 0,
26
+ height: shape?.height ?? 0,
27
+ rotation: shape?.rotation ?? 0,
28
+ scaleX: shape?.scaleX ?? 1,
29
+ scaleY: shape?.scaleY ?? 1,
30
+ opacity: shape?.opacity ?? 1,
31
+ visible: shape?.visible ?? true,
32
+ active: true,
33
+ debug: shape?.debug ?? false,
34
+
35
+ // Shape-specific properties
36
+ color: shape?.color ?? null,
37
+ stroke: shape?.stroke ?? null,
38
+ lineWidth: shape?.lineWidth ?? 1,
39
+ lineJoin: shape?.lineJoin ?? "miter",
40
+ lineCap: shape?.lineCap ?? "butt",
41
+ miterLimit: shape?.miterLimit ?? 10,
42
+
43
+ // Override with any user-provided options
44
+ ...opts,
45
+
46
+ // Default name from shape class
47
+ name: opts.name ?? shape?.constructor.name ?? "ShapeWrapper",
48
+ };
49
+
50
+ return new GameObjectShapeWrapper(game, shape, combinedOpts);
51
+ }
52
+ }
53
+
54
+ /**
55
+ * GameObjectShapeWrapper
56
+ * ----------------------
57
+ *
58
+ * A specialized GameObject that wraps a Shape.
59
+ *
60
+ * @extends GameObject
61
+ */
62
+ export class GameObjectShapeWrapper extends GameObject {
63
+ /**
64
+ * Creates a GameObject wrapper around a Shape instance
65
+ *
66
+ * @param {Game} game - The game instance
67
+ * @param {Shape} shape - The shape to wrap
68
+ * @param {Object} options - Configuration options
69
+ */
70
+ constructor(game, shape, options = {}) {
71
+ super(game, options);
72
+
73
+ // Validate shape
74
+ if (!shape || shape == null || shape == undefined) {
75
+ throw new Error("GameObjectShapeWrapper requires a shape");
76
+ }
77
+
78
+ // Store the shape
79
+ this.shape = shape;
80
+
81
+ // Apply Shape-specific properties directly to the shape
82
+ if (options.color !== undefined) shape.color = options.color;
83
+ if (options.stroke !== undefined) shape.stroke = options.stroke;
84
+ if (options.lineWidth !== undefined) shape.lineWidth = options.lineWidth;
85
+ if (options.lineJoin !== undefined) shape.lineJoin = options.lineJoin;
86
+ if (options.lineCap !== undefined) shape.lineCap = options.lineCap;
87
+ if (options.miterLimit !== undefined) shape.miterLimit = options.miterLimit;
88
+
89
+ // Apply standard properties
90
+ this.syncPropertiesToShape();
91
+
92
+ this.logger.log(`Created GameObject(${this.constructor.name}):`, {
93
+ x: this.x,
94
+ y: this.y,
95
+ width: this.width,
96
+ height: this.height,
97
+ color: this.color,
98
+ stroke: this.stroke
99
+ });
100
+ }
101
+
102
+ /**
103
+ * Synchronizes common properties from wrapper to shape
104
+ */
105
+ syncPropertiesToShape() {
106
+ if (!this.shape) return;
107
+
108
+ // Common transformable properties
109
+ const propsToSync = [
110
+ 'width', 'height', 'rotation', 'scaleX', 'scaleY',
111
+ 'visible', 'debug', 'debugColor'
112
+ ];
113
+
114
+ // Sync each property from this wrapper to the shape
115
+ for (const prop of propsToSync) {
116
+ if (prop in this && prop in this.shape) {
117
+ if (this[prop] !== this.shape[prop]) {
118
+ this.shape[prop] = this[prop];
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ // Shape-specific property getters and setters
125
+
126
+ /**
127
+ * Fill color for the shape
128
+ * @type {string|null}
129
+ */
130
+ get color() {
131
+ return this.shape ? this.shape.color : null;
132
+ }
133
+
134
+ set color(value) {
135
+ if (this.shape) {
136
+ this.shape.color = value;
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Stroke color for the shape
142
+ * @type {string|null}
143
+ */
144
+ get stroke() {
145
+ return this.shape ? this.shape.stroke : null;
146
+ }
147
+
148
+ set stroke(value) {
149
+ if (this.shape) {
150
+ this.shape.stroke = value;
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Line width for the shape's stroke
156
+ * @type {number}
157
+ */
158
+ get lineWidth() {
159
+ return this.shape ? this.shape.lineWidth : 1;
160
+ }
161
+
162
+ set lineWidth(value) {
163
+ if (this.shape) {
164
+ this.shape.lineWidth = value;
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Line join style ("miter", "round", "bevel")
170
+ * @type {string}
171
+ */
172
+ get lineJoin() {
173
+ return this.shape ? this.shape.lineJoin : "miter";
174
+ }
175
+
176
+ set lineJoin(value) {
177
+ if (this.shape) {
178
+ this.shape.lineJoin = value;
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Line cap style ("butt", "round", "square")
184
+ * @type {string}
185
+ */
186
+ get lineCap() {
187
+ return this.shape ? this.shape.lineCap : "butt";
188
+ }
189
+
190
+ set lineCap(value) {
191
+ if (this.shape) {
192
+ this.shape.lineCap = value;
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Miter limit for line joins
198
+ * @type {number}
199
+ */
200
+ get miterLimit() {
201
+ return this.shape ? this.shape.miterLimit : 10;
202
+ }
203
+
204
+ set miterLimit(value) {
205
+ if (this.shape) {
206
+ this.shape.miterLimit = value;
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Update method called each frame
212
+ * @param {number} dt - Delta time in seconds
213
+ */
214
+ update(dt) {
215
+ if (!this.active) return;
216
+ this.onUpdate?.(dt);
217
+ // Check if bounds need to be recalculated
218
+ if (this._boundsDirty || this.tweening) {
219
+ this.syncPropertiesToShape();
220
+ this._boundsDirty = false;
221
+ }
222
+ super.update(dt);
223
+ }
224
+
225
+ /**
226
+ * Draw method to render the shape
227
+ */
228
+ draw() {
229
+ super.draw();
230
+ this.shape.render();
231
+ }
232
+ }
@@ -0,0 +1,243 @@
1
+ /***************************************************************
2
+ * Pipeline.js
3
+ *
4
+ * Manages and updates/renders a collection of GameObjects.
5
+ * Handles input event dispatch to the topmost interactive object,
6
+ * including special handling for Scenes (nested children).
7
+ ***************************************************************/
8
+
9
+ import { Scene } from "./objects";
10
+ import { Tweenetik } from "../motion";
11
+ import { Loggable } from "../logger/loggable";
12
+ import { ZOrderedCollection } from "../util";
13
+ /**
14
+ * Pipeline - Maintains a list of GameObjects, updating and rendering them
15
+ * each frame. It also centralizes and dispatches pointer events (inputdown,
16
+ * inputup, inputmove) to interactive objects, including nested Scene children.
17
+ */
18
+ export class Pipeline extends Loggable {
19
+ /**
20
+ * Create a new Pipeline.
21
+ * @param {Game} game - A reference to the main Game instance.
22
+ */
23
+ constructor(game) {
24
+ super();
25
+ /**
26
+ * Reference to the owning Game.
27
+ * @type {Game}
28
+ */
29
+ this.game = game;
30
+ /**
31
+ * The master list of top-level GameObjects to update and render.
32
+ * @type {GameObject[]}
33
+ */
34
+ // Create the z-ordered collection
35
+ this._collection = new ZOrderedCollection();
36
+ this._collection._owner = this; // Give collection a reference to its owner
37
+
38
+ // Listen for pointer events from the Game's central event system.
39
+ const types = ["inputdown", "inputup", "inputmove", "click"];
40
+ types.forEach((type) => {
41
+ this.game.events.on(type, (e) => {
42
+ this.dispatchInputEvent(type, e);
43
+ });
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Internal helper to check if a single GameObject is hovered, and emit
49
+ * mouseover/mouseout as needed.
50
+ * @param {GameObject} obj - The object to hover-test.
51
+ * @param {object} e - Event data containing pointer coordinates (e.x, e.y).
52
+ * @private
53
+ */
54
+ _hoverObject(obj, e) {
55
+ //console.log("hoverObject", obj.constructor.name, obj.interactive, obj._hitTest != null);
56
+ // Only applies to interactive objects with a shape and a _hitTest method.
57
+ if (!obj.interactive || !obj._hitTest) return;
58
+ const hit = obj._hitTest(e.x, e.y);
59
+ if (hit && !obj._hovered) {
60
+ // Pointer entered this object
61
+ obj._hovered = true;
62
+ obj.events.emit("mouseover", e);
63
+ //this.logger.log("Mouseover", obj, e.x, e.y);
64
+ } else if (!hit && obj._hovered) {
65
+ // Pointer left this object
66
+ obj._hovered = false;
67
+ obj.events.emit("mouseout", e);
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Recursively checks all children of a Scene for hover state.
73
+ * @param {Scene} scene - The scene whose children will be hover-tested.
74
+ * @param {object} e - Event data containing pointer coordinates (e.x, e.y).
75
+ * @private
76
+ */
77
+ _hoverScene(scene, e) {
78
+ for (let i = scene.children.length - 1; i >= 0; i--) {
79
+ const child = scene.children[i];
80
+ if (child instanceof Scene) {
81
+ this._hoverScene(child, e); // recurse into nested scenes
82
+ } else {
83
+ this._hoverObject(child, e); // hover actual objects
84
+ }
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Dispatch a pointer event (inputdown, inputup, inputmove) to the first
90
+ * GameObject that is hit, or to Scenes that can recursively handle children.
91
+ * Also triggers _dispatchHover if needed.
92
+ * @param {string} type - Event type (e.g., "inputdown", "inputup", "inputmove").
93
+ * @param {object} e - Event data containing pointer coordinates (e.x, e.y).
94
+ */
95
+ dispatchInputEvent(type, e) {
96
+ let handled = false;
97
+ // Check from topmost to bottommost object to find the first that was hit.
98
+ for (let i = this.gameObjects.length - 1; i >= 0; i--) {
99
+ const obj = this.gameObjects[i];
100
+ if (type === "inputdown") {
101
+ //this.logger.log("inputdown", obj);
102
+ }
103
+ if (obj instanceof Scene) {
104
+ // If it's a Scene, see if any of its children were hit.
105
+ if (this._dispatchToScene(obj, type, e)) {
106
+ handled = true;
107
+ break;
108
+ }
109
+ } else if (obj.interactive && obj._hitTest?.(e.x, e.y)) {
110
+ // Found a regular interactive GameObject that was hit
111
+ obj.events.emit(type, e);
112
+ handled = true;
113
+ break;
114
+ }
115
+ }
116
+
117
+ // If this is a pointer move event, we also check for hover transitions.
118
+ if (type === "inputmove") {
119
+ this._dispatchHover(e);
120
+ }
121
+ }
122
+
123
+ /**
124
+ * After handling inputmove at the top level, this updates hover states
125
+ * for all interactive objects, including children in Scenes.
126
+ * @param {object} e - Event data containing pointer coordinates (e.x, e.y).
127
+ * @private
128
+ */
129
+ _dispatchHover(e) {
130
+ // Check from topmost to bottommost for hover changes.
131
+ for (let i = this.gameObjects.length - 1; i >= 0; i--) {
132
+ const obj = this.gameObjects[i];
133
+ //this.logger.log("Hover test for", obj, e.x, e.y);
134
+ if (obj instanceof Scene) {
135
+ this._hoverScene(obj, e);
136
+ } else {
137
+ this._hoverObject(obj, e);
138
+ }
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Recursively dispatch an event to a Scene and possibly its nested child Scenes.
144
+ * @param {Scene} scene - The scene to dispatch the event to.
145
+ * @param {string} type - The type of pointer event ("inputdown", "inputup", etc).
146
+ * @param {object} e - Event data with pointer coordinates.
147
+ * @returns {boolean} True if the event was handled by a child, false otherwise.
148
+ * @private
149
+ */
150
+ _dispatchToScene(scene, type, e) {
151
+ //if(type === "inputdown") this.logger.log("inputdown", scene);
152
+ for (let i = scene.children.length - 1; i >= 0; i--) {
153
+ const child = scene.children[i];
154
+ if (child instanceof Scene) {
155
+ // Recurse deeper if child is also a Scene
156
+ const hit = this._dispatchToScene(child, type, e);
157
+ if (hit) {
158
+ //if(type === "inputdown") this.logger.log("HIT", child, type);
159
+ return true;
160
+ }
161
+ } else if (child.interactive && child._hitTest?.(e.x, e.y)) {
162
+ // Found a child that was hit
163
+ //if(type === "inputdown") this.logger.log("Dispatching to child", child, type);
164
+ child.events.emit(type, e);
165
+ return true;
166
+ }
167
+ }
168
+ return false;
169
+ }
170
+
171
+ /**
172
+ * Add a GameObject to the pipeline so it will be updated and rendered each frame.
173
+ * @param {GameObject} gameObject - The game object to add.
174
+ * @returns {GameObject} Returns the same object for convenience.
175
+ */
176
+ add(gameObject) {
177
+ gameObject.parent = this.game;
178
+ const go = this._collection.add(gameObject);
179
+ // call the init() method on the go if it exists
180
+ if (go.init) {
181
+ go.init();
182
+ }
183
+ return go;
184
+ }
185
+
186
+ /**
187
+ * Remove a GameObject from the pipeline.
188
+ * @param {GameObject} gameObject - The object to remove.
189
+ */
190
+ remove(gameObject) {
191
+ if(gameObject === undefined || gameObject === null) {
192
+ this.logger.warn("Cannot remove undefined or null object", gameObject);
193
+ return;
194
+ }
195
+ this._collection.remove(gameObject);
196
+ }
197
+
198
+ bringToFront(gameObject) {
199
+ return this._collection.bringToFront(gameObject);
200
+ }
201
+
202
+ sendToBack(gameObject) {
203
+ return this._collection.sendToBack(gameObject);
204
+ }
205
+
206
+ bringForward(gameObject) {
207
+ return this._collection.bringForward(gameObject);
208
+ }
209
+
210
+ sendBackward(gameObject) {
211
+ return this._collection.sendBackward(gameObject);
212
+ }
213
+
214
+ clear() {
215
+ return this._collection.clear();
216
+ }
217
+
218
+ // Getter to access children
219
+ get gameObjects() {
220
+ return this._collection.children;
221
+ }
222
+
223
+ update(dt) {
224
+ this.logger.groupCollapsed("Pipeline.update");
225
+ this._collection.children
226
+ .filter((obj) => obj.active)
227
+ .forEach((obj) => obj.update(dt));
228
+ Tweenetik.updateAll(dt);
229
+ this.logger.groupEnd();
230
+ }
231
+
232
+ render() {
233
+ const renderObj = (obj) => obj.render();
234
+ const filterVisible = (obj) => obj.visible;
235
+ const filterActive = (obj) => obj.active;
236
+ this.logger.groupCollapsed("Pipeline.render");
237
+ this._collection.getSortedChildren()
238
+ .filter(filterVisible)
239
+ .filter(filterActive)
240
+ .forEach(renderObj);
241
+ this.logger.groupEnd();
242
+ }
243
+ }