@almadar/ui 5.41.0 → 5.43.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/avl/index.cjs +329 -123
- package/dist/avl/index.js +329 -123
- package/dist/components/game/organisms/UncontrolledBattleBoard.d.ts +9 -1
- package/dist/components/game/organisms/physics-sim/SimulationCanvas.d.ts +8 -2
- package/dist/components/game/organisms/puzzles/sequencer/SequencerBoard.d.ts +16 -1
- package/dist/components/index.cjs +329 -123
- package/dist/components/index.js +329 -123
- package/dist/hooks/index.cjs +68 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +68 -1
- package/dist/hooks/useRenderInterpolation.d.ts +33 -0
- package/dist/providers/index.cjs +329 -123
- package/dist/providers/index.js +329 -123
- package/dist/runtime/index.cjs +329 -123
- package/dist/runtime/index.js +329 -123
- package/package.json +1 -1
package/dist/avl/index.cjs
CHANGED
|
@@ -31086,6 +31086,78 @@ var init_GameOverScreen = __esm({
|
|
|
31086
31086
|
GameOverScreen.displayName = "GameOverScreen";
|
|
31087
31087
|
}
|
|
31088
31088
|
});
|
|
31089
|
+
function useRenderInterpolation(options = {}) {
|
|
31090
|
+
const tickIntervalMs = options.tickIntervalMs ?? 1e3 / 30;
|
|
31091
|
+
const prevRef = React91.useRef(null);
|
|
31092
|
+
const currRef = React91.useRef(null);
|
|
31093
|
+
const rafRef = React91.useRef(null);
|
|
31094
|
+
const onSnapshot = React91.useCallback((entities) => {
|
|
31095
|
+
prevRef.current = currRef.current;
|
|
31096
|
+
currRef.current = { entities, arrivedAt: performance.now() };
|
|
31097
|
+
}, []);
|
|
31098
|
+
const getInterpolated = React91.useCallback((now2) => {
|
|
31099
|
+
const out = /* @__PURE__ */ new Map();
|
|
31100
|
+
const curr = currRef.current;
|
|
31101
|
+
if (!curr) return out;
|
|
31102
|
+
const prev = prevRef.current;
|
|
31103
|
+
if (!prev) {
|
|
31104
|
+
for (const e of curr.entities) out.set(e.id, { x: e.x, y: e.y });
|
|
31105
|
+
return out;
|
|
31106
|
+
}
|
|
31107
|
+
const rawAlpha = (now2 - curr.arrivedAt) / tickIntervalMs;
|
|
31108
|
+
const alpha = rawAlpha < 0 ? 0 : rawAlpha > 1 ? 1 : rawAlpha;
|
|
31109
|
+
const prevMap = /* @__PURE__ */ new Map();
|
|
31110
|
+
for (const e of prev.entities) prevMap.set(e.id, e);
|
|
31111
|
+
for (const c of curr.entities) {
|
|
31112
|
+
const p2 = prevMap.get(c.id);
|
|
31113
|
+
if (!p2) {
|
|
31114
|
+
out.set(c.id, { x: c.x, y: c.y });
|
|
31115
|
+
} else {
|
|
31116
|
+
out.set(c.id, {
|
|
31117
|
+
x: p2.x + (c.x - p2.x) * alpha,
|
|
31118
|
+
y: p2.y + (c.y - p2.y) * alpha
|
|
31119
|
+
});
|
|
31120
|
+
}
|
|
31121
|
+
}
|
|
31122
|
+
return out;
|
|
31123
|
+
}, [tickIntervalMs]);
|
|
31124
|
+
const startLoop = React91.useCallback(
|
|
31125
|
+
(draw) => {
|
|
31126
|
+
let active = true;
|
|
31127
|
+
const loop = () => {
|
|
31128
|
+
if (!active) return;
|
|
31129
|
+
try {
|
|
31130
|
+
draw(getInterpolated(performance.now()));
|
|
31131
|
+
} catch {
|
|
31132
|
+
}
|
|
31133
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
31134
|
+
};
|
|
31135
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
31136
|
+
return () => {
|
|
31137
|
+
active = false;
|
|
31138
|
+
if (rafRef.current !== null) {
|
|
31139
|
+
cancelAnimationFrame(rafRef.current);
|
|
31140
|
+
rafRef.current = null;
|
|
31141
|
+
}
|
|
31142
|
+
};
|
|
31143
|
+
},
|
|
31144
|
+
[getInterpolated]
|
|
31145
|
+
);
|
|
31146
|
+
React91.useEffect(() => {
|
|
31147
|
+
return () => {
|
|
31148
|
+
if (rafRef.current !== null) {
|
|
31149
|
+
cancelAnimationFrame(rafRef.current);
|
|
31150
|
+
rafRef.current = null;
|
|
31151
|
+
}
|
|
31152
|
+
};
|
|
31153
|
+
}, []);
|
|
31154
|
+
return { onSnapshot, getInterpolated, startLoop };
|
|
31155
|
+
}
|
|
31156
|
+
var init_useRenderInterpolation = __esm({
|
|
31157
|
+
"hooks/useRenderInterpolation.ts"() {
|
|
31158
|
+
"use client";
|
|
31159
|
+
}
|
|
31160
|
+
});
|
|
31089
31161
|
function PlatformerCanvas({
|
|
31090
31162
|
player,
|
|
31091
31163
|
platforms = [
|
|
@@ -31154,8 +31226,43 @@ function PlatformerCanvas({
|
|
|
31154
31226
|
y: 336,
|
|
31155
31227
|
width: 32,
|
|
31156
31228
|
height: 48,
|
|
31229
|
+
vx: 0,
|
|
31230
|
+
vy: 0,
|
|
31231
|
+
grounded: true,
|
|
31157
31232
|
facingRight: true
|
|
31158
31233
|
};
|
|
31234
|
+
const playerRef = React91.useRef(resolvedPlayer);
|
|
31235
|
+
playerRef.current = resolvedPlayer;
|
|
31236
|
+
const interp = useRenderInterpolation();
|
|
31237
|
+
React91.useEffect(() => {
|
|
31238
|
+
interp.onSnapshot([{ id: "player", x: resolvedPlayer.x, y: resolvedPlayer.y }]);
|
|
31239
|
+
}, [resolvedPlayer.x, resolvedPlayer.y]);
|
|
31240
|
+
const propsRef = React91.useRef({
|
|
31241
|
+
platforms,
|
|
31242
|
+
worldWidth,
|
|
31243
|
+
worldHeight,
|
|
31244
|
+
canvasWidth,
|
|
31245
|
+
canvasHeight,
|
|
31246
|
+
followCamera,
|
|
31247
|
+
bgColor,
|
|
31248
|
+
playerSprite,
|
|
31249
|
+
tileSprites,
|
|
31250
|
+
backgroundImage,
|
|
31251
|
+
assetBaseUrl
|
|
31252
|
+
});
|
|
31253
|
+
propsRef.current = {
|
|
31254
|
+
platforms,
|
|
31255
|
+
worldWidth,
|
|
31256
|
+
worldHeight,
|
|
31257
|
+
canvasWidth,
|
|
31258
|
+
canvasHeight,
|
|
31259
|
+
followCamera,
|
|
31260
|
+
bgColor,
|
|
31261
|
+
playerSprite,
|
|
31262
|
+
tileSprites,
|
|
31263
|
+
backgroundImage,
|
|
31264
|
+
assetBaseUrl
|
|
31265
|
+
};
|
|
31159
31266
|
const handleKeyDown = React91.useCallback((e) => {
|
|
31160
31267
|
if (keysRef.current.has(e.code)) return;
|
|
31161
31268
|
keysRef.current.add(e.code);
|
|
@@ -31204,124 +31311,149 @@ function PlatformerCanvas({
|
|
|
31204
31311
|
canvas.width = canvasWidth * dpr;
|
|
31205
31312
|
canvas.height = canvasHeight * dpr;
|
|
31206
31313
|
ctx.scale(dpr, dpr);
|
|
31207
|
-
|
|
31208
|
-
|
|
31209
|
-
|
|
31210
|
-
|
|
31211
|
-
|
|
31212
|
-
|
|
31213
|
-
|
|
31214
|
-
|
|
31215
|
-
|
|
31216
|
-
|
|
31217
|
-
|
|
31218
|
-
|
|
31219
|
-
|
|
31220
|
-
|
|
31221
|
-
|
|
31222
|
-
|
|
31223
|
-
|
|
31224
|
-
|
|
31225
|
-
|
|
31226
|
-
|
|
31227
|
-
|
|
31228
|
-
|
|
31229
|
-
|
|
31230
|
-
|
|
31231
|
-
|
|
31232
|
-
|
|
31233
|
-
|
|
31234
|
-
|
|
31235
|
-
|
|
31236
|
-
|
|
31237
|
-
|
|
31238
|
-
|
|
31239
|
-
|
|
31240
|
-
|
|
31241
|
-
|
|
31242
|
-
const px = plat.x - camX;
|
|
31243
|
-
const py = plat.y - camY;
|
|
31244
|
-
const platType = plat.type ?? "ground";
|
|
31245
|
-
const spriteUrl = tileSprites?.[platType];
|
|
31246
|
-
const tileImg = spriteUrl ? loadImage(spriteUrl) : null;
|
|
31247
|
-
if (tileImg) {
|
|
31248
|
-
const tileW = tileImg.naturalWidth;
|
|
31249
|
-
const tileH = tileImg.naturalHeight;
|
|
31250
|
-
const scaleH = plat.height / tileH;
|
|
31251
|
-
const scaledW = tileW * scaleH;
|
|
31252
|
-
for (let tx = 0; tx < plat.width; tx += scaledW) {
|
|
31253
|
-
const drawW = Math.min(scaledW, plat.width - tx);
|
|
31254
|
-
const srcW = drawW / scaleH;
|
|
31255
|
-
ctx.drawImage(tileImg, 0, 0, srcW, tileH, px + tx, py, drawW, plat.height);
|
|
31256
|
-
}
|
|
31314
|
+
}, [canvasWidth, canvasHeight]);
|
|
31315
|
+
React91.useEffect(() => {
|
|
31316
|
+
const drawFrame = (positions) => {
|
|
31317
|
+
const canvas = canvasRef.current;
|
|
31318
|
+
if (!canvas) return;
|
|
31319
|
+
const ctx = canvas.getContext("2d");
|
|
31320
|
+
if (!ctx) return;
|
|
31321
|
+
const {
|
|
31322
|
+
platforms: plats,
|
|
31323
|
+
worldWidth: ww,
|
|
31324
|
+
worldHeight: wh,
|
|
31325
|
+
canvasWidth: cw,
|
|
31326
|
+
canvasHeight: ch,
|
|
31327
|
+
followCamera: fc,
|
|
31328
|
+
bgColor: bg,
|
|
31329
|
+
playerSprite: pSprite,
|
|
31330
|
+
tileSprites: tSprites,
|
|
31331
|
+
backgroundImage: bgImg
|
|
31332
|
+
} = propsRef.current;
|
|
31333
|
+
const auth = playerRef.current;
|
|
31334
|
+
const interped = positions.get("player");
|
|
31335
|
+
const px = interped?.x ?? auth.x;
|
|
31336
|
+
const py = interped?.y ?? auth.y;
|
|
31337
|
+
let camX = 0;
|
|
31338
|
+
let camY = 0;
|
|
31339
|
+
if (fc) {
|
|
31340
|
+
camX = Math.max(0, Math.min(px - cw / 2, ww - cw));
|
|
31341
|
+
camY = Math.max(0, Math.min(py - ch / 2 - 50, wh - ch));
|
|
31342
|
+
}
|
|
31343
|
+
const bgImage = bgImg ? loadImage(bgImg) : null;
|
|
31344
|
+
if (bgImage) {
|
|
31345
|
+
ctx.drawImage(bgImage, 0, 0, cw, ch);
|
|
31346
|
+
} else if (bg) {
|
|
31347
|
+
ctx.fillStyle = bg;
|
|
31348
|
+
ctx.fillRect(0, 0, cw, ch);
|
|
31257
31349
|
} else {
|
|
31258
|
-
const
|
|
31259
|
-
|
|
31260
|
-
|
|
31261
|
-
ctx.fillStyle =
|
|
31262
|
-
ctx.fillRect(
|
|
31263
|
-
|
|
31264
|
-
|
|
31265
|
-
|
|
31266
|
-
|
|
31267
|
-
|
|
31268
|
-
|
|
31350
|
+
const grad = ctx.createLinearGradient(0, 0, 0, ch);
|
|
31351
|
+
grad.addColorStop(0, SKY_GRADIENT_TOP);
|
|
31352
|
+
grad.addColorStop(1, SKY_GRADIENT_BOTTOM);
|
|
31353
|
+
ctx.fillStyle = grad;
|
|
31354
|
+
ctx.fillRect(0, 0, cw, ch);
|
|
31355
|
+
}
|
|
31356
|
+
ctx.strokeStyle = GRID_COLOR;
|
|
31357
|
+
ctx.lineWidth = 1;
|
|
31358
|
+
const gridSize = 32;
|
|
31359
|
+
for (let gx = -camX % gridSize; gx < cw; gx += gridSize) {
|
|
31360
|
+
ctx.beginPath();
|
|
31361
|
+
ctx.moveTo(gx, 0);
|
|
31362
|
+
ctx.lineTo(gx, ch);
|
|
31363
|
+
ctx.stroke();
|
|
31364
|
+
}
|
|
31365
|
+
for (let gy = -camY % gridSize; gy < ch; gy += gridSize) {
|
|
31366
|
+
ctx.beginPath();
|
|
31367
|
+
ctx.moveTo(0, gy);
|
|
31368
|
+
ctx.lineTo(cw, gy);
|
|
31369
|
+
ctx.stroke();
|
|
31370
|
+
}
|
|
31371
|
+
for (const plat of plats) {
|
|
31372
|
+
const platX = plat.x - camX;
|
|
31373
|
+
const platY = plat.y - camY;
|
|
31374
|
+
const platType = plat.type ?? "ground";
|
|
31375
|
+
const spriteUrl = tSprites?.[platType];
|
|
31376
|
+
const tileImg = spriteUrl ? loadImage(spriteUrl) : null;
|
|
31377
|
+
if (tileImg) {
|
|
31378
|
+
const tileW = tileImg.naturalWidth;
|
|
31379
|
+
const tileH = tileImg.naturalHeight;
|
|
31380
|
+
const scaleH = plat.height / tileH;
|
|
31381
|
+
const scaledW = tileW * scaleH;
|
|
31382
|
+
for (let tx = 0; tx < plat.width; tx += scaledW) {
|
|
31383
|
+
const drawW = Math.min(scaledW, plat.width - tx);
|
|
31384
|
+
const srcW = drawW / scaleH;
|
|
31385
|
+
ctx.drawImage(tileImg, 0, 0, srcW, tileH, platX + tx, platY, drawW, plat.height);
|
|
31386
|
+
}
|
|
31387
|
+
} else {
|
|
31388
|
+
const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
|
|
31389
|
+
ctx.fillStyle = color;
|
|
31390
|
+
ctx.fillRect(platX, platY, plat.width, plat.height);
|
|
31391
|
+
ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
|
|
31392
|
+
ctx.fillRect(platX, platY, plat.width, 3);
|
|
31393
|
+
ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
|
|
31394
|
+
ctx.fillRect(platX, platY + plat.height - 2, plat.width, 2);
|
|
31395
|
+
if (platType === "hazard") {
|
|
31396
|
+
ctx.strokeStyle = "#e74c3c";
|
|
31397
|
+
ctx.lineWidth = 2;
|
|
31398
|
+
for (let sx = platX; sx < platX + plat.width; sx += 12) {
|
|
31399
|
+
ctx.beginPath();
|
|
31400
|
+
ctx.moveTo(sx, platY);
|
|
31401
|
+
ctx.lineTo(sx + 6, platY + plat.height);
|
|
31402
|
+
ctx.stroke();
|
|
31403
|
+
}
|
|
31404
|
+
}
|
|
31405
|
+
if (platType === "goal") {
|
|
31406
|
+
ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
|
|
31269
31407
|
ctx.beginPath();
|
|
31270
|
-
ctx.
|
|
31271
|
-
ctx.
|
|
31272
|
-
ctx.stroke();
|
|
31408
|
+
ctx.arc(platX + plat.width / 2, platY - 10, 8, 0, Math.PI * 2);
|
|
31409
|
+
ctx.fill();
|
|
31273
31410
|
}
|
|
31274
31411
|
}
|
|
31275
|
-
if (platType === "goal") {
|
|
31276
|
-
ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
|
|
31277
|
-
ctx.beginPath();
|
|
31278
|
-
ctx.arc(px + plat.width / 2, py - 10, 8, 0, Math.PI * 2);
|
|
31279
|
-
ctx.fill();
|
|
31280
|
-
}
|
|
31281
31412
|
}
|
|
31282
|
-
|
|
31283
|
-
|
|
31284
|
-
|
|
31285
|
-
|
|
31286
|
-
|
|
31287
|
-
|
|
31288
|
-
|
|
31289
|
-
|
|
31290
|
-
|
|
31291
|
-
|
|
31292
|
-
|
|
31293
|
-
|
|
31294
|
-
|
|
31413
|
+
const pw = auth.width ?? 24;
|
|
31414
|
+
const ph = auth.height ?? 32;
|
|
31415
|
+
const ppx = px - camX;
|
|
31416
|
+
const ppy = py - camY;
|
|
31417
|
+
const facingRight = auth.facingRight ?? true;
|
|
31418
|
+
const playerImg = pSprite ? loadImage(pSprite) : null;
|
|
31419
|
+
if (playerImg) {
|
|
31420
|
+
ctx.save();
|
|
31421
|
+
if (!facingRight) {
|
|
31422
|
+
ctx.translate(ppx + pw, ppy);
|
|
31423
|
+
ctx.scale(-1, 1);
|
|
31424
|
+
ctx.drawImage(playerImg, 0, 0, pw, ph);
|
|
31425
|
+
} else {
|
|
31426
|
+
ctx.drawImage(playerImg, ppx, ppy, pw, ph);
|
|
31427
|
+
}
|
|
31428
|
+
ctx.restore();
|
|
31295
31429
|
} else {
|
|
31296
|
-
ctx.
|
|
31430
|
+
ctx.fillStyle = PLAYER_COLOR;
|
|
31431
|
+
const radius = Math.min(pw, ph) * 0.25;
|
|
31432
|
+
ctx.beginPath();
|
|
31433
|
+
ctx.moveTo(ppx + radius, ppy);
|
|
31434
|
+
ctx.lineTo(ppx + pw - radius, ppy);
|
|
31435
|
+
ctx.quadraticCurveTo(ppx + pw, ppy, ppx + pw, ppy + radius);
|
|
31436
|
+
ctx.lineTo(ppx + pw, ppy + ph - radius);
|
|
31437
|
+
ctx.quadraticCurveTo(ppx + pw, ppy + ph, ppx + pw - radius, ppy + ph);
|
|
31438
|
+
ctx.lineTo(ppx + radius, ppy + ph);
|
|
31439
|
+
ctx.quadraticCurveTo(ppx, ppy + ph, ppx, ppy + ph - radius);
|
|
31440
|
+
ctx.lineTo(ppx, ppy + radius);
|
|
31441
|
+
ctx.quadraticCurveTo(ppx, ppy, ppx + radius, ppy);
|
|
31442
|
+
ctx.fill();
|
|
31443
|
+
const eyeY = ppy + ph * 0.3;
|
|
31444
|
+
const eyeSize = 3;
|
|
31445
|
+
const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
|
|
31446
|
+
ctx.fillStyle = PLAYER_EYE_COLOR;
|
|
31447
|
+
ctx.beginPath();
|
|
31448
|
+
ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
|
|
31449
|
+
ctx.fill();
|
|
31450
|
+
ctx.beginPath();
|
|
31451
|
+
ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
|
|
31452
|
+
ctx.fill();
|
|
31297
31453
|
}
|
|
31298
|
-
|
|
31299
|
-
|
|
31300
|
-
|
|
31301
|
-
const radius = Math.min(pw, ph) * 0.25;
|
|
31302
|
-
ctx.beginPath();
|
|
31303
|
-
ctx.moveTo(ppx + radius, ppy);
|
|
31304
|
-
ctx.lineTo(ppx + pw - radius, ppy);
|
|
31305
|
-
ctx.quadraticCurveTo(ppx + pw, ppy, ppx + pw, ppy + radius);
|
|
31306
|
-
ctx.lineTo(ppx + pw, ppy + ph - radius);
|
|
31307
|
-
ctx.quadraticCurveTo(ppx + pw, ppy + ph, ppx + pw - radius, ppy + ph);
|
|
31308
|
-
ctx.lineTo(ppx + radius, ppy + ph);
|
|
31309
|
-
ctx.quadraticCurveTo(ppx, ppy + ph, ppx, ppy + ph - radius);
|
|
31310
|
-
ctx.lineTo(ppx, ppy + radius);
|
|
31311
|
-
ctx.quadraticCurveTo(ppx, ppy, ppx + radius, ppy);
|
|
31312
|
-
ctx.fill();
|
|
31313
|
-
const eyeY = ppy + ph * 0.3;
|
|
31314
|
-
const eyeSize = 3;
|
|
31315
|
-
const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
|
|
31316
|
-
ctx.fillStyle = PLAYER_EYE_COLOR;
|
|
31317
|
-
ctx.beginPath();
|
|
31318
|
-
ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
|
|
31319
|
-
ctx.fill();
|
|
31320
|
-
ctx.beginPath();
|
|
31321
|
-
ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
|
|
31322
|
-
ctx.fill();
|
|
31323
|
-
}
|
|
31324
|
-
}, [player, platforms, worldWidth, worldHeight, canvasWidth, canvasHeight, followCamera, bgColor, playerSprite, tileSprites, backgroundImage, assetBaseUrl, loadedImages]);
|
|
31454
|
+
};
|
|
31455
|
+
return interp.startLoop(drawFrame);
|
|
31456
|
+
}, [interp.startLoop, loadImage]);
|
|
31325
31457
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
31326
31458
|
"canvas",
|
|
31327
31459
|
{
|
|
@@ -31339,6 +31471,7 @@ var init_PlatformerCanvas = __esm({
|
|
|
31339
31471
|
init_cn();
|
|
31340
31472
|
init_useEventBus();
|
|
31341
31473
|
init_verificationRegistry();
|
|
31474
|
+
init_useRenderInterpolation();
|
|
31342
31475
|
PLATFORM_COLORS = {
|
|
31343
31476
|
ground: "#4a7c59",
|
|
31344
31477
|
platform: "#7c6b4a",
|
|
@@ -31721,13 +31854,13 @@ var init_MapView = __esm({
|
|
|
31721
31854
|
shadowSize: [41, 41]
|
|
31722
31855
|
});
|
|
31723
31856
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
31724
|
-
const { useEffect:
|
|
31857
|
+
const { useEffect: useEffect79, useRef: useRef71, useCallback: useCallback118, useState: useState115 } = React91__namespace.default;
|
|
31725
31858
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
31726
31859
|
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
31727
31860
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
31728
31861
|
const map = useMap();
|
|
31729
|
-
const prevRef =
|
|
31730
|
-
|
|
31862
|
+
const prevRef = useRef71({ centerLat, centerLng, zoom });
|
|
31863
|
+
useEffect79(() => {
|
|
31731
31864
|
const prev = prevRef.current;
|
|
31732
31865
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
31733
31866
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -31738,7 +31871,7 @@ var init_MapView = __esm({
|
|
|
31738
31871
|
}
|
|
31739
31872
|
function MapClickHandler({ onMapClick }) {
|
|
31740
31873
|
const map = useMap();
|
|
31741
|
-
|
|
31874
|
+
useEffect79(() => {
|
|
31742
31875
|
if (!onMapClick) return;
|
|
31743
31876
|
const handler = (e) => {
|
|
31744
31877
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -31767,7 +31900,7 @@ var init_MapView = __esm({
|
|
|
31767
31900
|
}) {
|
|
31768
31901
|
const eventBus = useEventBus3();
|
|
31769
31902
|
const [clickedPosition, setClickedPosition] = useState115(null);
|
|
31770
|
-
const handleMapClick =
|
|
31903
|
+
const handleMapClick = useCallback118((lat, lng) => {
|
|
31771
31904
|
if (showClickedPin) {
|
|
31772
31905
|
setClickedPosition({ lat, lng });
|
|
31773
31906
|
}
|
|
@@ -31776,7 +31909,7 @@ var init_MapView = __esm({
|
|
|
31776
31909
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
31777
31910
|
}
|
|
31778
31911
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
31779
|
-
const handleMarkerClick =
|
|
31912
|
+
const handleMarkerClick = useCallback118((marker) => {
|
|
31780
31913
|
onMarkerClick?.(marker);
|
|
31781
31914
|
if (markerClickEvent) {
|
|
31782
31915
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -46871,6 +47004,10 @@ function SequencerBoard({
|
|
|
46871
47004
|
stepDurationMs = 1e3,
|
|
46872
47005
|
playEvent,
|
|
46873
47006
|
completeEvent,
|
|
47007
|
+
placeEvent,
|
|
47008
|
+
removeEvent,
|
|
47009
|
+
checkEvent,
|
|
47010
|
+
playAgainEvent,
|
|
46874
47011
|
className
|
|
46875
47012
|
}) {
|
|
46876
47013
|
const { emit } = useEventBus();
|
|
@@ -46906,7 +47043,8 @@ function SequencerBoard({
|
|
|
46906
47043
|
return next;
|
|
46907
47044
|
});
|
|
46908
47045
|
emit("UI:PLAY_SOUND", { key: "drop_slot" });
|
|
46909
|
-
|
|
47046
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotIndex: index, actionId: item.id });
|
|
47047
|
+
}, [emit, placeEvent]);
|
|
46910
47048
|
const handleSlotRemove = React91.useCallback((index) => {
|
|
46911
47049
|
setSlots((prev) => {
|
|
46912
47050
|
const next = [...prev];
|
|
@@ -46919,7 +47057,8 @@ function SequencerBoard({
|
|
|
46919
47057
|
return next;
|
|
46920
47058
|
});
|
|
46921
47059
|
emit("UI:PLAY_SOUND", { key: "back" });
|
|
46922
|
-
|
|
47060
|
+
if (removeEvent) emit(`UI:${removeEvent}`, { slotIndex: index });
|
|
47061
|
+
}, [emit, removeEvent]);
|
|
46923
47062
|
const handleReset = React91.useCallback(() => {
|
|
46924
47063
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
46925
47064
|
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
@@ -46927,7 +47066,8 @@ function SequencerBoard({
|
|
|
46927
47066
|
setCurrentStep(-1);
|
|
46928
47067
|
setAttempts(0);
|
|
46929
47068
|
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
46930
|
-
|
|
47069
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
47070
|
+
}, [maxSlots, playAgainEvent, emit]);
|
|
46931
47071
|
const filledSlots = slots.filter((s) => !!s);
|
|
46932
47072
|
const canPlay = filledSlots.length > 0 && playState === "idle";
|
|
46933
47073
|
const handlePlay = React91.useCallback(() => {
|
|
@@ -46949,6 +47089,7 @@ function SequencerBoard({
|
|
|
46949
47089
|
const success = solutions.some(
|
|
46950
47090
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
46951
47091
|
);
|
|
47092
|
+
if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
|
|
46952
47093
|
if (success) {
|
|
46953
47094
|
setPlayState("success");
|
|
46954
47095
|
setCurrentStep(-1);
|
|
@@ -46976,7 +47117,7 @@ function SequencerBoard({
|
|
|
46976
47117
|
}
|
|
46977
47118
|
};
|
|
46978
47119
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
46979
|
-
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, emit]);
|
|
47120
|
+
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, checkEvent, emit]);
|
|
46980
47121
|
const machine = {
|
|
46981
47122
|
name: str(resolved?.title),
|
|
46982
47123
|
description: str(resolved?.description),
|
|
@@ -47231,11 +47372,13 @@ function SimulationCanvas({
|
|
|
47231
47372
|
height = 400,
|
|
47232
47373
|
running,
|
|
47233
47374
|
speed = 1,
|
|
47375
|
+
bodies: externalBodies,
|
|
47234
47376
|
className
|
|
47235
47377
|
}) {
|
|
47236
47378
|
const preset = React91.useMemo(() => resolvePreset(presetProp), [presetProp]);
|
|
47237
47379
|
const canvasRef = React91.useRef(null);
|
|
47238
47380
|
const bodiesRef = React91.useRef(structuredClone(preset.bodies));
|
|
47381
|
+
const interp = useRenderInterpolation();
|
|
47239
47382
|
React91.useEffect(() => {
|
|
47240
47383
|
bodiesRef.current = structuredClone(preset.bodies);
|
|
47241
47384
|
}, [preset]);
|
|
@@ -47333,6 +47476,67 @@ function SimulationCanvas({
|
|
|
47333
47476
|
}
|
|
47334
47477
|
}, [width, height, preset]);
|
|
47335
47478
|
React91.useEffect(() => {
|
|
47479
|
+
if (!externalBodies) return;
|
|
47480
|
+
interp.onSnapshot(externalBodies.map((b) => ({ id: b.id, x: b.x, y: b.y })));
|
|
47481
|
+
}, [externalBodies]);
|
|
47482
|
+
const presetRef = React91.useRef(preset);
|
|
47483
|
+
presetRef.current = preset;
|
|
47484
|
+
const widthRef = React91.useRef(width);
|
|
47485
|
+
widthRef.current = width;
|
|
47486
|
+
const heightRef = React91.useRef(height);
|
|
47487
|
+
heightRef.current = height;
|
|
47488
|
+
React91.useEffect(() => {
|
|
47489
|
+
if (!externalBodies) return;
|
|
47490
|
+
const drawInterpolated = (positions) => {
|
|
47491
|
+
const canvas = canvasRef.current;
|
|
47492
|
+
if (!canvas) return;
|
|
47493
|
+
const ctx = canvas.getContext("2d");
|
|
47494
|
+
if (!ctx) return;
|
|
47495
|
+
const bodies = bodiesRef.current;
|
|
47496
|
+
const p2 = presetRef.current;
|
|
47497
|
+
const w = widthRef.current;
|
|
47498
|
+
const h = heightRef.current;
|
|
47499
|
+
ctx.clearRect(0, 0, w, h);
|
|
47500
|
+
ctx.fillStyle = p2.backgroundColor ?? "#1a1a2e";
|
|
47501
|
+
ctx.fillRect(0, 0, w, h);
|
|
47502
|
+
if (p2.constraints) {
|
|
47503
|
+
for (const c of p2.constraints) {
|
|
47504
|
+
const a = bodies[c.bodyA];
|
|
47505
|
+
const b = bodies[c.bodyB];
|
|
47506
|
+
if (a && b) {
|
|
47507
|
+
const aPos = positions.get(a.id) ?? a;
|
|
47508
|
+
const bPos = positions.get(b.id) ?? b;
|
|
47509
|
+
ctx.beginPath();
|
|
47510
|
+
ctx.moveTo(aPos.x, aPos.y);
|
|
47511
|
+
ctx.lineTo(bPos.x, bPos.y);
|
|
47512
|
+
ctx.strokeStyle = "#533483";
|
|
47513
|
+
ctx.lineWidth = 1;
|
|
47514
|
+
ctx.setLineDash([4, 4]);
|
|
47515
|
+
ctx.stroke();
|
|
47516
|
+
ctx.setLineDash([]);
|
|
47517
|
+
}
|
|
47518
|
+
}
|
|
47519
|
+
}
|
|
47520
|
+
for (const body of bodies) {
|
|
47521
|
+
const pos = positions.get(body.id) ?? body;
|
|
47522
|
+
ctx.beginPath();
|
|
47523
|
+
ctx.arc(pos.x, pos.y, body.radius, 0, Math.PI * 2);
|
|
47524
|
+
ctx.fillStyle = body.color ?? "#e94560";
|
|
47525
|
+
ctx.fill();
|
|
47526
|
+
if (p2.showVelocity) {
|
|
47527
|
+
ctx.beginPath();
|
|
47528
|
+
ctx.moveTo(pos.x, pos.y);
|
|
47529
|
+
ctx.lineTo(pos.x + body.vx * 0.1, pos.y + body.vy * 0.1);
|
|
47530
|
+
ctx.strokeStyle = "#16213e";
|
|
47531
|
+
ctx.lineWidth = 2;
|
|
47532
|
+
ctx.stroke();
|
|
47533
|
+
}
|
|
47534
|
+
}
|
|
47535
|
+
};
|
|
47536
|
+
return interp.startLoop(drawInterpolated);
|
|
47537
|
+
}, [externalBodies !== void 0, interp.startLoop]);
|
|
47538
|
+
React91.useEffect(() => {
|
|
47539
|
+
if (externalBodies !== void 0) return;
|
|
47336
47540
|
if (!running) return;
|
|
47337
47541
|
let raf;
|
|
47338
47542
|
const loop = () => {
|
|
@@ -47342,10 +47546,11 @@ function SimulationCanvas({
|
|
|
47342
47546
|
};
|
|
47343
47547
|
raf = requestAnimationFrame(loop);
|
|
47344
47548
|
return () => cancelAnimationFrame(raf);
|
|
47345
|
-
}, [running, step, draw]);
|
|
47549
|
+
}, [running, step, draw, externalBodies]);
|
|
47346
47550
|
React91.useEffect(() => {
|
|
47551
|
+
if (externalBodies !== void 0) return;
|
|
47347
47552
|
draw();
|
|
47348
|
-
}, [draw]);
|
|
47553
|
+
}, [draw, externalBodies]);
|
|
47349
47554
|
React91.useEffect(() => {
|
|
47350
47555
|
if (typeof window === "undefined") return;
|
|
47351
47556
|
const canvas = canvasRef.current;
|
|
@@ -47371,6 +47576,7 @@ var init_SimulationCanvas = __esm({
|
|
|
47371
47576
|
init_atoms2();
|
|
47372
47577
|
init_verificationRegistry();
|
|
47373
47578
|
init_presets();
|
|
47579
|
+
init_useRenderInterpolation();
|
|
47374
47580
|
SimulationCanvas.displayName = "SimulationCanvas";
|
|
47375
47581
|
}
|
|
47376
47582
|
});
|