@almadar/ui 5.91.0 → 5.94.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.
@@ -16348,6 +16348,7 @@ function Canvas2D({
16348
16348
  unitScale = 1,
16349
16349
  showMinimap = true,
16350
16350
  animate,
16351
+ interpolateUnits = false,
16351
16352
  // Tuning
16352
16353
  debug: debug2 = false,
16353
16354
  spriteHeightRatio = 1.5,
@@ -16382,6 +16383,8 @@ function Canvas2D({
16382
16383
  const containerRef = React74.useRef(null);
16383
16384
  const lerpRafRef = React74.useRef(0);
16384
16385
  const animRafRef = React74.useRef(0);
16386
+ const unitInterp = useRenderInterpolation();
16387
+ const interpolatedUnitPositionsRef = React74.useRef(/* @__PURE__ */ new Map());
16385
16388
  const [viewportSize, setViewportSize] = React74.useState({ width: 800, height: 600 });
16386
16389
  React74.useEffect(() => {
16387
16390
  const el = containerRef.current;
@@ -16696,7 +16699,8 @@ function Canvas2D({
16696
16699
  return depthA !== depthB ? depthA - depthB : a.position.y - b.position.y;
16697
16700
  });
16698
16701
  for (const unit of sortedUnits) {
16699
- const pos = project(unit.position.x, unit.position.y, baseOffsetX);
16702
+ const interpolated = interpolateUnits ? interpolatedUnitPositionsRef.current.get(unit.id) : void 0;
16703
+ const pos = project(interpolated?.x ?? unit.position.x, interpolated?.y ?? unit.position.y, baseOffsetX);
16700
16704
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
16701
16705
  continue;
16702
16706
  }
@@ -16848,7 +16852,8 @@ function Canvas2D({
16848
16852
  unitScale,
16849
16853
  assetManifest,
16850
16854
  spriteHeightRatio,
16851
- spriteMaxWidthRatio
16855
+ spriteMaxWidthRatio,
16856
+ interpolateUnits
16852
16857
  ]);
16853
16858
  React74.useEffect(() => {
16854
16859
  if (camera === "fixed") return;
@@ -16863,6 +16868,19 @@ function Canvas2D({
16863
16868
  y: centerY - viewportSize.height / 2
16864
16869
  };
16865
16870
  }, [camera, selectedUnitId, units, project, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
16871
+ React74.useEffect(() => {
16872
+ if (isSide || !interpolateUnits) return;
16873
+ unitInterp.onSnapshot(
16874
+ units.filter((u) => !!u.position).map((u) => ({ id: u.id, x: u.position.x, y: u.position.y }))
16875
+ );
16876
+ }, [isSide, interpolateUnits, units, unitInterp]);
16877
+ React74.useEffect(() => {
16878
+ if (isSide || !interpolateUnits) return;
16879
+ return unitInterp.startLoop((positions) => {
16880
+ interpolatedUnitPositionsRef.current = positions;
16881
+ draw();
16882
+ });
16883
+ }, [isSide, interpolateUnits, unitInterp, draw]);
16866
16884
  React74.useEffect(() => {
16867
16885
  if (isSide) return;
16868
16886
  draw();
@@ -26647,6 +26665,7 @@ function GameCard({
26647
26665
  selected = false,
26648
26666
  disabled = false,
26649
26667
  size = "md",
26668
+ animState = "idle",
26650
26669
  onClick,
26651
26670
  clickEvent,
26652
26671
  className
@@ -26674,6 +26693,7 @@ function GameCard({
26674
26693
  cardSizeMap[size],
26675
26694
  disabled ? "border-border opacity-50 cursor-not-allowed" : "border-accent hover:brightness-125 hover:-translate-y-1 cursor-pointer",
26676
26695
  selected && "ring-2 ring-foreground ring-offset-1 ring-offset-background -translate-y-1",
26696
+ ANIM_STATE_CLASS[animState],
26677
26697
  className
26678
26698
  ),
26679
26699
  children: [
@@ -26706,7 +26726,7 @@ function GameCard({
26706
26726
  }
26707
26727
  );
26708
26728
  }
26709
- var cardSizeMap, artPxMap;
26729
+ var cardSizeMap, artPxMap, ANIM_STATE_CLASS;
26710
26730
  var init_GameCard = __esm({
26711
26731
  "components/game/2d/atoms/GameCard.tsx"() {
26712
26732
  "use client";
@@ -26722,6 +26742,12 @@ var init_GameCard = __esm({
26722
26742
  lg: "w-24 h-36"
26723
26743
  };
26724
26744
  artPxMap = { sm: 40, md: 52, lg: 64 };
26745
+ ANIM_STATE_CLASS = {
26746
+ idle: "",
26747
+ drawn: "scale-105",
26748
+ played: "-translate-y-2 opacity-80",
26749
+ flipped: "scale-x-0"
26750
+ };
26725
26751
  GameCard.displayName = "GameCard";
26726
26752
  }
26727
26753
  });
@@ -27412,8 +27438,11 @@ function DialogueBubble({
27412
27438
  text = "The dungeon awaits. Choose your path wisely.",
27413
27439
  portrait = DEFAULT_PORTRAIT,
27414
27440
  position = "bottom",
27441
+ mood = "neutral",
27442
+ revealedChars,
27415
27443
  className
27416
27444
  }) {
27445
+ const visibleText = revealedChars === void 0 ? text : text.slice(0, revealedChars);
27417
27446
  return /* @__PURE__ */ jsxRuntime.jsxs(
27418
27447
  exports.Box,
27419
27448
  {
@@ -27423,16 +27452,16 @@ function DialogueBubble({
27423
27452
  className
27424
27453
  ),
27425
27454
  children: [
27426
- portrait && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl: portrait, icon: "image", size: 48, alt: speaker ?? "speaker", className: "w-full h-full object-cover" }) }),
27455
+ portrait && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: cn("flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 transition-colors duration-300", MOOD_RING_CLASS[mood]), children: /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl: portrait, icon: "image", size: 48, alt: speaker ?? "speaker", className: "w-full h-full object-cover" }) }),
27427
27456
  /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "flex flex-col gap-1 min-w-0", children: [
27428
27457
  speaker && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-sm font-bold text-warning", children: speaker }),
27429
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-sm text-foreground leading-relaxed", children: text })
27458
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-sm text-foreground leading-relaxed", children: visibleText })
27430
27459
  ] })
27431
27460
  ]
27432
27461
  }
27433
27462
  );
27434
27463
  }
27435
- var DEFAULT_PORTRAIT;
27464
+ var DEFAULT_PORTRAIT, MOOD_RING_CLASS;
27436
27465
  var init_DialogueBubble = __esm({
27437
27466
  "components/game/2d/atoms/DialogueBubble.tsx"() {
27438
27467
  init_cn();
@@ -27444,6 +27473,12 @@ var init_DialogueBubble = __esm({
27444
27473
  role: "effect",
27445
27474
  category: "character"
27446
27475
  };
27476
+ MOOD_RING_CLASS = {
27477
+ neutral: "border-warning/60",
27478
+ happy: "border-success/70",
27479
+ concerned: "border-info/70",
27480
+ angry: "border-error/70"
27481
+ };
27447
27482
  DialogueBubble.displayName = "DialogueBubble";
27448
27483
  }
27449
27484
  });
@@ -29035,6 +29070,8 @@ function SequenceBar({
29035
29070
  maxSlots,
29036
29071
  onSlotDrop,
29037
29072
  onSlotRemove,
29073
+ slotDropEvent,
29074
+ slotRemoveEvent,
29038
29075
  playing = false,
29039
29076
  currentStep = -1,
29040
29077
  categoryColors,
@@ -29042,14 +29079,17 @@ function SequenceBar({
29042
29079
  size = "lg",
29043
29080
  className
29044
29081
  }) {
29082
+ const { emit } = useEventBus();
29045
29083
  const handleDrop = React74.useCallback((index) => (item) => {
29046
29084
  if (playing) return;
29047
- onSlotDrop(index, item);
29048
- }, [onSlotDrop, playing]);
29085
+ if (slotDropEvent) emit(`UI:${slotDropEvent}`, { slotNumber: index, itemId: item.id });
29086
+ else onSlotDrop?.(index, item);
29087
+ }, [emit, slotDropEvent, onSlotDrop, playing]);
29049
29088
  const handleRemove = React74.useCallback((index) => () => {
29050
29089
  if (playing) return;
29051
- onSlotRemove(index);
29052
- }, [onSlotRemove, playing]);
29090
+ if (slotRemoveEvent) emit(`UI:${slotRemoveEvent}`, { slotNumber: index });
29091
+ else onSlotRemove?.(index);
29092
+ }, [emit, slotRemoveEvent, onSlotRemove, playing]);
29053
29093
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
29054
29094
  return /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxRuntime.jsxs(React74__namespace.default.Fragment, { children: [
29055
29095
  i > 0 && /* @__PURE__ */ jsxRuntime.jsx(
@@ -29081,9 +29121,10 @@ function SequenceBar({
29081
29121
  ] }, i)) });
29082
29122
  }
29083
29123
  var init_SequenceBar = __esm({
29084
- "components/game/2d/organisms/SequenceBar.tsx"() {
29124
+ "components/game/2d/molecules/SequenceBar.tsx"() {
29085
29125
  init_atoms();
29086
29126
  init_cn();
29127
+ init_useEventBus();
29087
29128
  init_TraitSlot();
29088
29129
  SequenceBar.displayName = "SequenceBar";
29089
29130
  }
@@ -30817,336 +30858,6 @@ var init_physicsPresets = __esm({
30817
30858
  ];
30818
30859
  }
30819
30860
  });
30820
- function resolvePreset(preset) {
30821
- if (typeof preset !== "string") return preset;
30822
- return PRESET_BY_ID[preset] ?? exports.projectileMotion;
30823
- }
30824
- function SimulationCanvas({
30825
- preset: presetProp,
30826
- width = 600,
30827
- height = 400,
30828
- bodies: externalBodies,
30829
- className
30830
- }) {
30831
- const preset = React74.useMemo(() => resolvePreset(presetProp), [presetProp]);
30832
- const canvasRef = React74.useRef(null);
30833
- const bodiesRef = React74.useRef(structuredClone(preset.bodies));
30834
- const interp = useRenderInterpolation();
30835
- React74.useEffect(() => {
30836
- bodiesRef.current = structuredClone(preset.bodies);
30837
- }, [preset]);
30838
- const draw = React74.useCallback(() => {
30839
- const canvas = canvasRef.current;
30840
- if (!canvas) return;
30841
- const ctx = canvas.getContext("2d");
30842
- if (!ctx) return;
30843
- const bodies = bodiesRef.current;
30844
- ctx.clearRect(0, 0, width, height);
30845
- ctx.fillStyle = preset.backgroundColor ?? "#1a1a2e";
30846
- ctx.fillRect(0, 0, width, height);
30847
- if (preset.constraints) {
30848
- for (const c of preset.constraints) {
30849
- const a = bodies[c.bodyA];
30850
- const b = bodies[c.bodyB];
30851
- if (a && b) {
30852
- ctx.beginPath();
30853
- ctx.moveTo(a.x, a.y);
30854
- ctx.lineTo(b.x, b.y);
30855
- ctx.strokeStyle = "#533483";
30856
- ctx.lineWidth = 1;
30857
- ctx.setLineDash([4, 4]);
30858
- ctx.stroke();
30859
- ctx.setLineDash([]);
30860
- }
30861
- }
30862
- }
30863
- for (const body of bodies) {
30864
- ctx.beginPath();
30865
- ctx.arc(body.x, body.y, body.radius, 0, Math.PI * 2);
30866
- ctx.fillStyle = body.color ?? "#e94560";
30867
- ctx.fill();
30868
- if (preset.showVelocity) {
30869
- ctx.beginPath();
30870
- ctx.moveTo(body.x, body.y);
30871
- ctx.lineTo(body.x + body.vx * 0.1, body.y + body.vy * 0.1);
30872
- ctx.strokeStyle = "#16213e";
30873
- ctx.lineWidth = 2;
30874
- ctx.stroke();
30875
- }
30876
- }
30877
- }, [width, height, preset]);
30878
- React74.useEffect(() => {
30879
- if (!externalBodies) return;
30880
- interp.onSnapshot(externalBodies.map((b) => ({ id: b.id, x: b.x, y: b.y })));
30881
- }, [externalBodies]);
30882
- const presetRef = React74.useRef(preset);
30883
- presetRef.current = preset;
30884
- const widthRef = React74.useRef(width);
30885
- widthRef.current = width;
30886
- const heightRef = React74.useRef(height);
30887
- heightRef.current = height;
30888
- React74.useEffect(() => {
30889
- if (!externalBodies) return;
30890
- const drawInterpolated = (positions) => {
30891
- const canvas = canvasRef.current;
30892
- if (!canvas) return;
30893
- const ctx = canvas.getContext("2d");
30894
- if (!ctx) return;
30895
- const bodies = bodiesRef.current;
30896
- const p = presetRef.current;
30897
- const w = widthRef.current;
30898
- const h = heightRef.current;
30899
- ctx.clearRect(0, 0, w, h);
30900
- ctx.fillStyle = p.backgroundColor ?? "#1a1a2e";
30901
- ctx.fillRect(0, 0, w, h);
30902
- if (p.constraints) {
30903
- for (const c of p.constraints) {
30904
- const a = bodies[c.bodyA];
30905
- const b = bodies[c.bodyB];
30906
- if (a && b) {
30907
- const aPos = positions.get(a.id) ?? a;
30908
- const bPos = positions.get(b.id) ?? b;
30909
- ctx.beginPath();
30910
- ctx.moveTo(aPos.x, aPos.y);
30911
- ctx.lineTo(bPos.x, bPos.y);
30912
- ctx.strokeStyle = "#533483";
30913
- ctx.lineWidth = 1;
30914
- ctx.setLineDash([4, 4]);
30915
- ctx.stroke();
30916
- ctx.setLineDash([]);
30917
- }
30918
- }
30919
- }
30920
- for (const body of bodies) {
30921
- const pos = positions.get(body.id) ?? body;
30922
- ctx.beginPath();
30923
- ctx.arc(pos.x, pos.y, body.radius, 0, Math.PI * 2);
30924
- ctx.fillStyle = body.color ?? "#e94560";
30925
- ctx.fill();
30926
- if (p.showVelocity) {
30927
- ctx.beginPath();
30928
- ctx.moveTo(pos.x, pos.y);
30929
- ctx.lineTo(pos.x + body.vx * 0.1, pos.y + body.vy * 0.1);
30930
- ctx.strokeStyle = "#16213e";
30931
- ctx.lineWidth = 2;
30932
- ctx.stroke();
30933
- }
30934
- }
30935
- };
30936
- return interp.startLoop(drawInterpolated);
30937
- }, [externalBodies !== void 0, interp.startLoop]);
30938
- React74.useEffect(() => {
30939
- draw();
30940
- }, [draw]);
30941
- React74.useEffect(() => {
30942
- if (typeof window === "undefined") return;
30943
- const canvas = canvasRef.current;
30944
- if (!canvas) return;
30945
- bindCanvasCapture(() => canvas.toDataURL("image/png"));
30946
- return () => {
30947
- bindCanvasCapture(() => null);
30948
- };
30949
- }, []);
30950
- return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: cn("flex justify-center", className), children: /* @__PURE__ */ jsxRuntime.jsx(
30951
- "canvas",
30952
- {
30953
- ref: canvasRef,
30954
- width,
30955
- height,
30956
- className: "rounded-container block max-w-full h-auto"
30957
- }
30958
- ) });
30959
- }
30960
- var PRESET_BY_ID;
30961
- var init_SimulationCanvas = __esm({
30962
- "components/game/2d/organisms/SimulationCanvas.tsx"() {
30963
- init_cn();
30964
- init_atoms();
30965
- init_verificationRegistry();
30966
- init_physicsPresets();
30967
- init_useRenderInterpolation();
30968
- PRESET_BY_ID = {
30969
- "mechanics-projectile": exports.projectileMotion,
30970
- "mechanics-pendulum": exports.pendulum,
30971
- "mechanics-spring": exports.springOscillator
30972
- };
30973
- SimulationCanvas.displayName = "SimulationCanvas";
30974
- }
30975
- });
30976
- function SimulationControls({
30977
- running,
30978
- speed,
30979
- parameters,
30980
- onPlay,
30981
- onPause,
30982
- onStep,
30983
- onReset,
30984
- onSpeedChange,
30985
- onParameterChange,
30986
- playEvent,
30987
- pauseEvent,
30988
- stepEvent,
30989
- resetEvent,
30990
- speedChangeEvent,
30991
- parameterChangeEvent,
30992
- assetManifest,
30993
- className
30994
- }) {
30995
- const eventBus = useEventBus();
30996
- const ui = assetManifest?.ui;
30997
- const handlePlay = () => {
30998
- if (playEvent) eventBus.emit(`UI:${playEvent}`, {});
30999
- onPlay?.();
31000
- };
31001
- const handlePause = () => {
31002
- if (pauseEvent) eventBus.emit(`UI:${pauseEvent}`, {});
31003
- onPause?.();
31004
- };
31005
- const handleStep = () => {
31006
- if (stepEvent) eventBus.emit(`UI:${stepEvent}`, {});
31007
- onStep?.();
31008
- };
31009
- const handleReset = () => {
31010
- if (resetEvent) eventBus.emit(`UI:${resetEvent}`, {});
31011
- onReset?.();
31012
- };
31013
- const handleSpeedChange = (s) => {
31014
- if (speedChangeEvent) eventBus.emit(`UI:${speedChangeEvent}`, { speed: s });
31015
- onSpeedChange?.(s);
31016
- };
31017
- const handleParameterChange = (name, value) => {
31018
- if (parameterChangeEvent) eventBus.emit(`UI:${parameterChangeEvent}`, { name, value });
31019
- onParameterChange?.(name, value);
31020
- };
31021
- return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "md", className, children: [
31022
- /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", align: "center", children: [
31023
- running ? /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "secondary", onClick: handlePause, children: [
31024
- /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.Pause, assetUrl: ui?.["pause"], size: "sm" }),
31025
- "Pause"
31026
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "primary", onClick: handlePlay, children: [
31027
- /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.Play, assetUrl: ui?.["play"], size: "sm" }),
31028
- "Play"
31029
- ] }),
31030
- /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "ghost", onClick: handleStep, disabled: running, children: [
31031
- /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.SkipForward, assetUrl: ui?.["step"], size: "sm" }),
31032
- "Step"
31033
- ] }),
31034
- /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { size: "sm", variant: "ghost", onClick: handleReset, children: [
31035
- /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { icon: LucideIcons2.RotateCcw, assetUrl: ui?.["reset"], size: "sm" }),
31036
- "Reset"
31037
- ] })
31038
- ] }),
31039
- /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", children: [
31040
- /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "caption", color: "muted", children: [
31041
- "Speed: ",
31042
- speed.toFixed(1),
31043
- "x"
31044
- ] }),
31045
- /* @__PURE__ */ jsxRuntime.jsx(
31046
- "input",
31047
- {
31048
- type: "range",
31049
- min: 0.1,
31050
- max: 5,
31051
- step: 0.1,
31052
- value: speed,
31053
- onChange: (e) => handleSpeedChange(parseFloat(e.target.value)),
31054
- className: "w-full"
31055
- }
31056
- )
31057
- ] }),
31058
- Object.entries(parameters).map(([name, param]) => /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", children: [
31059
- /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "caption", color: "muted", children: [
31060
- param.label,
31061
- ": ",
31062
- param.value.toFixed(2)
31063
- ] }),
31064
- /* @__PURE__ */ jsxRuntime.jsx(
31065
- "input",
31066
- {
31067
- type: "range",
31068
- min: param.min,
31069
- max: param.max,
31070
- step: param.step,
31071
- value: param.value,
31072
- onChange: (e) => handleParameterChange(name, parseFloat(e.target.value)),
31073
- className: "w-full"
31074
- }
31075
- )
31076
- ] }, name))
31077
- ] });
31078
- }
31079
- var init_SimulationControls = __esm({
31080
- "components/game/2d/organisms/SimulationControls.tsx"() {
31081
- init_useEventBus();
31082
- init_atoms();
31083
- init_GameIcon();
31084
- SimulationControls.displayName = "SimulationControls";
31085
- }
31086
- });
31087
- function SimulationGraph({
31088
- label,
31089
- unit,
31090
- data,
31091
- maxPoints = 200,
31092
- width = 300,
31093
- height = 120,
31094
- color = "#e94560",
31095
- className
31096
- }) {
31097
- const canvasRef = React74.useRef(null);
31098
- const visibleData = data.slice(-maxPoints);
31099
- React74.useEffect(() => {
31100
- const canvas = canvasRef.current;
31101
- if (!canvas || visibleData.length < 2) return;
31102
- const ctx = canvas.getContext("2d");
31103
- if (!ctx) return;
31104
- ctx.clearRect(0, 0, width, height);
31105
- ctx.fillStyle = "#0f0f23";
31106
- ctx.fillRect(0, 0, width, height);
31107
- ctx.strokeStyle = "#1a1a3e";
31108
- ctx.lineWidth = 0.5;
31109
- for (let i = 0; i < 5; i++) {
31110
- const y = height / 5 * i;
31111
- ctx.beginPath();
31112
- ctx.moveTo(0, y);
31113
- ctx.lineTo(width, y);
31114
- ctx.stroke();
31115
- }
31116
- let minVal = Infinity;
31117
- let maxVal = -Infinity;
31118
- for (const pt of visibleData) {
31119
- if (pt.value < minVal) minVal = pt.value;
31120
- if (pt.value > maxVal) maxVal = pt.value;
31121
- }
31122
- const range = maxVal - minVal || 1;
31123
- const pad = height * 0.1;
31124
- ctx.beginPath();
31125
- ctx.strokeStyle = color;
31126
- ctx.lineWidth = 2;
31127
- for (let i = 0; i < visibleData.length; i++) {
31128
- const x = i / (maxPoints - 1) * width;
31129
- const y = pad + (maxVal - visibleData[i].value) / range * (height - 2 * pad);
31130
- if (i === 0) ctx.moveTo(x, y);
31131
- else ctx.lineTo(x, y);
31132
- }
31133
- ctx.stroke();
31134
- const last = visibleData[visibleData.length - 1];
31135
- ctx.fillStyle = color;
31136
- ctx.font = "12px monospace";
31137
- ctx.fillText(`${last.value.toFixed(2)} ${unit}`, width - 80, 16);
31138
- }, [visibleData, width, height, color, unit, maxPoints]);
31139
- return /* @__PURE__ */ jsxRuntime.jsx(exports.Card, { padding: "sm", className, children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", children: [
31140
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", weight: "bold", children: label }),
31141
- /* @__PURE__ */ jsxRuntime.jsx("canvas", { ref: canvasRef, width, height, className: "rounded" })
31142
- ] }) });
31143
- }
31144
- var init_SimulationGraph = __esm({
31145
- "components/game/2d/organisms/SimulationGraph.tsx"() {
31146
- init_atoms();
31147
- SimulationGraph.displayName = "SimulationGraph";
31148
- }
31149
- });
31150
30861
  exports.GameTemplate = void 0;
