@guinetik/gcanvas 1.0.2 → 1.0.4

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 (217) hide show
  1. package/dist/gcanvas.es.js +25656 -0
  2. package/dist/gcanvas.es.min.js +1 -0
  3. package/dist/gcanvas.umd.js +1 -0
  4. package/dist/gcanvas.umd.min.js +1 -0
  5. package/package.json +23 -6
  6. package/src/game/objects/index.js +1 -0
  7. package/src/game/objects/spritesheet.js +260 -0
  8. package/src/game/ui/theme.js +6 -0
  9. package/src/io/keys.js +9 -1
  10. package/src/math/boolean.js +481 -0
  11. package/src/math/index.js +1 -0
  12. package/.github/workflows/release.yaml +0 -70
  13. package/.jshintrc +0 -4
  14. package/.vscode/settings.json +0 -22
  15. package/CLAUDE.md +0 -310
  16. package/blackhole.jpg +0 -0
  17. package/demo.png +0 -0
  18. package/demos/CNAME +0 -1
  19. package/demos/animations.html +0 -31
  20. package/demos/basic.html +0 -38
  21. package/demos/baskara.html +0 -31
  22. package/demos/bezier.html +0 -35
  23. package/demos/beziersignature.html +0 -29
  24. package/demos/blackhole.html +0 -28
  25. package/demos/blob.html +0 -35
  26. package/demos/coordinates.html +0 -698
  27. package/demos/cube3d.html +0 -23
  28. package/demos/demos.css +0 -303
  29. package/demos/dino.html +0 -42
  30. package/demos/easing.html +0 -28
  31. package/demos/events.html +0 -195
  32. package/demos/fluent.html +0 -647
  33. package/demos/fluid-simple.html +0 -22
  34. package/demos/fluid.html +0 -37
  35. package/demos/fractals.html +0 -36
  36. package/demos/gameobjects.html +0 -626
  37. package/demos/genart.html +0 -26
  38. package/demos/gendream.html +0 -26
  39. package/demos/group.html +0 -36
  40. package/demos/home.html +0 -587
  41. package/demos/index.html +0 -376
  42. package/demos/isometric.html +0 -34
  43. package/demos/js/animations.js +0 -452
  44. package/demos/js/basic.js +0 -204
  45. package/demos/js/baskara.js +0 -751
  46. package/demos/js/bezier.js +0 -692
  47. package/demos/js/beziersignature.js +0 -241
  48. package/demos/js/blackhole/accretiondisk.obj.js +0 -379
  49. package/demos/js/blackhole/blackhole.obj.js +0 -318
  50. package/demos/js/blackhole/index.js +0 -409
  51. package/demos/js/blackhole/particle.js +0 -56
  52. package/demos/js/blackhole/starfield.obj.js +0 -218
  53. package/demos/js/blob.js +0 -2276
  54. package/demos/js/coordinates.js +0 -840
  55. package/demos/js/cube3d.js +0 -789
  56. package/demos/js/dino.js +0 -1420
  57. package/demos/js/easing.js +0 -477
  58. package/demos/js/fluent.js +0 -183
  59. package/demos/js/fluid-simple.js +0 -253
  60. package/demos/js/fluid.js +0 -527
  61. package/demos/js/fractals.js +0 -931
  62. package/demos/js/fractalworker.js +0 -93
  63. package/demos/js/gameobjects.js +0 -176
  64. package/demos/js/genart.js +0 -268
  65. package/demos/js/gendream.js +0 -209
  66. package/demos/js/group.js +0 -140
  67. package/demos/js/info-toggle.js +0 -25
  68. package/demos/js/isometric.js +0 -863
  69. package/demos/js/kerr.js +0 -1556
  70. package/demos/js/lavalamp.js +0 -590
  71. package/demos/js/layout.js +0 -354
  72. package/demos/js/mondrian.js +0 -285
  73. package/demos/js/opacity.js +0 -275
  74. package/demos/js/painter.js +0 -484
  75. package/demos/js/particles-showcase.js +0 -514
  76. package/demos/js/particles.js +0 -299
  77. package/demos/js/patterns.js +0 -397
  78. package/demos/js/penrose/artifact.js +0 -69
  79. package/demos/js/penrose/blackhole.js +0 -121
  80. package/demos/js/penrose/constants.js +0 -73
  81. package/demos/js/penrose/game.js +0 -943
  82. package/demos/js/penrose/lore.js +0 -278
  83. package/demos/js/penrose/penrosescene.js +0 -892
  84. package/demos/js/penrose/ship.js +0 -216
  85. package/demos/js/penrose/sounds.js +0 -211
  86. package/demos/js/penrose/voidparticle.js +0 -55
  87. package/demos/js/penrose/voidscene.js +0 -258
  88. package/demos/js/penrose/voidship.js +0 -144
  89. package/demos/js/penrose/wormhole.js +0 -46
  90. package/demos/js/pipeline.js +0 -555
  91. package/demos/js/plane3d.js +0 -256
  92. package/demos/js/platformer.js +0 -1579
  93. package/demos/js/scene.js +0 -304
  94. package/demos/js/scenes.js +0 -320
  95. package/demos/js/schrodinger.js +0 -410
  96. package/demos/js/schwarzschild.js +0 -1023
  97. package/demos/js/shapes.js +0 -628
  98. package/demos/js/space/alien.js +0 -171
  99. package/demos/js/space/boom.js +0 -98
  100. package/demos/js/space/boss.js +0 -353
  101. package/demos/js/space/buff.js +0 -73
  102. package/demos/js/space/bullet.js +0 -102
  103. package/demos/js/space/constants.js +0 -85
  104. package/demos/js/space/game.js +0 -1884
  105. package/demos/js/space/hud.js +0 -112
  106. package/demos/js/space/laserbeam.js +0 -179
  107. package/demos/js/space/lightning.js +0 -277
  108. package/demos/js/space/minion.js +0 -192
  109. package/demos/js/space/missile.js +0 -212
  110. package/demos/js/space/player.js +0 -430
  111. package/demos/js/space/powerup.js +0 -90
  112. package/demos/js/space/starfield.js +0 -58
  113. package/demos/js/space/starpower.js +0 -90
  114. package/demos/js/spacetime.js +0 -559
  115. package/demos/js/sphere3d.js +0 -229
  116. package/demos/js/sprite.js +0 -473
  117. package/demos/js/svgtween.js +0 -204
  118. package/demos/js/tde/accretiondisk.js +0 -471
  119. package/demos/js/tde/blackhole.js +0 -219
  120. package/demos/js/tde/blackholescene.js +0 -209
  121. package/demos/js/tde/config.js +0 -59
  122. package/demos/js/tde/index.js +0 -820
  123. package/demos/js/tde/jets.js +0 -290
  124. package/demos/js/tde/lensedstarfield.js +0 -154
  125. package/demos/js/tde/tdestar.js +0 -297
  126. package/demos/js/tde/tidalstream.js +0 -372
  127. package/demos/js/tde_old/blackhole.obj.js +0 -354
  128. package/demos/js/tde_old/debris.obj.js +0 -791
  129. package/demos/js/tde_old/flare.obj.js +0 -239
  130. package/demos/js/tde_old/index.js +0 -448
  131. package/demos/js/tde_old/star.obj.js +0 -812
  132. package/demos/js/tiles.js +0 -312
  133. package/demos/js/tweendemo.js +0 -79
  134. package/demos/js/visibility.js +0 -102
  135. package/demos/kerr.html +0 -28
  136. package/demos/lavalamp.html +0 -27
  137. package/demos/layouts.html +0 -37
  138. package/demos/logo.svg +0 -4
  139. package/demos/loop.html +0 -84
  140. package/demos/mondrian.html +0 -32
  141. package/demos/og_image.png +0 -0
  142. package/demos/opacity.html +0 -36
  143. package/demos/painter.html +0 -39
  144. package/demos/particles-showcase.html +0 -28
  145. package/demos/particles.html +0 -24
  146. package/demos/patterns.html +0 -33
  147. package/demos/penrose-game.html +0 -31
  148. package/demos/pipeline.html +0 -737
  149. package/demos/plane3d.html +0 -24
  150. package/demos/platformer.html +0 -43
  151. package/demos/scene.html +0 -33
  152. package/demos/scenes.html +0 -96
  153. package/demos/schrodinger.html +0 -27
  154. package/demos/schwarzschild.html +0 -27
  155. package/demos/shapes.html +0 -16
  156. package/demos/space.html +0 -85
  157. package/demos/spacetime.html +0 -27
  158. package/demos/sphere3d.html +0 -24
  159. package/demos/sprite.html +0 -18
  160. package/demos/svgtween.html +0 -29
  161. package/demos/tde.html +0 -28
  162. package/demos/tiles.html +0 -28
  163. package/demos/transforms.html +0 -400
  164. package/demos/tween.html +0 -45
  165. package/demos/visibility.html +0 -33
  166. package/docs/README.md +0 -230
  167. package/docs/api/FluidSystem.md +0 -173
  168. package/docs/concepts/architecture-overview.md +0 -204
  169. package/docs/concepts/coordinate-system.md +0 -384
  170. package/docs/concepts/lifecycle.md +0 -255
  171. package/docs/concepts/rendering-pipeline.md +0 -279
  172. package/docs/concepts/shapes-vs-gameobjects.md +0 -187
  173. package/docs/concepts/tde-zorder.md +0 -106
  174. package/docs/concepts/two-layer-architecture.md +0 -229
  175. package/docs/fluid-dynamics.md +0 -99
  176. package/docs/getting-started/first-game.md +0 -354
  177. package/docs/getting-started/hello-world.md +0 -269
  178. package/docs/getting-started/installation.md +0 -175
  179. package/docs/modules/collision/README.md +0 -453
  180. package/docs/modules/fluent/README.md +0 -1075
  181. package/docs/modules/game/README.md +0 -303
  182. package/docs/modules/isometric-camera.md +0 -210
  183. package/docs/modules/isometric.md +0 -275
  184. package/docs/modules/painter/README.md +0 -328
  185. package/docs/modules/particle/README.md +0 -559
  186. package/docs/modules/shapes/README.md +0 -221
  187. package/docs/modules/shapes/base/euclidian.md +0 -123
  188. package/docs/modules/shapes/base/geometry2d.md +0 -204
  189. package/docs/modules/shapes/base/renderable.md +0 -215
  190. package/docs/modules/shapes/base/shape.md +0 -262
  191. package/docs/modules/shapes/base/transformable.md +0 -243
  192. package/docs/modules/shapes/hierarchy.md +0 -218
  193. package/docs/modules/state/README.md +0 -577
  194. package/docs/modules/util/README.md +0 -99
  195. package/docs/modules/util/camera3d.md +0 -412
  196. package/docs/modules/util/scene3d.md +0 -395
  197. package/index.html +0 -17
  198. package/jsdoc.json +0 -50
  199. package/scripts/build-demo.js +0 -69
  200. package/scripts/bundle4llm.js +0 -276
  201. package/scripts/clearconsole.js +0 -48
  202. package/test/math/orbital.test.js +0 -61
  203. package/test/math/tensor.test.js +0 -114
  204. package/test/particle/emitter.test.js +0 -204
  205. package/test/particle/particle-system.test.js +0 -310
  206. package/test/particle/particle.test.js +0 -116
  207. package/test/particle/updaters.test.js +0 -386
  208. package/test/setup.js +0 -120
  209. package/test/shapes/euclidian.test.js +0 -44
  210. package/test/shapes/geometry.test.js +0 -86
  211. package/test/shapes/group.test.js +0 -86
  212. package/test/shapes/rectangle.test.js +0 -64
  213. package/test/shapes/transform.test.js +0 -379
  214. package/test/util/camera3d.test.js +0 -428
  215. package/test/util/scene3d.test.js +0 -352
  216. package/vite.config.js +0 -50
  217. package/vitest.config.js +0 -13
