@andresclua/perlindom 0.0.6 → 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.
- package/CHANGELOG.md +20 -0
- package/LICENSE +21 -0
- package/dist/perlindom.es.js +212 -0
- package/dist/perlindom.umd.js +1 -0
- package/package.json +14 -6
- package/readme.md +121 -50
- package/dist/PerlinDOM.es.js +0 -138
- package/dist/PerlinDOM.umd.js +0 -1
- package/docs/examples.html +0 -391
- package/public/vite.svg +0 -1
- package/src/index.html +0 -819
- package/src/js/PerlinDom.js +0 -318
- package/src/js/animated-button.js +0 -40
- package/src/js/basic-examples.js +0 -43
- package/src/js/index.js +0 -13
- package/src/js/interactive-controls.js +0 -43
- package/src/js/pause-play.js +0 -33
- package/src/js/triangle-animation.js +0 -48
- package/src/scss/style.scss +0 -20
- package/vite.config.js +0 -36
package/src/js/PerlinDom.js
DELETED
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
class PerlinDOM {
|
|
2
|
-
/* ---------- helpers privados y estáticos ---------- */
|
|
3
|
-
static #mulberry32(a) {
|
|
4
|
-
return function () {
|
|
5
|
-
let t = (a += 0x6d2b79f5);
|
|
6
|
-
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
7
|
-
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
8
|
-
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
static #generatePermutation(seed = 0) {
|
|
13
|
-
const permutation = Array.from({ length: 256 }, (_, i) => i);
|
|
14
|
-
const rand = PerlinDOM.#mulberry32(seed);
|
|
15
|
-
for (let i = 255; i > 0; i--) {
|
|
16
|
-
const j = Math.floor(rand() * (i + 1));
|
|
17
|
-
[permutation[i], permutation[j]] = [permutation[j], permutation[i]];
|
|
18
|
-
}
|
|
19
|
-
return permutation.concat(permutation);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Helper to check if a value is a percentage string
|
|
23
|
-
static #isPercentage(value) {
|
|
24
|
-
return typeof value === 'string' && value.endsWith('%');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Helper to convert percentage to pixels
|
|
28
|
-
static #percentToPixels(percentage, dimension) {
|
|
29
|
-
if (!PerlinDOM.#isPercentage(percentage)) return percentage;
|
|
30
|
-
const value = parseFloat(percentage);
|
|
31
|
-
return (value / 100) * dimension;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
constructor({
|
|
35
|
-
element,
|
|
36
|
-
x = null,
|
|
37
|
-
y = null,
|
|
38
|
-
speed = 0.01,
|
|
39
|
-
seed = 0,
|
|
40
|
-
lerpSpeed = 0.1,
|
|
41
|
-
preserveBaseTranslation = false, // <-- si querés mantener la traslación base
|
|
42
|
-
}) {
|
|
43
|
-
this.el = element;
|
|
44
|
-
this.xRange = x;
|
|
45
|
-
this.yRange = y;
|
|
46
|
-
this.speed = speed;
|
|
47
|
-
this.time = seed;
|
|
48
|
-
this.isPlaying = true;
|
|
49
|
-
this.lerpFactor = 1; // 1 = full speed, 0 = paused
|
|
50
|
-
this.lerpSpeed = lerpSpeed; // How fast to transition between play/pause states
|
|
51
|
-
this.targetLerpFactor = 1; // Target state (1 = play, 0 = pause)
|
|
52
|
-
this.lastX = 0;
|
|
53
|
-
this.lastY = 0;
|
|
54
|
-
this.preserveBaseTranslation = preserveBaseTranslation;
|
|
55
|
-
|
|
56
|
-
// Check if we have percentage values (paréntesis para evitar precedencia ambigua)
|
|
57
|
-
this.hasPercentages = !!(
|
|
58
|
-
(x && (PerlinDOM.#isPercentage(x.min) || PerlinDOM.#isPercentage(x.max))) ||
|
|
59
|
-
(y && (PerlinDOM.#isPercentage(y.min) || PerlinDOM.#isPercentage(y.max)))
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
// Solo inicializar estas propiedades si el elemento no es null
|
|
63
|
-
if (element) {
|
|
64
|
-
// Ensure element has positioning for transform to work properly
|
|
65
|
-
const computedStyle = window.getComputedStyle(element);
|
|
66
|
-
if (computedStyle.position === 'static') {
|
|
67
|
-
element.style.position = 'relative';
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Guardamos el transform inline original para restaurar en destroy()
|
|
71
|
-
this.originalInlineTransform = element.style.transform || '';
|
|
72
|
-
|
|
73
|
-
// Capturamos el transform base (quitando translate en 2D por defecto)
|
|
74
|
-
this.baseTransform = this.#extractBaseTransform(
|
|
75
|
-
computedStyle.transform,
|
|
76
|
-
this.preserveBaseTranslation
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
// Si usamos porcentajes, escuchamos resize
|
|
80
|
-
if (this.hasPercentages) {
|
|
81
|
-
this.handleResize = this.handleResize.bind(this);
|
|
82
|
-
window.addEventListener('resize', this.handleResize);
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
this.originalInlineTransform = '';
|
|
86
|
-
this.baseTransform = '';
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
this.animate = this.animate.bind(this);
|
|
90
|
-
this.init(seed);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
init(seed) {
|
|
94
|
-
this.noise = this.#createPerlin(PerlinDOM.#generatePermutation(seed));
|
|
95
|
-
this.isPlaying = true;
|
|
96
|
-
this.lerpFactor = 1;
|
|
97
|
-
this.targetLerpFactor = 1;
|
|
98
|
-
this.raf = requestAnimationFrame(this.animate);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Permite refrescar el transform base si cambian clases/estilos en runtime
|
|
102
|
-
refreshBaseTransform(preserveTranslation = this.preserveBaseTranslation) {
|
|
103
|
-
if (!this.el) return;
|
|
104
|
-
const cs = window.getComputedStyle(this.el);
|
|
105
|
-
this.baseTransform = this.#extractBaseTransform(cs.transform, preserveTranslation);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Handle window resize for percentage-based values
|
|
109
|
-
handleResize() {
|
|
110
|
-
// No necesitamos recalcular nada fuera de animate; se leen dimensiones en cada frame
|
|
111
|
-
// Este método queda por si querés extender la lógica (debounce, etc.).
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
pause() {
|
|
115
|
-
if (this.isPlaying) {
|
|
116
|
-
this.targetLerpFactor = 0; // Target paused state
|
|
117
|
-
this.isPlaying = false;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
play() {
|
|
122
|
-
if (!this.isPlaying) {
|
|
123
|
-
this.targetLerpFactor = 1; // Target playing state
|
|
124
|
-
this.isPlaying = true;
|
|
125
|
-
|
|
126
|
-
// Solo arrancar un nuevo frame si estaba completamente pausado
|
|
127
|
-
if (this.lerpFactor === 0) {
|
|
128
|
-
this.raf = requestAnimationFrame(this.animate);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
#createPerlin(p) {
|
|
134
|
-
const fade = t => t * t * t * (t * (t * 6 - 15) + 10);
|
|
135
|
-
const lerp = (t, a, b) => a + t * (b - a);
|
|
136
|
-
|
|
137
|
-
// Enhanced gradient function for 2D
|
|
138
|
-
const grad2D = (hash, x, y) => {
|
|
139
|
-
const h = hash & 15;
|
|
140
|
-
const u = h < 8 ? x : y;
|
|
141
|
-
const v = h < 4 ? y : (h === 12 || h === 14 ? x : 0);
|
|
142
|
-
return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
// 1D gradient (kept for backward compatibility)
|
|
146
|
-
const grad1D = (hash, x) => (hash & 1 ? -x : x);
|
|
147
|
-
|
|
148
|
-
return {
|
|
149
|
-
// Original 1D Perlin noise function
|
|
150
|
-
perlin1(x) {
|
|
151
|
-
const X = Math.floor(x) & 255;
|
|
152
|
-
x -= Math.floor(x);
|
|
153
|
-
const u = fade(x);
|
|
154
|
-
return lerp(u, grad1D(p[X], x), grad1D(p[X + 1], x - 1));
|
|
155
|
-
},
|
|
156
|
-
|
|
157
|
-
// New 2D Perlin noise function
|
|
158
|
-
perlin2(x, y) {
|
|
159
|
-
// Integer parts
|
|
160
|
-
const X = Math.floor(x) & 255;
|
|
161
|
-
const Y = Math.floor(y) & 255;
|
|
162
|
-
|
|
163
|
-
// Fractional parts
|
|
164
|
-
x -= Math.floor(x);
|
|
165
|
-
y -= Math.floor(y);
|
|
166
|
-
|
|
167
|
-
// Fade curves
|
|
168
|
-
const u = fade(x);
|
|
169
|
-
const v = fade(y);
|
|
170
|
-
|
|
171
|
-
// Hash coordinates of the 4 corners
|
|
172
|
-
const A = p[X] + Y;
|
|
173
|
-
const B = p[X + 1] + Y;
|
|
174
|
-
const AA = p[A];
|
|
175
|
-
const AB = p[A + 1];
|
|
176
|
-
const BA = p[B];
|
|
177
|
-
const BB = p[B + 1];
|
|
178
|
-
|
|
179
|
-
// Blend the four corner gradients
|
|
180
|
-
return lerp(
|
|
181
|
-
v,
|
|
182
|
-
lerp(u, grad2D(p[AA], x, y), grad2D(p[BA], x - 1, y)),
|
|
183
|
-
lerp(u, grad2D(p[AB], x, y - 1), grad2D(p[BB], x - 1, y - 1))
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
#lerp(a, b, t) {
|
|
190
|
-
return a + t * (b - a);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
animate = () => {
|
|
194
|
-
// Update lerp factor towards target
|
|
195
|
-
if (this.lerpFactor !== this.targetLerpFactor) {
|
|
196
|
-
this.lerpFactor = this.#lerp(this.lerpFactor, this.targetLerpFactor, this.lerpSpeed);
|
|
197
|
-
|
|
198
|
-
// Snap to target if very close
|
|
199
|
-
if (Math.abs(this.lerpFactor - this.targetLerpFactor) < 0.001) {
|
|
200
|
-
this.lerpFactor = this.targetLerpFactor;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Only update time if not completely paused
|
|
205
|
-
if (this.lerpFactor > 0) {
|
|
206
|
-
// Scale time increment by lerp factor for smooth speed transition
|
|
207
|
-
this.time += this.speed * this.lerpFactor;
|
|
208
|
-
|
|
209
|
-
// 2D Perlin noise for more natural movement
|
|
210
|
-
const noiseX = this.noise.perlin2(this.time, 0);
|
|
211
|
-
const noiseY = this.noise.perlin2(this.time, 100); // Different slice
|
|
212
|
-
|
|
213
|
-
// Only process if we have an element
|
|
214
|
-
if (this.el) {
|
|
215
|
-
let minX, maxX, minY, maxY;
|
|
216
|
-
|
|
217
|
-
// Get parent dimensions for percentage calculations if needed
|
|
218
|
-
if (this.hasPercentages) {
|
|
219
|
-
const parent = this.el.parentElement || document.body;
|
|
220
|
-
const parentWidth = parent.clientWidth;
|
|
221
|
-
const parentHeight = parent.clientHeight;
|
|
222
|
-
|
|
223
|
-
// Convert percentage values to pixels if needed
|
|
224
|
-
if (this.xRange) {
|
|
225
|
-
minX = PerlinDOM.#isPercentage(this.xRange.min)
|
|
226
|
-
? PerlinDOM.#percentToPixels(this.xRange.min, parentWidth)
|
|
227
|
-
: this.xRange.min;
|
|
228
|
-
|
|
229
|
-
maxX = PerlinDOM.#isPercentage(this.xRange.max)
|
|
230
|
-
? PerlinDOM.#percentToPixels(this.xRange.max, parentWidth)
|
|
231
|
-
: this.xRange.max;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (this.yRange) {
|
|
235
|
-
minY = PerlinDOM.#isPercentage(this.yRange.min)
|
|
236
|
-
? PerlinDOM.#percentToPixels(this.yRange.min, parentHeight)
|
|
237
|
-
: this.yRange.min;
|
|
238
|
-
|
|
239
|
-
maxY = PerlinDOM.#isPercentage(this.yRange.max)
|
|
240
|
-
? PerlinDOM.#percentToPixels(this.yRange.max, parentHeight)
|
|
241
|
-
: this.yRange.max;
|
|
242
|
-
}
|
|
243
|
-
} else {
|
|
244
|
-
// Use original values if not using percentages
|
|
245
|
-
minX = this.xRange?.min;
|
|
246
|
-
maxX = this.xRange?.max;
|
|
247
|
-
minY = this.yRange?.min;
|
|
248
|
-
maxY = this.yRange?.max;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Calculate pixel values
|
|
252
|
-
const valX = this.xRange ? this.#map(noiseX, -1, 1, minX, maxX) : 0;
|
|
253
|
-
const valY = this.yRange ? this.#map(noiseY, -1, 1, minY, maxY) : 0;
|
|
254
|
-
|
|
255
|
-
// Store current values for potential external use
|
|
256
|
-
this.lastX = valX;
|
|
257
|
-
this.lastY = valY;
|
|
258
|
-
|
|
259
|
-
// Compose translate3d with the base transform (scale/rotate/skew)
|
|
260
|
-
// Orden: primero translate (nuestro movimiento), luego el transform base del diseño
|
|
261
|
-
this.el.style.transform = `translate3d(${valX}px, ${valY}px, 0) ${this.baseTransform}`.trim();
|
|
262
|
-
} else {
|
|
263
|
-
// If no element, just calculate and store the values
|
|
264
|
-
const valX = this.xRange ? this.#map(noiseX, -1, 1, this.xRange.min, this.xRange.max) : 0;
|
|
265
|
-
const valY = this.yRange ? this.#map(noiseY, -1, 1, this.yRange.min, this.yRange.max) : 0;
|
|
266
|
-
|
|
267
|
-
this.lastX = valX;
|
|
268
|
-
this.lastY = valY;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Continue animation if not completely paused or still transitioning
|
|
273
|
-
if (this.lerpFactor > 0 || this.targetLerpFactor > 0) {
|
|
274
|
-
this.raf = requestAnimationFrame(this.animate);
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
#map(n, inMin, inMax, outMin, outMax) {
|
|
279
|
-
return ((n - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Quita o preserva la traslación del transform base en 2D según flag
|
|
283
|
-
#extractBaseTransform(transformValue, preserveTranslation = false) {
|
|
284
|
-
if (!transformValue || transformValue === 'none') return '';
|
|
285
|
-
|
|
286
|
-
try {
|
|
287
|
-
const m = new DOMMatrixReadOnly(transformValue);
|
|
288
|
-
if (m.is2D) {
|
|
289
|
-
// matrix(a, b, c, d, e, f) -> rearmamos con e,f = 0 si NO preservamos traslación
|
|
290
|
-
const e = preserveTranslation ? m.e : 0;
|
|
291
|
-
const f = preserveTranslation ? m.f : 0;
|
|
292
|
-
return `matrix(${m.a}, ${m.b}, ${m.c}, ${m.d}, ${e}, ${f})`;
|
|
293
|
-
} else {
|
|
294
|
-
// 3D: lo dejamos tal cual (remover traslación en 3D requiere descomposición)
|
|
295
|
-
return transformValue;
|
|
296
|
-
}
|
|
297
|
-
} catch {
|
|
298
|
-
// Fallback si DOMMatrix no está disponible o hay un valor raro
|
|
299
|
-
return transformValue;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
destroy() {
|
|
304
|
-
cancelAnimationFrame(this.raf);
|
|
305
|
-
|
|
306
|
-
// Restaurar transform inline original
|
|
307
|
-
if (this.el) {
|
|
308
|
-
this.el.style.transform = this.originalInlineTransform || '';
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Remove resize listener if it was added
|
|
312
|
-
if (this.hasPercentages) {
|
|
313
|
-
window.removeEventListener('resize', this.handleResize);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
export default PerlinDOM;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// Example 7: Animated Button with Circles
|
|
2
|
-
import PerlinDOM from './PerlinDom.js';
|
|
3
|
-
|
|
4
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
5
|
-
// Get all the circle elements inside the button
|
|
6
|
-
const circleElements = document.querySelectorAll('.animated-button .circle');
|
|
7
|
-
|
|
8
|
-
// Create an array to store the animation instances
|
|
9
|
-
let circleAnimations = [];
|
|
10
|
-
|
|
11
|
-
// Function to initialize animations
|
|
12
|
-
function initCircleAnimations() {
|
|
13
|
-
// Clear any existing animations
|
|
14
|
-
circleAnimations.forEach(anim => anim.destroy());
|
|
15
|
-
circleAnimations = [];
|
|
16
|
-
|
|
17
|
-
// Create new animations for each circle
|
|
18
|
-
circleElements.forEach((el, index) => {
|
|
19
|
-
const animation = new PerlinDOM({
|
|
20
|
-
element: el,
|
|
21
|
-
x: { min: -15, max: 15 },
|
|
22
|
-
y: { min: -15, max: 15 },
|
|
23
|
-
speed: 0.007,
|
|
24
|
-
seed: index * 1000,
|
|
25
|
-
lerpSpeed: 0.2 * index
|
|
26
|
-
});
|
|
27
|
-
circleAnimations.push(animation);
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Add event listeners to the button
|
|
32
|
-
document.querySelector('.animated-button')?.addEventListener('mouseenter', () => {
|
|
33
|
-
initCircleAnimations();
|
|
34
|
-
circleAnimations.forEach(anim => anim.play());
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
document.querySelector('.animated-button')?.addEventListener('mouseleave', () => {
|
|
38
|
-
circleAnimations.forEach(anim => anim.pause());
|
|
39
|
-
});
|
|
40
|
-
});
|
package/src/js/basic-examples.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// Examples 1-4: Basic PerlinDOM Examples
|
|
2
|
-
import PerlinDOM from './PerlinDom.js';
|
|
3
|
-
|
|
4
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
5
|
-
// Example 1: Basic Animation
|
|
6
|
-
const basicAnimation = new PerlinDOM({
|
|
7
|
-
element: document.querySelector('.basic-element'),
|
|
8
|
-
x: { min: -50, max: 50 },
|
|
9
|
-
y: { min: -50, max: 50 },
|
|
10
|
-
speed: 0.01,
|
|
11
|
-
seed: 123
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
// Example 2: Horizontal Only
|
|
15
|
-
const horizontalAnimation = new PerlinDOM({
|
|
16
|
-
element: document.querySelector('.horizontal-element'),
|
|
17
|
-
x: { min: -100, max: 100 },
|
|
18
|
-
y: null, // No vertical movement
|
|
19
|
-
speed: 0.02
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
// Example 3: Multiple Elements
|
|
23
|
-
document.querySelectorAll('.particle').forEach((el, index) => {
|
|
24
|
-
new PerlinDOM({
|
|
25
|
-
element: el,
|
|
26
|
-
x: { min: -100, max: 100 + index * 20 }, // Slightly wider range for each element
|
|
27
|
-
y: { min: -100, max: 120}, // Random vertical range
|
|
28
|
-
speed: index * 0.001, // Slightly different speed for each element
|
|
29
|
-
seed: index * 16700 // Different seed for each element
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// Example 4: Background Effect
|
|
34
|
-
document.querySelectorAll('.bg-element').forEach(el => {
|
|
35
|
-
new PerlinDOM({
|
|
36
|
-
element: el,
|
|
37
|
-
x: { min: -110, max: 110 },
|
|
38
|
-
y: { min: -110, max: 110 },
|
|
39
|
-
speed: 0.002, // Very slow movement
|
|
40
|
-
seed: Math.random() * 2000
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
});
|
package/src/js/index.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import PerlinDOM from "./PerlinDom";
|
|
2
|
-
console.log('PerlinDOM loaded');
|
|
3
|
-
|
|
4
|
-
const elements = document.querySelectorAll('.box');
|
|
5
|
-
elements.forEach(el =>
|
|
6
|
-
new PerlinDOM({
|
|
7
|
-
element: el,
|
|
8
|
-
x: { min: -120, max: 120 },
|
|
9
|
-
y: { min: 0, max: 120 },
|
|
10
|
-
speed: 0.001,
|
|
11
|
-
seed: 1
|
|
12
|
-
})
|
|
13
|
-
);
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// Example 6: Interactive Controls
|
|
2
|
-
import PerlinDOM from './PerlinDom.js';
|
|
3
|
-
|
|
4
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
5
|
-
let interactiveAnimation;
|
|
6
|
-
|
|
7
|
-
function initInteractiveAnimation() {
|
|
8
|
-
// Destroy previous instance if it exists
|
|
9
|
-
if (interactiveAnimation) {
|
|
10
|
-
interactiveAnimation.destroy();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// Get current values
|
|
14
|
-
const xRange = parseInt(document.getElementById('x-range').value);
|
|
15
|
-
const yRange = parseInt(document.getElementById('y-range').value);
|
|
16
|
-
const speed = parseFloat(document.getElementById('speed').value);
|
|
17
|
-
const seed = parseInt(document.getElementById('seed').value);
|
|
18
|
-
|
|
19
|
-
// Create new instance
|
|
20
|
-
interactiveAnimation = new PerlinDOM({
|
|
21
|
-
element: document.querySelector('.interactive-element'),
|
|
22
|
-
x: { min: -xRange, max: xRange },
|
|
23
|
-
y: { min: -yRange, max: yRange },
|
|
24
|
-
speed: speed,
|
|
25
|
-
seed: seed
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Update displays
|
|
29
|
-
document.querySelector('#x-range + .value-display').textContent = `-${xRange} to ${xRange}`;
|
|
30
|
-
document.querySelector('#y-range + .value-display').textContent = `-${yRange} to ${yRange}`;
|
|
31
|
-
document.querySelector('#speed + .value-display').textContent = speed.toFixed(3);
|
|
32
|
-
document.querySelector('#seed + .value-display').textContent = seed;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Initialize
|
|
36
|
-
initInteractiveAnimation();
|
|
37
|
-
|
|
38
|
-
// Add event listeners
|
|
39
|
-
document.getElementById('x-range')?.addEventListener('input', initInteractiveAnimation);
|
|
40
|
-
document.getElementById('y-range')?.addEventListener('input', initInteractiveAnimation);
|
|
41
|
-
document.getElementById('speed')?.addEventListener('input', initInteractiveAnimation);
|
|
42
|
-
document.getElementById('seed')?.addEventListener('input', initInteractiveAnimation);
|
|
43
|
-
});
|
package/src/js/pause-play.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
// Example 5: Pause and Play with Mouse Events
|
|
2
|
-
import PerlinDOM from './PerlinDom.js';
|
|
3
|
-
|
|
4
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
5
|
-
// Create the animation
|
|
6
|
-
const pausePlayAnimation = new PerlinDOM({
|
|
7
|
-
element: document.querySelector('.pause-play-element'),
|
|
8
|
-
x: { min: -80, max: 80 },
|
|
9
|
-
y: { min: -180, max: 80 },
|
|
10
|
-
speed: 0.01,
|
|
11
|
-
seed: 42,
|
|
12
|
-
lerpSpeed: 0.05 // Controls how smooth the transition is
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
// Pause on mouse leave
|
|
16
|
-
document.querySelector('.pause-play-container')?.addEventListener('mouseleave', () => {
|
|
17
|
-
pausePlayAnimation.pause();
|
|
18
|
-
document.querySelector('.status-indicator').textContent = 'Pausing...';
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// Play on mouse enter
|
|
22
|
-
document.querySelector('.pause-play-container')?.addEventListener('mouseenter', () => {
|
|
23
|
-
pausePlayAnimation.play();
|
|
24
|
-
document.querySelector('.status-indicator').textContent = 'Playing...';
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Update lerpSpeed when slider changes
|
|
28
|
-
document.getElementById('lerp-speed')?.addEventListener('input', (e) => {
|
|
29
|
-
const newSpeed = parseFloat(e.target.value);
|
|
30
|
-
pausePlayAnimation.lerpSpeed = newSpeed;
|
|
31
|
-
document.querySelector('.lerp-value').textContent = newSpeed.toFixed(2);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// Example 8: ClipPath Triangle with Animated Vertex
|
|
2
|
-
import PerlinDOM from './PerlinDom.js';
|
|
3
|
-
|
|
4
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
5
|
-
// Get the polygon element
|
|
6
|
-
const trianglePath = document.getElementById('trianglePath');
|
|
7
|
-
|
|
8
|
-
if (!trianglePath) return;
|
|
9
|
-
|
|
10
|
-
// Store the original points
|
|
11
|
-
const originalPoints = {
|
|
12
|
-
x1: 150, y1: 50, // Top vertex
|
|
13
|
-
x2: 250, y2: 250, // Bottom right
|
|
14
|
-
x3: 50, y3: 250 // Bottom left
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
// Create a custom animation function
|
|
18
|
-
function animateTriangle() {
|
|
19
|
-
// Create a PerlinDOM instance for the top vertex
|
|
20
|
-
const topVertexAnimation = new PerlinDOM({
|
|
21
|
-
element: null, // We're not moving a DOM element directly
|
|
22
|
-
x: { min: -30, max: 30 },
|
|
23
|
-
y: { min: -20, max: 20 },
|
|
24
|
-
speed: 0.005,
|
|
25
|
-
seed: 42
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Animation function
|
|
29
|
-
function updateTriangle() {
|
|
30
|
-
// Get the current noise values
|
|
31
|
-
const offsetX = topVertexAnimation.lastX;
|
|
32
|
-
const offsetY = topVertexAnimation.lastY;
|
|
33
|
-
|
|
34
|
-
// Update the polygon points
|
|
35
|
-
const newPoints = `${originalPoints.x1 + offsetX},${originalPoints.y1 + offsetY} ${originalPoints.x2},${originalPoints.y2} ${originalPoints.x3},${originalPoints.y3}`;
|
|
36
|
-
trianglePath.setAttribute('points', newPoints);
|
|
37
|
-
|
|
38
|
-
// Continue animation
|
|
39
|
-
requestAnimationFrame(updateTriangle);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Start the animation
|
|
43
|
-
updateTriangle();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Initialize the animation
|
|
47
|
-
animateTriangle();
|
|
48
|
-
});
|
package/src/scss/style.scss
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
.spacer{
|
|
2
|
-
padding:120px;
|
|
3
|
-
border:1px solid red;
|
|
4
|
-
position:relative;
|
|
5
|
-
overflow: hidden;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
.box{
|
|
10
|
-
width:120px;
|
|
11
|
-
height:120px;
|
|
12
|
-
border-radius: 50%;
|
|
13
|
-
background-color: blue;
|
|
14
|
-
position:absolute;
|
|
15
|
-
left:0;
|
|
16
|
-
top:-20%;
|
|
17
|
-
filter: blur(40px) drop-shadow(0 0 20px rgba(0, 0, 255, 0.5));
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
package/vite.config.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vite';
|
|
2
|
-
import { resolve } from 'path';
|
|
3
|
-
|
|
4
|
-
const root = resolve(__dirname, 'src');
|
|
5
|
-
const outDir = resolve(__dirname, 'dist');
|
|
6
|
-
const entryPath = resolve(__dirname, 'src/js/PerlinDOM.js');
|
|
7
|
-
|
|
8
|
-
export default defineConfig({
|
|
9
|
-
root,
|
|
10
|
-
publicDir: 'public',
|
|
11
|
-
plugins: [],
|
|
12
|
-
build: {
|
|
13
|
-
lib: {
|
|
14
|
-
entry: entryPath,
|
|
15
|
-
name: 'PerlinDOM', // Library name as : Counter | etc
|
|
16
|
-
formats: ['es', 'umd'], // Output formats as : es | umd, es is for modern browsers, umd is for older browsers
|
|
17
|
-
fileName: (format,name) => `PerlinDOM.${format}.js`, // File naming as : reveal-it | collapsify | etc
|
|
18
|
-
},
|
|
19
|
-
outDir,
|
|
20
|
-
emptyOutDir: true,
|
|
21
|
-
// rollupOptions: {
|
|
22
|
-
|
|
23
|
-
// output: {
|
|
24
|
-
// name: 'Validate',
|
|
25
|
-
// },
|
|
26
|
-
// },
|
|
27
|
-
},
|
|
28
|
-
resolve: {
|
|
29
|
-
alias: {
|
|
30
|
-
'@': resolve(__dirname, './src'),
|
|
31
|
-
'@js': resolve(__dirname, './src/js'),
|
|
32
|
-
'@scss': resolve(__dirname, './src/scss'),
|
|
33
|
-
'@assets': resolve(__dirname, './src/assets'),
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
});
|