@blorkfield/overlay-core 0.8.5 → 0.8.7

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.cjs CHANGED
@@ -1421,7 +1421,6 @@ var OverlayScene = class {
1421
1421
  this.updateCallbacks = [];
1422
1422
  this.animationFrameId = null;
1423
1423
  this.mouse = null;
1424
- this.mouseConstraint = null;
1425
1424
  this.fonts = [];
1426
1425
  this.fontsInitialized = false;
1427
1426
  this.letterDebugInfo = /* @__PURE__ */ new Map();
@@ -1443,18 +1442,29 @@ var OverlayScene = class {
1443
1442
  };
1444
1443
  // Follow targets for follow-{key} tagged objects
1445
1444
  this.followTargets = /* @__PURE__ */ new Map();
1446
- // Programmatic grab state - tracks initial positions for relative movement
1447
- this.grabState = null;
1448
- /** Filter drag events - only allow grabbing objects with 'grabable' tag */
1449
- this.handleStartDrag = (event) => {
1450
- const body = event.body;
1451
- if (!body) return;
1452
- const entry = this.findObjectByBody(body);
1453
- if (!entry || !entry.tags.includes("grabable")) {
1454
- if (this.mouseConstraint) {
1455
- this.mouseConstraint.constraint.bodyB = null;
1456
- }
1457
- }
1445
+ // Delta-based grab tracking
1446
+ this.grabbedObjectId = null;
1447
+ this.lastGrabMousePosition = null;
1448
+ this.grabbedWasDynamic = false;
1449
+ this.grabVelocity = { x: 0, y: 0 };
1450
+ /** Handle mouse down - start grab via programmatic API */
1451
+ this.handleMouseDown = (event) => {
1452
+ const rect = this.canvas.getBoundingClientRect();
1453
+ const x = event.clientX - rect.left;
1454
+ const y = event.clientY - rect.top;
1455
+ this.followTargets.set("mouse", { x, y });
1456
+ this.startGrab();
1457
+ };
1458
+ /** Handle mouse move - update follow target for grabbed entity */
1459
+ this.handleMouseMove = (event) => {
1460
+ const rect = this.canvas.getBoundingClientRect();
1461
+ const x = event.clientX - rect.left;
1462
+ const y = event.clientY - rect.top;
1463
+ this.followTargets.set("mouse", { x, y });
1464
+ };
1465
+ /** Handle mouse up - release grab */
1466
+ this.handleMouseUp = () => {
1467
+ this.endGrab();
1458
1468
  };
1459
1469
  /** Handle canvas clicks for click-to-fall behavior */
1460
1470
  this.handleCanvasClick = (event) => {
@@ -1520,8 +1530,21 @@ var OverlayScene = class {
1520
1530
  if (!this.followTargets.has("mouse") && this.mouse) {
1521
1531
  this.followTargets.set("mouse", { x: this.mouse.position.x, y: this.mouse.position.y });
1522
1532
  }
1533
+ if (this.grabbedObjectId && this.lastGrabMousePosition) {
1534
+ const entry = this.objects.get(this.grabbedObjectId);
1535
+ const mouseTarget = this.followTargets.get("mouse");
1536
+ if (entry && mouseTarget) {
1537
+ const dx = mouseTarget.x - this.lastGrabMousePosition.x;
1538
+ const dy = mouseTarget.y - this.lastGrabMousePosition.y;
1539
+ if (dx !== 0 || dy !== 0) {
1540
+ import_matter_js5.default.Body.translate(entry.body, { x: dx, y: dy });
1541
+ }
1542
+ this.grabVelocity = { x: dx * 0.5 + this.grabVelocity.x * 0.5, y: dy * 0.5 + this.grabVelocity.y * 0.5 };
1543
+ this.lastGrabMousePosition = { x: mouseTarget.x, y: mouseTarget.y };
1544
+ }
1545
+ }
1523
1546
  for (const entry of this.objects.values()) {
1524
- const isDragging = this.mouseConstraint?.body === entry.body;
1547
+ const isDragging = this.grabbedObjectId === entry.id;
1525
1548
  if (!isDragging) {
1526
1549
  for (const tag of entry.tags) {
1527
1550
  const key = tag === "follow" ? "mouse" : tag.startsWith("follow-") ? tag.slice(7) : null;
@@ -1569,24 +1592,10 @@ var OverlayScene = class {
1569
1592
  import_matter_js5.default.Composite.add(this.engine.world, this.boundaries);
1570
1593
  this.checkInitialFloorIntegrity();
1571
1594
  this.mouse = import_matter_js5.default.Mouse.create(canvas);
1572
- this.mouseConstraint = import_matter_js5.default.MouseConstraint.create(this.engine, {
1573
- mouse: this.mouse,
1574
- constraint: {
1575
- stiffness: 0.2,
1576
- render: { visible: false }
1577
- }
1578
- });
1579
- import_matter_js5.default.Composite.add(this.engine.world, this.mouseConstraint);
1580
- const wheelHandler = this.mouse.mousewheel;
1581
- if (wheelHandler) {
1582
- canvas.removeEventListener("mousewheel", wheelHandler);
1583
- canvas.removeEventListener("DOMMouseScroll", wheelHandler);
1584
- canvas.removeEventListener("wheel", wheelHandler);
1585
- }
1586
- canvas.style.touchAction = "pan-x pan-y";
1587
- import_matter_js5.default.Events.on(this.mouseConstraint, "startdrag", this.handleStartDrag);
1595
+ canvas.addEventListener("mousedown", this.handleMouseDown);
1596
+ canvas.addEventListener("mousemove", this.handleMouseMove);
1597
+ canvas.addEventListener("mouseup", this.handleMouseUp);
1588
1598
  canvas.addEventListener("click", this.handleCanvasClick);
1589
- this.render.mouse = this.mouse;
1590
1599
  this.effectManager = new EffectManager(
1591
1600
  this.config.bounds,
1592
1601
  (cfg) => this.spawnObjectAsync(cfg),
@@ -2008,9 +2017,9 @@ var OverlayScene = class {
2008
2017
  }
2009
2018
  destroy() {
2010
2019
  this.stop();
2011
- if (this.mouseConstraint) {
2012
- import_matter_js5.default.Events.off(this.mouseConstraint, "startdrag", this.handleStartDrag);
2013
- }
2020
+ this.canvas.removeEventListener("mousedown", this.handleMouseDown);
2021
+ this.canvas.removeEventListener("mousemove", this.handleMouseMove);
2022
+ this.canvas.removeEventListener("mouseup", this.handleMouseUp);
2014
2023
  this.canvas.removeEventListener("click", this.handleCanvasClick);
2015
2024
  import_matter_js5.default.Events.off(this.render, "beforeRender", this.handleBeforeRender);
2016
2025
  import_matter_js5.default.Events.off(this.render, "afterRender", this.handleAfterRender);
@@ -2338,23 +2347,6 @@ var OverlayScene = class {
2338
2347
  */
2339
2348
  setFollowTarget(key, x, y) {
2340
2349
  this.followTargets.set(key, { x, y });
2341
- if (key === "mouse" && this.mouse) {
2342
- if (this.grabState && this.mouseConstraint?.constraint.bodyB) {
2343
- const deltaX = x - this.grabState.grabMouseX;
2344
- const deltaY = y - this.grabState.grabMouseY;
2345
- const newX = this.grabState.grabBodyX + deltaX;
2346
- const newY = this.grabState.grabBodyY + deltaY;
2347
- this.mouse.position.x = newX;
2348
- this.mouse.position.y = newY;
2349
- this.mouse.absolute.x = newX;
2350
- this.mouse.absolute.y = newY;
2351
- } else {
2352
- this.mouse.position.x = x;
2353
- this.mouse.position.y = y;
2354
- this.mouse.absolute.x = x;
2355
- this.mouse.absolute.y = y;
2356
- }
2357
- }
2358
2350
  }
2359
2351
  /**
2360
2352
  * Remove a follow target. Objects with the corresponding tag will stop following.
@@ -2379,9 +2371,9 @@ var OverlayScene = class {
2379
2371
  * @returns The ID of the grabbed object, or null if no grabable object at position
2380
2372
  */
2381
2373
  startGrab() {
2382
- if (!this.mouseConstraint || !this.mouse) return null;
2383
2374
  const mouseTarget = this.followTargets.get("mouse");
2384
- const position = mouseTarget ?? { x: this.mouse.position.x, y: this.mouse.position.y };
2375
+ const position = mouseTarget ?? (this.mouse ? { x: this.mouse.position.x, y: this.mouse.position.y } : null);
2376
+ if (!position) return null;
2385
2377
  const bodies = import_matter_js5.default.Query.point(
2386
2378
  import_matter_js5.default.Composite.allBodies(this.engine.world),
2387
2379
  position
@@ -2389,30 +2381,11 @@ var OverlayScene = class {
2389
2381
  for (const body of bodies) {
2390
2382
  const entry = this.findObjectByBody(body);
2391
2383
  if (entry && entry.tags.includes("grabable")) {
2392
- this.mouse.button = 0;
2393
- this.grabState = {
2394
- entityId: entry.id,
2395
- grabMouseX: position.x,
2396
- grabMouseY: position.y,
2397
- grabBodyX: entry.body.position.x,
2398
- grabBodyY: entry.body.position.y
2399
- };
2400
- this.mouseConstraint.constraint.pointA = {
2401
- x: entry.body.position.x,
2402
- y: entry.body.position.y
2403
- };
2404
- this.mouseConstraint.constraint.bodyB = entry.body;
2405
- this.mouseConstraint.constraint.pointB = { x: 0, y: 0 };
2406
- this.mouse.position.x = entry.body.position.x;
2407
- this.mouse.position.y = entry.body.position.y;
2408
- this.mouse.absolute.x = entry.body.position.x;
2409
- this.mouse.absolute.y = entry.body.position.y;
2410
- console.log("[overlay-core] startGrab success", {
2411
- entityId: entry.id,
2412
- mousePosition: position,
2413
- bodyPosition: { x: entry.body.position.x, y: entry.body.position.y },
2414
- grabState: this.grabState
2415
- });
2384
+ this.grabbedObjectId = entry.id;
2385
+ this.lastGrabMousePosition = { x: position.x, y: position.y };
2386
+ this.grabVelocity = { x: 0, y: 0 };
2387
+ this.grabbedWasDynamic = !entry.body.isStatic;
2388
+ import_matter_js5.default.Body.setStatic(entry.body, true);
2416
2389
  return entry.id;
2417
2390
  }
2418
2391
  }
@@ -2422,22 +2395,26 @@ var OverlayScene = class {
2422
2395
  * Release any currently grabbed object.
2423
2396
  */
2424
2397
  endGrab() {
2425
- if (this.mouseConstraint) {
2426
- this.mouseConstraint.constraint.bodyB = null;
2427
- }
2428
- if (this.mouse) {
2429
- this.mouse.button = -1;
2398
+ if (this.grabbedObjectId && this.grabbedWasDynamic) {
2399
+ const entry = this.objects.get(this.grabbedObjectId);
2400
+ if (entry) {
2401
+ import_matter_js5.default.Body.setStatic(entry.body, false);
2402
+ import_matter_js5.default.Sleeping.set(entry.body, false);
2403
+ import_matter_js5.default.Body.setVelocity(entry.body, this.grabVelocity);
2404
+ import_matter_js5.default.Body.setAngularVelocity(entry.body, 0);
2405
+ }
2430
2406
  }
2431
- this.grabState = null;
2407
+ this.grabbedObjectId = null;
2408
+ this.lastGrabMousePosition = null;
2409
+ this.grabbedWasDynamic = false;
2410
+ this.grabVelocity = { x: 0, y: 0 };
2432
2411
  }
2433
2412
  /**
2434
2413
  * Get the ID of the currently grabbed object.
2435
2414
  * @returns The ID of the grabbed object, or null if nothing is grabbed
2436
2415
  */
2437
2416
  getGrabbedObject() {
2438
- if (!this.mouseConstraint?.constraint.bodyB) return null;
2439
- const entry = this.findObjectByBody(this.mouseConstraint.constraint.bodyB);
2440
- return entry?.id ?? null;
2417
+ return this.grabbedObjectId;
2441
2418
  }
2442
2419
  // ==================== PHYSICS MANIPULATION METHODS ====================
2443
2420
  /**