jaml-ui 0.13.1 → 0.14.1

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 (33) hide show
  1. package/assets/Balatro Seed Curator (DesignsV2)/Assets/Decks/playing_cards_metadata.json +230 -55
  2. package/dist/components/AnalyzerExplorer.js +75 -90
  3. package/dist/components/CardFan.js +2 -2
  4. package/dist/components/GameCard.js +9 -9
  5. package/dist/components/JamlAestheticSelector.d.ts +9 -0
  6. package/dist/components/JamlAestheticSelector.js +36 -0
  7. package/dist/components/JamlIde.d.ts +2 -1
  8. package/dist/components/JamlIde.js +6 -4
  9. package/dist/components/JamlIdeToolbar.js +1 -0
  10. package/dist/components/JamlSeedInput.d.ts +9 -0
  11. package/dist/components/JamlSeedInput.js +30 -0
  12. package/dist/components/JamlSpeedometer.d.ts +11 -0
  13. package/dist/components/JamlSpeedometer.js +54 -0
  14. package/dist/components/Standardcard.d.ts +18 -0
  15. package/dist/components/Standardcard.js +80 -0
  16. package/dist/decode/motelyItemDecoder.d.ts +3 -3
  17. package/dist/decode/motelyItemDecoder.js +12 -12
  18. package/dist/decode/packedBalatroItem.d.ts +1 -1
  19. package/dist/decode/packedBalatroItem.js +2 -2
  20. package/dist/hooks/searchWorkerCode.d.ts +1 -1
  21. package/dist/hooks/searchWorkerCode.js +31 -5
  22. package/dist/hooks/useSearch.d.ts +9 -0
  23. package/dist/hooks/useSearch.js +73 -17
  24. package/dist/index.d.ts +5 -1
  25. package/dist/index.js +5 -1
  26. package/dist/motely.d.ts +1 -1
  27. package/dist/motely.js +1 -1
  28. package/dist/ui/jimboTabs.js +1 -1
  29. package/dist/utils/fileSystem.d.ts +1 -0
  30. package/dist/utils/fileSystem.js +23 -0
  31. package/dist/utils/itemUtils.d.ts +1 -1
  32. package/dist/utils/itemUtils.js +3 -3
  33. package/package.json +4 -3
@@ -8,16 +8,20 @@ function createWorker(motelyWasmUrl) {
8
8
  worker.postMessage({ type: "init", url: motelyWasmUrl });
9
9
  return worker;
10
10
  }
