@blorkfield/overlay-core 0.8.8 → 0.8.10
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 +26 -7
- package/dist/index.cjs +59 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -5
- package/dist/index.d.ts +31 -5
- package/dist/index.js +55 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,13 +22,24 @@ pnpm add @blorkfield/overlay-core
|
|
|
22
22
|
|
|
23
23
|
### Tag Based Behavior
|
|
24
24
|
|
|
25
|
-
Objects don't have fixed types. Instead, their behavior is determined by string tags:
|
|
25
|
+
Objects don't have fixed types. Instead, their behavior is determined by string tags. Import the tag constants to avoid magic strings:
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
```typescript
|
|
28
|
+
import { TAGS, TAG_FALLING, TAG_GRABABLE, TAG_FOLLOW_WINDOW } from '@blorkfield/overlay-core';
|
|
29
|
+
|
|
30
|
+
// Use individual constants
|
|
31
|
+
scene.spawnObject({ tags: [TAG_FALLING, TAG_GRABABLE], ... });
|
|
32
|
+
|
|
33
|
+
// Or destructure from TAGS object
|
|
34
|
+
const { FALLING, GRABABLE } = TAGS;
|
|
35
|
+
scene.spawnObject({ tags: [FALLING, GRABABLE], ... });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| Constant | Value | Behavior |
|
|
39
|
+
|----------|-------|----------|
|
|
40
|
+
| `TAG_FALLING` / `TAGS.FALLING` | `'falling'` | Object is dynamic and affected by gravity |
|
|
41
|
+
| `TAG_FOLLOW_WINDOW` / `TAGS.FOLLOW_WINDOW` | `'follow_window'` | Object follows mouse position when grounded |
|
|
42
|
+
| `TAG_GRABABLE` / `TAGS.GRABABLE` | `'grabable'` | Object can be grabbed and moved with mouse |
|
|
32
43
|
|
|
33
44
|
Without the `falling` tag, objects are static and won't move.
|
|
34
45
|
|
|
@@ -378,6 +389,8 @@ The offset calculation is your responsibility - overlay-core uses whatever posit
|
|
|
378
389
|
|
|
379
390
|
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.
|
|
380
391
|
|
|
392
|
+
Grab detection uses a two-pass approach to handle fast-moving bodies. The first pass does an exact point query at the click position. If that misses (the body tunneled through the cursor between frames), a second pass sweeps the body's recent position history (last 5 frames, 20px radius) to catch it. This means you can grab entities even when they are moving quickly.
|
|
393
|
+
|
|
381
394
|
```typescript
|
|
382
395
|
// Grab object at current mouse position (only 'grabable' tagged objects)
|
|
383
396
|
const grabbedId = scene.startGrab();
|
|
@@ -712,6 +725,12 @@ import type {
|
|
|
712
725
|
UpdateCallbackData,
|
|
713
726
|
|
|
714
727
|
// Logging
|
|
715
|
-
LogLevel
|
|
728
|
+
LogLevel,
|
|
729
|
+
|
|
730
|
+
// Tags
|
|
731
|
+
Tag
|
|
716
732
|
} from '@blorkfield/overlay-core';
|
|
733
|
+
|
|
734
|
+
// Tag constants (values, not types)
|
|
735
|
+
import { TAGS, TAG_FALLING, TAG_GRABABLE, TAG_FOLLOW_WINDOW } from '@blorkfield/overlay-core';
|
|
717
736
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -32,6 +32,10 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
BackgroundManager: () => BackgroundManager,
|
|
34
34
|
OverlayScene: () => OverlayScene,
|
|
35
|
+
TAGS: () => TAGS,
|
|
36
|
+
TAG_FALLING: () => TAG_FALLING,
|
|
37
|
+
TAG_FOLLOW_WINDOW: () => TAG_FOLLOW_WINDOW,
|
|
38
|
+
TAG_GRABABLE: () => TAG_GRABABLE,
|
|
35
39
|
clearFontCache: () => clearFontCache,
|
|
36
40
|
getGlyphData: () => getGlyphData,
|
|
37
41
|
getKerning: () => getKerning,
|
|
@@ -1447,6 +1451,12 @@ var OverlayScene = class {
|
|
|
1447
1451
|
this.lastGrabMousePosition = null;
|
|
1448
1452
|
this.grabbedWasDynamic = false;
|
|
1449
1453
|
this.grabVelocity = { x: 0, y: 0 };
|
|
1454
|
+
// Position history for sweep-based grab detection (catches fast-moving bodies)
|
|
1455
|
+
this.bodyPositionHistory = /* @__PURE__ */ new Map();
|
|
1456
|
+
this.grabHistoryFrames = 5;
|
|
1457
|
+
this.grabHistoryRadius = 20;
|
|
1458
|
+
// Number of physics substeps per frame — more substeps = better collision at high speeds, more CPU
|
|
1459
|
+
this.substeps = 2;
|
|
1450
1460
|
/** Handle mouse down - start grab via programmatic API */
|
|
1451
1461
|
this.handleMouseDown = (event) => {
|
|
1452
1462
|
const rect = this.canvas.getBoundingClientRect();
|
|
@@ -1523,6 +1533,10 @@ var OverlayScene = class {
|
|
|
1523
1533
|
};
|
|
1524
1534
|
// ==================== PRIVATE ====================
|
|
1525
1535
|
this.loop = () => {
|
|
1536
|
+
const substepDelta = 1e3 / 60 / this.substeps;
|
|
1537
|
+
for (let i = 0; i < this.substeps; i++) {
|
|
1538
|
+
import_matter_js5.default.Engine.update(this.engine, substepDelta);
|
|
1539
|
+
}
|
|
1526
1540
|
this.effectManager.update();
|
|
1527
1541
|
this.checkTTLExpiration();
|
|
1528
1542
|
this.checkDespawnBelowFloor();
|
|
@@ -1547,7 +1561,7 @@ var OverlayScene = class {
|
|
|
1547
1561
|
const isDragging = this.grabbedObjectId === entry.id;
|
|
1548
1562
|
if (!isDragging) {
|
|
1549
1563
|
for (const tag of entry.tags) {
|
|
1550
|
-
const key = tag === "
|
|
1564
|
+
const key = tag === "follow_window" ? "mouse" : tag.startsWith("follow-") ? tag.slice(7) : null;
|
|
1551
1565
|
if (key) {
|
|
1552
1566
|
const target = this.followTargets.get(key);
|
|
1553
1567
|
if (target) {
|
|
@@ -1566,6 +1580,14 @@ var OverlayScene = class {
|
|
|
1566
1580
|
if (entry.domElement && entry.tags.includes("falling")) {
|
|
1567
1581
|
this.updateDOMElementTransform(entry);
|
|
1568
1582
|
}
|
|
1583
|
+
if (entry.tags.includes("grabable") && !entry.body.isStatic) {
|
|
1584
|
+
const history = this.bodyPositionHistory.get(entry.body.id) ?? [];
|
|
1585
|
+
history.push({ x: entry.body.position.x, y: entry.body.position.y });
|
|
1586
|
+
if (history.length > this.grabHistoryFrames) {
|
|
1587
|
+
history.shift();
|
|
1588
|
+
}
|
|
1589
|
+
this.bodyPositionHistory.set(entry.body.id, history);
|
|
1590
|
+
}
|
|
1569
1591
|
}
|
|
1570
1592
|
if (!this.config.debug) {
|
|
1571
1593
|
this.drawTTFGlyphs();
|
|
@@ -1827,7 +1849,7 @@ var OverlayScene = class {
|
|
|
1827
1849
|
}
|
|
1828
1850
|
}
|
|
1829
1851
|
if (parts.length > 0) {
|
|
1830
|
-
|
|
1852
|
+
logger.debug("[Pressure]", parts.join(" "));
|
|
1831
1853
|
}
|
|
1832
1854
|
}
|
|
1833
1855
|
/** Calculate weighted pressure from a set of object IDs */
|
|
@@ -2004,7 +2026,6 @@ var OverlayScene = class {
|
|
|
2004
2026
|
}
|
|
2005
2027
|
start() {
|
|
2006
2028
|
import_matter_js5.default.Render.run(this.render);
|
|
2007
|
-
import_matter_js5.default.Runner.run(this.runner, this.engine);
|
|
2008
2029
|
this.loop();
|
|
2009
2030
|
}
|
|
2010
2031
|
stop() {
|
|
@@ -2082,7 +2103,7 @@ var OverlayScene = class {
|
|
|
2082
2103
|
* Spawn an object synchronously.
|
|
2083
2104
|
* Object behavior is determined by tags:
|
|
2084
2105
|
* - 'falling': Object is dynamic (affected by gravity)
|
|
2085
|
-
* - '
|
|
2106
|
+
* - 'follow_window': Object follows mouse when grounded (walks toward mouse)
|
|
2086
2107
|
* - 'grabable': Object can be grabbed and moved with mouse
|
|
2087
2108
|
* Without 'falling' tag, object is static.
|
|
2088
2109
|
*/
|
|
@@ -2378,6 +2399,7 @@ var OverlayScene = class {
|
|
|
2378
2399
|
import_matter_js5.default.Composite.allBodies(this.engine.world),
|
|
2379
2400
|
position
|
|
2380
2401
|
);
|
|
2402
|
+
logger.debug("OverlayScene", "Grabbed position " + position + ', had "' + bodies.length + '"');
|
|
2381
2403
|
for (const body of bodies) {
|
|
2382
2404
|
const entry = this.findObjectByBody(body);
|
|
2383
2405
|
if (entry && entry.tags.includes("grabable")) {
|
|
@@ -2389,6 +2411,24 @@ var OverlayScene = class {
|
|
|
2389
2411
|
return entry.id;
|
|
2390
2412
|
}
|
|
2391
2413
|
}
|
|
2414
|
+
const r2 = this.grabHistoryRadius * this.grabHistoryRadius;
|
|
2415
|
+
for (const entry of this.objects.values()) {
|
|
2416
|
+
if (!entry.tags.includes("grabable")) continue;
|
|
2417
|
+
const history = this.bodyPositionHistory.get(entry.body.id);
|
|
2418
|
+
if (!history) continue;
|
|
2419
|
+
for (const pastPos of history) {
|
|
2420
|
+
const dx = position.x - pastPos.x;
|
|
2421
|
+
const dy = position.y - pastPos.y;
|
|
2422
|
+
if (dx * dx + dy * dy <= r2) {
|
|
2423
|
+
this.grabbedObjectId = entry.id;
|
|
2424
|
+
this.lastGrabMousePosition = { x: position.x, y: position.y };
|
|
2425
|
+
this.grabVelocity = { x: 0, y: 0 };
|
|
2426
|
+
this.grabbedWasDynamic = !entry.body.isStatic;
|
|
2427
|
+
import_matter_js5.default.Body.setStatic(entry.body, true);
|
|
2428
|
+
return entry.id;
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2392
2432
|
return null;
|
|
2393
2433
|
}
|
|
2394
2434
|
/**
|
|
@@ -2402,6 +2442,7 @@ var OverlayScene = class {
|
|
|
2402
2442
|
import_matter_js5.default.Sleeping.set(entry.body, false);
|
|
2403
2443
|
import_matter_js5.default.Body.setVelocity(entry.body, this.grabVelocity);
|
|
2404
2444
|
import_matter_js5.default.Body.setAngularVelocity(entry.body, 0);
|
|
2445
|
+
this.bodyPositionHistory.delete(entry.body.id);
|
|
2405
2446
|
}
|
|
2406
2447
|
}
|
|
2407
2448
|
this.grabbedObjectId = null;
|
|
@@ -3394,10 +3435,24 @@ var OverlayScene = class {
|
|
|
3394
3435
|
this.updateCallbacks.forEach((cb) => cb(data));
|
|
3395
3436
|
}
|
|
3396
3437
|
};
|
|
3438
|
+
|
|
3439
|
+
// src/tags.ts
|
|
3440
|
+
var TAG_FALLING = "falling";
|
|
3441
|
+
var TAG_FOLLOW_WINDOW = "follow_window";
|
|
3442
|
+
var TAG_GRABABLE = "grabable";
|
|
3443
|
+
var TAGS = {
|
|
3444
|
+
FALLING: TAG_FALLING,
|
|
3445
|
+
FOLLOW_WINDOW: TAG_FOLLOW_WINDOW,
|
|
3446
|
+
GRABABLE: TAG_GRABABLE
|
|
3447
|
+
};
|
|
3397
3448
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3398
3449
|
0 && (module.exports = {
|
|
3399
3450
|
BackgroundManager,
|
|
3400
3451
|
OverlayScene,
|
|
3452
|
+
TAGS,
|
|
3453
|
+
TAG_FALLING,
|
|
3454
|
+
TAG_FOLLOW_WINDOW,
|
|
3455
|
+
TAG_GRABABLE,
|
|
3401
3456
|
clearFontCache,
|
|
3402
3457
|
getGlyphData,
|
|
3403
3458
|
getKerning,
|