samengine 1.9.0 → 1.10.0

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 (87) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +203 -0
  3. package/dist/config/buildconfig.d.ts +146 -0
  4. package/dist/config/buildconfig.js +115 -0
  5. package/dist/config/index.d.ts +9 -0
  6. package/dist/config/index.js +1 -0
  7. package/dist/core.d.ts +17 -0
  8. package/dist/core.js +24 -0
  9. package/dist/html.d.ts +29 -0
  10. package/dist/html.js +20 -0
  11. package/dist/index.d.ts +2 -1
  12. package/dist/index.js +1 -2
  13. package/dist/input.d.ts +51 -0
  14. package/dist/input.js +44 -3
  15. package/dist/keys.d.ts +6 -0
  16. package/dist/keys.js +6 -2
  17. package/dist/logger.d.ts +8 -0
  18. package/dist/logger.js +8 -1
  19. package/dist/nonbrowser/getversion.d.ts +13 -0
  20. package/dist/nonbrowser/getversion.js +35 -0
  21. package/dist/nonbrowser/ghresolver.d.ts +1 -0
  22. package/dist/nonbrowser/ghresolver.js +7 -0
  23. package/dist/nonbrowser/index.d.ts +9 -0
  24. package/dist/nonbrowser/index.js +9 -0
  25. package/dist/nonbrowser/internal/buildhelper.d.ts +42 -0
  26. package/dist/nonbrowser/internal/buildhelper.js +144 -0
  27. package/dist/nonbrowser/internal/cli/argparser.d.ts +20 -0
  28. package/dist/nonbrowser/internal/cli/argparser.js +36 -0
  29. package/dist/nonbrowser/internal/cli/main.d.ts +13 -0
  30. package/dist/nonbrowser/internal/cli/main.js +262 -0
  31. package/dist/nonbrowser/internal/config.d.ts +9 -0
  32. package/dist/nonbrowser/internal/config.js +40 -0
  33. package/dist/nonbrowser/internal/exporthtml.d.ts +37 -0
  34. package/dist/nonbrowser/internal/exporthtml.js +622 -0
  35. package/dist/nonbrowser/internal/projcreator/downloadZip.d.ts +4 -0
  36. package/dist/nonbrowser/internal/projcreator/downloadZip.js +83 -0
  37. package/dist/nonbrowser/internal/projcreator/main.d.ts +1 -0
  38. package/dist/nonbrowser/internal/projcreator/main.js +81 -0
  39. package/dist/nonbrowser/utils.d.ts +8 -0
  40. package/dist/nonbrowser/utils.js +18 -0
  41. package/dist/physics/collision.d.ts +33 -0
  42. package/dist/physics/collision.js +27 -0
  43. package/dist/physics/physicsEngine.d.ts +18 -0
  44. package/dist/physics/physicsEngine.js +18 -0
  45. package/dist/physics/physicsObject.d.ts +20 -0
  46. package/dist/physics/physicsObject.js +20 -0
  47. package/dist/renderer.d.ts +85 -2
  48. package/dist/renderer.js +86 -7
  49. package/dist/samegui/index.d.ts +49 -0
  50. package/dist/samegui/index.js +137 -0
  51. package/dist/save.d.ts +30 -0
  52. package/dist/save.js +25 -0
  53. package/dist/sound/audioplayer.d.ts +39 -0
  54. package/dist/sound/audioplayer.js +39 -5
  55. package/dist/storage/index.d.ts +57 -0
  56. package/dist/storage/index.js +89 -0
  57. package/dist/text/index.d.ts +14 -0
  58. package/dist/text/index.js +58 -0
  59. package/dist/texture.d.ts +100 -0
  60. package/dist/texture.js +75 -41
  61. package/dist/types/button.d.ts +25 -0
  62. package/dist/types/button.js +22 -0
  63. package/dist/types/circle.d.ts +26 -0
  64. package/dist/types/circle.js +21 -7
  65. package/dist/types/color.d.ts +17 -0
  66. package/dist/types/color.js +11 -1
  67. package/dist/types/index.d.ts +1 -1
  68. package/dist/types/index.js +1 -1
  69. package/dist/types/rectangle.d.ts +29 -0
  70. package/dist/types/rectangle.js +23 -6
  71. package/dist/types/triangle.d.ts +23 -0
  72. package/dist/types/triangle.js +20 -6
  73. package/dist/types/vector2d.d.ts +42 -0
  74. package/dist/types/vector2d.js +39 -11
  75. package/dist/types/vector3d.d.ts +38 -0
  76. package/dist/types/vector3d.js +35 -11
  77. package/dist/utils/index.d.ts +13 -4
  78. package/dist/utils/index.js +26 -2
  79. package/dist/utils/logger/index.d.ts +24 -0
  80. package/dist/utils/logger/index.js +44 -0
  81. package/dist/utils/math.d.ts +18 -0
  82. package/dist/utils/math.js +18 -4
  83. package/package.json +40 -10
  84. package/dist/utils/jsonc-parser.d.ts +0 -4
  85. package/dist/utils/jsonc-parser.js +0 -166
  86. package/dist/utils/markdown.d.ts +0 -41
  87. package/dist/utils/markdown.js +0 -699
