@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,152 @@
1
+ /**
2
+ * @module FluentLayer
3
+ * @description Builder class for layer (z-indexed group) operations within a scene
4
+ *
5
+ * Layers are implemented as GameObjects containing Groups, allowing for
6
+ * z-indexed sub-grouping within a scene.
7
+ */
8
+
9
+ import { GameObject } from "../game/objects/go.js";
10
+ import { FluentGO } from "./fluent-go.js";
11
+
12
+ /**
13
+ * FluentLayer - Builder for layer (z-indexed group) within a scene
14
+ */
15
+ export class FluentLayer {
16
+ /** @type {import('./fluent-scene.js').FluentScene} */
17
+ #parent;
18
+ /** @type {GameObject} */
19
+ #layerGO;
20
+ /** @type {import('../shapes/group.js').Group} */
21
+ #group;
22
+ /** @type {Object} */
23
+ #refs;
24
+ /** @type {Object} */
25
+ #state;
26
+
27
+ /**
28
+ * @param {import('./fluent-scene.js').FluentScene} parent - Parent FluentScene
29
+ * @param {GameObject} layerGO - The GameObject holding the layer
30
+ * @param {import('../shapes/group.js').Group} group - The Group for the layer
31
+ * @param {Object} refs - Shared refs object
32
+ * @param {Object} state - Shared state object
33
+ */
34
+ constructor(parent, layerGO, group, refs, state) {
35
+ this.#parent = parent;
36
+ this.#layerGO = layerGO;
37
+ this.#group = group;
38
+ this.#refs = refs;
39
+ this.#state = state;
40
+ }
41
+
42
+ /**
43
+ * Create a GameObject in this layer
44
+ * @param {Object} [opts] - GameObject options
45
+ * @param {Function} [builderFn] - Optional builder callback
46
+ * @returns {FluentGO|FluentLayer}
47
+ */
48
+ go(opts = {}, builderFn) {
49
+ const {
50
+ name,
51
+ x = 0,
52
+ y = 0,
53
+ visible = true,
54
+ ...rest
55
+ } = opts;
56
+
57
+ const go = new GameObject({ x, y, visible, ...rest });
58
+
59
+ // Set game reference from parent
60
+ if (this.#parent.parent?.game) {
61
+ go.game = this.#parent.parent.game;
62
+ }
63
+
64
+ // Add to the layer's group
65
+ this.#group.add(go);
66
+
67
+ // Register in refs if named
68
+ if (name) {
69
+ go.name = name;
70
+ this.#refs[name] = go;
71
+ }
72
+
73
+ const fluentGO = new FluentGO(this, go, this.#refs, this.#state);
74
+
75
+ if (builderFn) {
76
+ builderFn(fluentGO);
77
+ return this;
78
+ }
79
+
80
+ return fluentGO;
81
+ }
82
+
83
+ /**
84
+ * Set layer visibility
85
+ * @param {boolean} visible - Visibility state
86
+ * @returns {FluentLayer}
87
+ */
88
+ visible(visible) {
89
+ this.#layerGO.visible = visible;
90
+ return this;
91
+ }
92
+
93
+ /**
94
+ * Set layer opacity
95
+ * @param {number} value - Opacity (0-1)
96
+ * @returns {FluentLayer}
97
+ */
98
+ opacity(value) {
99
+ this.#group.opacity = value;
100
+ return this;
101
+ }
102
+
103
+ /**
104
+ * End layer context and return to scene
105
+ * @returns {import('./fluent-scene.js').FluentScene}
106
+ */
107
+ endLayer() {
108
+ return this.#parent;
109
+ }
110
+
111
+ /**
112
+ * Navigate back to parent (same as endLayer)
113
+ * @returns {import('./fluent-scene.js').FluentScene}
114
+ */
115
+ end() {
116
+ return this.#parent;
117
+ }
118
+
119
+ /**
120
+ * Switch to another scene
121
+ * @param {string} name - Scene name
122
+ * @param {Object} [opts] - Scene options
123
+ * @returns {import('./fluent-scene.js').FluentScene}
124
+ */
125
+ scene(name, opts) {
126
+ return this.#parent.scene(name, opts);
127
+ }
128
+
129
+ /**
130
+ * Start the game
131
+ * @returns {import('./fluent-game.js').FluentGame}
132
+ */
133
+ start() {
134
+ return this.#parent.start();
135
+ }
136
+
137
+ // ─────────────────────────────────────────────────────────
138
+ // ACCESSORS
139
+ // ─────────────────────────────────────────────────────────
140
+
141
+ /** @returns {GameObject} The layer's wrapper GameObject */
142
+ get layerGO() { return this.#layerGO; }
143
+
144
+ /** @returns {import('../shapes/group.js').Group} The layer's Group */
145
+ get group() { return this.#group; }
146
+
147
+ /** @returns {Object} Named object references */
148
+ get refs() { return this.#refs; }
149
+
150
+ /** @returns {Object} Shared state */
151
+ get state() { return this.#state; }
152
+ }
@@ -0,0 +1,291 @@
1
+ /**
2
+ * @module FluentScene
3
+ * @description Builder class for Scene operations in the fluent API
4
+ *
5
+ * Provides chainable methods for creating and managing GameObjects within a scene.
6
+ */
7
+
8
+ import { GameObject } from "../game/objects/go.js";
9
+ import { Group } from "../shapes/group.js";
10
+ import { FluentGO } from "./fluent-go.js";
11
+ import { FluentLayer } from "./fluent-layer.js";
12
+
13
+ /**
14
+ * FluentScene - Builder class for Scene operations
15
+ */
16
+ export class FluentScene {
17
+ /** @type {import('./fluent-game.js').FluentGame} */
18
+ #parent;
19
+ /** @type {import('../game/objects/scene.js').Scene} */
20
+ #scene;
21
+ /** @type {Object} */
22
+ #refs;
23
+ /** @type {Object} */
24
+ #state;
25
+ /** @type {GameObject|null} */
26
+ #lastGO = null;
27
+
28
+ /**
29
+ * @param {import('./fluent-game.js').FluentGame} parent - Parent FluentGame
30
+ * @param {import('../game/objects/scene.js').Scene} scene - Wrapped Scene instance
31
+ * @param {Object} refs - Shared refs object
32
+ * @param {Object} state - Shared state object
33
+ */
34
+ constructor(parent, scene, refs, state) {
35
+ this.#parent = parent;
36
+ this.#scene = scene;
37
+ this.#refs = refs;
38
+ this.#state = state;
39
+ }
40
+
41
+ // ─────────────────────────────────────────────────────────
42
+ // GAMEOBJECT CREATION
43
+ // ─────────────────────────────────────────────────────────
44
+
45
+ /**
46
+ * Create a GameObject in this scene
47
+ *
48
+ * Supports multiple signatures:
49
+ * - go() - Create plain GameObject at origin
50
+ * - go(options) - Create plain GameObject with options
51
+ * - go(CustomClass) - Create custom GameObject class
52
+ * - go(CustomClass, options) - Custom class with options
53
+ * - go(options, builderFn) - Plain GO with builder callback
54
+ * - go(CustomClass, options, builderFn) - Custom class with builder
55
+ *
56
+ * @param {Object|Function} [optionsOrClass] - GameObject options or custom class
57
+ * @param {Object|Function} [optionsOrBuilder] - Options or builder function
58
+ * @param {Function} [builderFn] - Optional builder callback
59
+ * @returns {FluentGO|FluentScene}
60
+ */
61
+ go(optionsOrClass, optionsOrBuilder, builderFn) {
62
+ // Parse flexible arguments
63
+ let GOClass, options, builder;
64
+
65
+ if (typeof optionsOrClass === 'function' && optionsOrClass.prototype) {
66
+ // go(CustomClass) or go(CustomClass, options) or go(CustomClass, options, builder)
67
+ GOClass = optionsOrClass;
68
+ if (typeof optionsOrBuilder === 'function') {
69
+ options = {};
70
+ builder = optionsOrBuilder;
71
+ } else {
72
+ options = optionsOrBuilder || {};
73
+ builder = builderFn;
74
+ }
75
+ } else {
76
+ // go() or go(options) or go(options, builder)
77
+ GOClass = GameObject;
78
+ options = optionsOrClass || {};
79
+ builder = optionsOrBuilder;
80
+ }
81
+
82
+ const {
83
+ name,
84
+ x = 0,
85
+ y = 0,
86
+ visible = true,
87
+ ...rest
88
+ } = options;
89
+
90
+ // Instantiate the GO class (custom or default)
91
+ // GameObject constructor signature is (game, options)
92
+ const go = new GOClass(this.#parent.game, { x, y, visible, ...rest });
93
+ this.#scene.add(go);
94
+ this.#lastGO = go;
95
+
96
+ // Register in refs if named
97
+ if (name) {
98
+ go.name = name;
99
+ this.#refs[name] = go;
100
+ }
101
+
102
+ const fluentGO = new FluentGO(this, go, this.#refs, this.#state);
103
+
104
+ // If builder function provided, execute and return scene context
105
+ if (builder) {
106
+ builder(fluentGO);
107
+ return this;
108
+ }
109
+
110
+ return fluentGO;
111
+ }
112
+
113
+ /**
114
+ * Create multiple GOs with a builder
115
+ * @param {string|Function} groupNameOrFn - Group name or builder function
116
+ * @param {Function} [builderFn] - Builder function if name provided
117
+ * @returns {FluentScene}
118
+ */
119
+ group(groupNameOrFn, builderFn) {
120
+ const groupName = typeof groupNameOrFn === 'string' ? groupNameOrFn : null;
121
+ const fn = typeof groupNameOrFn === 'function' ? groupNameOrFn : builderFn;
122
+
123
+ const groupGOs = [];
124
+
125
+ const groupApi = {
126
+ go: (opts) => {
127
+ const fluentGO = this.go(opts);
128
+ groupGOs.push(fluentGO.goInstance);
129
+ return fluentGO;
130
+ }
131
+ };
132
+
133
+ fn(groupApi);
134
+
135
+ if (groupName) {
136
+ this.#refs[groupName] = groupGOs;
137
+ }
138
+
139
+ return this;
140
+ }
141
+
142
+ // ─────────────────────────────────────────────────────────
143
+ // LAYER MANAGEMENT (sub-grouping within scene)
144
+ // ─────────────────────────────────────────────────────────
145
+
146
+ /**
147
+ * Create a layer (z-indexed group) within the scene
148
+ * @param {string} name - Layer name
149
+ * @param {number} [zIndex=0] - Layer z-index (relative to scene)
150
+ * @returns {FluentLayer}
151
+ */
152
+ layer(name, zIndex = 0) {
153
+ // Layers are implemented as Groups with zIndex
154
+ const layerGroup = new Group({ zIndex });
155
+ layerGroup.name = name;
156
+
157
+ // Create a wrapper GO to hold the group
158
+ // GameObject constructor signature is (game, options)
159
+ const layerGO = new GameObject(this.#parent.game, { x: 0, y: 0 });
160
+ layerGO._fluentShape = layerGroup;
161
+ layerGO.renderable = layerGroup;
162
+ layerGO.zIndex = zIndex;
163
+
164
+ // Hook into draw to render the group
165
+ const originalDraw = layerGO.draw?.bind(layerGO) || (() => {});
166
+ layerGO.draw = function() {
167
+ originalDraw();
168
+ if (this._fluentShape && this.visible) {
169
+ this._fluentShape.render();
170
+ }
171
+ };
172
+
173
+ this.#scene.add(layerGO);
174
+
175
+ if (name) {
176
+ this.#refs[`${this.#scene.name}_${name}`] = layerGO;
177
+ }
178
+
179
+ return new FluentLayer(this, layerGO, layerGroup, this.#refs, this.#state);
180
+ }
181
+
182
+ // ─────────────────────────────────────────────────────────
183
+ // SCENE LIFECYCLE HOOKS
184
+ // ─────────────────────────────────────────────────────────
185
+
186
+ /**
187
+ * Register scene enter callback
188
+ * @param {Function} handler
189
+ * @returns {FluentScene}
190
+ */
191
+ onEnter(handler) {
192
+ this.#scene._onEnter = handler;
193
+ return this;
194
+ }
195
+
196
+ /**
197
+ * Register scene exit callback
198
+ * @param {Function} handler
199
+ * @returns {FluentScene}
200
+ */
201
+ onExit(handler) {
202
+ this.#scene._onExit = handler;
203
+ return this;
204
+ }
205
+
206
+ // ─────────────────────────────────────────────────────────
207
+ // NAVIGATION
208
+ // ─────────────────────────────────────────────────────────
209
+
210
+ /**
211
+ * Switch to another scene (creates if needed)
212
+ * @param {string} name - Scene name
213
+ * @param {Object} [options] - Scene options
214
+ * @returns {FluentScene}
215
+ */
216
+ scene(name, options) {
217
+ return this.#parent.scene(name, options);
218
+ }
219
+
220
+ /**
221
+ * Return to game context
222
+ * @returns {import('./fluent-game.js').FluentGame}
223
+ */
224
+ end() {
225
+ return this.#parent;
226
+ }
227
+
228
+ // ─────────────────────────────────────────────────────────
229
+ // SHORTCUTS (delegate to parent)
230
+ // ─────────────────────────────────────────────────────────
231
+
232
+ /**
233
+ * Start the game
234
+ * @returns {import('./fluent-game.js').FluentGame}
235
+ */
236
+ start() {
237
+ return this.#parent.start();
238
+ }
239
+
240
+ /**
241
+ * Stop the game
242
+ * @returns {import('./fluent-game.js').FluentGame}
243
+ */
244
+ stop() {
245
+ return this.#parent.stop();
246
+ }
247
+
248
+ /**
249
+ * Register event handler
250
+ * @param {string} event - Event name
251
+ * @param {Function} handler - Handler function
252
+ * @returns {import('./fluent-game.js').FluentGame}
253
+ */
254
+ on(event, handler) {
255
+ return this.#parent.on(event, handler);
256
+ }
257
+
258
+ /**
259
+ * Use a plugin
260
+ * @param {Function} plugin - Plugin function
261
+ * @returns {import('./fluent-game.js').FluentGame}
262
+ */
263
+ use(plugin) {
264
+ return this.#parent.use(plugin);
265
+ }
266
+
267
+ /**
268
+ * Set state
269
+ * @param {Object} stateObj - State object
270
+ * @returns {import('./fluent-game.js').FluentGame}
271
+ */
272
+ state(stateObj) {
273
+ return this.#parent.state(stateObj);
274
+ }
275
+
276
+ // ─────────────────────────────────────────────────────────
277
+ // ACCESSORS
278
+ // ─────────────────────────────────────────────────────────
279
+
280
+ /** @returns {import('../game/objects/scene.js').Scene} Underlying Scene instance */
281
+ get sceneInstance() { return this.#scene; }
282
+
283
+ /** @returns {Object} Named object references */
284
+ get refs() { return this.#refs; }
285
+
286
+ /** @returns {Object} Shared state */
287
+ get state() { return this.#state; }
288
+
289
+ /** @returns {import('./fluent-game.js').FluentGame} Parent FluentGame */
290
+ get parent() { return this.#parent; }
291
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @module Fluent
3
+ * @description Declarative fluent builder API for GCanvas
4
+ *
5
+ * This module provides a chainable, declarative API layer on top of GCanvas's
6
+ * object-oriented architecture. It enables rapid creative coding while maintaining
7
+ * full access to the underlying power.
8
+ *
9
+ * ## Entry Points
10
+ *
11
+ * - **gcanvas(options)** - Full fluent API for building games and interactive apps
12
+ * - **sketch(w, h, bg)** - Ultra-simple mode for quick creative coding prototypes
13
+ *
14
+ * ## Quick Start
15
+ *
16
+ * @example
17
+ * // Full fluent API
18
+ * import { gcanvas } from 'gcanvas';
19
+ *
20
+ * gcanvas({ bg: 'black' })
21
+ * .scene('game')
22
+ * .go({ x: 400, y: 300, name: 'player' })
23
+ * .circle({ radius: 30, fill: 'lime' })
24
+ * .pulse({ min: 0.9, max: 1.1, duration: 1 })
25
+ * .scene('ui', { zIndex: 100 })
26
+ * .go({ x: 20, y: 20 })
27
+ * .text('SCORE: 0', { font: '24px monospace', fill: 'white' })
28
+ * .on('update', (dt, ctx) => {
29
+ * // Game logic
30
+ * })
31
+ * .start();
32
+ *
33
+ * @example
34
+ * // Sketch mode for quick prototypes
35
+ * import { sketch } from 'gcanvas';
36
+ *
37
+ * sketch(800, 600, '#1a1a1a')
38
+ * .grid(10, 10, 80, (s, x, y, i, j) => {
39
+ * s.circle(x, y, 20, `hsl(${(i + j) * 20}, 70%, 60%)`);
40
+ * })
41
+ * .update((dt, ctx) => {
42
+ * ctx.shapes.forEach((shape, i) => {
43
+ * shape.y += Math.sin(ctx.time * 2 + i * 0.1) * 0.5;
44
+ * });
45
+ * })
46
+ * .start();
47
+ *
48
+ * @example
49
+ * // Class injection - use custom classes with fluent API
50
+ * import { gcanvas } from 'gcanvas';
51
+ * import { SpaceScene } from './scenes/space-scene';
52
+ * import { Player, Alien, Boss } from './entities';
53
+ *
54
+ * gcanvas({ bg: 'black' })
55
+ * // Pass custom scene class
56
+ * .scene(SpaceScene)
57
+ * // Or with name: .scene('game', SpaceScene, { zIndex: 0 })
58
+ *
59
+ * // Pass custom GameObject classes
60
+ * .go(Player, { x: 400, y: 500, name: 'player' })
61
+ * .go(Alien, { x: 100, y: 100, type: 0 })
62
+ * .go(Boss, { x: 400, y: 150, bossType: 2 })
63
+ *
64
+ * .start();
65
+ *
66
+ * @example
67
+ * // Composable scene modules
68
+ * // scenes/player.js
69
+ * export const playerScene = (g) => g
70
+ * .inScene('game')
71
+ * .go({ x: 400, y: 300, name: 'player' })
72
+ * .circle({ radius: 25, fill: '#00ff88' });
73
+ *
74
+ * // main.js
75
+ * import { gcanvas } from 'gcanvas';
76
+ * import { playerScene } from './scenes/player';
77
+ *
78
+ * gcanvas({ bg: 'black' })
79
+ * .scene('game')
80
+ * .use(playerScene)
81
+ * .start();
82
+ */
83
+
84
+ // Main entry points
85
+ export { gcanvas, FluentGame } from "./fluent-game.js";
86
+ export { sketch } from "./sketch.js";
87
+
88
+ // Builder classes (for advanced usage/extension)
89
+ export { FluentScene } from "./fluent-scene.js";
90
+ export { FluentGO } from "./fluent-go.js";
91
+ export { FluentLayer } from "./fluent-layer.js";
92
+
93
+ // Re-export commonly used items for convenience
94
+ export { Motion } from "../motion/motion.js";
95
+ export { Easing } from "../motion/easing.js";
96
+ export { Tweenetik } from "../motion/tweenetik.js";
97
+ export { Keys } from "../io/keys.js";
98
+ export { Mouse } from "../io/mouse.js";