11
+ const INITIAL_STATE = {
12
+ results: [],
13
+ totalSearched: 0n,
14
+ matchingSeeds: 0n,
15
+ status: "idle",
16
+ error: null,
17
+ seedsPerSecond: 0,
18
+ tallyLabels: [],
19
+ };
11
20
  export function useSearch(motelyWasmUrl) {
12
- const [state, setState] = useState({
13
- results: [],
14
- totalSearched: 0n,
15
- matchingSeeds: 0n,
16
- status: "idle",
17
- error: null,
18
- });
21
+ const [state, setState] = useState(INITIAL_STATE);
19
22
  const workerRef = useRef(null);
20
23
  const readyRef = useRef(false);
24
+ const speedRef = useRef({ lastSearched: 0n, lastTime: 0, ema: 0 });
21
25
  useEffect(() => {
22
26
  setState((s) => ({ ...s, status: "booting" }));
23
27
  const worker = createWorker(motelyWasmUrl);
@@ -30,16 +34,51 @@ export function useSearch(motelyWasmUrl) {
30
34
  setState((s) => s.status === "booting" ? { ...s, status: "idle" } : s);
31
35
  }
32
36
  else if (msg.type === "result") {
33
- setState((s) => ({ ...s, results: [...s.results, { seed: msg.seed, score: msg.score }] }));
37
+ setState((s) => ({
38
+ ...s,
39
+ results: [...s.results, {
40
+ seed: msg.seed,
41
+ score: msg.score,
42
+ tallyColumns: msg.tallyColumns,
43
+ }],
44
+ }));
34
45
  }
35
46
  else if (msg.type === "progress") {
36
- setState((s) => ({ ...s, totalSearched: BigInt(msg.searched), matchingSeeds: BigInt(msg.matching) }));
47
+ const searched = BigInt(msg.searched);
48
+ const matching = BigInt(msg.matching);
49
+ const now = performance.now();
50
+ const ref = speedRef.current;
51
+ let sps = ref.ema;
52
+ if (ref.lastTime > 0) {
53
+ const dtMs = now - ref.lastTime;
54
+ if (dtMs > 0) {
55
+ const delta = Number(searched - ref.lastSearched);
56
+ const instantSps = delta / (dtMs / 1000);
57
+ sps = ref.ema === 0 ? instantSps : ref.ema * 0.7 + instantSps * 0.3;
58
+ }
59
+ }
60
+ ref.lastSearched = searched;
61
+ ref.lastTime = now;
62
+ ref.ema = sps;
63
+ setState((s) => ({ ...s, totalSearched: searched, matchingSeeds: matching, seedsPerSecond: Math.round(sps) }));
37
64
  }
38
65
  else if (msg.type === "complete") {
39
- setState((s) => ({ ...s, status: msg.status === "Completed" ? "completed" : "error", error: msg.status !== "Completed" ? msg.status : null, totalSearched: BigInt(msg.searched), matchingSeeds: BigInt(msg.matched) }));
66
+ speedRef.current = { lastSearched: 0n, lastTime: 0, ema: 0 };
67
+ setState((s) => ({
68
+ ...s,
69
+ status: msg.status === "Completed" ? "completed" : "error",
70
+ error: msg.status !== "Completed" ? msg.status : null,
71
+ totalSearched: BigInt(msg.searched),
72
+ matchingSeeds: BigInt(msg.matched),
73
+ seedsPerSecond: 0,
74
+ }));
40
75
  }
41
76
  else if (msg.type === "cancelled") {
42
- setState((s) => ({ ...s, status: "cancelled" }));
77
+ speedRef.current = { lastSearched: 0n, lastTime: 0, ema: 0 };
78
+ setState((s) => ({ ...s, status: "cancelled", seedsPerSecond: 0 }));
79
+ }
80
+ else if (msg.type === "tally_labels") {
81
+ setState((s) => ({ ...s, tallyLabels: msg.labels }));
43
82
  }
44
83
  else if (msg.type === "error") {
45
84
  setState((s) => ({ ...s, status: "error", error: msg.message }));
@@ -50,13 +89,15 @@ export function useSearch(motelyWasmUrl) {
50
89
  workerRef.current = null;
51
90
  };
52
91
  }, [motelyWasmUrl]);
53
- const start = useCallback((jaml, count) => {
92
+ const sendStart = useCallback((payload) => {
54
93
  const worker = workerRef.current;
55
94
  if (!worker)
56
95
  return;
57
- setState({ results: [], totalSearched: 0n, matchingSeeds: 0n, status: "running", error: null });
96
+ speedRef.current = { lastSearched: 0n, lastTime: 0, ema: 0 };
97
+ setState({ ...INITIAL_STATE, status: "running", tallyLabels: state.tallyLabels });
98
+ const send = () => worker.postMessage(payload);
58
99
  if (readyRef.current) {
59
- worker.postMessage({ type: "start", jaml, count });
100
+ send();
60
101
  }
61
102
  else {
62
103
  const orig = worker.onmessage;
@@ -64,16 +105,31 @@ export function useSearch(motelyWasmUrl) {
64
105
  orig?.call(worker, e);
65
106
  if (e.data.type === "ready") {
66
107
  worker.onmessage = orig;
67
- worker.postMessage({ type: "start", jaml, count });
108
+ send();
68
109
  }
69
110
  };
70
111
  }
71
- }, []);
112
+ }, [state.tallyLabels]);
113
+ const start = useCallback((jaml, count) => {
114
+ sendStart({ type: "start", mode: "random", jaml, count });
115
+ }, [sendStart]);
116
+ const startAesthetic = useCallback((jaml, aesthetic) => {
117
+ sendStart({ type: "start", mode: "aesthetic", jaml, aesthetic });
118
+ }, [sendStart]);
119
+ const startSeedList = useCallback((jaml, seeds) => {
120
+ sendStart({ type: "start", mode: "seedList", jaml, seeds });
121
+ }, [sendStart]);
122
+ const startKeyword = useCallback((jaml, keywords, padding) => {
123
+ sendStart({ type: "start", mode: "keyword", jaml, keywords, padding });
124
+ }, [sendStart]);
72
125
  const cancel = useCallback(() => {
73
126
  workerRef.current?.postMessage({ type: "stop" });
74
127
  }, []);
75
128
  const clearError = useCallback(() => {
76
129
  setState((s) => (s.error || s.status === "error" ? { ...s, error: null, status: "idle" } : s));
77
130
  }, []);
78
- return { ...state, start, cancel, clearError };
131
+ const fetchTallyLabels = useCallback((jaml) => {
132
+ workerRef.current?.postMessage({ type: "get_tally_labels", jaml });
133
+ }, []);
134
+ return { ...state, start, startAesthetic, startSeedList, startKeyword, cancel, clearError, fetchTallyLabels };
79
135
  }
package/dist/index.d.ts CHANGED
@@ -18,10 +18,14 @@ export { JimboTooltip, type JimboTooltipProps, type JimboTooltipMode, type Jimbo
18
18
  export { JamlIdeToolbar, type JamlIdeMode, type JamlIdeToolbarProps, } from "./components/JamlIdeToolbar.js";
19
19
  export { CardList, type CardListProps } from "./components/CardList.js";
20
20
  export { CardFan, type CardFanProps } from "./components/CardFan.js";
21
- export { RealPlayingCard, type CardSuit, type CardRank, type CardEnhancement, type CardSeal, type CardEdition, } from "./components/PlayingCard.js";
21
+ export { RealStandardcard, type CardSuit, type CardRank, type CardEnhancement, type CardSeal, type CardEdition, } from "./components/Standardcard.js";
22
22
  export { DeckSprite, DECK_SPRITE_POS, STAKE_SPRITE_POS, type DeckSpriteProps, } from "./components/DeckSprite.js";
23
23
  export { MotelyVersionBadge, type MotelyVersionBadgeProps, type MotelyCapabilities, } from "./components/MotelyVersionBadge.js";
24
24
  export { extractVisualJamlItems, type JamlPreviewGroups, type JamlPreviewItem, type JamlPreviewSection, type JamlPreviewVisualType, } from "./utils/jamlMapPreview.js";
25
25
  export { useMotelyStream, type StreamItem, type StreamState } from "./hooks/useShopStream.js";
26
26
  export { useSearch, type SearchResult, type SearchStatus, type UseSearchState, } from "./hooks/useSearch.js";
27
27
  export { useAnalyzer, type AnalyzerStatus, type AnalyzerLive, type MotelyJsRunState, } from "./hooks/useAnalyzer.js";
28
+ export { JamlSpeedometer, type JamlSpeedometerProps, } from "./components/JamlSpeedometer.js";
29
+ export { JamlAestheticSelector, type JamlAestheticSelectorProps, type JamlAestheticOption, } from "./components/JamlAestheticSelector.js";
30
+ export { JamlSeedInput, type JamlSeedInputProps, } from "./components/JamlSeedInput.js";
31
+ export { initJamlFileSystem } from "./utils/fileSystem.js";
package/dist/index.js CHANGED
@@ -19,10 +19,14 @@ export { JimboTooltip, } from "./ui/jimboTooltip.js";
19
19
  export { JamlIdeToolbar, } from "./components/JamlIdeToolbar.js";
20
20
  export { CardList } from "./components/CardList.js";
21
21
  export { CardFan } from "./components/CardFan.js";
22
- export { RealPlayingCard, } from "./components/PlayingCard.js";
22
+ export { RealStandardcard, } from "./components/Standardcard.js";
23
23
  export { DeckSprite, DECK_SPRITE_POS, STAKE_SPRITE_POS, } from "./components/DeckSprite.js";
24
24
  export { MotelyVersionBadge, } from "./components/MotelyVersionBadge.js";
25
25
  export { extractVisualJamlItems, } from "./utils/jamlMapPreview.js";
26
26
  export { useMotelyStream } from "./hooks/useShopStream.js";
27
27
  export { useSearch, } from "./hooks/useSearch.js";
28
28
  export { useAnalyzer, } from "./hooks/useAnalyzer.js";
29
+ export { JamlSpeedometer, } from "./components/JamlSpeedometer.js";
30
+ export { JamlAestheticSelector, } from "./components/JamlAestheticSelector.js";
31
+ export { JamlSeedInput, } from "./components/JamlSeedInput.js";
32
+ export { initJamlFileSystem } from "./utils/fileSystem.js";
package/dist/motely.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { decodeMotelyItem, decodeMotelyItemToJamlCard, motelyItemTypeName, motelyItemCategory, motelyItemDisplayName, motelyItemRenderCategory, motelyItemEditionName, motelyItemSealName, motelyItemEnhancementName, motelyPlayingCardRankName, motelyPlayingCardSuitName, decodeMotelyItemName, resolveMotelyItemType, warmMotelyItemCache, motelyItemCacheSize, type DecodedMotelyItem, type MotelyItemInput, type MotelyJamlCard, type MotelyRenderableCategory, type MotelyRuntimeItem, } from "./decode/motelyItemDecoder.js";
1
+ export { decodeMotelyItem, decodeMotelyItemToJamlCard, motelyItemTypeName, motelyItemCategory, motelyItemDisplayName, motelyItemRenderCategory, motelyItemEditionName, motelyItemSealName, motelyItemEnhancementName, motelyStandardcardRankName, motelyStandardcardSuitName, decodeMotelyItemName, resolveMotelyItemType, warmMotelyItemCache, motelyItemCacheSize, type DecodedMotelyItem, type MotelyItemInput, type MotelyJamlCard, type MotelyRenderableCategory, type MotelyRuntimeItem, } from "./decode/motelyItemDecoder.js";
2
2
  export { MOTELY_DISPLAY_SCHEMA, motelyBossDisplayName, motelyBossDisplayNameFromKey, motelyBossKeyFromDisplayName, motelyBoosterPackDisplayName, motelyBoosterPackDisplayNameFromKey, motelyBoosterPackKeyFromDisplayName, motelyItemDisplayNameFromKey, motelyItemDisplayNameFromValue, motelyTagDisplayName, motelyTagDisplayNameFromKey, motelyTagKeyFromDisplayName, motelyVoucherDisplayName, motelyVoucherDisplayNameFromKey, motelyVoucherKeyFromDisplayName, type MotelyBoosterPackKey, type MotelyBossKey, type MotelyDisplaySchema, type MotelyTagKey, type MotelyVoucherKey, } from "./motelyDisplay.js";
package/dist/motely.js CHANGED
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- export { decodeMotelyItem, decodeMotelyItemToJamlCard, motelyItemTypeName, motelyItemCategory, motelyItemDisplayName, motelyItemRenderCategory, motelyItemEditionName, motelyItemSealName, motelyItemEnhancementName, motelyPlayingCardRankName, motelyPlayingCardSuitName, decodeMotelyItemName, resolveMotelyItemType, warmMotelyItemCache, motelyItemCacheSize, } from "./decode/motelyItemDecoder.js";
2
+ export { decodeMotelyItem, decodeMotelyItemToJamlCard, motelyItemTypeName, motelyItemCategory, motelyItemDisplayName, motelyItemRenderCategory, motelyItemEditionName, motelyItemSealName, motelyItemEnhancementName, motelyStandardcardRankName, motelyStandardcardSuitName, decodeMotelyItemName, resolveMotelyItemType, warmMotelyItemCache, motelyItemCacheSize, } from "./decode/motelyItemDecoder.js";
3
3
  export { MOTELY_DISPLAY_SCHEMA, motelyBossDisplayName, motelyBossDisplayNameFromKey, motelyBossKeyFromDisplayName, motelyBoosterPackDisplayName, motelyBoosterPackDisplayNameFromKey, motelyBoosterPackKeyFromDisplayName, motelyItemDisplayNameFromKey, motelyItemDisplayNameFromValue, motelyTagDisplayName, motelyTagDisplayNameFromKey, motelyTagKeyFromDisplayName, motelyVoucherDisplayName, motelyVoucherDisplayNameFromKey, motelyVoucherKeyFromDisplayName, } from "./motelyDisplay.js";
@@ -9,7 +9,7 @@ import { JimboText } from './jimboText.js';
9
9
  * button and animates only on the active one.
10
10
  */
11
11
  export function JimboTabs({ tabs, activeTab, onTabChange, className = '', style }) {
12
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: className, style: { display: 'flex', gap: 8, alignItems: 'flex-end', ...style }, children: tabs.map((tab) => (_jsx(TabButton, { label: tab.label, active: activeTab === tab.id, onClick: () => onTabChange(tab.id) }, tab.id))) }), _jsx("style", { children: JIMBO_BOUNCE_KEYFRAMES })] }));
12
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: className, style: { display: 'flex', gap: 8, alignItems: 'flex-end', flexWrap: 'wrap', ...style }, children: tabs.map((tab) => (_jsx(TabButton, { label: tab.label, active: activeTab === tab.id, onClick: () => onTabChange(tab.id) }, tab.id))) }), _jsx("style", { children: JIMBO_BOUNCE_KEYFRAMES })] }));
13
13
  }
