jaml-ui 0.24.20 → 0.25.2

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 (233) hide show
  1. package/README.md +0 -13
  2. package/assets/WeeJokerExampleDAilyGame.png +0 -0
  3. package/assets/balatro-stake-chips.png +0 -0
  4. package/dist/assets.d.ts +1 -2
  5. package/dist/chunks/Layer-BBPJFHfs.js +17 -0
  6. package/dist/chunks/Layer-BBPJFHfs.js.map +1 -0
  7. package/dist/chunks/assets-RWUiFSTc.js +37 -0
  8. package/dist/chunks/assets-RWUiFSTc.js.map +1 -0
  9. package/dist/chunks/motelyItemDecoder-CueyZ0XD.js +6039 -0
  10. package/dist/chunks/motelyItemDecoder-CueyZ0XD.js.map +1 -0
  11. package/dist/chunks/spriteMapper-CFjN0_TV.js +2415 -0
  12. package/dist/chunks/spriteMapper-CFjN0_TV.js.map +1 -0
  13. package/dist/chunks/tokens-B65Fzble.js +57 -0
  14. package/dist/chunks/tokens-B65Fzble.js.map +1 -0
  15. package/dist/chunks/ui-5cBy3zAm.js +1387 -0
  16. package/dist/chunks/ui-5cBy3zAm.js.map +1 -0
  17. package/dist/components/AnalyzerExplorer.d.ts +1 -1
  18. package/dist/components/CardFan.d.ts +1 -1
  19. package/dist/components/CardList.d.ts +1 -1
  20. package/dist/components/DeckSprite.d.ts +1 -1
  21. package/dist/components/JamlAestheticSelector.d.ts +1 -1
  22. package/dist/components/JamlAnalyzerFullscreen.d.ts +5 -5
  23. package/dist/components/JamlCurator.d.ts +1 -6
  24. package/dist/components/JamlIde.d.ts +5 -5
  25. package/dist/components/JamlSeedInput.d.ts +1 -1
  26. package/dist/components/JamlSpeedometer.d.ts +1 -1
  27. package/dist/components/MotelyVersionBadge.d.ts +1 -1
  28. package/dist/components/Standardcard.d.ts +1 -1
  29. package/dist/components/jamlMap/CategoryPicker.d.ts +3 -3
  30. package/dist/components/jamlMap/JamlMapEditor.d.ts +1 -1
  31. package/dist/components/jamlMap/JokerPicker.d.ts +1 -1
  32. package/dist/components/jamlMap/MysterySlot.d.ts +2 -2
  33. package/dist/components/jamlMap/index.d.ts +4 -4
  34. package/dist/core.d.ts +5 -5
  35. package/dist/core.js +27 -5
  36. package/dist/core.js.map +1 -0
  37. package/dist/decode/motelyItemDecoder.d.ts +0 -10
  38. package/dist/decode/motelySprite.d.ts +1 -1
  39. package/dist/fonts/m6x11plus.otf +0 -0
  40. package/dist/hooks/analyzerStreamRegistry.d.ts +2 -2
  41. package/dist/hooks/useAnalyzer.d.ts +3 -3
  42. package/dist/hooks/useSearch.d.ts +2 -2
  43. package/dist/index.d.ts +29 -31
  44. package/dist/index.js +16721 -34
  45. package/dist/index.js.map +1 -0
  46. package/dist/lib/const.d.ts +2 -2
  47. package/dist/lib/hooks/useDragScroll.d.ts +1 -1
  48. package/dist/lib/hooks/useJamlFilter.d.ts +2 -2
  49. package/dist/lib/hooks/useSeedAnalyzer.d.ts +2 -2
  50. package/dist/lib/utils.d.ts +1 -1
  51. package/dist/motely.d.ts +4 -3
  52. package/dist/motely.js +65 -3
  53. package/dist/motely.js.map +1 -0
  54. package/dist/motelyBoot.d.ts +2 -0
  55. package/dist/motelyDisplay.d.ts +0 -2
  56. package/dist/r3f/Card3D.d.ts +2 -2
  57. package/dist/r3f/JimboBillboard.d.ts +1 -1
  58. package/dist/r3f.js +235 -3
  59. package/dist/r3f.js.map +1 -0
  60. package/dist/render/CanvasRenderer.d.ts +1 -1
  61. package/dist/sprites/spriteData.d.ts +1 -6
  62. package/dist/sprites/spriteMapper.d.ts +1 -1
  63. package/dist/ui/JimboBadge.d.ts +1 -1
  64. package/dist/ui/JimboFloating.d.ts +1 -1
  65. package/dist/ui/JimboIconButton.d.ts +1 -1
  66. package/dist/ui/JimboSelect.d.ts +1 -1
  67. package/dist/ui/footer.d.ts +2 -3
  68. package/dist/ui/hooks.d.ts +1 -1
  69. package/dist/ui/ide/DeckSprite.d.ts +1 -1
  70. package/dist/ui/jimbo.css +2 -1856
  71. package/dist/ui/jimboApp.d.ts +1 -1
  72. package/dist/ui/jimboFilterBar.d.ts +1 -1
  73. package/dist/ui/jimboFlankNav.d.ts +1 -1
  74. package/dist/ui/jimboInfoCard.d.ts +1 -1
  75. package/dist/ui/jimboInset.d.ts +1 -1
  76. package/dist/ui/jimboStatGrid.d.ts +1 -1
  77. package/dist/ui/jimboText.d.ts +1 -1
  78. package/dist/ui/jimboTooltip.d.ts +2 -2
  79. package/dist/ui/mascot/SeedMascot.d.ts +2 -2
  80. package/dist/ui/panel.d.ts +1 -1
  81. package/dist/ui/radial/RadialBadge.d.ts +1 -2
  82. package/dist/ui/radial/RadialButton.d.ts +1 -2
  83. package/dist/ui/radial/RadialMenu.d.ts +2 -2
  84. package/dist/ui/radial/RadialPill.d.ts +1 -2
  85. package/dist/ui/radial/index.d.ts +16 -16
  86. package/dist/ui/radial/radialMenuStore.d.ts +1 -1
  87. package/dist/ui/showcase.d.ts +1 -1
  88. package/dist/ui/sprites.d.ts +2 -2
  89. package/dist/ui.d.ts +0 -1
  90. package/dist/ui.js +3 -36
  91. package/dist/utils/gameCardUtils.d.ts +1 -1
  92. package/dist/utils/jamlVisualFilter.d.ts +1 -7
  93. package/package.json +13 -25
  94. package/dist/assets.js +0 -48
  95. package/dist/components/AnalyzerExplorer.js +0 -391
  96. package/dist/components/CardFan.js +0 -80
  97. package/dist/components/CardList.js +0 -5
  98. package/dist/components/DeckSprite.js +0 -75
  99. package/dist/components/GameCard.js +0 -355
  100. package/dist/components/JamlAestheticSelector.js +0 -22
  101. package/dist/components/JamlAnalyzerFullscreen.js +0 -263
  102. package/dist/components/JamlCodeEditor.js +0 -137
  103. package/dist/components/JamlCurator.js +0 -64
  104. package/dist/components/JamlCurator.stories.d.ts +0 -6
  105. package/dist/components/JamlCurator.stories.js +0 -14
  106. package/dist/components/JamlIde.js +0 -193
  107. package/dist/components/JamlIdeToolbar.js +0 -23
  108. package/dist/components/JamlIdeVisual.js +0 -218
  109. package/dist/components/JamlMapPreview.js +0 -121
  110. package/dist/components/JamlSeedInput.js +0 -26
  111. package/dist/components/JamlSpeedometer.js +0 -70
  112. package/dist/components/Jimbolate.js +0 -17
  113. package/dist/components/MotelyVersionBadge.js +0 -19
  114. package/dist/components/PaginatedFilterBrowser.js +0 -54
  115. package/dist/components/RunConfigModal.js +0 -59
  116. package/dist/components/Standardcard.js +0 -80
  117. package/dist/components/jamlMap/CategoryPicker.js +0 -135
  118. package/dist/components/jamlMap/JamlMapEditor.js +0 -304
  119. package/dist/components/jamlMap/JamlMapEditor.stories.d.ts +0 -7
  120. package/dist/components/jamlMap/JamlMapEditor.stories.js +0 -26
  121. package/dist/components/jamlMap/JamlMapEditorDemo.d.ts +0 -8
  122. package/dist/components/jamlMap/JamlMapEditorDemo.js +0 -323
  123. package/dist/components/jamlMap/JokerPicker.js +0 -113
  124. package/dist/components/jamlMap/MysterySlot.js +0 -128
  125. package/dist/components/jamlMap/MysterySlot.stories.d.ts +0 -7
  126. package/dist/components/jamlMap/MysterySlot.stories.js +0 -31
  127. package/dist/components/jamlMap/index.js +0 -4
  128. package/dist/decode/motelyItemDecoder.js +0 -164
  129. package/dist/decode/motelySprite.js +0 -84
  130. package/dist/hooks/analyzerStreamRegistry.js +0 -96
  131. package/dist/hooks/searchWorker.d.ts +0 -1
  132. package/dist/hooks/searchWorker.js +0 -119
  133. package/dist/hooks/searchWorkerCode.d.ts +0 -1
  134. package/dist/hooks/searchWorkerCode.js +0 -85
  135. package/dist/hooks/useAnalyzer.js +0 -91
  136. package/dist/hooks/useIntersectionObserver.js +0 -52
  137. package/dist/hooks/useSearch.js +0 -161
  138. package/dist/hooks/useShopStream.js +0 -85
  139. package/dist/lib/SpriteMapper.js +0 -48
  140. package/dist/lib/cardParser.js +0 -67
  141. package/dist/lib/classes/BuyMetaData.js +0 -1
  142. package/dist/lib/config.js +0 -15
  143. package/dist/lib/const.js +0 -521
  144. package/dist/lib/data/constants.js +0 -14
  145. package/dist/lib/hooks/useDragScroll.js +0 -48
  146. package/dist/lib/hooks/useJamlFilter.js +0 -219
  147. package/dist/lib/hooks/useSeedAnalyzer.js +0 -50
  148. package/dist/lib/jaml/jamlCompletion.js +0 -13
  149. package/dist/lib/jaml/jamlData.js +0 -6
  150. package/dist/lib/jaml/jamlObjectives.js +0 -97
  151. package/dist/lib/jaml/jamlParser.js +0 -47
  152. package/dist/lib/jaml/jamlPresets.js +0 -61
  153. package/dist/lib/jaml/jamlSchema.js +0 -91
  154. package/dist/lib/parseDailyRitual.js +0 -70
  155. package/dist/lib/tts/getRevealPos.js +0 -16
  156. package/dist/lib/tts/splitTtsDisplay.js +0 -35
  157. package/dist/lib/types.js +0 -1
  158. package/dist/lib/utils.js +0 -5
  159. package/dist/motelyDisplay.js +0 -59
  160. package/dist/r3f/Card3D.js +0 -72
  161. package/dist/r3f/JimboBillboard.js +0 -32
  162. package/dist/r3f/JimboText3D.js +0 -8
  163. package/dist/render/CanvasRenderer.js +0 -11
  164. package/dist/render/Layer.js +0 -18
  165. package/dist/sprites/spriteData.js +0 -100
  166. package/dist/sprites/spriteMapper.js +0 -75
  167. package/dist/stories/Button.d.ts +0 -15
  168. package/dist/stories/Button.js +0 -7
  169. package/dist/stories/Button.stories.d.ts +0 -24
  170. package/dist/stories/Button.stories.js +0 -50
  171. package/dist/stories/Header.d.ts +0 -12
  172. package/dist/stories/Header.js +0 -4
  173. package/dist/stories/Header.stories.d.ts +0 -18
  174. package/dist/stories/Header.stories.js +0 -26
  175. package/dist/stories/Page.d.ts +0 -3
  176. package/dist/stories/Page.js +0 -8
  177. package/dist/stories/Page.stories.d.ts +0 -12
  178. package/dist/stories/Page.stories.js +0 -24
  179. package/dist/ui/Jimbo.stories.d.ts +0 -7
  180. package/dist/ui/Jimbo.stories.js +0 -28
  181. package/dist/ui/JimboBadge.js +0 -8
  182. package/dist/ui/JimboFloating.js +0 -17
  183. package/dist/ui/JimboIconButton.js +0 -28
  184. package/dist/ui/JimboInputModal.js +0 -66
  185. package/dist/ui/JimboSelect.js +0 -43
  186. package/dist/ui/JimboToggleList.js +0 -5
  187. package/dist/ui/PanelSplitter.js +0 -78
  188. package/dist/ui/codeBlock.js +0 -14
  189. package/dist/ui/footer.js +0 -20
  190. package/dist/ui/hooks.js +0 -634
  191. package/dist/ui/ide/AgnosticSeedCard.d.ts +0 -19
  192. package/dist/ui/ide/AgnosticSeedCard.js +0 -48
  193. package/dist/ui/ide/DeckSprite.js +0 -2
  194. package/dist/ui/ide/JamlBuilder.d.ts +0 -1
  195. package/dist/ui/ide/JamlBuilder.js +0 -112
  196. package/dist/ui/ide/JamlEditor.js +0 -486
  197. package/dist/ui/ide/JamlEditorMonaco.d.ts +0 -8
  198. package/dist/ui/ide/JamlEditorMonaco.js +0 -78
  199. package/dist/ui/ide/WasmStatus.d.ts +0 -1
  200. package/dist/ui/ide/WasmStatus.js +0 -42
  201. package/dist/ui/jimboApp.js +0 -15
  202. package/dist/ui/jimboBackground.js +0 -27
  203. package/dist/ui/jimboCopyRow.js +0 -18
  204. package/dist/ui/jimboFilterBar.js +0 -16
  205. package/dist/ui/jimboFlankNav.js +0 -18
  206. package/dist/ui/jimboInfoCard.js +0 -26
  207. package/dist/ui/jimboInset.js +0 -9
  208. package/dist/ui/jimboSectionHeader.js +0 -9
  209. package/dist/ui/jimboStatGrid.js +0 -9
  210. package/dist/ui/jimboTabs.js +0 -22
  211. package/dist/ui/jimboText.js +0 -33
  212. package/dist/ui/jimboTooltip.js +0 -39
  213. package/dist/ui/jimboWordmark.js +0 -9
  214. package/dist/ui/mascot/JammySpeechBox.js +0 -30
  215. package/dist/ui/mascot/SeedMascot.js +0 -17
  216. package/dist/ui/mascot/index.js +0 -3
  217. package/dist/ui/mascot/menuConfig.js +0 -12
  218. package/dist/ui/panel.js +0 -24
  219. package/dist/ui/radial/RadialBadge.js +0 -43
  220. package/dist/ui/radial/RadialBreadcrumb.js +0 -18
  221. package/dist/ui/radial/RadialButton.js +0 -102
  222. package/dist/ui/radial/RadialMenu.js +0 -168
  223. package/dist/ui/radial/RadialPill.js +0 -15
  224. package/dist/ui/radial/index.js +0 -18
  225. package/dist/ui/radial/radialMenuStore.js +0 -122
  226. package/dist/ui/radial/radialMenuViewport.js +0 -59
  227. package/dist/ui/radial/useRadialMenu.js +0 -107
  228. package/dist/ui/showcase.js +0 -20
  229. package/dist/ui/sprites.js +0 -77
  230. package/dist/ui/tokens.js +0 -64
  231. package/dist/utils/gameCardUtils.js +0 -15
  232. package/dist/utils/jamlMapPreview.js +0 -106
  233. package/dist/utils/jamlVisualFilter.js +0 -210
