minimojs 1.0.0-alpha.18 → 1.0.0-alpha.19
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/dist/minimo-arcaderacer.d.ts +35 -4
- package/dist/minimo-arcaderacer.js +168 -12
- package/package.json +1 -1
|
@@ -216,6 +216,25 @@ export interface ArcadeRacerMinimapOptions {
|
|
|
216
216
|
/** Player marker radius in pixels. Default: `4`. */
|
|
217
217
|
playerRadius: number;
|
|
218
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Debug overlay settings for inspecting projected car bounds and collisions.
|
|
221
|
+
*/
|
|
222
|
+
export interface ArcadeRacerDebugOptions {
|
|
223
|
+
/** Whether the debug overlay is rendered. Default: `false`. */
|
|
224
|
+
enabled: boolean;
|
|
225
|
+
/** Draws the actual screen-space image/emoji rectangle. Default: `true`. */
|
|
226
|
+
visualBounds: boolean;
|
|
227
|
+
/** Draws the approximate road-space collision body rectangle. Default: `true`. */
|
|
228
|
+
collisionBounds: boolean;
|
|
229
|
+
/** Stroke color for the rendered visual rectangle. Default: `rgba(80, 220, 255, 0.9)`. */
|
|
230
|
+
visualBoundsColor: string;
|
|
231
|
+
/** Stroke color for the player collision body. Default: `rgba(255, 238, 88, 0.95)`. */
|
|
232
|
+
playerCollisionBoundsColor: string;
|
|
233
|
+
/** Stroke color for traffic collision bodies. Default: `rgba(255, 82, 82, 0.95)`. */
|
|
234
|
+
trafficCollisionBoundsColor: string;
|
|
235
|
+
/** Debug stroke width in screen pixels. Default: `2`. */
|
|
236
|
+
lineWidth: number;
|
|
237
|
+
}
|
|
219
238
|
/**
|
|
220
239
|
* Construction options for {@link ArcadeRacerEngine}.
|
|
221
240
|
*/
|
|
@@ -258,9 +277,9 @@ export interface ArcadeRacerEngineOptions {
|
|
|
258
277
|
playerBaseScale?: number;
|
|
259
278
|
/** Player visual source. Default: `🏎️`. */
|
|
260
279
|
playerVisual?: ArcadeRacerVisualSource;
|
|
261
|
-
/** Player collision width in lane units.
|
|
280
|
+
/** Player collision width in lane units. Defaults to a value derived from the player visual size. */
|
|
262
281
|
playerBodyWidth?: number;
|
|
263
|
-
/** Player collision length in world distance units.
|
|
282
|
+
/** Player collision length in world distance units. Defaults to a value derived from the player visual size. */
|
|
264
283
|
playerBodyLength?: number;
|
|
265
284
|
/** Steering speed in lane units per second. Default: `1.85`. */
|
|
266
285
|
steeringRate?: number;
|
|
@@ -304,6 +323,8 @@ export interface ArcadeRacerEngineOptions {
|
|
|
304
323
|
horizon?: Partial<ArcadeRacerHorizonOptions>;
|
|
305
324
|
/** Optional partial minimap overlay override. */
|
|
306
325
|
minimap?: Partial<ArcadeRacerMinimapOptions>;
|
|
326
|
+
/** Optional debug overlay for car visual and collision bounds. */
|
|
327
|
+
debug?: boolean | Partial<ArcadeRacerDebugOptions>;
|
|
307
328
|
/** Optional partial theme override. */
|
|
308
329
|
theme?: Partial<ArcadeRacerTheme>;
|
|
309
330
|
}
|
|
@@ -343,9 +364,9 @@ export interface ArcadeRacerTrafficConfig {
|
|
|
343
364
|
speed?: number;
|
|
344
365
|
/** Optional multiplier applied to the projected scale. Default: `1`. */
|
|
345
366
|
baseScale?: number;
|
|
346
|
-
/** Collision width in lane units.
|
|
367
|
+
/** Collision width in lane units. Defaults to a value derived from the traffic visual size. */
|
|
347
368
|
bodyWidth?: number;
|
|
348
|
-
/** Collision length in world distance units.
|
|
369
|
+
/** Collision length in world distance units. Defaults to a value derived from the traffic visual size. */
|
|
349
370
|
bodyLength?: number;
|
|
350
371
|
/** Whether the car should be recycled one lap ahead when it falls behind. Default: `true`. */
|
|
351
372
|
loop?: boolean;
|
|
@@ -465,6 +486,8 @@ export interface ArcadeRacerTrafficCollision {
|
|
|
465
486
|
* certain headings.
|
|
466
487
|
* - Use {@link setPlayerBody} when you need to tune collisions without changing
|
|
467
488
|
* the player artwork.
|
|
489
|
+
* - Use {@link setDebug} when you need to visualize car image bounds and
|
|
490
|
+
* collision bodies while tuning traffic hits.
|
|
468
491
|
*
|
|
469
492
|
* This interface is the canonical public surface of the module. Its JSDoc is
|
|
470
493
|
* intended to be consumed directly by AI agents and tooling that generate code
|
|
@@ -683,6 +706,14 @@ export interface ArcadeRacerEngine {
|
|
|
683
706
|
* Merges minimap settings into the current minimap config.
|
|
684
707
|
*/
|
|
685
708
|
setMinimap(options: Partial<ArcadeRacerMinimapOptions>): void;
|
|
709
|
+
/**
|
|
710
|
+
* Enables, disables, or updates the debug overlay for car bounds.
|
|
711
|
+
*
|
|
712
|
+
* Pass `true` to enable defaults, `false` to disable, or a partial options
|
|
713
|
+
* object to customize colors and which rectangles are shown. The overlay draws
|
|
714
|
+
* visual rectangles and collision-body rectangles for the player and traffic.
|
|
715
|
+
*/
|
|
716
|
+
setDebug(options: boolean | Partial<ArcadeRacerDebugOptions>): void;
|
|
686
717
|
/**
|
|
687
718
|
* Shows the minimap and optionally applies a partial minimap config update.
|
|
688
719
|
*/
|
|
@@ -45,6 +45,17 @@ const DEFAULT_MINIMAP = {
|
|
|
45
45
|
playerStrokeColor: "#fff7dd",
|
|
46
46
|
playerRadius: 4,
|
|
47
47
|
};
|
|
48
|
+
const AUTO_BODY_WIDTH_VISUAL_RATIO = 0.76;
|
|
49
|
+
const AUTO_BODY_LENGTH_PER_PIXEL = 1.92;
|
|
50
|
+
const DEFAULT_DEBUG = {
|
|
51
|
+
enabled: false,
|
|
52
|
+
visualBounds: true,
|
|
53
|
+
collisionBounds: true,
|
|
54
|
+
visualBoundsColor: "rgba(80, 220, 255, 0.9)",
|
|
55
|
+
playerCollisionBoundsColor: "rgba(255, 238, 88, 0.95)",
|
|
56
|
+
trafficCollisionBoundsColor: "rgba(255, 82, 82, 0.95)",
|
|
57
|
+
lineWidth: 2,
|
|
58
|
+
};
|
|
48
59
|
const MPH_PER_SPEED_UNIT = 0.22;
|
|
49
60
|
const DEFAULT_GROUND_FILL = {
|
|
50
61
|
enabled: true,
|
|
@@ -104,6 +115,10 @@ class ArcadeRacerEngineImpl {
|
|
|
104
115
|
/** @internal */
|
|
105
116
|
this.backgroundLayersState = [];
|
|
106
117
|
/** @internal */
|
|
118
|
+
this.playerBodyWidthManual = false;
|
|
119
|
+
/** @internal */
|
|
120
|
+
this.playerBodyLengthManual = false;
|
|
121
|
+
/** @internal */
|
|
107
122
|
this.distanceState = 0;
|
|
108
123
|
/** @internal */
|
|
109
124
|
this.nextId = 1;
|
|
@@ -180,16 +195,24 @@ class ArcadeRacerEngineImpl {
|
|
|
180
195
|
playerStrokeColor: options.minimap?.playerStrokeColor ?? DEFAULT_MINIMAP.playerStrokeColor,
|
|
181
196
|
playerRadius: options.minimap?.playerRadius ?? DEFAULT_MINIMAP.playerRadius,
|
|
182
197
|
});
|
|
198
|
+
this.debugState = this.sanitizeDebugOptions(options.debug ?? false);
|
|
183
199
|
this.playerVisualState =
|
|
184
200
|
options.playerVisual ?? { type: "emoji", value: "🏎️", size: 48 };
|
|
185
201
|
this.playerScreenYState =
|
|
186
202
|
options.playerScreenY ?? Math.round(this.height * 0.86);
|
|
187
203
|
this.playerBaseScaleState =
|
|
188
204
|
options.playerBaseScale ?? DEFAULT_OPTIONS.playerBaseScale;
|
|
205
|
+
this.playerBodyWidthManual = Number.isFinite(options.playerBodyWidth);
|
|
206
|
+
this.playerBodyLengthManual = Number.isFinite(options.playerBodyLength);
|
|
207
|
+
const autoPlayerBody = this.resolveAutoBodyFromVisual(this.playerVisualState, this.playerBaseScaleState);
|
|
189
208
|
this.playerBodyWidthState =
|
|
190
|
-
options.playerBodyWidth ??
|
|
209
|
+
options.playerBodyWidth ??
|
|
210
|
+
autoPlayerBody?.width ??
|
|
211
|
+
DEFAULT_OPTIONS.playerBodyWidth;
|
|
191
212
|
this.playerBodyLengthState =
|
|
192
|
-
options.playerBodyLength ??
|
|
213
|
+
options.playerBodyLength ??
|
|
214
|
+
autoPlayerBody?.length ??
|
|
215
|
+
DEFAULT_OPTIONS.playerBodyLength;
|
|
193
216
|
this.speedState = options.speed ?? DEFAULT_OPTIONS.speed;
|
|
194
217
|
this.playerLaneState = this.clampPlayerLane(options.playerLane ?? DEFAULT_OPTIONS.playerLane);
|
|
195
218
|
this.resetTrack();
|
|
@@ -468,21 +491,23 @@ class ArcadeRacerEngineImpl {
|
|
|
468
491
|
*/
|
|
469
492
|
addTraffic(visual, config) {
|
|
470
493
|
const id = this.makeId("car");
|
|
494
|
+
const baseScale = Number.isFinite(config.baseScale)
|
|
495
|
+
? Math.max(0, config.baseScale)
|
|
496
|
+
: 1;
|
|
497
|
+
const autoBody = this.resolveAutoBodyFromVisual(visual, baseScale);
|
|
471
498
|
this.trafficState.push({
|
|
472
499
|
id,
|
|
473
500
|
visual,
|
|
474
501
|
distance: Math.max(0, config.distance),
|
|
475
502
|
lane: this.clampRoadLane(config.lane),
|
|
476
503
|
speed: Number.isFinite(config.speed) ? config.speed : 140,
|
|
477
|
-
baseScale
|
|
478
|
-
? Math.max(0, config.baseScale)
|
|
479
|
-
: 1,
|
|
504
|
+
baseScale,
|
|
480
505
|
bodyWidth: Number.isFinite(config.bodyWidth)
|
|
481
506
|
? Math.max(0.01, config.bodyWidth)
|
|
482
|
-
: 0.26,
|
|
507
|
+
: autoBody?.width ?? 0.26,
|
|
483
508
|
bodyLength: Number.isFinite(config.bodyLength)
|
|
484
509
|
? Math.max(1, config.bodyLength)
|
|
485
|
-
: 120,
|
|
510
|
+
: autoBody?.length ?? 120,
|
|
486
511
|
loop: config.loop ?? true,
|
|
487
512
|
alpha: this.clamp01(config.alpha ?? 1),
|
|
488
513
|
});
|
|
@@ -598,6 +623,12 @@ class ArcadeRacerEngineImpl {
|
|
|
598
623
|
...options,
|
|
599
624
|
});
|
|
600
625
|
}
|
|
626
|
+
/**
|
|
627
|
+
* Enables, disables, or updates car bounds debug rendering.
|
|
628
|
+
*/
|
|
629
|
+
setDebug(options) {
|
|
630
|
+
this.debugState = this.sanitizeDebugOptions(typeof options === "boolean" ? options : { ...this.debugState, ...options });
|
|
631
|
+
}
|
|
601
632
|
/**
|
|
602
633
|
* Shows the minimap and optionally applies overrides.
|
|
603
634
|
*/
|
|
@@ -615,6 +646,7 @@ class ArcadeRacerEngineImpl {
|
|
|
615
646
|
*/
|
|
616
647
|
setPlayerVisual(source) {
|
|
617
648
|
this.playerVisualState = source;
|
|
649
|
+
this.refreshAutoPlayerBodyFromVisual();
|
|
618
650
|
}
|
|
619
651
|
/**
|
|
620
652
|
* Updates the player screen-space Y position.
|
|
@@ -630,9 +662,11 @@ class ArcadeRacerEngineImpl {
|
|
|
630
662
|
setPlayerBody(width, length) {
|
|
631
663
|
if (Number.isFinite(width)) {
|
|
632
664
|
this.playerBodyWidthState = Math.max(0.01, width);
|
|
665
|
+
this.playerBodyWidthManual = true;
|
|
633
666
|
}
|
|
634
667
|
if (Number.isFinite(length)) {
|
|
635
668
|
this.playerBodyLengthState = Math.max(1, length);
|
|
669
|
+
this.playerBodyLengthManual = true;
|
|
636
670
|
}
|
|
637
671
|
}
|
|
638
672
|
/**
|
|
@@ -642,6 +676,7 @@ class ArcadeRacerEngineImpl {
|
|
|
642
676
|
if (!Number.isFinite(value))
|
|
643
677
|
return;
|
|
644
678
|
this.playerBaseScaleState = Math.max(0, value);
|
|
679
|
+
this.refreshAutoPlayerBodyFromVisual();
|
|
645
680
|
}
|
|
646
681
|
/**
|
|
647
682
|
* Updates the player lane position.
|
|
@@ -1076,6 +1111,7 @@ class ArcadeRacerEngineImpl {
|
|
|
1076
1111
|
scale: projection.scale * billboard.baseScale,
|
|
1077
1112
|
alpha: billboard.alpha,
|
|
1078
1113
|
visual: billboard.visual,
|
|
1114
|
+
kind: "billboard",
|
|
1079
1115
|
});
|
|
1080
1116
|
}
|
|
1081
1117
|
for (const traffic of this.trafficState) {
|
|
@@ -1093,34 +1129,135 @@ class ArcadeRacerEngineImpl {
|
|
|
1093
1129
|
scale: projection.scale * traffic.baseScale,
|
|
1094
1130
|
alpha: traffic.alpha,
|
|
1095
1131
|
visual: traffic.visual,
|
|
1132
|
+
kind: "traffic",
|
|
1133
|
+
bodyWidth: traffic.bodyWidth,
|
|
1134
|
+
bodyLength: traffic.bodyLength,
|
|
1135
|
+
bodyReferenceScale: traffic.baseScale,
|
|
1096
1136
|
});
|
|
1097
1137
|
}
|
|
1098
1138
|
const playerProjection = this.projectTrafficPoint(current, this.playerProjectionAheadDistance, width, height);
|
|
1099
|
-
const
|
|
1139
|
+
const playerCenterX = this.getPlayerScreenX();
|
|
1100
1140
|
visible.push({
|
|
1101
1141
|
depth: this.playerProjectionAheadDistance,
|
|
1102
|
-
x:
|
|
1142
|
+
x: playerCenterX,
|
|
1103
1143
|
y: this.playerScreenYState,
|
|
1104
1144
|
scale: playerProjection.scale * this.playerBaseScaleState,
|
|
1105
1145
|
alpha: 1,
|
|
1106
1146
|
visual: this.playerVisualState,
|
|
1147
|
+
kind: "player",
|
|
1148
|
+
bodyWidth: this.playerBodyWidthState,
|
|
1149
|
+
bodyLength: this.playerBodyLengthState,
|
|
1150
|
+
bodyReferenceScale: this.playerBaseScaleState,
|
|
1107
1151
|
});
|
|
1108
1152
|
visible.sort((a, b) => b.depth - a.depth);
|
|
1109
1153
|
for (const entry of visible) {
|
|
1110
|
-
this.drawVisual(ctx, entry.visual, entry.x, entry.y, entry.scale, entry.alpha);
|
|
1154
|
+
const visualRect = this.drawVisual(ctx, entry.visual, entry.x, entry.y, entry.scale, entry.alpha);
|
|
1155
|
+
if (entry.kind !== "billboard") {
|
|
1156
|
+
this.drawCarDebugBounds(ctx, entry.kind, visualRect, entry.visual, entry.bodyReferenceScale, entry.bodyWidth, entry.bodyLength);
|
|
1157
|
+
}
|
|
1111
1158
|
}
|
|
1112
1159
|
}
|
|
1113
1160
|
/** @internal */
|
|
1114
1161
|
drawVisual(ctx, visual, x, y, scale, alpha) {
|
|
1115
1162
|
const surface = this.resolveVisualSurface(visual);
|
|
1163
|
+
const rect = this.getVisualRect(surface, x, y, scale);
|
|
1164
|
+
ctx.save();
|
|
1165
|
+
ctx.globalAlpha = this.clamp01(alpha);
|
|
1166
|
+
ctx.drawImage(surface.source, rect.x, rect.y, rect.width, rect.height);
|
|
1167
|
+
ctx.restore();
|
|
1168
|
+
return rect;
|
|
1169
|
+
}
|
|
1170
|
+
/** @internal */
|
|
1171
|
+
getVisualRect(surface, x, y, scale) {
|
|
1116
1172
|
const drawWidth = Math.max(1, surface.width * Math.max(0, scale));
|
|
1117
1173
|
const drawHeight = Math.max(1, surface.height * Math.max(0, scale));
|
|
1174
|
+
return {
|
|
1175
|
+
x: Math.round(x - drawWidth / 2),
|
|
1176
|
+
y: Math.round(y - drawHeight),
|
|
1177
|
+
width: drawWidth,
|
|
1178
|
+
height: drawHeight,
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
/** @internal */
|
|
1182
|
+
drawCarDebugBounds(ctx, kind, visualRect, visual, bodyReferenceScale, bodyWidth, bodyLength) {
|
|
1183
|
+
if (!this.debugState.enabled)
|
|
1184
|
+
return;
|
|
1118
1185
|
ctx.save();
|
|
1119
|
-
ctx.
|
|
1120
|
-
ctx.
|
|
1186
|
+
ctx.lineWidth = this.debugState.lineWidth;
|
|
1187
|
+
ctx.setLineDash([]);
|
|
1188
|
+
if (this.debugState.visualBounds) {
|
|
1189
|
+
ctx.strokeStyle = this.debugState.visualBoundsColor;
|
|
1190
|
+
ctx.strokeRect(visualRect.x, visualRect.y, visualRect.width, visualRect.height);
|
|
1191
|
+
}
|
|
1192
|
+
const collisionRect = this.debugState.collisionBounds &&
|
|
1193
|
+
Number.isFinite(bodyWidth) &&
|
|
1194
|
+
Number.isFinite(bodyLength)
|
|
1195
|
+
? this.getDebugCollisionRectFromVisual(visualRect, visual, bodyReferenceScale ?? 1, bodyWidth, bodyLength)
|
|
1196
|
+
: null;
|
|
1197
|
+
if (this.debugState.collisionBounds && collisionRect) {
|
|
1198
|
+
ctx.strokeStyle =
|
|
1199
|
+
kind === "player"
|
|
1200
|
+
? this.debugState.playerCollisionBoundsColor
|
|
1201
|
+
: this.debugState.trafficCollisionBoundsColor;
|
|
1202
|
+
ctx.setLineDash([6, 4]);
|
|
1203
|
+
ctx.strokeRect(collisionRect.x, collisionRect.y, collisionRect.width, collisionRect.height);
|
|
1204
|
+
}
|
|
1121
1205
|
ctx.restore();
|
|
1122
1206
|
}
|
|
1123
1207
|
/** @internal */
|
|
1208
|
+
getDebugCollisionRectFromVisual(visualRect, visual, referenceScale, bodyWidth, bodyLength) {
|
|
1209
|
+
const autoBody = this.resolveAutoBodyFromVisual(visual, referenceScale);
|
|
1210
|
+
if (!autoBody)
|
|
1211
|
+
return null;
|
|
1212
|
+
const widthRatio = Math.max(0.05, bodyWidth / autoBody.width);
|
|
1213
|
+
const heightRatio = Math.max(0.05, bodyLength / autoBody.length);
|
|
1214
|
+
const rectWidth = Math.max(4, visualRect.width * AUTO_BODY_WIDTH_VISUAL_RATIO * widthRatio);
|
|
1215
|
+
const rectHeight = Math.max(8, visualRect.height * heightRatio);
|
|
1216
|
+
return {
|
|
1217
|
+
x: visualRect.x + (visualRect.width - rectWidth) / 2,
|
|
1218
|
+
y: visualRect.y + visualRect.height - rectHeight,
|
|
1219
|
+
width: rectWidth,
|
|
1220
|
+
height: rectHeight,
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
/** @internal */
|
|
1224
|
+
getPlayerScreenLaneUnit() {
|
|
1225
|
+
return this.roadNearWidth * 0.38;
|
|
1226
|
+
}
|
|
1227
|
+
/** @internal */
|
|
1228
|
+
resolveAutoBodyFromVisual(visual, scale) {
|
|
1229
|
+
try {
|
|
1230
|
+
const surface = this.resolveVisualSurface(visual);
|
|
1231
|
+
const safeScale = Number.isFinite(scale) ? Math.max(0, scale) : 1;
|
|
1232
|
+
const visualWidth = Math.max(1, surface.width * safeScale);
|
|
1233
|
+
const visualHeight = Math.max(1, surface.height * safeScale);
|
|
1234
|
+
const laneUnit = Math.max(1, this.getPlayerScreenLaneUnit());
|
|
1235
|
+
return {
|
|
1236
|
+
width: Math.max(0.01, (visualWidth * AUTO_BODY_WIDTH_VISUAL_RATIO) / laneUnit),
|
|
1237
|
+
length: Math.max(1, visualHeight * AUTO_BODY_LENGTH_PER_PIXEL),
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
catch {
|
|
1241
|
+
return null;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
/** @internal */
|
|
1245
|
+
refreshAutoPlayerBodyFromVisual() {
|
|
1246
|
+
const autoBody = this.resolveAutoBodyFromVisual(this.playerVisualState, this.playerBaseScaleState);
|
|
1247
|
+
if (!autoBody)
|
|
1248
|
+
return;
|
|
1249
|
+
if (!this.playerBodyWidthManual) {
|
|
1250
|
+
this.playerBodyWidthState = autoBody.width;
|
|
1251
|
+
}
|
|
1252
|
+
if (!this.playerBodyLengthManual) {
|
|
1253
|
+
this.playerBodyLengthState = autoBody.length;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
/** @internal */
|
|
1257
|
+
getPlayerScreenX() {
|
|
1258
|
+
return this.width / 2 + this.playerLaneState * this.getPlayerScreenLaneUnit();
|
|
1259
|
+
}
|
|
1260
|
+
/** @internal */
|
|
1124
1261
|
resolveVisualSurface(visual) {
|
|
1125
1262
|
if (visual.type === "image") {
|
|
1126
1263
|
const image = this.game.getImage(visual.key);
|
|
@@ -1824,6 +1961,25 @@ class ArcadeRacerEngineImpl {
|
|
|
1824
1961
|
};
|
|
1825
1962
|
}
|
|
1826
1963
|
/** @internal */
|
|
1964
|
+
sanitizeDebugOptions(options) {
|
|
1965
|
+
if (typeof options === "boolean") {
|
|
1966
|
+
return { ...DEFAULT_DEBUG, enabled: options };
|
|
1967
|
+
}
|
|
1968
|
+
return {
|
|
1969
|
+
enabled: options.enabled ?? DEFAULT_DEBUG.enabled,
|
|
1970
|
+
visualBounds: options.visualBounds ?? DEFAULT_DEBUG.visualBounds,
|
|
1971
|
+
collisionBounds: options.collisionBounds ?? DEFAULT_DEBUG.collisionBounds,
|
|
1972
|
+
visualBoundsColor: options.visualBoundsColor || DEFAULT_DEBUG.visualBoundsColor,
|
|
1973
|
+
playerCollisionBoundsColor: options.playerCollisionBoundsColor ||
|
|
1974
|
+
DEFAULT_DEBUG.playerCollisionBoundsColor,
|
|
1975
|
+
trafficCollisionBoundsColor: options.trafficCollisionBoundsColor ||
|
|
1976
|
+
DEFAULT_DEBUG.trafficCollisionBoundsColor,
|
|
1977
|
+
lineWidth: Number.isFinite(options.lineWidth)
|
|
1978
|
+
? Math.max(1, options.lineWidth)
|
|
1979
|
+
: DEFAULT_DEBUG.lineWidth,
|
|
1980
|
+
};
|
|
1981
|
+
}
|
|
1982
|
+
/** @internal */
|
|
1827
1983
|
normalizeAngle(angle) {
|
|
1828
1984
|
if (!Number.isFinite(angle))
|
|
1829
1985
|
return 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "minimojs",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.19",
|
|
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",
|