@pieai/swimmer-ui-kit 1.7.0 → 1.8.0

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/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes to `@pieai/swimmer-ui-kit`.
4
4
  Format: [Keep a Changelog](https://keepachangelog.com); versioning: semver.
5
5
 
6
+ ## 1.8.0
7
+
8
+ ### Added
9
+
10
+ - **`<LiquidMetalButton>`**, a decision-surface CTA with two renderers and
11
+ one set of tokens. Default is CSS (zero WebGL contexts). It upgrades to
12
+ the ThreeUI dispersion shader (MIT, inlined — not the iframe wrapper)
13
+ only when webgl2 is available, `prefers-reduced-motion` is not `reduce`,
14
+ the button is on screen, and a process-wide budget (default **2**,
15
+ `setLiquidMetalContextBudget`) still has a slot. Exhausted budget, a
16
+ missing webgl2, or reduced motion stays on CSS without throwing. Hidden
17
+ tabs pause RAF rather than destroying the context.
18
+
19
+ Use it on checkout, sign-up, unlock, landing CTA. Do not use it on
20
+ reading, queues, forms, or the map. More than two on a page means the
21
+ page is the wrong place.
22
+
23
+ Colours are `--game-ui-liquid-metal-face` / `--ink` (defined on both
24
+ light and night so they cannot inherit an inverting ink) plus the
25
+ existing accent; the effect knobs are `--game-ui-liquid-metal-dispersion`,
26
+ `--sweep-speed`, and `--rest`.
27
+
6
28
  ## 1.7.0
7
29
 
8
30
  ### Fixed
package/NOTICE ADDED
@@ -0,0 +1,38 @@
1
+ Third-party notices
2
+ ===================
3
+
4
+ Liquid-metal dispersion shader
5
+ ------------------------------
6
+ Portions of the WebGL2 renderer in `src/liquidMetalWebGL.ts` are adapted
7
+ from ThreeUI (https://github.com/MengTo/threeui), Copyright (c) 2026
8
+ Meng To, licensed under the MIT License.
9
+
10
+ The upstream ships the shader inside a standalone HTML page and embeds
11
+ that page in an iframe. This package inlines the shader so colours can
12
+ follow `--game-ui-*` tokens, adds a CSS renderer as the default, and
13
+ caps simultaneous WebGL contexts.
14
+
15
+ The MIT License text for that material:
16
+
17
+ Permission is hereby granted, free of charge, to any person obtaining a copy
18
+ of this software and associated documentation files (the "Software"), to deal
19
+ in the Software without restriction, including without limitation the rights
20
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21
+ copies of the Software, and to permit persons to whom the Software is
22
+ furnished to do so, subject to the following conditions:
23
+
24
+ The above copyright notice and this permission notice shall be included in all
25
+ copies or substantial portions of the Software.
26
+
27
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33
+ SOFTWARE.
34
+
35
+ Fonts
36
+ -----
37
+ Baloo 2 and Geist Variable are licensed under the SIL Open Font License.
38
+ See `src/fonts/OFL-Baloo2.txt` and `src/fonts/OFL-Geist.txt`.
package/README.md CHANGED
@@ -48,7 +48,8 @@ import '@pieai/swimmer-ui-kit/tailwind.css';
48
48
 
49
49
  ## What's inside
50
50
 
51
- - **~60 components** across: core controls (`GameButton`, `GameTabs`,
51
+ - **~60 components** across: core controls (`GameButton`,
52
+ `LiquidMetalButton`, `GameTabs`,
52
53
  `GameSlider`, `GameToggle`, `GameForms` inputs…), panels and windows
53
54
  (`GamePanel`, `GameCollapsiblePanel`, `GameWindowPanel`, `GameModal` on
54
55
  native `<dialog>`), HUD/shell surfaces (`GameShell`, `GameHud`,
package/dist/index.d.ts CHANGED
@@ -78,6 +78,9 @@ export declare const CLAY_COLOR_TOKENS: {
78
78
  /** Official HUD-on-scene glass fill (matches SupaLuv stage chrome). */
79
79
  readonly overlayGlass: "rgba(12, 14, 20, 0.72)";
80
80
  readonly overlayGlassText: "#fff6ee";
81
+ /** Liquid-metal plate fill (light). Dedicated so it cannot inherit ink-deep, which inverts on night. */
82
+ readonly liquidMetalFace: "#3a2518";
83
+ readonly liquidMetalInk: "#fff8ec";
81
84
  };
82
85
 
83
86
  export declare const CLAY_ELEVATION_TOKENS: {
@@ -265,6 +268,23 @@ export declare const CLAY_LAYER_TOKENS: {
265
268
  readonly toast: "var(--game-ui-z-toast)";
266
269
  };
267
270
 
271
+ /**
272
+ * Effect knobs for `<LiquidMetalButton>`. Face/ink are real colours (both
273
+ * themes must set them); accent aliases `--game-ui-accent` so a host can
274
+ * retint just this button without rebranding every primary.
275
+ */
276
+ declare const CLAY_LIQUID_METAL_TOKENS: {
277
+ readonly face: "var(--game-ui-liquid-metal-face)";
278
+ readonly ink: "var(--game-ui-liquid-metal-ink)";
279
+ readonly accent: "var(--game-ui-liquid-metal-accent)";
280
+ readonly dispersion: "var(--game-ui-liquid-metal-dispersion)";
281
+ readonly sweepSpeed: "var(--game-ui-liquid-metal-sweep-speed)";
282
+ readonly rest: "var(--game-ui-liquid-metal-rest)";
283
+ readonly bloom: "var(--game-ui-liquid-metal-bloom)";
284
+ };
285
+ export { CLAY_LIQUID_METAL_TOKENS }
286
+ export { CLAY_LIQUID_METAL_TOKENS as GAME_UI_LIQUID_METAL_TOKENS }
287
+
268
288
  export declare const CLAY_MOTION_TOKENS: {
269
289
  readonly fast: "var(--game-ui-motion-fast)";
270
290
  readonly base: "var(--game-ui-motion-base)";
@@ -396,6 +416,9 @@ export declare const CLAY_UI_TOKENS: {
396
416
  /** Official HUD-on-scene glass fill (matches SupaLuv stage chrome). */
397
417
  readonly overlayGlass: "rgba(12, 14, 20, 0.72)";
398
418
  readonly overlayGlassText: "#fff6ee";
419
+ /** Liquid-metal plate fill (light). Dedicated so it cannot inherit ink-deep, which inverts on night. */
420
+ readonly liquidMetalFace: "#3a2518";
421
+ readonly liquidMetalInk: "#fff8ec";
399
422
  };
400
423
  readonly semantic: {
401
424
  readonly background: "var(--game-ui-bg)";
@@ -520,6 +543,15 @@ export declare const CLAY_UI_TOKENS: {
520
543
  readonly focusRing: "var(--game-ui-overlay-glass-focus-ring)";
521
544
  readonly primaryFill: "var(--game-ui-overlay-glass-primary-fill)";
522
545
  };
546
+ readonly liquidMetal: {
547
+ readonly face: "var(--game-ui-liquid-metal-face)";
548
+ readonly ink: "var(--game-ui-liquid-metal-ink)";
549
+ readonly accent: "var(--game-ui-liquid-metal-accent)";
550
+ readonly dispersion: "var(--game-ui-liquid-metal-dispersion)";
551
+ readonly sweepSpeed: "var(--game-ui-liquid-metal-sweep-speed)";
552
+ readonly rest: "var(--game-ui-liquid-metal-rest)";
553
+ readonly bloom: "var(--game-ui-liquid-metal-bloom)";
554
+ };
523
555
  };
524
556
 
525
557
  export declare type ClayAssetGroup = keyof typeof CLAY_ASSETS;
@@ -557,6 +589,18 @@ export declare type ClayIconStyle = 'game' | 'line';
557
589
 
558
590
  export declare type ClayTokenCategory = keyof typeof CLAY_UI_TOKENS;
559
591
 
592
+ /**
593
+ * Process-wide ledger for liquid-metal WebGL2 contexts.
594
+ *
595
+ * Chrome gives a tab about 16 contexts (Android about 8) and silently
596
+ * kills the oldest when the cap is hit. In University that oldest context
597
+ * is the 3D world map. These buttons are allowed to light up a shader,
598
+ * but they are not allowed to evict the map — so the default budget is
599
+ * 2, hosts can raise or lower it, and a button that cannot get a slot
600
+ * stays on the CSS renderer without throwing.
601
+ */
602
+ export declare const DEFAULT_LIQUID_METAL_CONTEXT_BUDGET = 2;
603
+
560
604
  export declare function FirstSessionHud({ authenticated, batteryCount, className, dailyStreak, iconSlots, labels, onHistory, onSettings, onWardrobe, playerName, }: FirstSessionHudProps): ReactNode;
561
605
 
562
606
  export declare interface FirstSessionHudIconSlots {
@@ -661,7 +705,7 @@ export declare const GAME_UI_TARGETS: {
661
705
  * to check its own CSS for the same completeness instead of eyeballing it —
662
706
  * see "自定义第三主题" in design-system-guide.md for a usage example.
663
707
  */
664
- export declare const GAME_UI_THEME_CONTRACT: readonly ["--game-ui-bg", "--game-ui-surface", "--game-ui-surface-raised", "--game-ui-panel", "--game-ui-panel-strong", "--game-ui-panel-deep", "--game-ui-text", "--game-ui-text-muted", "--game-ui-accent", "--game-ui-accent-bright", "--game-ui-secondary", "--game-ui-success", "--game-ui-success-bright", "--game-ui-danger", "--game-ui-danger-bright", "--game-ui-warning", "--game-ui-focus-ring", "--game-ui-border-subtle", "--game-ui-border-strong", "--game-ui-disabled", "--game-ui-ink-deep", "--game-ui-border-ink", "--game-ui-wood", "--game-ui-ink-title", "--game-ui-ink-heading"];
708
+ export declare const GAME_UI_THEME_CONTRACT: readonly ["--game-ui-bg", "--game-ui-surface", "--game-ui-surface-raised", "--game-ui-panel", "--game-ui-panel-strong", "--game-ui-panel-deep", "--game-ui-text", "--game-ui-text-muted", "--game-ui-accent", "--game-ui-accent-bright", "--game-ui-secondary", "--game-ui-success", "--game-ui-success-bright", "--game-ui-danger", "--game-ui-danger-bright", "--game-ui-warning", "--game-ui-focus-ring", "--game-ui-border-subtle", "--game-ui-border-strong", "--game-ui-disabled", "--game-ui-ink-deep", "--game-ui-border-ink", "--game-ui-wood", "--game-ui-ink-title", "--game-ui-ink-heading", "--game-ui-liquid-metal-face", "--game-ui-liquid-metal-ink"];
665
709
 
666
710
  export declare const GAME_UI_TOKENS: {
667
711
  readonly iconSm: "var(--game-ui-asset-icon-sm)";
@@ -1880,6 +1924,28 @@ export declare function getClayIconStyles(icon: ClayIconName): ClayIconStyle[];
1880
1924
 
1881
1925
  export declare function getClaySourceAssetPath(icon: ClayIconName, style?: ClayIconStyle): string;
1882
1926
 
1927
+ export declare function getLiquidMetalContextBudget(): {
1928
+ limit: number;
1929
+ used: number;
1930
+ };
1931
+
1932
+ export declare function LiquidMetalButton({ children, className, onClick, sound, type, renderer, ...props }: LiquidMetalButtonProps): ReactNode;
1933
+
1934
+ export declare interface LiquidMetalButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
1935
+ children: ReactNode;
1936
+ sound?: GameInteractionSoundOptions | false;
1937
+ /**
1938
+ * `auto` (default) starts on CSS and upgrades to WebGL when the four
1939
+ * gates pass. `css` never spends a context — needed so a side-by-side
1940
+ * demo can show the fallback without the CSS column taking the slot
1941
+ * the WebGL column needs. `webgl` still respects the gates; it is not
1942
+ * a way to bypass reduced-motion or the budget.
1943
+ */
1944
+ renderer?: LiquidMetalRendererMode;
1945
+ }
1946
+
1947
+ export declare type LiquidMetalRendererMode = 'auto' | 'css' | 'webgl';
1948
+
1883
1949
  export declare function playGameInteractionSound(options?: GameInteractionSoundOptions): boolean;
1884
1950
 
1885
1951
  export declare function playGameInteractionSoundForContext(audioContext: GameInteractionAudioContext, options?: GameInteractionSoundOptions): boolean;
@@ -1904,4 +1970,6 @@ export declare function setClayAssetBasePath(basePath: string): void;
1904
1970
  */
1905
1971
  export declare function setClayAssetMode(mode: ClayAssetMode): void;
1906
1972
 
1973
+ export declare function setLiquidMetalContextBudget(nextLimit: number): void;
1974
+
1907
1975
  export { }