@almadar/ui 5.64.0 → 5.67.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.
Files changed (31) hide show
  1. package/dist/avl/index.cjs +241 -71
  2. package/dist/avl/index.d.cts +10 -2
  3. package/dist/avl/index.d.ts +1 -0
  4. package/dist/avl/index.js +244 -75
  5. package/dist/components/avl/derive-edit-focus.d.ts +8 -0
  6. package/dist/components/core/organisms/ChatBar.d.ts +31 -0
  7. package/dist/components/core/organisms/SubagentTracePanel.d.ts +50 -0
  8. package/dist/components/core/organisms/index.d.ts +3 -0
  9. package/dist/components/core/organisms/trace-edit-focus.d.ts +14 -0
  10. package/dist/components/game/atoms/ChoiceButton.d.ts +7 -1
  11. package/dist/components/game/molecules/HealthPanel.d.ts +3 -0
  12. package/dist/components/game/molecules/IsometricCanvas.d.ts +4 -1
  13. package/dist/components/game/molecules/PowerupSlots.d.ts +3 -0
  14. package/dist/components/game/molecules/TurnPanel.d.ts +3 -0
  15. package/dist/components/game/molecules/index.d.ts +1 -0
  16. package/dist/components/game/molecules/three/index.cjs +6 -6
  17. package/dist/components/game/molecules/three/index.js +6 -6
  18. package/dist/components/game/organisms/HexStrategyBoard.d.ts +37 -0
  19. package/dist/components/game/organisms/index.d.ts +2 -0
  20. package/dist/components/game/organisms/utils/isometric.d.ts +20 -7
  21. package/dist/components/index.cjs +1241 -53
  22. package/dist/components/index.js +1243 -60
  23. package/dist/hooks/index.cjs +94 -0
  24. package/dist/hooks/index.d.ts +1 -0
  25. package/dist/hooks/index.js +95 -2
  26. package/dist/hooks/useAgentTrace.d.ts +85 -0
  27. package/dist/providers/index.cjs +210 -45
  28. package/dist/providers/index.js +213 -48
  29. package/dist/runtime/index.cjs +212 -47
  30. package/dist/runtime/index.js +215 -50
  31. package/package.json +2 -2
