@edv4h/usketch-plugin-character 0.2.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/LICENSE +21 -0
- package/README.md +84 -0
- package/dist/character-camera.d.ts +33 -0
- package/dist/character-camera.d.ts.map +1 -0
- package/dist/character-camera.js +45 -0
- package/dist/character-camera.js.map +1 -0
- package/dist/character-input.d.ts +18 -0
- package/dist/character-input.d.ts.map +1 -0
- package/dist/character-input.js +89 -0
- package/dist/character-input.js.map +1 -0
- package/dist/character-layer.d.ts +7 -0
- package/dist/character-layer.d.ts.map +1 -0
- package/dist/character-layer.js +53 -0
- package/dist/character-layer.js.map +1 -0
- package/dist/character-physics.d.ts +55 -0
- package/dist/character-physics.d.ts.map +1 -0
- package/dist/character-physics.js +97 -0
- package/dist/character-physics.js.map +1 -0
- package/dist/character-runtime.d.ts +30 -0
- package/dist/character-runtime.d.ts.map +1 -0
- package/dist/character-runtime.js +229 -0
- package/dist/character-runtime.js.map +1 -0
- package/dist/character-service.d.ts +47 -0
- package/dist/character-service.d.ts.map +1 -0
- package/dist/character-service.js +36 -0
- package/dist/character-service.js.map +1 -0
- package/dist/character-store.d.ts +55 -0
- package/dist/character-store.d.ts.map +1 -0
- package/dist/character-store.js +100 -0
- package/dist/character-store.js.map +1 -0
- package/dist/character-sync.d.ts +42 -0
- package/dist/character-sync.d.ts.map +1 -0
- package/dist/character-sync.js +117 -0
- package/dist/character-sync.js.map +1 -0
- package/dist/character-types.d.ts +52 -0
- package/dist/character-types.d.ts.map +1 -0
- package/dist/character-types.js +7 -0
- package/dist/character-types.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +36 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +38 -0
- package/dist/plugin.js.map +1 -0
- package/dist/register-character-hud.d.ts +4 -0
- package/dist/register-character-hud.d.ts.map +1 -0
- package/dist/register-character-hud.js +122 -0
- package/dist/register-character-hud.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// The runtime loop: held keys → physics step → follow camera → awareness publish,
|
|
3
|
+
// plus smoothing of remote characters. One rAF loop that runs only while the local
|
|
4
|
+
// character is enabled or a remote one is still easing into place.
|
|
5
|
+
import { screenToWorld, viewportRotation, } from "@edv4h/usketch-shared";
|
|
6
|
+
import { anchorPx, easeFocus, followViewport, sameViewport, smoothingAlpha, targetRotation, } from "./character-camera.js";
|
|
7
|
+
import { createKeyInput } from "./character-input.js";
|
|
8
|
+
import { CharacterLayer } from "./character-layer.js";
|
|
9
|
+
import { stepCharacter } from "./character-physics.js";
|
|
10
|
+
import { createCharacterSync, easeRemotes, } from "./character-sync.js";
|
|
11
|
+
export const CHARACTER_LAYER_ID = "character";
|
|
12
|
+
/** Above shapes and most overlays, below the HUD (9999). */
|
|
13
|
+
const CHARACTER_LAYER_ORDER = 700;
|
|
14
|
+
/** `viewport:claimed` priority: above start-position (10), below deep links (100). */
|
|
15
|
+
export const CHARACTER_VIEWPORT_PRIORITY = 20;
|
|
16
|
+
/** Remote pose smoothing (see `smoothingAlpha`). */
|
|
17
|
+
const REMOTE_SMOOTHING = 0.75;
|
|
18
|
+
/** Largest simulated step, so a background-tab pause doesn't teleport the character. */
|
|
19
|
+
const MAX_DT = 0.05;
|
|
20
|
+
function scheduleFrame(fn) {
|
|
21
|
+
if (typeof requestAnimationFrame === "function")
|
|
22
|
+
return requestAnimationFrame(fn);
|
|
23
|
+
return setTimeout(() => fn(Date.now()), 16);
|
|
24
|
+
}
|
|
25
|
+
function cancelFrame(handle) {
|
|
26
|
+
if (typeof cancelAnimationFrame === "function")
|
|
27
|
+
cancelAnimationFrame(handle);
|
|
28
|
+
else
|
|
29
|
+
clearTimeout(handle);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The main canvas's pixel size. Found via `[data-layer-id]` wrappers' parent (the
|
|
33
|
+
* app build strips `data-testid`, so `canvas-container` can't be queried); the
|
|
34
|
+
* largest wins when a minimap also renders layers. Falls back to the window.
|
|
35
|
+
*/
|
|
36
|
+
export function canvasSize() {
|
|
37
|
+
if (typeof document !== "undefined") {
|
|
38
|
+
let best = null;
|
|
39
|
+
const seen = new Set();
|
|
40
|
+
for (const el of document.querySelectorAll("[data-layer-id]")) {
|
|
41
|
+
const parent = el.parentElement;
|
|
42
|
+
if (!parent || seen.has(parent))
|
|
43
|
+
continue;
|
|
44
|
+
seen.add(parent);
|
|
45
|
+
const r = parent.getBoundingClientRect();
|
|
46
|
+
if (!best || r.width * r.height > best.width * best.height) {
|
|
47
|
+
best = { width: r.width, height: r.height };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (best && best.width > 0 && best.height > 0)
|
|
51
|
+
return best;
|
|
52
|
+
}
|
|
53
|
+
if (typeof window !== "undefined")
|
|
54
|
+
return { width: window.innerWidth, height: window.innerHeight };
|
|
55
|
+
return { width: 0, height: 0 };
|
|
56
|
+
}
|
|
57
|
+
export function setupCharacterRuntime(ctx, store, options) {
|
|
58
|
+
const keys = createKeyInput(options.keys, () => store.getState().enabled);
|
|
59
|
+
let cam = null;
|
|
60
|
+
let display = new Map();
|
|
61
|
+
let rafId = null;
|
|
62
|
+
let lastFrame = null;
|
|
63
|
+
// Set while WE write the viewport, so our own writes don't read as a user pan.
|
|
64
|
+
let writing = false;
|
|
65
|
+
const anchorPoint = () => anchorPx(store.getState().anchor, canvasSize());
|
|
66
|
+
const sync = options.awareness
|
|
67
|
+
? createCharacterSync(options.awareness, store, () => ensureLoop())
|
|
68
|
+
: null;
|
|
69
|
+
const placeAtAnchor = () => {
|
|
70
|
+
const vp = ctx.store.getViewport();
|
|
71
|
+
const a = anchorPoint();
|
|
72
|
+
store.setPosition(screenToWorld(a.x, a.y, vp));
|
|
73
|
+
cam = null;
|
|
74
|
+
};
|
|
75
|
+
const writeViewport = (vp) => {
|
|
76
|
+
writing = true;
|
|
77
|
+
try {
|
|
78
|
+
ctx.store.setViewport(vp);
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
writing = false;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
// A hoisted declaration: the awareness sync (created above) can request a frame
|
|
85
|
+
// during its initial read, before this point in setup has run.
|
|
86
|
+
function frame(now) {
|
|
87
|
+
rafId = null;
|
|
88
|
+
const dt = lastFrame === null ? 0 : Math.min(MAX_DT, Math.max(0, (now - lastFrame) / 1000));
|
|
89
|
+
lastFrame = now;
|
|
90
|
+
let s = store.getState();
|
|
91
|
+
if (s.enabled) {
|
|
92
|
+
if (!s.spawned) {
|
|
93
|
+
placeAtAnchor();
|
|
94
|
+
// Face screen-up in whatever way the camera is currently turned.
|
|
95
|
+
store.setHeading(-viewportRotation(ctx.store.getViewport()));
|
|
96
|
+
s = store.getState();
|
|
97
|
+
}
|
|
98
|
+
const input = keys.read();
|
|
99
|
+
if (s.followSuspended && keys.anyHeld())
|
|
100
|
+
store.setFollowSuspended(false);
|
|
101
|
+
const vp = ctx.store.getViewport();
|
|
102
|
+
const pose = stepCharacter(s.pose, input, dt, s.controlScheme, s.motion, viewportRotation(vp));
|
|
103
|
+
store.setPose(pose);
|
|
104
|
+
s = store.getState();
|
|
105
|
+
if (s.cameraMode !== "free" && !s.followSuspended) {
|
|
106
|
+
const target = {
|
|
107
|
+
focus: { x: pose.x, y: pose.y },
|
|
108
|
+
rotation: targetRotation(s.cameraMode, pose.heading),
|
|
109
|
+
};
|
|
110
|
+
const anchor = anchorPoint();
|
|
111
|
+
// (Re)seed from what's on screen now, so resuming/switching eases instead of jumping.
|
|
112
|
+
const from = cam ?? {
|
|
113
|
+
focus: screenToWorld(anchor.x, anchor.y, vp),
|
|
114
|
+
rotation: viewportRotation(vp),
|
|
115
|
+
};
|
|
116
|
+
cam = easeFocus(from, target, smoothingAlpha(s.followSmoothing, dt));
|
|
117
|
+
const next = followViewport(cam, anchor, vp.zoom);
|
|
118
|
+
if (!sameViewport(vp, next))
|
|
119
|
+
writeViewport(next);
|
|
120
|
+
}
|
|
121
|
+
sync?.publish();
|
|
122
|
+
}
|
|
123
|
+
let settling = false;
|
|
124
|
+
if (sync) {
|
|
125
|
+
const eased = easeRemotes(display, sync.targets(), smoothingAlpha(REMOTE_SMOOTHING, dt));
|
|
126
|
+
settling = eased.settling;
|
|
127
|
+
if (!sameRemotes(display, eased.next)) {
|
|
128
|
+
display = eased.next;
|
|
129
|
+
store.setRemotes(display);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (store.getState().enabled || settling)
|
|
133
|
+
ensureLoop();
|
|
134
|
+
else
|
|
135
|
+
lastFrame = null;
|
|
136
|
+
}
|
|
137
|
+
function ensureLoop() {
|
|
138
|
+
if (rafId === null)
|
|
139
|
+
rafId = scheduleFrame(frame);
|
|
140
|
+
}
|
|
141
|
+
// Enable/disable + mode transitions.
|
|
142
|
+
let prev = store.getState();
|
|
143
|
+
const unsubscribe = store.subscribe(() => {
|
|
144
|
+
const s = store.getState();
|
|
145
|
+
if (s.enabled !== prev.enabled) {
|
|
146
|
+
if (s.enabled) {
|
|
147
|
+
cam = null;
|
|
148
|
+
// Tell load-time camera plugins (start-position, …) to stand down.
|
|
149
|
+
ctx.events.emit("viewport:claimed", {
|
|
150
|
+
source: "character",
|
|
151
|
+
priority: CHARACTER_VIEWPORT_PRIORITY,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
cam = null;
|
|
156
|
+
// Hand the camera back upright.
|
|
157
|
+
if (viewportRotation(ctx.store.getViewport()) !== 0) {
|
|
158
|
+
ctx.store.rotateTo(0, anchorPoint(), { animate: true });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
sync?.publish(true);
|
|
162
|
+
}
|
|
163
|
+
if (s.cameraMode !== prev.cameraMode || s.followSuspended !== prev.followSuspended) {
|
|
164
|
+
// Re-seed the smoothed camera from the live viewport so resuming never jumps.
|
|
165
|
+
cam = null;
|
|
166
|
+
}
|
|
167
|
+
prev = s;
|
|
168
|
+
if (s.enabled)
|
|
169
|
+
ensureLoop();
|
|
170
|
+
});
|
|
171
|
+
// A viewport change we didn't make: zoom (wheel / keys) is welcome — the follow
|
|
172
|
+
// keeps the character on its anchor at the new zoom. A pure pan means the user
|
|
173
|
+
// wants to look around, so pause following until a movement key is pressed.
|
|
174
|
+
let lastZoom = ctx.store.getViewport().zoom;
|
|
175
|
+
const offViewport = ctx.store.onMutation((e) => {
|
|
176
|
+
if (e.type !== "viewport:changed")
|
|
177
|
+
return;
|
|
178
|
+
const vp = ctx.store.getViewport();
|
|
179
|
+
const zoomChanged = Math.abs(vp.zoom - lastZoom) > 1e-9;
|
|
180
|
+
lastZoom = vp.zoom;
|
|
181
|
+
if (writing || zoomChanged)
|
|
182
|
+
return;
|
|
183
|
+
const s = store.getState();
|
|
184
|
+
if (s.enabled && s.cameraMode !== "free")
|
|
185
|
+
store.setFollowSuspended(true);
|
|
186
|
+
});
|
|
187
|
+
ctx.layers.register({
|
|
188
|
+
id: CHARACTER_LAYER_ID,
|
|
189
|
+
order: CHARACTER_LAYER_ORDER,
|
|
190
|
+
fixed: true,
|
|
191
|
+
render: (rc) => _jsx(CharacterLayer, { store: store, viewport: rc.viewport }),
|
|
192
|
+
});
|
|
193
|
+
if (store.getState().enabled || sync)
|
|
194
|
+
ensureLoop();
|
|
195
|
+
return {
|
|
196
|
+
placeAtAnchor,
|
|
197
|
+
anchorPoint,
|
|
198
|
+
setKeys: (k) => keys.setKeys(k),
|
|
199
|
+
dispose() {
|
|
200
|
+
if (rafId !== null)
|
|
201
|
+
cancelFrame(rafId);
|
|
202
|
+
rafId = null;
|
|
203
|
+
unsubscribe();
|
|
204
|
+
offViewport();
|
|
205
|
+
keys.dispose();
|
|
206
|
+
sync?.dispose();
|
|
207
|
+
ctx.layers.unregister(CHARACTER_LAYER_ID);
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function sameRemotes(a, b) {
|
|
212
|
+
if (a.size !== b.size)
|
|
213
|
+
return false;
|
|
214
|
+
for (const [id, r] of b) {
|
|
215
|
+
const o = a.get(id);
|
|
216
|
+
if (!o ||
|
|
217
|
+
o.x !== r.x ||
|
|
218
|
+
o.y !== r.y ||
|
|
219
|
+
o.heading !== r.heading ||
|
|
220
|
+
o.moving !== r.moving ||
|
|
221
|
+
o.speed !== r.speed ||
|
|
222
|
+
o.name !== r.name ||
|
|
223
|
+
o.appearance !== r.appearance) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=character-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"character-runtime.js","sourceRoot":"","sources":["../src/character-runtime.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type Point, type ServiceRegistry } from "@edv4h/usketch-shared";
|
|
2
|
+
import type { CameraMode } from "./character-camera.js";
|
|
3
|
+
import type { CharacterPose, ControlScheme, MotionParams } from "./character-physics.js";
|
|
4
|
+
import type { CharacterRuntime } from "./character-runtime.js";
|
|
5
|
+
import type { CharacterStore } from "./character-store.js";
|
|
6
|
+
import type { CharacterAppearance, CharacterKeys, CharacterRenderer, RemoteCharacter } from "./character-types.js";
|
|
7
|
+
export interface CharacterApi {
|
|
8
|
+
isEnabled(): boolean;
|
|
9
|
+
enable(): void;
|
|
10
|
+
disable(): void;
|
|
11
|
+
toggle(): void;
|
|
12
|
+
/** Local character pose (world position, heading, speed). */
|
|
13
|
+
getPose(): CharacterPose;
|
|
14
|
+
/** Teleport the local character (world coordinates). */
|
|
15
|
+
setPosition(p: Point): void;
|
|
16
|
+
/** Face a direction (degrees, 0 = up, clockwise). */
|
|
17
|
+
setHeading(deg: number): void;
|
|
18
|
+
/** Move the character to the world point under its screen anchor. */
|
|
19
|
+
placeAtAnchor(): void;
|
|
20
|
+
getCameraMode(): CameraMode;
|
|
21
|
+
setCameraMode(mode: CameraMode): void;
|
|
22
|
+
getControlScheme(): ControlScheme;
|
|
23
|
+
setControlScheme(scheme: ControlScheme): void;
|
|
24
|
+
getMotion(): MotionParams;
|
|
25
|
+
setMotion(motion: Partial<MotionParams>): void;
|
|
26
|
+
/** Screen anchor as canvas fractions (0..1). */
|
|
27
|
+
getAnchor(): Point;
|
|
28
|
+
setAnchor(anchor: Partial<Point>): void;
|
|
29
|
+
/** Follow smoothing (0 = rigid … 0.99 = heavy lag). */
|
|
30
|
+
getFollowSmoothing(): number;
|
|
31
|
+
setFollowSmoothing(value: number): void;
|
|
32
|
+
/** Replace the movement key bindings (`KeyboardEvent.code` values). */
|
|
33
|
+
setKeys(keys: CharacterKeys): void;
|
|
34
|
+
/** Swap the character renderer (`undefined` = draw nothing). */
|
|
35
|
+
setRenderer(renderer: CharacterRenderer | undefined): void;
|
|
36
|
+
/** Replace the broadcast appearance data. */
|
|
37
|
+
setAppearance(appearance: CharacterAppearance): void;
|
|
38
|
+
/** Other clients' live characters. */
|
|
39
|
+
getRemotes(): ReadonlyMap<string, RemoteCharacter>;
|
|
40
|
+
/** Fire on any state change. Returns an unsubscribe. */
|
|
41
|
+
onChange(listener: () => void): () => void;
|
|
42
|
+
}
|
|
43
|
+
export declare const characterService: import("@edv4h/usketch-shared").ServiceHandle<CharacterApi>;
|
|
44
|
+
export declare function createCharacterApi(store: CharacterStore, runtime: CharacterRuntime): CharacterApi;
|
|
45
|
+
/** Host accessor: `getCharacterApi(app.services)?.enable()`. Undefined when inactive. */
|
|
46
|
+
export declare function getCharacterApi(services: ServiceRegistry): CharacterApi | undefined;
|
|
47
|
+
//# sourceMappingURL=character-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"character-service.d.ts","sourceRoot":"","sources":["../src/character-service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,KAAK,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EACX,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,YAAY;IAC5B,SAAS,IAAI,OAAO,CAAC;IACrB,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;IAChB,MAAM,IAAI,IAAI,CAAC;IACf,6DAA6D;IAC7D,OAAO,IAAI,aAAa,CAAC;IACzB,wDAAwD;IACxD,WAAW,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IAC5B,qDAAqD;IACrD,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,qEAAqE;IACrE,aAAa,IAAI,IAAI,CAAC;IACtB,aAAa,IAAI,UAAU,CAAC;IAC5B,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACtC,gBAAgB,IAAI,aAAa,CAAC;IAClC,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9C,SAAS,IAAI,YAAY,CAAC;IAC1B,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IAC/C,gDAAgD;IAChD,SAAS,IAAI,KAAK,CAAC;IACnB,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;IACxC,uDAAuD;IACvD,kBAAkB,IAAI,MAAM,CAAC;IAC7B,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,uEAAuE;IACvE,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IACnC,gEAAgE;IAChE,WAAW,CAAC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,GAAG,IAAI,CAAC;IAC3D,6CAA6C;IAC7C,aAAa,CAAC,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrD,sCAAsC;IACtC,UAAU,IAAI,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACnD,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC3C;AAED,eAAO,MAAM,gBAAgB,6DAA0D,CAAC;AAExF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,YAAY,CA0BjG;AAED,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,GAAG,YAAY,GAAG,SAAS,CAEnF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Host-facing API on the `ctx.services` seam: everything the HUD does, plus the
|
|
2
|
+
// render/appearance hooks, as typed calls a host or another plugin can drive.
|
|
3
|
+
import { defineService } from "@edv4h/usketch-shared";
|
|
4
|
+
export const characterService = defineService("usketch-plugin-character");
|
|
5
|
+
export function createCharacterApi(store, runtime) {
|
|
6
|
+
return {
|
|
7
|
+
isEnabled: () => store.getState().enabled,
|
|
8
|
+
enable: () => store.setEnabled(true),
|
|
9
|
+
disable: () => store.setEnabled(false),
|
|
10
|
+
toggle: () => store.setEnabled(!store.getState().enabled),
|
|
11
|
+
getPose: () => store.getState().pose,
|
|
12
|
+
setPosition: (p) => store.setPosition(p),
|
|
13
|
+
setHeading: (deg) => store.setHeading(deg),
|
|
14
|
+
placeAtAnchor: () => runtime.placeAtAnchor(),
|
|
15
|
+
getCameraMode: () => store.getState().cameraMode,
|
|
16
|
+
setCameraMode: (mode) => store.setCameraMode(mode),
|
|
17
|
+
getControlScheme: () => store.getState().controlScheme,
|
|
18
|
+
setControlScheme: (scheme) => store.setControlScheme(scheme),
|
|
19
|
+
getMotion: () => store.getState().motion,
|
|
20
|
+
setMotion: (motion) => store.setMotion(motion),
|
|
21
|
+
getAnchor: () => store.getState().anchor,
|
|
22
|
+
setAnchor: (anchor) => store.setAnchor(anchor),
|
|
23
|
+
getFollowSmoothing: () => store.getState().followSmoothing,
|
|
24
|
+
setFollowSmoothing: (v) => store.setFollowSmoothing(v),
|
|
25
|
+
setKeys: (keys) => runtime.setKeys(keys),
|
|
26
|
+
setRenderer: (r) => store.setRenderer(r),
|
|
27
|
+
setAppearance: (a) => store.setAppearance(a),
|
|
28
|
+
getRemotes: () => store.getState().remotes,
|
|
29
|
+
onChange: (listener) => store.subscribe(listener),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** Host accessor: `getCharacterApi(app.services)?.enable()`. Undefined when inactive. */
|
|
33
|
+
export function getCharacterApi(services) {
|
|
34
|
+
return characterService.get(services);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=character-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"character-service.js","sourceRoot":"","sources":["../src/character-service.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,8EAA8E;AAC9E,OAAO,EAAE,aAAa,EAAoC,MAAM,uBAAuB,CAAC;AAiDxF,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAe,0BAA0B,CAAC,CAAC;AAExF,MAAM,UAAU,kBAAkB,CAAC,KAAqB,EAAE,OAAyB;IAClF,OAAO;QACN,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,OAAO;QACzC,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;QACpC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;QACtC,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC;QACzD,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,IAAI;QACpC,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;QACxC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QAC1C,aAAa,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE;QAC5C,aAAa,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,UAAU;QAChD,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC;QAClD,gBAAgB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,aAAa;QACtD,gBAAgB,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC;QAC5D,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,MAAM;QACxC,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;QAC9C,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,MAAM;QACxC,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;QAC9C,kBAAkB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,eAAe;QAC1D,kBAAkB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC;QACtD,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;QACxC,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;QACxC,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;QAC5C,UAAU,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,OAAO;QAC1C,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC;KACjD,CAAC;AACH,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,eAAe,CAAC,QAAyB;IACxD,OAAO,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type Point } from "@edv4h/usketch-shared";
|
|
2
|
+
import type { CameraMode } from "./character-camera.js";
|
|
3
|
+
import { type CharacterPose, type ControlScheme, type MotionParams } from "./character-physics.js";
|
|
4
|
+
import type { CharacterAppearance, CharacterRenderer, RemoteCharacter } from "./character-types.js";
|
|
5
|
+
export interface CharacterState {
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
pose: CharacterPose;
|
|
8
|
+
/** Whether the pose has been placed yet (the first enable spawns at the anchor). */
|
|
9
|
+
spawned: boolean;
|
|
10
|
+
cameraMode: CameraMode;
|
|
11
|
+
controlScheme: ControlScheme;
|
|
12
|
+
motion: MotionParams;
|
|
13
|
+
/** Screen anchor as fractions of the canvas (0..1). */
|
|
14
|
+
anchor: Point;
|
|
15
|
+
/** 0 = rigid follow … 0.99 = heavy lag. */
|
|
16
|
+
followSmoothing: number;
|
|
17
|
+
/** True after the user panned by hand; a movement key resumes following. */
|
|
18
|
+
followSuspended: boolean;
|
|
19
|
+
appearance: CharacterAppearance;
|
|
20
|
+
name?: string;
|
|
21
|
+
/** Other clients' characters, keyed by id (display poses, smoothed). */
|
|
22
|
+
remotes: ReadonlyMap<string, RemoteCharacter>;
|
|
23
|
+
}
|
|
24
|
+
export interface CharacterStoreInit {
|
|
25
|
+
enabled?: boolean;
|
|
26
|
+
cameraMode?: CameraMode;
|
|
27
|
+
controlScheme?: ControlScheme;
|
|
28
|
+
motion?: Partial<MotionParams>;
|
|
29
|
+
anchor?: Partial<Point>;
|
|
30
|
+
followSmoothing?: number;
|
|
31
|
+
appearance?: CharacterAppearance;
|
|
32
|
+
name?: string;
|
|
33
|
+
renderer?: CharacterRenderer;
|
|
34
|
+
}
|
|
35
|
+
export declare function createCharacterStore(init?: CharacterStoreInit): {
|
|
36
|
+
getState: () => CharacterState;
|
|
37
|
+
subscribe(listener: () => void): () => void;
|
|
38
|
+
getRenderer: () => CharacterRenderer | undefined;
|
|
39
|
+
setRenderer(fn: CharacterRenderer | undefined): void;
|
|
40
|
+
setEnabled(enabled: boolean): void;
|
|
41
|
+
setPose(pose: CharacterPose): void;
|
|
42
|
+
setPosition(p: Point): void;
|
|
43
|
+
setHeading(deg: number): void;
|
|
44
|
+
setCameraMode(cameraMode: CameraMode): void;
|
|
45
|
+
setControlScheme(controlScheme: ControlScheme): void;
|
|
46
|
+
setMotion(m: Partial<MotionParams>): void;
|
|
47
|
+
setAnchor(a: Partial<Point>): void;
|
|
48
|
+
setFollowSmoothing(v: number): void;
|
|
49
|
+
setFollowSuspended(followSuspended: boolean): void;
|
|
50
|
+
setAppearance(appearance: CharacterAppearance): void;
|
|
51
|
+
setName(name: string | undefined): void;
|
|
52
|
+
setRemotes(remotes: ReadonlyMap<string, RemoteCharacter>): void;
|
|
53
|
+
};
|
|
54
|
+
export type CharacterStore = ReturnType<typeof createCharacterStore>;
|
|
55
|
+
//# sourceMappingURL=character-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"character-store.d.ts","sourceRoot":"","sources":["../src/character-store.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,KAAK,EAAW,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,aAAa,EAElB,KAAK,YAAY,EACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEpG,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,aAAa,CAAC;IACpB,oFAAoF;IACpF,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,aAAa,CAAC;IAC7B,MAAM,EAAE,YAAY,CAAC;IACrB,uDAAuD;IACvD,MAAM,EAAE,KAAK,CAAC;IACd,2CAA2C;IAC3C,eAAe,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,mBAAmB,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC7B;AAeD,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,kBAAuB;IAwBhE,QAAQ,QAAM,cAAc;IAC5B,SAAS,WAAW,MAAM,IAAI,GAAG,MAAM,IAAI;IAI3C,WAAW,QAAM,iBAAiB,GAAG,SAAS;IAC9C,WAAW,KAAK,iBAAiB,GAAG,SAAS,GAAG,IAAI;IAIpD,UAAU,UAAU,OAAO,GAAG,IAAI;IAGlC,OAAO,OAAO,aAAa,GAAG,IAAI;IAGlC,WAAW,IAAI,KAAK,GAAG,IAAI;IAG3B,UAAU,MAAM,MAAM,GAAG,IAAI;IAG7B,aAAa,aAAa,UAAU,GAAG,IAAI;IAG3C,gBAAgB,gBAAgB,aAAa,GAAG,IAAI;IAKpD,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI;IAGzC,SAAS,IAAI,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI;IAKlC,kBAAkB,IAAI,MAAM,GAAG,IAAI;IAGnC,kBAAkB,kBAAkB,OAAO,GAAG,IAAI;IAGlD,aAAa,aAAa,mBAAmB,GAAG,IAAI;IAGpD,OAAO,OAAO,MAAM,GAAG,SAAS,GAAG,IAAI;IAGvC,UAAU,UAAU,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,IAAI;EAIhE;AAED,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// The plugin's per-viewer state (never persisted as shapes — it is ephemeral, and
|
|
2
|
+
// shared with others only through awareness). A tiny subscribe/notify store so the
|
|
3
|
+
// layer, HUD and service all read the same source of truth.
|
|
4
|
+
import { wrapDeg } from "@edv4h/usketch-shared";
|
|
5
|
+
import { DEFAULT_MOTION, } from "./character-physics.js";
|
|
6
|
+
const clamp01 = (v) => Math.min(1, Math.max(0, v));
|
|
7
|
+
const positive = (v, fallback) => (Number.isFinite(v) && v > 0 ? v : fallback);
|
|
8
|
+
function sanitizeMotion(m, base) {
|
|
9
|
+
return {
|
|
10
|
+
moveSpeed: positive(m.moveSpeed ?? base.moveSpeed, base.moveSpeed),
|
|
11
|
+
turnRate: positive(m.turnRate ?? base.turnRate, base.turnRate),
|
|
12
|
+
acceleration: positive(m.acceleration ?? base.acceleration, base.acceleration),
|
|
13
|
+
friction: positive(m.friction ?? base.friction, base.friction),
|
|
14
|
+
reverseRatio: clamp01(m.reverseRatio ?? base.reverseRatio),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function createCharacterStore(init = {}) {
|
|
18
|
+
let state = {
|
|
19
|
+
enabled: init.enabled ?? false,
|
|
20
|
+
pose: { x: 0, y: 0, heading: 0, speed: 0, moving: false },
|
|
21
|
+
spawned: false,
|
|
22
|
+
cameraMode: init.cameraMode ?? "fixed",
|
|
23
|
+
controlScheme: init.controlScheme ?? "directional",
|
|
24
|
+
motion: sanitizeMotion(init.motion ?? {}, DEFAULT_MOTION),
|
|
25
|
+
anchor: { x: clamp01(init.anchor?.x ?? 0.5), y: clamp01(init.anchor?.y ?? 0.5) },
|
|
26
|
+
followSmoothing: Math.min(0.99, Math.max(0, init.followSmoothing ?? 0)),
|
|
27
|
+
followSuspended: false,
|
|
28
|
+
appearance: init.appearance ?? {},
|
|
29
|
+
name: init.name,
|
|
30
|
+
remotes: new Map(),
|
|
31
|
+
};
|
|
32
|
+
let renderer = init.renderer;
|
|
33
|
+
const listeners = new Set();
|
|
34
|
+
const set = (patch) => {
|
|
35
|
+
state = { ...state, ...patch };
|
|
36
|
+
for (const l of listeners)
|
|
37
|
+
l();
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
getState: () => state,
|
|
41
|
+
subscribe(listener) {
|
|
42
|
+
listeners.add(listener);
|
|
43
|
+
return () => listeners.delete(listener);
|
|
44
|
+
},
|
|
45
|
+
getRenderer: () => renderer,
|
|
46
|
+
setRenderer(fn) {
|
|
47
|
+
renderer = fn;
|
|
48
|
+
set({}); // re-render with the new look
|
|
49
|
+
},
|
|
50
|
+
setEnabled(enabled) {
|
|
51
|
+
if (enabled !== state.enabled)
|
|
52
|
+
set({ enabled, followSuspended: false });
|
|
53
|
+
},
|
|
54
|
+
setPose(pose) {
|
|
55
|
+
if (pose !== state.pose)
|
|
56
|
+
set({ pose, spawned: true });
|
|
57
|
+
},
|
|
58
|
+
setPosition(p) {
|
|
59
|
+
set({ pose: { ...state.pose, x: p.x, y: p.y, speed: 0, moving: false }, spawned: true });
|
|
60
|
+
},
|
|
61
|
+
setHeading(deg) {
|
|
62
|
+
set({ pose: { ...state.pose, heading: wrapDeg(deg) } });
|
|
63
|
+
},
|
|
64
|
+
setCameraMode(cameraMode) {
|
|
65
|
+
if (cameraMode !== state.cameraMode)
|
|
66
|
+
set({ cameraMode, followSuspended: false });
|
|
67
|
+
},
|
|
68
|
+
setControlScheme(controlScheme) {
|
|
69
|
+
if (controlScheme !== state.controlScheme) {
|
|
70
|
+
set({ controlScheme, pose: { ...state.pose, speed: 0, moving: false } });
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
setMotion(m) {
|
|
74
|
+
set({ motion: sanitizeMotion(m, state.motion) });
|
|
75
|
+
},
|
|
76
|
+
setAnchor(a) {
|
|
77
|
+
set({
|
|
78
|
+
anchor: { x: clamp01(a.x ?? state.anchor.x), y: clamp01(a.y ?? state.anchor.y) },
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
setFollowSmoothing(v) {
|
|
82
|
+
if (Number.isFinite(v))
|
|
83
|
+
set({ followSmoothing: Math.min(0.99, Math.max(0, v)) });
|
|
84
|
+
},
|
|
85
|
+
setFollowSuspended(followSuspended) {
|
|
86
|
+
if (followSuspended !== state.followSuspended)
|
|
87
|
+
set({ followSuspended });
|
|
88
|
+
},
|
|
89
|
+
setAppearance(appearance) {
|
|
90
|
+
set({ appearance });
|
|
91
|
+
},
|
|
92
|
+
setName(name) {
|
|
93
|
+
set({ name });
|
|
94
|
+
},
|
|
95
|
+
setRemotes(remotes) {
|
|
96
|
+
set({ remotes });
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=character-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"character-store.js","sourceRoot":"","sources":["../src/character-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CharacterStore } from "./character-store.js";
|
|
2
|
+
import type { CharacterAppearance, RemoteCharacter } from "./character-types.js";
|
|
3
|
+
/** The slice of a y-protocols `Awareness` this plugin uses. */
|
|
4
|
+
export interface CharacterAwareness {
|
|
5
|
+
clientID: number;
|
|
6
|
+
setLocalStateField(field: string, value: unknown): void;
|
|
7
|
+
getStates(): Map<number, Record<string, unknown>>;
|
|
8
|
+
on(event: "change", handler: () => void): void;
|
|
9
|
+
off(event: "change", handler: () => void): void;
|
|
10
|
+
}
|
|
11
|
+
export declare const AWARENESS_FIELD = "character";
|
|
12
|
+
/** The wire shape published under the `character` awareness field. */
|
|
13
|
+
export interface CharacterWireState {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
heading: number;
|
|
17
|
+
speed: number;
|
|
18
|
+
moving: boolean;
|
|
19
|
+
appearance: CharacterAppearance;
|
|
20
|
+
name?: string;
|
|
21
|
+
}
|
|
22
|
+
/** Validate an untrusted awareness payload (other clients can send anything). */
|
|
23
|
+
export declare function parseWireState(v: unknown): CharacterWireState | null;
|
|
24
|
+
/** Minimum interval between broadcasts (≈20 Hz) — remote views interpolate between. */
|
|
25
|
+
export declare const BROADCAST_INTERVAL_MS = 50;
|
|
26
|
+
export interface CharacterSync {
|
|
27
|
+
/** Publish the local character now if due (throttled) or `force`d. */
|
|
28
|
+
publish(force?: boolean): void;
|
|
29
|
+
/** Latest received remote targets (raw, not smoothed). */
|
|
30
|
+
targets(): ReadonlyMap<string, RemoteCharacter>;
|
|
31
|
+
dispose(): void;
|
|
32
|
+
}
|
|
33
|
+
export declare function createCharacterSync(awareness: CharacterAwareness, store: CharacterStore, onTargetsChanged: () => void, now?: () => number): CharacterSync;
|
|
34
|
+
/**
|
|
35
|
+
* Ease displayed remote poses toward their latest targets (hides the ~20 Hz
|
|
36
|
+
* update steps). Returns the next display map and whether anything is still moving.
|
|
37
|
+
*/
|
|
38
|
+
export declare function easeRemotes(display: ReadonlyMap<string, RemoteCharacter>, targets: ReadonlyMap<string, RemoteCharacter>, alpha: number): {
|
|
39
|
+
next: Map<string, RemoteCharacter>;
|
|
40
|
+
settling: boolean;
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=character-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"character-sync.d.ts","sourceRoot":"","sources":["../src/character-sync.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEjF,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACxD,SAAS,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC/C,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAChD;AAED,eAAO,MAAM,eAAe,cAAc,CAAC;AAE3C,sEAAsE;AACtE,MAAM,WAAW,kBAAkB;IAClC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,mBAAmB,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,kBAAkB,GAAG,IAAI,CAsBpE;AAED,uFAAuF;AACvF,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,MAAM,WAAW,aAAa;IAC7B,sEAAsE;IACtE,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,0DAA0D;IAC1D,OAAO,IAAI,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAChD,OAAO,IAAI,IAAI,CAAC;CAChB;AAED,wBAAgB,mBAAmB,CAClC,SAAS,EAAE,kBAAkB,EAC7B,KAAK,EAAE,cAAc,EACrB,gBAAgB,EAAE,MAAM,IAAI,EAC5B,GAAG,GAAE,MAAM,MAAyB,GAClC,aAAa,CAoDf;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAC1B,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC7C,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC7C,KAAK,EAAE,MAAM,GACX;IAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAyB3D"}
|