@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.
- package/demos/coordinates.html +698 -0
- package/demos/cube3d.html +23 -0
- package/demos/demos.css +17 -3
- package/demos/dino.html +42 -0
- package/demos/fluid-simple.html +22 -0
- package/demos/fluid.html +37 -0
- package/demos/gameobjects.html +626 -0
- package/demos/index.html +19 -7
- package/demos/js/blob.js +18 -5
- package/demos/js/coordinates.js +840 -0
- package/demos/js/cube3d.js +789 -0
- package/demos/js/dino.js +1420 -0
- package/demos/js/fluid-simple.js +253 -0
- package/demos/js/fluid.js +527 -0
- package/demos/js/gameobjects.js +176 -0
- package/demos/js/plane3d.js +256 -0
- package/demos/js/platformer.js +1579 -0
- package/demos/js/sphere3d.js +229 -0
- package/demos/js/sprite.js +473 -0
- package/demos/js/tde/accretiondisk.js +65 -12
- package/demos/js/tde/blackholescene.js +2 -2
- package/demos/js/tde/config.js +2 -2
- package/demos/js/tde/index.js +152 -27
- package/demos/js/tde/lensedstarfield.js +32 -25
- package/demos/js/tde/tdestar.js +78 -98
- package/demos/js/tde/tidalstream.js +24 -8
- package/demos/plane3d.html +24 -0
- package/demos/platformer.html +43 -0
- package/demos/sphere3d.html +24 -0
- package/demos/sprite.html +18 -0
- package/docs/README.md +230 -222
- package/docs/api/FluidSystem.md +173 -0
- package/docs/concepts/architecture-overview.md +204 -204
- package/docs/concepts/coordinate-system.md +384 -0
- package/docs/concepts/rendering-pipeline.md +279 -279
- package/docs/concepts/shapes-vs-gameobjects.md +187 -0
- package/docs/concepts/two-layer-architecture.md +229 -229
- package/docs/fluid-dynamics.md +99 -0
- package/docs/getting-started/first-game.md +354 -354
- package/docs/getting-started/installation.md +175 -157
- package/docs/modules/collision/README.md +2 -2
- package/docs/modules/fluent/README.md +6 -6
- package/docs/modules/game/README.md +303 -303
- package/docs/modules/isometric-camera.md +2 -2
- package/docs/modules/isometric.md +1 -1
- package/docs/modules/painter/README.md +328 -328
- package/docs/modules/particle/README.md +3 -3
- package/docs/modules/shapes/README.md +221 -221
- package/docs/modules/shapes/base/euclidian.md +123 -123
- package/docs/modules/shapes/base/shape.md +262 -262
- package/docs/modules/shapes/base/transformable.md +243 -243
- package/docs/modules/state/README.md +2 -2
- package/docs/modules/util/README.md +1 -1
- package/docs/modules/util/camera3d.md +3 -3
- package/docs/modules/util/scene3d.md +1 -1
- package/package.json +3 -1
- package/readme.md +19 -5
- package/src/collision/collision.js +75 -0
- package/src/game/game.js +11 -5
- package/src/game/index.js +2 -1
- package/src/game/objects/index.js +3 -0
- package/src/game/objects/platformer-scene.js +411 -0
- package/src/game/objects/scene.js +14 -0
- package/src/game/objects/sprite.js +529 -0
- package/src/game/pipeline.js +20 -16
- package/src/game/systems/FluidSystem.js +835 -0
- package/src/game/systems/index.js +11 -0
- package/src/game/ui/button.js +39 -18
- package/src/game/ui/cursor.js +14 -0
- package/src/game/ui/fps.js +12 -4
- package/src/game/ui/index.js +2 -0
- package/src/game/ui/stepper.js +549 -0
- package/src/game/ui/theme.js +123 -0
- package/src/game/ui/togglebutton.js +9 -3
- package/src/game/ui/tooltip.js +11 -4
- package/src/io/input.js +75 -45
- package/src/io/mouse.js +44 -19
- package/src/io/touch.js +35 -12
- package/src/math/fluid.js +507 -0
- package/src/math/index.js +2 -0
- package/src/mixins/anchor.js +17 -7
- package/src/motion/tweenetik.js +16 -0
- package/src/shapes/cube3d.js +599 -0
- package/src/shapes/index.js +3 -0
- package/src/shapes/plane3d.js +687 -0
- package/src/shapes/sphere3d.js +75 -6
- package/src/util/camera2d.js +315 -0
- package/src/util/camera3d.js +218 -12
- package/src/util/index.js +1 -0
- package/src/webgl/shaders/plane-shaders.js +332 -0
- package/src/webgl/shaders/sphere-shaders.js +4 -2
- package/types/fluent.d.ts +361 -0
- package/types/game.d.ts +303 -0
- package/types/index.d.ts +144 -5
- package/types/math.d.ts +361 -0
- package/types/motion.d.ts +271 -0
- package/types/particle.d.ts +373 -0
- package/types/shapes.d.ts +107 -9
- package/types/util.d.ts +353 -0
- package/types/webgl.d.ts +109 -0
- package/disk_example.png +0 -0
- 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
|
+
});
|