@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.
@@ -6,7 +6,7 @@ import { twMerge } from 'tailwind-merge';
6
6
  import { EventBusContext, useTraitScope, useCurrentPagePath, useEntitySchemaOptional, TraitScopeProvider } from '@almadar/ui/providers';
7
7
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
8
8
  import * as LucideIcons2 from 'lucide-react';
9
- import { X, List, Printer, ChevronRight, ChevronLeft, CheckCircle, XCircle, Wrench, RotateCcw, Send, Play, Terminal, ChevronDown, Bug, ArrowRight, Pause, SkipForward, Search, ChevronUp, MoreHorizontal, Package, Calendar, Pencil, Eye, Image as Image$1, Upload, ZoomIn, TrendingUp, TrendingDown, Minus, AlertCircle, Circle, Clock, CheckCircle2, Loader2, Code, FileText, WrapText, Check, Copy, HelpCircle, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, GitBranch, Plus, Trash, ArrowLeft, Menu as Menu$1, AlertTriangle, Trash2, Eraser, ZoomOut, Download, Lightbulb, PauseCircle, Link2, Tag, User, DollarSign } from 'lucide-react';
9
+ import { X, List, Printer, ChevronRight, ChevronLeft, CheckCircle, XCircle, Wrench, RotateCcw, Send, Play, Terminal, ChevronDown, Bug, ArrowRight, Search, ChevronUp, MoreHorizontal, Package, Calendar, Pencil, Eye, Image as Image$1, Upload, ZoomIn, TrendingUp, TrendingDown, Minus, AlertCircle, Circle, Clock, CheckCircle2, Loader2, Code, FileText, WrapText, Check, Copy, HelpCircle, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, GitBranch, Plus, Trash, ArrowLeft, Menu as Menu$1, AlertTriangle, Trash2, Eraser, ZoomOut, Download, Lightbulb, PauseCircle, Link2, Tag, User, DollarSign } from 'lucide-react';
10
10
  import { useTranslate } from '@almadar/ui/hooks';
11
11
  import { useUISlots, useTheme } from '@almadar/ui/context';
