@vysmo/text 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 (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +429 -0
  3. package/dist/animate.d.ts +28 -0
  4. package/dist/animate.d.ts.map +1 -0
  5. package/dist/animate.js +418 -0
  6. package/dist/animate.js.map +1 -0
  7. package/dist/index.d.ts +8 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +6 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/presets/emphasis.d.ts +11 -0
  12. package/dist/presets/emphasis.d.ts.map +1 -0
  13. package/dist/presets/emphasis.js +54 -0
  14. package/dist/presets/emphasis.js.map +1 -0
  15. package/dist/presets/enter.d.ts +8 -0
  16. package/dist/presets/enter.d.ts.map +1 -0
  17. package/dist/presets/enter.js +58 -0
  18. package/dist/presets/enter.js.map +1 -0
  19. package/dist/presets/exit.d.ts +5 -0
  20. package/dist/presets/exit.d.ts.map +1 -0
  21. package/dist/presets/exit.js +30 -0
  22. package/dist/presets/exit.js.map +1 -0
  23. package/dist/presets/generated.d.ts +240 -0
  24. package/dist/presets/generated.d.ts.map +1 -0
  25. package/dist/presets/generated.js +3084 -0
  26. package/dist/presets/generated.js.map +1 -0
  27. package/dist/presets/index.d.ts +15 -0
  28. package/dist/presets/index.d.ts.map +1 -0
  29. package/dist/presets/index.js +43 -0
  30. package/dist/presets/index.js.map +1 -0
  31. package/dist/properties.d.ts +10 -0
  32. package/dist/properties.d.ts.map +1 -0
  33. package/dist/properties.js +80 -0
  34. package/dist/properties.js.map +1 -0
  35. package/dist/split.d.ts +21 -0
  36. package/dist/split.d.ts.map +1 -0
  37. package/dist/split.js +171 -0
  38. package/dist/split.js.map +1 -0
  39. package/dist/stagger.d.ts +13 -0
  40. package/dist/stagger.d.ts.map +1 -0
  41. package/dist/stagger.js +53 -0
  42. package/dist/stagger.js.map +1 -0
  43. package/dist/types.d.ts +204 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +2 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +56 -0
  48. package/src/__tests__/animate.test.ts +638 -0
  49. package/src/__tests__/presets.test.ts +87 -0
  50. package/src/__tests__/properties.test.ts +62 -0
  51. package/src/__tests__/split.test.ts +140 -0
  52. package/src/__tests__/ssr.test.ts +48 -0
  53. package/src/__tests__/stagger.test.ts +47 -0
  54. package/src/__tests__/types-check.ts +80 -0
  55. package/src/animate.ts +469 -0
  56. package/src/index.ts +38 -0
  57. package/src/presets/emphasis.ts +60 -0
  58. package/src/presets/enter.ts +64 -0
  59. package/src/presets/exit.ts +33 -0
  60. package/src/presets/generated.ts +3315 -0
  61. package/src/presets/index.ts +62 -0
  62. package/src/properties.ts +78 -0
  63. package/src/split.ts +180 -0
  64. package/src/stagger.ts +55 -0
  65. package/src/types.ts +245 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"properties.js","sourceRoot":"","sources":["../src/properties.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { SplitOptions, Splits } from "./types.js";
2
+ /**
3
+ * Split an element's text into per-slice spans suitable for independent
4
+ * transform/filter/opacity animation. Grapheme-safe via `Intl.Segmenter`
5
+ * when available (falls back to `Array.from(text)` for character mode and
6
+ * a whitespace-preserving regex for word mode).
7
+ *
8
+ * Line mode requires the element to be in the DOM and laid out — line
9
+ * boundaries are detected via `getBoundingClientRect().top` after words
10
+ * have been inserted.
11
+ *
12
+ * Script compatibility:
13
+ * - LTR and RTL (Arabic, Hebrew): word and line modes work correctly; the
14
+ * browser's bidi algorithm places inline-block siblings in visual order.
15
+ * - Connected / contextually-shaped scripts (Arabic, Devanagari, Lao,
16
+ * Khmer, …): character mode breaks shaping because each grapheme lands
17
+ * in its own inline-block box, preventing letters from joining. Prefer
18
+ * word or line mode for these scripts.
19
+ */
20
+ export declare function splitText(element: HTMLElement, options?: SplitOptions): Splits;
21
+ //# sourceMappingURL=split.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../src/split.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AA6DlE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAoGlF"}
package/dist/split.js ADDED
@@ -0,0 +1,171 @@
1
+ const WHITESPACE_ONLY = /^\s+$/;
2
+ function hasSegmenter() {
3
+ return typeof Intl !== "undefined" && typeof Intl.Segmenter === "function";
4
+ }
5
+ function graphemeSegments(text, locale) {
6
+ if (hasSegmenter()) {
7
+ const seg = new Intl.Segmenter(locale, { granularity: "grapheme" });
8
+ return Array.from(seg.segment(text), (s) => s.segment);
9
+ }
10
+ return Array.from(text);
11
+ }
12
+ function wordSegments(text, locale) {
13
+ if (hasSegmenter()) {
14
+ const seg = new Intl.Segmenter(locale, { granularity: "word" });
15
+ return Array.from(seg.segment(text), (s) => ({
16
+ segment: s.segment,
17
+ isWordLike: s.isWordLike ?? false,
18
+ }));
19
+ }
20
+ const parts = text.split(/(\s+)/).filter((s) => s.length > 0);
21
+ return parts.map((segment) => ({
22
+ segment,
23
+ isWordLike: !WHITESPACE_ONLY.test(segment),
24
+ }));
25
+ }
26
+ function makeSliceSpan(text, kind) {
27
+ const span = document.createElement("span");
28
+ span.textContent = text;
29
+ span.style.display = "inline-block";
30
+ span.style.willChange = "transform, opacity, filter";
31
+ span.setAttribute("data-text-slice", kind);
32
+ span.setAttribute("aria-hidden", "true");
33
+ return span;
34
+ }
35
+ function appendScreenReaderCopy(element, text) {
36
+ const sr = document.createElement("span");
37
+ sr.textContent = text;
38
+ sr.setAttribute("data-text-sr", "");
39
+ const s = sr.style;
40
+ s.position = "absolute";
41
+ s.width = "1px";
42
+ s.height = "1px";
43
+ s.padding = "0";
44
+ s.margin = "-1px";
45
+ s.overflow = "hidden";
46
+ s.clip = "rect(0, 0, 0, 0)";
47
+ s.whiteSpace = "nowrap";
48
+ s.border = "0";
49
+ element.appendChild(sr);
50
+ }
51
+ /**
52
+ * Split an element's text into per-slice spans suitable for independent
53
+ * transform/filter/opacity animation. Grapheme-safe via `Intl.Segmenter`
54
+ * when available (falls back to `Array.from(text)` for character mode and
55
+ * a whitespace-preserving regex for word mode).
56
+ *
57
+ * Line mode requires the element to be in the DOM and laid out — line
58
+ * boundaries are detected via `getBoundingClientRect().top` after words
59
+ * have been inserted.
60
+ *
61
+ * Script compatibility:
62
+ * - LTR and RTL (Arabic, Hebrew): word and line modes work correctly; the
63
+ * browser's bidi algorithm places inline-block siblings in visual order.
64
+ * - Connected / contextually-shaped scripts (Arabic, Devanagari, Lao,
65
+ * Khmer, …): character mode breaks shaping because each grapheme lands
66
+ * in its own inline-block box, preventing letters from joining. Prefer
67
+ * word or line mode for these scripts.
68
+ */
69
+ export function splitText(element, options = {}) {
70
+ if (typeof document === "undefined") {
71
+ throw new Error("splitText: requires a browser environment");
72
+ }
73
+ const mode = options.mode ?? "character";
74
+ const original = element.textContent ?? "";
75
+ element.textContent = "";
76
+ appendScreenReaderCopy(element, original);
77
+ const slices = [];
78
+ if (mode === "character") {
79
+ for (const g of graphemeSegments(original, options.locale)) {
80
+ if (WHITESPACE_ONLY.test(g)) {
81
+ element.appendChild(document.createTextNode(g));
82
+ }
83
+ else {
84
+ const span = makeSliceSpan(g, "character");
85
+ element.appendChild(span);
86
+ slices.push(span);
87
+ }
88
+ }
89
+ }
90
+ else if (mode === "word") {
91
+ // Wrap every non-whitespace segment (words AND punctuation) so nothing
92
+ // is left behind at opacity 0 / blur. Intl.Segmenter's word granularity
93
+ // classifies commas/exclamations/etc as `isWordLike: false`; relying on
94
+ // that would leave punctuation unanimated while its neighbours faded.
95
+ for (const { segment } of wordSegments(original, options.locale)) {
96
+ if (WHITESPACE_ONLY.test(segment)) {
97
+ element.appendChild(document.createTextNode(segment));
98
+ }
99
+ else {
100
+ const span = makeSliceSpan(segment, "word");
101
+ element.appendChild(span);
102
+ slices.push(span);
103
+ }
104
+ }
105
+ }
106
+ else {
107
+ // Line mode: insert temporary word spans, measure, wrap each visual
108
+ // line into a single line span, then demote inner word spans back to
109
+ // plain text so only the line span carries animatable style.
110
+ const tempWords = [];
111
+ for (const { segment } of wordSegments(original, options.locale)) {
112
+ if (WHITESPACE_ONLY.test(segment)) {
113
+ element.appendChild(document.createTextNode(segment));
114
+ }
115
+ else {
116
+ const span = makeSliceSpan(segment, "word");
117
+ element.appendChild(span);
118
+ tempWords.push(span);
119
+ }
120
+ }
121
+ const groups = [];
122
+ let currentTop = null;
123
+ let currentGroup = [];
124
+ for (const span of tempWords) {
125
+ const top = Math.round(span.getBoundingClientRect().top);
126
+ if (currentTop === null || Math.abs(top - currentTop) > 1) {
127
+ if (currentGroup.length > 0)
128
+ groups.push(currentGroup);
129
+ currentGroup = [];
130
+ currentTop = top;
131
+ }
132
+ currentGroup.push(span);
133
+ }
134
+ if (currentGroup.length > 0)
135
+ groups.push(currentGroup);
136
+ for (const group of groups) {
137
+ const firstWord = group[0];
138
+ const lastWord = group[group.length - 1];
139
+ const lineWrap = makeSliceSpan("", "line");
140
+ lineWrap.textContent = "";
141
+ firstWord.parentNode.insertBefore(lineWrap, firstWord);
142
+ let node = firstWord;
143
+ while (node) {
144
+ const next = node.nextSibling;
145
+ lineWrap.appendChild(node);
146
+ if (node === lastWord)
147
+ break;
148
+ node = next;
149
+ }
150
+ // Demote inner word spans to plain text — only the line span animates.
151
+ for (const word of group) {
152
+ word.replaceWith(document.createTextNode(word.textContent ?? ""));
153
+ }
154
+ slices.push(lineWrap);
155
+ }
156
+ }
157
+ let restored = false;
158
+ const splits = {
159
+ slices,
160
+ mode,
161
+ original,
162
+ restore() {
163
+ if (restored)
164
+ return;
165
+ restored = true;
166
+ element.textContent = original;
167
+ },
168
+ };
169
+ return splits;
170
+ }
171
+ //# sourceMappingURL=split.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"split.js","sourceRoot":"","sources":["../src/split.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { StaggerOrder } from "./types.js";
2
+ /**
3
+ * Given N slices, a per-step gap, and an order strategy, return the
4
+ * start-delay (in ms) to apply to each slice — index-aligned.
5
+ *
6
+ * - "start": 0, 1g, 2g, 3g, …
7
+ * - "end": reversed
8
+ * - "center": grows outward from the center index
9
+ * - "edges": grows inward from the edges toward the center
10
+ * - "random": a uniform random permutation of the above ranks
11
+ */
12
+ export declare function computeStaggerDelays(count: number, stagger: number, order: StaggerOrder, rng?: () => number): number[];
13
+ //# sourceMappingURL=stagger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stagger.d.ts","sourceRoot":"","sources":["../src/stagger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,YAAY,EACnB,GAAG,GAAE,MAAM,MAAoB,GAC9B,MAAM,EAAE,CAqCV"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Given N slices, a per-step gap, and an order strategy, return the
3
+ * start-delay (in ms) to apply to each slice — index-aligned.
4
+ *
5
+ * - "start": 0, 1g, 2g, 3g, …
6
+ * - "end": reversed
7
+ * - "center": grows outward from the center index
8
+ * - "edges": grows inward from the edges toward the center
9
+ * - "random": a uniform random permutation of the above ranks
10
+ */
11
+ export function computeStaggerDelays(count, stagger, order, rng = Math.random) {
12
+ if (count <= 0)
13
+ return [];
14
+ if (stagger <= 0)
15
+ return new Array(count).fill(0);
16
+ const ranks = new Array(count);
17
+ switch (order) {
18
+ case "start":
19
+ for (let i = 0; i < count; i++)
20
+ ranks[i] = i;
21
+ break;
22
+ case "end":
23
+ for (let i = 0; i < count; i++)
24
+ ranks[i] = count - 1 - i;
25
+ break;
26
+ case "center": {
27
+ const mid = (count - 1) / 2;
28
+ for (let i = 0; i < count; i++)
29
+ ranks[i] = Math.round(Math.abs(i - mid));
30
+ break;
31
+ }
32
+ case "edges": {
33
+ const mid = (count - 1) / 2;
34
+ for (let i = 0; i < count; i++)
35
+ ranks[i] = Math.round(mid - Math.abs(i - mid));
36
+ break;
37
+ }
38
+ case "random": {
39
+ const perm = Array.from({ length: count }, (_, i) => i);
40
+ for (let i = perm.length - 1; i > 0; i--) {
41
+ const j = Math.floor(rng() * (i + 1));
42
+ const tmp = perm[i];
43
+ perm[i] = perm[j];
44
+ perm[j] = tmp;
45
+ }
46
+ for (let rank = 0; rank < count; rank++)
47
+ ranks[perm[rank]] = rank;
48
+ break;
49
+ }
50
+ }
51
+ return ranks.map((r) => r * stagger);
52
+ }
53
+ //# sourceMappingURL=stagger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stagger.js","sourceRoot":"","sources":["../src/stagger.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAa,EACb,OAAe,EACf,KAAmB,EACnB,MAAoB,IAAI,CAAC,MAAM;IAE/B,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAC1B,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,IAAI,KAAK,CAAS,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAE1D,MAAM,KAAK,GAAG,IAAI,KAAK,CAAS,KAAK,CAAC,CAAC;IAEvC,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,OAAO;YACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE;gBAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAC7C,MAAM;QACR,KAAK,KAAK;YACR,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE;gBAAE,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;YACzD,MAAM;QACR,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;YAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE;gBAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YACzE,MAAM;QACR,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;YAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE;gBAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YAC/E,MAAM;QACR,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;YACxD,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACtC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;gBACrB,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;gBACnB,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;YAChB,CAAC;YACD,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,KAAK,EAAE,IAAI,EAAE;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC,GAAG,IAAI,CAAC;YACnE,MAAM;QACR,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,204 @@
1
+ import type { EasingFn } from "@vysmo/easings";
2
+ import type { Scheduler } from "@vysmo/animations";
3
+ export type SplitMode = "character" | "word" | "line";
4
+ export type SplitOptions = {
5
+ /** Granularity of the split. Default "character". */
6
+ mode?: SplitMode;
7
+ /** BCP-47 locale for Intl.Segmenter. Falls back to the environment default. */
8
+ locale?: string;
9
+ };
10
+ export type Splits = {
11
+ /** Slice elements in document order (characters, words, or lines). */
12
+ readonly slices: HTMLElement[];
13
+ /** The split granularity. */
14
+ readonly mode: SplitMode;
15
+ /** The original text captured before the split. */
16
+ readonly original: string;
17
+ /** Restore the element's original text. Idempotent. */
18
+ restore(): void;
19
+ };
20
+ /**
21
+ * The animatable axes understood by animateText. Numeric-only by design — the
22
+ * runtime composes these into `transform` / `filter` / `opacity` strings per
23
+ * frame, so shape mismatches are impossible and per-slice blending stays cheap.
24
+ */
25
+ export type TextProperty = "opacity" | "translateX" | "translateY" | "translateZ" | "scale" | "scaleX" | "scaleY" | "rotate" | "rotateX" | "rotateY" | "rotateZ" | "skewX" | "skewY" | "blur" | "brightness" | "contrast" | "saturate" | "hueRotate";
26
+ /**
27
+ * A scalar or a uniform range. Range values resolve **per slice** at
28
+ * animate-start: every slice samples its own value, so animations like
29
+ * "letters scatter from random offsets and converge on 0" become a
30
+ * one-line spec change. `{ min: x, max: x }` resolves to the constant
31
+ * `x` without consuming an rng draw.
32
+ */
33
+ export type TextValue = number | {
34
+ min: number;
35
+ max: number;
36
+ };
37
+ /**
38
+ * Transform-origin in normalized form. `x`/`y` are fractions (0..1, where
39
+ * 0 is left/top and 1 is right/bottom — `{ x: 0.5, y: 1 }` = bottom
40
+ * center). Optional `z` is in pixels and lets 3D transforms pivot in
41
+ * front of / behind the slice. Stored as data instead of a CSS string so
42
+ * the same preset can drive a future canvas/Skia runtime without parsing.
43
+ */
44
+ export type TransformOrigin = {
45
+ x: number;
46
+ y: number;
47
+ z?: number;
48
+ };
49
+ export type TextAnimationSpec = {
50
+ prop: TextProperty;
51
+ from: TextValue;
52
+ to: TextValue;
53
+ /** Duration in milliseconds. Default 600. */
54
+ duration?: number;
55
+ /**
56
+ * Delay (ms) from the slice's stagger offset before this spec begins.
57
+ * Sequential specs targeting the same prop chain via their delays.
58
+ */
59
+ delay?: number;
60
+ /**
61
+ * Easing for this spec. Default linear.
62
+ *
63
+ * Two forms accepted:
64
+ * - **String** (preferred for catalog presets) — a GSAP-style spec like
65
+ * `"power2.out"`, `"back.out(2)"`, `"elastic.out(1.2, 0.4)"`,
66
+ * `"cubic-bezier(0.42, 0, 0.58, 1)"`. Resolved at animate-start via
67
+ * `parseEasing()` from `@vysmo/easings`. Strings are JSON-serializable
68
+ * so the same preset data can drive a future canvas/Skia runtime
69
+ * without losing fidelity.
70
+ * - **Function** — any `EasingFn`/`(t: number) => number`. Use this when
71
+ * you bring a custom curve that isn't in the catalog.
72
+ */
73
+ ease?: string | EasingFn | ((t: number) => number);
74
+ /**
75
+ * Override the root stagger for this spec only. Enables a per-prop cadence
76
+ * — e.g. translateY staggered at 30ms while opacity staggers at 10ms —
77
+ * which is the main knob the authoring studio uses to explore variety.
78
+ */
79
+ stagger?: number;
80
+ /** Override the root staggerOrder for this spec only. */
81
+ staggerOrder?: StaggerOrder;
82
+ /**
83
+ * Per-slice random delay in ms added on top of the slice's stagger
84
+ * offset. Each slice gets its own value uniformly sampled from
85
+ * `[0, jitterDelay]` at animate-start. Default 0. Useful for breaking
86
+ * the "metronome" feel of pure stagger by spraying start times.
87
+ */
88
+ jitterDelay?: number;
89
+ /**
90
+ * Override the preset / option-level `transformOrigin` for the
91
+ * duration of this spec. Written to each slice's inline style at the
92
+ * moment the spec's window opens for that slice; persists until the
93
+ * next override on the same slice (or `stop()`). When two specs with
94
+ * different origins overlap on a slice, the most recently-opened
95
+ * spec wins (last-write-wins).
96
+ */
97
+ transformOrigin?: TransformOrigin;
98
+ /**
99
+ * Override the container `perspective` (in px) for the duration of
100
+ * this spec. Written to the container element when the spec's window
101
+ * first opens for any slice; persists until the next override (or
102
+ * `stop()`). Container-scoped, so it affects every slice — same
103
+ * scope as the option / preset-level `perspective`.
104
+ */
105
+ perspective?: number;
106
+ };
107
+ export type StaggerOrder = "start" | "end" | "center" | "edges" | "random";
108
+ export type AnimateTextOptions = {
109
+ /** Split granularity. Overridden by the preset's split when unset. Default "character". */
110
+ split?: SplitMode;
111
+ /** BCP-47 locale for Intl.Segmenter. */
112
+ locale?: string;
113
+ /** Milliseconds between consecutive slices starting to animate. Default 30. */
114
+ stagger?: number;
115
+ /** Order in which slices receive their stagger offset. Default "start". */
116
+ staggerOrder?: StaggerOrder;
117
+ /** One or more animated properties running in parallel per slice. */
118
+ animations?: TextAnimationSpec[];
119
+ /**
120
+ * Preset to apply. Accepts either the catalog name (convenience, pulls
121
+ * the whole registry) or a `Preset` object reference (tree-shakable —
122
+ * the unused 14/15/… presets stay out of the bundle).
123
+ */
124
+ preset?: PresetName | Preset;
125
+ /**
126
+ * CSS perspective (px) applied to the container so children's rotateX /
127
+ * rotateY / translateZ render with depth. Required for 3D transforms to
128
+ * look 3D — without it, rotateY(90deg) is just a 1px-wide line.
129
+ */
130
+ perspective?: number;
131
+ /** CSS perspective-origin string applied to the container (e.g., "50% 30%"). */
132
+ perspectiveOrigin?: string;
133
+ /** Transform-origin applied to every slice. `{ x: 0.5, y: 0 }` = top center. */
134
+ transformOrigin?: TransformOrigin;
135
+ /** Begin playing automatically. Default true. */
136
+ autoPlay?: boolean;
137
+ /** When true, skip animation under prefers-reduced-motion. Default true. */
138
+ respectReducedMotion?: boolean;
139
+ /**
140
+ * Delay in ms before the first play begins. Useful for sequencing an
141
+ * entry after some other animation completes.
142
+ */
143
+ delay?: number;
144
+ /**
145
+ * How many times the whole choreography plays. `1` (default) = play
146
+ * once. A number > 1 = that many cycles. `"infinite"` = loop forever
147
+ * (or until `.stop()`). Emphasis presets like pulse typically want
148
+ * `repeat: 3, repeatDelay: 400` for a "triple-tap" feel.
149
+ */
150
+ repeat?: number | "infinite";
151
+ /** Delay between successive cycles when `repeat > 1`. Default 0. */
152
+ repeatDelay?: number;
153
+ /** Override the time source for deterministic playback in tests. */
154
+ scheduler?: Scheduler;
155
+ /** Deterministic RNG for "random" stagger order. Defaults to Math.random. */
156
+ rng?: () => number;
157
+ };
158
+ export type AnimateTextHandle = {
159
+ /** Start or resume playback. */
160
+ play(): AnimateTextHandle;
161
+ /** Pause playback, preserving progress. */
162
+ pause(): AnimateTextHandle;
163
+ /** Stop playback and reset slices to their un-animated style. */
164
+ stop(): AnimateTextHandle;
165
+ /** Jump every slice to the given progress in [0, 1]. */
166
+ seek(progress: number): AnimateTextHandle;
167
+ /** Resolves when every slice has finished naturally. */
168
+ readonly finished: Promise<void>;
169
+ /** The split result backing this animation. */
170
+ readonly splits: Splits;
171
+ };
172
+ export type Preset = {
173
+ name: PresetName;
174
+ /** Split granularity this preset was tuned against. */
175
+ split?: SplitMode;
176
+ /** Default stagger; callers can override. */
177
+ stagger: number;
178
+ /** Stagger order this preset was tuned against. */
179
+ staggerOrder?: StaggerOrder;
180
+ animations: TextAnimationSpec[];
181
+ /** Container perspective (px) required for this preset's 3D transforms. */
182
+ perspective?: number;
183
+ /** Slice-level transform-origin this preset was tuned against. */
184
+ transformOrigin?: TransformOrigin;
185
+ /** Default play count for this preset (e.g. emphasis/pulse repeating 3×). */
186
+ repeat?: number | "infinite";
187
+ /** Default gap between cycles in ms. */
188
+ repeatDelay?: number;
189
+ };
190
+ /**
191
+ * Hand-curated preset names — the seed catalog. These autocomplete in
192
+ * IDEs and stay typed in tests / consumer code.
193
+ */
194
+ export type HandcuratedPresetName = "enter/fade-up" | "enter/elastic-rise" | "enter/blur-in" | "enter/scale-in" | "enter/flip-x" | "enter/depth-zoom" | "exit/fade-down" | "exit/scale-out" | "exit/flip-away" | "emphasis/pulse" | "emphasis/shake" | "emphasis/wobble" | "emphasis/coin-flip" | "emphasis/spin";
195
+ /**
196
+ * Any registered preset name — handcurated entries autocomplete via the
197
+ * literal union; the `string & {}` branch keeps the type open for the
198
+ * generated catalog (300+ entries authored via the Studio's random
199
+ * generator). Lookup at runtime is a string key against `PRESETS`, so
200
+ * unknown names throw at `resolvePreset` rather than at the type
201
+ * boundary.
202
+ */
203
+ export type PresetName = HandcuratedPresetName | (string & {});
204
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@vysmo/text",
3
+ "version": "0.1.0",
4
+ "description": "Multi-property choreographed text animation with a 300+ preset catalog. Grapheme-safe splitting via Intl.Segmenter; per-slice stagger / jitter / range; serializable preset format (string easings, normalized origins) so the same data drives DOM today and canvas tomorrow.",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "text",
8
+ "animation",
9
+ "split",
10
+ "stagger",
11
+ "kinetic-typography",
12
+ "choreography",
13
+ "presets",
14
+ "intl-segmenter",
15
+ "tree-shakable",
16
+ "headless"
17
+ ],
18
+ "type": "module",
19
+ "sideEffects": false,
20
+ "main": "./dist/index.js",
21
+ "module": "./src/index.ts",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "src",
32
+ "README.md",
33
+ "LICENSE"
34
+ ],
35
+ "dependencies": {
36
+ "@vysmo/easings": "0.1.0",
37
+ "@vysmo/animations": "0.1.0"
38
+ },
39
+ "devDependencies": {
40
+ "@vitest/browser": "^3.2.4",
41
+ "esbuild": "^0.28.0",
42
+ "playwright": "^1.59.1",
43
+ "typescript": "^5.6.3",
44
+ "vitest": "^3.2.4"
45
+ },
46
+ "scripts": {
47
+ "build": "tsc -p tsconfig.json",
48
+ "typecheck": "tsc -p tsconfig.typecheck.json",
49
+ "test": "vitest run && vitest run --config vitest.ssr.config.ts",
50
+ "test:browser": "vitest run",
51
+ "test:ssr": "vitest run --config vitest.ssr.config.ts",
52
+ "test:watch": "vitest",
53
+ "ingest": "node scripts/ingest-generated.mjs",
54
+ "size": "node scripts/check-bundle-size.mjs"
55
+ }
56
+ }