@@ -0,0 +1,81 @@
1
+ import inquirer from "inquirer";
2
+ import path from "path";
3
+ import fs from "fs-extra";
4
+ import { downloadAndExtract, flattenGitHubZip } from "./downloadZip.js";
5
+ const USERNAME = "Shadowdara";
6
+ const REPO = "samengine-project-templates";
7
+ export async function run() {
8
+ const answers = await inquirer.prompt([
9
+ {
10
+ name: "projectName",
11
+ message: "Project name?",
12
+ default: "my-game"
13
+ }
14
+ ]);
15
+ const targetDir = path.join(process.cwd(), answers.projectName);
16
+ console.log("📦 Downloading template repo...");
17
+ await downloadAndExtract(`https://codeload.github.com/${USERNAME}/${REPO}/zip/refs/heads/main`, targetDir);
18
+ await flattenGitHubZip(targetDir);
19
+ // -------------------------
20
+ // 1. VERSIONEN LADEN
21
+ // -------------------------
22
+ const versions = (await fs.readdir(targetDir))
23
+ .filter(v => fs.statSync(path.join(targetDir, v)).isDirectory());
24
+ const { version } = await inquirer.prompt([
25
+ {
26
+ name: "version",
27
+ message: "Choose version",
28
+ type: "select",
29
+ choices: versions
30
+ }
31
+ ]);
32
+ const versionPath = path.join(targetDir, version);
33
+ // -------------------------
34
+ // 2. STARTER LADEN
35
+ // -------------------------
36
+ const starters = (await fs.readdir(versionPath))
37
+ .filter(s => fs.statSync(path.join(versionPath, s)).isDirectory());
38
+ const { starter } = await inquirer.prompt([
39
+ {
40
+ name: "starter",
41
+ message: "Choose starter",
42
+ type: "select",
43
+ choices: starters
44
+ }
45
+ ]);
46
+ // -------------------------
47
+ // 3. CLEANUP (KEEP ONLY SELECTED)
48
+ // -------------------------
49
+ for (const v of await fs.readdir(targetDir)) {
50
+ const vPath = path.join(targetDir, v);
51
+ if (!(await fs.stat(vPath)).isDirectory())
52
+ continue;
53
+ if (v !== version) {
54
+ await fs.remove(vPath);
55
+ continue;
56
+ }
57
+ // remove other starters inside selected version
58
+ for (const s of await fs.readdir(vPath)) {
59
+ const sPath = path.join(vPath, s);
60
+ if (!(await fs.stat(sPath)).isDirectory())
61
+ continue;
62
+ if (s !== starter) {
63
+ await fs.remove(sPath);
64
+ }
65
+ }
66
+ }
67
+ // -------------------------
68
+ // 4. MOVE STARTER TO ROOT
69
+ // -------------------------
70
+ const starterPath = path.join(targetDir, version, starter);
71
+ const files = await fs.readdir(starterPath);
72
+ for (const file of files) {
73
+ await fs.move(path.join(starterPath, file), path.join(targetDir, file), { overwrite: true });
74
+ }
75
+ // -------------------------
76
+ // 5. FINAL CLEANUP
77
+ // -------------------------
78
+ await fs.remove(path.join(targetDir, version));
79
+ console.log("✅ Done!");
80
+ console.log(`👉 cd ${answers.projectName} && npm install`);
81
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Minifies generated HTML for release builds.
3
+ *
4
+ * The minifier also processes inline CSS and JavaScript, which matters for
5
+ * single-file builds because they can place the whole game shell into one
6
+ * `index.html`.
7
+ */
8
+ export declare function compressHTML(html: string): Promise<string>;
@@ -0,0 +1,18 @@
1
+ import { minify } from "html-minifier-terser";
2
+ /**
3
+ * Minifies generated HTML for release builds.
4
+ *
5
+ * The minifier also processes inline CSS and JavaScript, which matters for
6
+ * single-file builds because they can place the whole game shell into one
7
+ * `index.html`.
8
+ */
9
+ export async function compressHTML(html) {
10
+ return await minify(html, {
11
+ collapseWhitespace: true,
12
+ removeComments: true,
13
+ removeRedundantAttributes: true,
14
+ removeEmptyAttributes: true,
15
+ minifyCSS: true,
16
+ minifyJS: true,
17
+ });
18
+ }
@@ -1,5 +1,11 @@
1
1
  import { Vector2d } from "../types/vector2d.js";
2
2
  import { PhysicsObject } from "./physicsObject.js";
3
+ /**
4
+ * Collision shape used by `PhysicsObject`.
5
+ *
6
+ * Circle and box colliders are centered on `body.position`. Box width and height
7
+ * are full extents, not half extents.
8
+ */
3
9
  export type Collider = {
4
10
  type: "circle";
5
11
  radius: number;
@@ -8,17 +14,44 @@ export type Collider = {
8
14
  width: number;
9
15
  height: number;
10
16
  };
17
+ /**
18
+ * Tests two axis-aligned box colliders for overlap.
19
+ *
20
+ * @returns Collision normal and penetration depth, or `null` when separated.
21
+ */
11
22
  export declare function aabbCollision(a: PhysicsObject, b: PhysicsObject): {
12
23
  normal: Vector2d;
13
24
  penetration: number;
14
25
  } | null;
26
+ /**
27
+ * Tests two circle colliders for overlap.
28
+ *
29
+ * @returns Collision normal from `a` to `b` and penetration depth, or `null`.
30
+ */
15
31
  export declare function circleCollision(a: PhysicsObject, b: PhysicsObject): {
16
32
  normal: Vector2d;
17
33
  penetration: number;
18
34
  } | null;
35
+ /**
36
+ * Tests a circle collider against a box collider.
37
+ *
38
+ * The returned normal points from the closest box point toward the circle.
39
+ */
19
40
  export declare function circleBoxCollision(circleObj: PhysicsObject, boxObj: PhysicsObject): {
20
41
  normal: Vector2d;
21
42
  penetration: number;
22
43
  } | null;
44
+ /**
45
+ * Applies an impulse to two bodies so their velocities respond to a collision.
46
+ *
47
+ * Static bodies are treated as having inverse mass `0`, so only dynamic bodies
48
+ * receive velocity changes.
49
+ */
23
50
  export declare function resolveCollision(a: PhysicsObject, b: PhysicsObject, normal: Vector2d): void;
51
+ /**
52
+ * Moves overlapping bodies apart to remove visible penetration.
53
+ *
54
+ * The correction is distributed by inverse mass, so lighter dynamic bodies move
55
+ * more than heavier ones and static bodies do not move.
56
+ */
24
57
  export declare function positionalCorrection(a: PhysicsObject, b: PhysicsObject, normal: Vector2d, penetration: number): void;
@@ -1,5 +1,10 @@
1
1
  import { add2d, dot2d, length2d, makeVector2d, normalize2d, scale2d, subtract2d } from "../types/vector2d.js";
2
2
  import { clamp } from "../utils/math.js";
3
+ /**
4
+ * Tests two axis-aligned box colliders for overlap.
5
+ *
6
+ * @returns Collision normal and penetration depth, or `null` when separated.
7
+ */
3
8
  export function aabbCollision(a, b) {
4
9
  const posA = a.body.position;
5
10
  const posB = b.body.position;
@@ -27,6 +32,11 @@ export function aabbCollision(a, b) {
27
32
  }
28
33
  return null;
29
34
  }
35
+ /**
36
+ * Tests two circle colliders for overlap.
37
+ *
38
+ * @returns Collision normal from `a` to `b` and penetration depth, or `null`.
39
+ */
30
40
  export function circleCollision(a, b) {
31
41
  const posA = a.body.position;
32
42
  const posB = b.body.position;
@@ -42,6 +52,11 @@ export function circleCollision(a, b) {
42
52
  }
43
53
  return null;
44
54
  }
55
+ /**
56
+ * Tests a circle collider against a box collider.
57
+ *
58
+ * The returned normal points from the closest box point toward the circle.
59
+ */
45
60
  export function circleBoxCollision(circleObj, boxObj) {
46
61
  const circle = circleObj.collider;
47
62
  const box = boxObj.collider;
@@ -65,6 +80,12 @@ export function circleBoxCollision(circleObj, boxObj) {
65
80
  }
66
81
  return null;
67
82
  }
83
+ /**
84
+ * Applies an impulse to two bodies so their velocities respond to a collision.
85
+ *
86
+ * Static bodies are treated as having inverse mass `0`, so only dynamic bodies
87
+ * receive velocity changes.
88
+ */
68
89
  export function resolveCollision(a, b, normal) {
69
90
  const rv = subtract2d(b.body.velocity, a.body.velocity);
70
91
  let velAlongNormal = dot2d(rv, normal);
@@ -83,6 +104,12 @@ export function resolveCollision(a, b, normal) {
83
104
  if (!b.body.isStatic)
84
105
  b.body.velocity = add2d(b.body.velocity, scale2d(impulse, invMassB));
85
106
  }
107
+ /**
108
+ * Moves overlapping bodies apart to remove visible penetration.
109
+ *
110
+ * The correction is distributed by inverse mass, so lighter dynamic bodies move
111
+ * more than heavier ones and static bodies do not move.
112
+ */
86
113
  export function positionalCorrection(a, b, normal, penetration) {
87
114
  const percent = 1.0; // vorher 0.8
88
115
  const slop = 0.001; // vorher 0.01
@@ -1,8 +1,26 @@
1
1
  import { Vector2d } from "../types/vector2d.js";
2
2
  import { PhysicsObject } from "./physicsObject.js";
3
+ /**
4
+ * Simple 2D physics simulation.
5
+ *
6
+ * `step(dt)` applies gravity, integrates positions, checks all object pairs, and
7
+ * resolves circle/box collisions. The implementation is intentionally small and
8
+ * best suited for arcade-style games rather than physically exact simulation.
9
+ */
3
10
  export declare class PhysicsWorld {
4
11
  objects: PhysicsObject[];
5
12
  gravity: Vector2d;
13
+ /**
14
+ * Advances the simulation by `dt` seconds.
15
+ *
16
+ * Use the delta time from `startEngine` for frame-rate independent motion.
17
+ */
6
18
  step(dt: number): void;
7
19
  }
20
+ /**
21
+ * Sets gravity by direction and strength.
22
+ *
23
+ * `x` and `y` describe the direction vector and do not need to be normalized.
24
+ * `strength` becomes the final acceleration magnitude.
25
+ */
8
26
  export declare function setGravityDirection(world: PhysicsWorld, x: number, y: number, strength: number): void;
@@ -15,11 +15,23 @@ import { aabbCollision, circleBoxCollision, circleCollision, positionalCorrectio
15
15
  // function update(dt: number) {
16
16
  // world.step(dt);
17
17
  // }
18
+ /**
19
+ * Simple 2D physics simulation.
20
+ *
21
+ * `step(dt)` applies gravity, integrates positions, checks all object pairs, and
22
+ * resolves circle/box collisions. The implementation is intentionally small and
23
+ * best suited for arcade-style games rather than physically exact simulation.
24
+ */
18
25
  export class PhysicsWorld {
19
26
  constructor() {
20
27
  this.objects = [];
21
28
  this.gravity = makeVector2d(0, 500); // px/s²
22
29
  }
30
+ /**
31
+ * Advances the simulation by `dt` seconds.
32
+ *
33
+ * Use the delta time from `startEngine` for frame-rate independent motion.
34
+ */
23
35
  step(dt) {
24
36
  // Bewegung
25
37
  for (const obj of this.objects) {
@@ -74,6 +86,12 @@ export class PhysicsWorld {
74
86
  }
75
87
  }
76
88
  }
89
+ /**
90
+ * Sets gravity by direction and strength.
91
+ *
92
+ * `x` and `y` describe the direction vector and do not need to be normalized.
93
+ * `strength` becomes the final acceleration magnitude.
94
+ */
77
95
  export function setGravityDirection(world, x, y, strength) {
78
96
  const len = Math.sqrt(x * x + y * y);
79
97
  if (len === 0)
@@ -1,15 +1,35 @@
1
1
  import { Vector2d } from "../types/vector2d.js";
2
2
  import { Collider } from "./collision.js";
3
+ /**
4
+ * Physical body state used by the simple physics world.
5
+ *
6
+ * Positions and velocities use canvas-style 2D coordinates. Static bodies get
7
+ * infinite mass and are not moved by gravity or collision impulses.
8
+ */
3
9
  export declare class RigidBody {
4
10
  position: Vector2d;
5
11
  velocity: Vector2d;
6
12
  mass: number;
7
13
  restitution: number;
8
14
  isStatic: boolean;
15
+ /**
16
+ * Creates a rigid body.
17
+ *
18
+ * @param pos Initial center position.
19
+ * @param mass Body mass. Ignored for static bodies.
20
+ * @param restitution Bounciness factor used during collision resolution.
21
+ * @param isStatic Whether the body should behave like an immovable object.
22
+ */
9
23
  constructor(pos: Vector2d, mass?: number, restitution?: number, isStatic?: boolean);
10
24
  }
25
+ /**
26
+ * Combines physical state with a collision shape.
27
+ */
11
28
  export declare class PhysicsObject {
12
29
  body: RigidBody;
13
30
  collider: Collider;
31
+ /**
32
+ * Creates a physics object from a body and collider.
33
+ */
14
34
  constructor(body: RigidBody, collider: Collider);
15
35
  }
@@ -1,5 +1,19 @@
1
1
  import { makeVector2d } from "../types/vector2d.js";
2
+ /**
3
+ * Physical body state used by the simple physics world.
4
+ *
5
+ * Positions and velocities use canvas-style 2D coordinates. Static bodies get
6
+ * infinite mass and are not moved by gravity or collision impulses.
7
+ */
2
8
  export class RigidBody {
9
+ /**
10
+ * Creates a rigid body.
11
+ *
12
+ * @param pos Initial center position.
13
+ * @param mass Body mass. Ignored for static bodies.
14
+ * @param restitution Bounciness factor used during collision resolution.
15
+ * @param isStatic Whether the body should behave like an immovable object.
16
+ */
3
17
  constructor(pos, mass = 1, restitution = 0.8, isStatic = false) {
4
18
  this.position = pos;
5
19
  this.velocity = makeVector2d(0, 0);
@@ -8,7 +22,13 @@ export class RigidBody {
8
22
  this.isStatic = isStatic;
9
23
  }
10
24
  }
25
+ /**
26
+ * Combines physical state with a collision shape.
27
+ */
11
28
  export class PhysicsObject {
29
+ /**
30
+ * Creates a physics object from a body and collider.
31
+ */
12
32
  constructor(body, collider) {
13
33
  this.body = body;
14
34
  this.collider = collider;
@@ -1,13 +1,96 @@
1
1
  import { type Rect } from "./types/rectangle.js";
2
2
  import { type Circle } from "./types/circle.js";
3
3
  import { type Triangle } from "./types/triangle.js";
4
+ /**
5
+ * Draws normal browser/canvas text at the given position.
6
+ *
7
+ * The text baseline is set to `"top"`, so `x` and `y` describe the upper-left
8
+ * corner of the text area rather than the alphabetic baseline.
9
+ *
10
+ * @param ctx Canvas 2D rendering context to draw into.
11
+ * @param text Text that should be rendered.
12
+ * @param x Horizontal canvas coordinate.
13
+ * @param y Vertical canvas coordinate.
14
+ * @param color Fill color used for the text. Defaults to white.
15
+ * @param font Canvas font string, for example `"20px Arial"`.
16
+ * @deprecated Use samengine/text instead!
17
+ */
4
18
  export declare function renderText(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, color?: string, font?: string): void;
5
- type CharMap = Record<string, Rect>;
19
+ /**
20
+ * Maps a character to the rectangle where that character is located inside a
21
+ * bitmap font spritesheet.
22
+ */
23
+ export type CharMap = Record<string, Rect>;
24
+ /**
25
+ * Renders text from a bitmap font spritesheet.
26
+ *
27
+ * Every character in `text` is looked up in `charMap`. Characters that are not
28
+ * present in the map are skipped. Each source rectangle is drawn next to the
29
+ * previous one, so this is best suited for fixed-height bitmap fonts.
30
+ *
31
+ * @param ctx Canvas 2D rendering context to draw into.
32
+ * @param text Text to render.
33
+ * @param x Start x coordinate.
34
+ * @param y Start y coordinate.
35
+ * @param sprite Image containing all bitmap font glyphs.
36
+ * @param charMap Mapping from character to source rectangle in `sprite`.
37
+ * @param scale Size multiplier for rendered glyphs.
38
+ */
6
39
  export declare function renderBitmapText(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, sprite: HTMLImageElement, charMap: CharMap, scale?: number): void;
40
+ /**
41
+ * Draws a filled rectangle.
42
+ *
43
+ * If `rect.borderRadius` is greater than `0` and the browser supports
44
+ * `CanvasRenderingContext2D.roundRect`, a rounded rectangle is drawn.
45
+ * Otherwise the function falls back to `fillRect`.
46
+ */
7
47
  export declare function drawRect(ctx: CanvasRenderingContext2D, rect: Rect, color?: string): void;
48
+ /**
49
+ * Draws the outline of a rectangle.
50
+ *
51
+ * Supports `rect.borderRadius` in the same way as `drawRect`.
52
+ *
53
+ * @param lineWidth Stroke width in canvas pixels.
54
+ */
8
55
  export declare function drawRectOutline(ctx: CanvasRenderingContext2D, rect: Rect, color?: string, lineWidth?: number): void;
56
+ /**
57
+ * Draws a filled circle using the circle center and radius.
58
+ */
9
59
  export declare function drawCircle(ctx: CanvasRenderingContext2D, circle: Circle, color?: string): void;
60
+ /**
61
+ * Draws the outline of a circle using the circle center and radius.
62
+ *
63
+ * @param lineWidth Stroke width in canvas pixels.
64
+ */
10
65
  export declare function drawCircleOutline(ctx: CanvasRenderingContext2D, circle: Circle, color?: string, lineWidth?: number): void;
66
+ /**
67
+ * Draws a filled triangle from three points.
68
+ */
11
69
  export declare function drawTriangle(ctx: CanvasRenderingContext2D, triangle: Triangle, color?: string): void;
70
+ /**
71
+ * Draws the outline of a triangle from three points.
72
+ *
73
+ * @param lineWidth Stroke width in canvas pixels.
74
+ */
12
75
  export declare function drawTriangleOutline(ctx: CanvasRenderingContext2D, triangle: Triangle, color?: string, lineWidth?: number): void;
13
- export {};
76
+ /**
77
+ * Renders one horizontally repeating parallax background layer.
78
+ *
79
+ * `cameraX` is multiplied by `speed` to create the parallax offset. Lower speed
80
+ * values make the layer move more slowly and feel farther away. The image is
81
+ * repeated horizontally until the full canvas width is covered.
82
+ */
83
+ export declare function renderParallaxBackground(ctx: CanvasRenderingContext2D, image: HTMLImageElement, cameraX: number, speed?: number, canvasWidth?: number, canvasHeight?: number): void;
84
+ export interface ParallaxLayer {
85
+ /** Image used for this layer. It must be loaded before it can be rendered. */
86
+ image: HTMLImageElement;
87
+ /** Movement multiplier relative to `cameraX`. */
88
+ speed: number;
89
+ }
90
+ /**
91
+ * Renders multiple parallax layers in array order.
92
+ *
93
+ * Place distant background layers first and foreground layers later so they draw
94
+ * on top of earlier layers.
95
+ */
96
+ export declare function renderParallaxLayers(ctx: CanvasRenderingContext2D, layers: ParallaxLayer[], cameraX: number): void;
package/dist/renderer.js CHANGED
@@ -1,10 +1,38 @@
1
- // Function to render Text
1
+ /**
2
+ * Draws normal browser/canvas text at the given position.
3
+ *
4
+ * The text baseline is set to `"top"`, so `x` and `y` describe the upper-left
5
+ * corner of the text area rather than the alphabetic baseline.
6
+ *
7
+ * @param ctx Canvas 2D rendering context to draw into.
8
+ * @param text Text that should be rendered.
9
+ * @param x Horizontal canvas coordinate.
10
+ * @param y Vertical canvas coordinate.
11
+ * @param color Fill color used for the text. Defaults to white.
12
+ * @param font Canvas font string, for example `"20px Arial"`.
13
+ * @deprecated Use samengine/text instead!
14
+ */
2
15
  export function renderText(ctx, text, x, y, color = "white", font = "20px Arial") {
3
16
  ctx.fillStyle = color;
4
17
  ctx.font = font;
5
18
  ctx.textBaseline = "top";
6
19
  ctx.fillText(text, x, y);
7
20
  }
21
+ /**
22
+ * Renders text from a bitmap font spritesheet.
23
+ *
24
+ * Every character in `text` is looked up in `charMap`. Characters that are not
25
+ * present in the map are skipped. Each source rectangle is drawn next to the
26
+ * previous one, so this is best suited for fixed-height bitmap fonts.
27
+ *
28
+ * @param ctx Canvas 2D rendering context to draw into.
29
+ * @param text Text to render.
30
+ * @param x Start x coordinate.
31
+ * @param y Start y coordinate.
32
+ * @param sprite Image containing all bitmap font glyphs.
33
+ * @param charMap Mapping from character to source rectangle in `sprite`.
34
+ * @param scale Size multiplier for rendered glyphs.
35
+ */
8
36
  export function renderBitmapText(ctx, text, x, y, sprite, charMap, scale = 1) {
9
37
  let offsetX = 0;
10
38
  for (const c of text) {
@@ -16,7 +44,13 @@ export function renderBitmapText(ctx, text, x, y, sprite, charMap, scale = 1) {
16
44
  }
17
45
  }
18
46
  // ===== SHAPE DRAWING =====
19
- // Function to draw a filled Rectangle
47
+ /**
48
+ * Draws a filled rectangle.
49
+ *
50
+ * If `rect.borderRadius` is greater than `0` and the browser supports
51
+ * `CanvasRenderingContext2D.roundRect`, a rounded rectangle is drawn.
52
+ * Otherwise the function falls back to `fillRect`.
53
+ */
20
54
  export function drawRect(ctx, rect, color = "white") {
21
55
  ctx.fillStyle = color;
22
56
  const radius = rect.borderRadius ?? 0;
@@ -29,7 +63,13 @@ export function drawRect(ctx, rect, color = "white") {
29
63
  ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
30
64
  }
31
65
  }
32
- // Function to draw a Rectangle outline
66
+ /**
67
+ * Draws the outline of a rectangle.
68
+ *
69
+ * Supports `rect.borderRadius` in the same way as `drawRect`.
70
+ *
71
+ * @param lineWidth Stroke width in canvas pixels.
72
+ */
33
73
  export function drawRectOutline(ctx, rect, color = "white", lineWidth = 1) {
34
74
  ctx.strokeStyle = color;
35
75
  ctx.lineWidth = lineWidth;
@@ -43,14 +83,20 @@ export function drawRectOutline(ctx, rect, color = "white", lineWidth = 1) {
43
83
  ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);
44
84
  }
45
85
  }
46
- // Function to draw a filled Circle
86
+ /**
87
+ * Draws a filled circle using the circle center and radius.
88
+ */
47
89
  export function drawCircle(ctx, circle, color = "white") {
48
90
  ctx.fillStyle = color;
49
91
  ctx.beginPath();
50
92
  ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
51
93
  ctx.fill();
52
94
  }
53
- // Function to draw a Circle outline
95
+ /**
96
+ * Draws the outline of a circle using the circle center and radius.
97
+ *
98
+ * @param lineWidth Stroke width in canvas pixels.
99
+ */
54
100
  export function drawCircleOutline(ctx, circle, color = "white", lineWidth = 1) {
55
101
  ctx.strokeStyle = color;
56
102
  ctx.lineWidth = lineWidth;
@@ -58,7 +104,9 @@ export function drawCircleOutline(ctx, circle, color = "white", lineWidth = 1) {
58
104
  ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
59
105
  ctx.stroke();
60
106
  }
61
- // Function to draw a filled Triangle
107
+ /**
108
+ * Draws a filled triangle from three points.
109
+ */
62
110
  export function drawTriangle(ctx, triangle, color = "white") {
63
111
  ctx.fillStyle = color;
64
112
  ctx.beginPath();
@@ -68,7 +116,11 @@ export function drawTriangle(ctx, triangle, color = "white") {
68
116
  ctx.closePath();
69
117
  ctx.fill();
70
118
  }
71
- // Function to draw a Triangle outline
119
+ /**
120
+ * Draws the outline of a triangle from three points.
121
+ *
122
+ * @param lineWidth Stroke width in canvas pixels.
123
+ */
72
124
  export function drawTriangleOutline(ctx, triangle, color = "white", lineWidth = 1) {
73
125
  ctx.strokeStyle = color;
74
126
  ctx.lineWidth = lineWidth;
@@ -79,3 +131,30 @@ export function drawTriangleOutline(ctx, triangle, color = "white", lineWidth =
79
131
  ctx.closePath();
80
132
  ctx.stroke();
81
133
  }
134
+ /**
135
+ * Renders one horizontally repeating parallax background layer.
136
+ *
137
+ * `cameraX` is multiplied by `speed` to create the parallax offset. Lower speed
138
+ * values make the layer move more slowly and feel farther away. The image is
139
+ * repeated horizontally until the full canvas width is covered.
140
+ */
141
+ export function renderParallaxBackground(ctx, image, cameraX, speed = 0.5, canvasWidth = ctx.canvas.width, canvasHeight = ctx.canvas.height) {
142
+ if (!image.complete)
143
+ return;
144
+ const offsetX = -(cameraX * speed) % image.width;
145
+ // Draw enough copies to fill the screen
146
+ for (let x = offsetX - image.width; x < canvasWidth; x += image.width) {
147
+ ctx.drawImage(image, x, 0, image.width, canvasHeight);
148
+ }
149
+ }
150
+ /**
151
+ * Renders multiple parallax layers in array order.
152
+ *
153
+ * Place distant background layers first and foreground layers later so they draw
154
+ * on top of earlier layers.
155
+ */
156
+ export function renderParallaxLayers(ctx, layers, cameraX) {
157
+ for (const layer of layers) {
158
+ renderParallaxBackground(ctx, layer.image, cameraX, layer.speed);
159
+ }
160
+ }
@@ -0,0 +1,49 @@
1
+ export type UIElementType = "button" | "text" | "checkbox";
2
+ /**
3
+ * Stored DOM node for one immediate-mode UI element.
4
+ */
5
+ export type UIElement = {
6
+ el: HTMLElement;
7
+ type: UIElementType;
8
+ };
9
+ /**
10
+ * Tiny immediate-mode HTML overlay for debug tools and simple in-game menus.
11
+ *
12
+ * Call `begin()` before emitting UI for the frame, then call `button`, `text`,
13
+ * and `checkbox` in a stable order, and finally call `end()`. Elements are
14
+ * backed by real DOM nodes but identified by hashed labels or explicit ids.
15
+ */
16
+ export declare class HtmlUI {
17
+ private root;
18
+ private panel;
19
+ private elements;
20
+ private clicked;
21
+ private frameIds;
22
+ private valueMap;
23
+ constructor();
24
+ /**
25
+ * Starts a new UI frame and records which controls are used this frame.
26
+ */
27
+ begin(): void;
28
+ /**
29
+ * Ends the UI frame and clears one-frame button click states.
30
+ */
31
+ end(): void;
32
+ private getButton;
33
+ /**
34
+ * Creates or updates a button.
35
+ *
36
+ * @returns `true` during the frame after the DOM button was clicked.
37
+ */
38
+ button(label: string, idOverride?: string): boolean;
39
+ /**
40
+ * Creates or updates a text label in the overlay panel.
41
+ */
42
+ text(label: string, idOverride?: string): void;
43
+ /**
44
+ * Creates or updates a checkbox and returns its current value.
45
+ *
46
+ * `defaultValue` is only used the first time the checkbox id appears.
47
+ */
48
+ checkbox(label: string, defaultValue: boolean, idOverride?: string): boolean;
49
+ }