12
12
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
@@ -16302,6 +16302,7 @@ function Canvas2D({
16302
16302
  unitScale = 1,
16303
16303
  showMinimap = true,
16304
16304
  animate,
16305
+ interpolateUnits = false,
16305
16306
  // Tuning
16306
16307
  debug: debug2 = false,
16307
16308
  spriteHeightRatio = 1.5,
@@ -16336,6 +16337,8 @@ function Canvas2D({
16336
16337
  const containerRef = useRef(null);
16337
16338
  const lerpRafRef = useRef(0);
16338
16339
  const animRafRef = useRef(0);
16340
+ const unitInterp = useRenderInterpolation();
16341
+ const interpolatedUnitPositionsRef = useRef(/* @__PURE__ */ new Map());
16339
16342
  const [viewportSize, setViewportSize] = useState({ width: 800, height: 600 });
16340
16343
  useEffect(() => {
16341
16344
  const el = containerRef.current;
@@ -16650,7 +16653,8 @@ function Canvas2D({
16650
16653
  return depthA !== depthB ? depthA - depthB : a.position.y - b.position.y;
16651
16654
  });
16652
16655
  for (const unit of sortedUnits) {
16653
- const pos = project(unit.position.x, unit.position.y, baseOffsetX);
16656
+ const interpolated = interpolateUnits ? interpolatedUnitPositionsRef.current.get(unit.id) : void 0;
16657
+ const pos = project(interpolated?.x ?? unit.position.x, interpolated?.y ?? unit.position.y, baseOffsetX);
16654
16658
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
16655
16659
  continue;
16656
16660
  }
@@ -16802,7 +16806,8 @@ function Canvas2D({
16802
16806
  unitScale,
16803
16807
  assetManifest,
16804
16808
  spriteHeightRatio,
16805
- spriteMaxWidthRatio
16809
+ spriteMaxWidthRatio,
16810
+ interpolateUnits
16806
16811
  ]);
16807
16812
  useEffect(() => {
16808
16813
  if (camera === "fixed") return;
@@ -16817,6 +16822,19 @@ function Canvas2D({
16817
16822
  y: centerY - viewportSize.height / 2
16818
16823
  };
16819
16824
  }, [camera, selectedUnitId, units, project, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
16825
+ useEffect(() => {
16826
+ if (isSide || !interpolateUnits) return;
16827
+ unitInterp.onSnapshot(
16828
+ units.filter((u) => !!u.position).map((u) => ({ id: u.id, x: u.position.x, y: u.position.y }))
16829
+ );
16830
+ }, [isSide, interpolateUnits, units, unitInterp]);
16831
+ useEffect(() => {
16832
+ if (isSide || !interpolateUnits) return;
16833
+ return unitInterp.startLoop((positions) => {
16834
+ interpolatedUnitPositionsRef.current = positions;
16835
+ draw();
16836
+ });
16837
+ }, [isSide, interpolateUnits, unitInterp, draw]);
16820
16838
  useEffect(() => {
16821
16839
  if (isSide) return;
16822
16840
  draw();
@@ -26601,6 +26619,7 @@ function GameCard({
26601
26619
  selected = false,
26602
26620
  disabled = false,
26603
26621
  size = "md",
26622
+ animState = "idle",
26604
26623
  onClick,
26605
26624
  clickEvent,
26606
26625
  className
@@ -26628,6 +26647,7 @@ function GameCard({
26628
26647
  cardSizeMap[size],
26629
26648
  disabled ? "border-border opacity-50 cursor-not-allowed" : "border-accent hover:brightness-125 hover:-translate-y-1 cursor-pointer",
26630
26649
  selected && "ring-2 ring-foreground ring-offset-1 ring-offset-background -translate-y-1",
26650
+ ANIM_STATE_CLASS[animState],
26631
26651
  className
26632
26652
  ),
26633
26653
  children: [
@@ -26660,7 +26680,7 @@ function GameCard({
26660
26680
  }
26661
26681
  );
26662
26682
  }
26663
- var cardSizeMap, artPxMap;
26683
+ var cardSizeMap, artPxMap, ANIM_STATE_CLASS;
26664
26684
  var init_GameCard = __esm({
26665
26685
  "components/game/2d/atoms/GameCard.tsx"() {
26666
26686
  "use client";
@@ -26676,6 +26696,12 @@ var init_GameCard = __esm({
26676
26696
  lg: "w-24 h-36"
26677
26697
  };
26678
26698
  artPxMap = { sm: 40, md: 52, lg: 64 };
26699
+ ANIM_STATE_CLASS = {
26700
+ idle: "",
26701
+ drawn: "scale-105",
26702
+ played: "-translate-y-2 opacity-80",
26703
+ flipped: "scale-x-0"
26704
+ };
26679
26705
  GameCard.displayName = "GameCard";
26680
26706
  }
26681
26707
  });
@@ -27366,8 +27392,11 @@ function DialogueBubble({
27366
27392
  text = "The dungeon awaits. Choose your path wisely.",
27367
27393
  portrait = DEFAULT_PORTRAIT,
27368
27394
  position = "bottom",
27395
+ mood = "neutral",
27396
+ revealedChars,
27369
27397
  className
27370
27398
  }) {
27399
+ const visibleText = revealedChars === void 0 ? text : text.slice(0, revealedChars);
27371
27400
  return /* @__PURE__ */ jsxs(
27372
27401
  Box,
27373
27402
  {
@@ -27377,16 +27406,16 @@ function DialogueBubble({
27377
27406
  className
27378
27407
  ),
27379
27408
  children: [
27380
- portrait && /* @__PURE__ */ jsx(Box, { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsx(GameIcon, { assetUrl: portrait, icon: "image", size: 48, alt: speaker ?? "speaker", className: "w-full h-full object-cover" }) }),
27409
+ portrait && /* @__PURE__ */ jsx(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__ */ jsx(GameIcon, { assetUrl: portrait, icon: "image", size: 48, alt: speaker ?? "speaker", className: "w-full h-full object-cover" }) }),
27381
27410
  /* @__PURE__ */ jsxs(Box, { className: "flex flex-col gap-1 min-w-0", children: [
27382
27411
  speaker && /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-sm font-bold text-warning", children: speaker }),
27383
- /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-sm text-foreground leading-relaxed", children: text })
27412
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-sm text-foreground leading-relaxed", children: visibleText })
27384
27413
  ] })
27385
27414
  ]
27386
27415
  }
27387
27416
  );
27388
27417
  }
27389
- var DEFAULT_PORTRAIT;
27418
+ var DEFAULT_PORTRAIT, MOOD_RING_CLASS;
27390
27419
  var init_DialogueBubble = __esm({
27391
27420
  "components/game/2d/atoms/DialogueBubble.tsx"() {
27392
27421
  init_cn();
@@ -27398,6 +27427,12 @@ var init_DialogueBubble = __esm({
27398
27427
  role: "effect",
27399
27428
  category: "character"
27400
27429
  };
27430
+ MOOD_RING_CLASS = {
27431
+ neutral: "border-warning/60",
27432
+ happy: "border-success/70",
27433
+ concerned: "border-info/70",
27434
+ angry: "border-error/70"
27435
+ };
27401
27436
  DialogueBubble.displayName = "DialogueBubble";
27402
27437
  }
27403
27438
  });
@@ -28989,6 +29024,8 @@ function SequenceBar({
28989
29024
  maxSlots,
28990
29025
  onSlotDrop,
28991
29026
  onSlotRemove,
29027
+ slotDropEvent,
29028
+ slotRemoveEvent,
28992
29029
  playing = false,
28993
29030
  currentStep = -1,
28994
29031
  categoryColors,
@@ -28996,14 +29033,17 @@ function SequenceBar({
28996
29033
  size = "lg",
28997
29034
  className
28998
29035
  }) {
29036
+ const { emit } = useEventBus();
28999
29037
  const handleDrop = useCallback((index) => (item) => {
29000
29038
  if (playing) return;
29001
- onSlotDrop(index, item);
29002
- }, [onSlotDrop, playing]);
29039
+ if (slotDropEvent) emit(`UI:${slotDropEvent}`, { slotNumber: index, itemId: item.id });
29040
+ else onSlotDrop?.(index, item);
29041
+ }, [emit, slotDropEvent, onSlotDrop, playing]);
29003
29042
  const handleRemove = useCallback((index) => () => {
29004
29043
  if (playing) return;
29005
- onSlotRemove(index);
29006
- }, [onSlotRemove, playing]);
29044
+ if (slotRemoveEvent) emit(`UI:${slotRemoveEvent}`, { slotNumber: index });
29045
+ else onSlotRemove?.(index);
29046
+ }, [emit, slotRemoveEvent, onSlotRemove, playing]);
29007
29047
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
29008
29048
  return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
29009
29049
  i > 0 && /* @__PURE__ */ jsx(
@@ -29035,9 +29075,10 @@ function SequenceBar({
29035
29075
  ] }, i)) });
29036
29076
  }
29037
29077
  var init_SequenceBar = __esm({
29038
- "components/game/2d/organisms/SequenceBar.tsx"() {
29078
+ "components/game/2d/molecules/SequenceBar.tsx"() {
29039
29079
  init_atoms();
29040
29080
  init_cn();
29081
+ init_useEventBus();
29041
29082
  init_TraitSlot();
29042
29083
  SequenceBar.displayName = "SequenceBar";
29043
29084
  }
@@ -30771,336 +30812,6 @@ var init_physicsPresets = __esm({
30771
30812
  ];
30772
30813
  }
30773
30814
  });
30774
- function resolvePreset(preset) {
30775
- if (typeof preset !== "string") return preset;
30776
- return PRESET_BY_ID[preset] ?? projectileMotion;
30777
- }
30778
- function SimulationCanvas({
30779
- preset: presetProp,
30780
- width = 600,
30781
- height = 400,
30782
- bodies: externalBodies,
30783
- className
30784
- }) {
30785
- const preset = useMemo(() => resolvePreset(presetProp), [presetProp]);
30786
- const canvasRef = useRef(null);
30787
- const bodiesRef = useRef(structuredClone(preset.bodies));
30788
- const interp = useRenderInterpolation();
30789
- useEffect(() => {
30790
- bodiesRef.current = structuredClone(preset.bodies);
30791
- }, [preset]);
30792
- const draw = useCallback(() => {
30793
- const canvas = canvasRef.current;
30794
- if (!canvas) return;
30795
- const ctx = canvas.getContext("2d");
30796
- if (!ctx) return;
30797
- const bodies = bodiesRef.current;
30798
- ctx.clearRect(0, 0, width, height);
30799
- ctx.fillStyle = preset.backgroundColor ?? "#1a1a2e";
30800
- ctx.fillRect(0, 0, width, height);
30801
- if (preset.constraints) {
30802
- for (const c of preset.constraints) {
30803
- const a = bodies[c.bodyA];
30804
- const b = bodies[c.bodyB];
30805
- if (a && b) {
30806
- ctx.beginPath();
30807
- ctx.moveTo(a.x, a.y);
30808
- ctx.lineTo(b.x, b.y);
30809
- ctx.strokeStyle = "#533483";
30810
- ctx.lineWidth = 1;
30811
- ctx.setLineDash([4, 4]);
30812
- ctx.stroke();
30813
- ctx.setLineDash([]);
30814
- }
30815
- }
30816
- }
30817
- for (const body of bodies) {
30818
- ctx.beginPath();
30819
- ctx.arc(body.x, body.y, body.radius, 0, Math.PI * 2);
30820
- ctx.fillStyle = body.color ?? "#e94560";
30821
- ctx.fill();
30822
- if (preset.showVelocity) {
30823
- ctx.beginPath();
30824
- ctx.moveTo(body.x, body.y);
30825
- ctx.lineTo(body.x + body.vx * 0.1, body.y + body.vy * 0.1);
30826
- ctx.strokeStyle = "#16213e";
30827
- ctx.lineWidth = 2;
30828
- ctx.stroke();
30829
- }
30830
- }
30831
- }, [width, height, preset]);
30832
- useEffect(() => {
30833
- if (!externalBodies) return;
30834
- interp.onSnapshot(externalBodies.map((b) => ({ id: b.id, x: b.x, y: b.y })));
30835
- }, [externalBodies]);
30836
- const presetRef = useRef(preset);
30837
- presetRef.current = preset;
30838
- const widthRef = useRef(width);
30839
- widthRef.current = width;
30840
- const heightRef = useRef(height);
30841
- heightRef.current = height;
30842
- useEffect(() => {
30843
- if (!externalBodies) return;
30844
- const drawInterpolated = (positions) => {
30845
- const canvas = canvasRef.current;
30846
- if (!canvas) return;
30847
- const ctx = canvas.getContext("2d");
30848
- if (!ctx) return;
30849
- const bodies = bodiesRef.current;
30850
- const p = presetRef.current;
30851
- const w = widthRef.current;
30852
- const h = heightRef.current;
30853
- ctx.clearRect(0, 0, w, h);
30854
- ctx.fillStyle = p.backgroundColor ?? "#1a1a2e";
30855
- ctx.fillRect(0, 0, w, h);
30856
- if (p.constraints) {
30857
- for (const c of p.constraints) {
30858
- const a = bodies[c.bodyA];
30859
- const b = bodies[c.bodyB];
30860
- if (a && b) {
30861
- const aPos = positions.get(a.id) ?? a;
30862
- const bPos = positions.get(b.id) ?? b;
30863
- ctx.beginPath();
30864
- ctx.moveTo(aPos.x, aPos.y);
30865
- ctx.lineTo(bPos.x, bPos.y);
30866
- ctx.strokeStyle = "#533483";
30867
- ctx.lineWidth = 1;
30868
- ctx.setLineDash([4, 4]);
30869
- ctx.stroke();
30870
- ctx.setLineDash([]);
30871
- }
30872
- }
30873
- }
30874
- for (const body of bodies) {
30875
- const pos = positions.get(body.id) ?? body;
30876
- ctx.beginPath();
30877
- ctx.arc(pos.x, pos.y, body.radius, 0, Math.PI * 2);
30878
- ctx.fillStyle = body.color ?? "#e94560";
30879
- ctx.fill();
30880
- if (p.showVelocity) {
30881
- ctx.beginPath();
30882
- ctx.moveTo(pos.x, pos.y);
30883
- ctx.lineTo(pos.x + body.vx * 0.1, pos.y + body.vy * 0.1);
30884
- ctx.strokeStyle = "#16213e";
30885
- ctx.lineWidth = 2;
30886
- ctx.stroke();
30887
- }
30888
- }
30889
- };
30890
- return interp.startLoop(drawInterpolated);
30891
- }, [externalBodies !== void 0, interp.startLoop]);
30892
- useEffect(() => {
30893
- draw();
30894
- }, [draw]);
30895
- useEffect(() => {
30896
- if (typeof window === "undefined") return;
30897
- const canvas = canvasRef.current;
30898
- if (!canvas) return;
30899
- bindCanvasCapture(() => canvas.toDataURL("image/png"));
30900
- return () => {
30901
- bindCanvasCapture(() => null);
30902
- };
30903
- }, []);
30904
- return /* @__PURE__ */ jsx(Box, { className: cn("flex justify-center", className), children: /* @__PURE__ */ jsx(
30905
- "canvas",
30906
- {
30907
- ref: canvasRef,
30908
- width,
30909
- height,
30910
- className: "rounded-container block max-w-full h-auto"
30911
- }
30912
- ) });
30913
- }
30914
- var PRESET_BY_ID;
30915
- var init_SimulationCanvas = __esm({
30916
- "components/game/2d/organisms/SimulationCanvas.tsx"() {
30917
- init_cn();
30918
- init_atoms();
30919
- init_verificationRegistry();
30920
- init_physicsPresets();
30921
- init_useRenderInterpolation();
30922
- PRESET_BY_ID = {
30923
- "mechanics-projectile": projectileMotion,
30924
- "mechanics-pendulum": pendulum,
30925
- "mechanics-spring": springOscillator
30926
- };
30927
- SimulationCanvas.displayName = "SimulationCanvas";
30928
- }
30929
- });
30930
- function SimulationControls({
30931
- running,
30932
- speed,
30933
- parameters,
30934
- onPlay,
30935
- onPause,
30936
- onStep,
30937
- onReset,
30938
- onSpeedChange,
30939
- onParameterChange,
30940
- playEvent,
30941
- pauseEvent,
30942
- stepEvent,
30943
- resetEvent,
30944
- speedChangeEvent,
30945
- parameterChangeEvent,
30946
- assetManifest,
30947
- className
30948
- }) {
30949
- const eventBus = useEventBus();
30950
- const ui = assetManifest?.ui;
30951
- const handlePlay = () => {
30952
- if (playEvent) eventBus.emit(`UI:${playEvent}`, {});
30953
- onPlay?.();
30954
- };
30955
- const handlePause = () => {
30956
- if (pauseEvent) eventBus.emit(`UI:${pauseEvent}`, {});
30957
- onPause?.();
30958
- };
30959
- const handleStep = () => {
30960
- if (stepEvent) eventBus.emit(`UI:${stepEvent}`, {});
30961
- onStep?.();
30962
- };
30963
- const handleReset = () => {
30964
- if (resetEvent) eventBus.emit(`UI:${resetEvent}`, {});
30965
- onReset?.();
30966
- };
30967
- const handleSpeedChange = (s) => {
30968
- if (speedChangeEvent) eventBus.emit(`UI:${speedChangeEvent}`, { speed: s });
30969
- onSpeedChange?.(s);
30970
- };
30971
- const handleParameterChange = (name, value) => {
30972
- if (parameterChangeEvent) eventBus.emit(`UI:${parameterChangeEvent}`, { name, value });
30973
- onParameterChange?.(name, value);
30974
- };
30975
- return /* @__PURE__ */ jsxs(VStack, { gap: "md", className, children: [
30976
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "center", children: [
30977
- running ? /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "secondary", onClick: handlePause, children: [
30978
- /* @__PURE__ */ jsx(GameIcon, { icon: Pause, assetUrl: ui?.["pause"], size: "sm" }),
30979
- "Pause"
30980
- ] }) : /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "primary", onClick: handlePlay, children: [
30981
- /* @__PURE__ */ jsx(GameIcon, { icon: Play, assetUrl: ui?.["play"], size: "sm" }),
30982
- "Play"
30983
- ] }),
30984
- /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: handleStep, disabled: running, children: [
30985
- /* @__PURE__ */ jsx(GameIcon, { icon: SkipForward, assetUrl: ui?.["step"], size: "sm" }),
30986
- "Step"
30987
- ] }),
30988
- /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "ghost", onClick: handleReset, children: [
30989
- /* @__PURE__ */ jsx(GameIcon, { icon: RotateCcw, assetUrl: ui?.["reset"], size: "sm" }),
30990
- "Reset"
30991
- ] })
30992
- ] }),
30993
- /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
30994
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "muted", children: [
30995
- "Speed: ",
30996
- speed.toFixed(1),
30997
- "x"
30998
- ] }),
30999
- /* @__PURE__ */ jsx(
31000
- "input",
31001
- {
31002
- type: "range",
31003
- min: 0.1,
31004
- max: 5,
31005
- step: 0.1,
31006
- value: speed,
31007
- onChange: (e) => handleSpeedChange(parseFloat(e.target.value)),
31008
- className: "w-full"
31009
- }
31010
- )
31011
- ] }),
31012
- Object.entries(parameters).map(([name, param]) => /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
31013
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "muted", children: [
31014
- param.label,
31015
- ": ",
31016
- param.value.toFixed(2)
31017
- ] }),
31018
- /* @__PURE__ */ jsx(
31019
- "input",
31020
- {
31021
- type: "range",
31022
- min: param.min,
31023
- max: param.max,
31024
- step: param.step,
31025
- value: param.value,
31026
- onChange: (e) => handleParameterChange(name, parseFloat(e.target.value)),
31027
- className: "w-full"
31028
- }
31029
- )
31030
- ] }, name))
31031
- ] });
31032
- }
31033
- var init_SimulationControls = __esm({
31034
- "components/game/2d/organisms/SimulationControls.tsx"() {
31035
- init_useEventBus();
31036
- init_atoms();
31037
- init_GameIcon();
31038
- SimulationControls.displayName = "SimulationControls";
31039
- }
31040
- });
31041
- function SimulationGraph({
31042
- label,
31043
- unit,
31044
- data,
31045
- maxPoints = 200,
31046
- width = 300,
31047
- height = 120,
31048
- color = "#e94560",
31049
- className
31050
- }) {
31051
- const canvasRef = useRef(null);
31052
- const visibleData = data.slice(-maxPoints);
31053
- useEffect(() => {
31054
- const canvas = canvasRef.current;
31055
- if (!canvas || visibleData.length < 2) return;
31056
- const ctx = canvas.getContext("2d");
31057
- if (!ctx) return;
31058
- ctx.clearRect(0, 0, width, height);
31059
- ctx.fillStyle = "#0f0f23";
31060
- ctx.fillRect(0, 0, width, height);
31061
- ctx.strokeStyle = "#1a1a3e";
31062
- ctx.lineWidth = 0.5;
31063
- for (let i = 0; i < 5; i++) {
31064
- const y = height / 5 * i;
31065
- ctx.beginPath();
31066
- ctx.moveTo(0, y);
31067
- ctx.lineTo(width, y);
31068
- ctx.stroke();
31069
- }
31070
- let minVal = Infinity;
31071
- let maxVal = -Infinity;
31072
- for (const pt of visibleData) {
31073
- if (pt.value < minVal) minVal = pt.value;
31074
- if (pt.value > maxVal) maxVal = pt.value;
31075
- }
31076
- const range = maxVal - minVal || 1;
31077
- const pad = height * 0.1;
31078
- ctx.beginPath();
31079
- ctx.strokeStyle = color;
31080
- ctx.lineWidth = 2;
31081
- for (let i = 0; i < visibleData.length; i++) {
31082
- const x = i / (maxPoints - 1) * width;
31083
- const y = pad + (maxVal - visibleData[i].value) / range * (height - 2 * pad);
31084
- if (i === 0) ctx.moveTo(x, y);
31085
- else ctx.lineTo(x, y);
31086
- }
31087
- ctx.stroke();
31088
- const last = visibleData[visibleData.length - 1];
31089
- ctx.fillStyle = color;
31090
- ctx.font = "12px monospace";
31091
- ctx.fillText(`${last.value.toFixed(2)} ${unit}`, width - 80, 16);
31092
- }, [visibleData, width, height, color, unit, maxPoints]);
31093
- return /* @__PURE__ */ jsx(Card, { padding: "sm", className, children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
31094
- /* @__PURE__ */ jsx(Typography, { variant: "caption", weight: "bold", children: label }),
31095
- /* @__PURE__ */ jsx("canvas", { ref: canvasRef, width, height, className: "rounded" })
31096
- ] }) });
31097
- }
31098
- var init_SimulationGraph = __esm({
31099
- "components/game/2d/organisms/SimulationGraph.tsx"() {
31100
- init_atoms();
31101
- SimulationGraph.displayName = "SimulationGraph";
31102
- }
31103
- });
31104
30815
  var GameTemplate;
