animejs 4.3.6 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -11
- package/dist/bundles/anime.esm.js +1033 -421
- package/dist/bundles/anime.esm.min.js +2 -2
- package/dist/bundles/anime.umd.js +1038 -421
- package/dist/bundles/anime.umd.min.js +2 -2
- package/dist/modules/animatable/animatable.cjs +1 -1
- package/dist/modules/animatable/animatable.js +2 -2
- package/dist/modules/animatable/index.cjs +1 -1
- package/dist/modules/animatable/index.js +1 -1
- package/dist/modules/animation/additive.cjs +1 -1
- package/dist/modules/animation/additive.js +1 -1
- package/dist/modules/animation/animation.cjs +38 -16
- package/dist/modules/animation/animation.d.ts +2 -2
- package/dist/modules/animation/animation.js +42 -20
- package/dist/modules/animation/composition.cjs +1 -1
- package/dist/modules/animation/composition.js +3 -3
- package/dist/modules/animation/index.cjs +1 -1
- package/dist/modules/animation/index.js +1 -1
- package/dist/modules/core/clock.cjs +1 -1
- package/dist/modules/core/clock.js +1 -1
- package/dist/modules/core/colors.cjs +1 -1
- package/dist/modules/core/colors.js +1 -1
- package/dist/modules/core/consts.cjs +3 -9
- package/dist/modules/core/consts.d.ts +1 -5
- package/dist/modules/core/consts.js +4 -8
- package/dist/modules/core/globals.cjs +16 -5
- package/dist/modules/core/globals.d.ts +22 -1
- package/dist/modules/core/globals.js +18 -6
- package/dist/modules/core/helpers.cjs +7 -10
- package/dist/modules/core/helpers.js +8 -11
- package/dist/modules/core/render.cjs +66 -63
- package/dist/modules/core/render.js +68 -65
- package/dist/modules/core/styles.cjs +53 -32
- package/dist/modules/core/styles.d.ts +1 -0
- package/dist/modules/core/styles.js +55 -35
- package/dist/modules/core/targets.cjs +1 -1
- package/dist/modules/core/targets.js +1 -1
- package/dist/modules/core/transforms.cjs +129 -13
- package/dist/modules/core/transforms.d.ts +1 -0
- package/dist/modules/core/transforms.js +130 -15
- package/dist/modules/core/units.cjs +1 -1
- package/dist/modules/core/units.js +1 -1
- package/dist/modules/core/values.cjs +68 -8
- package/dist/modules/core/values.d.ts +5 -2
- package/dist/modules/core/values.js +69 -11
- package/dist/modules/draggable/draggable.cjs +1 -1
- package/dist/modules/draggable/draggable.js +1 -1
- package/dist/modules/draggable/index.cjs +1 -1
- package/dist/modules/draggable/index.js +1 -1
- package/dist/modules/easings/cubic-bezier/index.cjs +1 -1
- package/dist/modules/easings/cubic-bezier/index.js +1 -1
- package/dist/modules/easings/eases/index.cjs +1 -1
- package/dist/modules/easings/eases/index.js +1 -1
- package/dist/modules/easings/eases/parser.cjs +1 -1
- package/dist/modules/easings/eases/parser.js +1 -1
- package/dist/modules/easings/index.cjs +1 -1
- package/dist/modules/easings/index.js +1 -1
- package/dist/modules/easings/irregular/index.cjs +1 -1
- package/dist/modules/easings/irregular/index.js +1 -1
- package/dist/modules/easings/linear/index.cjs +1 -1
- package/dist/modules/easings/linear/index.js +1 -1
- package/dist/modules/easings/none.cjs +1 -1
- package/dist/modules/easings/none.js +1 -1
- package/dist/modules/easings/spring/index.cjs +1 -1
- package/dist/modules/easings/spring/index.js +1 -1
- package/dist/modules/easings/steps/index.cjs +1 -1
- package/dist/modules/easings/steps/index.js +1 -1
- package/dist/modules/engine/engine.cjs +1 -1
- package/dist/modules/engine/engine.js +1 -1
- package/dist/modules/engine/index.cjs +1 -1
- package/dist/modules/engine/index.js +1 -1
- package/dist/modules/events/index.cjs +1 -1
- package/dist/modules/events/index.js +1 -1
- package/dist/modules/events/scroll.cjs +1 -1
- package/dist/modules/events/scroll.js +1 -1
- package/dist/modules/index.cjs +9 -1
- package/dist/modules/index.d.ts +1 -0
- package/dist/modules/index.js +4 -1
- package/dist/modules/layout/index.cjs +1 -1
- package/dist/modules/layout/index.js +1 -1
- package/dist/modules/layout/layout.cjs +29 -25
- package/dist/modules/layout/layout.d.ts +4 -3
- package/dist/modules/layout/layout.js +30 -26
- package/dist/modules/scope/index.cjs +1 -1
- package/dist/modules/scope/index.js +1 -1
- package/dist/modules/scope/scope.cjs +1 -1
- package/dist/modules/scope/scope.js +1 -1
- package/dist/modules/svg/drawable.cjs +1 -1
- package/dist/modules/svg/drawable.js +1 -1
- package/dist/modules/svg/helpers.cjs +1 -1
- package/dist/modules/svg/helpers.js +1 -1
- package/dist/modules/svg/index.cjs +1 -1
- package/dist/modules/svg/index.js +1 -1
- package/dist/modules/svg/morphto.cjs +3 -6
- package/dist/modules/svg/morphto.js +3 -6
- package/dist/modules/svg/motionpath.cjs +1 -1
- package/dist/modules/svg/motionpath.js +1 -1
- package/dist/modules/text/index.cjs +3 -1
- package/dist/modules/text/index.d.ts +1 -0
- package/dist/modules/text/index.js +2 -1
- package/dist/modules/text/scramble.cjs +272 -0
- package/dist/modules/text/scramble.d.ts +3 -0
- package/dist/modules/text/scramble.js +270 -0
- package/dist/modules/text/split.cjs +5 -5
- package/dist/modules/text/split.d.ts +5 -5
- package/dist/modules/text/split.js +5 -5
- package/dist/modules/timeline/index.cjs +1 -1
- package/dist/modules/timeline/index.js +1 -1
- package/dist/modules/timeline/position.cjs +1 -1
- package/dist/modules/timeline/position.js +1 -1
- package/dist/modules/timeline/timeline.cjs +36 -18
- package/dist/modules/timeline/timeline.d.ts +6 -5
- package/dist/modules/timeline/timeline.js +37 -19
- package/dist/modules/timer/index.cjs +1 -1
- package/dist/modules/timer/index.js +1 -1
- package/dist/modules/timer/timer.cjs +8 -12
- package/dist/modules/timer/timer.d.ts +2 -0
- package/dist/modules/timer/timer.js +9 -13
- package/dist/modules/types/index.d.ts +76 -8
- package/dist/modules/utils/chainable.cjs +8 -5
- package/dist/modules/utils/chainable.js +8 -5
- package/dist/modules/utils/index.cjs +5 -1
- package/dist/modules/utils/index.d.ts +1 -0
- package/dist/modules/utils/index.js +2 -1
- package/dist/modules/utils/number.cjs +1 -1
- package/dist/modules/utils/number.js +1 -1
- package/dist/modules/utils/random.cjs +1 -1
- package/dist/modules/utils/random.js +1 -1
- package/dist/modules/utils/stagger.cjs +117 -20
- package/dist/modules/utils/stagger.js +118 -21
- package/dist/modules/utils/target.cjs +1 -1
- package/dist/modules/utils/target.js +1 -1
- package/dist/modules/utils/time.cjs +5 -3
- package/dist/modules/utils/time.d.ts +1 -1
- package/dist/modules/utils/time.js +5 -3
- package/dist/modules/waapi/composition.cjs +1 -1
- package/dist/modules/waapi/composition.js +1 -1
- package/dist/modules/waapi/index.cjs +1 -1
- package/dist/modules/waapi/index.js +1 -1
- package/dist/modules/waapi/waapi.cjs +19 -20
- package/dist/modules/waapi/waapi.js +20 -21
- package/package.json +2 -1
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anime.js - text - CJS
|
|
3
|
+
* @version v4.4.0
|
|
4
|
+
* @license MIT
|
|
5
|
+
* @copyright 2026 - Julian Garnier
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
var random = require('../utils/random.cjs');
|
|
11
|
+
var globals = require('../core/globals.cjs');
|
|
12
|
+
var helpers = require('../core/helpers.cjs');
|
|
13
|
+
var parser = require('../easings/eases/parser.cjs');
|
|
14
|
+
var consts = require('../core/consts.cjs');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @import {
|
|
18
|
+
* ScrambleTextParams,
|
|
19
|
+
* FunctionValue,
|
|
20
|
+
* } from '../types/index.js'
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* '-' is the range operator; place it at the start or end of the string to use it as a literal (e.g. '-abc' or 'abc-')
|
|
25
|
+
* @param {String} str
|
|
26
|
+
* @return {String}
|
|
27
|
+
*/
|
|
28
|
+
const expandCharRanges = (str) => {
|
|
29
|
+
let result = '';
|
|
30
|
+
for (let i = 0, l = str.length; i < l; i++) {
|
|
31
|
+
if (i + 2 < l && str[i + 1] === '-' && str.charCodeAt(i) < str.charCodeAt(i + 2)) {
|
|
32
|
+
const start = str.charCodeAt(i);
|
|
33
|
+
const end = str.charCodeAt(i + 2);
|
|
34
|
+
for (let c = start; c <= end; c++) result += String.fromCharCode(c);
|
|
35
|
+
i += 2;
|
|
36
|
+
} else {
|
|
37
|
+
result += str[i];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const charSets = {
|
|
44
|
+
lowercase: 'a-z',
|
|
45
|
+
uppercase: 'A-Z',
|
|
46
|
+
numbers: '0-9',
|
|
47
|
+
symbols: '!%#_|*+=',
|
|
48
|
+
braille: '⠀-⣿',
|
|
49
|
+
blocks: '▀-▟',
|
|
50
|
+
shades: '░-▓',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const originalTexts = new WeakMap();
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns a function-based tween value that scrambles the target's text content,
|
|
57
|
+
* progressively revealing the original text.
|
|
58
|
+
*
|
|
59
|
+
* @param {ScrambleTextParams} [params]
|
|
60
|
+
* @return {FunctionValue}
|
|
61
|
+
*/
|
|
62
|
+
const scrambleText = (params = {}) => {
|
|
63
|
+
if (!params) params = {};
|
|
64
|
+
const charsParam = params.chars;
|
|
65
|
+
const easeFn = parser.parseEase(params.ease || 'linear');
|
|
66
|
+
const text = params.text;
|
|
67
|
+
const fromParam = params.from;
|
|
68
|
+
const reversed = params.reversed || false;
|
|
69
|
+
const perturbation = params.perturbation || 0;
|
|
70
|
+
const cursorParam = params.cursor;
|
|
71
|
+
const cursorChars = cursorParam === true ? '_'
|
|
72
|
+
: typeof cursorParam === 'number' ? String.fromCharCode(cursorParam)
|
|
73
|
+
: typeof cursorParam === 'string' ? cursorParam
|
|
74
|
+
: '';
|
|
75
|
+
const cursorLen = cursorChars.length;
|
|
76
|
+
const seed = params.seed || 0;
|
|
77
|
+
const override = params.override !== undefined ? params.override : true;
|
|
78
|
+
const revealRate = params.revealRate || 60;
|
|
79
|
+
const interval = 1000 * globals.globals.timeScale / revealRate;
|
|
80
|
+
const settleDuration = params.settleDuration || 300 * globals.globals.timeScale;
|
|
81
|
+
const settleRate = params.settleRate || 30;
|
|
82
|
+
const durationParam = params.duration;
|
|
83
|
+
const revealDelayParam = params.revealDelay;
|
|
84
|
+
const delayParam = params.delay;
|
|
85
|
+
const onChange = params.onChange || consts.noop;
|
|
86
|
+
|
|
87
|
+
return (target, index, targets, prevTween) => {
|
|
88
|
+
const rawChars = typeof charsParam === 'function' ? charsParam(target, index, targets) : (charsParam || 'a-zA-Z0-9!%#_');
|
|
89
|
+
const characters = expandCharRanges(charSets[rawChars] || rawChars);
|
|
90
|
+
const totalChars = characters.length - 1;
|
|
91
|
+
const duration = typeof durationParam === 'function' ? durationParam(target, index, targets) : durationParam;
|
|
92
|
+
const revealDelay = typeof revealDelayParam === 'function' ? revealDelayParam(target, index, targets) : (revealDelayParam || 0);
|
|
93
|
+
const delay = typeof delayParam === 'function' ? delayParam(target, index, targets) : (delayParam || 0);
|
|
94
|
+
const rng = seed ? random.createSeededRandom(seed) : random.createSeededRandom();
|
|
95
|
+
if (!originalTexts.has(target)) originalTexts.set(target, target.textContent);
|
|
96
|
+
const startingText = prevTween ? prevTween._value : target.textContent;
|
|
97
|
+
const targetText = text !== undefined
|
|
98
|
+
? (typeof text === 'function' ? text(target, index, targets) : text)
|
|
99
|
+
: prevTween ? prevTween._value
|
|
100
|
+
: originalTexts.get(target);
|
|
101
|
+
const settledText = targetText === ' ' || targetText === ' ' ? ' ' : targetText;
|
|
102
|
+
const startLength = startingText === ' ' ? 0 : startingText.length;
|
|
103
|
+
const endLength = settledText.length;
|
|
104
|
+
const overrideChars = override === true ? characters
|
|
105
|
+
: typeof override === 'string' && override.length > 0 ? expandCharRanges(charSets[/** @type {String} */(override)] || /** @type {String} */(override))
|
|
106
|
+
: null;
|
|
107
|
+
const totalOverrideChars = overrideChars ? overrideChars.length - 1 : 0;
|
|
108
|
+
// Space override uses so the browser doesn't collapse consecutive spaces in innerHTML
|
|
109
|
+
const overrideChar = override === ' ' ? ' ' : null;
|
|
110
|
+
// When starting from blank, only animate the target text length to avoid padding beyond it
|
|
111
|
+
const animLength = override === '' ? endLength : Math.max(startLength, endLength);
|
|
112
|
+
// Compute total duration from interval spacing and settle time, or use the explicit duration
|
|
113
|
+
const animDuration = duration > 0 ? duration : (animLength - 1) * interval + settleDuration;
|
|
114
|
+
const computedDuration = helpers.round((animDuration + revealDelay) / globals.globals.timeScale, 0) * globals.globals.timeScale;
|
|
115
|
+
const revealDelayRatio = revealDelay > 0 ? helpers.round(revealDelay / computedDuration, 12) : 0;
|
|
116
|
+
// Auto-resolve reveal direction: shrinking text reveals from right, growing from left
|
|
117
|
+
const resolvedFrom = fromParam === undefined || fromParam === 'auto' ? (endLength < startLength ? 'right' : 'left') : fromParam;
|
|
118
|
+
const charOrder = new Int32Array(animLength);
|
|
119
|
+
if (resolvedFrom === 'random') {
|
|
120
|
+
for (let i = 0; i < animLength; i++) charOrder[i] = i;
|
|
121
|
+
for (let i = animLength - 1; i > 0; i--) {
|
|
122
|
+
const j = rng(0, i);
|
|
123
|
+
const t = charOrder[i]; charOrder[i] = charOrder[j]; charOrder[j] = t;
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
const ref = resolvedFrom === 'right' ? (override === '' || !startLength ? animLength : startLength) - 1
|
|
127
|
+
: resolvedFrom === 'center' ? ((override === '' || !startLength ? animLength : startLength) - 1) / 2
|
|
128
|
+
: typeof resolvedFrom === 'number' ? resolvedFrom
|
|
129
|
+
: 0;
|
|
130
|
+
const abs = Math.abs;
|
|
131
|
+
const indices = new Array(animLength);
|
|
132
|
+
for (let i = 0; i < animLength; i++) indices[i] = i;
|
|
133
|
+
indices.sort((a, b) => abs(a - ref) - abs(b - ref));
|
|
134
|
+
for (let i = 0; i < animLength; i++) charOrder[indices[i]] = i;
|
|
135
|
+
}
|
|
136
|
+
if (reversed) {
|
|
137
|
+
const last = animLength - 1;
|
|
138
|
+
for (let i = 0; i < animLength; i++) charOrder[i] = last - charOrder[i];
|
|
139
|
+
}
|
|
140
|
+
// settleRatio is the fraction of the animation each character spends in the active scrambling zone
|
|
141
|
+
const settleRatio = helpers.round(settleDuration / animDuration, 12);
|
|
142
|
+
// settleSpacing is the time gap between consecutive characters entering the active zone
|
|
143
|
+
const settleSpacing = helpers.round((1 - settleRatio) / animLength, 12);
|
|
144
|
+
const cursorZone = cursorLen * settleSpacing;
|
|
145
|
+
// stepRatio controls how often scramble characters refresh (based on settleRate)
|
|
146
|
+
const stepRatio = helpers.round(1000 * globals.globals.timeScale / (settleRate * computedDuration), 12);
|
|
147
|
+
// Pre-compute per-character start and settle times
|
|
148
|
+
const charStarts = new Float32Array(animLength);
|
|
149
|
+
const charEnds = new Float32Array(animLength);
|
|
150
|
+
const scale = perturbation > 0 ? perturbation * settleRatio : 0;
|
|
151
|
+
for (let c = 0; c < animLength; c++) {
|
|
152
|
+
const so = scale > 0 ? (rng(0, 2000) - 1000) / 1000 * scale : 0;
|
|
153
|
+
const eo = scale > 0 ? (rng(0, 2000) - 1000) / 1000 * scale : 0;
|
|
154
|
+
charStarts[c] = charOrder[c] * settleSpacing + so;
|
|
155
|
+
charEnds[c] = Math.ceil((charStarts[c] + settleRatio + eo) / stepRatio) * stepRatio;
|
|
156
|
+
}
|
|
157
|
+
// When text shrinks with non-sequential from modes, delay target settle times past all extras
|
|
158
|
+
if (endLength < animLength && resolvedFrom !== 'left' && resolvedFrom !== 'right' && resolvedFrom !== 'random') {
|
|
159
|
+
let maxExtraEnd = 0;
|
|
160
|
+
for (let c = endLength; c < animLength; c++) {
|
|
161
|
+
if (charEnds[c] > maxExtraEnd) maxExtraEnd = charEnds[c];
|
|
162
|
+
}
|
|
163
|
+
const targets = new Array(endLength);
|
|
164
|
+
for (let c = 0; c < endLength; c++) targets[c] = c;
|
|
165
|
+
targets.sort((a, b) => charOrder[a] - charOrder[b]);
|
|
166
|
+
const targetSpacing = (1 - maxExtraEnd) / endLength;
|
|
167
|
+
for (let i = 0; i < endLength; i++) {
|
|
168
|
+
const revealTime = maxExtraEnd + i * targetSpacing;
|
|
169
|
+
if (revealTime > charEnds[targets[i]]) {
|
|
170
|
+
charEnds[targets[i]] = revealTime;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// charCache holds the current scramble character for each position, refreshed at settleRate
|
|
175
|
+
const charCache = new Array(animLength);
|
|
176
|
+
for (let c = 0; c < animLength; c++) {
|
|
177
|
+
charCache[c] = characters[rng(0, totalChars)];
|
|
178
|
+
}
|
|
179
|
+
// overrideCache holds scramble characters for the starting text (override: true or custom string)
|
|
180
|
+
const overrideCache = overrideChars ? (overrideChars === characters ? charCache : new Array(animLength)) : null;
|
|
181
|
+
if (overrideCache && overrideCache !== charCache) {
|
|
182
|
+
for (let c = 0; c < animLength; c++) {
|
|
183
|
+
overrideCache[c] = overrideChar || /** @type {String} */(overrideChars)[rng(0, overrideChars.length - 1)];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Build the initial display text based on override mode
|
|
187
|
+
let fillStartText = startingText;
|
|
188
|
+
if (!prevTween) {
|
|
189
|
+
if (override === '') {
|
|
190
|
+
fillStartText = '';
|
|
191
|
+
} else if (overrideChars) {
|
|
192
|
+
fillStartText = '';
|
|
193
|
+
for (let c = 0; c < startLength; c++) {
|
|
194
|
+
fillStartText += startingText[c] === ' ' ? ' ' : /** @type {Array<String>} */(overrideCache)[c];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
let lastValue = -1;
|
|
200
|
+
let lastStep = -1;
|
|
201
|
+
let scrambled = '';
|
|
202
|
+
const hasOverride = override !== '';
|
|
203
|
+
const hasOverrideChars = !!overrideChars;
|
|
204
|
+
const hasCursor = cursorLen > 0;
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
from: 0,
|
|
208
|
+
to: 1,
|
|
209
|
+
duration: computedDuration,
|
|
210
|
+
delay: delay,
|
|
211
|
+
ease: 'linear',
|
|
212
|
+
modifier: (v) => {
|
|
213
|
+
if (v === lastValue) return scrambled;
|
|
214
|
+
lastValue = v;
|
|
215
|
+
if (delay > 0 && v <= 0) { scrambled = startingText; return startingText; }
|
|
216
|
+
if (v <= 0) { scrambled = fillStartText; return fillStartText; }
|
|
217
|
+
if (v >= 1) { scrambled = settledText; return settledText; }
|
|
218
|
+
scrambled = '';
|
|
219
|
+
// Only refresh scramble characters when we cross a settleRate step boundary
|
|
220
|
+
const currentStep = (v / stepRatio) | 0;
|
|
221
|
+
const refreshChars = currentStep !== lastStep;
|
|
222
|
+
if (refreshChars) lastStep = currentStep;
|
|
223
|
+
// Subtract delay ratio to get the effective animation progress
|
|
224
|
+
const linear = revealDelayRatio > 0 ? (v - revealDelayRatio) / (1 - revealDelayRatio) : v;
|
|
225
|
+
const t = linear > 0 ? easeFn(linear) : 0;
|
|
226
|
+
for (let c = 0; c < animLength; c++) {
|
|
227
|
+
// Each character has its own start/end window based on its reveal order
|
|
228
|
+
const charStart = charStarts[c];
|
|
229
|
+
const charEnd = charEnds[c];
|
|
230
|
+
// Settled zone: character has finished its transition
|
|
231
|
+
if (t >= charEnd) {
|
|
232
|
+
if (c < endLength) scrambled += settledText[c];
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
// Pre-transition zone: reveal wave hasn't reached this character yet
|
|
236
|
+
if (t <= 0 || t < charStart) {
|
|
237
|
+
if (hasOverride && c < startLength) {
|
|
238
|
+
if (hasOverrideChars) {
|
|
239
|
+
if (startingText[c] === ' ') {
|
|
240
|
+
scrambled += ' ';
|
|
241
|
+
} else {
|
|
242
|
+
if (refreshChars) /** @type {Array<String>} */(overrideCache)[c] = overrideChar || /** @type {String} */(overrideChars)[rng(0, totalOverrideChars)];
|
|
243
|
+
scrambled += /** @type {Array<String>} */(overrideCache)[c];
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
// Default (override: false): show the original starting text
|
|
247
|
+
scrambled += startingText[c];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
// Active zone: character is between charStart and charEnd
|
|
253
|
+
const isSpace = (c < endLength && settledText[c] === ' ') || (c < startLength && startingText[c] === ' ');
|
|
254
|
+
if (isSpace) {
|
|
255
|
+
scrambled += ' ';
|
|
256
|
+
} else if (hasCursor && t - charStart < cursorZone) {
|
|
257
|
+
// Cursor sub-zone: show cursor character based on position within cursor width
|
|
258
|
+
scrambled += cursorChars[cursorLen - 1 - (((t - charStart) / settleSpacing) | 0)];
|
|
259
|
+
} else {
|
|
260
|
+
// Scramble zone: show cycling random characters
|
|
261
|
+
if (refreshChars) charCache[c] = characters[rng(0, totalChars)];
|
|
262
|
+
scrambled += charCache[c];
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (refreshChars) onChange(scrambled, t);
|
|
266
|
+
return scrambled;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
exports.scrambleText = scrambleText;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anime.js - text - ESM
|
|
3
|
+
* @version v4.4.0
|
|
4
|
+
* @license MIT
|
|
5
|
+
* @copyright 2026 - Julian Garnier
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createSeededRandom } from '../utils/random.js';
|
|
9
|
+
import { globals } from '../core/globals.js';
|
|
10
|
+
import { round } from '../core/helpers.js';
|
|
11
|
+
import { parseEase } from '../easings/eases/parser.js';
|
|
12
|
+
import { noop } from '../core/consts.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @import {
|
|
16
|
+
* ScrambleTextParams,
|
|
17
|
+
* FunctionValue,
|
|
18
|
+
* } from '../types/index.js'
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* '-' is the range operator; place it at the start or end of the string to use it as a literal (e.g. '-abc' or 'abc-')
|
|
23
|
+
* @param {String} str
|
|
24
|
+
* @return {String}
|
|
25
|
+
*/
|
|
26
|
+
const expandCharRanges = (str) => {
|
|
27
|
+
let result = '';
|
|
28
|
+
for (let i = 0, l = str.length; i < l; i++) {
|
|
29
|
+
if (i + 2 < l && str[i + 1] === '-' && str.charCodeAt(i) < str.charCodeAt(i + 2)) {
|
|
30
|
+
const start = str.charCodeAt(i);
|
|
31
|
+
const end = str.charCodeAt(i + 2);
|
|
32
|
+
for (let c = start; c <= end; c++) result += String.fromCharCode(c);
|
|
33
|
+
i += 2;
|
|
34
|
+
} else {
|
|
35
|
+
result += str[i];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const charSets = {
|
|
42
|
+
lowercase: 'a-z',
|
|
43
|
+
uppercase: 'A-Z',
|
|
44
|
+
numbers: '0-9',
|
|
45
|
+
symbols: '!%#_|*+=',
|
|
46
|
+
braille: '⠀-⣿',
|
|
47
|
+
blocks: '▀-▟',
|
|
48
|
+
shades: '░-▓',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const originalTexts = new WeakMap();
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns a function-based tween value that scrambles the target's text content,
|
|
55
|
+
* progressively revealing the original text.
|
|
56
|
+
*
|
|
57
|
+
* @param {ScrambleTextParams} [params]
|
|
58
|
+
* @return {FunctionValue}
|
|
59
|
+
*/
|
|
60
|
+
const scrambleText = (params = {}) => {
|
|
61
|
+
if (!params) params = {};
|
|
62
|
+
const charsParam = params.chars;
|
|
63
|
+
const easeFn = parseEase(params.ease || 'linear');
|
|
64
|
+
const text = params.text;
|
|
65
|
+
const fromParam = params.from;
|
|
66
|
+
const reversed = params.reversed || false;
|
|
67
|
+
const perturbation = params.perturbation || 0;
|
|
68
|
+
const cursorParam = params.cursor;
|
|
69
|
+
const cursorChars = cursorParam === true ? '_'
|
|
70
|
+
: typeof cursorParam === 'number' ? String.fromCharCode(cursorParam)
|
|
71
|
+
: typeof cursorParam === 'string' ? cursorParam
|
|
72
|
+
: '';
|
|
73
|
+
const cursorLen = cursorChars.length;
|
|
74
|
+
const seed = params.seed || 0;
|
|
75
|
+
const override = params.override !== undefined ? params.override : true;
|
|
76
|
+
const revealRate = params.revealRate || 60;
|
|
77
|
+
const interval = 1000 * globals.timeScale / revealRate;
|
|
78
|
+
const settleDuration = params.settleDuration || 300 * globals.timeScale;
|
|
79
|
+
const settleRate = params.settleRate || 30;
|
|
80
|
+
const durationParam = params.duration;
|
|
81
|
+
const revealDelayParam = params.revealDelay;
|
|
82
|
+
const delayParam = params.delay;
|
|
83
|
+
const onChange = params.onChange || noop;
|
|
84
|
+
|
|
85
|
+
return (target, index, targets, prevTween) => {
|
|
86
|
+
const rawChars = typeof charsParam === 'function' ? charsParam(target, index, targets) : (charsParam || 'a-zA-Z0-9!%#_');
|
|
87
|
+
const characters = expandCharRanges(charSets[rawChars] || rawChars);
|
|
88
|
+
const totalChars = characters.length - 1;
|
|
89
|
+
const duration = typeof durationParam === 'function' ? durationParam(target, index, targets) : durationParam;
|
|
90
|
+
const revealDelay = typeof revealDelayParam === 'function' ? revealDelayParam(target, index, targets) : (revealDelayParam || 0);
|
|
91
|
+
const delay = typeof delayParam === 'function' ? delayParam(target, index, targets) : (delayParam || 0);
|
|
92
|
+
const rng = seed ? createSeededRandom(seed) : createSeededRandom();
|
|
93
|
+
if (!originalTexts.has(target)) originalTexts.set(target, target.textContent);
|
|
94
|
+
const startingText = prevTween ? prevTween._value : target.textContent;
|
|
95
|
+
const targetText = text !== undefined
|
|
96
|
+
? (typeof text === 'function' ? text(target, index, targets) : text)
|
|
97
|
+
: prevTween ? prevTween._value
|
|
98
|
+
: originalTexts.get(target);
|
|
99
|
+
const settledText = targetText === ' ' || targetText === ' ' ? ' ' : targetText;
|
|
100
|
+
const startLength = startingText === ' ' ? 0 : startingText.length;
|
|
101
|
+
const endLength = settledText.length;
|
|
102
|
+
const overrideChars = override === true ? characters
|
|
103
|
+
: typeof override === 'string' && override.length > 0 ? expandCharRanges(charSets[/** @type {String} */(override)] || /** @type {String} */(override))
|
|
104
|
+
: null;
|
|
105
|
+
const totalOverrideChars = overrideChars ? overrideChars.length - 1 : 0;
|
|
106
|
+
// Space override uses so the browser doesn't collapse consecutive spaces in innerHTML
|
|
107
|
+
const overrideChar = override === ' ' ? ' ' : null;
|
|
108
|
+
// When starting from blank, only animate the target text length to avoid padding beyond it
|
|
109
|
+
const animLength = override === '' ? endLength : Math.max(startLength, endLength);
|
|
110
|
+
// Compute total duration from interval spacing and settle time, or use the explicit duration
|
|
111
|
+
const animDuration = duration > 0 ? duration : (animLength - 1) * interval + settleDuration;
|
|
112
|
+
const computedDuration = round((animDuration + revealDelay) / globals.timeScale, 0) * globals.timeScale;
|
|
113
|
+
const revealDelayRatio = revealDelay > 0 ? round(revealDelay / computedDuration, 12) : 0;
|
|
114
|
+
// Auto-resolve reveal direction: shrinking text reveals from right, growing from left
|
|
115
|
+
const resolvedFrom = fromParam === undefined || fromParam === 'auto' ? (endLength < startLength ? 'right' : 'left') : fromParam;
|
|
116
|
+
const charOrder = new Int32Array(animLength);
|
|
117
|
+
if (resolvedFrom === 'random') {
|
|
118
|
+
for (let i = 0; i < animLength; i++) charOrder[i] = i;
|
|
119
|
+
for (let i = animLength - 1; i > 0; i--) {
|
|
120
|
+
const j = rng(0, i);
|
|
121
|
+
const t = charOrder[i]; charOrder[i] = charOrder[j]; charOrder[j] = t;
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
const ref = resolvedFrom === 'right' ? (override === '' || !startLength ? animLength : startLength) - 1
|
|
125
|
+
: resolvedFrom === 'center' ? ((override === '' || !startLength ? animLength : startLength) - 1) / 2
|
|
126
|
+
: typeof resolvedFrom === 'number' ? resolvedFrom
|
|
127
|
+
: 0;
|
|
128
|
+
const abs = Math.abs;
|
|
129
|
+
const indices = new Array(animLength);
|
|
130
|
+
for (let i = 0; i < animLength; i++) indices[i] = i;
|
|
131
|
+
indices.sort((a, b) => abs(a - ref) - abs(b - ref));
|
|
132
|
+
for (let i = 0; i < animLength; i++) charOrder[indices[i]] = i;
|
|
133
|
+
}
|
|
134
|
+
if (reversed) {
|
|
135
|
+
const last = animLength - 1;
|
|
136
|
+
for (let i = 0; i < animLength; i++) charOrder[i] = last - charOrder[i];
|
|
137
|
+
}
|
|
138
|
+
// settleRatio is the fraction of the animation each character spends in the active scrambling zone
|
|
139
|
+
const settleRatio = round(settleDuration / animDuration, 12);
|
|
140
|
+
// settleSpacing is the time gap between consecutive characters entering the active zone
|
|
141
|
+
const settleSpacing = round((1 - settleRatio) / animLength, 12);
|
|
142
|
+
const cursorZone = cursorLen * settleSpacing;
|
|
143
|
+
// stepRatio controls how often scramble characters refresh (based on settleRate)
|
|
144
|
+
const stepRatio = round(1000 * globals.timeScale / (settleRate * computedDuration), 12);
|
|
145
|
+
// Pre-compute per-character start and settle times
|
|
146
|
+
const charStarts = new Float32Array(animLength);
|
|
147
|
+
const charEnds = new Float32Array(animLength);
|
|
148
|
+
const scale = perturbation > 0 ? perturbation * settleRatio : 0;
|
|
149
|
+
for (let c = 0; c < animLength; c++) {
|
|
150
|
+
const so = scale > 0 ? (rng(0, 2000) - 1000) / 1000 * scale : 0;
|
|
151
|
+
const eo = scale > 0 ? (rng(0, 2000) - 1000) / 1000 * scale : 0;
|
|
152
|
+
charStarts[c] = charOrder[c] * settleSpacing + so;
|
|
153
|
+
charEnds[c] = Math.ceil((charStarts[c] + settleRatio + eo) / stepRatio) * stepRatio;
|
|
154
|
+
}
|
|
155
|
+
// When text shrinks with non-sequential from modes, delay target settle times past all extras
|
|
156
|
+
if (endLength < animLength && resolvedFrom !== 'left' && resolvedFrom !== 'right' && resolvedFrom !== 'random') {
|
|
157
|
+
let maxExtraEnd = 0;
|
|
158
|
+
for (let c = endLength; c < animLength; c++) {
|
|
159
|
+
if (charEnds[c] > maxExtraEnd) maxExtraEnd = charEnds[c];
|
|
160
|
+
}
|
|
161
|
+
const targets = new Array(endLength);
|
|
162
|
+
for (let c = 0; c < endLength; c++) targets[c] = c;
|
|
163
|
+
targets.sort((a, b) => charOrder[a] - charOrder[b]);
|
|
164
|
+
const targetSpacing = (1 - maxExtraEnd) / endLength;
|
|
165
|
+
for (let i = 0; i < endLength; i++) {
|
|
166
|
+
const revealTime = maxExtraEnd + i * targetSpacing;
|
|
167
|
+
if (revealTime > charEnds[targets[i]]) {
|
|
168
|
+
charEnds[targets[i]] = revealTime;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// charCache holds the current scramble character for each position, refreshed at settleRate
|
|
173
|
+
const charCache = new Array(animLength);
|
|
174
|
+
for (let c = 0; c < animLength; c++) {
|
|
175
|
+
charCache[c] = characters[rng(0, totalChars)];
|
|
176
|
+
}
|
|
177
|
+
// overrideCache holds scramble characters for the starting text (override: true or custom string)
|
|
178
|
+
const overrideCache = overrideChars ? (overrideChars === characters ? charCache : new Array(animLength)) : null;
|
|
179
|
+
if (overrideCache && overrideCache !== charCache) {
|
|
180
|
+
for (let c = 0; c < animLength; c++) {
|
|
181
|
+
overrideCache[c] = overrideChar || /** @type {String} */(overrideChars)[rng(0, overrideChars.length - 1)];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Build the initial display text based on override mode
|
|
185
|
+
let fillStartText = startingText;
|
|
186
|
+
if (!prevTween) {
|
|
187
|
+
if (override === '') {
|
|
188
|
+
fillStartText = '';
|
|
189
|
+
} else if (overrideChars) {
|
|
190
|
+
fillStartText = '';
|
|
191
|
+
for (let c = 0; c < startLength; c++) {
|
|
192
|
+
fillStartText += startingText[c] === ' ' ? ' ' : /** @type {Array<String>} */(overrideCache)[c];
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
let lastValue = -1;
|
|
198
|
+
let lastStep = -1;
|
|
199
|
+
let scrambled = '';
|
|
200
|
+
const hasOverride = override !== '';
|
|
201
|
+
const hasOverrideChars = !!overrideChars;
|
|
202
|
+
const hasCursor = cursorLen > 0;
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
from: 0,
|
|
206
|
+
to: 1,
|
|
207
|
+
duration: computedDuration,
|
|
208
|
+
delay: delay,
|
|
209
|
+
ease: 'linear',
|
|
210
|
+
modifier: (v) => {
|
|
211
|
+
if (v === lastValue) return scrambled;
|
|
212
|
+
lastValue = v;
|
|
213
|
+
if (delay > 0 && v <= 0) { scrambled = startingText; return startingText; }
|
|
214
|
+
if (v <= 0) { scrambled = fillStartText; return fillStartText; }
|
|
215
|
+
if (v >= 1) { scrambled = settledText; return settledText; }
|
|
216
|
+
scrambled = '';
|
|
217
|
+
// Only refresh scramble characters when we cross a settleRate step boundary
|
|
218
|
+
const currentStep = (v / stepRatio) | 0;
|
|
219
|
+
const refreshChars = currentStep !== lastStep;
|
|
220
|
+
if (refreshChars) lastStep = currentStep;
|
|
221
|
+
// Subtract delay ratio to get the effective animation progress
|
|
222
|
+
const linear = revealDelayRatio > 0 ? (v - revealDelayRatio) / (1 - revealDelayRatio) : v;
|
|
223
|
+
const t = linear > 0 ? easeFn(linear) : 0;
|
|
224
|
+
for (let c = 0; c < animLength; c++) {
|
|
225
|
+
// Each character has its own start/end window based on its reveal order
|
|
226
|
+
const charStart = charStarts[c];
|
|
227
|
+
const charEnd = charEnds[c];
|
|
228
|
+
// Settled zone: character has finished its transition
|
|
229
|
+
if (t >= charEnd) {
|
|
230
|
+
if (c < endLength) scrambled += settledText[c];
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
// Pre-transition zone: reveal wave hasn't reached this character yet
|
|
234
|
+
if (t <= 0 || t < charStart) {
|
|
235
|
+
if (hasOverride && c < startLength) {
|
|
236
|
+
if (hasOverrideChars) {
|
|
237
|
+
if (startingText[c] === ' ') {
|
|
238
|
+
scrambled += ' ';
|
|
239
|
+
} else {
|
|
240
|
+
if (refreshChars) /** @type {Array<String>} */(overrideCache)[c] = overrideChar || /** @type {String} */(overrideChars)[rng(0, totalOverrideChars)];
|
|
241
|
+
scrambled += /** @type {Array<String>} */(overrideCache)[c];
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
// Default (override: false): show the original starting text
|
|
245
|
+
scrambled += startingText[c];
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
// Active zone: character is between charStart and charEnd
|
|
251
|
+
const isSpace = (c < endLength && settledText[c] === ' ') || (c < startLength && startingText[c] === ' ');
|
|
252
|
+
if (isSpace) {
|
|
253
|
+
scrambled += ' ';
|
|
254
|
+
} else if (hasCursor && t - charStart < cursorZone) {
|
|
255
|
+
// Cursor sub-zone: show cursor character based on position within cursor width
|
|
256
|
+
scrambled += cursorChars[cursorLen - 1 - (((t - charStart) / settleSpacing) | 0)];
|
|
257
|
+
} else {
|
|
258
|
+
// Scramble zone: show cycling random characters
|
|
259
|
+
if (refreshChars) charCache[c] = characters[rng(0, totalChars)];
|
|
260
|
+
scrambled += charCache[c];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (refreshChars) onChange(scrambled, t);
|
|
264
|
+
return scrambled;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
export { scrambleText };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Anime.js - text - CJS
|
|
3
|
-
* @version v4.
|
|
3
|
+
* @version v4.4.0
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @copyright 2026 - Julian Garnier
|
|
6
6
|
*/
|
|
@@ -197,7 +197,7 @@ const processHTMLTemplate = (htmlTemplate, store, node, $parentFragment, type, d
|
|
|
197
197
|
*/
|
|
198
198
|
class TextSplitter {
|
|
199
199
|
/**
|
|
200
|
-
* @param {
|
|
200
|
+
* @param {Element|NodeList|String|Array<Element>} target
|
|
201
201
|
* @param {TextSplitterParams} [parameters]
|
|
202
202
|
*/
|
|
203
203
|
constructor(target, parameters = {}) {
|
|
@@ -269,11 +269,11 @@ class TextSplitter {
|
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
/**
|
|
272
|
-
* @param {(...args: any[]) => Tickable | (() => void)} effect
|
|
272
|
+
* @param {(...args: any[]) => Tickable | (() => void) | void} effect
|
|
273
273
|
* @return this
|
|
274
274
|
*/
|
|
275
275
|
addEffect(effect) {
|
|
276
|
-
if (!helpers.isFnc(effect))
|
|
276
|
+
if (!helpers.isFnc(effect)) { console.warn('Effect must return a function.'); return this; }
|
|
277
277
|
const refreshableEffect = time.keepTime(effect);
|
|
278
278
|
this.effects.push(refreshableEffect);
|
|
279
279
|
if (this.ready) this.effectsCleanups[this.effects.length - 1] = refreshableEffect(this);
|
|
@@ -479,7 +479,7 @@ class TextSplitter {
|
|
|
479
479
|
}
|
|
480
480
|
|
|
481
481
|
/**
|
|
482
|
-
* @param {
|
|
482
|
+
* @param {Element|NodeList|String|Array<Element>} target
|
|
483
483
|
* @param {TextSplitterParams} [parameters]
|
|
484
484
|
* @return {TextSplitter}
|
|
485
485
|
*/
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export class TextSplitter {
|
|
6
6
|
/**
|
|
7
|
-
* @param {
|
|
7
|
+
* @param {Element|NodeList|String|Array<Element>} target
|
|
8
8
|
* @param {TextSplitterParams} [parameters]
|
|
9
9
|
*/
|
|
10
|
-
constructor(target:
|
|
10
|
+
constructor(target: Element | NodeList | string | Array<Element>, parameters?: TextSplitterParams);
|
|
11
11
|
debug: boolean;
|
|
12
12
|
includeSpaces: boolean;
|
|
13
13
|
accessible: boolean;
|
|
@@ -31,10 +31,10 @@ export class TextSplitter {
|
|
|
31
31
|
resizeTimeout: NodeJS.Timeout;
|
|
32
32
|
resizeObserver: ResizeObserver;
|
|
33
33
|
/**
|
|
34
|
-
* @param {(...args: any[]) => Tickable | (() => void)} effect
|
|
34
|
+
* @param {(...args: any[]) => Tickable | (() => void) | void} effect
|
|
35
35
|
* @return this
|
|
36
36
|
*/
|
|
37
|
-
addEffect(effect: (...args: any[]) => Tickable | (() => void)):
|
|
37
|
+
addEffect(effect: (...args: any[]) => Tickable | (() => void) | void): this;
|
|
38
38
|
revert(): this;
|
|
39
39
|
/**
|
|
40
40
|
* Recursively processes a node and its children
|
|
@@ -48,7 +48,7 @@ export class TextSplitter {
|
|
|
48
48
|
split(clearCache?: boolean): this;
|
|
49
49
|
refresh(): void;
|
|
50
50
|
}
|
|
51
|
-
export function splitText(target:
|
|
51
|
+
export function splitText(target: Element | NodeList | string | Array<Element>, parameters?: TextSplitterParams): TextSplitter;
|
|
52
52
|
export function split(target: HTMLElement | NodeList | string | Array<HTMLElement>, parameters?: TextSplitterParams): TextSplitter;
|
|
53
53
|
export type Segment = {
|
|
54
54
|
segment: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Anime.js - text - ESM
|
|
3
|
-
* @version v4.
|
|
3
|
+
* @version v4.4.0
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @copyright 2026 - Julian Garnier
|
|
6
6
|
*/
|
|
@@ -195,7 +195,7 @@ const processHTMLTemplate = (htmlTemplate, store, node, $parentFragment, type, d
|
|
|
195
195
|
*/
|
|
196
196
|
class TextSplitter {
|
|
197
197
|
/**
|
|
198
|
-
* @param {
|
|
198
|
+
* @param {Element|NodeList|String|Array<Element>} target
|
|
199
199
|
* @param {TextSplitterParams} [parameters]
|
|
200
200
|
*/
|
|
201
201
|
constructor(target, parameters = {}) {
|
|
@@ -267,11 +267,11 @@ class TextSplitter {
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
/**
|
|
270
|
-
* @param {(...args: any[]) => Tickable | (() => void)} effect
|
|
270
|
+
* @param {(...args: any[]) => Tickable | (() => void) | void} effect
|
|
271
271
|
* @return this
|
|
272
272
|
*/
|
|
273
273
|
addEffect(effect) {
|
|
274
|
-
if (!isFnc(effect))
|
|
274
|
+
if (!isFnc(effect)) { console.warn('Effect must return a function.'); return this; }
|
|
275
275
|
const refreshableEffect = keepTime(effect);
|
|
276
276
|
this.effects.push(refreshableEffect);
|
|
277
277
|
if (this.ready) this.effectsCleanups[this.effects.length - 1] = refreshableEffect(this);
|
|
@@ -477,7 +477,7 @@ class TextSplitter {
|
|
|
477
477
|
}
|
|
478
478
|
|
|
479
479
|
/**
|
|
480
|
-
* @param {
|
|
480
|
+
* @param {Element|NodeList|String|Array<Element>} target
|
|
481
481
|
* @param {TextSplitterParams} [parameters]
|
|
482
482
|
* @return {TextSplitter}
|
|
483
483
|
*/
|