kuinetic 0.1.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 (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +99 -0
  3. package/dist/esm/chunk-LWS4OSLX.mjs +730 -0
  4. package/dist/esm/chunk-QZIJ7WZI.mjs +3312 -0
  5. package/dist/esm/chunk-R3TGDJKA.mjs +1264 -0
  6. package/dist/esm/core/index.mjs +34 -0
  7. package/dist/esm/effects/index.mjs +27 -0
  8. package/dist/esm/index.mjs +52 -0
  9. package/dist/kuinetic.all.js +5291 -0
  10. package/dist/kuinetic.css +2338 -0
  11. package/dist/kuinetic.js +5281 -0
  12. package/dist/types/core/activation.d.ts +21 -0
  13. package/dist/types/core/animator.d.ts +216 -0
  14. package/dist/types/core/attrs.d.ts +15 -0
  15. package/dist/types/core/capabilities.d.ts +19 -0
  16. package/dist/types/core/channels.d.ts +25 -0
  17. package/dist/types/core/compile.d.ts +49 -0
  18. package/dist/types/core/dom-watcher.d.ts +35 -0
  19. package/dist/types/core/effect-context.d.ts +49 -0
  20. package/dist/types/core/element-config.d.ts +52 -0
  21. package/dist/types/core/flip.d.ts +80 -0
  22. package/dist/types/core/gesture.d.ts +99 -0
  23. package/dist/types/core/index.d.ts +14 -0
  24. package/dist/types/core/instances.d.ts +98 -0
  25. package/dist/types/core/js-effect-preparer.d.ts +46 -0
  26. package/dist/types/core/js-params.d.ts +124 -0
  27. package/dist/types/core/owned-styles.d.ts +44 -0
  28. package/dist/types/core/params.d.ts +65 -0
  29. package/dist/types/core/parse.d.ts +22 -0
  30. package/dist/types/core/path-morph.d.ts +83 -0
  31. package/dist/types/core/play.d.ts +48 -0
  32. package/dist/types/core/registry.d.ts +38 -0
  33. package/dist/types/core/reporter.d.ts +35 -0
  34. package/dist/types/core/scroll-scheduler.d.ts +153 -0
  35. package/dist/types/core/spring.d.ts +83 -0
  36. package/dist/types/core/stagger.d.ts +19 -0
  37. package/dist/types/core/style-plan.d.ts +56 -0
  38. package/dist/types/core/types.d.ts +239 -0
  39. package/dist/types/effects/catalog/ambient.d.ts +18 -0
  40. package/dist/types/effects/catalog/core.d.ts +19 -0
  41. package/dist/types/effects/catalog/feedback.d.ts +21 -0
  42. package/dist/types/effects/catalog/index.d.ts +21 -0
  43. package/dist/types/effects/catalog/interaction-shared.d.ts +56 -0
  44. package/dist/types/effects/catalog/interaction.d.ts +22 -0
  45. package/dist/types/effects/catalog/media.d.ts +13 -0
  46. package/dist/types/effects/catalog/numbers-shared.d.ts +103 -0
  47. package/dist/types/effects/catalog/numbers.d.ts +31 -0
  48. package/dist/types/effects/catalog/shared.d.ts +3 -0
  49. package/dist/types/effects/catalog/text-shared.d.ts +180 -0
  50. package/dist/types/effects/catalog/text.d.ts +17 -0
  51. package/dist/types/effects/forms/index.d.ts +14 -0
  52. package/dist/types/effects/forms/primitives.d.ts +32 -0
  53. package/dist/types/effects/gestures/index.d.ts +19 -0
  54. package/dist/types/effects/gestures/primitives.d.ts +2 -0
  55. package/dist/types/effects/index.d.ts +19 -0
  56. package/dist/types/effects/layout/index.d.ts +12 -0
  57. package/dist/types/effects/layout/presets.d.ts +9 -0
  58. package/dist/types/effects/layout/primitives.d.ts +2 -0
  59. package/dist/types/effects/navigation/index.d.ts +30 -0
  60. package/dist/types/effects/scroll-mechanics/index.d.ts +14 -0
  61. package/dist/types/effects/scroll-mechanics/presets.d.ts +6 -0
  62. package/dist/types/effects/scroll-mechanics/primitives.d.ts +2 -0
  63. package/dist/types/effects/scroll-mechanics/tracker.d.ts +55 -0
  64. package/dist/types/effects/shared.d.ts +26 -0
  65. package/dist/types/effects/svg/index.d.ts +13 -0
  66. package/dist/types/effects/three-d/index.d.ts +20 -0
  67. package/dist/types/index.d.ts +16 -0
  68. package/package.json +78 -0
@@ -0,0 +1,153 @@
1
+ import type { Cleanup } from './types.js';
2
+ /**
3
+ * Shared scroll orchestration.
4
+ *
5
+ * "Zero scroll listeners" is a property of *native timeline* effects and does not survive contact
6
+ * with pinning, scrubbing, or spying — those need the scroll position as a number. The correct
7
+ * architecture is the one docs/design.md §13 names: one passive listener per scroll root that
8
+ * marks a shared scheduler dirty, and exactly one rAF callback per dirtied frame. An
9
+ * always-running rAF loop is the thing being avoided, not the listener.
10
+ *
11
+ * Every collaborator is injected. The frame source, the scroll roots, and the scrollability test
12
+ * are all parameters, so the whole module is drivable from tests with no layout, no timers, and
13
+ * no real scrolling.
14
+ */
15
+ /** What a scroll root reports each frame. One read per root, shared by all its subscribers. */
16
+ export interface ScrollMetrics {
17
+ scrollTop: number;
18
+ scrollLeft: number;
19
+ /** Visible size of the root's scrollport. */
20
+ viewportWidth: number;
21
+ viewportHeight: number;
22
+ /**
23
+ * Position of the scrollport itself in the viewport. Zero for the window.
24
+ *
25
+ * Without this, a subscriber measuring an element with `getBoundingClientRect` — which is
26
+ * viewport-relative — and subtracting a nested scroller's `scrollTop` — which is local to that
27
+ * scroller — mixes two coordinate systems, and every nested progress value is wrong by the
28
+ * scroller's own offset.
29
+ */
30
+ viewportTop: number;
31
+ viewportLeft: number;
32
+ }
33
+ /**
34
+ * A scrollable context. The window is one; any `overflow: auto` element is another.
35
+ *
36
+ * `key` identifies the root for deduplication: two effects inside the same scroller must share a
37
+ * listener, or a page with 200 pinned elements installs 200 listeners.
38
+ */
39
+ export interface ScrollRoot {
40
+ key: string;
41
+ metrics(): ScrollMetrics;
42
+ /** Attach a passive scroll listener. Returns its own removal. */
43
+ onScroll(handler: () => void): Cleanup;
44
+ /** Attach a resize listener. Resize invalidates cached measurements, so it bumps the epoch. */
45
+ onResize(handler: () => void): Cleanup;
46
+ }
47
+ export interface ScrollFrame {
48
+ metrics: ScrollMetrics;
49
+ /**
50
+ * Increments whenever something invalidated cached geometry. Subscribers cache measurements
51
+ * against this number instead of re-measuring every frame, which is what keeps a scroll frame
52
+ * off the layout path.
53
+ */
54
+ epoch: number;
55
+ }
56
+ export type ScrollSubscriber = (frame: ScrollFrame) => void;
57
+ export interface SchedulerDeps {
58
+ requestFrame(callback: () => void): number;
59
+ cancelFrame(handle: number): void;
60
+ }
61
+ export interface ScrollScheduler {
62
+ /**
63
+ * Receive a frame whenever `root` scrolls or resizes, plus one immediately-scheduled frame so a
64
+ * subscriber never has to wait for user input to reach its initial state.
65
+ */
66
+ subscribe(root: ScrollRoot, onFrame: ScrollSubscriber): Cleanup;
67
+ /** Bump the epoch and schedule a frame, for layout changes the scheduler cannot observe. */
68
+ invalidate(): void;
69
+ /** Live root count. Diagnostics and leak assertions. */
70
+ rootCount(): number;
71
+ destroy(): void;
72
+ }
73
+ /**
74
+ * Create a scroll scheduler.
75
+ *
76
+ * @param deps - Frame source. Defaults to `requestAnimationFrame`, falling back to a timer where
77
+ * rAF does not exist (jsdom, workers).
78
+ * @returns A scheduler that runs at most one frame per dirtying event.
79
+ * @complexity O(s) time per frame in subscribers of dirtied roots; O(r + s) space.
80
+ * @overallScore 100
81
+ */
82
+ export declare function createScrollScheduler(deps?: SchedulerDeps): ScrollScheduler;
83
+ /**
84
+ * The window as a scroll root.
85
+ *
86
+ * @param win - Window to observe. Passed in so iframes, test doubles, and multiple documents work.
87
+ * @complexity O(1) time and space.
88
+ * @overallScore 100
89
+ */
90
+ export declare function windowScrollRoot(win: Window): ScrollRoot;
91
+ /**
92
+ * An `overflow: auto` element as a scroll root.
93
+ *
94
+ * Nested scroll containers are a first-class case, not an edge case: a pinned element inside a
95
+ * modal or a horizontally scrolled track must track *its* scroller, not the page.
96
+ *
97
+ * @param el - The scrolling element.
98
+ * @param win - Window used for resize notification; element resize alone does not cover viewport
99
+ * changes that alter the element's own box.
100
+ * @complexity O(1) time and space.
101
+ * @overallScore 100
102
+ */
103
+ export declare function elementScrollRoot(el: Element, win: Window): ScrollRoot;
104
+ export interface RootResolverOptions {
105
+ win: Window;
106
+ /** Injected so the overflow test is fakeable; the default reads computed style. */
107
+ isScrollable?: (el: Element) => boolean;
108
+ }
109
+ /**
110
+ * Find the scroll root that actually moves a given element.
111
+ *
112
+ * @param options - Window plus an optional scrollability predicate.
113
+ * @returns A resolver returning the nearest scrollable ancestor, or the window root.
114
+ * @complexity O(d) time in DOM depth per call; O(1) space.
115
+ * @overallScore 100
116
+ */
117
+ export declare function createRootResolver(options: RootResolverOptions): (el: Element) => ScrollRoot;
118
+ /**
119
+ * Clamp to the unit interval.
120
+ *
121
+ * @complexity O(1) time and space.
122
+ * @overallScore 100
123
+ */
124
+ export declare function clamp01(value: number): number;
125
+ /**
126
+ * Progress of `position` through the range `[start, end]`, clamped.
127
+ *
128
+ * A zero-length range is the degenerate case that matters: an element shorter than its own pin
129
+ * distance, or a track no wider than its viewport. Returning 0 rather than `Infinity`/`NaN` keeps
130
+ * every downstream write finite.
131
+ *
132
+ * @complexity O(1) time and space.
133
+ * @overallScore 100
134
+ */
135
+ export declare function progressBetween(start: number, end: number, position: number): number;
136
+ export interface MeasureCache<T> {
137
+ /** Measured value for this epoch, re-measuring only when the epoch moved. */
138
+ read(epoch: number): T;
139
+ clear(): void;
140
+ }
141
+ /**
142
+ * Memoise a measurement against the scheduler's epoch.
143
+ *
144
+ * This is what makes a scroll frame cheap: geometry is read once per resize, not once per frame.
145
+ * Getting this wrong is the difference between a pinned page that scrolls at 60fps and one that
146
+ * forces a full layout on every wheel tick.
147
+ *
148
+ * @param measure - The layout-reading function to memoise.
149
+ * @returns A cache keyed on epoch.
150
+ * @complexity O(1) amortised per read; O(1) space.
151
+ * @overallScore 100
152
+ */
153
+ export declare function createMeasureCache<T>(measure: () => T): MeasureCache<T>;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Spring integration.
3
+ *
4
+ * Gestures need physics rather than easing curves: when a user throws an element, the animation
5
+ * has to start at whatever velocity their finger had, and no duration-plus-easing formulation can
6
+ * express that. A spring is the smallest model that can — it takes an initial velocity and
7
+ * settles on its own.
8
+ *
9
+ * The integrator is a pure function of `(state, target, config, dt)`, so the whole model is
10
+ * assertable without timers, rAF, or a DOM.
11
+ */
12
+ export interface SpringConfig {
13
+ /** Higher pulls harder toward the target. */
14
+ stiffness: number;
15
+ /** Higher removes energy faster. Critical damping is `2 * sqrt(stiffness * mass)`. */
16
+ damping: number;
17
+ mass: number;
18
+ /** Settled when both velocity and displacement fall below these. */
19
+ restVelocity: number;
20
+ restDisplacement: number;
21
+ }
22
+ export interface SpringState {
23
+ value: number;
24
+ velocity: number;
25
+ }
26
+ export declare const DEFAULT_SPRING: SpringConfig;
27
+ /**
28
+ * Advance a spring toward `target`.
29
+ *
30
+ * @param state - Current value and velocity.
31
+ * @param target - Value the spring is pulling toward.
32
+ * @param config - Stiffness, damping, mass, and rest thresholds.
33
+ * @param dt - Elapsed seconds since the last step.
34
+ * @returns The new state; input is not mutated.
35
+ * @complexity O(dt / SUBSTEP) time, bounded by MAX_STEP; O(1) space.
36
+ * @overallScore 100
37
+ */
38
+ export declare function stepSpring(state: SpringState, target: number, config: SpringConfig, dt: number): SpringState;
39
+ /**
40
+ * Whether a spring has settled.
41
+ *
42
+ * Both conditions are required: a spring passing through its target at speed has zero
43
+ * displacement but is nowhere near done.
44
+ *
45
+ * @complexity O(1) time and space.
46
+ * @overallScore 100
47
+ */
48
+ export declare function isSettled(state: SpringState, target: number, config: SpringConfig): boolean;
49
+ export interface SpringDeps {
50
+ requestFrame(callback: (time: number) => void): number;
51
+ cancelFrame(handle: number): void;
52
+ now(): number;
53
+ warn?(message: string): void;
54
+ }
55
+ export interface SpringRunner {
56
+ /** Retarget without losing velocity — an interrupted spring stays continuous. */
57
+ to(target: number, velocity?: number): void;
58
+ /** Adopt a position and velocity directly, e.g. from a drag in progress. */
59
+ set(value: number, velocity?: number): void;
60
+ current(): SpringState;
61
+ stop(): void;
62
+ }
63
+ /**
64
+ * Drive a spring with a frame loop, calling `onChange` with each new value.
65
+ *
66
+ * The loop runs only while the spring is moving and stops itself on settle — an always-running
67
+ * rAF is exactly what the rest of this library avoids.
68
+ *
69
+ * @param config - Spring constants.
70
+ * @param onChange - Receives each integrated value, plus `true` on the final settled frame.
71
+ * @param deps - Frame source and clock; injected so tests can step time by hand.
72
+ * @returns A runner exposing retarget, adopt, read, and stop.
73
+ * @complexity O(1) per frame; O(1) space.
74
+ * @overallScore 100
75
+ */
76
+ export declare function createSpringRunner(config: SpringConfig, onChange: (value: number, settled: boolean) => void, deps: SpringDeps): SpringRunner;
77
+ /**
78
+ * Frame source defaults, kept at the construction boundary so no logic below reads a global.
79
+ *
80
+ * @complexity O(1) time and space.
81
+ * @overallScore 100
82
+ */
83
+ export declare function defaultSpringDeps(): SpringDeps;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Index the animated children of one stagger group.
3
+ *
4
+ * Only the index is written; the offset arithmetic stays in the CSS `calc()` so the browser
5
+ * applies it, rather than JS recomputing a delay per element.
6
+ *
7
+ * @param group - Element carrying `data-kui-stagger`.
8
+ * @complexity O(n) time in the number of children; O(1) extra space.
9
+ * @overallScore 100
10
+ */
11
+ export declare function indexStaggerGroup(group: Element): void;
12
+ /**
13
+ * Index every stagger group in a subtree, including the root itself.
14
+ *
15
+ * @param root - Subtree to search.
16
+ * @complexity O(n) time in the number of elements in the subtree; O(g) space in group count.
17
+ * @overallScore 100
18
+ */
19
+ export declare function applyStagger(root: ParentNode): void;
@@ -0,0 +1,56 @@
1
+ import type { Capabilities } from './capabilities.js';
2
+ import type { CompiledPlan } from './compile.js';
3
+ import type { ElementConfig } from './element-config.js';
4
+ import type { AttributeLedger, StyleLedger } from './owned-styles.js';
5
+ import type { Activation } from './types.js';
6
+ /**
7
+ * How the animation is started.
8
+ *
9
+ * - `native-timeline` — a scroll/view timeline drives progress; nothing to start.
10
+ * - `immediate` — runs as soon as it is applied.
11
+ * - `deferred` — held at its from-state until an activation fires.
12
+ */
13
+ export type Gate = 'native-timeline' | 'immediate' | 'deferred';
14
+ export interface StylePlan {
15
+ /** Custom properties and animation longhands to write, in application order. */
16
+ properties: Record<string, string>;
17
+ /** Attributes to stamp. */
18
+ attributes: Record<string, string>;
19
+ gate: Gate;
20
+ /** Activation to bind; `null` when the gate does not need one. */
21
+ activation: Activation | null;
22
+ }
23
+ export interface StylePlanInput {
24
+ plan: CompiledPlan;
25
+ config: ElementConfig;
26
+ capabilities: Capabilities;
27
+ /** Whether the reduced-motion preference should be honoured. */
28
+ respectReducedMotion: boolean;
29
+ }
30
+ /**
31
+ * Decide every style write for one element — a pure function returning a description of the
32
+ * writes rather than performing them.
33
+ *
34
+ * This is the decision half of the decision/effect split: it can be asserted with plain objects
35
+ * and no DOM, which is what keeps `applyStylePlan` trivial enough to need no branching tests.
36
+ *
37
+ * @param input - Compiled effects, element configuration, and the environment's capabilities.
38
+ * @returns The properties, attributes, gate, and activation to apply.
39
+ * @complexity O(n) time in the number of compiled declarations; O(n) space for the result.
40
+ * @overallScore 100
41
+ */
42
+ export declare function planStyles(input: StylePlanInput): StylePlan;
43
+ /**
44
+ * Write a style plan to an element. The effect half of the split — deliberately branch-free.
45
+ *
46
+ * @param el - Target element.
47
+ * @param plan - Description produced by `planStyles`.
48
+ * @complexity O(n) time in the number of properties and attributes; O(1) extra space.
49
+ * @overallScore 100
50
+ */
51
+ export declare function applyStylePlan(request: {
52
+ el: Element;
53
+ plan: StylePlan;
54
+ ledger: StyleLedger;
55
+ attributes: AttributeLedger;
56
+ }): void;
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Core type model.
3
+ *
4
+ * The four questions that the earlier `Tier` enum wrongly collapsed into one axis are kept
5
+ * orthogonal here:
6
+ * - `renderer` — who produces the frame
7
+ * - `Activation` — what starts it
8
+ * - `Timeline` — what drives progress
9
+ * - `prepare` — whether DOM surgery is required first
10
+ * A `css-keyframes` effect can still need observer activation; a `prepare`d effect (split-text)
11
+ * can render through CSS afterwards. See docs/design.md §6.
12
+ */
13
+ /**
14
+ * A CSS property group an effect writes to. Two effects may only be composed in one
15
+ * `data-kui` list when their channel sets are disjoint — see `core/channels.ts`.
16
+ *
17
+ * `translate` / `rotate` / `scale` are separate channels because they are independent CSS
18
+ * properties in modern browsers. Under the old `transform` shorthand they would all have
19
+ * collided and this composition model would be impossible.
20
+ */
21
+ export declare const CHANNEL: {
22
+ readonly opacity: "opacity";
23
+ readonly translate: "translate";
24
+ readonly scale: "scale";
25
+ readonly rotate: "rotate";
26
+ readonly filter: "filter";
27
+ readonly clip: "clip";
28
+ readonly background: "background";
29
+ readonly color: "color";
30
+ readonly stroke: "stroke";
31
+ readonly text: "text";
32
+ };
33
+ /**
34
+ * A CSS property group an effect writes to. Two effects may only be composed in one `data-kui`
35
+ * list when their channel sets are disjoint — see `core/channels.ts`.
36
+ *
37
+ * `translate` / `rotate` / `scale` are separate channels because they are independent CSS
38
+ * properties in modern browsers. Under the old `transform` shorthand they would all collide and
39
+ * this composition model would be impossible.
40
+ *
41
+ * The open `string` arm is deliberate: third-party primitives register their own channels, so
42
+ * the union documents the built-ins without closing the set.
43
+ */
44
+ export type Channel = (typeof CHANNEL)[keyof typeof CHANNEL] | (string & {});
45
+ /** What starts the animation. Distinct from — and never a substitute for — a Timeline. */
46
+ export type Activation = 'load' | 'enter' | 'hover' | 'focus' | 'click' | 'manual';
47
+ /**
48
+ * What drives progress.
49
+ *
50
+ * `time` runs a clock. `view` / `scroll` map progress continuously to scroll position and so
51
+ * *reverse when the user scrolls back*, which a time-based reveal does not. These are different
52
+ * animation models, not fallbacks for each other. See docs/design.md §5.
53
+ */
54
+ export type Timeline = 'time' | 'view' | 'scroll' | 'pointer';
55
+ export type Renderer = 'css-keyframes' | 'waapi' | 'javascript';
56
+ /** Governs the performance budget a primitive is held to in tests. */
57
+ export type PerfClass = 'compositor' | 'paint' | 'layout' | 'continuous' | 'dom-transform';
58
+ /**
59
+ * Per-effect reduced-motion policy. A blanket `1ms` override is wrong: it does not meaningfully
60
+ * reduce parallax, pinning, flashing or continuous ambient motion.
61
+ */
62
+ export type ReducedMotionPolicy = 'shorten' | 'crossfade' | 'disable';
63
+ export type ParamType = 'length' | 'time' | 'number' | 'percentage' | 'angle' | 'color' | 'easing' | 'keyword'
64
+ /**
65
+ * Free text — a CSS selector, a URL pattern. Consumed only by JS primitives and **never
66
+ * written to a stylesheet**, which is what makes accepting arbitrary characters safe here.
67
+ * `resolveParams` drops these on the CSS path; `readParams` keeps them for `prepare`.
68
+ */
69
+ | 'text';
70
+ export interface ParamSpec {
71
+ type: ParamType;
72
+ /** Used as the `var()` fallback in CSS. Never written to element.style — see design.md §7. */
73
+ default: string;
74
+ /** Custom property this parameter feeds, e.g. `--kui-reveal-distance`. */
75
+ cssProperty: string;
76
+ /** For `keyword` params. */
77
+ values?: readonly string[];
78
+ /** Require a numeric parameter to convert to a finite JavaScript number. */
79
+ finite?: boolean;
80
+ /** Inclusive lower bound for numeric parameters. */
81
+ minimum?: number;
82
+ /** Inclusive upper bound for numeric parameters. */
83
+ maximum?: number;
84
+ /** Require a numeric parameter to have no fractional part. */
85
+ integer?: boolean;
86
+ }
87
+ export type ParameterSchema = Record<string, ParamSpec>;
88
+ import type { PrepareContext } from './effect-context.js';
89
+ import type { AttributeLedger, StyleLedger } from './owned-styles.js';
90
+ export type { PrepareContext };
91
+ export type Cleanup = () => void;
92
+ /**
93
+ * Renderer-neutral lifecycle handle.
94
+ *
95
+ * CSS-rendered and JS-rendered effects expose the same five operations, so the animator can gate,
96
+ * cancel, and await either one without knowing which it holds. That uniformity is the whole point:
97
+ * every contract the library advertises — activation, reduced motion, `play().finished`,
98
+ * cancellation — is enforced here rather than re-implemented per renderer.
99
+ */
100
+ export interface EffectInstance {
101
+ /** Start. Called by the animator once its gate opens, never by `prepare`. */
102
+ activate(): void;
103
+ /** Stop where it is, leaving the element mid-effect. */
104
+ cancel(): void;
105
+ /** Jump to the end state immediately. */
106
+ finish(): void;
107
+ /** Resolves when the effect completes. Resolves — never rejects — on cancel. */
108
+ readonly finished: Promise<void>;
109
+ /** Release every listener, observer, subscription, and inserted node. */
110
+ destroy(): void;
111
+ }
112
+ /**
113
+ * An instance that does nothing, for effects with no work to do in the current environment.
114
+ *
115
+ * @complexity O(1) time and space.
116
+ * @overallScore 100
117
+ */
118
+ export declare function inertInstance(destroy?: Cleanup): EffectInstance;
119
+ /**
120
+ * Author timing for one effect segment — the positional `2s 1s linear` of `data-kui`.
121
+ *
122
+ * Separate from `EffectParams` because it is not a parameter: it is not declared in any
123
+ * `ParameterSchema`, it means the same thing for every effect, and the CSS renderer already reads
124
+ * it straight off the `EffectSpec` in `compile.pushTrack`. A JS-rendered primitive gets the same
125
+ * three values here rather than having to declare look-alike parameters of its own.
126
+ *
127
+ * Every field is optional and `undefined` means *the author named none* — a primitive must be able
128
+ * to tell that apart from an explicit `0ms` so its own default still applies.
129
+ */
130
+ export interface EffectTiming {
131
+ /** Total time the whole effect should take, in milliseconds. */
132
+ durationMs?: number;
133
+ /** Time before the effect starts, in milliseconds. */
134
+ delayMs?: number;
135
+ /** Validated CSS easing keyword or function. */
136
+ easing?: string;
137
+ }
138
+ /**
139
+ * Validated parameter reader handed to JS-rendered primitives.
140
+ *
141
+ * A reader rather than a plain record for three reasons: every declared parameter is guaranteed
142
+ * present (so no `| undefined` at every call site), unit conversion lives in one place instead of
143
+ * being re-derived per primitive, and it is structurally distinct from `ResolvedParams`.
144
+ *
145
+ * That last point is not cosmetic. `prepare` previously declared `ResolvedParams` while the
146
+ * animator passed raw author strings; both were `Record<string, string>`, so TypeScript accepted
147
+ * a call that bypassed all validation. Two different shapes make that class of mistake impossible.
148
+ */
149
+ export interface EffectParams {
150
+ /** Validated string value. */
151
+ text(name: string, fallback?: string): string;
152
+ /** Milliseconds, from a `time` parameter. */
153
+ ms(name: string, fallback?: number): number;
154
+ /** Bare number, or a percentage as a 0–1 ratio. */
155
+ num(name: string, fallback?: number): number;
156
+ /** Whether a keyword parameter equals `value` (default `'true'`). */
157
+ is(name: string, value?: string): boolean;
158
+ /**
159
+ * Author timing for this effect segment. Time-driven primitives should honour it; the many that
160
+ * are driven by a pointer or the scroll position instead can ignore it entirely.
161
+ */
162
+ readonly timing: EffectTiming;
163
+ }
164
+ /**
165
+ * A primitive is an implementation. Presets are names that point at a primitive with different
166
+ * default parameters — 48 of the entrance/exit names come from one primitive.
167
+ */
168
+ export interface Primitive {
169
+ id: string;
170
+ renderer: Renderer;
171
+ channels: Channel[];
172
+ parameters: ParameterSchema;
173
+ supportedTimelines: Timeline[];
174
+ supportedActivations: Activation[];
175
+ /**
176
+ * Activation used when the author specifies none.
177
+ *
178
+ * `enter` is right for an entrance reveal and wrong for behaviour: a drag handler, a FLIP
179
+ * container, or a hover morph that only wires itself up once scrolled into view is broken, not
180
+ * lazy. Defaults to `enter` when unset.
181
+ */
182
+ defaultActivation?: Activation;
183
+ perfClass: PerfClass;
184
+ reducedMotion: ReducedMotionPolicy;
185
+ /**
186
+ * JS-side setup. Returns a lifecycle handle, **not** a teardown function.
187
+ *
188
+ * `prepare` must only wire things up — it must not start anything. The animator decides when
189
+ * (or whether) to call `activate()`, which is what makes `on:enter`, `on:click`, `manual`, and
190
+ * `reducedMotion: 'disable'` apply to JS-rendered effects at all. Returning a bare `Cleanup`
191
+ * previously meant every JS effect started at install time and no declared activation or
192
+ * reduced-motion policy was ever enforced.
193
+ *
194
+ * `params` are validated and defaulted — never raw author input.
195
+ */
196
+ prepare?(el: Element, params: EffectParams, ctx: PrepareContext): EffectInstance;
197
+ }
198
+ export interface Preset {
199
+ name: string;
200
+ primitive: string;
201
+ /** Parameter overrides that differentiate this name from its primitive's defaults. */
202
+ params?: Record<string, string>;
203
+ /** CSS `@keyframes` name this preset animates, when renderer is `css-keyframes`. */
204
+ keyframes?: string;
205
+ }
206
+ export type ResolvedParams = Record<string, string>;
207
+ /** One effect segment parsed out of a `data-kui` value. */
208
+ export interface EffectSpec {
209
+ name: string;
210
+ duration?: string;
211
+ delay?: string;
212
+ easing?: string;
213
+ params: Record<string, string>;
214
+ }
215
+ /** The full parse of one element's `data-kui` attribute. */
216
+ export interface ParsedValue {
217
+ specs: EffectSpec[];
218
+ /** Hoisted from reserved `on:` / `timeline:` / `threshold:` keys. Element-scoped. */
219
+ activation?: Activation;
220
+ timeline?: string;
221
+ threshold?: string;
222
+ warnings: string[];
223
+ }
224
+ /** Runtime truth. Attributes are for CSS and debugging; they make a poor state machine. */
225
+ export interface InstanceState {
226
+ /** Whole-configuration identity, not just `data-kui` — see `fingerprintOf`. */
227
+ fingerprint: string;
228
+ specs: EffectSpec[];
229
+ activation: Activation;
230
+ timeline: Timeline;
231
+ /** One handle per renderer in play; the animator gates them uniformly. */
232
+ instances: EffectInstance[];
233
+ /** Inline properties this element's effects wrote, and what they replaced. */
234
+ ledger: StyleLedger;
235
+ attributes: AttributeLedger;
236
+ /** Aborted on release, detaching bindings and primitive listeners. */
237
+ controller: AbortController;
238
+ status: 'pending' | 'ready' | 'running' | 'finished' | 'failed';
239
+ }
@@ -0,0 +1,18 @@
1
+ import type { Preset, Primitive } from '../../core/types.js';
2
+ import type { Registry } from '../../core/registry.js';
3
+ /**
4
+ * Continuous ambient motion never shortens to 1ms under reduced motion — a 1ms aurora is
5
+ * meaningless, so every primitive here declares `reducedMotion: 'disable'` and starts on
6
+ * `load` rather than waiting on a scroll-triggered `enter`.
7
+ */
8
+ export declare const AMBIENT_PRIMITIVES: Primitive[];
9
+ export declare const AMBIENT_PRESETS: Preset[];
10
+ /**
11
+ * Register catalog section J (ambient backgrounds) into a registry.
12
+ *
13
+ * @param registry - Registry to populate.
14
+ * @returns The same registry, for chaining.
15
+ * @complexity O(n) time in registered primitives and presets; O(1) extra space.
16
+ * @overallScore 100
17
+ */
18
+ export declare function registerAmbient(registry: Registry): Registry;
@@ -0,0 +1,19 @@
1
+ import type { Preset, Primitive } from '../../core/types.js';
2
+ import type { Registry } from '../../core/registry.js';
3
+ export declare const PRIMITIVES: Primitive[];
4
+ export declare const PRESETS: Preset[];
5
+ /**
6
+ * Combinations with a purpose-built single keyframe. Checked before channel analysis, so
7
+ * `fade-up, blur-in` resolves here instead of being rejected for both writing opacity.
8
+ */
9
+ export declare const COMBOS: Array<[string[], string]>;
10
+ /**
11
+ * Register the v1 catalog: entrance/exit, scroll reveal, and parallax primitives, presets, and
12
+ * combos.
13
+ *
14
+ * @param registry - Registry to populate.
15
+ * @returns The same registry, for chaining.
16
+ * @complexity O(n) time in the number of primitives, presets, and combos.
17
+ * @overallScore 100
18
+ */
19
+ export declare function registerCore(registry: Registry): Registry;
@@ -0,0 +1,21 @@
1
+ import type { Preset, Primitive } from '../../core/types.js';
2
+ import type { Registry } from '../../core/registry.js';
3
+ /**
4
+ * Feedback & status effects (catalog section K). Loading indicators default to `load` and
5
+ * `reducedMotion: 'disable'` — an infinite loop shortened to 1ms strobes rather than stopping,
6
+ * which is worse than not reducing it at all. One-shot reactions (toast, shake, pop, burst) keep
7
+ * the default `shorten` policy and default to whichever activation their real usage implies:
8
+ * `click` for effects that react to the element the user just clicked, `manual` for effects an
9
+ * application triggers from its own state (a toast appearing, a field failing validation).
10
+ */
11
+ export declare const FEEDBACK_PRIMITIVES: Primitive[];
12
+ export declare const FEEDBACK_PRESETS: Preset[];
13
+ /**
14
+ * Register catalog section K (feedback & status) into a registry.
15
+ *
16
+ * @param registry - Registry to populate.
17
+ * @returns The same registry, for chaining.
18
+ * @complexity O(n) time in registered primitives and presets; O(1) extra space.
19
+ * @overallScore 100
20
+ */
21
+ export declare function registerFeedback(registry: Registry): Registry;
@@ -0,0 +1,21 @@
1
+ import type { Registry } from '../../core/registry.js';
2
+ export { AMBIENT_PRESETS, AMBIENT_PRIMITIVES } from './ambient.js';
3
+ export { FEEDBACK_PRESETS, FEEDBACK_PRIMITIVES } from './feedback.js';
4
+ export { INTERACTION_PRESETS, INTERACTION_PRIMITIVES } from './interaction.js';
5
+ export { MEDIA_PRESETS, MEDIA_PRIMITIVES } from './media.js';
6
+ export { NUMBERS_PRESETS, NUMBERS_PRIMITIVES } from './numbers.js';
7
+ export { TEXT_PRESETS, TEXT_PRIMITIVES } from './text.js';
8
+ /**
9
+ * Register the CSS-oriented catalog sections.
10
+ *
11
+ * Delegates to each section's own `register*` function — the same shape every other top-level
12
+ * category (`registerGestures`, `registerThreeD`, ...) uses — instead of re-registering their
13
+ * constants inline, so this aggregator and each section's own registration path can never drift
14
+ * apart from each other.
15
+ *
16
+ * @param registry - Registry to populate.
17
+ * @returns The same registry, for chaining.
18
+ * @complexity O(n) time in registered primitives and presets.
19
+ * @overallScore 100
20
+ */
21
+ export declare function registerCatalog(registry: Registry): Registry;