@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
package/src/game/ui/tooltip.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { GameObject } from "../objects/go.js";
|
|
2
2
|
import { Rectangle, TextShape, Group } from "../../shapes/index.js";
|
|
3
|
+
import { UI_THEME } from "./theme.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Tooltip
|
|
6
7
|
*
|
|
7
8
|
* A GameObject that displays text near the cursor when shown.
|
|
8
9
|
* Supports multiline text with automatic word wrapping.
|
|
10
|
+
*
|
|
11
|
+
* Theme: Terminal × Vercel aesthetic
|
|
12
|
+
* - Dark translucent background
|
|
13
|
+
* - Subtle green border glow
|
|
14
|
+
* - Neon green monospace text
|
|
9
15
|
*
|
|
10
16
|
* Usage:
|
|
11
17
|
* const tooltip = new Tooltip(game, { ... });
|
|
@@ -34,10 +40,11 @@ export class Tooltip extends GameObject {
|
|
|
34
40
|
constructor(game, options = {}) {
|
|
35
41
|
super(game, { ...options, zIndex: 9999 }); // Always on top
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
this.
|
|
39
|
-
this.
|
|
40
|
-
this.
|
|
43
|
+
// Terminal × Vercel theme defaults
|
|
44
|
+
this.font = options.font || UI_THEME.fonts.small;
|
|
45
|
+
this.textColor = options.textColor || UI_THEME.tooltip.text;
|
|
46
|
+
this.bgColor = options.bgColor || UI_THEME.tooltip.bg;
|
|
47
|
+
this.borderColor = options.borderColor || UI_THEME.tooltip.border;
|
|
41
48
|
this.padding = options.padding ?? 8;
|
|
42
49
|
this.offsetX = options.offsetX ?? 15;
|
|
43
50
|
this.offsetY = options.offsetY ?? 15;
|
package/src/io/input.js
CHANGED
|
@@ -1,15 +1,38 @@
|
|
|
1
1
|
export class Input {
|
|
2
2
|
static init(game) {
|
|
3
|
+
// Set defaults for last initialized game (backwards compatibility)
|
|
3
4
|
Input.game = game;
|
|
4
5
|
Input.x = 0;
|
|
5
6
|
Input.y = 0;
|
|
6
7
|
Input.down = false;
|
|
7
|
-
|
|
8
|
-
game
|
|
9
|
-
game.events.on("
|
|
10
|
-
game.events.on("
|
|
11
|
-
game.events.on("
|
|
12
|
-
game.events.on("
|
|
8
|
+
|
|
9
|
+
// Create bound handlers that know which game they belong to
|
|
10
|
+
game.events.on("mousedown", (e) => Input._onDown(e, game));
|
|
11
|
+
game.events.on("mouseup", (e) => Input._onUp(e, game));
|
|
12
|
+
game.events.on("mousemove", (e) => Input._onMove(e, game));
|
|
13
|
+
game.events.on("touchstart", (e) => Input._onTouchStart(e, game));
|
|
14
|
+
game.events.on("touchend", (e) => Input._onTouchEnd(e, game));
|
|
15
|
+
game.events.on("touchmove", (e) => Input._onTouchMove(e, game));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Scales CSS pixel coordinates to canvas internal coordinates.
|
|
20
|
+
* This handles the case where the canvas is CSS-scaled (display size differs from resolution).
|
|
21
|
+
* @param {Object} game - The game instance
|
|
22
|
+
* @param {number} cssX - X coordinate in CSS pixels
|
|
23
|
+
* @param {number} cssY - Y coordinate in CSS pixels
|
|
24
|
+
* @returns {{x: number, y: number}} Scaled coordinates in canvas pixels
|
|
25
|
+
*/
|
|
26
|
+
static _scaleToCanvas(game, cssX, cssY) {
|
|
27
|
+
const canvas = game.canvas;
|
|
28
|
+
const rect = canvas.getBoundingClientRect();
|
|
29
|
+
// Scale from CSS pixels to canvas internal pixels
|
|
30
|
+
const scaleX = canvas.width / rect.width;
|
|
31
|
+
const scaleY = canvas.height / rect.height;
|
|
32
|
+
return {
|
|
33
|
+
x: cssX * scaleX,
|
|
34
|
+
y: cssY * scaleY
|
|
35
|
+
};
|
|
13
36
|
}
|
|
14
37
|
|
|
15
38
|
static _setPosition(x, y) {
|
|
@@ -17,54 +40,61 @@ export class Input {
|
|
|
17
40
|
Input.y = y;
|
|
18
41
|
}
|
|
19
42
|
|
|
20
|
-
static _onDown
|
|
43
|
+
static _onDown(e, game) {
|
|
21
44
|
Input.down = true;
|
|
22
|
-
Input.
|
|
23
|
-
|
|
24
|
-
Object.defineProperty(e, "
|
|
25
|
-
|
|
26
|
-
|
|
45
|
+
const scaled = Input._scaleToCanvas(game, e.offsetX, e.offsetY);
|
|
46
|
+
Input._setPosition(scaled.x, scaled.y);
|
|
47
|
+
Object.defineProperty(e, "x", { value: scaled.x, configurable: true });
|
|
48
|
+
Object.defineProperty(e, "y", { value: scaled.y, configurable: true });
|
|
49
|
+
game.events.emit("inputdown", e);
|
|
50
|
+
}
|
|
27
51
|
|
|
28
|
-
static _onUp
|
|
52
|
+
static _onUp(e, game) {
|
|
29
53
|
Input.down = false;
|
|
30
|
-
Input.
|
|
31
|
-
|
|
32
|
-
Object.defineProperty(e, "
|
|
33
|
-
|
|
34
|
-
|
|
54
|
+
const scaled = Input._scaleToCanvas(game, e.offsetX, e.offsetY);
|
|
55
|
+
Input._setPosition(scaled.x, scaled.y);
|
|
56
|
+
Object.defineProperty(e, "x", { value: scaled.x, configurable: true });
|
|
57
|
+
Object.defineProperty(e, "y", { value: scaled.y, configurable: true });
|
|
58
|
+
game.events.emit("inputup", e);
|
|
59
|
+
}
|
|
35
60
|
|
|
36
|
-
static _onMove
|
|
37
|
-
Input.
|
|
38
|
-
|
|
39
|
-
Object.defineProperty(e, "
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
static _onMove(e, game) {
|
|
62
|
+
const scaled = Input._scaleToCanvas(game, e.offsetX, e.offsetY);
|
|
63
|
+
Input._setPosition(scaled.x, scaled.y);
|
|
64
|
+
Object.defineProperty(e, "x", { value: scaled.x, configurable: true });
|
|
65
|
+
Object.defineProperty(e, "y", { value: scaled.y, configurable: true });
|
|
66
|
+
game.events.emit("inputmove", e);
|
|
67
|
+
}
|
|
42
68
|
|
|
43
|
-
static _onTouchStart
|
|
69
|
+
static _onTouchStart(e, game) {
|
|
44
70
|
const touch = e.touches[0];
|
|
45
|
-
const rect =
|
|
71
|
+
const rect = game.canvas.getBoundingClientRect();
|
|
46
72
|
Input.down = true;
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
73
|
+
// Calculate CSS-relative position, then scale to canvas coordinates
|
|
74
|
+
const cssX = touch.clientX - rect.left;
|
|
75
|
+
const cssY = touch.clientY - rect.top;
|
|
76
|
+
const scaled = Input._scaleToCanvas(game, cssX, cssY);
|
|
77
|
+
Input._setPosition(scaled.x, scaled.y);
|
|
78
|
+
Object.defineProperty(e, "x", { value: scaled.x, configurable: true });
|
|
79
|
+
Object.defineProperty(e, "y", { value: scaled.y, configurable: true });
|
|
80
|
+
game.events.emit("inputdown", e);
|
|
81
|
+
}
|
|
54
82
|
|
|
55
|
-
static _onTouchEnd
|
|
83
|
+
static _onTouchEnd(e, game) {
|
|
56
84
|
Input.down = false;
|
|
57
|
-
|
|
58
|
-
}
|
|
85
|
+
game.events.emit("inputup", e);
|
|
86
|
+
}
|
|
59
87
|
|
|
60
|
-
static _onTouchMove
|
|
88
|
+
static _onTouchMove(e, game) {
|
|
61
89
|
const touch = e.touches[0];
|
|
62
|
-
const rect =
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
90
|
+
const rect = game.canvas.getBoundingClientRect();
|
|
91
|
+
// Calculate CSS-relative position, then scale to canvas coordinates
|
|
92
|
+
const cssX = touch.clientX - rect.left;
|
|
93
|
+
const cssY = touch.clientY - rect.top;
|
|
94
|
+
const scaled = Input._scaleToCanvas(game, cssX, cssY);
|
|
95
|
+
Input._setPosition(scaled.x, scaled.y);
|
|
96
|
+
Object.defineProperty(e, "x", { value: scaled.x, configurable: true });
|
|
97
|
+
Object.defineProperty(e, "y", { value: scaled.y, configurable: true });
|
|
98
|
+
game.events.emit("inputmove", e);
|
|
99
|
+
}
|
|
70
100
|
}
|
package/src/io/mouse.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
export class Mouse {
|
|
2
|
+
// Map of canvas -> game for multi-game support
|
|
3
|
+
static _gameMap = new Map();
|
|
4
|
+
|
|
2
5
|
static init(game) {
|
|
6
|
+
// Store mapping from canvas to game
|
|
7
|
+
Mouse._gameMap.set(game.canvas, game);
|
|
8
|
+
|
|
9
|
+
// Set defaults for last initialized game (backwards compatibility)
|
|
3
10
|
Mouse.game = game;
|
|
4
11
|
Mouse.canvas = game.canvas;
|
|
5
12
|
Mouse.x = 0;
|
|
@@ -8,42 +15,59 @@ export class Mouse {
|
|
|
8
15
|
Mouse.middleDown = false;
|
|
9
16
|
Mouse.rightDown = false;
|
|
10
17
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
game.canvas.addEventListener("mousemove", Mouse._onMove);
|
|
19
|
+
game.canvas.addEventListener("mousedown", Mouse._onDown);
|
|
20
|
+
game.canvas.addEventListener("mouseup", Mouse._onUp);
|
|
21
|
+
game.canvas.addEventListener("click", Mouse._onClick);
|
|
22
|
+
game.canvas.addEventListener("wheel", Mouse._onWheel);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Get the game instance for a given event's target canvas
|
|
26
|
+
static _getGameForEvent(e) {
|
|
27
|
+
const canvas = e.currentTarget;
|
|
28
|
+
return Mouse._gameMap.get(canvas) || Mouse.game;
|
|
16
29
|
}
|
|
17
30
|
|
|
18
|
-
static _updatePosition(e) {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
static _updatePosition(e, game) {
|
|
32
|
+
const canvas = game.canvas;
|
|
33
|
+
const rect = canvas.getBoundingClientRect();
|
|
34
|
+
// Calculate CSS-relative position
|
|
35
|
+
const cssX = e.clientX - rect.left;
|
|
36
|
+
const cssY = e.clientY - rect.top;
|
|
37
|
+
// Scale to canvas internal coordinates (handles CSS scaling)
|
|
38
|
+
const scaleX = canvas.width / rect.width;
|
|
39
|
+
const scaleY = canvas.height / rect.height;
|
|
40
|
+
Mouse.x = cssX * scaleX;
|
|
41
|
+
Mouse.y = cssY * scaleY;
|
|
22
42
|
}
|
|
23
43
|
|
|
24
44
|
static _onMove = (e) => {
|
|
25
|
-
Mouse.
|
|
26
|
-
Mouse.
|
|
45
|
+
const game = Mouse._getGameForEvent(e);
|
|
46
|
+
Mouse._updatePosition(e, game);
|
|
47
|
+
game.events.emit("mousemove", e);
|
|
27
48
|
};
|
|
28
49
|
|
|
29
50
|
static _onDown = (e) => {
|
|
30
|
-
Mouse.
|
|
51
|
+
const game = Mouse._getGameForEvent(e);
|
|
52
|
+
Mouse._updatePosition(e, game);
|
|
31
53
|
if (e.button === 0) Mouse.leftDown = true;
|
|
32
54
|
if (e.button === 1) Mouse.middleDown = true;
|
|
33
55
|
if (e.button === 2) Mouse.rightDown = true;
|
|
34
|
-
|
|
56
|
+
game.events.emit("mousedown", e);
|
|
35
57
|
};
|
|
36
58
|
|
|
37
59
|
static _onUp = (e) => {
|
|
38
|
-
Mouse.
|
|
60
|
+
const game = Mouse._getGameForEvent(e);
|
|
61
|
+
Mouse._updatePosition(e, game);
|
|
39
62
|
if (e.button === 0) Mouse.leftDown = false;
|
|
40
63
|
if (e.button === 1) Mouse.middleDown = false;
|
|
41
64
|
if (e.button === 2) Mouse.rightDown = false;
|
|
42
|
-
|
|
65
|
+
game.events.emit("mouseup", e);
|
|
43
66
|
};
|
|
44
67
|
|
|
45
68
|
static _onClick = (e) => {
|
|
46
|
-
Mouse.
|
|
69
|
+
const game = Mouse._getGameForEvent(e);
|
|
70
|
+
Mouse._updatePosition(e, game);
|
|
47
71
|
// Emit enhanced event with canvas-relative coordinates
|
|
48
72
|
// Note: e is a MouseEvent, add canvas-relative x/y directly
|
|
49
73
|
e.canvasX = Mouse.x;
|
|
@@ -51,11 +75,12 @@ export class Mouse {
|
|
|
51
75
|
// Also set x/y for convenience (matches expected fluent API)
|
|
52
76
|
Object.defineProperty(e, 'x', { value: Mouse.x, writable: false });
|
|
53
77
|
Object.defineProperty(e, 'y', { value: Mouse.y, writable: false });
|
|
54
|
-
|
|
78
|
+
game.events.emit("click", e);
|
|
55
79
|
};
|
|
56
80
|
|
|
57
81
|
static _onWheel = (e) => {
|
|
58
|
-
Mouse.
|
|
59
|
-
Mouse.
|
|
82
|
+
const game = Mouse._getGameForEvent(e);
|
|
83
|
+
Mouse._updatePosition(e, game);
|
|
84
|
+
game.events.emit("wheel", e);
|
|
60
85
|
};
|
|
61
86
|
}
|
package/src/io/touch.js
CHANGED
|
@@ -1,39 +1,62 @@
|
|
|
1
1
|
export class Touch {
|
|
2
|
+
// Map of canvas -> game for multi-game support
|
|
3
|
+
static _gameMap = new Map();
|
|
4
|
+
|
|
2
5
|
static init(game) {
|
|
6
|
+
// Store mapping from canvas to game
|
|
7
|
+
Touch._gameMap.set(game.canvas, game);
|
|
8
|
+
|
|
9
|
+
// Set defaults for last initialized game (backwards compatibility)
|
|
3
10
|
Touch.game = game;
|
|
4
11
|
Touch.canvas = game.canvas;
|
|
5
12
|
Touch.x = 0;
|
|
6
13
|
Touch.y = 0;
|
|
7
14
|
Touch.active = false;
|
|
8
15
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
16
|
+
game.canvas.addEventListener("touchstart", Touch._onStart);
|
|
17
|
+
game.canvas.addEventListener("touchend", Touch._onEnd);
|
|
18
|
+
game.canvas.addEventListener("touchmove", Touch._onMove);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Get the game instance for a given event's target canvas
|
|
22
|
+
static _getGameForEvent(e) {
|
|
23
|
+
const canvas = e.currentTarget;
|
|
24
|
+
return Touch._gameMap.get(canvas) || Touch.game;
|
|
12
25
|
}
|
|
13
26
|
|
|
14
|
-
static _updatePosition(touch) {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
27
|
+
static _updatePosition(touch, game) {
|
|
28
|
+
const canvas = game.canvas;
|
|
29
|
+
const rect = canvas.getBoundingClientRect();
|
|
30
|
+
// Calculate CSS-relative position
|
|
31
|
+
const cssX = touch.clientX - rect.left;
|
|
32
|
+
const cssY = touch.clientY - rect.top;
|
|
33
|
+
// Scale to canvas internal coordinates (handles CSS scaling)
|
|
34
|
+
const scaleX = canvas.width / rect.width;
|
|
35
|
+
const scaleY = canvas.height / rect.height;
|
|
36
|
+
Touch.x = cssX * scaleX;
|
|
37
|
+
Touch.y = cssY * scaleY;
|
|
18
38
|
}
|
|
19
39
|
|
|
20
40
|
static _onStart = (e) => {
|
|
21
41
|
if (e.touches.length > 0) {
|
|
42
|
+
const game = Touch._getGameForEvent(e);
|
|
22
43
|
Touch.active = true;
|
|
23
|
-
Touch._updatePosition(e.touches[0]);
|
|
24
|
-
|
|
44
|
+
Touch._updatePosition(e.touches[0], game);
|
|
45
|
+
game.events.emit("touchstart", e);
|
|
25
46
|
}
|
|
26
47
|
};
|
|
27
48
|
|
|
28
49
|
static _onEnd = (e) => {
|
|
50
|
+
const game = Touch._getGameForEvent(e);
|
|
29
51
|
Touch.active = false;
|
|
30
|
-
|
|
52
|
+
game.events.emit("touchend", e);
|
|
31
53
|
};
|
|
32
54
|
|
|
33
55
|
static _onMove = (e) => {
|
|
34
56
|
if (e.touches.length > 0) {
|
|
35
|
-
Touch.
|
|
36
|
-
Touch.
|
|
57
|
+
const game = Touch._getGameForEvent(e);
|
|
58
|
+
Touch._updatePosition(e.touches[0], game);
|
|
59
|
+
game.events.emit("touchmove", e);
|
|
37
60
|
}
|
|
38
61
|
};
|
|
39
62
|
}
|