minimojs 1.0.0-alpha.2 → 1.0.0-alpha.21

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 (55) hide show
  1. package/README.md +82 -285
  2. package/dist/internal/AnimationSystem.js +345 -0
  3. package/dist/internal/AssetSystem.d.ts +1 -0
  4. package/dist/internal/AssetSystem.js +101 -0
  5. package/dist/internal/BackgroundSystem.d.ts +1 -0
  6. package/dist/internal/BackgroundSystem.js +26 -0
  7. package/dist/internal/CanvasSystem.d.ts +1 -0
  8. package/dist/internal/CanvasSystem.js +51 -0
  9. package/dist/internal/ExplosionSystem.d.ts +1 -0
  10. package/dist/internal/ExplosionSystem.js +540 -0
  11. package/dist/internal/InputSystem.d.ts +1 -0
  12. package/dist/internal/InputSystem.js +265 -0
  13. package/dist/internal/LoopSystem.d.ts +1 -0
  14. package/dist/internal/LoopSystem.js +61 -0
  15. package/dist/internal/PhysicsSystem.d.ts +1 -0
  16. package/dist/internal/PhysicsSystem.js +174 -0
  17. package/dist/internal/RenderSystem.d.ts +1 -0
  18. package/dist/internal/RenderSystem.js +910 -0
  19. package/dist/internal/SoundSystem.d.ts +1 -0
  20. package/dist/internal/SoundSystem.js +55 -0
  21. package/dist/internal/SpriteSystem.d.ts +1 -0
  22. package/dist/internal/SpriteSystem.js +32 -0
  23. package/dist/internal/TextSystem.d.ts +1 -0
  24. package/dist/internal/TextSystem.js +16 -0
  25. package/dist/internal/TimerSystem.d.ts +1 -0
  26. package/dist/internal/TimerSystem.js +43 -0
  27. package/dist/internal/TrailSystem.d.ts +1 -0
  28. package/dist/internal/TrailSystem.js +116 -0
  29. package/dist/internal/TransitionSystem.d.ts +1 -0
  30. package/dist/internal/TransitionSystem.js +74 -0
  31. package/dist/internal/arcade-racer/ArcadeRacerCollisionSystem.d.ts +1 -0
  32. package/dist/internal/arcade-racer/ArcadeRacerCollisionSystem.js +198 -0
  33. package/dist/internal/arcade-racer/ArcadeRacerLaneSystem.d.ts +1 -0
  34. package/dist/internal/arcade-racer/ArcadeRacerLaneSystem.js +120 -0
  35. package/dist/internal/arcade-racer/ArcadeRacerRenderSystem.d.ts +1 -0
  36. package/dist/internal/arcade-racer/ArcadeRacerRenderSystem.js +599 -0
  37. package/dist/internal/arcade-racer/ArcadeRacerRoadSprite.d.ts +1 -0
  38. package/dist/internal/arcade-racer/ArcadeRacerRoadSprite.js +13 -0
  39. package/dist/internal/arcade-racer/ArcadeRacerTrackSystem.d.ts +1 -0
  40. package/dist/internal/arcade-racer/ArcadeRacerTrackSystem.js +447 -0
  41. package/dist/minimo-arcaderacer.d.ts +1431 -0
  42. package/dist/minimo-arcaderacer.js +2060 -0
  43. package/dist/minimo.d.ts +1412 -162
  44. package/dist/minimo.js +2083 -816
  45. package/package.json +3 -2
  46. package/dist/animations.js +0 -30
  47. package/dist/audio.js +0 -17
  48. package/dist/game.js +0 -1105
  49. package/dist/input.js +0 -185
  50. package/dist/internal-types.js +0 -4
  51. package/dist/physics.js +0 -10
  52. package/dist/render.js +0 -75
  53. package/dist/sprite.js +0 -149
  54. package/dist/timers.js +0 -23
  55. /package/dist/{pointer-info.js → internal/AnimationSystem.d.ts} +0 -0
