@almadar/ui 5.42.0 → 5.44.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.
@@ -6,7 +6,7 @@ import { EventBusContext, useTraitScope, TraitScopeProvider } from '@almadar/ui/
6
6
  import { clsx } from 'clsx';
7
7
  import { twMerge } from 'tailwind-merge';
8
8
  import * as LucideIcons2 from 'lucide-react';
9
- import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ZoomOut, ZoomIn, Download, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, ArrowLeft, HelpCircle, PauseCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, Pause, SkipForward, Bug, Send, ChevronUp, ChevronDown, Wrench, Tag, User, DollarSign, Zap, Sword, Move, Heart, Shield } from 'lucide-react';
9
+ import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ZoomOut, ZoomIn, Download, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, ArrowLeft, HelpCircle, PauseCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, Bug, Send, ChevronUp, ChevronDown, Wrench, Tag, User, DollarSign, Zap, Sword, Move, Heart, Shield } from 'lucide-react';
10
10
  import { createPortal } from 'react-dom';
11
11
  import { useTranslate } from '@almadar/ui/hooks';
12
12
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
@@ -28563,6 +28563,78 @@ var init_GameOverScreen = __esm({
28563
28563
  GameOverScreen.displayName = "GameOverScreen";
28564
28564
  }
28565
28565
  });
