@almadar/ui 5.49.0 → 5.50.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
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import * as React77 from 'react';
3
- import React77__default, { useContext, useMemo, useRef, useEffect, useCallback, useState, Suspense, lazy, createContext, useLayoutEffect, useId, forwardRef, useImperativeHandle, useSyncExternalStore, Component } from 'react';
2
+ import * as React76 from 'react';
3
+ import React76__default, { useContext, useMemo, useRef, useEffect, useCallback, useState, Suspense, lazy, createContext, useLayoutEffect, useId, forwardRef, useImperativeHandle, useSyncExternalStore, Component } from 'react';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { EventBusContext, useTraitScope, TraitScopeProvider } from '@almadar/ui/providers';
@@ -9,6 +9,7 @@ import * as LucideIcons2 from 'lucide-react';
9
9
  import { Loader2, X, List, Printer, ChevronRight, ChevronLeft, CheckCircle, XCircle, Wrench, RotateCcw, Send, Play, Terminal, Search, ChevronUp, ChevronDown, MoreHorizontal, Bug, Package, Calendar, Pencil, Eye, Image as Image$1, Upload, ZoomIn, ArrowRight, TrendingUp, TrendingDown, Minus, AlertCircle, Circle, Clock, CheckCircle2, Pause, SkipForward, Code, FileText, WrapText, Check, Copy, HelpCircle, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, GitBranch, Plus, Trash, ArrowLeft, Menu as Menu$1, AlertTriangle, Trash2, Eraser, ZoomOut, Download, Lightbulb, PauseCircle, Link2, Tag, User, DollarSign, Zap, Sword, Move, Heart, Shield } from 'lucide-react';
10
10
  import { useTranslate } from '@almadar/ui/hooks';
11
11
  export * from '@almadar/ui/hooks';
12
+ import { useUISlots, useTheme } from '@almadar/ui/context';
12
13
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
13
14
  import { createPortal } from 'react-dom';
14
15
  import { Link, Outlet, useLocation } from 'react-router-dom';