@@ -0,0 +1,8 @@
1
+ import type { EditFocus } from '@almadar/core';
2
+ /**
3
+ * Build an `EditFocus` from a clicked element's `data-orb-*` address (stamped by
4
+ * UISlotRenderer). The owning orbital is read from the DOM (`data-orb-orbital`,
5
+ * walking up via `closest` when the clicked node itself doesn't carry it); since
6
+ * `EditFocus.orbital` is required, returns `null` when it can't be resolved.
7
+ */
8
+ export declare function deriveEditFocusFromElement(el: HTMLElement): EditFocus | null;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * ChatBar Organism
3
+ *
4
+ * The always-visible bottom chat bar. A single-row input surface for talking
5
+ * to the agent: status icon, optional context badge, text input, and a
6
+ * status-driven action button (Send / Pause+Stop / Resume / Retry).
7
+ *
8
+ * The agent's activity stream lives in the dedicated Trace tab (see
9
+ * SubagentTracePanel). ChatBar emits generic EventBus events
10
+ * (`UI:CHAT_SEND`, `UI:ELEMENT_SELECTED`, plus the declarative `UI:*` actions
11
+ * the Button atom raises) — it owns no app-specific state.
12
+ */
13
+ import React from 'react';
14
+ import type { DisplayStateProps } from './types';
15
+ export type ChatBarStatus = 'idle' | 'running' | 'paused' | 'complete' | 'error';
16
+ export interface ChatBarProps extends DisplayStateProps {
17
+ /** Pipeline status */
18
+ status?: ChatBarStatus;
19
+ /** Currently active gate label, e.g. "Gate 2: State machines" */
20
+ activeGate?: string;
21
+ /** JEPA validity probability 0-1 */
22
+ jepaValidity?: number;
23
+ /** Input placeholder text */
24
+ placeholder?: string;
25
+ /** Agent context description */
26
+ context?: string;
27
+ }
28
+ export declare function ChatBar({ status, activeGate, jepaValidity, placeholder, context, className, }: ChatBarProps): React.ReactElement;
29
+ export declare namespace ChatBar {
30
+ var displayName: string;
31
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * SubagentTracePanel — contextual side panel that surfaces subagent activity.
3
+ *
4
+ * Density adapts to disclosure level:
5
+ * - L1/L2 (builder/designer): compact mode — name + role badge + last message
6
+ * - L3/L4 (architect): full mode — rich per-subagent activity streams
7
+ *
8
+ * Atomic design: composes Box / VStack / HStack / Typography / Badge / Icon /
9
+ * Button / Modal / Accordion / CodeBlock / MarkdownContent from this package.
10
+ * It reads the agent-trace view-model from `@almadar/core` (Trace* types) and
11
+ * owns no transport — the consumer feeds it already-mapped view-model props.
12
+ */
13
+ import React from 'react';
14
+ import type { DisplayStateProps } from './types';
15
+ import type { TraceActivity, TraceSubagent, TraceChatMessage } from '@almadar/core';
16
+ /** Disclosure level driving panel density (builder=1 … architect=4). */
17
+ export type TraceDisclosureLevel = 1 | 2 | 3 | 4;
18
+ export interface SubagentTracePanelProps extends DisplayStateProps {
19
+ /** All known subagents from the runner. */
20
+ subagents: TraceSubagent[];
21
+ /** Current canvas focus orbital — only used by overlay mode. Tab mode ignores this. */
22
+ focusedOrbital?: string;
23
+ /** Drives density: 1-2 → compact, 3-4 → full activity embed (when mode='overlay'). */
24
+ disclosureLevel: TraceDisclosureLevel;
25
+ /** Whether the panel is visible. Typically auto-opens during generation in overlay mode. */
26
+ open: boolean;
27
+ /** Optional dismiss handler. */
28
+ onClose?: () => void;
29
+ /** Full coordinator activities (tool calls, results, messages, errors). */
30
+ coordinatorActivities?: TraceActivity[];
31
+ /**
32
+ * Canonical Coordinator conversation — same shape live and on reload. When
33
+ * present, takes precedence over `coordinatorActivities` for the Coordinator
34
+ * section.
35
+ */
36
+ coordinatorMessages?: readonly TraceChatMessage[];
37
+ /**
38
+ * Rendering mode.
39
+ * - `'overlay'` (default): floating side panel positioned absolutely over the
40
+ * canvas. Density follows `disclosureLevel` (compact L1/L2, rich L3+). The
41
+ * `open` flag actually hides the panel when false.
42
+ * - `'tab'`: full-width content for a dedicated 'trace' supplemental tab.
43
+ * Always renders rich (regardless of disclosure level), always visible (the
44
+ * `open` flag is ignored), and includes an empty state when no subagents
45
+ * are present so users see the surface even before generation starts.
46
+ */
47
+ mode?: 'overlay' | 'tab';
48
+ }
49
+ export declare const SubagentTracePanel: React.FC<SubagentTracePanelProps>;
50
+ export default SubagentTracePanel;
@@ -28,3 +28,6 @@ export { TeamOrganism, type TeamOrganismProps, } from "../../marketing/organisms
28
28
  export { CaseStudyOrganism, type CaseStudyOrganismProps, } from "../../marketing/organisms/CaseStudyOrganism";
29
29
  export { CodeRunnerPanel, type CodeRunnerPanelProps, type CodeSimulationOutput, } from './CodeRunnerPanel';
30
30
  export { SegmentRenderer, type SegmentRendererProps, } from './SegmentRenderer';
31
+ export { ChatBar, type ChatBarProps, type ChatBarStatus } from './ChatBar';
32
+ export { ELEMENT_SELECTED_EVENT, parseEditFocus, } from './trace-edit-focus';
33
+ export { SubagentTracePanel, type SubagentTracePanelProps, type TraceDisclosureLevel, } from './SubagentTracePanel';
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Edit Focus — the contextual-edit selection contract for the trace chat bar.
3
+ *
4
+ * A canvas element-pick emits `UI:ELEMENT_SELECTED` on the EventBus carrying an
5
+ * `EditFocus`. This module names that event and narrows the bus payload back
6
+ * into a typed `EditFocus` for `ChatBar`'s focus chip. It depends only on
7
+ * `@almadar/core` types; the DOM→focus build lives at the emitting canvas
8
+ * (`avl/derive-edit-focus`), not here.
9
+ */
10
+ import type { EditFocus, EventPayloadValue } from '@almadar/core';
11
+ /** The dedicated bus event a canvas element-pick emits. */
12
+ export declare const ELEMENT_SELECTED_EVENT = "UI:ELEMENT_SELECTED";
13
+ /** Narrow a `UI:ELEMENT_SELECTED` payload value back into an `EditFocus`. */
14
+ export declare function parseEditFocus(value: EventPayloadValue | undefined): EditFocus | null;
@@ -1,8 +1,14 @@
1
+ import { type IconInput } from '../../core/atoms/Icon';
2
+ import type { AssetUrl } from '@almadar/core';
1
3
  export interface ChoiceButtonProps {
2
4
  /** Choice text content */
3
5
  text: string;
4
6
  /** Choice index number (displayed as prefix) */
5
7
  index?: number;
8
+ /** Sprite image URL — takes precedence over icon when provided */
9
+ assetUrl?: AssetUrl;
10
+ /** Icon displayed before the text */
11
+ icon?: IconInput;
6
12
  /** Whether the choice is disabled */
7
13
  disabled?: boolean;
8
14
  /** Whether the choice is currently selected */
@@ -12,7 +18,7 @@ export interface ChoiceButtonProps {
12
18
  /** Additional CSS classes */
13
19
  className?: string;
14
20
  }
15
- export declare function ChoiceButton({ text, index, disabled, selected, onClick, className, }: ChoiceButtonProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function ChoiceButton({ text, index, assetUrl, icon, disabled, selected, onClick, className, }: ChoiceButtonProps): import("react/jsx-runtime").JSX.Element;
16
22
  export declare namespace ChoiceButton {
17
23
  var displayName: string;
18
24
  }
@@ -1,6 +1,9 @@
1
1
  import type { IconInput } from '../../core/atoms';
2
+ import type { AssetUrl } from '@almadar/core';
2
3
  export interface HealthEffect {
3
4
  icon: IconInput;
5
+ /** Sprite image URL — takes precedence over icon when provided */
6
+ assetUrl?: AssetUrl;
4
7
  label?: string;
5
8
  variant?: 'buff' | 'debuff' | 'neutral';
6
9
  }
@@ -27,6 +27,7 @@ import * as React from 'react';
27
27
  import type { AssetUrl, EventEmit } from '@almadar/core';
28
28
  import type { IsometricTile, IsometricUnit, IsometricFeature } from '../organisms/types/isometric';
29
29
  import type { ResolvedFrame } from '../organisms/types/spriteAnimation';
30
+ import type { TileLayout } from '../organisms/utils/isometric';
30
31
  import type { UiError } from '../../core/atoms/types';
31
32
  /** Event Contract:
32
33
  * Emits: UI:TILE_CLICK
@@ -79,6 +80,8 @@ export interface IsometricCanvasProps {
79
80
  }>;
80
81
  /** Declarative event: emits UI:{tileLeaveEvent} with {} on tile leave */
81
82
  tileLeaveEvent?: EventEmit<Record<string, never>>;
83
+ /** Tile layout projection: 'isometric' (default 2:1 diamond) or 'hex' (pointy-top offset rows) */
84
+ tileLayout?: TileLayout;
82
85
  /** Render scale (0.4 = 40% zoom) */
83
86
  scale?: number;
84
87
  /** Show debug grid lines and coordinates */
@@ -129,7 +132,7 @@ export interface IsometricCanvasProps {
129
132
  effects?: Record<string, string>;
130
133
  };
131
134
  }
132
- export declare function IsometricCanvas({ className, isLoading, error, tiles: _tilesPropRaw, units: _unitsPropRaw, features: _featuresPropRaw, selectedUnitId, validMoves, attackTargets, hoveredTile, onTileClick, onUnitClick, onTileHover, onTileLeave, tileClickEvent, unitClickEvent, tileHoverEvent, tileLeaveEvent, scale, debug, backgroundImage, showMinimap, enableCamera, unitScale, spriteHeightRatio, spriteMaxWidthRatio, getTerrainSprite, getFeatureSprite, getUnitSprite, resolveUnitFrame, effectSpriteUrls, onDrawEffects, hasActiveEffects, diamondTopY: diamondTopYProp, assetBaseUrl, assetManifest, }: IsometricCanvasProps): React.JSX.Element;
135
+ export declare function IsometricCanvas({ className, isLoading, error, tiles: _tilesPropRaw, units: _unitsPropRaw, features: _featuresPropRaw, selectedUnitId, validMoves, attackTargets, hoveredTile, onTileClick, onUnitClick, onTileHover, onTileLeave, tileClickEvent, unitClickEvent, tileHoverEvent, tileLeaveEvent, tileLayout, scale, debug, backgroundImage, showMinimap, enableCamera, unitScale, spriteHeightRatio, spriteMaxWidthRatio, getTerrainSprite, getFeatureSprite, getUnitSprite, resolveUnitFrame, effectSpriteUrls, onDrawEffects, hasActiveEffects, diamondTopY: diamondTopYProp, assetBaseUrl, assetManifest, }: IsometricCanvasProps): React.JSX.Element;
133
136
  export declare namespace IsometricCanvas {
134
137
  var displayName: string;
135
138
  }
@@ -1,7 +1,10 @@
1
1
  import type { IconInput } from '../../core/atoms';
2
+ import type { AssetUrl } from '@almadar/core';
2
3
  export interface ActivePowerup {
3
4
  /** Unique powerup ID */
4
5
  id: string;
6
+ /** Sprite image URL — takes precedence over icon when provided */
7
+ assetUrl?: AssetUrl;
5
8
  /** Icon component or emoji */
6
9
  icon?: IconInput;
7
10
  /** Powerup label */
@@ -1,7 +1,10 @@
1
1
  import type { IconInput } from '../../core/atoms';
2
+ import type { AssetUrl } from '@almadar/core';
2
3
  export interface TurnPanelAction {
3
4
  /** Action button label */
4
5
  label: string;
6
+ /** Sprite image URL — takes precedence over icon when provided */
7
+ assetUrl?: AssetUrl;
5
8
  /** Icon for the button */
6
9
  icon?: IconInput;
7
10
  /** Event name to emit when clicked */
@@ -28,4 +28,5 @@ export { GameMenu, type GameMenuProps, type MenuOption } from './GameMenu';
28
28
  export { GameOverScreen, type GameOverScreenProps, type GameOverStat, type GameOverAction } from './GameOverScreen';
29
29
  export { PlatformerCanvas, type PlatformerCanvasProps, type PlatformerPlatform, type PlatformerPlayer } from './PlatformerCanvas';
30
30
  export { IsometricCanvas, type IsometricCanvasProps } from './IsometricCanvas';
31
+ export type { TileLayout } from '../organisms/utils/isometric';
31
32
  export type { IsometricTile, IsometricUnit, IsometricFeature } from '../organisms/types/isometric';
@@ -2845,9 +2845,9 @@ var GameCanvas3D = React11.forwardRef(
2845
2845
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
2846
2846
  const hasAtlas = unitAtlasUrl(unit) !== null;
2847
2847
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
2848
- const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
2849
- const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
2850
- const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
2848
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale * gridConfig.cellSize;
2849
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale * gridConfig.cellSize;
2850
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale * gridConfig.cellSize;
2851
2851
  return /* @__PURE__ */ jsxRuntime.jsxs(
2852
2852
  "group",
2853
2853
  {
@@ -2894,7 +2894,7 @@ var GameCanvas3D = React11.forwardRef(
2894
2894
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
2895
2895
  ] })
2896
2896
  ] }),
2897
- unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, 1.2, 0], children: [
2897
+ unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, billboardHeight, 0], children: [
2898
2898
  /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [-0.25, 0, 0], children: [
2899
2899
  /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5, 0.05] }),
