@pieai/swimmer-ui-kit 2.2.0 → 2.4.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,126 @@
3
3
  All notable changes to `@pieai/swimmer-ui-kit`.
4
4
  Format: [Keep a Changelog](https://keepachangelog.com); versioning: semver.
5
5
 
6
+ ## 2.4.0 — 2026-09-11
7
+
8
+ Minor: additive. One new token, six new form names, and a cast shadow that
9
+ every liquid body was missing.
10
+
11
+ ### Added
12
+
13
+ - **A cast shadow on the single-body forms.** `LiquidSurface` accepted a
14
+ `shadow` and no form set one, so every liquid button floated: the flat button
15
+ standing next to it carries a solid lip *and* `--game-ui-shadow-button`, and
16
+ the liquid one carried neither. `press`, `settle`, `drain`, and the new
17
+ `swell`, `reach`, `ripple` and `set` now carry two layers each — a tight,
18
+ barely-offset seat that says the body is touching, and a wide low cast that
19
+ gives it height. Compared at device ratio 1 against the flat control, a seat
20
+ alone glues the body to the page and a cast alone leaves it hovering.
21
+
22
+ Every layer is outer and spreadless, which is the case
23
+ `compositorDropShadowFilter` lifts onto the compositor: it costs no filter
24
+ area and it hugs the poured outline rather than a rounded rectangle. A caller
25
+ that wants its own ground still passes `shadow`, and `shadow="none"` removes
26
+ it.
27
+
28
+ - **`--game-ui-shadow-liquid-ink`.** The colour a liquid body casts, per theme.
29
+ It is a solid colour rather than a finished shadow, so a form states strength
30
+ and offset without restating the room's light. Deliberately **not** added to
31
+ `GAME_UI_THEME_CONTRACT`: that list is exported for downstream themes to
32
+ self-check, and adding an entry would turn a consumer's green check red for a
33
+ token they have never heard of. A theme that does not define it gets the
34
+ light theme's warm brown ink.
35
+
36
+ - **`shadowEngaged` on a form, and a shadow that answers the gesture.** A
37
+ pressed body is nearer the ground, so its seat hardens and its cast collapses
38
+ toward it; `settle` rests mid-air with no seat at all and gains one on
39
+ landing, which is the moment that form exists to mark. The silhouette's
40
+ filter transitions, so the shadow no longer arrives before the thing casting
41
+ it.
42
+
43
+ - **Six more forms: `set`, `swell`, `reach`, `ripple`, `split`, `bead`.** Each
44
+ says something none of the previous six could. `set` is the only one that
45
+ stops being liquid — everything else is a degree of wetness — and it snaps
46
+ rather than tweening, because setting is a discontinuity. `swell` is
47
+ attention with nothing touching it, so it is the one moving form with no
48
+ squash. `reach` is the only form with a direction. `ripple` says 「no」 by
49
+ moving and leaves its shape alone. `split` is `merge` backwards with a harder
50
+ edge and more recoil. `bead` is the one relationship form that pours, because
51
+ its bodies are the message rather than the neck between them.
52
+
53
+ - **`kind` on every form, and `LiquidFormKind`.** A form is one body or a
54
+ relationship between siblings. `LiquidSurface` can only draw the first;
55
+ handing it a group form used to render a correct-looking body that silently
56
+ never moved, and it now warns once, in every build.
57
+
58
+ - **`groupEngaged` on a form.** Group knobs that change while engaged. Only
59
+ `set` uses it. `blob` is path data and `gloss` is a filter pass, so neither
60
+ tweens — they snap, which is right for one form and a flicker for any other.
61
+
62
+ - **`LIQUID_BLOB_MAX_FRACTION`.** The share of a box's shorter side a poured
63
+ outline may swell by (0.18). Exported because it is why one `blob` value can
64
+ be handed to a 44px button and a 14px meter, and a number written in three
65
+ places drifts in two.
66
+
67
+ - **A Liquid page on the showcase site, at `/liquid.html`.** Every form live and
68
+ triggerable, at a control size and a meter size, on any of the four tones, in
69
+ both themes, with its knobs — including the derived edge width in px — written
70
+ out beside it.
71
+
72
+ ### Changed
73
+
74
+ - **`GameUiPreview`'s liquid section is smaller.** It keeps what a component
75
+ gallery is for — `surface` is a second axis on `GameButton` — and links out to
76
+ the Liquid page for the vocabulary. Two shelves meant two to update and, in
77
+ practice, one of them lagging. Hosts that render `<GameUiPreview />` and do
78
+ not serve `liquid.html` will have a link that does not resolve; the section
79
+ otherwise stands on its own.
80
+
81
+ ## 2.3.0 — 2026-09-11
82
+
83
+ Minor: additive, plus one token value change on the default liquid fill.
84
+
85
+ ### Added
86
+
87
+ - **`scaleY` on `LiquidGroup.Item`.** The two scale axes can now disagree, which
88
+ is what squash and stretch needs. A body that spreads sideways as it is pushed
89
+ down is made of something; one that scales uniformly is a thing getting
90
+ smaller.
91
+
92
+ - **`wobbly` transition preset.** Damping ratio 0.24 against `bouncy`'s 0.48, so
93
+ a pressed body crosses its rest shape three or four times instead of once —
94
+ the difference between 「it bounced」 and 「it is made of something」. `press`
95
+ and `settle` use it.
96
+
97
+ - **A Liquid surface section in `GameUiPreview`.** The showcase had a section
98
+ for the WebGL metal CTA, which no product uses, and none for the surface that
99
+ actually ships — so the only way to see a liquid button was to know which
100
+ screen of which product happened to render one.
101
+
102
+ ### Changed
103
+
104
+ - **The default liquid fill is `--game-ui-accent-pale`, not
105
+ `--game-ui-surface-raised`.** `surface-raised` is the right fill for a flat
106
+ secondary button and the wrong one for a liquid body: the whole point of this
107
+ surface is a shape you can see, and a near-white shape on a cream panel has no
108
+ shape at all. It was invisible next to its own flat twin while every coloured
109
+ tone read clearly. A product that wants the old fill sets
110
+ `--game-ui-liquid-surface-fill` back.
111
+
112
+ - **The button lip is shallower at compact density.** Height reads as height
113
+ because there is room around it; four solid bands stacked close together in a
114
+ 34px row read as ruled lines instead of as four keys.
115
+
116
+ ### Not shipped
117
+
118
+ A jelly material — four lighting terms, hue-preserving sheen, luminance-scaled
119
+ headroom — was built, reviewed against the 2.2.0 look, and rejected: it read as
120
+ too abrupt on a coloured body, and the existing single specular pass was better.
121
+ The motion from that work is what shipped. The material is in the history at
122
+ `ab3d706` if a surface ever wants it, and the two measured dead ends behind it
123
+ are worth keeping: multiplying the fill by a diffuse term darkens a brand colour
124
+ to ceramic, and adding white light at gel strength desaturates it to cream.
125
+
6
126
  ## 2.2.0 — 2026-09-11
7
127
 
8
128
  Minor, not major: nothing published is removed or renamed, and no `--game-ui-*`
package/dist/index.d.ts CHANGED
@@ -2353,10 +2353,22 @@ export declare const LIQUID_FORMS: Readonly<Record<LiquidForm, LiquidFormSpec>>;
2353
2353
  export declare const LIQUID_GOOEY_WAVINESS_MAX_FRACTION = 0.3;
2354
2354
 
2355
2355
  /**
2356
- * The named looks, ordered by how much cohesion the liquid is losing:
2357
- * `press` barely deforms, `drain` stops being a shape at all.
2356
+ * The named looks.
2357
+ *
2358
+ * Bodies first, then the forms that only mean something between siblings, and
2359
+ * within each run they are ordered by how much cohesion the liquid is losing:
2360
+ * `set` stops being liquid at all, `press` barely deforms, `drain` stops being
2361
+ * a shape.
2362
+ *
2363
+ * Six of these were the whole vocabulary until the brand needed more of it,
2364
+ * and six is worth saying out loud as *where it got to* rather than as a
2365
+ * complete set. A form earns its place by having something to say that none of
2366
+ * the others says. That is the only entry requirement — and it is also why a
2367
+ * form existing here is not permission to put it on a screen: the recorded
2368
+ * finding is that gooey on a static solid block reads as damage, and that one
2369
+ * screen wants one liquid element carrying one layer of intent.
2358
2370
  */
2359
- export declare type LiquidForm = 'press' | 'settle' | 'merge' | 'follow' | 'fill' | 'drain';
2371
+ export declare type LiquidForm = 'set' | 'press' | 'swell' | 'settle' | 'fill' | 'reach' | 'ripple' | 'drain' | 'follow' | 'merge' | 'split' | 'bead';
2360
2372
 
2361
2373
  /** Filter-level knobs a form fixes on the group. */
2362
2374
  export declare interface LiquidFormGroup {
@@ -2377,6 +2389,32 @@ export declare interface LiquidFormGroup {
2377
2389
  */
2378
2390
  readonly gloss: number;
2379
2391
  readonly filterPadding: number;
2392
+ /**
2393
+ * What the body casts on the ground at rest, in CSS box-shadow syntax.
2394
+ *
2395
+ * Every liquid button floated before this existed: the flat button has a lip
2396
+ * *and* `--game-ui-shadow-button`, and the liquid one had neither, which is
2397
+ * most of why it read flatter than its own flat twin. A form is where this
2398
+ * belongs rather than a call site, because how far a body sits off the
2399
+ * surface is part of what the form means.
2400
+ *
2401
+ * Keep it to outer layers with no spread. `liquidGooeyShadow` compiles those
2402
+ * to a CSS `drop-shadow()` on the silhouette — the compositor does the blur,
2403
+ * the shadow hugs the poured outline rather than a rounded rectangle, and it
2404
+ * is allowed to paint outside the filter region. Inset and spread are legal
2405
+ * but stay inside the SVG filter and are charged against the filter-area
2406
+ * budget, so they are a deliberate purchase, not a default.
2407
+ */
2408
+ readonly shadow?: string;
2409
+ /**
2410
+ * What it casts while the form is engaged, when that differs.
2411
+ *
2412
+ * A body that squashes toward the surface gets *closer* to it, and a real
2413
+ * contact shadow answers by tightening and darkening rather than staying
2414
+ * put. Leaving this out is fine; the rest shadow then holds through the
2415
+ * whole gesture, which is what a form with no vertical travel wants.
2416
+ */
2417
+ readonly shadowEngaged?: string;
2380
2418
  }
2381
2419
 
2382
2420
  /**
@@ -2399,10 +2437,37 @@ export declare interface LiquidFormItem {
2399
2437
  /** Resolve a form into item props, with the same merge-don't-replace rule. */
2400
2438
  export declare function liquidFormItem(form: LiquidForm, overrides?: LiquidFormItem): LiquidFormItem;
2401
2439
 
2440
+ /**
2441
+ * Whether a form describes one body or a relationship between siblings.
2442
+ *
2443
+ * `LiquidSurface` draws one silhouette, so it can only honour a `body` form;
2444
+ * a `group` form says something about the space *between* items and needs a
2445
+ * `LiquidGroup` the caller arranges. That distinction used to live in a
2446
+ * parenthetical — `ENGAGED` carried two entries marked 「present for
2447
+ * exhaustiveness」 — which meant picking the wrong one failed silently, by
2448
+ * rendering a body that never moves. Naming it lets a shelf group itself, lets
2449
+ * a caller check, and lets the kit say so out loud in development.
2450
+ */
2451
+ export declare type LiquidFormKind = 'body' | 'group';
2452
+
2402
2453
  export declare interface LiquidFormSpec {
2403
2454
  /** One sentence on what a viewer sees, for docs and for picking. */
2404
2455
  readonly summary: string;
2456
+ /** One body, or a relationship between siblings the caller arranges. */
2457
+ readonly kind: LiquidFormKind;
2405
2458
  readonly group: LiquidFormGroup;
2459
+ /**
2460
+ * Group knobs that change while the form is engaged.
2461
+ *
2462
+ * Only `set` uses this, and only because `set` is the one form whose subject
2463
+ * is *stopping* being liquid — without it the vocabulary can say a dozen
2464
+ * degrees of liquid and never say 「solid」. Be careful with it: `blob` is
2465
+ * path data and `gloss` is a filter pass, so neither tweens. They snap. For
2466
+ * `set` that snap is the gesture — a thing clicking into place — and for
2467
+ * anything continuous it would be a flicker, which is why this is not a
2468
+ * general-purpose second bundle.
2469
+ */
2470
+ readonly groupEngaged?: Partial<LiquidFormGroup>;
2406
2471
  readonly item: LiquidFormItem;
2407
2472
  }
2408
2473
 
@@ -2503,6 +2568,12 @@ export declare interface LiquidItemProps extends Omit<HTMLAttributes<HTMLDivElem
2503
2568
  x?: number;
2504
2569
  y?: number;
2505
2570
  scale?: number;
2571
+ /**
2572
+ * Vertical scale, when it should differ from `scale`. A body that squashes
2573
+ * wider as it gets shorter reads as jelly; one that scales uniformly reads
2574
+ * as a thing getting smaller.
2575
+ */
2576
+ scaleY?: number;
2506
2577
  /** Spring preset/config or an explicit duration/easing pair. */
2507
2578
  transition?: Transition;
2508
2579
  /** Delay before this item starts its group-clock transition, in ms. */
@@ -2551,7 +2622,7 @@ export declare interface LiquidMetalButtonProps extends ButtonHTMLAttributes<HTM
2551
2622
 
2552
2623
  export declare type LiquidMetalRendererMode = 'auto' | 'css' | 'webgl';
2553
2624
 
2554
- export declare function LiquidSurface({ children, form, active, fill, stroke, shadow, radius, className, style, }: LiquidSurfaceProps): ReactNode;
2625
+ export declare function LiquidSurface({ children, form, active, fill, stroke, shadow: shadowOverride, radius, className, style, }: LiquidSurfaceProps): ReactNode;
2555
2626
 
2556
2627
  export declare interface LiquidSurfaceProps {
2557
2628
  children: ReactNode;
@@ -2565,6 +2636,7 @@ export declare interface LiquidSurfaceProps {
2565
2636
  /** Silhouette paint. Defaults to the kit's raised surface token. */
2566
2637
  fill?: string;
2567
2638
  stroke?: string;
2639
+ /** Overrides the form's own cast shadow. `none` removes it. */
2568
2640
  shadow?: string;
2569
2641
  /** Corner radius of the body, in px. 999 gives a pill. */
2570
2642
  radius?: number;
@@ -2649,6 +2721,6 @@ declare type Transition = TransitionPreset | SpringConfig | {
2649
2721
  ease?: string;
2650
2722
  };
2651
2723
 
2652
- declare type TransitionPreset = 'snappy' | 'smooth' | 'bouncy';
2724
+ declare type TransitionPreset = 'snappy' | 'smooth' | 'bouncy' | 'wobbly';
2653
2725
 
2654
2726
  export { }