31105
30816
  var init_GameTemplate = __esm({
31106
30817
  "components/game/2d/templates/GameTemplate.tsx"() {
@@ -31364,9 +31075,6 @@ var init_molecules = __esm({
31364
31075
  init_BuilderBoard();
31365
31076
  init_DebuggerBoard();
31366
31077
  init_NegotiatorBoard();
31367
- init_SimulationCanvas();
31368
- init_SimulationControls();
31369
- init_SimulationGraph();
31370
31078
  init_physicsPresets();
31371
31079
  init_GameTemplate();
31372
31080
  init_GameShell();
@@ -31971,13 +31679,13 @@ var init_MapView = __esm({
31971
31679
  shadowSize: [41, 41]
31972
31680
  });
31973
31681
  L.Marker.prototype.options.icon = defaultIcon;
31974
- const { useEffect: useEffect71, useRef: useRef66, useCallback: useCallback114, useState: useState108 } = React74__default;
31682
+ const { useEffect: useEffect69, useRef: useRef64, useCallback: useCallback113, useState: useState108 } = React74__default;
31975
31683
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
31976
31684
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
31977
31685
  function MapUpdater({ centerLat, centerLng, zoom }) {
31978
31686
  const map = useMap();
31979
- const prevRef = useRef66({ centerLat, centerLng, zoom });
31980
- useEffect71(() => {
31687
+ const prevRef = useRef64({ centerLat, centerLng, zoom });
31688
+ useEffect69(() => {
31981
31689
  const prev = prevRef.current;
31982
31690
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
31983
31691
  map.setView([centerLat, centerLng], zoom);
@@ -31988,7 +31696,7 @@ var init_MapView = __esm({
31988
31696
  }
31989
31697
  function MapClickHandler({ onMapClick }) {
31990
31698
  const map = useMap();
31991
- useEffect71(() => {
31699
+ useEffect69(() => {
31992
31700
  if (!onMapClick) return;
31993
31701
  const handler = (e) => {
31994
31702
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -32017,7 +31725,7 @@ var init_MapView = __esm({
32017
31725
  }) {
32018
31726
  const eventBus = useEventBus2();
32019
31727
  const [clickedPosition, setClickedPosition] = useState108(null);
32020
- const handleMapClick = useCallback114((lat, lng) => {
31728
+ const handleMapClick = useCallback113((lat, lng) => {
32021
31729
  if (showClickedPin) {
32022
31730
  setClickedPosition({ lat, lng });
32023
31731
  }
@@ -32026,7 +31734,7 @@ var init_MapView = __esm({
32026
31734
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
32027
31735
  }
32028
31736
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
32029
- const handleMarkerClick = useCallback114((marker) => {
31737
+ const handleMarkerClick = useCallback113((marker) => {
32030
31738
  onMarkerClick?.(marker);
32031
31739
  if (markerClickEvent) {
32032
31740
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -48023,7 +47731,6 @@ var init_component_registry_generated = __esm({
48023
47731
  init_Sidebar();
48024
47732
  init_SignaturePad();
48025
47733
  init_SimpleGrid();
48026
- init_SimulationCanvas();
48027
47734
  init_SimulatorBoard();
48028
47735
  init_Skeleton();
48029
47736
  init_SocialProof();
@@ -48335,7 +48042,6 @@ var init_component_registry_generated = __esm({
48335
48042
  "Sidebar": Sidebar,
48336
48043
  "SignaturePad": SignaturePad,
48337
48044
  "SimpleGrid": SimpleGrid,
48338
- "SimulationCanvas": SimulationCanvas,
48339
48045
  "SimulatorBoard": SimulatorBoard,
48340
48046
  "Skeleton": Skeleton,
48341
48047
  "SocialProof": SocialProof,
@@ -51648,4 +51354,4 @@ function useGitHubBranches(owner, repo, enabled = true) {
51648
51354
  });
51649
51355
  }
51650
51356
 
51651
- export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AuthLayout, Avatar, Badge, BehaviorView, BiologyCanvas, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, Canvas2D, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, Center, Chart, ChartLegend, ChatBar, Checkbox, ChemistryCanvas, ChoiceButton, ClassifierBoard, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, ControlGrid, CounterTemplate, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DEFAULT_SLOTS, DIAMOND_TOP_Y, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, Dialog, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, ELEMENT_SELECTED_EVENT, EMPTY_EFFECT_STATE, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameCard, GameHud, GameIcon, GameMenu, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, IconPicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, ItemSlot, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, LearningCanvas, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MathCanvas, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NodeSlotEditor, NotifyListener, NumberStepper, ObjectRulePanel, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsCanvas, Popover, PositionedCanvas, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateGraph, StateIndicator, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SubagentTracePanel, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, boardEntity, bool, calculateAttackTargets, calculateValidMoves, cn, createInitialGameState, createTranslate, createUnitAnimationState, drawSprite, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, makeAsset, makeAssetMap, mapBookData, num, objAvailableActions, objAvailableEvents, objCurrentState, objIcon, objId, objMaxRules, objName, objRules, objStates, parseEditFocus, parseLessonSegments, parseMarkdownWithCodeBlocks, parseQueryBinding, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, rows, screenToIso, springOscillator, str, tickAnimationState, toCodeLanguage, transitionAnimation, unitHealth, unitPosition, unitTeam, useAgentChat, useAnchorRect, useAuthContext, useCamera, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGameAudio, useGameAudioContext, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useImageCache, useInfiniteScroll, useLongPress, useOrbitalHistory, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSwipeGesture, useTapReveal, useTraitListens, useTranslate127 as useTranslate, useUIEvents, useUISlotManager, useUnitSpriteAtlas, useValidation, vec2 };
51357
+ export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AuthLayout, Avatar, Badge, BehaviorView, BiologyCanvas, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, Canvas2D, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, Center, Chart, ChartLegend, ChatBar, Checkbox, ChemistryCanvas, ChoiceButton, ClassifierBoard, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, ControlGrid, CounterTemplate, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DEFAULT_SLOTS, DIAMOND_TOP_Y, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, Dialog, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, ELEMENT_SELECTED_EVENT, EMPTY_EFFECT_STATE, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameCard, GameHud, GameIcon, GameMenu, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, IconPicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, ItemSlot, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, LearningCanvas, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MathCanvas, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NodeSlotEditor, NotifyListener, NumberStepper, ObjectRulePanel, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsCanvas, Popover, PositionedCanvas, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateGraph, StateIndicator, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SubagentTracePanel, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, boardEntity, bool, calculateAttackTargets, calculateValidMoves, cn, createInitialGameState, createTranslate, createUnitAnimationState, drawSprite, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, makeAsset, makeAssetMap, mapBookData, num, objAvailableActions, objAvailableEvents, objCurrentState, objIcon, objId, objMaxRules, objName, objRules, objStates, parseEditFocus, parseLessonSegments, parseMarkdownWithCodeBlocks, parseQueryBinding, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, rows, screenToIso, springOscillator, str, tickAnimationState, toCodeLanguage, transitionAnimation, unitHealth, unitPosition, unitTeam, useAgentChat, useAnchorRect, useAuthContext, useCamera, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGameAudio, useGameAudioContext, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useImageCache, useInfiniteScroll, useLongPress, useOrbitalHistory, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSwipeGesture, useTapReveal, useTraitListens, useTranslate127 as useTranslate, useUIEvents, useUISlotManager, useUnitSpriteAtlas, useValidation, vec2 };