2900
2900
  /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: 3355443 })
@@ -2923,7 +2923,7 @@ var GameCanvas3D = React11.forwardRef(
2923
2923
  }
2924
2924
  );
2925
2925
  },
2926
- [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
2926
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale, gridConfig]
2927
2927
  );
2928
2928
  const DefaultFeatureRenderer = React11.useCallback(
2929
2929
  ({
@@ -3011,7 +3011,7 @@ var GameCanvas3D = React11.forwardRef(
3011
3011
  {
3012
3012
  ref: containerRef,
3013
3013
  className: cn("game-canvas-3d relative w-full overflow-hidden", className),
3014
- style: { height: "85vh" },
3014
+ style: { flex: "1 1 0", minHeight: "400px" },
3015
3015
  "data-orientation": orientation,
3016
3016
  "data-camera-mode": cameraMode,
3017
3017
  "data-overlay": overlay,
@@ -2821,9 +2821,9 @@ var GameCanvas3D = forwardRef(
2821
2821
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
2822
2822
  const hasAtlas = unitAtlasUrl(unit) !== null;
2823
2823
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
2824
- const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
2825
- const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
2826
- const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
2824
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale * gridConfig.cellSize;
2825
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale * gridConfig.cellSize;
2826
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale * gridConfig.cellSize;
2827
2827
  return /* @__PURE__ */ jsxs(
2828
2828
  "group",
2829
2829
  {
@@ -2870,7 +2870,7 @@ var GameCanvas3D = forwardRef(
2870
2870
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
2871
2871
  ] })
2872
2872
  ] }),
2873
- unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxs("group", { position: [0, 1.2, 0], children: [
2873
+ unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxs("group", { position: [0, billboardHeight, 0], children: [
2874
2874
  /* @__PURE__ */ jsxs("mesh", { position: [-0.25, 0, 0], children: [
2875
2875
  /* @__PURE__ */ jsx("planeGeometry", { args: [0.5, 0.05] }),
2876
2876
  /* @__PURE__ */ jsx("meshBasicMaterial", { color: 3355443 })
@@ -2899,7 +2899,7 @@ var GameCanvas3D = forwardRef(
2899
2899
  }
2900
2900
  );
2901
2901
  },
2902
- [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
2902
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale, gridConfig]
2903
2903
  );
2904
2904
  const DefaultFeatureRenderer = useCallback(
2905
2905
  ({
@@ -2987,7 +2987,7 @@ var GameCanvas3D = forwardRef(
2987
2987
  {
2988
2988
  ref: containerRef,
2989
2989
  className: cn("game-canvas-3d relative w-full overflow-hidden", className),
2990
- style: { height: "85vh" },
2990
+ style: { flex: "1 1 0", minHeight: "400px" },
2991
2991
  "data-orientation": orientation,
2992
2992
  "data-camera-mode": cameraMode,
2993
2993
  "data-overlay": overlay,
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import type { AssetUrl, EventEmit } from '@almadar/core';
3
+ import type { IsometricTile, IsometricUnit, IsometricFeature } from './types/isometric';
4
+ import type { DisplayStateProps } from '../../core/organisms/types';
5
+ import type { IsometricCanvasProps } from '../molecules/IsometricCanvas';
6
+ export interface HexStrategyBoardProps extends DisplayStateProps {
7
+ /** Hex grid tiles */
8
+ tiles?: IsometricTile[];
9
+ /** Units on the board */
10
+ units?: IsometricUnit[];
11
+ /** Features (resources, structures, etc.) on the board */
12
+ features?: IsometricFeature[];
13
+ /** Asset sprite manifest (same shape as IsometricCanvas.assetManifest) */
14
+ assetManifest?: IsometricCanvasProps['assetManifest'];
15
+ /** Base URL prepended to manifest sprite paths */
16
+ assetBaseUrl?: AssetUrl;
17
+ /** Render scale */
18
+ scale?: number;
19
+ /** Show minimap overlay */
20
+ showMinimap?: boolean;
21
+ /** Enable camera pan/zoom controls */
22
+ enableCamera?: boolean;
23
+ /** Declarative event: emits UI:{tileClickEvent} with { x, y } on tile click */
24
+ tileClickEvent?: EventEmit<{
25
+ x: number;
26
+ y: number;
27
+ }>;
28
+ /** Declarative event: emits UI:{unitClickEvent} with { unitId } on unit click */
29
+ unitClickEvent?: EventEmit<{
30
+ unitId: string;
31
+ }>;
32
+ }
33
+ export declare function HexStrategyBoard({ tiles, units, features, assetManifest, assetBaseUrl, scale, showMinimap, enableCamera, tileClickEvent, unitClickEvent, isLoading, error, className, }: HexStrategyBoardProps): React.ReactElement;
34
+ export declare namespace HexStrategyBoard {
35
+ var displayName: string;
36
+ }
37
+ export default HexStrategyBoard;
@@ -18,6 +18,7 @@ export { useSpriteAnimations, type UseSpriteAnimationsResult, type UseSpriteAnim
18
18
  export { usePhysics2D, type UsePhysics2DOptions, type UsePhysics2DReturn, } from './hooks/usePhysics2D';
19
19
  export { PhysicsManager, type Physics2DState, type PhysicsBounds, type PhysicsConfig, } from './managers/PhysicsManager';
20
20
  export { isoToScreen, screenToIso, TILE_WIDTH, TILE_HEIGHT, FLOOR_HEIGHT, DIAMOND_TOP_Y, FEATURE_COLORS, } from './utils/isometric';
21
+ export type { TileLayout } from './utils/isometric';
21
22
  export { inferDirection, resolveSheetDirection, getCurrentFrame, resolveFrame, createUnitAnimationState, transitionAnimation, tickAnimationState, } from './utils/spriteAnimation';
22
23
  export { SPRITE_SHEET_LAYOUT, SHEET_COLUMNS } from './utils/spriteSheetConstants';
23
24
  export { BattleBoard, type BattleBoardProps, type BattlePhase, type BattleSlotContext, } from './BattleBoard';
@@ -33,6 +34,7 @@ export { CityBuilderBoard, type CityBuilderBoardProps, } from './CityBuilderBoar
33
34
  export { GameBoard3D, type GameBoard3DProps, } from './GameBoard3D';
34
35
  export { VisualNovelBoard, type VisualNovelBoardProps, type VisualNovelNode, type VisualNovelChoice, } from './VisualNovelBoard';
35
36
  export { CardBattlerBoard, type CardBattlerBoardProps, type CardBattlerCard, } from './CardBattlerBoard';
37
+ export { HexStrategyBoard, type HexStrategyBoardProps, } from './HexStrategyBoard';
36
38
  export { TraitStateViewer, type TraitStateViewerProps, type TraitStateMachineDefinition, type TraitTransition, } from './TraitStateViewer';
37
39
  export { TraitSlot, type TraitSlotProps, type SlotItemData, } from './TraitSlot';
38
40
  export { CollapsibleSection, EditorSlider, EditorSelect, EditorCheckbox, EditorTextInput, StatusBar, TerrainPalette, EditorToolbar, TERRAIN_COLORS, FEATURE_TYPES, type EditorMode, type CollapsibleSectionProps, type EditorSliderProps, type EditorSelectProps, type EditorCheckboxProps, type EditorTextInputProps, type StatusBarProps, type TerrainPaletteProps, type EditorToolbarProps, } from './editor';
@@ -27,20 +27,32 @@ export declare const DIAMOND_TOP_Y = 374;
27
27
  * Feature type → fallback color mapping (when sprites not loaded).
28
28
  */
29
29
  export declare const FEATURE_COLORS: Record<string, string>;
30
+ /**
31
+ * Tile layout mode. 'isometric' = 2:1 diamond projection (default).
32
+ * 'hex' = pointy-top offset-row hex grid.
33
+ *
34
+ * Hex constants (at scale=1):
35
+ * w = TILE_WIDTH (256) — horizontal cell width
36
+ * h = FLOOR_HEIGHT (128) — vertical row stride (= w/2; hex row-to-row = h*0.75 = 96)
37
+ * Forward: screenX = col*w + (row&1)*(w/2) + baseOffsetX
38
+ * screenY = row * (h * 0.75)
39
+ * Inverse: row = round(screenY / (h*0.75)); col = round((screenX - (row&1)*(w/2) - baseOffsetX) / w)
40
+ */
41
+ export type TileLayout = 'isometric' | 'hex';
30
42
  /**
31
43
  * Convert tile grid coordinates to screen pixel coordinates.
32
44
  *
33
- * Uses 2:1 diamond isometric projection:
34
- * - X increases to the lower-right
35
- * - Y increases to the lower-left
45
+ * For 'isometric' (default): 2:1 diamond projection.
46
+ * For 'hex': pointy-top offset-row projection (odd rows shifted right by w/2).
36
47
  *
37
- * @param tileX - Grid X coordinate
38
- * @param tileY - Grid Y coordinate
48
+ * @param tileX - Grid X (col) coordinate
49
+ * @param tileY - Grid Y (row) coordinate
39
50
  * @param scale - Render scale factor
40
51
  * @param baseOffsetX - Horizontal offset to center the grid
52
+ * @param layout - Tile layout mode (default: 'isometric')
41
53
  * @returns Screen position { x, y } of the tile's top-left corner
42
54
  */
43
- export declare function isoToScreen(tileX: number, tileY: number, scale: number, baseOffsetX: number): {
55
+ export declare function isoToScreen(tileX: number, tileY: number, scale: number, baseOffsetX: number, layout?: TileLayout): {
44
56
  x: number;
45
57
  y: number;
46
58
  };
@@ -53,9 +65,10 @@ export declare function isoToScreen(tileX: number, tileY: number, scale: number,
53
65
  * @param screenY - Screen Y in pixels
54
66
  * @param scale - Render scale factor
55
67
  * @param baseOffsetX - Horizontal offset used in isoToScreen
68
+ * @param layout - Tile layout mode (default: 'isometric')
56
69
  * @returns Snapped grid position { x, y }
57
70
  */
58
- export declare function screenToIso(screenX: number, screenY: number, scale: number, baseOffsetX: number): {
71
+ export declare function screenToIso(screenX: number, screenY: number, scale: number, baseOffsetX: number, layout?: TileLayout): {
59
72
  x: number;
60
73
  y: number;
61
74
  };