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
package/dist/ui/hooks.js DELETED
@@ -1,634 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react';
2
- import { JIMBO_ANIMATIONS } from './tokens.js';
3
- import { SPRITE_SHEETS } from '../sprites/spriteData.js';
4
- function loadImage(url) {
5
- return new Promise((resolve) => {
6
- const image = new window.Image();
7
- image.addEventListener('load', () => resolve(image));
8
- image.addEventListener('error', () => resolve(null));
9
- image.src = url;
10
- });
11
- }
12
- function renderImage(canvas, context, image, layer, timestamp) {
13
- if (!image || !layer || !layer?.pos)
14
- return 0;
15
- const cardWidth = image.width / layer.columns;
16
- const cardHeight = image.height / layer.rows;
17
- const canvasStyle = canvas.style;
18
- if (layer.order === 0) {
19
- canvas.width = cardWidth;
20
- canvas.height = cardHeight;
21
- canvasStyle.width = `${cardWidth}px`;
22
- canvasStyle.height = `${cardHeight}px`;
23
- }
24
- canvasStyle.imageRendering = 'pixelated';
25
- context.imageSmoothingEnabled = true;
26
- context.save();
27
- if (layer.animated && timestamp) {
28
- const elapsed = timestamp;
29
- const yOffset = Math.sin(elapsed / 1000) * 3;
30
- const xOffset = Math.sin(elapsed / 1500) * 1.5;
31
- context.globalAlpha = 0.65 + (Math.sin(elapsed / 2000) + 1) * 0.075;
32
- context.translate(xOffset, yOffset);
33
- }
34
- context.drawImage(image, layer.pos.x * cardWidth, layer.pos.y * cardHeight, cardWidth, cardHeight, 0, 0, canvas.width, canvas.height);
35
- context.restore();
36
- return cardWidth / cardHeight;
37
- }
38
- /**
39
- * Sway animation for Balatro-style UI elements.
40
- */
41
- export function useSway(active) {
42
- const ref = useRef(null);
43
- useEffect(() => {
44
- if (!active || !ref.current)
45
- return;
46
- let frame;
47
- const start = Date.now();
48
- const el = ref.current;
49
- const tick = () => {
50
- const t = ((Date.now() - start) % JIMBO_ANIMATIONS.SWAY_DURATION) / JIMBO_ANIMATIONS.SWAY_DURATION * Math.PI * 2;
51
- el.style.transform = `translate(${Math.sin(t) * JIMBO_ANIMATIONS.SWAY_AMOUNT * 0.3}px, ${Math.sin(t * 0.8) * JIMBO_ANIMATIONS.SWAY_AMOUNT}px)`;
52
- frame = requestAnimationFrame(tick);
53
- };
54
- frame = requestAnimationFrame(tick);
55
- return () => {
56
- cancelAnimationFrame(frame);
57
- if (el)
58
- el.style.transform = '';
59
- };
60
- }, [active]);
61
- return ref;
62
- }
63
- /**
64
- * Handles delayed visibility for transitions (e.g. modals).
65
- */
66
- export function useDelayedVisibility(open, delay) {
67
- const [visible, setVisible] = useState(open);
68
- const [opacity, setOpacity] = useState(open ? 1 : 0);
69
- const [prevOpen, setPrevOpen] = useState(open);
70
- if (open !== prevOpen) {
71
- setPrevOpen(open);
72
- if (open) {
73
- setVisible(true);
74
- }
75
- else {
76
- setOpacity(0);
77
- }
78
- }
79
- useEffect(() => {
80
- if (open) {
81
- const frame = requestAnimationFrame(() => setOpacity(1));
82
- return () => cancelAnimationFrame(frame);
83
- }
84
- else {
85
- const t = setTimeout(() => setVisible(false), delay);
86
- return () => clearTimeout(t);
87
- }
88
- }, [open, delay]);
89
- return { visible, opacity };
90
- }
91
- /**
92
- * Hook for the Balatro hypnotic swirl background.
93
- * Manages WebGL context, shader compilation, and animation loop.
94
- */
95
- export function useBalatroBackground() {
96
- const canvasRef = useRef(null);
97
- useEffect(() => {
98
- const canvas = canvasRef.current;
99
- if (!canvas)
100
- return;
101
- const gl = canvas.getContext('webgl');
102
- if (!gl)
103
- return;
104
- const vsSource = `
105
- attribute vec2 position;
106
- void main() {
107
- gl_Position = vec4(position, 0.0, 1.0);
108
- }
109
- `;
110
- const fsSource = `
111
- precision mediump float;
112
-
113
- uniform float u_time;
114
- uniform vec2 u_resolution;
115
-
116
- const float SPIN_ROTATION = -2.0;
117
- const float SPIN_SPEED = 4.5;
118
- const vec4 COLOUR_1 = vec4(1.0, 0.2, 0.2, 1.0);
119
- const vec4 COLOUR_2 = vec4(0.0, 0.5, 1.0, 1.0);
120
- const vec4 COLOUR_3 = vec4(0.05, 0.08, 0.1, 1.0);
121
- const float CONTRAST = 4.5;
122
- const float LIGTHING = 0.5;
123
- const float SPIN_AMOUNT = 0.35;
124
- const float PIXEL_FILTER = 1024.0;
125
- const float PI = 3.14159265359;
126
-
127
- void main() {
128
- vec2 screenSize = u_resolution;
129
- float pixel_size = length(screenSize.xy) / PIXEL_FILTER;
130
- vec2 uv = (floor(gl_FragCoord.xy*(1.0/pixel_size))*pixel_size - 0.5*screenSize.xy)/length(screenSize.xy);
131
- float uv_len = length(uv);
132
-
133
- float speed = (SPIN_ROTATION * 0.2) + 302.2;
134
- float new_pixel_angle = atan(uv.y, uv.x) + speed - 20.0*(1.0*SPIN_AMOUNT*uv_len + (1.0 - 1.0*SPIN_AMOUNT));
135
-
136
- vec2 mid = (screenSize.xy/length(screenSize.xy))/2.0;
137
- uv = (vec2((uv_len * cos(new_pixel_angle) + mid.x), (uv_len * sin(new_pixel_angle) + mid.y)) - mid);
138
-
139
- uv *= 30.0;
140
- speed = u_time * SPIN_SPEED;
141
- vec2 uv2 = vec2(uv.x, uv.y);
142
-
143
- for(int i=0; i < 5; i++) {
144
- uv2 += sin(max(uv.x, uv.y)) + uv;
145
- uv += 0.5*vec2(cos(5.1123314 + 0.353*uv2.y + speed*0.131121), sin(uv2.x - 0.113*speed));
146
- uv -= 1.0*cos(uv.x + uv.y) - 1.0*sin(uv.x*0.711 - uv.y);
147
- }
148
-
149
- float contrast_mod = (0.25*CONTRAST + 0.5*SPIN_AMOUNT + 1.2);
150
- float paint_res = min(2.0, max(0.0, length(uv)*(0.035)*contrast_mod));
151
- float c1p = max(0.0, 1.0 - contrast_mod*abs(1.0 - paint_res));
152
- float c2p = max(0.0, 1.0 - contrast_mod*abs(paint_res));
153
- float c3p = 1.0 - min(1.0, c1p + c2p);
154
- float light = (LIGTHING - 0.2)*max(c1p*5.0 - 4.0, 0.0) + LIGTHING*max(c2p*5.0 - 4.0, 0.0);
155
-
156
- vec4 finalCol = (0.3/CONTRAST)*COLOUR_1 + (1.0 - 0.3/CONTRAST)*(COLOUR_1*c1p + COLOUR_2*c2p + vec4(c3p*COLOUR_3.rgb, c3p*COLOUR_1.a)) + light;
157
-
158
- gl_FragColor = finalCol;
159
- }
160
- `;
161
- const createShader = (type, source) => {
162
- const shader = gl.createShader(type);
163
- if (!shader)
164
- return null;
165
- gl.shaderSource(shader, source);
166
- gl.compileShader(shader);
167
- if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
168
- console.error('[JimboBackground] shader compile error:', gl.getShaderInfoLog(shader));
169
- gl.deleteShader(shader);
170
- return null;
171
- }
172
- return shader;
173
- };
174
- const vertexShader = createShader(gl.VERTEX_SHADER, vsSource);
175
- const fragmentShader = createShader(gl.FRAGMENT_SHADER, fsSource);
176
- if (!vertexShader || !fragmentShader)
177
- return;
178
- const program = gl.createProgram();
179
- if (!program)
180
- return;
181
- gl.attachShader(program, vertexShader);
182
- gl.attachShader(program, fragmentShader);
183
- gl.linkProgram(program);
184
- if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
185
- console.error('[JimboBackground] program link error:', gl.getProgramInfoLog(program));
186
- return;
187
- }
188
- gl.useProgram(program);
189
- const positionBuffer = gl.createBuffer();
190
- gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
191
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
192
- -1.0, -1.0, 1.0, -1.0, -1.0, 1.0,
193
- -1.0, 1.0, 1.0, -1.0, 1.0, 1.0,
194
- ]), gl.STATIC_DRAW);
195
- const positionLocation = gl.getAttribLocation(program, 'position');
196
- gl.enableVertexAttribArray(positionLocation);
197
- gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
198
- const timeLocation = gl.getUniformLocation(program, 'u_time');
199
- const resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
200
- const startTime = Date.now();
201
- let animationFrameId;
202
- const render = () => {
203
- const displayWidth = canvas.clientWidth;
204
- const displayHeight = canvas.clientHeight;
205
- if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
206
- canvas.width = displayWidth;
207
- canvas.height = displayHeight;
208
- gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
209
- }
210
- const currentTime = (Date.now() - startTime) / 1000.0;
211
- gl.uniform1f(timeLocation, currentTime);
212
- gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
213
- gl.drawArrays(gl.TRIANGLES, 0, 6);
214
- animationFrameId = requestAnimationFrame(render);
215
- };
216
- render();
217
- return () => {
218
- cancelAnimationFrame(animationFrameId);
219
- gl.deleteProgram(program);
220
- gl.deleteShader(vertexShader);
221
- gl.deleteShader(fragmentShader);
222
- gl.deleteBuffer(positionBuffer);
223
- };
224
- }, []);
225
- return canvasRef;
226
- }
227
- /**
228
- * Hook for managing JimboTooltip state and positioning.
229
- */
230
- export function useJimboTooltip({ mode = 'snap', placement = 'auto', delay = 80, disabled = false, }) {
231
- const [visible, setVisible] = useState(false);
232
- const [pos, setPos] = useState(null);
233
- const targetRef = useRef(null);
234
- const tooltipRef = useRef(null);
235
- const delayTimerRef = useRef(null);
236
- const show = useCallback(() => {
237
- if (disabled)
238
- return;
239
- if (delayTimerRef.current)
240
- clearTimeout(delayTimerRef.current);
241
- delayTimerRef.current = setTimeout(() => setVisible(true), delay);
242
- }, [disabled, delay]);
243
- const hide = useCallback(() => {
244
- if (delayTimerRef.current)
245
- clearTimeout(delayTimerRef.current);
246
- setVisible(false);
247
- setPos(null);
248
- }, []);
249
- const computeSnapPos = useCallback(() => {
250
- const el = targetRef.current;
251
- const tip = tooltipRef.current;
252
- if (!el || !tip)
253
- return;
254
- const rect = el.getBoundingClientRect();
255
- const tipRect = tip.getBoundingClientRect();
256
- const roomAbove = rect.top;
257
- const align = placement === 'top' ? 'top'
258
- : placement === 'bottom' ? 'bottom'
259
- : roomAbove >= tipRect.height + 12 ? 'top' : 'bottom';
260
- const left = rect.left + rect.width / 2 - tipRect.width / 2;
261
- const top = align === 'top' ? rect.top - tipRect.height - 8 : rect.bottom + 8;
262
- setPos({
263
- left: Math.max(8, Math.min(window.innerWidth - tipRect.width - 8, left)),
264
- top,
265
- align
266
- });
267
- }, [placement]);
268
- useEffect(() => {
269
- if (!visible || mode !== 'snap')
270
- return;
271
- const raf = requestAnimationFrame(computeSnapPos);
272
- window.addEventListener('resize', computeSnapPos);
273
- window.addEventListener('scroll', computeSnapPos, true);
274
- return () => {
275
- cancelAnimationFrame(raf);
276
- window.removeEventListener('resize', computeSnapPos);
277
- window.removeEventListener('scroll', computeSnapPos, true);
278
- };
279
- }, [visible, mode, computeSnapPos]);
280
- useEffect(() => () => {
281
- if (delayTimerRef.current)
282
- clearTimeout(delayTimerRef.current);
283
- }, []);
284
- const handleMouseMove = useCallback((e) => {
285
- if (mode !== 'mouse')
286
- return;
287
- setPos({ left: e.clientX + 12, top: e.clientY + 16, align: 'bottom' });
288
- }, [mode]);
289
- return {
290
- visible,
291
- pos,
292
- targetRef,
293
- tooltipRef,
294
- show,
295
- hide,
296
- handleMouseMove,
297
- };
298
- }
299
- /**
300
- * Hook for managing the JamlCardRenderer logic.
301
- */
302
- export function useJamlCardRenderer({ layers, invert = false, hoverTilt = false, }) {
303
- const canvasRef = useRef(null);
304
- const imageCacheRef = useRef(new Map());
305
- const [ratio, setRatio] = useState(3 / 4);
306
- const [, forceUpdate] = useState(0);
307
- const animationFrameRef = useRef(null);
308
- const [elapsed, setElapsed] = useState(0);
309
- const [isHovered, setIsHovered] = useState(false);
310
- const [transform, setTransform] = useState('none');
311
- const hasAnimatedLayer = layers?.some((layer) => layer.animated);
312
- // Preload all known sheets once
313
- useEffect(() => {
314
- let cancelled = false;
315
- const imageCache = imageCacheRef.current;
316
- const preload = async () => {
317
- const urls = Array.from(new Set(Object.values(SPRITE_SHEETS).map((sheet) => sheet.src)));
318
- const images = await Promise.all(urls.map((url) => loadImage(url)));
319
- if (cancelled)
320
- return;
321
- images.forEach((image, index) => {
322
- if (image)
323
- imageCache.set(urls[index], image);
324
- });
325
- forceUpdate((prev) => prev + 1);
326
- };
327
- preload().catch((err) => console.error('[JamlCardRenderer]', err));
328
- return () => {
329
- cancelled = true;
330
- imageCache.clear();
331
- };
332
- }, []);
333
- // Animation loop for animated layers
334
- useEffect(() => {
335
- if (!hasAnimatedLayer)
336
- return;
337
- let startTime;
338
- const animate = (timestamp) => {
339
- if (!startTime)
340
- startTime = timestamp;
341
- const now = timestamp - startTime;
342
- if (!animationFrameRef.current || timestamp - 100 > animationFrameRef.current) {
343
- animationFrameRef.current = timestamp;
344
- setElapsed(now);
345
- }
346
- animationFrameRef.current = requestAnimationFrame(animate);
347
- };
348
- animationFrameRef.current = requestAnimationFrame(animate);
349
- return () => {
350
- if (animationFrameRef.current)
351
- cancelAnimationFrame(animationFrameRef.current);
352
- };
353
- }, [hasAnimatedLayer]);
354
- // Core drawing logic
355
- useEffect(() => {
356
- const canvas = canvasRef.current;
357
- if (!canvas || !layers || layers.length === 0)
358
- return;
359
- const context = canvas.getContext('2d');
360
- if (!context)
361
- return;
362
- let cancelled = false;
363
- context.clearRect(0, 0, canvas.width, canvas.height);
364
- [...layers]
365
- .sort((a, b) => a.order - b.order)
366
- .forEach((layer) => {
367
- if (imageCacheRef.current.has(layer.source)) {
368
- const image = imageCacheRef.current.get(layer.source);
369
- if (!image)
370
- return;
371
- const imageRatio = renderImage(canvas, context, image, layer, hasAnimatedLayer ? elapsed : undefined);
372
- if (layer.order === 0)
373
- setRatio(imageRatio);
374
- return;
375
- }
376
- loadImage(layer.source).then((img) => {
377
- if (cancelled || !img)
378
- return;
379
- const imageRatio = renderImage(canvas, context, img, layer, hasAnimatedLayer ? elapsed : undefined);
380
- imageCacheRef.current.set(layer.source, img);
381
- if (layer.order === 0)
382
- setRatio(imageRatio);
383
- forceUpdate((prev) => prev + 1);
384
- });
385
- });
386
- canvas.style.filter = invert ? 'invert(0.94)' : 'none';
387
- return () => { cancelled = true; };
388
- }, [layers, elapsed, invert, hasAnimatedLayer]);
389
- const onPointerEnter = (event) => {
390
- if (!hoverTilt || event.pointerType === 'touch')
391
- return;
392
- setIsHovered(true);
393
- };
394
- const onPointerLeave = () => {
395
- if (!hoverTilt)
396
- return;
397
- setIsHovered(false);
398
- setTransform('none');
399
- };
400
- const onPointerMove = (event) => {
401
- if (!hoverTilt || event.pointerType === 'touch')
402
- return;
403
- const rect = event.currentTarget.getBoundingClientRect();
404
- const x = event.clientX - rect.left;
405
- const y = event.clientY - rect.top;
406
- const rotateY = (x / rect.width) * 12 - 6;
407
- const rotateX = (y / rect.height) * -16 + 8;
408
- const juiceScale = 1.05;
409
- const juiceY = -2; // slight move up
410
- setTransform(`perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale(${juiceScale}) translateY(${juiceY}px)`);
411
- };
412
- const containerStyle = {
413
- aspectRatio: String(ratio),
414
- width: '100%',
415
- display: 'flex',
416
- perspective: hoverTilt ? '1000px' : undefined,
417
- userSelect: 'none',
418
- WebkitUserSelect: 'none',
419
- };
420
- const canvasStyle = {
421
- transition: hoverTilt && !isHovered ? 'transform 0.4s ease, box-shadow 0.4s ease-out' : 'transform 0.1s ease-out',
422
- transform: hoverTilt ? (isHovered ? transform : 'none') : undefined,
423
- transformStyle: hoverTilt ? 'preserve-3d' : undefined,
424
- transformOrigin: hoverTilt ? 'center center' : undefined,
425
- borderRadius: '6px',
426
- boxShadow: hoverTilt && isHovered ? '0 2px 12px rgba(0,0,0,0.3)' : '0 2px 8px rgba(0,0,0,0.2)',
427
- imageRendering: 'pixelated',
428
- pointerEvents: 'none',
429
- };
430
- return {
431
- canvasRef,
432
- containerStyle,
433
- canvasStyle,
434
- handlers: {
435
- onPointerEnter: hoverTilt ? onPointerEnter : undefined,
436
- onPointerLeave: hoverTilt ? onPointerLeave : undefined,
437
- onPointerMove: hoverTilt ? onPointerMove : undefined,
438
- }
439
- };
440
- }
441
- /**
442
- * Tracks which 'ante' section is currently most visible in a scrollable container.
443
- * Used in JamlAnalyzerFullscreen and AnalyzerExplorer.
444
- */
445
- export function useAnteTracker(antes, options = {}) {
446
- const [currentAnte, setCurrentAnte] = useState(antes[0]?.ante ?? 0);
447
- const [prevFirstAnte, setPrevFirstAnte] = useState(antes[0]?.ante);
448
- const scrollRef = useRef(null);
449
- const anteRefs = useRef(new Map());
450
- if (antes[0]?.ante !== prevFirstAnte) {
451
- setPrevFirstAnte(antes[0]?.ante);
452
- if (antes.length > 0) {
453
- setCurrentAnte(antes[0].ante);
454
- }
455
- }
456
- useEffect(() => {
457
- const root = scrollRef.current;
458
- if (!root || antes.length === 0)
459
- return;
460
- const observer = new IntersectionObserver((entries) => {
461
- // Find the entry with the highest intersection ratio
462
- const mostVisible = entries
463
- .filter((e) => e.isIntersecting)
464
- .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
465
- if (mostVisible) {
466
- const ante = Number(mostVisible.target.dataset.ante);
467
- if (!Number.isNaN(ante)) {
468
- setCurrentAnte(ante);
469
- }
470
- }
471
- }, {
472
- root,
473
- threshold: options.threshold ?? [0.4, 0.6, 0.8],
474
- });
475
- anteRefs.current.forEach((el) => observer.observe(el));
476
- return () => observer.disconnect();
477
- }, [antes, options.threshold]);
478
- const scrollToAnte = useCallback((ante) => {
479
- const el = anteRefs.current.get(ante);
480
- if (el) {
481
- el.scrollIntoView({ behavior: 'smooth', block: 'start' });
482
- }
483
- }, []);
484
- const registerAnteRef = useCallback((ante, el) => {
485
- if (el) {
486
- anteRefs.current.set(ante, el);
487
- }
488
- else {
489
- anteRefs.current.delete(ante);
490
- }
491
- }, []);
492
- return {
493
- currentAnte,
494
- scrollRef,
495
- scrollToAnte,
496
- registerAnteRef,
497
- };
498
- }
499
- /**
500
- * Manages drag-and-drop state for the Jaml IDE visual filter editor.
501
- */
502
- export function useJamlIdeDrag(filter, onChange, rootRef) {
503
- const [drag, setDrag] = useState(null);
504
- const [pendingDrag, setPendingDrag] = useState(null);
505
- const [hoverZone, setHoverZone] = useState(null);
506
- const onDragStart = useCallback((e, clause, fromZone) => {
507
- const t = 'touches' in e ? e.touches[0] : e;
508
- const rect = e.currentTarget.getBoundingClientRect();
509
- setPendingDrag({
510
- clause,
511
- fromZone,
512
- x: t.clientX,
513
- y: t.clientY,
514
- offX: t.clientX - rect.left,
515
- offY: t.clientY - rect.top,
516
- });
517
- setHoverZone(null);
518
- }, []);
519
- useEffect(() => {
520
- if (!pendingDrag && !drag)
521
- return;
522
- const move = (e) => {
523
- const touchEvent = 'touches' in e ? e : null;
524
- const t = touchEvent ? touchEvent.touches[0] : e;
525
- if (!t)
526
- return;
527
- let activeDrag = drag;
528
- if (!activeDrag && pendingDrag) {
529
- const dx = t.clientX - pendingDrag.x;
530
- const dy = t.clientY - pendingDrag.y;
531
- if (Math.hypot(dx, dy) < 8)
532
- return;
533
- activeDrag = {
534
- ...pendingDrag,
535
- x: t.clientX,
536
- y: t.clientY,
537
- };
538
- setPendingDrag(null);
539
- setDrag(activeDrag);
540
- }
541
- else if (activeDrag) {
542
- activeDrag = { ...activeDrag, x: t.clientX, y: t.clientY };
543
- setDrag(activeDrag);
544
- }
545
- if (!activeDrag)
546
- return;
547
- if (touchEvent?.cancelable)
548
- touchEvent.preventDefault();
549
- const rails = rootRef.current?.querySelectorAll('[data-zone]') ?? [];
550
- let found = null;
551
- for (const r of rails) {
552
- const rc = r.getBoundingClientRect();
553
- if (t.clientX >= rc.left && t.clientX <= rc.right && t.clientY >= rc.top && t.clientY <= rc.bottom) {
554
- found = r.getAttribute('data-zone');
555
- break;
556
- }
557
- }
558
- setHoverZone(found);
559
- };
560
- const up = () => {
561
- if (drag && hoverZone && hoverZone !== drag.fromZone) {
562
- const to = hoverZone;
563
- onChange({
564
- ...filter,
565
- [drag.fromZone]: filter[drag.fromZone].filter((c) => c.id !== drag.clause.id),
566
- [to]: [...filter[to], { ...drag.clause }],
567
- });
568
- }
569
- setPendingDrag(null);
570
- setDrag(null);
571
- setHoverZone(null);
572
- };
573
- window.addEventListener('mousemove', move);
574
- window.addEventListener('mouseup', up);
575
- window.addEventListener('touchmove', move, { passive: false });
576
- window.addEventListener('touchend', up);
577
- return () => {
578
- window.removeEventListener('mousemove', move);
579
- window.removeEventListener('mouseup', up);
580
- window.removeEventListener('touchmove', move);
581
- window.removeEventListener('touchend', up);
582
- };
583
- }, [pendingDrag, drag, hoverZone, filter, onChange, rootRef]);
584
- return {
585
- drag,
586
- hoverZone,
587
- onDragStart,
588
- };
589
- }
590
- /**
591
- * Provides a magnetic 3D tilt effect for DOM elements, replicating the 'juice' of Balatro cards.
592
- * Ensures the hit-detection area remains stable by separating container events from the transformed style.
593
- */
594
- export function useDOMMagneticTilt(enabled = true) {
595
- const [isHovered, setIsHovered] = useState(false);
596
- const [transform, setTransform] = useState('none');
597
- const onPointerEnter = (event) => {
598
- if (!enabled || event.pointerType === 'touch')
599
- return;
600
- setIsHovered(true);
601
- };
602
- const onPointerLeave = () => {
603
- if (!enabled)
604
- return;
605
- setIsHovered(false);
606
- setTransform('none');
607
- };
608
- const onPointerMove = (event) => {
609
- if (!enabled || event.pointerType === 'touch')
610
- return;
611
- const rect = event.currentTarget.getBoundingClientRect();
612
- const x = event.clientX - rect.left;
613
- const y = event.clientY - rect.top;
614
- const rotateY = (x / rect.width) * 12 - 6;
615
- const rotateX = (y / rect.height) * -16 + 8;
616
- const juiceScale = 1.05;
617
- const juiceY = -2; // slight move up
618
- setTransform(`perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale(${juiceScale}) translateY(${juiceY}px)`);
619
- };
620
- const handlers = {
621
- onPointerEnter: enabled ? onPointerEnter : undefined,
622
- onPointerLeave: enabled ? onPointerLeave : undefined,
623
- onPointerMove: enabled ? onPointerMove : undefined,
624
- };
625
- const tiltStyle = {
626
- transition: enabled && !isHovered ? 'transform 0.4s ease, box-shadow 0.4s ease-out' : 'transform 0.1s ease-out',
627
- transform: enabled ? (isHovered ? transform : 'none') : undefined,
628
- transformStyle: enabled ? 'preserve-3d' : undefined,
629
- transformOrigin: enabled ? 'center center' : undefined,
630
- willChange: enabled ? 'transform' : undefined,
631
- pointerEvents: enabled ? 'none' : undefined,
632
- };
633
- return { handlers, tiltStyle, isHovered };
634
- }
@@ -1,19 +0,0 @@
1
- interface AgnosticSeedCardProps {
2
- seed: string;
3
- deckSlug?: string;
4
- stakeSlug?: string;
5
- className?: string;
6
- onClick?: () => void;
7
- analysis?: any;
8
- result?: any;
9
- dayNumber?: number;
10
- ritualId?: string;
11
- jamlConfig?: string | null;
12
- isLocked?: boolean;
13
- onShowHowTo?: () => void;
14
- onOpenSubmit?: () => void;
15
- canSubmit?: boolean;
16
- filter?: any;
17
- }
18
- export declare function AgnosticSeedCard({ seed, deckSlug, stakeSlug, isLocked, dayNumber, className, onClick, analysis: propAnalysis, result: propResult, filter }: AgnosticSeedCardProps): import("react/jsx-runtime").JSX.Element;
19
- export {};