jaml-ui 0.24.19 → 0.24.20

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.
package/DESIGN.md CHANGED
@@ -197,13 +197,13 @@ Panels sit on a dark south-shadow (`0 3px 0 rgba(0,0,0,0.55)`). Translucent pane
197
197
 
198
198
  JAML-hit items get a GlowRing: `box-shadow: 0 0 0 2px [color], 0 0 10px [color]` with a 1.6s pulse animation. Must = blue glow, should = gold/green glow.
199
199
 
200
- **Button:** Chunky 3D press. DO NOT ADD A COLORED EDGE/BORDER. Buttons rely entirely on a solid `box-shadow` to create the colored "underside" depth. Hover brightness bump. Press sinks +2-3px and the box-shadow collapses to 0. Variants: primary (red), secondary (blue), back (orange), default (grey). NO GOLD BUTTONS. Sizes via padding, not font-size. Easing: `cubic-bezier(0.34, 1.56, 0.64, 1)`.
200
+ **Button:** Chunky 3D press. DO NOT ADD A COLORED EDGE/BORDER. Buttons rely entirely on a solid `box-shadow` to create the colored "underside" depth. Hover = dark variant of the button color. Press sinks +2-3px and the box-shadow collapses to 0. Variants: primary (red), secondary (blue), back (orange), default (grey). NO GOLD BUTTONS. Sizes via padding, not font-size. Easing: `cubic-bezier(0.34, 1.56, 0.64, 1)`.
201
201
 
202
202
  **Badge (JimboBadge):** Badges indicate status and DO NOT CLICK. They are strictly flat. They have a colored background and flat borders, but NO 3D BOX-SHADOW and NO PRESS ANIMATIONS. Variants: dark, blue, red, green, orange, purple, grey. NO GOLD BADGES.
203
203
 
204
204
  **Panel:** Dark grey (#3a5055) background, 2px solid border (silver top/sides, south bottom), border-radius 6px. Inner highlight: `inset 0 0 0 1px rgba(255,255,255,0.04)`. Drop: `0 2px 0 #000`.
205
205
 
206
- **Tabs (JimboTabs):** Active tab = gold background + black text. Inactive = transparent + grey text. No bold. Small radius (4px). Tabs are the ONLY navigation — no hamburger menus, no sidebars on mobile.
206
+ **Tabs (JimboTabs):** All tabs are red. Active tab has the bouncing triangle indicator above it. Hover and press = dark red. No opacity changes, no dimming, no gold. Small radius (4px). Tabs are the ONLY navigation — no hamburger menus, no sidebars on mobile.
207
207
 
208
208
  **ScoreCol:** Must-clauses show as blue-framed boxes with checkmark/cross badge. Should-clauses show as bare sprites with a red corner count badge (x2, x3...). Unlit = 40% opacity + grayscale.
209
209
 
package/dist/ui/jimbo.css CHANGED
@@ -6,7 +6,8 @@
6
6
 
7
7
  @font-face {
8
8
  font-family: 'm6x11plus';
9
- src: url('/fonts/m6x11plus.otf') format('opentype');
9
+ src: local('m6x11plus'), local('m6x11plusplus'),
10
+ url('../../assets/fonts/m6x11plusplus.otf') format('opentype');
10
11
  font-weight: normal;
11
12
  font-style: normal;
12
13
  font-display: swap;
@@ -324,7 +325,7 @@
324
325
  }
325
326
 
326
327
  .j-btn:not(.j-btn--disabled):hover .j-btn__face {
327
- filter: brightness(1.1);
328
+ background: var(--j-btn-hover-color, var(--j-btn-face-color));
328
329
  }
329
330
 
330
331
  /* Sizes */
@@ -351,30 +352,37 @@
351
352
  /* Tone colors — set via CSS custom properties */
352
353
  .j-btn--orange {
353
354
  --j-btn-face-color: var(--j-orange);
355
+ --j-btn-hover-color: var(--j-dark-orange);
354
356
  }
355
357
 
356
358
  .j-btn--red {
357
359
  --j-btn-face-color: var(--j-red);
360
+ --j-btn-hover-color: var(--j-dark-red);
358
361
  }
359
362
 
360
363
  .j-btn--blue {
361
364
  --j-btn-face-color: var(--j-blue);
365
+ --j-btn-hover-color: var(--j-dark-blue);
362
366
  }
363
367
 
364
368
  .j-btn--green {
365
369
  --j-btn-face-color: var(--j-green);
370
+ --j-btn-hover-color: var(--j-dark-green);
366
371
  }
367
372
 
368
373
  .j-btn--tarot {
369
374
  --j-btn-face-color: var(--j-tarot-btn);
375
+ --j-btn-hover-color: var(--j-tarot-btn-dark);
370
376
  }
371
377
 
372
378
  .j-btn--planet {
373
379
  --j-btn-face-color: var(--j-planet-btn);
380
+ --j-btn-hover-color: var(--j-planet-btn-dark);
374
381
  }
375
382
 
376
383
  .j-btn--spectral {
377
384
  --j-btn-face-color: var(--j-spectral-btn);
385
+ --j-btn-hover-color: var(--j-spectral-btn-dark);
378
386
  }
379
387
 
380
388
 
@@ -470,7 +478,7 @@
470
478
  }
