@ansh-ui/core 0.2.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.
Files changed (100) hide show
  1. package/LICENSE +21 -0
  2. package/dist/behaviours.cjs +64 -0
  3. package/dist/behaviours.cjs.map +1 -0
  4. package/dist/behaviours.d.cts +3 -0
  5. package/dist/behaviours.d.ts +3 -0
  6. package/dist/behaviours.js +7 -0
  7. package/dist/behaviours.js.map +1 -0
  8. package/dist/chunk-23GSSIMK.cjs +439 -0
  9. package/dist/chunk-23GSSIMK.cjs.map +1 -0
  10. package/dist/chunk-56NNBIAO.js +2446 -0
  11. package/dist/chunk-56NNBIAO.js.map +1 -0
  12. package/dist/chunk-6PFYGJWD.cjs +136 -0
  13. package/dist/chunk-6PFYGJWD.cjs.map +1 -0
  14. package/dist/chunk-7MEIXWPH.js +313 -0
  15. package/dist/chunk-7MEIXWPH.js.map +1 -0
  16. package/dist/chunk-7MYTSAPR.js +83 -0
  17. package/dist/chunk-7MYTSAPR.js.map +1 -0
  18. package/dist/chunk-BOQQHICI.js +1036 -0
  19. package/dist/chunk-BOQQHICI.js.map +1 -0
  20. package/dist/chunk-C6XPQO2O.js +1170 -0
  21. package/dist/chunk-C6XPQO2O.js.map +1 -0
  22. package/dist/chunk-DXJ63QAR.cjs +723 -0
  23. package/dist/chunk-DXJ63QAR.cjs.map +1 -0
  24. package/dist/chunk-FAVIEION.js +705 -0
  25. package/dist/chunk-FAVIEION.js.map +1 -0
  26. package/dist/chunk-FNR35HTL.cjs +107 -0
  27. package/dist/chunk-FNR35HTL.cjs.map +1 -0
  28. package/dist/chunk-GHBRGMSO.cjs +91 -0
  29. package/dist/chunk-GHBRGMSO.cjs.map +1 -0
  30. package/dist/chunk-GJRIHN76.cjs +359 -0
  31. package/dist/chunk-GJRIHN76.cjs.map +1 -0
  32. package/dist/chunk-ILKUL7GD.cjs +115 -0
  33. package/dist/chunk-ILKUL7GD.cjs.map +1 -0
  34. package/dist/chunk-KTUBCQC3.js +409 -0
  35. package/dist/chunk-KTUBCQC3.js.map +1 -0
  36. package/dist/chunk-KU2C6GEA.js +90 -0
  37. package/dist/chunk-KU2C6GEA.js.map +1 -0
  38. package/dist/chunk-LGA3N3YJ.cjs +413 -0
  39. package/dist/chunk-LGA3N3YJ.cjs.map +1 -0
  40. package/dist/chunk-MMO7KO53.cjs +1060 -0
  41. package/dist/chunk-MMO7KO53.cjs.map +1 -0
  42. package/dist/chunk-NSXKCJJ7.js +109 -0
  43. package/dist/chunk-NSXKCJJ7.js.map +1 -0
  44. package/dist/chunk-QALZKHWH.js +387 -0
  45. package/dist/chunk-QALZKHWH.js.map +1 -0
  46. package/dist/chunk-R7UJ7MWP.cjs +2479 -0
  47. package/dist/chunk-R7UJ7MWP.cjs.map +1 -0
  48. package/dist/chunk-UJBXY6QC.cjs +1186 -0
  49. package/dist/chunk-UJBXY6QC.cjs.map +1 -0
  50. package/dist/chunk-YFQXRC5R.js +99 -0
  51. package/dist/chunk-YFQXRC5R.js.map +1 -0
  52. package/dist/color.cjs +257 -0
  53. package/dist/color.cjs.map +1 -0
  54. package/dist/color.d.cts +303 -0
  55. package/dist/color.d.ts +303 -0
  56. package/dist/color.js +8 -0
  57. package/dist/color.js.map +1 -0
  58. package/dist/easing.cjs +189 -0
  59. package/dist/easing.cjs.map +1 -0
  60. package/dist/easing.d.cts +134 -0
  61. package/dist/easing.d.ts +134 -0
  62. package/dist/easing.js +4 -0
  63. package/dist/easing.js.map +1 -0
  64. package/dist/effects.cjs +99 -0
  65. package/dist/effects.cjs.map +1 -0
  66. package/dist/effects.d.cts +5 -0
  67. package/dist/effects.d.ts +5 -0
  68. package/dist/effects.js +10 -0
  69. package/dist/effects.js.map +1 -0
  70. package/dist/index-CCdpefMp.d.ts +967 -0
  71. package/dist/index-CQEEPu-D.d.ts +435 -0
  72. package/dist/index-DHOfsEIn.d.cts +967 -0
  73. package/dist/index-Dl8GCsya.d.cts +435 -0
  74. package/dist/index.cjs +2206 -0
  75. package/dist/index.cjs.map +1 -0
  76. package/dist/index.d.cts +1122 -0
  77. package/dist/index.d.ts +1122 -0
  78. package/dist/index.js +1182 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/math.cjs +238 -0
  81. package/dist/math.cjs.map +1 -0
  82. package/dist/math.d.cts +120 -0
  83. package/dist/math.d.ts +120 -0
  84. package/dist/math.js +5 -0
  85. package/dist/math.js.map +1 -0
  86. package/dist/noise.cjs +78 -0
  87. package/dist/noise.cjs.map +1 -0
  88. package/dist/noise.d.cts +190 -0
  89. package/dist/noise.d.ts +190 -0
  90. package/dist/noise.js +5 -0
  91. package/dist/noise.js.map +1 -0
  92. package/dist/palette-6HkVltYU.d.cts +219 -0
  93. package/dist/palette-6HkVltYU.d.ts +219 -0
  94. package/dist/random--4mSc5Lp.d.cts +75 -0
  95. package/dist/random--4mSc5Lp.d.ts +75 -0
  96. package/dist/reduced-motion-D0LUgZle.d.cts +120 -0
  97. package/dist/reduced-motion-D0LUgZle.d.ts +120 -0
  98. package/dist/types-B1FLLf3-.d.cts +21 -0
  99. package/dist/types-B1FLLf3-.d.ts +21 -0
  100. package/package.json +78 -0
