@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/runtime/index.cjs
CHANGED
|
@@ -28176,6 +28176,78 @@ var init_GameOverScreen = __esm({
|
|
|
28176
28176
|
GameOverScreen.displayName = "GameOverScreen";
|
|
28177
28177
|
}
|
|
28178
28178
|
});
|
|
28179
|
+
function useRenderInterpolation(options = {}) {
|
|
28180
|
+
const tickIntervalMs = options.tickIntervalMs ?? 1e3 / 30;
|
|
28181
|
+
const prevRef = React82.useRef(null);
|
|
28182
|
+
const currRef = React82.useRef(null);
|
|
28183
|
+
const rafRef = React82.useRef(null);
|
|
28184
|
+
const onSnapshot = React82.useCallback((entities) => {
|
|
28185
|
+
prevRef.current = currRef.current;
|
|
28186
|
+
currRef.current = { entities, arrivedAt: performance.now() };
|
|
28187
|
+
}, []);
|
|
28188
|
+
const getInterpolated = React82.useCallback((now2) => {
|
|
28189
|
+
const out = /* @__PURE__ */ new Map();
|
|
28190
|
+
const curr = currRef.current;
|
|
28191
|
+
if (!curr) return out;
|
|
28192
|
+
const prev = prevRef.current;
|
|
28193
|
+
if (!prev) {
|
|
28194
|
+
for (const e of curr.entities) out.set(e.id, { x: e.x, y: e.y });
|
|
28195
|
+
return out;
|
|
28196
|
+
}
|
|
28197
|
+
const rawAlpha = (now2 - curr.arrivedAt) / tickIntervalMs;
|
|
28198
|
+
const alpha = rawAlpha < 0 ? 0 : rawAlpha > 1 ? 1 : rawAlpha;
|
|
28199
|
+
const prevMap = /* @__PURE__ */ new Map();
|
|
28200
|
+
for (const e of prev.entities) prevMap.set(e.id, e);
|
|
28201
|
+
for (const c of curr.entities) {
|
|
28202
|
+
const p2 = prevMap.get(c.id);
|
|
28203
|
+
if (!p2) {
|
|
28204
|
+
out.set(c.id, { x: c.x, y: c.y });
|
|
28205
|
+
} else {
|
|
28206
|
+
out.set(c.id, {
|
|
28207
|
+
x: p2.x + (c.x - p2.x) * alpha,
|
|
28208
|
+
y: p2.y + (c.y - p2.y) * alpha
|
|
28209
|
+
});
|
|
28210
|
+
}
|
|
28211
|
+
}
|
|
28212
|
+
return out;
|
|
28213
|
+
}, [tickIntervalMs]);
|
|
28214
|
+
const startLoop = React82.useCallback(
|
|
28215
|
+
(draw) => {
|
|
28216
|
+
let active = true;
|
|
28217
|
+
const loop = () => {
|
|
28218
|
+
if (!active) return;
|
|
28219
|
+
try {
|
|
28220
|
+
draw(getInterpolated(performance.now()));
|
|
28221
|
+
} catch {
|
|
28222
|
+
}
|
|
28223
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
28224
|
+
};
|
|
28225
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
28226
|
+
return () => {
|
|
28227
|
+
active = false;
|
|
28228
|
+
if (rafRef.current !== null) {
|
|
28229
|
+
cancelAnimationFrame(rafRef.current);
|
|
28230
|
+
rafRef.current = null;
|
|
28231
|
+
}
|
|
28232
|
+
};
|
|
28233
|
+
},
|
|
28234
|
+
[getInterpolated]
|
|
28235
|
+
);
|
|
28236
|
+
React82.useEffect(() => {
|
|
28237
|
+
return () => {
|
|
28238
|
+
if (rafRef.current !== null) {
|
|
28239
|
+
cancelAnimationFrame(rafRef.current);
|
|
28240
|
+
rafRef.current = null;
|
|
28241
|
+
}
|
|
28242
|
+
};
|
|
28243
|
+
}, []);
|
|
28244
|
+
return { onSnapshot, getInterpolated, startLoop };
|
|
28245
|
+
}
|
|
28246
|
+
var init_useRenderInterpolation = __esm({
|
|
28247
|
+
"hooks/useRenderInterpolation.ts"() {
|
|
28248
|
+
"use client";
|
|
28249
|
+
}
|
|
28250
|
+
});
|
|
28179
28251
|
function PlatformerCanvas({
|
|
28180
28252
|
player,
|
|
28181
28253
|
platforms = [
|
|
@@ -28244,8 +28316,43 @@ function PlatformerCanvas({
|
|
|
28244
28316
|
y: 336,
|
|
28245
28317
|
width: 32,
|
|
28246
28318
|
height: 48,
|
|
28319
|
+
vx: 0,
|
|
28320
|
+
vy: 0,
|
|
28321
|
+
grounded: true,
|
|
28247
28322
|
facingRight: true
|
|
28248
28323
|
};
|
|
28324
|
+
const playerRef = React82.useRef(resolvedPlayer);
|
|
28325
|
+
playerRef.current = resolvedPlayer;
|
|
28326
|
+
const interp = useRenderInterpolation();
|
|
28327
|
+
React82.useEffect(() => {
|
|
28328
|
+
interp.onSnapshot([{ id: "player", x: resolvedPlayer.x, y: resolvedPlayer.y }]);
|
|
28329
|
+
}, [resolvedPlayer.x, resolvedPlayer.y]);
|
|
28330
|
+
const propsRef = React82.useRef({
|
|
28331
|
+
platforms,
|
|
28332
|
+
worldWidth,
|
|
28333
|
+
worldHeight,
|
|
28334
|
+
canvasWidth,
|
|
28335
|
+
canvasHeight,
|
|
28336
|
+
followCamera,
|
|
28337
|
+
bgColor,
|
|
28338
|
+
playerSprite,
|
|
28339
|
+
tileSprites,
|
|
28340
|
+
backgroundImage,
|
|
28341
|
+
assetBaseUrl
|
|
28342
|
+
});
|
|
28343
|
+
propsRef.current = {
|
|
28344
|
+
platforms,
|
|
28345
|
+
worldWidth,
|
|
28346
|
+
worldHeight,
|
|
28347
|
+
canvasWidth,
|
|
28348
|
+
canvasHeight,
|
|
28349
|
+
followCamera,
|
|
28350
|
+
bgColor,
|
|
28351
|
+
playerSprite,
|
|
28352
|
+
tileSprites,
|
|
28353
|
+
backgroundImage,
|
|
28354
|
+
assetBaseUrl
|
|
28355
|
+
};
|
|
28249
28356
|
const handleKeyDown = React82.useCallback((e) => {
|
|
28250
28357
|
if (keysRef.current.has(e.code)) return;
|
|
28251
28358
|
keysRef.current.add(e.code);
|
|
@@ -28294,124 +28401,149 @@ function PlatformerCanvas({
|
|
|
28294
28401
|
canvas.width = canvasWidth * dpr;
|
|
28295
28402
|
canvas.height = canvasHeight * dpr;
|
|
28296
28403
|
ctx.scale(dpr, dpr);
|
|
28297
|
-
|
|
28298
|
-
|
|
28299
|
-
|
|
28300
|
-
|
|
28301
|
-
|
|
28302
|
-
|
|
28303
|
-
|
|
28304
|
-
|
|
28305
|
-
|
|
28306
|
-
|
|
28307
|
-
|
|
28308
|
-
|
|
28309
|
-
|
|
28310
|
-
|
|
28311
|
-
|
|
28312
|
-
|
|
28313
|
-
|
|
28314
|
-
|
|
28315
|
-
|
|
28316
|
-
|
|
28317
|
-
|
|
28318
|
-
|
|
28319
|
-
|
|
28320
|
-
|
|
28321
|
-
|
|
28322
|
-
|
|
28323
|
-
|
|
28324
|
-
|
|
28325
|
-
|
|
28326
|
-
|
|
28327
|
-
|
|
28328
|
-
|
|
28329
|
-
|
|
28330
|
-
|
|
28331
|
-
|
|
28332
|
-
const px = plat.x - camX;
|
|
28333
|
-
const py = plat.y - camY;
|
|
28334
|
-
const platType = plat.type ?? "ground";
|
|
28335
|
-
const spriteUrl = tileSprites?.[platType];
|
|
28336
|
-
const tileImg = spriteUrl ? loadImage(spriteUrl) : null;
|
|
28337
|
-
if (tileImg) {
|
|
28338
|
-
const tileW = tileImg.naturalWidth;
|
|
28339
|
-
const tileH = tileImg.naturalHeight;
|
|
28340
|
-
const scaleH = plat.height / tileH;
|
|
28341
|
-
const scaledW = tileW * scaleH;
|
|
28342
|
-
for (let tx = 0; tx < plat.width; tx += scaledW) {
|
|
28343
|
-
const drawW = Math.min(scaledW, plat.width - tx);
|
|
28344
|
-
const srcW = drawW / scaleH;
|
|
28345
|
-
ctx.drawImage(tileImg, 0, 0, srcW, tileH, px + tx, py, drawW, plat.height);
|
|
28346
|
-
}
|
|
28404
|
+
}, [canvasWidth, canvasHeight]);
|
|
28405
|
+
React82.useEffect(() => {
|
|
28406
|
+
const drawFrame = (positions) => {
|
|
28407
|
+
const canvas = canvasRef.current;
|
|
28408
|
+
if (!canvas) return;
|
|
28409
|
+
const ctx = canvas.getContext("2d");
|
|
28410
|
+
if (!ctx) return;
|
|
28411
|
+
const {
|
|
28412
|
+
platforms: plats,
|
|
28413
|
+
worldWidth: ww,
|
|
28414
|
+
worldHeight: wh,
|
|
28415
|
+
canvasWidth: cw,
|
|
28416
|
+
canvasHeight: ch,
|
|
28417
|
+
followCamera: fc,
|
|
28418
|
+
bgColor: bg,
|
|
28419
|
+
playerSprite: pSprite,
|
|
28420
|
+
tileSprites: tSprites,
|
|
28421
|
+
backgroundImage: bgImg
|
|
28422
|
+
} = propsRef.current;
|
|
28423
|
+
const auth = playerRef.current;
|
|
28424
|
+
const interped = positions.get("player");
|
|
28425
|
+
const px = interped?.x ?? auth.x;
|
|
28426
|
+
const py = interped?.y ?? auth.y;
|
|
28427
|
+
let camX = 0;
|
|
28428
|
+
let camY = 0;
|
|
28429
|
+
if (fc) {
|
|
28430
|
+
camX = Math.max(0, Math.min(px - cw / 2, ww - cw));
|
|
28431
|
+
camY = Math.max(0, Math.min(py - ch / 2 - 50, wh - ch));
|
|
28432
|
+
}
|
|
28433
|
+
const bgImage = bgImg ? loadImage(bgImg) : null;
|
|
28434
|
+
if (bgImage) {
|
|
28435
|
+
ctx.drawImage(bgImage, 0, 0, cw, ch);
|
|
28436
|
+
} else if (bg) {
|
|
28437
|
+
ctx.fillStyle = bg;
|
|
28438
|
+
ctx.fillRect(0, 0, cw, ch);
|
|
28347
28439
|
} else {
|
|
28348
|
-
const
|
|
28349
|
-
|
|
28350
|
-
|
|
28351
|
-
ctx.fillStyle =
|
|
28352
|
-
ctx.fillRect(
|
|
28353
|
-
|
|
28354
|
-
|
|
28355
|
-
|
|
28356
|
-
|
|
28357
|
-
|
|
28358
|
-
|
|
28440
|
+
const grad = ctx.createLinearGradient(0, 0, 0, ch);
|
|
28441
|
+
grad.addColorStop(0, SKY_GRADIENT_TOP);
|
|
28442
|
+
grad.addColorStop(1, SKY_GRADIENT_BOTTOM);
|
|
28443
|
+
ctx.fillStyle = grad;
|
|
28444
|
+
ctx.fillRect(0, 0, cw, ch);
|
|
28445
|
+
}
|
|
28446
|
+
ctx.strokeStyle = GRID_COLOR;
|
|
28447
|
+
ctx.lineWidth = 1;
|
|
28448
|
+
const gridSize = 32;
|
|
28449
|
+
for (let gx = -camX % gridSize; gx < cw; gx += gridSize) {
|
|
28450
|
+
ctx.beginPath();
|
|
28451
|
+
ctx.moveTo(gx, 0);
|
|
28452
|
+
ctx.lineTo(gx, ch);
|
|
28453
|
+
ctx.stroke();
|
|
28454
|
+
}
|
|
28455
|
+
for (let gy = -camY % gridSize; gy < ch; gy += gridSize) {
|
|
28456
|
+
ctx.beginPath();
|
|
28457
|
+
ctx.moveTo(0, gy);
|
|
28458
|
+
ctx.lineTo(cw, gy);
|
|
28459
|
+
ctx.stroke();
|
|
28460
|
+
}
|
|
28461
|
+
for (const plat of plats) {
|
|
28462
|
+
const platX = plat.x - camX;
|
|
28463
|
+
const platY = plat.y - camY;
|
|
28464
|
+
const platType = plat.type ?? "ground";
|
|
28465
|
+
const spriteUrl = tSprites?.[platType];
|
|
28466
|
+
const tileImg = spriteUrl ? loadImage(spriteUrl) : null;
|
|
28467
|
+
if (tileImg) {
|
|
28468
|
+
const tileW = tileImg.naturalWidth;
|
|
28469
|
+
const tileH = tileImg.naturalHeight;
|
|
28470
|
+
const scaleH = plat.height / tileH;
|
|
28471
|
+
const scaledW = tileW * scaleH;
|
|
28472
|
+
for (let tx = 0; tx < plat.width; tx += scaledW) {
|
|
28473
|
+
const drawW = Math.min(scaledW, plat.width - tx);
|
|
28474
|
+
const srcW = drawW / scaleH;
|
|
28475
|
+
ctx.drawImage(tileImg, 0, 0, srcW, tileH, platX + tx, platY, drawW, plat.height);
|
|
28476
|
+
}
|
|
28477
|
+
} else {
|
|
28478
|
+
const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
|
|
28479
|
+
ctx.fillStyle = color;
|
|
28480
|
+
ctx.fillRect(platX, platY, plat.width, plat.height);
|
|
28481
|
+
ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
|
|
28482
|
+
ctx.fillRect(platX, platY, plat.width, 3);
|
|
28483
|
+
ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
|
|
28484
|
+
ctx.fillRect(platX, platY + plat.height - 2, plat.width, 2);
|
|
28485
|
+
if (platType === "hazard") {
|
|
28486
|
+
ctx.strokeStyle = "#e74c3c";
|
|
28487
|
+
ctx.lineWidth = 2;
|
|
28488
|
+
for (let sx = platX; sx < platX + plat.width; sx += 12) {
|
|
28489
|
+
ctx.beginPath();
|
|
28490
|
+
ctx.moveTo(sx, platY);
|
|
28491
|
+
ctx.lineTo(sx + 6, platY + plat.height);
|
|
28492
|
+
ctx.stroke();
|
|
28493
|
+
}
|
|
28494
|
+
}
|
|
28495
|
+
if (platType === "goal") {
|
|
28496
|
+
ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
|
|
28359
28497
|
ctx.beginPath();
|
|
28360
|
-
ctx.
|
|
28361
|
-
ctx.
|
|
28362
|
-
ctx.stroke();
|
|
28498
|
+
ctx.arc(platX + plat.width / 2, platY - 10, 8, 0, Math.PI * 2);
|
|
28499
|
+
ctx.fill();
|
|
28363
28500
|
}
|
|
28364
28501
|
}
|
|
28365
|
-
if (platType === "goal") {
|
|
28366
|
-
ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
|
|
28367
|
-
ctx.beginPath();
|
|
28368
|
-
ctx.arc(px + plat.width / 2, py - 10, 8, 0, Math.PI * 2);
|
|
28369
|
-
ctx.fill();
|
|
28370
|
-
}
|
|
28371
28502
|
}
|
|
28372
|
-
|
|
28373
|
-
|
|
28374
|
-
|
|
28375
|
-
|
|
28376
|
-
|
|
28377
|
-
|
|
28378
|
-
|
|
28379
|
-
|
|
28380
|
-
|
|
28381
|
-
|
|
28382
|
-
|
|
28383
|
-
|
|
28384
|
-
|
|
28503
|
+
const pw = auth.width ?? 24;
|
|
28504
|
+
const ph = auth.height ?? 32;
|
|
28505
|
+
const ppx = px - camX;
|
|
28506
|
+
const ppy = py - camY;
|
|
28507
|
+
const facingRight = auth.facingRight ?? true;
|
|
28508
|
+
const playerImg = pSprite ? loadImage(pSprite) : null;
|
|
28509
|
+
if (playerImg) {
|
|
28510
|
+
ctx.save();
|
|
28511
|
+
if (!facingRight) {
|
|
28512
|
+
ctx.translate(ppx + pw, ppy);
|
|
28513
|
+
ctx.scale(-1, 1);
|
|
28514
|
+
ctx.drawImage(playerImg, 0, 0, pw, ph);
|
|
28515
|
+
} else {
|
|
28516
|
+
ctx.drawImage(playerImg, ppx, ppy, pw, ph);
|
|
28517
|
+
}
|
|
28518
|
+
ctx.restore();
|
|
28385
28519
|
} else {
|
|
28386
|
-
ctx.
|
|
28520
|
+
ctx.fillStyle = PLAYER_COLOR;
|
|
28521
|
+
const radius = Math.min(pw, ph) * 0.25;
|
|
28522
|
+
ctx.beginPath();
|
|
28523
|
+
ctx.moveTo(ppx + radius, ppy);
|
|
28524
|
+
ctx.lineTo(ppx + pw - radius, ppy);
|
|
28525
|
+
ctx.quadraticCurveTo(ppx + pw, ppy, ppx + pw, ppy + radius);
|
|
28526
|
+
ctx.lineTo(ppx + pw, ppy + ph - radius);
|
|
28527
|
+
ctx.quadraticCurveTo(ppx + pw, ppy + ph, ppx + pw - radius, ppy + ph);
|
|
28528
|
+
ctx.lineTo(ppx + radius, ppy + ph);
|
|
28529
|
+
ctx.quadraticCurveTo(ppx, ppy + ph, ppx, ppy + ph - radius);
|
|
28530
|
+
ctx.lineTo(ppx, ppy + radius);
|
|
28531
|
+
ctx.quadraticCurveTo(ppx, ppy, ppx + radius, ppy);
|
|
28532
|
+
ctx.fill();
|
|
28533
|
+
const eyeY = ppy + ph * 0.3;
|
|
28534
|
+
const eyeSize = 3;
|
|
28535
|
+
const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
|
|
28536
|
+
ctx.fillStyle = PLAYER_EYE_COLOR;
|
|
28537
|
+
ctx.beginPath();
|
|
28538
|
+
ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
|
|
28539
|
+
ctx.fill();
|
|
28540
|
+
ctx.beginPath();
|
|
28541
|
+
ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
|
|
28542
|
+
ctx.fill();
|
|
28387
28543
|
}
|
|
28388
|
-
|
|
28389
|
-
|
|
28390
|
-
|
|
28391
|
-
const radius = Math.min(pw, ph) * 0.25;
|
|
28392
|
-
ctx.beginPath();
|
|
28393
|
-
ctx.moveTo(ppx + radius, ppy);
|
|
28394
|
-
ctx.lineTo(ppx + pw - radius, ppy);
|
|
28395
|
-
ctx.quadraticCurveTo(ppx + pw, ppy, ppx + pw, ppy + radius);
|
|
28396
|
-
ctx.lineTo(ppx + pw, ppy + ph - radius);
|
|
28397
|
-
ctx.quadraticCurveTo(ppx + pw, ppy + ph, ppx + pw - radius, ppy + ph);
|
|
28398
|
-
ctx.lineTo(ppx + radius, ppy + ph);
|
|
28399
|
-
ctx.quadraticCurveTo(ppx, ppy + ph, ppx, ppy + ph - radius);
|
|
28400
|
-
ctx.lineTo(ppx, ppy + radius);
|
|
28401
|
-
ctx.quadraticCurveTo(ppx, ppy, ppx + radius, ppy);
|
|
28402
|
-
ctx.fill();
|
|
28403
|
-
const eyeY = ppy + ph * 0.3;
|
|
28404
|
-
const eyeSize = 3;
|
|
28405
|
-
const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
|
|
28406
|
-
ctx.fillStyle = PLAYER_EYE_COLOR;
|
|
28407
|
-
ctx.beginPath();
|
|
28408
|
-
ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
|
|
28409
|
-
ctx.fill();
|
|
28410
|
-
ctx.beginPath();
|
|
28411
|
-
ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
|
|
28412
|
-
ctx.fill();
|
|
28413
|
-
}
|
|
28414
|
-
}, [player, platforms, worldWidth, worldHeight, canvasWidth, canvasHeight, followCamera, bgColor, playerSprite, tileSprites, backgroundImage, assetBaseUrl, loadedImages]);
|
|
28544
|
+
};
|
|
28545
|
+
return interp.startLoop(drawFrame);
|
|
28546
|
+
}, [interp.startLoop, loadImage]);
|
|
28415
28547
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
28416
28548
|
"canvas",
|
|
28417
28549
|
{
|
|
@@ -28429,6 +28561,7 @@ var init_PlatformerCanvas = __esm({
|
|
|
28429
28561
|
init_cn();
|
|
28430
28562
|
init_useEventBus();
|
|
28431
28563
|
init_verificationRegistry();
|
|
28564
|
+
init_useRenderInterpolation();
|
|
28432
28565
|
PLATFORM_COLORS = {
|
|
28433
28566
|
ground: "#4a7c59",
|
|
28434
28567
|
platform: "#7c6b4a",
|
|
@@ -28811,13 +28944,13 @@ var init_MapView = __esm({
|
|
|
28811
28944
|
shadowSize: [41, 41]
|
|
28812
28945
|
});
|
|
28813
28946
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
28814
|
-
const { useEffect:
|
|
28947
|
+
const { useEffect: useEffect75, useRef: useRef69, useCallback: useCallback112, useState: useState107 } = React82__namespace.default;
|
|
28815
28948
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
28816
28949
|
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
28817
28950
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
28818
28951
|
const map = useMap();
|
|
28819
|
-
const prevRef =
|
|
28820
|
-
|
|
28952
|
+
const prevRef = useRef69({ centerLat, centerLng, zoom });
|
|
28953
|
+
useEffect75(() => {
|
|
28821
28954
|
const prev = prevRef.current;
|
|
28822
28955
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
28823
28956
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -28828,7 +28961,7 @@ var init_MapView = __esm({
|
|
|
28828
28961
|
}
|
|
28829
28962
|
function MapClickHandler({ onMapClick }) {
|
|
28830
28963
|
const map = useMap();
|
|
28831
|
-
|
|
28964
|
+
useEffect75(() => {
|
|
28832
28965
|
if (!onMapClick) return;
|
|
28833
28966
|
const handler = (e) => {
|
|
28834
28967
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -28857,7 +28990,7 @@ var init_MapView = __esm({
|
|
|
28857
28990
|
}) {
|
|
28858
28991
|
const eventBus = useEventBus3();
|
|
28859
28992
|
const [clickedPosition, setClickedPosition] = useState107(null);
|
|
28860
|
-
const handleMapClick =
|
|
28993
|
+
const handleMapClick = useCallback112((lat, lng) => {
|
|
28861
28994
|
if (showClickedPin) {
|
|
28862
28995
|
setClickedPosition({ lat, lng });
|
|
28863
28996
|
}
|
|
@@ -28866,7 +28999,7 @@ var init_MapView = __esm({
|
|
|
28866
28999
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
28867
29000
|
}
|
|
28868
29001
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
28869
|
-
const handleMarkerClick =
|
|
29002
|
+
const handleMarkerClick = useCallback112((marker) => {
|
|
28870
29003
|
onMarkerClick?.(marker);
|
|
28871
29004
|
if (markerClickEvent) {
|
|
28872
29005
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -44370,6 +44503,10 @@ function SequencerBoard({
|
|
|
44370
44503
|
stepDurationMs = 1e3,
|
|
44371
44504
|
playEvent,
|
|
44372
44505
|
completeEvent,
|
|
44506
|
+
placeEvent,
|
|
44507
|
+
removeEvent,
|
|
44508
|
+
checkEvent,
|
|
44509
|
+
playAgainEvent,
|
|
44373
44510
|
className
|
|
44374
44511
|
}) {
|
|
44375
44512
|
const { emit } = useEventBus();
|
|
@@ -44405,7 +44542,8 @@ function SequencerBoard({
|
|
|
44405
44542
|
return next;
|
|
44406
44543
|
});
|
|
44407
44544
|
emit("UI:PLAY_SOUND", { key: "drop_slot" });
|
|
44408
|
-
|
|
44545
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotIndex: index, actionId: item.id });
|
|
44546
|
+
}, [emit, placeEvent]);
|
|
44409
44547
|
const handleSlotRemove = React82.useCallback((index) => {
|
|
44410
44548
|
setSlots((prev) => {
|
|
44411
44549
|
const next = [...prev];
|
|
@@ -44418,7 +44556,8 @@ function SequencerBoard({
|
|
|
44418
44556
|
return next;
|
|
44419
44557
|
});
|
|
44420
44558
|
emit("UI:PLAY_SOUND", { key: "back" });
|
|
44421
|
-
|
|
44559
|
+
if (removeEvent) emit(`UI:${removeEvent}`, { slotIndex: index });
|
|
44560
|
+
}, [emit, removeEvent]);
|
|
44422
44561
|
const handleReset = React82.useCallback(() => {
|
|
44423
44562
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
44424
44563
|
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
@@ -44426,7 +44565,8 @@ function SequencerBoard({
|
|
|
44426
44565
|
setCurrentStep(-1);
|
|
44427
44566
|
setAttempts(0);
|
|
44428
44567
|
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
44429
|
-
|
|
44568
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
44569
|
+
}, [maxSlots, playAgainEvent, emit]);
|
|
44430
44570
|
const filledSlots = slots.filter((s) => !!s);
|
|
44431
44571
|
const canPlay = filledSlots.length > 0 && playState === "idle";
|
|
44432
44572
|
const handlePlay = React82.useCallback(() => {
|
|
@@ -44448,6 +44588,7 @@ function SequencerBoard({
|
|
|
44448
44588
|
const success = solutions.some(
|
|
44449
44589
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
44450
44590
|
);
|
|
44591
|
+
if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
|
|
44451
44592
|
if (success) {
|
|
44452
44593
|
setPlayState("success");
|
|
44453
44594
|
setCurrentStep(-1);
|
|
@@ -44475,7 +44616,7 @@ function SequencerBoard({
|
|
|
44475
44616
|
}
|
|
44476
44617
|
};
|
|
44477
44618
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
44478
|
-
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, emit]);
|
|
44619
|
+
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, checkEvent, emit]);
|
|
44479
44620
|
const machine = {
|
|
44480
44621
|
name: str(resolved?.title),
|
|
44481
44622
|
description: str(resolved?.description),
|
|
@@ -44730,11 +44871,13 @@ function SimulationCanvas({
|
|
|
44730
44871
|
height = 400,
|
|
44731
44872
|
running,
|
|
44732
44873
|
speed = 1,
|
|
44874
|
+
bodies: externalBodies,
|
|
44733
44875
|
className
|
|
44734
44876
|
}) {
|
|
44735
44877
|
const preset = React82.useMemo(() => resolvePreset(presetProp), [presetProp]);
|
|
44736
44878
|
const canvasRef = React82.useRef(null);
|
|
44737
44879
|
const bodiesRef = React82.useRef(structuredClone(preset.bodies));
|
|
44880
|
+
const interp = useRenderInterpolation();
|
|
44738
44881
|
React82.useEffect(() => {
|
|
44739
44882
|
bodiesRef.current = structuredClone(preset.bodies);
|
|
44740
44883
|
}, [preset]);
|
|
@@ -44832,6 +44975,67 @@ function SimulationCanvas({
|
|
|
44832
44975
|
}
|
|
44833
44976
|
}, [width, height, preset]);
|
|
44834
44977
|
React82.useEffect(() => {
|
|
44978
|
+
if (!externalBodies) return;
|
|
44979
|
+
interp.onSnapshot(externalBodies.map((b) => ({ id: b.id, x: b.x, y: b.y })));
|
|
44980
|
+
}, [externalBodies]);
|
|
44981
|
+
const presetRef = React82.useRef(preset);
|
|
44982
|
+
presetRef.current = preset;
|
|
44983
|
+
const widthRef = React82.useRef(width);
|
|
44984
|
+
widthRef.current = width;
|
|
44985
|
+
const heightRef = React82.useRef(height);
|
|
44986
|
+
heightRef.current = height;
|
|
44987
|
+
React82.useEffect(() => {
|
|
44988
|
+
if (!externalBodies) return;
|
|
44989
|
+
const drawInterpolated = (positions) => {
|
|
44990
|
+
const canvas = canvasRef.current;
|
|
44991
|
+
if (!canvas) return;
|
|
44992
|
+
const ctx = canvas.getContext("2d");
|
|
44993
|
+
if (!ctx) return;
|
|
44994
|
+
const bodies = bodiesRef.current;
|
|
44995
|
+
const p2 = presetRef.current;
|
|
44996
|
+
const w = widthRef.current;
|
|
44997
|
+
const h = heightRef.current;
|
|
44998
|
+
ctx.clearRect(0, 0, w, h);
|
|
44999
|
+
ctx.fillStyle = p2.backgroundColor ?? "#1a1a2e";
|
|
45000
|
+
ctx.fillRect(0, 0, w, h);
|
|
45001
|
+
if (p2.constraints) {
|
|
45002
|
+
for (const c of p2.constraints) {
|
|
45003
|
+
const a = bodies[c.bodyA];
|
|
45004
|
+
const b = bodies[c.bodyB];
|
|
45005
|
+
if (a && b) {
|
|
45006
|
+
const aPos = positions.get(a.id) ?? a;
|
|
45007
|
+
const bPos = positions.get(b.id) ?? b;
|
|
45008
|
+
ctx.beginPath();
|
|
45009
|
+
ctx.moveTo(aPos.x, aPos.y);
|
|
45010
|
+
ctx.lineTo(bPos.x, bPos.y);
|
|
45011
|
+
ctx.strokeStyle = "#533483";
|
|
45012
|
+
ctx.lineWidth = 1;
|
|
45013
|
+
ctx.setLineDash([4, 4]);
|
|
45014
|
+
ctx.stroke();
|
|
45015
|
+
ctx.setLineDash([]);
|
|
45016
|
+
}
|
|
45017
|
+
}
|
|
45018
|
+
}
|
|
45019
|
+
for (const body of bodies) {
|
|
45020
|
+
const pos = positions.get(body.id) ?? body;
|
|
45021
|
+
ctx.beginPath();
|
|
45022
|
+
ctx.arc(pos.x, pos.y, body.radius, 0, Math.PI * 2);
|
|
45023
|
+
ctx.fillStyle = body.color ?? "#e94560";
|
|
45024
|
+
ctx.fill();
|
|
45025
|
+
if (p2.showVelocity) {
|
|
45026
|
+
ctx.beginPath();
|
|
45027
|
+
ctx.moveTo(pos.x, pos.y);
|
|
45028
|
+
ctx.lineTo(pos.x + body.vx * 0.1, pos.y + body.vy * 0.1);
|
|
45029
|
+
ctx.strokeStyle = "#16213e";
|
|
45030
|
+
ctx.lineWidth = 2;
|
|
45031
|
+
ctx.stroke();
|
|
45032
|
+
}
|
|
45033
|
+
}
|
|
45034
|
+
};
|
|
45035
|
+
return interp.startLoop(drawInterpolated);
|
|
45036
|
+
}, [externalBodies !== void 0, interp.startLoop]);
|
|
45037
|
+
React82.useEffect(() => {
|
|
45038
|
+
if (externalBodies !== void 0) return;
|
|
44835
45039
|
if (!running) return;
|
|
44836
45040
|
let raf;
|
|
44837
45041
|
const loop = () => {
|
|
@@ -44841,10 +45045,11 @@ function SimulationCanvas({
|
|
|
44841
45045
|
};
|
|
44842
45046
|
raf = requestAnimationFrame(loop);
|
|
44843
45047
|
return () => cancelAnimationFrame(raf);
|
|
44844
|
-
}, [running, step, draw]);
|
|
45048
|
+
}, [running, step, draw, externalBodies]);
|
|
44845
45049
|
React82.useEffect(() => {
|
|
45050
|
+
if (externalBodies !== void 0) return;
|
|
44846
45051
|
draw();
|
|
44847
|
-
}, [draw]);
|
|
45052
|
+
}, [draw, externalBodies]);
|
|
44848
45053
|
React82.useEffect(() => {
|
|
44849
45054
|
if (typeof window === "undefined") return;
|
|
44850
45055
|
const canvas = canvasRef.current;
|
|
@@ -44870,6 +45075,7 @@ var init_SimulationCanvas = __esm({
|
|
|
44870
45075
|
init_atoms2();
|
|
44871
45076
|
init_verificationRegistry();
|
|
44872
45077
|
init_presets();
|
|
45078
|
+
init_useRenderInterpolation();
|
|
44873
45079
|
SimulationCanvas.displayName = "SimulationCanvas";
|
|
44874
45080
|
}
|
|
44875
45081
|
});
|