@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,303 @@
1
+ # Game Module
2
+
3
+ > Core game loop, Pipeline, GameObjects, and Scenes.
4
+
5
+ ## Overview
6
+
7
+ The game module provides the interactive layer of GCanvas. It manages the game loop, object lifecycle, input handling, and scene organization.
8
+
9
+ ## Quick Start
10
+
11
+ ```js
12
+ import { Game, Scene, GameObject, Circle } from 'gcanvas';
13
+
14
+ class Player extends GameObject {
15
+ constructor(game) {
16
+ super(game);
17
+ this.shape = new Circle(30, { color: 'blue' });
18
+ this.enableInteractivity(this.shape);
19
+ }
20
+
21
+ update(dt) {
22
+ if (this.game.input.isKeyDown('ArrowRight')) {
23
+ this.shape.x += 200 * dt;
24
+ }
25
+ }
26
+
27
+ render() {
28
+ this.shape.draw();
29
+ }
30
+ }
31
+
32
+ class MyGame extends Game {
33
+ init() {
34
+ super.init();
35
+ this.enableFluidSize();
36
+
37
+ const scene = new Scene(this);
38
+ scene.add(new Player(this));
39
+ this.pipeline.add(scene);
40
+ }
41
+ }
42
+
43
+ const game = new MyGame(document.getElementById('canvas'));
44
+ game.start();
45
+ ```
46
+
47
+ ## Core Classes
48
+
49
+ | Class | Description |
50
+ |-------|-------------|
51
+ | **Game** | Main loop, canvas management, input initialization |
52
+ | **Pipeline** | Manages object collections, update/render dispatch |
53
+ | **GameObject** | Base class for interactive entities |
54
+ | **Scene** | Hierarchical container for GameObjects |
55
+
56
+ ## Game Class
57
+
58
+ The entry point for interactive applications.
59
+
60
+ ```js
61
+ class MyGame extends Game {
62
+ constructor(canvas) {
63
+ super(canvas);
64
+ this.enableFluidSize(); // Canvas fills viewport
65
+ this.backgroundColor = '#1a1a2e';
66
+ }
67
+
68
+ init() {
69
+ super.init(); // Initialize input systems
70
+ // Create scenes and objects
71
+ }
72
+
73
+ update(dt) {
74
+ super.update(dt); // Update pipeline
75
+ // Custom game logic
76
+ }
77
+
78
+ render() {
79
+ super.render(); // Render pipeline
80
+ // Custom rendering
81
+ }
82
+ }
83
+
84
+ const game = new MyGame(canvas);
85
+ game.setFPS(60); // Set target FPS
86
+ game.start(); // Begin game loop
87
+ ```
88
+
89
+ ### Key Properties
90
+
91
+ | Property | Type | Description |
92
+ |----------|------|-------------|
93
+ | `canvas` | `HTMLCanvasElement` | The canvas element |
94
+ | `ctx` | `CanvasRenderingContext2D` | 2D context |
95
+ | `pipeline` | `Pipeline` | Object manager |
96
+ | `events` | `EventEmitter` | Event system |
97
+ | `width` | `number` | Canvas width |
98
+ | `height` | `number` | Canvas height |
99
+ | `running` | `boolean` | Is loop running? |
100
+ | `dt` | `number` | Last delta time |
101
+
102
+ ### Key Methods
103
+
104
+ | Method | Description |
105
+ |--------|-------------|
106
+ | `start()` | Begin the game loop |
107
+ | `stop()` | Stop the game loop |
108
+ | `init()` | Initialize game (override) |
109
+ | `update(dt)` | Update logic (override) |
110
+ | `render()` | Render logic (override) |
111
+ | `enableFluidSize()` | Auto-resize to window |
112
+ | `setFPS(fps)` | Set target frame rate |
113
+ | `enablePauseOnBlur(bool)` | Pause when tab loses focus |
114
+
115
+ ## Pipeline Class
116
+
117
+ Manages collections of objects for update and render.
118
+
119
+ ```js
120
+ // Add objects
121
+ game.pipeline.add(scene);
122
+ game.pipeline.add(gameObject);
123
+
124
+ // Remove objects
125
+ game.pipeline.remove(object);
126
+
127
+ // Clear all
128
+ game.pipeline.clear();
129
+ ```
130
+
131
+ Pipeline automatically:
132
+ - Calls `update(dt)` on active objects
133
+ - Calls `render()` on visible objects
134
+ - Sorts by zIndex
135
+ - Dispatches input events
136
+
137
+ ## GameObject Class
138
+
139
+ Base class for all interactive entities.
140
+
141
+ ```js
142
+ class Enemy extends GameObject {
143
+ constructor(game) {
144
+ super(game);
145
+ this.shape = new Rectangle({ width: 40, height: 40, color: 'red' });
146
+ this.enableInteractivity(this.shape);
147
+ this.speed = 100;
148
+ }
149
+
150
+ update(dt) {
151
+ this.shape.x += this.speed * dt;
152
+ }
153
+
154
+ render() {
155
+ this.shape.draw();
156
+ }
157
+
158
+ // Input events
159
+ onPointerDown(e) { }
160
+ onPointerUp(e) { }
161
+ onPointerMove(e) { }
162
+ onMouseOver() { }
163
+ onMouseOut() { }
164
+ }
165
+ ```
166
+
167
+ ### Lifecycle Methods
168
+
169
+ | Method | When Called |
170
+ |--------|-------------|
171
+ | `update(dt)` | Every frame (if active) |
172
+ | `render()` | Every frame (if visible) |
173
+ | `destroy()` | When removed from pipeline |
174
+
175
+ ### Input Methods
176
+
177
+ | Method | Event |
178
+ |--------|-------|
179
+ | `onPointerDown(e)` | Click/tap start |
180
+ | `onPointerUp(e)` | Click/tap end |
181
+ | `onPointerMove(e)` | Pointer movement |
182
+ | `onMouseOver()` | Hover enter |
183
+ | `onMouseOut()` | Hover leave |
184
+
185
+ ## Scene Class
186
+
187
+ Hierarchical container for GameObjects.
188
+
189
+ ```js
190
+ const gameScene = new Scene(game);
191
+ const uiScene = new Scene(game);
192
+
193
+ // Add objects to scenes
194
+ gameScene.add(player);
195
+ gameScene.add(enemy);
196
+
197
+ uiScene.add(healthBar);
198
+ uiScene.add(scoreDisplay);
199
+
200
+ // Add scenes to pipeline (order matters)
201
+ game.pipeline.add(gameScene); // Rendered first
202
+ game.pipeline.add(uiScene); // Rendered on top
203
+ ```
204
+
205
+ Scenes provide:
206
+ - Hierarchical organization
207
+ - Coordinate spaces
208
+ - Z-ordering of children
209
+ - Collective transforms
210
+
211
+ ## UI Components
212
+
213
+ Built on GameObject and Scene:
214
+
215
+ | Component | Description |
216
+ |-----------|-------------|
217
+ | `Button` | Clickable with visual states |
218
+ | `ToggleButton` | On/off toggle |
219
+ | `Cursor` | Custom cursor |
220
+ | `FPSCounter` | FPS display |
221
+
222
+ ```js
223
+ import { Button, FPSCounter } from 'gcanvas';
224
+
225
+ const button = new Button(game, 'Click Me', {
226
+ x: 400,
227
+ y: 300
228
+ });
229
+
230
+ button.on('click', () => {
231
+ console.log('Clicked!');
232
+ });
233
+
234
+ scene.add(button);
235
+ scene.add(new FPSCounter(game, { anchor: 'bottom-right' }));
236
+ ```
237
+
238
+ ## Input Access
239
+
240
+ ```js
241
+ // In GameObject or Game
242
+ update(dt) {
243
+ // Keyboard
244
+ if (this.game.input.isKeyDown('ArrowLeft')) { }
245
+ if (this.game.input.isKeyDown('Space')) { }
246
+ if (this.game.input.isKeyDown('KeyW')) { }
247
+
248
+ // Mouse position
249
+ const mx = this.game.mouse.x;
250
+ const my = this.game.mouse.y;
251
+ }
252
+ ```
253
+
254
+ ## Events
255
+
256
+ ```js
257
+ // Custom events
258
+ game.events.on('player-died', (data) => {
259
+ console.log('Player died:', data);
260
+ });
261
+
262
+ game.events.emit('player-died', { score: 100 });
263
+
264
+ // Remove listener
265
+ game.events.off('player-died', handler);
266
+ ```
267
+
268
+ ## Architecture Diagram
269
+
270
+ ```
271
+ ┌─────────────────────────────────────────────────────────┐
272
+ │ Game │
273
+ │ ┌────────────────────────────────────────────────────┐ │
274
+ │ │ Pipeline │ │
275
+ │ │ ┌──────────────────────────────────────────────┐ │ │
276
+ │ │ │ Scene │ │ │
277
+ │ │ │ ┌────────────┐ ┌────────────┐ │ │ │
278
+ │ │ │ │ GameObject │ │ GameObject │ ... │ │ │
279
+ │ │ │ │ + Shape │ │ + Shape │ │ │ │
280
+ │ │ │ └────────────┘ └────────────┘ │ │ │
281
+ │ │ └──────────────────────────────────────────────┘ │ │
282
+ │ └────────────────────────────────────────────────────┘ │
283
+ │ │ │
284
+ │ ▼ │
285
+ │ ┌────────────┐ │
286
+ │ │ Game Loop │ │
287
+ │ │ update(dt) │ │
288
+ │ │ render() │ │
289
+ │ └────────────┘ │
290
+ └─────────────────────────────────────────────────────────┘
291
+ ```
292
+
293
+ ## Related
294
+
295
+ - [Game Lifecycle](../../concepts/lifecycle.md) - Update/render cycle
296
+ - [Two-Layer Architecture](../../concepts/two-layer-architecture.md) - Shape vs Game layer
297
+ - [First Game Guide](../../getting-started/first-game.md)
298
+
299
+ ## See Also
300
+
301
+ - [Shapes Module](../shapes/README.md)
302
+ - [IO Module](../io/README.md) - Input handling
303
+ - [Motion Module](../motion/README.md) - Animation
@@ -0,0 +1,210 @@
1
+ # IsometricCamera
2
+
3
+ A camera for isometric views with step-based rotation and smooth animation.
4
+
5
+ Unlike `Camera3D` which provides free 3D rotation, `IsometricCamera` is designed for isometric games where the view rotates in fixed increments (e.g., 45° or 90°), similar to classic games like SimCity or Age of Empires.
6
+
7
+ ## Features
8
+
9
+ - **Step-based rotation** - Rotate in fixed increments (default 45°)
10
+ - **Smooth animation** - Animated transitions between angles with easing
11
+ - **Easy integration** - Works seamlessly with `IsometricScene`
12
+ - **Multiple easing options** - Choose from various easing functions
13
+ - **Callbacks** - Get notified when rotation starts/ends
14
+
15
+ ## Basic Usage
16
+
17
+ ```javascript
18
+ import { IsometricCamera, IsometricScene } from 'gcanvas';
19
+
20
+ // Create camera with 90° rotation steps (recommended for isometric)
21
+ const camera = new IsometricCamera({
22
+ rotationStep: Math.PI / 2, // 90 degrees (default)
23
+ animationDuration: 0.5 // 500ms transition
24
+ });
25
+
26
+ // Create scene with camera attached
27
+ const scene = new IsometricScene(game, {
28
+ x: game.width / 2,
29
+ y: game.height / 2,
30
+ camera: camera
31
+ });
32
+
33
+ // Rotate the view
34
+ camera.rotateRight(); // Rotate 45° clockwise
35
+ camera.rotateLeft(); // Rotate 45° counter-clockwise
36
+ ```
37
+
38
+ ## Constructor Options
39
+
40
+ | Option | Type | Default | Description |
41
+ |--------|------|---------|-------------|
42
+ | `angle` | number | `0` | Initial viewing angle in radians |
43
+ | `rotationStep` | number | `Math.PI / 2` | Rotation step size (default 90°). Use 90° for proper isometric look. |
44
+ | `animationDuration` | number | `0.4` | Transition duration in seconds |
45
+ | `easing` | string | `'easeInOutCubic'` | Easing function name |
46
+
47
+ > **Note:** 45° rotation steps can cause visual flattening at certain angles due to how isometric projection works. 90° steps are recommended for the best visual results (like SimCity, Age of Empires).
48
+
49
+ ## Available Easing Functions
50
+
51
+ - `linear` - No easing
52
+ - `easeInQuad`, `easeOutQuad`, `easeInOutQuad` - Quadratic
53
+ - `easeInCubic`, `easeOutCubic`, `easeInOutCubic` - Cubic
54
+ - `easeOutBack` - Overshoot effect
55
+
56
+ ## API Reference
57
+
58
+ ### Methods
59
+
60
+ #### `rotateRight()`
61
+ Rotate view clockwise by one step. Returns `this` for chaining.
62
+
63
+ ```javascript
64
+ camera.rotateRight(); // Rotate 45° right
65
+ ```
66
+
67
+ #### `rotateLeft()`
68
+ Rotate view counter-clockwise by one step. Returns `this` for chaining.
69
+
70
+ ```javascript
71
+ camera.rotateLeft(); // Rotate 45° left
72
+ ```
73
+
74
+ #### `rotateTo(angle)`
75
+ Rotate to a specific angle (animated).
76
+
77
+ ```javascript
78
+ camera.rotateTo(Math.PI / 2); // Rotate to 90°
79
+ ```
80
+
81
+ #### `setAngle(angle)`
82
+ Set angle immediately (no animation).
83
+
84
+ ```javascript
85
+ camera.setAngle(0); // Jump to 0° instantly
86
+ ```
87
+
88
+ #### `update(dt)`
89
+ Update camera animation. Call each frame with delta time in seconds.
90
+
91
+ ```javascript
92
+ // In your update loop
93
+ camera.update(dt);
94
+ ```
95
+
96
+ > Note: If using with `IsometricScene`, the scene calls this automatically.
97
+
98
+ #### `isAnimating()`
99
+ Check if camera is currently animating.
100
+
101
+ ```javascript
102
+ if (!camera.isAnimating()) {
103
+ // Safe to trigger another rotation
104
+ }
105
+ ```
106
+
107
+ #### `getAngleDegrees()`
108
+ Get current angle in degrees (0-360).
109
+
110
+ #### `getNormalizedAngle()`
111
+ Get angle in radians, normalized to 0-2π range.
112
+
113
+ #### `reset()`
114
+ Reset camera to angle 0.
115
+
116
+ ### Callbacks
117
+
118
+ #### `onRotationStart(callback)`
119
+ Set callback for when rotation begins.
120
+
121
+ ```javascript
122
+ camera.onRotationStart((startAngle, targetAngle) => {
123
+ console.log(`Rotating from ${startAngle} to ${targetAngle}`);
124
+ });
125
+ ```
126
+
127
+ #### `onRotationEnd(callback)`
128
+ Set callback for when rotation completes.
129
+
130
+ ```javascript
131
+ camera.onRotationEnd((finalAngle) => {
132
+ console.log(`Rotation complete at ${finalAngle}`);
133
+ });
134
+ ```
135
+
136
+ ## Integration with IsometricScene
137
+
138
+ When attached to an `IsometricScene`, the camera's angle is automatically applied to the `toIsometric()` projection:
139
+
140
+ ```javascript
141
+ // Attach camera to scene
142
+ scene.setCamera(camera);
143
+
144
+ // The scene automatically:
145
+ // 1. Updates the camera each frame
146
+ // 2. Applies camera rotation to all projections
147
+ // 3. Handles depth sorting correctly during rotation
148
+ ```
149
+
150
+ ### How It Works
151
+
152
+ The camera modifies the isometric projection by rotating grid coordinates before projecting:
153
+
154
+ ```javascript
155
+ // Standard isometric projection
156
+ isoX = (x - y) * (tileWidth / 2)
157
+ isoY = (x + y) * (tileHeight / 2)
158
+
159
+ // With camera rotation
160
+ rotatedX = x * cos(angle) - y * sin(angle)
161
+ rotatedY = x * sin(angle) + y * cos(angle)
162
+ isoX = (rotatedX - rotatedY) * (tileWidth / 2)
163
+ isoY = (rotatedX + rotatedY) * (tileHeight / 2)
164
+ ```
165
+
166
+ ## UI Controls Example
167
+
168
+ Add rotation buttons to your game:
169
+
170
+ ```javascript
171
+ import { Button, Keys } from 'gcanvas';
172
+
173
+ // Arrow buttons
174
+ const leftBtn = new Button(game, {
175
+ x: 50, y: game.height - 50,
176
+ width: 50, height: 50,
177
+ text: "◀",
178
+ onClick: () => camera.rotateLeft()
179
+ });
180
+
181
+ const rightBtn = new Button(game, {
182
+ x: 110, y: game.height - 50,
183
+ width: 50, height: 50,
184
+ text: "▶",
185
+ onClick: () => camera.rotateRight()
186
+ });
187
+
188
+ game.pipeline.add(leftBtn);
189
+ game.pipeline.add(rightBtn);
190
+
191
+ // Keyboard controls (Q/E)
192
+ game.events.on(Keys.Q, () => camera.rotateLeft());
193
+ game.events.on(Keys.E, () => camera.rotateRight());
194
+ ```
195
+
196
+ ## Why 90° Rotation Steps?
197
+
198
+ Isometric projection uses the formula:
199
+ - `screenX = (x - y) * tileWidth / 2`
200
+ - `screenY = (x + y) * tileHeight / 2`
201
+
202
+ At 45° rotation angles (like 45°, 135°, 225°, 315°), the `(x + y)` term can become very small, causing the view to appear flat. At 90° increments (0°, 90°, 180°, 270°), the rotation simply swaps axes, maintaining the proper 3D look.
203
+
204
+ This is why classic isometric games like SimCity and Age of Empires use 4-direction rotation (90° steps).
205
+
206
+ ## See Also
207
+
208
+ - [IsometricScene](./isometric.md) - Isometric scene rendering
209
+ - [Camera3D](./camera3d.md) - Free 3D rotation camera
210
+ - [Button](./button.md) - UI buttons