@@ -0,0 +1,447 @@
1
+ /** @internal */
2
+ export class ArcadeRacerTrackSystem {
3
+ constructor() {
4
+ /** @internal */
5
+ this.segments = [];
6
+ /** @internal */
7
+ this.pathPrimitives = [];
8
+ /** @internal */
9
+ this.pathPointsCacheVersion = -1;
10
+ /** @internal */
11
+ this.pathPointsCache = [];
12
+ /** @internal */
13
+ this.totalTrackLengthState = 0;
14
+ /** @internal */
15
+ this.trackVersion = 0;
16
+ /** @internal */
17
+ this.trackClosureMetricsVersion = -1;
18
+ /** @internal */
19
+ this.trackClosureMetrics = null;
20
+ /** @internal */
21
+ this.minimapPathCacheVersion = -1;
22
+ /** @internal */
23
+ this.minimapPathCache = [];
24
+ this.resetTrack();
25
+ this.addLegacyTrackSegment({ length: 4000, curve: 0, hill: 0 });
26
+ }
27
+ get totalTrackLength() {
28
+ return this.totalTrackLengthState;
29
+ }
30
+ get hasPathPrimitives() {
31
+ return this.pathPrimitives.length > 0;
32
+ }
33
+ clearTrack() {
34
+ this.resetTrack();
35
+ }
36
+ appendPathLine(length, options = {}) {
37
+ const safeLength = Math.max(1, Math.abs(length));
38
+ if (this.pathPrimitives.length === 0 && this.segments.length > 0) {
39
+ this.resetTrack();
40
+ }
41
+ this.pathPrimitives.push({
42
+ type: "line",
43
+ length: safeLength,
44
+ elevationDelta: Number.isFinite(options.elevationDelta)
45
+ ? options.elevationDelta
46
+ : 0,
47
+ });
48
+ this.totalTrackLengthState += safeLength;
49
+ this.trackVersion += 1;
50
+ this.pathPointsCache = [];
51
+ this.pathPointsCacheVersion = -1;
52
+ }
53
+ appendPathArc(radius, degrees, direction, options = {}) {
54
+ const safeRadius = Math.max(1, Math.abs(radius));
55
+ const safeDegrees = Math.max(0.1, Math.abs(degrees));
56
+ if (this.pathPrimitives.length === 0 && this.segments.length > 0) {
57
+ this.resetTrack();
58
+ }
59
+ const angleRad = ((safeDegrees * Math.PI) / 180) * direction;
60
+ this.pathPrimitives.push({
61
+ type: "arc",
62
+ radius: safeRadius,
63
+ angleRad,
64
+ elevationDelta: Number.isFinite(options.elevationDelta)
65
+ ? options.elevationDelta
66
+ : 0,
67
+ });
68
+ this.totalTrackLengthState += Math.abs(safeRadius * angleRad);
69
+ this.trackVersion += 1;
70
+ this.pathPointsCache = [];
71
+ this.pathPointsCacheVersion = -1;
72
+ }
73
+ setRoundedRectTrack(circuitWidth, circuitHeight, cornerRadius) {
74
+ const safeWidth = Math.max(48, Math.abs(circuitWidth));
75
+ const safeHeight = Math.max(48, Math.abs(circuitHeight));
76
+ const radius = Math.max(12, Math.min(Math.abs(cornerRadius), safeWidth / 2 - 1, safeHeight / 2 - 1));
77
+ const horizontal = Math.max(1, safeWidth - radius * 2);
78
+ const vertical = Math.max(1, safeHeight - radius * 2);
79
+ const arcAngle = Math.PI / 2;
80
+ this.resetTrack();
81
+ this.pathPrimitives = [
82
+ { type: "line", length: horizontal, elevationDelta: 0 },
83
+ { type: "arc", radius, angleRad: arcAngle, elevationDelta: 0 },
84
+ { type: "line", length: vertical, elevationDelta: 0 },
85
+ { type: "arc", radius, angleRad: arcAngle, elevationDelta: 0 },
86
+ { type: "line", length: horizontal, elevationDelta: 0 },
87
+ { type: "arc", radius, angleRad: arcAngle, elevationDelta: 0 },
88
+ { type: "line", length: vertical, elevationDelta: 0 },
89
+ { type: "arc", radius, angleRad: arcAngle, elevationDelta: 0 },
90
+ ];
91
+ this.totalTrackLengthState =
92
+ horizontal * 2 + vertical * 2 + radius * Math.PI * 2;
93
+ this.trackVersion += 1;
94
+ this.pathPointsCache = [];
95
+ this.pathPointsCacheVersion = -1;
96
+ }
97
+ sampleTrack(distance) {
98
+ if (this.pathPrimitives.length > 0) {
99
+ return this.samplePathTrack(distance);
100
+ }
101
+ if (this.segments.length === 0 || this.totalTrackLengthState <= 0) {
102
+ return this.makeZeroSample();
103
+ }
104
+ const raw = this.sampleRawTrack(distance);
105
+ const metrics = this.getTrackClosureMetrics();
106
+ const wrapped = this.wrapDistance(distance);
107
+ const t = this.totalTrackLengthState <= 0
108
+ ? 0
109
+ : Math.max(0, Math.min(1, wrapped / this.totalTrackLengthState));
110
+ return {
111
+ lateralOffset: raw.lateralOffset - metrics.offsetDrift * t,
112
+ elevation: raw.elevation - metrics.elevationDrift * t,
113
+ curve: raw.curve - metrics.curveDrift * t,
114
+ hill: raw.hill - metrics.hillDrift * t,
115
+ worldX: raw.lateralOffset - metrics.offsetDrift * t,
116
+ worldY: wrapped,
117
+ heading: 0,
118
+ };
119
+ }
120
+ getMinimapPathPoints() {
121
+ if (this.pathPrimitives.length > 0) {
122
+ const pathPoints = this.getPathTrackPoints();
123
+ let visiblePathPoints = pathPoints;
124
+ if (pathPoints.length >= 3) {
125
+ const first = pathPoints[0];
126
+ const last = pathPoints[pathPoints.length - 1];
127
+ const previous = pathPoints[pathPoints.length - 2];
128
+ const lastMatchesStart = Math.hypot(last.x - first.x, last.y - first.y) <= 0.001;
129
+ const previousStillOpen = Math.hypot(previous.x - first.x, previous.y - first.y) > 0.001;
130
+ if (lastMatchesStart && previousStillOpen) {
131
+ visiblePathPoints = pathPoints.slice(0, -1);
132
+ }
133
+ }
134
+ return visiblePathPoints.map((point) => ({
135
+ x: point.x,
136
+ y: point.y,
137
+ distance: point.distance,
138
+ }));
139
+ }
140
+ if (this.minimapPathCacheVersion === this.trackVersion) {
141
+ return this.minimapPathCache;
142
+ }
143
+ if (this.totalTrackLengthState <= 0) {
144
+ this.minimapPathCache = [];
145
+ this.minimapPathCacheVersion = this.trackVersion;
146
+ return this.minimapPathCache;
147
+ }
148
+ const sampleCount = Math.max(64, Math.round(this.totalTrackLengthState / 80));
149
+ const points = [{ x: 0, y: 0, distance: 0 }];
150
+ let x = 0;
151
+ let y = 0;
152
+ let heading = -Math.PI / 2;
153
+ let previousDistance = 0;
154
+ const turnFactor = 0.0034;
155
+ for (let i = 1; i <= sampleCount; i++) {
156
+ const distance = (i / sampleCount) * this.totalTrackLengthState;
157
+ const delta = distance - previousDistance;
158
+ const sample = this.sampleTrack(previousDistance + delta * 0.5);
159
+ heading += sample.curve * delta * turnFactor;
160
+ x += Math.cos(heading) * delta;
161
+ y += Math.sin(heading) * delta;
162
+ points.push({ x, y, distance });
163
+ previousDistance = distance;
164
+ }
165
+ this.minimapPathCache = points;
166
+ this.minimapPathCacheVersion = this.trackVersion;
167
+ return this.minimapPathCache;
168
+ }
169
+ getLoopingAheadDistance(currentDistance, targetDistance) {
170
+ if (this.totalTrackLengthState <= 0) {
171
+ return targetDistance - currentDistance;
172
+ }
173
+ const currentWrapped = this.wrapDistance(currentDistance);
174
+ const targetWrapped = this.wrapDistance(targetDistance);
175
+ let delta = targetWrapped - currentWrapped;
176
+ if (delta < 0) {
177
+ delta += this.totalTrackLengthState;
178
+ }
179
+ return delta;
180
+ }
181
+ wrapDistance(distance) {
182
+ if (this.totalTrackLengthState <= 0)
183
+ return 0;
184
+ const wrapped = distance % this.totalTrackLengthState;
185
+ return wrapped < 0 ? wrapped + this.totalTrackLengthState : wrapped;
186
+ }
187
+ addLegacyTrackSegment(config) {
188
+ const length = Math.max(1, Number.isFinite(config.length) ? config.length : 1);
189
+ const previous = this.segments[this.segments.length - 1];
190
+ const curveFrom = previous ? previous.curveTo : 0;
191
+ const hillFrom = previous ? previous.hillTo : 0;
192
+ const curveTo = Number.isFinite(config.curve)
193
+ ? config.curve
194
+ : curveFrom;
195
+ const hillTo = Number.isFinite(config.hill)
196
+ ? config.hill
197
+ : hillFrom;
198
+ const start = previous ? previous.end : 0;
199
+ const offsetAtStart = previous
200
+ ? previous.offsetAtStart +
201
+ ((previous.curveFrom + previous.curveTo) * 0.5) * previous.length
202
+ : 0;
203
+ const elevationAtStart = previous
204
+ ? previous.elevationAtStart +
205
+ ((previous.hillFrom + previous.hillTo) * 0.5) * previous.length
206
+ : 0;
207
+ this.segments.push({
208
+ length,
209
+ curveFrom,
210
+ curveTo,
211
+ hillFrom,
212
+ hillTo,
213
+ start,
214
+ end: start + length,
215
+ offsetAtStart,
216
+ elevationAtStart,
217
+ });
218
+ this.totalTrackLengthState = this.segments[this.segments.length - 1].end;
219
+ this.trackVersion += 1;
220
+ }
221
+ /** @internal */
222
+ makeZeroSample() {
223
+ return {
224
+ lateralOffset: 0,
225
+ elevation: 0,
226
+ curve: 0,
227
+ hill: 0,
228
+ worldX: 0,
229
+ worldY: 0,
230
+ heading: 0,
231
+ };
232
+ }
233
+ /** @internal */
234
+ sampleRawTrack(distance) {
235
+ if (this.segments.length === 0 || this.totalTrackLengthState <= 0) {
236
+ return this.makeZeroSample();
237
+ }
238
+ const wrapped = this.wrapDistance(distance);
239
+ let segment = this.segments[this.segments.length - 1];
240
+ for (const candidate of this.segments) {
241
+ if (wrapped >= candidate.start && wrapped <= candidate.end) {
242
+ segment = candidate;
243
+ break;
244
+ }
245
+ }
246
+ const local = wrapped - segment.start;
247
+ const t = segment.length <= 0 ? 0 : Math.max(0, Math.min(1, local / segment.length));
248
+ const eased = this.easeInOut(t);
249
+ const curve = this.lerp(segment.curveFrom, segment.curveTo, eased);
250
+ const hill = this.lerp(segment.hillFrom, segment.hillTo, eased);
251
+ const localOffset = ((segment.curveFrom + curve) * 0.5) * local;
252
+ const localElevation = ((segment.hillFrom + hill) * 0.5) * local;
253
+ return {
254
+ lateralOffset: segment.offsetAtStart + localOffset,
255
+ elevation: segment.elevationAtStart + localElevation,
256
+ curve,
257
+ hill,
258
+ worldX: segment.offsetAtStart + localOffset,
259
+ worldY: wrapped,
260
+ heading: 0,
261
+ };
262
+ }
263
+ /** @internal */
264
+ samplePathTrack(distance) {
265
+ const points = this.getPathTrackPoints();
266
+ if (points.length === 0 || this.totalTrackLengthState <= 0) {
267
+ return this.makeZeroSample();
268
+ }
269
+ const wrapped = this.wrapDistance(distance);
270
+ for (let i = 1; i < points.length; i++) {
271
+ const from = points[i - 1];
272
+ const to = points[i];
273
+ if (wrapped > to.distance)
274
+ continue;
275
+ const span = Math.max(0.0001, to.distance - from.distance);
276
+ const t = Math.max(0, Math.min(1, (wrapped - from.distance) / span));
277
+ const heading = this.lerp(from.heading, to.heading, t);
278
+ const elevation = this.lerp(from.elevation, to.elevation, t);
279
+ const curve = this.lerp(from.curve, to.curve, t);
280
+ const hill = this.lerp(from.hill, to.hill, t);
281
+ const worldX = this.lerp(from.x, to.x, t);
282
+ const worldY = this.lerp(from.y, to.y, t);
283
+ return {
284
+ lateralOffset: worldX,
285
+ elevation,
286
+ curve,
287
+ hill,
288
+ worldX,
289
+ worldY,
290
+ heading,
291
+ };
292
+ }
293
+ const last = points[points.length - 1];
294
+ return {
295
+ lateralOffset: last.x,
296
+ elevation: last.elevation,
297
+ curve: last.curve,
298
+ hill: last.hill,
299
+ worldX: last.x,
300
+ worldY: last.y,
301
+ heading: last.heading,
302
+ };
303
+ }
304
+ /** @internal */
305
+ getPathTrackPoints() {
306
+ if (this.pathPointsCacheVersion === this.trackVersion) {
307
+ return this.pathPointsCache;
308
+ }
309
+ const points = [];
310
+ if (this.pathPrimitives.length === 0) {
311
+ this.pathPointsCache = points;
312
+ this.pathPointsCacheVersion = this.trackVersion;
313
+ return points;
314
+ }
315
+ let x = 0;
316
+ let y = 0;
317
+ let heading = 0;
318
+ let distance = 0;
319
+ let elevation = 0;
320
+ points.push({
321
+ distance,
322
+ x,
323
+ y,
324
+ heading,
325
+ elevation,
326
+ curve: 0,
327
+ hill: 0,
328
+ });
329
+ for (const primitive of this.pathPrimitives) {
330
+ if (primitive.type === "line") {
331
+ const steps = Math.max(1, Math.ceil(primitive.length / 40));
332
+ const stepLength = primitive.length / steps;
333
+ const stepElevation = primitive.elevationDelta / steps;
334
+ const hill = primitive.elevationDelta / Math.max(1, primitive.length);
335
+ for (let i = 0; i < steps; i++) {
336
+ x += Math.cos(heading) * stepLength;
337
+ y += Math.sin(heading) * stepLength;
338
+ distance += stepLength;
339
+ elevation += stepElevation;
340
+ points.push({
341
+ distance,
342
+ x,
343
+ y,
344
+ heading,
345
+ elevation,
346
+ curve: 0,
347
+ hill,
348
+ });
349
+ }
350
+ continue;
351
+ }
352
+ const arcLength = Math.abs(primitive.radius * primitive.angleRad);
353
+ const steps = Math.max(4, Math.ceil(arcLength / 32));
354
+ const stepAngle = primitive.angleRad / steps;
355
+ const stepLength = arcLength / steps;
356
+ const curve = primitive.angleRad >= 0 ? 1 / primitive.radius : -1 / primitive.radius;
357
+ const stepElevation = primitive.elevationDelta / steps;
358
+ const hill = primitive.elevationDelta / Math.max(1, arcLength);
359
+ for (let i = 0; i < steps; i++) {
360
+ const headingMid = heading + stepAngle * 0.5;
361
+ x += Math.cos(headingMid) * stepLength;
362
+ y += Math.sin(headingMid) * stepLength;
363
+ heading += stepAngle;
364
+ distance += stepLength;
365
+ elevation += stepElevation;
366
+ points.push({
367
+ distance,
368
+ x,
369
+ y,
370
+ heading,
371
+ elevation,
372
+ curve,
373
+ hill,
374
+ });
375
+ }
376
+ }
377
+ const start = points[0];
378
+ const end = points[points.length - 1];
379
+ if (Math.hypot(end.x - start.x, end.y - start.y) > 0.001) {
380
+ points.push({
381
+ distance: this.totalTrackLengthState,
382
+ x: start.x,
383
+ y: start.y,
384
+ heading: start.heading + Math.PI * 2,
385
+ elevation: start.elevation,
386
+ curve: 0,
387
+ hill: 0,
388
+ });
389
+ }
390
+ else {
391
+ end.x = start.x;
392
+ end.y = start.y;
393
+ end.heading = start.heading + Math.PI * 2;
394
+ end.elevation = start.elevation;
395
+ }
396
+ this.pathPointsCache = points;
397
+ this.pathPointsCacheVersion = this.trackVersion;
398
+ return this.pathPointsCache;
399
+ }
400
+ /** @internal */
401
+ getTrackClosureMetrics() {
402
+ if (this.trackClosureMetrics &&
403
+ this.trackClosureMetricsVersion === this.trackVersion) {
404
+ return this.trackClosureMetrics;
405
+ }
406
+ const start = this.sampleRawTrack(0);
407
+ const end = this.sampleRawTrack(Math.max(0, this.totalTrackLengthState - 0.0001));
408
+ this.trackClosureMetrics = {
409
+ startCurve: start.curve,
410
+ startHill: start.hill,
411
+ startOffset: start.lateralOffset,
412
+ startElevation: start.elevation,
413
+ endCurve: end.curve,
414
+ endHill: end.hill,
415
+ endOffset: end.lateralOffset,
416
+ endElevation: end.elevation,
417
+ curveDrift: end.curve - start.curve,
418
+ hillDrift: end.hill - start.hill,
419
+ offsetDrift: end.lateralOffset - start.lateralOffset,
420
+ elevationDrift: end.elevation - start.elevation,
421
+ };
422
+ this.trackClosureMetricsVersion = this.trackVersion;
423
+ return this.trackClosureMetrics;
424
+ }
425
+ /** @internal */
426
+ resetTrack() {
427
+ this.segments = [];
428
+ this.pathPrimitives = [];
429
+ this.pathPointsCache = [];
430
+ this.pathPointsCacheVersion = -1;
431
+ this.totalTrackLengthState = 0;
432
+ this.trackVersion += 1;
433
+ this.trackClosureMetrics = null;
434
+ this.trackClosureMetricsVersion = -1;
435
+ this.minimapPathCache = [];
436
+ this.minimapPathCacheVersion = -1;
437
+ }
438
+ /** @internal */
439
+ lerp(from, to, t) {
440
+ return from + (to - from) * t;
441
+ }
442
+ /** @internal */
443
+ easeInOut(t) {
444
+ const safeT = Math.max(0, Math.min(1, t));
445
+ return safeT * safeT * (3 - 2 * safeT);
446
+ }
447
+ }