@@ -1,168 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useLayoutEffect, useRef, useState } from "react";
4
- import { RadialPill } from "./RadialPill";
5
- import { RadialButton } from "./RadialButton";
6
- import { RadialBadge } from "./RadialBadge";
7
- // ── Type guards ───────────────────────────────────────────────────────────────
8
- function hasDim(item) {
9
- return "_dim" in item;
10
- }
11
- function hasSouth(item) {
12
- return "_south" in item && item._south === true;
13
- }
14
- function hasIcon(item) {
15
- return "icon" in item && typeof item.icon === "string";
16
- }
17
- function hasCount(item) {
18
- return "count" in item && typeof item.count === "number";
19
- }
20
- function isToggleItem(item) {
21
- return "active" in item && typeof item.active === "boolean";
22
- }
23
- // ── Orbit geometry constants ──────────────────────────────────────────────────
24
- /** Degrees reserved on each side of south (90°) for the south-pinned button. */
25
- const FULL_CIRCLE_RAD = 2 * Math.PI;
26
- const SOUTH_ANGLE_RAD = Math.PI / 2;
27
- /** ~half height of a radial pill (px) — used with width for clearance vs round mascot. */
28
- const PILL_HALF_H = 15;
29
- /**
30
- * Estimated pill width for clamp math — tuned for m6x11 ~12px + padding + toggle dot.
31
- */
32
- function estimatePillWidth(item) {
33
- const label = item.label || "";
34
- const charW = 7.25;
35
- const basePad = 36;
36
- const hasToggle = "active" in item && typeof item.active === "boolean";
37
- const dot = hasToggle ? 16 : 0;
38
- const w = basePad + dot + label.length * charW;
39
- return Math.min(200, Math.max(56, w));
40
- }
41
- /**
42
- * Minimum distance from orbit center to pill center so the pill clears the round mascot bitmap.
43
- */
44
- function minDistanceFromMascotCenter(mascotHalfPx, pillHalfW) {
45
- const gap = 10;
46
- const cornerReach = Math.hypot(pillHalfW, PILL_HALF_H);
47
- return mascotHalfPx + gap + cornerReach;
48
- }
49
- /**
50
- * Even ellipse; if a slot sits inside the mascot keep-out, scale **outward** along the same ray
51
- * (`k ≥ 1`). We do **not** clamp X toward 0 — that was pulling pills **inward** onto Jammy.
52
- * Edge overflow is handled by orbit radius + narrow column in `SeedMascot` / layout, not here.
53
- */
54
- function layoutOrbitalEllipse(items, Rx, Ry, startAngle, stepRad, mascotSizePx) {
55
- if (items.length === 0)
56
- return [];
57
- const mascotHalf = Math.max(0, mascotSizePx) / 2;
58
- return items.map((item, i) => {
59
- const angle = startAngle + i * stepRad;
60
- const ux = Math.cos(angle) * Rx;
61
- const uy = Math.sin(angle) * Ry;
62
- const d0 = Math.hypot(ux, uy);
63
- const halfW = estimatePillWidth(item) / 2;
64
- const minDist = minDistanceFromMascotCenter(mascotHalf, halfW);
65
- if (d0 < 1e-4) {
66
- return { item, x: minDist, y: 0 };
67
- }
68
- const k = Math.max(1, minDist / d0);
69
- const x = ux * k;
70
- const y = uy * k;
71
- return { item, x, y };
72
- });
73
- }
74
- /**
75
- * Orbital radial menu layout engine.
76
- *
77
- * South (`_south`) stays pinned under the mascot. Everyone else sits on an ellipse
78
- * at equal angle steps, with a single radial push if a pill would overlap the
79
- * center — no iterative “solver” (that was causing mushy, uneven layouts).
80
- */
81
- export function RadialMenu({ items, showClosing, mascotSizePx, orbitRadiusX, orbitRadiusY, mascotTranslateY, currentMenu, onItemClick, onBack, breadcrumb, showPageControls = false, onPagePrev, onPageNext, }) {
82
- const rootRef = useRef(null);
83
- const [containerW, setContainerW] = useState(320);
84
- useLayoutEffect(() => {
85
- const el = rootRef.current;
86
- if (!el)
87
- return;
88
- const apply = () => setContainerW(Math.max(1, el.clientWidth));
89
- apply();
90
- const ro = new ResizeObserver(apply);
91
- ro.observe(el);
92
- return () => ro.disconnect();
93
- }, []);
94
- if (items.length === 0)
95
- return null;
96
- // ── Separate south-pinned item from orbital items ─────────────────────────
97
- const southItem = items.find(hasSouth) ?? null;
98
- const orbitalItems = items.filter((item) => !hasSouth(item));
99
- const totalSlots = orbitalItems.length + (southItem ? 1 : 0);
100
- const slotStepRad = FULL_CIRCLE_RAD / totalSlots;
101
- const orbitalStartAngle = southItem ? SOUTH_ANGLE_RAD + slotStepRad : SOUTH_ANGLE_RAD;
102
- // South button (Start / Back) — always clearly wider than any orbital pill.
103
- // Minimum 160px so it reads as the primary action even with few orbital items.
104
- const MIN_SOUTH_WIDTH = 148;
105
- const southWidth = Math.max(MIN_SOUTH_WIDTH, totalSlots <= 1
106
- ? Math.min(Math.round(2 * orbitRadiusX * 1.05), containerW - 16)
107
- : Math.min(Math.round(2 * orbitRadiusX * Math.sin(slotStepRad / 2) * 1.28), containerW - 16));
108
- // Breadcrumb above south (Back): fixed ctr–ctr gap so it stays attached above the southmost pill.
109
- const southButtonY = orbitRadiusY + 8;
110
- const breadcrumbCenterY = southButtonY - 46;
111
- const pageControlWidth = Math.max(56, Math.floor(southWidth * 0.5));
112
- const pageControlY = southButtonY - 20;
113
- const pageControlLeftX = -(southWidth / 2) + pageControlWidth / 2;
114
- const pageControlRightX = (southWidth / 2) - pageControlWidth / 2;
115
- const makeClickHandler = (item) => (e) => {
116
- e.stopPropagation();
117
- if (item.action === "back-action") {
118
- onBack();
119
- }
120
- else {
121
- onItemClick(item);
122
- }
123
- };
124
- return (_jsx("div", { ref: rootRef, className: "pointer-events-none absolute inset-0 z-30 flex min-w-0 items-center justify-center", style: { transform: `translateY(${mascotTranslateY}px)` }, children: _jsxs("div", { className: "relative h-0 w-0", children: [breadcrumb ? (_jsx("div", { className: "pointer-events-auto absolute", style: {
125
- left: 0,
126
- top: breadcrumbCenterY,
127
- transform: "translate(-50%, -50%)",
128
- zIndex: 20,
129
- }, children: breadcrumb })) : null, (() => {
130
- const solved = layoutOrbitalEllipse(orbitalItems, orbitRadiusX, orbitRadiusY, orbitalStartAngle, slotStepRad, mascotSizePx);
131
- return solved.map(({ item, x, y }, i) => {
132
- const isDim = hasDim(item) && item._dim === true;
133
- const extraClass = isDim ? "opacity-40" : "";
134
- return (_jsx(RadialPill, { x: x, y: y, hiding: showClosing, children: renderItem(item, extraClass, makeClickHandler(item)) }, `${item.label}-${i}-${currentMenu}`));
135
- });
136
- })(), southItem && (_jsx(RadialPill, { x: 0, y: southButtonY, hiding: showClosing, children: renderSouthItem(southItem, southWidth, makeClickHandler(southItem)) })), southItem && showPageControls && (_jsxs(_Fragment, { children: [_jsx(RadialPill, { x: pageControlLeftX, y: pageControlY, hiding: showClosing, children: _jsx(RadialButton, { label: "<", color: "blue", tooltip: "Previous page", onClick: (e) => {
137
- e.stopPropagation();
138
- onPagePrev?.();
139
- }, style: { width: pageControlWidth } }) }), _jsx(RadialPill, { x: pageControlRightX, y: pageControlY, hiding: showClosing, children: _jsx(RadialButton, { label: ">", color: "blue", tooltip: "Next page", onClick: (e) => {
140
- e.stopPropagation();
141
- onPageNext?.();
142
- }, style: { width: pageControlWidth } }) })] }))] }) }));
143
- }
144
- // ── South item renderer ───────────────────────────────────────────────────────
145
- function renderSouthItem(item, width, onClick) {
146
- const variant = item.label === "Start" ? "start" : "back";
147
- return (_jsx(RadialButton, { variant: variant, label: item.label, color: "orange", tooltip: item.tooltip, onClick: onClick, style: { width } }));
148
- }
149
- // ── Regular item renderer ─────────────────────────────────────────────────────
150
- function renderItem(item, className, onClick) {
151
- // Badge (display-only)
152
- if (item.badge) {
153
- return (_jsx(RadialBadge, { label: item.badge.label, state: item.badge.state, color: item.color, tooltip: item.tooltip }));
154
- }
155
- // Toggle
156
- if (isToggleItem(item)) {
157
- return (_jsx(RadialButton, { variant: "toggle", label: item.label, active: item.active, disabled: item.disabled === true, color: item.color, tooltip: item.tooltip, className: className, onClick: onClick }));
158
- }
159
- // Count indicator (with icon or numeric count)
160
- if (hasIcon(item)) {
161
- return (_jsx(RadialButton, { variant: "count", label: item.label, count: 0, icon: item.icon, color: item.color, tooltip: item.tooltip, className: className, onClick: onClick }));
162
- }
163
- if (hasCount(item)) {
164
- return (_jsx(RadialButton, { variant: "count", label: item.label, count: item.count, color: item.color, tooltip: item.tooltip, className: className, onClick: onClick }));
165
- }
166
- // Default action button
167
- return (_jsx(RadialButton, { label: item.label, color: item.color, tooltip: item.tooltip, className: className, onClick: onClick }));
168
- }
@@ -1,15 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- import "./radial-navigation.css";
4
- /**
5
- * Absolutely-positioned wrapper for a radial menu item.
6
- *
7
- * Uses CSS custom properties + a shared `@starting-style` rule
8
- * instead of injecting per-instance `<style>` tags.
9
- */
10
- export function RadialPill({ x, y, hiding, children }) {
11
- return (_jsx("div", { className: "orbital-pill", "data-hiding": hiding ? "true" : "false", style: {
12
- "--orbital-x": `${hiding ? 0 : x}px`,
13
- "--orbital-y": `${hiding ? 0 : y}px`,
14
- }, children: _jsx("span", { className: "orbital-pill-inner", children: children }) }));
15
- }
@@ -1,18 +0,0 @@
1
- // Jimbo UI — Radial Navigation Module
2
- // Orbital/radial menu system for the Jammy mascot.
3
- // Layout
4
- export { RadialMenu } from "./RadialMenu";
5
- // Primitives
6
- export { RadialPill } from "./RadialPill";
7
- export { RadialButton } from "./RadialButton";
8
- export { RadialBadge } from "./RadialBadge";
9
- export { RadialBreadcrumb } from "./RadialBreadcrumb";
10
- // State hook
11
- export { useRadialMenu } from "./useRadialMenu";
12
- // ── Backwards-compatibility aliases ───────────────────────────────────────────
13
- // These match the old export names from the flat RadialNavigation.tsx file.
14
- // Consumers using the old names will keep working without import changes.
15
- export { RadialButton as JimboRadialNavigationButton } from "./RadialButton";
16
- export { RadialBadge as JimboRadialNavigationBadge } from "./RadialBadge";
17
- export { RadialBreadcrumb as BreadcrumNavPill } from "./RadialBreadcrumb";
18
- export { RadialPill as JimboOrbitalPill } from "./RadialPill";
@@ -1,122 +0,0 @@
1
- "use client";
2
- import { create } from "zustand";
3
- import { JIMBO_ANIMATIONS } from "../tokens";
4
- let closingTimer = null;
5
- /** Clears pending close/navigate animation timeout (e.g. unmount). */
6
- export function clearRadialMenuTimers() {
7
- if (closingTimer !== null) {
8
- clearTimeout(closingTimer);
9
- closingTimer = null;
10
- }
11
- }
12
- /** Full reset when `SeedMascot` unmounts — Zustand survives the component; hook `useState` did not. */
13
- export function resetRadialMenuState() {
14
- clearRadialMenuTimers();
15
- useRadialMenuStore.setState({
16
- nav: { stack: [], page: 0 },
17
- breadcrumbStack: [],
18
- isClosing: false,
19
- announcementPrimedForDismiss: false,
20
- });
21
- }
22
- function armTimer(fn, ms) {
23
- clearRadialMenuTimers();
24
- closingTimer = setTimeout(() => {
25
- closingTimer = null;
26
- fn();
27
- }, ms);
28
- }
29
- export const useRadialMenuStore = create((set, get) => ({
30
- nav: { stack: [], page: 0 },
31
- breadcrumbStack: [],
32
- isClosing: false,
33
- announcementPrimedForDismiss: false,
34
- prevMaxScore: -1,
35
- prevResultCount: 0,
36
- resetAnnouncementPrimed: () => {
37
- if (!get().announcementPrimedForDismiss)
38
- return;
39
- set({ announcementPrimedForDismiss: false });
40
- },
41
- setAnnouncementPrimedForDismiss: (v) => {
42
- if (get().announcementPrimedForDismiss === v)
43
- return;
44
- set({ announcementPrimedForDismiss: v });
45
- },
46
- open: (isWelcome) => {
47
- const { nav } = get();
48
- const target = isWelcome ? "welcome" : "main";
49
- // Guard: skip if already at the target root — avoids creating a new array
50
- // reference that would trigger Zustand subscribers and cause infinite re-renders
51
- // in effects that depend on the radial menu state object.
52
- if (nav.stack.length === 1 && nav.stack[0] === target && nav.page === 0)
53
- return;
54
- set({ nav: { stack: [target], page: 0 } });
55
- },
56
- close: () => {
57
- clearRadialMenuTimers();
58
- set({ isClosing: true });
59
- armTimer(() => {
60
- set({ nav: { stack: [], page: 0 }, breadcrumbStack: [], isClosing: false });
61
- }, JIMBO_ANIMATIONS.MENU_ORBIT_DURATION);
62
- },
63
- back: () => {
64
- const stackBefore = get().nav.stack;
65
- set((s) => ({ breadcrumbStack: s.breadcrumbStack.slice(0, -1) }));
66
- if (stackBefore.length <= 1) {
67
- get().close();
68
- return;
69
- }
70
- clearRadialMenuTimers();
71
- set({ isClosing: true });
72
- armTimer(() => {
73
- set((s) => ({
74
- nav: { stack: s.nav.stack.slice(0, -1), page: 0 },
75
- isClosing: false,
76
- }));
77
- }, JIMBO_ANIMATIONS.MENU_SINK_DURATION);
78
- },
79
- navigateTo: (submenuLabel) => {
80
- clearRadialMenuTimers();
81
- set((s) => ({
82
- breadcrumbStack: [...s.breadcrumbStack, submenuLabel],
83
- isClosing: true,
84
- }));
85
- armTimer(() => {
86
- set((s) => ({
87
- nav: { stack: [...s.nav.stack, submenuLabel], page: 0 },
88
- isClosing: false,
89
- }));
90
- }, JIMBO_ANIMATIONS.MENU_SINK_DURATION);
91
- },
92
- nextPage: (totalPages) => set((s) => {
93
- const pages = Math.max(1, totalPages);
94
- const next = pages <= 1 ? 0 : (s.nav.page + 1) % pages;
95
- return { nav: { ...s.nav, page: next } };
96
- }),
97
- prevPage: (totalPages) => set((s) => {
98
- const pages = Math.max(1, totalPages);
99
- const prev = pages <= 1 ? 0 : (s.nav.page - 1 + pages) % pages;
100
- return { nav: { ...s.nav, page: prev } };
101
- }),
102
- updateSeedResults: (seedResults) => {
103
- const state = get();
104
- let shouldClose = false;
105
- if (seedResults.length > 0) {
106
- const currentMax = Math.max(...seedResults.map((r) => r.score));
107
- if (currentMax > state.prevMaxScore) {
108
- shouldClose = state.nav.stack.length > 1;
109
- }
110
- }
111
- if (seedResults.length > 0 && seedResults.length > state.prevResultCount) {
112
- shouldClose = shouldClose || state.nav.stack.length > 0;
113
- }
114
- set({
115
- prevMaxScore: seedResults.length > 0 ? Math.max(...seedResults.map(r => r.score)) : -1,
116
- prevResultCount: seedResults.length
117
- });
118
- if (shouldClose) {
119
- get().close();
120
- }
121
- },
122
- }));
@@ -1,59 +0,0 @@
1
- "use client";
2
- import { useSyncExternalStore } from "react";
3
- /**
4
- * React requires `getSnapshot` to return the **same object reference** when values are unchanged.
5
- * A fresh `{ ... }` every call makes `useSyncExternalStore` think the store changed every render →
6
- * maximum update depth. See: https://react.dev/reference/react/useSyncExternalStore
7
- */
8
- const SERVER_SNAPSHOT = Object.freeze({
9
- baseRadius: 66,
10
- keyboardHeight: 0,
11
- });
12
- const clientCache = {
13
- baseRadius: SERVER_SNAPSHOT.baseRadius,
14
- keyboardHeight: SERVER_SNAPSHOT.keyboardHeight,
15
- };
16
- function getServerSnapshot() {
17
- return SERVER_SNAPSHOT;
18
- }
19
- function readGeometry() {
20
- if (typeof window === "undefined") {
21
- return { baseRadius: 66, keyboardHeight: 0 };
22
- }
23
- const w = window.innerWidth;
24
- const baseRadius = w < 320 ? 58 : 66;
25
- const vv = window.visualViewport;
26
- let keyboardHeight = 0;
27
- if (vv) {
28
- const raw = Math.max(0, window.innerHeight - vv.height);
29
- keyboardHeight = raw > 100 ? raw * 0.6 : 0;
30
- }
31
- return { baseRadius, keyboardHeight };
32
- }
33
- function getSnapshot() {
34
- if (typeof window === "undefined")
35
- return SERVER_SNAPSHOT;
36
- const { baseRadius, keyboardHeight } = readGeometry();
37
- if (clientCache.baseRadius === baseRadius && clientCache.keyboardHeight === keyboardHeight) {
38
- return clientCache;
39
- }
40
- clientCache.baseRadius = baseRadius;
41
- clientCache.keyboardHeight = keyboardHeight;
42
- return clientCache;
43
- }
44
- function subscribe(onStoreChange) {
45
- if (typeof window === "undefined")
46
- return () => { };
47
- const run = () => onStoreChange();
48
- const vv = window.visualViewport;
49
- window.addEventListener("resize", run);
50
- vv?.addEventListener("resize", run);
51
- return () => {
52
- window.removeEventListener("resize", run);
53
- vv?.removeEventListener("resize", run);
54
- };
55
- }
56
- /** Keyboard dodge + narrow-orbit radius — `useSyncExternalStore` (stable snapshot identity). */
57
- export function useRadialViewportGeometry() {
58
- return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
59
- }
@@ -1,107 +0,0 @@
1
- "use client";
2
- import { useCallback, useEffect, useMemo } from "react";
3
- import { useRadialMenuStore } from "./radialMenuStore";
4
- import { useRadialViewportGeometry } from "./radialMenuViewport";
5
- /**
6
- * Radial menu: **Zustand** (`useRadialMenuStore`) for stack / pagination / animations;
7
- * **useSyncExternalStore** (`useRadialViewportGeometry`) for keyboard + narrow-width radius.
8
- */
9
- export function useRadialMenu({ isWelcome, announcementActive, isTalking, seedResults, onDismissAnnouncement, }) {
10
- const menuStack = useRadialMenuStore((s) => s.nav.stack);
11
- const menuPage = useRadialMenuStore((s) => s.nav.page);
12
- const breadcrumbStack = useRadialMenuStore((s) => s.breadcrumbStack);
13
- const isClosing = useRadialMenuStore((s) => s.isClosing);
14
- const storeOpen = useRadialMenuStore((s) => s.open);
15
- const storeClose = useRadialMenuStore((s) => s.close);
16
- const storeBack = useRadialMenuStore((s) => s.back);
17
- const storeNavigateTo = useRadialMenuStore((s) => s.navigateTo);
18
- const storeNextPage = useRadialMenuStore((s) => s.nextPage);
19
- const storePrevPage = useRadialMenuStore((s) => s.prevPage);
20
- const { baseRadius, keyboardHeight } = useRadialViewportGeometry();
21
- useEffect(() => {
22
- if (!announcementActive) {
23
- useRadialMenuStore.getState().resetAnnouncementPrimed();
24
- }
25
- }, [announcementActive]);
26
- const currentMenu = useMemo(() => (isWelcome ? "welcome" : menuStack.at(-1) ?? "main"), [isWelcome, menuStack]);
27
- const showMenu = useMemo(() => !announcementActive && (menuStack.length > 0 || seedResults.length > 0) && !isClosing, [announcementActive, menuStack.length, seedResults.length, isClosing]);
28
- const showClosing = useMemo(() => isClosing && menuStack.length > 0, [isClosing, menuStack.length]);
29
- const showBack = useMemo(() => menuStack.length >= 1, [menuStack.length]);
30
- const mascotTranslateY = useMemo(() => -keyboardHeight + 2, [keyboardHeight]);
31
- const open = useCallback(() => {
32
- storeOpen(isWelcome);
33
- }, [isWelcome, storeOpen]);
34
- const close = useCallback(() => {
35
- storeClose();
36
- }, [storeClose]);
37
- const back = useCallback(() => {
38
- storeBack();
39
- }, [storeBack]);
40
- const navigateTo = useCallback((submenuLabel) => {
41
- storeNavigateTo(submenuLabel);
42
- }, [storeNavigateTo]);
43
- const nextPage = useCallback((totalPages) => {
44
- storeNextPage(totalPages);
45
- }, [storeNextPage]);
46
- const prevPage = useCallback((totalPages) => {
47
- storePrevPage(totalPages);
48
- }, [storePrevPage]);
49
- const handleTap = useCallback(() => {
50
- const api = useRadialMenuStore.getState();
51
- if (announcementActive) {
52
- if (isTalking) {
53
- return;
54
- }
55
- onDismissAnnouncement();
56
- api.resetAnnouncementPrimed();
57
- api.open(isWelcome);
58
- return;
59
- }
60
- const menuIsOpen = api.nav.stack.length > 0;
61
- if (!menuIsOpen && !api.isClosing) {
62
- api.open(isWelcome);
63
- }
64
- else {
65
- api.close();
66
- }
67
- }, [announcementActive, isTalking, isWelcome, onDismissAnnouncement]);
68
- return useMemo(() => ({
69
- menuStack,
70
- breadcrumbStack,
71
- currentMenu,
72
- isClosing,
73
- showMenu,
74
- showClosing,
75
- showBack,
76
- menuPage,
77
- baseRadius,
78
- keyboardHeight,
79
- mascotTranslateY,
80
- open,
81
- close,
82
- back,
83
- navigateTo,
84
- nextPage,
85
- prevPage,
86
- handleTap,
87
- }), [
88
- menuStack,
89
- breadcrumbStack,
90
- currentMenu,
91
- isClosing,
92
- showMenu,
93
- showClosing,
94
- showBack,
95
- menuPage,
96
- baseRadius,
97
- keyboardHeight,
98
- mascotTranslateY,
99
- open,
100
- close,
101
- back,
102
- navigateTo,
103
- nextPage,
104
- prevPage,
105
- handleTap,
106
- ]);
107
- }
@@ -1,20 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { JimboButton } from './panel.js';
4
- import { JimboSprite } from './sprites.js';
5
- import { JimboText } from './jimboText.js';
6
- import { JimboApp, JimboAppFooter } from './jimboApp.js';
7
- import { JimboBalatroFooter } from './footer.js';
8
- import { JimboSectionHeader } from './jimboSectionHeader.js';
9
- import { JimboInfoCard, JimboInfoCardBody, JimboInfoCardTitle, JimboInfoCardSub, JimboInfoCardAside } from './jimboInfoCard.js';
10
- /**
11
- * Landing/showcase screen — 320×568, NO SCROLL.
12
- * Every pixel accounted for. No flex stretching. No gaps.
13
- */
14
- export function Showcase({ title = 'Balatro', subtitle = 'Seed Curator', hotFilters = [], recentFinds = [], mcpInfo, onNewSearch, onBrowseFilters, onFilterClick, }) {
15
- return (_jsxs(JimboApp, { children: [_jsxs("div", { style: { padding: '12px 12px 8px', display: 'flex', flexDirection: 'column', gap: 6 }, children: [_jsxs("div", { className: "j-text-center", children: [_jsx(JimboText, { size: "lg", tone: "gold", children: title }), _jsx(JimboText, { size: "micro", tone: "grey", style: { letterSpacing: 3 }, children: subtitle })] }), mcpInfo && (_jsxs("div", { className: "j-flex j-justify-between", style: {
16
- padding: '3px 8px',
17
- background: 'var(--j-dark-grey)', borderRadius: 4,
18
- border: '1px solid var(--j-panel-edge)',
19
- }, children: [_jsx(JimboText, { size: "micro", tone: "purple", children: mcpInfo.engine }), _jsx(JimboText, { size: "micro", tone: "grey", children: mcpInfo.features })] })), hotFilters.length > 0 && (_jsxs(_Fragment, { children: [_jsx(JimboSectionHeader, { label: "Filters", tone: "blue" }), _jsx("div", { className: "j-flex-col", style: { gap: 4 }, children: hotFilters.slice(0, 4).map((f, i) => (_jsxs(JimboInfoCard, { tone: f.tone, onClick: () => onFilterClick?.(f, i), style: { cursor: onFilterClick ? 'pointer' : undefined }, children: [_jsx("div", { className: "j-flex j-gap-xs", children: f.sample.slice(0, 2).map((name, j) => (_jsx("div", { style: { width: 22, height: 28, display: 'flex', alignItems: 'center', justifyContent: 'center' }, children: _jsx(JimboSprite, { name: name, width: 20 }) }, j))) }), _jsxs(JimboInfoCardBody, { children: [_jsx(JimboInfoCardTitle, { children: f.name }), _jsxs(JimboInfoCardSub, { children: ["by ", f.author] })] }), _jsx(JimboInfoCardAside, { children: _jsx(JimboText, { size: "xs", tone: f.tone === 'gold' ? 'gold' : f.tone, children: f.hits }) })] }, i))) })] })), recentFinds.length > 0 && (_jsxs(_Fragment, { children: [_jsx(JimboSectionHeader, { label: "Recent", tone: "green" }), _jsx("div", { style: { lineHeight: 1.5 }, children: recentFinds.slice(0, 3).map((r, i) => (_jsxs("div", { className: "j-flex j-gap-sm", children: [_jsx(JimboText, { size: "micro", tone: "gold", children: r.seed }), _jsx(JimboText, { size: "micro", tone: "grey", children: r.filterName }), r.score > 0 && _jsxs(JimboText, { size: "micro", tone: "green", children: ["+", r.score] })] }, i))) })] }))] }), _jsxs(JimboAppFooter, { children: [_jsx(JimboButton, { tone: "green", fullWidth: true, size: "lg", onClick: onNewSearch, children: "New Search" }), _jsx(JimboButton, { tone: "blue", fullWidth: true, size: "lg", onClick: onBrowseFilters, children: "Browse Filters" })] }), _jsx(JimboBalatroFooter, {})] }));
20
- }
@@ -1,77 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- import { resolveJamlAssetUrl } from '../assets.js';
4
- import { getSpriteData, getMysterySprite, SHEET_META } from '../sprites/spriteMapper.js';
5
- export function JimboSprite({ name, sheet, width = 40, height, style }) {
6
- const sprite = getSpriteData(name);
7
- const resolvedSheet = sheet ?? sprite?.type ?? 'Jokers';
8
- const meta = SHEET_META[resolvedSheet];
9
- const mystery = getMysterySprite(resolvedSheet);
10
- const pos = sprite?.pos ?? mystery.pos;
11
- let defaultH = width;
12
- if (["Jokers", "Tarots", "Vouchers", "Boosters", "Decks", "Enhancers", "Editions"].includes(resolvedSheet)) {
13
- defaultH = Math.round((width * 95) / 71);
14
- }
15
- const h = height ?? defaultH;
16
- if (!meta)
17
- return null;
18
- const bgW = width * meta.cols;
19
- const bgH = h * meta.rows;
20
- const bgX = -(pos.x * width);
21
- const bgY = -(pos.y * h);
22
- return (_jsx("div", { style: {
23
- width, height: h, flexShrink: 0,
24
- backgroundImage: `url(${resolveJamlAssetUrl(meta.assetKey)})`,
25
- backgroundSize: `${bgW}px ${bgH}px`,
26
- backgroundPosition: `${bgX}px ${bgY}px`,
27
- backgroundRepeat: 'no-repeat',
28
- imageRendering: 'pixelated',
29
- ...style,
30
- } }));
31
- }
32
- const STAKE_MAP = ["White", "Red", "Green", "Black", "Blue", "Purple", "Orange", "Gold"];
33
- export function StakeSprite({ stake, width = 29, height, style }) {
34
- const index = STAKE_MAP.indexOf(stake.replace(" Stake", ""));
35
- const idx = index >= 0 ? index : 0;
36
- const x = idx % 5;
37
- const y = Math.floor(idx / 5);
38
- const h = height ?? width;
39
- const bgW = width * 5;
40
- const bgH = h * 2;
41
- return (_jsx("div", { style: {
42
- width, height: h, flexShrink: 0,
43
- backgroundImage: `url(${resolveJamlAssetUrl('stakes')})`,
44
- backgroundSize: `${bgW}px ${bgH}px`,
45
- backgroundPosition: `-${x * width}px -${y * h}px`,
46
- backgroundRepeat: 'no-repeat',
47
- imageRendering: 'pixelated',
48
- ...style,
49
- } }));
50
- }
51
- const DECK_ROWS = {
52
- Red: 0,
53
- Blue: 1,
54
- Yellow: 2,
55
- Green: 3,
56
- Black: 0,
57
- Magic: 1,
58
- Nebula: 2,
59
- Ghost: 3,
60
- };
61
- export function DeckSprite({ deck, width = 71, height, style }) {
62
- const baseDeck = deck.replace(" Deck", "");
63
- const y = DECK_ROWS[baseDeck] ?? 0;
64
- const x = 12;
65
- const h = height ?? (width * 95 / 71);
66
- const bgW = width * 13;
67
- const bgH = h * 4;
68
- return (_jsx("div", { style: {
69
- width, height: h, flexShrink: 0,
70
- backgroundImage: `url(${resolveJamlAssetUrl('deck')})`,
71
- backgroundSize: `${bgW}px ${bgH}px`,
72
- backgroundPosition: `-${x * width}px -${y * h}px`,
73
- backgroundRepeat: 'no-repeat',
74
- imageRendering: 'pixelated',
75
- ...style,
76
- } }));
77
- }
package/dist/ui/tokens.js DELETED
@@ -1,64 +0,0 @@
1
- /**
2
- * Balatro design tokens — colors eyedropped from actual game pixels.
3
- * Do NOT replace with Lua HEX values; the game's shader pipeline transforms them.
4
- *
5
- * IMPORTANT: For DOM components, use CSS custom properties (--j-red, etc.)
6
- * from jimbo.css. Only use these JS constants for contexts that cannot use
7
- * CSS — such as R3F/Canvas, inline SVG fills, or imperative animation APIs.
8
- */
9
- export const JimboColorOption = {
10
- RED: '#ff4c40',
11
- BLUE: '#0093ff',
12
- GREEN: '#429f79',
13
- ORANGE: '#ff9800',
14
- GOLD: '#e4b643',
15
- PURPLE: '#9e74ce',
16
- DARK_RED: '#a02721',
17
- DARK_BLUE: '#0057a1',
18
- DARK_ORANGE: '#a05b00',
19
- DARK_GREEN: '#215f46',
20
- DARK_PURPLE: '#5e437e',
21
- DARK_GREY: '#3a5055',
22
- DARKEST: '#1e2b2d',
23
- GREY: '#708386',
24
- TEAL_GREY: '#404c4e',
25
- PANEL_EDGE: '#1e2e32',
26
- INNER_BORDER: '#334461',
27
- BORDER_SILVER: '#b9c2d2',
28
- BORDER_SOUTH: '#777e89',
29
- GOLD_TEXT: '#e4b643',
30
- GREEN_TEXT: '#35bd86',
31
- ORANGE_TEXT: '#ff8f00',
32
- WHITE: '#ffffff',
33
- BLACK: '#000000',
34
- TAROT_BUTTON: '#9e74ce',
35
- PLANET_BUTTON: '#00a7ca',
36
- SPECTRAL_BUTTON: '#2e76fd',
37
- TAROT_BUTTON_DARK: '#5e437e',
38
- PLANET_BUTTON_DARK: '#00657c',
39
- SPECTRAL_BUTTON_DARK: '#14449e',
40
- };
41
- /** Convert hex to rgba for inline styles in Canvas/SVG/R3F contexts. */
42
- export function withAlpha(hex, alpha) {
43
- const clean = hex.replace('#', '');
44
- const r = parseInt(clean.slice(0, 2), 16);
45
- const g = parseInt(clean.slice(2, 4), 16);
46
- const b = parseInt(clean.slice(4, 6), 16);
47
- return `rgba(${r}, ${g}, ${b}, ${alpha})`;
48
- }
49
- export const JIMBO_ANIMATIONS = {
50
- JUICE_UP_SCALE: 1.05,
51
- JUICE_DOWN_SCALE: 1.0,
52
- JUICE_DURATION: 150,
53
- JUICE_EASING: 'cubic-bezier(0.34, 1.56, 0.64, 1)',
54
- SWAY_AMOUNT: 1.5,
55
- SWAY_DURATION: 4000,
56
- PRESS_TRANSLATE_Y: 2,
57
- PRESS_DURATION: 50,
58
- CARD_TILT_MAX: 6,
59
- MENU_SINK_DURATION: 200,
60
- MENU_RISE_DURATION: 300,
61
- MENU_ORBIT_DURATION: 320,
62
- LETTER_POP_RATE: 3,
63
- LETTER_BUMP_RATE: 2.666,
64
- };
@@ -1,15 +0,0 @@
1
- import { RANK_MAP, SUIT_MAP, SEAL_MAP, ENHANCER_MAP } from "../sprites/spriteData.js";
2
- export function getStandardCardPosition(rank, suit) {
3
- return { x: RANK_MAP[rank] ?? 0, y: SUIT_MAP[suit] ?? 0 };
4
- }
5
- export function getSealPosition(seal) {
6
- return SEAL_MAP[seal];
7
- }
8
- export function getEnhancerPosition(modifiers) {
9
- for (const m of modifiers) {
10
- const pos = ENHANCER_MAP[m];
11
- if (pos)
12
- return pos;
13
- }
14
- return { x: 1, y: 0 };
15
- }