28566
+ function useRenderInterpolation(options = {}) {
28567
+ const tickIntervalMs = options.tickIntervalMs ?? 1e3 / 30;
28568
+ const prevRef = useRef(null);
28569
+ const currRef = useRef(null);
28570
+ const rafRef = useRef(null);
28571
+ const onSnapshot = useCallback((entities) => {
28572
+ prevRef.current = currRef.current;
28573
+ currRef.current = { entities, arrivedAt: performance.now() };
28574
+ }, []);
28575
+ const getInterpolated = useCallback((now) => {
28576
+ const out = /* @__PURE__ */ new Map();
28577
+ const curr = currRef.current;
28578
+ if (!curr) return out;
28579
+ const prev = prevRef.current;
28580
+ if (!prev) {
28581
+ for (const e of curr.entities) out.set(e.id, { x: e.x, y: e.y });
28582
+ return out;
28583
+ }
28584
+ const rawAlpha = (now - curr.arrivedAt) / tickIntervalMs;
28585
+ const alpha = rawAlpha < 0 ? 0 : rawAlpha > 1 ? 1 : rawAlpha;
28586
+ const prevMap = /* @__PURE__ */ new Map();
28587
+ for (const e of prev.entities) prevMap.set(e.id, e);
28588
+ for (const c of curr.entities) {
28589
+ const p2 = prevMap.get(c.id);
28590
+ if (!p2) {
28591
+ out.set(c.id, { x: c.x, y: c.y });
28592
+ } else {
28593
+ out.set(c.id, {
28594
+ x: p2.x + (c.x - p2.x) * alpha,
28595
+ y: p2.y + (c.y - p2.y) * alpha
28596
+ });
28597
+ }
28598
+ }
28599
+ return out;
28600
+ }, [tickIntervalMs]);
28601
+ const startLoop = useCallback(
28602
+ (draw) => {
28603
+ let active = true;
28604
+ const loop = () => {
28605
+ if (!active) return;
28606
+ try {
28607
+ draw(getInterpolated(performance.now()));
28608
+ } catch {
28609
+ }
28610
+ rafRef.current = requestAnimationFrame(loop);
28611
+ };
28612
+ rafRef.current = requestAnimationFrame(loop);
28613
+ return () => {
28614
+ active = false;
28615
+ if (rafRef.current !== null) {
28616
+ cancelAnimationFrame(rafRef.current);
28617
+ rafRef.current = null;
28618
+ }
28619
+ };
28620
+ },
28621
+ [getInterpolated]
28622
+ );
28623
+ useEffect(() => {
28624
+ return () => {
28625
+ if (rafRef.current !== null) {
28626
+ cancelAnimationFrame(rafRef.current);
28627
+ rafRef.current = null;
28628
+ }
28629
+ };
28630
+ }, []);
28631
+ return { onSnapshot, getInterpolated, startLoop };
28632
+ }
28633
+ var init_useRenderInterpolation = __esm({
28634
+ "hooks/useRenderInterpolation.ts"() {
28635
+ "use client";
28636
+ }
28637
+ });
28566
28638
  function PlatformerCanvas({
28567
28639
  player,
28568
28640
  platforms = [
@@ -28631,8 +28703,43 @@ function PlatformerCanvas({
28631
28703
  y: 336,
28632
28704
  width: 32,
28633
28705
  height: 48,
28706
+ vx: 0,
28707
+ vy: 0,
28708
+ grounded: true,
28634
28709
  facingRight: true
28635
28710
  };
28711
+ const playerRef = useRef(resolvedPlayer);
28712
+ playerRef.current = resolvedPlayer;
28713
+ const interp = useRenderInterpolation();
28714
+ useEffect(() => {
28715
+ interp.onSnapshot([{ id: "player", x: resolvedPlayer.x, y: resolvedPlayer.y }]);
28716
+ }, [resolvedPlayer.x, resolvedPlayer.y]);
28717
+ const propsRef = useRef({
28718
+ platforms,
28719
+ worldWidth,
28720
+ worldHeight,
28721
+ canvasWidth,
28722
+ canvasHeight,
28723
+ followCamera,
28724
+ bgColor,
28725
+ playerSprite,
28726
+ tileSprites,
28727
+ backgroundImage,
28728
+ assetBaseUrl
28729
+ });
28730
+ propsRef.current = {
28731
+ platforms,
28732
+ worldWidth,
28733
+ worldHeight,
28734
+ canvasWidth,
28735
+ canvasHeight,
28736
+ followCamera,
28737
+ bgColor,
28738
+ playerSprite,
28739
+ tileSprites,
28740
+ backgroundImage,
28741
+ assetBaseUrl
28742
+ };
28636
28743
  const handleKeyDown = useCallback((e) => {
28637
28744
  if (keysRef.current.has(e.code)) return;
28638
28745
  keysRef.current.add(e.code);
@@ -28681,124 +28788,149 @@ function PlatformerCanvas({
28681
28788
  canvas.width = canvasWidth * dpr;
28682
28789
  canvas.height = canvasHeight * dpr;
28683
28790
  ctx.scale(dpr, dpr);
28684
- let camX = 0;
28685
- let camY = 0;
28686
- if (followCamera) {
28687
- camX = Math.max(0, Math.min(resolvedPlayer.x - canvasWidth / 2, worldWidth - canvasWidth));
28688
- camY = Math.max(0, Math.min(resolvedPlayer.y - canvasHeight / 2 - 50, worldHeight - canvasHeight));
28689
- }
28690
- const bgImg = backgroundImage ? loadImage(backgroundImage) : null;
28691
- if (bgImg) {
28692
- ctx.drawImage(bgImg, 0, 0, canvasWidth, canvasHeight);
28693
- } else if (bgColor) {
28694
- ctx.fillStyle = bgColor;
28695
- ctx.fillRect(0, 0, canvasWidth, canvasHeight);
28696
- } else {
28697
- const grad = ctx.createLinearGradient(0, 0, 0, canvasHeight);
28698
- grad.addColorStop(0, SKY_GRADIENT_TOP);
28699
- grad.addColorStop(1, SKY_GRADIENT_BOTTOM);
28700
- ctx.fillStyle = grad;
28701
- ctx.fillRect(0, 0, canvasWidth, canvasHeight);
28702
- }
28703
- ctx.strokeStyle = GRID_COLOR;
28704
- ctx.lineWidth = 1;
28705
- const gridSize = 32;
28706
- for (let gx = -camX % gridSize; gx < canvasWidth; gx += gridSize) {
28707
- ctx.beginPath();
28708
- ctx.moveTo(gx, 0);
28709
- ctx.lineTo(gx, canvasHeight);
28710
- ctx.stroke();
28711
- }
28712
- for (let gy = -camY % gridSize; gy < canvasHeight; gy += gridSize) {
28713
- ctx.beginPath();
28714
- ctx.moveTo(0, gy);
28715
- ctx.lineTo(canvasWidth, gy);
28716
- ctx.stroke();
28717
- }
28718
- for (const plat of platforms) {
28719
- const px = plat.x - camX;
28720
- const py = plat.y - camY;
28721
- const platType = plat.type ?? "ground";
28722
- const spriteUrl = tileSprites?.[platType];
28723
- const tileImg = spriteUrl ? loadImage(spriteUrl) : null;
28724
- if (tileImg) {
28725
- const tileW = tileImg.naturalWidth;
28726
- const tileH = tileImg.naturalHeight;
28727
- const scaleH = plat.height / tileH;
28728
- const scaledW = tileW * scaleH;
28729
- for (let tx = 0; tx < plat.width; tx += scaledW) {
28730
- const drawW = Math.min(scaledW, plat.width - tx);
28731
- const srcW = drawW / scaleH;
28732
- ctx.drawImage(tileImg, 0, 0, srcW, tileH, px + tx, py, drawW, plat.height);
28733
- }
28791
+ }, [canvasWidth, canvasHeight]);
28792
+ useEffect(() => {
28793
+ const drawFrame = (positions) => {
28794
+ const canvas = canvasRef.current;
28795
+ if (!canvas) return;
28796
+ const ctx = canvas.getContext("2d");
28797
+ if (!ctx) return;
28798
+ const {
28799
+ platforms: plats,
28800
+ worldWidth: ww,
28801
+ worldHeight: wh,
28802
+ canvasWidth: cw,
28803
+ canvasHeight: ch,
28804
+ followCamera: fc,
28805
+ bgColor: bg,
28806
+ playerSprite: pSprite,
28807
+ tileSprites: tSprites,
28808
+ backgroundImage: bgImg
28809
+ } = propsRef.current;
28810
+ const auth = playerRef.current;
28811
+ const interped = positions.get("player");
28812
+ const px = interped?.x ?? auth.x;
28813
+ const py = interped?.y ?? auth.y;
28814
+ let camX = 0;
28815
+ let camY = 0;
28816
+ if (fc) {
28817
+ camX = Math.max(0, Math.min(px - cw / 2, ww - cw));
28818
+ camY = Math.max(0, Math.min(py - ch / 2 - 50, wh - ch));
28819
+ }
28820
+ const bgImage = bgImg ? loadImage(bgImg) : null;
28821
+ if (bgImage) {
28822
+ ctx.drawImage(bgImage, 0, 0, cw, ch);
28823
+ } else if (bg) {
28824
+ ctx.fillStyle = bg;
28825
+ ctx.fillRect(0, 0, cw, ch);
28734
28826
  } else {
28735
- const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
28736
- ctx.fillStyle = color;
28737
- ctx.fillRect(px, py, plat.width, plat.height);
28738
- ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
28739
- ctx.fillRect(px, py, plat.width, 3);
28740
- ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
28741
- ctx.fillRect(px, py + plat.height - 2, plat.width, 2);
28742
- if (platType === "hazard") {
28743
- ctx.strokeStyle = "#e74c3c";
28744
- ctx.lineWidth = 2;
28745
- for (let sx = px; sx < px + plat.width; sx += 12) {
28827
+ const grad = ctx.createLinearGradient(0, 0, 0, ch);
28828
+ grad.addColorStop(0, SKY_GRADIENT_TOP);
28829
+ grad.addColorStop(1, SKY_GRADIENT_BOTTOM);
28830
+ ctx.fillStyle = grad;
28831
+ ctx.fillRect(0, 0, cw, ch);
28832
+ }
28833
+ ctx.strokeStyle = GRID_COLOR;
28834
+ ctx.lineWidth = 1;
28835
+ const gridSize = 32;
28836
+ for (let gx = -camX % gridSize; gx < cw; gx += gridSize) {
28837
+ ctx.beginPath();
28838
+ ctx.moveTo(gx, 0);
28839
+ ctx.lineTo(gx, ch);
28840
+ ctx.stroke();
28841
+ }
28842
+ for (let gy = -camY % gridSize; gy < ch; gy += gridSize) {
28843
+ ctx.beginPath();
28844
+ ctx.moveTo(0, gy);
28845
+ ctx.lineTo(cw, gy);
28846
+ ctx.stroke();
28847
+ }
28848
+ for (const plat of plats) {
28849
+ const platX = plat.x - camX;
28850
+ const platY = plat.y - camY;
28851
+ const platType = plat.type ?? "ground";
28852
+ const spriteUrl = tSprites?.[platType];
28853
+ const tileImg = spriteUrl ? loadImage(spriteUrl) : null;
28854
+ if (tileImg) {
28855
+ const tileW = tileImg.naturalWidth;
28856
+ const tileH = tileImg.naturalHeight;
28857
+ const scaleH = plat.height / tileH;
28858
+ const scaledW = tileW * scaleH;
28859
+ for (let tx = 0; tx < plat.width; tx += scaledW) {
28860
+ const drawW = Math.min(scaledW, plat.width - tx);
28861
+ const srcW = drawW / scaleH;
28862
+ ctx.drawImage(tileImg, 0, 0, srcW, tileH, platX + tx, platY, drawW, plat.height);
28863
+ }
28864
+ } else {
28865
+ const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
28866
+ ctx.fillStyle = color;
28867
+ ctx.fillRect(platX, platY, plat.width, plat.height);
28868
+ ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
28869
+ ctx.fillRect(platX, platY, plat.width, 3);
28870
+ ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
28871
+ ctx.fillRect(platX, platY + plat.height - 2, plat.width, 2);
28872
+ if (platType === "hazard") {
28873
+ ctx.strokeStyle = "#e74c3c";
28874
+ ctx.lineWidth = 2;
28875
+ for (let sx = platX; sx < platX + plat.width; sx += 12) {
28876
+ ctx.beginPath();
28877
+ ctx.moveTo(sx, platY);
28878
+ ctx.lineTo(sx + 6, platY + plat.height);
28879
+ ctx.stroke();
28880
+ }
28881
+ }
28882
+ if (platType === "goal") {
28883
+ ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
28746
28884
  ctx.beginPath();
28747
- ctx.moveTo(sx, py);
28748
- ctx.lineTo(sx + 6, py + plat.height);
28749
- ctx.stroke();
28885
+ ctx.arc(platX + plat.width / 2, platY - 10, 8, 0, Math.PI * 2);
28886
+ ctx.fill();
28750
28887
  }
28751
28888
  }
28752
- if (platType === "goal") {
28753
- ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
28754
- ctx.beginPath();
28755
- ctx.arc(px + plat.width / 2, py - 10, 8, 0, Math.PI * 2);
28756
- ctx.fill();
28757
- }
28758
28889
  }
28759
- }
28760
- const pw = resolvedPlayer.width ?? 24;
28761
- const ph = resolvedPlayer.height ?? 32;
28762
- const ppx = resolvedPlayer.x - camX;
28763
- const ppy = resolvedPlayer.y - camY;
28764
- const facingRight = resolvedPlayer.facingRight ?? true;
28765
- const playerImg = playerSprite ? loadImage(playerSprite) : null;
28766
- if (playerImg) {
28767
- ctx.save();
28768
- if (!facingRight) {
28769
- ctx.translate(ppx + pw, ppy);
28770
- ctx.scale(-1, 1);
28771
- ctx.drawImage(playerImg, 0, 0, pw, ph);
28890
+ const pw = auth.width ?? 24;
28891
+ const ph = auth.height ?? 32;
28892
+ const ppx = px - camX;
28893
+ const ppy = py - camY;
28894
+ const facingRight = auth.facingRight ?? true;
28895
+ const playerImg = pSprite ? loadImage(pSprite) : null;
28896
+ if (playerImg) {
28897
+ ctx.save();
28898
+ if (!facingRight) {
28899
+ ctx.translate(ppx + pw, ppy);
28900
+ ctx.scale(-1, 1);
28901
+ ctx.drawImage(playerImg, 0, 0, pw, ph);
28902
+ } else {
28903
+ ctx.drawImage(playerImg, ppx, ppy, pw, ph);
28904
+ }
28905
+ ctx.restore();
28772
28906
  } else {
28773
- ctx.drawImage(playerImg, ppx, ppy, pw, ph);
28907
+ ctx.fillStyle = PLAYER_COLOR;
28908
+ const radius = Math.min(pw, ph) * 0.25;
28909
+ ctx.beginPath();
28910
+ ctx.moveTo(ppx + radius, ppy);
28911
+ ctx.lineTo(ppx + pw - radius, ppy);
28912
+ ctx.quadraticCurveTo(ppx + pw, ppy, ppx + pw, ppy + radius);
28913
+ ctx.lineTo(ppx + pw, ppy + ph - radius);
28914
+ ctx.quadraticCurveTo(ppx + pw, ppy + ph, ppx + pw - radius, ppy + ph);
28915
+ ctx.lineTo(ppx + radius, ppy + ph);
28916
+ ctx.quadraticCurveTo(ppx, ppy + ph, ppx, ppy + ph - radius);
28917
+ ctx.lineTo(ppx, ppy + radius);
28918
+ ctx.quadraticCurveTo(ppx, ppy, ppx + radius, ppy);
28919
+ ctx.fill();
28920
+ const eyeY = ppy + ph * 0.3;
28921
+ const eyeSize = 3;
28922
+ const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
28923
+ ctx.fillStyle = PLAYER_EYE_COLOR;
28924
+ ctx.beginPath();
28925
+ ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
28926
+ ctx.fill();
28927
+ ctx.beginPath();
28928
+ ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
28929
+ ctx.fill();
28774
28930
  }
28775
- ctx.restore();
28776
- } else {
28777
- ctx.fillStyle = PLAYER_COLOR;
28778
- const radius = Math.min(pw, ph) * 0.25;
28779
- ctx.beginPath();
28780
- ctx.moveTo(ppx + radius, ppy);
28781
- ctx.lineTo(ppx + pw - radius, ppy);
28782
- ctx.quadraticCurveTo(ppx + pw, ppy, ppx + pw, ppy + radius);
28783
- ctx.lineTo(ppx + pw, ppy + ph - radius);
28784
- ctx.quadraticCurveTo(ppx + pw, ppy + ph, ppx + pw - radius, ppy + ph);
28785
- ctx.lineTo(ppx + radius, ppy + ph);
28786
- ctx.quadraticCurveTo(ppx, ppy + ph, ppx, ppy + ph - radius);
28787
- ctx.lineTo(ppx, ppy + radius);
28788
- ctx.quadraticCurveTo(ppx, ppy, ppx + radius, ppy);
28789
- ctx.fill();
28790
- const eyeY = ppy + ph * 0.3;
28791
- const eyeSize = 3;
28792
- const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
28793
- ctx.fillStyle = PLAYER_EYE_COLOR;
28794
- ctx.beginPath();
28795
- ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
28796
- ctx.fill();
28797
- ctx.beginPath();
28798
- ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
28799
- ctx.fill();
28800
- }
28801
- }, [player, platforms, worldWidth, worldHeight, canvasWidth, canvasHeight, followCamera, bgColor, playerSprite, tileSprites, backgroundImage, assetBaseUrl, loadedImages]);
28931
+ };
28932
+ return interp.startLoop(drawFrame);
28933
+ }, [interp.startLoop, loadImage]);
28802
28934
  return /* @__PURE__ */ jsx(
28803
28935
  "canvas",
28804
28936
  {
@@ -28816,6 +28948,7 @@ var init_PlatformerCanvas = __esm({
28816
28948
  init_cn();
28817
28949
  init_useEventBus();
28818
28950
  init_verificationRegistry();
28951
+ init_useRenderInterpolation();
28819
28952
  PLATFORM_COLORS = {
28820
28953
  ground: "#4a7c59",
28821
28954
  platform: "#7c6b4a",
@@ -29198,7 +29331,7 @@ var init_MapView = __esm({
29198
29331
  shadowSize: [41, 41]
29199
29332
  });
29200
29333
  L.Marker.prototype.options.icon = defaultIcon;
29201
- const { useEffect: useEffect73, useRef: useRef68, useCallback: useCallback111, useState: useState104 } = React83__default;
29334
+ const { useEffect: useEffect73, useRef: useRef68, useCallback: useCallback112, useState: useState104 } = React83__default;
29202
29335
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
29203
29336
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
29204
29337
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -29244,7 +29377,7 @@ var init_MapView = __esm({
29244
29377
  }) {
29245
29378
  const eventBus = useEventBus2();
29246
29379
  const [clickedPosition, setClickedPosition] = useState104(null);
29247
- const handleMapClick = useCallback111((lat, lng) => {
29380
+ const handleMapClick = useCallback112((lat, lng) => {
29248
29381
  if (showClickedPin) {
29249
29382
  setClickedPosition({ lat, lng });
29250
29383
  }
@@ -29253,7 +29386,7 @@ var init_MapView = __esm({
29253
29386
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
29254
29387
  }
29255
29388
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
29256
- const handleMarkerClick = useCallback111((marker) => {
29389
+ const handleMarkerClick = useCallback112((marker) => {
29257
29390
  onMarkerClick?.(marker);
29258
29391
  if (markerClickEvent) {
29259
29392
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -34252,7 +34385,7 @@ var init_RichBlockEditor = __esm({
34252
34385
  "border-b border-border bg-muted/30 px-2 py-2"
34253
34386
  ),
34254
34387
  children: TOOLBAR_ENTRIES.map((entry) => {
34255
- const Icon3 = entry.icon;
34388
+ const Icon2 = entry.icon;
34256
34389
  const entryLabel = t(entry.labelKey);
34257
34390
  return /* @__PURE__ */ jsxs(
34258
34391
  Button,
@@ -34264,7 +34397,7 @@ var init_RichBlockEditor = __esm({
34264
34397
  title: entryLabel,
34265
34398
  onClick: () => handleAppend(entry.type),
34266
34399
  children: [
34267
- /* @__PURE__ */ jsx(Icon3, { size: 14 }),
34400
+ /* @__PURE__ */ jsx(Icon2, { size: 14 }),
34268
34401
  /* @__PURE__ */ jsx(Typography, { as: "span", variant: "caption", className: "ml-1 hidden text-xs sm:inline", children: entryLabel })
34269
34402
  ]
34270
34403
  },
@@ -45106,11 +45239,13 @@ function SimulationCanvas({
45106
45239
  height = 400,
45107
45240
  running,
45108
45241
  speed = 1,
45242
+ bodies: externalBodies,
45109
45243
  className
45110
45244
  }) {
45111
45245
  const preset = useMemo(() => resolvePreset(presetProp), [presetProp]);
45112
45246
  const canvasRef = useRef(null);
45113
45247
  const bodiesRef = useRef(structuredClone(preset.bodies));
45248
+ const interp = useRenderInterpolation();
45114
45249
  useEffect(() => {
45115
45250
  bodiesRef.current = structuredClone(preset.bodies);
45116
45251
  }, [preset]);
@@ -45208,6 +45343,67 @@ function SimulationCanvas({
45208
45343
  }
45209
45344
  }, [width, height, preset]);
45210
45345
  useEffect(() => {
45346
+ if (!externalBodies) return;
45347
+ interp.onSnapshot(externalBodies.map((b) => ({ id: b.id, x: b.x, y: b.y })));
45348
+ }, [externalBodies]);
45349
+ const presetRef = useRef(preset);
45350
+ presetRef.current = preset;
45351
+ const widthRef = useRef(width);
45352
+ widthRef.current = width;
45353
+ const heightRef = useRef(height);
45354
+ heightRef.current = height;
45355
+ useEffect(() => {
45356
+ if (!externalBodies) return;
45357
+ const drawInterpolated = (positions) => {
45358
+ const canvas = canvasRef.current;
45359
+ if (!canvas) return;
45360
+ const ctx = canvas.getContext("2d");
45361
+ if (!ctx) return;
45362
+ const bodies = bodiesRef.current;
45363
+ const p2 = presetRef.current;
45364
+ const w = widthRef.current;
45365
+ const h = heightRef.current;
45366
+ ctx.clearRect(0, 0, w, h);
45367
+ ctx.fillStyle = p2.backgroundColor ?? "#1a1a2e";
45368
+ ctx.fillRect(0, 0, w, h);
45369
+ if (p2.constraints) {
45370
+ for (const c of p2.constraints) {
45371
+ const a = bodies[c.bodyA];
45372
+ const b = bodies[c.bodyB];
45373
+ if (a && b) {
45374
+ const aPos = positions.get(a.id) ?? a;
45375
+ const bPos = positions.get(b.id) ?? b;
45376
+ ctx.beginPath();
45377
+ ctx.moveTo(aPos.x, aPos.y);
45378
+ ctx.lineTo(bPos.x, bPos.y);
45379
+ ctx.strokeStyle = "#533483";
45380
+ ctx.lineWidth = 1;
45381
+ ctx.setLineDash([4, 4]);
45382
+ ctx.stroke();
45383
+ ctx.setLineDash([]);
45384
+ }
45385
+ }
45386
+ }
45387
+ for (const body of bodies) {
45388
+ const pos = positions.get(body.id) ?? body;
45389
+ ctx.beginPath();
45390
+ ctx.arc(pos.x, pos.y, body.radius, 0, Math.PI * 2);
45391
+ ctx.fillStyle = body.color ?? "#e94560";
45392
+ ctx.fill();
45393
+ if (p2.showVelocity) {
45394
+ ctx.beginPath();
45395
+ ctx.moveTo(pos.x, pos.y);
45396
+ ctx.lineTo(pos.x + body.vx * 0.1, pos.y + body.vy * 0.1);
45397
+ ctx.strokeStyle = "#16213e";
45398
+ ctx.lineWidth = 2;
45399
+ ctx.stroke();
45400
+ }
45401
+ }
45402
+ };
45403
+ return interp.startLoop(drawInterpolated);
45404
+ }, [externalBodies !== void 0, interp.startLoop]);
45405
+ useEffect(() => {
45406
+ if (externalBodies !== void 0) return;
45211
45407
  if (!running) return;
45212
45408
  let raf;
45213
45409
  const loop = () => {
@@ -45217,10 +45413,11 @@ function SimulationCanvas({
45217
45413
  };
45218
45414
  raf = requestAnimationFrame(loop);
45219
45415
  return () => cancelAnimationFrame(raf);
45220
- }, [running, step, draw]);
45416
+ }, [running, step, draw, externalBodies]);
45221
45417
  useEffect(() => {
45418
+ if (externalBodies !== void 0) return;
45222
45419
  draw();
45223
- }, [draw]);
45420
+ }, [draw, externalBodies]);
45224
45421
  useEffect(() => {
45225
45422
  if (typeof window === "undefined") return;
45226
45423
  const canvas = canvasRef.current;
@@ -45246,136 +45443,10 @@ var init_SimulationCanvas = __esm({
45246
45443
  init_atoms2();
45247
45444
  init_verificationRegistry();
45248
45445
  init_presets();
45446
+ init_useRenderInterpolation();
45249
45447
  SimulationCanvas.displayName = "SimulationCanvas";
45250
45448
  }
45251
45449
  });
45252
- function SimulationControls({
45253
- running,
45254
- speed,
45255
- parameters,
45256
- onPlay,
45257
- onPause,
45258
- onStep,
45259
- onReset,
45260
- onSpeedChange,
45261
- onParameterChange,
45262
- className
45263
- }) {
45264
- return /* @__PURE__ */ jsxs(VStack, { gap: "md", className, children: [
45265
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "center", children: [
45266
- running ? /* @__PURE__ */ jsx(Button, { size: "sm", variant: "secondary", onClick: onPause, icon: Pause, children: "Pause" }) : /* @__PURE__ */ jsx(Button, { size: "sm", variant: "primary", onClick: onPlay, icon: Play, children: "Play" }),
45267
- /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: onStep, icon: SkipForward, disabled: running, children: "Step" }),
45268
- /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: onReset, icon: RotateCcw, children: "Reset" })
45269
- ] }),
45270
- /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
45271
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "muted", children: [
45272
- "Speed: ",
45273
- speed.toFixed(1),
45274
- "x"
45275
- ] }),
45276
- /* @__PURE__ */ jsx(
45277
- "input",
45278
- {
45279
- type: "range",
45280
- min: 0.1,
45281
- max: 5,
45282
- step: 0.1,
45283
- value: speed,
45284
- onChange: (e) => onSpeedChange(parseFloat(e.target.value)),
45285
- className: "w-full"
45286
- }
45287
- )
45288
- ] }),
45289
- Object.entries(parameters).map(([name, param]) => /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
45290
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "muted", children: [
45291
- param.label,
45292
- ": ",
45293
- param.value.toFixed(2)
45294
- ] }),
45295
- /* @__PURE__ */ jsx(
45296
- "input",
45297
- {
45298
- type: "range",
45299
- min: param.min,
45300
- max: param.max,
45301
- step: param.step,
45302
- value: param.value,
45303
- onChange: (e) => onParameterChange(name, parseFloat(e.target.value)),
45304
- className: "w-full"
45305
- }
45306
- )
45307
- ] }, name))
45308
- ] });
45309
- }
45310
- var init_SimulationControls = __esm({
45311
- "components/game/organisms/physics-sim/SimulationControls.tsx"() {
45312
- init_atoms2();
45313
- SimulationControls.displayName = "SimulationControls";
45314
- }
45315
- });
45316
- function SimulationGraph({
45317
- label,
45318
- unit,
45319
- data,
45320
- maxPoints = 200,
45321
- width = 300,
45322
- height = 120,
45323
- color = "#e94560",
45324
- className
45325
- }) {
45326
- const canvasRef = useRef(null);
45327
- const visibleData = data.slice(-maxPoints);
45328
- useEffect(() => {
45329
- const canvas = canvasRef.current;
45330
- if (!canvas || visibleData.length < 2) return;
45331
- const ctx = canvas.getContext("2d");
45332
- if (!ctx) return;
45333
- ctx.clearRect(0, 0, width, height);
45334
- ctx.fillStyle = "#0f0f23";
45335
- ctx.fillRect(0, 0, width, height);
45336
- ctx.strokeStyle = "#1a1a3e";
45337
- ctx.lineWidth = 0.5;
45338
- for (let i = 0; i < 5; i++) {
45339
- const y = height / 5 * i;
45340
- ctx.beginPath();
45341
- ctx.moveTo(0, y);
45342
- ctx.lineTo(width, y);
45343
- ctx.stroke();
45344
- }
45345
- let minVal = Infinity;
45346
- let maxVal = -Infinity;
45347
- for (const pt of visibleData) {
45348
- if (pt.value < minVal) minVal = pt.value;
45349
- if (pt.value > maxVal) maxVal = pt.value;
45350
- }
45351
- const range = maxVal - minVal || 1;
45352
- const pad = height * 0.1;
45353
- ctx.beginPath();
45354
- ctx.strokeStyle = color;
45355
- ctx.lineWidth = 2;
45356
- for (let i = 0; i < visibleData.length; i++) {
45357
- const x = i / (maxPoints - 1) * width;
45358
- const y = pad + (maxVal - visibleData[i].value) / range * (height - 2 * pad);
45359
- if (i === 0) ctx.moveTo(x, y);
45360
- else ctx.lineTo(x, y);
45361
- }
45362
- ctx.stroke();
45363
- const last = visibleData[visibleData.length - 1];
45364
- ctx.fillStyle = color;
45365
- ctx.font = "12px monospace";
45366
- ctx.fillText(`${last.value.toFixed(2)} ${unit}`, width - 80, 16);
45367
- }, [visibleData, width, height, color, unit, maxPoints]);
45368
- return /* @__PURE__ */ jsx(Card, { padding: "sm", className, children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
45369
- /* @__PURE__ */ jsx(Typography, { variant: "caption", weight: "bold", children: label }),
45370
- /* @__PURE__ */ jsx("canvas", { ref: canvasRef, width, height, className: "rounded" })
45371
- ] }) });
45372
- }
45373
- var init_SimulationGraph = __esm({
45374
- "components/game/organisms/physics-sim/SimulationGraph.tsx"() {
45375
- init_atoms2();
45376
- SimulationGraph.displayName = "SimulationGraph";
45377
- }
45378
- });
45379
45450
  function SimulatorBoard({
45380
45451
  entity,
45381
45452
  completeEvent = "PUZZLE_COMPLETE",
@@ -45646,7 +45717,7 @@ var init_StatCard = __esm({
45646
45717
  isLoading: externalLoading,
45647
45718
  error: externalError
45648
45719
  }) => {
45649
- const Icon3 = typeof iconProp === "string" ? resolveIcon(iconProp) ?? void 0 : iconProp;
45720
+ const Icon2 = typeof iconProp === "string" ? resolveIcon(iconProp) ?? void 0 : iconProp;
45650
45721
  const labelToUse = propLabel ?? propTitle;
45651
45722
  const eventBus = useEventBus();
45652
45723
  const { t } = useTranslate();
@@ -45789,7 +45860,7 @@ var init_StatCard = __esm({
45789
45860
  subtitle && !calculatedTrend && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: subtitle })
45790
45861
  ] }),
45791
45862
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
45792
- Icon3 && /* @__PURE__ */ jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
45863
+ Icon2 && /* @__PURE__ */ jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsx(Icon2, { className: cn("h-6 w-6", iconColor) }) }),
45793
45864
  sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
45794
45865
  ] })
45795
45866
  ] }),
@@ -47592,7 +47663,6 @@ var init_component_registry_generated = __esm({
47592
47663
  init_Navigation();
47593
47664
  init_NegotiatorBoard();
47594
47665
  init_NumberStepper();
47595
- init_ObjectRulePanel();
47596
47666
  init_OptionConstraintGroup();
47597
47667
  init_OrbitalVisualization();
47598
47668
  init_Overlay();
@@ -47623,7 +47693,6 @@ var init_component_registry_generated = __esm({
47623
47693
  init_ResourceBar();
47624
47694
  init_ResourceCounter();
47625
47695
  init_RichBlockEditor();
47626
- init_RuleEditor();
47627
47696
  init_RuntimeDebugger2();
47628
47697
  init_ScaledDiagram();
47629
47698
  init_ScoreBoard();
@@ -47643,8 +47712,6 @@ var init_component_registry_generated = __esm({
47643
47712
  init_SignaturePad();
47644
47713
  init_SimpleGrid();
47645
47714
  init_SimulationCanvas();
47646
- init_SimulationControls();
47647
- init_SimulationGraph();
47648
47715
  init_SimulatorBoard();
47649
47716
  init_Skeleton();
47650
47717
  init_SocialProof();
@@ -47662,7 +47729,6 @@ var init_component_registry_generated = __esm({
47662
47729
  init_StateArchitectBoard();
47663
47730
  init_StateIndicator();
47664
47731
  init_StateMachineView();
47665
- init_StateNode();
47666
47732
  init_StatsGrid();
47667
47733
  init_StatsOrganism();
47668
47734
  init_StatusDot();
@@ -47701,8 +47767,6 @@ var init_component_registry_generated = __esm({
47701
47767
  init_Tooltip();
47702
47768
  init_TraitFrame();
47703
47769
  init_TraitSlot();
47704
- init_TraitStateViewer();
47705
- init_TransitionArrow();
47706
47770
  init_TrendIndicator();
47707
47771
  init_TurnIndicator();
47708
47772
  init_TurnPanel();
@@ -47712,7 +47776,6 @@ var init_component_registry_generated = __esm({
47712
47776
  init_UncontrolledBattleBoard();
47713
47777
  init_UnitCommandBar();
47714
47778
  init_UploadDropZone();
47715
- init_VariablePanel();
47716
47779
  init_VersionDiff();
47717
47780
  init_ViolationAlert();
47718
47781
  init_VoteStack();
@@ -47922,7 +47985,6 @@ var init_component_registry_generated = __esm({
47922
47985
  "Navigation": Navigation,
47923
47986
  "NegotiatorBoard": NegotiatorBoard,
47924
47987
  "NumberStepper": NumberStepper,
47925
- "ObjectRulePanel": ObjectRulePanel,
47926
47988
  "OptionConstraintGroup": OptionConstraintGroup,
47927
47989
  "OrbitalVisualization": OrbitalVisualization,
47928
47990
  "Overlay": Overlay,
@@ -47953,7 +48015,6 @@ var init_component_registry_generated = __esm({
47953
48015
  "ResourceBar": ResourceBar,
47954
48016
  "ResourceCounter": ResourceCounter,
47955
48017
  "RichBlockEditor": RichBlockEditor,
47956
- "RuleEditor": RuleEditor,
47957
48018
  "RuntimeDebugger": RuntimeDebugger,
47958
48019
  "ScaledDiagram": ScaledDiagram,
47959
48020
  "ScoreBoard": ScoreBoard,
@@ -47973,8 +48034,6 @@ var init_component_registry_generated = __esm({
47973
48034
  "SignaturePad": SignaturePad,
47974
48035
  "SimpleGrid": SimpleGrid,
47975
48036
  "SimulationCanvas": SimulationCanvas,
47976
- "SimulationControls": SimulationControls,
47977
- "SimulationGraph": SimulationGraph,
47978
48037
  "SimulatorBoard": SimulatorBoard,
47979
48038
  "Skeleton": Skeleton,
47980
48039
  "SocialProof": SocialProof,
@@ -47995,7 +48054,6 @@ var init_component_registry_generated = __esm({
47995
48054
  "StateArchitectBoard": StateArchitectBoard,
47996
48055
  "StateIndicator": StateIndicator,
47997
48056
  "StateMachineView": StateMachineView,
47998
- "StateNode": StateNode2,
47999
48057
  "StatsGrid": StatsGrid,
48000
48058
  "StatsOrganism": StatsOrganism,
48001
48059
  "StatusDot": StatusDot,
@@ -48034,8 +48092,6 @@ var init_component_registry_generated = __esm({
48034
48092
  "Tooltip": Tooltip,
48035
48093
  "TraitFrame": TraitFrame,
48036
48094
  "TraitSlot": TraitSlot,
48037
- "TraitStateViewer": TraitStateViewer,
48038
- "TransitionArrow": TransitionArrow,
48039
48095
  "TrendIndicator": TrendIndicator,
48040
48096
  "TurnIndicator": TurnIndicator,
48041
48097
  "TurnPanel": TurnPanel,
@@ -48046,7 +48102,6 @@ var init_component_registry_generated = __esm({
48046
48102
  "UnitCommandBar": UnitCommandBar,
48047
48103
  "UploadDropZone": UploadDropZone,
48048
48104
  "VStack": VStack,
48049
- "VariablePanel": VariablePanel,
48050
48105
  "VersionDiff": VersionDiff,
48051
48106
  "ViolationAlert": ViolationAlert,
48052
48107
  "VoteStack": VoteStack,