@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/components/index.js
CHANGED
|
@@ -28789,6 +28789,78 @@ var init_GameOverScreen = __esm({
|
|
|
28789
28789
|
GameOverScreen.displayName = "GameOverScreen";
|
|
28790
28790
|
}
|
|
28791
28791
|
});
|
|
28792
|
+
function useRenderInterpolation(options = {}) {
|
|
28793
|
+
const tickIntervalMs = options.tickIntervalMs ?? 1e3 / 30;
|
|
28794
|
+
const prevRef = useRef(null);
|
|
28795
|
+
const currRef = useRef(null);
|
|
28796
|
+
const rafRef = useRef(null);
|
|
28797
|
+
const onSnapshot = useCallback((entities) => {
|
|
28798
|
+
prevRef.current = currRef.current;
|
|
28799
|
+
currRef.current = { entities, arrivedAt: performance.now() };
|
|
28800
|
+
}, []);
|
|
28801
|
+
const getInterpolated = useCallback((now) => {
|
|
28802
|
+
const out = /* @__PURE__ */ new Map();
|
|
28803
|
+
const curr = currRef.current;
|
|
28804
|
+
if (!curr) return out;
|
|
28805
|
+
const prev = prevRef.current;
|
|
28806
|
+
if (!prev) {
|
|
28807
|
+
for (const e of curr.entities) out.set(e.id, { x: e.x, y: e.y });
|
|
28808
|
+
return out;
|
|
28809
|
+
}
|
|
28810
|
+
const rawAlpha = (now - curr.arrivedAt) / tickIntervalMs;
|
|
28811
|
+
const alpha = rawAlpha < 0 ? 0 : rawAlpha > 1 ? 1 : rawAlpha;
|
|
28812
|
+
const prevMap = /* @__PURE__ */ new Map();
|
|
28813
|
+
for (const e of prev.entities) prevMap.set(e.id, e);
|
|
28814
|
+
for (const c of curr.entities) {
|
|
28815
|
+
const p2 = prevMap.get(c.id);
|
|
28816
|
+
if (!p2) {
|
|
28817
|
+
out.set(c.id, { x: c.x, y: c.y });
|
|
28818
|
+
} else {
|
|
28819
|
+
out.set(c.id, {
|
|
28820
|
+
x: p2.x + (c.x - p2.x) * alpha,
|
|
28821
|
+
y: p2.y + (c.y - p2.y) * alpha
|
|
28822
|
+
});
|
|
28823
|
+
}
|
|
28824
|
+
}
|
|
28825
|
+
return out;
|
|
28826
|
+
}, [tickIntervalMs]);
|
|
28827
|
+
const startLoop = useCallback(
|
|
28828
|
+
(draw) => {
|
|
28829
|
+
let active = true;
|
|
28830
|
+
const loop = () => {
|
|
28831
|
+
if (!active) return;
|
|
28832
|
+
try {
|
|
28833
|
+
draw(getInterpolated(performance.now()));
|
|
28834
|
+
} catch {
|
|
28835
|
+
}
|
|
28836
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
28837
|
+
};
|
|
28838
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
28839
|
+
return () => {
|
|
28840
|
+
active = false;
|
|
28841
|
+
if (rafRef.current !== null) {
|
|
28842
|
+
cancelAnimationFrame(rafRef.current);
|
|
28843
|
+
rafRef.current = null;
|
|
28844
|
+
}
|
|
28845
|
+
};
|
|
28846
|
+
},
|
|
28847
|
+
[getInterpolated]
|
|
28848
|
+
);
|
|
28849
|
+
useEffect(() => {
|
|
28850
|
+
return () => {
|
|
28851
|
+
if (rafRef.current !== null) {
|
|
28852
|
+
cancelAnimationFrame(rafRef.current);
|
|
28853
|
+
rafRef.current = null;
|
|
28854
|
+
}
|
|
28855
|
+
};
|
|
28856
|
+
}, []);
|
|
28857
|
+
return { onSnapshot, getInterpolated, startLoop };
|
|
28858
|
+
}
|
|
28859
|
+
var init_useRenderInterpolation = __esm({
|
|
28860
|
+
"hooks/useRenderInterpolation.ts"() {
|
|
28861
|
+
"use client";
|
|
28862
|
+
}
|
|
28863
|
+
});
|
|
28792
28864
|
function PlatformerCanvas({
|
|
28793
28865
|
player,
|
|
28794
28866
|
platforms = [
|
|
@@ -28857,8 +28929,43 @@ function PlatformerCanvas({
|
|
|
28857
28929
|
y: 336,
|
|
28858
28930
|
width: 32,
|
|
28859
28931
|
height: 48,
|
|
28932
|
+
vx: 0,
|
|
28933
|
+
vy: 0,
|
|
28934
|
+
grounded: true,
|
|
28860
28935
|
facingRight: true
|
|
28861
28936
|
};
|
|
28937
|
+
const playerRef = useRef(resolvedPlayer);
|
|
28938
|
+
playerRef.current = resolvedPlayer;
|
|
28939
|
+
const interp = useRenderInterpolation();
|
|
28940
|
+
useEffect(() => {
|
|
28941
|
+
interp.onSnapshot([{ id: "player", x: resolvedPlayer.x, y: resolvedPlayer.y }]);
|
|
28942
|
+
}, [resolvedPlayer.x, resolvedPlayer.y]);
|
|
28943
|
+
const propsRef = useRef({
|
|
28944
|
+
platforms,
|
|
28945
|
+
worldWidth,
|
|
28946
|
+
worldHeight,
|
|
28947
|
+
canvasWidth,
|
|
28948
|
+
canvasHeight,
|
|
28949
|
+
followCamera,
|
|
28950
|
+
bgColor,
|
|
28951
|
+
playerSprite,
|
|
28952
|
+
tileSprites,
|
|
28953
|
+
backgroundImage,
|
|
28954
|
+
assetBaseUrl
|
|
28955
|
+
});
|
|
28956
|
+
propsRef.current = {
|
|
28957
|
+
platforms,
|
|
28958
|
+
worldWidth,
|
|
28959
|
+
worldHeight,
|
|
28960
|
+
canvasWidth,
|
|
28961
|
+
canvasHeight,
|
|
28962
|
+
followCamera,
|
|
28963
|
+
bgColor,
|
|
28964
|
+
playerSprite,
|
|
28965
|
+
tileSprites,
|
|
28966
|
+
backgroundImage,
|
|
28967
|
+
assetBaseUrl
|
|
28968
|
+
};
|
|
28862
28969
|
const handleKeyDown = useCallback((e) => {
|
|
28863
28970
|
if (keysRef.current.has(e.code)) return;
|
|
28864
28971
|
keysRef.current.add(e.code);
|
|
@@ -28907,124 +29014,149 @@ function PlatformerCanvas({
|
|
|
28907
29014
|
canvas.width = canvasWidth * dpr;
|
|
28908
29015
|
canvas.height = canvasHeight * dpr;
|
|
28909
29016
|
ctx.scale(dpr, dpr);
|
|
28910
|
-
|
|
28911
|
-
|
|
28912
|
-
|
|
28913
|
-
|
|
28914
|
-
|
|
28915
|
-
|
|
28916
|
-
|
|
28917
|
-
|
|
28918
|
-
|
|
28919
|
-
|
|
28920
|
-
|
|
28921
|
-
|
|
28922
|
-
|
|
28923
|
-
|
|
28924
|
-
|
|
28925
|
-
|
|
28926
|
-
|
|
28927
|
-
|
|
28928
|
-
|
|
28929
|
-
|
|
28930
|
-
|
|
28931
|
-
|
|
28932
|
-
|
|
28933
|
-
|
|
28934
|
-
|
|
28935
|
-
|
|
28936
|
-
|
|
28937
|
-
|
|
28938
|
-
|
|
28939
|
-
|
|
28940
|
-
|
|
28941
|
-
|
|
28942
|
-
|
|
28943
|
-
|
|
28944
|
-
|
|
28945
|
-
const px = plat.x - camX;
|
|
28946
|
-
const py = plat.y - camY;
|
|
28947
|
-
const platType = plat.type ?? "ground";
|
|
28948
|
-
const spriteUrl = tileSprites?.[platType];
|
|
28949
|
-
const tileImg = spriteUrl ? loadImage(spriteUrl) : null;
|
|
28950
|
-
if (tileImg) {
|
|
28951
|
-
const tileW = tileImg.naturalWidth;
|
|
28952
|
-
const tileH = tileImg.naturalHeight;
|
|
28953
|
-
const scaleH = plat.height / tileH;
|
|
28954
|
-
const scaledW = tileW * scaleH;
|
|
28955
|
-
for (let tx = 0; tx < plat.width; tx += scaledW) {
|
|
28956
|
-
const drawW = Math.min(scaledW, plat.width - tx);
|
|
28957
|
-
const srcW = drawW / scaleH;
|
|
28958
|
-
ctx.drawImage(tileImg, 0, 0, srcW, tileH, px + tx, py, drawW, plat.height);
|
|
28959
|
-
}
|
|
29017
|
+
}, [canvasWidth, canvasHeight]);
|
|
29018
|
+
useEffect(() => {
|
|
29019
|
+
const drawFrame = (positions) => {
|
|
29020
|
+
const canvas = canvasRef.current;
|
|
29021
|
+
if (!canvas) return;
|
|
29022
|
+
const ctx = canvas.getContext("2d");
|
|
29023
|
+
if (!ctx) return;
|
|
29024
|
+
const {
|
|
29025
|
+
platforms: plats,
|
|
29026
|
+
worldWidth: ww,
|
|
29027
|
+
worldHeight: wh,
|
|
29028
|
+
canvasWidth: cw,
|
|
29029
|
+
canvasHeight: ch,
|
|
29030
|
+
followCamera: fc,
|
|
29031
|
+
bgColor: bg,
|
|
29032
|
+
playerSprite: pSprite,
|
|
29033
|
+
tileSprites: tSprites,
|
|
29034
|
+
backgroundImage: bgImg
|
|
29035
|
+
} = propsRef.current;
|
|
29036
|
+
const auth = playerRef.current;
|
|
29037
|
+
const interped = positions.get("player");
|
|
29038
|
+
const px = interped?.x ?? auth.x;
|
|
29039
|
+
const py = interped?.y ?? auth.y;
|
|
29040
|
+
let camX = 0;
|
|
29041
|
+
let camY = 0;
|
|
29042
|
+
if (fc) {
|
|
29043
|
+
camX = Math.max(0, Math.min(px - cw / 2, ww - cw));
|
|
29044
|
+
camY = Math.max(0, Math.min(py - ch / 2 - 50, wh - ch));
|
|
29045
|
+
}
|
|
29046
|
+
const bgImage = bgImg ? loadImage(bgImg) : null;
|
|
29047
|
+
if (bgImage) {
|
|
29048
|
+
ctx.drawImage(bgImage, 0, 0, cw, ch);
|
|
29049
|
+
} else if (bg) {
|
|
29050
|
+
ctx.fillStyle = bg;
|
|
29051
|
+
ctx.fillRect(0, 0, cw, ch);
|
|
28960
29052
|
} else {
|
|
28961
|
-
const
|
|
28962
|
-
|
|
28963
|
-
|
|
28964
|
-
ctx.fillStyle =
|
|
28965
|
-
ctx.fillRect(
|
|
28966
|
-
|
|
28967
|
-
|
|
28968
|
-
|
|
28969
|
-
|
|
28970
|
-
|
|
28971
|
-
|
|
29053
|
+
const grad = ctx.createLinearGradient(0, 0, 0, ch);
|
|
29054
|
+
grad.addColorStop(0, SKY_GRADIENT_TOP);
|
|
29055
|
+
grad.addColorStop(1, SKY_GRADIENT_BOTTOM);
|
|
29056
|
+
ctx.fillStyle = grad;
|
|
29057
|
+
ctx.fillRect(0, 0, cw, ch);
|
|
29058
|
+
}
|
|
29059
|
+
ctx.strokeStyle = GRID_COLOR;
|
|
29060
|
+
ctx.lineWidth = 1;
|
|
29061
|
+
const gridSize = 32;
|
|
29062
|
+
for (let gx = -camX % gridSize; gx < cw; gx += gridSize) {
|
|
29063
|
+
ctx.beginPath();
|
|
29064
|
+
ctx.moveTo(gx, 0);
|
|
29065
|
+
ctx.lineTo(gx, ch);
|
|
29066
|
+
ctx.stroke();
|
|
29067
|
+
}
|
|
29068
|
+
for (let gy = -camY % gridSize; gy < ch; gy += gridSize) {
|
|
29069
|
+
ctx.beginPath();
|
|
29070
|
+
ctx.moveTo(0, gy);
|
|
29071
|
+
ctx.lineTo(cw, gy);
|
|
29072
|
+
ctx.stroke();
|
|
29073
|
+
}
|
|
29074
|
+
for (const plat of plats) {
|
|
29075
|
+
const platX = plat.x - camX;
|
|
29076
|
+
const platY = plat.y - camY;
|
|
29077
|
+
const platType = plat.type ?? "ground";
|
|
29078
|
+
const spriteUrl = tSprites?.[platType];
|
|
29079
|
+
const tileImg = spriteUrl ? loadImage(spriteUrl) : null;
|
|
29080
|
+
if (tileImg) {
|
|
29081
|
+
const tileW = tileImg.naturalWidth;
|
|
29082
|
+
const tileH = tileImg.naturalHeight;
|
|
29083
|
+
const scaleH = plat.height / tileH;
|
|
29084
|
+
const scaledW = tileW * scaleH;
|
|
29085
|
+
for (let tx = 0; tx < plat.width; tx += scaledW) {
|
|
29086
|
+
const drawW = Math.min(scaledW, plat.width - tx);
|
|
29087
|
+
const srcW = drawW / scaleH;
|
|
29088
|
+
ctx.drawImage(tileImg, 0, 0, srcW, tileH, platX + tx, platY, drawW, plat.height);
|
|
29089
|
+
}
|
|
29090
|
+
} else {
|
|
29091
|
+
const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
|
|
29092
|
+
ctx.fillStyle = color;
|
|
29093
|
+
ctx.fillRect(platX, platY, plat.width, plat.height);
|
|
29094
|
+
ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
|
|
29095
|
+
ctx.fillRect(platX, platY, plat.width, 3);
|
|
29096
|
+
ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
|
|
29097
|
+
ctx.fillRect(platX, platY + plat.height - 2, plat.width, 2);
|
|
29098
|
+
if (platType === "hazard") {
|
|
29099
|
+
ctx.strokeStyle = "#e74c3c";
|
|
29100
|
+
ctx.lineWidth = 2;
|
|
29101
|
+
for (let sx = platX; sx < platX + plat.width; sx += 12) {
|
|
29102
|
+
ctx.beginPath();
|
|
29103
|
+
ctx.moveTo(sx, platY);
|
|
29104
|
+
ctx.lineTo(sx + 6, platY + plat.height);
|
|
29105
|
+
ctx.stroke();
|
|
29106
|
+
}
|
|
29107
|
+
}
|
|
29108
|
+
if (platType === "goal") {
|
|
29109
|
+
ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
|
|
28972
29110
|
ctx.beginPath();
|
|
28973
|
-
ctx.
|
|
28974
|
-
ctx.
|
|
28975
|
-
ctx.stroke();
|
|
29111
|
+
ctx.arc(platX + plat.width / 2, platY - 10, 8, 0, Math.PI * 2);
|
|
29112
|
+
ctx.fill();
|
|
28976
29113
|
}
|
|
28977
29114
|
}
|
|
28978
|
-
if (platType === "goal") {
|
|
28979
|
-
ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
|
|
28980
|
-
ctx.beginPath();
|
|
28981
|
-
ctx.arc(px + plat.width / 2, py - 10, 8, 0, Math.PI * 2);
|
|
28982
|
-
ctx.fill();
|
|
28983
|
-
}
|
|
28984
29115
|
}
|
|
28985
|
-
|
|
28986
|
-
|
|
28987
|
-
|
|
28988
|
-
|
|
28989
|
-
|
|
28990
|
-
|
|
28991
|
-
|
|
28992
|
-
|
|
28993
|
-
|
|
28994
|
-
|
|
28995
|
-
|
|
28996
|
-
|
|
28997
|
-
|
|
29116
|
+
const pw = auth.width ?? 24;
|
|
29117
|
+
const ph = auth.height ?? 32;
|
|
29118
|
+
const ppx = px - camX;
|
|
29119
|
+
const ppy = py - camY;
|
|
29120
|
+
const facingRight = auth.facingRight ?? true;
|
|
29121
|
+
const playerImg = pSprite ? loadImage(pSprite) : null;
|
|
29122
|
+
if (playerImg) {
|
|
29123
|
+
ctx.save();
|
|
29124
|
+
if (!facingRight) {
|
|
29125
|
+
ctx.translate(ppx + pw, ppy);
|
|
29126
|
+
ctx.scale(-1, 1);
|
|
29127
|
+
ctx.drawImage(playerImg, 0, 0, pw, ph);
|
|
29128
|
+
} else {
|
|
29129
|
+
ctx.drawImage(playerImg, ppx, ppy, pw, ph);
|
|
29130
|
+
}
|
|
29131
|
+
ctx.restore();
|
|
28998
29132
|
} else {
|
|
28999
|
-
ctx.
|
|
29133
|
+
ctx.fillStyle = PLAYER_COLOR;
|
|
29134
|
+
const radius = Math.min(pw, ph) * 0.25;
|
|
29135
|
+
ctx.beginPath();
|
|
29136
|
+
ctx.moveTo(ppx + radius, ppy);
|
|
29137
|
+
ctx.lineTo(ppx + pw - radius, ppy);
|
|
29138
|
+
ctx.quadraticCurveTo(ppx + pw, ppy, ppx + pw, ppy + radius);
|
|
29139
|
+
ctx.lineTo(ppx + pw, ppy + ph - radius);
|
|
29140
|
+
ctx.quadraticCurveTo(ppx + pw, ppy + ph, ppx + pw - radius, ppy + ph);
|
|
29141
|
+
ctx.lineTo(ppx + radius, ppy + ph);
|
|
29142
|
+
ctx.quadraticCurveTo(ppx, ppy + ph, ppx, ppy + ph - radius);
|
|
29143
|
+
ctx.lineTo(ppx, ppy + radius);
|
|
29144
|
+
ctx.quadraticCurveTo(ppx, ppy, ppx + radius, ppy);
|
|
29145
|
+
ctx.fill();
|
|
29146
|
+
const eyeY = ppy + ph * 0.3;
|
|
29147
|
+
const eyeSize = 3;
|
|
29148
|
+
const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
|
|
29149
|
+
ctx.fillStyle = PLAYER_EYE_COLOR;
|
|
29150
|
+
ctx.beginPath();
|
|
29151
|
+
ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
|
|
29152
|
+
ctx.fill();
|
|
29153
|
+
ctx.beginPath();
|
|
29154
|
+
ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
|
|
29155
|
+
ctx.fill();
|
|
29000
29156
|
}
|
|
29001
|
-
|
|
29002
|
-
|
|
29003
|
-
|
|
29004
|
-
const radius = Math.min(pw, ph) * 0.25;
|
|
29005
|
-
ctx.beginPath();
|
|
29006
|
-
ctx.moveTo(ppx + radius, ppy);
|
|
29007
|
-
ctx.lineTo(ppx + pw - radius, ppy);
|
|
29008
|
-
ctx.quadraticCurveTo(ppx + pw, ppy, ppx + pw, ppy + radius);
|
|
29009
|
-
ctx.lineTo(ppx + pw, ppy + ph - radius);
|
|
29010
|
-
ctx.quadraticCurveTo(ppx + pw, ppy + ph, ppx + pw - radius, ppy + ph);
|
|
29011
|
-
ctx.lineTo(ppx + radius, ppy + ph);
|
|
29012
|
-
ctx.quadraticCurveTo(ppx, ppy + ph, ppx, ppy + ph - radius);
|
|
29013
|
-
ctx.lineTo(ppx, ppy + radius);
|
|
29014
|
-
ctx.quadraticCurveTo(ppx, ppy, ppx + radius, ppy);
|
|
29015
|
-
ctx.fill();
|
|
29016
|
-
const eyeY = ppy + ph * 0.3;
|
|
29017
|
-
const eyeSize = 3;
|
|
29018
|
-
const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
|
|
29019
|
-
ctx.fillStyle = PLAYER_EYE_COLOR;
|
|
29020
|
-
ctx.beginPath();
|
|
29021
|
-
ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
|
|
29022
|
-
ctx.fill();
|
|
29023
|
-
ctx.beginPath();
|
|
29024
|
-
ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
|
|
29025
|
-
ctx.fill();
|
|
29026
|
-
}
|
|
29027
|
-
}, [player, platforms, worldWidth, worldHeight, canvasWidth, canvasHeight, followCamera, bgColor, playerSprite, tileSprites, backgroundImage, assetBaseUrl, loadedImages]);
|
|
29157
|
+
};
|
|
29158
|
+
return interp.startLoop(drawFrame);
|
|
29159
|
+
}, [interp.startLoop, loadImage]);
|
|
29028
29160
|
return /* @__PURE__ */ jsx(
|
|
29029
29161
|
"canvas",
|
|
29030
29162
|
{
|
|
@@ -29042,6 +29174,7 @@ var init_PlatformerCanvas = __esm({
|
|
|
29042
29174
|
init_cn();
|
|
29043
29175
|
init_useEventBus();
|
|
29044
29176
|
init_verificationRegistry();
|
|
29177
|
+
init_useRenderInterpolation();
|
|
29045
29178
|
PLATFORM_COLORS = {
|
|
29046
29179
|
ground: "#4a7c59",
|
|
29047
29180
|
platform: "#7c6b4a",
|
|
@@ -29446,13 +29579,13 @@ var init_MapView = __esm({
|
|
|
29446
29579
|
shadowSize: [41, 41]
|
|
29447
29580
|
});
|
|
29448
29581
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
29449
|
-
const { useEffect:
|
|
29582
|
+
const { useEffect: useEffect74, useRef: useRef71, useCallback: useCallback114, useState: useState105 } = React77__default;
|
|
29450
29583
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
29451
29584
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
29452
29585
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
29453
29586
|
const map = useMap();
|
|
29454
|
-
const prevRef =
|
|
29455
|
-
|
|
29587
|
+
const prevRef = useRef71({ centerLat, centerLng, zoom });
|
|
29588
|
+
useEffect74(() => {
|
|
29456
29589
|
const prev = prevRef.current;
|
|
29457
29590
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
29458
29591
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -29463,7 +29596,7 @@ var init_MapView = __esm({
|
|
|
29463
29596
|
}
|
|
29464
29597
|
function MapClickHandler({ onMapClick }) {
|
|
29465
29598
|
const map = useMap();
|
|
29466
|
-
|
|
29599
|
+
useEffect74(() => {
|
|
29467
29600
|
if (!onMapClick) return;
|
|
29468
29601
|
const handler = (e) => {
|
|
29469
29602
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -29492,7 +29625,7 @@ var init_MapView = __esm({
|
|
|
29492
29625
|
}) {
|
|
29493
29626
|
const eventBus = useEventBus2();
|
|
29494
29627
|
const [clickedPosition, setClickedPosition] = useState105(null);
|
|
29495
|
-
const handleMapClick =
|
|
29628
|
+
const handleMapClick = useCallback114((lat, lng) => {
|
|
29496
29629
|
if (showClickedPin) {
|
|
29497
29630
|
setClickedPosition({ lat, lng });
|
|
29498
29631
|
}
|
|
@@ -29501,7 +29634,7 @@ var init_MapView = __esm({
|
|
|
29501
29634
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29502
29635
|
}
|
|
29503
29636
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29504
|
-
const handleMarkerClick =
|
|
29637
|
+
const handleMarkerClick = useCallback114((marker) => {
|
|
29505
29638
|
onMarkerClick?.(marker);
|
|
29506
29639
|
if (markerClickEvent) {
|
|
29507
29640
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -45463,6 +45596,10 @@ function SequencerBoard({
|
|
|
45463
45596
|
stepDurationMs = 1e3,
|
|
45464
45597
|
playEvent,
|
|
45465
45598
|
completeEvent,
|
|
45599
|
+
placeEvent,
|
|
45600
|
+
removeEvent,
|
|
45601
|
+
checkEvent,
|
|
45602
|
+
playAgainEvent,
|
|
45466
45603
|
className
|
|
45467
45604
|
}) {
|
|
45468
45605
|
const { emit } = useEventBus();
|
|
@@ -45498,7 +45635,8 @@ function SequencerBoard({
|
|
|
45498
45635
|
return next;
|
|
45499
45636
|
});
|
|
45500
45637
|
emit("UI:PLAY_SOUND", { key: "drop_slot" });
|
|
45501
|
-
|
|
45638
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotIndex: index, actionId: item.id });
|
|
45639
|
+
}, [emit, placeEvent]);
|
|
45502
45640
|
const handleSlotRemove = useCallback((index) => {
|
|
45503
45641
|
setSlots((prev) => {
|
|
45504
45642
|
const next = [...prev];
|
|
@@ -45511,7 +45649,8 @@ function SequencerBoard({
|
|
|
45511
45649
|
return next;
|
|
45512
45650
|
});
|
|
45513
45651
|
emit("UI:PLAY_SOUND", { key: "back" });
|
|
45514
|
-
|
|
45652
|
+
if (removeEvent) emit(`UI:${removeEvent}`, { slotIndex: index });
|
|
45653
|
+
}, [emit, removeEvent]);
|
|
45515
45654
|
const handleReset = useCallback(() => {
|
|
45516
45655
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
45517
45656
|
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
@@ -45519,7 +45658,8 @@ function SequencerBoard({
|
|
|
45519
45658
|
setCurrentStep(-1);
|
|
45520
45659
|
setAttempts(0);
|
|
45521
45660
|
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
45522
|
-
|
|
45661
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
45662
|
+
}, [maxSlots, playAgainEvent, emit]);
|
|
45523
45663
|
const filledSlots = slots.filter((s) => !!s);
|
|
45524
45664
|
const canPlay = filledSlots.length > 0 && playState === "idle";
|
|
45525
45665
|
const handlePlay = useCallback(() => {
|
|
@@ -45541,6 +45681,7 @@ function SequencerBoard({
|
|
|
45541
45681
|
const success = solutions.some(
|
|
45542
45682
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
45543
45683
|
);
|
|
45684
|
+
if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
|
|
45544
45685
|
if (success) {
|
|
45545
45686
|
setPlayState("success");
|
|
45546
45687
|
setCurrentStep(-1);
|
|
@@ -45568,7 +45709,7 @@ function SequencerBoard({
|
|
|
45568
45709
|
}
|
|
45569
45710
|
};
|
|
45570
45711
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
45571
|
-
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, emit]);
|
|
45712
|
+
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, checkEvent, emit]);
|
|
45572
45713
|
const machine = {
|
|
45573
45714
|
name: str(resolved?.title),
|
|
45574
45715
|
description: str(resolved?.description),
|
|
@@ -45823,11 +45964,13 @@ function SimulationCanvas({
|
|
|
45823
45964
|
height = 400,
|
|
45824
45965
|
running,
|
|
45825
45966
|
speed = 1,
|
|
45967
|
+
bodies: externalBodies,
|
|
45826
45968
|
className
|
|
45827
45969
|
}) {
|
|
45828
45970
|
const preset = useMemo(() => resolvePreset(presetProp), [presetProp]);
|
|
45829
45971
|
const canvasRef = useRef(null);
|
|
45830
45972
|
const bodiesRef = useRef(structuredClone(preset.bodies));
|
|
45973
|
+
const interp = useRenderInterpolation();
|
|
45831
45974
|
useEffect(() => {
|
|
45832
45975
|
bodiesRef.current = structuredClone(preset.bodies);
|
|
45833
45976
|
}, [preset]);
|
|
@@ -45925,6 +46068,67 @@ function SimulationCanvas({
|
|
|
45925
46068
|
}
|
|
45926
46069
|
}, [width, height, preset]);
|
|
45927
46070
|
useEffect(() => {
|
|
46071
|
+
if (!externalBodies) return;
|
|
46072
|
+
interp.onSnapshot(externalBodies.map((b) => ({ id: b.id, x: b.x, y: b.y })));
|
|
46073
|
+
}, [externalBodies]);
|
|
46074
|
+
const presetRef = useRef(preset);
|
|
46075
|
+
presetRef.current = preset;
|
|
46076
|
+
const widthRef = useRef(width);
|
|
46077
|
+
widthRef.current = width;
|
|
46078
|
+
const heightRef = useRef(height);
|
|
46079
|
+
heightRef.current = height;
|
|
46080
|
+
useEffect(() => {
|
|
46081
|
+
if (!externalBodies) return;
|
|
46082
|
+
const drawInterpolated = (positions) => {
|
|
46083
|
+
const canvas = canvasRef.current;
|
|
46084
|
+
if (!canvas) return;
|
|
46085
|
+
const ctx = canvas.getContext("2d");
|
|
46086
|
+
if (!ctx) return;
|
|
46087
|
+
const bodies = bodiesRef.current;
|
|
46088
|
+
const p2 = presetRef.current;
|
|
46089
|
+
const w = widthRef.current;
|
|
46090
|
+
const h = heightRef.current;
|
|
46091
|
+
ctx.clearRect(0, 0, w, h);
|
|
46092
|
+
ctx.fillStyle = p2.backgroundColor ?? "#1a1a2e";
|
|
46093
|
+
ctx.fillRect(0, 0, w, h);
|
|
46094
|
+
if (p2.constraints) {
|
|
46095
|
+
for (const c of p2.constraints) {
|
|
46096
|
+
const a = bodies[c.bodyA];
|
|
46097
|
+
const b = bodies[c.bodyB];
|
|
46098
|
+
if (a && b) {
|
|
46099
|
+
const aPos = positions.get(a.id) ?? a;
|
|
46100
|
+
const bPos = positions.get(b.id) ?? b;
|
|
46101
|
+
ctx.beginPath();
|
|
46102
|
+
ctx.moveTo(aPos.x, aPos.y);
|
|
46103
|
+
ctx.lineTo(bPos.x, bPos.y);
|
|
46104
|
+
ctx.strokeStyle = "#533483";
|
|
46105
|
+
ctx.lineWidth = 1;
|
|
46106
|
+
ctx.setLineDash([4, 4]);
|
|
46107
|
+
ctx.stroke();
|
|
46108
|
+
ctx.setLineDash([]);
|
|
46109
|
+
}
|
|
46110
|
+
}
|
|
46111
|
+
}
|
|
46112
|
+
for (const body of bodies) {
|
|
46113
|
+
const pos = positions.get(body.id) ?? body;
|
|
46114
|
+
ctx.beginPath();
|
|
46115
|
+
ctx.arc(pos.x, pos.y, body.radius, 0, Math.PI * 2);
|
|
46116
|
+
ctx.fillStyle = body.color ?? "#e94560";
|
|
46117
|
+
ctx.fill();
|
|
46118
|
+
if (p2.showVelocity) {
|
|
46119
|
+
ctx.beginPath();
|
|
46120
|
+
ctx.moveTo(pos.x, pos.y);
|
|
46121
|
+
ctx.lineTo(pos.x + body.vx * 0.1, pos.y + body.vy * 0.1);
|
|
46122
|
+
ctx.strokeStyle = "#16213e";
|
|
46123
|
+
ctx.lineWidth = 2;
|
|
46124
|
+
ctx.stroke();
|
|
46125
|
+
}
|
|
46126
|
+
}
|
|
46127
|
+
};
|
|
46128
|
+
return interp.startLoop(drawInterpolated);
|
|
46129
|
+
}, [externalBodies !== void 0, interp.startLoop]);
|
|
46130
|
+
useEffect(() => {
|
|
46131
|
+
if (externalBodies !== void 0) return;
|
|
45928
46132
|
if (!running) return;
|
|
45929
46133
|
let raf;
|
|
45930
46134
|
const loop = () => {
|
|
@@ -45934,10 +46138,11 @@ function SimulationCanvas({
|
|
|
45934
46138
|
};
|
|
45935
46139
|
raf = requestAnimationFrame(loop);
|
|
45936
46140
|
return () => cancelAnimationFrame(raf);
|
|
45937
|
-
}, [running, step, draw]);
|
|
46141
|
+
}, [running, step, draw, externalBodies]);
|
|
45938
46142
|
useEffect(() => {
|
|
46143
|
+
if (externalBodies !== void 0) return;
|
|
45939
46144
|
draw();
|
|
45940
|
-
}, [draw]);
|
|
46145
|
+
}, [draw, externalBodies]);
|
|
45941
46146
|
useEffect(() => {
|
|
45942
46147
|
if (typeof window === "undefined") return;
|
|
45943
46148
|
const canvas = canvasRef.current;
|
|
@@ -45963,6 +46168,7 @@ var init_SimulationCanvas = __esm({
|
|
|
45963
46168
|
init_atoms2();
|
|
45964
46169
|
init_verificationRegistry();
|
|
45965
46170
|
init_presets();
|
|
46171
|
+
init_useRenderInterpolation();
|
|
45966
46172
|
SimulationCanvas.displayName = "SimulationCanvas";
|
|
45967
46173
|
}
|
|
45968
46174
|
});
|
package/dist/hooks/index.cjs
CHANGED
|
@@ -2504,6 +2504,73 @@ function useDropZone({ accepts, onDrop, disabled = false }) {
|
|
|
2504
2504
|
);
|
|
2505
2505
|
return { dropProps, isOver };
|
|
2506
2506
|
}
|
|
2507
|
+
function useRenderInterpolation(options = {}) {
|
|
2508
|
+
const tickIntervalMs = options.tickIntervalMs ?? 1e3 / 30;
|
|
2509
|
+
const prevRef = react.useRef(null);
|
|
2510
|
+
const currRef = react.useRef(null);
|
|
2511
|
+
const rafRef = react.useRef(null);
|
|
2512
|
+
const onSnapshot = react.useCallback((entities2) => {
|
|
2513
|
+
prevRef.current = currRef.current;
|
|
2514
|
+
currRef.current = { entities: entities2, arrivedAt: performance.now() };
|
|
2515
|
+
}, []);
|
|
2516
|
+
const getInterpolated = react.useCallback((now) => {
|
|
2517
|
+
const out = /* @__PURE__ */ new Map();
|
|
2518
|
+
const curr = currRef.current;
|
|
2519
|
+
if (!curr) return out;
|
|
2520
|
+
const prev = prevRef.current;
|
|
2521
|
+
if (!prev) {
|
|
2522
|
+
for (const e of curr.entities) out.set(e.id, { x: e.x, y: e.y });
|
|
2523
|
+
return out;
|
|
2524
|
+
}
|
|
2525
|
+
const rawAlpha = (now - curr.arrivedAt) / tickIntervalMs;
|
|
2526
|
+
const alpha = rawAlpha < 0 ? 0 : rawAlpha > 1 ? 1 : rawAlpha;
|
|
2527
|
+
const prevMap = /* @__PURE__ */ new Map();
|
|
2528
|
+
for (const e of prev.entities) prevMap.set(e.id, e);
|
|
2529
|
+
for (const c of curr.entities) {
|
|
2530
|
+
const p = prevMap.get(c.id);
|
|
2531
|
+
if (!p) {
|
|
2532
|
+
out.set(c.id, { x: c.x, y: c.y });
|
|
2533
|
+
} else {
|
|
2534
|
+
out.set(c.id, {
|
|
2535
|
+
x: p.x + (c.x - p.x) * alpha,
|
|
2536
|
+
y: p.y + (c.y - p.y) * alpha
|
|
2537
|
+
});
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
return out;
|
|
2541
|
+
}, [tickIntervalMs]);
|
|
2542
|
+
const startLoop = react.useCallback(
|
|
2543
|
+
(draw) => {
|
|
2544
|
+
let active = true;
|
|
2545
|
+
const loop = () => {
|
|
2546
|
+
if (!active) return;
|
|
2547
|
+
try {
|
|
2548
|
+
draw(getInterpolated(performance.now()));
|
|
2549
|
+
} catch {
|
|
2550
|
+
}
|
|
2551
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
2552
|
+
};
|
|
2553
|
+
rafRef.current = requestAnimationFrame(loop);
|
|
2554
|
+
return () => {
|
|
2555
|
+
active = false;
|
|
2556
|
+
if (rafRef.current !== null) {
|
|
2557
|
+
cancelAnimationFrame(rafRef.current);
|
|
2558
|
+
rafRef.current = null;
|
|
2559
|
+
}
|
|
2560
|
+
};
|
|
2561
|
+
},
|
|
2562
|
+
[getInterpolated]
|
|
2563
|
+
);
|
|
2564
|
+
react.useEffect(() => {
|
|
2565
|
+
return () => {
|
|
2566
|
+
if (rafRef.current !== null) {
|
|
2567
|
+
cancelAnimationFrame(rafRef.current);
|
|
2568
|
+
rafRef.current = null;
|
|
2569
|
+
}
|
|
2570
|
+
};
|
|
2571
|
+
}, []);
|
|
2572
|
+
return { onSnapshot, getInterpolated, startLoop };
|
|
2573
|
+
}
|
|
2507
2574
|
var API_BASE = typeof process !== "undefined" && process.env?.VITE_API_URL ? process.env.VITE_API_URL : "http://localhost:3000";
|
|
2508
2575
|
function getUserId() {
|
|
2509
2576
|
return localStorage.getItem("userId") || "anonymous";
|
|
@@ -2626,6 +2693,7 @@ exports.usePlayer = usePlayer;
|
|
|
2626
2693
|
exports.usePreview = usePreview;
|
|
2627
2694
|
exports.usePullToRefresh = usePullToRefresh;
|
|
2628
2695
|
exports.useQuerySingleton = useQuerySingleton;
|
|
2696
|
+
exports.useRenderInterpolation = useRenderInterpolation;
|
|
2629
2697
|
exports.useSingletonEntity = useSingletonEntity;
|
|
2630
2698
|
exports.useSwipeGesture = useSwipeGesture;
|
|
2631
2699
|
exports.useTraitListens = useTraitListens;
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -26,4 +26,5 @@ export { usePullToRefresh, type PullToRefreshOptions, type PullToRefreshResult,
|
|
|
26
26
|
export { usePinchZoom, type PinchZoomOptions, type PinchZoomResult, } from './usePinchZoom';
|
|
27
27
|
export { useDraggable, ALMADAR_DND_MIME, type DraggablePayload, type UseDraggableOptions, type UseDraggableResult, } from './useDraggable';
|
|
28
28
|
export { useDropZone, type UseDropZoneOptions, type UseDropZoneResult, } from './useDropZone';
|
|
29
|
+
export { useRenderInterpolation, type Positioned, type RenderInterpolationOptions, type RenderInterpolationHandle, } from './useRenderInterpolation';
|
|
29
30
|
export { useGitHubStatus, useConnectGitHub, useDisconnectGitHub, useGitHubRepos, useGitHubRepo, useGitHubBranches, type GitHubStatus, type GitHubRepo, } from './useGitHub';
|