mudlet-map-renderer 0.43.0-konva → 1.1.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 +520 -522
- package/dist/AreaMapRenderer.d.ts +2 -2
- package/dist/ExitRenderer.d.ts +5 -5
- package/dist/MapGraph.d.ts +2 -2
- package/dist/MapReader-mU_4JWv_.js +224 -0
- package/dist/MapReader-mU_4JWv_.js.map +1 -0
- package/dist/MapState.d.ts +15 -9
- package/dist/PathData.d.ts +2 -2
- package/dist/PathFinder.d.ts +2 -2
- package/dist/ScenePipeline.d.ts +19 -6
- package/dist/binary/BinaryMapReader.d.ts +36 -0
- package/dist/binary/index.d.ts +2 -0
- package/dist/binary.mjs +34 -0
- package/dist/binary.mjs.map +1 -0
- package/dist/index.d.ts +13 -3
- package/dist/index.mjs +1086 -1147
- package/dist/index.mjs.map +1 -1
- package/dist/lens/ExplorationLens.d.ts +29 -0
- package/dist/lens/RoomLens.d.ts +47 -0
- package/dist/lens/composeLenses.d.ts +31 -0
- package/dist/lens/index.d.ts +5 -0
- package/dist/overlay/LiveEffect.d.ts +33 -0
- package/dist/overlay/SceneOverlay.d.ts +18 -89
- package/dist/reader/Area.d.ts +40 -4
- package/dist/reader/Exit.d.ts +4 -1
- package/dist/reader/MapReader.d.ts +23 -17
- package/dist/reader/Plane.d.ts +19 -1
- package/dist/rendering/KonvaRenderBackend.d.ts +4 -8
- package/dist/rendering/MapRenderer.d.ts +31 -7
- package/dist/rendering/SceneManager.d.ts +7 -6
- package/dist/scene/InnerExitStyle.d.ts +2 -2
- package/dist/scene/OverlayStyle.d.ts +8 -4
- package/dist/scene/RoomStyle.d.ts +2 -2
- package/dist/scene/elements/ExitLayout.d.ts +2 -2
- package/dist/scene/elements/RoomLayout.d.ts +2 -2
- package/dist/types/Settings.d.ts +44 -0
- package/dist/utils/color.d.ts +9 -1
- package/package.json +17 -1
- package/dist/reader/ExplorationArea.d.ts +0 -32
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { RoomLens } from './RoomLens';
|
|
2
|
+
/**
|
|
3
|
+
* Fog-of-war lens: rooms render only when their id is in the visited set.
|
|
4
|
+
*
|
|
5
|
+
* Default exit treatment is left to {@link RoomLens}'s built-in derivation
|
|
6
|
+
* (both visible → full, one visible → stub, neither → hidden), which produces
|
|
7
|
+
* the "explored frontier" look without any extra wiring.
|
|
8
|
+
*
|
|
9
|
+
* Mutations bump {@link getVersion} so a composing renderer can detect the
|
|
10
|
+
* change; the renderer still needs an explicit `refresh()` after mutation —
|
|
11
|
+
* the lens doesn't emit events.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ExplorationLens implements RoomLens {
|
|
14
|
+
private readonly visited;
|
|
15
|
+
private version;
|
|
16
|
+
constructor(visited?: Iterable<number>);
|
|
17
|
+
isVisible(room: MapData.Room): boolean;
|
|
18
|
+
getVersion(): number;
|
|
19
|
+
hasVisited(roomId: number): boolean;
|
|
20
|
+
getVisitedRoomIds(): number[];
|
|
21
|
+
getVisitedCount(): number;
|
|
22
|
+
/** Returns true if the room was newly added. */
|
|
23
|
+
addVisited(roomId: number): boolean;
|
|
24
|
+
/** Returns the number of newly added rooms. */
|
|
25
|
+
addVisitedAll(roomIds: Iterable<number>): number;
|
|
26
|
+
/** Replace the visited set wholesale. */
|
|
27
|
+
setVisited(roomIds: Iterable<number>): void;
|
|
28
|
+
clear(): void;
|
|
29
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { default as IExit } from '../reader/Exit';
|
|
2
|
+
/**
|
|
3
|
+
* How the renderer should treat an exit whose endpoints are not both visible.
|
|
4
|
+
*
|
|
5
|
+
* - `"full"` — draw the exit normally (both endpoints are visible, or the
|
|
6
|
+
* lens overrides the default and wants the full line anyway).
|
|
7
|
+
* - `"stub"` — draw only a short stub leaving the visible endpoint; the
|
|
8
|
+
* far end isn't shown. This is the "explored frontier" look.
|
|
9
|
+
* - `"hidden"` — don't draw the exit at all.
|
|
10
|
+
*
|
|
11
|
+
* Cross-area exits (rooms in different `area` ids) are an orthogonal concept
|
|
12
|
+
* decided by raw room data, not by the lens. A lens that returns `"full"` for
|
|
13
|
+
* a cross-area exit still gets the cross-area arrow treatment.
|
|
14
|
+
*/
|
|
15
|
+
export type ExitTreatment = "full" | "stub" | "hidden";
|
|
16
|
+
/**
|
|
17
|
+
* Visibility filter applied during scene build.
|
|
18
|
+
*
|
|
19
|
+
* `IArea` / `IPlane` / `IMapReader` are pure data — they return every room and
|
|
20
|
+
* every link exit the underlying map defines. The lens decides which of those
|
|
21
|
+
* actually paint, and (optionally) how partially-visible exits should be
|
|
22
|
+
* stubbed or hidden. Multiple concerns (exploration, guild scope, quest
|
|
23
|
+
* overlay, …) compose through {@link composeLenses}.
|
|
24
|
+
*/
|
|
25
|
+
export interface RoomLens {
|
|
26
|
+
isVisible(room: MapData.Room): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Decide how an exit between `a` and `b` should be drawn.
|
|
29
|
+
*
|
|
30
|
+
* Optional — when omitted, treatment is derived from endpoint visibility:
|
|
31
|
+
* both visible → `"full"`, one visible → `"stub"`, neither → `"hidden"`.
|
|
32
|
+
*/
|
|
33
|
+
getExitTreatment?(exit: IExit, a: MapData.Room, b: MapData.Room): ExitTreatment;
|
|
34
|
+
/**
|
|
35
|
+
* Monotonically increasing version. The renderer caches the value from the
|
|
36
|
+
* last build and rebuilds when it changes. Mutations on a stateful lens
|
|
37
|
+
* (e.g. {@link ExplorationLens.addVisited}) bump this; callers that mutate
|
|
38
|
+
* the lens still call `renderer.refresh()` explicitly.
|
|
39
|
+
*/
|
|
40
|
+
getVersion(): number;
|
|
41
|
+
}
|
|
42
|
+
export declare const ALL_VISIBLE: RoomLens;
|
|
43
|
+
/**
|
|
44
|
+
* Default treatment when no lens supplies `getExitTreatment`: derive purely
|
|
45
|
+
* from endpoint visibility.
|
|
46
|
+
*/
|
|
47
|
+
export declare function defaultExitTreatment(lens: RoomLens, _exit: IExit, a: MapData.Room, b: MapData.Room): ExitTreatment;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { RoomLens } from './RoomLens';
|
|
2
|
+
/**
|
|
3
|
+
* How a composite lens reconciles disagreeing children when both expose
|
|
4
|
+
* `getExitTreatment`.
|
|
5
|
+
*
|
|
6
|
+
* - `"most-restrictive"` (default): `hidden` > `stub` > `full`. A single
|
|
7
|
+
* child that says hide wins. Safe default for stacked visibility filters.
|
|
8
|
+
* - `"least-restrictive"`: `full` > `stub` > `hidden`. Useful when lenses are
|
|
9
|
+
* additive scopes ("show guild rooms OR quest rooms").
|
|
10
|
+
* - `"first"`: the first child whose `getExitTreatment` returns non-undefined
|
|
11
|
+
* decides. Lets the caller pick a dominant lens by ordering.
|
|
12
|
+
*/
|
|
13
|
+
export type ExitConflictStrategy = "most-restrictive" | "least-restrictive" | "first";
|
|
14
|
+
export type ComposeOptions = {
|
|
15
|
+
/** Defaults to `"most-restrictive"`. */
|
|
16
|
+
exitStrategy?: ExitConflictStrategy;
|
|
17
|
+
/**
|
|
18
|
+
* AND (visibility must hold in every lens) vs OR (any lens may grant
|
|
19
|
+
* visibility). Defaults to `"and"` — restrictive intersection.
|
|
20
|
+
*/
|
|
21
|
+
visibility?: "and" | "or";
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Combine multiple lenses into one. Visibility uses AND by default (a room
|
|
25
|
+
* must pass every lens to render); exit treatment uses most-restrictive when
|
|
26
|
+
* children disagree. Both behaviours are configurable via {@link ComposeOptions}.
|
|
27
|
+
*
|
|
28
|
+
* Composing zero lenses returns a no-op equivalent to `ALL_VISIBLE`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function composeLenses(...lenses: RoomLens[]): RoomLens;
|
|
31
|
+
export declare function composeLenses(options: ComposeOptions, ...lenses: RoomLens[]): RoomLens;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { RoomLens, ExitTreatment } from './RoomLens';
|
|
2
|
+
export { ALL_VISIBLE, defaultExitTreatment } from './RoomLens';
|
|
3
|
+
export { composeLenses } from './composeLenses';
|
|
4
|
+
export type { ComposeOptions, ExitConflictStrategy } from './composeLenses';
|
|
5
|
+
export { ExplorationLens } from './ExplorationLens';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { default as Konva } from 'konva';
|
|
2
|
+
import { ViewportBounds } from '../types/Settings';
|
|
3
|
+
/** Map-space → render-space coordinate transform. */
|
|
4
|
+
export type CoordinateTransform = (x: number, y: number) => {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Interactive-only animated effect. A {@link LiveEffect} receives a live Konva
|
|
10
|
+
* layer and viewport updates so it can react to pan/zoom and run its own
|
|
11
|
+
* animation loop.
|
|
12
|
+
*
|
|
13
|
+
* Exporters (SVG, PNG, PDF, …) skip `LiveEffect`s by design — use
|
|
14
|
+
* `SceneOverlay` when you need an overlay to appear in exports.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* class PulseEffect implements LiveEffect {
|
|
18
|
+
* private shape?: Konva.Shape;
|
|
19
|
+
* attach(layer: Konva.Layer) {
|
|
20
|
+
* this.shape = new Konva.Shape({ sceneFunc: (ctx) => { ... } });
|
|
21
|
+
* layer.add(this.shape);
|
|
22
|
+
* }
|
|
23
|
+
* updateViewport(bounds, scale) { ... }
|
|
24
|
+
* destroy() { this.shape?.destroy(); }
|
|
25
|
+
* }
|
|
26
|
+
* renderer.konvaBackend?.addLiveEffect('pulse', new PulseEffect());
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export interface LiveEffect {
|
|
30
|
+
attach(layer: Konva.Layer): void;
|
|
31
|
+
updateViewport(bounds: ViewportBounds, scale: number, coordinateTransform: CoordinateTransform): void;
|
|
32
|
+
destroy(): void;
|
|
33
|
+
}
|
|
@@ -1,35 +1,6 @@
|
|
|
1
1
|
import { MapState } from '../MapState';
|
|
2
2
|
import { ViewportBounds } from '../types/Settings';
|
|
3
3
|
import { Shape } from '../scene/Shape';
|
|
4
|
-
/**
|
|
5
|
-
* State passed to {@link SceneOverlay.draw} on every repaint. Contains
|
|
6
|
-
* everything needed to draw in world-space or screen-space without holding
|
|
7
|
-
* any Konva references.
|
|
8
|
-
*/
|
|
9
|
-
export interface CanvasDrawState {
|
|
10
|
-
/** Current viewport in world coordinates. */
|
|
11
|
-
bounds: ViewportBounds;
|
|
12
|
-
/** Current zoom scale (world units → canvas pixels). */
|
|
13
|
-
scale: number;
|
|
14
|
-
/** World → scene coordinate transform (identity for flat styles, isometric for IsometricBackend). */
|
|
15
|
-
coordinateTransform: (x: number, y: number) => {
|
|
16
|
-
x: number;
|
|
17
|
-
y: number;
|
|
18
|
-
};
|
|
19
|
-
/** Canvas element width in CSS pixels. */
|
|
20
|
-
canvasWidth: number;
|
|
21
|
-
/** Canvas element height in CSS pixels. */
|
|
22
|
-
canvasHeight: number;
|
|
23
|
-
/**
|
|
24
|
-
* Stage offset in CSS pixels. Together with `scale` this lets you convert
|
|
25
|
-
* a world point to screen coordinates:
|
|
26
|
-
* screenX = worldX * scale + canvasOffset.x
|
|
27
|
-
*/
|
|
28
|
-
canvasOffset: {
|
|
29
|
-
x: number;
|
|
30
|
-
y: number;
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
4
|
/**
|
|
34
5
|
* Context handed to a {@link SceneOverlay} when it is registered. Gives the
|
|
35
6
|
* overlay access to {@link MapState} events, viewport changes, and a way to
|
|
@@ -44,60 +15,31 @@ export interface SceneOverlayContext {
|
|
|
44
15
|
onViewportChange(cb: () => void): () => void;
|
|
45
16
|
/** Request a re-render of this overlay only. Cheap — no full scene rebuild. */
|
|
46
17
|
invalidate(): void;
|
|
47
|
-
/**
|
|
48
|
-
* Register a per-frame callback driven by the backend's animation loop.
|
|
49
|
-
* `dt` is elapsed seconds since the last frame (capped at 0.1 s).
|
|
50
|
-
* The backend repaints the overlay layer after all registered callbacks
|
|
51
|
-
* fire each frame.
|
|
52
|
-
*
|
|
53
|
-
* Returns an unsubscribe function — call it from {@link SceneOverlay.detach}.
|
|
54
|
-
*/
|
|
55
|
-
onFrame(cb: (dt: number) => void): () => void;
|
|
56
18
|
}
|
|
57
19
|
/**
|
|
58
|
-
* Target-agnostic overlay. A {@link SceneOverlay} contributes geometry
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* - **{@link render}** — emits {@link Shape} descriptors. Shapes are converted to
|
|
63
|
-
* recording nodes and appear in every output path: interactive canvas, SVG
|
|
64
|
-
* export, PNG export, and any future {@link Exporter}.
|
|
20
|
+
* Target-agnostic overlay. A {@link SceneOverlay} contributes static geometry
|
|
21
|
+
* to the scene by emitting one or more {@link Shape}s, so it renders in every
|
|
22
|
+
* output path: interactive canvas, SVG export, PNG export, and any future
|
|
23
|
+
* {@link Exporter}.
|
|
65
24
|
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* skip `draw()` overlays (same behaviour as the former `LiveEffect`).
|
|
70
|
-
*
|
|
71
|
-
* Overlays opt into reactivity via {@link attach}: subscribe to MapState or
|
|
72
|
-
* viewport events, use {@link SceneOverlayContext.onFrame} for animation, then
|
|
73
|
-
* call `ctx.invalidate()` for data-driven repaints.
|
|
25
|
+
* Overlays may opt into reactivity via {@link attach}: subscribe to MapState or
|
|
26
|
+
* viewport events, then call `ctx.invalidate()` to re-render. Exporters skip
|
|
27
|
+
* `attach`/`detach` — they just call {@link render} once.
|
|
74
28
|
*
|
|
75
29
|
* ```ts
|
|
76
|
-
* // Shape-based (appears in exports)
|
|
77
30
|
* class BadgeOverlay implements SceneOverlay {
|
|
78
|
-
* render(state, bounds) {
|
|
79
|
-
* return {
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* attach(ctx) {
|
|
87
|
-
* this.unsub = ctx.onFrame((dt) => { this.t += dt; });
|
|
88
|
-
* }
|
|
89
|
-
* detach() { this.unsub?.(); }
|
|
90
|
-
* draw(ctx, state) {
|
|
91
|
-
* const alpha = 0.5 + 0.5 * Math.sin(this.t * 3);
|
|
92
|
-
* ctx.save(); ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
93
|
-
* ctx.globalAlpha = alpha;
|
|
94
|
-
* // ...
|
|
95
|
-
* ctx.restore();
|
|
31
|
+
* render(state: MapState, bounds: ViewportBounds): Shape {
|
|
32
|
+
* return {
|
|
33
|
+
* type: 'circle',
|
|
34
|
+
* cx: 5, cy: 5,
|
|
35
|
+
* radius: 0.4,
|
|
36
|
+
* paint: { fill: '#ff0' },
|
|
37
|
+
* layer: 'overlay',
|
|
38
|
+
* };
|
|
96
39
|
* }
|
|
97
40
|
* }
|
|
98
41
|
*
|
|
99
42
|
* renderer.addSceneOverlay('badge', new BadgeOverlay());
|
|
100
|
-
* renderer.addSceneOverlay('pulse', new PulseOverlay());
|
|
101
43
|
* ```
|
|
102
44
|
*/
|
|
103
45
|
export interface SceneOverlay {
|
|
@@ -115,25 +57,12 @@ export interface SceneOverlay {
|
|
|
115
57
|
*/
|
|
116
58
|
detach?(): void;
|
|
117
59
|
/**
|
|
118
|
-
* Contribute
|
|
119
|
-
*
|
|
60
|
+
* Contribute geometry to the scene. Called on register, on invalidate, and
|
|
61
|
+
* by every exporter.
|
|
120
62
|
*
|
|
121
63
|
* @returns one or more world-space {@link Shape}s, or `void` to emit
|
|
122
64
|
* nothing this frame. Shapes carry their own {@link Shape.layer} hint;
|
|
123
65
|
* leaving it unset routes them to the overlay layer.
|
|
124
66
|
*/
|
|
125
|
-
render
|
|
126
|
-
/**
|
|
127
|
-
* Draw directly onto the canvas using the provided `CanvasRenderingContext2D`.
|
|
128
|
-
* Called on every repaint of the overlay layer (including every animation
|
|
129
|
-
* frame when {@link SceneOverlayContext.onFrame} is in use).
|
|
130
|
-
*
|
|
131
|
-
* The context already has the stage transform applied (world-space drawing
|
|
132
|
-
* works at face value). Reset with `ctx.setTransform(1,0,0,1,0,0)` to
|
|
133
|
-
* draw in screen space.
|
|
134
|
-
*
|
|
135
|
-
* Exporters skip `draw()` overlays — use {@link render} for geometry that
|
|
136
|
-
* must appear in SVG/PNG exports.
|
|
137
|
-
*/
|
|
138
|
-
draw?(ctx: CanvasRenderingContext2D, state: CanvasDrawState): void;
|
|
67
|
+
render(state: MapState, bounds: ViewportBounds): Shape | Shape[] | void;
|
|
139
68
|
}
|
package/dist/reader/Area.d.ts
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
|
-
import { default as Plane } from './Plane';
|
|
2
|
-
import { default as
|
|
3
|
-
|
|
1
|
+
import { default as Plane, IPlane } from './Plane';
|
|
2
|
+
import { default as IExit } from './Exit';
|
|
3
|
+
/**
|
|
4
|
+
* Public, renderer-facing surface of an area. The renderer never inspects
|
|
5
|
+
* private state of {@link Area}; it talks to this interface only. Custom data
|
|
6
|
+
* models (e.g. an app that owns its own room store) can satisfy `IArea` and
|
|
7
|
+
* hand the result to {@link MapRenderer} without subclassing.
|
|
8
|
+
*
|
|
9
|
+
* Mutability lives on the concrete implementation: {@link Area.markDirty} is
|
|
10
|
+
* `protected`, kept off the public interface. Consumers signal "redraw me" by
|
|
11
|
+
* bumping {@link getVersion}; the renderer reads the version to decide
|
|
12
|
+
* whether to rebuild.
|
|
13
|
+
*/
|
|
14
|
+
export interface IArea {
|
|
15
|
+
getAreaName(): string;
|
|
16
|
+
getAreaId(): number;
|
|
17
|
+
/**
|
|
18
|
+
* Monotonically increasing version. The renderer compares the value it
|
|
19
|
+
* cached on the last build against the current value to decide whether
|
|
20
|
+
* the area needs a rebuild.
|
|
21
|
+
*/
|
|
22
|
+
getVersion(): number;
|
|
23
|
+
getPlane(zIndex: number): IPlane;
|
|
24
|
+
getPlanes(): IPlane[];
|
|
25
|
+
getZLevels(): number[];
|
|
26
|
+
getRooms(): MapData.Room[];
|
|
27
|
+
getFullBounds(): {
|
|
28
|
+
minX: number;
|
|
29
|
+
maxX: number;
|
|
30
|
+
minY: number;
|
|
31
|
+
maxY: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Inter-room exits drawn on the given z-level. Each exit is bidirectional
|
|
35
|
+
* with optional one-way fallback; see {@link IExit}.
|
|
36
|
+
*/
|
|
37
|
+
getLinkExits(zIndex: number): IExit[];
|
|
38
|
+
}
|
|
39
|
+
export default class Area implements IArea {
|
|
4
40
|
private readonly planes;
|
|
5
41
|
private readonly area;
|
|
6
42
|
private readonly exits;
|
|
@@ -20,7 +56,7 @@ export default class Area {
|
|
|
20
56
|
minY: number;
|
|
21
57
|
maxY: number;
|
|
22
58
|
};
|
|
23
|
-
getLinkExits(zIndex: number):
|
|
59
|
+
getLinkExits(zIndex: number): IExit[];
|
|
24
60
|
private createPlanes;
|
|
25
61
|
private static readonly oppositeDir;
|
|
26
62
|
private createExits;
|
package/dist/reader/Exit.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type Kind = "exit" | "specialExit";
|
|
2
|
-
export default interface
|
|
2
|
+
export default interface IExit {
|
|
3
3
|
a: number;
|
|
4
4
|
b: number;
|
|
5
5
|
aDir?: MapData.direction;
|
|
@@ -7,6 +7,9 @@ export default interface Exit {
|
|
|
7
7
|
kind?: Kind;
|
|
8
8
|
zIndex: number[];
|
|
9
9
|
}
|
|
10
|
+
export type { IExit };
|
|
11
|
+
/** @deprecated Use {@link IExit}. Retained as a structural alias for backwards compatibility. */
|
|
12
|
+
export type Exit = IExit;
|
|
10
13
|
export declare const regularExits: MapData.direction[];
|
|
11
14
|
export declare const shortTolong: Record<string, MapData.direction>;
|
|
12
15
|
export declare const longToShort: Record<MapData.direction, string>;
|
|
@@ -1,28 +1,34 @@
|
|
|
1
|
-
import { default as Area } from './Area';
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { default as Area, IArea } from './Area';
|
|
2
|
+
/**
|
|
3
|
+
* Public, renderer-facing surface for map data. Everything the renderer
|
|
4
|
+
* (and other library consumers) call on `MapReader` is on this interface —
|
|
5
|
+
* private state and internal helpers are not.
|
|
6
|
+
*
|
|
7
|
+
* Downstream apps with their own room/area store can implement `IMapReader`
|
|
8
|
+
* directly (no need to subclass {@link MapReader}) and hand the result to
|
|
9
|
+
* {@link MapRenderer}. Visibility filtering (exploration, scope overlays,
|
|
10
|
+
* etc.) lives on the renderer's lens — it is intentionally not on this
|
|
11
|
+
* interface.
|
|
12
|
+
*/
|
|
13
|
+
export interface IMapReader {
|
|
14
|
+
getArea(areaId: number): IArea;
|
|
15
|
+
getAreas(): IArea[];
|
|
16
|
+
getRooms(): MapData.Room[];
|
|
17
|
+
getRoom(roomId: number): MapData.Room;
|
|
18
|
+
/** Returns the env's `rgb(r,g,b)` string, or a default colour if the env id is unknown. */
|
|
19
|
+
getColorValue(envId: number): string;
|
|
20
|
+
/** Returns a contrasting symbol colour for the env, optionally with the given alpha. */
|
|
21
|
+
getSymbolColor(envId: number, opacity?: number): string;
|
|
22
|
+
}
|
|
23
|
+
export default class MapReader implements IMapReader {
|
|
4
24
|
private rooms;
|
|
5
25
|
private areas;
|
|
6
|
-
private areaSources;
|
|
7
|
-
private visitedRooms?;
|
|
8
|
-
private explorationEnabled;
|
|
9
26
|
private colors;
|
|
10
27
|
constructor(map: MapData.Map, envs: MapData.Env[]);
|
|
11
28
|
getArea(areaId: number): Area;
|
|
12
|
-
getExplorationArea(areaId: number): ExplorationArea | undefined;
|
|
13
29
|
getAreas(): Area[];
|
|
14
30
|
getRooms(): MapData.Room[];
|
|
15
31
|
getRoom(roomId: number): MapData.Room;
|
|
16
|
-
private ensureVisitedRooms;
|
|
17
|
-
private applyExplorationDecoration;
|
|
18
|
-
decorateWithExploration(visitedRooms?: Iterable<number> | Set<number>): Set<number> | undefined;
|
|
19
|
-
getVisitedRooms(): Set<number> | undefined;
|
|
20
|
-
clearExplorationDecoration(): void;
|
|
21
|
-
isExplorationEnabled(): boolean;
|
|
22
|
-
setVisitedRooms(visitedRooms: Iterable<number> | Set<number>): Set<number>;
|
|
23
|
-
addVisitedRoom(roomId: number): boolean;
|
|
24
|
-
addVisitedRooms(roomIds: Iterable<number>): number;
|
|
25
|
-
hasVisitedRoom(roomId: number): boolean;
|
|
26
32
|
getColorValue(envId: number): string;
|
|
27
33
|
getSymbolColor(envId: number, opacity?: number): string;
|
|
28
34
|
}
|
package/dist/reader/Plane.d.ts
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Public, renderer-facing surface of a z-level slice of an area.
|
|
3
|
+
*
|
|
4
|
+
* The renderer (and other library consumers) only depend on this interface;
|
|
5
|
+
* the concrete {@link Plane} class is one implementation of it. Downstream
|
|
6
|
+
* apps that want to drive the renderer from their own data model can hand it
|
|
7
|
+
* any `IPlane`-shaped object (typically returned from an {@link IArea}).
|
|
8
|
+
*/
|
|
9
|
+
export interface IPlane {
|
|
10
|
+
getRooms(): MapData.Room[];
|
|
11
|
+
getLabels(): MapData.Label[];
|
|
12
|
+
getBounds(): {
|
|
13
|
+
minX: number;
|
|
14
|
+
maxX: number;
|
|
15
|
+
minY: number;
|
|
16
|
+
maxY: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export default class Plane implements IPlane {
|
|
2
20
|
private readonly bounds;
|
|
3
21
|
private readonly rooms;
|
|
4
22
|
private readonly labels;
|
|
@@ -7,6 +7,7 @@ import { CullingManager } from '../CullingManager';
|
|
|
7
7
|
import { TypedEventEmitter } from '../TypedEventEmitter';
|
|
8
8
|
import { InteractiveBackend } from './MapRenderer';
|
|
9
9
|
import { CoordFn } from '../coord/CoordFn';
|
|
10
|
+
import { LiveEffect } from '../overlay/LiveEffect';
|
|
10
11
|
import { SceneOverlay } from '../overlay/SceneOverlay';
|
|
11
12
|
import { ExportCanvas } from '../export/Exporter';
|
|
12
13
|
import { HitTester } from '../hit/HitTester';
|
|
@@ -61,14 +62,10 @@ export declare class KonvaRenderBackend implements InteractiveBackend {
|
|
|
61
62
|
private _coordinateTransform;
|
|
62
63
|
private coordinateInverse;
|
|
63
64
|
get coordinateTransform(): CoordFn;
|
|
65
|
+
private liveEffects;
|
|
64
66
|
private sceneOverlays;
|
|
65
67
|
private sceneOverlayNodes;
|
|
66
|
-
private drawOverlayShapes;
|
|
67
68
|
private viewportSubscribers;
|
|
68
|
-
private frameCallbacks;
|
|
69
|
-
private rafHandle;
|
|
70
|
-
private lastFrameTime;
|
|
71
|
-
private frameSeq;
|
|
72
69
|
constructor(state: MapState, container?: HTMLDivElement);
|
|
73
70
|
setStyle(style: Style): void;
|
|
74
71
|
/** Pull forward/inverse coord transforms from the active shape Style. */
|
|
@@ -86,14 +83,13 @@ export declare class KonvaRenderBackend implements InteractiveBackend {
|
|
|
86
83
|
}): ExportCanvas | undefined;
|
|
87
84
|
private applyViewportToStage;
|
|
88
85
|
refresh(): void;
|
|
86
|
+
addLiveEffect(id: string, effect: LiveEffect): void;
|
|
87
|
+
removeLiveEffect(id: string): void;
|
|
89
88
|
addSceneOverlay(id: string, overlay: SceneOverlay): void;
|
|
90
89
|
removeSceneOverlay(id: string): void;
|
|
91
90
|
/** Iterable of scene overlays — used by exporters to apply them over static outputs. */
|
|
92
91
|
getSceneOverlays(): Iterable<SceneOverlay>;
|
|
93
92
|
private createOverlayContext;
|
|
94
|
-
private startFrameLoop;
|
|
95
|
-
private stopFrameLoop;
|
|
96
|
-
private getCanvasDrawState;
|
|
97
93
|
private renderSceneOverlay;
|
|
98
94
|
private clearSceneOverlayNodes;
|
|
99
95
|
private subscribeToState;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { IMapReader } from '../reader/MapReader';
|
|
2
|
+
import { IArea } from '../reader/Area';
|
|
3
|
+
import { RoomLens } from '../lens/RoomLens';
|
|
3
4
|
import { ViewportBounds, RendererEventMap, CullingMode, Settings } from '../types/Settings';
|
|
4
5
|
import { MapState } from '../MapState';
|
|
5
6
|
import { CoordFn } from '../coord/CoordFn';
|
|
@@ -8,6 +9,7 @@ import { Camera } from '../camera/Camera';
|
|
|
8
9
|
import { CullingManager } from '../CullingManager';
|
|
9
10
|
import { TypedEventEmitter } from '../TypedEventEmitter';
|
|
10
11
|
import { SceneOverlay } from '../overlay/SceneOverlay';
|
|
12
|
+
import { LiveEffect } from '../overlay/LiveEffect';
|
|
11
13
|
import { Exporter, ExportCanvas } from '../export/Exporter';
|
|
12
14
|
import { DrawnExitEntry, DrawnSpecialExitEntry, DrawnStubEntry } from '../ScenePipeline';
|
|
13
15
|
import { HitTester, HitResult } from '../hit/HitTester';
|
|
@@ -16,7 +18,7 @@ import { HitTester, HitResult } from '../hit/HitTester';
|
|
|
16
18
|
*
|
|
17
19
|
* Engine-neutral surface — anything that requires a specific render engine
|
|
18
20
|
* (Konva layers for live effects, Konva.Stage for `toCanvas`) is intentionally
|
|
19
|
-
* not on this interface and lives only on the concrete backend.
|
|
21
|
+
* not on this interface and lives only on the concrete backend.
|
|
20
22
|
*/
|
|
21
23
|
export interface InteractiveBackend {
|
|
22
24
|
readonly camera: Camera;
|
|
@@ -66,8 +68,8 @@ export interface InteractiveBackend {
|
|
|
66
68
|
* (SVG string, PNG data URL, canvas, PDF bytes, …). New formats are added by
|
|
67
69
|
* shipping new `Exporter<T>` implementations — no new methods on this class.
|
|
68
70
|
* - **{@link addSceneOverlay}** is target-agnostic and appears in every output.
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
+
* - **{@link addLiveEffect}** registers interactive-only animated effects (Konva
|
|
72
|
+
* canvas only; skipped by exporters).
|
|
71
73
|
*/
|
|
72
74
|
export declare class MapRenderer {
|
|
73
75
|
readonly state: MapState;
|
|
@@ -89,10 +91,10 @@ export declare class MapRenderer {
|
|
|
89
91
|
* @param backendFactory Optional factory that receives the `MapState` and returns
|
|
90
92
|
* a custom `InteractiveBackend`. When omitted, a `KonvaRenderBackend` is created.
|
|
91
93
|
*/
|
|
92
|
-
constructor(mapReader:
|
|
94
|
+
constructor(mapReader: IMapReader, settings?: Settings, container?: HTMLDivElement, backendFactory?: (state: MapState) => InteractiveBackend);
|
|
93
95
|
destroy(): void;
|
|
94
96
|
drawArea(id: number, zIndex: number): void;
|
|
95
|
-
getCurrentArea():
|
|
97
|
+
getCurrentArea(): IArea | undefined;
|
|
96
98
|
setPosition(roomId: number, center?: boolean): void;
|
|
97
99
|
updatePositionMarker(roomId: number): void;
|
|
98
100
|
clearPosition(): void;
|
|
@@ -104,6 +106,17 @@ export declare class MapRenderer {
|
|
|
104
106
|
renderPath(locations: number[], color?: string): void;
|
|
105
107
|
clearPaths(): void;
|
|
106
108
|
refreshCurrentRoomOverlay(): void;
|
|
109
|
+
/**
|
|
110
|
+
* Replace the active visibility lens. Lenses filter which rooms (and how
|
|
111
|
+
* partially-visible exits) the renderer draws — exploration / fog-of-war
|
|
112
|
+
* is one example, guild/quest scope overlays are others. Compose multiple
|
|
113
|
+
* concerns with `composeLenses(...)`.
|
|
114
|
+
*
|
|
115
|
+
* Triggers an immediate rebuild. For mutations on a stateful lens (e.g.
|
|
116
|
+
* `ExplorationLens.addVisited`), call {@link refresh} explicitly.
|
|
117
|
+
*/
|
|
118
|
+
setLens(lens: RoomLens): void;
|
|
119
|
+
getLens(): RoomLens;
|
|
107
120
|
/**
|
|
108
121
|
* Apply a {@link Style} to the interactive canvas and every export path.
|
|
109
122
|
* The backend rebuilds the current scene under the new style — no explicit
|
|
@@ -126,6 +139,17 @@ export declare class MapRenderer {
|
|
|
126
139
|
/** Target-agnostic overlay; appears in every output including exporters. */
|
|
127
140
|
addSceneOverlay(id: string, overlay: SceneOverlay): void;
|
|
128
141
|
removeSceneOverlay(id: string): void;
|
|
142
|
+
/**
|
|
143
|
+
* Register an interactive-only animated effect. No-ops when running with a
|
|
144
|
+
* non-Konva backend. Does not appear in SVG/PNG exports — use
|
|
145
|
+
* {@link addSceneOverlay} for overlays that must appear in exports.
|
|
146
|
+
*
|
|
147
|
+
* ```ts
|
|
148
|
+
* renderer.addLiveEffect('rain', new RainEffect());
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
addLiveEffect(id: string, effect: LiveEffect): void;
|
|
152
|
+
removeLiveEffect(id: string): void;
|
|
129
153
|
/**
|
|
130
154
|
* Hit-test a world-space map point against the current scene.
|
|
131
155
|
*
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { IArea } from '../reader/Area';
|
|
2
|
+
import { IPlane } from '../reader/Plane';
|
|
3
3
|
import { Settings } from '../types/Settings';
|
|
4
4
|
import { SceneBuildResult, SceneShapesByLayer, AreaExitHitZone, DrawnExitEntry, DrawnSpecialExitEntry, DrawnStubEntry } from '../ScenePipeline';
|
|
5
5
|
import { Camera } from '../camera/Camera';
|
|
6
6
|
import { CoordFn } from '../coord/CoordFn';
|
|
7
7
|
import { GroupShape, Shape } from '../scene/Shape';
|
|
8
|
-
import {
|
|
8
|
+
import { IMapReader } from '../reader/MapReader';
|
|
9
|
+
import { RoomLens } from '../lens/RoomLens';
|
|
9
10
|
import { ExitDrawData } from '../ExitRenderer';
|
|
10
11
|
export interface CullStats {
|
|
11
12
|
visibleRooms: number;
|
|
@@ -30,7 +31,7 @@ export declare class SceneManager {
|
|
|
30
31
|
private pipeline;
|
|
31
32
|
private lastBuildResult?;
|
|
32
33
|
private standaloneExitShapeSet;
|
|
33
|
-
constructor(camera: Camera, settings: Settings, mapReader:
|
|
34
|
+
constructor(camera: Camera, settings: Settings, mapReader: IMapReader);
|
|
34
35
|
get exitRenderer(): import('../ExitRenderer').default;
|
|
35
36
|
get lastResult(): SceneBuildResult | undefined;
|
|
36
37
|
get drawnExits(): readonly DrawnExitEntry[];
|
|
@@ -38,10 +39,10 @@ export declare class SceneManager {
|
|
|
38
39
|
get drawnStubs(): readonly DrawnStubEntry[];
|
|
39
40
|
get areaExitHitZones(): readonly AreaExitHitZone[];
|
|
40
41
|
get hitShapes(): readonly Shape[];
|
|
41
|
-
rebuild(area:
|
|
42
|
+
rebuild(area: IArea, plane: IPlane, zIndex: number, lens?: RoomLens): SceneBuildResult;
|
|
42
43
|
buildExitShape(data: ExitDrawData): GroupShape;
|
|
43
44
|
reset(): void;
|
|
44
|
-
resetPipeline(mapReader:
|
|
45
|
+
resetPipeline(mapReader: IMapReader): void;
|
|
45
46
|
/**
|
|
46
47
|
* Lightweight cull for the interactive render path. Returns a
|
|
47
48
|
* `Map<Shape, boolean>` where absent shapes are unmanaged pass-throughs
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Settings } from '../types/Settings';
|
|
2
|
-
import {
|
|
2
|
+
import { IMapReader } from '../reader/MapReader';
|
|
3
3
|
export type TriangleData = {
|
|
4
4
|
cx: number;
|
|
5
5
|
cy: number;
|
|
@@ -17,7 +17,7 @@ declare function computeTriangleVertices(cx: number, cy: number, radius: number,
|
|
|
17
17
|
* Compute inner exit triangle data for a room.
|
|
18
18
|
* Returns pre-computed vertex positions so each backend just draws polygons.
|
|
19
19
|
*/
|
|
20
|
-
export declare function computeInnerExits(room: MapData.Room, mapReader:
|
|
20
|
+
export declare function computeInnerExits(room: MapData.Room, mapReader: IMapReader, settings: Settings): InnerExitData;
|
|
21
21
|
/**
|
|
22
22
|
* Compute triangle vertices for a standalone triangle (used by path overlay markers).
|
|
23
23
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Settings } from '../types/Settings';
|
|
2
|
-
import {
|
|
2
|
+
import { IMapReader } from '../reader/MapReader';
|
|
3
3
|
export type HighlightData = {
|
|
4
4
|
shape: 'circle' | 'rect';
|
|
5
5
|
cx: number;
|
|
@@ -7,9 +7,13 @@ export type HighlightData = {
|
|
|
7
7
|
/** For circle: radius. For rect: half-size. */
|
|
8
8
|
size: number;
|
|
9
9
|
cornerRadius: number;
|
|
10
|
-
|
|
10
|
+
strokeColor: string;
|
|
11
|
+
strokeAlpha: number;
|
|
11
12
|
strokeWidth: number;
|
|
12
|
-
|
|
13
|
+
fillColor: string;
|
|
14
|
+
fillAlpha: number;
|
|
15
|
+
dash?: number[];
|
|
16
|
+
dashEnabled: boolean;
|
|
13
17
|
};
|
|
14
18
|
export declare function computeHighlight(room: MapData.Room, color: string, settings: Settings): HighlightData;
|
|
15
19
|
export type PositionMarkerData = {
|
|
@@ -40,4 +44,4 @@ export type PathOverlayData = {
|
|
|
40
44
|
outlineWidth: number;
|
|
41
45
|
lineWidth: number;
|
|
42
46
|
};
|
|
43
|
-
export declare function computePathOverlay(mapReader:
|
|
47
|
+
export declare function computePathOverlay(mapReader: IMapReader, settings: Settings, locations: number[], color: string, areaId: number, zIndex: number): PathOverlayData;
|