jaml-ui 0.1.0 → 0.3.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 (47) hide show
  1. package/README.md +37 -0
  2. package/dist/components/GameCard.d.ts +8 -4
  3. package/dist/components/GameCard.js +8 -8
  4. package/dist/components/JamlIde.d.ts +17 -0
  5. package/dist/components/JamlIde.js +61 -0
  6. package/dist/components/JamlIdeToolbar.d.ts +8 -0
  7. package/dist/components/JamlIdeToolbar.js +36 -0
  8. package/dist/components/JamlMapPreview.d.ts +10 -0
  9. package/dist/components/JamlMapPreview.js +117 -0
  10. package/dist/data/balatro-jokers.json +1241 -0
  11. package/dist/decode/motelyItemDecoder.d.ts +49 -5
  12. package/dist/decode/motelyItemDecoder.js +227 -8
  13. package/dist/index.d.ts +4 -0
  14. package/dist/index.js +4 -0
  15. package/dist/motely.d.ts +1 -1
  16. package/dist/motely.js +1 -1
  17. package/dist/r3f/BalatroJokerMesh3D.d.ts +8 -0
  18. package/dist/r3f/BalatroJokerMesh3D.js +98 -0
  19. package/dist/r3f/BalatroJokerPreview3D.d.ts +14 -0
  20. package/dist/r3f/BalatroJokerPreview3D.js +30 -0
  21. package/dist/r3f/BalatroPlayingCard3D.d.ts +22 -0
  22. package/dist/r3f/BalatroPlayingCard3D.js +62 -0
  23. package/dist/r3f/cardConstants.d.ts +16 -0
  24. package/dist/r3f/cardConstants.js +14 -0
  25. package/dist/r3f/compositedAtlas.d.ts +5 -0
  26. package/dist/r3f/compositedAtlas.js +56 -0
  27. package/dist/r3f/gridUV.d.ts +22 -0
  28. package/dist/r3f/gridUV.js +30 -0
  29. package/dist/r3f/index.d.ts +12 -0
  30. package/dist/r3f/index.js +13 -0
  31. package/dist/r3f/jokerRegistry.d.ts +28 -0
  32. package/dist/r3f/jokerRegistry.js +40 -0
  33. package/dist/r3f/jokerTilt.d.ts +8 -0
  34. package/dist/r3f/jokerTilt.js +41 -0
  35. package/dist/r3f/magneticTilt.d.ts +18 -0
  36. package/dist/r3f/magneticTilt.js +34 -0
  37. package/dist/r3f/playingCardTypes.d.ts +24 -0
  38. package/dist/r3f/playingCardTypes.js +32 -0
  39. package/dist/r3f/playingCardVisuals.d.ts +7 -0
  40. package/dist/r3f/playingCardVisuals.js +45 -0
  41. package/dist/r3f/usePlayingCardTexture.d.ts +7 -0
  42. package/dist/r3f/usePlayingCardTexture.js +92 -0
  43. package/dist/render/CanvasRenderer.d.ts +2 -1
  44. package/dist/render/CanvasRenderer.js +31 -3
  45. package/dist/utils/jamlMapPreview.d.ts +12 -0
  46. package/dist/utils/jamlMapPreview.js +105 -0
  47. package/package.json +11 -3
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Balatro rendering components, sprite metadata, and optional Motely helpers for React apps.
4
4
 
5
+ `jaml-ui` is the shared UI layer for Balatro/JAML surfaces: low-level renderers, asset helpers, visual JAML previews, and a lightweight browser-first JAML IDE shell.
6
+
5
7
  ## Package shape
6
8
 
7
9
  - `jaml-ui`
@@ -45,6 +47,39 @@ export function Example() {
45
47
  }
