@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,192 @@
1
+ import { Shape } from "./shape.js";
2
+ import { Painter } from "../painter";
3
+
4
+ /**
5
+ * Draws an arbitrary pixel buffer inside the normal Shape pipeline.
6
+ *
7
+ * ───────────────────────────────────────────────────────────────────────────
8
+ * Usage:
9
+ * const data = Painter.img.getImageData(0, 0, 320, 200); // any ImageData
10
+ * const fract = new ImageShape(data, { x: 100, y: 50, anchor: "center" });
11
+ * scene.add(fract); // acts like any Shape
12
+ */
13
+ export class ImageShape extends Shape {
14
+ /**
15
+ * @param {HTMLImageElement|HTMLCanvasElement|ImageBitmap|Video|ImageData} bitmap Anything the 2‑D API understands
16
+ * @param {object} [options] Usual Shape options + anchor, etc.
17
+ */
18
+ constructor(bitmap, options = {}) {
19
+ if (!bitmap && !options.width && !options.height) {
20
+ throw new Error(
21
+ "ImageShape must be initialized with either a bitmap or width and height"
22
+ );
23
+ }
24
+ super(options);
25
+
26
+ // Store the bitmap passed in
27
+ this._bitmap = bitmap ?? Painter.img.createImageData(options.width, options.height);
28
+
29
+ // Set dimensions based on bitmap or options
30
+ this._width = options.width ?? bitmap?.width ?? 0;
31
+ this._height = options.height ?? bitmap?.height ?? 0;
32
+
33
+ // Set anchor point (default to center)
34
+ this.anchor = options.anchor ?? "center";
35
+
36
+ // Track anchor x/y offsets (0-1 range)
37
+ this._anchorX = 0.5;
38
+ this._anchorY = 0.5;
39
+ this._updateAnchorOffsets();
40
+
41
+ // Enable image smoothing by default
42
+ this.smoothing = options.smoothing !== false;
43
+
44
+ // ImageData can't be transformed directly; cache an off‑screen canvas
45
+ if (bitmap instanceof ImageData) {
46
+ this.buffer(bitmap);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Calculate anchor point offsets based on anchor string
52
+ * @private
53
+ */
54
+ _updateAnchorOffsets() {
55
+ // Parse anchor string to get x/y offsets
56
+ const anchor = this.anchor?.toLowerCase() ?? "center";
57
+
58
+ // X offset: left=0, center=0.5, right=1
59
+ if (anchor.includes("left")) this._anchorX = 0;
60
+ else if (anchor.includes("right")) this._anchorX = 1;
61
+ else this._anchorX = 0.5;
62
+
63
+ // Y offset: top=0, center=0.5, bottom=1
64
+ if (anchor.includes("top")) this._anchorY = 0;
65
+ else if (anchor.includes("bottom")) this._anchorY = 1;
66
+ else this._anchorY = 0.5;
67
+ }
68
+
69
+ /**
70
+ * Access the internal bitmap
71
+ * @returns {HTMLImageElement|HTMLCanvasElement|ImageBitmap|Video|ImageData} Current bitmap
72
+ */
73
+ get bitmap() {
74
+ return this._bitmap;
75
+ }
76
+
77
+ /**
78
+ * Change the internal bitmap
79
+ * @param {HTMLImageElement|HTMLCanvasElement|ImageBitmap|Video|ImageData} bmp New bitmap
80
+ */
81
+ set bitmap(bmp) {
82
+ //console.log("setting bitmap", bmp);
83
+ if (!bmp) return;
84
+
85
+ this._bitmap = bmp;
86
+
87
+ // Update width and height if not already set
88
+ if (!this._width && bmp.width) this._width = bmp.width;
89
+ if (!this._height && bmp.height) this._height = bmp.height;
90
+
91
+ // If it's ImageData, prepare the buffer
92
+ if (bmp instanceof ImageData) {
93
+ this.buffer(bmp);
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Create or update the canvas buffer for ImageData
99
+ * @param {ImageData} bitmap ImageData to put in the buffer
100
+ */
101
+ buffer(bitmap) {
102
+ if (!bitmap) return;
103
+
104
+ //console.log("Creating buffer for ImageData", bitmap.width, "x", bitmap.height);
105
+
106
+ // Create the buffer canvas if needed
107
+ if (!this._buffer) {
108
+ this._buffer = document.createElement("canvas");
109
+ //console.log("Created new buffer canvas");
110
+ }
111
+
112
+ // Resize buffer if needed
113
+ if (this._buffer.width !== bitmap.width || this._buffer.height !== bitmap.height) {
114
+ this._buffer.width = bitmap.width;
115
+ this._buffer.height = bitmap.height;
116
+ //console.log("Resized buffer to", bitmap.width, "x", bitmap.height);
117
+ }
118
+
119
+ // Draw the ImageData to the buffer canvas
120
+ const ctx = this._buffer.getContext("2d");
121
+ ctx.putImageData(bitmap, 0, 0);
122
+ //console.log("Updated buffer with ImageData");
123
+ }
124
+
125
+ /**
126
+ * Reset the image to an empty state
127
+ */
128
+ reset() {
129
+ this._buffer = null;
130
+ this._bitmap = Painter.img.createImageData(this.width, this.height);
131
+ }
132
+
133
+ /**
134
+ * Set the anchor point
135
+ * @param {string} anchor Anchor position (e.g. "center", "top-left")
136
+ */
137
+ setAnchor(anchor) {
138
+ this.anchor = anchor;
139
+ this._updateAnchorOffsets();
140
+ }
141
+
142
+ /* ------------------------------------------------------------------ draw */
143
+ /**
144
+ * Draw the image to the canvas
145
+ */
146
+ draw() {
147
+ // Skip drawing if not visible or no bitmap available
148
+ if (!this.visible) return;
149
+ if (!this._bitmap && !this._buffer) return;
150
+
151
+ super.draw();
152
+
153
+ // For ImageData, we must use the buffer
154
+ let source = (this._bitmap instanceof ImageData) ? this._buffer : this._bitmap;
155
+
156
+ if (!source || (this._bitmap instanceof ImageData && !this._buffer)) {
157
+ // If we need a buffer but don't have one yet, try to create it
158
+ if (this._bitmap instanceof ImageData) {
159
+ this.buffer(this._bitmap);
160
+ source = this._buffer;
161
+ }
162
+
163
+ // If we still don't have a valid source, skip drawing
164
+ if (!source) return;
165
+ }
166
+
167
+ // Delegates all transform/alpha/smoothing handling to Painter.img.draw
168
+ Painter.img.draw(source, 0, 0, {
169
+ width: this.width,
170
+ height: this.height,
171
+ anchor: this.anchor,
172
+ rotation: this.rotation,
173
+ scaleX: this.scaleX,
174
+ scaleY: this.scaleY,
175
+ alpha: this.opacity,
176
+ smoothing: this.smoothing,
177
+ flipX: this.scaleX < 0,
178
+ flipY: this.scaleY < 0,
179
+ });
180
+ }
181
+
182
+ /* ---------------------------------------------------- bounds & geometry */
183
+ /** Re‑compute bounding box (called by base class when something changes). */
184
+ calculateBounds() {
185
+ return {
186
+ x: -this._anchorX * this.width,
187
+ y: -this._anchorY * this.height,
188
+ width: this.width,
189
+ height: this.height,
190
+ };
191
+ }
192
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @module Shapes
3
+ * @description Comprehensive collection of drawable shapes and visual elements for canvas rendering.
4
+ *
5
+ * This module provides a rich library of shape primitives that can be used to create
6
+ * complex visual elements in canvas-based games and applications. All shapes are built on
7
+ * a consistent foundation that includes:
8
+ *
9
+ * - Common positioning and sizing (x, y, width, height)
10
+ * - Transformation capabilities (rotation, scaling)
11
+ * - Styling options (fill, stroke, opacity)
12
+ * - Shadow effects
13
+ * - Consistent bounding box calculations for hit detection
14
+ *
15
+ * The hierarchy is as follows:
16
+ * - {@link Transformable}: Base class providing transformation properties
17
+ * - {@link Shape}: Abstract base class adding drawing capabilities
18
+ * - Numerous concrete shape implementations like {@link Rectangle}, {@link Circle}, {@link Cube}, etc.
19
+ *
20
+ * Each shape can be used standalone with the Painter system or wrapped in a
21
+ * GameObject to participate in the game's update/render pipeline.
22
+ *
23
+ * @example
24
+ * // Creating and styling a simple rectangle
25
+ * import { Rectangle } from './core/shapes';
26
+ * import { Painter } from './core/painter';
27
+ *
28
+ * // Initialize painter with canvas context
29
+ * Painter.init(ctx);
30
+ *
31
+ * // Create and draw a rectangle
32
+ * const rect = new Rectangle(100, 100, 200, 150, {
33
+ * color: '#3498db',
34
+ * stroke: '#2980b9',
35
+ * lineWidth: 2,
36
+ * rotation: Math.PI / 6, // 30 degrees in radians
37
+ * opacity: 0.8
38
+ * });
39
+ * rect.draw();
40
+ *
41
+ * @example
42
+ * // Creating a 3D-looking isometric cube
43
+ * import { Cube } from './core/shapes';
44
+ *
45
+ * const cube = new Cube(200, 200, 80, {
46
+ * faceTopColor: '#e74c3c',
47
+ * faceLeftColor: '#c0392b',
48
+ * faceRightColor: '#a93226',
49
+ * rotationX: Math.PI / 8,
50
+ * rotationY: Math.PI / 6
51
+ * });
52
+ * cube.draw();
53
+ *
54
+ * @example
55
+ * // Adding text with wrapping capabilities
56
+ * import { WrappedText } from './core/shapes';
57
+ *
58
+ * const text = new WrappedText(50, 50,
59
+ * "This is a longer text that will automatically wrap to fit within the specified width.",
60
+ * 300, 24, {
61
+ * color: '#333',
62
+ * font: '18px Arial',
63
+ * align: 'center',
64
+ * outlineColor: '#fff',
65
+ * outlineWidth: 2
66
+ * }
67
+ * );
68
+ * text.draw();
69
+ *
70
+ * @see {@link GameObject} For wrapping shapes in game objects to add to the pipeline
71
+ * @see {@link ShapeGOFactory} For a utility to quickly create GameObject wrappers for shapes
72
+ */
73
+ //Shape Abstracts
74
+ export { Euclidian } from "./euclidian.js";
75
+ export { Geometry2d } from "./geometry.js";
76
+ export { Traceable } from "./traceable.js";
77
+ export { Renderable } from "./renderable.js";
78
+ export { Transformable } from "./transformable.js";
79
+ export { Transform } from "./transform.js";
80
+ export { Shape } from "./shape.js";
81
+ export { Group } from "./group.js";
82
+ // Shape Primitives
83
+ export { Arc } from "./arc.js";
84
+ export { Circle } from "./circle.js";
85
+ export { Cloud } from "./clouds.js";
86
+ export { BezierShape } from "./bezier.js";
87
+ export { Rectangle } from "./rect.js";
88
+ export { RoundedRectangle } from "./roundrect.js";
89
+ export { PatternRectangle } from "./pattern";
90
+ export { Square } from "./square.js";
91
+ export { Cube } from "./cube.js";
92
+ export { Cone } from "./cone.js";
93
+ export { Prism } from "./prism.js";
94
+ export { Cylinder } from "./cylinder.js";
95
+ export { Diamond } from "./diamond.js";
96
+ export { Line } from "./line.js";
97
+ export { Triangle } from "./triangle.js";
98
+ export { Star } from "./star.js";
99
+ export { Sphere } from "./sphere.js";
100
+ export { Sphere3D } from "./sphere3d.js";
101
+ export { SVGShape } from "./svg.js";
102
+ export { StickFigure } from "./figure.js";
103
+ export { Ring } from "./ring.js";
104
+ export { Polygon } from "./poly.js";
105
+ export { Arrow } from "./arrow.js";
106
+ export { Pin } from "./pin.js";
107
+ export { PieSlice } from "./slice.js";
108
+ export { Hexagon } from "./hexagon.js";
109
+ export { Heart } from "./heart.js";
110
+ export { Cross } from "./cross.js";
111
+ export * from "./text.js";
@@ -0,0 +1,29 @@
1
+ import { Shape } from "./shape.js";
2
+ import { Painter } from "../painter/painter.js";
3
+
4
+ export class Line extends Shape {
5
+ /**
6
+ * Creates a line shape centered around (x, y)
7
+ * @param {number} x - Center X
8
+ * @param {number} y - Center Y
9
+ * @param {number} length - Length of the line
10
+ * @param {Object} options - Style options
11
+ */
12
+ constructor(length = 40, options = {}) {
13
+ super(options);
14
+ this.length = length;
15
+ }
16
+
17
+ draw() {
18
+ super.draw();
19
+ const half = this.length / 2;
20
+ Painter.lines.line(
21
+ -half,
22
+ -half,
23
+ half,
24
+ half,
25
+ this.stroke,
26
+ this.lineWidth
27
+ );
28
+ }
29
+ }
@@ -0,0 +1,90 @@
1
+ import { Shape } from "./shape.js";
2
+ import { Painter } from "../painter/painter.js";
3
+
4
+ /**
5
+ * PatternRectangle - A drawable centered rectangle filled with a pattern.
6
+ * Supports lazy image loading and CanvasImageSource types.
7
+ */
8
+ export class PatternRectangle extends Shape {
9
+ /**
10
+ * @param {CanvasImageSource|null} image - Optional pattern source
11
+ * @param {string} [repetition='repeat'] - Pattern repetition mode
12
+ * @param {Object} [options] - Shape rendering options
13
+ */
14
+ constructor(image = null, repetition = "repeat", options = {}) {
15
+ super(options);
16
+ this.image = image;
17
+ this.repetition = repetition;
18
+ this.pattern = null;
19
+
20
+ if (image) this._tryCreatePattern(image);
21
+ }
22
+
23
+ _tryCreatePattern(image) {
24
+ const isAsyncImage =
25
+ image instanceof HTMLImageElement ||
26
+ (typeof image.complete === "boolean");
27
+
28
+ if (isAsyncImage) {
29
+ if (image.complete) {
30
+ this._createPattern();
31
+ } else {
32
+ image.addEventListener("load", () => this._createPattern(), {
33
+ once: true,
34
+ });
35
+ }
36
+ } else {
37
+ this._createPattern();
38
+ }
39
+ }
40
+
41
+ _createPattern() {
42
+ this.pattern = Painter.img.createPattern(this.image, this.repetition);
43
+ }
44
+
45
+ setImage(image, repetition) {
46
+ this.image = image;
47
+ if (repetition) this.repetition = repetition;
48
+ this.pattern = null;
49
+ this._tryCreatePattern(image);
50
+ }
51
+
52
+ draw() {
53
+ super.draw();
54
+
55
+ if (!this.pattern && this.image) {
56
+ this._tryCreatePattern(this.image);
57
+ }
58
+
59
+ const x = -this.width / 2;
60
+ const y = -this.height / 2;
61
+
62
+ if (this.pattern) {
63
+ Painter.img.fillPattern(
64
+ this.pattern,
65
+ x,
66
+ y,
67
+ this.width,
68
+ this.height
69
+ );
70
+ } else if (this.strokeColor) {
71
+ Painter.shapes.outlineRect(
72
+ x,
73
+ y,
74
+ this.width,
75
+ this.height,
76
+ this.strokeColor,
77
+ this.lineWidth
78
+ );
79
+ }
80
+ }
81
+
82
+ getBounds() {
83
+ return {
84
+ x: this.x,
85
+ y: this.y,
86
+ width: this.width,
87
+ height: this.height,
88
+ };
89
+ }
90
+ }
@@ -0,0 +1,44 @@
1
+ import { Shape } from "./shape.js";
2
+ import { Painter } from "../painter/painter.js";
3
+
4
+ export class Pin extends Shape {
5
+ constructor(radius = 20, options = {}) {
6
+ super(options);
7
+ this.radius = radius;
8
+ }
9
+
10
+ draw() {
11
+ super.draw();
12
+ const r = this.radius;
13
+ const h = r * 2.5;
14
+ const baseY = 0;
15
+
16
+ Painter.lines.beginPath();
17
+
18
+ // Draw circle head
19
+ Painter.shapes.arc(0, baseY, r, Math.PI, 0);
20
+
21
+ // Draw tail (triangle)
22
+ Painter.lines.lineTo(r, baseY);
23
+ Painter.lines.lineTo(0, h);
24
+ Painter.lines.lineTo(-r, baseY);
25
+ Painter.lines.closePath();
26
+
27
+ if (this.color) {
28
+ Painter.colors.fill(this.color);
29
+ }
30
+
31
+ if (this.stroke) {
32
+ Painter.colors.stroke(this.stroke, this.lineWidth);
33
+ }
34
+ }
35
+
36
+ getBounds() {
37
+ return {
38
+ x: this.x,
39
+ y: this.y + this.radius * 0.98, // shift center lower
40
+ width: this.radius * 2,
41
+ height: this.radius * 2.5,
42
+ };
43
+ }
44
+ }
@@ -0,0 +1,31 @@
1
+ import { Shape } from "./shape.js";
2
+ import { Painter } from "../painter/painter.js";
3
+
4
+ export class Polygon extends Shape {
5
+ constructor(sides = 6, radius = 40, options = {}) {
6
+ super(options);
7
+ this.sides = sides;
8
+ this.radius = radius;
9
+ }
10
+
11
+ draw() {
12
+ super.draw();
13
+ const points = [];
14
+ const step = (2 * Math.PI) / this.sides;
15
+
16
+ for (let i = 0; i < this.sides; i++) {
17
+ const angle = i * step;
18
+ points.push({
19
+ x: Math.cos(angle) * this.radius,
20
+ y: Math.sin(angle) * this.radius,
21
+ });
22
+ }
23
+
24
+ Painter.shapes.polygon(
25
+ points,
26
+ this.color,
27
+ this.stroke,
28
+ this.lineWidth
29
+ );
30
+ }
31
+ }