@blorkfield/overlay-core 0.8.4 → 0.8.6

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/README.md CHANGED
@@ -323,28 +323,27 @@ For scenarios where mouse input comes from an external source (e.g., system-wide
323
323
  const canvasX = screenMouseX - canvasOffsetX;
324
324
  const canvasY = screenMouseY - canvasOffsetY;
325
325
  scene.setFollowTarget('mouse', canvasX, canvasY);
326
-
327
- // This position is now used for:
328
- // - Objects with 'follow' tag (they move toward this position)
329
- // - Programmatic grab detection via startGrab()
330
- // - MouseConstraint during drag (grabbed objects follow this position)
331
326
  ```
332
327
 
333
328
  The offset calculation is your responsibility - overlay-core uses whatever position you provide.
334
329
 
335
330
  ### Programmatic Grab/Release
336
331
 
332
+ Grab uses delta-based movement: when grabbed, the entity and mouse become linked. The entity moves BY the same amount as the mouse moves, not TO the mouse position. This ensures the entity stays at its original position on grab and follows mouse movement naturally.
333
+
337
334
  ```typescript
338
335
  // Grab object at current mouse position (only 'grabable' tagged objects)
339
336
  const grabbedId = scene.startGrab();
340
337
  if (grabbedId) {
338
+ // Entity stays at its current position, now linked to mouse
341
339
  console.log(`Grabbed: ${grabbedId}`);
342
340
  }
343
341
 
344
- // Update mouse position while dragging - object follows automatically
342
+ // As mouse moves, entity moves by the same delta
343
+ // Mouse moves +50px right → entity moves +50px right
345
344
  scene.setFollowTarget('mouse', newX, newY);
346
345
 
347
- // Release the grabbed object
346
+ // Release unlinks entity from mouse
348
347
  scene.endGrab();
349
348
 
350
349
  // Check what's currently grabbed
@@ -354,9 +353,9 @@ const currentGrab = scene.getGrabbedObject(); // Returns ID or null
354
353
  | Method | Returns | Description |
355
354
  |--------|---------|-------------|
356
355
  | `setFollowTarget('mouse', x, y)` | void | Set mouse position for follow behavior and grab detection |
357
- | `startGrab()` | string \| null | Grab object at current mouse position, returns object ID |
358
- | `endGrab()` | void | Release any currently grabbed object |
359
- | `getGrabbedObject()` | string \| null | Get ID of currently grabbed object |
356
+ | `startGrab()` | string \| null | Link entity at current mouse position to mouse, returns entity ID |
357
+ | `endGrab()` | void | Unlink currently grabbed entity |
358
+ | `getGrabbedObject()` | string \| null | Get ID of currently grabbed entity |
360
359
 
361
360
  ## Configuration
362
361
 
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,17 +1442,9 @@ var OverlayScene = class {
1443
1442
  };
1444
1443
  // Follow targets for follow-{key} tagged objects
1445
1444
  this.followTargets = /* @__PURE__ */ new Map();
1446
- /** Filter drag events - only allow grabbing objects with 'grabable' tag */
1447
- this.handleStartDrag = (event) => {
1448
- const body = event.body;
1449
- if (!body) return;
1450
- const entry = this.findObjectByBody(body);
1451
- if (!entry || !entry.tags.includes("grabable")) {
1452
- if (this.mouseConstraint) {
1453
- this.mouseConstraint.constraint.bodyB = null;
1454
- }
1455
- }
1456
- };
1445
+ // Delta-based grab tracking (no constraint physics)
1446
+ this.grabbedObjectId = null;
1447
+ this.lastGrabMousePosition = null;
1457
1448
  /** Handle canvas clicks for click-to-fall behavior */
1458
1449
  this.handleCanvasClick = (event) => {
1459
1450
  const rect = this.canvas.getBoundingClientRect();
@@ -1518,8 +1509,20 @@ var OverlayScene = class {
1518
1509
  if (!this.followTargets.has("mouse") && this.mouse) {
1519
1510
  this.followTargets.set("mouse", { x: this.mouse.position.x, y: this.mouse.position.y });
1520
1511
  }
1512
+ if (this.grabbedObjectId && this.lastGrabMousePosition) {
1513
+ const entry = this.objects.get(this.grabbedObjectId);
1514
+ const mouseTarget = this.followTargets.get("mouse");
1515
+ if (entry && mouseTarget) {
1516
+ const dx = mouseTarget.x - this.lastGrabMousePosition.x;
1517
+ const dy = mouseTarget.y - this.lastGrabMousePosition.y;
1518
+ if (dx !== 0 || dy !== 0) {
1519
+ import_matter_js5.default.Body.translate(entry.body, { x: dx, y: dy });
1520
+ }
1521
+ this.lastGrabMousePosition = { x: mouseTarget.x, y: mouseTarget.y };
1522
+ }
1523
+ }
1521
1524
  for (const entry of this.objects.values()) {
1522
- const isDragging = this.mouseConstraint?.body === entry.body;
1525
+ const isDragging = this.grabbedObjectId === entry.id;
1523
1526
  if (!isDragging) {
1524
1527
  for (const tag of entry.tags) {
1525
1528
  const key = tag === "follow" ? "mouse" : tag.startsWith("follow-") ? tag.slice(7) : null;
@@ -1567,24 +1570,7 @@ var OverlayScene = class {
1567
1570
  import_matter_js5.default.Composite.add(this.engine.world, this.boundaries);
1568
1571
  this.checkInitialFloorIntegrity();
1569
1572
  this.mouse = import_matter_js5.default.Mouse.create(canvas);
1570
- this.mouseConstraint = import_matter_js5.default.MouseConstraint.create(this.engine, {
1571
- mouse: this.mouse,
1572
- constraint: {
1573
- stiffness: 0.2,
1574
- render: { visible: false }
1575
- }
1576
- });
1577
- import_matter_js5.default.Composite.add(this.engine.world, this.mouseConstraint);
1578
- const wheelHandler = this.mouse.mousewheel;
1579
- if (wheelHandler) {
1580
- canvas.removeEventListener("mousewheel", wheelHandler);
1581
- canvas.removeEventListener("DOMMouseScroll", wheelHandler);
1582
- canvas.removeEventListener("wheel", wheelHandler);
1583
- }
1584
- canvas.style.touchAction = "pan-x pan-y";
1585
- import_matter_js5.default.Events.on(this.mouseConstraint, "startdrag", this.handleStartDrag);
1586
1573
  canvas.addEventListener("click", this.handleCanvasClick);
1587
- this.render.mouse = this.mouse;
1588
1574
  this.effectManager = new EffectManager(
1589
1575
  this.config.bounds,
1590
1576
  (cfg) => this.spawnObjectAsync(cfg),
@@ -2006,9 +1992,6 @@ var OverlayScene = class {
2006
1992
  }
2007
1993
  destroy() {
2008
1994
  this.stop();
2009
- if (this.mouseConstraint) {
2010
- import_matter_js5.default.Events.off(this.mouseConstraint, "startdrag", this.handleStartDrag);
2011
- }
2012
1995
  this.canvas.removeEventListener("click", this.handleCanvasClick);
2013
1996
  import_matter_js5.default.Events.off(this.render, "beforeRender", this.handleBeforeRender);
2014
1997
  import_matter_js5.default.Events.off(this.render, "afterRender", this.handleAfterRender);
@@ -2336,12 +2319,6 @@ var OverlayScene = class {
2336
2319
  */
2337
2320
  setFollowTarget(key, x, y) {
2338
2321
  this.followTargets.set(key, { x, y });
2339
- if (key === "mouse" && this.mouse) {
2340
- this.mouse.position.x = x;
2341
- this.mouse.position.y = y;
2342
- this.mouse.absolute.x = x;
2343
- this.mouse.absolute.y = y;
2344
- }
2345
2322
  }
2346
2323
  /**
2347
2324
  * Remove a follow target. Objects with the corresponding tag will stop following.
@@ -2366,9 +2343,9 @@ var OverlayScene = class {
2366
2343
  * @returns The ID of the grabbed object, or null if no grabable object at position
2367
2344
  */
2368
2345
  startGrab() {
2369
- if (!this.mouseConstraint || !this.mouse) return null;
2370
2346
  const mouseTarget = this.followTargets.get("mouse");
2371
- const position = mouseTarget ?? { x: this.mouse.position.x, y: this.mouse.position.y };
2347
+ const position = mouseTarget ?? (this.mouse ? { x: this.mouse.position.x, y: this.mouse.position.y } : null);
2348
+ if (!position) return null;
2372
2349
  const bodies = import_matter_js5.default.Query.point(
2373
2350
  import_matter_js5.default.Composite.allBodies(this.engine.world),
2374
2351
  position
@@ -2376,18 +2353,8 @@ var OverlayScene = class {
2376
2353
  for (const body of bodies) {
2377
2354
  const entry = this.findObjectByBody(body);
2378
2355
  if (entry && entry.tags.includes("grabable")) {
2379
- this.mouse.button = 0;
2380
- this.mouseConstraint.constraint.pointA = { x: position.x, y: position.y };
2381
- this.mouseConstraint.constraint.bodyB = entry.body;
2382
- this.mouseConstraint.constraint.pointB = { x: 0, y: 0 };
2383
- console.log("[overlay-core] startGrab success", {
2384
- entityId: entry.id,
2385
- mousePosition: position,
2386
- bodyPosition: { x: entry.body.position.x, y: entry.body.position.y },
2387
- constraintPointA: this.mouseConstraint.constraint.pointA,
2388
- constraintPointB: this.mouseConstraint.constraint.pointB,
2389
- mouseButton: this.mouse.button
2390
- });
2356
+ this.grabbedObjectId = entry.id;
2357
+ this.lastGrabMousePosition = { x: position.x, y: position.y };
2391
2358
  return entry.id;
2392
2359
  }
2393
2360
  }
@@ -2397,21 +2364,15 @@ var OverlayScene = class {
2397
2364
  * Release any currently grabbed object.
2398
2365
  */
2399
2366
  endGrab() {
2400
- if (this.mouseConstraint) {
2401
- this.mouseConstraint.constraint.bodyB = null;
2402
- }
2403
- if (this.mouse) {
2404
- this.mouse.button = -1;
2405
- }
2367
+ this.grabbedObjectId = null;
2368
+ this.lastGrabMousePosition = null;
2406
2369
  }
2407
2370
  /**
2408
2371
  * Get the ID of the currently grabbed object.
2409
2372
  * @returns The ID of the grabbed object, or null if nothing is grabbed
2410
2373
  */
2411
2374
  getGrabbedObject() {
2412
- if (!this.mouseConstraint?.constraint.bodyB) return null;
2413
- const entry = this.findObjectByBody(this.mouseConstraint.constraint.bodyB);
2414
- return entry?.id ?? null;
2375
+ return this.grabbedObjectId;
2415
2376
  }
2416
2377
  // ==================== PHYSICS MANIPULATION METHODS ====================
2417
2378
  /**