@almadar/ui 5.94.1 → 5.96.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.
@@ -1,6 +1,6 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import * as React74 from 'react';
3
- import React74__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, useState, Suspense, lazy, useLayoutEffect, useId, useSyncExternalStore } from 'react';
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import * as React75 from 'react';
3
+ import React75__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, useState, Suspense, lazy, useLayoutEffect, useId, useSyncExternalStore } from 'react';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { EventBusContext, useTraitScope, useCurrentPagePath, useEntitySchemaOptional, TraitScopeProvider } from '@almadar/ui/providers';
@@ -227,7 +227,7 @@ var init_SvgFlow = __esm({
227
227
  width = 100,
228
228
  height = 100
229
229
  }) => {
230
- const markerId = React74__default.useMemo(() => {
230
+ const markerId = React75__default.useMemo(() => {
231
231
  flowIdCounter += 1;
232
232
  return `almadar-flow-arrow-${flowIdCounter}`;
233
233
  }, []);
@@ -820,7 +820,7 @@ var init_SvgRing = __esm({
820
820
  width = 100,
821
821
  height = 100
822
822
  }) => {
823
- const gradientId = React74__default.useMemo(() => {
823
+ const gradientId = React75__default.useMemo(() => {
824
824
  ringIdCounter += 1;
825
825
  return `almadar-ring-glow-${ringIdCounter}`;
826
826
  }, []);
@@ -1232,7 +1232,7 @@ function loadLib(key, importer) {
1232
1232
  return p;
1233
1233
  }
1234
1234
  function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
1235
- const Lazy = React74__default.lazy(async () => {
1235
+ const Lazy = React75__default.lazy(async () => {
1236
1236
  const lib = await loadLib(libKey, importer);
1237
1237
  const Comp = pick(lib);
1238
1238
  if (!Comp) {
@@ -1242,7 +1242,7 @@ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
1242
1242
  return { default: Comp };
1243
1243
  });
1244
1244
  const Wrapped = (props) => /* @__PURE__ */ jsx(
1245
- React74__default.Suspense,
1245
+ React75__default.Suspense,
1246
1246
  {
1247
1247
  fallback: /* @__PURE__ */ jsx(
1248
1248
  "span",
@@ -1973,7 +1973,7 @@ var init_Icon = __esm({
1973
1973
  const directIcon = typeof icon === "string" ? void 0 : icon;
1974
1974
  const effectiveName = typeof icon === "string" ? icon : name;
1975
1975
  const family = useIconFamily();
1976
- const RenderedComponent = React74__default.useMemo(() => {
1976
+ const RenderedComponent = React75__default.useMemo(() => {
1977
1977
  if (directIcon) return null;
1978
1978
  return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
1979
1979
  }, [directIcon, effectiveName, family]);
@@ -2023,6 +2023,210 @@ var init_Icon = __esm({
2023
2023
  Icon.displayName = "Icon";
2024
2024
  }
2025
2025
  });
2026
+
2027
+ // lib/atlasSlice.ts
2028
+ function isTilesheet(a) {
2029
+ return typeof a.tileWidth === "number";
2030
+ }
2031
+ function getAtlas(url, onReady) {
2032
+ if (atlasCache.has(url)) return atlasCache.get(url) ?? void 0;
2033
+ atlasCache.set(url, void 0);
2034
+ fetch(url).then((r) => r.json()).then((json) => {
2035
+ atlasCache.set(url, json);
2036
+ onReady();
2037
+ }).catch(() => {
2038
+ atlasCache.set(url, null);
2039
+ });
2040
+ return void 0;
2041
+ }
2042
+ function subRectFor(atlas, sprite) {
2043
+ if (isTilesheet(atlas)) {
2044
+ let col;
2045
+ let row;
2046
+ if (sprite.includes(",")) {
2047
+ const [c, r] = sprite.split(",").map((n) => Number(n.trim()));
2048
+ col = c;
2049
+ row = r;
2050
+ } else {
2051
+ const i = Number(sprite);
2052
+ if (!Number.isFinite(i)) return null;
2053
+ col = i % atlas.columns;
2054
+ row = Math.floor(i / atlas.columns);
2055
+ }
2056
+ if (!Number.isFinite(col) || !Number.isFinite(row) || col < 0 || row < 0 || col >= atlas.columns || row >= atlas.rows) return null;
2057
+ const margin = atlas.margin ?? 0;
2058
+ const spacing = atlas.spacing ?? 0;
2059
+ return {
2060
+ sx: margin + col * (atlas.tileWidth + spacing),
2061
+ sy: margin + row * (atlas.tileHeight + spacing),
2062
+ sw: atlas.tileWidth,
2063
+ sh: atlas.tileHeight
2064
+ };
2065
+ }
2066
+ const st = atlas.subTextures[sprite];
2067
+ if (!st) return null;
2068
+ return { sx: st.x, sy: st.y, sw: st.width, sh: st.height };
2069
+ }
2070
+ function isAtlasAsset(asset) {
2071
+ return !!asset && typeof asset.atlas === "string" && typeof asset.sprite === "string";
2072
+ }
2073
+ function resolveAssetSource(img, asset, onReady) {
2074
+ if (isAtlasAsset(asset)) {
2075
+ const atlas = getAtlas(asset.atlas, onReady);
2076
+ if (!atlas) return null;
2077
+ const rect = subRectFor(atlas, asset.sprite);
2078
+ if (!rect) return null;
2079
+ return { img, rect, aspect: rect.sw / rect.sh };
2080
+ }
2081
+ const natW = img.naturalWidth || 1;
2082
+ const natH = img.naturalHeight || 1;
2083
+ return { img, rect: null, aspect: natW / natH };
2084
+ }
2085
+ function blit(ctx, src, dx, dy, dw, dh) {
2086
+ if (src.rect) ctx.drawImage(src.img, src.rect.sx, src.rect.sy, src.rect.sw, src.rect.sh, dx, dy, dw, dh);
2087
+ else ctx.drawImage(src.img, dx, dy, dw, dh);
2088
+ }
2089
+ var atlasCache;
2090
+ var init_atlasSlice = __esm({
2091
+ "lib/atlasSlice.ts"() {
2092
+ "use client";
2093
+ atlasCache = /* @__PURE__ */ new Map();
2094
+ }
2095
+ });
2096
+ function useAtlasSliceDataUrl(asset) {
2097
+ const [, bump] = React75.useReducer((x) => x + 1, 0);
2098
+ if (!isAtlasAsset(asset)) return void 0;
2099
+ const key = `${asset.atlas}#${asset.sprite}`;
2100
+ const cached = sliceDataUrlCache.get(key);
2101
+ if (cached) return cached;
2102
+ const atlas = getAtlas(asset.atlas, bump);
2103
+ const img = asset?.url ? getSheetImage(asset.url, bump) : null;
2104
+ if (!atlas || !img) return void 0;
2105
+ const rect = subRectFor(atlas, asset.sprite);
2106
+ if (!rect) return void 0;
2107
+ const canvas = document.createElement("canvas");
2108
+ canvas.width = rect.sw;
2109
+ canvas.height = rect.sh;
2110
+ const ctx = canvas.getContext("2d");
2111
+ if (!ctx) return void 0;
2112
+ ctx.imageSmoothingEnabled = false;
2113
+ ctx.drawImage(img, rect.sx, rect.sy, rect.sw, rect.sh, 0, 0, rect.sw, rect.sh);
2114
+ const url = canvas.toDataURL();
2115
+ sliceDataUrlCache.set(key, url);
2116
+ return url;
2117
+ }
2118
+ function AtlasPanel({ asset, borderSlice = 16, borderWidth = 16, mode = "nineSlice", className, style, children, "aria-hidden": ariaHidden }) {
2119
+ const dataUrl = useAtlasSliceDataUrl(asset);
2120
+ const skin = !dataUrl ? {} : mode === "repeat" ? { backgroundImage: `url(${dataUrl})`, backgroundRepeat: "repeat" } : {
2121
+ borderStyle: "solid",
2122
+ borderWidth,
2123
+ borderImageSource: `url(${dataUrl})`,
2124
+ borderImageSlice: `${borderSlice} fill`,
2125
+ borderImageWidth: borderWidth,
2126
+ borderImageRepeat: "stretch",
2127
+ imageRendering: "pixelated"
2128
+ };
2129
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": ariaHidden, className: cn("inline-block", className), style: { ...skin, ...style }, children });
2130
+ }
2131
+ function getSheetImage(url, onReady) {
2132
+ const cached = imageCache.get(url);
2133
+ if (cached) return cached;
2134
+ (imageWaiters.get(url) ?? imageWaiters.set(url, /* @__PURE__ */ new Set()).get(url)).add(onReady);
2135
+ if (!imageCache.has(url)) {
2136
+ imageCache.set(url, null);
2137
+ const img = new Image();
2138
+ img.crossOrigin = "anonymous";
2139
+ img.onload = () => {
2140
+ imageCache.set(url, img);
2141
+ imageWaiters.get(url)?.forEach((fn) => fn());
2142
+ imageWaiters.delete(url);
2143
+ };
2144
+ img.src = url;
2145
+ }
2146
+ return null;
2147
+ }
2148
+ function AtlasImage({
2149
+ asset,
2150
+ size,
2151
+ width,
2152
+ height,
2153
+ fill = false,
2154
+ fit = "contain",
2155
+ alt,
2156
+ className,
2157
+ style,
2158
+ "aria-hidden": ariaHidden
2159
+ }) {
2160
+ const [, bump] = React75.useReducer((x) => x + 1, 0);
2161
+ const canvasRef = React75.useRef(null);
2162
+ const sliced = isAtlasAsset(asset);
2163
+ const atlas = sliced ? getAtlas(asset.atlas, bump) : void 0;
2164
+ const img = sliced && asset?.url ? getSheetImage(asset.url, bump) : null;
2165
+ const rect = sliced && atlas ? subRectFor(atlas, asset.sprite) : null;
2166
+ React75.useEffect(() => {
2167
+ const canvas = canvasRef.current;
2168
+ if (!canvas || !img || !rect) return;
2169
+ canvas.width = rect.sw;
2170
+ canvas.height = rect.sh;
2171
+ const ctx = canvas.getContext("2d");
2172
+ if (!ctx) return;
2173
+ ctx.imageSmoothingEnabled = false;
2174
+ ctx.clearRect(0, 0, rect.sw, rect.sh);
2175
+ ctx.drawImage(img, rect.sx, rect.sy, rect.sw, rect.sh, 0, 0, rect.sw, rect.sh);
2176
+ }, [img, rect?.sx, rect?.sy, rect?.sw, rect?.sh]);
2177
+ const w = fill ? "100%" : width ?? size;
2178
+ const h = fill ? "100%" : height ?? size;
2179
+ const boxStyle = {
2180
+ ...fill ? { position: "absolute", inset: 0 } : {},
2181
+ width: w,
2182
+ height: h,
2183
+ objectFit: fit,
2184
+ imageRendering: "pixelated",
2185
+ ...style
2186
+ };
2187
+ if (!asset?.url) return null;
2188
+ if (sliced) {
2189
+ if (!rect || !img) {
2190
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("inline-block flex-shrink-0", className), style: { ...boxStyle, objectFit: void 0 } });
2191
+ }
2192
+ return /* @__PURE__ */ jsx(
2193
+ "canvas",
2194
+ {
2195
+ ref: canvasRef,
2196
+ role: ariaHidden ? void 0 : "img",
2197
+ "aria-hidden": ariaHidden,
2198
+ "aria-label": ariaHidden ? void 0 : alt ?? asset.name ?? asset.category ?? "",
2199
+ className: cn("flex-shrink-0", className),
2200
+ style: boxStyle
2201
+ }
2202
+ );
2203
+ }
2204
+ return /* @__PURE__ */ jsx(
2205
+ "img",
2206
+ {
2207
+ src: asset.url,
2208
+ alt: alt ?? asset.name ?? asset.category ?? "",
2209
+ "aria-hidden": ariaHidden,
2210
+ ...typeof w === "number" ? { width: w } : {},
2211
+ ...typeof h === "number" ? { height: h } : {},
2212
+ className: cn("flex-shrink-0", className),
2213
+ style: boxStyle
2214
+ }
2215
+ );
2216
+ }
2217
+ var sliceDataUrlCache, imageCache, imageWaiters;
2218
+ var init_AtlasImage = __esm({
2219
+ "components/core/atoms/AtlasImage.tsx"() {
2220
+ "use client";
2221
+ init_atlasSlice();
2222
+ init_cn();
2223
+ sliceDataUrlCache = /* @__PURE__ */ new Map();
2224
+ AtlasPanel.displayName = "AtlasPanel";
2225
+ imageCache = /* @__PURE__ */ new Map();
2226
+ imageWaiters = /* @__PURE__ */ new Map();
2227
+ AtlasImage.displayName = "AtlasImage";
2228
+ }
2229
+ });
2026
2230
  function isIconLike(v) {
2027
2231
  return typeof v.render === "function";
2028
2232
  }
@@ -2035,7 +2239,7 @@ function resolveIconProp(value, sizeClass) {
2035
2239
  const IconComp = value;
2036
2240
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
2037
2241
  }
2038
- if (React74__default.isValidElement(value)) {
2242
+ if (React75__default.isValidElement(value)) {
2039
2243
  return value;
2040
2244
  }
2041
2245
  if (typeof value === "object" && value !== null && isIconLike(value)) {
@@ -2051,6 +2255,7 @@ var init_Button = __esm({
2051
2255
  init_cn();
2052
2256
  init_useEventBus();
2053
2257
  init_Icon();
2258
+ init_AtlasImage();
2054
2259
  variantStyles = {
2055
2260
  primary: [
2056
2261
  "bg-primary text-primary-foreground",
@@ -2111,7 +2316,7 @@ var init_Button = __esm({
2111
2316
  md: "h-icon-default w-icon-default",
2112
2317
  lg: "h-icon-default w-icon-default"
2113
2318
  };
2114
- Button = React74__default.forwardRef(
2319
+ Button = React75__default.forwardRef(
2115
2320
  ({
2116
2321
  className,
2117
2322
  variant = "primary",
@@ -2135,7 +2340,7 @@ var init_Button = __esm({
2135
2340
  const leftIconValue = leftIcon || iconProp;
2136
2341
  const rightIconValue = rightIcon || iconRightProp;
2137
2342
  const px = size === "sm" ? 16 : size === "lg" ? 20 : 16;
2138
- const resolvedLeftIcon = iconAsset?.url ? /* @__PURE__ */ jsx("img", { src: iconAsset.url, alt: iconAsset.name ?? iconAsset.category ?? "", width: px, height: px, style: { imageRendering: "pixelated", objectFit: "contain", width: px, height: px }, className: "flex-shrink-0" }) : resolveIconProp(leftIconValue, iconSizeStyles[size]);
2343
+ const resolvedLeftIcon = iconAsset?.url ? /* @__PURE__ */ jsx(AtlasImage, { asset: iconAsset, size: px, alt: iconAsset.name ?? iconAsset.category ?? "", className: "flex-shrink-0" }) : resolveIconProp(leftIconValue, iconSizeStyles[size]);
2139
2344
  const resolvedRightIcon = resolveIconProp(rightIconValue, iconSizeStyles[size]);
2140
2345
  const handleClick = (e) => {
2141
2346
  if (action) {
@@ -2181,7 +2386,7 @@ var init_Input = __esm({
2181
2386
  init_cn();
2182
2387
  init_Icon();
2183
2388
  init_useEventBus();
2184
- Input = React74__default.forwardRef(
2389
+ Input = React75__default.forwardRef(
2185
2390
  ({
2186
2391
  className,
2187
2392
  inputType,
@@ -2341,7 +2546,7 @@ var Label;
2341
2546
  var init_Label = __esm({
2342
2547
  "components/core/atoms/Label.tsx"() {
2343
2548
  init_cn();
2344
- Label = React74__default.forwardRef(
2549
+ Label = React75__default.forwardRef(
2345
2550
  ({ className, required, children, ...props }, ref) => {
2346
2551
  return /* @__PURE__ */ jsxs(
2347
2552
  "label",
@@ -2368,7 +2573,7 @@ var init_Textarea = __esm({
2368
2573
  "components/core/atoms/Textarea.tsx"() {
2369
2574
  init_cn();
2370
2575
  init_useEventBus();
2371
- Textarea = React74__default.forwardRef(
2576
+ Textarea = React75__default.forwardRef(
2372
2577
  ({ className, error, onChange, ...props }, ref) => {
2373
2578
  const eventBus = useEventBus();
2374
2579
  const handleChange = (e) => {
@@ -2607,7 +2812,7 @@ var init_Select = __esm({
2607
2812
  init_cn();
2608
2813
  init_Icon();
2609
2814
  init_useEventBus();
2610
- Select = React74__default.forwardRef(
2815
+ Select = React75__default.forwardRef(
2611
2816
  (props, _ref) => {
2612
2817
  const { multiple, searchable, clearable } = props;
2613
2818
  if (multiple || searchable || clearable) {
@@ -2624,7 +2829,7 @@ var init_Checkbox = __esm({
2624
2829
  "components/core/atoms/Checkbox.tsx"() {
2625
2830
  init_cn();
2626
2831
  init_useEventBus();
2627
- Checkbox = React74__default.forwardRef(
2832
+ Checkbox = React75__default.forwardRef(
2628
2833
  ({ className, label, id, onChange, ...props }, ref) => {
2629
2834
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
2630
2835
  const eventBus = useEventBus();
@@ -2678,7 +2883,7 @@ var init_Spinner = __esm({
2678
2883
  md: "h-6 w-6",
2679
2884
  lg: "h-8 w-8"
2680
2885
  };
2681
- Spinner = React74__default.forwardRef(
2886
+ Spinner = React75__default.forwardRef(
2682
2887
  ({ className, size = "md", overlay, ...props }, ref) => {
2683
2888
  if (overlay) {
2684
2889
  return /* @__PURE__ */ jsx(
@@ -2768,7 +2973,7 @@ var init_Card = __esm({
2768
2973
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
2769
2974
  "tile-image-first": "p-0 overflow-hidden"
2770
2975
  };
2771
- Card = React74__default.forwardRef(
2976
+ Card = React75__default.forwardRef(
2772
2977
  ({
2773
2978
  className,
2774
2979
  variant = "bordered",
@@ -2816,9 +3021,9 @@ var init_Card = __esm({
2816
3021
  }
2817
3022
  );
2818
3023
  Card.displayName = "Card";
2819
- CardHeader = React74__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
3024
+ CardHeader = React75__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
2820
3025
  CardHeader.displayName = "CardHeader";
2821
- CardTitle = React74__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3026
+ CardTitle = React75__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2822
3027
  "h3",
2823
3028
  {
2824
3029
  ref,
@@ -2831,11 +3036,11 @@ var init_Card = __esm({
2831
3036
  }
2832
3037
  ));
2833
3038
  CardTitle.displayName = "CardTitle";
2834
- CardContent = React74__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
3039
+ CardContent = React75__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
2835
3040
  CardContent.displayName = "CardContent";
2836
3041
  CardBody = CardContent;
2837
3042
  CardBody.displayName = "CardBody";
2838
- CardFooter = React74__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3043
+ CardFooter = React75__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2839
3044
  "div",
2840
3045
  {
2841
3046
  ref,
@@ -2851,6 +3056,7 @@ var init_Badge = __esm({
2851
3056
  "components/core/atoms/Badge.tsx"() {
2852
3057
  init_cn();
2853
3058
  init_Icon();
3059
+ init_AtlasImage();
2854
3060
  variantStyles3 = {
2855
3061
  default: [
2856
3062
  "bg-muted text-foreground",
@@ -2888,7 +3094,7 @@ var init_Badge = __esm({
2888
3094
  md: "px-2.5 py-1 text-sm",
2889
3095
  lg: "px-3 py-1.5 text-base"
2890
3096
  };
2891
- Badge = React74__default.forwardRef(
3097
+ Badge = React75__default.forwardRef(
2892
3098
  ({ className, variant = "default", size = "sm", amount, label, icon, iconAsset, children, onRemove, removeLabel, ...props }, ref) => {
2893
3099
  const iconSizes3 = {
2894
3100
  sm: "h-icon-default w-icon-default",
@@ -2896,7 +3102,7 @@ var init_Badge = __esm({
2896
3102
  lg: "h-icon-default w-icon-default"
2897
3103
  };
2898
3104
  const iconPx = size === "lg" ? 20 : 16;
2899
- const resolvedIcon = iconAsset?.url ? /* @__PURE__ */ jsx("img", { src: iconAsset.url, alt: iconAsset.name ?? iconAsset.category ?? "", width: iconPx, height: iconPx, style: { imageRendering: "pixelated", objectFit: "contain", width: iconPx, height: iconPx }, className: "flex-shrink-0" }) : typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, className: iconSizes3[size] }) : icon ? /* @__PURE__ */ jsx(Icon, { icon, className: iconSizes3[size] }) : null;
3105
+ const resolvedIcon = iconAsset?.url ? /* @__PURE__ */ jsx(AtlasImage, { asset: iconAsset, size: iconPx, alt: iconAsset.name ?? iconAsset.category ?? "", className: "flex-shrink-0" }) : typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, className: iconSizes3[size] }) : icon ? /* @__PURE__ */ jsx(Icon, { icon, className: iconSizes3[size] }) : null;
2900
3106
  return /* @__PURE__ */ jsxs(
2901
3107
  "span",
2902
3108
  {
@@ -2982,7 +3188,7 @@ var init_FilterPill = __esm({
2982
3188
  md: "w-3.5 h-3.5",
2983
3189
  lg: "w-4 h-4"
2984
3190
  };
2985
- FilterPill = React74__default.forwardRef(
3191
+ FilterPill = React75__default.forwardRef(
2986
3192
  ({
2987
3193
  className,
2988
3194
  variant = "default",
@@ -3111,8 +3317,8 @@ var init_Avatar = __esm({
3111
3317
  actionPayload
3112
3318
  }) => {
3113
3319
  const eventBus = useEventBus();
3114
- const [imgFailed, setImgFailed] = React74__default.useState(false);
3115
- React74__default.useEffect(() => {
3320
+ const [imgFailed, setImgFailed] = React75__default.useState(false);
3321
+ React75__default.useEffect(() => {
3116
3322
  setImgFailed(false);
3117
3323
  }, [src]);
3118
3324
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -3364,7 +3570,7 @@ var init_Box = __esm({
3364
3570
  fixed: "fixed",
3365
3571
  sticky: "sticky"
3366
3572
  };
3367
- Box = React74__default.forwardRef(
3573
+ Box = React75__default.forwardRef(
3368
3574
  ({
3369
3575
  padding,
3370
3576
  paddingX,
@@ -3429,7 +3635,7 @@ var init_Box = __esm({
3429
3635
  onPointerDown?.(e);
3430
3636
  }, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
3431
3637
  const isClickable = action || onClick;
3432
- return React74__default.createElement(
3638
+ return React75__default.createElement(
3433
3639
  Component,
3434
3640
  {
3435
3641
  ref,
@@ -3483,7 +3689,7 @@ var init_Center = __esm({
3483
3689
  as: Component = "div"
3484
3690
  }) => {
3485
3691
  const mergedStyle = minHeight ? { minHeight, ...style } : style;
3486
- return React74__default.createElement(Component, {
3692
+ return React75__default.createElement(Component, {
3487
3693
  className: cn(
3488
3694
  inline ? "inline-flex" : "flex",
3489
3695
  horizontal && "justify-center",
@@ -3751,7 +3957,7 @@ var init_Radio = __esm({
3751
3957
  md: "w-2.5 h-2.5",
3752
3958
  lg: "w-3 h-3"
3753
3959
  };
3754
- Radio = React74__default.forwardRef(
3960
+ Radio = React75__default.forwardRef(
3755
3961
  ({
3756
3962
  label,
3757
3963
  helperText,
@@ -3768,12 +3974,12 @@ var init_Radio = __esm({
3768
3974
  onChange,
3769
3975
  ...props
3770
3976
  }, ref) => {
3771
- const reactId = React74__default.useId();
3977
+ const reactId = React75__default.useId();
3772
3978
  const baseId = id || `radio-${reactId}`;
3773
3979
  const hasError = !!error;
3774
3980
  const eventBus = useEventBus();
3775
- const [selected, setSelected] = React74__default.useState(value);
3776
- React74__default.useEffect(() => {
3981
+ const [selected, setSelected] = React75__default.useState(value);
3982
+ React75__default.useEffect(() => {
3777
3983
  if (value !== void 0) setSelected(value);
3778
3984
  }, [value]);
3779
3985
  const pick = (next, e) => {
@@ -3955,7 +4161,7 @@ var init_Switch = __esm({
3955
4161
  "components/core/atoms/Switch.tsx"() {
3956
4162
  "use client";
3957
4163
  init_cn();
3958
- Switch = React74.forwardRef(
4164
+ Switch = React75.forwardRef(
3959
4165
  ({
3960
4166
  checked,
3961
4167
  defaultChecked = false,
@@ -3966,10 +4172,10 @@ var init_Switch = __esm({
3966
4172
  name,
3967
4173
  className
3968
4174
  }, ref) => {
3969
- const [isChecked, setIsChecked] = React74.useState(
4175
+ const [isChecked, setIsChecked] = React75.useState(
3970
4176
  checked !== void 0 ? checked : defaultChecked
3971
4177
  );
3972
- React74.useEffect(() => {
4178
+ React75.useEffect(() => {
3973
4179
  if (checked !== void 0) {
3974
4180
  setIsChecked(checked);
3975
4181
  }
@@ -4132,7 +4338,7 @@ var init_Stack = __esm({
4132
4338
  };
4133
4339
  const isHorizontal = direction === "horizontal";
4134
4340
  const directionClass = responsive && isHorizontal ? reverse ? "flex-col-reverse md:flex-row-reverse" : "flex-col md:flex-row" : isHorizontal ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
4135
- return React74__default.createElement(
4341
+ return React75__default.createElement(
4136
4342
  Component,
4137
4343
  {
4138
4344
  className: cn(
@@ -4328,7 +4534,7 @@ var init_Typography = __esm({
4328
4534
  }) => {
4329
4535
  const variant = variantProp ?? (level ? `h${level}` : "body1");
4330
4536
  const Component = as || defaultElements[variant];
4331
- return React74__default.createElement(
4537
+ return React75__default.createElement(
4332
4538
  Component,
4333
4539
  {
4334
4540
  id,
@@ -4487,7 +4693,7 @@ var Dialog;
4487
4693
  var init_Dialog = __esm({
4488
4694
  "components/core/atoms/Dialog.tsx"() {
4489
4695
  init_cn();
4490
- Dialog = React74__default.forwardRef(
4696
+ Dialog = React75__default.forwardRef(
4491
4697
  ({
4492
4698
  role = "dialog",
4493
4699
  "aria-modal": ariaModal = true,
@@ -4513,7 +4719,7 @@ var Aside;
4513
4719
  var init_Aside = __esm({
4514
4720
  "components/core/atoms/Aside.tsx"() {
4515
4721
  init_cn();
4516
- Aside = React74__default.forwardRef(
4722
+ Aside = React75__default.forwardRef(
4517
4723
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
4518
4724
  );
4519
4725
  Aside.displayName = "Aside";
@@ -4592,9 +4798,9 @@ var init_LawReferenceTooltip = __esm({
4592
4798
  className
4593
4799
  }) => {
4594
4800
  const { t } = useTranslate();
4595
- const [isVisible, setIsVisible] = React74__default.useState(false);
4596
- const timeoutRef = React74__default.useRef(null);
4597
- const triggerRef = React74__default.useRef(null);
4801
+ const [isVisible, setIsVisible] = React75__default.useState(false);
4802
+ const timeoutRef = React75__default.useRef(null);
4803
+ const triggerRef = React75__default.useRef(null);
4598
4804
  const handleMouseEnter = () => {
4599
4805
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
4600
4806
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -4605,7 +4811,7 @@ var init_LawReferenceTooltip = __esm({
4605
4811
  };
4606
4812
  const { revealed, triggerProps } = useTapReveal({ refs: [triggerRef] });
4607
4813
  const open = isVisible || revealed;
4608
- React74__default.useEffect(() => {
4814
+ React75__default.useEffect(() => {
4609
4815
  return () => {
4610
4816
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
4611
4817
  };
@@ -4815,7 +5021,7 @@ var init_StatusDot = __esm({
4815
5021
  md: "w-2.5 h-2.5",
4816
5022
  lg: "w-3 h-3"
4817
5023
  };
4818
- StatusDot = React74__default.forwardRef(
5024
+ StatusDot = React75__default.forwardRef(
4819
5025
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
4820
5026
  return /* @__PURE__ */ jsx(
4821
5027
  "span",
@@ -4869,7 +5075,7 @@ var init_TrendIndicator = __esm({
4869
5075
  down: "trending-down",
4870
5076
  flat: "arrow-right"
4871
5077
  };
4872
- TrendIndicator = React74__default.forwardRef(
5078
+ TrendIndicator = React75__default.forwardRef(
4873
5079
  ({
4874
5080
  className,
4875
5081
  value,
@@ -4936,7 +5142,7 @@ var init_RangeSlider = __esm({
4936
5142
  md: "w-4 h-4",
4937
5143
  lg: "w-5 h-5"
4938
5144
  };
4939
- RangeSlider = React74__default.forwardRef(
5145
+ RangeSlider = React75__default.forwardRef(
4940
5146
  ({
4941
5147
  className,
4942
5148
  min = 0,
@@ -5530,7 +5736,7 @@ var init_ContentSection = __esm({
5530
5736
  md: "py-16",
5531
5737
  lg: "py-24"
5532
5738
  };
5533
- ContentSection = React74__default.forwardRef(
5739
+ ContentSection = React75__default.forwardRef(
5534
5740
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
5535
5741
  return /* @__PURE__ */ jsx(
5536
5742
  Box,
@@ -6064,7 +6270,7 @@ var init_AnimatedReveal = __esm({
6064
6270
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
6065
6271
  "none": {}
6066
6272
  };
6067
- AnimatedReveal = React74__default.forwardRef(
6273
+ AnimatedReveal = React75__default.forwardRef(
6068
6274
  ({
6069
6275
  trigger = "scroll",
6070
6276
  animation = "fade-up",
@@ -6224,7 +6430,7 @@ var init_AnimatedGraphic = __esm({
6224
6430
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
6225
6431
  "use client";
6226
6432
  init_cn();
6227
- AnimatedGraphic = React74__default.forwardRef(
6433
+ AnimatedGraphic = React75__default.forwardRef(
6228
6434
  ({
6229
6435
  src,
6230
6436
  svgContent,
@@ -6247,7 +6453,7 @@ var init_AnimatedGraphic = __esm({
6247
6453
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
6248
6454
  const resolvedSvg = svgContent ?? fetchedSvg;
6249
6455
  const prevAnimateRef = useRef(animate);
6250
- const setRef = React74__default.useCallback(
6456
+ const setRef = React75__default.useCallback(
6251
6457
  (node) => {
6252
6458
  containerRef.current = node;
6253
6459
  if (typeof ref === "function") ref(node);
@@ -6920,7 +7126,7 @@ var init_ErrorBoundary = __esm({
6920
7126
  }
6921
7127
  );
6922
7128
  };
6923
- ErrorBoundary = class extends React74__default.Component {
7129
+ ErrorBoundary = class extends React75__default.Component {
6924
7130
  constructor(props) {
6925
7131
  super(props);
6926
7132
  __publicField(this, "reset", () => {
@@ -7216,7 +7422,7 @@ var init_Container = __esm({
7216
7422
  as: Component = "div"
7217
7423
  }) => {
7218
7424
  const resolvedSize = maxWidth ?? size ?? "lg";
7219
- return React74__default.createElement(
7425
+ return React75__default.createElement(
7220
7426
  Component,
7221
7427
  {
7222
7428
  className: cn(
@@ -7933,13 +8139,11 @@ function GameIcon({ assetUrl, icon, size = "md", alt, className }) {
7933
8139
  const px = typeof size === "number" ? size : sizeMap[size];
7934
8140
  if (assetUrl?.url) {
7935
8141
  return /* @__PURE__ */ jsx(
7936
- "img",
8142
+ AtlasImage,
7937
8143
  {
7938
- src: assetUrl.url,
8144
+ asset: assetUrl,
8145
+ size: px,
7939
8146
  alt: alt ?? assetUrl.category ?? "",
7940
- width: px,
7941
- height: px,
7942
- style: { imageRendering: "pixelated", objectFit: "contain", width: px, height: px },
7943
8147
  className: cn("flex-shrink-0", className)
7944
8148
  }
7945
8149
  );
@@ -7953,6 +8157,7 @@ var init_GameIcon = __esm({
7953
8157
  "use client";
7954
8158
  init_cn();
7955
8159
  init_Icon();
8160
+ init_AtlasImage();
7956
8161
  sizeMap = {
7957
8162
  sm: 16,
7958
8163
  md: 24,
@@ -8549,6 +8754,462 @@ var init_ComponentPatterns = __esm({
8549
8754
  AlertPattern.displayName = "AlertPattern";
8550
8755
  }
8551
8756
  });
8757
+ function resolveColor2(color, ctx, fallback) {
8758
+ if (!color) return fallback;
8759
+ if (color.startsWith("var(")) {
8760
+ ctx.canvas.style;
8761
+ const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color);
8762
+ if (m) {
8763
+ const computed = getComputedStyle(ctx.canvas).getPropertyValue(m[1]).trim();
8764
+ return computed || m[2]?.trim() || fallback;
8765
+ }
8766
+ }
8767
+ return color;
8768
+ }
8769
+ function shapeBounds(shape) {
8770
+ switch (shape.type) {
8771
+ case "line":
8772
+ case "arrow":
8773
+ if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) return null;
8774
+ return {
8775
+ x: Math.min(shape.x1, shape.x2) - 6,
8776
+ y: Math.min(shape.y1, shape.y2) - 6,
8777
+ w: Math.abs(shape.x2 - shape.x1) + 12,
8778
+ h: Math.abs(shape.y2 - shape.y1) + 12
8779
+ };
8780
+ case "circle":
8781
+ if (shape.x == null || shape.y == null || shape.radius == null) return null;
8782
+ return {
8783
+ x: shape.x - shape.radius - 4,
8784
+ y: shape.y - shape.radius - 4,
8785
+ w: shape.radius * 2 + 8,
8786
+ h: shape.radius * 2 + 8
8787
+ };
8788
+ case "rect":
8789
+ if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) return null;
8790
+ return { x: shape.x - 4, y: shape.y - 4, w: shape.width + 8, h: shape.height + 8 };
8791
+ case "polygon":
8792
+ if (!shape.points || shape.points.length === 0) return null;
8793
+ {
8794
+ const xs = shape.points.map((p) => p.x);
8795
+ const ys = shape.points.map((p) => p.y);
8796
+ const minX = Math.min(...xs);
8797
+ const minY = Math.min(...ys);
8798
+ return {
8799
+ x: minX - 4,
8800
+ y: minY - 4,
8801
+ w: Math.max(...xs) - minX + 8,
8802
+ h: Math.max(...ys) - minY + 8
8803
+ };
8804
+ }
8805
+ case "text":
8806
+ if (shape.x == null || shape.y == null) return null;
8807
+ return { x: shape.x - 4, y: shape.y - (shape.fontSize ?? 14) - 4, w: 120, h: (shape.fontSize ?? 14) + 8 };
8808
+ default:
8809
+ return null;
8810
+ }
8811
+ }
8812
+ function drawArrowHead(ctx, x1, y1, x2, y2, size) {
8813
+ const angle = Math.atan2(y2 - y1, x2 - x1);
8814
+ ctx.beginPath();
8815
+ ctx.moveTo(x2, y2);
8816
+ ctx.lineTo(x2 - size * Math.cos(angle - Math.PI / 6), y2 - size * Math.sin(angle - Math.PI / 6));
8817
+ ctx.lineTo(x2 - size * Math.cos(angle + Math.PI / 6), y2 - size * Math.sin(angle + Math.PI / 6));
8818
+ ctx.closePath();
8819
+ ctx.fill();
8820
+ }
8821
+ function drawShape(ctx, shape, width, height) {
8822
+ ctx.save();
8823
+ const opacity = shape.opacity ?? 1;
8824
+ ctx.globalAlpha = opacity;
8825
+ const stroke = resolveColor2(shape.color, ctx, "#333333");
8826
+ const fill = shape.fill ? resolveColor2(shape.fill, ctx, "#cccccc") : void 0;
8827
+ ctx.lineWidth = shape.lineWidth ?? 2;
8828
+ switch (shape.type) {
8829
+ case "grid": {
8830
+ const step = shape.step ?? 40;
8831
+ ctx.strokeStyle = stroke;
8832
+ ctx.globalAlpha = opacity * 0.25;
8833
+ ctx.lineWidth = 1;
8834
+ ctx.beginPath();
8835
+ for (let x = 0; x <= width; x += step) {
8836
+ ctx.moveTo(x, 0);
8837
+ ctx.lineTo(x, height);
8838
+ }
8839
+ for (let y = 0; y <= height; y += step) {
8840
+ ctx.moveTo(0, y);
8841
+ ctx.lineTo(width, y);
8842
+ }
8843
+ ctx.stroke();
8844
+ break;
8845
+ }
8846
+ case "axis": {
8847
+ const axis = shape.axis ?? "x";
8848
+ ctx.strokeStyle = stroke;
8849
+ ctx.lineWidth = shape.lineWidth ?? 2;
8850
+ ctx.beginPath();
8851
+ if (axis === "x") {
8852
+ ctx.moveTo(0, height / 2);
8853
+ ctx.lineTo(width, height / 2);
8854
+ } else {
8855
+ ctx.moveTo(width / 2, 0);
8856
+ ctx.lineTo(width / 2, height);
8857
+ }
8858
+ ctx.stroke();
8859
+ break;
8860
+ }
8861
+ case "line": {
8862
+ if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
8863
+ ctx.strokeStyle = stroke;
8864
+ ctx.beginPath();
8865
+ ctx.moveTo(shape.x1, shape.y1);
8866
+ ctx.lineTo(shape.x2, shape.y2);
8867
+ ctx.stroke();
8868
+ break;
8869
+ }
8870
+ case "arrow": {
8871
+ if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
8872
+ ctx.strokeStyle = stroke;
8873
+ ctx.fillStyle = stroke;
8874
+ ctx.beginPath();
8875
+ ctx.moveTo(shape.x1, shape.y1);
8876
+ ctx.lineTo(shape.x2, shape.y2);
8877
+ ctx.stroke();
8878
+ drawArrowHead(ctx, shape.x1, shape.y1, shape.x2, shape.y2, 10);
8879
+ break;
8880
+ }
8881
+ case "circle": {
8882
+ if (shape.x == null || shape.y == null || shape.radius == null) break;
8883
+ ctx.beginPath();
8884
+ ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2);
8885
+ if (fill) {
8886
+ ctx.fillStyle = fill;
8887
+ ctx.fill();
8888
+ }
8889
+ ctx.strokeStyle = stroke;
8890
+ ctx.stroke();
8891
+ break;
8892
+ }
8893
+ case "rect": {
8894
+ if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) break;
8895
+ if (fill) {
8896
+ ctx.fillStyle = fill;
8897
+ ctx.fillRect(shape.x, shape.y, shape.width, shape.height);
8898
+ }
8899
+ ctx.strokeStyle = stroke;
8900
+ ctx.strokeRect(shape.x, shape.y, shape.width, shape.height);
8901
+ break;
8902
+ }
8903
+ case "polygon": {
8904
+ if (!shape.points || shape.points.length < 2) break;
8905
+ ctx.beginPath();
8906
+ ctx.moveTo(shape.points[0].x, shape.points[0].y);
8907
+ for (let i = 1; i < shape.points.length; i++) {
8908
+ ctx.lineTo(shape.points[i].x, shape.points[i].y);
8909
+ }
8910
+ ctx.closePath();
8911
+ if (fill) {
8912
+ ctx.fillStyle = fill;
8913
+ ctx.fill();
8914
+ }
8915
+ ctx.strokeStyle = stroke;
8916
+ ctx.stroke();
8917
+ break;
8918
+ }
8919
+ case "path": {
8920
+ if (!shape.path) break;
8921
+ const p = new Path2D(shape.path);
8922
+ if (fill) {
8923
+ ctx.fillStyle = fill;
8924
+ ctx.fill(p);
8925
+ }
8926
+ ctx.strokeStyle = stroke;
8927
+ ctx.stroke(p);
8928
+ break;
8929
+ }
8930
+ case "text": {
8931
+ if (shape.x == null || shape.y == null || !shape.text) break;
8932
+ ctx.fillStyle = stroke;
8933
+ ctx.font = `${shape.fontSize ?? 14}px system-ui, sans-serif`;
8934
+ ctx.textAlign = shape.align ?? "left";
8935
+ ctx.textBaseline = "middle";
8936
+ ctx.fillText(shape.text, shape.x, shape.y);
8937
+ break;
8938
+ }
8939
+ }
8940
+ ctx.restore();
8941
+ }
8942
+ var LearningCanvas;
8943
+ var init_LearningCanvas = __esm({
8944
+ "components/learning/atoms/LearningCanvas.tsx"() {
8945
+ "use client";
8946
+ init_cn();
8947
+ init_useEventBus();
8948
+ LearningCanvas = ({
8949
+ className,
8950
+ width = 600,
8951
+ height = 400,
8952
+ backgroundColor,
8953
+ shapes = [],
8954
+ interactive = false,
8955
+ animate = false,
8956
+ onShapeClick,
8957
+ onShapeHover,
8958
+ isLoading,
8959
+ error
8960
+ }) => {
8961
+ const canvasRef = useRef(null);
8962
+ const eventBus = useEventBus();
8963
+ const animRef = useRef(0);
8964
+ const hoverIndexRef = useRef(-1);
8965
+ const findShapeAt = useCallback((clientX, clientY) => {
8966
+ const canvas = canvasRef.current;
8967
+ if (!canvas) return -1;
8968
+ const rect = canvas.getBoundingClientRect();
8969
+ const x = clientX - rect.left;
8970
+ const y = clientY - rect.top;
8971
+ for (let i = shapes.length - 1; i >= 0; i--) {
8972
+ const b = shapeBounds(shapes[i]);
8973
+ if (b && x >= b.x && x <= b.x + b.w && y >= b.y && y <= b.y + b.h) {
8974
+ return i;
8975
+ }
8976
+ }
8977
+ return -1;
8978
+ }, [shapes]);
8979
+ const draw = useCallback(() => {
8980
+ const canvas = canvasRef.current;
8981
+ if (!canvas) return;
8982
+ const ctx = canvas.getContext("2d");
8983
+ if (!ctx) return;
8984
+ const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
8985
+ canvas.width = Math.max(1, Math.floor(width * dpr));
8986
+ canvas.height = Math.max(1, Math.floor(height * dpr));
8987
+ canvas.style.width = `${width}px`;
8988
+ canvas.style.height = `${height}px`;
8989
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
8990
+ ctx.clearRect(0, 0, width, height);
8991
+ if (backgroundColor) {
8992
+ ctx.fillStyle = backgroundColor;
8993
+ ctx.fillRect(0, 0, width, height);
8994
+ }
8995
+ for (const shape of shapes) {
8996
+ drawShape(ctx, shape, width, height);
8997
+ }
8998
+ }, [width, height, backgroundColor, shapes]);
8999
+ useEffect(() => {
9000
+ draw();
9001
+ }, [draw]);
9002
+ useEffect(() => {
9003
+ if (!animate) return;
9004
+ const loop = () => {
9005
+ draw();
9006
+ animRef.current = requestAnimationFrame(loop);
9007
+ };
9008
+ animRef.current = requestAnimationFrame(loop);
9009
+ return () => cancelAnimationFrame(animRef.current);
9010
+ }, [animate, draw]);
9011
+ const handlePointerMove = useCallback(
9012
+ (e) => {
9013
+ if (!interactive) return;
9014
+ const idx = findShapeAt(e.clientX, e.clientY);
9015
+ if (idx !== hoverIndexRef.current) {
9016
+ hoverIndexRef.current = idx;
9017
+ if (idx >= 0) {
9018
+ const shape = shapes[idx];
9019
+ const payload = { id: shape.id, type: shape.type, index: idx };
9020
+ if (onShapeHover) onShapeHover(payload);
9021
+ else if (eventBus) eventBus.emit(`UI:SHAPE_HOVER`, payload);
9022
+ }
9023
+ }
9024
+ },
9025
+ [interactive, onShapeHover, eventBus, findShapeAt, shapes]
9026
+ );
9027
+ const handleClick = useCallback(
9028
+ (e) => {
9029
+ if (!interactive) return;
9030
+ const idx = findShapeAt(e.clientX, e.clientY);
9031
+ if (idx >= 0) {
9032
+ const shape = shapes[idx];
9033
+ const payload = { id: shape.id, type: shape.type, index: idx };
9034
+ if (onShapeClick) onShapeClick(payload);
9035
+ else if (eventBus) eventBus.emit(`UI:SHAPE_CLICK`, payload);
9036
+ }
9037
+ },
9038
+ [interactive, onShapeClick, eventBus, findShapeAt, shapes]
9039
+ );
9040
+ if (isLoading || error) {
9041
+ return /* @__PURE__ */ jsx(
9042
+ "div",
9043
+ {
9044
+ className: cn(
9045
+ "flex items-center justify-center rounded border border-border bg-surface",
9046
+ className
9047
+ ),
9048
+ style: { width, height },
9049
+ children: error ? /* @__PURE__ */ jsx("span", { className: "text-sm text-destructive", children: error.message }) : /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Loading canvas\u2026" })
9050
+ }
9051
+ );
9052
+ }
9053
+ return /* @__PURE__ */ jsx(
9054
+ "canvas",
9055
+ {
9056
+ ref: canvasRef,
9057
+ className: cn("block touch-none rounded border border-border", className),
9058
+ style: { width, height },
9059
+ onClick: handleClick,
9060
+ onPointerMove: handlePointerMove
9061
+ }
9062
+ );
9063
+ };
9064
+ }
9065
+ });
9066
+ var DEFAULT_BAR_COLOR, DEFAULT_CELL_COLOR, DEFAULT_POINTER_COLOR, POINTER_BAND, TOP_PAD, AlgorithmCanvas;
9067
+ var init_AlgorithmCanvas = __esm({
9068
+ "components/learning/molecules/AlgorithmCanvas.tsx"() {
9069
+ "use client";
9070
+ init_atoms();
9071
+ init_Stack();
9072
+ init_LearningCanvas();
9073
+ DEFAULT_BAR_COLOR = "#3b82f6";
9074
+ DEFAULT_CELL_COLOR = "#e5e7eb";
9075
+ DEFAULT_POINTER_COLOR = "#dc2626";
9076
+ POINTER_BAND = 34;
9077
+ TOP_PAD = 12;
9078
+ AlgorithmCanvas = ({
9079
+ className,
9080
+ width = 600,
9081
+ height = 400,
9082
+ title,
9083
+ backgroundColor,
9084
+ bars = [],
9085
+ cells = [],
9086
+ pointers = [],
9087
+ shapes = [],
9088
+ interactive = false,
9089
+ animate = false,
9090
+ onShapeClick,
9091
+ isLoading,
9092
+ error
9093
+ }) => {
9094
+ const derivedShapes = useMemo(() => {
9095
+ const out = [];
9096
+ if (bars.length > 0) {
9097
+ const slot = width / bars.length;
9098
+ const barW = slot * 0.8;
9099
+ const gap = slot * 0.1;
9100
+ const baseline = height - POINTER_BAND;
9101
+ const usableH = baseline - TOP_PAD;
9102
+ const maxV = Math.max(1, ...bars.map((b) => Number.isFinite(b.value) ? b.value : 0));
9103
+ bars.forEach((bar, i) => {
9104
+ const v = Number.isFinite(bar.value) ? bar.value : 0;
9105
+ const bh = Math.max(0, v / maxV * usableH);
9106
+ const x = i * slot + gap;
9107
+ const color = bar.color ?? DEFAULT_BAR_COLOR;
9108
+ out.push({
9109
+ type: "rect",
9110
+ id: `bar-${i}`,
9111
+ x,
9112
+ y: baseline - bh,
9113
+ width: barW,
9114
+ height: bh,
9115
+ color,
9116
+ fill: color
9117
+ });
9118
+ const label = bar.label ?? (bars.length <= 24 ? String(v) : void 0);
9119
+ if (label) {
9120
+ out.push({
9121
+ type: "text",
9122
+ x: x + barW / 2,
9123
+ y: baseline - bh - 8,
9124
+ text: label,
9125
+ color: "#374151",
9126
+ fontSize: 11,
9127
+ align: "center"
9128
+ });
9129
+ }
9130
+ });
9131
+ pointers.forEach((p) => {
9132
+ if (p.index < 0 || p.index >= bars.length) return;
9133
+ const cx = p.index * slot + slot / 2;
9134
+ const color = p.color ?? DEFAULT_POINTER_COLOR;
9135
+ out.push({
9136
+ type: "arrow",
9137
+ x1: cx,
9138
+ y1: height - 6,
9139
+ x2: cx,
9140
+ y2: baseline + 4,
9141
+ color,
9142
+ lineWidth: 2
9143
+ });
9144
+ if (p.label) {
9145
+ out.push({
9146
+ type: "text",
9147
+ x: cx,
9148
+ y: height - 22,
9149
+ text: p.label,
9150
+ color,
9151
+ fontSize: 11,
9152
+ align: "center"
9153
+ });
9154
+ }
9155
+ });
9156
+ }
9157
+ if (cells.length > 0) {
9158
+ const maxCol = Math.max(0, ...cells.map((c) => c.col)) + 1;
9159
+ const maxRow = Math.max(0, ...cells.map((c) => c.row)) + 1;
9160
+ const cw = width / maxCol;
9161
+ const ch = height / maxRow;
9162
+ cells.forEach((c, i) => {
9163
+ const x = c.col * cw;
9164
+ const y = c.row * ch;
9165
+ const color = c.color ?? DEFAULT_CELL_COLOR;
9166
+ out.push({
9167
+ type: "rect",
9168
+ id: `cell-${i}`,
9169
+ x: x + 1,
9170
+ y: y + 1,
9171
+ width: cw - 2,
9172
+ height: ch - 2,
9173
+ color: "#9ca3af",
9174
+ fill: color
9175
+ });
9176
+ const label = c.label ?? (c.value != null ? String(c.value) : void 0);
9177
+ if (label && cw >= 18 && ch >= 14) {
9178
+ out.push({
9179
+ type: "text",
9180
+ x: x + cw / 2,
9181
+ y: y + ch / 2,
9182
+ text: label,
9183
+ color: "#111827",
9184
+ fontSize: 12,
9185
+ align: "center"
9186
+ });
9187
+ }
9188
+ });
9189
+ }
9190
+ out.push(...shapes);
9191
+ return out;
9192
+ }, [bars, cells, pointers, shapes, width, height]);
9193
+ return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
9194
+ title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
9195
+ /* @__PURE__ */ jsx(
9196
+ LearningCanvas,
9197
+ {
9198
+ width,
9199
+ height,
9200
+ backgroundColor,
9201
+ shapes: derivedShapes,
9202
+ interactive,
9203
+ animate,
9204
+ onShapeClick,
9205
+ isLoading,
9206
+ error
9207
+ }
9208
+ )
9209
+ ] }) });
9210
+ };
9211
+ }
9212
+ });
8552
9213
  var AuthLayout;
8553
9214
  var init_AuthLayout = __esm({
8554
9215
  "components/marketing/templates/AuthLayout.tsx"() {
@@ -9517,315 +10178,6 @@ var init_BehaviorView = __esm({
9517
10178
  BehaviorView.displayName = "BehaviorView";
9518
10179
  }
9519
10180
  });
9520
- function resolveColor2(color, ctx, fallback) {
9521
- if (!color) return fallback;
9522
- if (color.startsWith("var(")) {
9523
- ctx.canvas.style;
9524
- const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color);
9525
- if (m) {
9526
- const computed = getComputedStyle(ctx.canvas).getPropertyValue(m[1]).trim();
9527
- return computed || m[2]?.trim() || fallback;
9528
- }
9529
- }
9530
- return color;
9531
- }
9532
- function shapeBounds(shape) {
9533
- switch (shape.type) {
9534
- case "line":
9535
- case "arrow":
9536
- if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) return null;
9537
- return {
9538
- x: Math.min(shape.x1, shape.x2) - 6,
9539
- y: Math.min(shape.y1, shape.y2) - 6,
9540
- w: Math.abs(shape.x2 - shape.x1) + 12,
9541
- h: Math.abs(shape.y2 - shape.y1) + 12
9542
- };
9543
- case "circle":
9544
- if (shape.x == null || shape.y == null || shape.radius == null) return null;
9545
- return {
9546
- x: shape.x - shape.radius - 4,
9547
- y: shape.y - shape.radius - 4,
9548
- w: shape.radius * 2 + 8,
9549
- h: shape.radius * 2 + 8
9550
- };
9551
- case "rect":
9552
- if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) return null;
9553
- return { x: shape.x - 4, y: shape.y - 4, w: shape.width + 8, h: shape.height + 8 };
9554
- case "polygon":
9555
- if (!shape.points || shape.points.length === 0) return null;
9556
- {
9557
- const xs = shape.points.map((p) => p.x);
9558
- const ys = shape.points.map((p) => p.y);
9559
- const minX = Math.min(...xs);
9560
- const minY = Math.min(...ys);
9561
- return {
9562
- x: minX - 4,
9563
- y: minY - 4,
9564
- w: Math.max(...xs) - minX + 8,
9565
- h: Math.max(...ys) - minY + 8
9566
- };
9567
- }
9568
- case "text":
9569
- if (shape.x == null || shape.y == null) return null;
9570
- return { x: shape.x - 4, y: shape.y - (shape.fontSize ?? 14) - 4, w: 120, h: (shape.fontSize ?? 14) + 8 };
9571
- default:
9572
- return null;
9573
- }
9574
- }
9575
- function drawArrowHead(ctx, x1, y1, x2, y2, size) {
9576
- const angle = Math.atan2(y2 - y1, x2 - x1);
9577
- ctx.beginPath();
9578
- ctx.moveTo(x2, y2);
9579
- ctx.lineTo(x2 - size * Math.cos(angle - Math.PI / 6), y2 - size * Math.sin(angle - Math.PI / 6));
9580
- ctx.lineTo(x2 - size * Math.cos(angle + Math.PI / 6), y2 - size * Math.sin(angle + Math.PI / 6));
9581
- ctx.closePath();
9582
- ctx.fill();
9583
- }
9584
- function drawShape(ctx, shape, width, height) {
9585
- ctx.save();
9586
- const opacity = shape.opacity ?? 1;
9587
- ctx.globalAlpha = opacity;
9588
- const stroke = resolveColor2(shape.color, ctx, "#333333");
9589
- const fill = shape.fill ? resolveColor2(shape.fill, ctx, "#cccccc") : void 0;
9590
- ctx.lineWidth = shape.lineWidth ?? 2;
9591
- switch (shape.type) {
9592
- case "grid": {
9593
- const step = shape.step ?? 40;
9594
- ctx.strokeStyle = stroke;
9595
- ctx.globalAlpha = opacity * 0.25;
9596
- ctx.lineWidth = 1;
9597
- ctx.beginPath();
9598
- for (let x = 0; x <= width; x += step) {
9599
- ctx.moveTo(x, 0);
9600
- ctx.lineTo(x, height);
9601
- }
9602
- for (let y = 0; y <= height; y += step) {
9603
- ctx.moveTo(0, y);
9604
- ctx.lineTo(width, y);
9605
- }
9606
- ctx.stroke();
9607
- break;
9608
- }
9609
- case "axis": {
9610
- const axis = shape.axis ?? "x";
9611
- ctx.strokeStyle = stroke;
9612
- ctx.lineWidth = shape.lineWidth ?? 2;
9613
- ctx.beginPath();
9614
- if (axis === "x") {
9615
- ctx.moveTo(0, height / 2);
9616
- ctx.lineTo(width, height / 2);
9617
- } else {
9618
- ctx.moveTo(width / 2, 0);
9619
- ctx.lineTo(width / 2, height);
9620
- }
9621
- ctx.stroke();
9622
- break;
9623
- }
9624
- case "line": {
9625
- if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
9626
- ctx.strokeStyle = stroke;
9627
- ctx.beginPath();
9628
- ctx.moveTo(shape.x1, shape.y1);
9629
- ctx.lineTo(shape.x2, shape.y2);
9630
- ctx.stroke();
9631
- break;
9632
- }
9633
- case "arrow": {
9634
- if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
9635
- ctx.strokeStyle = stroke;
9636
- ctx.fillStyle = stroke;
9637
- ctx.beginPath();
9638
- ctx.moveTo(shape.x1, shape.y1);
9639
- ctx.lineTo(shape.x2, shape.y2);
9640
- ctx.stroke();
9641
- drawArrowHead(ctx, shape.x1, shape.y1, shape.x2, shape.y2, 10);
9642
- break;
9643
- }
9644
- case "circle": {
9645
- if (shape.x == null || shape.y == null || shape.radius == null) break;
9646
- ctx.beginPath();
9647
- ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2);
9648
- if (fill) {
9649
- ctx.fillStyle = fill;
9650
- ctx.fill();
9651
- }
9652
- ctx.strokeStyle = stroke;
9653
- ctx.stroke();
9654
- break;
9655
- }
9656
- case "rect": {
9657
- if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) break;
9658
- if (fill) {
9659
- ctx.fillStyle = fill;
9660
- ctx.fillRect(shape.x, shape.y, shape.width, shape.height);
9661
- }
9662
- ctx.strokeStyle = stroke;
9663
- ctx.strokeRect(shape.x, shape.y, shape.width, shape.height);
9664
- break;
9665
- }
9666
- case "polygon": {
9667
- if (!shape.points || shape.points.length < 2) break;
9668
- ctx.beginPath();
9669
- ctx.moveTo(shape.points[0].x, shape.points[0].y);
9670
- for (let i = 1; i < shape.points.length; i++) {
9671
- ctx.lineTo(shape.points[i].x, shape.points[i].y);
9672
- }
9673
- ctx.closePath();
9674
- if (fill) {
9675
- ctx.fillStyle = fill;
9676
- ctx.fill();
9677
- }
9678
- ctx.strokeStyle = stroke;
9679
- ctx.stroke();
9680
- break;
9681
- }
9682
- case "path": {
9683
- if (!shape.path) break;
9684
- const p = new Path2D(shape.path);
9685
- if (fill) {
9686
- ctx.fillStyle = fill;
9687
- ctx.fill(p);
9688
- }
9689
- ctx.strokeStyle = stroke;
9690
- ctx.stroke(p);
9691
- break;
9692
- }
9693
- case "text": {
9694
- if (shape.x == null || shape.y == null || !shape.text) break;
9695
- ctx.fillStyle = stroke;
9696
- ctx.font = `${shape.fontSize ?? 14}px system-ui, sans-serif`;
9697
- ctx.textAlign = shape.align ?? "left";
9698
- ctx.textBaseline = "middle";
9699
- ctx.fillText(shape.text, shape.x, shape.y);
9700
- break;
9701
- }
9702
- }
9703
- ctx.restore();
9704
- }
9705
- var LearningCanvas;
9706
- var init_LearningCanvas = __esm({
9707
- "components/learning/atoms/LearningCanvas.tsx"() {
9708
- "use client";
9709
- init_cn();
9710
- init_useEventBus();
9711
- LearningCanvas = ({
9712
- className,
9713
- width = 600,
9714
- height = 400,
9715
- backgroundColor,
9716
- shapes = [],
9717
- interactive = false,
9718
- animate = false,
9719
- onShapeClick,
9720
- onShapeHover,
9721
- isLoading,
9722
- error
9723
- }) => {
9724
- const canvasRef = useRef(null);
9725
- const eventBus = useEventBus();
9726
- const animRef = useRef(0);
9727
- const hoverIndexRef = useRef(-1);
9728
- const findShapeAt = useCallback((clientX, clientY) => {
9729
- const canvas = canvasRef.current;
9730
- if (!canvas) return -1;
9731
- const rect = canvas.getBoundingClientRect();
9732
- const x = clientX - rect.left;
9733
- const y = clientY - rect.top;
9734
- for (let i = shapes.length - 1; i >= 0; i--) {
9735
- const b = shapeBounds(shapes[i]);
9736
- if (b && x >= b.x && x <= b.x + b.w && y >= b.y && y <= b.y + b.h) {
9737
- return i;
9738
- }
9739
- }
9740
- return -1;
9741
- }, [shapes]);
9742
- const draw = useCallback(() => {
9743
- const canvas = canvasRef.current;
9744
- if (!canvas) return;
9745
- const ctx = canvas.getContext("2d");
9746
- if (!ctx) return;
9747
- const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
9748
- canvas.width = Math.max(1, Math.floor(width * dpr));
9749
- canvas.height = Math.max(1, Math.floor(height * dpr));
9750
- canvas.style.width = `${width}px`;
9751
- canvas.style.height = `${height}px`;
9752
- ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
9753
- ctx.clearRect(0, 0, width, height);
9754
- if (backgroundColor) {
9755
- ctx.fillStyle = backgroundColor;
9756
- ctx.fillRect(0, 0, width, height);
9757
- }
9758
- for (const shape of shapes) {
9759
- drawShape(ctx, shape, width, height);
9760
- }
9761
- }, [width, height, backgroundColor, shapes]);
9762
- useEffect(() => {
9763
- draw();
9764
- }, [draw]);
9765
- useEffect(() => {
9766
- if (!animate) return;
9767
- const loop = () => {
9768
- draw();
9769
- animRef.current = requestAnimationFrame(loop);
9770
- };
9771
- animRef.current = requestAnimationFrame(loop);
9772
- return () => cancelAnimationFrame(animRef.current);
9773
- }, [animate, draw]);
9774
- const handlePointerMove = useCallback(
9775
- (e) => {
9776
- if (!interactive) return;
9777
- const idx = findShapeAt(e.clientX, e.clientY);
9778
- if (idx !== hoverIndexRef.current) {
9779
- hoverIndexRef.current = idx;
9780
- if (idx >= 0) {
9781
- const shape = shapes[idx];
9782
- const payload = { id: shape.id, type: shape.type, index: idx };
9783
- if (onShapeHover) onShapeHover(payload);
9784
- else if (eventBus) eventBus.emit(`UI:SHAPE_HOVER`, payload);
9785
- }
9786
- }
9787
- },
9788
- [interactive, onShapeHover, eventBus, findShapeAt, shapes]
9789
- );
9790
- const handleClick = useCallback(
9791
- (e) => {
9792
- if (!interactive) return;
9793
- const idx = findShapeAt(e.clientX, e.clientY);
9794
- if (idx >= 0) {
9795
- const shape = shapes[idx];
9796
- const payload = { id: shape.id, type: shape.type, index: idx };
9797
- if (onShapeClick) onShapeClick(payload);
9798
- else if (eventBus) eventBus.emit(`UI:SHAPE_CLICK`, payload);
9799
- }
9800
- },
9801
- [interactive, onShapeClick, eventBus, findShapeAt, shapes]
9802
- );
9803
- if (isLoading || error) {
9804
- return /* @__PURE__ */ jsx(
9805
- "div",
9806
- {
9807
- className: cn(
9808
- "flex items-center justify-center rounded border border-border bg-surface",
9809
- className
9810
- ),
9811
- style: { width, height },
9812
- children: error ? /* @__PURE__ */ jsx("span", { className: "text-sm text-destructive", children: error.message }) : /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Loading canvas\u2026" })
9813
- }
9814
- );
9815
- }
9816
- return /* @__PURE__ */ jsx(
9817
- "canvas",
9818
- {
9819
- ref: canvasRef,
9820
- className: cn("block touch-none rounded border border-border", className),
9821
- style: { width, height },
9822
- onClick: handleClick,
9823
- onPointerMove: handlePointerMove
9824
- }
9825
- );
9826
- };
9827
- }
9828
- });
9829
10181
  var BiologyCanvas;
9830
10182
  var init_BiologyCanvas = __esm({
9831
10183
  "components/learning/molecules/BiologyCanvas.tsx"() {
@@ -10410,7 +10762,7 @@ var init_CodeBlock = __esm({
10410
10762
  DIFF_STYLE_FALLBACK = { bg: "", prefix: " ", text: "text-foreground" };
10411
10763
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
10412
10764
  HIDDEN_LINE_NUMBERS = { display: "none" };
10413
- CodeBlock = React74__default.memo(
10765
+ CodeBlock = React75__default.memo(
10414
10766
  ({
10415
10767
  code: rawCode,
10416
10768
  language = "text",
@@ -10997,7 +11349,7 @@ var init_MarkdownContent = __esm({
10997
11349
  init_Box();
10998
11350
  init_CodeBlock();
10999
11351
  init_cn();
11000
- MarkdownContent = React74__default.memo(
11352
+ MarkdownContent = React75__default.memo(
11001
11353
  ({ content, direction = "ltr", className }) => {
11002
11354
  const { t: _t } = useTranslate();
11003
11355
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -12324,7 +12676,7 @@ var init_StateMachineView = __esm({
12324
12676
  style: { top: title ? 30 : 0 },
12325
12677
  children: [
12326
12678
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
12327
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React74__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
12679
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React75__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
12328
12680
  StateNode,
12329
12681
  {
12330
12682
  state,
@@ -14948,8 +15300,8 @@ function MiniMap({
14948
15300
  tileAssets,
14949
15301
  unitAssets
14950
15302
  }) {
14951
- const canvasRef = React74.useRef(null);
14952
- const imgCacheRef = React74.useRef(/* @__PURE__ */ new Map());
15303
+ const canvasRef = React75.useRef(null);
15304
+ const imgCacheRef = React75.useRef(/* @__PURE__ */ new Map());
14953
15305
  function loadImg(url) {
14954
15306
  const cached = imgCacheRef.current.get(url);
14955
15307
  if (cached) return cached.complete ? cached : null;
@@ -14964,7 +15316,7 @@ function MiniMap({
14964
15316
  imgCacheRef.current.set(url, img);
14965
15317
  return null;
14966
15318
  }
14967
- React74.useEffect(() => {
15319
+ React75.useEffect(() => {
14968
15320
  const canvas = canvasRef.current;
14969
15321
  if (!canvas) return;
14970
15322
  const ctx = canvas.getContext("2d");
@@ -15938,7 +16290,7 @@ function isoToScreen(tileX, tileY, scale, baseOffsetX, layout = "isometric") {
15938
16290
  }
15939
16291
  if (layout === "flat") {
15940
16292
  const screenX2 = tileX * scaledTileWidth + baseOffsetX;
15941
- const screenY2 = tileY * scaledFloorHeight;
16293
+ const screenY2 = tileY * scaledTileWidth;
15942
16294
  return { x: screenX2, y: screenY2 };
15943
16295
  }
15944
16296
  const screenX = (tileX - tileY) * (scaledTileWidth / 2) + baseOffsetX;
@@ -15955,7 +16307,7 @@ function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric")
15955
16307
  }
15956
16308
  if (layout === "flat") {
15957
16309
  const col = Math.round((screenX - baseOffsetX) / scaledTileWidth);
15958
- const row = Math.round(screenY / scaledFloorHeight);
16310
+ const row = Math.round(screenY / scaledTileWidth);
15959
16311
  return { x: col, y: row };
15960
16312
  }
15961
16313
  const adjustedX = screenX - baseOffsetX;
@@ -16002,11 +16354,11 @@ function SideView({
16002
16354
  const canvasRef = useRef(null);
16003
16355
  const eventBus = useEventBus();
16004
16356
  const keysRef = useRef(/* @__PURE__ */ new Set());
16005
- const imageCache = useRef(/* @__PURE__ */ new Map());
16357
+ const imageCache2 = useRef(/* @__PURE__ */ new Map());
16006
16358
  const [loadedImages, setLoadedImages] = useState(/* @__PURE__ */ new Set());
16007
16359
  const loadImage = useCallback((url) => {
16008
16360
  if (!url) return null;
16009
- const cached = imageCache.current.get(url);
16361
+ const cached = imageCache2.current.get(url);
16010
16362
  if (cached?.complete && cached.naturalWidth > 0) {
16011
16363
  if (!loadedImages.has(url)) setLoadedImages((prev) => new Set(prev).add(url));
16012
16364
  return cached;
@@ -16016,7 +16368,7 @@ function SideView({
16016
16368
  img.crossOrigin = "anonymous";
16017
16369
  img.src = url;
16018
16370
  img.onload = () => setLoadedImages((prev) => new Set(prev).add(url));
16019
- imageCache.current.set(url, img);
16371
+ imageCache2.current.set(url, img);
16020
16372
  }
16021
16373
  return null;
16022
16374
  }, [loadedImages]);
@@ -16133,7 +16485,10 @@ function SideView({
16133
16485
  camY = Math.max(0, Math.min(py - ch / 2 - 50, wh - ch));
16134
16486
  }
16135
16487
  const bgImage = bgImg ? loadImage(bgImg.url) : null;
16136
- if (bgImage) {
16488
+ const bgSrc = bgImage ? resolveAssetSource(bgImage, bgImg, NOOP) : null;
16489
+ if (bgSrc) {
16490
+ blit(ctx, bgSrc, 0, 0, cw, ch);
16491
+ } else if (bgImage) {
16137
16492
  ctx.drawImage(bgImage, 0, 0, cw, ch);
16138
16493
  } else if (bg) {
16139
16494
  ctx.fillStyle = bg;
@@ -16166,15 +16521,18 @@ function SideView({
16166
16521
  const platType = plat.type ?? "ground";
16167
16522
  const spriteAsset = tSprites?.[platType];
16168
16523
  const tileImg = spriteAsset ? loadImage(spriteAsset.url) : null;
16169
- if (tileImg) {
16170
- const tileW = tileImg.naturalWidth;
16171
- const tileH = tileImg.naturalHeight;
16524
+ const tileSrc = tileImg ? resolveAssetSource(tileImg, spriteAsset, NOOP) : null;
16525
+ if (tileSrc) {
16526
+ const originX = tileSrc.rect ? tileSrc.rect.sx : 0;
16527
+ const originY = tileSrc.rect ? tileSrc.rect.sy : 0;
16528
+ const tileW = tileSrc.rect ? tileSrc.rect.sw : tileImg.naturalWidth;
16529
+ const tileH = tileSrc.rect ? tileSrc.rect.sh : tileImg.naturalHeight;
16172
16530
  const scaleH = plat.height / tileH;
16173
16531
  const scaledW = tileW * scaleH;
16174
16532
  for (let tx = 0; tx < plat.width; tx += scaledW) {
16175
16533
  const drawW = Math.min(scaledW, plat.width - tx);
16176
16534
  const srcW = drawW / scaleH;
16177
- ctx.drawImage(tileImg, 0, 0, srcW, tileH, platX + tx, platY, drawW, plat.height);
16535
+ ctx.drawImage(tileImg, originX, originY, srcW, tileH, platX + tx, platY, drawW, plat.height);
16178
16536
  }
16179
16537
  } else {
16180
16538
  const color = PLATFORM_COLORS[platType] ?? PLATFORM_COLORS.ground;
@@ -16208,14 +16566,15 @@ function SideView({
16208
16566
  const ppy = py - camY;
16209
16567
  const facingRight = auth.facingRight ?? true;
16210
16568
  const playerImg = pSprite ? loadImage(pSprite.url) : null;
16211
- if (playerImg) {
16569
+ const playerSrc = playerImg ? resolveAssetSource(playerImg, pSprite, NOOP) : null;
16570
+ if (playerSrc) {
16212
16571
  ctx.save();
16213
16572
  if (!facingRight) {
16214
16573
  ctx.translate(ppx + pw, ppy);
16215
16574
  ctx.scale(-1, 1);
16216
- ctx.drawImage(playerImg, 0, 0, pw, ph);
16575
+ blit(ctx, playerSrc, 0, 0, pw, ph);
16217
16576
  } else {
16218
- ctx.drawImage(playerImg, ppx, ppy, pw, ph);
16577
+ blit(ctx, playerSrc, ppx, ppy, pw, ph);
16219
16578
  }
16220
16579
  ctx.restore();
16221
16580
  } else {
@@ -16327,6 +16686,7 @@ function Canvas2D({
16327
16686
  const isSide = projection === "side";
16328
16687
  const isFree = projection === "free";
16329
16688
  const flatLike = projection === "hex" || projection === "flat" || isFree;
16689
+ const squareGrid = projection === "flat";
16330
16690
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
16331
16691
  const unitsProp = Array.isArray(_unitsPropRaw) ? _unitsPropRaw : [];
16332
16692
  const featuresProp = Array.isArray(_featuresPropRaw) ? _featuresPropRaw : [];
@@ -16409,17 +16769,18 @@ function Canvas2D({
16409
16769
  const effectiveDiamondTopY = diamondTopYProp ?? DIAMOND_TOP_Y;
16410
16770
  const scaledDiamondTopY = effectiveDiamondTopY * scale;
16411
16771
  const baseOffsetX = useMemo(() => {
16412
- if (isFree) return 0;
16772
+ if (isFree || projection === "flat") return 0;
16413
16773
  return (gridHeight - 1) * (scaledTileWidth / 2);
16414
- }, [isFree, gridHeight, scaledTileWidth]);
16774
+ }, [isFree, projection, gridHeight, scaledTileWidth]);
16415
16775
  const validMoveSet = useMemo(() => new Set(validMoves.map((p) => `${p.x},${p.y}`)), [validMoves]);
16416
16776
  const attackTargetSet = useMemo(() => new Set(attackTargets.map((p) => `${p.x},${p.y}`)), [attackTargets]);
16417
16777
  const spriteUrls = useMemo(() => {
16418
16778
  const urls = [];
16779
+ const toUrl = (x) => typeof x === "string" ? x : x?.url;
16419
16780
  for (const tile of sortedTiles) {
16420
16781
  if (tile.terrainSprite) urls.push(tile.terrainSprite.url);
16421
16782
  else if (getTerrainSprite) {
16422
- const url = getTerrainSprite(tile.terrain ?? "");
16783
+ const url = toUrl(getTerrainSprite(tile.terrain ?? ""));
16423
16784
  if (url) urls.push(url);
16424
16785
  } else {
16425
16786
  const url = assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
@@ -16429,7 +16790,7 @@ function Canvas2D({
16429
16790
  for (const feature of features) {
16430
16791
  if (feature.sprite) urls.push(feature.sprite.url);
16431
16792
  else if (getFeatureSprite) {
16432
- const url = getFeatureSprite(feature.type);
16793
+ const url = toUrl(getFeatureSprite(feature.type));
16433
16794
  if (url) urls.push(url);
16434
16795
  } else {
16435
16796
  const url = assetManifest?.features?.[feature.type]?.url;
@@ -16439,7 +16800,7 @@ function Canvas2D({
16439
16800
  for (const unit of units) {
16440
16801
  if (unit.sprite) urls.push(unit.sprite.url);
16441
16802
  else if (getUnitSprite) {
16442
- const url = getUnitSprite(unit);
16803
+ const url = toUrl(getUnitSprite(unit));
16443
16804
  if (url) urls.push(url);
16444
16805
  } else if (unit.unitType) {
16445
16806
  const url = assetManifest?.units?.[unit.unitType]?.url;
@@ -16480,14 +16841,25 @@ function Canvas2D({
16480
16841
  screenToWorld,
16481
16842
  lerpToTarget
16482
16843
  } = useCamera();
16483
- const resolveTerrainSpriteUrl = useCallback((tile) => {
16484
- return tile.terrainSprite?.url || getTerrainSprite?.(tile.terrain ?? "") || assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
16844
+ const [, setAtlasVersion] = useState(0);
16845
+ const bumpAtlas = useCallback(() => setAtlasVersion((v) => v + 1), []);
16846
+ const resolveTerrainAsset = useCallback((tile) => {
16847
+ if (tile.terrainSprite) return tile.terrainSprite;
16848
+ const s = getTerrainSprite?.(tile.terrain ?? "");
16849
+ if (s) return typeof s === "string" ? { url: s } : s;
16850
+ return assetManifest?.terrains?.[tile.terrain ?? ""];
16485
16851
  }, [getTerrainSprite, assetManifest]);
16486
- const resolveFeatureSpriteUrl = useCallback((featureType) => {
16487
- return getFeatureSprite?.(featureType) || assetManifest?.features?.[featureType]?.url;
16852
+ const resolveFeatureAsset = useCallback((feature) => {
16853
+ if (feature.sprite) return feature.sprite;
16854
+ const s = getFeatureSprite?.(feature.type);
16855
+ if (s) return typeof s === "string" ? { url: s } : s;
16856
+ return assetManifest?.features?.[feature.type];
16488
16857
  }, [getFeatureSprite, assetManifest]);
16489
- const resolveUnitSpriteUrl = useCallback((unit) => {
16490
- return unit.sprite?.url || getUnitSprite?.(unit) || (unit.unitType ? assetManifest?.units?.[unit.unitType]?.url : void 0);
16858
+ const resolveUnitAsset = useCallback((unit) => {
16859
+ if (unit.sprite) return unit.sprite;
16860
+ const s = getUnitSprite?.(unit);
16861
+ if (s) return typeof s === "string" ? { url: s } : s;
16862
+ return unit.unitType ? assetManifest?.units?.[unit.unitType] : void 0;
16491
16863
  }, [getUnitSprite, assetManifest]);
16492
16864
  const miniMapTiles = useMemo(() => {
16493
16865
  if (!showMinimap) return [];
@@ -16520,7 +16892,13 @@ function Canvas2D({
16520
16892
  ctx.clearRect(0, 0, viewportSize.width, viewportSize.height);
16521
16893
  if (backgroundImage) {
16522
16894
  const bgImg = getImage(backgroundImage.url);
16523
- if (bgImg) {
16895
+ const bgSrc = bgImg ? resolveAssetSource(bgImg, backgroundImage, bumpAtlas) : null;
16896
+ if (bgSrc?.rect) {
16897
+ const k = Math.max(viewportSize.width / bgSrc.rect.sw, viewportSize.height / bgSrc.rect.sh);
16898
+ const dw = bgSrc.rect.sw * k;
16899
+ const dh = bgSrc.rect.sh * k;
16900
+ blit(ctx, bgSrc, (viewportSize.width - dw) / 2, (viewportSize.height - dh) / 2, dw, dh);
16901
+ } else if (bgImg) {
16524
16902
  const cam2 = cameraRef.current;
16525
16903
  const patW = bgImg.naturalWidth;
16526
16904
  const patH = bgImg.naturalHeight;
@@ -16551,18 +16929,23 @@ function Canvas2D({
16551
16929
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
16552
16930
  continue;
16553
16931
  }
16554
- const spriteUrl = resolveTerrainSpriteUrl(tile);
16555
- const img = spriteUrl ? getImage(spriteUrl) : null;
16556
- if (img) {
16557
- if (img.naturalWidth === 0) {
16558
- ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
16559
- } else {
16560
- const drawW = scaledTileWidth;
16561
- const drawH = scaledTileWidth * (img.naturalHeight / img.naturalWidth);
16562
- const drawX = pos.x;
16563
- const drawY = flatLike ? pos.y : pos.y + scaledTileHeight - drawH;
16564
- ctx.drawImage(img, drawX, drawY, drawW, drawH);
16565
- }
16932
+ const terrainAsset = resolveTerrainAsset(tile);
16933
+ const img = terrainAsset?.url ? getImage(terrainAsset.url) : null;
16934
+ const src = img ? resolveAssetSource(img, terrainAsset, bumpAtlas) : null;
16935
+ if (src) {
16936
+ const drawW = scaledTileWidth;
16937
+ const drawH = squareGrid ? scaledTileWidth : scaledTileWidth / src.aspect;
16938
+ const drawX = pos.x;
16939
+ const drawY = flatLike ? pos.y : pos.y + scaledTileHeight - drawH;
16940
+ blit(ctx, src, drawX, drawY, drawW, drawH);
16941
+ } else if (img && img.naturalWidth === 0) {
16942
+ ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
16943
+ } else if (squareGrid) {
16944
+ ctx.fillStyle = tile.terrain === "water" ? "#3b82f6" : tile.terrain === "mountain" ? "#78716c" : tile.terrain === "stone" ? "#9ca3af" : "#4ade80";
16945
+ ctx.fillRect(pos.x, pos.y, scaledTileWidth, scaledTileWidth);
16946
+ ctx.strokeStyle = "rgba(0,0,0,0.2)";
16947
+ ctx.lineWidth = 1;
16948
+ ctx.strokeRect(pos.x, pos.y, scaledTileWidth, scaledTileWidth);
16566
16949
  } else {
16567
16950
  const centerX = pos.x + scaledTileWidth / 2;
16568
16951
  const topY = pos.y + scaledDiamondTopY;
@@ -16579,9 +16962,13 @@ function Canvas2D({
16579
16962
  ctx.stroke();
16580
16963
  }
16581
16964
  const drawHighlight = (color) => {
16965
+ ctx.fillStyle = color;
16966
+ if (squareGrid) {
16967
+ ctx.fillRect(pos.x, pos.y, scaledTileWidth, scaledTileWidth);
16968
+ return;
16969
+ }
16582
16970
  const centerX = pos.x + scaledTileWidth / 2;
16583
16971
  const topY = pos.y + scaledDiamondTopY;
16584
- ctx.fillStyle = color;
16585
16972
  ctx.beginPath();
16586
16973
  ctx.moveTo(centerX, topY);
16587
16974
  ctx.lineTo(pos.x + scaledTileWidth, topY + scaledFloorHeight / 2);
@@ -16598,7 +16985,7 @@ function Canvas2D({
16598
16985
  if (attackTargetSet.has(tileKey)) drawHighlight("rgba(239, 68, 68, 0.35)");
16599
16986
  if (debug2) {
16600
16987
  const centerX = pos.x + scaledTileWidth / 2;
16601
- const centerY = pos.y + scaledFloorHeight / 2 + scaledDiamondTopY;
16988
+ const centerY = squareGrid ? pos.y + scaledTileWidth / 2 : pos.y + scaledFloorHeight / 2 + scaledDiamondTopY;
16602
16989
  ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
16603
16990
  ctx.font = `${12 * scale * 2}px monospace`;
16604
16991
  ctx.textAlign = "center";
@@ -16616,15 +17003,16 @@ function Canvas2D({
16616
17003
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
16617
17004
  continue;
16618
17005
  }
16619
- const spriteUrl = feature.sprite?.url || resolveFeatureSpriteUrl(feature.type);
16620
- const img = spriteUrl ? getImage(spriteUrl) : null;
17006
+ const featureAsset = resolveFeatureAsset(feature);
17007
+ const img = featureAsset?.url ? getImage(featureAsset.url) : null;
17008
+ const src = img ? resolveAssetSource(img, featureAsset, bumpAtlas) : null;
16621
17009
  const centerX = pos.x + scaledTileWidth / 2;
16622
- const featureGroundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
17010
+ const featureGroundY = squareGrid ? pos.y + scaledTileWidth * 0.92 : pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
16623
17011
  const isCastle = feature.type === "castle";
16624
- const featureDrawH = isCastle ? scaledFloorHeight * 3.5 : scaledFloorHeight * 1.6;
17012
+ const featureDrawH = squareGrid ? isCastle ? scaledTileWidth * 1.4 : scaledTileWidth * 0.8 : isCastle ? scaledFloorHeight * 3.5 : scaledFloorHeight * 1.6;
16625
17013
  const maxFeatureW = isCastle ? scaledTileWidth * 1.8 : scaledTileWidth * 0.7;
16626
- if (img) {
16627
- const ar = img.naturalWidth / img.naturalHeight;
17014
+ if (src) {
17015
+ const ar = src.aspect;
16628
17016
  let drawH = featureDrawH;
16629
17017
  let drawW = featureDrawH * ar;
16630
17018
  if (drawW > maxFeatureW) {
@@ -16633,7 +17021,7 @@ function Canvas2D({
16633
17021
  }
16634
17022
  const drawX = centerX - drawW / 2;
16635
17023
  const drawY = featureGroundY - drawH;
16636
- ctx.drawImage(img, drawX, drawY, drawW, drawH);
17024
+ blit(ctx, src, drawX, drawY, drawW, drawH);
16637
17025
  } else {
16638
17026
  const color = FEATURE_COLORS[feature.type] || FEATURE_COLORS.default;
16639
17027
  ctx.beginPath();
@@ -16660,19 +17048,20 @@ function Canvas2D({
16660
17048
  }
16661
17049
  const isSelected = unit.id === selectedUnitId;
16662
17050
  const centerX = pos.x + scaledTileWidth / 2;
16663
- const groundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
17051
+ const groundY = squareGrid ? pos.y + scaledTileWidth * 0.92 : pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
16664
17052
  const breatheOffset = 0;
16665
- const unitSpriteUrl = resolveUnitSpriteUrl(unit);
16666
- const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
16667
- const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
17053
+ const unitAsset = resolveUnitAsset(unit);
17054
+ const img = unitAsset?.url ? getImage(unitAsset.url) : null;
17055
+ const unitDrawH = squareGrid ? scaledTileWidth * 0.55 * spriteHeightRatio * unitScale : scaledFloorHeight * spriteHeightRatio * unitScale;
16668
17056
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
16669
17057
  const unitIsSheet = unit.spriteSheet?.url !== void 0;
17058
+ const unitSrc = img && !unitIsSheet ? resolveAssetSource(img, unitAsset, bumpAtlas) : null;
16670
17059
  const SHEET_ROWS = 5;
16671
17060
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
16672
17061
  const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
16673
17062
  const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
16674
17063
  const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
16675
- const ar = frameW / (frameH || 1);
17064
+ const ar = unitIsSheet ? sheetFrameW / (sheetFrameH || 1) : unitSrc ? unitSrc.aspect : frameW / (frameH || 1);
16676
17065
  let drawH = unitDrawH;
16677
17066
  let drawW = unitDrawH * ar;
16678
17067
  if (drawW > maxUnitW) {
@@ -16682,12 +17071,14 @@ function Canvas2D({
16682
17071
  if (unit.previousPosition && (unit.previousPosition.x !== unit.position.x || unit.previousPosition.y !== unit.position.y)) {
16683
17072
  const ghostPos = project(unit.previousPosition.x, unit.previousPosition.y, baseOffsetX);
16684
17073
  const ghostCenterX = ghostPos.x + scaledTileWidth / 2;
16685
- const ghostGroundY = ghostPos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
17074
+ const ghostGroundY = squareGrid ? ghostPos.y + scaledTileWidth * 0.92 : ghostPos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
16686
17075
  ctx.save();
16687
17076
  ctx.globalAlpha = 0.25;
16688
17077
  if (img) {
16689
17078
  if (unitIsSheet) {
16690
17079
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
17080
+ } else if (unitSrc) {
17081
+ blit(ctx, unitSrc, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
16691
17082
  } else {
16692
17083
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
16693
17084
  }
@@ -16736,6 +17127,8 @@ function Canvas2D({
16736
17127
  const drawUnit = (x) => {
16737
17128
  if (unitIsSheet) {
16738
17129
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
17130
+ } else if (unitSrc) {
17131
+ blit(ctx, unitSrc, x, spriteY, drawW, drawH);
16739
17132
  } else {
16740
17133
  ctx.drawImage(img, x, spriteY, drawW, drawH);
16741
17134
  }
@@ -16761,17 +17154,24 @@ function Canvas2D({
16761
17154
  }
16762
17155
  }
16763
17156
  for (const fx of effects) {
16764
- const spriteUrl = assetManifest?.effects?.[fx.key]?.url;
16765
- if (!spriteUrl) continue;
16766
- const img = getImage(spriteUrl);
17157
+ const fxAsset = assetManifest?.effects?.[fx.key];
17158
+ if (!fxAsset?.url) continue;
17159
+ const img = getImage(fxAsset.url);
16767
17160
  if (!img) continue;
17161
+ const src = resolveAssetSource(img, fxAsset, bumpAtlas);
16768
17162
  const pos = project(fx.x, fx.y, baseOffsetX);
16769
17163
  const cx = pos.x + scaledTileWidth / 2;
16770
- const cy = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
17164
+ const cy = squareGrid ? pos.y + scaledTileWidth / 2 : pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
16771
17165
  const alpha = Math.min(1, fx.ttl / 4);
16772
17166
  const prev = ctx.globalAlpha;
16773
17167
  ctx.globalAlpha = alpha;
16774
- ctx.drawImage(img, cx - img.naturalWidth / 2, cy - img.naturalHeight / 2);
17168
+ if (src?.rect) {
17169
+ const dw = scaledTileWidth;
17170
+ const dh = dw / src.aspect;
17171
+ blit(ctx, src, cx - dw / 2, cy - dh / 2, dw, dh);
17172
+ } else {
17173
+ ctx.drawImage(img, cx - img.naturalWidth / 2, cy - img.naturalHeight / 2);
17174
+ }
16775
17175
  ctx.globalAlpha = prev;
16776
17176
  }
16777
17177
  onDrawEffects?.(ctx, 0, getImage);
@@ -16784,13 +17184,15 @@ function Canvas2D({
16784
17184
  effects,
16785
17185
  project,
16786
17186
  flatLike,
17187
+ squareGrid,
16787
17188
  scale,
16788
17189
  debug2,
16789
- resolveTerrainSpriteUrl,
16790
- resolveFeatureSpriteUrl,
16791
- resolveUnitSpriteUrl,
17190
+ resolveTerrainAsset,
17191
+ resolveFeatureAsset,
17192
+ resolveUnitAsset,
16792
17193
  resolveFrameForUnit,
16793
17194
  getImage,
17195
+ bumpAtlas,
16794
17196
  baseOffsetX,
16795
17197
  scaledTileWidth,
16796
17198
  scaledTileHeight,
@@ -16816,12 +17218,12 @@ function Canvas2D({
16816
17218
  if (!unit?.position) return;
16817
17219
  const pos = project(unit.position.x, unit.position.y, baseOffsetX);
16818
17220
  const centerX = pos.x + scaledTileWidth / 2;
16819
- const centerY = pos.y + scaledDiamondTopY + scaledFloorHeight / 2;
17221
+ const centerY = squareGrid ? pos.y + scaledTileWidth / 2 : pos.y + scaledDiamondTopY + scaledFloorHeight / 2;
16820
17222
  targetCameraRef.current = {
16821
17223
  x: centerX - viewportSize.width / 2,
16822
17224
  y: centerY - viewportSize.height / 2
16823
17225
  };
16824
- }, [camera, selectedUnitId, units, project, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
17226
+ }, [camera, selectedUnitId, units, project, baseOffsetX, scaledTileWidth, squareGrid, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
16825
17227
  useEffect(() => {
16826
17228
  if (isSide || !interpolateUnits) return;
16827
17229
  unitInterp.onSnapshot(
@@ -16892,11 +17294,11 @@ function Canvas2D({
16892
17294
  if (!tileHoverEvent || !canvasRef.current) return;
16893
17295
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
16894
17296
  const adjustedX = world.x - scaledTileWidth / 2;
16895
- const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
17297
+ const adjustedY = squareGrid ? world.y - scaledTileWidth / 2 : world.y - scaledDiamondTopY - scaledFloorHeight / 2;
16896
17298
  const isoPos = unproject(adjustedX, adjustedY, baseOffsetX);
16897
17299
  const tileExists = tilesProp.some((t2) => t2.x === isoPos.x && t2.y === isoPos.y);
16898
17300
  if (tileExists) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
16899
- }, [screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, unproject, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
17301
+ }, [screenToWorld, viewportSize, scaledTileWidth, squareGrid, scaledDiamondTopY, scaledFloorHeight, unproject, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
16900
17302
  const handleCanvasPointerUp = useCallback((e) => {
16901
17303
  singlePointerActiveRef.current = false;
16902
17304
  if (enableCamera) handlePointerUp();
@@ -16904,7 +17306,7 @@ function Canvas2D({
16904
17306
  if (!canvasRef.current) return;
16905
17307
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
16906
17308
  const adjustedX = world.x - scaledTileWidth / 2;
16907
- const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
17309
+ const adjustedY = squareGrid ? world.y - scaledTileWidth / 2 : world.y - scaledDiamondTopY - scaledFloorHeight / 2;
16908
17310
  const isoPos = unproject(adjustedX, adjustedY, baseOffsetX);
16909
17311
  const clickedUnit = units.find((u) => u.position?.x === isoPos.x && u.position?.y === isoPos.y);
16910
17312
  if (clickedUnit && unitClickEvent) {
@@ -16913,7 +17315,7 @@ function Canvas2D({
16913
17315
  const tileExists = tilesProp.some((t2) => t2.x === isoPos.x && t2.y === isoPos.y);
16914
17316
  if (tileExists) eventBus.emit(`UI:${tileClickEvent}`, { x: isoPos.x, y: isoPos.y });
16915
17317
  }
16916
- }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, unproject, baseOffsetX, units, tilesProp, unitClickEvent, tileClickEvent, eventBus]);
17318
+ }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, squareGrid, scaledDiamondTopY, scaledFloorHeight, unproject, baseOffsetX, units, tilesProp, unitClickEvent, tileClickEvent, eventBus]);
16917
17319
  const handleCanvasPointerLeave = useCallback(() => {
16918
17320
  handleMouseLeave();
16919
17321
  if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
@@ -16963,11 +17365,12 @@ function Canvas2D({
16963
17365
  return units.filter((u) => !!u.position).map((u) => {
16964
17366
  const pos = project(u.position.x, u.position.y, baseOffsetX);
16965
17367
  const cam = cameraRef.current;
17368
+ const anchorY = squareGrid ? pos.y + scaledTileWidth * 0.92 : pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
16966
17369
  const screenX = (pos.x + scaledTileWidth / 2 - (cam.x + viewportSize.width / 2)) * cam.zoom + viewportSize.width / 2;
16967
- const screenY = (pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5 - (cam.y + viewportSize.height / 2)) * cam.zoom + viewportSize.height / 2;
17370
+ const screenY = (anchorY - (cam.y + viewportSize.height / 2)) * cam.zoom + viewportSize.height / 2;
16968
17371
  return { unit: u, screenX, screenY };
16969
17372
  });
16970
- }, [units, project, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, cameraRef]);
17373
+ }, [units, project, baseOffsetX, scaledTileWidth, squareGrid, scaledDiamondTopY, scaledFloorHeight, viewportSize, cameraRef]);
16971
17374
  if (error) {
16972
17375
  return /* @__PURE__ */ jsx(Box, { className: cn("flex items-center justify-center w-full h-full bg-[var(--color-card)] rounded-container", className), children: /* @__PURE__ */ jsxs(Stack, { direction: "vertical", gap: "md", align: "center", children: [
16973
17376
  /* @__PURE__ */ jsx(Icon, { name: "alert-circle", size: "xl" }),
@@ -17104,7 +17507,7 @@ function Canvas2D({
17104
17507
  }
17105
17508
  );
17106
17509
  }
17107
- var PLATFORM_COLORS, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
17510
+ var PLATFORM_COLORS, NOOP, PLAYER_COLOR, PLAYER_EYE_COLOR, SKY_GRADIENT_TOP, SKY_GRADIENT_BOTTOM, GRID_COLOR, DEFAULT_PLATFORMS;
17108
17511
  var init_Canvas2D = __esm({
17109
17512
  "components/game/2d/molecules/Canvas2D.tsx"() {
17110
17513
  "use client";
@@ -17118,6 +17521,7 @@ var init_Canvas2D = __esm({
17118
17521
  init_MiniMap();
17119
17522
  init_HealthBar();
17120
17523
  init_useImageCache();
17524
+ init_atlasSlice();
17121
17525
  init_useCamera();
17122
17526
  init_useCanvasGestures();
17123
17527
  init_useRenderInterpolation();
@@ -17131,6 +17535,8 @@ var init_Canvas2D = __esm({
17131
17535
  hazard: "#c0392b",
17132
17536
  goal: "#f1c40f"
17133
17537
  };
17538
+ NOOP = () => {
17539
+ };
17134
17540
  PLAYER_COLOR = "#3498db";
17135
17541
  PLAYER_EYE_COLOR = "#ffffff";
17136
17542
  SKY_GRADIENT_TOP = "#1a1a2e";
@@ -19661,9 +20067,9 @@ function ControlButton({
19661
20067
  className
19662
20068
  }) {
19663
20069
  const eventBus = useEventBus();
19664
- const [isPressed, setIsPressed] = React74.useState(false);
20070
+ const [isPressed, setIsPressed] = React75.useState(false);
19665
20071
  const actualPressed = pressed ?? isPressed;
19666
- const handlePointerDown = React74.useCallback(
20072
+ const handlePointerDown = React75.useCallback(
19667
20073
  (e) => {
19668
20074
  e.preventDefault();
19669
20075
  if (disabled) return;
@@ -19673,7 +20079,7 @@ function ControlButton({
19673
20079
  },
19674
20080
  [disabled, pressEvent, eventBus, onPress]
19675
20081
  );
19676
- const handlePointerUp = React74.useCallback(
20082
+ const handlePointerUp = React75.useCallback(
19677
20083
  (e) => {
19678
20084
  e.preventDefault();
19679
20085
  if (disabled) return;
@@ -19683,7 +20089,7 @@ function ControlButton({
19683
20089
  },
19684
20090
  [disabled, releaseEvent, eventBus, onRelease]
19685
20091
  );
19686
- const handlePointerLeave = React74.useCallback(
20092
+ const handlePointerLeave = React75.useCallback(
19687
20093
  (e) => {
19688
20094
  if (isPressed) {
19689
20095
  setIsPressed(false);
@@ -19776,8 +20182,8 @@ function ControlGrid({
19776
20182
  className
19777
20183
  }) {
19778
20184
  const eventBus = useEventBus();
19779
- const [active, setActive] = React74.useState(/* @__PURE__ */ new Set());
19780
- const handlePress = React74.useCallback(
20185
+ const [active, setActive] = React75.useState(/* @__PURE__ */ new Set());
20186
+ const handlePress = React75.useCallback(
19781
20187
  (id) => {
19782
20188
  setActive((prev) => new Set(prev).add(id));
19783
20189
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -19791,7 +20197,7 @@ function ControlGrid({
19791
20197
  },
19792
20198
  [kind, actionEvent, directionEvent, directionEvents, eventBus, onAction, onDirection]
19793
20199
  );
19794
- const handleRelease = React74.useCallback(
20200
+ const handleRelease = React75.useCallback(
19795
20201
  (id) => {
19796
20202
  setActive((prev) => {
19797
20203
  const next = new Set(prev);
@@ -21057,8 +21463,8 @@ var init_Menu = __esm({
21057
21463
  "bottom-end": "bottom-start"
21058
21464
  };
21059
21465
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
21060
- const triggerChild = React74__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
21061
- const triggerElement = React74__default.cloneElement(
21466
+ const triggerChild = React75__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
21467
+ const triggerElement = React75__default.cloneElement(
21062
21468
  triggerChild,
21063
21469
  {
21064
21470
  ref: triggerRef,
@@ -21153,14 +21559,14 @@ function useDataDnd(args) {
21153
21559
  const isZone = Boolean(dragGroup || accepts || sortable);
21154
21560
  const enabled = isZone || Boolean(dndRoot);
21155
21561
  const eventBus = useEventBus();
21156
- const parentRoot = React74__default.useContext(RootCtx);
21562
+ const parentRoot = React75__default.useContext(RootCtx);
21157
21563
  const isRoot = enabled && parentRoot === null;
21158
- const zoneId = React74__default.useId();
21564
+ const zoneId = React75__default.useId();
21159
21565
  const ownGroup = dragGroup ?? accepts ?? zoneId;
21160
- const [optimisticOrders, setOptimisticOrders] = React74__default.useState(() => /* @__PURE__ */ new Map());
21161
- const optimisticOrdersRef = React74__default.useRef(optimisticOrders);
21566
+ const [optimisticOrders, setOptimisticOrders] = React75__default.useState(() => /* @__PURE__ */ new Map());
21567
+ const optimisticOrdersRef = React75__default.useRef(optimisticOrders);
21162
21568
  optimisticOrdersRef.current = optimisticOrders;
21163
- const clearOptimisticOrder = React74__default.useCallback((group) => {
21569
+ const clearOptimisticOrder = React75__default.useCallback((group) => {
21164
21570
  setOptimisticOrders((prev) => {
21165
21571
  if (!prev.has(group)) return prev;
21166
21572
  const next = new Map(prev);
@@ -21185,7 +21591,7 @@ function useDataDnd(args) {
21185
21591
  const raw = it[dndItemIdField];
21186
21592
  return raw != null ? String(raw) : `__idx_${idx}`;
21187
21593
  }).join("|");
21188
- const itemIds = React74__default.useMemo(
21594
+ const itemIds = React75__default.useMemo(
21189
21595
  () => orderedItems.map((it, idx) => {
21190
21596
  const raw = it[dndItemIdField];
21191
21597
  return raw != null ? String(raw) : `__idx_${idx}`;
@@ -21196,7 +21602,7 @@ function useDataDnd(args) {
21196
21602
  const raw = it[dndItemIdField];
21197
21603
  return raw != null ? String(raw) : `__${idx}`;
21198
21604
  }).join("|");
21199
- React74__default.useEffect(() => {
21605
+ React75__default.useEffect(() => {
21200
21606
  const root = isRoot ? null : parentRoot;
21201
21607
  if (root) {
21202
21608
  root.clearOptimisticOrder(ownGroup);
@@ -21204,20 +21610,20 @@ function useDataDnd(args) {
21204
21610
  clearOptimisticOrder(ownGroup);
21205
21611
  }
21206
21612
  }, [itemsContentSig, ownGroup]);
21207
- const zonesRef = React74__default.useRef(/* @__PURE__ */ new Map());
21208
- const registerZone = React74__default.useCallback((zoneId2, meta2) => {
21613
+ const zonesRef = React75__default.useRef(/* @__PURE__ */ new Map());
21614
+ const registerZone = React75__default.useCallback((zoneId2, meta2) => {
21209
21615
  zonesRef.current.set(zoneId2, meta2);
21210
21616
  }, []);
21211
- const unregisterZone = React74__default.useCallback((zoneId2) => {
21617
+ const unregisterZone = React75__default.useCallback((zoneId2) => {
21212
21618
  zonesRef.current.delete(zoneId2);
21213
21619
  }, []);
21214
- const [activeDrag, setActiveDrag] = React74__default.useState(null);
21215
- const [overZoneGroup, setOverZoneGroup] = React74__default.useState(null);
21216
- const meta = React74__default.useMemo(
21620
+ const [activeDrag, setActiveDrag] = React75__default.useState(null);
21621
+ const [overZoneGroup, setOverZoneGroup] = React75__default.useState(null);
21622
+ const meta = React75__default.useMemo(
21217
21623
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
21218
21624
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
21219
21625
  );
21220
- React74__default.useEffect(() => {
21626
+ React75__default.useEffect(() => {
21221
21627
  const target = isRoot ? null : parentRoot;
21222
21628
  if (!target) {
21223
21629
  zonesRef.current.set(zoneId, meta);
@@ -21236,7 +21642,7 @@ function useDataDnd(args) {
21236
21642
  }, [parentRoot, isRoot, zoneId, meta]);
21237
21643
  const sensors = useAlmadarDndSensors(true);
21238
21644
  const collisionDetection = almadarDndCollisionDetection;
21239
- const findZoneByItem = React74__default.useCallback(
21645
+ const findZoneByItem = React75__default.useCallback(
21240
21646
  (id) => {
21241
21647
  for (const z of zonesRef.current.values()) {
21242
21648
  if (z.itemIds.includes(id)) return z;
@@ -21245,7 +21651,7 @@ function useDataDnd(args) {
21245
21651
  },
21246
21652
  []
21247
21653
  );
21248
- React74__default.useCallback(
21654
+ React75__default.useCallback(
21249
21655
  (group) => {
21250
21656
  for (const z of zonesRef.current.values()) {
21251
21657
  if (z.group === group) return z;
@@ -21254,7 +21660,7 @@ function useDataDnd(args) {
21254
21660
  },
21255
21661
  []
21256
21662
  );
21257
- const handleDragEnd = React74__default.useCallback(
21663
+ const handleDragEnd = React75__default.useCallback(
21258
21664
  (event) => {
21259
21665
  const { active, over } = event;
21260
21666
  const activeIdStr = String(active.id);
@@ -21345,8 +21751,8 @@ function useDataDnd(args) {
21345
21751
  },
21346
21752
  [eventBus]
21347
21753
  );
21348
- const sortableData = React74__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
21349
- const SortableItem = React74__default.useCallback(
21754
+ const sortableData = React75__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
21755
+ const SortableItem = React75__default.useCallback(
21350
21756
  ({ id, children }) => {
21351
21757
  const {
21352
21758
  attributes,
@@ -21386,7 +21792,7 @@ function useDataDnd(args) {
21386
21792
  id: droppableId,
21387
21793
  data: sortableData
21388
21794
  });
21389
- const ctx = React74__default.useContext(RootCtx);
21795
+ const ctx = React75__default.useContext(RootCtx);
21390
21796
  const activeDrag2 = ctx?.activeDrag ?? null;
21391
21797
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
21392
21798
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -21401,7 +21807,7 @@ function useDataDnd(args) {
21401
21807
  showForeignPlaceholder,
21402
21808
  ctxAvailable: ctx != null
21403
21809
  });
21404
- React74__default.useEffect(() => {
21810
+ React75__default.useEffect(() => {
21405
21811
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
21406
21812
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
21407
21813
  return /* @__PURE__ */ jsx(
@@ -21415,11 +21821,11 @@ function useDataDnd(args) {
21415
21821
  }
21416
21822
  );
21417
21823
  };
21418
- const rootContextValue = React74__default.useMemo(
21824
+ const rootContextValue = React75__default.useMemo(
21419
21825
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
21420
21826
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
21421
21827
  );
21422
- const handleDragStart = React74__default.useCallback((event) => {
21828
+ const handleDragStart = React75__default.useCallback((event) => {
21423
21829
  const sourceZone = findZoneByItem(event.active.id);
21424
21830
  const rect = event.active.rect.current.initial;
21425
21831
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -21438,7 +21844,7 @@ function useDataDnd(args) {
21438
21844
  isRoot
21439
21845
  });
21440
21846
  }, [findZoneByItem, isRoot, zoneId]);
21441
- const handleDragOver = React74__default.useCallback((event) => {
21847
+ const handleDragOver = React75__default.useCallback((event) => {
21442
21848
  const { active, over } = event;
21443
21849
  const overData = over?.data?.current;
21444
21850
  const overGroup = overData?.dndGroup ?? null;
@@ -21508,7 +21914,7 @@ function useDataDnd(args) {
21508
21914
  return next;
21509
21915
  });
21510
21916
  }, []);
21511
- const handleDragCancel = React74__default.useCallback((event) => {
21917
+ const handleDragCancel = React75__default.useCallback((event) => {
21512
21918
  setActiveDrag(null);
21513
21919
  setOverZoneGroup(null);
21514
21920
  dndLog.warn("dragCancel", {
@@ -21516,12 +21922,12 @@ function useDataDnd(args) {
21516
21922
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
21517
21923
  });
21518
21924
  }, []);
21519
- const handleDragEndWithCleanup = React74__default.useCallback((event) => {
21925
+ const handleDragEndWithCleanup = React75__default.useCallback((event) => {
21520
21926
  handleDragEnd(event);
21521
21927
  setActiveDrag(null);
21522
21928
  setOverZoneGroup(null);
21523
21929
  }, [handleDragEnd]);
21524
- const wrapContainer = React74__default.useCallback(
21930
+ const wrapContainer = React75__default.useCallback(
21525
21931
  (children) => {
21526
21932
  if (!enabled) return children;
21527
21933
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -21575,7 +21981,7 @@ var init_useDataDnd = __esm({
21575
21981
  init_useAlmadarDndCollision();
21576
21982
  init_Box();
21577
21983
  dndLog = createLogger("almadar:ui:dnd");
21578
- RootCtx = React74__default.createContext(null);
21984
+ RootCtx = React75__default.createContext(null);
21579
21985
  }
21580
21986
  });
21581
21987
  function renderIconInput(icon, props) {
@@ -22101,7 +22507,7 @@ function DataList({
22101
22507
  }) {
22102
22508
  const eventBus = useEventBus();
22103
22509
  const { t } = useTranslate();
22104
- const [visibleCount, setVisibleCount] = React74__default.useState(pageSize || Infinity);
22510
+ const [visibleCount, setVisibleCount] = React75__default.useState(pageSize || Infinity);
22105
22511
  const fieldDefs = fields ?? columns ?? [];
22106
22512
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
22107
22513
  const dnd = useDataDnd({
@@ -22120,7 +22526,7 @@ function DataList({
22120
22526
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
22121
22527
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
22122
22528
  const hasRenderProp = typeof children === "function";
22123
- React74__default.useEffect(() => {
22529
+ React75__default.useEffect(() => {
22124
22530
  const renderItemTypeOf = typeof schemaRenderItem;
22125
22531
  const childrenTypeOf = typeof children;
22126
22532
  if (data.length > 0 && !hasRenderProp) {
@@ -22224,7 +22630,7 @@ function DataList({
22224
22630
  const items2 = [...data];
22225
22631
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
22226
22632
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
22227
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
22633
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React75__default.Fragment, { children: [
22228
22634
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
22229
22635
  group.items.map((itemData, index) => {
22230
22636
  const id = itemData.id || `${gi}-${index}`;
@@ -22365,7 +22771,7 @@ function DataList({
22365
22771
  className
22366
22772
  ),
22367
22773
  children: [
22368
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
22774
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React75__default.Fragment, { children: [
22369
22775
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
22370
22776
  group.items.map(
22371
22777
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -22472,8 +22878,8 @@ function ScalarControl({
22472
22878
  }
22473
22879
  const numeric = typeof value === "number";
22474
22880
  const initial = value === null ? "" : String(value);
22475
- const [draft, setDraft] = React74__default.useState(initial);
22476
- React74__default.useEffect(() => setDraft(initial), [initial]);
22881
+ const [draft, setDraft] = React75__default.useState(initial);
22882
+ React75__default.useEffect(() => setDraft(initial), [initial]);
22477
22883
  const commit = () => {
22478
22884
  if (numeric) {
22479
22885
  const n = draft.trim() === "" ? 0 : Number(draft);
@@ -22541,8 +22947,8 @@ function Row({
22541
22947
  onRemove,
22542
22948
  readonly
22543
22949
  }) {
22544
- const [keyDraft, setKeyDraft] = React74__default.useState(rowKey);
22545
- React74__default.useEffect(() => setKeyDraft(rowKey), [rowKey]);
22950
+ const [keyDraft, setKeyDraft] = React75__default.useState(rowKey);
22951
+ React75__default.useEffect(() => setKeyDraft(rowKey), [rowKey]);
22546
22952
  const container = isObj(value) || isArr(value);
22547
22953
  return /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "group w-max min-w-full", children: [
22548
22954
  /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", className: "py-0.5 w-max", children: [
@@ -22585,7 +22991,7 @@ function ContainerNode({
22585
22991
  depth,
22586
22992
  readonly
22587
22993
  }) {
22588
- const [open, setOpen] = React74__default.useState(depth < 2);
22994
+ const [open, setOpen] = React75__default.useState(depth < 2);
22589
22995
  const array = isArr(value);
22590
22996
  const entries = array ? value.map((v, i) => [String(i), v]) : Object.entries(value);
22591
22997
  const setObjValue = (key, next) => {
@@ -22727,7 +23133,7 @@ var init_FormSection = __esm({
22727
23133
  columns = 1,
22728
23134
  className
22729
23135
  }) => {
22730
- const [collapsed, setCollapsed] = React74__default.useState(defaultCollapsed);
23136
+ const [collapsed, setCollapsed] = React75__default.useState(defaultCollapsed);
22731
23137
  const { t } = useTranslate();
22732
23138
  const eventBus = useEventBus();
22733
23139
  const gridClass = {
@@ -22735,7 +23141,7 @@ var init_FormSection = __esm({
22735
23141
  2: "grid-cols-1 md:grid-cols-2",
22736
23142
  3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
22737
23143
  }[columns];
22738
- React74__default.useCallback(() => {
23144
+ React75__default.useCallback(() => {
22739
23145
  if (collapsible) {
22740
23146
  setCollapsed((prev) => !prev);
22741
23147
  eventBus.emit("UI:TOGGLE_COLLAPSE", { collapsed: !collapsed });
@@ -23143,8 +23549,8 @@ function TextLikeControl({
23143
23549
  onCommit
23144
23550
  }) {
23145
23551
  const initial = value === void 0 || value === null ? "" : String(value);
23146
- const [draft, setDraft] = React74__default.useState(initial);
23147
- React74__default.useEffect(() => setDraft(initial), [initial]);
23552
+ const [draft, setDraft] = React75__default.useState(initial);
23553
+ React75__default.useEffect(() => setDraft(initial), [initial]);
23148
23554
  const commit = () => {
23149
23555
  if (numeric) {
23150
23556
  const n = draft.trim() === "" ? 0 : Number(draft);
@@ -23329,14 +23735,14 @@ var init_NodeSlotEditor = __esm({
23329
23735
  isObj2 = (v) => v !== null && v !== void 0 && typeof v === "object" && !Array.isArray(v);
23330
23736
  NodeSlotEditor = ({ value, onChange, className }) => {
23331
23737
  const { type, props, wasArray } = normalize(value);
23332
- const patterns = React74__default.useMemo(() => {
23738
+ const patterns = React75__default.useMemo(() => {
23333
23739
  try {
23334
23740
  return [...getKnownPatterns()].sort();
23335
23741
  } catch {
23336
23742
  return [];
23337
23743
  }
23338
23744
  }, []);
23339
- const options = React74__default.useMemo(
23745
+ const options = React75__default.useMemo(
23340
23746
  () => [{ value: "", label: "\u2014 none \u2014" }, ...patterns.map((p) => ({ value: p, label: p }))],
23341
23747
  [patterns]
23342
23748
  );
@@ -23348,7 +23754,7 @@ var init_NodeSlotEditor = __esm({
23348
23754
  const pattern = { type: nextType, ...nextProps };
23349
23755
  onChange(wasArray || value === void 0 ? [pattern] : pattern);
23350
23756
  };
23351
- const schemaEntries = React74__default.useMemo(() => {
23757
+ const schemaEntries = React75__default.useMemo(() => {
23352
23758
  if (!type) return [];
23353
23759
  const def = getPatternDefinition(type);
23354
23760
  if (!def?.propsSchema) return [];
@@ -24250,7 +24656,7 @@ var init_Flex = __esm({
24250
24656
  flexStyle.flexBasis = typeof basis === "number" ? `${basis}px` : basis;
24251
24657
  }
24252
24658
  }
24253
- return React74__default.createElement(Component, {
24659
+ return React75__default.createElement(Component, {
24254
24660
  className: cn(
24255
24661
  inline ? "inline-flex" : "flex",
24256
24662
  directionStyles[direction],
@@ -24369,7 +24775,7 @@ var init_Grid = __esm({
24369
24775
  as: Component = "div"
24370
24776
  }) => {
24371
24777
  const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
24372
- return React74__default.createElement(
24778
+ return React75__default.createElement(
24373
24779
  Component,
24374
24780
  {
24375
24781
  className: cn(
@@ -24565,9 +24971,9 @@ var init_Popover = __esm({
24565
24971
  onMouseLeave: handleClose,
24566
24972
  onPointerDown: tapTriggerProps.onPointerDown
24567
24973
  };
24568
- const childElement = React74__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
24974
+ const childElement = React75__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
24569
24975
  const childPointerDown = childElement.props.onPointerDown;
24570
- const triggerElement = React74__default.cloneElement(
24976
+ const triggerElement = React75__default.cloneElement(
24571
24977
  childElement,
24572
24978
  {
24573
24979
  ref: triggerRef,
@@ -25419,9 +25825,9 @@ var init_Tooltip = __esm({
25419
25825
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
25420
25826
  };
25421
25827
  }, []);
25422
- const triggerElement = React74__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25828
+ const triggerElement = React75__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25423
25829
  const childPointerDown = triggerElement.props.onPointerDown;
25424
- const trigger = React74__default.cloneElement(triggerElement, {
25830
+ const trigger = React75__default.cloneElement(triggerElement, {
25425
25831
  ref: triggerRef,
25426
25832
  onMouseEnter: handleMouseEnter,
25427
25833
  onMouseLeave: handleMouseLeave,
@@ -25511,7 +25917,7 @@ var init_WizardProgress = __esm({
25511
25917
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
25512
25918
  const isActive = index === currentStep;
25513
25919
  const isCompleted = index < currentStep;
25514
- return /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
25920
+ return /* @__PURE__ */ jsxs(React75__default.Fragment, { children: [
25515
25921
  /* @__PURE__ */ jsx(
25516
25922
  "button",
25517
25923
  {
@@ -26625,13 +27031,12 @@ function GameCard({
26625
27031
  className
26626
27032
  }) {
26627
27033
  const eventBus = useEventBus();
26628
- const handleClick = React74.useCallback(() => {
27034
+ const handleClick = React75.useCallback(() => {
26629
27035
  if (disabled) return;
26630
27036
  onClick?.(id);
26631
27037
  if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { cardId: id });
26632
27038
  }, [disabled, id, onClick, clickEvent, eventBus]);
26633
27039
  const artPx = artPxMap[size];
26634
- const frameStyle = frameAsset?.url ? { backgroundImage: `url(${frameAsset.url})`, backgroundSize: "100% 100%", backgroundRepeat: "no-repeat" } : {};
26635
27040
  return /* @__PURE__ */ jsxs(
26636
27041
  Button,
26637
27042
  {
@@ -26639,11 +27044,10 @@ function GameCard({
26639
27044
  onClick: handleClick,
26640
27045
  disabled,
26641
27046
  title: name,
26642
- style: frameStyle,
26643
27047
  className: cn(
26644
- "relative flex flex-col items-center rounded-interactive",
26645
- "bg-card/90 px-1.5 pt-1.5 pb-1 transition-all duration-150",
26646
- frameAsset?.url ? "border-0" : "border-2",
27048
+ "relative isolate flex flex-col items-center rounded-interactive",
27049
+ "px-1.5 pt-1.5 pb-1 transition-all duration-150",
27050
+ frameAsset?.url ? "border-0" : "border-2 bg-card/90",
26647
27051
  cardSizeMap[size],
26648
27052
  disabled ? "border-border opacity-50 cursor-not-allowed" : "border-accent hover:brightness-125 hover:-translate-y-1 cursor-pointer",
26649
27053
  selected && "ring-2 ring-foreground ring-offset-1 ring-offset-background -translate-y-1",
@@ -26651,6 +27055,7 @@ function GameCard({
26651
27055
  className
26652
27056
  ),
26653
27057
  children: [
27058
+ frameAsset?.url && /* @__PURE__ */ jsx(AtlasImage, { asset: frameAsset, fill: true, fit: "fill", "aria-hidden": true, style: { zIndex: -1 } }),
26654
27059
  cost != null && /* @__PURE__ */ jsx(
26655
27060
  Typography,
26656
27061
  {
@@ -26689,6 +27094,7 @@ var init_GameCard = __esm({
26689
27094
  init_Box();
26690
27095
  init_Button();
26691
27096
  init_Typography();
27097
+ init_AtlasImage();
26692
27098
  init_GameIcon();
26693
27099
  cardSizeMap = {
26694
27100
  sm: "w-16 h-24",
@@ -26706,7 +27112,7 @@ var init_GameCard = __esm({
26706
27112
  }
26707
27113
  });
26708
27114
  function ScoreDisplay({
26709
- assetUrl = DEFAULT_ASSET_URL5,
27115
+ assetUrl,
26710
27116
  value,
26711
27117
  score,
26712
27118
  label,
@@ -26733,7 +27139,7 @@ function ScoreDisplay({
26733
27139
  }
26734
27140
  );
26735
27141
  }
26736
- var sizeMap8, DEFAULT_ASSET_URL5;
27142
+ var sizeMap8;
26737
27143
  var init_ScoreDisplay = __esm({
26738
27144
  "components/game/2d/atoms/ScoreDisplay.tsx"() {
26739
27145
  init_cn();
@@ -26747,11 +27153,6 @@ var init_ScoreDisplay = __esm({
26747
27153
  lg: "text-2xl",
26748
27154
  xl: "text-4xl"
26749
27155
  };
26750
- DEFAULT_ASSET_URL5 = {
26751
- url: "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png",
26752
- role: "effect",
26753
- category: "effect"
26754
- };
26755
27156
  ScoreDisplay.displayName = "ScoreDisplay";
26756
27157
  }
26757
27158
  });
@@ -26875,7 +27276,7 @@ function isKnownState(s) {
26875
27276
  return s in DEFAULT_STATE_STYLES;
26876
27277
  }
26877
27278
  function StateIndicator({
26878
- assetUrl = DEFAULT_ASSET_URL6,
27279
+ assetUrl = DEFAULT_ASSET_URL5,
26879
27280
  state = "idle",
26880
27281
  label,
26881
27282
  size = "md",
@@ -26905,14 +27306,14 @@ function StateIndicator({
26905
27306
  }
26906
27307
  );
26907
27308
  }
26908
- var DEFAULT_ASSET_URL6, DEFAULT_STATE_STYLES, DEFAULT_STYLE, STATIC_STATES, SIZE_CLASSES;
27309
+ var DEFAULT_ASSET_URL5, DEFAULT_STATE_STYLES, DEFAULT_STYLE, STATIC_STATES, SIZE_CLASSES;
26909
27310
  var init_StateIndicator = __esm({
26910
27311
  "components/game/2d/atoms/StateIndicator.tsx"() {
26911
27312
  init_Box();
26912
27313
  init_Icon();
26913
27314
  init_cn();
26914
27315
  init_GameIcon();
26915
- DEFAULT_ASSET_URL6 = {
27316
+ DEFAULT_ASSET_URL5 = {
26916
27317
  url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
26917
27318
  role: "ui",
26918
27319
  category: "state"
@@ -26998,7 +27399,7 @@ var init_TimerDisplay = __esm({
26998
27399
  }
26999
27400
  });
27000
27401
  function ResourceCounter({
27001
- assetUrl = DEFAULT_ASSET_URL7,
27402
+ assetUrl = DEFAULT_ASSET_URL6,
27002
27403
  icon,
27003
27404
  label = "Gold",
27004
27405
  value = 250,
@@ -27031,7 +27432,7 @@ function ResourceCounter({
27031
27432
  }
27032
27433
  );
27033
27434
  }
27034
- var colorTokenClasses2, DEFAULT_ASSET_URL7, sizeMap10;
27435
+ var colorTokenClasses2, DEFAULT_ASSET_URL6, sizeMap10;
27035
27436
  var init_ResourceCounter = __esm({
27036
27437
  "components/game/2d/atoms/ResourceCounter.tsx"() {
27037
27438
  init_cn();
@@ -27047,7 +27448,7 @@ var init_ResourceCounter = __esm({
27047
27448
  error: "text-error",
27048
27449
  muted: "text-muted-foreground"
27049
27450
  };
27050
- DEFAULT_ASSET_URL7 = {
27451
+ DEFAULT_ASSET_URL6 = {
27051
27452
  url: "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png",
27052
27453
  role: "ui",
27053
27454
  category: "coin"
@@ -27061,7 +27462,7 @@ var init_ResourceCounter = __esm({
27061
27462
  }
27062
27463
  });
27063
27464
  function ItemSlot({
27064
- assetUrl = DEFAULT_ASSET_URL8,
27465
+ assetUrl = DEFAULT_ASSET_URL7,
27065
27466
  icon = "sword",
27066
27467
  label = "Iron Sword",
27067
27468
  quantity,
@@ -27116,7 +27517,7 @@ function ItemSlot({
27116
27517
  }
27117
27518
  );
27118
27519
  }
27119
- var sizeMap11, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL8, assetSizeMap;
27520
+ var sizeMap11, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL7, assetSizeMap;
27120
27521
  var init_ItemSlot = __esm({
27121
27522
  "components/game/2d/atoms/ItemSlot.tsx"() {
27122
27523
  "use client";
@@ -27146,7 +27547,7 @@ var init_ItemSlot = __esm({
27146
27547
  epic: "shadow-lg",
27147
27548
  legendary: "shadow-lg"
27148
27549
  };
27149
- DEFAULT_ASSET_URL8 = {
27550
+ DEFAULT_ASSET_URL7 = {
27150
27551
  url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
27151
27552
  role: "item",
27152
27553
  category: "item"
@@ -27160,7 +27561,7 @@ var init_ItemSlot = __esm({
27160
27561
  }
27161
27562
  });
27162
27563
  function TurnIndicator({
27163
- assetUrl = DEFAULT_ASSET_URL9,
27564
+ assetUrl = DEFAULT_ASSET_URL8,
27164
27565
  currentTurn = 1,
27165
27566
  maxTurns,
27166
27567
  activeTeam,
@@ -27200,7 +27601,7 @@ function TurnIndicator({
27200
27601
  }
27201
27602
  );
27202
27603
  }
27203
- var sizeMap12, DEFAULT_ASSET_URL9;
27604
+ var sizeMap12, DEFAULT_ASSET_URL8;
27204
27605
  var init_TurnIndicator = __esm({
27205
27606
  "components/game/2d/atoms/TurnIndicator.tsx"() {
27206
27607
  init_cn();
@@ -27212,7 +27613,7 @@ var init_TurnIndicator = __esm({
27212
27613
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
27213
27614
  lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
27214
27615
  };
27215
- DEFAULT_ASSET_URL9 = {
27616
+ DEFAULT_ASSET_URL8 = {
27216
27617
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png",
27217
27618
  role: "ui",
27218
27619
  category: "turn"
@@ -27221,7 +27622,7 @@ var init_TurnIndicator = __esm({
27221
27622
  }
27222
27623
  });
27223
27624
  function WaypointMarker({
27224
- assetUrl = DEFAULT_ASSET_URL10,
27625
+ assetUrl = DEFAULT_ASSET_URL9,
27225
27626
  label,
27226
27627
  icon,
27227
27628
  active = true,
@@ -27281,7 +27682,7 @@ function WaypointMarker({
27281
27682
  )
27282
27683
  ] });
27283
27684
  }
27284
- var DEFAULT_ASSET_URL10, sizeMap13, checkIcon;
27685
+ var DEFAULT_ASSET_URL9, sizeMap13, checkIcon;
27285
27686
  var init_WaypointMarker = __esm({
27286
27687
  "components/game/2d/atoms/WaypointMarker.tsx"() {
27287
27688
  init_cn();
@@ -27289,7 +27690,7 @@ var init_WaypointMarker = __esm({
27289
27690
  init_Box();
27290
27691
  init_Typography();
27291
27692
  init_GameIcon();
27292
- DEFAULT_ASSET_URL10 = {
27693
+ DEFAULT_ASSET_URL9 = {
27293
27694
  url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
27294
27695
  role: "ui",
27295
27696
  category: "waypoint"
@@ -27310,7 +27711,7 @@ function formatDuration(seconds) {
27310
27711
  return `${Math.round(seconds)}s`;
27311
27712
  }
27312
27713
  function StatusEffect({
27313
- assetUrl = DEFAULT_ASSET_URL11,
27714
+ assetUrl = DEFAULT_ASSET_URL10,
27314
27715
  icon,
27315
27716
  label = "Shield",
27316
27717
  duration = 30,
@@ -27361,7 +27762,7 @@ function StatusEffect({
27361
27762
  label && /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
27362
27763
  ] });
27363
27764
  }
27364
- var DEFAULT_ASSET_URL11, sizeMap14, variantStyles8;
27765
+ var DEFAULT_ASSET_URL10, sizeMap14, variantStyles8;
27365
27766
  var init_StatusEffect = __esm({
27366
27767
  "components/game/2d/atoms/StatusEffect.tsx"() {
27367
27768
  init_cn();
@@ -27369,7 +27770,7 @@ var init_StatusEffect = __esm({
27369
27770
  init_Box();
27370
27771
  init_Typography();
27371
27772
  init_GameIcon();
27372
- DEFAULT_ASSET_URL11 = {
27773
+ DEFAULT_ASSET_URL10 = {
27373
27774
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
27374
27775
  role: "ui",
27375
27776
  category: "effect"
@@ -27533,7 +27934,7 @@ function InventoryGrid({
27533
27934
  const eventBus = useEventBus();
27534
27935
  const slotCount = totalSlots ?? items.length;
27535
27936
  const emptySlotCount = Math.max(0, slotCount - items.length);
27536
- const handleSelect = React74.useCallback(
27937
+ const handleSelect = React75.useCallback(
27537
27938
  (id) => {
27538
27939
  onSelect?.(id);
27539
27940
  if (selectEvent) {
@@ -27750,7 +28151,7 @@ function GameMenu({
27750
28151
  }) {
27751
28152
  const resolvedOptions = options ?? menuItems ?? DEFAULT_MENU_OPTIONS;
27752
28153
  const eventBus = useEventBus();
27753
- const handleOptionClick = React74.useCallback(
28154
+ const handleOptionClick = React75.useCallback(
27754
28155
  (option) => {
27755
28156
  if (option.event) {
27756
28157
  eventBus.emit(`UI:${option.event}`, { option });
@@ -27976,7 +28377,7 @@ function StateGraph({
27976
28377
  }) {
27977
28378
  const eventBus = useEventBus();
27978
28379
  const nodes = states ?? [];
27979
- const positions = React74.useMemo(() => layoutStates(nodes, width, height), [nodes, width, height]);
28380
+ const positions = React75.useMemo(() => layoutStates(nodes, width, height), [nodes, width, height]);
27980
28381
  return /* @__PURE__ */ jsxs(
27981
28382
  Box,
27982
28383
  {
@@ -28412,7 +28813,7 @@ function LinearView({
28412
28813
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
28413
28814
  const isDone = i < currentIdx;
28414
28815
  const isCurrent = i === currentIdx;
28415
- return /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
28816
+ return /* @__PURE__ */ jsxs(React75__default.Fragment, { children: [
28416
28817
  i > 0 && /* @__PURE__ */ jsx(
28417
28818
  Typography,
28418
28819
  {
@@ -29045,7 +29446,7 @@ function SequenceBar({
29045
29446
  else onSlotRemove?.(index);
29046
29447
  }, [emit, slotRemoveEvent, onSlotRemove, playing]);
29047
29448
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
29048
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
29449
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React75__default.Fragment, { children: [
29049
29450
  i > 0 && /* @__PURE__ */ jsx(
29050
29451
  Typography,
29051
29452
  {
@@ -30931,82 +31332,167 @@ var init_GameTemplate = __esm({
30931
31332
  GameTemplate.displayName = "GameTemplate";
30932
31333
  }
30933
31334
  });
30934
- var GameShell;
31335
+ var FONT_BASE, GAME_FONTS, FONT_FACES, GameShell;
30935
31336
  var init_GameShell = __esm({
30936
31337
  "components/game/2d/templates/GameShell.tsx"() {
30937
31338
  init_cn();
30938
31339
  init_Box();
30939
- init_Stack();
30940
31340
  init_Typography();
31341
+ init_AtlasImage();
31342
+ FONT_BASE = "https://almadar-kflow-assets.web.app/shared/_shared/kenney-fonts/fonts";
31343
+ GAME_FONTS = {
31344
+ future: "Kenney Future",
31345
+ "future-narrow": "Kenney Future Narrow",
31346
+ pixel: "Kenney Pixel",
31347
+ blocks: "Kenney Blocks",
31348
+ mini: "Kenney Mini"
31349
+ };
31350
+ FONT_FACES = `
31351
+ @font-face { font-family: 'Kenney Future'; src: url('${FONT_BASE}/Kenney%20Future.ttf') format('truetype'); font-display: swap; }
31352
+ @font-face { font-family: 'Kenney Future Narrow'; src: url('${FONT_BASE}/Kenney%20Future%20Narrow.ttf') format('truetype'); font-display: swap; }
31353
+ @font-face { font-family: 'Kenney Pixel'; src: url('${FONT_BASE}/Kenney%20Pixel.ttf') format('truetype'); font-display: swap; }
31354
+ @font-face { font-family: 'Kenney Blocks'; src: url('${FONT_BASE}/Kenney%20Blocks.ttf') format('truetype'); font-display: swap; }
31355
+ @font-face { font-family: 'Kenney Mini'; src: url('${FONT_BASE}/Kenney%20Mini.ttf') format('truetype'); font-display: swap; }
31356
+ .game-shell, .game-shell * { font-family: inherit; }
31357
+ `;
30941
31358
  GameShell = ({
30942
31359
  appName = "Game",
30943
31360
  hud,
31361
+ addons,
31362
+ controls,
31363
+ overlay,
30944
31364
  className,
30945
31365
  showTopBar = true,
30946
31366
  children,
30947
31367
  backgroundAsset,
30948
- hudBackgroundAsset
31368
+ hudBackgroundAsset,
31369
+ fontFamily = "future"
30949
31370
  }) => {
31371
+ const font = GAME_FONTS[fontFamily] ?? fontFamily;
30950
31372
  return /* @__PURE__ */ jsxs(
30951
31373
  Box,
30952
31374
  {
30953
- display: "flex",
30954
- className: cn(
30955
- "game-shell",
30956
- "flex-col w-full h-screen overflow-hidden",
30957
- className
30958
- ),
31375
+ className: cn("game-shell", className),
30959
31376
  style: {
31377
+ position: "relative",
30960
31378
  width: "100vw",
30961
31379
  height: "100vh",
30962
31380
  overflow: "hidden",
30963
- background: backgroundAsset ? `url(${backgroundAsset.url}) center/cover no-repeat` : "var(--color-background, #0a0a0f)",
30964
- color: "var(--color-text, #e0e0e0)"
31381
+ background: "var(--color-background, #0a0a0f)",
31382
+ color: "var(--color-text, #e0e0e0)",
31383
+ fontFamily: `'${font}', system-ui, sans-serif`
30965
31384
  },
30966
31385
  children: [
30967
- showTopBar && /* @__PURE__ */ jsxs(
31386
+ /* @__PURE__ */ jsx("style", { children: FONT_FACES }),
31387
+ backgroundAsset && /* @__PURE__ */ jsx(
31388
+ AtlasPanel,
31389
+ {
31390
+ asset: backgroundAsset,
31391
+ mode: "repeat",
31392
+ "aria-hidden": true,
31393
+ className: "game-shell__bg",
31394
+ style: { position: "absolute", inset: 0, opacity: 0.18, zIndex: 0, display: "block" }
31395
+ }
31396
+ ),
31397
+ /* @__PURE__ */ jsx(Box, { className: "game-shell__content", style: { position: "absolute", inset: 0, zIndex: 1 }, children }),
31398
+ (showTopBar || hud) && /* @__PURE__ */ jsxs(
30968
31399
  Box,
30969
31400
  {
30970
- className: "game-shell__header",
31401
+ className: "game-shell__top pointer-events-none",
30971
31402
  style: {
30972
- flexShrink: 0,
30973
- background: hudBackgroundAsset ? `url(${hudBackgroundAsset.url}) center/cover no-repeat` : "var(--color-surface, #12121f)",
30974
- borderBottom: "1px solid var(--color-border, #2a2a3a)"
31403
+ position: "absolute",
31404
+ top: 12,
31405
+ left: 12,
31406
+ right: 12,
31407
+ zIndex: 2,
31408
+ display: "flex",
31409
+ alignItems: "flex-start",
31410
+ gap: 12
30975
31411
  },
30976
31412
  children: [
30977
- /* @__PURE__ */ jsx(
30978
- HStack,
31413
+ showTopBar && /* @__PURE__ */ jsx(
31414
+ AtlasPanel,
30979
31415
  {
30980
- align: "center",
30981
- justify: "between",
30982
- style: { padding: "0.375rem 1rem" },
31416
+ asset: hudBackgroundAsset,
31417
+ borderSlice: 12,
31418
+ borderWidth: 10,
31419
+ className: "game-shell__title pointer-events-auto",
31420
+ style: {
31421
+ padding: "6px 16px",
31422
+ background: hudBackgroundAsset ? void 0 : "rgba(18, 18, 31, 0.85)",
31423
+ borderRadius: hudBackgroundAsset ? void 0 : 10,
31424
+ boxShadow: "0 4px 14px rgba(0,0,0,0.45)",
31425
+ flexShrink: 0
31426
+ },
30983
31427
  children: /* @__PURE__ */ jsx(
30984
31428
  Typography,
30985
31429
  {
30986
- variant: "h6",
31430
+ as: "span",
30987
31431
  style: {
30988
31432
  fontWeight: 700,
30989
- letterSpacing: "0.02em"
31433
+ fontSize: "1.05rem",
31434
+ letterSpacing: "0.06em",
31435
+ textShadow: "0 2px 0 rgba(0,0,0,0.5)",
31436
+ whiteSpace: "nowrap"
30990
31437
  },
30991
31438
  children: appName
30992
31439
  }
30993
31440
  )
30994
31441
  }
30995
31442
  ),
30996
- hud && /* @__PURE__ */ jsx(Box, { className: "game-shell__hud", style: { width: "100%" }, children: hud })
31443
+ hud && /* @__PURE__ */ jsx(Box, { className: "game-shell__hud pointer-events-auto", style: { flex: 1, minWidth: 0 }, children: hud })
30997
31444
  ]
30998
31445
  }
30999
31446
  ),
31000
- /* @__PURE__ */ jsx(
31447
+ controls && /* @__PURE__ */ jsx(
31001
31448
  Box,
31002
31449
  {
31003
- className: "game-shell__content",
31450
+ className: "game-shell__controls pointer-events-auto",
31004
31451
  style: {
31005
- flex: 1,
31006
- overflow: "hidden",
31007
- position: "relative"
31452
+ position: "absolute",
31453
+ left: 16,
31454
+ bottom: 16,
31455
+ zIndex: 2,
31456
+ display: "flex",
31457
+ flexDirection: "column",
31458
+ alignItems: "flex-start",
31459
+ gap: 10,
31460
+ filter: "drop-shadow(0 6px 12px rgba(0,0,0,0.5))"
31008
31461
  },
31009
- children
31462
+ children: controls
31463
+ }
31464
+ ),
31465
+ addons && /* @__PURE__ */ jsx(
31466
+ Box,
31467
+ {
31468
+ className: "game-shell__actions pointer-events-auto",
31469
+ style: {
31470
+ position: "absolute",
31471
+ right: 16,
31472
+ bottom: 16,
31473
+ zIndex: 2,
31474
+ display: "flex",
31475
+ flexDirection: "column",
31476
+ alignItems: "flex-end",
31477
+ gap: 10,
31478
+ filter: "drop-shadow(0 6px 12px rgba(0,0,0,0.5))"
31479
+ },
31480
+ children: addons
31481
+ }
31482
+ ),
31483
+ overlay && /* @__PURE__ */ jsx(
31484
+ Box,
31485
+ {
31486
+ className: "game-shell__overlay pointer-events-none",
31487
+ style: {
31488
+ position: "absolute",
31489
+ inset: 0,
31490
+ zIndex: 3,
31491
+ display: "flex",
31492
+ alignItems: "center",
31493
+ justifyContent: "center"
31494
+ },
31495
+ children: /* @__PURE__ */ jsx(Box, { className: "pointer-events-auto", children: overlay })
31010
31496
  }
31011
31497
  )
31012
31498
  ]
@@ -31679,13 +32165,13 @@ var init_MapView = __esm({
31679
32165
  shadowSize: [41, 41]
31680
32166
  });
31681
32167
  L.Marker.prototype.options.icon = defaultIcon;
31682
- const { useEffect: useEffect69, useRef: useRef64, useCallback: useCallback113, useState: useState108 } = React74__default;
32168
+ const { useEffect: useEffect70, useRef: useRef65, useCallback: useCallback113, useState: useState108 } = React75__default;
31683
32169
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
31684
32170
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
31685
32171
  function MapUpdater({ centerLat, centerLng, zoom }) {
31686
32172
  const map = useMap();
31687
- const prevRef = useRef64({ centerLat, centerLng, zoom });
31688
- useEffect69(() => {
32173
+ const prevRef = useRef65({ centerLat, centerLng, zoom });
32174
+ useEffect70(() => {
31689
32175
  const prev = prevRef.current;
31690
32176
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
31691
32177
  map.setView([centerLat, centerLng], zoom);
@@ -31696,7 +32182,7 @@ var init_MapView = __esm({
31696
32182
  }
31697
32183
  function MapClickHandler({ onMapClick }) {
31698
32184
  const map = useMap();
31699
- useEffect69(() => {
32185
+ useEffect70(() => {
31700
32186
  if (!onMapClick) return;
31701
32187
  const handler = (e) => {
31702
32188
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -32594,8 +33080,8 @@ function TableView({
32594
33080
  }) {
32595
33081
  const eventBus = useEventBus();
32596
33082
  const { t } = useTranslate();
32597
- const [visibleCount, setVisibleCount] = React74__default.useState(pageSize > 0 ? pageSize : Infinity);
32598
- const [localSelected, setLocalSelected] = React74__default.useState(/* @__PURE__ */ new Set());
33083
+ const [visibleCount, setVisibleCount] = React75__default.useState(pageSize > 0 ? pageSize : Infinity);
33084
+ const [localSelected, setLocalSelected] = React75__default.useState(/* @__PURE__ */ new Set());
32599
33085
  const colDefs = columns ?? fields ?? [];
32600
33086
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
32601
33087
  const dnd = useDataDnd({
@@ -32790,12 +33276,12 @@ function TableView({
32790
33276
  ]
32791
33277
  }
32792
33278
  );
32793
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React74__default.Fragment, { children: rowInner }, id);
33279
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React75__default.Fragment, { children: rowInner }, id);
32794
33280
  };
32795
33281
  const items = Array.from(data);
32796
33282
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
32797
33283
  let runningIndex = 0;
32798
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
33284
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React75__default.Fragment, { children: [
32799
33285
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
32800
33286
  group.items.map((row) => renderRow(row, runningIndex++))
32801
33287
  ] }, gi)) });
@@ -34152,7 +34638,7 @@ var init_StepFlow = __esm({
34152
34638
  className
34153
34639
  }) => {
34154
34640
  if (orientation === "vertical") {
34155
- return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React74__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
34641
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React75__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
34156
34642
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
34157
34643
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
34158
34644
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -34163,7 +34649,7 @@ var init_StepFlow = __esm({
34163
34649
  ] })
34164
34650
  ] }) }, index)) });
34165
34651
  }
34166
- return /* @__PURE__ */ jsx(Box, { className: cn("w-full flex flex-col md:flex-row items-start gap-0", className), children: steps.map((step, index) => /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
34652
+ return /* @__PURE__ */ jsx(Box, { className: cn("w-full flex flex-col md:flex-row items-start gap-0", className), children: steps.map((step, index) => /* @__PURE__ */ jsxs(React75__default.Fragment, { children: [
34167
34653
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
34168
34654
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
34169
34655
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -35148,7 +35634,7 @@ var init_LikertScale = __esm({
35148
35634
  md: "text-base",
35149
35635
  lg: "text-lg"
35150
35636
  };
35151
- LikertScale = React74__default.forwardRef(
35637
+ LikertScale = React75__default.forwardRef(
35152
35638
  ({
35153
35639
  question,
35154
35640
  options = DEFAULT_LIKERT_OPTIONS,
@@ -35160,7 +35646,7 @@ var init_LikertScale = __esm({
35160
35646
  variant = "radios",
35161
35647
  className
35162
35648
  }, ref) => {
35163
- const groupId = React74__default.useId();
35649
+ const groupId = React75__default.useId();
35164
35650
  const eventBus = useEventBus();
35165
35651
  const handleSelect = useCallback(
35166
35652
  (next) => {
@@ -37442,7 +37928,7 @@ var init_DocBreadcrumb = __esm({
37442
37928
  "aria-label": t("aria.breadcrumb"),
37443
37929
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
37444
37930
  const isLast = idx === items.length - 1;
37445
- return /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
37931
+ return /* @__PURE__ */ jsxs(React75__default.Fragment, { children: [
37446
37932
  idx > 0 && /* @__PURE__ */ jsx(
37447
37933
  Icon,
37448
37934
  {
@@ -38311,7 +38797,7 @@ var init_MiniStateMachine = __esm({
38311
38797
  const x = 2 + i * (NODE_W + GAP2 + ARROW_W + GAP2);
38312
38798
  const tc = transitionCounts[s.name] ?? 0;
38313
38799
  const role = getStateRole(s.name, s.isInitial ?? void 0, s.isTerminal ?? void 0, tc, maxTC);
38314
- return /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
38800
+ return /* @__PURE__ */ jsxs(React75__default.Fragment, { children: [
38315
38801
  /* @__PURE__ */ jsx(
38316
38802
  AvlState,
38317
38803
  {
@@ -38515,7 +39001,7 @@ var init_PageHeader = __esm({
38515
39001
  info: "bg-info/10 text-info"
38516
39002
  };
38517
39003
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
38518
- breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
39004
+ breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React75__default.Fragment, { children: [
38519
39005
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
38520
39006
  crumb.href ? /* @__PURE__ */ jsx(
38521
39007
  "a",
@@ -38873,7 +39359,7 @@ var init_Section = __esm({
38873
39359
  as: Component = "section"
38874
39360
  }) => {
38875
39361
  const hasHeader = title || description || action;
38876
- return React74__default.createElement(
39362
+ return React75__default.createElement(
38877
39363
  Component,
38878
39364
  {
38879
39365
  className: cn(
@@ -39247,7 +39733,7 @@ var init_WizardContainer = __esm({
39247
39733
  const isCompleted = index < currentStep;
39248
39734
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
39249
39735
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
39250
- return /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
39736
+ return /* @__PURE__ */ jsxs(React75__default.Fragment, { children: [
39251
39737
  /* @__PURE__ */ jsx(
39252
39738
  Button,
39253
39739
  {
@@ -40883,6 +41369,7 @@ var init_molecules2 = __esm({
40883
41369
  init_PhysicsCanvas();
40884
41370
  init_BiologyCanvas();
40885
41371
  init_ChemistryCanvas();
41372
+ init_AlgorithmCanvas();
40886
41373
  init_GraphView();
40887
41374
  init_MapView();
40888
41375
  init_NumberStepper();
@@ -41896,7 +42383,7 @@ var init_DetailPanel = __esm({
41896
42383
  }
41897
42384
  });
41898
42385
  function extractTitle(children) {
41899
- if (!React74__default.isValidElement(children)) return void 0;
42386
+ if (!React75__default.isValidElement(children)) return void 0;
41900
42387
  const props = children.props;
41901
42388
  if (typeof props.title === "string") {
41902
42389
  return props.title;
@@ -42246,12 +42733,12 @@ var init_Form = __esm({
42246
42733
  const isSchemaEntity = isOrbitalEntitySchema(entity);
42247
42734
  const resolvedEntity = isSchemaEntity ? entity : void 0;
42248
42735
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
42249
- const normalizedInitialData = React74__default.useMemo(() => {
42736
+ const normalizedInitialData = React75__default.useMemo(() => {
42250
42737
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
42251
42738
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
42252
42739
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
42253
42740
  }, [entity, initialData]);
42254
- const entityDerivedFields = React74__default.useMemo(() => {
42741
+ const entityDerivedFields = React75__default.useMemo(() => {
42255
42742
  if (fields && fields.length > 0) return void 0;
42256
42743
  if (!resolvedEntity) return void 0;
42257
42744
  return resolvedEntity.fields.map(
@@ -42272,16 +42759,16 @@ var init_Form = __esm({
42272
42759
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
42273
42760
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
42274
42761
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
42275
- const [formData, setFormData] = React74__default.useState(
42762
+ const [formData, setFormData] = React75__default.useState(
42276
42763
  normalizedInitialData
42277
42764
  );
42278
- const [collapsedSections, setCollapsedSections] = React74__default.useState(
42765
+ const [collapsedSections, setCollapsedSections] = React75__default.useState(
42279
42766
  /* @__PURE__ */ new Set()
42280
42767
  );
42281
- const [submitError, setSubmitError] = React74__default.useState(null);
42282
- const formRef = React74__default.useRef(null);
42768
+ const [submitError, setSubmitError] = React75__default.useState(null);
42769
+ const formRef = React75__default.useRef(null);
42283
42770
  const formMode = props.mode;
42284
- const mountedRef = React74__default.useRef(false);
42771
+ const mountedRef = React75__default.useRef(false);
42285
42772
  if (!mountedRef.current) {
42286
42773
  mountedRef.current = true;
42287
42774
  debug("forms", "mount", {
@@ -42294,7 +42781,7 @@ var init_Form = __esm({
42294
42781
  });
42295
42782
  }
42296
42783
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
42297
- const evalContext = React74__default.useMemo(
42784
+ const evalContext = React75__default.useMemo(
42298
42785
  () => ({
42299
42786
  formValues: formData,
42300
42787
  globalVariables: externalContext?.globalVariables ?? {},
@@ -42303,7 +42790,7 @@ var init_Form = __esm({
42303
42790
  }),
42304
42791
  [formData, externalContext]
42305
42792
  );
42306
- React74__default.useEffect(() => {
42793
+ React75__default.useEffect(() => {
42307
42794
  debug("forms", "initialData-sync", {
42308
42795
  mode: formMode,
42309
42796
  normalizedInitialData,
@@ -42314,7 +42801,7 @@ var init_Form = __esm({
42314
42801
  setFormData(normalizedInitialData);
42315
42802
  }
42316
42803
  }, [normalizedInitialData]);
42317
- const processCalculations = React74__default.useCallback(
42804
+ const processCalculations = React75__default.useCallback(
42318
42805
  (changedFieldId, newFormData) => {
42319
42806
  if (!hiddenCalculations.length) return;
42320
42807
  const context = {
@@ -42339,7 +42826,7 @@ var init_Form = __esm({
42339
42826
  },
42340
42827
  [hiddenCalculations, externalContext, eventBus]
42341
42828
  );
42342
- const checkViolations = React74__default.useCallback(
42829
+ const checkViolations = React75__default.useCallback(
42343
42830
  (changedFieldId, newFormData) => {
42344
42831
  if (!violationTriggers.length) return;
42345
42832
  const context = {
@@ -42377,7 +42864,7 @@ var init_Form = __esm({
42377
42864
  processCalculations(name, newFormData);
42378
42865
  checkViolations(name, newFormData);
42379
42866
  };
42380
- const isFieldVisible = React74__default.useCallback(
42867
+ const isFieldVisible = React75__default.useCallback(
42381
42868
  (fieldName) => {
42382
42869
  const condition = conditionalFields[fieldName];
42383
42870
  if (!condition) return true;
@@ -42385,7 +42872,7 @@ var init_Form = __esm({
42385
42872
  },
42386
42873
  [conditionalFields, evalContext]
42387
42874
  );
42388
- const isSectionVisible = React74__default.useCallback(
42875
+ const isSectionVisible = React75__default.useCallback(
42389
42876
  (section) => {
42390
42877
  if (!section.condition) return true;
42391
42878
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -42461,7 +42948,7 @@ var init_Form = __esm({
42461
42948
  eventBus.emit(`UI:${onCancel}`);
42462
42949
  }
42463
42950
  };
42464
- const renderField = React74__default.useCallback(
42951
+ const renderField = React75__default.useCallback(
42465
42952
  (field) => {
42466
42953
  const fieldName = field.name || field.field;
42467
42954
  if (!fieldName) return null;
@@ -42482,7 +42969,7 @@ var init_Form = __esm({
42482
42969
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
42483
42970
  );
42484
42971
  const effectiveFields = entityDerivedFields ?? fields;
42485
- const normalizedFields = React74__default.useMemo(() => {
42972
+ const normalizedFields = React75__default.useMemo(() => {
42486
42973
  if (!effectiveFields || effectiveFields.length === 0) return [];
42487
42974
  return effectiveFields.map((field) => {
42488
42975
  if (typeof field === "string") {
@@ -42506,7 +42993,7 @@ var init_Form = __esm({
42506
42993
  return field;
42507
42994
  });
42508
42995
  }, [effectiveFields, resolvedEntity]);
42509
- const schemaFields = React74__default.useMemo(() => {
42996
+ const schemaFields = React75__default.useMemo(() => {
42510
42997
  if (normalizedFields.length === 0) return null;
42511
42998
  if (isDebugEnabled()) {
42512
42999
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -42516,7 +43003,7 @@ var init_Form = __esm({
42516
43003
  }
42517
43004
  return normalizedFields.map(renderField).filter(Boolean);
42518
43005
  }, [normalizedFields, renderField, entityName, conditionalFields]);
42519
- const sectionElements = React74__default.useMemo(() => {
43006
+ const sectionElements = React75__default.useMemo(() => {
42520
43007
  if (!sections || sections.length === 0) return null;
42521
43008
  return sections.map((section) => {
42522
43009
  if (!isSectionVisible(section)) {
@@ -43241,7 +43728,7 @@ var init_List = __esm({
43241
43728
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
43242
43729
  return [];
43243
43730
  }, [entity]);
43244
- const getItemActions = React74__default.useCallback(
43731
+ const getItemActions = React75__default.useCallback(
43245
43732
  (item) => {
43246
43733
  if (!itemActions) return [];
43247
43734
  if (typeof itemActions === "function") {
@@ -43716,7 +44203,7 @@ var init_MediaGallery = __esm({
43716
44203
  [selectable, selectedItems, selectionEvent, eventBus]
43717
44204
  );
43718
44205
  const entityData = Array.isArray(entity) ? entity : [];
43719
- const items = React74__default.useMemo(() => {
44206
+ const items = React75__default.useMemo(() => {
43720
44207
  if (propItems) return propItems;
43721
44208
  if (entityData.length === 0) return [];
43722
44209
  return entityData.map((record, idx) => {
@@ -43879,7 +44366,7 @@ var init_MediaGallery = __esm({
43879
44366
  }
43880
44367
  });
43881
44368
  function extractTitle2(children) {
43882
- if (!React74__default.isValidElement(children)) return void 0;
44369
+ if (!React75__default.isValidElement(children)) return void 0;
43883
44370
  const props = children.props;
43884
44371
  if (typeof props.title === "string") {
43885
44372
  return props.title;
@@ -44134,7 +44621,7 @@ var init_debugRegistry = __esm({
44134
44621
  }
44135
44622
  });
44136
44623
  function useDebugData() {
44137
- const [data, setData] = React74.useState(() => ({
44624
+ const [data, setData] = React75.useState(() => ({
44138
44625
  traits: [],
44139
44626
  ticks: [],
44140
44627
  guards: [],
@@ -44148,7 +44635,7 @@ function useDebugData() {
44148
44635
  },
44149
44636
  lastUpdate: Date.now()
44150
44637
  }));
44151
- React74.useEffect(() => {
44638
+ React75.useEffect(() => {
44152
44639
  const updateData = () => {
44153
44640
  setData({
44154
44641
  traits: getAllTraits(),
@@ -44257,12 +44744,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
44257
44744
  return positions;
44258
44745
  }
44259
44746
  function WalkMinimap() {
44260
- const [walkStep, setWalkStep] = React74.useState(null);
44261
- const [traits2, setTraits] = React74.useState([]);
44262
- const [coveredEdges, setCoveredEdges] = React74.useState([]);
44263
- const [completedTraits, setCompletedTraits] = React74.useState(/* @__PURE__ */ new Set());
44264
- const prevTraitRef = React74.useRef(null);
44265
- React74.useEffect(() => {
44747
+ const [walkStep, setWalkStep] = React75.useState(null);
44748
+ const [traits2, setTraits] = React75.useState([]);
44749
+ const [coveredEdges, setCoveredEdges] = React75.useState([]);
44750
+ const [completedTraits, setCompletedTraits] = React75.useState(/* @__PURE__ */ new Set());
44751
+ const prevTraitRef = React75.useRef(null);
44752
+ React75.useEffect(() => {
44266
44753
  const interval = setInterval(() => {
44267
44754
  const w = window;
44268
44755
  const step = w.__orbitalWalkStep;
@@ -44698,15 +45185,15 @@ var init_EntitiesTab = __esm({
44698
45185
  });
44699
45186
  function EventFlowTab({ events: events2 }) {
44700
45187
  const { t } = useTranslate();
44701
- const [filter, setFilter] = React74.useState("all");
44702
- const containerRef = React74.useRef(null);
44703
- const [autoScroll, setAutoScroll] = React74.useState(true);
44704
- React74.useEffect(() => {
45188
+ const [filter, setFilter] = React75.useState("all");
45189
+ const containerRef = React75.useRef(null);
45190
+ const [autoScroll, setAutoScroll] = React75.useState(true);
45191
+ React75.useEffect(() => {
44705
45192
  if (autoScroll && containerRef.current) {
44706
45193
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
44707
45194
  }
44708
45195
  }, [events2.length, autoScroll]);
44709
- const filteredEvents = React74.useMemo(() => {
45196
+ const filteredEvents = React75.useMemo(() => {
44710
45197
  if (filter === "all") return events2;
44711
45198
  return events2.filter((e) => e.type === filter);
44712
45199
  }, [events2, filter]);
@@ -44822,7 +45309,7 @@ var init_EventFlowTab = __esm({
44822
45309
  });
44823
45310
  function GuardsPanel({ guards }) {
44824
45311
  const { t } = useTranslate();
44825
- const [filter, setFilter] = React74.useState("all");
45312
+ const [filter, setFilter] = React75.useState("all");
44826
45313
  if (guards.length === 0) {
44827
45314
  return /* @__PURE__ */ jsx(
44828
45315
  EmptyState,
@@ -44835,7 +45322,7 @@ function GuardsPanel({ guards }) {
44835
45322
  }
44836
45323
  const passedCount = guards.filter((g) => g.result).length;
44837
45324
  const failedCount = guards.length - passedCount;
44838
- const filteredGuards = React74.useMemo(() => {
45325
+ const filteredGuards = React75.useMemo(() => {
44839
45326
  if (filter === "all") return guards;
44840
45327
  if (filter === "passed") return guards.filter((g) => g.result);
44841
45328
  return guards.filter((g) => !g.result);
@@ -44998,10 +45485,10 @@ function EffectBadge({ effect }) {
44998
45485
  }
44999
45486
  function TransitionTimeline({ transitions }) {
45000
45487
  const { t } = useTranslate();
45001
- const containerRef = React74.useRef(null);
45002
- const [autoScroll, setAutoScroll] = React74.useState(true);
45003
- const [expandedId, setExpandedId] = React74.useState(null);
45004
- React74.useEffect(() => {
45488
+ const containerRef = React75.useRef(null);
45489
+ const [autoScroll, setAutoScroll] = React75.useState(true);
45490
+ const [expandedId, setExpandedId] = React75.useState(null);
45491
+ React75.useEffect(() => {
45005
45492
  if (autoScroll && containerRef.current) {
45006
45493
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
45007
45494
  }
@@ -45281,9 +45768,9 @@ function getAllEvents(traits2) {
45281
45768
  function EventDispatcherTab({ traits: traits2, schema }) {
45282
45769
  const eventBus = useEventBus();
45283
45770
  const { t } = useTranslate();
45284
- const [log18, setLog] = React74.useState([]);
45285
- const prevStatesRef = React74.useRef(/* @__PURE__ */ new Map());
45286
- React74.useEffect(() => {
45771
+ const [log18, setLog] = React75.useState([]);
45772
+ const prevStatesRef = React75.useRef(/* @__PURE__ */ new Map());
45773
+ React75.useEffect(() => {
45287
45774
  for (const trait of traits2) {
45288
45775
  const prev = prevStatesRef.current.get(trait.id);
45289
45776
  if (prev && prev !== trait.currentState) {
@@ -45452,10 +45939,10 @@ function VerifyModePanel({
45452
45939
  localCount
45453
45940
  }) {
45454
45941
  const { t } = useTranslate();
45455
- const [expanded, setExpanded] = React74.useState(true);
45456
- const scrollRef = React74.useRef(null);
45457
- const prevCountRef = React74.useRef(0);
45458
- React74.useEffect(() => {
45942
+ const [expanded, setExpanded] = React75.useState(true);
45943
+ const scrollRef = React75.useRef(null);
45944
+ const prevCountRef = React75.useRef(0);
45945
+ React75.useEffect(() => {
45459
45946
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
45460
45947
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
45461
45948
  }
@@ -45512,10 +45999,10 @@ function RuntimeDebugger({
45512
45999
  schema
45513
46000
  }) {
45514
46001
  const { t } = useTranslate();
45515
- const [isCollapsed, setIsCollapsed] = React74.useState(mode === "verify" ? true : defaultCollapsed);
45516
- const [isVisible, setIsVisible] = React74.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
46002
+ const [isCollapsed, setIsCollapsed] = React75.useState(mode === "verify" ? true : defaultCollapsed);
46003
+ const [isVisible, setIsVisible] = React75.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
45517
46004
  const debugData = useDebugData();
45518
- React74.useEffect(() => {
46005
+ React75.useEffect(() => {
45519
46006
  if (mode === "inline") return;
45520
46007
  return onDebugToggle((enabled) => {
45521
46008
  setIsVisible(enabled);
@@ -45524,7 +46011,7 @@ function RuntimeDebugger({
45524
46011
  }
45525
46012
  });
45526
46013
  }, [mode]);
45527
- React74.useEffect(() => {
46014
+ React75.useEffect(() => {
45528
46015
  if (mode === "inline") return;
45529
46016
  const handleKeyDown = (e) => {
45530
46017
  if (e.key === "`" && isVisible) {
@@ -46044,7 +46531,7 @@ var init_StatCard = __esm({
46044
46531
  const labelToUse = propLabel ?? propTitle;
46045
46532
  const eventBus = useEventBus();
46046
46533
  const { t } = useTranslate();
46047
- const handleActionClick = React74__default.useCallback(() => {
46534
+ const handleActionClick = React75__default.useCallback(() => {
46048
46535
  if (action?.event) {
46049
46536
  eventBus.emit(`UI:${action.event}`, {});
46050
46537
  }
@@ -46055,7 +46542,7 @@ var init_StatCard = __esm({
46055
46542
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
46056
46543
  const isLoading = externalLoading ?? false;
46057
46544
  const error = externalError;
46058
- const computeMetricValue = React74__default.useCallback(
46545
+ const computeMetricValue = React75__default.useCallback(
46059
46546
  (metric, items) => {
46060
46547
  if (metric.value !== void 0) {
46061
46548
  return metric.value;
@@ -46094,7 +46581,7 @@ var init_StatCard = __esm({
46094
46581
  },
46095
46582
  []
46096
46583
  );
46097
- const schemaStats = React74__default.useMemo(() => {
46584
+ const schemaStats = React75__default.useMemo(() => {
46098
46585
  if (!metrics || metrics.length === 0) return null;
46099
46586
  return metrics.map((metric) => ({
46100
46587
  label: metric.label,
@@ -46102,7 +46589,7 @@ var init_StatCard = __esm({
46102
46589
  format: metric.format
46103
46590
  }));
46104
46591
  }, [metrics, data, computeMetricValue]);
46105
- const calculatedTrend = React74__default.useMemo(() => {
46592
+ const calculatedTrend = React75__default.useMemo(() => {
46106
46593
  if (manualTrend !== void 0) return manualTrend;
46107
46594
  if (previousValue === void 0 || currentValue2 === void 0)
46108
46595
  return void 0;
@@ -46742,8 +47229,8 @@ var init_SubagentTracePanel = __esm({
46742
47229
  ] });
46743
47230
  };
46744
47231
  InlineActivityStream = ({ activities, autoScroll = true, className }) => {
46745
- const endRef = React74__default.useRef(null);
46746
- React74__default.useEffect(() => {
47232
+ const endRef = React75__default.useRef(null);
47233
+ React75__default.useEffect(() => {
46747
47234
  if (!autoScroll) return;
46748
47235
  endRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
46749
47236
  }, [activities.length, autoScroll]);
@@ -46837,7 +47324,7 @@ var init_SubagentTracePanel = __esm({
46837
47324
  };
46838
47325
  SubagentRichCard = ({ subagent }) => {
46839
47326
  const { t } = useTranslate();
46840
- const activities = React74__default.useMemo(
47327
+ const activities = React75__default.useMemo(
46841
47328
  () => subagentMessagesToActivities(subagent.messages),
46842
47329
  [subagent.messages]
46843
47330
  );
@@ -46914,8 +47401,8 @@ var init_SubagentTracePanel = __esm({
46914
47401
  ] });
46915
47402
  };
46916
47403
  CoordinatorConversation = ({ messages, autoScroll = true, className }) => {
46917
- const endRef = React74__default.useRef(null);
46918
- React74__default.useEffect(() => {
47404
+ const endRef = React75__default.useRef(null);
47405
+ React75__default.useEffect(() => {
46919
47406
  if (!autoScroll) return;
46920
47407
  endRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
46921
47408
  }, [messages.length, autoScroll]);
@@ -47345,7 +47832,7 @@ var init_Timeline = __esm({
47345
47832
  }) => {
47346
47833
  const { t } = useTranslate();
47347
47834
  const entityData = entity ?? [];
47348
- const items = React74__default.useMemo(() => {
47835
+ const items = React75__default.useMemo(() => {
47349
47836
  if (propItems) return propItems;
47350
47837
  if (entityData.length === 0) return [];
47351
47838
  return entityData.map((record, idx) => {
@@ -47447,7 +47934,7 @@ var init_Timeline = __esm({
47447
47934
  }
47448
47935
  });
47449
47936
  function extractToastProps(children) {
47450
- if (!React74__default.isValidElement(children)) {
47937
+ if (!React75__default.isValidElement(children)) {
47451
47938
  if (typeof children === "string") {
47452
47939
  return { message: children };
47453
47940
  }
@@ -47489,7 +47976,7 @@ var init_ToastSlot = __esm({
47489
47976
  eventBus.emit(`${prefix}CLOSE`);
47490
47977
  };
47491
47978
  if (!isVisible) return null;
47492
- const isCustomContent = React74__default.isValidElement(children) && !message;
47979
+ const isCustomContent = React75__default.isValidElement(children) && !message;
47493
47980
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
47494
47981
  Toast,
47495
47982
  {
@@ -47506,7 +47993,7 @@ var init_ToastSlot = __esm({
47506
47993
  }
47507
47994
  });
47508
47995
  function lazyThree(name, loader) {
47509
- const Lazy = React74__default.lazy(
47996
+ const Lazy = React75__default.lazy(
47510
47997
  () => loader().then((m) => {
47511
47998
  const Resolved = m[name];
47512
47999
  if (!Resolved) {
@@ -47518,13 +48005,13 @@ function lazyThree(name, loader) {
47518
48005
  })
47519
48006
  );
47520
48007
  function ThreeWrapper(props) {
47521
- return React74__default.createElement(
48008
+ return React75__default.createElement(
47522
48009
  ThreeBoundary,
47523
48010
  { name },
47524
- React74__default.createElement(
47525
- React74__default.Suspense,
48011
+ React75__default.createElement(
48012
+ React75__default.Suspense,
47526
48013
  { fallback: null },
47527
- React74__default.createElement(Lazy, props)
48014
+ React75__default.createElement(Lazy, props)
47528
48015
  )
47529
48016
  );
47530
48017
  }
@@ -47541,11 +48028,13 @@ var init_component_registry_generated = __esm({
47541
48028
  init_ActionTile();
47542
48029
  init_ActivationBlock();
47543
48030
  init_ComponentPatterns();
48031
+ init_AlgorithmCanvas();
47544
48032
  init_AnimatedCounter();
47545
48033
  init_AnimatedGraphic();
47546
48034
  init_AnimatedReveal();
47547
48035
  init_ArticleSection();
47548
48036
  init_Aside();
48037
+ init_AtlasImage();
47549
48038
  init_AuthLayout();
47550
48039
  init_Avatar();
47551
48040
  init_Badge();
@@ -47803,7 +48292,7 @@ var init_component_registry_generated = __esm({
47803
48292
  init_WizardContainer();
47804
48293
  init_WizardNavigation();
47805
48294
  init_WizardProgress();
47806
- ThreeBoundary = class extends React74__default.Component {
48295
+ ThreeBoundary = class extends React75__default.Component {
47807
48296
  constructor() {
47808
48297
  super(...arguments);
47809
48298
  __publicField(this, "state", { failed: false });
@@ -47813,7 +48302,7 @@ var init_component_registry_generated = __esm({
47813
48302
  }
47814
48303
  render() {
47815
48304
  if (this.state.failed) {
47816
- return React74__default.createElement(
48305
+ return React75__default.createElement(
47817
48306
  "div",
47818
48307
  {
47819
48308
  "data-testid": "three-unavailable",
@@ -47839,11 +48328,14 @@ var init_component_registry_generated = __esm({
47839
48328
  "ActivationBlock": ActivationBlock,
47840
48329
  "Alert": AlertPattern,
47841
48330
  "AlertPattern": AlertPattern,
48331
+ "AlgorithmCanvas": AlgorithmCanvas,
47842
48332
  "AnimatedCounter": AnimatedCounter,
47843
48333
  "AnimatedGraphic": AnimatedGraphic,
47844
48334
  "AnimatedReveal": AnimatedReveal,
47845
48335
  "ArticleSection": ArticleSection,
47846
48336
  "Aside": Aside,
48337
+ "AtlasImage": AtlasImage,
48338
+ "AtlasPanel": AtlasPanel,
47847
48339
  "AuthLayout": AuthLayout,
47848
48340
  "Avatar": Avatar,
47849
48341
  "Badge": Badge,
@@ -48136,7 +48628,7 @@ function SuspenseConfigProvider({
48136
48628
  config,
48137
48629
  children
48138
48630
  }) {
48139
- return React74__default.createElement(
48631
+ return React75__default.createElement(
48140
48632
  SuspenseConfigContext.Provider,
48141
48633
  { value: config },
48142
48634
  children
@@ -48178,7 +48670,7 @@ function enrichFormFields(fields, entityDef) {
48178
48670
  }
48179
48671
  return { name: field, label: field.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\b\w/g, (c) => c.toUpperCase()) };
48180
48672
  }
48181
- if (field && typeof field === "object" && !Array.isArray(field) && !React74__default.isValidElement(field) && !(field instanceof Date)) {
48673
+ if (field && typeof field === "object" && !Array.isArray(field) && !React75__default.isValidElement(field) && !(field instanceof Date)) {
48182
48674
  const obj = field;
48183
48675
  const fieldName = typeof obj.name === "string" ? obj.name : typeof obj.field === "string" ? obj.field : void 0;
48184
48676
  if (!fieldName) return field;
@@ -48631,7 +49123,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
48631
49123
  const key = `${parentId}-${index}-trait:${traitName}`;
48632
49124
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
48633
49125
  }
48634
- return /* @__PURE__ */ jsx(React74__default.Fragment, { children: child }, `${parentId}-${index}`);
49126
+ return /* @__PURE__ */ jsx(React75__default.Fragment, { children: child }, `${parentId}-${index}`);
48635
49127
  }
48636
49128
  if (!child || typeof child !== "object") return null;
48637
49129
  const childId = `${parentId}-${index}`;
@@ -48671,14 +49163,14 @@ function isPatternConfig(value) {
48671
49163
  if (value === null || value === void 0) return false;
48672
49164
  if (typeof value !== "object") return false;
48673
49165
  if (Array.isArray(value)) return false;
48674
- if (React74__default.isValidElement(value)) return false;
49166
+ if (React75__default.isValidElement(value)) return false;
48675
49167
  if (value instanceof Date) return false;
48676
49168
  if (typeof value === "function") return false;
48677
49169
  const record = value;
48678
49170
  return "type" in record && typeof record.type === "string" && getComponentForPattern$1(record.type) !== null;
48679
49171
  }
48680
49172
  function isPlainConfigObject(value) {
48681
- if (React74__default.isValidElement(value)) return false;
49173
+ if (React75__default.isValidElement(value)) return false;
48682
49174
  if (value instanceof Date) return false;
48683
49175
  const proto = Object.getPrototypeOf(value);
48684
49176
  return proto === Object.prototype || proto === null;
@@ -48804,7 +49296,7 @@ function SlotContentRenderer({
48804
49296
  for (const slotKey of CONTENT_NODE_SLOTS) {
48805
49297
  const slotVal = restProps[slotKey];
48806
49298
  if (slotVal === void 0 || slotVal === null) continue;
48807
- if (React74__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
49299
+ if (React75__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
48808
49300
  if (Array.isArray(slotVal) || typeof slotVal === "object" && "type" in slotVal) {
48809
49301
  nodeSlotOverrides[slotKey] = renderPatternChildren(
48810
49302
  slotVal,
@@ -48853,7 +49345,7 @@ function SlotContentRenderer({
48853
49345
  const resolvedItems = Array.isArray(entityVal) && entityVal[0] !== "fn" ? entityVal : null;
48854
49346
  if (resolvedItems && resolvedItems.length > 0 && !finalProps.fields && !finalProps.columns) {
48855
49347
  const sample = resolvedItems[0];
48856
- if (sample && typeof sample === "object" && !Array.isArray(sample) && !React74__default.isValidElement(sample) && !(sample instanceof Date)) {
49348
+ if (sample && typeof sample === "object" && !Array.isArray(sample) && !React75__default.isValidElement(sample) && !(sample instanceof Date)) {
48857
49349
  const keys = Object.keys(sample).filter((k) => k !== "id" && k !== "_id");
48858
49350
  finalProps.fields = keys.map((k, i) => ({ name: k, variant: i === 0 ? "h4" : "body" }));
48859
49351
  }
@@ -49014,7 +49506,9 @@ var init_UISlotRenderer = __esm({
49014
49506
  "content",
49015
49507
  "addons",
49016
49508
  "hud",
49017
- "fallback"
49509
+ "fallback",
49510
+ "controls",
49511
+ "overlay"
49018
49512
  ]);
49019
49513
  PATTERNS_WITH_CHILDREN = /* @__PURE__ */ new Set([
49020
49514
  "stack",
@@ -49111,6 +49605,7 @@ var init_atoms = __esm({
49111
49605
  init_Checkbox();
49112
49606
  init_Card();
49113
49607
  init_Badge();
49608
+ init_AtlasImage();
49114
49609
  init_FilterPill();
49115
49610
  init_Spinner();
49116
49611
  init_Avatar();
@@ -51354,4 +51849,4 @@ function useGitHubBranches(owner, repo, enabled = true) {
51354
51849
  });
51355
51850
  }
51356
51851
 
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 };
51852
+ export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AlgorithmCanvas, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AtlasImage, AtlasPanel, 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, useAtlasSliceDataUrl, 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 };