@blorkfield/overlay-core 0.8.9 → 0.8.11

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/index.d.cts CHANGED
@@ -7,8 +7,6 @@ interface OverlaySceneConfig {
7
7
  debug?: boolean;
8
8
  /** Background configuration with color, image, and transparency layers */
9
9
  background?: BackgroundConfig;
10
- /** @deprecated Use floorConfig instead. Pressure threshold for the floor boundary. */
11
- floorThreshold?: number;
12
10
  /** Distance below floor (as fraction of container height) at which objects despawn. Default: 1.0 (100%) */
13
11
  despawnBelowFloor?: number;
14
12
  /** Configuration for floor segments and thresholds */
@@ -536,7 +534,6 @@ declare class OverlayScene {
536
534
  private updateCallbacks;
537
535
  private config;
538
536
  private animationFrameId;
539
- private mouse;
540
537
  private effectManager;
541
538
  private fonts;
542
539
  private fontsInitialized;
@@ -554,6 +551,10 @@ declare class OverlayScene {
554
551
  private lastGrabMousePosition;
555
552
  private grabbedWasDynamic;
556
553
  private grabVelocity;
554
+ private bodyPositionHistory;
555
+ private readonly grabHistoryFrames;
556
+ private readonly grabHistoryRadius;
557
+ private readonly substeps;
557
558
  static createContainer(parent: HTMLElement, options?: ContainerOptions): {
558
559
  canvas: HTMLCanvasElement;
559
560
  bounds: Bounds;
package/dist/index.d.ts CHANGED
@@ -7,8 +7,6 @@ interface OverlaySceneConfig {
7
7
  debug?: boolean;
8
8
  /** Background configuration with color, image, and transparency layers */
9
9
  background?: BackgroundConfig;
10
- /** @deprecated Use floorConfig instead. Pressure threshold for the floor boundary. */
11
- floorThreshold?: number;
12
10
  /** Distance below floor (as fraction of container height) at which objects despawn. Default: 1.0 (100%) */
13
11
  despawnBelowFloor?: number;
14
12
  /** Configuration for floor segments and thresholds */
@@ -536,7 +534,6 @@ declare class OverlayScene {
536
534
  private updateCallbacks;
537
535
  private config;
538
536
  private animationFrameId;
539
- private mouse;
540
537
  private effectManager;
541
538
  private fonts;
542
539
  private fontsInitialized;
@@ -554,6 +551,10 @@ declare class OverlayScene {
554
551
  private lastGrabMousePosition;
555
552
  private grabbedWasDynamic;
556
553
  private grabVelocity;
554
+ private bodyPositionHistory;
555
+ private readonly grabHistoryFrames;
556
+ private readonly grabHistoryRadius;
557
+ private readonly substeps;
557
558
  static createContainer(parent: HTMLElement, options?: ContainerOptions): {
558
559
  canvas: HTMLCanvasElement;
559
560
  bounds: Bounds;
package/dist/index.js CHANGED
@@ -1375,7 +1375,6 @@ var OverlayScene = class {
1375
1375
  this.boundaries = [];
1376
1376
  this.updateCallbacks = [];
1377
1377
  this.animationFrameId = null;
1378
- this.mouse = null;
1379
1378
  this.fonts = [];
1380
1379
  this.fontsInitialized = false;
1381
1380
  this.letterDebugInfo = /* @__PURE__ */ new Map();
@@ -1402,6 +1401,12 @@ var OverlayScene = class {
1402
1401
  this.lastGrabMousePosition = null;
1403
1402
  this.grabbedWasDynamic = false;
1404
1403
  this.grabVelocity = { x: 0, y: 0 };
1404
+ // Position history for sweep-based grab detection (catches fast-moving bodies)
1405
+ this.bodyPositionHistory = /* @__PURE__ */ new Map();
1406
+ this.grabHistoryFrames = 5;
1407
+ this.grabHistoryRadius = 20;
1408
+ // Number of physics substeps per frame — more substeps = better collision at high speeds, more CPU
1409
+ this.substeps = 2;
1405
1410
  /** Handle mouse down - start grab via programmatic API */
1406
1411
  this.handleMouseDown = (event) => {
1407
1412
  const rect = this.canvas.getBoundingClientRect();
@@ -1478,13 +1483,14 @@ var OverlayScene = class {
1478
1483
  };
1479
1484
  // ==================== PRIVATE ====================
1480
1485
  this.loop = () => {
1486
+ const substepDelta = 1e3 / 60 / this.substeps;
1487
+ for (let i = 0; i < this.substeps; i++) {
1488
+ Matter5.Engine.update(this.engine, substepDelta);
1489
+ }
1481
1490
  this.effectManager.update();
1482
1491
  this.checkTTLExpiration();
1483
1492
  this.checkDespawnBelowFloor();
1484
1493
  this.updatePressure();
1485
- if (!this.followTargets.has("mouse") && this.mouse) {
1486
- this.followTargets.set("mouse", { x: this.mouse.position.x, y: this.mouse.position.y });
1487
- }
1488
1494
  if (this.grabbedObjectId && this.lastGrabMousePosition) {
1489
1495
  const entry = this.objects.get(this.grabbedObjectId);
1490
1496
  const mouseTarget = this.followTargets.get("mouse");
@@ -1521,6 +1527,14 @@ var OverlayScene = class {
1521
1527
  if (entry.domElement && entry.tags.includes("falling")) {
1522
1528
  this.updateDOMElementTransform(entry);
1523
1529
  }
1530
+ if (entry.tags.includes("grabable") && !entry.body.isStatic) {
1531
+ const history = this.bodyPositionHistory.get(entry.body.id) ?? [];
1532
+ history.push({ x: entry.body.position.x, y: entry.body.position.y });
1533
+ if (history.length > this.grabHistoryFrames) {
1534
+ history.shift();
1535
+ }
1536
+ this.bodyPositionHistory.set(entry.body.id, history);
1537
+ }
1524
1538
  }
1525
1539
  if (!this.config.debug) {
1526
1540
  this.drawTTFGlyphs();
@@ -1546,7 +1560,6 @@ var OverlayScene = class {
1546
1560
  this.floorSegments = boundariesResult.floorSegments;
1547
1561
  Matter5.Composite.add(this.engine.world, this.boundaries);
1548
1562
  this.checkInitialFloorIntegrity();
1549
- this.mouse = Matter5.Mouse.create(canvas);
1550
1563
  canvas.addEventListener("mousedown", this.handleMouseDown);
1551
1564
  canvas.addEventListener("mousemove", this.handleMouseMove);
1552
1565
  canvas.addEventListener("mouseup", this.handleMouseUp);
@@ -1782,7 +1795,7 @@ var OverlayScene = class {
1782
1795
  }
1783
1796
  }
1784
1797
  if (parts.length > 0) {
1785
- console.log("[Pressure]", parts.join(" "));
1798
+ logger.debug("[Pressure]", parts.join(" "));
1786
1799
  }
1787
1800
  }
1788
1801
  /** Calculate weighted pressure from a set of object IDs */
@@ -1959,7 +1972,6 @@ var OverlayScene = class {
1959
1972
  }
1960
1973
  start() {
1961
1974
  Matter5.Render.run(this.render);
1962
- Matter5.Runner.run(this.runner, this.engine);
1963
1975
  this.loop();
1964
1976
  }
1965
1977
  stop() {
@@ -2326,13 +2338,13 @@ var OverlayScene = class {
2326
2338
  * @returns The ID of the grabbed object, or null if no grabable object at position
2327
2339
  */
2328
2340
  startGrab() {
2329
- const mouseTarget = this.followTargets.get("mouse");
2330
- const position = mouseTarget ?? (this.mouse ? { x: this.mouse.position.x, y: this.mouse.position.y } : null);
2341
+ const position = this.followTargets.get("mouse") ?? null;
2331
2342
  if (!position) return null;
2332
2343
  const bodies = Matter5.Query.point(
2333
2344
  Matter5.Composite.allBodies(this.engine.world),
2334
2345
  position
2335
2346
  );
2347
+ logger.debug("OverlayScene", "Grabbed position " + position + ', had "' + bodies.length + '"');
2336
2348
  for (const body of bodies) {
2337
2349
  const entry = this.findObjectByBody(body);
2338
2350
  if (entry && entry.tags.includes("grabable")) {
@@ -2344,6 +2356,24 @@ var OverlayScene = class {
2344
2356
  return entry.id;
2345
2357
  }
2346
2358
  }
2359
+ const r2 = this.grabHistoryRadius * this.grabHistoryRadius;
2360
+ for (const entry of this.objects.values()) {
2361
+ if (!entry.tags.includes("grabable")) continue;
2362
+ const history = this.bodyPositionHistory.get(entry.body.id);
2363
+ if (!history) continue;
2364
+ for (const pastPos of history) {
2365
+ const dx = position.x - pastPos.x;
2366
+ const dy = position.y - pastPos.y;
2367
+ if (dx * dx + dy * dy <= r2) {
2368
+ this.grabbedObjectId = entry.id;
2369
+ this.lastGrabMousePosition = { x: position.x, y: position.y };
2370
+ this.grabVelocity = { x: 0, y: 0 };
2371
+ this.grabbedWasDynamic = !entry.body.isStatic;
2372
+ Matter5.Body.setStatic(entry.body, true);
2373
+ return entry.id;
2374
+ }
2375
+ }
2376
+ }
2347
2377
  return null;
2348
2378
  }
2349
2379
  /**
@@ -2357,6 +2387,7 @@ var OverlayScene = class {
2357
2387
  Matter5.Sleeping.set(entry.body, false);
2358
2388
  Matter5.Body.setVelocity(entry.body, this.grabVelocity);
2359
2389
  Matter5.Body.setAngularVelocity(entry.body, 0);
2390
+ this.bodyPositionHistory.delete(entry.body.id);
2360
2391
  }
2361
2392
  }
2362
2393
  this.grabbedObjectId = null;