jaml-ui 0.24.19 → 0.25.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 (235) hide show
  1. package/DESIGN.md +2 -2
  2. package/README.md +0 -13
  3. package/assets/WeeJokerExampleDAilyGame.png +0 -0
  4. package/assets/balatro-stake-chips.png +0 -0
  5. package/dist/assets.d.ts +1 -2
  6. package/dist/chunks/Layer-BBPJFHfs.js +17 -0
  7. package/dist/chunks/Layer-BBPJFHfs.js.map +1 -0
  8. package/dist/chunks/assets-RWUiFSTc.js +37 -0
  9. package/dist/chunks/assets-RWUiFSTc.js.map +1 -0
  10. package/dist/chunks/motelyItemDecoder-CueyZ0XD.js +6039 -0
  11. package/dist/chunks/motelyItemDecoder-CueyZ0XD.js.map +1 -0
  12. package/dist/chunks/spriteMapper-CFjN0_TV.js +2415 -0
  13. package/dist/chunks/spriteMapper-CFjN0_TV.js.map +1 -0
  14. package/dist/chunks/tokens-B65Fzble.js +57 -0
  15. package/dist/chunks/tokens-B65Fzble.js.map +1 -0
  16. package/dist/chunks/ui-5cBy3zAm.js +1387 -0
  17. package/dist/chunks/ui-5cBy3zAm.js.map +1 -0
  18. package/dist/components/AnalyzerExplorer.d.ts +1 -1
  19. package/dist/components/CardFan.d.ts +1 -1
  20. package/dist/components/CardList.d.ts +1 -1
  21. package/dist/components/DeckSprite.d.ts +1 -1
  22. package/dist/components/JamlAestheticSelector.d.ts +1 -1
  23. package/dist/components/JamlAnalyzerFullscreen.d.ts +5 -5
  24. package/dist/components/JamlCurator.d.ts +1 -1
  25. package/dist/components/JamlIde.d.ts +5 -5
  26. package/dist/components/JamlSeedInput.d.ts +1 -1
  27. package/dist/components/JamlSpeedometer.d.ts +1 -1
  28. package/dist/components/MotelyVersionBadge.d.ts +1 -1
  29. package/dist/components/Standardcard.d.ts +1 -1
  30. package/dist/components/jamlMap/CategoryPicker.d.ts +3 -3
  31. package/dist/components/jamlMap/JamlMapEditor.d.ts +1 -1
  32. package/dist/components/jamlMap/JokerPicker.d.ts +1 -1
  33. package/dist/components/jamlMap/MysterySlot.d.ts +2 -2
  34. package/dist/components/jamlMap/index.d.ts +4 -4
  35. package/dist/core.d.ts +5 -5
  36. package/dist/core.js +27 -5
  37. package/dist/core.js.map +1 -0
  38. package/dist/decode/motelyItemDecoder.d.ts +0 -10
  39. package/dist/decode/motelySprite.d.ts +1 -1
  40. package/dist/fonts/m6x11plus.otf +0 -0
  41. package/dist/hooks/analyzerStreamRegistry.d.ts +2 -2
  42. package/dist/hooks/useAnalyzer.d.ts +2 -2
  43. package/dist/hooks/useSearch.d.ts +2 -2
  44. package/dist/index.d.ts +29 -31
  45. package/dist/index.js +16725 -34
  46. package/dist/index.js.map +1 -0
  47. package/dist/lib/const.d.ts +2 -2
  48. package/dist/lib/hooks/useDragScroll.d.ts +1 -1
  49. package/dist/lib/hooks/useJamlFilter.d.ts +2 -2
  50. package/dist/lib/hooks/useSeedAnalyzer.d.ts +2 -2
  51. package/dist/lib/utils.d.ts +1 -1
  52. package/dist/motely.d.ts +4 -3
  53. package/dist/motely.js +65 -3
  54. package/dist/motely.js.map +1 -0
  55. package/dist/motelyBoot.d.ts +2 -0
  56. package/dist/motelyDisplay.d.ts +0 -2
  57. package/dist/r3f/Card3D.d.ts +2 -2
  58. package/dist/r3f/JimboBillboard.d.ts +1 -1
  59. package/dist/r3f.js +235 -3
  60. package/dist/r3f.js.map +1 -0
  61. package/dist/render/CanvasRenderer.d.ts +1 -1
  62. package/dist/sprites/spriteData.d.ts +1 -6
  63. package/dist/sprites/spriteMapper.d.ts +1 -1
  64. package/dist/ui/JimboBadge.d.ts +1 -1
  65. package/dist/ui/JimboFloating.d.ts +1 -1
  66. package/dist/ui/JimboIconButton.d.ts +1 -1
  67. package/dist/ui/JimboSelect.d.ts +1 -1
  68. package/dist/ui/footer.d.ts +2 -3
  69. package/dist/ui/hooks.d.ts +1 -1
  70. package/dist/ui/ide/DeckSprite.d.ts +1 -1
  71. package/dist/ui/jimbo.css +2 -1837
  72. package/dist/ui/jimboApp.d.ts +1 -1
  73. package/dist/ui/jimboBackground.d.ts +4 -4
  74. package/dist/ui/jimboFilterBar.d.ts +1 -1
  75. package/dist/ui/jimboFlankNav.d.ts +1 -1
  76. package/dist/ui/jimboInfoCard.d.ts +1 -1
  77. package/dist/ui/jimboInset.d.ts +1 -1
  78. package/dist/ui/jimboStatGrid.d.ts +1 -1
  79. package/dist/ui/jimboText.d.ts +1 -1
  80. package/dist/ui/jimboTooltip.d.ts +2 -2
  81. package/dist/ui/mascot/SeedMascot.d.ts +2 -2
  82. package/dist/ui/panel.d.ts +1 -1
  83. package/dist/ui/radial/RadialBadge.d.ts +1 -2
  84. package/dist/ui/radial/RadialButton.d.ts +1 -2
  85. package/dist/ui/radial/RadialMenu.d.ts +2 -2
  86. package/dist/ui/radial/RadialPill.d.ts +1 -2
  87. package/dist/ui/radial/index.d.ts +16 -16
  88. package/dist/ui/radial/radialMenuStore.d.ts +1 -1
  89. package/dist/ui/showcase.d.ts +1 -1
  90. package/dist/ui/sprites.d.ts +2 -2
  91. package/dist/ui.d.ts +0 -1
  92. package/dist/ui.js +3 -36
  93. package/dist/utils/gameCardUtils.d.ts +1 -1
  94. package/dist/utils/jamlVisualFilter.d.ts +1 -7
  95. package/package.json +18 -30
  96. package/dist/assets.js +0 -48
  97. package/dist/components/AnalyzerExplorer.js +0 -391
  98. package/dist/components/CardFan.js +0 -80
  99. package/dist/components/CardList.js +0 -5
  100. package/dist/components/DeckSprite.js +0 -75
  101. package/dist/components/GameCard.js +0 -355
  102. package/dist/components/JamlAestheticSelector.js +0 -22
  103. package/dist/components/JamlAnalyzerFullscreen.js +0 -263
  104. package/dist/components/JamlCodeEditor.js +0 -137
  105. package/dist/components/JamlCurator.js +0 -64
  106. package/dist/components/JamlCurator.stories.d.ts +0 -6
  107. package/dist/components/JamlCurator.stories.js +0 -14
  108. package/dist/components/JamlIde.js +0 -193
  109. package/dist/components/JamlIdeToolbar.js +0 -23
  110. package/dist/components/JamlIdeVisual.js +0 -218
  111. package/dist/components/JamlMapPreview.js +0 -121
  112. package/dist/components/JamlSeedInput.js +0 -26
  113. package/dist/components/JamlSpeedometer.js +0 -70
  114. package/dist/components/Jimbolate.js +0 -17
  115. package/dist/components/MotelyVersionBadge.js +0 -19
  116. package/dist/components/PaginatedFilterBrowser.js +0 -54
  117. package/dist/components/RunConfigModal.js +0 -59
  118. package/dist/components/Standardcard.js +0 -80
  119. package/dist/components/jamlMap/CategoryPicker.js +0 -135
  120. package/dist/components/jamlMap/JamlMapEditor.js +0 -304
  121. package/dist/components/jamlMap/JamlMapEditor.stories.d.ts +0 -7
  122. package/dist/components/jamlMap/JamlMapEditor.stories.js +0 -26
  123. package/dist/components/jamlMap/JamlMapEditorDemo.d.ts +0 -8
  124. package/dist/components/jamlMap/JamlMapEditorDemo.js +0 -323
  125. package/dist/components/jamlMap/JokerPicker.js +0 -113
  126. package/dist/components/jamlMap/MysterySlot.js +0 -128
  127. package/dist/components/jamlMap/MysterySlot.stories.d.ts +0 -7
  128. package/dist/components/jamlMap/MysterySlot.stories.js +0 -31
  129. package/dist/components/jamlMap/index.js +0 -4
  130. package/dist/decode/motelyItemDecoder.js +0 -164
  131. package/dist/decode/motelySprite.js +0 -84
  132. package/dist/hooks/analyzerStreamRegistry.js +0 -96
  133. package/dist/hooks/searchWorker.d.ts +0 -1
  134. package/dist/hooks/searchWorker.js +0 -119
  135. package/dist/hooks/searchWorkerCode.d.ts +0 -1
  136. package/dist/hooks/searchWorkerCode.js +0 -85
  137. package/dist/hooks/useAnalyzer.js +0 -91
  138. package/dist/hooks/useIntersectionObserver.js +0 -52
  139. package/dist/hooks/useSearch.js +0 -161
  140. package/dist/hooks/useShopStream.js +0 -85
  141. package/dist/lib/SpriteMapper.js +0 -48
  142. package/dist/lib/cardParser.js +0 -67
  143. package/dist/lib/classes/BuyMetaData.js +0 -1
  144. package/dist/lib/config.js +0 -15
  145. package/dist/lib/const.js +0 -521
  146. package/dist/lib/data/constants.js +0 -14
  147. package/dist/lib/hooks/useDragScroll.js +0 -48
  148. package/dist/lib/hooks/useJamlFilter.js +0 -219
  149. package/dist/lib/hooks/useSeedAnalyzer.js +0 -50
  150. package/dist/lib/jaml/jamlCompletion.js +0 -13
  151. package/dist/lib/jaml/jamlData.js +0 -6
  152. package/dist/lib/jaml/jamlObjectives.js +0 -97
  153. package/dist/lib/jaml/jamlParser.js +0 -47
  154. package/dist/lib/jaml/jamlPresets.js +0 -61
  155. package/dist/lib/jaml/jamlSchema.js +0 -91
  156. package/dist/lib/parseDailyRitual.js +0 -70
  157. package/dist/lib/tts/getRevealPos.js +0 -16
  158. package/dist/lib/tts/splitTtsDisplay.js +0 -35
  159. package/dist/lib/types.js +0 -1
  160. package/dist/lib/utils.js +0 -5
  161. package/dist/motelyDisplay.js +0 -59
  162. package/dist/r3f/Card3D.js +0 -72
  163. package/dist/r3f/JimboBillboard.js +0 -32
  164. package/dist/r3f/JimboText3D.js +0 -8
  165. package/dist/render/CanvasRenderer.js +0 -11
  166. package/dist/render/Layer.js +0 -18
  167. package/dist/sprites/spriteData.js +0 -100
  168. package/dist/sprites/spriteMapper.js +0 -75
  169. package/dist/stories/Button.d.ts +0 -15
  170. package/dist/stories/Button.js +0 -7
  171. package/dist/stories/Button.stories.d.ts +0 -24
  172. package/dist/stories/Button.stories.js +0 -50
  173. package/dist/stories/Header.d.ts +0 -12
  174. package/dist/stories/Header.js +0 -4
  175. package/dist/stories/Header.stories.d.ts +0 -18
  176. package/dist/stories/Header.stories.js +0 -26
  177. package/dist/stories/Page.d.ts +0 -3
  178. package/dist/stories/Page.js +0 -8
  179. package/dist/stories/Page.stories.d.ts +0 -12
  180. package/dist/stories/Page.stories.js +0 -24
  181. package/dist/ui/Jimbo.stories.d.ts +0 -7
  182. package/dist/ui/Jimbo.stories.js +0 -28
  183. package/dist/ui/JimboBadge.js +0 -8
  184. package/dist/ui/JimboFloating.js +0 -17
  185. package/dist/ui/JimboIconButton.js +0 -28
  186. package/dist/ui/JimboInputModal.js +0 -66
  187. package/dist/ui/JimboSelect.js +0 -43
  188. package/dist/ui/JimboToggleList.js +0 -5
  189. package/dist/ui/PanelSplitter.js +0 -78
  190. package/dist/ui/codeBlock.js +0 -14
  191. package/dist/ui/footer.js +0 -20
  192. package/dist/ui/hooks.js +0 -634
  193. package/dist/ui/ide/AgnosticSeedCard.d.ts +0 -19
  194. package/dist/ui/ide/AgnosticSeedCard.js +0 -48
  195. package/dist/ui/ide/DeckSprite.js +0 -2
  196. package/dist/ui/ide/JamlBuilder.d.ts +0 -1
  197. package/dist/ui/ide/JamlBuilder.js +0 -112
  198. package/dist/ui/ide/JamlEditor.js +0 -486
  199. package/dist/ui/ide/JamlEditorMonaco.d.ts +0 -8
  200. package/dist/ui/ide/JamlEditorMonaco.js +0 -78
  201. package/dist/ui/ide/WasmStatus.d.ts +0 -1
  202. package/dist/ui/ide/WasmStatus.js +0 -42
  203. package/dist/ui/jimboApp.js +0 -15
  204. package/dist/ui/jimboBackground.js +0 -26
  205. package/dist/ui/jimboCopyRow.js +0 -18
  206. package/dist/ui/jimboFilterBar.js +0 -16
  207. package/dist/ui/jimboFlankNav.js +0 -18
  208. package/dist/ui/jimboInfoCard.js +0 -26
  209. package/dist/ui/jimboInset.js +0 -9
  210. package/dist/ui/jimboSectionHeader.js +0 -9
  211. package/dist/ui/jimboStatGrid.js +0 -9
  212. package/dist/ui/jimboTabs.js +0 -22
  213. package/dist/ui/jimboText.js +0 -33
  214. package/dist/ui/jimboTooltip.js +0 -39
  215. package/dist/ui/jimboWordmark.js +0 -9
  216. package/dist/ui/mascot/JammySpeechBox.js +0 -30
  217. package/dist/ui/mascot/SeedMascot.js +0 -17
  218. package/dist/ui/mascot/index.js +0 -3
  219. package/dist/ui/mascot/menuConfig.js +0 -12
  220. package/dist/ui/panel.js +0 -24
  221. package/dist/ui/radial/RadialBadge.js +0 -43
  222. package/dist/ui/radial/RadialBreadcrumb.js +0 -18
  223. package/dist/ui/radial/RadialButton.js +0 -102
  224. package/dist/ui/radial/RadialMenu.js +0 -168
  225. package/dist/ui/radial/RadialPill.js +0 -15
  226. package/dist/ui/radial/index.js +0 -18
  227. package/dist/ui/radial/radialMenuStore.js +0 -122
  228. package/dist/ui/radial/radialMenuViewport.js +0 -59
  229. package/dist/ui/radial/useRadialMenu.js +0 -107
  230. package/dist/ui/showcase.js +0 -20
  231. package/dist/ui/sprites.js +0 -77
  232. package/dist/ui/tokens.js +0 -64
  233. package/dist/utils/gameCardUtils.js +0 -15
  234. package/dist/utils/jamlMapPreview.js +0 -106
  235. 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 {};