@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/providers/index.cjs
CHANGED
|
@@ -28609,6 +28609,78 @@ var init_GameOverScreen = __esm({
|
|
|
28609
28609
|
GameOverScreen.displayName = "GameOverScreen";
|
|
28610
28610
|
}
|
|
28611
28611
|
});
|
|
28612
|
+
function useRenderInterpolation(options = {}) {
|
|
28613
|
+
const tickIntervalMs = options.tickIntervalMs ?? 1e3 / 30;
|
|
28614
|
+
const prevRef = React83.useRef(null);
|
|
28615
|
+
const currRef = React83.useRef(null);
|
|
28616
|
+
const rafRef = React83.useRef(null);
|
|
28617
|
+
const onSnapshot = React83.useCallback((entities) => {
|
|
28618
|
+
prevRef.current = currRef.current;
|
|
28619
|
+
currRef.current = { entities, arrivedAt: performance.now() };
|
|
28620
|
+
}, []);
|
|
28621
|
+
const getInterpolated = React83.useCallback((now) => {
|
|
28622
|
+
const out = /* @__PURE__ */ new Map();
|
|
28623
|
+
const curr = currRef.current;
|
|
28624
|
+
if (!curr) return out;
|
|
28625
|
+
const prev = prevRef.current;
|
|
28626
|
+
if (!prev) {
|
|
28627
|
+
for (const e of curr.entities) out.set(e.id, { x: e.x, y: e.y });
|
|
28628
|
+
return out;
|
|
28629
|
+
}
|
|
28630
|
+
const rawAlpha = (now - curr.arrivedAt) / tickIntervalMs;
|
|
28631
|
+
const alpha = rawAlpha < 0 ? 0 : rawAlpha > 1 ? 1 : rawAlpha;
|
|
28632
|
+
const prevMap = /* @__PURE__ */ new Map();
|
|
28633
|
+
for (const e of prev.entities) prevMap.set(e.id, e);
|
|
28634
|
+
for (const c of curr.entities) {
|
|
28635
|
+
const p2 = prevMap.get(c.id);
|
|
28636
|
+
if (!p2) {
|
|
28637
|
+
out.set(c.id, { x: c.x, y: c.y });
|
|
28638
|
+
} else {
|
|
28639
|
+
out.set(c.id, {
|
|
28640
|
+
x: p2.x + (c.x - p2.x) * alpha,
|
|
28641
|
+
y: p2.y + (c.y - p2.y) * alpha
|
|
28642
|
+
});
|
|
28643
|
+
}
|
|
28644
|
+
}
|
|
28645
|
+
return out;
|
|
28646
|
+
}, [tickIntervalMs]);
|
|
28647
|
+
const startLoop = React83.useCallback(
|
|
28648
|
+
(draw) => {
|
|
28649
|
+
let active = true;
|
|
28650
|
+
const loop = () => {
|
|
28651
|
+
if (!active) return;
|
|
28652
|
+
try {
|
|
28653
|
+
draw(getInterpolated(performance.now()));
|
|
28654
|
+
} catch {
|
|
28655
|
+
}
|
|
28656
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
28657
|
+
};
|
|
28658
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
28659
|
+
return () => {
|
|
28660
|
+
active = false;
|
|
28661
|
+
if (rafRef.current !== null) {
|
|
28662
|
+
cancelAnimationFrame(rafRef.current);
|
|
28663
|
+
rafRef.current = null;
|
|
28664
|
+
}
|
|
28665
|
+
};
|
|
28666
|
+
},
|
|
28667
|
+
[getInterpolated]
|
|
28668
|
+
);
|
|
28669
|
+
React83.useEffect(() => {
|
|
28670
|
+
return () => {
|
|
28671
|
+
if (rafRef.current !== null) {
|
|
28672
|
+
cancelAnimationFrame(rafRef.current);
|
|
28673
|
+
rafRef.current = null;
|
|
28674
|
+
}
|
|
28675
|
+
};
|
|
28676
|
+
}, []);
|
|
28677
|
+
return { onSnapshot, getInterpolated, startLoop };
|
|
28678
|
+
}
|
|
28679
|
+
var init_useRenderInterpolation = __esm({
|
|
28680
|
+
"hooks/useRenderInterpolation.ts"() {
|
|
28681
|
+
"use client";
|
|
28682
|
+
}
|
|
28683
|
+
});
|
|
28612
28684
|
function PlatformerCanvas({
|
|
28613
28685
|
player,
|
|
28614
28686
|
platforms = [
|
|
@@ -28677,8 +28749,43 @@ function PlatformerCanvas({
|
|
|
28677
28749
|
y: 336,
|
|
28678
28750
|
width: 32,
|
|
28679
28751
|
height: 48,
|
|
28752
|
+
vx: 0,
|
|
28753
|
+
vy: 0,
|
|
28754
|
+
grounded: true,
|
|
28680
28755
|
facingRight: true
|
|
28681
28756
|
};
|
|
28757
|
+
const playerRef = React83.useRef(resolvedPlayer);
|
|
28758
|
+
playerRef.current = resolvedPlayer;
|
|
28759
|
+
const interp = useRenderInterpolation();
|
|
28760
|
+
React83.useEffect(() => {
|
|
28761
|
+
interp.onSnapshot([{ id: "player", x: resolvedPlayer.x, y: resolvedPlayer.y }]);
|
|
28762
|
+
}, [resolvedPlayer.x, resolvedPlayer.y]);
|
|
28763
|
+
const propsRef = React83.useRef({
|
|
28764
|
+
platforms,
|
|
28765
|
+
worldWidth,
|
|
28766
|
+
worldHeight,
|
|
28767
|
+
canvasWidth,
|
|
28768
|
+
canvasHeight,
|
|
28769
|
+
followCamera,
|
|
28770
|
+
bgColor,
|
|
28771
|
+
playerSprite,
|
|
28772
|
+
tileSprites,
|
|
28773
|
+
backgroundImage,
|
|
28774
|
+
assetBaseUrl
|
|
28775
|
+
});
|
|
28776
|
+
propsRef.current = {
|
|
28777
|
+
platforms,
|
|
28778
|
+
worldWidth,
|
|
28779
|
+
worldHeight,
|
|
28780
|
+
canvasWidth,
|
|
28781
|
+
canvasHeight,
|
|
28782
|
+
followCamera,
|
|
28783
|
+
bgColor,
|
|
28784
|
+
playerSprite,
|
|
28785
|
+
tileSprites,
|
|
28786
|
+
backgroundImage,
|
|
28787
|
+
assetBaseUrl
|
|
28788
|
+
};
|
|
28682
28789
|
const handleKeyDown = React83.useCallback((e) => {
|
|
28683
28790
|
if (keysRef.current.has(e.code)) return;
|
|
28684
28791
|
keysRef.current.add(e.code);
|
|
@@ -28727,124 +28834,149 @@ function PlatformerCanvas({
|
|
|
28727
28834
|
canvas.width = canvasWidth * dpr;
|
|
28728
28835
|
canvas.height = canvasHeight * dpr;
|
|
28729
28836
|
ctx.scale(dpr, dpr);
|
|
28730
|
-
|
|
28731
|
-
|
|
28732
|
-
|
|
28733
|
-
|
|
28734
|
-
|
|
28735
|
-
|
|
28736
|
-
|
|
28737
|
-
|
|
28738
|
-
|
|
28739
|
-
|
|
28740
|
-
|
|
28741
|
-
|
|
28742
|
-
|
|
28743
|
-
|
|
28744
|
-
|
|
28745
|
-
|
|
28746
|
-
|
|
28747
|
-
|
|
28748
|
-
|
|
28749
|
-
|
|
28750
|
-
|
|
28751
|
-
|
|
28752
|
-
|
|
28753
|
-
|
|
28754
|
-
|
|
28755
|
-
|
|
28756
|
-
|
|
28757
|
-
|
|
28758
|
-
|
|
28759
|
-
|
|
28760
|
-
|
|
28761
|
-
|
|
28762
|
-
|
|
28763
|
-
|
|
28764
|
-
|
|
28765
|
-
const px = plat.x - camX;
|
|
28766
|
-
const py = plat.y - camY;
|
|
28767
|
-
const platType = plat.type ?? "ground";
|
|
28768
|
-
const spriteUrl = tileSprites?.[platType];
|
|
28769
|
-
const tileImg = spriteUrl ? loadImage(spriteUrl) : null;
|
|
28770
|
-
if (tileImg) {
|
|
28771
|
-
const tileW = tileImg.naturalWidth;
|
|
28772
|
-
const tileH = tileImg.naturalHeight;
|
|
28773
|
-
const scaleH = plat.height / tileH;
|
|
28774
|
-
const scaledW = tileW * scaleH;
|
|
28775
|
-
for (let tx = 0; tx < plat.width; tx += scaledW) {
|
|
28776
|
-
const drawW = Math.min(scaledW, plat.width - tx);
|
|
28777
|
-
const srcW = drawW / scaleH;
|
|
28778
|
-
ctx.drawImage(tileImg, 0, 0, srcW, tileH, px + tx, py, drawW, plat.height);
|
|
28779
|
-
}
|
|
28837
|
+
}, [canvasWidth, canvasHeight]);
|
|
28838
|
+
React83.useEffect(() => {
|
|
28839
|
+
const drawFrame = (positions) => {
|
|
28840
|
+
const canvas = canvasRef.current;
|
|
28841
|
+
if (!canvas) return;
|
|
28842
|
+
const ctx = canvas.getContext("2d");
|
|
28843
|
+
if (!ctx) return;
|
|
28844
|
+
const {
|
|
28845
|
+
platforms: plats,
|
|
28846
|
+
worldWidth: ww,
|
|
28847
|
+
worldHeight: wh,
|
|
28848
|
+
canvasWidth: cw,
|
|
28849
|
+
canvasHeight: ch,
|
|
28850
|
+
followCamera: fc,
|
|
28851
|
+
bgColor: bg,
|
|
28852
|
+
playerSprite: pSprite,
|
|
28853
|
+
tileSprites: tSprites,
|
|
28854
|
+
backgroundImage: bgImg
|
|
28855
|
+
} = propsRef.current;
|
|
28856
|
+
const auth = playerRef.current;
|
|
28857
|
+
const interped = positions.get("player");
|
|
28858
|
+
const px = interped?.x ?? auth.x;
|
|
28859
|
+
const py = interped?.y ?? auth.y;
|
|
28860
|
+
let camX = 0;
|
|
28861
|
+
let camY = 0;
|
|
28862
|
+
if (fc) {
|
|
28863
|
+
camX = Math.max(0, Math.min(px - cw / 2, ww - cw));
|
|
28864
|
+
camY = Math.max(0, Math.min(py - ch / 2 - 50, wh - ch));
|
|
28865
|
+
}
|
|
28866
|
+
const bgImage = bgImg ? loadImage(bgImg) : null;
|
|
28867
|
+
if (bgImage) {
|
|
28868
|
+
ctx.drawImage(bgImage, 0, 0, cw, ch);
|
|
28869
|
+
} else if (bg) {
|
|
28870
|
+
ctx.fillStyle = bg;
|
|
28871
|
+
ctx.fillRect(0, 0, cw, ch);
|
|
28780
28872
|
} else {
|
|
28781
|
-
const
|
|
28782
|
-
|
|
28783
|
-
|
|
28784
|
-
ctx.fillStyle =
|
|
28785
|
-
ctx.fillRect(
|
|
28786
|
-
|
|
28787
|
-
|
|
28788
|
-
|
|
28789
|
-
|
|
28790
|
-
|
|
28791
|
-
|
|
28873
|
+
const grad = ctx.createLinearGradient(0, 0, 0, ch);
|
|
28874
|
+
grad.addColorStop(0, SKY_GRADIENT_TOP);
|
|
28875
|
+
grad.addColorStop(1, SKY_GRADIENT_BOTTOM);
|
|
28876
|
+
ctx.fillStyle = grad;
|
|
28877
|
+
ctx.fillRect(0, 0, cw, ch);
|
|
28878
|
+
}
|
|
28879
|
+
ctx.strokeStyle = GRID_COLOR;
|
|
28880
|
+
ctx.lineWidth = 1;
|
|
28881
|
+
const gridSize = 32;
|
|
28882
|
+
for (let gx = -camX % gridSize; gx < cw; gx += gridSize) {
|
|
28883
|
+
ctx.beginPath();
|
|
28884
|
+
ctx.moveTo(gx, 0);
|
|
28885
|
+
ctx.lineTo(gx, ch);
|
|
28886
|
+
ctx.stroke();
|
|
28887
|
+
}
|
|
28888
|
+
for (let gy = -camY % gridSize; gy < ch; gy += gridSize) {
|
|
28889
|
+
ctx.beginPath();
|
|
28890
|
+
ctx.moveTo(0, gy);
|
|
28891
|
+
ctx.lineTo(cw, gy);
|
|
28892
|
+
ctx.stroke();
|
|
28893
|
+
}
|
|
28894
|
+
for (const plat of plats) {
|
|
28895
|
+
const platX = plat.x - camX;
|
|
28896
|
+
const platY = plat.y - camY;
|
|
28897
|
+
const platType = plat.type ?? "ground";
|
|
28898
|
+
const spriteUrl = tSprites?.[platType];
|
|
28899
|
+
const tileImg = spriteUrl ? loadImage(spriteUrl) : null;
|
|
28900
|
+
if (tileImg) {
|
|
28901
|
+
const tileW = tileImg.naturalWidth;
|
|
28902
|
+
const tileH = tileImg.naturalHeight;
|
|
28903
|
+
const scaleH = plat.height / tileH;
|
|
28904
|
+
const scaledW = tileW * scaleH;
|
|
28905
|
+
for (let tx = 0; tx < plat.width; tx += scaledW) {
|
|
28906
|
+
const drawW = Math.min(scaledW, plat.width - tx);
|
|
28907
|
+
const srcW = drawW / scaleH;
|
|
28908
|
+
ctx.drawImage(tileImg, 0, 0, srcW, tileH, platX + tx, platY, drawW, plat.height);
|
|
28909
|
+
}
|
|
28910
|
+
} else {
|
|
28911
|
+
const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
|
|
28912
|
+
ctx.fillStyle = color;
|
|
28913
|
+
ctx.fillRect(platX, platY, plat.width, plat.height);
|
|
28914
|
+
ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
|
|
28915
|
+
ctx.fillRect(platX, platY, plat.width, 3);
|
|
28916
|
+
ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
|
|
28917
|
+
ctx.fillRect(platX, platY + plat.height - 2, plat.width, 2);
|
|
28918
|
+
if (platType === "hazard") {
|
|
28919
|
+
ctx.strokeStyle = "#e74c3c";
|
|
28920
|
+
ctx.lineWidth = 2;
|
|
28921
|
+
for (let sx = platX; sx < platX + plat.width; sx += 12) {
|
|
28922
|
+
ctx.beginPath();
|
|
28923
|
+
ctx.moveTo(sx, platY);
|
|
28924
|
+
ctx.lineTo(sx + 6, platY + plat.height);
|
|
28925
|
+
ctx.stroke();
|
|
28926
|
+
}
|
|
28927
|
+
}
|
|
28928
|
+
if (platType === "goal") {
|
|
28929
|
+
ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
|
|
28792
28930
|
ctx.beginPath();
|
|
28793
|
-
ctx.
|
|
28794
|
-
ctx.
|
|
28795
|
-
ctx.stroke();
|
|
28931
|
+
ctx.arc(platX + plat.width / 2, platY - 10, 8, 0, Math.PI * 2);
|
|
28932
|
+
ctx.fill();
|
|
28796
28933
|
}
|
|
28797
28934
|
}
|
|
28798
|
-
if (platType === "goal") {
|
|
28799
|
-
ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
|
|
28800
|
-
ctx.beginPath();
|
|
28801
|
-
ctx.arc(px + plat.width / 2, py - 10, 8, 0, Math.PI * 2);
|
|
28802
|
-
ctx.fill();
|
|
28803
|
-
}
|
|
28804
28935
|
}
|
|
28805
|
-
|
|
28806
|
-
|
|
28807
|
-
|
|
28808
|
-
|
|
28809
|
-
|
|
28810
|
-
|
|
28811
|
-
|
|
28812
|
-
|
|
28813
|
-
|
|
28814
|
-
|
|
28815
|
-
|
|
28816
|
-
|
|
28817
|
-
|
|
28936
|
+
const pw = auth.width ?? 24;
|
|
28937
|
+
const ph = auth.height ?? 32;
|
|
28938
|
+
const ppx = px - camX;
|
|
28939
|
+
const ppy = py - camY;
|
|
28940
|
+
const facingRight = auth.facingRight ?? true;
|
|
28941
|
+
const playerImg = pSprite ? loadImage(pSprite) : null;
|
|
28942
|
+
if (playerImg) {
|
|
28943
|
+
ctx.save();
|
|
28944
|
+
if (!facingRight) {
|
|
28945
|
+
ctx.translate(ppx + pw, ppy);
|
|
28946
|
+
ctx.scale(-1, 1);
|
|
28947
|
+
ctx.drawImage(playerImg, 0, 0, pw, ph);
|
|
28948
|
+
} else {
|
|
28949
|
+
ctx.drawImage(playerImg, ppx, ppy, pw, ph);
|
|
28950
|
+
}
|
|
28951
|
+
ctx.restore();
|
|
28818
28952
|
} else {
|
|
28819
|
-
ctx.
|
|
28953
|
+
ctx.fillStyle = PLAYER_COLOR;
|
|
28954
|
+
const radius = Math.min(pw, ph) * 0.25;
|
|
28955
|
+
ctx.beginPath();
|
|
28956
|
+
ctx.moveTo(ppx + radius, ppy);
|
|
28957
|
+
ctx.lineTo(ppx + pw - radius, ppy);
|
|
28958
|
+
ctx.quadraticCurveTo(ppx + pw, ppy, ppx + pw, ppy + radius);
|
|
28959
|
+
ctx.lineTo(ppx + pw, ppy + ph - radius);
|
|
28960
|
+
ctx.quadraticCurveTo(ppx + pw, ppy + ph, ppx + pw - radius, ppy + ph);
|
|
28961
|
+
ctx.lineTo(ppx + radius, ppy + ph);
|
|
28962
|
+
ctx.quadraticCurveTo(ppx, ppy + ph, ppx, ppy + ph - radius);
|
|
28963
|
+
ctx.lineTo(ppx, ppy + radius);
|
|
28964
|
+
ctx.quadraticCurveTo(ppx, ppy, ppx + radius, ppy);
|
|
28965
|
+
ctx.fill();
|
|
28966
|
+
const eyeY = ppy + ph * 0.3;
|
|
28967
|
+
const eyeSize = 3;
|
|
28968
|
+
const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
|
|
28969
|
+
ctx.fillStyle = PLAYER_EYE_COLOR;
|
|
28970
|
+
ctx.beginPath();
|
|
28971
|
+
ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
|
|
28972
|
+
ctx.fill();
|
|
28973
|
+
ctx.beginPath();
|
|
28974
|
+
ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
|
|
28975
|
+
ctx.fill();
|
|
28820
28976
|
}
|
|
28821
|
-
|
|
28822
|
-
|
|
28823
|
-
|
|
28824
|
-
const radius = Math.min(pw, ph) * 0.25;
|
|
28825
|
-
ctx.beginPath();
|
|
28826
|
-
ctx.moveTo(ppx + radius, ppy);
|
|
28827
|
-
ctx.lineTo(ppx + pw - radius, ppy);
|
|
28828
|
-
ctx.quadraticCurveTo(ppx + pw, ppy, ppx + pw, ppy + radius);
|
|
28829
|
-
ctx.lineTo(ppx + pw, ppy + ph - radius);
|
|
28830
|
-
ctx.quadraticCurveTo(ppx + pw, ppy + ph, ppx + pw - radius, ppy + ph);
|
|
28831
|
-
ctx.lineTo(ppx + radius, ppy + ph);
|
|
28832
|
-
ctx.quadraticCurveTo(ppx, ppy + ph, ppx, ppy + ph - radius);
|
|
28833
|
-
ctx.lineTo(ppx, ppy + radius);
|
|
28834
|
-
ctx.quadraticCurveTo(ppx, ppy, ppx + radius, ppy);
|
|
28835
|
-
ctx.fill();
|
|
28836
|
-
const eyeY = ppy + ph * 0.3;
|
|
28837
|
-
const eyeSize = 3;
|
|
28838
|
-
const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
|
|
28839
|
-
ctx.fillStyle = PLAYER_EYE_COLOR;
|
|
28840
|
-
ctx.beginPath();
|
|
28841
|
-
ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
|
|
28842
|
-
ctx.fill();
|
|
28843
|
-
ctx.beginPath();
|
|
28844
|
-
ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
|
|
28845
|
-
ctx.fill();
|
|
28846
|
-
}
|
|
28847
|
-
}, [player, platforms, worldWidth, worldHeight, canvasWidth, canvasHeight, followCamera, bgColor, playerSprite, tileSprites, backgroundImage, assetBaseUrl, loadedImages]);
|
|
28977
|
+
};
|
|
28978
|
+
return interp.startLoop(drawFrame);
|
|
28979
|
+
}, [interp.startLoop, loadImage]);
|
|
28848
28980
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
28849
28981
|
"canvas",
|
|
28850
28982
|
{
|
|
@@ -28862,6 +28994,7 @@ var init_PlatformerCanvas = __esm({
|
|
|
28862
28994
|
init_cn();
|
|
28863
28995
|
init_useEventBus();
|
|
28864
28996
|
init_verificationRegistry();
|
|
28997
|
+
init_useRenderInterpolation();
|
|
28865
28998
|
PLATFORM_COLORS = {
|
|
28866
28999
|
ground: "#4a7c59",
|
|
28867
29000
|
platform: "#7c6b4a",
|
|
@@ -29244,13 +29377,13 @@ var init_MapView = __esm({
|
|
|
29244
29377
|
shadowSize: [41, 41]
|
|
29245
29378
|
});
|
|
29246
29379
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
29247
|
-
const { useEffect:
|
|
29380
|
+
const { useEffect: useEffect74, useRef: useRef69, useCallback: useCallback112, useState: useState104 } = React83__namespace.default;
|
|
29248
29381
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
29249
29382
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
29250
29383
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
29251
29384
|
const map = useMap();
|
|
29252
|
-
const prevRef =
|
|
29253
|
-
|
|
29385
|
+
const prevRef = useRef69({ centerLat, centerLng, zoom });
|
|
29386
|
+
useEffect74(() => {
|
|
29254
29387
|
const prev = prevRef.current;
|
|
29255
29388
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
29256
29389
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -29261,7 +29394,7 @@ var init_MapView = __esm({
|
|
|
29261
29394
|
}
|
|
29262
29395
|
function MapClickHandler({ onMapClick }) {
|
|
29263
29396
|
const map = useMap();
|
|
29264
|
-
|
|
29397
|
+
useEffect74(() => {
|
|
29265
29398
|
if (!onMapClick) return;
|
|
29266
29399
|
const handler = (e) => {
|
|
29267
29400
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -29290,7 +29423,7 @@ var init_MapView = __esm({
|
|
|
29290
29423
|
}) {
|
|
29291
29424
|
const eventBus = useEventBus2();
|
|
29292
29425
|
const [clickedPosition, setClickedPosition] = useState104(null);
|
|
29293
|
-
const handleMapClick =
|
|
29426
|
+
const handleMapClick = useCallback112((lat, lng) => {
|
|
29294
29427
|
if (showClickedPin) {
|
|
29295
29428
|
setClickedPosition({ lat, lng });
|
|
29296
29429
|
}
|
|
@@ -29299,7 +29432,7 @@ var init_MapView = __esm({
|
|
|
29299
29432
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29300
29433
|
}
|
|
29301
29434
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29302
|
-
const handleMarkerClick =
|
|
29435
|
+
const handleMarkerClick = useCallback112((marker) => {
|
|
29303
29436
|
onMarkerClick?.(marker);
|
|
29304
29437
|
if (markerClickEvent) {
|
|
29305
29438
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -44784,6 +44917,10 @@ function SequencerBoard({
|
|
|
44784
44917
|
stepDurationMs = 1e3,
|
|
44785
44918
|
playEvent,
|
|
44786
44919
|
completeEvent,
|
|
44920
|
+
placeEvent,
|
|
44921
|
+
removeEvent,
|
|
44922
|
+
checkEvent,
|
|
44923
|
+
playAgainEvent,
|
|
44787
44924
|
className
|
|
44788
44925
|
}) {
|
|
44789
44926
|
const { emit } = useEventBus();
|
|
@@ -44819,7 +44956,8 @@ function SequencerBoard({
|
|
|
44819
44956
|
return next;
|
|
44820
44957
|
});
|
|
44821
44958
|
emit("UI:PLAY_SOUND", { key: "drop_slot" });
|
|
44822
|
-
|
|
44959
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotIndex: index, actionId: item.id });
|
|
44960
|
+
}, [emit, placeEvent]);
|
|
44823
44961
|
const handleSlotRemove = React83.useCallback((index) => {
|
|
44824
44962
|
setSlots((prev) => {
|
|
44825
44963
|
const next = [...prev];
|
|
@@ -44832,7 +44970,8 @@ function SequencerBoard({
|
|
|
44832
44970
|
return next;
|
|
44833
44971
|
});
|
|
44834
44972
|
emit("UI:PLAY_SOUND", { key: "back" });
|
|
44835
|
-
|
|
44973
|
+
if (removeEvent) emit(`UI:${removeEvent}`, { slotIndex: index });
|
|
44974
|
+
}, [emit, removeEvent]);
|
|
44836
44975
|
const handleReset = React83.useCallback(() => {
|
|
44837
44976
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
44838
44977
|
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
@@ -44840,7 +44979,8 @@ function SequencerBoard({
|
|
|
44840
44979
|
setCurrentStep(-1);
|
|
44841
44980
|
setAttempts(0);
|
|
44842
44981
|
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
44843
|
-
|
|
44982
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
44983
|
+
}, [maxSlots, playAgainEvent, emit]);
|
|
44844
44984
|
const filledSlots = slots.filter((s) => !!s);
|
|
44845
44985
|
const canPlay = filledSlots.length > 0 && playState === "idle";
|
|
44846
44986
|
const handlePlay = React83.useCallback(() => {
|
|
@@ -44862,6 +45002,7 @@ function SequencerBoard({
|
|
|
44862
45002
|
const success = solutions.some(
|
|
44863
45003
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
44864
45004
|
);
|
|
45005
|
+
if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
|
|
44865
45006
|
if (success) {
|
|
44866
45007
|
setPlayState("success");
|
|
44867
45008
|
setCurrentStep(-1);
|
|
@@ -44889,7 +45030,7 @@ function SequencerBoard({
|
|
|
44889
45030
|
}
|
|
44890
45031
|
};
|
|
44891
45032
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
44892
|
-
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, emit]);
|
|
45033
|
+
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, checkEvent, emit]);
|
|
44893
45034
|
const machine = {
|
|
44894
45035
|
name: str(resolved?.title),
|
|
44895
45036
|
description: str(resolved?.description),
|
|
@@ -45144,11 +45285,13 @@ function SimulationCanvas({
|
|
|
45144
45285
|
height = 400,
|
|
45145
45286
|
running,
|
|
45146
45287
|
speed = 1,
|
|
45288
|
+
bodies: externalBodies,
|
|
45147
45289
|
className
|
|
45148
45290
|
}) {
|
|
45149
45291
|
const preset = React83.useMemo(() => resolvePreset(presetProp), [presetProp]);
|
|
45150
45292
|
const canvasRef = React83.useRef(null);
|
|
45151
45293
|
const bodiesRef = React83.useRef(structuredClone(preset.bodies));
|
|
45294
|
+
const interp = useRenderInterpolation();
|
|
45152
45295
|
React83.useEffect(() => {
|
|
45153
45296
|
bodiesRef.current = structuredClone(preset.bodies);
|
|
45154
45297
|
}, [preset]);
|
|
@@ -45246,6 +45389,67 @@ function SimulationCanvas({
|
|
|
45246
45389
|
}
|
|
45247
45390
|
}, [width, height, preset]);
|
|
45248
45391
|
React83.useEffect(() => {
|
|
45392
|
+
if (!externalBodies) return;
|
|
45393
|
+
interp.onSnapshot(externalBodies.map((b) => ({ id: b.id, x: b.x, y: b.y })));
|
|
45394
|
+
}, [externalBodies]);
|
|
45395
|
+
const presetRef = React83.useRef(preset);
|
|
45396
|
+
presetRef.current = preset;
|
|
45397
|
+
const widthRef = React83.useRef(width);
|
|
45398
|
+
widthRef.current = width;
|
|
45399
|
+
const heightRef = React83.useRef(height);
|
|
45400
|
+
heightRef.current = height;
|
|
45401
|
+
React83.useEffect(() => {
|
|
45402
|
+
if (!externalBodies) return;
|
|
45403
|
+
const drawInterpolated = (positions) => {
|
|
45404
|
+
const canvas = canvasRef.current;
|
|
45405
|
+
if (!canvas) return;
|
|
45406
|
+
const ctx = canvas.getContext("2d");
|
|
45407
|
+
if (!ctx) return;
|
|
45408
|
+
const bodies = bodiesRef.current;
|
|
45409
|
+
const p2 = presetRef.current;
|
|
45410
|
+
const w = widthRef.current;
|
|
45411
|
+
const h = heightRef.current;
|
|
45412
|
+
ctx.clearRect(0, 0, w, h);
|
|
45413
|
+
ctx.fillStyle = p2.backgroundColor ?? "#1a1a2e";
|
|
45414
|
+
ctx.fillRect(0, 0, w, h);
|
|
45415
|
+
if (p2.constraints) {
|
|
45416
|
+
for (const c of p2.constraints) {
|
|
45417
|
+
const a = bodies[c.bodyA];
|
|
45418
|
+
const b = bodies[c.bodyB];
|
|
45419
|
+
if (a && b) {
|
|
45420
|
+
const aPos = positions.get(a.id) ?? a;
|
|
45421
|
+
const bPos = positions.get(b.id) ?? b;
|
|
45422
|
+
ctx.beginPath();
|
|
45423
|
+
ctx.moveTo(aPos.x, aPos.y);
|
|
45424
|
+
ctx.lineTo(bPos.x, bPos.y);
|
|
45425
|
+
ctx.strokeStyle = "#533483";
|
|
45426
|
+
ctx.lineWidth = 1;
|
|
45427
|
+
ctx.setLineDash([4, 4]);
|
|
45428
|
+
ctx.stroke();
|
|
45429
|
+
ctx.setLineDash([]);
|
|
45430
|
+
}
|
|
45431
|
+
}
|
|
45432
|
+
}
|
|
45433
|
+
for (const body of bodies) {
|
|
45434
|
+
const pos = positions.get(body.id) ?? body;
|
|
45435
|
+
ctx.beginPath();
|
|
45436
|
+
ctx.arc(pos.x, pos.y, body.radius, 0, Math.PI * 2);
|
|
45437
|
+
ctx.fillStyle = body.color ?? "#e94560";
|
|
45438
|
+
ctx.fill();
|
|
45439
|
+
if (p2.showVelocity) {
|
|
45440
|
+
ctx.beginPath();
|
|
45441
|
+
ctx.moveTo(pos.x, pos.y);
|
|
45442
|
+
ctx.lineTo(pos.x + body.vx * 0.1, pos.y + body.vy * 0.1);
|
|
45443
|
+
ctx.strokeStyle = "#16213e";
|
|
45444
|
+
ctx.lineWidth = 2;
|
|
45445
|
+
ctx.stroke();
|
|
45446
|
+
}
|
|
45447
|
+
}
|
|
45448
|
+
};
|
|
45449
|
+
return interp.startLoop(drawInterpolated);
|
|
45450
|
+
}, [externalBodies !== void 0, interp.startLoop]);
|
|
45451
|
+
React83.useEffect(() => {
|
|
45452
|
+
if (externalBodies !== void 0) return;
|
|
45249
45453
|
if (!running) return;
|
|
45250
45454
|
let raf;
|
|
45251
45455
|
const loop = () => {
|
|
@@ -45255,10 +45459,11 @@ function SimulationCanvas({
|
|
|
45255
45459
|
};
|
|
45256
45460
|
raf = requestAnimationFrame(loop);
|
|
45257
45461
|
return () => cancelAnimationFrame(raf);
|
|
45258
|
-
}, [running, step, draw]);
|
|
45462
|
+
}, [running, step, draw, externalBodies]);
|
|
45259
45463
|
React83.useEffect(() => {
|
|
45464
|
+
if (externalBodies !== void 0) return;
|
|
45260
45465
|
draw();
|
|
45261
|
-
}, [draw]);
|
|
45466
|
+
}, [draw, externalBodies]);
|
|
45262
45467
|
React83.useEffect(() => {
|
|
45263
45468
|
if (typeof window === "undefined") return;
|
|
45264
45469
|
const canvas = canvasRef.current;
|
|
@@ -45284,6 +45489,7 @@ var init_SimulationCanvas = __esm({
|
|
|
45284
45489
|
init_atoms2();
|
|
45285
45490
|
init_verificationRegistry();
|
|
45286
45491
|
init_presets();
|
|
45492
|
+
init_useRenderInterpolation();
|
|
45287
45493
|
SimulationCanvas.displayName = "SimulationCanvas";
|
|
45288
45494
|
}
|
|
45289
45495
|
});
|