14
14
  const JIMBO_BOUNCE_KEYFRAMES = `
15
15
  @keyframes jimbo-bounce {
@@ -0,0 +1 @@
1
+ export declare function initJamlFileSystem(): boolean;
@@ -0,0 +1,23 @@
1
+ import { init } from "@rewaffle/bootsharp-file-system";
2
+ // Assuming motely-wasm exposes Bootsharp APIs
3
+ // We need to pass the FileMounter export generated by Bootsharp
4
+ import * as motelyWasm from "motely-wasm";
5
+ export function initJamlFileSystem() {
6
+ if (motelyWasm && motelyWasm.Bootsharp && motelyWasm.Bootsharp.FileSystem) {
7
+ const fileMounter = motelyWasm.Bootsharp.FileSystem.FileMounter;
8
+ if (fileMounter) {
9
+ init(fileMounter);
10
+ return true;
11
+ }
12
+ }
13
+ // Also try lowercase namespaces depending on how bootsharp generates it
14
+ if (motelyWasm && motelyWasm.bootsharp && motelyWasm.bootsharp.fileSystem) {
15
+ const fileMounter = motelyWasm.bootsharp.fileSystem.fileMounter;
16
+ if (fileMounter) {
17
+ init(fileMounter);
18
+ return true;
19
+ }
20
+ }
21
+ console.warn("Could not initialize Jaml File System: Bootsharp.FileSystem.FileMounter not found in motely-wasm.");
22
+ return false;
23
+ }
@@ -7,5 +7,5 @@ export declare const CATEGORY_COLORS: Record<CardCategory, {
7
7
  border: string;
8
8
  text: string;
9
9
  }>;
10
- /** Suit color for playing cards */
10
+ /** Suit color for standard cards */
11
11
  export declare function getSuitColor(enumKey: string): string;
@@ -17,7 +17,7 @@ export function getItemDisplayName(enumKey) {
17
17
  };
18
18
  if (specials[enumKey])
19
19
  return specials[enumKey];
20
- // Playing cards: C2 = 2 of Clubs, D10 = 10 of Diamonds, etc.
20
+ // Standard cards: C2 = 2 of Clubs, D10 = 10 of Diamonds, etc.
21
21
  const suitMap = { C: "♣", D: "♦", H: "♥", S: "♠" };
22
22
  const cardMatch = enumKey.match(/^([CDHS])([2-9JQKA]|10)$/);
23
23
  if (cardMatch) {
@@ -52,7 +52,7 @@ export function getItemCategory(enumKey) {
52
52
  return "planet";
53
53
  if (SPECTRAL_NAMES.has(enumKey))
54
54
  return "spectral";
55
- // Everything else between the playing cards and Invalid is a joker
55
+ // Everything else between the standard cards and Invalid is a joker
56
56
  return "joker";
57
57
  }
58
58
  export const CATEGORY_COLORS = {
@@ -63,7 +63,7 @@ export const CATEGORY_COLORS = {
63
63
  playing: { bg: "bg-neutral-100 dark:bg-neutral-800", border: "border-neutral-300 dark:border-neutral-600", text: "text-neutral-900 dark:text-neutral-100" },
64
64
  unknown: { bg: "bg-neutral-900/30", border: "border-neutral-500/50", text: "text-neutral-300" },
65
65
  };
66
- /** Suit color for playing cards */
66
+ /** Suit color for standard cards */
67
67
  export function getSuitColor(enumKey) {
68
68
  if (enumKey.startsWith("H") || enumKey.startsWith("D"))
69
69
  return "text-red-500";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaml-ui",
3
- "version": "0.13.1",
3
+ "version": "0.14.1",
4
4
  "description": "Balatro rendering components, sprite metadata, and optional Motely helpers for React apps.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -76,7 +76,7 @@
76
76
  "@react-spring/three": ">=9.0.0",
77
77
  "@react-three/fiber": ">=8.0.0",
78
78
  "monaco-editor": ">=0.50.0",
79
- "motely-wasm": "^10.2.0 || ^11.0.0 || ^12.0.0 || ^13.0.0",
79
+ "motely-wasm": "^10.2.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0",
80
80
  "react": "^18.2.0 || ^19.0.0",
81
81
  "react-dom": "^18.2.0 || ^19.0.0",
82
82
  "react-icons": ">=5.0.0",
@@ -108,7 +108,8 @@
108
108
  "@types/three": "^0.184.0",
109
109
  "@vitejs/plugin-react": "^5.0.4",
110
110
  "monaco-editor": "^0.55.1",
111
- "motely-wasm": "^13.0.1",
111
+ "motely-wasm": "link:../JammySeedFinder/src/MotelyJAML/Motely.Wasm/bin/motely-wasm",
112
+ "@rewaffle/bootsharp-file-system": "link:D:/extra/bootsharp/dist/packages/file-system",
112
113
  "react": "^19.2.4",
113
114
  "react-dom": "^19.2.4",
114
115
  "react-icons": "^5.6.0",