@blorkfield/overlay-core 0.11.6 → 0.11.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/README.md CHANGED
@@ -215,9 +215,11 @@ scene.spawnObject({
215
215
  });
216
216
  ```
217
217
 
218
+ **Positioning convention:** overlay-core sets `position: absolute` on the element and owns `left`, `top`, and `transform` entirely via inline styles. Position is expressed as `left: x - width/2; top: y - height/2` (body centre → top-left corner). Rotation is applied via `transform: rotate(angle)`. Do not set `left`, `top`, or `transform` on the element yourself — they will be overwritten. To place the element before spawn, set it off-screen or hidden; overlay-core writes the correct position on `spawnObject` for both static and dynamic elements, so it is visible and correctly placed immediately after the call returns.
219
+
218
220
  When a DOM element collapses:
219
- - The element's CSS transform is updated each frame to follow physics
220
- - Shadow creates a cloned DOM element at the original position
221
+ - The element follows its physics body each frame via `left`/`top` updates
222
+ - If `shadow` is configured, a cloned DOM element is left at the original spawn position
221
223
 
222
224
  ```typescript
223
225
  // Get the shadow element after collapse (if shadow was configured)
@@ -555,7 +557,7 @@ const scene = new OverlayScene(canvas, {
555
557
  | `floorConfig.minIntegrity` | none | Minimum segments required, otherwise all collapse |
556
558
  | `floorConfig.segmentWidths` | none | Proportional widths for each segment (array that sums to 1.0) |
557
559
  | `despawnBelowFloor` | 1.0 | Distance below floor to despawn objects (as fraction of height) |
558
- | `recenterOnResize` | false | Translate all objects to stay centred when canvas dimensions change — useful for phone rotation and responsive layouts |
560
+ | `recenterOnResize` | false | Translate all objects to stay centred when canvas dimensions change — useful for phone rotation and responsive layouts. Applies to all object types including static DOM obstacles (their CSS `left`/`top` is updated immediately at resize time, not deferred to the next frame). |
559
561
 
560
562
  ### Background Configuration
561
563
 
package/dist/index.cjs CHANGED
@@ -1498,6 +1498,8 @@ var OverlayScene = class {
1498
1498
  this.pressureObstacleIds = /* @__PURE__ */ new Set();
1499
1499
  // Active collision pairs: id -> Set of ids currently colliding with it
1500
1500
  this.activeCollisions = /* @__PURE__ */ new Map();
1501
+ // DOM shadow elements whose parent entry has been removed (live body despawned after collapse)
1502
+ this.orphanedDOMShadows = /* @__PURE__ */ new Set();
1501
1503
  /** Handle mouse down - start grab via programmatic API */
1502
1504
  this.handleMouseDown = (event) => {
1503
1505
  const rect = this.canvas.getBoundingClientRect();
@@ -2052,9 +2054,9 @@ var OverlayScene = class {
2052
2054
  transform: entry.domElement.style.transform
2053
2055
  }
2054
2056
  });
2055
- shadowElement.style.setProperty("left", `${computedLeft}px`, "important");
2056
- shadowElement.style.setProperty("top", `${computedTop}px`, "important");
2057
- shadowElement.style.setProperty("transform", "rotate(0deg)", "important");
2057
+ shadowElement.style.left = `${computedLeft}px`;
2058
+ shadowElement.style.top = `${computedTop}px`;
2059
+ shadowElement.style.transform = "rotate(0deg)";
2058
2060
  entry.domElement.parentNode?.insertBefore(shadowElement, entry.domElement);
2059
2061
  entry.domShadowElement = shadowElement;
2060
2062
  return;
@@ -2169,6 +2171,7 @@ var OverlayScene = class {
2169
2171
  import_matter_js5.default.Events.off(this.engine, "collisionEnd", this.handleCollisionEnd);
2170
2172
  import_matter_js5.default.Engine.clear(this.engine);
2171
2173
  this.objects.clear();
2174
+ this.orphanedDOMShadows.clear();
2172
2175
  this.gravityOverrideEntries.clear();
2173
2176
  this.followWindowEntries.clear();
2174
2177
  this.pressureObstacleIds.clear();
@@ -2319,15 +2322,24 @@ var OverlayScene = class {
2319
2322
  };
2320
2323
  }
2321
2324
  if (entry.domElement && entry.tags.includes("static")) {
2322
- this.updateDOMElementTransform(entry);
2325
+ const currentLeft = parseFloat(entry.domElement.style.left) || 0;
2326
+ const currentTop = parseFloat(entry.domElement.style.top) || 0;
2327
+ entry.domElement.style.left = `${currentLeft + dx}px`;
2328
+ entry.domElement.style.top = `${currentTop + dy}px`;
2323
2329
  }
2324
2330
  if (entry.domShadowElement) {
2325
2331
  const currentLeft = parseFloat(entry.domShadowElement.style.left) || 0;
2326
2332
  const currentTop = parseFloat(entry.domShadowElement.style.top) || 0;
2327
- entry.domShadowElement.style.setProperty("left", `${currentLeft + dx}px`, "important");
2328
- entry.domShadowElement.style.setProperty("top", `${currentTop + dy}px`, "important");
2333
+ entry.domShadowElement.style.left = `${currentLeft + dx}px`;
2334
+ entry.domShadowElement.style.top = `${currentTop + dy}px`;
2329
2335
  }
2330
2336
  }
2337
+ for (const shadowEl of this.orphanedDOMShadows) {
2338
+ const currentLeft = parseFloat(shadowEl.style.left) || 0;
2339
+ const currentTop = parseFloat(shadowEl.style.top) || 0;
2340
+ shadowEl.style.left = `${currentLeft + dx}px`;
2341
+ shadowEl.style.top = `${currentTop + dy}px`;
2342
+ }
2331
2343
  }
2332
2344
  this.canvas.width = width;
2333
2345
  this.canvas.height = height;
@@ -2659,6 +2671,9 @@ var OverlayScene = class {
2659
2671
  }
2660
2672
  this.activeCollisions.delete(id);
2661
2673
  }
2674
+ if (entry.domShadowElement) {
2675
+ this.orphanedDOMShadows.add(entry.domShadowElement);
2676
+ }
2662
2677
  this.objects.delete(id);
2663
2678
  }
2664
2679
  removeObjects(ids) {
@@ -3788,9 +3803,9 @@ var OverlayScene = class {
3788
3803
  const angleDeg = angle * (180 / Math.PI);
3789
3804
  const width = entry.domElement.offsetWidth;
3790
3805
  const height = entry.domElement.offsetHeight;
3791
- entry.domElement.style.setProperty("left", `${x - width / 2}px`, "important");
3792
- entry.domElement.style.setProperty("top", `${y - height / 2}px`, "important");
3793
- entry.domElement.style.setProperty("transform", `rotate(${angleDeg}deg)`, "important");
3806
+ entry.domElement.style.left = `${x - width / 2}px`;
3807
+ entry.domElement.style.top = `${y - height / 2}px`;
3808
+ entry.domElement.style.transform = `rotate(${angleDeg}deg)`;
3794
3809
  }
3795
3810
  /** TTL expiration + below-floor despawn in a single O(N) pass */
3796
3811
  checkExpiration() {