kuinetic 0.1.3 → 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 (125) hide show
  1. package/README.md +93 -10
  2. package/dist/esm/advanced/index.mjs +4727 -0
  3. package/dist/esm/chunk-AEQGC2KM.mjs +189 -0
  4. package/dist/esm/chunk-MQSNMYRP.mjs +9332 -0
  5. package/dist/esm/chunk-RVTYN6NZ.mjs +3446 -0
  6. package/dist/esm/chunk-U43BX5O2.mjs +2984 -0
  7. package/dist/esm/core/index.mjs +16 -9
  8. package/dist/esm/effects/index.mjs +19 -4
  9. package/dist/esm/index.mjs +17 -10
  10. package/dist/kuinetic.advanced.js +5070 -0
  11. package/dist/kuinetic.advanced.min.js +749 -0
  12. package/dist/kuinetic.all.js +15218 -5595
  13. package/dist/kuinetic.all.min.js +2 -0
  14. package/dist/kuinetic.css +2900 -360
  15. package/dist/kuinetic.js +15217 -5593
  16. package/dist/kuinetic.min.css +1 -0
  17. package/dist/kuinetic.min.js +7 -0
  18. package/dist/types/3d/angles.d.ts +30 -0
  19. package/dist/types/3d/flattening.d.ts +49 -0
  20. package/dist/types/3d/index.d.ts +36 -0
  21. package/dist/types/3d/model-3d.d.ts +115 -0
  22. package/dist/types/3d/register.d.ts +26 -0
  23. package/dist/types/3d/webgl.d.ts +24 -0
  24. package/dist/types/advanced/audio.d.ts +322 -0
  25. package/dist/types/advanced/base.d.ts +233 -0
  26. package/dist/types/advanced/camera-3d.d.ts +236 -0
  27. package/dist/types/advanced/fluid-cursor.d.ts +149 -0
  28. package/dist/types/advanced/gl-utils.d.ts +52 -0
  29. package/dist/types/advanced/glsl.d.ts +60 -0
  30. package/dist/types/advanced/index.d.ts +23 -0
  31. package/dist/types/advanced/particles.d.ts +108 -0
  32. package/dist/types/advanced/scenes.d.ts +207 -0
  33. package/dist/types/advanced/shaders.d.ts +972 -0
  34. package/dist/types/browser/boot.d.ts +72 -0
  35. package/dist/types/core/activation.d.ts +227 -2
  36. package/dist/types/core/animator.d.ts +446 -11
  37. package/dist/types/core/attrs.d.ts +9 -0
  38. package/dist/types/core/breakpoints.d.ts +260 -0
  39. package/dist/types/core/bundles.d.ts +71 -0
  40. package/dist/types/core/callback.d.ts +64 -0
  41. package/dist/types/core/capabilities.d.ts +47 -0
  42. package/dist/types/core/channels.d.ts +120 -2
  43. package/dist/types/core/cloak-selectors.d.ts +47 -0
  44. package/dist/types/core/compile.d.ts +207 -2
  45. package/dist/types/core/control.d.ts +218 -0
  46. package/dist/types/core/declarations.d.ts +128 -0
  47. package/dist/types/core/derived/aggregate.d.ts +43 -0
  48. package/dist/types/core/derived/book.d.ts +30 -0
  49. package/dist/types/core/derived/diagnostics.d.ts +51 -0
  50. package/dist/types/core/derived/group-gate.d.ts +62 -0
  51. package/dist/types/core/derived/install.d.ts +110 -0
  52. package/dist/types/core/derived/late-matches.d.ts +19 -0
  53. package/dist/types/core/derived/types.d.ts +108 -0
  54. package/dist/types/core/easing.d.ts +57 -0
  55. package/dist/types/core/element-config.d.ts +47 -6
  56. package/dist/types/core/element-size.d.ts +23 -0
  57. package/dist/types/core/event-sources.d.ts +39 -0
  58. package/dist/types/core/flip.d.ts +34 -1
  59. package/dist/types/core/gesture.d.ts +12 -0
  60. package/dist/types/core/host-facts.d.ts +155 -0
  61. package/dist/types/core/index.d.ts +7 -3
  62. package/dist/types/core/owned-styles.d.ts +129 -2
  63. package/dist/types/core/params.d.ts +48 -0
  64. package/dist/types/core/parse.d.ts +28 -1
  65. package/dist/types/core/register-into.d.ts +29 -0
  66. package/dist/types/core/registry.d.ts +10 -3
  67. package/dist/types/core/repeat.d.ts +91 -0
  68. package/dist/types/core/sequence.d.ts +126 -0
  69. package/dist/types/core/stagger-config.d.ts +199 -0
  70. package/dist/types/core/stagger-keys.d.ts +63 -0
  71. package/dist/types/core/stagger.d.ts +187 -6
  72. package/dist/types/core/style-plan.d.ts +21 -16
  73. package/dist/types/core/target.d.ts +128 -0
  74. package/dist/types/core/threshold-reachability.d.ts +45 -0
  75. package/dist/types/core/time-scale.d.ts +9 -0
  76. package/dist/types/core/toggle-actions.d.ts +141 -0
  77. package/dist/types/core/travel.d.ts +59 -0
  78. package/dist/types/core/types.d.ts +705 -13
  79. package/dist/types/core/unquoted-selectors.d.ts +53 -0
  80. package/dist/types/effects/carousel/drag.d.ts +80 -0
  81. package/dist/types/effects/carousel/index.d.ts +149 -0
  82. package/dist/types/effects/catalog/background-media.d.ts +152 -0
  83. package/dist/types/effects/catalog/discrete.d.ts +13 -0
  84. package/dist/types/effects/catalog/interaction-proximity.d.ts +24 -0
  85. package/dist/types/effects/catalog/interaction-reveal.d.ts +248 -0
  86. package/dist/types/effects/catalog/interaction-shared.d.ts +42 -0
  87. package/dist/types/effects/catalog/interaction-states.d.ts +68 -0
  88. package/dist/types/effects/catalog/materials.d.ts +67 -0
  89. package/dist/types/effects/catalog/media-shared.d.ts +3 -2
  90. package/dist/types/effects/catalog/numbers-shared.d.ts +8 -5
  91. package/dist/types/effects/catalog/shared.d.ts +2 -2
  92. package/dist/types/effects/catalog/text-shared.d.ts +92 -10
  93. package/dist/types/effects/catalog/transforms.d.ts +13 -0
  94. package/dist/types/effects/catalog/view-transitions.d.ts +13 -0
  95. package/dist/types/effects/forms/primitives.d.ts +15 -4
  96. package/dist/types/effects/gestures/index.d.ts +53 -0
  97. package/dist/types/effects/index.d.ts +5 -0
  98. package/dist/types/effects/layout/presets.d.ts +35 -0
  99. package/dist/types/effects/motion-path/index.d.ts +35 -0
  100. package/dist/types/effects/scroll-mechanics/params.d.ts +23 -0
  101. package/dist/types/effects/scroll-mechanics/presets.d.ts +51 -0
  102. package/dist/types/effects/scroll-mechanics/section-index.d.ts +47 -0
  103. package/dist/types/effects/shared.d.ts +162 -2
  104. package/dist/types/effects/step-index.d.ts +121 -0
  105. package/dist/types/effects/step-marking.d.ts +41 -33
  106. package/dist/types/effects/svg/icon-parts.d.ts +23 -0
  107. package/dist/types/effects/three-d/flip-parts.d.ts +46 -0
  108. package/dist/types/effects/tween/index.d.ts +57 -0
  109. package/dist/types/effects/tween/properties.d.ts +107 -0
  110. package/dist/types/effects/tween/waypoints.d.ts +106 -0
  111. package/dist/types/showcase/compare.d.ts +4 -0
  112. package/dist/types/showcase/device-frame.d.ts +3 -0
  113. package/dist/types/showcase/hotspots.d.ts +3 -0
  114. package/dist/types/showcase/index.d.ts +30 -0
  115. package/dist/types/showcase/lightbox.d.ts +3 -0
  116. package/dist/types/showcase/media-source.d.ts +13 -0
  117. package/dist/types/showcase/modal-shell.d.ts +22 -0
  118. package/dist/types/showcase/scroll-story.d.ts +4 -0
  119. package/dist/types/showcase/shared.d.ts +47 -0
  120. package/dist/types/showcase/slideshow.d.ts +3 -0
  121. package/dist/types/showcase/slow-mo.d.ts +5 -0
  122. package/package.json +14 -7
  123. package/dist/esm/chunk-5DON3UFQ.mjs +0 -4380
  124. package/dist/esm/chunk-JT4PZL3A.mjs +0 -773
  125. package/dist/esm/chunk-QUVFODSQ.mjs +0 -1278