@@ -0,0 +1,435 @@
1
+ import { R as ReducedMotionStrategy } from './reduced-motion-D0LUgZle.cjs';
2
+ import { E as EasingInput } from './types-B1FLLf3-.cjs';
3
+
4
+ /**
5
+ * The Behaviour contract — the DOM counterpart to {@link import('../effects/types').EffectDefinition}.
6
+ *
7
+ * An Effect owns a canvas and draws pixels. A Behaviour owns an element and manipulates styles,
8
+ * transforms or child nodes. Magnetic hover, 3D tilt, marquee scrolling, split-text reveals and
9
+ * parallax are all Behaviours.
10
+ *
11
+ * They share the same shape deliberately: identical lifecycle, identical option-merging, and a
12
+ * single `createBehaviourComponent` helper per framework. Whether a component is canvas-backed or
13
+ * DOM-backed becomes an implementation detail rather than an API difference.
14
+ */
15
+ interface BaseBehaviourOptions {
16
+ /** Multiplier on the behaviour's characteristic strength. Default `1`. */
17
+ intensity?: number;
18
+ /** How to behave under `prefers-reduced-motion`. */
19
+ reducedMotion?: ReducedMotionStrategy;
20
+ /** Suspend the behaviour without unmounting. Default `false`. */
21
+ disabled?: boolean;
22
+ }
23
+ interface BehaviourInstance<Options = Record<string, unknown>> {
24
+ /** Apply changed options. Omit to have the host remount on any change. */
25
+ update?(options: Partial<Options>): void;
26
+ /**
27
+ * Release everything.
28
+ *
29
+ * Must restore any inline styles the behaviour set, remove any nodes it created, and detach
30
+ * every listener. The test suite's leak harness asserts all three.
31
+ */
32
+ destroy(): void;
33
+ }
34
+ interface BehaviourDefinition<Options extends BaseBehaviourOptions = BaseBehaviourOptions, Element extends HTMLElement = HTMLElement> {
35
+ readonly name: string;
36
+ readonly defaults: Required<Options>;
37
+ readonly capability?: string;
38
+ setup(element: Element, options: Required<Options>): BehaviourInstance<Options>;
39
+ }
40
+ interface BehaviourHandle<Options> {
41
+ update(options: Partial<Options>): void;
42
+ destroy(): void;
43
+ }
44
+ /**
45
+ * Mount a behaviour onto an element.
46
+ *
47
+ * Thinner than the effect mount because there is no canvas, no surface and no render loop to
48
+ * manage — a behaviour that needs frames subscribes to the ticker itself. What this does provide
49
+ * is the uniform option merge (including the `undefined`-stripping that React and Vue both
50
+ * require), capability gating, and idempotent teardown.
51
+ */
52
+ declare function mountBehaviour<Options extends BaseBehaviourOptions, El extends HTMLElement = HTMLElement>(definition: BehaviourDefinition<Options, El>, element: El, userOptions?: Partial<Options>): BehaviourHandle<Options>;
53
+ /** Register a behaviour so the CLI and docs site can discover it. */
54
+ declare function defineBehaviour<Options extends BaseBehaviourOptions, El extends HTMLElement = HTMLElement>(definition: BehaviourDefinition<Options, El>): BehaviourDefinition<Options, El>;
55
+ /**
56
+ * Remember an element's inline styles so they can be restored exactly on teardown.
57
+ *
58
+ * Setting `element.style.transform = ''` is *not* a restore — it destroys an inline transform
59
+ * the author may have set themselves. This captures the previous value per property and puts it
60
+ * back, including removing the property entirely if it wasn't there before.
61
+ */
62
+ declare function captureStyles<K extends keyof CSSStyleDeclaration & string>(element: HTMLElement, properties: readonly K[]): () => void;
63
+
64
+ /**
65
+ * Ripple — a wave that expands from the point of contact.
66
+ *
67
+ * Material Design's ripple, done properly. Three details most implementations miss:
68
+ *
69
+ * **The radius must reach the furthest corner.** A ripple sized to the element's width leaves the
70
+ * corners untouched on a wide button, which looks like a bug. The correct radius is the distance
71
+ * from the contact point to the furthest corner, computed per press.
72
+ *
73
+ * **Fade-out must outlast expansion.** If opacity and scale finish together, the ripple appears to
74
+ * vanish mid-motion. The expansion completes first and the fade continues past it, so the ripple
75
+ * dissolves at full size.
76
+ *
77
+ * **Multiple ripples must coexist.** Rapid clicking should produce overlapping ripples, not one
78
+ * that restarts. Each press gets its own element, and they are cleaned up independently.
79
+ *
80
+ * The ripple layer is inserted as a positioned child with `overflow: hidden`, so it is clipped to
81
+ * the element's own border radius via `border-radius: inherit` — no need for the author to
82
+ * duplicate their radius in a prop.
83
+ */
84
+ interface RippleOptions extends BaseBehaviourOptions {
85
+ /** Ripple colour. Any CSS colour. Default `'currentColor'` at low alpha. */
86
+ color?: string;
87
+ /** Peak opacity, in `[0, 1]`. Default `0.28`. */
88
+ opacity?: number;
89
+ /** Expansion duration in seconds. Default `0.55`. */
90
+ duration?: number;
91
+ /** Additional seconds the fade continues past the expansion. Default `0.25`. */
92
+ fadeDuration?: number;
93
+ easing?: EasingInput;
94
+ /** Always start from the element's centre rather than the contact point. Default `false`. */
95
+ centered?: boolean;
96
+ /** Trigger on keyboard activation (Enter/Space) as well as pointer. Default `true`. */
97
+ keyboard?: boolean;
98
+ /** Maximum simultaneous ripples. Older ones are removed beyond this. Default `6`. */
99
+ maxRipples?: number;
100
+ }
101
+ declare const ripple: BehaviourDefinition<RippleOptions, HTMLElement>;
102
+
103
+ /**
104
+ * Parallax — elements that move at a different rate from the scroll.
105
+ *
106
+ * Parallax has a bad reputation, and mostly it is deserved: it is the effect most likely to
107
+ * cause motion sickness, and the most commonly implemented by reading
108
+ * `getBoundingClientRect()` in a `scroll` handler — which forces a synchronous layout on every
109
+ * scroll event and is the single most common cause of janky scrolling on the web.
110
+ *
111
+ * Two structural fixes here:
112
+ *
113
+ * **All measurement happens in the ticker's `read` phase, all writes in `write`.** The scroll
114
+ * handler does nothing at all; scroll position is sampled once per frame. Fifty parallax elements
115
+ * therefore cost one layout read per frame between them, not fifty per event.
116
+ *
117
+ * **The element's own document position is cached and only re-measured on resize.** Scrolling
118
+ * does not change where an element sits in the document, so re-measuring per frame is pure waste.
119
+ */
120
+ interface ParallaxOptions extends BaseBehaviourOptions {
121
+ /**
122
+ * Movement rate relative to the scroll.
123
+ *
124
+ * `0` is fixed to the page (no parallax). `0.3` moves at 30% of scroll speed — the element
125
+ * appears further away. Negative values move against the scroll, appearing nearer.
126
+ * Values beyond ±0.5 read as broken rather than deep. Default `0.3`.
127
+ */
128
+ speed?: number;
129
+ /** Axis to translate along. Default `'y'`. */
130
+ axis?: 'y' | 'x';
131
+ /** Also scale as the element passes through. `1` disables. Default `1`. */
132
+ scale?: number;
133
+ /** Also rotate as the element passes through, in degrees. Default `0`. */
134
+ rotate?: number;
135
+ /** Also fade. `[enterOpacity, centreOpacity, exitOpacity]`. Default no fade. */
136
+ fade?: readonly [number, number, number];
137
+ /**
138
+ * Clamp the translation so the element cannot leave its own container.
139
+ *
140
+ * Strongly recommended for background images inside a fixed-height section: without it, a
141
+ * parallax image reveals the empty space behind it at the extremes. Default `true`.
142
+ */
143
+ contain?: boolean;
144
+ /** Smoothing applied to the parallax position, in `[0, 1)`. `0` tracks scroll exactly. Default `0`. */
145
+ smoothing?: number;
146
+ }
147
+ declare const parallax: BehaviourDefinition<ParallaxOptions, HTMLElement>;
148
+
149
+ /**
150
+ * Stagger — the per-element delay that turns N simultaneous animations into a sequence.
151
+ *
152
+ * The reason this deserves its own module rather than being `index * 0.05`: *where* the wave
153
+ * originates changes what the motion communicates. A list that reveals from the top reads as
154
+ * "loading in order". The same list revealing from the item the user clicked reads as
155
+ * "responding to you". Getting the origin right is most of the craft in orchestration.
156
+ */
157
+ /**
158
+ * Where the stagger wave begins.
159
+ *
160
+ * - `'first'` — index 0 goes first. The default; reads as natural reading order.
161
+ * - `'last'` — reversed. Useful for exits, so the last thing in stays longest.
162
+ * - `'center'` — radiates outward from the middle. Good for symmetric layouts and hero content.
163
+ * - `'edges'` — converges inward from both ends. Reads as "gathering".
164
+ * - a number — a specific index. Pass the index the user interacted with.
165
+ */
166
+ type StaggerFrom = 'first' | 'last' | 'center' | 'edges' | number;
167
+ interface StaggerOptions {
168
+ /** Seconds between consecutive elements. Default `0.05`. */
169
+ each?: number;
170
+ /**
171
+ * Total seconds the whole wave should span. Overrides `each` when set — the more useful knob
172
+ * for "reveal these however many items there are in 400ms".
173
+ */
174
+ total?: number;
175
+ from?: StaggerFrom;
176
+ /**
177
+ * Easing applied to the *distribution* of delays, not to each animation.
178
+ *
179
+ * `easeOutQuad` bunches later elements closer together, so a long list accelerates rather
180
+ * than plodding at a constant rate — the difference between 40 items feeling fast and
181
+ * feeling interminable.
182
+ */
183
+ easing?: EasingInput;
184
+ /** Base delay added to every element. Default `0`. */
185
+ delay?: number;
186
+ /**
187
+ * For grid layouts: `[columns, rows]`. Distance is then measured in 2D, so `from: 'center'`
188
+ * radiates as a circle rather than along a single index axis.
189
+ */
190
+ grid?: readonly [number, number];
191
+ /** Which axis to measure along in a grid. `undefined` uses true 2D distance. */
192
+ axis?: 'x' | 'y';
193
+ }
194
+ /**
195
+ * Build a delay function for a set of `count` elements.
196
+ *
197
+ * @returns `(index) => delayInSeconds`
198
+ */
199
+ declare function stagger(count: number, options?: StaggerOptions): (index: number) => number;
200
+ /**
201
+ * Total wall-clock time a staggered set will take.
202
+ *
203
+ * Needed so a timeline can place whatever comes *after* a staggered group without the author
204
+ * having to work out `count × each + duration` themselves.
205
+ */
206
+ declare function staggerDuration(count: number, itemDuration: number, options?: StaggerOptions): number;
207
+
208
+ /**
209
+ * Scroll Reveal — animate elements in as they enter the viewport.
210
+ *
211
+ * The critical correctness requirement is **SSR and no-JS safety**. The common implementation
212
+ * sets `opacity: 0` in CSS and removes it with JavaScript, which means that if JavaScript fails
213
+ * to load, is blocked, or throws before this runs, the content is permanently invisible. That has
214
+ * shipped to production on a lot of marketing sites.
215
+ *
216
+ * So: the initial hidden state is applied *by this behaviour, in JavaScript*, immediately on
217
+ * setup. If the script never runs, the content is simply visible — degraded but correct. This is
218
+ * the only defensible default for content the user came to read.
219
+ *
220
+ * The reveal itself runs on the shared ticker rather than a CSS transition, so a staggered group
221
+ * shares one clock and cannot drift, and so `prefers-reduced-motion` is handled in one place.
222
+ */
223
+ interface ScrollRevealOptions extends BaseBehaviourOptions {
224
+ /** Distance in pixels the element travels into place. Default `24`. */
225
+ distance?: number;
226
+ /** Direction the element travels *from*. Default `'up'` (enters moving upward). */
227
+ direction?: 'up' | 'down' | 'left' | 'right' | 'none';
228
+ /** Starting opacity. Default `0`. */
229
+ opacity?: number;
230
+ /** Starting scale. `1` disables scaling. Default `1`. */
231
+ scale?: number;
232
+ /** Starting rotation in degrees. Default `0`. */
233
+ rotate?: number;
234
+ /** Starting blur in pixels. Default `0`. */
235
+ blur?: number;
236
+ /** Duration in seconds. Default `0.7`. */
237
+ duration?: number;
238
+ easing?: EasingInput;
239
+ /** Seconds to wait after entering the viewport. Default `0`. */
240
+ delay?: number;
241
+ /** Fraction of the element that must be visible to trigger, in `[0, 1]`. Default `0.15`. */
242
+ threshold?: number;
243
+ /** Extra margin around the viewport, as a CSS margin string. Default `'0px 0px -10% 0px'`. */
244
+ rootMargin?: string;
245
+ /** Reverse the animation when the element leaves the viewport. Default `false`. */
246
+ repeat?: boolean;
247
+ /**
248
+ * Selector for descendants to reveal individually rather than the host itself.
249
+ * When set, the host stays untouched and its matching descendants are staggered.
250
+ *
251
+ * Named `selector`, not `children`. The framework bindings spread these options onto a
252
+ * component's props, where `children` means the rendered subtree — a `children: string` option
253
+ * silently narrows the component's real `children` to `string`, making `<ScrollReveal><p/></ScrollReveal>`
254
+ * a type error with an unreadable message. The collision is invisible in the engine and only
255
+ * surfaces at the binding layer.
256
+ */
257
+ selector?: string;
258
+ /** Stagger configuration when `selector` is set. */
259
+ stagger?: StaggerOptions;
260
+ }
261
+ declare const scrollReveal: BehaviourDefinition<ScrollRevealOptions, HTMLElement>;
262
+
263
+ type SplitUnit = 'chars' | 'words' | 'lines';
264
+ interface SplitTextOptions extends BaseBehaviourOptions {
265
+ /**
266
+ * What to split into. `'lines'` requires a layout measurement pass and re-splits on resize,
267
+ * so it is more expensive — but it is the only way to animate by visual line.
268
+ */
269
+ by?: SplitUnit | readonly SplitUnit[];
270
+ /** Class applied to character spans. Default `'ansh-char'`. */
271
+ charClass?: string;
272
+ /** Class applied to word spans. Default `'ansh-word'`. */
273
+ wordClass?: string;
274
+ /** Class applied to line spans. Default `'ansh-line'`. */
275
+ lineClass?: string;
276
+ /**
277
+ * Set `--ansh-index` and `--ansh-total` custom properties on each unit.
278
+ *
279
+ * This is what lets a pure-CSS stagger work: `animation-delay: calc(var(--ansh-index) * 40ms)`.
280
+ * Default `true`.
281
+ */
282
+ cssVariables?: boolean;
283
+ /** Wrap each unit in an extra element with `overflow: hidden`, for mask-reveal animations. */
284
+ mask?: boolean;
285
+ }
286
+ interface SplitTextResult {
287
+ chars: HTMLElement[];
288
+ words: HTMLElement[];
289
+ lines: HTMLElement[];
290
+ }
291
+ /** Read the split result for an element, if it has been split. */
292
+ declare function getSplitResult(element: HTMLElement): SplitTextResult | undefined;
293
+ declare const splitText: BehaviourDefinition<SplitTextOptions, HTMLElement>;
294
+ /**
295
+ * Split text imperatively, outside the behaviour lifecycle.
296
+ *
297
+ * Returns the produced elements plus a `restore` function. Framework bindings use the behaviour;
298
+ * this is for one-off use in vanilla JS and in tests.
299
+ */
300
+ declare function split(element: HTMLElement, options?: Partial<SplitTextOptions>): SplitTextResult & {
301
+ restore(): void;
302
+ };
303
+
304
+ /**
305
+ * Marquee — seamless infinite scrolling content.
306
+ *
307
+ * The CSS-only approach (`animation: scroll linear infinite` on a duplicated track) has three
308
+ * problems this solves:
309
+ *
310
+ * 1. **The seam.** A CSS marquee animates `translateX` from `0` to `-50%` on a doubled track. If
311
+ * the content doesn't exactly fill the container, there is a visible gap or overlap at the
312
+ * wrap point. Here the track is duplicated as many times as needed to exceed the container
313
+ * width, and the wrap distance is the measured width of *one* copy — so it is always exact.
314
+ *
315
+ * 2. **Speed is expressed in duration, not velocity.** A CSS duration means a marquee with more
316
+ * items scrolls faster, so adding a logo to a customer strip changes the animation speed. Here
317
+ * speed is pixels per second, which is what an author actually means.
318
+ *
319
+ * 3. **Pause on hover can't be smooth.** Toggling `animation-play-state` stops dead. This eases
320
+ * the velocity to zero, which reads as deliberate rather than broken.
321
+ */
322
+ interface MarqueeOptions extends BaseBehaviourOptions {
323
+ /** Scroll speed in pixels per second. Negative reverses. Default `60`. */
324
+ speed?: number;
325
+ /** Scroll direction. Default `'left'`. */
326
+ direction?: 'left' | 'right' | 'up' | 'down';
327
+ /** Ease to a stop while the pointer is over the marquee. Default `true`. */
328
+ pauseOnHover?: boolean;
329
+ /** Seconds to ease in and out of a pause. Default `0.4`. */
330
+ pauseEasing?: number;
331
+ /** Gap between repeated copies, in pixels. Default `0` — use CSS `gap` on the track instead. */
332
+ gap?: number;
333
+ /** Fade the edges with a mask, in pixels. `0` disables. Default `0`. */
334
+ fadeEdges?: number;
335
+ }
336
+ declare const marquee: BehaviourDefinition<MarqueeOptions, HTMLElement>;
337
+
338
+ /**
339
+ * Tilt — 3D perspective rotation following the pointer.
340
+ *
341
+ * The single most common mistake in tilt implementations is putting `perspective` on the element
342
+ * being rotated. CSS `perspective` on an element applies to its *children*, so tilting the same
343
+ * element that carries the perspective produces a flat, sheared result rather than a 3D one. The
344
+ * perspective must live on the parent, or be baked into the transform via `perspective()` as its
345
+ * **first** function — which is what this does, so no wrapper element is required.
346
+ *
347
+ * The second mistake is omitting the glare. A card that rotates without its highlight moving
348
+ * reads as a flat image being turned, because the brain expects specular reflection to shift.
349
+ * The optional glare layer is what makes it read as a physical surface.
350
+ */
351
+ interface TiltOptions extends BaseBehaviourOptions {
352
+ /** Maximum rotation in degrees on each axis. Default `10`. */
353
+ max?: number;
354
+ /** Perspective distance in pixels. Lower is a more extreme effect. Default `900`. */
355
+ perspective?: number;
356
+ /** Scale applied while hovering. Default `1.02`. */
357
+ scale?: number;
358
+ /** Spring stiffness. Default `180`. */
359
+ stiffness?: number;
360
+ /** Spring damping. Default `22`. */
361
+ damping?: number;
362
+ /** Invert the rotation direction. Default `false`. */
363
+ reverse?: boolean;
364
+ /** Lift the element toward the viewer in pixels while hovering. Default `0`. */
365
+ lift?: number;
366
+ /** Add a moving specular highlight. Default `true`. */
367
+ glare?: boolean;
368
+ /** Glare opacity at maximum, in `[0, 1]`. Default `0.18`. */
369
+ glareOpacity?: number;
370
+ /** Restrict rotation to one axis. Default `'both'`. */
371
+ axis?: 'both' | 'x' | 'y';
372
+ }
373
+ declare const tilt: BehaviourDefinition<TiltOptions, HTMLElement>;
374
+
375
+ /**
376
+ * Magnetic — an element that leans toward the pointer.
377
+ *
378
+ * Deceptively subtle to get right. Three things separate a magnetic button that feels expensive
379
+ * from one that feels broken:
380
+ *
381
+ * 1. **The pull must be spring-driven, not proportional.** Setting
382
+ * `translate = pointerOffset * 0.2` means the element is rigidly locked to the cursor with no
383
+ * weight. A spring gives it mass, so it lags into position and overshoots slightly on release.
384
+ *
385
+ * 2. **The influence zone must extend beyond the element.** If the effect only starts on hover,
386
+ * the element jumps the instant the cursor crosses its edge. Tracking from a surrounding
387
+ * radius means it is already reaching toward the cursor before contact.
388
+ *
389
+ * 3. **Displacement must be capped, not just scaled.** Otherwise a cursor at the far edge of a
390
+ * large influence zone drags the element clean out of its layout box.
391
+ */
392
+ interface MagneticOptions extends BaseBehaviourOptions {
393
+ /** Maximum displacement in pixels. Default `12`. */
394
+ strength?: number;
395
+ /**
396
+ * Radius in pixels around the element within which the pointer has influence.
397
+ * Measured from the element's edges, not its centre. Default `120`.
398
+ */
399
+ radius?: number;
400
+ /** Spring stiffness. Higher is snappier. Default `260`. */
401
+ stiffness?: number;
402
+ /** Spring damping. Higher settles sooner. Default `24`. */
403
+ damping?: number;
404
+ /** Also scale the element on approach. `1.04` is a 4% grow. Default `1`. */
405
+ scale?: number;
406
+ /** Also rotate toward the pointer, in degrees at maximum displacement. Default `0`. */
407
+ rotate?: number;
408
+ /** Restrict movement to one axis. Default `'both'`. */
409
+ axis?: 'both' | 'x' | 'y';
410
+ /**
411
+ * Apply the transform to a child element instead of the host.
412
+ *
413
+ * Useful when the host must stay put for layout or hit-testing reasons — a nav link whose
414
+ * text should lean but whose click target should not move.
415
+ */
416
+ target?: string;
417
+ }
418
+ declare const magnetic: BehaviourDefinition<MagneticOptions, HTMLElement>;
419
+
420
+ /**
421
+ * Every built-in behaviour, keyed by name. Used by the CLI and docs site for discovery.
422
+ * Import individual behaviours in application code so the rest tree-shake away.
423
+ */
424
+ declare const behaviours: {
425
+ readonly magnetic: BehaviourDefinition<MagneticOptions, HTMLElement>;
426
+ readonly tilt: BehaviourDefinition<TiltOptions, HTMLElement>;
427
+ readonly marquee: BehaviourDefinition<MarqueeOptions, HTMLElement>;
428
+ readonly 'split-text': BehaviourDefinition<SplitTextOptions, HTMLElement>;
429
+ readonly 'scroll-reveal': BehaviourDefinition<ScrollRevealOptions, HTMLElement>;
430
+ readonly parallax: BehaviourDefinition<ParallaxOptions, HTMLElement>;
431
+ readonly ripple: BehaviourDefinition<RippleOptions, HTMLElement>;
432
+ };
433
+ type BehaviourName = keyof typeof behaviours;
434
+
435
+ export { type BaseBehaviourOptions as B, type MagneticOptions as M, type ParallaxOptions as P, type RippleOptions as R, type StaggerOptions as S, type TiltOptions as T, type BehaviourDefinition as a, type BehaviourHandle as b, type BehaviourInstance as c, type BehaviourName as d, type MarqueeOptions as e, type ScrollRevealOptions as f, type SplitTextOptions as g, type SplitTextResult as h, type SplitUnit as i, type StaggerFrom as j, behaviours as k, captureStyles as l, defineBehaviour as m, getSplitResult as n, magnetic as o, marquee as p, mountBehaviour as q, parallax as r, ripple as s, scrollReveal as t, split as u, splitText as v, stagger as w, staggerDuration as x, tilt as y };