471
479
 
472
480
  .j-tab__indicator[data-active="true"] {
473
- animation: jimbo-bounce 0.6s ease-in-out infinite;
481
+ animation: jimbo-bounce 0.7s ease-in-out infinite;
474
482
  }
475
483
 
476
484
  .j-tab__indicator[data-active="false"] {
@@ -482,7 +490,7 @@
482
490
  -webkit-appearance: none;
483
491
  border: none;
484
492
  cursor: pointer;
485
- border-radius: var(--j-radius-md);
493
+ border-radius: var(--j-radius-sm);
486
494
  padding: 6px 14px;
487
495
  min-height: 28px;
488
496
  background: var(--j-red);
@@ -490,33 +498,35 @@
490
498
  color: var(--j-white);
491
499
  text-align: center;
492
500
  text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.8);
493
- transition: filter 80ms linear, opacity 80ms linear;
501
+ transition: background var(--j-press-speed) linear;
494
502
  outline: none;
495
503
  }
496
504
 
497
- .j-tab__btn[data-active="true"] {
498
- opacity: 1;
505
+ .j-tab__btn .j-text {
506
+ color: inherit;
507
+ text-shadow: inherit;
499
508
  }
500
509
 
501
- .j-tab__btn[data-active="true"]:hover {
502
- background: var(--j-red);
510
+ .j-tab__btn:hover {
511
+ background: var(--j-dark-red);
503
512
  }
504
513
 
505
- .j-tab__btn[data-active="false"]:hover {
506
- background: var(--j-red);
507
- filter: brightness(1.08);
514
+ .j-tab__btn:active {
515
+ background: var(--j-dark-red);
508
516
  }
509
517
 
510
518
 
511
519
  @keyframes jimbo-bounce {
512
-
513
- 0%,
514
- 100% {
520
+ 0% {
515
521
  transform: translateY(0);
522
+ animation-timing-function: ease-out;
516
523
  }
517
-
518
- 50% {
519
- transform: translateY(-3px);
524
+ 45% {
525
+ transform: translateY(-5px);
526
+ animation-timing-function: ease-in;
527
+ }
528
+ 100% {
529
+ transform: translateY(0);
520
530
  }
521
531
  }
522
532
 
@@ -991,7 +1001,11 @@
991
1001
  /* ── Footer ───────────────────────────────────────────────────────────── */
992
1002
 
993
1003
  .j-footer {
994
- width: 100%;
1004
+ position: fixed;
1005
+ bottom: 0;
1006
+ left: 0;
1007
+ right: 0;
1008
+ z-index: 100;
995
1009
  transition: opacity 200ms;
996
1010
  }
997
1011
 
@@ -1248,6 +1262,11 @@
1248
1262
  padding: var(--j-space-lg) var(--j-space-lg) var(--j-space-md);
1249
1263
  scrollbar-width: none;
1250
1264
  -ms-overflow-style: none;
1265
+ scroll-snap-type: y mandatory;
1266
+ }
1267
+
1268
+ .j-app__scroll > * {
1269
+ scroll-snap-align: start;
1251
1270
  }
1252
1271
 
1253
1272
  .j-app__scroll::-webkit-scrollbar {
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Fullscreen WebGL CRT/spin background — the authentic Balatro hypnotic
3
- * swirl, pixelated and animated. Ported from weejoker.app's
4
- * BackgroundShader.tsx; no config required.
3
+ * swirl, pixelated and animated. Also renders the attribution footer at the
4
+ * bottom of the viewport (position: fixed) so it is always present and no
5
+ * consumer can accidentally omit it.
5
6
  *
6
- * Renders a fixed-position canvas at z-index: -10 that fills the viewport
7
- * and ignores pointer events. Drop it once at the root of your page:
7
+ * Drop it once at the root of your page:
8
8
  *
9
9
  * <JimboBackground />
10
10
  * <YourAppContent />
@@ -1,12 +1,13 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useBalatroBackground } from './hooks.js';
3
+ import { JimboBalatroFooter } from './footer.js';
3
4
  /**
4
5
  * Fullscreen WebGL CRT/spin background — the authentic Balatro hypnotic
5
- * swirl, pixelated and animated. Ported from weejoker.app's
6
- * BackgroundShader.tsx; no config required.
6
+ * swirl, pixelated and animated. Also renders the attribution footer at the
7
+ * bottom of the viewport (position: fixed) so it is always present and no
8
+ * consumer can accidentally omit it.
7
9
  *
8
- * Renders a fixed-position canvas at z-index: -10 that fills the viewport
9
- * and ignores pointer events. Drop it once at the root of your page:
10
+ * Drop it once at the root of your page:
10
11
  *
11
12
  * <JimboBackground />
12
13
  * <YourAppContent />
@@ -15,12 +16,12 @@ import { useBalatroBackground } from './hooks.js';
15
16
  */
16
17
  export function JimboBackground() {
17
18
  const canvasRef = useBalatroBackground();
18
- return (_jsx("canvas", { ref: canvasRef, "aria-hidden": true, style: {
19
- position: 'fixed',
20
- inset: 0,
21
- width: '100%',
22
- height: '100%',
23
- zIndex: -10,
24
- pointerEvents: 'none',
25
- } }));
19
+ return (_jsxs(_Fragment, { children: [_jsx("canvas", { ref: canvasRef, "aria-hidden": true, style: {
20
+ position: 'fixed',
21
+ inset: 0,
22
+ width: '100%',
23
+ height: '100%',
24
+ zIndex: -10,
25
+ pointerEvents: 'none',
26
+ } }), _jsx(JimboBalatroFooter, {})] }));
26
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaml-ui",
3
- "version": "0.24.19",
3
+ "version": "0.24.20",
4
4
  "description": "Balatro rendering components, sprite metadata, and optional Motely helpers for React apps.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -57,7 +57,8 @@
57
57
  "LICENSE"
58
58
  ],
59
59
  "engines": {
60
- "node": ">=18"
60
+ "node": ">=18",
61
+ "pnpm": ">=10"
61
62
  },
62
63
  "publishConfig": {
63
64
  "access": "public"
@@ -114,10 +115,9 @@
114
115
  "devDependencies": {
115
116
  "@chromatic-com/storybook": "^5.1.2",
116
117
  "@eslint/js": "^10.0.1",
117
- "@google/design.md": "^0.1.1",
118
118
  "@react-spring/three": "^10.0.3",
119
- "@react-three/drei": ">=9.0.0",
120
- "@react-three/fiber": "^9.6.0",
119
+ "@react-three/drei": "^10.7.7",
120
+ "@react-three/fiber": "^9.6.1",
121
121
  "@storybook/addon-a11y": "^10.3.6",
122
122
  "@storybook/addon-docs": "^10.3.6",
123
123
  "@storybook/addon-onboarding": "^10.3.6",
@@ -127,7 +127,7 @@
127
127
  "@types/react": "^19.2.14",
128
128
  "@types/react-dom": "^19.2.3",
129
129
  "@types/three": "^0.184.0",
130
- "@vitejs/plugin-react": "^5.0.4",
130
+ "@vitejs/plugin-react": "^5.2.0",
131
131
  "@vitest/browser-playwright": "^4.1.5",
132
132
  "@vitest/coverage-v8": "^4.1.5",
133
133
  "eslint": "^10.3.0",
@@ -136,23 +136,23 @@
136
136
  "globals": "^17.6.0",
137
137
  "motely-wasm": "^15.1.3",
138
138
  "playwright": "^1.59.1",
139
- "react": "^19.2.4",
140
- "react-dom": "^19.2.4",
139
+ "react": "^19.2.6",
140
+ "react-dom": "^19.2.6",
141
141
  "react-icons": "^5.6.0",
142
142
  "storybook": "^10.3.6",
143
143
  "three": "^0.184.0",
144
144
  "typescript": "^5.9.3",
145
145
  "typescript-eslint": "^8.59.2",
146
- "vite": "^8.0.9",
146
+ "vite": "^8.0.10",
147
147
  "vitest": "^4.1.5"
148
148
  },
149
149
  "dependencies": {
150
- "@codemirror/autocomplete": "^6.20.1",
150
+ "@codemirror/autocomplete": "^6.20.2",
151
151
  "@codemirror/commands": "^6.10.3",
152
152
  "@codemirror/lang-yaml": "^6.1.3",
153
153
  "@codemirror/language": "^6.12.3",
154
154
  "@codemirror/state": "^6.6.0",
155
- "@codemirror/view": "^6.41.1",
155
+ "@codemirror/view": "^6.42.0",
156
156
  "@json-render/core": "^0.18.0",
157
157
  "@lezer/highlight": "^1.2.3",
158
158
  "@types/js-yaml": "^4.0.9",
@@ -160,7 +160,7 @@
160
160
  "js-yaml": "^4.1.1",
161
161
  "lucide-react": "^1.14.0",
162
162
  "tailwind-merge": "^2.6.1",
163
- "zustand": "^5.0.0"
163
+ "zustand": "^5.0.13"
164
164
  },
165
165
  "scripts": {
166
166
  "build": "tsc --pretty false && node -e \"const fs=require('fs');fs.mkdirSync('dist/ui',{recursive:true});fs.copyFileSync('src/ui/jimbo.css','dist/ui/jimbo.css');\"",