@@ -1,4 +1,3 @@
1
- import type { PrepareContext } from '../core/effect-context.js';
2
1
  import type { Cleanup } from '../core/types.js';
3
2
  /**
4
3
  * Marking the children of a stepped effect, shared by every primitive that has an index.
@@ -25,42 +24,23 @@ import type { Cleanup } from '../core/types.js';
25
24
  */
26
25
  /** The attribute this module owns. Never write it from anywhere else. */
27
26
  export declare const STEP_STATE_ATTR = "data-kui-step-state";
28
- export type StepState = 'before' | 'active' | 'after';
29
27
  /**
30
- * Classify a selector as unusable, dangerously broad, or fine.
31
- *
32
- * `matches` against the two roots catches every selector that reaches the whole document — `*`,
33
- * `html`, `body` and compounds like `*, a` with one rule and no bespoke parser — while leaving a
34
- * deliberately scoped wildcard such as `.spy-nav > *` working, which a syntactic ban on `*` would
35
- * not. `matches` throws on invalid syntax exactly as `querySelectorAll` does, so the same call
36
- * still answers the validity question.
28
+ * The ring place, as a selectable attribute beside the `--kui-offset` custom property.
37
29
  *
38
- * @complexity O(1) time and space.
39
- * @overallScore 100
30
+ * Also owned here, and written to the same elements. See `createStepMarker` for why both forms
31
+ * exist: the number does arithmetic a selector cannot, the attribute selects what arithmetic
32
+ * cannot — and hiding a slide properly (`visibility`, not `opacity`) needs a keyword.
40
33
  */
41
- export declare function selectorBreadth(selector: string, doc: Document): 'invalid' | 'document-wide' | 'ok';
34
+ export declare const STEP_OFFSET_ATTR = "data-kui-step-offset";
35
+ export type StepState = 'before' | 'active' | 'after';
42
36
  /**
43
- * Resolve a `target:` selector once at setup, rejecting both the unusable and the over-broad.
44
- *
45
- * Two distinct failures, one warning channel. An invalid selector thrown from inside the shared
46
- * scheduler's frame callback would skip every other subscriber on that root, not just this one. An
47
- * over-broad one is worse for being silent: `target:*` is perfectly valid syntax, so a syntax-only
48
- * check passed it straight through to stamp an attribute onto every element in the document, on
49
- * every frame.
50
- *
51
- * Rejecting rather than silently narrowing is the honest response, because there is no narrower
52
- * selector that could be meant. A selector reaching `<html>` or `<body>` is not naming a set of
53
- * steps or a nav link, it is naming the page, and guessing which of its thousands of descendants
54
- * the author meant would be worse than saying so.
55
- *
56
- * @param selector - The authored `target:` value; empty is the no-op default, not an error.
57
- * @param ctx - Prepare context, for `doc` and the warning channel.
58
- * @param effect - Effect name, so the warning says which attribute to go and fix.
59
- * @returns The selector, or `''` when it must be ignored.
60
- * @complexity O(1) time and space; `matches` walks the selector, not the document.
61
- * @overallScore 100
37
+ * `target:`/`scope:` resolution — `resolveTarget`, `queryScoped`, `TargetScope`, `SCOPE_PARAM`,
38
+ * `scopeParam` — moved to `core/target.ts`. `core/compile.ts` and `core/animator.ts` need the same
39
+ * resolution for the *universal* `target:` (any effect, not just the handful of primitives that
40
+ * used to be the only place this grammar existed — see `compile.ts`'s `liftTarget` for who those
41
+ * are today), and `core` must not depend on `effects`. Import from `../core/target.js` here as
42
+ * everywhere else; this module keeps only the step-index-specific half.
62
43
  */
