@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,384 +0,0 @@
1
- # Coordinate System
2
-
3
- GCanvas uses a **center-based coordinate system** where `x` and `y` refer to an object's center point, not its top-left corner. This guide explains how positioning works throughout the library.
4
-
5
- ## TL;DR
6
-
7
- | Situation | How It Works |
8
- |-----------|--------------|
9
- | Object at `(100, 100)` | Center is at screen position (100, 100) |
10
- | Child at `(10, 20)` in a Scene at `(100, 100)` | Child center is at screen position (110, 120) |
11
- | Camera3D `project()` returns `(0, 0)` | Object is at the center of the 3D view |
12
- | Scene3D at `(width/2, height/2)` | 3D origin appears at canvas center |
13
-
14
- ---
15
-
16
- ## 1. Center-Based Positioning
17
-
18
- Unlike many graphics libraries that use top-left corners, GCanvas positions objects by their **center point**. This makes rotation and scaling more intuitive since transforms happen around the object's center.
19
-
20
- ```javascript
21
- // This circle's CENTER is at (100, 100)
22
- const circle = new Circle(50, { x: 100, y: 100, color: "#0f0" });
23
-
24
- // The circle extends from:
25
- // - Left edge: 50 (100 - radius)
26
- // - Right edge: 150 (100 + radius)
27
- // - Top edge: 50 (100 - radius)
28
- // - Bottom edge: 150 (100 + radius)
29
- ```
30
-
31
- ### Comparison with Top-Left Systems
32
-
33
- | System | `x: 100, y: 100` means... | Rotation pivot |
34
- |--------|---------------------------|----------------|
35
- | **GCanvas (center)** | Center at (100, 100) | Around center |
36
- | Top-left systems | Top-left at (100, 100) | Around top-left corner |
37
-
38
- **Why center-based?** When you rotate or scale an object, it transforms around its center naturally. No need to manually adjust the pivot point.
39
-
40
- ---
41
-
42
- ## 2. Basic Positioning
43
-
44
- When you add an object directly to the pipeline, its coordinates are **absolute screen coordinates**.
45
-
46
- ```javascript
47
- class MyGame extends Game {
48
- init() {
49
- super.init();
50
-
51
- // Circle centered at screen position (200, 150)
52
- const circle = new Circle(30, { x: 200, y: 150, color: "#0ff" });
53
- this.pipeline.add(circle);
54
-
55
- // Rectangle centered at screen position (400, 300)
56
- const rect = new Rectangle({
57
- x: 400, y: 300,
58
- width: 100, height: 60,
59
- color: "#f0f"
60
- });
61
- this.pipeline.add(rect);
62
- }
63
- }
64
- ```
65
-
66
- Canvas origin `(0, 0)` is the **top-left corner**:
67
- - **X increases** going right
68
- - **Y increases** going down
69
-
70
- ---
71
-
72
- ## 3. Parent-Child Relationships
73
-
74
- When you add objects to a **Scene**, their coordinates become **relative to the parent's center**.
75
-
76
- ```javascript
77
- // Scene centered at (200, 200)
78
- const scene = new Scene(this, { x: 200, y: 200 });
79
-
80
- // Child at (50, 30) relative to scene
81
- const child = new Circle(20, { x: 50, y: 30, color: "#0f0" });
82
- scene.add(child);
83
-
84
- // Child's screen position: (200 + 50, 200 + 30) = (250, 230)
85
- ```
86
-
87
- ### Visual Diagram
88
-
89
- ```
90
- Canvas (0,0)───────────────────────────────►X
91
-
92
- │ Scene at (200, 200)
93
- │ ┌─────────────────────┐
94
- │ │ Scene's local │
95
- │ │ origin (0, 0) │
96
- │ │ ●───────────┼──► Scene's X
97
- │ │ │ │
98
- │ │ │ Child at │
99
- │ │ │ (50, 30) │
100
- │ │ ▼ ◉ │
101
- │ │ Scene's Y │
102
- │ └─────────────────────┘
103
-
104
-
105
- Y
106
- ```
107
-
108
- When the Scene renders:
109
- 1. Canvas translates to `(200, 200)` — Scene's position
110
- 2. Child renders at `(50, 30)` — relative to Scene's origin
111
- 3. Final screen position: `(250, 230)`
112
-
113
- ### Nested Scenes
114
-
115
- Coordinates stack through the hierarchy:
116
-
117
- ```javascript
118
- const outer = new Scene(this, { x: 100, y: 100 });
119
- const inner = new Scene(this, { x: 50, y: 50 });
120
- const shape = new Circle(10, { x: 25, y: 25, color: "#ff0" });
121
-
122
- inner.add(shape);
123
- outer.add(inner);
124
- this.pipeline.add(outer);
125
-
126
- // Screen position calculation:
127
- // outer.x + inner.x + shape.x = 100 + 50 + 25 = 175
128
- // outer.y + inner.y + shape.y = 100 + 50 + 25 = 175
129
- // Shape appears at screen (175, 175)
130
- ```
131
-
132
- ---
133
-
134
- ## 4. Camera3D and Scene3D
135
-
136
- When using 3D projection, an additional coordinate transformation layer is introduced.
137
-
138
- ### How Camera3D.project() Works
139
-
140
- `Camera3D.project(x, y, z)` transforms a 3D world position to 2D screen coordinates:
141
-
142
- ```javascript
143
- const camera = new Camera3D({ perspective: 800 });
144
-
145
- // Object at 3D position (100, 0, 200)
146
- const projected = camera.project(100, 0, 200);
147
- // Returns: { x: 80, y: 0, z: 200, scale: 0.8 }
148
- ```
149
-
150
- **Key insight:** The returned `x` and `y` are offsets **from the center of the view**, not absolute screen coordinates. An object at world origin `(0, 0, 0)` projects to screen `(0, 0)`.
151
-
152
- ### Why Scene3D Centers the View
153
-
154
- Since Camera3D returns origin-centered coordinates, Scene3D must translate to the canvas center:
155
-
156
- ```javascript
157
- // Scene3D at canvas center
158
- const scene3d = new Scene3D(this, {
159
- x: this.width / 2, // 400 for 800px canvas
160
- y: this.height / 2, // 300 for 600px canvas
161
- camera: this.camera
162
- });
163
- ```
164
-
165
- This means:
166
- - 3D origin `(0, 0, 0)` appears at screen center
167
- - Objects with positive X move right of center
168
- - Objects with positive Y move down from center
169
- - Objects with positive Z are further away (smaller due to perspective)
170
-
171
- ### Code Example: Basic Scene3D
172
-
173
- ```javascript
174
- import { Game, Scene3D, Sphere3D, Camera3D } from "gcanvas";
175
-
176
- class My3DDemo extends Game {
177
- init() {
178
- super.init();
179
-
180
- // Create camera with perspective
181
- this.camera = new Camera3D({
182
- perspective: 800,
183
- rotationY: 0.3
184
- });
185
-
186
- // Scene3D MUST be centered for 3D projection to work correctly
187
- this.scene = new Scene3D(this, {
188
- x: this.width / 2,
189
- y: this.height / 2,
190
- camera: this.camera
191
- });
192
-
193
- // Sphere at 3D origin - appears at screen center
194
- const sphere1 = new Sphere3D(50, {
195
- x: 0, y: 0, z: 0,
196
- color: "#0ff",
197
- camera: this.camera
198
- });
199
-
200
- // Sphere offset in 3D space - appears right of center
201
- const sphere2 = new Sphere3D(30, {
202
- x: 150, y: 0, z: 0,
203
- color: "#f0f",
204
- camera: this.camera
205
- });
206
-
207
- this.scene.add(sphere1);
208
- this.scene.add(sphere2);
209
- this.pipeline.add(this.scene);
210
- }
211
-
212
- update(dt) {
213
- super.update(dt);
214
- this.camera.update(dt); // For auto-rotation/inertia
215
- }
216
- }
217
- ```
218
-
219
- ### Common Gotcha: Manual Centering
220
-
221
- If you're rendering 3D-projected content **outside** of Scene3D, you must manually center:
222
-
223
- ```javascript
224
- // In ParticleSystem.renderWithDepthSort():
225
- // When NOT inside a Scene3D, we must translate to center ourselves
226
- if (!this.worldSpace && !isInsideScene3D) {
227
- ctx.save();
228
- ctx.translate(this.game.width / 2, this.game.height / 2);
229
- // ... render particles at projected positions ...
230
- ctx.restore();
231
- }
232
- ```
233
-
234
- Similarly, `Sphere3D` with shader rendering extracts the current transform to find the scene center:
235
-
236
- ```javascript
237
- // From sphere3d.js - getting scene center for WebGL compositing
238
- const transform = ctx.getTransform();
239
- const sceneX = transform.e; // Translation X (scene center)
240
- const sceneY = transform.f; // Translation Y (scene center)
241
- ```
242
-
243
- ---
244
-
245
- ## 5. Anchoring and Layouts
246
-
247
- ### Position Anchoring
248
-
249
- The `applyAnchor` mixin positions objects relative to the game canvas or a parent container:
250
-
251
- ```javascript
252
- import { Text, applyAnchor, Position } from "gcanvas";
253
-
254
- // Anchor text to top-center of canvas
255
- const title = new Text(this, "Game Title", { font: "24px sans-serif" });
256
- applyAnchor(title, {
257
- anchor: Position.TOP_CENTER,
258
- anchorMargin: 20 // 20px from top edge
259
- });
260
- this.pipeline.add(title);
261
- ```
262
-
263
- Available positions:
264
- - `Position.TOP_LEFT`, `Position.TOP_CENTER`, `Position.TOP_RIGHT`
265
- - `Position.CENTER_LEFT`, `Position.CENTER`, `Position.CENTER_RIGHT`
266
- - `Position.BOTTOM_LEFT`, `Position.BOTTOM_CENTER`, `Position.BOTTOM_RIGHT`
267
-
268
- ### Relative Anchoring
269
-
270
- Anchor relative to another object:
271
-
272
- ```javascript
273
- const panel = new Scene(this, { x: 200, y: 200, width: 300, height: 200 });
274
-
275
- const label = new Text(this, "Panel Title", {});
276
- applyAnchor(label, {
277
- anchor: Position.TOP_CENTER,
278
- anchorRelative: panel, // Position relative to panel
279
- anchorMargin: 10
280
- });
281
-
282
- panel.add(label);
283
- ```
284
-
285
- ### Layout Utilities
286
-
287
- Layouts automatically position multiple items:
288
-
289
- ```javascript
290
- import { verticalLayout, applyLayout, Scene, Text } from "gcanvas";
291
-
292
- const items = [
293
- new Text(this, "Option 1", {}),
294
- new Text(this, "Option 2", {}),
295
- new Text(this, "Option 3", {})
296
- ];
297
-
298
- // Compute vertical layout
299
- const layout = verticalLayout(items, {
300
- spacing: 15,
301
- padding: 10,
302
- align: "center"
303
- });
304
-
305
- // Apply positions to items
306
- applyLayout(items, layout.positions);
307
-
308
- // Add to scene (layout is centered by offset)
309
- const menu = new Scene(this, { x: this.width / 2, y: this.height / 2 });
310
- items.forEach(item => menu.add(item));
311
- ```
312
-
313
- **How layouts work internally:**
314
- 1. Layouts compute positions in a top-left coordinate system starting at `(0, 0)`
315
- 2. `applyLayout` applies these positions plus any offset
316
- 3. LayoutScene subclasses (like `VerticalLayout`) apply a centering offset:
317
- - Vertical: `offsetY = -totalHeight / 2`
318
- - Horizontal: `offsetX = -totalWidth / 2`
319
-
320
- ---
321
-
322
- ## 6. Practical Tips
323
-
324
- ### Quick Reference
325
-
326
- | I want to... | Do this |
327
- |--------------|---------|
328
- | Place object at screen position | Set `x`, `y` directly, add to pipeline |
329
- | Place object relative to parent | Add to Scene, set local `x`, `y` |
330
- | Center object on screen | `x: game.width / 2, y: game.height / 2` |
331
- | Anchor to screen edge | Use `applyAnchor` with `Position` constant |
332
- | Use 3D projection | Use `Scene3D` centered at canvas center |
333
- | Position particles with Camera3D | Set `camera` and `depthSort: true` on ParticleSystem |
334
-
335
- ### Common Mistakes
336
-
337
- **1. Forgetting to center Scene3D**
338
- ```javascript
339
- // WRONG - 3D origin appears at top-left
340
- const scene = new Scene3D(this, { x: 0, y: 0, camera });
341
-
342
- // CORRECT - 3D origin appears at canvas center
343
- const scene = new Scene3D(this, {
344
- x: this.width / 2,
345
- y: this.height / 2,
346
- camera
347
- });
348
- ```
349
-
350
- **2. Confusing local and screen coordinates**
351
- ```javascript
352
- const scene = new Scene(this, { x: 100, y: 100 });
353
- const child = new Circle(20, { x: 50, y: 50 });
354
- scene.add(child);
355
-
356
- // WRONG assumption: child is at screen (50, 50)
357
- // CORRECT: child is at screen (150, 150)
358
- ```
359
-
360
- **3. Not updating Camera3D in game loop**
361
- ```javascript
362
- update(dt) {
363
- super.update(dt);
364
- // If using auto-rotation or inertia, camera needs update
365
- this.camera.update(dt);
366
- }
367
- ```
368
-
369
- **4. Using world coordinates with Camera3D outside Scene3D**
370
- ```javascript
371
- // If using Camera3D projection directly (not in Scene3D),
372
- // remember to translate to canvas center before drawing
373
- Painter.useCtx((ctx) => {
374
- ctx.translate(this.width / 2, this.height / 2);
375
- // Now draw at projected coordinates
376
- });
377
- ```
378
-
379
- ---
380
-
381
- ## See Also
382
-
383
- - [Shapes vs GameObjects](./shapes-vs-gameobjects.md) - Understanding the two hierarchies
384
- - [Rendering Pipeline](./rendering-pipeline.md) - How objects are rendered each frame
@@ -1,255 +0,0 @@
1
- # Game Lifecycle
2
-
3
- > Understanding the update/render cycle and frame timing.
4
-
5
- ## Overview
6
-
7
- The Game class manages the core game loop using `requestAnimationFrame`. It provides a fixed-timestep update cycle with automatic delta time calculation, ensuring consistent gameplay regardless of frame rate.
8
-
9
- ## The Game Loop
10
-
11
- ```
12
- ┌─────────────────────────────────────────────────────────────────┐
13
- │ Game Loop │
14
- │ │
15
- │ game.start() │
16
- │ │ │
17
- │ ▼ │
18
- │ ┌─────────────────────────────────────────────────────────┐ │
19
- │ │ requestAnimationFrame │ │
20
- │ │ │ │ │
21
- │ │ ▼ │ │
22
- │ │ ┌─────────────────────────────────────────────────┐ │ │
23
- │ │ │ loop(timestamp) │ │ │
24
- │ │ │ │ │ │
25
- │ │ │ 1. Calculate elapsed time │ │ │
26
- │ │ │ elapsed = timestamp - lastTime │ │ │
27
- │ │ │ │ │ │
28
- │ │ │ 2. Accumulate time │ │ │
29
- │ │ │ accumulator += elapsed │ │ │
30
- │ │ │ │ │ │
31
- │ │ │ 3. While accumulator >= frameInterval: │ │ │
32
- │ │ │ │ │ │ │
33
- │ │ │ ├─► update(dt) │ │ │
34
- │ │ │ │ │ │ │ │
35
- │ │ │ │ ├─► Pipeline.update(dt) │ │ │
36
- │ │ │ │ │ └─► GameObject.update(dt) │ │ │
37
- │ │ │ │ │ │ │ │
38
- │ │ │ │ └─► Tweenetik.updateAll(dt) │ │ │
39
- │ │ │ │ │ │ │
40
- │ │ │ └─► accumulator -= frameInterval │ │ │
41
- │ │ │ │ │ │
42
- │ │ │ 4. render() │ │ │
43
- │ │ │ │ │ │ │
44
- │ │ │ ├─► Painter.clear() │ │ │
45
- │ │ │ │ │ │ │
46
- │ │ │ └─► Pipeline.render() │ │ │
47
- │ │ │ └─► GameObject.render() │ │ │
48
- │ │ │ └─► Shape.draw() │ │ │
49
- │ │ │ │ │ │
50
- │ │ │ 5. requestAnimationFrame(loop) │ │ │
51
- │ │ │ │ │ │
52
- │ │ └─────────────────────────────────────────────────┘ │ │
53
- │ │ │ │ │
54
- │ │ └───────────────────────────────┼───┘
55
- │ └─────────────────────────────────────────────────────────┘ │
56
- │ │
57
- └─────────────────────────────────────────────────────────────────┘
58
- ```
59
-
60
- ## Fixed Timestep
61
-
62
- GCanvas uses a **fixed timestep** pattern. This means:
63
-
64
- - Updates happen at a consistent rate (default: 60 FPS)
65
- - `dt` (delta time) is always the same value
66
- - Game logic is frame-rate independent
67
-
68
- ```js
69
- // Default: 60 FPS = 16.67ms per frame
70
- game.setFPS(60);
71
-
72
- // dt in update() is always 1/60 = 0.01667 seconds
73
- update(dt) {
74
- // Move 200 pixels per second, regardless of actual frame rate
75
- this.x += 200 * dt;
76
- }
77
- ```
78
-
79
- ## Lifecycle Methods
80
-
81
- ### Game Lifecycle
82
-
83
- ```js
84
- class MyGame extends Game {
85
- constructor(canvas) {
86
- super(canvas);
87
- // 1. Constructor: Setup canvas, context, pipeline
88
- }
89
-
90
- init() {
91
- super.init();
92
- // 2. Init: Create scenes, objects, set up game state
93
- // Called once before start()
94
- }
95
-
96
- update(dt) {
97
- super.update(dt);
98
- // 3. Update: Game logic (called every frame)
99
- // dt = time since last update in seconds
100
- }
101
-
102
- render() {
103
- super.render();
104
- // 4. Render: Drawing (called every frame after update)
105
- }
106
- }
107
-
108
- const game = new MyGame(canvas);
109
- game.start(); // Calls init() then starts the loop
110
- ```
111
-
112
- ### GameObject Lifecycle
113
-
114
- ```js
115
- class Player extends GameObject {
116
- constructor(game) {
117
- super(game);
118
- // 1. Constructor: Create shapes, set initial state
119
- }
120
-
121
- update(dt) {
122
- // 2. Update: Movement, physics, game logic
123
- // Called every frame while active
124
- }
125
-
126
- render() {
127
- // 3. Render: Draw the object
128
- // Called every frame while visible
129
- }
130
-
131
- destroy() {
132
- super.destroy();
133
- // 4. Destroy: Cleanup when removed
134
- }
135
- }
136
- ```
137
-
138
- ## Delta Time (dt)
139
-
140
- The `dt` parameter represents time elapsed since the last update, in **seconds**.
141
-
142
- ```js
143
- update(dt) {
144
- // dt ≈ 0.01667 at 60 FPS
145
- // dt ≈ 0.03333 at 30 FPS
146
-
147
- // Movement: pixels per second
148
- this.x += this.speed * dt; // speed = 200 means 200 px/sec
149
-
150
- // Rotation: radians per second
151
- this.rotation += Math.PI * dt; // Half rotation per second
152
-
153
- // Timers
154
- this.timer += dt;
155
- if (this.timer >= 2.0) { // 2 seconds
156
- this.doSomething();
157
- this.timer = 0;
158
- }
159
- }
160
- ```
161
-
162
- ## Frame Rate Control
163
-
164
- ```js
165
- // Set target FPS
166
- game.setFPS(60); // Default
167
- game.setFPS(30); // Lower for mobile/performance
168
-
169
- // Current frame number
170
- console.log(game.frame);
171
-
172
- // Pause on blur (tab switch)
173
- game.enablePauseOnBlur(true);
174
- ```
175
-
176
- ## Pipeline Execution Order
177
-
178
- The Pipeline manages multiple objects and ensures proper execution order:
179
-
180
- ```
181
- Pipeline.update(dt)
182
- ├─► Filter active objects
183
- ├─► Sort by zIndex
184
- ├─► For each object:
185
- │ └─► object.update(dt)
186
- └─► Tweenetik.updateAll(dt)
187
-
188
- Pipeline.render()
189
- ├─► Filter visible objects
190
- ├─► Sort by zIndex (low to high)
191
- └─► For each object:
192
- └─► object.render()
193
- ```
194
-
195
- ## Scenes and Hierarchy
196
-
197
- Scenes create nested lifecycles:
198
-
199
- ```js
200
- // Scene contains GameObjects
201
- const scene = new Scene(game);
202
- scene.add(player);
203
- scene.add(enemy);
204
- game.pipeline.add(scene);
205
-
206
- // Lifecycle flows through hierarchy:
207
- // Pipeline.update()
208
- // └─► Scene.update()
209
- // ├─► player.update()
210
- // └─► enemy.update()
211
- ```
212
-
213
- ## State Management
214
-
215
- ```js
216
- class MyGame extends Game {
217
- init() {
218
- this.state = 'menu'; // menu, playing, paused, gameover
219
- }
220
-
221
- update(dt) {
222
- switch (this.state) {
223
- case 'menu':
224
- this.menuScene.update(dt);
225
- break;
226
- case 'playing':
227
- this.gameScene.update(dt);
228
- break;
229
- case 'paused':
230
- // Don't update game objects
231
- break;
232
- }
233
- }
234
- }
235
- ```
236
-
237
- ## Performance Tips
238
-
239
- 1. **Use `active` flag** - Set `gameObject.active = false` to skip updates
240
- 2. **Use `visible` flag** - Set `shape.visible = false` to skip rendering
241
- 3. **Pool objects** - Reuse objects instead of creating/destroying
242
- 4. **Batch similar operations** - Group shapes in containers
243
- 5. **Profile with DevTools** - Use browser performance tools
244
-
245
- ## Related
246
-
247
- - [Architecture Overview](./architecture-overview.md) - Full system architecture
248
- - [Two-Layer Architecture](./two-layer-architecture.md) - Shape vs Game layer
249
- - [Rendering Pipeline](./rendering-pipeline.md) - Shape inheritance chain
250
-
251
- ## See Also
252
-
253
- - [Game Module](../modules/game/README.md)
254
- - [Pipeline](../modules/game/pipeline.md)
255
- - [GameObject](../modules/game/gameobject.md)