@@ -1,229 +0,0 @@
1
- # Two-Layer Architecture
2
-
3
- > Understanding when to use the Shape Layer vs the Game Layer.
4
-
5
- ## Overview
6
-
7
- GCanvas provides two complementary approaches to building canvas applications:
8
-
9
- 1. **Shape Layer** - For declarative, static graphics
10
- 2. **Game Layer** - For interactive, dynamic applications
11
-
12
- You can use either layer independently or combine them for complex applications.
13
-
14
- ## Shape Layer
15
-
16
- The Shape Layer is for drawing graphics without a game loop. Shapes are self-contained objects that know how to render themselves.
17
-
18
- ### When to Use
19
-
20
- - Static visualizations
21
- - Data charts and graphs
22
- - Decorative graphics
23
- - Simple animations (manual redraw)
24
- - Learning canvas fundamentals
25
-
26
- ### Key Classes
27
-
28
- - `Shape` and subclasses (`Circle`, `Rectangle`, `Star`, etc.)
29
- - `Group` for composing shapes
30
- - `Painter` for direct canvas control
31
-
32
- ### Example
33
-
34
- ```js
35
- import { Circle, Rectangle, Group, Painter } from '@guinetik/gcanvas';
36
-
37
- // Initialize Painter with canvas context
38
- const canvas = document.getElementById('canvas');
39
- Painter.init(canvas.getContext('2d'));
40
-
41
- // Create shapes
42
- const circle = new Circle(50, { x: 100, y: 100, color: 'red' });
43
- const rect = new Rectangle(80, 40, { x: 200, y: 100, color: 'blue' });
44
-
45
- // Draw immediately
46
- Painter.clear();
47
- circle.draw();
48
- rect.draw();
49
- ```
50
-
51
- ### Characteristics
52
-
53
- | Aspect | Shape Layer |
54
- |--------|-------------|
55
- | Loop | None (manual redraw) |
56
- | State | Shapes hold their own state |
57
- | Input | Manual event handling |
58
- | Animation | Call draw() on each frame manually |
59
- | Complexity | Simple, direct |
60
-
61
- ## Game Layer
62
-
63
- The Game Layer provides a complete game loop with automatic updates, rendering, and input handling.
64
-
65
- ### When to Use
66
-
67
- - Games and simulations
68
- - Interactive applications
69
- - Real-time animations
70
- - Complex state management
71
- - Multi-object coordination
72
-
73
- ### Key Classes
74
-
75
- - `Game` - Main loop and canvas management
76
- - `Pipeline` - Object lifecycle management
77
- - `GameObject` - Interactive entities
78
- - `Scene` - Hierarchical organization
79
-
80
- ### Example
81
-
82
- ```js
83
- import { Game, Scene, GameObject, Circle } from '@guinetik/gcanvas';
84
-
85
- class Player extends GameObject {
86
- constructor(game) {
87
- super(game);
88
- this.shape = new Circle(40, { color: 'blue' });
89
- this.enableInteractivity(this.shape);
90
- }
91
-
92
- update(dt) {
93
- // Called every frame
94
- if (this.game.input.isKeyDown('ArrowRight')) {
95
- this.shape.x += 200 * dt;
96
- }
97
- }
98
-
99
- render() {
100
- // Called every frame after update
101
- this.shape.draw();
102
- }
103
-
104
- onPointerDown(e) {
105
- // Automatic input handling
106
- console.log('Clicked!');
107
- }
108
- }
109
-
110
- class MyGame extends Game {
111
- init() {
112
- this.enableFluidSize();
113
- const scene = new Scene(this);
114
- scene.add(new Player(this));
115
- this.pipeline.add(scene);
116
- }
117
- }
118
-
119
- const game = new MyGame(document.getElementById('canvas'));
120
- game.start();
121
- ```
122
-
123
- ### Characteristics
124
-
125
- | Aspect | Game Layer |
126
- |--------|-------------|
127
- | Loop | Automatic (requestAnimationFrame) |
128
- | State | Managed by Pipeline |
129
- | Input | Automatic dispatching to objects |
130
- | Animation | Built-in with dt (delta time) |
131
- | Complexity | Full-featured |
132
-
133
- ## Comparison
134
-
135
- ```
136
- ┌─────────────────────────────────────────────────────────────┐
137
- │ Shape Layer │
138
- │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
139
- │ │ Circle │ │Rectangle│ │ Star │ ... more shapes │
140
- │ └────┬────┘ └────┬────┘ └────┬────┘ │
141
- │ │ │ │ │
142
- │ └────────────┼────────────┘ │
143
- │ ▼ │
144
- │ ┌──────────┐ │
145
- │ │ Group │ (optional composition) │
146
- │ └────┬─────┘ │
147
- │ │ │
148
- │ ▼ │
149
- │ ┌──────────┐ │
150
- │ │ draw() │ (manual call) │
151
- │ └──────────┘ │
152
- └─────────────────────────────────────────────────────────────┘
153
-
154
- ┌─────────────────────────────────────────────────────────────┐
155
- │ Game Layer │
156
- │ ┌─────────────────────────────────────────────────────┐ │
157
- │ │ Game │ │
158
- │ │ ┌─────────────────────────────────────────────┐ │ │
159
- │ │ │ Pipeline │ │ │
160
- │ │ │ ┌─────────────────────────────────────┐ │ │ │
161
- │ │ │ │ Scene │ │ │ │
162
- │ │ │ │ ┌───────────┐ ┌───────────┐ │ │ │ │
163
- │ │ │ │ │GameObject │ │GameObject │ ... │ │ │ │
164
- │ │ │ │ │ + Shape │ │ + Shape │ │ │ │ │
165
- │ │ │ │ └───────────┘ └───────────┘ │ │ │ │
166
- │ │ │ └─────────────────────────────────────┘ │ │ │
167
- │ │ └─────────────────────────────────────────────┘ │ │
168
- │ └─────────────────────────────────────────────────────┘ │
169
- │ │ │
170
- │ ▼ │
171
- │ ┌────────────┐ │
172
- │ │ Game Loop │ (automatic) │
173
- │ │ update(dt) │ │
174
- │ │ render() │ │
175
- │ └────────────┘ │
176
- └─────────────────────────────────────────────────────────────┘
177
- ```
178
-
179
- ## Mixing Layers
180
-
181
- You can use shapes without GameObjects, or combine both approaches:
182
-
183
- ```js
184
- class HybridGame extends Game {
185
- init() {
186
- // Game layer for interactive elements
187
- const scene = new Scene(this);
188
- scene.add(new Player(this));
189
- this.pipeline.add(scene);
190
-
191
- // Shape layer for static background
192
- this.background = new Group();
193
- this.background.add(new Rectangle(this.width, this.height, { color: '#222' }));
194
- }
195
-
196
- render() {
197
- // Draw static shapes first
198
- this.background.draw();
199
-
200
- // Then let pipeline draw interactive objects
201
- super.render();
202
- }
203
- }
204
- ```
205
-
206
- ## Decision Guide
207
-
208
- | If you need... | Use |
209
- |---------------|-----|
210
- | Static graphics | Shape Layer |
211
- | Simple animations | Shape Layer + manual loop |
212
- | Keyboard/mouse input | Game Layer |
213
- | Multiple interactive objects | Game Layer |
214
- | Collision detection | Game Layer |
215
- | Scene organization | Game Layer |
216
- | Quick prototype | Shape Layer |
217
- | Full game | Game Layer |
218
-
219
- ## Related
220
-
221
- - [Architecture Overview](./architecture-overview.md) - Full system architecture
222
- - [Rendering Pipeline](./rendering-pipeline.md) - Shape inheritance chain
223
- - [Game Lifecycle](./lifecycle.md) - Update/render cycle
224
-
225
- ## See Also
226
-
227
- - [Shapes Module](../modules/shapes/README.md)
228
- - [Game Module](../modules/game/README.md)
229
- - [Getting Started: Hello World](../getting-started/hello-world.md)
@@ -1,99 +0,0 @@
1
- # Fluid & Gas Dynamics (Math-Only)
2
-
3
- Pure math helpers for SPH-style liquids and lightweight gas simulation. The math stays in `src/math/fluid.js`; consumers (games/demos) are responsible for applying forces to their particles.
4
-
5
- ## What’s Included
6
- - SPH density, pressure, and viscosity kernels (`computeDensities`, `computePressures`, `computeFluidForces`).
7
- - Simplified gas mixing with diffusion/pressure/turbulence (`computeGasForces`).
8
- - Thermal buoyancy coupling (`computeThermalBuoyancy`) that pairs with `src/math/heat.js`.
9
- - Force blending and pure Euler integration (`blendForces`, `integrateEuler`).
10
- - Config factory with no magic numbers (`getDefaultFluidConfig`).
11
-
12
- ## Config
13
- Defined in `src/math/fluid.js` and merged via `mergeConfig` internally.
14
-
15
- ```js
16
- const CONFIG = {
17
- kernel: { smoothingRadius: 28 },
18
- fluid: {
19
- restDensity: 1.1,
20
- particleMass: 1,
21
- pressureStiffness: 1800,
22
- viscosity: 0.18,
23
- surfaceTension: 0,
24
- maxForce: 6000,
25
- },
26
- gas: {
27
- interactionRadius: 34,
28
- pressure: 12,
29
- diffusion: 0.08,
30
- drag: 0.04,
31
- buoyancy: 260,
32
- neutralTemperature: 0.5,
33
- turbulence: 16,
34
- },
35
- external: { gravity: { x: 0, y: 820 } },
36
- };
37
- ```
38
-
39
- Override by passing `{ fluid: { … }, gas: { … }, kernel: { … } }` to any helper.
40
-
41
- ## Particle Shape
42
- Any object with `{ x, y, vx, vy, size?, mass?, custom? }`. Mass is resolved from:
43
- `custom.mass` → `mass` → `size` → `config.fluid.particleMass`.
44
-
45
- ## Core API (pure)
46
- - `computeDensities(particles, cfg?)` → `Float32Array densities`.
47
- - `computePressures(densities, cfg?)` → `Float32Array pressures`.
48
- - `computeFluidForces(particles, cfg?)` → `{ forces, densities, pressures }`.
49
- - `computeGasForces(particles, cfg?)` → `{ forces }`.
50
- - `computeThermalBuoyancy(particles, cfg?)` → `forces[]` using `temperature` or `custom.temperature`.
51
- - `blendForces(a, b, t)` → lerped forces.
52
- - `integrateEuler(particles, forces, dt, cfg?)` → new `{ x, y, vx, vy }[]` (no mutation).
53
-
54
- ## Applying in a Game (pattern)
55
- 1) Build forces:
56
-
57
- ```js
58
- import { computeFluidForces, computeGasForces, blendForces, computeThermalBuoyancy } from "../../src/math/fluid.js";
59
-
60
- const liquid = computeFluidForces(particles, { kernel: { smoothingRadius: 26 } });
61
- const gas = computeGasForces(particles, { gas: { interactionRadius: 40 } });
62
- const buoyancy = computeThermalBuoyancy(particles);
63
-
64
- // Combine as you see fit (example: mix liquid & gas modes, then add buoyancy)
65
- const mixed = blendForces(liquid.forces, gas.forces, modeT); // modeT: 0..1
66
- for (let i = 0; i < particles.length; i++) {
67
- mixed[i].x += buoyancy[i].x;
68
- mixed[i].y += buoyancy[i].y;
69
- }
70
- ```
71
-
72
- 2) Apply to your particles (consumer-controlled):
73
-
74
- ```js
75
- // Mutate in your game loop; math module stays pure.
76
- for (let i = 0; i < particles.length; i++) {
77
- const p = particles[i];
78
- const f = mixed[i];
79
- const mass = p.custom.mass ?? 1;
80
- p.vx += (f.x / mass) * dt;
81
- p.vy += (f.y / mass) * dt;
82
- }
83
- ```
84
-
85
- 3) Let your normal updaters move/render (e.g., `ParticleSystem` velocity updater).
86
-
87
- ## Heat Coupling
88
- Assign `p.temperature` or `p.custom.temperature` each frame (e.g., via `heat.zoneTemperature`). Pass the same particles to `computeThermalBuoyancy` and add the resulting forces.
89
-
90
- ## Notes & Tips
91
- - Keep `smoothingRadius` proportional to particle spacing (roughly 2–3× average spacing).
92
- - Clamp velocities in the consumer if you target 10k–20k particles to keep the frame budget.
93
- - For gases, favor lower `pressure` and higher `diffusion` to avoid jitter.
94
- - The math never allocates inside the hot path besides output arrays; reuse them between frames if you need fewer allocations (pass your own particles array).
95
-
96
-
97
-
98
-
99
-
@@ -1,354 +0,0 @@
1
- # First Game
2
-
3
- > Create an interactive game with the Game layer.
4
-
5
- ## Overview
6
-
7
- This guide shows how to use the Game layer to create interactive applications. We'll build a simple game with keyboard input, collision detection, and animations.
8
-
9
- ## Basic Game Setup
10
-
11
- ```js
12
- import { Game, Scene, GameObject, Circle, Group, Rectangle, TextShape } from '@guinetik/gcanvas';
13
-
14
- class MyGame extends Game {
15
- constructor(canvas) {
16
- super(canvas);
17
- this.enableFluidSize(); // Canvas fills window
18
- this.backgroundColor = '#1a1a2e';
19
- }
20
-
21
- init() {
22
- super.init(); // Initialize input systems
23
-
24
- // Create a scene
25
- this.scene = new Scene(this);
26
- this.pipeline.add(this.scene);
27
-
28
- // Add game objects
29
- this.scene.add(new Player(this));
30
- }
31
- }
32
-
33
- // Start the game
34
- const canvas = document.getElementById('game');
35
- const game = new MyGame(canvas);
36
- game.start();
37
- ```
38
-
39
- ## Creating a Player
40
-
41
- ```js
42
- class Player extends GameObject {
43
- constructor(game) {
44
- super(game);
45
-
46
- // Create the player shape
47
- this.shape = new Circle(30, {
48
- color: '#4ecdc4',
49
- stroke: '#fff',
50
- lineWidth: 2
51
- });
52
-
53
- // Position at center
54
- this.shape.x = game.width / 2;
55
- this.shape.y = game.height / 2;
56
-
57
- // Movement speed (pixels per second)
58
- this.speed = 300;
59
-
60
- // Enable mouse/touch input on this shape
61
- this.enableInteractivity(this.shape);
62
- }
63
-
64
- update(dt) {
65
- // Handle keyboard input
66
- const input = this.game.input;
67
-
68
- if (input.isKeyDown('ArrowLeft') || input.isKeyDown('KeyA')) {
69
- this.shape.x -= this.speed * dt;
70
- }
71
- if (input.isKeyDown('ArrowRight') || input.isKeyDown('KeyD')) {
72
- this.shape.x += this.speed * dt;
73
- }
74
- if (input.isKeyDown('ArrowUp') || input.isKeyDown('KeyW')) {
75
- this.shape.y -= this.speed * dt;
76
- }
77
- if (input.isKeyDown('ArrowDown') || input.isKeyDown('KeyS')) {
78
- this.shape.y += this.speed * dt;
79
- }
80
-
81
- // Keep player on screen
82
- this.shape.x = Math.max(30, Math.min(this.game.width - 30, this.shape.x));
83
- this.shape.y = Math.max(30, Math.min(this.game.height - 30, this.shape.y));
84
- }
85
-
86
- render() {
87
- this.shape.draw();
88
- }
89
-
90
- // Called when player is clicked
91
- onPointerDown(e) {
92
- console.log('Player clicked!');
93
- }
94
- }
95
- ```
96
-
97
- ## Adding Enemies
98
-
99
- ```js
100
- class Enemy extends GameObject {
101
- constructor(game, x, y) {
102
- super(game);
103
-
104
- this.shape = new Rectangle({
105
- x: x,
106
- y: y,
107
- width: 40,
108
- height: 40,
109
- color: '#ff6b6b'
110
- });
111
-
112
- // Random direction
113
- this.vx = (Math.random() - 0.5) * 200;
114
- this.vy = (Math.random() - 0.5) * 200;
115
- }
116
-
117
- update(dt) {
118
- // Move
119
- this.shape.x += this.vx * dt;
120
- this.shape.y += this.vy * dt;
121
-
122
- // Bounce off walls
123
- if (this.shape.x < 20 || this.shape.x > this.game.width - 20) {
124
- this.vx *= -1;
125
- }
126
- if (this.shape.y < 20 || this.shape.y > this.game.height - 20) {
127
- this.vy *= -1;
128
- }
129
-
130
- // Rotate
131
- this.shape.rotation += dt * 2;
132
- }
133
-
134
- render() {
135
- this.shape.draw();
136
- }
137
- }
138
- ```
139
-
140
- ## Complete Game Example
141
-
142
- Here's a complete game from `demos/js/basic.js`:
143
-
144
- ```js
145
- import {
146
- Game,
147
- GameObject,
148
- Scene,
149
- Circle,
150
- Rectangle,
151
- TextShape,
152
- Group,
153
- Motion,
154
- Easing,
155
- FPSCounter
156
- } from '@guinetik/gcanvas';
157
-
158
- /**
159
- * HelloWorldBox - A simple animated text box
160
- */
161
- class HelloWorldBox extends GameObject {
162
- constructor(game) {
163
- super(game);
164
-
165
- // Create a group to hold shapes
166
- this.group = new Group({});
167
-
168
- // Background box
169
- this.box = new Rectangle({
170
- width: 200,
171
- height: 80,
172
- color: '#333'
173
- });
174
-
175
- // Text label
176
- this.label = new TextShape('Hello World!', {
177
- font: '18px monospace',
178
- color: '#0f0',
179
- align: 'center',
180
- baseline: 'middle'
181
- });
182
-
183
- // Add to group
184
- this.group.add(this.box);
185
- this.group.add(this.label);
186
-
187
- // Animation time
188
- this.animTime = 0;
189
- }
190
-
191
- update(dt) {
192
- this.animTime += dt;
193
-
194
- // Pulse the text opacity
195
- const pulse = Motion.pulse(
196
- 0, 1, // min, max opacity
197
- this.animTime,
198
- 2, // 2 second cycle
199
- true, // loop
200
- false, // no yoyo
201
- Easing.easeInOutSine
202
- );
203
- this.label.opacity = pulse.value;
204
-
205
- // Float the group
206
- const float = Motion.float(
207
- { x: 0, y: 0 },
208
- this.animTime,
209
- 5, // 5 second cycle
210
- 0.5, // speed
211
- 0.5, // randomness
212
- 50, // radius
213
- true,
214
- Easing.easeInOutSine
215
- );
216
- this.group.x = float.x;
217
- this.group.y = float.y;
218
-
219
- super.update(dt);
220
- }
221
-
222
- render() {
223
- this.group.render();
224
- }
225
- }
226
-
227
- /**
228
- * DemoGame - Main game class
229
- */
230
- class DemoGame extends Game {
231
- constructor(canvas) {
232
- super(canvas);
233
- this.enableFluidSize();
234
- this.backgroundColor = 'black';
235
- }
236
-
237
- init() {
238
- super.init();
239
-
240
- // Create main scene
241
- this.gameScene = new Scene(this);
242
- this.gameScene.add(new HelloWorldBox(this));
243
- this.pipeline.add(this.gameScene);
244
-
245
- // Add orbiting circle
246
- this.floatingCircle = new Circle(30, {
247
- x: this.width / 2 + 200,
248
- y: this.height / 2,
249
- color: '#0f0'
250
- });
251
- this.floatingCircle.animTime = 0;
252
- this.pipeline.add(this.floatingCircle);
253
-
254
- // Add FPS counter
255
- this.pipeline.add(new FPSCounter(this, {
256
- anchor: 'bottom-right'
257
- }));
258
- }
259
-
260
- update(dt) {
261
- super.update(dt);
262
-
263
- // Center the scene
264
- this.gameScene.x = this.width / 2;
265
- this.gameScene.y = this.height / 2;
266
-
267
- // Orbit the circle
268
- this.floatingCircle.animTime += dt;
269
- const orbit = Motion.orbit(
270
- this.width / 2, this.height / 2,
271
- 200, 200, // radius X, Y
272
- 0, // start angle
273
- this.floatingCircle.animTime,
274
- 8, // 8 second orbit
275
- true, // loop
276
- true // clockwise
277
- );
278
- this.floatingCircle.x = orbit.x;
279
- this.floatingCircle.y = orbit.y;
280
- }
281
- }
282
-
283
- // Run the game
284
- window.addEventListener('load', () => {
285
- const canvas = document.getElementById('game');
286
- const game = new DemoGame(canvas);
287
- game.start();
288
- });
289
- ```
290
-
291
- ## HTML Template
292
-
293
- ```html
294
- <!DOCTYPE html>
295
- <html>
296
- <head>
297
- <meta charset="UTF-8">
298
- <title>My First Game</title>
299
- <style>
300
- body { margin: 0; overflow: hidden; }
301
- canvas { display: block; }
302
- </style>
303
- </head>
304
- <body>
305
- <canvas id="game"></canvas>
306
- <script type="module" src="./game.js"></script>
307
- </body>
308
- </html>
309
- ```
310
-
311
- ## Key Concepts
312
-
313
- | Concept | Description |
314
- |---------|-------------|
315
- | `Game` | Main class managing loop, canvas, input |
316
- | `Scene` | Container for GameObjects |
317
- | `GameObject` | Interactive entity with update/render |
318
- | `enableInteractivity(shape)` | Enable click/hover on a shape |
319
- | `dt` | Delta time in seconds |
320
- | `game.input.isKeyDown(key)` | Check if key is pressed |
321
- | `Motion.*` | Animation helper functions |
322
- | `FPSCounter` | Built-in FPS display |
323
-
324
- ## Input Reference
325
-
326
- ```js
327
- // Keyboard
328
- game.input.isKeyDown('ArrowUp')
329
- game.input.isKeyDown('KeyW')
330
- game.input.isKeyDown('Space')
331
-
332
- // Mouse position
333
- game.mouse.x
334
- game.mouse.y
335
-
336
- // GameObject events
337
- onPointerDown(e) { }
338
- onPointerUp(e) { }
339
- onPointerMove(e) { }
340
- onMouseOver() { }
341
- onMouseOut() { }
342
- ```
343
-
344
- ## Next Steps
345
-
346
- - [Game Module](../modules/game/README.md) - Full Game API reference
347
- - [Motion Patterns](../modules/motion/README.md) - Animation functions
348
- - [Input Handling](../modules/io/README.md) - Mouse, keyboard, touch
349
-
350
- ## Related
351
-
352
- - [Hello World](./hello-world.md)
353
- - [Two-Layer Architecture](../concepts/two-layer-architecture.md)
354
- - [Game Lifecycle](../concepts/lifecycle.md)