mudlet-map-renderer 2.2.0 → 2.3.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 +28 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.mjs +913 -485
- package/dist/index.mjs.map +1 -1
- package/dist/labelPlacement.d.ts +132 -0
- package/dist/overlay/RippleEffect.d.ts +48 -0
- package/dist/style/index.d.ts +14 -0
- package/dist/style/shape/DarkModernStyle.d.ts +15 -0
- package/dist/style/shape/TreasureMapStyle.d.ts +23 -0
- package/dist/style/shape/index.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Point-feature label placement.
|
|
3
|
+
*
|
|
4
|
+
* Given a set of anchored labels (e.g. waypoints on rooms) and obstacles
|
|
5
|
+
* (rooms, exits, already-placed labels), choose for each label the candidate
|
|
6
|
+
* slot around its anchor that best avoids collisions. Pure and deterministic —
|
|
7
|
+
* the same inputs always produce the same layout — so it's reusable beyond
|
|
8
|
+
* waypoints and easy to test.
|
|
9
|
+
*
|
|
10
|
+
* For each slot the label is scanned outward (up to {@link extend}); the spot
|
|
11
|
+
* with the most CLEARANCE — distance to the nearest room, exit line, or other
|
|
12
|
+
* placed label — wins, lightly penalised by how far it had to push. This puts
|
|
13
|
+
* labels in open space, off every line, and only as far out as openness needs.
|
|
14
|
+
* Positions overlapping a room/label are skipped; sitting on an exit just reads
|
|
15
|
+
* as zero clearance. Cardinal-over-diagonal and an optional preferred direction
|
|
16
|
+
* break ties between equally-open slots.
|
|
17
|
+
*
|
|
18
|
+
* Placement is greedy: items are processed in input order and each placed label
|
|
19
|
+
* becomes an obstacle for the ones after it.
|
|
20
|
+
*/
|
|
21
|
+
export type Direction8 = "n" | "s" | "e" | "w" | "ne" | "nw" | "se" | "sw";
|
|
22
|
+
export interface Rect {
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
}
|
|
28
|
+
/** An obstacle the placement should avoid. `kind` weights how hard to avoid it. */
|
|
29
|
+
export interface Obstacle extends Rect {
|
|
30
|
+
kind?: "room" | "label" | "exit" | string;
|
|
31
|
+
}
|
|
32
|
+
export interface LabelPlacementItem {
|
|
33
|
+
/** Anchor point (e.g. room centre), world coords. */
|
|
34
|
+
x: number;
|
|
35
|
+
y: number;
|
|
36
|
+
/** Label box size, world units. */
|
|
37
|
+
width: number;
|
|
38
|
+
height: number;
|
|
39
|
+
/** Optional preferred direction — nudges the choice, never forces overlap. */
|
|
40
|
+
preferred?: Direction8;
|
|
41
|
+
/** Optional stable id, echoed back on the result. */
|
|
42
|
+
id?: string | number;
|
|
43
|
+
}
|
|
44
|
+
export interface PlacedLabel {
|
|
45
|
+
id?: string | number;
|
|
46
|
+
/** Top-left of the placed label box, world coords. */
|
|
47
|
+
x: number;
|
|
48
|
+
y: number;
|
|
49
|
+
width: number;
|
|
50
|
+
height: number;
|
|
51
|
+
/** Chosen slot. */
|
|
52
|
+
direction: Direction8;
|
|
53
|
+
/** Leader endpoint on the box edge nearest the anchor (for drawing a connector). */
|
|
54
|
+
leader: {
|
|
55
|
+
x: number;
|
|
56
|
+
y: number;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** Per-slot diagnostic from {@link PlaceLabelsOptions.onScored}. */
|
|
60
|
+
export interface SlotScore {
|
|
61
|
+
dir: Direction8;
|
|
62
|
+
/** False when no non-overlapping position exists in this slot. */
|
|
63
|
+
valid: boolean;
|
|
64
|
+
/** Clearance (distance to nearest obstacle) at the best position found. */
|
|
65
|
+
clearance: number;
|
|
66
|
+
/** Outward offset of the best position. */
|
|
67
|
+
off: number;
|
|
68
|
+
/** Final cost (lower = better; Infinity when invalid). */
|
|
69
|
+
cost: number;
|
|
70
|
+
/** The label box at the best position. */
|
|
71
|
+
box: Rect;
|
|
72
|
+
}
|
|
73
|
+
export interface PlaceLabelsOptions {
|
|
74
|
+
/** Gap between the anchor and the near edge of the label box, world units. Default 0.6. */
|
|
75
|
+
offset?: number;
|
|
76
|
+
/** Use only N/S/E/W (4) or all 8 slots. Default 8. */
|
|
77
|
+
slots?: 4 | 8;
|
|
78
|
+
/**
|
|
79
|
+
* How far (world units) a label may be pushed outward along a slot, beyond
|
|
80
|
+
* the base {@link offset}, while searching for the most open spot. 0 keeps
|
|
81
|
+
* labels at the base offset; larger lets them float into open pockets away
|
|
82
|
+
* from rooms/exit lines.
|
|
83
|
+
*/
|
|
84
|
+
extend?: number;
|
|
85
|
+
/**
|
|
86
|
+
* Clearance is only rewarded up to this many world units — past it a spot is
|
|
87
|
+
* "open enough" and extra distance isn't worth pushing further for. Defaults
|
|
88
|
+
* to the label's larger side.
|
|
89
|
+
*/
|
|
90
|
+
clearCap?: number;
|
|
91
|
+
/**
|
|
92
|
+
* When the best slot's clearance is below this (world units), the room is
|
|
93
|
+
* treated as "surrounded": instead of floating out for a marginal gain, the
|
|
94
|
+
* label sits close at the base offset on an exit, preferring north. Default 0
|
|
95
|
+
* (disabled — always go for max clearance).
|
|
96
|
+
*/
|
|
97
|
+
minClearance?: number;
|
|
98
|
+
/**
|
|
99
|
+
* Debug hook — called once per item with the score of every candidate slot
|
|
100
|
+
* and the chosen direction. For visualising/diagnosing placement decisions.
|
|
101
|
+
*/
|
|
102
|
+
onScored?: (item: LabelPlacementItem, slots: SlotScore[], chosen: Direction8) => void;
|
|
103
|
+
/** Cost weights (sane defaults; overlap dominates, then openness, then direction). */
|
|
104
|
+
weights?: Partial<typeof DEFAULT_WEIGHTS>;
|
|
105
|
+
}
|
|
106
|
+
declare const DEFAULT_WEIGHTS: {
|
|
107
|
+
/**
|
|
108
|
+
* Reward per world unit of clearance (distance from the label box to the
|
|
109
|
+
* nearest room/exit/label), capped at {@link PlaceLabelsOptions.clearCap}.
|
|
110
|
+
* The dominant term — pushes labels into open space, off every line.
|
|
111
|
+
*/
|
|
112
|
+
clear: number;
|
|
113
|
+
/**
|
|
114
|
+
* Cardinal-over-diagonal preference — a TRUE tie-break only. Kept tiny so
|
|
115
|
+
* any real clearance advantage (≳0.03 units) overrides it: a clearly more
|
|
116
|
+
* open diagonal always beats an on-a-line cardinal.
|
|
117
|
+
*/
|
|
118
|
+
diagonal: number;
|
|
119
|
+
/** Bonus (subtracted from cost) when a slot matches the item's preferred direction. */
|
|
120
|
+
preferred: number;
|
|
121
|
+
/**
|
|
122
|
+
* Penalty per world unit the label is pushed out — keeps it close, but small
|
|
123
|
+
* enough not to cancel the clearance gained by pushing into open space.
|
|
124
|
+
*/
|
|
125
|
+
distance: number;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Place each item at its best-scoring slot. Returns one {@link PlacedLabel} per
|
|
129
|
+
* input item, in the same order.
|
|
130
|
+
*/
|
|
131
|
+
export declare function placeLabels(items: LabelPlacementItem[], obstacles: Obstacle[], options?: PlaceLabelsOptions): PlacedLabel[];
|
|
132
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { default as Konva } from 'konva';
|
|
2
|
+
import { CoordinateTransform, LiveEffect } from './LiveEffect';
|
|
3
|
+
import { ViewportBounds } from '../types/Settings';
|
|
4
|
+
export interface RippleOptions {
|
|
5
|
+
/** Animation length in milliseconds. Default 400. */
|
|
6
|
+
duration?: number;
|
|
7
|
+
/** Ring colour (any CSS colour). Default "#00e5b2". */
|
|
8
|
+
color?: string;
|
|
9
|
+
/** Starting ring radius in world units. Default 0.3. */
|
|
10
|
+
startRadius?: number;
|
|
11
|
+
/** Final ring radius in world units. Default 1.2. */
|
|
12
|
+
endRadius?: number;
|
|
13
|
+
/** Ring stroke width in world units. Default 0.08. */
|
|
14
|
+
strokeWidth?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Invoked once when the animation finishes. The host should use this to
|
|
17
|
+
* remove the (now spent) effect, e.g. `removeLiveEffect(id)`.
|
|
18
|
+
*/
|
|
19
|
+
onComplete?: () => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* One-shot expanding, fading ring centred on a world-space point — used to
|
|
23
|
+
* pulse the player marker when it moves. Implements {@link LiveEffect}, so it
|
|
24
|
+
* works on both the Konva and OffscreenCanvas backends (the latter composites
|
|
25
|
+
* it on its main-thread effect stage).
|
|
26
|
+
*
|
|
27
|
+
* The ring lives in scene space (the host layer carries the camera transform),
|
|
28
|
+
* so it tracks the map as the user pans/zooms. It self-animates and calls
|
|
29
|
+
* {@link RippleOptions.onComplete} when done.
|
|
30
|
+
*/
|
|
31
|
+
export declare class RippleEffect implements LiveEffect {
|
|
32
|
+
private readonly worldX;
|
|
33
|
+
private readonly worldY;
|
|
34
|
+
private ring?;
|
|
35
|
+
private rafId?;
|
|
36
|
+
private cancelled;
|
|
37
|
+
private transform;
|
|
38
|
+
private readonly duration;
|
|
39
|
+
private readonly color;
|
|
40
|
+
private readonly startRadius;
|
|
41
|
+
private readonly endRadius;
|
|
42
|
+
private readonly strokeWidth;
|
|
43
|
+
private readonly onComplete?;
|
|
44
|
+
constructor(worldX: number, worldY: number, options?: RippleOptions);
|
|
45
|
+
attach(layer: Konva.Layer): void;
|
|
46
|
+
updateViewport(_bounds: ViewportBounds, _scale: number, coordinateTransform: CoordinateTransform): void;
|
|
47
|
+
destroy(): void;
|
|
48
|
+
}
|
package/dist/style/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { SketchyOptions } from './shape/SketchyStyle';
|
|
|
3
3
|
import { IsometricOptions, IsometricRotation } from './shape/IsometricStyle';
|
|
4
4
|
import { GradientRoomsOptions } from './shape/GradientRoomsStyle';
|
|
5
5
|
import { WatercolorOptions } from './shape/WatercolorStyle';
|
|
6
|
+
import { treasureMapDecorations } from './shape/TreasureMapStyle';
|
|
6
7
|
export { compose, identityStyle } from './Style';
|
|
7
8
|
export type { Style, StyleContext } from './Style';
|
|
8
9
|
export { applyStyleToShapes } from './applyStyle';
|
|
@@ -34,4 +35,17 @@ export declare const GraphPaper: Style;
|
|
|
34
35
|
export declare const Topographic: Style;
|
|
35
36
|
/** Hand-painted watercolour — translucent edge-bled washes that pool on overlap. */
|
|
36
37
|
export declare function Watercolor(options?: WatercolorOptions): Style;
|
|
38
|
+
/** Flat dark "modern UI" theme — muted dark rooms with subtle elevation shadows. */
|
|
39
|
+
export declare const DarkModern: Style;
|
|
40
|
+
/**
|
|
41
|
+
* Aged treasure-map palette — weathered-paper rooms inked in faded brown.
|
|
42
|
+
* Pair with {@link treasureMapDecorations} (a scene overlay) for the compass
|
|
43
|
+
* rose and double border frame:
|
|
44
|
+
* ```ts
|
|
45
|
+
* renderer.setStyle(TreasureMap);
|
|
46
|
+
* renderer.addSceneOverlay('treasure-decor', treasureMapDecorations());
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare const TreasureMap: Style;
|
|
50
|
+
export { treasureMapDecorations };
|
|
37
51
|
export type { SketchyOptions, IsometricOptions, IsometricRotation, GradientRoomsOptions, WatercolorOptions };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Style } from '../Style';
|
|
2
|
+
/**
|
|
3
|
+
* Flat dark "modern UI" aesthetic as a {@link Style}.
|
|
4
|
+
*
|
|
5
|
+
* - Room fills are flattened into a muted dark palette (hue kept, saturation
|
|
6
|
+
* capped, lightness compressed) so the map reads as a calm dark dashboard.
|
|
7
|
+
* - Room outlines become a subtle translucent light border.
|
|
8
|
+
* - Each room body casts a soft offset drop-shadow (emitted **before** the
|
|
9
|
+
* body, like Neon's glow, so it renders underneath) for a sense of
|
|
10
|
+
* elevation.
|
|
11
|
+
* - Exit lines become a muted grey-blue; text is off-white.
|
|
12
|
+
* - Images and groups pass through unchanged (the caller walks group
|
|
13
|
+
* children separately).
|
|
14
|
+
*/
|
|
15
|
+
export declare const darkModernShapeStyle: Style;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Style } from '../Style';
|
|
2
|
+
import { SceneOverlay } from '../../overlay/SceneOverlay';
|
|
3
|
+
/**
|
|
4
|
+
* Aged treasure-map palette as a {@link Style}.
|
|
5
|
+
*
|
|
6
|
+
* Recolours rooms onto a warm weathered-paper ramp and inks every line in
|
|
7
|
+
* faded brown. For the decorative compass rose and double border frame, add
|
|
8
|
+
* {@link treasureMapDecorations} as a scene overlay alongside this style.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* renderer.setStyle(TreasureMap);
|
|
12
|
+
* renderer.addSceneOverlay('treasure-decor', treasureMapDecorations());
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare const treasureMapShapeStyle: Style;
|
|
16
|
+
/**
|
|
17
|
+
* Decorative scene overlay for the treasure-map look: a double-line border
|
|
18
|
+
* frame inset from the viewport and a compass rose in the top-right corner.
|
|
19
|
+
*
|
|
20
|
+
* Emitted in world space and pinned to the current viewport, so it tracks the
|
|
21
|
+
* visible region as the user pans/zooms and appears in every export path.
|
|
22
|
+
*/
|
|
23
|
+
export declare function treasureMapDecorations(): SceneOverlay;
|
|
@@ -30,3 +30,5 @@ export { graphPaperShapeStyle } from './GraphPaperStyle';
|
|
|
30
30
|
export { topographicShapeStyle } from './TopographicStyle';
|
|
31
31
|
export { watercolorShapeStyle } from './WatercolorStyle';
|
|
32
32
|
export type { WatercolorOptions } from './WatercolorStyle';
|
|
33
|
+
export { darkModernShapeStyle } from './DarkModernStyle';
|
|
34
|
+
export { treasureMapShapeStyle, treasureMapDecorations } from './TreasureMapStyle';
|