@blorkfield/overlay-core 0.8.3 → 0.8.5

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
@@ -1443,6 +1443,8 @@ var OverlayScene = class {
1443
1443
  };
1444
1444
  // Follow targets for follow-{key} tagged objects
1445
1445
  this.followTargets = /* @__PURE__ */ new Map();
1446
+ // Programmatic grab state - tracks initial positions for relative movement
1447
+ this.grabState = null;
1446
1448
  /** Filter drag events - only allow grabbing objects with 'grabable' tag */
1447
1449
  this.handleStartDrag = (event) => {
1448
1450
  const body = event.body;
@@ -2337,10 +2339,21 @@ var OverlayScene = class {
2337
2339
  setFollowTarget(key, x, y) {
2338
2340
  this.followTargets.set(key, { x, y });
2339
2341
  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;
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
+ }
2344
2357
  }
2345
2358
  }
2346
2359
  /**
@@ -2377,11 +2390,29 @@ var OverlayScene = class {
2377
2390
  const entry = this.findObjectByBody(body);
2378
2391
  if (entry && entry.tags.includes("grabable")) {
2379
2392
  this.mouse.button = 0;
2380
- this.mouseConstraint.constraint.bodyB = entry.body;
2381
- this.mouseConstraint.constraint.pointB = {
2382
- x: position.x - entry.body.position.x,
2383
- y: position.y - entry.body.position.y
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
2384
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
+ });
2385
2416
  return entry.id;
2386
2417
  }
2387
2418
  }
@@ -2397,6 +2428,7 @@ var OverlayScene = class {
2397
2428
  if (this.mouse) {
2398
2429
  this.mouse.button = -1;
2399
2430
  }
2431
+ this.grabState = null;
2400
2432
  }
2401
2433
  /**
2402
2434
  * Get the ID of the currently grabbed object.