@guinetik/gcanvas 1.0.0 → 1.0.2

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 (102) hide show
  1. package/demos/coordinates.html +698 -0
  2. package/demos/cube3d.html +23 -0
  3. package/demos/demos.css +17 -3
  4. package/demos/dino.html +42 -0
  5. package/demos/fluid-simple.html +22 -0
  6. package/demos/fluid.html +37 -0
  7. package/demos/gameobjects.html +626 -0
  8. package/demos/index.html +19 -7
  9. package/demos/js/blob.js +18 -5
  10. package/demos/js/coordinates.js +840 -0
  11. package/demos/js/cube3d.js +789 -0
  12. package/demos/js/dino.js +1420 -0
  13. package/demos/js/fluid-simple.js +253 -0
  14. package/demos/js/fluid.js +527 -0
  15. package/demos/js/gameobjects.js +176 -0
  16. package/demos/js/plane3d.js +256 -0
  17. package/demos/js/platformer.js +1579 -0
  18. package/demos/js/sphere3d.js +229 -0
  19. package/demos/js/sprite.js +473 -0
  20. package/demos/js/tde/accretiondisk.js +65 -12
  21. package/demos/js/tde/blackholescene.js +2 -2
  22. package/demos/js/tde/config.js +2 -2
  23. package/demos/js/tde/index.js +152 -27
  24. package/demos/js/tde/lensedstarfield.js +32 -25
  25. package/demos/js/tde/tdestar.js +78 -98
  26. package/demos/js/tde/tidalstream.js +24 -8
  27. package/demos/plane3d.html +24 -0
  28. package/demos/platformer.html +43 -0
  29. package/demos/sphere3d.html +24 -0
  30. package/demos/sprite.html +18 -0
  31. package/docs/README.md +230 -222
  32. package/docs/api/FluidSystem.md +173 -0
  33. package/docs/concepts/architecture-overview.md +204 -204
  34. package/docs/concepts/coordinate-system.md +384 -0
  35. package/docs/concepts/rendering-pipeline.md +279 -279
  36. package/docs/concepts/shapes-vs-gameobjects.md +187 -0
  37. package/docs/concepts/two-layer-architecture.md +229 -229
  38. package/docs/fluid-dynamics.md +99 -0
  39. package/docs/getting-started/first-game.md +354 -354
  40. package/docs/getting-started/installation.md +175 -157
  41. package/docs/modules/collision/README.md +2 -2
  42. package/docs/modules/fluent/README.md +6 -6
  43. package/docs/modules/game/README.md +303 -303
  44. package/docs/modules/isometric-camera.md +2 -2
  45. package/docs/modules/isometric.md +1 -1
  46. package/docs/modules/painter/README.md +328 -328
  47. package/docs/modules/particle/README.md +3 -3
  48. package/docs/modules/shapes/README.md +221 -221
  49. package/docs/modules/shapes/base/euclidian.md +123 -123
  50. package/docs/modules/shapes/base/shape.md +262 -262
  51. package/docs/modules/shapes/base/transformable.md +243 -243
  52. package/docs/modules/state/README.md +2 -2
  53. package/docs/modules/util/README.md +1 -1
  54. package/docs/modules/util/camera3d.md +3 -3
  55. package/docs/modules/util/scene3d.md +1 -1
  56. package/package.json +3 -1
  57. package/readme.md +19 -5
  58. package/src/collision/collision.js +75 -0
  59. package/src/game/game.js +11 -5
  60. package/src/game/index.js +2 -1
  61. package/src/game/objects/index.js +3 -0
  62. package/src/game/objects/platformer-scene.js +411 -0
  63. package/src/game/objects/scene.js +14 -0
  64. package/src/game/objects/sprite.js +529 -0
  65. package/src/game/pipeline.js +20 -16
  66. package/src/game/systems/FluidSystem.js +835 -0
  67. package/src/game/systems/index.js +11 -0
  68. package/src/game/ui/button.js +39 -18
  69. package/src/game/ui/cursor.js +14 -0
  70. package/src/game/ui/fps.js +12 -4
  71. package/src/game/ui/index.js +2 -0
  72. package/src/game/ui/stepper.js +549 -0
  73. package/src/game/ui/theme.js +123 -0
  74. package/src/game/ui/togglebutton.js +9 -3
  75. package/src/game/ui/tooltip.js +11 -4
  76. package/src/io/input.js +75 -45
  77. package/src/io/mouse.js +44 -19
  78. package/src/io/touch.js +35 -12
  79. package/src/math/fluid.js +507 -0
  80. package/src/math/index.js +2 -0
  81. package/src/mixins/anchor.js +17 -7
  82. package/src/motion/tweenetik.js +16 -0
  83. package/src/shapes/cube3d.js +599 -0
  84. package/src/shapes/index.js +3 -0
  85. package/src/shapes/plane3d.js +687 -0
  86. package/src/shapes/sphere3d.js +75 -6
  87. package/src/util/camera2d.js +315 -0
  88. package/src/util/camera3d.js +218 -12
  89. package/src/util/index.js +1 -0
  90. package/src/webgl/shaders/plane-shaders.js +332 -0
  91. package/src/webgl/shaders/sphere-shaders.js +4 -2
  92. package/types/fluent.d.ts +361 -0
  93. package/types/game.d.ts +303 -0
  94. package/types/index.d.ts +144 -5
  95. package/types/math.d.ts +361 -0
  96. package/types/motion.d.ts +271 -0
  97. package/types/particle.d.ts +373 -0
  98. package/types/shapes.d.ts +107 -9
  99. package/types/util.d.ts +353 -0
  100. package/types/webgl.d.ts +109 -0
  101. package/disk_example.png +0 -0
  102. package/tde.png +0 -0
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Simplified Fluid Demo using FluidSystem
3
+ *
4
+ * Demonstrates how the FluidSystem class dramatically reduces
5
+ * the boilerplate needed for fluid simulations.
6
+ */
7
+ import {
8
+ Game,
9
+ FPSCounter,
10
+ FluidSystem,
11
+ applyAnchor,
12
+ Position,
13
+ Button,
14
+ ToggleButton,
15
+ HorizontalLayout,
16
+ } from "../../src/index.js";
17
+
18
+ const PARTICLE_SIZE = 32;
19
+
20
+ const CONFIG = {
21
+ particleSize: PARTICLE_SIZE,
22
+ maxParticles: 500,
23
+ gravity: 200,
24
+ container: {
25
+ marginX: 80,
26
+ marginY: 200,
27
+ strokeColor: "#22c55e",
28
+ strokeWidth: 2,
29
+ },
30
+ pointer: {
31
+ radius: PARTICLE_SIZE * 4,
32
+ push: 3000,
33
+ pull: 600,
34
+ },
35
+ ui: {
36
+ margin: 12,
37
+ width: 130,
38
+ height: 32,
39
+ spacing: 6,
40
+ },
41
+ };
42
+
43
+ /**
44
+ * Simplified fluid demo using FluidSystem.
45
+ */
46
+ class FluidSimpleDemo extends Game {
47
+ constructor(canvas) {
48
+ super(canvas);
49
+ this.backgroundColor = "#0f172a";
50
+ this.enableFluidSize();
51
+ this.pointer = { x: 0, y: 0, down: false };
52
+ }
53
+
54
+ init() {
55
+ super.init();
56
+
57
+ // Create container bounds
58
+ this._updateBounds();
59
+
60
+ // Create FluidSystem - ALL the physics is handled internally!
61
+ this.fluid = new FluidSystem(this, {
62
+ maxParticles: CONFIG.maxParticles,
63
+ particleSize: CONFIG.particleSize,
64
+ width: this.bounds.w,
65
+ height: this.bounds.h,
66
+ bounds: this.bounds,
67
+ physics: "liquid",
68
+ debug: true,
69
+ debugColor: CONFIG.container.strokeColor,
70
+ gravity: CONFIG.gravity,
71
+ particleColor: { r: 80, g: 180, b: 255, a: 0.9 },
72
+ });
73
+
74
+ // Spawn particles
75
+ this.fluid.spawn(CONFIG.maxParticles);
76
+
77
+ this.pipeline.add(this.fluid);
78
+
79
+ // Build UI controls
80
+ this._buildUI();
81
+
82
+ // FPS counter
83
+ this.pipeline.add(
84
+ new FPSCounter(this, { color: "#6af", anchor: "top-right" })
85
+ );
86
+
87
+ // Mouse interaction
88
+ this._setupInteraction();
89
+ }
90
+
91
+ /**
92
+ * Build the UI control bar.
93
+ */
94
+ _buildUI() {
95
+ const { margin, width, height, spacing } = CONFIG.ui;
96
+
97
+ // Create horizontal layout for buttons, anchored to bottom left
98
+ const uiPanel = new HorizontalLayout(this, {
99
+ width: width * 3 + spacing * 2,
100
+ height: height,
101
+ spacing,
102
+ padding: 0,
103
+ align: "center",
104
+ });
105
+ applyAnchor(uiPanel, {
106
+ anchor: Position.BOTTOM_LEFT,
107
+ anchorMargin: margin,
108
+ });
109
+
110
+ this.btnMode = new ToggleButton(this, {
111
+ width,
112
+ height,
113
+ text: "Mode: Liquid",
114
+ startToggled: false,
115
+ onToggle: (on) => {
116
+ this.fluid.setPhysicsMode(on ? "gas" : "liquid");
117
+ this.btnMode.text = on ? "Mode: Gas" : "Mode: Liquid";
118
+ },
119
+ });
120
+ uiPanel.add(this.btnMode);
121
+
122
+ this.btnGravity = new ToggleButton(this, {
123
+ width,
124
+ height,
125
+ text: "Gravity: On",
126
+ startToggled: true,
127
+ onToggle: (on) => {
128
+ this.fluid.gravityEnabled = on;
129
+ this.btnGravity.text = on ? "Gravity: On" : "Gravity: Off";
130
+ },
131
+ });
132
+ uiPanel.add(this.btnGravity);
133
+
134
+ this.btnReset = new Button(this, {
135
+ width,
136
+ height,
137
+ text: "Reset",
138
+ onClick: () => this.fluid.reset(),
139
+ });
140
+ uiPanel.add(this.btnReset);
141
+
142
+ this.pipeline.add(uiPanel);
143
+ }
144
+
145
+ _updateBounds() {
146
+ const { marginX, marginY } = CONFIG.container;
147
+ this.bounds = {
148
+ x: marginX,
149
+ y: marginY,
150
+ w: this.width - marginX * 2,
151
+ h: this.height - marginY * 2,
152
+ };
153
+ }
154
+
155
+ onResize() {
156
+ this._updateBounds();
157
+ if (this.fluid) {
158
+ this.fluid.setBounds(this.bounds);
159
+ }
160
+ }
161
+
162
+ _setupInteraction() {
163
+ // Track pointer position and state
164
+ this.events.on("inputmove", (e) => {
165
+ this.pointer.x = e.x;
166
+ this.pointer.y = e.y;
167
+ });
168
+ this.events.on("inputdown", () => (this.pointer.down = true));
169
+ this.events.on("inputup", () => (this.pointer.down = false));
170
+ }
171
+
172
+ /**
173
+ * Apply continuous pointer forces to particles.
174
+ * Push when clicking, gentle pull when hovering.
175
+ * @param {number} dt - Delta time
176
+ */
177
+ _applyPointerForces(dt) {
178
+ const { radius, push, pull } = CONFIG.pointer;
179
+ const r2 = radius * radius;
180
+ const mx = this.pointer.x;
181
+ const my = this.pointer.y;
182
+
183
+ for (const p of this.fluid.particles) {
184
+ const dx = mx - p.x;
185
+ const dy = my - p.y;
186
+ const dist2 = dx * dx + dy * dy;
187
+
188
+ if (dist2 >= r2 || dist2 < 1) continue;
189
+
190
+ const dist = Math.sqrt(dist2);
191
+ const t = 1 - dist / radius;
192
+ const strength = (this.pointer.down ? push : -pull) * t * t;
193
+
194
+ p.vx += (dx / dist) * strength * dt;
195
+ p.vy += (dy / dist) * strength * dt;
196
+ }
197
+ }
198
+
199
+ update(dt) {
200
+ // Apply pointer forces continuously
201
+ this._applyPointerForces(dt);
202
+
203
+ super.update(dt);
204
+ this._colorByVelocity();
205
+ }
206
+
207
+ /**
208
+ * Color particles by velocity (Sebastian Lague style).
209
+ */
210
+ _colorByVelocity() {
211
+ const maxSpeed = 300;
212
+
213
+ for (const p of this.fluid.particles) {
214
+ const speed = Math.sqrt(p.vx * p.vx + p.vy * p.vy);
215
+ const t = Math.min(1, speed / maxSpeed);
216
+
217
+ // Blue (slow) -> Cyan -> Green -> Yellow -> Orange (fast)
218
+ const hue = 210 - t * 180;
219
+ const sat = 80;
220
+ const light = 50 + t * 15;
221
+
222
+ // Simple HSL to RGB approximation
223
+ const c = ((1 - Math.abs((2 * light) / 100 - 1)) * sat) / 100;
224
+ const x = c * (1 - Math.abs(((hue / 60) % 2) - 1));
225
+ const m = light / 100 - c / 2;
226
+
227
+ let r, g, b;
228
+ if (hue < 60) {
229
+ r = c; g = x; b = 0;
230
+ } else if (hue < 120) {
231
+ r = x; g = c; b = 0;
232
+ } else if (hue < 180) {
233
+ r = 0; g = c; b = x;
234
+ } else if (hue < 240) {
235
+ r = 0; g = x; b = c;
236
+ } else if (hue < 300) {
237
+ r = x; g = 0; b = c;
238
+ } else {
239
+ r = c; g = 0; b = x;
240
+ }
241
+
242
+ p.color.r = Math.round((r + m) * 255);
243
+ p.color.g = Math.round((g + m) * 255);
244
+ p.color.b = Math.round((b + m) * 255);
245
+ }
246
+ }
247
+ }
248
+
249
+ window.addEventListener("load", () => {
250
+ const canvas = document.getElementById("game");
251
+ const demo = new FluidSimpleDemo(canvas);
252
+ demo.start();
253
+ });