@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.d.cts CHANGED
@@ -537,7 +537,6 @@ declare class OverlayScene {
537
537
  private config;
538
538
  private animationFrameId;
539
539
  private mouse;
540
- private mouseConstraint;
541
540
  private effectManager;
542
541
  private fonts;
543
542
  private fontsInitialized;
@@ -551,14 +550,21 @@ declare class OverlayScene {
551
550
  private backgroundManager;
552
551
  private lifecycleCallbacks;
553
552
  private followTargets;
554
- private grabState;
553
+ private grabbedObjectId;
554
+ private lastGrabMousePosition;
555
+ private grabbedWasDynamic;
556
+ private grabVelocity;
555
557
  static createContainer(parent: HTMLElement, options?: ContainerOptions): {
556
558
  canvas: HTMLCanvasElement;
557
559
  bounds: Bounds;
558
560
  };
559
561
  constructor(canvas: HTMLCanvasElement, config: OverlaySceneConfig);
560
- /** Filter drag events - only allow grabbing objects with 'grabable' tag */
561
- private handleStartDrag;
562
+ /** Handle mouse down - start grab via programmatic API */
563
+ private handleMouseDown;
564
+ /** Handle mouse move - update follow target for grabbed entity */
565
+ private handleMouseMove;
566
+ /** Handle mouse up - release grab */
567
+ private handleMouseUp;
562
568
  /** Handle canvas clicks for click-to-fall behavior */
563
569
  private handleCanvasClick;
564
570
  /**
package/dist/index.d.ts CHANGED
@@ -537,7 +537,6 @@ declare class OverlayScene {
537
537
  private config;
538
538
  private animationFrameId;
539
539
  private mouse;
540
- private mouseConstraint;
541
540
  private effectManager;
542
541
  private fonts;
543
542
  private fontsInitialized;
@@ -551,14 +550,21 @@ declare class OverlayScene {
551
550
  private backgroundManager;
552
551
  private lifecycleCallbacks;
553
552
  private followTargets;
554
- private grabState;
553
+ private grabbedObjectId;
554
+ private lastGrabMousePosition;
555
+ private grabbedWasDynamic;
556
+ private grabVelocity;
555
557
  static createContainer(parent: HTMLElement, options?: ContainerOptions): {
556
558
  canvas: HTMLCanvasElement;
557
559
  bounds: Bounds;
558
560
  };
559
561
  constructor(canvas: HTMLCanvasElement, config: OverlaySceneConfig);
560
- /** Filter drag events - only allow grabbing objects with 'grabable' tag */
561
- private handleStartDrag;
562
+ /** Handle mouse down - start grab via programmatic API */
563
+ private handleMouseDown;
564
+ /** Handle mouse move - update follow target for grabbed entity */
565
+ private handleMouseMove;
566
+ /** Handle mouse up - release grab */
567
+ private handleMouseUp;
562
568
  /** Handle canvas clicks for click-to-fall behavior */
563
569
  private handleCanvasClick;
564
570
  /**
package/dist/index.js CHANGED
@@ -1376,7 +1376,6 @@ var OverlayScene = class {
1376
1376
  this.updateCallbacks = [];
1377
1377
  this.animationFrameId = null;
1378
1378
  this.mouse = null;
1379
- this.mouseConstraint = null;
1380
1379
  this.fonts = [];
1381
1380
  this.fontsInitialized = false;
1382
1381
  this.letterDebugInfo = /* @__PURE__ */ new Map();
@@ -1398,18 +1397,29 @@ var OverlayScene = class {
1398
1397
  };
1399
1398
  // Follow targets for follow-{key} tagged objects
1400
1399
  this.followTargets = /* @__PURE__ */ new Map();
1401
- // Programmatic grab state - tracks initial positions for relative movement
1402
- this.grabState = null;
1403
- /** Filter drag events - only allow grabbing objects with 'grabable' tag */
1404
- this.handleStartDrag = (event) => {
1405
- const body = event.body;
1406
- if (!body) return;
1407
- const entry = this.findObjectByBody(body);
1408
- if (!entry || !entry.tags.includes("grabable")) {
1409
- if (this.mouseConstraint) {
1410
- this.mouseConstraint.constraint.bodyB = null;
1411
- }
1412
- }
1400
+ // Delta-based grab tracking
1401
+ this.grabbedObjectId = null;
1402
+ this.lastGrabMousePosition = null;
1403
+ this.grabbedWasDynamic = false;
1404
+ this.grabVelocity = { x: 0, y: 0 };
1405
+ /** Handle mouse down - start grab via programmatic API */
1406
+ this.handleMouseDown = (event) => {
1407
+ const rect = this.canvas.getBoundingClientRect();
1408
+ const x = event.clientX - rect.left;
1409
+ const y = event.clientY - rect.top;
1410
+ this.followTargets.set("mouse", { x, y });
1411
+ this.startGrab();
1412
+ };
1413
+ /** Handle mouse move - update follow target for grabbed entity */
1414
+ this.handleMouseMove = (event) => {
1415
+ const rect = this.canvas.getBoundingClientRect();
1416
+ const x = event.clientX - rect.left;
1417
+ const y = event.clientY - rect.top;
1418
+ this.followTargets.set("mouse", { x, y });
1419
+ };
1420
+ /** Handle mouse up - release grab */
1421
+ this.handleMouseUp = () => {
1422
+ this.endGrab();
1413
1423
  };
1414
1424
  /** Handle canvas clicks for click-to-fall behavior */
1415
1425
  this.handleCanvasClick = (event) => {
@@ -1475,8 +1485,21 @@ var OverlayScene = class {
1475
1485
  if (!this.followTargets.has("mouse") && this.mouse) {
1476
1486
  this.followTargets.set("mouse", { x: this.mouse.position.x, y: this.mouse.position.y });
1477
1487
  }
1488
+ if (this.grabbedObjectId && this.lastGrabMousePosition) {
1489
+ const entry = this.objects.get(this.grabbedObjectId);
1490
+ const mouseTarget = this.followTargets.get("mouse");
1491
+ if (entry && mouseTarget) {
1492
+ const dx = mouseTarget.x - this.lastGrabMousePosition.x;
1493
+ const dy = mouseTarget.y - this.lastGrabMousePosition.y;
1494
+ if (dx !== 0 || dy !== 0) {
1495
+ Matter5.Body.translate(entry.body, { x: dx, y: dy });
1496
+ }
1497
+ this.grabVelocity = { x: dx * 0.5 + this.grabVelocity.x * 0.5, y: dy * 0.5 + this.grabVelocity.y * 0.5 };
1498
+ this.lastGrabMousePosition = { x: mouseTarget.x, y: mouseTarget.y };
1499
+ }
1500
+ }
1478
1501
  for (const entry of this.objects.values()) {
1479
- const isDragging = this.mouseConstraint?.body === entry.body;
1502
+ const isDragging = this.grabbedObjectId === entry.id;
1480
1503
  if (!isDragging) {
1481
1504
  for (const tag of entry.tags) {
1482
1505
  const key = tag === "follow" ? "mouse" : tag.startsWith("follow-") ? tag.slice(7) : null;
@@ -1524,24 +1547,10 @@ var OverlayScene = class {
1524
1547
  Matter5.Composite.add(this.engine.world, this.boundaries);
1525
1548
  this.checkInitialFloorIntegrity();
1526
1549
  this.mouse = Matter5.Mouse.create(canvas);
1527
- this.mouseConstraint = Matter5.MouseConstraint.create(this.engine, {
1528
- mouse: this.mouse,
1529
- constraint: {
1530
- stiffness: 0.2,
1531
- render: { visible: false }
1532
- }
1533
- });
1534
- Matter5.Composite.add(this.engine.world, this.mouseConstraint);
1535
- const wheelHandler = this.mouse.mousewheel;
1536
- if (wheelHandler) {
1537
- canvas.removeEventListener("mousewheel", wheelHandler);
1538
- canvas.removeEventListener("DOMMouseScroll", wheelHandler);
1539
- canvas.removeEventListener("wheel", wheelHandler);
1540
- }
1541
- canvas.style.touchAction = "pan-x pan-y";
1542
- Matter5.Events.on(this.mouseConstraint, "startdrag", this.handleStartDrag);
1550
+ canvas.addEventListener("mousedown", this.handleMouseDown);
1551
+ canvas.addEventListener("mousemove", this.handleMouseMove);
1552
+ canvas.addEventListener("mouseup", this.handleMouseUp);
1543
1553
  canvas.addEventListener("click", this.handleCanvasClick);
1544
- this.render.mouse = this.mouse;
1545
1554
  this.effectManager = new EffectManager(
1546
1555
  this.config.bounds,
1547
1556
  (cfg) => this.spawnObjectAsync(cfg),
@@ -1963,9 +1972,9 @@ var OverlayScene = class {
1963
1972
  }
1964
1973
  destroy() {
1965
1974
  this.stop();
1966
- if (this.mouseConstraint) {
1967
- Matter5.Events.off(this.mouseConstraint, "startdrag", this.handleStartDrag);
1968
- }
1975
+ this.canvas.removeEventListener("mousedown", this.handleMouseDown);
1976
+ this.canvas.removeEventListener("mousemove", this.handleMouseMove);
1977
+ this.canvas.removeEventListener("mouseup", this.handleMouseUp);
1969
1978
  this.canvas.removeEventListener("click", this.handleCanvasClick);
1970
1979
  Matter5.Events.off(this.render, "beforeRender", this.handleBeforeRender);
1971
1980
  Matter5.Events.off(this.render, "afterRender", this.handleAfterRender);
@@ -2293,23 +2302,6 @@ var OverlayScene = class {
2293
2302
  */
2294
2303
  setFollowTarget(key, x, y) {
2295
2304
  this.followTargets.set(key, { x, y });
2296
- if (key === "mouse" && this.mouse) {
2297
- if (this.grabState && this.mouseConstraint?.constraint.bodyB) {
2298
- const deltaX = x - this.grabState.grabMouseX;
2299
- const deltaY = y - this.grabState.grabMouseY;
2300
- const newX = this.grabState.grabBodyX + deltaX;
2301
- const newY = this.grabState.grabBodyY + deltaY;
2302
- this.mouse.position.x = newX;
2303
- this.mouse.position.y = newY;
2304
- this.mouse.absolute.x = newX;
2305
- this.mouse.absolute.y = newY;
2306
- } else {
2307
- this.mouse.position.x = x;
2308
- this.mouse.position.y = y;
2309
- this.mouse.absolute.x = x;
2310
- this.mouse.absolute.y = y;
2311
- }
2312
- }
2313
2305
  }
2314
2306
  /**
2315
2307
  * Remove a follow target. Objects with the corresponding tag will stop following.
@@ -2334,9 +2326,9 @@ var OverlayScene = class {
2334
2326
  * @returns The ID of the grabbed object, or null if no grabable object at position
2335
2327
  */
2336
2328
  startGrab() {
2337
- if (!this.mouseConstraint || !this.mouse) return null;
2338
2329
  const mouseTarget = this.followTargets.get("mouse");
2339
- const position = mouseTarget ?? { x: this.mouse.position.x, y: this.mouse.position.y };
2330
+ const position = mouseTarget ?? (this.mouse ? { x: this.mouse.position.x, y: this.mouse.position.y } : null);
2331
+ if (!position) return null;
2340
2332
  const bodies = Matter5.Query.point(
2341
2333
  Matter5.Composite.allBodies(this.engine.world),
2342
2334
  position
@@ -2344,30 +2336,11 @@ var OverlayScene = class {
2344
2336
  for (const body of bodies) {
2345
2337
  const entry = this.findObjectByBody(body);
2346
2338
  if (entry && entry.tags.includes("grabable")) {
2347
- this.mouse.button = 0;
2348
- this.grabState = {
2349
- entityId: entry.id,
2350
- grabMouseX: position.x,
2351
- grabMouseY: position.y,
2352
- grabBodyX: entry.body.position.x,
2353
- grabBodyY: entry.body.position.y
2354
- };
2355
- this.mouseConstraint.constraint.pointA = {
2356
- x: entry.body.position.x,
2357
- y: entry.body.position.y
2358
- };
2359
- this.mouseConstraint.constraint.bodyB = entry.body;
2360
- this.mouseConstraint.constraint.pointB = { x: 0, y: 0 };
2361
- this.mouse.position.x = entry.body.position.x;
2362
- this.mouse.position.y = entry.body.position.y;
2363
- this.mouse.absolute.x = entry.body.position.x;
2364
- this.mouse.absolute.y = entry.body.position.y;
2365
- console.log("[overlay-core] startGrab success", {
2366
- entityId: entry.id,
2367
- mousePosition: position,
2368
- bodyPosition: { x: entry.body.position.x, y: entry.body.position.y },
2369
- grabState: this.grabState
2370
- });
2339
+ this.grabbedObjectId = entry.id;
2340
+ this.lastGrabMousePosition = { x: position.x, y: position.y };
2341
+ this.grabVelocity = { x: 0, y: 0 };
2342
+ this.grabbedWasDynamic = !entry.body.isStatic;
2343
+ Matter5.Body.setStatic(entry.body, true);
2371
2344
  return entry.id;
2372
2345
  }
2373
2346
  }
@@ -2377,22 +2350,26 @@ var OverlayScene = class {
2377
2350
  * Release any currently grabbed object.
2378
2351
  */
2379
2352
  endGrab() {
2380
- if (this.mouseConstraint) {
2381
- this.mouseConstraint.constraint.bodyB = null;
2382
- }
2383
- if (this.mouse) {
2384
- this.mouse.button = -1;
2353
+ if (this.grabbedObjectId && this.grabbedWasDynamic) {
2354
+ const entry = this.objects.get(this.grabbedObjectId);
2355
+ if (entry) {
2356
+ Matter5.Body.setStatic(entry.body, false);
2357
+ Matter5.Sleeping.set(entry.body, false);
2358
+ Matter5.Body.setVelocity(entry.body, this.grabVelocity);
2359
+ Matter5.Body.setAngularVelocity(entry.body, 0);
2360
+ }
2385
2361
  }
2386
- this.grabState = null;
2362
+ this.grabbedObjectId = null;
2363
+ this.lastGrabMousePosition = null;
2364
+ this.grabbedWasDynamic = false;
2365
+ this.grabVelocity = { x: 0, y: 0 };
2387
2366
  }
2388
2367
  /**
2389
2368
  * Get the ID of the currently grabbed object.
2390
2369
  * @returns The ID of the grabbed object, or null if nothing is grabbed
2391
2370
  */
2392
2371
  getGrabbedObject() {
2393
- if (!this.mouseConstraint?.constraint.bodyB) return null;
2394
- const entry = this.findObjectByBody(this.mouseConstraint.constraint.bodyB);
2395
- return entry?.id ?? null;
2372
+ return this.grabbedObjectId;
2396
2373
  }
2397
2374
  // ==================== PHYSICS MANIPULATION METHODS ====================
2398
2375
  /**