@@ -41,13 +42,12 @@ import { DndContext, useSensors, useSensor, PointerSensor, KeyboardSensor, useDr
41
42
  import { useSortable, arrayMove, sortableKeyboardCoordinates, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
42
43
  import { CSS } from '@dnd-kit/utilities';
43
44
  import { useNodeId, ReactFlowProvider, Handle, Position } from '@xyflow/react';
44
- import * as THREE from 'three';
45
+ import * as THREE3 from 'three';
45
46
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
46
47
  import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
47
48
  import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
48
- import { Canvas, useThree } from '@react-three/fiber';
49
- import { Grid as Grid$1, OrbitControls } from '@react-three/drei';
50
- import { useUISlots } from '@almadar/ui/context';
49
+ import { Canvas, useLoader, useFrame, useThree } from '@react-three/fiber';
50
+ import { Billboard, Grid as Grid$1, OrbitControls } from '@react-three/drei';
51
51
  import { getPatternDefinition as getPatternDefinition$1, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
52
52
 
53
53
  var __defProp = Object.defineProperty;
@@ -233,7 +233,7 @@ var init_SvgFlow = __esm({
233
233
  width = 100,
234
234
  height = 100
235
235
  }) => {
236
- const markerId = React77__default.useMemo(() => {
236
+ const markerId = React76__default.useMemo(() => {
237
237
  flowIdCounter += 1;
238
238
  return `almadar-flow-arrow-${flowIdCounter}`;
239
239
  }, []);
@@ -826,7 +826,7 @@ var init_SvgRing = __esm({
826
826
  width = 100,
827
827
  height = 100
828
828
  }) => {
829
- const gradientId = React77__default.useMemo(() => {
829
+ const gradientId = React76__default.useMemo(() => {
830
830
  ringIdCounter += 1;
831
831
  return `almadar-ring-glow-${ringIdCounter}`;
832
832
  }, []);
@@ -1238,7 +1238,7 @@ function loadLib(key, importer) {
1238
1238
  return p2;
1239
1239
  }
1240
1240
  function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
1241
- const Lazy = React77__default.lazy(async () => {
1241
+ const Lazy = React76__default.lazy(async () => {
1242
1242
  const lib = await loadLib(libKey, importer);
1243
1243
  const Comp = pick(lib);
1244
1244
  if (!Comp) {
@@ -1248,7 +1248,7 @@ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
1248
1248
  return { default: Comp };
1249
1249
  });
1250
1250
  const Wrapped = (props) => /* @__PURE__ */ jsx(
1251
- React77__default.Suspense,
1251
+ React76__default.Suspense,
1252
1252
  {
1253
1253
  fallback: /* @__PURE__ */ jsx(
1254
1254
  "span",
@@ -1974,7 +1974,7 @@ var init_Icon = __esm({
1974
1974
  const directIcon = typeof icon === "string" ? void 0 : icon;
1975
1975
  const effectiveName = typeof icon === "string" ? icon : name;
1976
1976
  const family = useIconFamily();
1977
- const RenderedComponent = React77__default.useMemo(() => {
1977
+ const RenderedComponent = React76__default.useMemo(() => {
1978
1978
  if (directIcon) return null;
1979
1979
  return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
1980
1980
  }, [directIcon, effectiveName, family]);
@@ -2033,7 +2033,7 @@ function resolveIconProp(value, sizeClass) {
2033
2033
  const IconComp = value;
2034
2034
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
2035
2035
  }
2036
- if (React77__default.isValidElement(value)) {
2036
+ if (React76__default.isValidElement(value)) {
2037
2037
  return value;
2038
2038
  }
2039
2039
  if (typeof value === "object" && value !== null && "render" in value) {
@@ -2109,7 +2109,7 @@ var init_Button = __esm({
2109
2109
  md: "h-icon-default w-icon-default",
2110
2110
  lg: "h-icon-default w-icon-default"
2111
2111
  };
2112
- Button = React77__default.forwardRef(
2112
+ Button = React76__default.forwardRef(
2113
2113
  ({
2114
2114
  className,
2115
2115
  variant = "primary",
@@ -2176,7 +2176,7 @@ var init_Input = __esm({
2176
2176
  init_cn();
2177
2177
  init_Icon();
2178
2178
  init_useEventBus();
2179
- Input = React77__default.forwardRef(
2179
+ Input = React76__default.forwardRef(
2180
2180
  ({
2181
2181
  className,
2182
2182
  inputType,
@@ -2336,7 +2336,7 @@ var Label;
2336
2336
  var init_Label = __esm({
2337
2337
  "components/core/atoms/Label.tsx"() {
2338
2338
  init_cn();
2339
- Label = React77__default.forwardRef(
2339
+ Label = React76__default.forwardRef(
2340
2340
  ({ className, required, children, ...props }, ref) => {
2341
2341
  return /* @__PURE__ */ jsxs(
2342
2342
  "label",
@@ -2363,7 +2363,7 @@ var init_Textarea = __esm({
2363
2363
  "components/core/atoms/Textarea.tsx"() {
2364
2364
  init_cn();
2365
2365
  init_useEventBus();
2366
- Textarea = React77__default.forwardRef(
2366
+ Textarea = React76__default.forwardRef(
2367
2367
  ({ className, error, onChange, ...props }, ref) => {
2368
2368
  const eventBus = useEventBus();
2369
2369
  const handleChange = (e) => {
@@ -2602,7 +2602,7 @@ var init_Select = __esm({
2602
2602
  init_cn();
2603
2603
  init_Icon();
2604
2604
  init_useEventBus();
2605
- Select = React77__default.forwardRef(
2605
+ Select = React76__default.forwardRef(
2606
2606
  (props, _ref) => {
2607
2607
  const { multiple, searchable, clearable } = props;
2608
2608
  if (multiple || searchable || clearable) {
@@ -2619,7 +2619,7 @@ var init_Checkbox = __esm({
2619
2619
  "components/core/atoms/Checkbox.tsx"() {
2620
2620
  init_cn();
2621
2621
  init_useEventBus();
2622
- Checkbox = React77__default.forwardRef(
2622
+ Checkbox = React76__default.forwardRef(
2623
2623
  ({ className, label, id, onChange, ...props }, ref) => {
2624
2624
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
2625
2625
  const eventBus = useEventBus();
@@ -2673,7 +2673,7 @@ var init_Spinner = __esm({
2673
2673
  md: "h-6 w-6",
2674
2674
  lg: "h-8 w-8"
2675
2675
  };
2676
- Spinner = React77__default.forwardRef(
2676
+ Spinner = React76__default.forwardRef(
2677
2677
  ({ className, size = "md", overlay, ...props }, ref) => {
2678
2678
  if (overlay) {
2679
2679
  return /* @__PURE__ */ jsx(
@@ -2763,7 +2763,7 @@ var init_Card = __esm({
2763
2763
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
2764
2764
  "tile-image-first": "p-0 overflow-hidden"
2765
2765
  };
2766
- Card = React77__default.forwardRef(
2766
+ Card = React76__default.forwardRef(
2767
2767
  ({
2768
2768
  className,
2769
2769
  variant = "bordered",
@@ -2811,9 +2811,9 @@ var init_Card = __esm({
2811
2811
  }
2812
2812
  );
2813
2813
  Card.displayName = "Card";
2814
- CardHeader = React77__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
2814
+ CardHeader = React76__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
2815
2815
  CardHeader.displayName = "CardHeader";
2816
- CardTitle = React77__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2816
+ CardTitle = React76__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2817
2817
  "h3",
2818
2818
  {
2819
2819
  ref,
@@ -2826,11 +2826,11 @@ var init_Card = __esm({
2826
2826
  }
2827
2827
  ));
2828
2828
  CardTitle.displayName = "CardTitle";
2829
- CardContent = React77__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
2829
+ CardContent = React76__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
2830
2830
  CardContent.displayName = "CardContent";
2831
2831
  CardBody = CardContent;
2832
2832
  CardBody.displayName = "CardBody";
2833
- CardFooter = React77__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2833
+ CardFooter = React76__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2834
2834
  "div",
2835
2835
  {
2836
2836
  ref,
@@ -2883,7 +2883,7 @@ var init_Badge = __esm({
2883
2883
  md: "px-2.5 py-1 text-sm",
2884
2884
  lg: "px-3 py-1.5 text-base"
2885
2885
  };
2886
- Badge = React77__default.forwardRef(
2886
+ Badge = React76__default.forwardRef(
2887
2887
  ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
2888
2888
  const iconSizes3 = {
2889
2889
  sm: "h-icon-default w-icon-default",
@@ -2976,7 +2976,7 @@ var init_FilterPill = __esm({
2976
2976
  md: "w-3.5 h-3.5",
2977
2977
  lg: "w-4 h-4"
2978
2978
  };
2979
- FilterPill = React77__default.forwardRef(
2979
+ FilterPill = React76__default.forwardRef(
2980
2980
  ({
2981
2981
  className,
2982
2982
  variant = "default",
@@ -3105,8 +3105,8 @@ var init_Avatar = __esm({
3105
3105
  actionPayload
3106
3106
  }) => {
3107
3107
  const eventBus = useEventBus();
3108
- const [imgFailed, setImgFailed] = React77__default.useState(false);
3109
- React77__default.useEffect(() => {
3108
+ const [imgFailed, setImgFailed] = React76__default.useState(false);
3109
+ React76__default.useEffect(() => {
3110
3110
  setImgFailed(false);
3111
3111
  }, [src]);
3112
3112
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -3310,7 +3310,7 @@ var init_Box = __esm({
3310
3310
  fixed: "fixed",
3311
3311
  sticky: "sticky"
3312
3312
  };
3313
- Box = React77__default.forwardRef(
3313
+ Box = React76__default.forwardRef(
3314
3314
  ({
3315
3315
  padding,
3316
3316
  paddingX,
@@ -3360,7 +3360,7 @@ var init_Box = __esm({
3360
3360
  onMouseLeave?.(e);
3361
3361
  }, [hoverEvent, eventBus, onMouseLeave]);
3362
3362
  const isClickable = action || onClick;
3363
- return React77__default.createElement(
3363
+ return React76__default.createElement(
3364
3364
  Component2,
3365
3365
  {
3366
3366
  ref,
@@ -3685,7 +3685,7 @@ var init_Radio = __esm({
3685
3685
  md: "w-2.5 h-2.5",
3686
3686
  lg: "w-3 h-3"
3687
3687
  };
3688
- Radio = React77__default.forwardRef(
3688
+ Radio = React76__default.forwardRef(
3689
3689
  ({
3690
3690
  label,
3691
3691
  helperText,
@@ -3702,12 +3702,12 @@ var init_Radio = __esm({
3702
3702
  onChange,
3703
3703
  ...props
3704
3704
  }, ref) => {
3705
- const reactId = React77__default.useId();
3705
+ const reactId = React76__default.useId();
3706
3706
  const baseId = id || `radio-${reactId}`;
3707
3707
  const hasError = !!error;
3708
3708
  const eventBus = useEventBus();
3709
- const [selected, setSelected] = React77__default.useState(value);
3710
- React77__default.useEffect(() => {
3709
+ const [selected, setSelected] = React76__default.useState(value);
3710
+ React76__default.useEffect(() => {
3711
3711
  if (value !== void 0) setSelected(value);
3712
3712
  }, [value]);
3713
3713
  const pick = (next, e) => {
@@ -3889,7 +3889,7 @@ var init_Switch = __esm({
3889
3889
  "components/core/atoms/Switch.tsx"() {
3890
3890
  "use client";
3891
3891
  init_cn();
3892
- Switch = React77.forwardRef(
3892
+ Switch = React76.forwardRef(
3893
3893
  ({
3894
3894
  checked,
3895
3895
  defaultChecked = false,
@@ -3900,10 +3900,10 @@ var init_Switch = __esm({
3900
3900
  name,
3901
3901
  className
3902
3902
  }, ref) => {
3903
- const [isChecked, setIsChecked] = React77.useState(
3903
+ const [isChecked, setIsChecked] = React76.useState(
3904
3904
  checked !== void 0 ? checked : defaultChecked
3905
3905
  );
3906
- React77.useEffect(() => {
3906
+ React76.useEffect(() => {
3907
3907
  if (checked !== void 0) {
3908
3908
  setIsChecked(checked);
3909
3909
  }
@@ -4277,188 +4277,12 @@ var init_Typography = __esm({
4277
4277
  Typography.displayName = "Typography";
4278
4278
  }
4279
4279
  });
4280
- function useTheme() {
4281
- const context = useContext(ThemeContext);
4282
- if (context === void 0) {
4283
- return {
4284
- theme: "wireframe",
4285
- mode: "light",
4286
- resolvedMode: "light",
4287
- setTheme: () => {
4288
- },
4289
- setMode: () => {
4290
- },
4291
- toggleMode: () => {
4292
- },
4293
- availableThemes: BUILT_IN_THEMES,
4294
- appliedTheme: "wireframe-light"
4295
- };
4296
- }
4297
- return context;
4298
- }
4299
- var BUILT_IN_THEMES, ThemeContext;
4300
- var init_ThemeContext = __esm({
4301
- "context/ThemeContext.tsx"() {
4302
- "use client";
4303
- createLogger("almadar:ui:theme");
4304
- BUILT_IN_THEMES = [
4305
- {
4306
- name: "wireframe",
4307
- displayName: "Wireframe",
4308
- hasLightMode: true,
4309
- hasDarkMode: true
4310
- },
4311
- {
4312
- name: "minimalist",
4313
- displayName: "Minimalist",
4314
- hasLightMode: true,
4315
- hasDarkMode: true
4316
- },
4317
- {
4318
- name: "almadar",
4319
- displayName: "Almadar",
4320
- hasLightMode: true,
4321
- hasDarkMode: true
4322
- },
4323
- {
4324
- name: "trait-wars",
4325
- displayName: "Trait Wars",
4326
- hasLightMode: false,
4327
- hasDarkMode: true
4328
- },
4329
- // Extended themes
4330
- {
4331
- name: "ocean",
4332
- displayName: "Ocean",
4333
- hasLightMode: true,
4334
- hasDarkMode: true
4335
- },
4336
- {
4337
- name: "forest",
4338
- displayName: "Forest",
4339
- hasLightMode: true,
4340
- hasDarkMode: true
4341
- },
4342
- {
4343
- name: "sunset",
4344
- displayName: "Sunset",
4345
- hasLightMode: true,
4346
- hasDarkMode: true
4347
- },
4348
- {
4349
- name: "lavender",
4350
- displayName: "Lavender",
4351
- hasLightMode: true,
4352
- hasDarkMode: true
4353
- },
4354
- {
4355
- name: "rose",
4356
- displayName: "Rose",
4357
- hasLightMode: true,
4358
- hasDarkMode: true
4359
- },
4360
- {
4361
- name: "slate",
4362
- displayName: "Slate",
4363
- hasLightMode: true,
4364
- hasDarkMode: true
4365
- },
4366
- {
4367
- name: "ember",
4368
- displayName: "Ember",
4369
- hasLightMode: true,
4370
- hasDarkMode: true
4371
- },
4372
- {
4373
- name: "midnight",
4374
- displayName: "Midnight",
4375
- hasLightMode: true,
4376
- hasDarkMode: true
4377
- },
4378
- {
4379
- name: "sand",
4380
- displayName: "Sand",
4381
- hasLightMode: true,
4382
- hasDarkMode: true
4383
- },
4384
- {
4385
- name: "neon",
4386
- displayName: "Neon",
4387
- hasLightMode: true,
4388
- hasDarkMode: true
4389
- },
4390
- {
4391
- name: "arctic",
4392
- displayName: "Arctic",
4393
- hasLightMode: true,
4394
- hasDarkMode: true
4395
- },
4396
- {
4397
- name: "copper",
4398
- displayName: "Copper",
4399
- hasLightMode: true,
4400
- hasDarkMode: true
4401
- },
4402
- // Layer 1 skin axes — truly-unique themes (compact tech / editorial / brutalist dense / display-heavy / touch-first)
4403
- {
4404
- name: "prism",
4405
- displayName: "Prism",
4406
- hasLightMode: true,
4407
- hasDarkMode: true
4408
- },
4409
- {
4410
- name: "gazette",
4411
- displayName: "Gazette",
4412
- hasLightMode: true,
4413
- hasDarkMode: true
4414
- },
4415
- {
4416
- name: "terminal",
4417
- displayName: "Terminal",
4418
- hasLightMode: true,
4419
- hasDarkMode: true
4420
- },
4421
- {
4422
- name: "atelier",
4423
- displayName: "Atelier",
4424
- hasLightMode: true,
4425
- hasDarkMode: true
4426
- },
4427
- {
4428
- name: "kiosk",
4429
- displayName: "Kiosk",
4430
- hasLightMode: true,
4431
- hasDarkMode: true
4432
- },
4433
- {
4434
- name: "linear-clean",
4435
- displayName: "Linear Clean",
4436
- hasLightMode: true,
4437
- hasDarkMode: true
4438
- },
4439
- {
4440
- name: "notion-editorial",
4441
- displayName: "Notion Editorial",
4442
- hasLightMode: true,
4443
- hasDarkMode: true
4444
- },
4445
- {
4446
- name: "bloomberg-dense",
4447
- displayName: "Bloomberg Dense",
4448
- hasLightMode: true,
4449
- hasDarkMode: true
4450
- }
4451
- ];
4452
- ThemeContext = createContext(void 0);
4453
- }
4454
- });
4455
4280
  var sizeClasses4, iconSizes2, ThemeToggle;
4456
4281
  var init_ThemeToggle = __esm({
4457
4282
  "components/core/atoms/ThemeToggle.tsx"() {
4458
4283
  "use client";
4459
4284
  init_Icon();
4460
4285
  init_cn();
4461
- init_ThemeContext();
4462
4286
  sizeClasses4 = {
4463
4287
  sm: "p-1.5",
4464
4288
  md: "p-2",
@@ -4521,7 +4345,6 @@ var THEME_LABELS, ThemeSelector;
4521
4345
  var init_ThemeSelector = __esm({
4522
4346
  "components/core/atoms/ThemeSelector.tsx"() {
4523
4347
  "use client";
4524
- init_ThemeContext();
4525
4348
  THEME_LABELS = {
4526
4349
  wireframe: {
4527
4350
  label: "Wireframe",
@@ -4732,7 +4555,7 @@ var Dialog;
4732
4555
  var init_Dialog = __esm({
4733
4556
  "components/core/atoms/Dialog.tsx"() {
4734
4557
  init_cn();
4735
- Dialog = React77__default.forwardRef(
4558
+ Dialog = React76__default.forwardRef(
4736
4559
  ({
4737
4560
  role = "dialog",
4738
4561
  "aria-modal": ariaModal = true,
@@ -4758,7 +4581,7 @@ var Aside;
4758
4581
  var init_Aside = __esm({
4759
4582
  "components/core/atoms/Aside.tsx"() {
4760
4583
  init_cn();
4761
- Aside = React77__default.forwardRef(
4584
+ Aside = React76__default.forwardRef(
4762
4585
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
4763
4586
  );
4764
4587
  Aside.displayName = "Aside";
@@ -4836,8 +4659,8 @@ var init_LawReferenceTooltip = __esm({
4836
4659
  className
4837
4660
  }) => {
4838
4661
  const { t } = useTranslate();
4839
- const [isVisible, setIsVisible] = React77__default.useState(false);
4840
- const timeoutRef = React77__default.useRef(null);
4662
+ const [isVisible, setIsVisible] = React76__default.useState(false);
4663
+ const timeoutRef = React76__default.useRef(null);
4841
4664
  const handleMouseEnter = () => {
4842
4665
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
4843
4666
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -4846,7 +4669,7 @@ var init_LawReferenceTooltip = __esm({
4846
4669
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
4847
4670
  setIsVisible(false);
4848
4671
  };
4849
- React77__default.useEffect(() => {
4672
+ React76__default.useEffect(() => {
4850
4673
  return () => {
4851
4674
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
4852
4675
  };
@@ -5056,7 +4879,7 @@ var init_StatusDot = __esm({
5056
4879
  md: "w-2.5 h-2.5",
5057
4880
  lg: "w-3 h-3"
5058
4881
  };
5059
- StatusDot = React77__default.forwardRef(
4882
+ StatusDot = React76__default.forwardRef(
5060
4883
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
5061
4884
  return /* @__PURE__ */ jsx(
5062
4885
  "span",
@@ -5110,7 +4933,7 @@ var init_TrendIndicator = __esm({
5110
4933
  down: "trending-down",
5111
4934
  flat: "arrow-right"
5112
4935
  };
5113
- TrendIndicator = React77__default.forwardRef(
4936
+ TrendIndicator = React76__default.forwardRef(
5114
4937
  ({
5115
4938
  className,
5116
4939
  value,
@@ -5177,7 +5000,7 @@ var init_RangeSlider = __esm({
5177
5000
  md: "w-4 h-4",
5178
5001
  lg: "w-5 h-5"
5179
5002
  };
5180
- RangeSlider = React77__default.forwardRef(
5003
+ RangeSlider = React76__default.forwardRef(
5181
5004
  ({
5182
5005
  className,
5183
5006
  min = 0,
@@ -5773,7 +5596,7 @@ var init_ContentSection = __esm({
5773
5596
  md: "py-16",
5774
5597
  lg: "py-24"
5775
5598
  };
5776
- ContentSection = React77__default.forwardRef(
5599
+ ContentSection = React76__default.forwardRef(
5777
5600
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
5778
5601
  return /* @__PURE__ */ jsx(
5779
5602
  Box,
@@ -6307,7 +6130,7 @@ var init_AnimatedReveal = __esm({
6307
6130
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
6308
6131
  "none": {}
6309
6132
  };
6310
- AnimatedReveal = React77__default.forwardRef(
6133
+ AnimatedReveal = React76__default.forwardRef(
6311
6134
  ({
6312
6135
  trigger = "scroll",
6313
6136
  animation = "fade-up",
@@ -6467,7 +6290,7 @@ var init_AnimatedGraphic = __esm({
6467
6290
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
6468
6291
  "use client";
6469
6292
  init_cn();
6470
- AnimatedGraphic = React77__default.forwardRef(
6293
+ AnimatedGraphic = React76__default.forwardRef(
6471
6294
  ({
6472
6295
  src,
6473
6296
  svgContent,
@@ -6490,7 +6313,7 @@ var init_AnimatedGraphic = __esm({
6490
6313
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
6491
6314
  const resolvedSvg = svgContent ?? fetchedSvg;
6492
6315
  const prevAnimateRef = useRef(animate);
6493
- const setRef = React77__default.useCallback(
6316
+ const setRef = React76__default.useCallback(
6494
6317
  (node) => {
6495
6318
  containerRef.current = node;
6496
6319
  if (typeof ref === "function") ref(node);
@@ -7172,7 +6995,7 @@ var init_ErrorBoundary = __esm({
7172
6995
  }
7173
6996
  );
7174
6997
  };
7175
- ErrorBoundary = class extends React77__default.Component {
6998
+ ErrorBoundary = class extends React76__default.Component {
7176
6999
  constructor(props) {
7177
7000
  super(props);
7178
7001
  __publicField(this, "reset", () => {
@@ -8292,9 +8115,9 @@ function ControlButton({
8292
8115
  className
8293
8116
  }) {
8294
8117
  const eventBus = useEventBus();
8295
- const [isPressed, setIsPressed] = React77.useState(false);
8118
+ const [isPressed, setIsPressed] = React76.useState(false);
8296
8119
  const actualPressed = pressed ?? isPressed;
8297
- const handlePointerDown = React77.useCallback(
8120
+ const handlePointerDown = React76.useCallback(
8298
8121
  (e) => {
8299
8122
  e.preventDefault();
8300
8123
  if (disabled) return;
@@ -8304,7 +8127,7 @@ function ControlButton({
8304
8127
  },
8305
8128
  [disabled, pressEvent, eventBus, onPress]
8306
8129
  );
8307
- const handlePointerUp = React77.useCallback(
8130
+ const handlePointerUp = React76.useCallback(
8308
8131
  (e) => {
8309
8132
  e.preventDefault();
8310
8133
  if (disabled) return;
@@ -8314,7 +8137,7 @@ function ControlButton({
8314
8137
  },
8315
8138
  [disabled, releaseEvent, eventBus, onRelease]
8316
8139
  );
8317
- const handlePointerLeave = React77.useCallback(
8140
+ const handlePointerLeave = React76.useCallback(
8318
8141
  (e) => {
8319
8142
  if (isPressed) {
8320
8143
  setIsPressed(false);
@@ -8402,8 +8225,8 @@ function ActionButtons({
8402
8225
  disabled
8403
8226
  }) {
8404
8227
  const eventBus = useEventBus();
8405
- const [activeButtons, setActiveButtons] = React77.useState(/* @__PURE__ */ new Set());
8406
- const handlePress = React77.useCallback(
8228
+ const [activeButtons, setActiveButtons] = React76.useState(/* @__PURE__ */ new Set());
8229
+ const handlePress = React76.useCallback(
8407
8230
  (id) => {
8408
8231
  setActiveButtons((prev) => new Set(prev).add(id));
8409
8232
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -8411,7 +8234,7 @@ function ActionButtons({
8411
8234
  },
8412
8235
  [actionEvent, eventBus, onAction]
8413
8236
  );
8414
- const handleRelease = React77.useCallback(
8237
+ const handleRelease = React76.useCallback(
8415
8238
  (id) => {
8416
8239
  setActiveButtons((prev) => {
8417
8240
  const next = new Set(prev);
@@ -9342,7 +9165,7 @@ function getTraitSnapshots() {
9342
9165
  try {
9343
9166
  snapshots.push(getter());
9344
9167
  } catch (err) {
9345
- log4.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
9168
+ log3.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
9346
9169
  }
9347
9170
  }
9348
9171
  return snapshots;
@@ -9420,10 +9243,10 @@ function updateAssetStatus(url, status) {
9420
9243
  window.__orbitalVerification.assetStatus[url] = status;
9421
9244
  }
9422
9245
  }
9423
- var log4;
9246
+ var log3;
9424
9247
  var init_verificationRegistry = __esm({
9425
9248
  "lib/verificationRegistry.ts"() {
9426
- log4 = createLogger("almadar:bridge");
9249
+ log3 = createLogger("almadar:bridge");
9427
9250
  exposeOnWindow();
9428
9251
  }
9429
9252
  });
@@ -9550,6 +9373,291 @@ var init_useCamera = __esm({
9550
9373
  }
9551
9374
  });
9552
9375
 
9376
+ // components/game/organisms/utils/spriteSheetConstants.ts
9377
+ var SHEET_COLUMNS, SPRITE_SHEET_LAYOUT;
9378
+ var init_spriteSheetConstants = __esm({
9379
+ "components/game/organisms/utils/spriteSheetConstants.ts"() {
9380
+ SHEET_COLUMNS = 8;
9381
+ SPRITE_SHEET_LAYOUT = {
9382
+ idle: { row: 0, frames: 4, frameRate: 6, loop: true },
9383
+ walk: { row: 1, frames: 8, frameRate: 10, loop: true },
9384
+ attack: { row: 2, frames: 6, frameRate: 12, loop: false },
9385
+ hit: { row: 3, frames: 3, frameRate: 8, loop: false },
9386
+ death: { row: 4, frames: 6, frameRate: 8, loop: false }
9387
+ };
9388
+ }
9389
+ });
9390
+
9391
+ // components/game/organisms/utils/spriteAnimation.ts
9392
+ function inferDirection(dx, dy) {
9393
+ if (dx === 0 && dy === 0) return "se";
9394
+ if (dx >= 0 && dy >= 0) return "se";
9395
+ if (dx <= 0 && dy >= 0) return "sw";
9396
+ if (dx >= 0 && dy <= 0) return "ne";
9397
+ return "nw";
9398
+ }
9399
+ function resolveSheetDirection(facing) {
9400
+ switch (facing) {
9401
+ case "se":
9402
+ return { sheetDir: "se", flipX: false };
9403
+ case "sw":
9404
+ return { sheetDir: "sw", flipX: false };
9405
+ case "ne":
9406
+ return { sheetDir: "sw", flipX: true };
9407
+ case "nw":
9408
+ return { sheetDir: "se", flipX: true };
9409
+ }
9410
+ }
9411
+ function frameRect(frame, row, columns, frameWidth, frameHeight) {
9412
+ return {
9413
+ sx: frame % columns * frameWidth,
9414
+ sy: row * frameHeight,
9415
+ sw: frameWidth,
9416
+ sh: frameHeight
9417
+ };
9418
+ }
9419
+ function getCurrentFrameFromDef(def, elapsed) {
9420
+ const frameDuration = 1e3 / def.frameRate;
9421
+ const totalDuration = def.frames * frameDuration;
9422
+ if (def.loop) {
9423
+ const frame2 = Math.floor(elapsed % totalDuration / frameDuration);
9424
+ return { frame: frame2, finished: false };
9425
+ }
9426
+ if (elapsed >= totalDuration) {
9427
+ return { frame: def.frames - 1, finished: true };
9428
+ }
9429
+ const frame = Math.floor(elapsed / frameDuration);
9430
+ return { frame, finished: false };
9431
+ }
9432
+ function getCurrentFrame(animName, elapsed) {
9433
+ return getCurrentFrameFromDef(SPRITE_SHEET_LAYOUT[animName], elapsed);
9434
+ }
9435
+ function resolveFrame(sheetUrls, frameDims, animState) {
9436
+ if (!sheetUrls) return null;
9437
+ const { sheetDir, flipX } = resolveSheetDirection(animState.direction);
9438
+ const sheetUrl = sheetUrls[sheetDir];
9439
+ if (!sheetUrl) return null;
9440
+ const def = SPRITE_SHEET_LAYOUT[animState.animation];
9441
+ const { frame } = getCurrentFrame(animState.animation, animState.elapsed);
9442
+ const rect = frameRect(frame, def.row, def.frames, frameDims.width, frameDims.height);
9443
+ return {
9444
+ sheetUrl,
9445
+ sx: rect.sx,
9446
+ sy: rect.sy,
9447
+ sw: rect.sw,
9448
+ sh: rect.sh,
9449
+ flipX
9450
+ };
9451
+ }
9452
+ function createUnitAnimationState(unitId) {
9453
+ return {
9454
+ unitId,
9455
+ animation: "idle",
9456
+ direction: "se",
9457
+ frame: 0,
9458
+ elapsed: 0,
9459
+ queuedAnimation: null,
9460
+ finished: false
9461
+ };
9462
+ }
9463
+ function transitionAnimation(state, newAnim, direction) {
9464
+ if (state.animation === "death" && state.finished) return state;
9465
+ if (state.animation === newAnim && SPRITE_SHEET_LAYOUT[newAnim].loop) {
9466
+ return direction ? { ...state, direction } : state;
9467
+ }
9468
+ return {
9469
+ ...state,
9470
+ animation: newAnim,
9471
+ direction: direction ?? state.direction,
9472
+ frame: 0,
9473
+ elapsed: 0,
9474
+ queuedAnimation: null,
9475
+ finished: false
9476
+ };
9477
+ }
9478
+ function tickAnimationState(state, deltaMs) {
9479
+ const newElapsed = state.elapsed + deltaMs;
9480
+ const { frame, finished } = getCurrentFrame(state.animation, newElapsed);
9481
+ const def = SPRITE_SHEET_LAYOUT[state.animation];
9482
+ if (finished && !def.loop && !state.finished) {
9483
+ if (state.animation === "death") {
9484
+ return { ...state, elapsed: newElapsed, frame, finished: true };
9485
+ }
9486
+ const nextAnim = state.queuedAnimation ?? "idle";
9487
+ return {
9488
+ ...state,
9489
+ animation: nextAnim,
9490
+ elapsed: 0,
9491
+ frame: 0,
9492
+ queuedAnimation: null,
9493
+ finished: false
9494
+ };
9495
+ }
9496
+ return { ...state, elapsed: newElapsed, frame, finished };
9497
+ }
9498
+ var init_spriteAnimation = __esm({
9499
+ "components/game/organisms/utils/spriteAnimation.ts"() {
9500
+ init_spriteSheetConstants();
9501
+ }
9502
+ });
9503
+ function unitAtlasUrl(unit) {
9504
+ if (unit.spriteSheet) return unit.spriteSheet;
9505
+ const sprite = unit.sprite;
9506
+ if (!sprite) return null;
9507
+ const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
9508
+ if (!match) return null;
9509
+ return `${match[1]}.json`;
9510
+ }
9511
+ function resolveSheetUrl(atlasUrl, relativeSheetPath) {
9512
+ try {
9513
+ return new URL(relativeSheetPath, atlasUrl).toString();
9514
+ } catch {
9515
+ const base = atlasUrl.slice(0, atlasUrl.lastIndexOf("/") + 1);
9516
+ return `${base}${relativeSheetPath.replace(/^\.\//, "")}`;
9517
+ }
9518
+ }
9519
+ function useUnitSpriteAtlas(units) {
9520
+ const atlasCacheRef = useRef(/* @__PURE__ */ new Map());
9521
+ const loadingRef = useRef(/* @__PURE__ */ new Set());
9522
+ const [pendingCount, setPendingCount] = useState(0);
9523
+ const [, forceTick] = useState(0);
9524
+ const animStatesRef = useRef(/* @__PURE__ */ new Map());
9525
+ const lastTickRef = useRef(0);
9526
+ const rafRef = useRef(0);
9527
+ const atlasUrls = useMemo(() => {
9528
+ const set = /* @__PURE__ */ new Set();
9529
+ for (const unit of units) {
9530
+ const url = unitAtlasUrl(unit);
9531
+ if (url) set.add(url);
9532
+ }
9533
+ return [...set];
9534
+ }, [units]);
9535
+ useEffect(() => {
9536
+ const cache = atlasCacheRef.current;
9537
+ const loading = loadingRef.current;
9538
+ const toLoad = atlasUrls.filter((url) => !cache.has(url) && !loading.has(url));
9539
+ if (toLoad.length === 0) return;
9540
+ let cancelled = false;
9541
+ setPendingCount((prev) => prev + toLoad.length);
9542
+ for (const url of toLoad) {
9543
+ loading.add(url);
9544
+ fetch(url).then((res) => res.ok ? res.json() : Promise.reject(new Error(String(res.status)))).then((atlas) => {
9545
+ if (cancelled) return;
9546
+ cache.set(url, atlas);
9547
+ }).catch(() => {
9548
+ }).finally(() => {
9549
+ if (cancelled) return;
9550
+ loading.delete(url);
9551
+ setPendingCount((prev) => Math.max(0, prev - 1));
9552
+ forceTick((n) => n + 1);
9553
+ });
9554
+ }
9555
+ return () => {
9556
+ cancelled = true;
9557
+ };
9558
+ }, [atlasUrls]);
9559
+ const sheetUrls = useMemo(() => {
9560
+ const urls = /* @__PURE__ */ new Set();
9561
+ for (const unit of units) {
9562
+ const atlasUrl = unitAtlasUrl(unit);
9563
+ if (!atlasUrl) continue;
9564
+ const atlas = atlasCacheRef.current.get(atlasUrl);
9565
+ if (!atlas) continue;
9566
+ for (const rel of Object.values(atlas.sheets)) {
9567
+ if (rel) urls.add(resolveSheetUrl(atlasUrl, rel));
9568
+ }
9569
+ }
9570
+ return [...urls];
9571
+ }, [units, pendingCount]);
9572
+ useEffect(() => {
9573
+ const hasAtlasUnits = units.some((u) => unitAtlasUrl(u) !== null);
9574
+ if (!hasAtlasUnits) return;
9575
+ let running = true;
9576
+ const tick = (ts) => {
9577
+ if (!running) return;
9578
+ const last = lastTickRef.current || ts;
9579
+ const delta = ts - last;
9580
+ lastTickRef.current = ts;
9581
+ const states = animStatesRef.current;
9582
+ const currentIds = /* @__PURE__ */ new Set();
9583
+ for (const unit of units) {
9584
+ if (unitAtlasUrl(unit) === null) continue;
9585
+ currentIds.add(unit.id);
9586
+ let state = states.get(unit.id);
9587
+ if (!state) {
9588
+ state = { animation: "idle", direction: "se", elapsed: 0, walkHold: 0, prev: null };
9589
+ states.set(unit.id, state);
9590
+ }
9591
+ const posX = unit.position?.x ?? unit.x ?? 0;
9592
+ const posY = unit.position?.y ?? unit.y ?? 0;
9593
+ if (state.prev) {
9594
+ const dx = posX - state.prev.x;
9595
+ const dy = posY - state.prev.y;
9596
+ if (dx !== 0 || dy !== 0) {
9597
+ state.animation = "walk";
9598
+ state.direction = inferDirection(dx, dy);
9599
+ state.walkHold = WALK_HOLD_MS;
9600
+ } else if (state.animation === "walk") {
9601
+ state.walkHold -= delta;
9602
+ if (state.walkHold <= 0) state.animation = "idle";
9603
+ }
9604
+ }
9605
+ state.prev = { x: posX, y: posY };
9606
+ state.elapsed += delta;
9607
+ }
9608
+ for (const id of states.keys()) {
9609
+ if (!currentIds.has(id)) states.delete(id);
9610
+ }
9611
+ rafRef.current = requestAnimationFrame(tick);
9612
+ };
9613
+ rafRef.current = requestAnimationFrame(tick);
9614
+ return () => {
9615
+ running = false;
9616
+ cancelAnimationFrame(rafRef.current);
9617
+ lastTickRef.current = 0;
9618
+ };
9619
+ }, [units]);
9620
+ const resolveUnitFrame = useCallback((unitId) => {
9621
+ const unit = units.find((u) => u.id === unitId);
9622
+ if (!unit) return null;
9623
+ const atlasUrl = unitAtlasUrl(unit);
9624
+ if (!atlasUrl) return null;
9625
+ const atlas = atlasCacheRef.current.get(atlasUrl);
9626
+ if (!atlas) return null;
9627
+ const state = animStatesRef.current.get(unitId);
9628
+ const animation = state?.animation ?? "idle";
9629
+ const direction = state?.direction ?? "se";
9630
+ const elapsed = state?.elapsed ?? 0;
9631
+ const def = atlas.animations[animation] ?? atlas.animations.idle;
9632
+ if (!def) return null;
9633
+ const { sheetDir, flipX } = resolveSheetDirection(direction);
9634
+ const rel = atlas.sheets[sheetDir] ?? atlas.sheets.se ?? atlas.sheets.sw;
9635
+ if (!rel) return null;
9636
+ const sheetUrl = resolveSheetUrl(atlasUrl, rel);
9637
+ const isIdle = animation === "idle";
9638
+ const frame = isIdle ? 0 : getCurrentFrameFromDef(def, elapsed).frame;
9639
+ const rect = frameRect(frame, def.row, atlas.columns, atlas.frameWidth, atlas.frameHeight);
9640
+ return {
9641
+ sheetUrl,
9642
+ sx: rect.sx,
9643
+ sy: rect.sy,
9644
+ sw: rect.sw,
9645
+ sh: rect.sh,
9646
+ flipX,
9647
+ applyBreathing: isIdle
9648
+ };
9649
+ }, [units]);
9650
+ return { sheetUrls, resolveUnitFrame, pendingCount };
9651
+ }
9652
+ var WALK_HOLD_MS;
9653
+ var init_useUnitSpriteAtlas = __esm({
9654
+ "components/game/molecules/useUnitSpriteAtlas.ts"() {
9655
+ "use client";
9656
+ init_spriteAnimation();
9657
+ WALK_HOLD_MS = 600;
9658
+ }
9659
+ });
9660
+
9553
9661
  // components/game/organisms/utils/isometric.ts
9554
9662
  function isoToScreen(tileX, tileY, scale, baseOffsetX) {
9555
9663
  const scaledTileWidth = TILE_WIDTH * scale;
@@ -9663,6 +9771,10 @@ function IsometricCanvas({
9663
9771
  () => unitsProp.map((u) => u.position ? u : { ...u, position: { x: u.x ?? 0, y: u.y ?? 0 } }),
9664
9772
  [unitsProp]
9665
9773
  );
9774
+ const { sheetUrls: atlasSheetUrls, resolveUnitFrame: resolveUnitFrameInternal, pendingCount: atlasPending } = useUnitSpriteAtlas(units);
9775
+ const resolveFrameForUnit = useCallback((unitId) => {
9776
+ return resolveUnitFrame?.(unitId) ?? resolveUnitFrameInternal(unitId);
9777
+ }, [resolveUnitFrame, resolveUnitFrameInternal]);
9666
9778
  const features = useMemo(
9667
9779
  () => featuresProp.map((f3) => {
9668
9780
  if (f3.type) return f3;
@@ -9746,9 +9858,10 @@ function IsometricCanvas({
9746
9858
  }
9747
9859
  }
9748
9860
  if (effectSpriteUrls) urls.push(...effectSpriteUrls);
9861
+ if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
9749
9862
  if (backgroundImage) urls.push(backgroundImage);
9750
9863
  return [...new Set(urls.filter(Boolean))];
9751
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, backgroundImage, assetManifest, resolveManifestUrl]);
9864
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl]);
9752
9865
  const { getImage, pendingCount } = useImageCache(spriteUrls);
9753
9866
  useEffect(() => {
9754
9867
  if (typeof window === "undefined") return;
@@ -10036,7 +10149,7 @@ function IsometricCanvas({
10036
10149
  ctx.lineWidth = 3;
10037
10150
  ctx.stroke();
10038
10151
  }
10039
- const frame = resolveUnitFrame?.(unit.id) ?? null;
10152
+ const frame = resolveFrameForUnit(unit.id);
10040
10153
  const frameImg = frame ? getImage(frame.sheetUrl) : null;
10041
10154
  if (frame && frameImg) {
10042
10155
  const frameAr = frame.sw / frame.sh;
@@ -10146,7 +10259,7 @@ function IsometricCanvas({
10146
10259
  resolveTerrainSpriteUrl,
10147
10260
  resolveFeatureSpriteUrl,
10148
10261
  resolveUnitSpriteUrl,
10149
- resolveUnitFrame,
10262
+ resolveFrameForUnit,
10150
10263
  getImage,
10151
10264
  gridWidth,
10152
10265
  gridHeight,
@@ -10178,7 +10291,7 @@ function IsometricCanvas({
10178
10291
  };
10179
10292
  }, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
10180
10293
  useEffect(() => {
10181
- const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0;
10294
+ const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
10182
10295
  draw(animTimeRef.current);
10183
10296
  if (!hasAnimations) return;
10184
10297
  let running = true;
@@ -10194,7 +10307,7 @@ function IsometricCanvas({
10194
10307
  running = false;
10195
10308
  cancelAnimationFrame(rafIdRef.current);
10196
10309
  };
10197
- }, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, lerpToTarget, targetCameraRef]);
10310
+ }, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, atlasPending, lerpToTarget, targetCameraRef]);
10198
10311
  const handleMouseMoveWithCamera = useCallback((e) => {
10199
10312
  if (enableCamera) {
10200
10313
  const wasPanning = handleMouseMove(e, () => draw(animTimeRef.current));
@@ -10339,6 +10452,7 @@ var init_IsometricCanvas = __esm({
10339
10452
  init_ErrorState();
10340
10453
  init_useImageCache();
10341
10454
  init_useCamera();
10455
+ init_useUnitSpriteAtlas();
10342
10456
  init_verificationRegistry();
10343
10457
  init_isometric();
10344
10458
  IsometricCanvas.displayName = "IsometricCanvas";
@@ -11554,7 +11668,7 @@ var init_avl_elk_layout = __esm({
11554
11668
  elk = new ELK();
11555
11669
  }
11556
11670
  });
11557
- var log5, SWIM_GUTTER, CENTER_W, BehaviorView;
11671
+ var log4, SWIM_GUTTER, CENTER_W, BehaviorView;
11558
11672
  var init_BehaviorView = __esm({
11559
11673
  "components/avl/molecules/BehaviorView.tsx"() {
11560
11674
  "use client";
@@ -11563,7 +11677,7 @@ var init_BehaviorView = __esm({
11563
11677
  init_AvlSwimLane();
11564
11678
  init_types();
11565
11679
  init_avl_elk_layout();
11566
- log5 = createLogger("almadar:ui:avl:behavior-view");
11680
+ log4 = createLogger("almadar:ui:avl:behavior-view");
11567
11681
  SWIM_GUTTER = 120;
11568
11682
  CENTER_W = 360;
11569
11683
  BehaviorView = ({ data }) => {
@@ -11574,7 +11688,7 @@ var init_BehaviorView = __esm({
11574
11688
  const dataKey = useMemo(() => JSON.stringify(traitData), [traitData]);
11575
11689
  useEffect(() => {
11576
11690
  if (!traitData) return;
11577
- computeTraitLayout(traitData).then(setLayout).catch((err) => log5.error("compute-trait-layout-failed", { error: err instanceof Error ? err : String(err) }));
11691
+ computeTraitLayout(traitData).then(setLayout).catch((err) => log4.error("compute-trait-layout-failed", { error: err instanceof Error ? err : String(err) }));
11578
11692
  }, [dataKey]);
11579
11693
  if (!traitData) {
11580
11694
  return /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-[var(--color-border)] bg-[var(--color-card)] p-4 text-center text-[var(--color-muted-foreground)] text-sm", children: t("avl.noTraitData") });
@@ -11985,7 +12099,7 @@ function generateDiff(oldVal, newVal) {
11985
12099
  }
11986
12100
  return diff;
11987
12101
  }
11988
- var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log6, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
12102
+ var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log5, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
11989
12103
  var init_CodeBlock = __esm({
11990
12104
  "components/core/molecules/markdown/CodeBlock.tsx"() {
11991
12105
  init_cn();
@@ -12068,7 +12182,7 @@ var init_CodeBlock = __esm({
12068
12182
  "lolo-op-async": { color: ORB_COLORS.dark.async }
12069
12183
  };
12070
12184
  loloStyle = { ...dark, ...loloStyleOverrides };
12071
- log6 = createLogger("almadar:ui:markdown-code");
12185
+ log5 = createLogger("almadar:ui:markdown-code");
12072
12186
  CODE_LANGUAGES = [
12073
12187
  "text",
12074
12188
  "json",
@@ -12107,7 +12221,7 @@ var init_CodeBlock = __esm({
12107
12221
  };
12108
12222
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
12109
12223
  HIDDEN_LINE_NUMBERS = { display: "none" };
12110
- CodeBlock = React77__default.memo(
12224
+ CodeBlock = React76__default.memo(
12111
12225
  ({
12112
12226
  code: rawCode,
12113
12227
  language = "text",
@@ -12332,7 +12446,7 @@ var init_CodeBlock = __esm({
12332
12446
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: true });
12333
12447
  setTimeout(() => setCopied(false), 2e3);
12334
12448
  } catch (err) {
12335
- log6.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
12449
+ log5.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
12336
12450
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: false });
12337
12451
  }
12338
12452
  };
@@ -12694,7 +12808,7 @@ var init_MarkdownContent = __esm({
12694
12808
  init_Box();
12695
12809
  init_CodeBlock();
12696
12810
  init_cn();
12697
- MarkdownContent = React77__default.memo(
12811
+ MarkdownContent = React76__default.memo(
12698
12812
  ({ content, direction = "ltr", className }) => {
12699
12813
  const { t: _t } = useTranslate();
12700
12814
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -14011,7 +14125,7 @@ var init_StateMachineView = __esm({
14011
14125
  style: { top: title ? 30 : 0 },
14012
14126
  children: [
14013
14127
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
14014
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React77__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
14128
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React76__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
14015
14129
  StateNode,
14016
14130
  {
14017
14131
  state,
@@ -16213,14 +16327,14 @@ function useSafeEventBus2() {
16213
16327
  } };
16214
16328
  }
16215
16329
  }
16216
- var log7, lookStyles4, ButtonGroup;
16330
+ var log6, lookStyles4, ButtonGroup;
16217
16331
  var init_ButtonGroup = __esm({
16218
16332
  "components/core/molecules/ButtonGroup.tsx"() {
16219
16333
  "use client";
16220
16334
  init_cn();
16221
16335
  init_atoms2();
16222
16336
  init_useEventBus();
16223
- log7 = createLogger("almadar:ui:button-group");
16337
+ log6 = createLogger("almadar:ui:button-group");
16224
16338
  lookStyles4 = {
16225
16339
  "right-aligned-buttons": "",
16226
16340
  "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
@@ -16301,7 +16415,7 @@ var init_ButtonGroup = __esm({
16301
16415
  {
16302
16416
  variant: "ghost",
16303
16417
  onClick: () => {
16304
- log7.debug("Filter clicked", { field: filter.field });
16418
+ log6.debug("Filter clicked", { field: filter.field });
16305
16419
  },
16306
16420
  children: filter.label
16307
16421
  },
@@ -20762,7 +20876,7 @@ function CraftingRecipe({
20762
20876
  className
20763
20877
  }) {
20764
20878
  const eventBus = useEventBus();
20765
- const handleCraft = React77.useCallback(() => {
20879
+ const handleCraft = React76.useCallback(() => {
20766
20880
  onCraft?.();
20767
20881
  if (craftEvent) {
20768
20882
  eventBus.emit(craftEvent, { output: output.label });
@@ -20779,7 +20893,7 @@ function CraftingRecipe({
20779
20893
  children: [
20780
20894
  /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap items-center", children: inputs.map((ingredient, index) => {
20781
20895
  const hasSufficient = ingredient.available >= ingredient.required;
20782
- return /* @__PURE__ */ jsxs(React77.Fragment, { children: [
20896
+ return /* @__PURE__ */ jsxs(React76.Fragment, { children: [
20783
20897
  /* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
20784
20898
  ItemSlot,
20785
20899
  {
@@ -20851,8 +20965,8 @@ function DPad({
20851
20965
  }) {
20852
20966
  const eventBus = useEventBus();
20853
20967
  const sizes = sizeMap6[size];
20854
- const [activeDirections, setActiveDirections] = React77.useState(/* @__PURE__ */ new Set());
20855
- const handlePress = React77.useCallback(
20968
+ const [activeDirections, setActiveDirections] = React76.useState(/* @__PURE__ */ new Set());
20969
+ const handlePress = React76.useCallback(
20856
20970
  (direction) => {
20857
20971
  setActiveDirections((prev) => new Set(prev).add(direction));
20858
20972
  if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
@@ -20860,7 +20974,7 @@ function DPad({
20860
20974
  },
20861
20975
  [directionEvent, eventBus, onDirection]
20862
20976
  );
20863
- const handleRelease = React77.useCallback(
20977
+ const handleRelease = React76.useCallback(
20864
20978
  (direction) => {
20865
20979
  setActiveDirections((prev) => {
20866
20980
  const next = new Set(prev);
@@ -21731,8 +21845,8 @@ var init_Menu = __esm({
21731
21845
  "bottom-end": "bottom-start"
21732
21846
  };
21733
21847
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
21734
- const triggerChild = React77__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
21735
- const triggerElement = React77__default.cloneElement(
21848
+ const triggerChild = React76__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
21849
+ const triggerElement = React76__default.cloneElement(
21736
21850
  triggerChild,
21737
21851
  {
21738
21852
  ref: triggerRef,
@@ -21866,14 +21980,14 @@ function useDataDnd(args) {
21866
21980
  const isZone = Boolean(dragGroup || accepts || sortable);
21867
21981
  const enabled = isZone || Boolean(dndRoot);
21868
21982
  const eventBus = useEventBus();
21869
- const parentRoot = React77__default.useContext(RootCtx);
21983
+ const parentRoot = React76__default.useContext(RootCtx);
21870
21984
  const isRoot = enabled && parentRoot === null;
21871
- const zoneId = React77__default.useId();
21985
+ const zoneId = React76__default.useId();
21872
21986
  const ownGroup = dragGroup ?? accepts ?? zoneId;
21873
- const [optimisticOrders, setOptimisticOrders] = React77__default.useState(() => /* @__PURE__ */ new Map());
21874
- const optimisticOrdersRef = React77__default.useRef(optimisticOrders);
21987
+ const [optimisticOrders, setOptimisticOrders] = React76__default.useState(() => /* @__PURE__ */ new Map());
21988
+ const optimisticOrdersRef = React76__default.useRef(optimisticOrders);
21875
21989
  optimisticOrdersRef.current = optimisticOrders;
21876
- const clearOptimisticOrder = React77__default.useCallback((group) => {
21990
+ const clearOptimisticOrder = React76__default.useCallback((group) => {
21877
21991
  setOptimisticOrders((prev) => {
21878
21992
  if (!prev.has(group)) return prev;
21879
21993
  const next = new Map(prev);
@@ -21898,7 +22012,7 @@ function useDataDnd(args) {
21898
22012
  const raw = it[dndItemIdField];
21899
22013
  return String(raw ?? `__idx_${idx}`);
21900
22014
  }).join("|");
21901
- const itemIds = React77__default.useMemo(
22015
+ const itemIds = React76__default.useMemo(
21902
22016
  () => orderedItems.map((it, idx) => {
21903
22017
  const raw = it[dndItemIdField];
21904
22018
  return raw ?? `__idx_${idx}`;
@@ -21906,7 +22020,7 @@ function useDataDnd(args) {
21906
22020
  [itemIdsSignature]
21907
22021
  );
21908
22022
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
21909
- React77__default.useEffect(() => {
22023
+ React76__default.useEffect(() => {
21910
22024
  const root = isRoot ? null : parentRoot;
21911
22025
  if (root) {
21912
22026
  root.clearOptimisticOrder(ownGroup);
@@ -21914,20 +22028,20 @@ function useDataDnd(args) {
21914
22028
  clearOptimisticOrder(ownGroup);
21915
22029
  }
21916
22030
  }, [itemsContentSig, ownGroup]);
21917
- const zonesRef = React77__default.useRef(/* @__PURE__ */ new Map());
21918
- const registerZone = React77__default.useCallback((zoneId2, meta2) => {
22031
+ const zonesRef = React76__default.useRef(/* @__PURE__ */ new Map());
22032
+ const registerZone = React76__default.useCallback((zoneId2, meta2) => {
21919
22033
  zonesRef.current.set(zoneId2, meta2);
21920
22034
  }, []);
21921
- const unregisterZone = React77__default.useCallback((zoneId2) => {
22035
+ const unregisterZone = React76__default.useCallback((zoneId2) => {
21922
22036
  zonesRef.current.delete(zoneId2);
21923
22037
  }, []);
21924
- const [activeDrag, setActiveDrag] = React77__default.useState(null);
21925
- const [overZoneGroup, setOverZoneGroup] = React77__default.useState(null);
21926
- const meta = React77__default.useMemo(
22038
+ const [activeDrag, setActiveDrag] = React76__default.useState(null);
22039
+ const [overZoneGroup, setOverZoneGroup] = React76__default.useState(null);
22040
+ const meta = React76__default.useMemo(
21927
22041
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
21928
22042
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
21929
22043
  );
21930
- React77__default.useEffect(() => {
22044
+ React76__default.useEffect(() => {
21931
22045
  const target = isRoot ? null : parentRoot;
21932
22046
  if (!target) {
21933
22047
  zonesRef.current.set(zoneId, meta);
@@ -21946,7 +22060,7 @@ function useDataDnd(args) {
21946
22060
  }, [parentRoot, isRoot, zoneId, meta]);
21947
22061
  const sensors = useAlmadarDndSensors(true);
21948
22062
  const collisionDetection = almadarDndCollisionDetection;
21949
- const findZoneByItem = React77__default.useCallback(
22063
+ const findZoneByItem = React76__default.useCallback(
21950
22064
  (id) => {
21951
22065
  for (const z of zonesRef.current.values()) {
21952
22066
  if (z.itemIds.includes(id)) return z;
@@ -21955,7 +22069,7 @@ function useDataDnd(args) {
21955
22069
  },
21956
22070
  []
21957
22071
  );
21958
- React77__default.useCallback(
22072
+ React76__default.useCallback(
21959
22073
  (group) => {
21960
22074
  for (const z of zonesRef.current.values()) {
21961
22075
  if (z.group === group) return z;
@@ -21964,7 +22078,7 @@ function useDataDnd(args) {
21964
22078
  },
21965
22079
  []
21966
22080
  );
21967
- const handleDragEnd = React77__default.useCallback(
22081
+ const handleDragEnd = React76__default.useCallback(
21968
22082
  (event) => {
21969
22083
  const { active, over } = event;
21970
22084
  const activeIdStr = String(active.id);
@@ -22055,8 +22169,8 @@ function useDataDnd(args) {
22055
22169
  },
22056
22170
  [eventBus]
22057
22171
  );
22058
- const sortableData = React77__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
22059
- const SortableItem = React77__default.useCallback(
22172
+ const sortableData = React76__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
22173
+ const SortableItem = React76__default.useCallback(
22060
22174
  ({ id, children }) => {
22061
22175
  const {
22062
22176
  attributes,
@@ -22096,7 +22210,7 @@ function useDataDnd(args) {
22096
22210
  id: droppableId,
22097
22211
  data: sortableData
22098
22212
  });
22099
- const ctx = React77__default.useContext(RootCtx);
22213
+ const ctx = React76__default.useContext(RootCtx);
22100
22214
  const activeDrag2 = ctx?.activeDrag ?? null;
22101
22215
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
22102
22216
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -22111,7 +22225,7 @@ function useDataDnd(args) {
22111
22225
  showForeignPlaceholder,
22112
22226
  ctxAvailable: ctx != null
22113
22227
  });
22114
- React77__default.useEffect(() => {
22228
+ React76__default.useEffect(() => {
22115
22229
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
22116
22230
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
22117
22231
  return /* @__PURE__ */ jsx(
@@ -22125,11 +22239,11 @@ function useDataDnd(args) {
22125
22239
  }
22126
22240
  );
22127
22241
  };
22128
- const rootContextValue = React77__default.useMemo(
22242
+ const rootContextValue = React76__default.useMemo(
22129
22243
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
22130
22244
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
22131
22245
  );
22132
- const handleDragStart = React77__default.useCallback((event) => {
22246
+ const handleDragStart = React76__default.useCallback((event) => {
22133
22247
  const sourceZone = findZoneByItem(event.active.id);
22134
22248
  const rect = event.active.rect.current.initial;
22135
22249
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -22148,7 +22262,7 @@ function useDataDnd(args) {
22148
22262
  isRoot
22149
22263
  });
22150
22264
  }, [findZoneByItem, isRoot, zoneId]);
22151
- const handleDragOver = React77__default.useCallback((event) => {
22265
+ const handleDragOver = React76__default.useCallback((event) => {
22152
22266
  const { active, over } = event;
22153
22267
  const overData = over?.data?.current;
22154
22268
  const overGroup = overData?.dndGroup ?? null;
@@ -22218,7 +22332,7 @@ function useDataDnd(args) {
22218
22332
  return next;
22219
22333
  });
22220
22334
  }, []);
22221
- const handleDragCancel = React77__default.useCallback((event) => {
22335
+ const handleDragCancel = React76__default.useCallback((event) => {
22222
22336
  setActiveDrag(null);
22223
22337
  setOverZoneGroup(null);
22224
22338
  dndLog.warn("dragCancel", {
@@ -22226,12 +22340,12 @@ function useDataDnd(args) {
22226
22340
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
22227
22341
  });
22228
22342
  }, []);
22229
- const handleDragEndWithCleanup = React77__default.useCallback((event) => {
22343
+ const handleDragEndWithCleanup = React76__default.useCallback((event) => {
22230
22344
  handleDragEnd(event);
22231
22345
  setActiveDrag(null);
22232
22346
  setOverZoneGroup(null);
22233
22347
  }, [handleDragEnd]);
22234
- const wrapContainer = React77__default.useCallback(
22348
+ const wrapContainer = React76__default.useCallback(
22235
22349
  (children) => {
22236
22350
  if (!enabled) return children;
22237
22351
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -22285,7 +22399,7 @@ var init_useDataDnd = __esm({
22285
22399
  init_useAlmadarDndCollision();
22286
22400
  init_Box();
22287
22401
  dndLog = createLogger("almadar:ui:dnd");
22288
- RootCtx = React77__default.createContext(null);
22402
+ RootCtx = React76__default.createContext(null);
22289
22403
  }
22290
22404
  });
22291
22405
  function renderIconInput(icon, props) {
@@ -22811,7 +22925,7 @@ function DataList({
22811
22925
  }) {
22812
22926
  const eventBus = useEventBus();
22813
22927
  const { t } = useTranslate();
22814
- const [visibleCount, setVisibleCount] = React77__default.useState(pageSize || Infinity);
22928
+ const [visibleCount, setVisibleCount] = React76__default.useState(pageSize || Infinity);
22815
22929
  const fieldDefs = fields ?? columns ?? [];
22816
22930
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
22817
22931
  const dnd = useDataDnd({
@@ -22830,7 +22944,7 @@ function DataList({
22830
22944
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
22831
22945
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
22832
22946
  const hasRenderProp = typeof children === "function";
22833
- React77__default.useEffect(() => {
22947
+ React76__default.useEffect(() => {
22834
22948
  const renderItemTypeOf = typeof schemaRenderItem;
22835
22949
  const childrenTypeOf = typeof children;
22836
22950
  if (data.length > 0 && !hasRenderProp) {
@@ -22935,7 +23049,7 @@ function DataList({
22935
23049
  const items2 = data.map((item) => item);
22936
23050
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
22937
23051
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
22938
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React77__default.Fragment, { children: [
23052
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
22939
23053
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
22940
23054
  group.items.map((itemData, index) => {
22941
23055
  const id = itemData.id || `${gi}-${index}`;
@@ -23076,7 +23190,7 @@ function DataList({
23076
23190
  className
23077
23191
  ),
23078
23192
  children: [
23079
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React77__default.Fragment, { children: [
23193
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
23080
23194
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
23081
23195
  group.items.map(
23082
23196
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -23183,8 +23297,8 @@ function ScalarControl({
23183
23297
  }
23184
23298
  const numeric = typeof value === "number";
23185
23299
  const initial = value === null ? "" : String(value);
23186
- const [draft, setDraft] = React77__default.useState(initial);
23187
- React77__default.useEffect(() => setDraft(initial), [initial]);
23300
+ const [draft, setDraft] = React76__default.useState(initial);
23301
+ React76__default.useEffect(() => setDraft(initial), [initial]);
23188
23302
  const commit = () => {
23189
23303
  if (numeric) {
23190
23304
  const n = draft.trim() === "" ? 0 : Number(draft);
@@ -23252,8 +23366,8 @@ function Row({
23252
23366
  onRemove,
23253
23367
  readonly
23254
23368
  }) {
23255
- const [keyDraft, setKeyDraft] = React77__default.useState(rowKey);
23256
- React77__default.useEffect(() => setKeyDraft(rowKey), [rowKey]);
23369
+ const [keyDraft, setKeyDraft] = React76__default.useState(rowKey);
23370
+ React76__default.useEffect(() => setKeyDraft(rowKey), [rowKey]);
23257
23371
  const container = isObj(value) || isArr(value);
23258
23372
  return /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "group w-max min-w-full", children: [
23259
23373
  /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", className: "py-0.5 w-max", children: [
@@ -23296,7 +23410,7 @@ function ContainerNode({
23296
23410
  depth,
23297
23411
  readonly
23298
23412
  }) {
23299
- const [open, setOpen] = React77__default.useState(depth < 2);
23413
+ const [open, setOpen] = React76__default.useState(depth < 2);
23300
23414
  const array = isArr(value);
23301
23415
  const entries = array ? value.map((v, i) => [String(i), v]) : Object.entries(value);
23302
23416
  const setObjValue = (key, next) => {
@@ -23438,7 +23552,7 @@ var init_FormSection = __esm({
23438
23552
  columns = 1,
23439
23553
  className
23440
23554
  }) => {
23441
- const [collapsed, setCollapsed] = React77__default.useState(defaultCollapsed);
23555
+ const [collapsed, setCollapsed] = React76__default.useState(defaultCollapsed);
23442
23556
  const { t } = useTranslate();
23443
23557
  const eventBus = useEventBus();
23444
23558
  const gridClass = {
@@ -23446,7 +23560,7 @@ var init_FormSection = __esm({
23446
23560
  2: "grid-cols-1 md:grid-cols-2",
23447
23561
  3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
23448
23562
  }[columns];
23449
- React77__default.useCallback(() => {
23563
+ React76__default.useCallback(() => {
23450
23564
  if (collapsible) {
23451
23565
  setCollapsed((prev) => !prev);
23452
23566
  eventBus.emit("UI:TOGGLE_COLLAPSE", { collapsed: !collapsed });
@@ -23854,8 +23968,8 @@ function TextLikeControl({
23854
23968
  onCommit
23855
23969
  }) {
23856
23970
  const initial = value === void 0 || value === null ? "" : String(value);
23857
- const [draft, setDraft] = React77__default.useState(initial);
23858
- React77__default.useEffect(() => setDraft(initial), [initial]);
23971
+ const [draft, setDraft] = React76__default.useState(initial);
23972
+ React76__default.useEffect(() => setDraft(initial), [initial]);
23859
23973
  const commit = () => {
23860
23974
  if (numeric) {
23861
23975
  const n = draft.trim() === "" ? 0 : Number(draft);
@@ -24021,14 +24135,14 @@ var init_NodeSlotEditor = __esm({
24021
24135
  isObj2 = (v) => v !== null && v !== void 0 && typeof v === "object" && !Array.isArray(v);
24022
24136
  NodeSlotEditor = ({ value, onChange, className }) => {
24023
24137
  const { type, props, wasArray } = normalize(value);
24024
- const patterns = React77__default.useMemo(() => {
24138
+ const patterns = React76__default.useMemo(() => {
24025
24139
  try {
24026
24140
  return [...getKnownPatterns()].sort();
24027
24141
  } catch {
24028
24142
  return [];
24029
24143
  }
24030
24144
  }, []);
24031
- const options = React77__default.useMemo(
24145
+ const options = React76__default.useMemo(
24032
24146
  () => [{ value: "", label: "\u2014 none \u2014" }, ...patterns.map((p2) => ({ value: p2, label: p2 }))],
24033
24147
  [patterns]
24034
24148
  );
@@ -24040,7 +24154,7 @@ var init_NodeSlotEditor = __esm({
24040
24154
  const pattern = { type: nextType, ...nextProps };
24041
24155
  onChange(wasArray || value === void 0 ? [pattern] : pattern);
24042
24156
  };
24043
- const schemaEntries = React77__default.useMemo(() => {
24157
+ const schemaEntries = React76__default.useMemo(() => {
24044
24158
  if (!type) return [];
24045
24159
  const def = getPatternDefinition(type);
24046
24160
  if (!def?.propsSchema) return [];
@@ -24934,7 +25048,7 @@ var init_Grid = __esm({
24934
25048
  as: Component2 = "div"
24935
25049
  }) => {
24936
25050
  const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
24937
- return React77__default.createElement(
25051
+ return React76__default.createElement(
24938
25052
  Component2,
24939
25053
  {
24940
25054
  className: cn(
@@ -25122,8 +25236,8 @@ var init_Popover = __esm({
25122
25236
  onMouseEnter: handleOpen,
25123
25237
  onMouseLeave: handleClose
25124
25238
  };
25125
- const childElement = React77__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25126
- const triggerElement = React77__default.cloneElement(
25239
+ const childElement = React76__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25240
+ const triggerElement = React76__default.cloneElement(
25127
25241
  childElement,
25128
25242
  {
25129
25243
  ref: triggerRef,
@@ -25429,9 +25543,9 @@ function debug(...args) {
25429
25543
  const [first, ...rest] = args;
25430
25544
  const message = typeof first === "string" ? first : "<debug>";
25431
25545
  if (rest.length === 0 && typeof first === "string") {
25432
- log8.debug(message);
25546
+ log7.debug(message);
25433
25547
  } else {
25434
- log8.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
25548
+ log7.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
25435
25549
  }
25436
25550
  }
25437
25551
  function debugGroup(label) {
@@ -25459,11 +25573,11 @@ function toLogMetaValue(v) {
25459
25573
  }
25460
25574
  return String(v);
25461
25575
  }
25462
- var NAMESPACE, log8;
25576
+ var NAMESPACE, log7;
25463
25577
  var init_debug = __esm({
25464
25578
  "lib/debug.ts"() {
25465
25579
  NAMESPACE = "almadar:ui:debug";
25466
- log8 = createLogger(NAMESPACE);
25580
+ log7 = createLogger(NAMESPACE);
25467
25581
  createLogger("almadar:ui:debug:input");
25468
25582
  createLogger("almadar:ui:debug:collision");
25469
25583
  createLogger("almadar:ui:debug:physics");
@@ -25963,8 +26077,8 @@ var init_Tooltip = __esm({
25963
26077
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
25964
26078
  };
25965
26079
  }, []);
25966
- const triggerElement = React77__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25967
- const trigger = React77__default.cloneElement(triggerElement, {
26080
+ const triggerElement = React76__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
26081
+ const trigger = React76__default.cloneElement(triggerElement, {
25968
26082
  ref: triggerRef,
25969
26083
  onMouseEnter: handleMouseEnter,
25970
26084
  onMouseLeave: handleMouseLeave,
@@ -26050,7 +26164,7 @@ var init_WizardProgress = __esm({
26050
26164
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
26051
26165
  const isActive = index === currentStep;
26052
26166
  const isCompleted = index < currentStep;
26053
- return /* @__PURE__ */ jsxs(React77__default.Fragment, { children: [
26167
+ return /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
26054
26168
  /* @__PURE__ */ jsx(
26055
26169
  "button",
26056
26170
  {
@@ -27095,9 +27209,9 @@ function ScoreDisplay({
27095
27209
  ...rest
27096
27210
  }) {
27097
27211
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof rest.score === "number" && !Number.isNaN(rest.score) ? rest.score : 0;
27098
- const [displayValue, setDisplayValue] = React77.useState(resolvedValue);
27099
- const [isAnimating, setIsAnimating] = React77.useState(false);
27100
- React77.useEffect(() => {
27212
+ const [displayValue, setDisplayValue] = React76.useState(resolvedValue);
27213
+ const [isAnimating, setIsAnimating] = React76.useState(false);
27214
+ React76.useEffect(() => {
27101
27215
  if (!animated || displayValue === resolvedValue) {
27102
27216
  setDisplayValue(resolvedValue);
27103
27217
  return;
@@ -27268,7 +27382,7 @@ function InventoryGrid({
27268
27382
  const eventBus = useEventBus();
27269
27383
  const slotCount = totalSlots ?? items.length;
27270
27384
  const emptySlotCount = Math.max(0, slotCount - items.length);
27271
- const handleSelect = React77.useCallback(
27385
+ const handleSelect = React76.useCallback(
27272
27386
  (id) => {
27273
27387
  onSelect?.(id);
27274
27388
  if (selectEvent) {
@@ -27584,31 +27698,31 @@ function GameCanvas2D({
27584
27698
  assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
27585
27699
  className
27586
27700
  }) {
27587
- const canvasRef = React77.useRef(null);
27588
- const rafRef = React77.useRef(0);
27589
- const frameRef = React77.useRef(0);
27590
- const lastTimeRef = React77.useRef(0);
27591
- const imageCache = React77.useRef(/* @__PURE__ */ new Map());
27701
+ const canvasRef = React76.useRef(null);
27702
+ const rafRef = React76.useRef(0);
27703
+ const frameRef = React76.useRef(0);
27704
+ const lastTimeRef = React76.useRef(0);
27705
+ const imageCache = React76.useRef(/* @__PURE__ */ new Map());
27592
27706
  const emit = useEmitEvent();
27593
- const onDrawRef = React77.useRef(onDraw);
27707
+ const onDrawRef = React76.useRef(onDraw);
27594
27708
  onDrawRef.current = onDraw;
27595
- const onTickRef = React77.useRef(onTick);
27709
+ const onTickRef = React76.useRef(onTick);
27596
27710
  onTickRef.current = onTick;
27597
- const tickEventRef = React77.useRef(tickEvent);
27711
+ const tickEventRef = React76.useRef(tickEvent);
27598
27712
  tickEventRef.current = tickEvent;
27599
- const drawEventRef = React77.useRef(drawEvent);
27713
+ const drawEventRef = React76.useRef(drawEvent);
27600
27714
  drawEventRef.current = drawEvent;
27601
- const emitRef = React77.useRef(emit);
27715
+ const emitRef = React76.useRef(emit);
27602
27716
  emitRef.current = emit;
27603
- const assetBaseUrlRef = React77.useRef(assetBaseUrl);
27717
+ const assetBaseUrlRef = React76.useRef(assetBaseUrl);
27604
27718
  assetBaseUrlRef.current = assetBaseUrl;
27605
- const backgroundImageRef = React77.useRef(backgroundImage);
27719
+ const backgroundImageRef = React76.useRef(backgroundImage);
27606
27720
  backgroundImageRef.current = backgroundImage;
27607
- const widthRef = React77.useRef(width);
27721
+ const widthRef = React76.useRef(width);
27608
27722
  widthRef.current = width;
27609
- const heightRef = React77.useRef(height);
27723
+ const heightRef = React76.useRef(height);
27610
27724
  heightRef.current = height;
27611
- const loadImage = React77.useCallback((url) => {
27725
+ const loadImage = React76.useCallback((url) => {
27612
27726
  const fullUrl = url.startsWith("http") ? url : `${assetBaseUrlRef.current}${url}`;
27613
27727
  const cached = imageCache.current.get(fullUrl);
27614
27728
  if (cached?.complete && cached.naturalWidth > 0) return cached;
@@ -27620,7 +27734,7 @@ function GameCanvas2D({
27620
27734
  }
27621
27735
  return null;
27622
27736
  }, []);
27623
- React77.useEffect(() => {
27737
+ React76.useEffect(() => {
27624
27738
  const canvas = canvasRef.current;
27625
27739
  if (!canvas) return;
27626
27740
  const ctx = canvas.getContext("2d");
@@ -27996,7 +28110,7 @@ function TurnPanel({
27996
28110
  className
27997
28111
  }) {
27998
28112
  const eventBus = useEventBus();
27999
- const handleAction = React77.useCallback(
28113
+ const handleAction = React76.useCallback(
28000
28114
  (event) => {
28001
28115
  if (event) {
28002
28116
  eventBus.emit(event, { turn: currentTurn, phase, activeTeam });
@@ -28165,7 +28279,7 @@ function UnitCommandBar({
28165
28279
  className
28166
28280
  }) {
28167
28281
  const eventBus = useEventBus();
28168
- const handleCommand = React77.useCallback(
28282
+ const handleCommand = React76.useCallback(
28169
28283
  (event) => {
28170
28284
  if (event) {
28171
28285
  eventBus.emit(event, { unitId: selectedUnitId });
@@ -28679,7 +28793,7 @@ function GameMenu({
28679
28793
  } catch {
28680
28794
  }
28681
28795
  const eventBus = eventBusProp || eventBusFromHook;
28682
- const handleOptionClick = React77.useCallback(
28796
+ const handleOptionClick = React76.useCallback(
28683
28797
  (option) => {
28684
28798
  if (option.event && eventBus) {
28685
28799
  eventBus.emit(`UI:${option.event}`, { option });
@@ -28798,7 +28912,7 @@ function GameOverScreen({
28798
28912
  } catch {
28799
28913
  }
28800
28914
  const eventBus = eventBusProp || eventBusFromHook;
28801
- const handleActionClick = React77.useCallback(
28915
+ const handleActionClick = React76.useCallback(
28802
28916
  (action) => {
28803
28917
  if (action.event && eventBus) {
28804
28918
  eventBus.emit(`UI:${action.event}`, { action });
@@ -29709,12 +29823,12 @@ var init_MapView = __esm({
29709
29823
  shadowSize: [41, 41]
29710
29824
  });
29711
29825
  L.Marker.prototype.options.icon = defaultIcon;
29712
- const { useEffect: useEffect80, useRef: useRef77, useCallback: useCallback120, useState: useState110 } = React77__default;
29826
+ const { useEffect: useEffect80, useRef: useRef78, useCallback: useCallback120, useState: useState110 } = React76__default;
29713
29827
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
29714
29828
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
29715
29829
  function MapUpdater({ centerLat, centerLng, zoom }) {
29716
29830
  const map = useMap();
29717
- const prevRef = useRef77({ centerLat, centerLng, zoom });
29831
+ const prevRef = useRef78({ centerLat, centerLng, zoom });
29718
29832
  useEffect80(() => {
29719
29833
  const prev = prevRef.current;
29720
29834
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
@@ -30615,8 +30729,8 @@ function TableView({
30615
30729
  }) {
30616
30730
  const eventBus = useEventBus();
30617
30731
  const { t } = useTranslate();
30618
- const [visibleCount, setVisibleCount] = React77__default.useState(pageSize > 0 ? pageSize : Infinity);
30619
- const [localSelected, setLocalSelected] = React77__default.useState(/* @__PURE__ */ new Set());
30732
+ const [visibleCount, setVisibleCount] = React76__default.useState(pageSize > 0 ? pageSize : Infinity);
30733
+ const [localSelected, setLocalSelected] = React76__default.useState(/* @__PURE__ */ new Set());
30620
30734
  const colDefs = columns ?? fields ?? [];
30621
30735
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
30622
30736
  const dnd = useDataDnd({
@@ -30811,12 +30925,12 @@ function TableView({
30811
30925
  ]
30812
30926
  }
30813
30927
  );
30814
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React77__default.Fragment, { children: rowInner }, id);
30928
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React76__default.Fragment, { children: rowInner }, id);
30815
30929
  };
30816
30930
  const items = data.map((row) => row);
30817
30931
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
30818
30932
  let runningIndex = 0;
30819
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React77__default.Fragment, { children: [
30933
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
30820
30934
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
30821
30935
  group.items.map((row) => renderRow(row, runningIndex++))
30822
30936
  ] }, gi)) });
@@ -32173,7 +32287,7 @@ var init_StepFlow = __esm({
32173
32287
  className
32174
32288
  }) => {
32175
32289
  if (orientation === "vertical") {
32176
- return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React77__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
32290
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React76__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
32177
32291
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
32178
32292
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
32179
32293
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -32184,7 +32298,7 @@ var init_StepFlow = __esm({
32184
32298
  ] })
32185
32299
  ] }) }, index)) });
32186
32300
  }
32187
- 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(React77__default.Fragment, { children: [
32301
+ 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(React76__default.Fragment, { children: [
32188
32302
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
32189
32303
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
32190
32304
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -33169,7 +33283,7 @@ var init_LikertScale = __esm({
33169
33283
  md: "text-base",
33170
33284
  lg: "text-lg"
33171
33285
  };
33172
- LikertScale = React77__default.forwardRef(
33286
+ LikertScale = React76__default.forwardRef(
33173
33287
  ({
33174
33288
  question,
33175
33289
  options = DEFAULT_LIKERT_OPTIONS,
@@ -33181,7 +33295,7 @@ var init_LikertScale = __esm({
33181
33295
  variant = "radios",
33182
33296
  className
33183
33297
  }, ref) => {
33184
- const groupId = React77__default.useId();
33298
+ const groupId = React76__default.useId();
33185
33299
  const eventBus = useEventBus();
33186
33300
  const handleSelect = useCallback(
33187
33301
  (next) => {
@@ -35463,7 +35577,7 @@ var init_DocBreadcrumb = __esm({
35463
35577
  "aria-label": t("aria.breadcrumb"),
35464
35578
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
35465
35579
  const isLast = idx === items.length - 1;
35466
- return /* @__PURE__ */ jsxs(React77__default.Fragment, { children: [
35580
+ return /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
35467
35581
  idx > 0 && /* @__PURE__ */ jsx(
35468
35582
  Icon,
35469
35583
  {
@@ -36332,7 +36446,7 @@ var init_MiniStateMachine = __esm({
36332
36446
  const x = 2 + i * (NODE_W + GAP2 + ARROW_W + GAP2);
36333
36447
  const tc = transitionCounts[s.name] ?? 0;
36334
36448
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
36335
- return /* @__PURE__ */ jsxs(React77__default.Fragment, { children: [
36449
+ return /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
36336
36450
  /* @__PURE__ */ jsx(
36337
36451
  AvlState,
36338
36452
  {
@@ -36536,7 +36650,7 @@ var init_PageHeader = __esm({
36536
36650
  info: "bg-info/10 text-info"
36537
36651
  };
36538
36652
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
36539
- 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(React77__default.Fragment, { children: [
36653
+ 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(React76__default.Fragment, { children: [
36540
36654
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
36541
36655
  crumb.href ? /* @__PURE__ */ jsx(
36542
36656
  "a",
@@ -37265,7 +37379,7 @@ var init_WizardContainer = __esm({
37265
37379
  const isCompleted = index < currentStep;
37266
37380
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
37267
37381
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
37268
- return /* @__PURE__ */ jsxs(React77__default.Fragment, { children: [
37382
+ return /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
37269
37383
  /* @__PURE__ */ jsx(
37270
37384
  Button,
37271
37385
  {
@@ -39850,7 +39964,7 @@ var init_DialogueBubble = __esm({
39850
39964
  }
39851
39965
  });
39852
39966
  function extractTitle(children) {
39853
- if (!React77__default.isValidElement(children)) return void 0;
39967
+ if (!React76__default.isValidElement(children)) return void 0;
39854
39968
  const props = children.props;
39855
39969
  if (typeof props.title === "string") {
39856
39970
  return props.title;
@@ -39975,7 +40089,7 @@ function LinearView({
39975
40089
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
39976
40090
  const isDone = i < currentIdx;
39977
40091
  const isCurrent = i === currentIdx;
39978
- return /* @__PURE__ */ jsxs(React77__default.Fragment, { children: [
40092
+ return /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
39979
40093
  i > 0 && /* @__PURE__ */ jsx(
39980
40094
  Typography,
39981
40095
  {
@@ -40925,12 +41039,12 @@ var init_Form = __esm({
40925
41039
  const isSchemaEntity = isOrbitalEntitySchema(entity);
40926
41040
  const resolvedEntity = isSchemaEntity ? entity : void 0;
40927
41041
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
40928
- const normalizedInitialData = React77__default.useMemo(() => {
41042
+ const normalizedInitialData = React76__default.useMemo(() => {
40929
41043
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
40930
41044
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
40931
41045
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
40932
41046
  }, [entity, initialData]);
40933
- const entityDerivedFields = React77__default.useMemo(() => {
41047
+ const entityDerivedFields = React76__default.useMemo(() => {
40934
41048
  if (fields && fields.length > 0) return void 0;
40935
41049
  if (!resolvedEntity) return void 0;
40936
41050
  return resolvedEntity.fields.map(
@@ -40950,16 +41064,16 @@ var init_Form = __esm({
40950
41064
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
40951
41065
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
40952
41066
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
40953
- const [formData, setFormData] = React77__default.useState(
41067
+ const [formData, setFormData] = React76__default.useState(
40954
41068
  normalizedInitialData
40955
41069
  );
40956
- const [collapsedSections, setCollapsedSections] = React77__default.useState(
41070
+ const [collapsedSections, setCollapsedSections] = React76__default.useState(
40957
41071
  /* @__PURE__ */ new Set()
40958
41072
  );
40959
- const [submitError, setSubmitError] = React77__default.useState(null);
40960
- const formRef = React77__default.useRef(null);
41073
+ const [submitError, setSubmitError] = React76__default.useState(null);
41074
+ const formRef = React76__default.useRef(null);
40961
41075
  const formMode = props.mode;
40962
- const mountedRef = React77__default.useRef(false);
41076
+ const mountedRef = React76__default.useRef(false);
40963
41077
  if (!mountedRef.current) {
40964
41078
  mountedRef.current = true;
40965
41079
  debug("forms", "mount", {
@@ -40972,7 +41086,7 @@ var init_Form = __esm({
40972
41086
  });
40973
41087
  }
40974
41088
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
40975
- const evalContext = React77__default.useMemo(
41089
+ const evalContext = React76__default.useMemo(
40976
41090
  () => ({
40977
41091
  formValues: formData,
40978
41092
  globalVariables: externalContext?.globalVariables ?? {},
@@ -40981,7 +41095,7 @@ var init_Form = __esm({
40981
41095
  }),
40982
41096
  [formData, externalContext]
40983
41097
  );
40984
- React77__default.useEffect(() => {
41098
+ React76__default.useEffect(() => {
40985
41099
  debug("forms", "initialData-sync", {
40986
41100
  mode: formMode,
40987
41101
  normalizedInitialData,
@@ -40992,7 +41106,7 @@ var init_Form = __esm({
40992
41106
  setFormData(normalizedInitialData);
40993
41107
  }
40994
41108
  }, [normalizedInitialData]);
40995
- const processCalculations = React77__default.useCallback(
41109
+ const processCalculations = React76__default.useCallback(
40996
41110
  (changedFieldId, newFormData) => {
40997
41111
  if (!hiddenCalculations.length) return;
40998
41112
  const context = {
@@ -41017,7 +41131,7 @@ var init_Form = __esm({
41017
41131
  },
41018
41132
  [hiddenCalculations, externalContext, eventBus]
41019
41133
  );
41020
- const checkViolations = React77__default.useCallback(
41134
+ const checkViolations = React76__default.useCallback(
41021
41135
  (changedFieldId, newFormData) => {
41022
41136
  if (!violationTriggers.length) return;
41023
41137
  const context = {
@@ -41055,7 +41169,7 @@ var init_Form = __esm({
41055
41169
  processCalculations(name, newFormData);
41056
41170
  checkViolations(name, newFormData);
41057
41171
  };
41058
- const isFieldVisible = React77__default.useCallback(
41172
+ const isFieldVisible = React76__default.useCallback(
41059
41173
  (fieldName) => {
41060
41174
  const condition = conditionalFields[fieldName];
41061
41175
  if (!condition) return true;
@@ -41063,7 +41177,7 @@ var init_Form = __esm({
41063
41177
  },
41064
41178
  [conditionalFields, evalContext]
41065
41179
  );
41066
- const isSectionVisible = React77__default.useCallback(
41180
+ const isSectionVisible = React76__default.useCallback(
41067
41181
  (section) => {
41068
41182
  if (!section.condition) return true;
41069
41183
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -41139,7 +41253,7 @@ var init_Form = __esm({
41139
41253
  eventBus.emit(`UI:${onCancel}`);
41140
41254
  }
41141
41255
  };
41142
- const renderField = React77__default.useCallback(
41256
+ const renderField = React76__default.useCallback(
41143
41257
  (field) => {
41144
41258
  const fieldName = field.name || field.field;
41145
41259
  if (!fieldName) return null;
@@ -41160,7 +41274,7 @@ var init_Form = __esm({
41160
41274
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
41161
41275
  );
41162
41276
  const effectiveFields = entityDerivedFields ?? fields;
41163
- const normalizedFields = React77__default.useMemo(() => {
41277
+ const normalizedFields = React76__default.useMemo(() => {
41164
41278
  if (!effectiveFields || effectiveFields.length === 0) return [];
41165
41279
  return effectiveFields.map((field) => {
41166
41280
  if (typeof field === "string") {
@@ -41183,7 +41297,7 @@ var init_Form = __esm({
41183
41297
  return field;
41184
41298
  });
41185
41299
  }, [effectiveFields, resolvedEntity]);
41186
- const schemaFields = React77__default.useMemo(() => {
41300
+ const schemaFields = React76__default.useMemo(() => {
41187
41301
  if (normalizedFields.length === 0) return null;
41188
41302
  if (isDebugEnabled()) {
41189
41303
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -41193,7 +41307,7 @@ var init_Form = __esm({
41193
41307
  }
41194
41308
  return normalizedFields.map(renderField).filter(Boolean);
41195
41309
  }, [normalizedFields, renderField, entityName, conditionalFields]);
41196
- const sectionElements = React77__default.useMemo(() => {
41310
+ const sectionElements = React76__default.useMemo(() => {
41197
41311
  if (!sections || sections.length === 0) return null;
41198
41312
  return sections.map((section) => {
41199
41313
  if (!isSectionVisible(section)) {
@@ -41809,7 +41923,7 @@ var init_AssetLoader = __esm({
41809
41923
  __publicField(this, "textureCache");
41810
41924
  __publicField(this, "loadingPromises");
41811
41925
  this.objLoader = new OBJLoader();
41812
- this.textureLoader = new THREE.TextureLoader();
41926
+ this.textureLoader = new THREE3.TextureLoader();
41813
41927
  this.modelCache = /* @__PURE__ */ new Map();
41814
41928
  this.textureCache = /* @__PURE__ */ new Map();
41815
41929
  this.loadingPromises = /* @__PURE__ */ new Map();
@@ -41883,7 +41997,7 @@ var init_AssetLoader = __esm({
41883
41997
  return this.loadingPromises.get(`texture:${url}`);
41884
41998
  }
41885
41999
  const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
41886
- texture.colorSpace = THREE.SRGBColorSpace;
42000
+ texture.colorSpace = THREE3.SRGBColorSpace;
41887
42001
  this.textureCache.set(url, texture);
41888
42002
  this.loadingPromises.delete(`texture:${url}`);
41889
42003
  return texture;
@@ -41957,7 +42071,7 @@ var init_AssetLoader = __esm({
41957
42071
  });
41958
42072
  this.modelCache.forEach((model) => {
41959
42073
  model.scene.traverse((child) => {
41960
- if (child instanceof THREE.Mesh) {
42074
+ if (child instanceof THREE3.Mesh) {
41961
42075
  child.geometry.dispose();
41962
42076
  if (Array.isArray(child.material)) {
41963
42077
  child.material.forEach((m) => m.dispose());
@@ -42370,11 +42484,11 @@ var init_Canvas3DErrorBoundary = __esm({
42370
42484
  "components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
42371
42485
  }
42372
42486
  });
42373
- var log9, Canvas3DErrorBoundary;
42487
+ var log8, Canvas3DErrorBoundary;
42374
42488
  var init_Canvas3DErrorBoundary2 = __esm({
42375
42489
  "components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
42376
42490
  init_Canvas3DErrorBoundary();
42377
- log9 = createLogger("almadar:ui:game:canvas3d:error-boundary");
42491
+ log8 = createLogger("almadar:ui:game:canvas3d:error-boundary");
42378
42492
  Canvas3DErrorBoundary = class extends Component {
42379
42493
  constructor(props) {
42380
42494
  super(props);
@@ -42402,8 +42516,8 @@ var init_Canvas3DErrorBoundary2 = __esm({
42402
42516
  componentDidCatch(error, errorInfo) {
42403
42517
  this.setState({ errorInfo });
42404
42518
  this.props.onError?.(error, errorInfo);
42405
- log9.error("Error caught", { error });
42406
- log9.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
42519
+ log8.error("Error caught", { error });
42520
+ log8.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
42407
42521
  }
42408
42522
  render() {
42409
42523
  if (this.state.hasError) {
@@ -42466,7 +42580,7 @@ function useGLTFModel(url, resourceBasePath) {
42466
42580
  setState({ model: null, isLoading: false, error: null });
42467
42581
  return;
42468
42582
  }
42469
- log10.debug("Loading", { url });
42583
+ log9.debug("Loading", { url });
42470
42584
  setState((prev) => ({ ...prev, isLoading: true, error: null }));
42471
42585
  const assetRoot = resourceBasePath || detectAssetRoot2(url);
42472
42586
  const loader = new GLTFLoader$1();
@@ -42474,7 +42588,7 @@ function useGLTFModel(url, resourceBasePath) {
42474
42588
  loader.load(
42475
42589
  url,
42476
42590
  (gltf) => {
42477
- log10.debug("Loaded", { url });
42591
+ log9.debug("Loaded", { url });
42478
42592
  setState({
42479
42593
  model: gltf.scene,
42480
42594
  isLoading: false,
@@ -42483,7 +42597,7 @@ function useGLTFModel(url, resourceBasePath) {
42483
42597
  },
42484
42598
  void 0,
42485
42599
  (err) => {
42486
- log10.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
42600
+ log9.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
42487
42601
  setState({
42488
42602
  model: null,
42489
42603
  isLoading: false,
@@ -42513,7 +42627,7 @@ function ModelLoader({
42513
42627
  if (!loadedModel) return null;
42514
42628
  const cloned = loadedModel.clone();
42515
42629
  cloned.traverse((child) => {
42516
- if (child instanceof THREE.Mesh) {
42630
+ if (child instanceof THREE3.Mesh) {
42517
42631
  child.castShadow = castShadow;
42518
42632
  child.receiveShadow = receiveShadow;
42519
42633
  }
@@ -42599,11 +42713,11 @@ function ModelLoader({
42599
42713
  }
42600
42714
  );
42601
42715
  }
42602
- var log10;
42716
+ var log9;
42603
42717
  var init_ModelLoader = __esm({
42604
42718
  "components/game/molecules/three/components/ModelLoader.tsx"() {
42605
42719
  "use client";
42606
- log10 = createLogger("almadar:ui:game:model-loader");
42720
+ log9 = createLogger("almadar:ui:game:model-loader");
42607
42721
  }
42608
42722
  });
42609
42723
 
@@ -42627,6 +42741,47 @@ function CameraController({
42627
42741
  }, [camera.position, onCameraChange]);
42628
42742
  return null;
42629
42743
  }
42744
+ function UnitSpriteBillboard({
42745
+ sheetUrl,
42746
+ resolveFrame: resolveFrame2,
42747
+ height = 1.2
42748
+ }) {
42749
+ const texture = useLoader(THREE3.TextureLoader, sheetUrl);
42750
+ const meshRef = useRef(null);
42751
+ const matRef = useRef(null);
42752
+ const [aspect, setAspect] = useState(1);
42753
+ useFrame(() => {
42754
+ const frame = resolveFrame2();
42755
+ if (!frame || !texture.image) return;
42756
+ const imgW = texture.image.width;
42757
+ const imgH = texture.image.height;
42758
+ if (!imgW || !imgH) return;
42759
+ texture.repeat.set((frame.flipX ? -1 : 1) * (frame.sw / imgW), frame.sh / imgH);
42760
+ texture.offset.set(
42761
+ frame.flipX ? (frame.sx + frame.sw) / imgW : frame.sx / imgW,
42762
+ 1 - (frame.sy + frame.sh) / imgH
42763
+ );
42764
+ texture.magFilter = THREE3.NearestFilter;
42765
+ texture.minFilter = THREE3.NearestFilter;
42766
+ texture.needsUpdate = true;
42767
+ const nextAspect = frame.sw / frame.sh;
42768
+ if (Math.abs(nextAspect - aspect) > 1e-3) setAspect(nextAspect);
42769
+ if (matRef.current) matRef.current.needsUpdate = true;
42770
+ });
42771
+ return /* @__PURE__ */ jsxs("mesh", { ref: meshRef, position: [0, height / 2, 0], children: [
42772
+ /* @__PURE__ */ jsx("planeGeometry", { args: [height * aspect, height] }),
42773
+ /* @__PURE__ */ jsx(
42774
+ "meshBasicMaterial",
42775
+ {
42776
+ ref: matRef,
42777
+ map: texture,
42778
+ transparent: true,
42779
+ alphaTest: 0.1,
42780
+ side: THREE3.DoubleSide
42781
+ }
42782
+ )
42783
+ ] });
42784
+ }
42630
42785
  var DEFAULT_GRID_CONFIG, GameCanvas3D;
42631
42786
  var init_GameCanvas3D2 = __esm({
42632
42787
  "components/game/molecules/GameCanvas3D.tsx"() {
@@ -42637,6 +42792,7 @@ var init_GameCanvas3D2 = __esm({
42637
42792
  init_Canvas3DLoadingState2();
42638
42793
  init_Canvas3DErrorBoundary2();
42639
42794
  init_ModelLoader();
42795
+ init_useUnitSpriteAtlas();
42640
42796
  init_cn();
42641
42797
  init_GameCanvas3D();
42642
42798
  DEFAULT_GRID_CONFIG = {
@@ -42693,8 +42849,10 @@ var init_GameCanvas3D2 = __esm({
42693
42849
  const controlsRef = useRef(null);
42694
42850
  const [hoveredTile, setHoveredTile] = useState(null);
42695
42851
  const [internalError, setInternalError] = useState(null);
42852
+ const { sheetUrls: atlasSheetUrls, resolveUnitFrame } = useUnitSpriteAtlas(units);
42853
+ const preloadUrls = useMemo(() => [...preloadAssets, ...atlasSheetUrls], [preloadAssets, atlasSheetUrls]);
42696
42854
  const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
42697
- preloadUrls: preloadAssets,
42855
+ preloadUrls,
42698
42856
  loader: customAssetLoader
42699
42857
  });
42700
42858
  const eventHandlers = useGameCanvas3DEvents({
@@ -42753,7 +42911,7 @@ var init_GameCanvas3D2 = __esm({
42753
42911
  getCameraPosition: () => {
42754
42912
  if (controlsRef.current) {
42755
42913
  const pos = controlsRef.current.object.position;
42756
- return new THREE.Vector3(pos.x, pos.y, pos.z);
42914
+ return new THREE3.Vector3(pos.x, pos.y, pos.z);
42757
42915
  }
42758
42916
  return null;
42759
42917
  },
@@ -42905,6 +43063,8 @@ var init_GameCanvas3D2 = __esm({
42905
43063
  ({ unit, position }) => {
42906
43064
  const isSelected = selectedUnitId === unit.id;
42907
43065
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
43066
+ const hasAtlas = unitAtlasUrl(unit) !== null;
43067
+ const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
42908
43068
  return /* @__PURE__ */ jsxs(
42909
43069
  "group",
42910
43070
  {
@@ -42916,7 +43076,16 @@ var init_GameCanvas3D2 = __esm({
42916
43076
  /* @__PURE__ */ jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
42917
43077
  /* @__PURE__ */ jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
42918
43078
  ] }),
42919
- unit.modelUrl ? (
43079
+ hasAtlas && initialFrame ? (
43080
+ /* Animated sprite-sheet billboard — single cropped frame, by state */
43081
+ /* @__PURE__ */ jsx(Billboard, { children: /* @__PURE__ */ jsx(
43082
+ UnitSpriteBillboard,
43083
+ {
43084
+ sheetUrl: initialFrame.sheetUrl,
43085
+ resolveFrame: () => resolveUnitFrame(unit.id)
43086
+ }
43087
+ ) })
43088
+ ) : unit.modelUrl ? (
42920
43089
  /* GLB unit model (box fallback while loading / on error) */
42921
43090
  /* @__PURE__ */ jsx(
42922
43091
  ModelLoader,
@@ -42970,7 +43139,7 @@ var init_GameCanvas3D2 = __esm({
42970
43139
  }
42971
43140
  );
42972
43141
  },
42973
- [selectedUnitId, handleUnitClick]
43142
+ [selectedUnitId, handleUnitClick, resolveUnitFrame]
42974
43143
  );
42975
43144
  const DefaultFeatureRenderer = useCallback(
42976
43145
  ({
@@ -44037,7 +44206,7 @@ var init_List = __esm({
44037
44206
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
44038
44207
  return [];
44039
44208
  }, [entity]);
44040
- const getItemActions = React77__default.useCallback(
44209
+ const getItemActions = React76__default.useCallback(
44041
44210
  (item) => {
44042
44211
  if (!itemActions) return [];
44043
44212
  if (typeof itemActions === "function") {
@@ -44513,7 +44682,7 @@ var init_MediaGallery = __esm({
44513
44682
  [selectable, selectedItems, selectionEvent, eventBus]
44514
44683
  );
44515
44684
  const entityData = Array.isArray(entity) ? entity : [];
44516
- const items = React77__default.useMemo(() => {
44685
+ const items = React76__default.useMemo(() => {
44517
44686
  if (propItems) return propItems;
44518
44687
  if (entityData.length === 0) return [];
44519
44688
  return entityData.map((record, idx) => ({
@@ -44683,9 +44852,9 @@ function MiniMap({
44683
44852
  viewportRect = DEFAULT_VIEWPORT,
44684
44853
  className
44685
44854
  }) {
44686
- const canvasRef = React77.useRef(null);
44687
- const frameRef = React77.useRef(0);
44688
- React77.useEffect(() => {
44855
+ const canvasRef = React76.useRef(null);
44856
+ const frameRef = React76.useRef(0);
44857
+ React76.useEffect(() => {
44689
44858
  const canvas = canvasRef.current;
44690
44859
  if (!canvas) return;
44691
44860
  const ctx = canvas.getContext("2d");
@@ -44782,7 +44951,7 @@ var init_MiniMap = __esm({
44782
44951
  }
44783
44952
  });
44784
44953
  function extractTitle2(children) {
44785
- if (!React77__default.isValidElement(children)) return void 0;
44954
+ if (!React76__default.isValidElement(children)) return void 0;
44786
44955
  const props = children.props;
44787
44956
  if (typeof props.title === "string") {
44788
44957
  return props.title;
@@ -45853,7 +46022,7 @@ var init_debugRegistry = __esm({
45853
46022
  }
45854
46023
  });
45855
46024
  function useDebugData() {
45856
- const [data, setData] = React77.useState(() => ({
46025
+ const [data, setData] = React76.useState(() => ({
45857
46026
  traits: [],
45858
46027
  ticks: [],
45859
46028
  guards: [],
@@ -45867,7 +46036,7 @@ function useDebugData() {
45867
46036
  },
45868
46037
  lastUpdate: Date.now()
45869
46038
  }));
45870
- React77.useEffect(() => {
46039
+ React76.useEffect(() => {
45871
46040
  const updateData = () => {
45872
46041
  setData({
45873
46042
  traits: getAllTraits(),
@@ -45976,12 +46145,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
45976
46145
  return positions;
45977
46146
  }
45978
46147
  function WalkMinimap() {
45979
- const [walkStep, setWalkStep] = React77.useState(null);
45980
- const [traits2, setTraits] = React77.useState([]);
45981
- const [coveredEdges, setCoveredEdges] = React77.useState([]);
45982
- const [completedTraits, setCompletedTraits] = React77.useState(/* @__PURE__ */ new Set());
45983
- const prevTraitRef = React77.useRef(null);
45984
- React77.useEffect(() => {
46148
+ const [walkStep, setWalkStep] = React76.useState(null);
46149
+ const [traits2, setTraits] = React76.useState([]);
46150
+ const [coveredEdges, setCoveredEdges] = React76.useState([]);
46151
+ const [completedTraits, setCompletedTraits] = React76.useState(/* @__PURE__ */ new Set());
46152
+ const prevTraitRef = React76.useRef(null);
46153
+ React76.useEffect(() => {
45985
46154
  const interval = setInterval(() => {
45986
46155
  const w = window;
45987
46156
  const step = w.__orbitalWalkStep;
@@ -46417,15 +46586,15 @@ var init_EntitiesTab = __esm({
46417
46586
  });
46418
46587
  function EventFlowTab({ events: events2 }) {
46419
46588
  const { t } = useTranslate();
46420
- const [filter, setFilter] = React77.useState("all");
46421
- const containerRef = React77.useRef(null);
46422
- const [autoScroll, setAutoScroll] = React77.useState(true);
46423
- React77.useEffect(() => {
46589
+ const [filter, setFilter] = React76.useState("all");
46590
+ const containerRef = React76.useRef(null);
46591
+ const [autoScroll, setAutoScroll] = React76.useState(true);
46592
+ React76.useEffect(() => {
46424
46593
  if (autoScroll && containerRef.current) {
46425
46594
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
46426
46595
  }
46427
46596
  }, [events2.length, autoScroll]);
46428
- const filteredEvents = React77.useMemo(() => {
46597
+ const filteredEvents = React76.useMemo(() => {
46429
46598
  if (filter === "all") return events2;
46430
46599
  return events2.filter((e) => e.type === filter);
46431
46600
  }, [events2, filter]);
@@ -46541,7 +46710,7 @@ var init_EventFlowTab = __esm({
46541
46710
  });
46542
46711
  function GuardsPanel({ guards }) {
46543
46712
  const { t } = useTranslate();
46544
- const [filter, setFilter] = React77.useState("all");
46713
+ const [filter, setFilter] = React76.useState("all");
46545
46714
  if (guards.length === 0) {
46546
46715
  return /* @__PURE__ */ jsx(
46547
46716
  EmptyState,
@@ -46554,7 +46723,7 @@ function GuardsPanel({ guards }) {
46554
46723
  }
46555
46724
  const passedCount = guards.filter((g) => g.result).length;
46556
46725
  const failedCount = guards.length - passedCount;
46557
- const filteredGuards = React77.useMemo(() => {
46726
+ const filteredGuards = React76.useMemo(() => {
46558
46727
  if (filter === "all") return guards;
46559
46728
  if (filter === "passed") return guards.filter((g) => g.result);
46560
46729
  return guards.filter((g) => !g.result);
@@ -46717,10 +46886,10 @@ function EffectBadge({ effect }) {
46717
46886
  }
46718
46887
  function TransitionTimeline({ transitions }) {
46719
46888
  const { t } = useTranslate();
46720
- const containerRef = React77.useRef(null);
46721
- const [autoScroll, setAutoScroll] = React77.useState(true);
46722
- const [expandedId, setExpandedId] = React77.useState(null);
46723
- React77.useEffect(() => {
46889
+ const containerRef = React76.useRef(null);
46890
+ const [autoScroll, setAutoScroll] = React76.useState(true);
46891
+ const [expandedId, setExpandedId] = React76.useState(null);
46892
+ React76.useEffect(() => {
46724
46893
  if (autoScroll && containerRef.current) {
46725
46894
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
46726
46895
  }
@@ -47000,9 +47169,9 @@ function getAllEvents(traits2) {
47000
47169
  function EventDispatcherTab({ traits: traits2, schema }) {
47001
47170
  const eventBus = useEventBus();
47002
47171
  const { t } = useTranslate();
47003
- const [log11, setLog] = React77.useState([]);
47004
- const prevStatesRef = React77.useRef(/* @__PURE__ */ new Map());
47005
- React77.useEffect(() => {
47172
+ const [log10, setLog] = React76.useState([]);
47173
+ const prevStatesRef = React76.useRef(/* @__PURE__ */ new Map());
47174
+ React76.useEffect(() => {
47006
47175
  for (const trait of traits2) {
47007
47176
  const prev = prevStatesRef.current.get(trait.id);
47008
47177
  if (prev && prev !== trait.currentState) {
@@ -47064,9 +47233,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
47064
47233
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
47065
47234
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: unavailableEvents.map((event) => /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", className: "opacity-50", children: event }, event)) })
47066
47235
  ] }),
47067
- log11.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
47236
+ log10.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
47068
47237
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
47069
- /* @__PURE__ */ jsx(Stack, { gap: "xs", children: log11.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
47238
+ /* @__PURE__ */ jsx(Stack, { gap: "xs", children: log10.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
47070
47239
  /* @__PURE__ */ jsx("span", { className: "text-purple-400", children: entry.traitName }),
47071
47240
  " ",
47072
47241
  /* @__PURE__ */ jsx("span", { className: "text-gray-500", children: entry.from }),
@@ -47171,10 +47340,10 @@ function VerifyModePanel({
47171
47340
  localCount
47172
47341
  }) {
47173
47342
  const { t } = useTranslate();
47174
- const [expanded, setExpanded] = React77.useState(true);
47175
- const scrollRef = React77.useRef(null);
47176
- const prevCountRef = React77.useRef(0);
47177
- React77.useEffect(() => {
47343
+ const [expanded, setExpanded] = React76.useState(true);
47344
+ const scrollRef = React76.useRef(null);
47345
+ const prevCountRef = React76.useRef(0);
47346
+ React76.useEffect(() => {
47178
47347
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
47179
47348
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
47180
47349
  }
@@ -47231,10 +47400,10 @@ function RuntimeDebugger({
47231
47400
  schema
47232
47401
  }) {
47233
47402
  const { t } = useTranslate();
47234
- const [isCollapsed, setIsCollapsed] = React77.useState(mode === "verify" ? true : defaultCollapsed);
47235
- const [isVisible, setIsVisible] = React77.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
47403
+ const [isCollapsed, setIsCollapsed] = React76.useState(mode === "verify" ? true : defaultCollapsed);
47404
+ const [isVisible, setIsVisible] = React76.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
47236
47405
  const debugData = useDebugData();
47237
- React77.useEffect(() => {
47406
+ React76.useEffect(() => {
47238
47407
  if (mode === "inline") return;
47239
47408
  return onDebugToggle((enabled) => {
47240
47409
  setIsVisible(enabled);
@@ -47243,7 +47412,7 @@ function RuntimeDebugger({
47243
47412
  }
47244
47413
  });
47245
47414
  }, [mode]);
47246
- React77.useEffect(() => {
47415
+ React76.useEffect(() => {
47247
47416
  if (mode === "inline") return;
47248
47417
  const handleKeyDown = (e) => {
47249
47418
  if (e.key === "`" && isVisible) {
@@ -47803,7 +47972,7 @@ function SequenceBar({
47803
47972
  onSlotRemove(index);
47804
47973
  }, [onSlotRemove, playing]);
47805
47974
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
47806
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React77__default.Fragment, { children: [
47975
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React76__default.Fragment, { children: [
47807
47976
  i > 0 && /* @__PURE__ */ jsx(
47808
47977
  Typography,
47809
47978
  {
@@ -48674,12 +48843,8 @@ function Sprite({
48674
48843
  }) {
48675
48844
  const eventBus = useEventBus();
48676
48845
  const sourcePosition = useMemo(() => {
48677
- const frameX = frame % columns;
48678
- const frameY = Math.floor(frame / columns);
48679
- return {
48680
- x: frameX * frameWidth,
48681
- y: frameY * frameHeight
48682
- };
48846
+ const { sx, sy } = frameRect(frame, Math.floor(frame / columns), columns, frameWidth, frameHeight);
48847
+ return { x: sx, y: sy };
48683
48848
  }, [frame, columns, frameWidth, frameHeight]);
48684
48849
  const transform = useMemo(() => {
48685
48850
  const transforms = [
@@ -48737,8 +48902,7 @@ function drawSprite(ctx, image, props) {
48737
48902
  opacity = 1,
48738
48903
  columns = 16
48739
48904
  } = props;
48740
- const sourceX = frame % columns * frameWidth;
48741
- const sourceY = Math.floor(frame / columns) * frameHeight;
48905
+ const { sx: sourceX, sy: sourceY } = frameRect(frame, Math.floor(frame / columns), columns, frameWidth, frameHeight);
48742
48906
  ctx.save();
48743
48907
  ctx.globalAlpha = opacity;
48744
48908
  ctx.translate(x + frameWidth / 2, y + frameHeight / 2);
@@ -48763,6 +48927,7 @@ var init_Sprite = __esm({
48763
48927
  "components/game/atoms/Sprite.tsx"() {
48764
48928
  "use client";
48765
48929
  init_useEventBus();
48930
+ init_spriteAnimation();
48766
48931
  }
48767
48932
  });
48768
48933
  var StatCard;
@@ -48803,7 +48968,7 @@ var init_StatCard = __esm({
48803
48968
  const labelToUse = propLabel ?? propTitle;
48804
48969
  const eventBus = useEventBus();
48805
48970
  const { t } = useTranslate();
48806
- const handleActionClick = React77__default.useCallback(() => {
48971
+ const handleActionClick = React76__default.useCallback(() => {
48807
48972
  if (action?.event) {
48808
48973
  eventBus.emit(`UI:${action.event}`, {});
48809
48974
  }
@@ -48814,7 +48979,7 @@ var init_StatCard = __esm({
48814
48979
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
48815
48980
  const isLoading = externalLoading ?? false;
48816
48981
  const error = externalError;
48817
- const computeMetricValue = React77__default.useCallback(
48982
+ const computeMetricValue = React76__default.useCallback(
48818
48983
  (metric, items) => {
48819
48984
  if (metric.value !== void 0) {
48820
48985
  return metric.value;
@@ -48853,7 +49018,7 @@ var init_StatCard = __esm({
48853
49018
  },
48854
49019
  []
48855
49020
  );
48856
- const schemaStats = React77__default.useMemo(() => {
49021
+ const schemaStats = React76__default.useMemo(() => {
48857
49022
  if (!metrics || metrics.length === 0) return null;
48858
49023
  return metrics.map((metric) => ({
48859
49024
  label: metric.label,
@@ -48861,7 +49026,7 @@ var init_StatCard = __esm({
48861
49026
  format: metric.format
48862
49027
  }));
48863
49028
  }, [metrics, data, computeMetricValue]);
48864
- const calculatedTrend = React77__default.useMemo(() => {
49029
+ const calculatedTrend = React76__default.useMemo(() => {
48865
49030
  if (manualTrend !== void 0) return manualTrend;
48866
49031
  if (previousValue === void 0 || currentValue2 === void 0)
48867
49032
  return void 0;
@@ -49911,7 +50076,7 @@ var init_Timeline = __esm({
49911
50076
  }) => {
49912
50077
  const { t } = useTranslate();
49913
50078
  const entityData = Array.isArray(entity) ? entity : [];
49914
- const items = React77__default.useMemo(() => {
50079
+ const items = React76__default.useMemo(() => {
49915
50080
  if (propItems) return propItems;
49916
50081
  if (entityData.length === 0) return [];
49917
50082
  return entityData.map((record, idx) => {
@@ -50068,7 +50233,7 @@ var init_TimerDisplay = __esm({
50068
50233
  }
50069
50234
  });
50070
50235
  function extractToastProps(children) {
50071
- if (!React77__default.isValidElement(children)) {
50236
+ if (!React76__default.isValidElement(children)) {
50072
50237
  if (typeof children === "string") {
50073
50238
  return { message: children };
50074
50239
  }
@@ -50106,7 +50271,7 @@ var init_ToastSlot = __esm({
50106
50271
  eventBus.emit("UI:CLOSE");
50107
50272
  };
50108
50273
  if (!isVisible) return null;
50109
- const isCustomContent = React77__default.isValidElement(children) && !message;
50274
+ const isCustomContent = React76__default.isValidElement(children) && !message;
50110
50275
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
50111
50276
  Toast,
50112
50277
  {
@@ -50985,8 +51150,8 @@ function XPBar({
50985
51150
  }) {
50986
51151
  const sizes = sizeMap18[size];
50987
51152
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
50988
- const [fillWidth, setFillWidth] = React77.useState(animated ? 0 : percentage);
50989
- React77.useEffect(() => {
51153
+ const [fillWidth, setFillWidth] = React76.useState(animated ? 0 : percentage);
51154
+ React76.useEffect(() => {
50990
51155
  if (!animated) {
50991
51156
  setFillWidth(percentage);
50992
51157
  return;
@@ -51059,7 +51224,7 @@ var init_XPBar = __esm({
51059
51224
  }
51060
51225
  });
51061
51226
  function lazyThree(name, loader) {
51062
- const Lazy = React77__default.lazy(
51227
+ const Lazy = React76__default.lazy(
51063
51228
  () => loader().then((m) => {
51064
51229
  const Resolved = m[name];
51065
51230
  if (!Resolved) {
@@ -51071,13 +51236,13 @@ function lazyThree(name, loader) {
51071
51236
  })
51072
51237
  );
51073
51238
  function ThreeWrapper(props) {
51074
- return React77__default.createElement(
51239
+ return React76__default.createElement(
51075
51240
  ThreeBoundary,
51076
51241
  { name },
51077
- React77__default.createElement(
51078
- React77__default.Suspense,
51242
+ React76__default.createElement(
51243
+ React76__default.Suspense,
51079
51244
  { fallback: null },
51080
- React77__default.createElement(Lazy, props)
51245
+ React76__default.createElement(Lazy, props)
51081
51246
  )
51082
51247
  );
51083
51248
  }
@@ -51375,7 +51540,7 @@ var init_component_registry_generated = __esm({
51375
51540
  init_WorldMapBoard();
51376
51541
  init_WorldMapTemplate();
51377
51542
  init_XPBar();
51378
- ThreeBoundary = class extends React77__default.Component {
51543
+ ThreeBoundary = class extends React76__default.Component {
51379
51544
  constructor() {
51380
51545
  super(...arguments);
51381
51546
  __publicField(this, "state", { failed: false });
@@ -51385,7 +51550,7 @@ var init_component_registry_generated = __esm({
51385
51550
  }
51386
51551
  render() {
51387
51552
  if (this.state.failed) {
51388
- return React77__default.createElement(
51553
+ return React76__default.createElement(
51389
51554
  "div",
51390
51555
  {
51391
51556
  "data-testid": "three-unavailable",
@@ -51726,7 +51891,7 @@ function SuspenseConfigProvider({
51726
51891
  config,
51727
51892
  children
51728
51893
  }) {
51729
- return React77__default.createElement(
51894
+ return React76__default.createElement(
51730
51895
  SuspenseConfigContext.Provider,
51731
51896
  { value: config },
51732
51897
  children
@@ -52216,7 +52381,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
52216
52381
  const key = `${parentId}-${index}-trait:${traitName}`;
52217
52382
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
52218
52383
  }
52219
- return /* @__PURE__ */ jsx(React77__default.Fragment, { children: child }, `${parentId}-${index}`);
52384
+ return /* @__PURE__ */ jsx(React76__default.Fragment, { children: child }, `${parentId}-${index}`);
52220
52385
  }
52221
52386
  if (!child || typeof child !== "object") return null;
52222
52387
  const childId = `${parentId}-${index}`;
@@ -52256,14 +52421,14 @@ function isPatternConfig(value) {
52256
52421
  if (value === null || value === void 0) return false;
52257
52422
  if (typeof value !== "object") return false;
52258
52423
  if (Array.isArray(value)) return false;
52259
- if (React77__default.isValidElement(value)) return false;
52424
+ if (React76__default.isValidElement(value)) return false;
52260
52425
  if (value instanceof Date) return false;
52261
52426
  if (typeof value === "function") return false;
52262
52427
  const record = value;
52263
52428
  return "type" in record && typeof record.type === "string";
52264
52429
  }
52265
52430
  function isPlainConfigObject(value) {
52266
- if (React77__default.isValidElement(value)) return false;
52431
+ if (React76__default.isValidElement(value)) return false;
52267
52432
  if (value instanceof Date) return false;
52268
52433
  const proto = Object.getPrototypeOf(value);
52269
52434
  return proto === Object.prototype || proto === null;
@@ -52770,121 +52935,15 @@ init_useGameAudio();
52770
52935
  init_useImageCache();
52771
52936
  init_useCamera();
52772
52937
 
52773
- // components/game/organisms/utils/spriteSheetConstants.ts
52774
- var SHEET_COLUMNS = 8;
52775
- var SPRITE_SHEET_LAYOUT = {
52776
- idle: { row: 0, frames: 4, frameRate: 6, loop: true },
52777
- walk: { row: 1, frames: 8, frameRate: 10, loop: true },
52778
- attack: { row: 2, frames: 6, frameRate: 12, loop: false },
52779
- hit: { row: 3, frames: 3, frameRate: 8, loop: false },
52780
- death: { row: 4, frames: 6, frameRate: 8, loop: false }
52781
- };
52782
-
52783
- // components/game/organisms/utils/spriteAnimation.ts
52784
- function inferDirection(dx, dy) {
52785
- if (dx === 0 && dy === 0) return "se";
52786
- if (dx >= 0 && dy >= 0) return "se";
52787
- if (dx <= 0 && dy >= 0) return "sw";
52788
- if (dx >= 0 && dy <= 0) return "ne";
52789
- return "nw";
52790
- }
52791
- function resolveSheetDirection(facing) {
52792
- switch (facing) {
52793
- case "se":
52794
- return { sheetDir: "se", flipX: false };
52795
- case "sw":
52796
- return { sheetDir: "sw", flipX: false };
52797
- case "ne":
52798
- return { sheetDir: "sw", flipX: true };
52799
- case "nw":
52800
- return { sheetDir: "se", flipX: true };
52801
- }
52802
- }
52803
- function getCurrentFrame(animName, elapsed) {
52804
- const def = SPRITE_SHEET_LAYOUT[animName];
52805
- const frameDuration = 1e3 / def.frameRate;
52806
- const totalDuration = def.frames * frameDuration;
52807
- if (def.loop) {
52808
- const frame2 = Math.floor(elapsed % totalDuration / frameDuration);
52809
- return { frame: frame2, finished: false };
52810
- }
52811
- if (elapsed >= totalDuration) {
52812
- return { frame: def.frames - 1, finished: true };
52813
- }
52814
- const frame = Math.floor(elapsed / frameDuration);
52815
- return { frame, finished: false };
52816
- }
52817
- function resolveFrame(sheetUrls, frameDims, animState) {
52818
- if (!sheetUrls) return null;
52819
- const { sheetDir, flipX } = resolveSheetDirection(animState.direction);
52820
- const sheetUrl = sheetUrls[sheetDir];
52821
- if (!sheetUrl) return null;
52822
- const def = SPRITE_SHEET_LAYOUT[animState.animation];
52823
- const { frame } = getCurrentFrame(animState.animation, animState.elapsed);
52824
- return {
52825
- sheetUrl,
52826
- sx: frame * frameDims.width,
52827
- sy: def.row * frameDims.height,
52828
- sw: frameDims.width,
52829
- sh: frameDims.height,
52830
- flipX
52831
- };
52832
- }
52833
- function createUnitAnimationState(unitId) {
52834
- return {
52835
- unitId,
52836
- animation: "idle",
52837
- direction: "se",
52838
- frame: 0,
52839
- elapsed: 0,
52840
- queuedAnimation: null,
52841
- finished: false
52842
- };
52843
- }
52844
- function transitionAnimation(state, newAnim, direction) {
52845
- if (state.animation === "death" && state.finished) return state;
52846
- if (state.animation === newAnim && SPRITE_SHEET_LAYOUT[newAnim].loop) {
52847
- return direction ? { ...state, direction } : state;
52848
- }
52849
- return {
52850
- ...state,
52851
- animation: newAnim,
52852
- direction: direction ?? state.direction,
52853
- frame: 0,
52854
- elapsed: 0,
52855
- queuedAnimation: null,
52856
- finished: false
52857
- };
52858
- }
52859
- function tickAnimationState(state, deltaMs) {
52860
- const newElapsed = state.elapsed + deltaMs;
52861
- const { frame, finished } = getCurrentFrame(state.animation, newElapsed);
52862
- const def = SPRITE_SHEET_LAYOUT[state.animation];
52863
- if (finished && !def.loop && !state.finished) {
52864
- if (state.animation === "death") {
52865
- return { ...state, elapsed: newElapsed, frame, finished: true };
52866
- }
52867
- const nextAnim = state.queuedAnimation ?? "idle";
52868
- return {
52869
- ...state,
52870
- animation: nextAnim,
52871
- elapsed: 0,
52872
- frame: 0,
52873
- queuedAnimation: null,
52874
- finished: false
52875
- };
52876
- }
52877
- return { ...state, elapsed: newElapsed, frame, finished };
52878
- }
52879
-
52880
52938
  // components/game/organisms/hooks/useSpriteAnimations.ts
52939
+ init_spriteAnimation();
52881
52940
  function useSpriteAnimations(getSheetUrls, getFrameDims, options = {}) {
52882
52941
  const speed = options.speed ?? 1;
52883
52942
  const animStatesRef = useRef(/* @__PURE__ */ new Map());
52884
52943
  const prevPositionsRef = useRef(/* @__PURE__ */ new Map());
52885
52944
  const unitDataRef = useRef(/* @__PURE__ */ new Map());
52886
52945
  const walkHoldRef = useRef(/* @__PURE__ */ new Map());
52887
- const WALK_HOLD_MS = 600;
52946
+ const WALK_HOLD_MS2 = 600;
52888
52947
  const syncUnits = useCallback((units, deltaMs) => {
52889
52948
  const scaledDelta = deltaMs * speed;
52890
52949
  const states = animStatesRef.current;
@@ -52910,7 +52969,7 @@ function useSpriteAnimations(getSheetUrls, getFrameDims, options = {}) {
52910
52969
  const dir = inferDirection(dx, dy);
52911
52970
  if (state.animation !== "attack" && state.animation !== "hit" && state.animation !== "death") {
52912
52971
  state = transitionAnimation(state, "walk", dir);
52913
- walkHold.set(unit.id, WALK_HOLD_MS);
52972
+ walkHold.set(unit.id, WALK_HOLD_MS2);
52914
52973
  }
52915
52974
  } else if (state.animation === "walk") {
52916
52975
  const remaining = (walkHold.get(unit.id) ?? 0) - scaledDelta;
@@ -53243,6 +53302,8 @@ function usePhysics2D(options = {}) {
53243
53302
 
53244
53303
  // components/game/organisms/index.ts
53245
53304
  init_isometric();
53305
+ init_spriteAnimation();
53306
+ init_spriteSheetConstants();
53246
53307
  init_BattleBoard();
53247
53308
  init_UncontrolledBattleBoard();
53248
53309
  init_useBattleState();