@blorkfield/overlay-core 0.8.11 → 0.9.0
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 +51 -9
- package/dist/index.cjs +68 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -2
- package/dist/index.d.ts +37 -2
- package/dist/index.js +67 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@ scene.spawnObject({ tags: [FALLING, GRABABLE], ... });
|
|
|
40
40
|
| `TAG_FALLING` / `TAGS.FALLING` | `'falling'` | Object is dynamic and affected by gravity |
|
|
41
41
|
| `TAG_FOLLOW_WINDOW` / `TAGS.FOLLOW_WINDOW` | `'follow_window'` | Object follows mouse position when grounded |
|
|
42
42
|
| `TAG_GRABABLE` / `TAGS.GRABABLE` | `'grabable'` | Object can be grabbed and moved with mouse |
|
|
43
|
+
| `TAG_GRAVITY_OVERRIDE` / `TAGS.GRAVITY_OVERRIDE` | `'gravity_override'` | Object uses its own gravity (set via `gravityOverride` in config) |
|
|
43
44
|
|
|
44
45
|
Without the `falling` tag, objects are static and won't move.
|
|
45
46
|
|
|
@@ -82,7 +83,7 @@ const { canvas, bounds } = OverlayScene.createContainer(container, {
|
|
|
82
83
|
// Create scene
|
|
83
84
|
const scene = new OverlayScene(canvas, {
|
|
84
85
|
bounds,
|
|
85
|
-
gravity: 1,
|
|
86
|
+
gravity: { x: 0, y: 1 },
|
|
86
87
|
wrapHorizontal: true,
|
|
87
88
|
background: 'transparent'
|
|
88
89
|
});
|
|
@@ -426,7 +427,7 @@ const currentGrab = scene.getGrabbedObject(); // Returns ID or null
|
|
|
426
427
|
```typescript
|
|
427
428
|
const scene = new OverlayScene(canvas, {
|
|
428
429
|
bounds: { top: 0, bottom: 600, left: 0, right: 800 },
|
|
429
|
-
gravity: 1,
|
|
430
|
+
gravity: { x: 0, y: 1 },
|
|
430
431
|
wrapHorizontal: true,
|
|
431
432
|
debug: false,
|
|
432
433
|
background: '#16213e',
|
|
@@ -443,7 +444,7 @@ const scene = new OverlayScene(canvas, {
|
|
|
443
444
|
|
|
444
445
|
| Option | Default | Description |
|
|
445
446
|
|--------|---------|-------------|
|
|
446
|
-
| `gravity` | 1 | Gravity
|
|
447
|
+
| `gravity` | `{ x: 0, y: 1 }` | Gravity vector. Both axes support negative values |
|
|
447
448
|
| `wrapHorizontal` | true | Objects wrap around screen edges |
|
|
448
449
|
| `debug` | false | Show collision wireframes |
|
|
449
450
|
| `background` | transparent | Canvas background color |
|
|
@@ -641,13 +642,53 @@ setLogLevel('debug'); // Options: debug, info, warn, error
|
|
|
641
642
|
## Lifecycle
|
|
642
643
|
|
|
643
644
|
```typescript
|
|
644
|
-
scene.start();
|
|
645
|
-
scene.stop();
|
|
646
|
-
scene.resize(w, h);
|
|
647
|
-
scene.setDebug(true);
|
|
648
|
-
scene.
|
|
645
|
+
scene.start(); // Start simulation
|
|
646
|
+
scene.stop(); // Pause simulation
|
|
647
|
+
scene.resize(w, h); // Resize canvas and bounds
|
|
648
|
+
scene.setDebug(true); // Toggle wireframe mode
|
|
649
|
+
scene.setGravity({ x: 0, y: -1 }); // Set gravity (negative y = upward)
|
|
650
|
+
scene.setGravity({ x: 0, y: 0 }); // Zero gravity
|
|
651
|
+
scene.setGravity({ x: 1, y: 0 }); // Sideways gravity
|
|
652
|
+
scene.destroy(); // Clean up resources
|
|
649
653
|
```
|
|
650
654
|
|
|
655
|
+
### Per-Object Gravity Override
|
|
656
|
+
|
|
657
|
+
Individual dynamic objects can have their own gravity vector, independent of the scene gravity. This is done via the `gravityOverride` field in `ObjectConfig`, which automatically adds the `gravity_override` tag to the object.
|
|
658
|
+
|
|
659
|
+
```typescript
|
|
660
|
+
// Spawn a floaty object that drifts upward
|
|
661
|
+
scene.spawnObject({
|
|
662
|
+
x: 200, y: 300,
|
|
663
|
+
radius: 20,
|
|
664
|
+
fillStyle: '#4a90d9',
|
|
665
|
+
tags: ['falling', 'grabable'],
|
|
666
|
+
gravityOverride: { x: 0, y: -0.3 } // floats upward
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
// Zero gravity — hovers in place
|
|
670
|
+
scene.spawnObject({
|
|
671
|
+
x: 400, y: 200,
|
|
672
|
+
radius: 15,
|
|
673
|
+
fillStyle: '#e94560',
|
|
674
|
+
tags: ['falling'],
|
|
675
|
+
gravityOverride: { x: 0, y: 0 }
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
// Change or clear a gravity override at runtime
|
|
679
|
+
scene.setObjectGravityOverride(id, { x: 0.5, y: 0 }); // drift sideways
|
|
680
|
+
scene.setObjectGravityOverride(id, null); // restore scene gravity
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
Tags are either boolean (presence = true) or carry a value. `gravity_override` is a value tag — its Vector2 value is set via `gravityOverride` in the config. Boolean tags (`falling`, `grabable`, `follow_window`) need no value.
|
|
684
|
+
|
|
685
|
+
| Tag | Type | Behavior |
|
|
686
|
+
|-----|------|----------|
|
|
687
|
+
| `falling` | boolean | Dynamic body affected by gravity |
|
|
688
|
+
| `grabable` | boolean | Can be grabbed with mouse |
|
|
689
|
+
| `follow_window` | boolean | Walks toward mouse when grounded |
|
|
690
|
+
| `gravity_override` | Vector2 | Uses own gravity instead of scene gravity |
|
|
691
|
+
|
|
651
692
|
## Examples
|
|
652
693
|
|
|
653
694
|
Working examples are provided in the `/examples` directory:
|
|
@@ -673,6 +714,7 @@ import type {
|
|
|
673
714
|
// Scene configuration
|
|
674
715
|
OverlaySceneConfig,
|
|
675
716
|
Bounds,
|
|
717
|
+
Vector2,
|
|
676
718
|
ContainerOptions,
|
|
677
719
|
FloorConfig,
|
|
678
720
|
|
|
@@ -732,5 +774,5 @@ import type {
|
|
|
732
774
|
} from '@blorkfield/overlay-core';
|
|
733
775
|
|
|
734
776
|
// Tag constants (values, not types)
|
|
735
|
-
import { TAGS, TAG_FALLING, TAG_GRABABLE, TAG_FOLLOW_WINDOW } from '@blorkfield/overlay-core';
|
|
777
|
+
import { TAGS, TAG_FALLING, TAG_GRABABLE, TAG_FOLLOW_WINDOW, TAG_GRAVITY_OVERRIDE } from '@blorkfield/overlay-core';
|
|
736
778
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,7 @@ __export(index_exports, {
|
|
|
36
36
|
TAG_FALLING: () => TAG_FALLING,
|
|
37
37
|
TAG_FOLLOW_WINDOW: () => TAG_FOLLOW_WINDOW,
|
|
38
38
|
TAG_GRABABLE: () => TAG_GRABABLE,
|
|
39
|
+
TAG_GRAVITY_OVERRIDE: () => TAG_GRAVITY_OVERRIDE,
|
|
39
40
|
clearFontCache: () => clearFontCache,
|
|
40
41
|
getGlyphData: () => getGlyphData,
|
|
41
42
|
getKerning: () => getKerning,
|
|
@@ -54,7 +55,8 @@ var import_matter_js5 = __toESM(require("matter-js"), 1);
|
|
|
54
55
|
var import_matter_js = __toESM(require("matter-js"), 1);
|
|
55
56
|
function createEngine(gravity) {
|
|
56
57
|
const engine = import_matter_js.default.Engine.create();
|
|
57
|
-
engine.gravity.
|
|
58
|
+
engine.gravity.x = gravity.x;
|
|
59
|
+
engine.gravity.y = gravity.y;
|
|
58
60
|
return engine;
|
|
59
61
|
}
|
|
60
62
|
function createRender(engine, canvas, config) {
|
|
@@ -1456,6 +1458,8 @@ var OverlayScene = class {
|
|
|
1456
1458
|
this.grabHistoryRadius = 20;
|
|
1457
1459
|
// Number of physics substeps per frame — more substeps = better collision at high speeds, more CPU
|
|
1458
1460
|
this.substeps = 2;
|
|
1461
|
+
// Tracks only the bodies with a gravity override — engine gravity handles everyone else
|
|
1462
|
+
this.gravityOverrideEntries = /* @__PURE__ */ new Set();
|
|
1459
1463
|
/** Handle mouse down - start grab via programmatic API */
|
|
1460
1464
|
this.handleMouseDown = (event) => {
|
|
1461
1465
|
const rect = this.canvas.getBoundingClientRect();
|
|
@@ -1533,7 +1537,16 @@ var OverlayScene = class {
|
|
|
1533
1537
|
// ==================== PRIVATE ====================
|
|
1534
1538
|
this.loop = () => {
|
|
1535
1539
|
const substepDelta = 1e3 / 60 / this.substeps;
|
|
1540
|
+
const scale = this.engine.gravity.scale;
|
|
1536
1541
|
for (let i = 0; i < this.substeps; i++) {
|
|
1542
|
+
for (const entry of this.gravityOverrideEntries) {
|
|
1543
|
+
if (entry.body.isStatic || entry.body.isSleeping) continue;
|
|
1544
|
+
const g = entry.gravityOverride;
|
|
1545
|
+
import_matter_js5.default.Body.applyForce(entry.body, entry.body.position, {
|
|
1546
|
+
x: entry.body.mass * (g.x - this.engine.gravity.x) * scale,
|
|
1547
|
+
y: entry.body.mass * (g.y - this.engine.gravity.y) * scale
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1537
1550
|
import_matter_js5.default.Engine.update(this.engine, substepDelta);
|
|
1538
1551
|
}
|
|
1539
1552
|
this.effectManager.update();
|
|
@@ -1596,7 +1609,7 @@ var OverlayScene = class {
|
|
|
1596
1609
|
};
|
|
1597
1610
|
this.canvas = canvas;
|
|
1598
1611
|
this.config = {
|
|
1599
|
-
gravity: 1,
|
|
1612
|
+
gravity: { x: 0, y: 1 },
|
|
1600
1613
|
wrapHorizontal: true,
|
|
1601
1614
|
debug: false,
|
|
1602
1615
|
...config
|
|
@@ -2062,6 +2075,39 @@ var OverlayScene = class {
|
|
|
2062
2075
|
}
|
|
2063
2076
|
}
|
|
2064
2077
|
}
|
|
2078
|
+
/**
|
|
2079
|
+
* Set gravity at runtime. Supports any direction including negative values.
|
|
2080
|
+
* @example
|
|
2081
|
+
* scene.setGravity({ x: 0, y: 1 }); // Normal downward gravity
|
|
2082
|
+
* scene.setGravity({ x: 0, y: -1 }); // Upward gravity
|
|
2083
|
+
* scene.setGravity({ x: 1, y: 0 }); // Sideways gravity
|
|
2084
|
+
* scene.setGravity({ x: 0, y: 0 }); // Zero gravity
|
|
2085
|
+
*/
|
|
2086
|
+
setGravity(gravity) {
|
|
2087
|
+
this.config.gravity = gravity;
|
|
2088
|
+
this.engine.gravity.x = gravity.x;
|
|
2089
|
+
this.engine.gravity.y = gravity.y;
|
|
2090
|
+
}
|
|
2091
|
+
/**
|
|
2092
|
+
* Set or clear a per-object gravity override at runtime.
|
|
2093
|
+
* Pass `null` to remove the override and restore scene gravity for that object.
|
|
2094
|
+
*/
|
|
2095
|
+
setObjectGravityOverride(id, gravity) {
|
|
2096
|
+
const entry = this.objects.get(id);
|
|
2097
|
+
if (!entry) return;
|
|
2098
|
+
if (gravity === null) {
|
|
2099
|
+
entry.gravityOverride = void 0;
|
|
2100
|
+
this.gravityOverrideEntries.delete(entry);
|
|
2101
|
+
const idx = entry.tags.indexOf("gravity_override");
|
|
2102
|
+
if (idx !== -1) entry.tags.splice(idx, 1);
|
|
2103
|
+
} else {
|
|
2104
|
+
entry.gravityOverride = gravity;
|
|
2105
|
+
this.gravityOverrideEntries.add(entry);
|
|
2106
|
+
if (!entry.tags.includes("gravity_override")) {
|
|
2107
|
+
entry.tags.push("gravity_override");
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2065
2111
|
/**
|
|
2066
2112
|
* Update the background configuration at runtime.
|
|
2067
2113
|
*/
|
|
@@ -2119,7 +2165,10 @@ var OverlayScene = class {
|
|
|
2119
2165
|
return result.id;
|
|
2120
2166
|
}
|
|
2121
2167
|
const id = crypto.randomUUID();
|
|
2122
|
-
const tags = config.tags ?? [];
|
|
2168
|
+
const tags = [...config.tags ?? []];
|
|
2169
|
+
if (config.gravityOverride && !tags.includes("gravity_override")) {
|
|
2170
|
+
tags.push("gravity_override");
|
|
2171
|
+
}
|
|
2123
2172
|
const isStatic = !tags.includes("falling");
|
|
2124
2173
|
logger.debug("OverlayScene", `Spawning object`, {
|
|
2125
2174
|
id,
|
|
@@ -2159,9 +2208,11 @@ var OverlayScene = class {
|
|
|
2159
2208
|
pressureThreshold,
|
|
2160
2209
|
shadow,
|
|
2161
2210
|
originalPosition: shadow || clicksRemaining !== void 0 ? { x: config.x, y: config.y } : void 0,
|
|
2162
|
-
clicksRemaining
|
|
2211
|
+
clicksRemaining,
|
|
2212
|
+
gravityOverride: config.gravityOverride
|
|
2163
2213
|
};
|
|
2164
2214
|
this.objects.set(id, entry);
|
|
2215
|
+
if (config.gravityOverride) this.gravityOverrideEntries.add(entry);
|
|
2165
2216
|
import_matter_js5.default.Composite.add(this.engine.world, body);
|
|
2166
2217
|
if (isStatic && pressureThreshold !== void 0) {
|
|
2167
2218
|
this.obstaclePressure.set(id, /* @__PURE__ */ new Set());
|
|
@@ -2175,7 +2226,10 @@ var OverlayScene = class {
|
|
|
2175
2226
|
*/
|
|
2176
2227
|
async spawnObjectAsync(config) {
|
|
2177
2228
|
const id = crypto.randomUUID();
|
|
2178
|
-
const tags = config.tags ?? [];
|
|
2229
|
+
const tags = [...config.tags ?? []];
|
|
2230
|
+
if (config.gravityOverride && !tags.includes("gravity_override")) {
|
|
2231
|
+
tags.push("gravity_override");
|
|
2232
|
+
}
|
|
2179
2233
|
const isStatic = !tags.includes("falling");
|
|
2180
2234
|
logger.debug("OverlayScene", `Spawning object async`, {
|
|
2181
2235
|
id,
|
|
@@ -2215,9 +2269,11 @@ var OverlayScene = class {
|
|
|
2215
2269
|
pressureThreshold,
|
|
2216
2270
|
shadow,
|
|
2217
2271
|
originalPosition: shadow || clicksRemaining !== void 0 ? { x: config.x, y: config.y } : void 0,
|
|
2218
|
-
clicksRemaining
|
|
2272
|
+
clicksRemaining,
|
|
2273
|
+
gravityOverride: config.gravityOverride
|
|
2219
2274
|
};
|
|
2220
2275
|
this.objects.set(id, entry);
|
|
2276
|
+
if (config.gravityOverride) this.gravityOverrideEntries.add(entry);
|
|
2221
2277
|
import_matter_js5.default.Composite.add(this.engine.world, body);
|
|
2222
2278
|
if (isStatic && pressureThreshold !== void 0) {
|
|
2223
2279
|
this.obstaclePressure.set(id, /* @__PURE__ */ new Set());
|
|
@@ -2306,6 +2362,7 @@ var OverlayScene = class {
|
|
|
2306
2362
|
if (!entry) return;
|
|
2307
2363
|
this.emitLifecycleEvent("objectRemoved", this.toObjectState(entry));
|
|
2308
2364
|
import_matter_js5.default.Composite.remove(this.engine.world, entry.body);
|
|
2365
|
+
this.gravityOverrideEntries.delete(entry);
|
|
2309
2366
|
this.objects.delete(id);
|
|
2310
2367
|
}
|
|
2311
2368
|
removeObjects(ids) {
|
|
@@ -2318,6 +2375,7 @@ var OverlayScene = class {
|
|
|
2318
2375
|
import_matter_js5.default.Composite.remove(this.engine.world, entry.body);
|
|
2319
2376
|
}
|
|
2320
2377
|
this.objects.clear();
|
|
2378
|
+
this.gravityOverrideEntries.clear();
|
|
2321
2379
|
}
|
|
2322
2380
|
removeObjectsByTag(tag) {
|
|
2323
2381
|
const toRemove = [];
|
|
@@ -3434,10 +3492,12 @@ var OverlayScene = class {
|
|
|
3434
3492
|
var TAG_FALLING = "falling";
|
|
3435
3493
|
var TAG_FOLLOW_WINDOW = "follow_window";
|
|
3436
3494
|
var TAG_GRABABLE = "grabable";
|
|
3495
|
+
var TAG_GRAVITY_OVERRIDE = "gravity_override";
|
|
3437
3496
|
var TAGS = {
|
|
3438
3497
|
FALLING: TAG_FALLING,
|
|
3439
3498
|
FOLLOW_WINDOW: TAG_FOLLOW_WINDOW,
|
|
3440
|
-
GRABABLE: TAG_GRABABLE
|
|
3499
|
+
GRABABLE: TAG_GRABABLE,
|
|
3500
|
+
GRAVITY_OVERRIDE: TAG_GRAVITY_OVERRIDE
|
|
3441
3501
|
};
|
|
3442
3502
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3443
3503
|
0 && (module.exports = {
|
|
@@ -3447,6 +3507,7 @@ var TAGS = {
|
|
|
3447
3507
|
TAG_FALLING,
|
|
3448
3508
|
TAG_FOLLOW_WINDOW,
|
|
3449
3509
|
TAG_GRABABLE,
|
|
3510
|
+
TAG_GRAVITY_OVERRIDE,
|
|
3450
3511
|
clearFontCache,
|
|
3451
3512
|
getGlyphData,
|
|
3452
3513
|
getKerning,
|