46
48
  ```
47
49
 
50
+ ## JAML preview
51
+
52
+ ```tsx
53
+ "use client";
54
+
55
+ import { JamlMapPreview } from "jaml-ui";
56
+
57
+ export function PreviewExample({ jaml }: { jaml: string }) {
58
+ return <JamlMapPreview jaml={jaml} title="JAML Intent Preview" />;
59
+ }
60
+ ```
61
+
62
+ ## Lightweight JAML IDE shell
63
+
64
+ ```tsx
65
+ "use client";
66
+
67
+ import { useState } from "react";
68
+ import { JamlIde } from "jaml-ui";
69
+
70
+ export function IdeExample() {
71
+ const [jaml, setJaml] = useState("must:\n joker: Blueprint");
72
+
73
+ return (
74
+ <JamlIde
75
+ jaml={jaml}
76
+ onChange={setJaml}
77
+ results={[]}
78
+ />
79
+ );
80
+ }
81
+ ```
82
+
48
83
  ## Asset handling
49
84
 
50
85
  By default, `jaml-ui` resolves its packaged sprite assets from the package `assets/` directory using `import.meta.url`.
@@ -108,3 +143,5 @@ export default nextConfig;
108
143
  ## Browser-first runtime direction
109
144
 
110
145
  `jaml-ui` is designed for browser/React consumers. The optional `jaml-ui/motely` entry targets plain `motely-wasm` and does not assume threaded WASM, SAB, or COEP setup.
146
+
147
+ The built-in `JamlIde` intentionally stays lightweight. Rich editor integrations like Monaco, custom language servers, or extension-host-specific tooling should live in app-level packages on top of `jaml-ui`, not in the base renderer package.
@@ -13,6 +13,7 @@ export interface JamlGameCardProps {
13
13
  };
14
14
  type: "joker" | "consumable" | "playing";
15
15
  className?: string;
16
+ hoverTilt?: boolean;
16
17
  }
17
18
  export type AnalyzerShopItem = {
18
19
  id: string;
@@ -31,22 +32,25 @@ export type AnalyzerResolvedItem = {
31
32
  label: string;
32
33
  };
33
34
  export declare function resolveAnalyzerShopItem(item: AnalyzerShopItem, scale?: number): AnalyzerResolvedItem;
34
- export declare function JamlGameCard({ card, type, className }: JamlGameCardProps): import("react/jsx-runtime").JSX.Element;
35
+ export declare function JamlGameCard({ card, type, className, hoverTilt }: JamlGameCardProps): import("react/jsx-runtime").JSX.Element;
35
36
  export interface VoucherProps {
36
37
  voucherName: string;
37
38
  scale?: number;
38
39
  className?: string;
40
+ hoverTilt?: boolean;
39
41
  }
40
- export declare function JamlVoucher({ voucherName, scale, className }: VoucherProps): import("react/jsx-runtime").JSX.Element | null;
42
+ export declare function JamlVoucher({ voucherName, scale, className, hoverTilt }: VoucherProps): import("react/jsx-runtime").JSX.Element | null;
41
43
  export interface TagProps {
42
44
  tagName: string;
43
45
  scale?: number;
44
46
  className?: string;
47
+ hoverTilt?: boolean;
45
48
  }
46
- export declare function JamlTag({ tagName, scale, className }: TagProps): import("react/jsx-runtime").JSX.Element | null;
49
+ export declare function JamlTag({ tagName, scale, className, hoverTilt }: TagProps): import("react/jsx-runtime").JSX.Element | null;
47
50
  export interface BossProps {
48
51
  bossName: string;
49
52
  scale?: number;
50
53
  className?: string;
54
+ hoverTilt?: boolean;
51
55
  }
52
- export declare function JamlBoss({ bossName, scale, className }: BossProps): import("react/jsx-runtime").JSX.Element | null;
56
+ export declare function JamlBoss({ bossName, scale, className, hoverTilt }: BossProps): import("react/jsx-runtime").JSX.Element | null;
@@ -198,7 +198,7 @@ export function resolveAnalyzerShopItem(item, scale = 1) {
198
198
  }
199
199
  return packedResolved ?? { kind: "unknown", label: displayName };
200
200
  }
201
- export function JamlGameCard({ card, type, className = "" }) {
201
+ export function JamlGameCard({ card, type, className = "", hoverTilt = false }) {
202
202
  const { name, edition, isEternal, isPerishable, isRental, rank, suit, enhancements, seal, scale = 1 } = card;
203
203
  const layers = [];
204
204
  if (type === "joker") {
@@ -299,9 +299,9 @@ export function JamlGameCard({ card, type, className = "" }) {
299
299
  }
300
300
  }
301
301
  const wrapperStyle = { width: `${71 * scale}px` };
302
- return (_jsx("div", { style: wrapperStyle, className: className, children: _jsx(JamlCardRenderer, { invert: edition === "Negative", layers: layers }) }));
302
+ return (_jsx("div", { style: wrapperStyle, className: className, children: _jsx(JamlCardRenderer, { invert: edition === "Negative", layers: layers, hoverTilt: hoverTilt }) }));
303
303
  }
304
- export function JamlVoucher({ voucherName, scale = 1, className = "" }) {
304
+ export function JamlVoucher({ voucherName, scale = 1, className = "", hoverTilt = false }) {
305
305
  const voucherData = VOUCHERS.find((v) => v.name === voucherName);
306
306
  if (!voucherData)
307
307
  return null;
@@ -315,9 +315,9 @@ export function JamlVoucher({ voucherName, scale = 1, className = "" }) {
315
315
  }),
316
316
  ];
317
317
  const wrapperStyle = { width: `${71 * scale}px` };
318
- return (_jsx("div", { style: wrapperStyle, className: className, children: _jsx(JamlCardRenderer, { layers: layers }) }));
318
+ return (_jsx("div", { style: wrapperStyle, className: className, children: _jsx(JamlCardRenderer, { layers: layers, hoverTilt: hoverTilt }) }));
319
319
  }
320
- export function JamlTag({ tagName, scale = 1, className = "" }) {
320
+ export function JamlTag({ tagName, scale = 1, className = "", hoverTilt = false }) {
321
321
  const tagData = TAGS.find((t) => t.name === tagName);
322
322
  if (!tagData)
323
323
  return null;
@@ -331,9 +331,9 @@ export function JamlTag({ tagName, scale = 1, className = "" }) {
331
331
  }),
332
332
  ];
333
333
  const wrapperStyle = { width: `${71 * scale}px` };
334
- return (_jsx("div", { style: wrapperStyle, className: className, children: _jsx(JamlCardRenderer, { layers: layers }) }));
334
+ return (_jsx("div", { style: wrapperStyle, className: className, children: _jsx(JamlCardRenderer, { layers: layers, hoverTilt: hoverTilt }) }));
335
335
  }
336
- export function JamlBoss({ bossName, scale = 1, className = "" }) {
336
+ export function JamlBoss({ bossName, scale = 1, className = "", hoverTilt = false }) {
337
337
  const bossData = BOSSES.find((b) => b.name === bossName);
338
338
  if (!bossData)
339
339
  return null;
@@ -347,5 +347,5 @@ export function JamlBoss({ bossName, scale = 1, className = "" }) {
347
347
  }),
348
348
  ];
349
349
  const wrapperStyle = { width: `${71 * scale}px` };
350
- return (_jsx("div", { style: wrapperStyle, className: className, children: _jsx(JamlCardRenderer, { layers: layers }) }));
350
+ return (_jsx("div", { style: wrapperStyle, className: className, children: _jsx(JamlCardRenderer, { layers: layers, hoverTilt: hoverTilt }) }));
351
351
  }
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ import { type JamlIdeMode } from "./JamlIdeToolbar.js";
3
+ export interface JamlIdeSearchResult {
4
+ seed: string;
5
+ score?: number;
6
+ }
7
+ export interface JamlIdeProps {
8
+ jaml: string;
9
+ onChange: (jaml: string) => void;
10
+ defaultMode?: JamlIdeMode;
11
+ searchResults?: JamlIdeSearchResult[];
12
+ className?: string;
13
+ title?: string;
14
+ actions?: React.ReactNode;
15
+ codePlaceholder?: string;
16
+ }
17
+ export declare function JamlIde({ jaml, onChange, defaultMode, searchResults, className, title, actions, codePlaceholder, }: JamlIdeProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,61 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useMemo, useState } from "react";
4
+ import { JamlMapPreview } from "./JamlMapPreview.js";
5
+ import { JamlIdeToolbar } from "./JamlIdeToolbar.js";
6
+ function ResultsView({ results }) {
7
+ if (results.length === 0) {
8
+ return (_jsx("div", { style: {
9
+ border: "1px dashed rgba(255,255,255,0.18)",
10
+ borderRadius: 12,
11
+ padding: 14,
12
+ fontSize: 12,
13
+ opacity: 0.72,
14
+ background: "rgba(255,255,255,0.03)",
15
+ }, children: "No results yet." }));
16
+ }
17
+ return (_jsx("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: results.map((result, index) => (_jsxs("div", { style: {
18
+ display: "flex",
19
+ alignItems: "center",
20
+ justifyContent: "space-between",
21
+ gap: 12,
22
+ borderRadius: 12,
23
+ border: "1px solid rgba(255,255,255,0.08)",
24
+ background: "rgba(255,255,255,0.03)",
25
+ padding: "10px 12px",
26
+ }, children: [_jsx("div", { style: { fontWeight: 700, letterSpacing: 0.4 }, children: result.seed }), _jsx("div", { style: { fontSize: 12, opacity: 0.7 }, children: result.score !== undefined ? result.score : "-" })] }, `${result.seed}-${index}`))) }));
27
+ }
28
+ export function JamlIde({ jaml, onChange, defaultMode = "code", searchResults = [], className = "", title = "JAML IDE", actions, codePlaceholder = "Enter JAML...", }) {
29
+ const [mode, setMode] = useState(defaultMode);
30
+ const results = useMemo(() => searchResults, [searchResults]);
31
+ return (_jsxs("div", { className: className, style: {
32
+ display: "flex",
33
+ flexDirection: "column",
34
+ minHeight: 420,
35
+ borderRadius: 16,
36
+ overflow: "hidden",
37
+ border: "1px solid rgba(255,255,255,0.08)",
38
+ background: "#17181c",
39
+ color: "#f5f5f5",
40
+ }, children: [_jsxs("div", { style: {
41
+ display: "flex",
42
+ alignItems: "center",
43
+ justifyContent: "space-between",
44
+ gap: 12,
45
+ padding: "12px 14px",
46
+ borderBottom: "1px solid rgba(255,255,255,0.08)",
47
+ background: "rgba(255,255,255,0.03)",
48
+ }, children: [_jsxs("div", { children: [_jsx("div", { style: { fontSize: 16, fontWeight: 800 }, children: title }), _jsx("div", { style: { fontSize: 11, opacity: 0.66 }, children: "Reusable JAML authoring and preview surface." })] }), actions ? _jsx("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: actions }) : null] }), _jsx(JamlIdeToolbar, { mode: mode, onModeChange: setMode, resultCount: results.length }), _jsxs("div", { style: { flex: 1, minHeight: 0, overflow: "auto" }, children: [mode === "code" ? (_jsx("textarea", { title: "JAML IDE Editor", value: jaml, onChange: (event) => onChange(event.target.value), placeholder: codePlaceholder, spellCheck: false, autoCapitalize: "off", autoCorrect: "off", style: {
49
+ width: "100%",
50
+ minHeight: 320,
51
+ resize: "vertical",
52
+ border: 0,
53
+ outline: 0,
54
+ padding: 16,
55
+ background: "transparent",
56
+ color: "inherit",
57
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
58
+ fontSize: 13,
59
+ lineHeight: 1.7,
60
+ } })) : null, mode === "map" ? _jsx(JamlMapPreview, { jaml: jaml }) : null, mode === "results" ? _jsx("div", { style: { padding: 16 }, children: _jsx(ResultsView, { results: results }) }) : null] })] }));
61
+ }
@@ -0,0 +1,8 @@
1
+ export type JamlIdeMode = "code" | "map" | "results";
2
+ export interface JamlIdeToolbarProps {
3
+ mode: JamlIdeMode;
4
+ onModeChange: (mode: JamlIdeMode) => void;
5
+ resultCount?: number;
6
+ className?: string;
7
+ }
8
+ export declare function JamlIdeToolbar({ mode, onModeChange, resultCount, className }: JamlIdeToolbarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ const TABS = [
4
+ { id: "code", label: "Code" },
5
+ { id: "map", label: "Map" },
6
+ { id: "results", label: "Results" },
7
+ ];
8
+ export function JamlIdeToolbar({ mode, onModeChange, resultCount = 0, className = "" }) {
9
+ return (_jsx("div", { className: className, style: {
10
+ display: "flex",
11
+ alignItems: "center",
12
+ justifyContent: "space-between",
13
+ gap: 8,
14
+ padding: "8px 10px",
15
+ borderBottom: "1px solid rgba(255,255,255,0.08)",
16
+ background: "rgba(255,255,255,0.04)",
17
+ }, children: _jsx("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: TABS.map((tab) => {
18
+ const selected = mode === tab.id;
19
+ return (_jsxs("button", { type: "button", onClick: () => onModeChange(tab.id), style: {
20
+ cursor: "pointer",
21
+ borderRadius: 8,
22
+ border: selected ? "1px solid rgba(247,185,85,0.55)" : "1px solid transparent",
23
+ background: selected ? "rgba(247,185,85,0.16)" : "transparent",
24
+ color: selected ? "#f7b955" : "rgba(255,255,255,0.58)",
25
+ padding: "6px 10px",
26
+ fontSize: 11,
27
+ fontWeight: 600,
28
+ }, children: [tab.label, tab.id === "results" && resultCount > 0 ? (_jsx("span", { style: {
29
+ marginLeft: 6,
30
+ borderRadius: 999,
31
+ background: "rgba(0,0,0,0.25)",
32
+ padding: "1px 6px",
33
+ fontSize: 10,
34
+ }, children: resultCount })) : null] }, tab.id));
35
+ }) }) }));
36
+ }
@@ -0,0 +1,10 @@
1
+ export interface JamlMapPreviewProps {
2
+ jaml: string;
3
+ className?: string;
4
+ title?: string;
5
+ emptyMessage?: string;
6
+ cardScale?: number;
7
+ tagScale?: number;
8
+ bossScale?: number;
9
+ }
10
+ export declare function JamlMapPreview({ jaml, className, title, emptyMessage, cardScale, tagScale, bossScale, }: JamlMapPreviewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,117 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useMemo } from "react";
4
+ import { JamlBoss, JamlGameCard, JamlTag, JamlVoucher } from "./GameCard.js";
5
+ import { extractVisualJamlItems } from "../utils/jamlMapPreview.js";
6
+ const SECTION_ORDER = ["must", "should", "mustNot"];
7
+ const SECTION_LABELS = {
8
+ must: "Must Requirements",
9
+ should: "Should Requirements",
10
+ mustNot: "Must Not Requirements",
11
+ };
12
+ const SECTION_ACCENTS = {
13
+ must: { color: "#ff6b6b", border: "rgba(255,107,107,0.35)", panel: "rgba(255,107,107,0.08)" },
14
+ should: { color: "#f7b955", border: "rgba(247,185,85,0.35)", panel: "rgba(247,185,85,0.08)" },
15
+ mustNot: { color: "#8d7dff", border: "rgba(141,125,255,0.35)", panel: "rgba(141,125,255,0.08)" },
16
+ };
17
+ function renderPreviewItem(item, cardScale, tagScale, bossScale) {
18
+ switch (item.visualType) {
19
+ case "joker":
20
+ return _jsx(JamlGameCard, { card: { name: item.value, scale: cardScale }, type: "joker" });
21
+ case "consumable":
22
+ return _jsx(JamlGameCard, { card: { name: item.value, scale: cardScale }, type: "consumable" });
23
+ case "voucher":
24
+ return _jsx(JamlVoucher, { voucherName: item.value, scale: cardScale });
25
+ case "tag":
26
+ return _jsx(JamlTag, { tagName: item.value, scale: tagScale });
27
+ case "boss":
28
+ return _jsx(JamlBoss, { bossName: item.value, scale: bossScale });
29
+ default:
30
+ return null;
31
+ }
32
+ }
33
+ export function JamlMapPreview({ jaml, className = "", title = "JAML Map Preview", emptyMessage = "No visual JAML clauses found yet.", cardScale = 0.8, tagScale = 1.1, bossScale = 1.1, }) {
34
+ const groups = useMemo(() => extractVisualJamlItems(jaml), [jaml]);
35
+ const totalItems = SECTION_ORDER.reduce((sum, section) => sum + groups[section].length, 0);
36
+ return (_jsxs("div", { className: className, style: {
37
+ display: "flex",
38
+ flexDirection: "column",
39
+ gap: 16,
40
+ padding: 16,
41
+ color: "#f5f5f5",
42
+ borderRadius: 20,
43
+ border: "1px solid rgba(152,152,192,0.18)",
44
+ background: "linear-gradient(180deg, rgba(28,26,52,0.96) 0%, rgba(18,16,36,0.96) 100%)",
45
+ boxShadow: "0 14px 32px rgba(0,0,0,0.16)",
46
+ }, children: [_jsxs("div", { style: { display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 12, flexWrap: "wrap" }, children: [_jsxs("div", { children: [_jsx("div", { style: { fontSize: 14, fontWeight: 700, marginBottom: 4 }, children: title }), _jsx("div", { style: { fontSize: 12, opacity: 0.74, maxWidth: 520 }, children: "Preview the visual targets described directly in your JAML without running a full search." })] }), _jsxs("div", { style: {
47
+ display: "inline-flex",
48
+ alignItems: "center",
49
+ gap: 6,
50
+ borderRadius: 999,
51
+ border: "1px solid rgba(141,125,255,0.3)",
52
+ background: "rgba(141,125,255,0.12)",
53
+ padding: "6px 10px",
54
+ fontSize: 11,
55
+ fontWeight: 700,
56
+ color: "#c8bcff",
57
+ letterSpacing: "0.04em",
58
+ textTransform: "uppercase",
59
+ }, children: [_jsx("span", { children: totalItems }), _jsx("span", { children: totalItems === 1 ? "visual target" : "visual targets" })] })] }), totalItems === 0 ? (_jsx("div", { style: {
60
+ border: "1px dashed rgba(152,152,192,0.28)",
61
+ borderRadius: 16,
62
+ padding: 16,
63
+ fontSize: 12,
64
+ opacity: 0.72,
65
+ background: "rgba(255,255,255,0.035)",
66
+ }, children: emptyMessage })) : null, SECTION_ORDER.map((section) => {
67
+ const items = groups[section];
68
+ if (items.length === 0)
69
+ return null;
70
+ const accent = SECTION_ACCENTS[section];
71
+ return (_jsxs("section", { style: {
72
+ display: "flex",
73
+ flexDirection: "column",
74
+ gap: 10,
75
+ borderRadius: 18,
76
+ border: `1px solid ${accent.border}`,
77
+ background: `linear-gradient(180deg, ${accent.panel} 0%, rgba(255,255,255,0.02) 100%)`,
78
+ padding: 12,
79
+ }, children: [_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [_jsx("div", { style: {
80
+ width: 6,
81
+ height: 18,
82
+ borderRadius: 999,
83
+ background: accent.color,
84
+ } }), _jsx("div", { style: { fontSize: 12, fontWeight: 700, color: accent.color }, children: SECTION_LABELS[section] }), _jsx("div", { style: {
85
+ marginLeft: "auto",
86
+ borderRadius: 999,
87
+ padding: "3px 8px",
88
+ fontSize: 10,
89
+ fontWeight: 700,
90
+ color: accent.color,
91
+ background: "rgba(255,255,255,0.04)",
92
+ }, children: items.length })] }), _jsx("div", { style: {
93
+ display: "flex",
94
+ flexWrap: "wrap",
95
+ gap: 12,
96
+ }, children: items.map((item) => (_jsxs("div", { style: {
97
+ display: "flex",
98
+ flexDirection: "column",
99
+ alignItems: "center",
100
+ gap: 8,
101
+ minWidth: 96,
102
+ padding: 12,
103
+ borderRadius: 16,
104
+ border: `1px solid ${accent.border}`,
105
+ background: "rgba(10,10,20,0.24)",
106
+ boxShadow: "inset 0 1px 0 rgba(255,255,255,0.04)",
107
+ }, title: `${item.clauseKey}: ${item.value}`, children: [_jsx("div", { style: { minHeight: 72, display: "flex", alignItems: "center", justifyContent: "center" }, children: renderPreviewItem(item, cardScale, tagScale, bossScale) }), _jsx("div", { style: { fontSize: 11, textAlign: "center", lineHeight: 1.35, fontWeight: 600 }, children: item.value }), _jsx("div", { style: { fontSize: 10, opacity: 0.62, textTransform: "uppercase", letterSpacing: "0.06em" }, children: item.clauseKey })] }, item.id))) })] }, section));
108
+ }), _jsx("div", { style: {
109
+ borderRadius: 16,
110
+ border: "1px dashed rgba(141,125,255,0.28)",
111
+ background: "rgba(141,125,255,0.08)",
112
+ padding: 14,
113
+ fontSize: 11,
114
+ lineHeight: 1.5,
115
+ opacity: 0.84,
116
+ }, children: "This preview shows direct visual targets that can be read from the JAML text itself. Advanced scoring logic, positional constraints, nested groups, and runtime-only search behavior are not fully represented here yet." })] }));
117
+ }