63
- export declare function resolveTarget(selector: string, ctx: PrepareContext, effect: string): string;
64
44
  /**
65
45
  * A set of step elements plus the ledgers that let their original attributes survive teardown.
66
46
  *
@@ -83,11 +63,39 @@ export interface StepMarker {
83
63
  * the index actually changing — while frames are not.
84
64
  *
85
65
  * @param resolve - Produces the current step elements, in document order.
66
+ * @param warn - Optional diagnostic sink, called at most once per marker. Callers prefix their own
67
+ * effect name, the way every other warning in this library names the attribute to go and fix.
86
68
  * @returns A marker; call `restore` from the primitive's teardown.
87
69
  * @complexity O(n) per `mark` in the number of step elements; O(n) space in elements ever touched.
88
70
  * @overallScore 100
89
71
  */
90
- export declare function createStepMarker(resolve: () => Iterable<Element>): StepMarker;
72
+ export declare function createStepMarker(resolve: () => Iterable<Element>, warn?: (message: string) => void): StepMarker;
73
+ /**
74
+ * Where one step sits relative to the live one, as a signed number of places *around a ring*.
75
+ *
76
+ * `before`/`active`/`after` is a three-way split, which is all a progress bar needs and not enough
77
+ * for a deck: it says slide 5 is "before" slide 1 but not that it is one place behind it, and one
78
+ * place is the whole difference between a carousel that loops and one that rewinds. Driving the
79
+ * track off the container's single `--kui-step` means the wrap from the last slide to the first
80
+ * runs the track back across every slide in between — the snap-back that reads as "it jumped to
81
+ * the beginning" rather than "it carried on".
82
+ *
83
+ * Published per element instead, each slide can place itself: at index 0 of five, the last slide
84
+ * reads `-1` and sits to the *left* of the live one, so stepping onto it moves one place forward
85
+ * like every other step. Nothing is cloned and nothing is reordered — the ends of the strip simply
86
+ * stop existing, because there is no strip, only positions on a ring.
87
+ *
88
+ * Signed and shortest-path: the far half of the ring counts backwards, so `+3` of five becomes
89
+ * `-2`. An even count has no midpoint to split, and the exact half goes positive by convention.
90
+ *
91
+ * @param position - The element's index within its own parent group.
92
+ * @param index - The live step.
93
+ * @param size - How many steps are in that group.
94
+ * @returns Places from the live step, negative for behind it.
95
+ * @complexity O(1) time and space.
96
+ * @overallScore 100
97
+ */
98
+ export declare function circularOffset(position: number, index: number, size: number): number;
91
99
  /**
92
100
  * Where one step sits relative to the live one.
93
101
  *
@@ -0,0 +1,23 @@
1
+ import type { Primitive } from '../../core/types.js';
2
+ /**
3
+ * Wrap an icon-toggle-family `prepare` so a host with no `.kui-bar` children gets
4
+ * `data-kui-part="bar"` on its positional bars.
5
+ *
6
+ * Stamps eagerly, before calling `inner`: `stylesheetTimingPrepare` (the only `inner` this ever
7
+ * wraps today) runs at install, not activation — only *its* inner mirroring is deferred — and the
8
+ * stamp has to be in place at the same moment, or `icon-parts.css`'s `[data-kui-part='bar']` rules
9
+ * have nothing to select yet when the browser's next paint reads them. Restored on `ctx.signal`
10
+ * abort, which fires when the instance releases (mirrors `flip-parts.ts`'s (7a) attribute-ledger
11
+ * cleanup one primitive over) — never on `reset()`/`destroy()` directly, since `PrepareContext`
12
+ * hands `prepare` nothing else that fires on every teardown path.
13
+ *
14
+ * A host that already wrote its own `.kui-bar` markup is untouched: `findBars` never runs, so
15
+ * nothing here can clash with class-based CSS an author is already relying on.
16
+ *
17
+ * @param inner - The primitive's own `prepare`, unwrapped.
18
+ * @returns A `prepare` of the same shape, with the part-stamping layered in.
19
+ * @complexity O(n) time in the host's children, beyond whatever `inner` itself costs; O(n)
20
+ * additional space held past `prepare` for the bars' ledgers, until `ctx.signal` aborts.
21
+ * @overallScore 100
22
+ */
23
+ export declare function withIconParts(inner: NonNullable<Primitive['prepare']>): NonNullable<Primitive['prepare']>;
@@ -0,0 +1,46 @@
1
+ import type { Cleanup, EffectParams, PrepareContext } from '../../core/types.js';
2
+ /**
3
+ * Phase 7a — the flip card's structural parts (owner decision E): `data-kui-part="front"`/`"back"`
4
+ * on an unclassed card's two faces, and the toggle control — an authored `.kui-flip-control`, an
5
+ * authored `button[aria-pressed]` (stamped so `flip-card-parts.css` reaches it, but never wired,
6
+ * since the author already owns its click handler), or a control this module injects and wires
7
+ * itself: `<button type="button" class="kui-flip-control" data-kui-part="control injected"
8
+ * aria-pressed="false">Flip card</button>` (the `quiet` token joins it for a hover trigger, so
9
+ * `flip-card-parts.css` can hide it until `:focus-visible` — the pointer path already has one).
10
+ *
11
+ * Classes win throughout: a card the author already marked up with `.kui-face-front`/`-back`/
12
+ * `.kui-flip-control` gets no redundant attribute next to a class its own CSS may already select.
13
+ */
14
+ /** What {@link prepareFlipParts} resolved for one flip card. */
15
+ export interface FlipParts {
16
+ /** The card's toggle control, whether authored or injected. `resolveControl`'s injected branch
17
+ * always succeeds, so this is never absent. */
18
+ control: Element;
19
+ /** Undo every attribute stamp and remove every injected node. */
20
+ cleanup: Cleanup;
21
+ }
22
+ /**
23
+ * Matches whichever control {@link prepareFlipParts} resolved for a card, whichever of the three
24
+ * branches produced it — an authored `.kui-flip-control`, an authored `button[aria-pressed]`
25
+ * (stamped `data-kui-part="control"`), or the injected fallback (both class and stamp). `three-d/
26
+ * index.ts`'s deferred `prepareCardToggle` re-finds the control through this selector rather than
27
+ * calling {@link prepareFlipParts} a second time — target:-everywhere reconcile R-7 moved the one
28
+ * call that stamps/injects to prepare time, before `prepareCardToggle` (deferred to activation)
29
+ * ever runs, so by the time it looks, the control this selector matches already exists.
30
+ */
31
+ export declare const CONTROL_SELECTOR: string;
32
+ /**
33
+ * Resolve (and stamp/inject) a flip card's structural parts.
34
+ *
35
+ * @param el - The flip card element.
36
+ * @param params - The effect's authored parameters; only `trigger` is read, to decide whether an
37
+ * injected control starts quiet (hidden until `:focus-visible`) — a hover trigger already has a
38
+ * pointer path, so the injected control is a keyboard fallback rather than the primary control.
39
+ * @param ctx - The prepare-time context; only `doc` is read, so an injected button is built
40
+ * through the same document the rest of this codebase's primitives use rather than a global.
41
+ * @returns The card's control and a cleanup that undoes every stamp and removes the injected node.
42
+ * @complexity O(c) time in the card's direct children; O(1) additional space per stamped/injected
43
+ * node.
44
+ * @overallScore 100
45
+ */
46
+ export declare function prepareFlipParts(el: Element, params: EffectParams, ctx: PrepareContext): FlipParts;
@@ -0,0 +1,57 @@
1
+ import type { Registry } from '../../core/registry.js';
2
+ import type { Preset, Primitive } from '../../core/types.js';
3
+ export declare const TWEEN_PRIMITIVES: Primitive[];
4
+ /**
5
+ * Two names, no parameter defaults of their own.
6
+ *
7
+ * `tween-from` cloaks and `tween` does not, which is the same rule every other name in the catalog
8
+ * follows: a `from` tween's start state is installed by the runtime, so between first paint and
9
+ * `start()` the element is painted at its *rest* state and then jumps back to animate — the flash
10
+ * `Preset.cloak` exists to remove. A `to` tween starts at the rest state by construction, so there
11
+ * is nothing to hide and cloaking it would blank an element that was always meant to be visible.
12
+ *
13
+ * **Neither declares `phase`, and that is deliberate — checked against the actual stylesheet, not
14
+ * assumed from "generic effect, therefore unknowable".**
15
+ *
16
+ * `tween` (the `to` direction) is knowable and the answer is still "no phase fits". Every block in
17
+ * `kui-tween-to-*` (`src/css/tween.css`) declares an explicit `to` — `translate: var(--kui-tween-x,
18
+ * 0) ...`, not a missing endpoint — so, per D1's correction #5, `animation-fill-mode: both` pins that
19
+ * exact authored value on the channel forever once the animation finishes; it never resolves against
20
+ * whatever the cascade underneath would otherwise say. That is precisely the shape `EffectPhase`'s
21
+ * own doc calls out as the trap: fifteen of the catalog's fifty-four `cloak: true` entrances close
22
+ * their block the same way and are *deliberately* left unphased rather than marked `entrance`,
23
+ * because `entrance` specifically means "plays once and releases the channel". `tween` is that same
24
+ * closed shape by construction — every property group's `to` block closes, with no exception — so it
25
+ * belongs in that same deliberately-unphased set on the same grounds, not because nothing is known.
26
+ * It is not `state` either (nothing gates it behind a visitor condition — it runs the moment it
27
+ * activates), not `idle` (it is a bounded, one-shot animation, not an unbounded loop), and not `exit`
28
+ * (it does not start at rest and depart; it moves *to* an arbitrary authored value).
29
+ *
30
+ * `tween-from` is where "cannot be known statically" is the literal, checked reason, not a hedge.
31
+ * Its two-point blocks (`kui-tween-from-*`) are the mirror of `tween`'s — `from` is explicit and `to`
32
+ * is missing, so a plain `tween-from y:40` *does* release: it is structurally identical to an open
33
+ * entrance like `fade-up`, and would be a defensible `phase: 'entrance'` on its own. But
34
+ * `waypoints.ts`'s `waypointKeyframes` compiles a **different, fully-explicit block** the moment any
35
+ * key in the group is authored as a list — `tween-from x:'0,100,40'` renders through
36
+ * `kui-tween-keys3-translate`, whose own comment in `tween.css` says it plainly: "unlike everything
37
+ * above they are fully explicit from 0% to 100%... there is no implicit half left for the browser to
38
+ * fill from computed style." That block does **not** release, for the same fill-forever reason
39
+ * `tween`'s `to` blocks do not. So whether this preset's one instance releases its channel depends on
40
+ * whether the *author* wrote a single value or a list for at least one key in the group — a fact
41
+ * about the spec, not about the preset, and exactly the shape D1 was killed over (`repeat:` turning
42
+ * a finite entrance into a loop at author time, invisible to a preset-level field). Declaring
43
+ * `phase: 'entrance'` here would be right for `tween-from y:40` and silently wrong for `tween-from
44
+ * y:'0,40'` on the very same element — the "wrong phase is worse than none" case this project was
45
+ * warned about, so it stays undeclared and collides with everything, exactly as before this field
46
+ * existed. See `test/catalog-phase-mechanics.test.ts` for what stays checked instead.
47
+ */
48
+ export declare const TWEEN_PRESETS: Preset[];
49
+ /**
50
+ * Register the generic tween.
51
+ *
52
+ * @param registry - Registry to populate.
53
+ * @returns The same registry, for chaining.
54
+ * @complexity O(1) time and space — two primitives, two presets.
55
+ * @overallScore 100
56
+ */
57
+ export declare function registerTween(registry: Registry): Registry;
@@ -0,0 +1,107 @@
1
+ import type { Channel, ParamSpec, ParameterSchema } from '../../core/types.js';
2
+ /**
3
+ * The generic tween's vocabulary: which property names an author may put in a `key:value` slot,
4
+ * what each one means, and which keyframe block renders it.
5
+ *
6
+ * **Why this is an allowlist and not a passthrough.** `tween <name>:<value>` is the one place in
7
+ * the library where an author names a *CSS property* rather than choosing from a primitive's
8
+ * declared parameters, so the obvious implementation — write whatever they typed into whatever
9
+ * they typed — is also the one that breaks two invariants at once. It breaks composition, because
10
+ * `core/channels.ts` decides whether two effects may share an element from their declared channel
11
+ * sets and an open-ended property list has no channel; and it breaks the parameter contract in
12
+ * `core/params.ts`, which exists precisely because author strings end up in a stylesheet. An
13
+ * allowlist keeps every tweenable property on a known channel with a known value grammar, and
14
+ * costs only that a property nobody listed here cannot be tweened until someone adds a row.
15
+ *
16
+ * **Why the rows are grouped.** CSS writes `translate` as one property, not three; a keyframe that
17
+ * sets it sets every axis. So the unit of rendering is the *group* — one `@keyframes` block per
18
+ * group, one animation track per group the author actually touched — and not the individual key.
19
+ * See `src/css/tween.css`, where each group's block is written out, including what the identity
20
+ * fallbacks mean for an axis the author did not name.
21
+ */
22
+ /** One rendering unit: a single CSS property (or filter list) written by one keyframe block. */
23
+ export type TweenGroup = 'translate' | 'rotate' | 'scale' | 'opacity' | 'filter' | 'color' | 'background';
24
+ /**
25
+ * Declared in rendering order rather than derived from `TWEEN_PROPERTIES`'s key order, so
26
+ * `tween opacity:0 x:100` and `tween x:100 opacity:0` compile to the same track order. Two
27
+ * spellings of one animation producing two different `animation-name` lists would make every
28
+ * assertion about a compiled plan depend on the order the author happened to type in.
29
+ */
30
+ export declare const TWEEN_GROUP_ORDER: readonly TweenGroup[];
31
+ /**
32
+ * The channel each group claims — the honest answer to "what does this spec collide with".
33
+ *
34
+ * These are the existing catalog channels, not new ones: a tween writing `translate` must collide
35
+ * with `fade-up` for the same reason two entrances do, and giving the tween a private channel name
36
+ * would let exactly that pair compose into one effect silently overwriting the other.
37
+ */
38
+ export declare const TWEEN_GROUP_CHANNELS: Record<TweenGroup, Channel>;
39
+ interface TweenProperty {
40
+ group: TweenGroup;
41
+ spec: ParamSpec;
42
+ }
43
+ /**
44
+ * Author key → what it animates.
45
+ *
46
+ * Deliberately absent, and each for a reason worth writing down rather than rediscovering:
47
+ *
48
+ * - **`rotate-x` / `rotate-y`.** The CSS `rotate` property takes one axis at a time, so they could
49
+ * not share the rotate group with `rotate` anyway; and rotating a flat box about x or y without a
50
+ * `perspective()` reads as a vertical squash, not a turn. Perspective only exists inside the
51
+ * `transform` shorthand, which is a different channel entirely (`CHANNEL.skew` — see
52
+ * `core/types.ts`) and already has an effect family of its own in `flip-in-x`/`flip-in-y`.
53
+ * - **`width` / `height` / `top` / `left`.** Animatable, and every one of them animates layout.
54
+ * The tween declares `perfClass: 'paint'`; admitting these would make that a lie for the whole
55
+ * effect rather than for the one attribute that used them, and the library has never offered a
56
+ * layout-animating primitive without saying so.
57
+ * - **`skew`.** Same `transform`-shorthand problem as 3D rotation, and skew has no property of its
58
+ * own to write — `CHANNEL.skew` documents exactly this.
59
+ */
60
+ export declare const TWEEN_PROPERTIES: Readonly<Record<string, TweenProperty>>;
61
+ /**
62
+ * The tween's parameter schema, declared statically even though which keys *matter* varies per
63
+ * attribute.
64
+ *
65
+ * Every key is always declared, so an author who mistypes one gets `resolveParams`' ordinary
66
+ * `unknown parameter "opactiy" (known: ...)` warning listing the whole vocabulary, exactly as they
67
+ * would on any other effect. Declaring only the keys a given attribute used would have produced a
68
+ * "known:" list containing nothing but the author's own typo-free keys, which is the least useful
69
+ * form that message could take.
70
+ */
71
+ export declare const TWEEN_SCHEMA: ParameterSchema;
72
+ /**
73
+ * `BARE_NUMBER` and {@link decimalNumber} used to live here. They moved to `core/params.ts` when
74
+ * the `'number|percentage'` union landed and the core needed the same lexical decimal shift to
75
+ * turn `opacity:80%` into `0.8` — one implementation, so the two paths cannot drift into
76
+ * disagreeing about what `50%` means.
77
+ */
78
+ /**
79
+ * Give a bare number the unit its property implies — `x:100` is `100px`, `rotate:45` is `45deg`.
80
+ *
81
+ * `core/params.ts` requires a unit on every `length`, and should keep doing so: a unitless
82
+ * `distance:24` on `fade-up` is a mistake worth naming, because the parameter is ambiguous between
83
+ * `px` and `%` and the author simply left the unit off. `angle` is not in that position and
84
+ * `params.ts` now coerces it there too, which makes this function's angle branch a no-op for
85
+ * anything that reaches validation — it is kept because it runs first and keeps the tween's own
86
+ * `rotate:45` identical to its `x:100`. A tween property is different for `length`. `x:100` is the
87
+ * syntax this feature was specified around, it is what every other animation library accepts, and
88
+ * "100 what" has exactly one sensible answer per property. So the coercion lives here, scoped to
89
+ * the tween's own keys, rather than loosening validation for the other 255 effects.
90
+ *
91
+ * Number-valued properties also accept percentages, expressed as decimal ratios for the core
92
+ * validator. Length percentages retain their units. Other values pass through unchanged: `2rem`
93
+ * and a quoted `calc(...)` still have to earn their acceptance in `params.ts`.
94
+ *
95
+ * @complexity O(n) time in value length; O(1) space.
96
+ * @overallScore 100
97
+ */
98
+ export declare function withImpliedUnit(raw: string, type: ParamSpec['type']): string;
99
+ /**
100
+ * A shared param type is intentionally broader than some CSS slots: percentages are lengths for
101
+ * x/y, but not z or blur, and a negative blur invalidates the entire filter list. Check these
102
+ * slot-specific constraints on scalar values and waypoints alike. CSS-wide keywords are also
103
+ * unsafe here: `--kui-tween-color: inherit` inherits the custom property, not the element's color.
104
+ * All other values still go through the core validator; this never opens a second CSS escape path.
105
+ */
106
+ export declare function tweenValue(key: string, raw: string, warn: (message: string) => void, label?: string): string | undefined;
107
+ export {};
@@ -0,0 +1,106 @@
1
+ import type { ParameterSchema } from '../../core/types.js';
2
+ import type { TweenGroup } from './properties.js';
3
+ /**
4
+ * Multi-waypoint tweening — `tween x:'0,100,40'`, a value list instead of a value.
5
+ *
6
+ * `tween`/`tween-from` animate between exactly two states: wherever the element is, and where the
7
+ * author said. That is `gsap.to()`/`gsap.from()`, and it is where the catalog stopped — nothing in
8
+ * it smooths a property through *several* states, which is the shape of most real choreography (out,
9
+ * over, settle) and of every keyframe array in Motion, GSAP and WAAPI.
10
+ *
11
+ * **The whole feature is still static CSS.** A list of N values selects an N-step `@keyframes` block
12
+ * from `src/css/tween.css`, and each step reads its own custom property. Nothing is generated at
13
+ * runtime, nothing is interpolated in JavaScript, and the result is an ordinary compositor-run CSS
14
+ * animation exactly as the two-point tween already was — see the outline's §2.3, and `tween.css`'s
15
+ * own header for what the blocks look like.
16
+ *
17
+ * **Why a value list rather than a waypoint list.** The alternative shape is per-waypoint objects —
18
+ * `at:'x:0 y:0' at:'x:100 y:-60'` — and the grammar cannot hold it: a `key:value` slot appears once
19
+ * per spec, so repeating one is a duplicate-parameter warning. Property-major is also what Motion
20
+ * and WAAPI use (`animate(el, { x: [0, 100, 40] })`), and it keeps the vocabulary identical to the
21
+ * two-point tween's: an author who knows `x:100` knows `x:'0,100,40'`.
22
+ *
23
+ * **Even spacing across the duration.** Also GSAP's own default for a bare keyframe array. A
24
+ * per-step position would need the *percentage* in the keyframe selector to vary, and a keyframe
25
+ * selector cannot be a `var()` — it is the one part of a keyframe block that has to be literal. An
26
+ * author who wants an uneven rhythm can repeat a value to hold it for a step.
27
+ */
28
+ /**
29
+ * The most waypoints one property may name.
30
+ *
31
+ * A budget rather than a limit of the technique: every count needs its own `@keyframes` block per
32
+ * property group, because the step percentages are literal, so the shipped stylesheet grows with
33
+ * this number. Five states keeps this static vocabulary bounded. Longer choreography needs another keyframe
34
+ * definition; two effects on the same property cannot bypass this budget by composing.
35
+ */
36
+ export declare const MAX_WAYPOINTS = 5;
37
+ /**
38
+ * One property group's waypoint shape, as read off the attribute.
39
+ *
40
+ * `count` is the group's, not the key's: a keyframe block has one step count, so every key in the
41
+ * group renders at the same steps whatever each of them individually wrote.
42
+ */
43
+ export interface GroupWaypoints {
44
+ count: number;
45
+ /** Author key → its values, already padded to `count` and unit-normalised. */
46
+ keys: Map<string, string[]>;
47
+ }
48
+ /**
49
+ * Read one authored value as a waypoint list, or as the single value it is.
50
+ *
51
+ * Commas inside functions and strings are data. Unlike the core tokenizer, this scanner must
52
+ * retain empty items: dropping the middle of `0,,100` changes both the count and the rhythm,
53
+ * while dropping every item of `,,` used to make the first-value lookup throw. Empty values now
54
+ * reach ordinary parameter validation at their authored index and use the CSS fallback.
55
+ *
56
+ * @returns The values in order. One entry means the author wrote a plain value, and every caller
57
+ * treats that as the two-point tween it has always been.
58
+ * @complexity O(n) time and space in the value's length.
59
+ * @overallScore 100
60
+ */
61
+ export declare function readWaypoints(raw: string): string[];
62
+ /**
63
+ * Collect the waypoint lists an attribute wrote, bucketed by the group that renders them.
64
+ *
65
+ * @param authored - Author key → raw value, for tween properties only.
66
+ * @returns One entry per group that named at least one list. Groups whose keys are all plain values
67
+ * are absent, and keep the two-point blocks they have always used.
68
+ * @complexity O(n) time and space in the number of values across the attribute.
69
+ * @overallScore 100
70
+ */
71
+ export declare function collectWaypoints(authored: [string, string[]][], warn: (message: string) => void): Map<TweenGroup, GroupWaypoints>;
72
+ /**
73
+ * Expand a group's lists into one parameter per waypoint, with a spec for each.
74
+ *
75
+ * The key is `x[2]`, not `x-2`, and the brackets are load-bearing: these keys are synthesised by
76
+ * the library and can never be authored, so when one of them appears in a `resolveParams`
77
+ * diagnostic — `parameter "x[2]": expected a length` — the author can see both which key and which
78
+ * waypoint without the message having to explain itself, and can tell at a glance that it is not a
79
+ * name they were supposed to have written.
80
+ *
81
+ * The custom property is `--kui-tween-<key>-<n>`, which is what `tween.css`'s step reads, with the
82
+ * plain `--kui-tween-<key>` as its fallback. That fallback is the whole broadcast rule: a key that
83
+ * wrote a single value (`tween x:'0,100,40' y:20`) sets only the plain property, so every step of
84
+ * the block reads the same `y` and it holds — no JavaScript, no per-step duplication of a value the
85
+ * author wrote once.
86
+ *
87
+ * @param waypoints - One group's padded lists.
88
+ * @param params - Sink for the expanded values, keyed as above.
89
+ * @param schema - Sink for the specs those values are validated against.
90
+ * @complexity O(n) time and space in the group's total number of values.
91
+ * @overallScore 100
92
+ */
93
+ export declare function expandWaypoints(waypoints: GroupWaypoints, params: Record<string, string>, schema: ParameterSchema, warn: (message: string) => void): void;
94
+ /**
95
+ * The keyframe block a group with waypoints renders through.
96
+ *
97
+ * One block per (group, count), all of them fully explicit from 0% to 100% — so unlike the
98
+ * two-point blocks there is no `to`-only and `from`-only pair, and `tween` and `tween-from` share
99
+ * them. That falls out of what a list *is*: an author who writes every state has written the first
100
+ * one too, so there is no implicit half left for the browser to fill from the element's computed
101
+ * style.
102
+ *
103
+ * @complexity O(1) time and space.
104
+ * @overallScore 100
105
+ */
106
+ export declare function waypointKeyframes(group: TweenGroup, count: number): string;
@@ -0,0 +1,4 @@
1
+ import type { Preset, Primitive } from '../core/types.js';
2
+ export declare const COMPARE_AXIS_ATTR = "data-kui-compare-axis";
3
+ export declare const COMPARE_PRIMITIVE: Primitive;
4
+ export declare const COMPARE_PRESETS: Preset[];
@@ -0,0 +1,3 @@
1
+ import type { Preset, Primitive } from '../core/types.js';
2
+ export declare const DEVICE_FRAME_PRIMITIVE: Primitive;
3
+ export declare const DEVICE_FRAME_PRESETS: Preset[];
@@ -0,0 +1,3 @@
1
+ import type { Preset, Primitive } from '../core/types.js';
2
+ export declare const HOTSPOTS_PRIMITIVE: Primitive;
3
+ export declare const HOTSPOTS_PRESETS: Preset[];
@@ -0,0 +1,30 @@
1
+ import type { Animator } from '../core/animator.js';
2
+ import type { Registry } from '../core/registry.js';
3
+ import type { Preset, Primitive } from '../core/types.js';
4
+ /**
5
+ * The showcase module: pre-built presentation widgets — a dialog, an ARIA carousel, image
6
+ * hotspots — the one part of this library that owns UI behaviour rather than only motion.
7
+ * `docs/design.md` §14's amendment is the boundary this module operates under; every widget's own
8
+ * file (`device-frame.ts`, `lightbox.ts`, …) argues its own case for why it needs the exception.
9
+ *
10
+ * This is the *only* file anything outside `src/showcase/` may import from — see
11
+ * `only-effects-barrel-imports-showcase` in `.dependency-cruiser.cjs`. That is what makes the
12
+ * later split into a standalone `kuinetic.showcase.js` a build-config change and not a source
13
+ * change: every showcase file keeps importing from inside `src/showcase/`, and the one line that
14
+ * moves is `src/effects/index.ts`'s call to {@link registerShowcase}.
15
+ */
16
+ export declare const SHOWCASE_PRIMITIVES: Primitive[];
17
+ export declare const SHOWCASE_PRESETS: Preset[];
18
+ /**
19
+ * Register every showcase widget onto a `Registry`, an `Animator`, or anything shaped like either.
20
+ *
21
+ * The shape check — not `instanceof` — is what lets this same function serve as both the in-core
22
+ * call `src/effects/index.ts` makes today and the `boot({ register })` callback a split
23
+ * `kuinetic.showcase.js` tag will hand a page's existing animator tomorrow. See
24
+ * `src/core/register-into.ts`'s docblock for why identity cannot survive that split and shape can.
25
+ *
26
+ * @param target - The registry, the animator, or a host exposing one as `.registry`.
27
+ * @returns `target`, so callers can chain.
28
+ * @complexity O(n) time in showcase primitives plus presets; O(1) extra space.
29
+ */
30
+ export declare function registerShowcase(target: unknown): Registry | Animator;
@@ -0,0 +1,3 @@
1
+ import type { Preset, Primitive } from '../core/types.js';
2
+ export declare const LIGHTBOX_PRIMITIVE: Primitive;
3
+ export declare const LIGHTBOX_PRESETS: Preset[];
@@ -0,0 +1,13 @@
1
+ /** A safe, supported video URL and its preferred frame shape. */
2
+ export interface MediaSource {
3
+ kind: 'youtube' | 'vimeo' | 'file';
4
+ embedUrl: string;
5
+ aspect: 'wide' | 'tall';
6
+ }
7
+ /**
8
+ * Resolve a real link into a supported player source. Unknown hosts and non-web schemes keep
9
+ * their normal link behavior; no attacker-controlled URL is handed to an iframe.
10
+ * @complexity O(n) in the URL length; O(1) extra space.
11
+ * @overallScore 100
12
+ */
13
+ export declare function resolveMediaSource(href: string): MediaSource | null;
@@ -0,0 +1,22 @@
1
+ export interface ModalContent {
2
+ node: HTMLElement;
3
+ label: string;
4
+ duration: number;
5
+ scale: string;
6
+ ease: string;
7
+ reducedMotion: boolean;
8
+ onKey?: (event: KeyboardEvent) => void;
9
+ onClose?: () => void;
10
+ }
11
+ export interface ModalShell {
12
+ open(content: ModalContent): void;
13
+ dismiss(): void;
14
+ release(): void;
15
+ }
16
+ /**
17
+ * Share one lazily built modal per document across image and video widgets. The final live
18
+ * instance removes it, including an in-flight close timer and any scroll lock.
19
+ * @complexity O(1) per operation; O(1) shared DOM per document.
20
+ * @overallScore 100
21
+ */
22
+ export declare function acquireModalShell(doc: Document): ModalShell;
@@ -0,0 +1,4 @@
1
+ import type { Preset, Primitive } from '../core/types.js';
2
+ export declare const STORY_SIDE_ATTR = "data-kui-story-side";
3
+ export declare const SCROLL_STORY_PRIMITIVE: Primitive;
4
+ export declare const SCROLL_STORY_PRESETS: Preset[];
@@ -0,0 +1,47 @@
1
+ import type { Channel, ParameterSchema, PerfClass, Primitive } from '../core/types.js';
2
+ /**
3
+ * The one shape every showcase widget shares.
4
+ *
5
+ * `src/showcase/` builds UI components the effect catalog deliberately stays out of (a dialog, an
6
+ * ARIA carousel, a native popover) — see `docs/design.md` §14's amendment. Every one of them is
7
+ * built the same way for the same reasons, so this bakes the shared answers in once rather than
8
+ * repeating them per widget:
9
+ *
10
+ * - `renderer: 'javascript'` — nothing here compiles to a `@keyframes` block; the DOM the widget
11
+ * builds and the states it toggles are the whole effect.
12
+ * - `supportedTimelines: ['time']` — a widget runs on a clock, never on scroll/view/pointer
13
+ * progress. Narrower than `TIMELINE_AGNOSTIC` (`effects/shared.ts`), which abstains for
14
+ * primitives that never read a `Timeline` at all; a widget primitive *could* be asked for one and
15
+ * the honest answer is "only time makes sense here".
16
+ * - `supportedActivations: ['load']`, `defaultActivation: 'load'` — a widget must be wired up
17
+ * before a keyboard user tabs to it or a crawler indexes it, not when it happens to scroll into
18
+ * view. `on:enter`'s lazy-install story is right for a decorative reveal and wrong for a control.
19
+ * - `reducedMotion: 'shorten'`, never `'disable'` — `'disable'` means the animator never calls
20
+ * `activate()` at all (`src/effects/forms/primitives.ts`'s doc on the same trap), which would
21
+ * leave the widget entirely unbuilt for a reduced-motion visitor. Motion is removed in CSS
22
+ * instead; the widget itself still has to exist.
23
+ * - `perfClass` is the one field every widget answers differently (a dialog's `backdrop-filter`
24
+ * is `'paint'`, a native-popover positioning read is `'layout'`, a synchronous attribute stamp is
25
+ * `'layout'` too), so it is a parameter rather than baked in.
26
+ *
27
+ * `prepare` is taken pre-built — already run through `deferPrepare` and, where the widget has
28
+ * nothing to time, `withTimingContract` — rather than assembled here, because the timing contract
29
+ * (which of `duration`/`delay`/`ease` a widget honours, and why not the rest) genuinely differs per
30
+ * widget and baking one reason in would misdescribe the others. Same division of labour
31
+ * `src/effects/navigation/index.ts`'s `navPrimitive` already uses for its own small family.
32
+ *
33
+ * @param id - Primitive id, also the preset name for every showcase widget shipped so far.
34
+ * @param spec - The three fields every widget answers differently: `channels` (CSS property
35
+ * groups this widget's CSS claims, see `core/channels.ts`), `parameters` (the widget's parameter
36
+ * schema), and `perfClass` (this widget's honest performance-budget class). Grouped into one
37
+ * object rather than three positional params so this factory stays under the four-parameter
38
+ * lint ceiling (`eslint.config.js`'s `max-params`) alongside `prepare`.
39
+ * @param prepare - Fully wrapped setup: `withTimingContract(...)`-and/or-`deferPrepare(...)`.
40
+ * @returns A complete `Primitive`.
41
+ * @complexity O(1) time and space.
42
+ */
43
+ export declare function widgetPrimitive(id: string, spec: {
44
+ channels: Channel[];
45
+ parameters: ParameterSchema;
46
+ perfClass: PerfClass;
47
+ }, prepare: NonNullable<Primitive['prepare']>): Primitive;
@@ -0,0 +1,3 @@
1
+ import type { Preset, Primitive } from '../core/types.js';
2
+ export declare const SLIDESHOW_PRIMITIVE: Primitive;
3
+ export declare const SLIDESHOW_PRESETS: Preset[];
@@ -0,0 +1,5 @@
1
+ import type { Preset, Primitive } from '../core/types.js';
2
+ /** A host-only speed control for Web Animations and CSS motion in its subtree. */
3
+ export declare const SLOW_MO_PRIMITIVE: Primitive;
4
+ /** The showcase name for the speed-control primitive. */
5
+ export declare const SLOW_MO_PRESETS: Preset[];