minimojs 1.0.0-alpha.15 → 1.0.0-alpha.16

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.
@@ -37,12 +37,12 @@ export class PhysicsSystem {
37
37
  }
38
38
  }
39
39
  overlap(a, b) {
40
- const halfWidthA = a.displayWidth / 2;
41
- const halfHeightA = a.displayHeight / 2;
42
- const halfWidthB = b.displayWidth / 2;
43
- const halfHeightB = b.displayHeight / 2;
44
- return (Math.abs(a.renderX - b.renderX) < halfWidthA + halfWidthB &&
45
- Math.abs(a.renderY - b.renderY) < halfHeightA + halfHeightB);
40
+ const halfWidthA = a.bodyDisplayWidth / 2;
41
+ const halfHeightA = a.bodyDisplayHeight / 2;
42
+ const halfWidthB = b.bodyDisplayWidth / 2;
43
+ const halfHeightB = b.bodyDisplayHeight / 2;
44
+ return (Math.abs(a.bodyCenterX - b.bodyCenterX) < halfWidthA + halfWidthB &&
45
+ Math.abs(a.bodyCenterY - b.bodyCenterY) < halfHeightA + halfHeightB);
46
46
  }
47
47
  overlapAny(listA, listB) {
48
48
  for (const a of listA) {
@@ -100,12 +100,12 @@ export class PhysicsSystem {
100
100
  }
101
101
  }
102
102
  getCollisionResolution(a, b) {
103
- const halfWidthA = a.displayWidth / 2;
104
- const halfHeightA = a.displayHeight / 2;
105
- const halfWidthB = b.displayWidth / 2;
106
- const halfHeightB = b.displayHeight / 2;
107
- const dx = b.renderX - a.renderX;
108
- const dy = b.renderY - a.renderY;
103
+ const halfWidthA = a.bodyDisplayWidth / 2;
104
+ const halfHeightA = a.bodyDisplayHeight / 2;
105
+ const halfWidthB = b.bodyDisplayWidth / 2;
106
+ const halfHeightB = b.bodyDisplayHeight / 2;
107
+ const dx = b.bodyCenterX - a.bodyCenterX;
108
+ const dy = b.bodyCenterY - a.bodyCenterY;
109
109
  const overlapX = halfWidthA + halfWidthB - Math.abs(dx);
110
110
  const overlapY = halfHeightA + halfHeightB - Math.abs(dy);
111
111
  if (overlapX <= 0 || overlapY <= 0) {
@@ -196,6 +196,60 @@ export class RenderSystem {
196
196
  ctx.fillText(entry.text, entry.x, entry.y);
197
197
  ctx.restore();
198
198
  }
199
+ if (options.debugBodies) {
200
+ this.drawBodyDebugOverlay(ctx, sorted, options.scrollX, options.scrollY);
201
+ }
202
+ if (options.debugInputAreas) {
203
+ this.drawInputDebugOverlay(ctx, sorted, options.scrollX, options.scrollY);
204
+ }
205
+ }
206
+ drawBodyDebugOverlay(ctx, sprites, scrollX, scrollY) {
207
+ ctx.save();
208
+ ctx.setLineDash([6, 4]);
209
+ ctx.lineWidth = 2;
210
+ for (const sprite of sprites) {
211
+ const halfWidth = sprite.bodyDisplayWidth / 2;
212
+ const halfHeight = sprite.bodyDisplayHeight / 2;
213
+ const centerX = sprite.ignoreScroll ? sprite.bodyCenterX : sprite.bodyCenterX - scrollX;
214
+ const centerY = sprite.ignoreScroll ? sprite.bodyCenterY : sprite.bodyCenterY - scrollY;
215
+ const left = Math.round(centerX - halfWidth) + 0.5;
216
+ const top = Math.round(centerY - halfHeight) + 0.5;
217
+ const width = Math.max(1, Math.round(sprite.bodyDisplayWidth) - 1);
218
+ const height = Math.max(1, Math.round(sprite.bodyDisplayHeight) - 1);
219
+ const stroke = sprite.isStatic
220
+ ? 'rgba(0, 217, 255, 0.95)'
221
+ : 'rgba(255, 77, 109, 0.95)';
222
+ const fill = sprite.isStatic
223
+ ? 'rgba(0, 217, 255, 0.12)'
224
+ : 'rgba(255, 77, 109, 0.12)';
225
+ ctx.strokeStyle = stroke;
226
+ ctx.fillStyle = fill;
227
+ ctx.fillRect(left, top, width, height);
228
+ ctx.strokeRect(left, top, width, height);
229
+ }
230
+ ctx.restore();
231
+ }
232
+ drawInputDebugOverlay(ctx, sprites, scrollX, scrollY) {
233
+ ctx.save();
234
+ ctx.setLineDash([3, 5]);
235
+ ctx.lineWidth = 2;
236
+ for (const sprite of sprites) {
237
+ const halfWidth = sprite.displayWidth / 2;
238
+ const halfHeight = sprite.displayHeight / 2;
239
+ const centerX = sprite.ignoreScroll ? sprite.renderX : sprite.renderX - scrollX;
240
+ const centerY = sprite.ignoreScroll ? sprite.renderY : sprite.renderY - scrollY;
241
+ const left = Math.round(centerX - halfWidth) + 0.5;
242
+ const top = Math.round(centerY - halfHeight) + 0.5;
243
+ const width = Math.max(1, Math.round(sprite.displayWidth) - 1);
244
+ const height = Math.max(1, Math.round(sprite.displayHeight) - 1);
245
+ const stroke = "rgba(255, 196, 0, 0.98)";
246
+ const fill = "rgba(255, 196, 0, 0.10)";
247
+ ctx.strokeStyle = stroke;
248
+ ctx.fillStyle = fill;
249
+ ctx.fillRect(left, top, width, height);
250
+ ctx.strokeRect(left, top, width, height);
251
+ }
252
+ ctx.restore();
199
253
  }
200
254
  renderLoadingScreen(options) {
201
255
  const ctx = options.context;
package/dist/minimo.d.ts CHANGED
@@ -252,6 +252,52 @@ export declare abstract class BaseSprite {
252
252
  * Effective rendered/collision height in pixels.
253
253
  */
254
254
  get displayHeight(): number;
255
+ /**
256
+ * Optional logical body width used by physics helpers and collision checks.
257
+ *
258
+ * When `null` (default), MinimoJS uses the sprite's visual {@link BaseSprite.width}.
259
+ * When set, this value is scaled by {@link BaseSprite.scale} the same way as the
260
+ * visual sprite size.
261
+ */
262
+ bodyWidth: number | null;
263
+ /**
264
+ * Optional logical body height used by physics helpers and collision checks.
265
+ *
266
+ * When `null` (default), MinimoJS uses the sprite's visual {@link BaseSprite.height}.
267
+ * When set, this value is scaled by {@link BaseSprite.scale} the same way as the
268
+ * visual sprite size.
269
+ */
270
+ bodyHeight: number | null;
271
+ /**
272
+ * Horizontal body offset, in local sprite pixels before scale is applied.
273
+ *
274
+ * Positive values move the collision body to the right of the sprite's rendered center.
275
+ * Negative values move it to the left.
276
+ */
277
+ bodyOffsetX: number;
278
+ /**
279
+ * Vertical body offset, in local sprite pixels before scale is applied.
280
+ *
281
+ * Positive values move the collision body downward relative to the sprite's
282
+ * rendered center. Negative values move it upward.
283
+ */
284
+ bodyOffsetY: number;
285
+ /**
286
+ * Effective collision-body width in pixels after applying {@link BaseSprite.scale}.
287
+ */
288
+ get bodyDisplayWidth(): number;
289
+ /**
290
+ * Effective collision-body height in pixels after applying {@link BaseSprite.scale}.
291
+ */
292
+ get bodyDisplayHeight(): number;
293
+ /**
294
+ * Resolved body center X used internally by physics helpers and collision checks.
295
+ */
296
+ get bodyCenterX(): number;
297
+ /**
298
+ * Resolved body center Y used internally by physics helpers and collision checks.
299
+ */
300
+ get bodyCenterY(): number;
255
301
  /**
256
302
  * CSS text color used when rendering this sprite.
257
303
  *
@@ -982,6 +1028,20 @@ export declare class Game {
982
1028
  from: string;
983
1029
  to: string;
984
1030
  } | null;
1031
+ /**
1032
+ * When `true`, MinimoJS draws every sprite's collision body as an overlay.
1033
+ *
1034
+ * This is a runtime debugging aid only. It does not change collisions,
1035
+ * input, rendering order, or physics behavior.
1036
+ */
1037
+ debugBodies: boolean;
1038
+ /**
1039
+ * When `true`, MinimoJS draws every sprite's input area as an overlay.
1040
+ *
1041
+ * This is a runtime debugging aid only. It does not change input behavior,
1042
+ * physics, or rendering.
1043
+ */
1044
+ debugInputAreas: boolean;
985
1045
  /**
986
1046
  * Background color for the full web page (`document.body`).
987
1047
  * Set to any valid CSS color string. Default: `null` (engine leaves page background unchanged).
package/dist/minimo.js CHANGED
@@ -53,6 +53,36 @@ export class BaseSprite {
53
53
  this.scale = 1;
54
54
  /** @internal */
55
55
  this._renderData = null;
56
+ /**
57
+ * Optional logical body width used by physics helpers and collision checks.
58
+ *
59
+ * When `null` (default), MinimoJS uses the sprite's visual {@link BaseSprite.width}.
60
+ * When set, this value is scaled by {@link BaseSprite.scale} the same way as the
61
+ * visual sprite size.
62
+ */
63
+ this.bodyWidth = null;
64
+ /**
65
+ * Optional logical body height used by physics helpers and collision checks.
66
+ *
67
+ * When `null` (default), MinimoJS uses the sprite's visual {@link BaseSprite.height}.
68
+ * When set, this value is scaled by {@link BaseSprite.scale} the same way as the
69
+ * visual sprite size.
70
+ */
71
+ this.bodyHeight = null;
72
+ /**
73
+ * Horizontal body offset, in local sprite pixels before scale is applied.
74
+ *
75
+ * Positive values move the collision body to the right of the sprite's rendered center.
76
+ * Negative values move it to the left.
77
+ */
78
+ this.bodyOffsetX = 0;
79
+ /**
80
+ * Vertical body offset, in local sprite pixels before scale is applied.
81
+ *
82
+ * Positive values move the collision body downward relative to the sprite's
83
+ * rendered center. Negative values move it upward.
84
+ */
85
+ this.bodyOffsetY = 0;
56
86
  /**
57
87
  * CSS text color used when rendering this sprite.
58
88
  *
@@ -179,6 +209,44 @@ export class BaseSprite {
179
209
  const safeScale = Number.isFinite(this.scale) ? this.scale : 1;
180
210
  return this.height * Math.max(0, safeScale);
181
211
  }
212
+ /**
213
+ * Effective collision-body width in pixels after applying {@link BaseSprite.scale}.
214
+ */
215
+ get bodyDisplayWidth() {
216
+ const safeScale = Number.isFinite(this.scale) ? this.scale : 1;
217
+ const baseWidth = typeof this.bodyWidth === "number" &&
218
+ Number.isFinite(this.bodyWidth) &&
219
+ this.bodyWidth > 0
220
+ ? this.bodyWidth
221
+ : this.width;
222
+ return baseWidth * Math.max(0, safeScale);
223
+ }
224
+ /**
225
+ * Effective collision-body height in pixels after applying {@link BaseSprite.scale}.
226
+ */
227
+ get bodyDisplayHeight() {
228
+ const safeScale = Number.isFinite(this.scale) ? this.scale : 1;
229
+ const baseHeight = typeof this.bodyHeight === "number" &&
230
+ Number.isFinite(this.bodyHeight) &&
231
+ this.bodyHeight > 0
232
+ ? this.bodyHeight
233
+ : this.height;
234
+ return baseHeight * Math.max(0, safeScale);
235
+ }
236
+ /**
237
+ * Resolved body center X used internally by physics helpers and collision checks.
238
+ */
239
+ get bodyCenterX() {
240
+ const safeScale = Number.isFinite(this.scale) ? this.scale : 1;
241
+ return this.renderX + this.bodyOffsetX * Math.max(0, safeScale);
242
+ }
243
+ /**
244
+ * Resolved body center Y used internally by physics helpers and collision checks.
245
+ */
246
+ get bodyCenterY() {
247
+ const safeScale = Number.isFinite(this.scale) ? this.scale : 1;
248
+ return this.renderY + this.bodyOffsetY * Math.max(0, safeScale);
249
+ }
182
250
  getAnchorOffsetX() {
183
251
  return 0;
184
252
  }
@@ -1053,6 +1121,20 @@ export class Game {
1053
1121
  * ```
1054
1122
  */
1055
1123
  this.backgroundGradient = null;
1124
+ /**
1125
+ * When `true`, MinimoJS draws every sprite's collision body as an overlay.
1126
+ *
1127
+ * This is a runtime debugging aid only. It does not change collisions,
1128
+ * input, rendering order, or physics behavior.
1129
+ */
1130
+ this.debugBodies = false;
1131
+ /**
1132
+ * When `true`, MinimoJS draws every sprite's input area as an overlay.
1133
+ *
1134
+ * This is a runtime debugging aid only. It does not change input behavior,
1135
+ * physics, or rendering.
1136
+ */
1137
+ this.debugInputAreas = false;
1056
1138
  /**
1057
1139
  * Background color for the full web page (`document.body`).
1058
1140
  * Set to any valid CSS color string. Default: `null` (engine leaves page background unchanged).
@@ -2584,6 +2666,8 @@ export class Game {
2584
2666
  background: this.background,
2585
2667
  backgroundGradient: this.backgroundGradient,
2586
2668
  pageBackground: this.pageBackground,
2669
+ debugBodies: this.debugBodies,
2670
+ debugInputAreas: this.debugInputAreas,
2587
2671
  });
2588
2672
  }
2589
2673
  /** @internal */ _renderTransition() {
@@ -2615,6 +2699,8 @@ export class Game {
2615
2699
  background: this.background,
2616
2700
  backgroundGradient: this.backgroundGradient,
2617
2701
  pageBackground: this.pageBackground,
2702
+ debugBodies: this.debugBodies,
2703
+ debugInputAreas: this.debugInputAreas,
2618
2704
  });
2619
2705
  }
2620
2706
  /** @internal */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minimojs",
3
- "version": "1.0.0-alpha.15",
3
+ "version": "1.0.0-alpha.16",
4
4
  "description": "MinimoJS v1 — ultra-minimal, flat, deterministic 2D web game engine. Emoji-only sprites, rAF loop, TypeScript-first, LLM-friendly.",
5
5
  "type": "module",
6
6
  "main": "dist/minimo.js",