31151
30862
  var init_GameTemplate = __esm({
31152
30863
  "components/game/2d/templates/GameTemplate.tsx"() {
@@ -31410,9 +31121,6 @@ var init_molecules = __esm({
31410
31121
  init_BuilderBoard();
31411
31122
  init_DebuggerBoard();
31412
31123
  init_NegotiatorBoard();
31413
- init_SimulationCanvas();
31414
- init_SimulationControls();
31415
- init_SimulationGraph();
31416
31124
  init_physicsPresets();
31417
31125
  init_GameTemplate();
31418
31126
  init_GameShell();
@@ -32017,13 +31725,13 @@ var init_MapView = __esm({
32017
31725
  shadowSize: [41, 41]
32018
31726
  });
32019
31727
  L.Marker.prototype.options.icon = defaultIcon;
32020
- const { useEffect: useEffect71, useRef: useRef66, useCallback: useCallback114, useState: useState108 } = React74__namespace.default;
31728
+ const { useEffect: useEffect69, useRef: useRef64, useCallback: useCallback113, useState: useState108 } = React74__namespace.default;
32021
31729
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
32022
31730
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
32023
31731
  function MapUpdater({ centerLat, centerLng, zoom }) {
32024
31732
  const map = useMap();
32025
- const prevRef = useRef66({ centerLat, centerLng, zoom });
32026
- useEffect71(() => {
31733
+ const prevRef = useRef64({ centerLat, centerLng, zoom });
31734
+ useEffect69(() => {
32027
31735
  const prev = prevRef.current;
32028
31736
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
32029
31737
  map.setView([centerLat, centerLng], zoom);
@@ -32034,7 +31742,7 @@ var init_MapView = __esm({
32034
31742
  }
32035
31743
  function MapClickHandler({ onMapClick }) {
32036
31744
  const map = useMap();
32037
- useEffect71(() => {
31745
+ useEffect69(() => {
32038
31746
  if (!onMapClick) return;
32039
31747
  const handler = (e) => {
32040
31748
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -32063,7 +31771,7 @@ var init_MapView = __esm({
32063
31771
  }) {
32064
31772
  const eventBus = useEventBus2();
32065
31773
  const [clickedPosition, setClickedPosition] = useState108(null);
32066
- const handleMapClick = useCallback114((lat, lng) => {
31774
+ const handleMapClick = useCallback113((lat, lng) => {
32067
31775
  if (showClickedPin) {
32068
31776
  setClickedPosition({ lat, lng });
32069
31777
  }
@@ -32072,7 +31780,7 @@ var init_MapView = __esm({
32072
31780
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
32073
31781
  }
32074
31782
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
32075
- const handleMarkerClick = useCallback114((marker) => {
31783
+ const handleMarkerClick = useCallback113((marker) => {
32076
31784
  onMarkerClick?.(marker);
32077
31785
  if (markerClickEvent) {
32078
31786
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -48069,7 +47777,6 @@ var init_component_registry_generated = __esm({
48069
47777
  init_Sidebar();
48070
47778
  init_SignaturePad();
48071
47779
  init_SimpleGrid();
48072
- init_SimulationCanvas();
48073
47780
  init_SimulatorBoard();
48074
47781
  init_Skeleton();
48075
47782
  init_SocialProof();
@@ -48381,7 +48088,6 @@ var init_component_registry_generated = __esm({
48381
48088
  "Sidebar": exports.Sidebar,
48382
48089
  "SignaturePad": exports.SignaturePad,
48383
48090
  "SimpleGrid": exports.SimpleGrid,
48384
- "SimulationCanvas": SimulationCanvas,
48385
48091
  "SimulatorBoard": SimulatorBoard,
48386
48092
  "Skeleton": Skeleton,
48387
48093
  "SocialProof": exports.SocialProof,
@@ -51751,9 +51457,6 @@ exports.RuntimeDebugger = RuntimeDebugger;
51751
51457
  exports.ScoreDisplay = ScoreDisplay;
51752
51458
  exports.SequenceBar = SequenceBar;
51753
51459
  exports.SequencerBoard = SequencerBoard;
51754
- exports.SimulationCanvas = SimulationCanvas;
51755
- exports.SimulationControls = SimulationControls;
51756
- exports.SimulationGraph = SimulationGraph;
51757
51460
  exports.SimulatorBoard = SimulatorBoard;
51758
51461
  exports.Skeleton = Skeleton;
51759
51462
  exports.SlotContentRenderer = SlotContentRenderer;