@blorkfield/overlay-core 0.4.2 → 0.5.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/dist/index.cjs +113 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -1
- package/dist/index.d.ts +54 -1
- package/dist/index.js +113 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -353,6 +353,41 @@ interface TTFTextObstacleConfig {
|
|
|
353
353
|
/** Click to fall config - when set, letters collapse after being clicked N times */
|
|
354
354
|
clickToFall?: ClickToFallConfig;
|
|
355
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* Configuration for attaching a DOM element to physics.
|
|
358
|
+
* The element will follow the physics body and can have pressure/shadow/click behavior.
|
|
359
|
+
*/
|
|
360
|
+
interface DOMObstacleConfig {
|
|
361
|
+
/** The DOM element to attach to physics */
|
|
362
|
+
element: HTMLElement;
|
|
363
|
+
/** X position of the element center */
|
|
364
|
+
x: number;
|
|
365
|
+
/** Y position of the element center */
|
|
366
|
+
y: number;
|
|
367
|
+
/** Width of the collision body (defaults to element.offsetWidth) */
|
|
368
|
+
width?: number;
|
|
369
|
+
/** Height of the collision body (defaults to element.offsetHeight) */
|
|
370
|
+
height?: number;
|
|
371
|
+
/** Tags that define object behavior */
|
|
372
|
+
tags?: string[];
|
|
373
|
+
/** Pressure threshold config - when reached, element collapses */
|
|
374
|
+
pressureThreshold?: PressureThresholdConfig;
|
|
375
|
+
/** Weight for pressure calculation (default: 1) */
|
|
376
|
+
weight?: number;
|
|
377
|
+
/** Shadow config - when enabled, a cloned element remains after collapse */
|
|
378
|
+
shadow?: ShadowConfig;
|
|
379
|
+
/** Click to fall config - when set, element collapses after being clicked N times */
|
|
380
|
+
clickToFall?: ClickToFallConfig;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Result of attaching a DOM element to physics
|
|
384
|
+
*/
|
|
385
|
+
interface DOMObstacleResult {
|
|
386
|
+
/** ID of the created physics object */
|
|
387
|
+
id: string;
|
|
388
|
+
/** The shadow element if shadow was configured (null until collapse) */
|
|
389
|
+
shadowElement: HTMLElement | null;
|
|
390
|
+
}
|
|
356
391
|
/**
|
|
357
392
|
* Information about an available font
|
|
358
393
|
*/
|
|
@@ -550,6 +585,20 @@ declare class OverlayScene {
|
|
|
550
585
|
* Check if fonts have been initialized.
|
|
551
586
|
*/
|
|
552
587
|
areFontsInitialized(): boolean;
|
|
588
|
+
/**
|
|
589
|
+
* Attach a DOM element to physics. The element will follow the physics body
|
|
590
|
+
* and can have pressure threshold, shadow, and click-to-fall behavior.
|
|
591
|
+
*
|
|
592
|
+
* When the element collapses (becomes dynamic), its CSS transform will be
|
|
593
|
+
* updated each frame to match the physics body position and rotation.
|
|
594
|
+
*
|
|
595
|
+
* Shadow creates a cloned DOM element that stays at the original position.
|
|
596
|
+
*/
|
|
597
|
+
addDOMObstacle(config: DOMObstacleConfig): DOMObstacleResult;
|
|
598
|
+
/**
|
|
599
|
+
* Get the shadow element for a DOM obstacle (available after collapse).
|
|
600
|
+
*/
|
|
601
|
+
getDOMObstacleShadow(id: string): HTMLElement | null;
|
|
553
602
|
/**
|
|
554
603
|
* Create text obstacles from a string. Each character becomes an individual obstacle
|
|
555
604
|
* with shape extracted from the corresponding letter PNG image.
|
|
@@ -639,6 +688,10 @@ declare class OverlayScene {
|
|
|
639
688
|
* Draw TTF glyphs using canvas fillText for clean text rendering
|
|
640
689
|
*/
|
|
641
690
|
private drawTTFGlyphs;
|
|
691
|
+
/**
|
|
692
|
+
* Update a DOM element's CSS transform to match its physics body position and rotation.
|
|
693
|
+
*/
|
|
694
|
+
private updateDOMElementTransform;
|
|
642
695
|
private checkTTLExpiration;
|
|
643
696
|
/** Despawn objects that have fallen below the floor by the configured distance */
|
|
644
697
|
private checkDespawnBelowFloor;
|
|
@@ -697,4 +750,4 @@ declare function measureText(loadedFont: LoadedFont, text: string, fontSize: num
|
|
|
697
750
|
*/
|
|
698
751
|
declare function clearFontCache(): void;
|
|
699
752
|
|
|
700
|
-
export { type BaseEffectConfig, type Bounds, type BurstEffectConfig, type ClickToFallConfig, type ContainerOptions, type DespawnEffectConfig, type DynamicObject, type EffectConfig, type EffectObjectConfig, type EffectType, type FloorConfig, type FontInfo, type FontManifest, type GlyphData, type LoadedFont, type ObjectConfig, OverlayScene, type OverlaySceneConfig, type PressureThresholdConfig, type RainEffectConfig, type ShadowConfig, type ShapeConfig, type ShapePreset, type StreamEffectConfig, type TTFTextObstacleConfig, type TextObstacleConfig, type TextObstacleResult, type UpdateCallback, type UpdateCallbackData, type WeightConfig, clearFontCache, getGlyphData, getKerning, getLogLevel, loadFont, logger, measureText, setLogLevel };
|
|
753
|
+
export { type BaseEffectConfig, type Bounds, type BurstEffectConfig, type ClickToFallConfig, type ContainerOptions, type DOMObstacleConfig, type DOMObstacleResult, type DespawnEffectConfig, type DynamicObject, type EffectConfig, type EffectObjectConfig, type EffectType, type FloorConfig, type FontInfo, type FontManifest, type GlyphData, type LoadedFont, type ObjectConfig, OverlayScene, type OverlaySceneConfig, type PressureThresholdConfig, type RainEffectConfig, type ShadowConfig, type ShapeConfig, type ShapePreset, type StreamEffectConfig, type TTFTextObstacleConfig, type TextObstacleConfig, type TextObstacleResult, type UpdateCallback, type UpdateCallbackData, type WeightConfig, clearFontCache, getGlyphData, getKerning, getLogLevel, loadFont, logger, measureText, setLogLevel };
|
package/dist/index.d.ts
CHANGED
|
@@ -353,6 +353,41 @@ interface TTFTextObstacleConfig {
|
|
|
353
353
|
/** Click to fall config - when set, letters collapse after being clicked N times */
|
|
354
354
|
clickToFall?: ClickToFallConfig;
|
|
355
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* Configuration for attaching a DOM element to physics.
|
|
358
|
+
* The element will follow the physics body and can have pressure/shadow/click behavior.
|
|
359
|
+
*/
|
|
360
|
+
interface DOMObstacleConfig {
|
|
361
|
+
/** The DOM element to attach to physics */
|
|
362
|
+
element: HTMLElement;
|
|
363
|
+
/** X position of the element center */
|
|
364
|
+
x: number;
|
|
365
|
+
/** Y position of the element center */
|
|
366
|
+
y: number;
|
|
367
|
+
/** Width of the collision body (defaults to element.offsetWidth) */
|
|
368
|
+
width?: number;
|
|
369
|
+
/** Height of the collision body (defaults to element.offsetHeight) */
|
|
370
|
+
height?: number;
|
|
371
|
+
/** Tags that define object behavior */
|
|
372
|
+
tags?: string[];
|
|
373
|
+
/** Pressure threshold config - when reached, element collapses */
|
|
374
|
+
pressureThreshold?: PressureThresholdConfig;
|
|
375
|
+
/** Weight for pressure calculation (default: 1) */
|
|
376
|
+
weight?: number;
|
|
377
|
+
/** Shadow config - when enabled, a cloned element remains after collapse */
|
|
378
|
+
shadow?: ShadowConfig;
|
|
379
|
+
/** Click to fall config - when set, element collapses after being clicked N times */
|
|
380
|
+
clickToFall?: ClickToFallConfig;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Result of attaching a DOM element to physics
|
|
384
|
+
*/
|
|
385
|
+
interface DOMObstacleResult {
|
|
386
|
+
/** ID of the created physics object */
|
|
387
|
+
id: string;
|
|
388
|
+
/** The shadow element if shadow was configured (null until collapse) */
|
|
389
|
+
shadowElement: HTMLElement | null;
|
|
390
|
+
}
|
|
356
391
|
/**
|
|
357
392
|
* Information about an available font
|
|
358
393
|
*/
|
|
@@ -550,6 +585,20 @@ declare class OverlayScene {
|
|
|
550
585
|
* Check if fonts have been initialized.
|
|
551
586
|
*/
|
|
552
587
|
areFontsInitialized(): boolean;
|
|
588
|
+
/**
|
|
589
|
+
* Attach a DOM element to physics. The element will follow the physics body
|
|
590
|
+
* and can have pressure threshold, shadow, and click-to-fall behavior.
|
|
591
|
+
*
|
|
592
|
+
* When the element collapses (becomes dynamic), its CSS transform will be
|
|
593
|
+
* updated each frame to match the physics body position and rotation.
|
|
594
|
+
*
|
|
595
|
+
* Shadow creates a cloned DOM element that stays at the original position.
|
|
596
|
+
*/
|
|
597
|
+
addDOMObstacle(config: DOMObstacleConfig): DOMObstacleResult;
|
|
598
|
+
/**
|
|
599
|
+
* Get the shadow element for a DOM obstacle (available after collapse).
|
|
600
|
+
*/
|
|
601
|
+
getDOMObstacleShadow(id: string): HTMLElement | null;
|
|
553
602
|
/**
|
|
554
603
|
* Create text obstacles from a string. Each character becomes an individual obstacle
|
|
555
604
|
* with shape extracted from the corresponding letter PNG image.
|
|
@@ -639,6 +688,10 @@ declare class OverlayScene {
|
|
|
639
688
|
* Draw TTF glyphs using canvas fillText for clean text rendering
|
|
640
689
|
*/
|
|
641
690
|
private drawTTFGlyphs;
|
|
691
|
+
/**
|
|
692
|
+
* Update a DOM element's CSS transform to match its physics body position and rotation.
|
|
693
|
+
*/
|
|
694
|
+
private updateDOMElementTransform;
|
|
642
695
|
private checkTTLExpiration;
|
|
643
696
|
/** Despawn objects that have fallen below the floor by the configured distance */
|
|
644
697
|
private checkDespawnBelowFloor;
|
|
@@ -697,4 +750,4 @@ declare function measureText(loadedFont: LoadedFont, text: string, fontSize: num
|
|
|
697
750
|
*/
|
|
698
751
|
declare function clearFontCache(): void;
|
|
699
752
|
|
|
700
|
-
export { type BaseEffectConfig, type Bounds, type BurstEffectConfig, type ClickToFallConfig, type ContainerOptions, type DespawnEffectConfig, type DynamicObject, type EffectConfig, type EffectObjectConfig, type EffectType, type FloorConfig, type FontInfo, type FontManifest, type GlyphData, type LoadedFont, type ObjectConfig, OverlayScene, type OverlaySceneConfig, type PressureThresholdConfig, type RainEffectConfig, type ShadowConfig, type ShapeConfig, type ShapePreset, type StreamEffectConfig, type TTFTextObstacleConfig, type TextObstacleConfig, type TextObstacleResult, type UpdateCallback, type UpdateCallbackData, type WeightConfig, clearFontCache, getGlyphData, getKerning, getLogLevel, loadFont, logger, measureText, setLogLevel };
|
|
753
|
+
export { type BaseEffectConfig, type Bounds, type BurstEffectConfig, type ClickToFallConfig, type ContainerOptions, type DOMObstacleConfig, type DOMObstacleResult, type DespawnEffectConfig, type DynamicObject, type EffectConfig, type EffectObjectConfig, type EffectType, type FloorConfig, type FontInfo, type FontManifest, type GlyphData, type LoadedFont, type ObjectConfig, OverlayScene, type OverlaySceneConfig, type PressureThresholdConfig, type RainEffectConfig, type ShadowConfig, type ShapeConfig, type ShapePreset, type StreamEffectConfig, type TTFTextObstacleConfig, type TextObstacleConfig, type TextObstacleResult, type UpdateCallback, type UpdateCallbackData, type WeightConfig, clearFontCache, getGlyphData, getKerning, getLogLevel, loadFont, logger, measureText, setLogLevel };
|
package/dist/index.js
CHANGED
|
@@ -1160,6 +1160,9 @@ var OverlayScene = class {
|
|
|
1160
1160
|
if (this.config.wrapHorizontal && entry.tags.includes("falling")) {
|
|
1161
1161
|
wrapHorizontal(entry.body, this.config.bounds);
|
|
1162
1162
|
}
|
|
1163
|
+
if (entry.domElement && entry.tags.includes("falling")) {
|
|
1164
|
+
this.updateDOMElementTransform(entry);
|
|
1165
|
+
}
|
|
1163
1166
|
}
|
|
1164
1167
|
if (!this.config.debug) {
|
|
1165
1168
|
this.drawTTFGlyphs();
|
|
@@ -1194,6 +1197,13 @@ var OverlayScene = class {
|
|
|
1194
1197
|
}
|
|
1195
1198
|
});
|
|
1196
1199
|
Matter5.Composite.add(this.engine.world, this.mouseConstraint);
|
|
1200
|
+
const wheelHandler = this.mouse.mousewheel;
|
|
1201
|
+
if (wheelHandler) {
|
|
1202
|
+
canvas.removeEventListener("mousewheel", wheelHandler);
|
|
1203
|
+
canvas.removeEventListener("DOMMouseScroll", wheelHandler);
|
|
1204
|
+
canvas.removeEventListener("wheel", wheelHandler);
|
|
1205
|
+
}
|
|
1206
|
+
canvas.style.touchAction = "pan-x pan-y";
|
|
1197
1207
|
Matter5.Events.on(this.mouseConstraint, "startdrag", this.handleStartDrag);
|
|
1198
1208
|
canvas.addEventListener("click", this.handleCanvasClick);
|
|
1199
1209
|
this.render.mouse = this.mouse;
|
|
@@ -1447,6 +1457,15 @@ var OverlayScene = class {
|
|
|
1447
1457
|
if (!entry.originalPosition) return;
|
|
1448
1458
|
const opacity = entry.shadow?.opacity ?? 0.3;
|
|
1449
1459
|
const shadowId = `shadow-${entry.id}`;
|
|
1460
|
+
if (entry.domElement) {
|
|
1461
|
+
const shadowElement = entry.domElement.cloneNode(true);
|
|
1462
|
+
shadowElement.style.opacity = String(opacity);
|
|
1463
|
+
shadowElement.style.pointerEvents = "none";
|
|
1464
|
+
shadowElement.style.transform = entry.domOriginalTransform || "";
|
|
1465
|
+
entry.domElement.parentNode?.insertBefore(shadowElement, entry.domElement);
|
|
1466
|
+
entry.domShadowElement = shadowElement;
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1450
1469
|
if (entry.ttfGlyph) {
|
|
1451
1470
|
const body = Matter5.Bodies.circle(entry.originalPosition.x, entry.originalPosition.y, 1, {
|
|
1452
1471
|
isStatic: true,
|
|
@@ -1920,6 +1939,84 @@ var OverlayScene = class {
|
|
|
1920
1939
|
areFontsInitialized() {
|
|
1921
1940
|
return this.fontsInitialized;
|
|
1922
1941
|
}
|
|
1942
|
+
// ==================== DOM OBSTACLE METHODS ====================
|
|
1943
|
+
/**
|
|
1944
|
+
* Attach a DOM element to physics. The element will follow the physics body
|
|
1945
|
+
* and can have pressure threshold, shadow, and click-to-fall behavior.
|
|
1946
|
+
*
|
|
1947
|
+
* When the element collapses (becomes dynamic), its CSS transform will be
|
|
1948
|
+
* updated each frame to match the physics body position and rotation.
|
|
1949
|
+
*
|
|
1950
|
+
* Shadow creates a cloned DOM element that stays at the original position.
|
|
1951
|
+
*/
|
|
1952
|
+
addDOMObstacle(config) {
|
|
1953
|
+
const { element, x, y } = config;
|
|
1954
|
+
const width = config.width ?? element.offsetWidth;
|
|
1955
|
+
const height = config.height ?? element.offsetHeight;
|
|
1956
|
+
const tags = config.tags ?? [];
|
|
1957
|
+
const isStatic = !tags.includes("falling");
|
|
1958
|
+
const body = Matter5.Bodies.rectangle(x, y, width, height, {
|
|
1959
|
+
isStatic,
|
|
1960
|
+
label: `dom-${crypto.randomUUID().slice(0, 8)}`,
|
|
1961
|
+
render: { visible: false }
|
|
1962
|
+
// Don't render the body, DOM element is the visual
|
|
1963
|
+
});
|
|
1964
|
+
const id = body.label;
|
|
1965
|
+
let pressureThreshold;
|
|
1966
|
+
if (config.pressureThreshold) {
|
|
1967
|
+
pressureThreshold = typeof config.pressureThreshold.value === "number" ? config.pressureThreshold.value : config.pressureThreshold.value[0];
|
|
1968
|
+
}
|
|
1969
|
+
const shadow = config.shadow ? { opacity: config.shadow.opacity ?? 0.3 } : void 0;
|
|
1970
|
+
const clicksRemaining = config.clickToFall?.clicks;
|
|
1971
|
+
const originalTransform = element.style.transform || "";
|
|
1972
|
+
element.style.position = "absolute";
|
|
1973
|
+
element.style.transformOrigin = "center center";
|
|
1974
|
+
const entry = {
|
|
1975
|
+
id,
|
|
1976
|
+
body,
|
|
1977
|
+
tags,
|
|
1978
|
+
spawnTime: performance.now(),
|
|
1979
|
+
pressureThreshold,
|
|
1980
|
+
weight: config.weight ?? 1,
|
|
1981
|
+
shadow,
|
|
1982
|
+
originalPosition: shadow || clicksRemaining !== void 0 ? { x, y } : void 0,
|
|
1983
|
+
clicksRemaining,
|
|
1984
|
+
domElement: element,
|
|
1985
|
+
domOriginalTransform: originalTransform
|
|
1986
|
+
};
|
|
1987
|
+
this.objects.set(id, entry);
|
|
1988
|
+
Matter5.Composite.add(this.engine.world, body);
|
|
1989
|
+
if (isStatic && pressureThreshold !== void 0) {
|
|
1990
|
+
this.obstaclePressure.set(id, /* @__PURE__ */ new Set());
|
|
1991
|
+
}
|
|
1992
|
+
if (clicksRemaining !== void 0) {
|
|
1993
|
+
const clickHandler = () => {
|
|
1994
|
+
const currentEntry = this.objects.get(id);
|
|
1995
|
+
if (!currentEntry) return;
|
|
1996
|
+
if (currentEntry.tags.includes("falling")) return;
|
|
1997
|
+
if (currentEntry.clicksRemaining === void 0) return;
|
|
1998
|
+
currentEntry.clicksRemaining--;
|
|
1999
|
+
logger.debug("OverlayScene", `Click on DOM element: ${currentEntry.clicksRemaining} clicks remaining`);
|
|
2000
|
+
if (currentEntry.clicksRemaining <= 0) {
|
|
2001
|
+
this.collapseObstacle(currentEntry);
|
|
2002
|
+
element.removeEventListener("click", clickHandler);
|
|
2003
|
+
}
|
|
2004
|
+
};
|
|
2005
|
+
element.addEventListener("click", clickHandler);
|
|
2006
|
+
}
|
|
2007
|
+
return {
|
|
2008
|
+
id,
|
|
2009
|
+
shadowElement: null
|
|
2010
|
+
// Will be populated on collapse
|
|
2011
|
+
};
|
|
2012
|
+
}
|
|
2013
|
+
/**
|
|
2014
|
+
* Get the shadow element for a DOM obstacle (available after collapse).
|
|
2015
|
+
*/
|
|
2016
|
+
getDOMObstacleShadow(id) {
|
|
2017
|
+
const entry = this.objects.get(id);
|
|
2018
|
+
return entry?.domShadowElement ?? null;
|
|
2019
|
+
}
|
|
1923
2020
|
// ==================== TEXT OBSTACLE METHODS ====================
|
|
1924
2021
|
/**
|
|
1925
2022
|
* Create text obstacles from a string. Each character becomes an individual obstacle
|
|
@@ -2416,6 +2513,22 @@ var OverlayScene = class {
|
|
|
2416
2513
|
ctx.restore();
|
|
2417
2514
|
}
|
|
2418
2515
|
}
|
|
2516
|
+
/**
|
|
2517
|
+
* Update a DOM element's CSS transform to match its physics body position and rotation.
|
|
2518
|
+
*/
|
|
2519
|
+
updateDOMElementTransform(entry) {
|
|
2520
|
+
if (!entry.domElement) return;
|
|
2521
|
+
const body = entry.body;
|
|
2522
|
+
const x = body.position.x;
|
|
2523
|
+
const y = body.position.y;
|
|
2524
|
+
const angle = body.angle;
|
|
2525
|
+
const angleDeg = angle * (180 / Math.PI);
|
|
2526
|
+
const width = entry.domElement.offsetWidth;
|
|
2527
|
+
const height = entry.domElement.offsetHeight;
|
|
2528
|
+
entry.domElement.style.left = `${x - width / 2}px`;
|
|
2529
|
+
entry.domElement.style.top = `${y - height / 2}px`;
|
|
2530
|
+
entry.domElement.style.transform = `rotate(${angleDeg}deg)`;
|
|
2531
|
+
}
|
|
2419
2532
|
checkTTLExpiration() {
|
|
2420
2533
|
const now = performance.now();
|
|
2421
2534
|
const expiredObjects = [];
|