@andresclua/perlindom 0.0.4 → 0.0.6

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 CHANGED
@@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.0.6] - 2025-02-09
9
+
10
+ ## Changed
11
+ - **Transform Handling**: Movement now composes `translate3d` with existing CSS transforms (`scale`, `rotate`, etc.) instead of overriding them
12
+ - **Base Transform Extraction**: Introduced `#extractBaseTransform()` to strip prior translations while keeping scale/rotate/skew intact
13
+ - **Destroy Behavior**: `destroy()` now restores the original inline `transform` value of the element
14
+
15
+ ### Improved
16
+ - **Configuration**: Added `preserveBaseTranslation` option to control whether original translations are kept
17
+ - **Flexibility**: New `refreshBaseTransform()` method allows recalculating the base transform when classes or styles change dynamically
18
+
19
+ ## [0.0.5] - 2025-01-07
20
+
21
+ - **Remove logs** : remove logs
22
+
23
+ ## [0.0.4] - 2025-01-07
24
+
25
+ ### Changed
26
+ - **Package Configuration**: Updated package to be public (removed `"private": true`)
27
+ - **NPM Publishing**: Package is now available for public installation via npm
28
+ - **Module Exports**: Enhanced module exports configuration for better compatibility
29
+ - **Package Metadata**: Updated package name to `@andresclua/perlindom` with proper scoping
30
+
31
+ ### Improved
32
+ - **Distribution**: Better UMD and ES module support through improved exports configuration
33
+ - **Accessibility**: Package now publicly available on npm registry
34
+
8
35
  ## [0.0.3] - 2025-01-07
9
36
 
10
37
  ### Fixed
@@ -1,121 +1,138 @@
1
- var $ = Object.defineProperty;
2
- var q = (c) => {
1
+ var D = Object.defineProperty;
2
+ var z = (c) => {
3
3
  throw TypeError(c);
4
4
  };
5
- var j = (c, t, i) => t in c ? $(c, t, { enumerable: !0, configurable: !0, writable: !0, value: i }) : c[t] = i;
6
- var D = (c, t, i) => j(c, typeof t != "symbol" ? t + "" : t, i), O = (c, t, i) => t.has(c) || q("Cannot " + i);
7
- var A = (c, t, i) => t.has(c) ? q("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(c) : t.set(c, i);
8
- var a = (c, t, i) => (O(c, t, "access private method"), i);
9
- var n, W, H, u, X, p, S, T, L;
10
- const o = class o {
5
+ var H = (c, t, s) => t in c ? D(c, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : c[t] = s;
6
+ var S = (c, t, s) => H(c, typeof t != "symbol" ? t + "" : t, s), j = (c, t, s) => t.has(c) || z("Cannot " + s);
7
+ var A = (c, t, s) => t.has(c) ? z("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(c) : t.set(c, s);
8
+ var n = (c, t, s) => (j(c, t, "access private method"), s);
9
+ var r, E, I, d, P, f, W, C, T, B;
10
+ const l = class l {
11
11
  constructor({
12
12
  element: t,
13
- x: i = null,
14
- y: h = null,
15
- speed: r = 0.01,
16
- seed: l = 0,
17
- lerpSpeed: s = 0.1
13
+ x: s = null,
14
+ y: e = null,
15
+ speed: h = 0.01,
16
+ seed: o = 0,
17
+ lerpSpeed: i = 0.1,
18
+ preserveBaseTranslation: a = !1
19
+ // <-- si querés mantener la traslación base
18
20
  }) {
19
- A(this, p);
20
- D(this, "animate", () => {
21
- var t, i, h, r, l, s, e, g, m, f, R, y;
22
- if (this.lerpFactor !== this.targetLerpFactor && (this.lerpFactor = a(this, p, T).call(this, this.lerpFactor, this.targetLerpFactor, this.lerpSpeed), Math.abs(this.lerpFactor - this.targetLerpFactor) < 1e-3 && (this.lerpFactor = this.targetLerpFactor)), this.lerpFactor > 0) {
21
+ A(this, f);
22
+ S(this, "animate", () => {
23
+ var t, s, e, h, o, i, a, m, g, p, u, R;
24
+ if (this.lerpFactor !== this.targetLerpFactor && (this.lerpFactor = n(this, f, C).call(this, this.lerpFactor, this.targetLerpFactor, this.lerpSpeed), Math.abs(this.lerpFactor - this.targetLerpFactor) < 1e-3 && (this.lerpFactor = this.targetLerpFactor)), this.lerpFactor > 0) {
23
25
  this.time += this.speed * this.lerpFactor;
24
- const P = this.noise.perlin2(this.time, 0), Y = this.noise.perlin2(this.time, 100);
26
+ const x = this.noise.perlin2(this.time, 0), b = this.noise.perlin2(this.time, 100);
25
27
  if (this.el) {
26
- let d, F, x, v;
28
+ let F, y, v, L;
27
29
  if (this.hasPercentages) {
28
- const b = this.el.parentElement || document.body, B = b.clientWidth, w = b.clientHeight;
29
- this.xRange && (d = a(t = o, n, u).call(t, this.xRange.min) ? a(i = o, n, X).call(i, this.xRange.min, B) : this.xRange.min, F = a(h = o, n, u).call(h, this.xRange.max) ? a(r = o, n, X).call(r, this.xRange.max, B) : this.xRange.max), this.yRange && (x = a(l = o, n, u).call(l, this.yRange.min) ? a(s = o, n, X).call(s, this.yRange.min, w) : this.yRange.min, v = a(e = o, n, u).call(e, this.yRange.max) ? a(g = o, n, X).call(g, this.yRange.max, w) : this.yRange.max);
30
+ const Y = this.el.parentElement || document.body, $ = Y.clientWidth, M = Y.clientHeight;
31
+ this.xRange && (F = n(t = l, r, d).call(t, this.xRange.min) ? n(s = l, r, P).call(s, this.xRange.min, $) : this.xRange.min, y = n(e = l, r, d).call(e, this.xRange.max) ? n(h = l, r, P).call(h, this.xRange.max, $) : this.xRange.max), this.yRange && (v = n(o = l, r, d).call(o, this.yRange.min) ? n(i = l, r, P).call(i, this.yRange.min, M) : this.yRange.min, L = n(a = l, r, d).call(a, this.yRange.max) ? n(m = l, r, P).call(m, this.yRange.max, M) : this.yRange.max);
30
32
  } else
31
- d = (m = this.xRange) == null ? void 0 : m.min, F = (f = this.xRange) == null ? void 0 : f.max, x = (R = this.yRange) == null ? void 0 : R.min, v = (y = this.yRange) == null ? void 0 : y.max;
32
- const M = this.xRange ? a(this, p, L).call(this, P, -1, 1, d, F) : 0, z = this.yRange ? a(this, p, L).call(this, Y, -1, 1, x, v) : 0;
33
- this.lastX = M, this.lastY = z, this.el.style.left = `${this.initialX + M}px`, this.el.style.top = `${this.initialY + z}px`;
33
+ F = (g = this.xRange) == null ? void 0 : g.min, y = (p = this.xRange) == null ? void 0 : p.max, v = (u = this.yRange) == null ? void 0 : u.min, L = (R = this.yRange) == null ? void 0 : R.max;
34
+ const X = this.xRange ? n(this, f, T).call(this, x, -1, 1, F, y) : 0, w = this.yRange ? n(this, f, T).call(this, b, -1, 1, v, L) : 0;
35
+ this.lastX = X, this.lastY = w, this.el.style.transform = `translate3d(${X}px, ${w}px, 0) ${this.baseTransform}`.trim();
34
36
  } else {
35
- const d = this.xRange ? a(this, p, L).call(this, P, -1, 1, this.xRange.min, this.xRange.max) : 0, F = this.yRange ? a(this, p, L).call(this, Y, -1, 1, this.yRange.min, this.yRange.max) : 0;
36
- this.lastX = d, this.lastY = F;
37
+ const F = this.xRange ? n(this, f, T).call(this, x, -1, 1, this.xRange.min, this.xRange.max) : 0, y = this.yRange ? n(this, f, T).call(this, b, -1, 1, this.yRange.min, this.yRange.max) : 0;
38
+ this.lastX = F, this.lastY = y;
37
39
  }
38
40
  }
39
41
  (this.lerpFactor > 0 || this.targetLerpFactor > 0) && (this.raf = requestAnimationFrame(this.animate));
40
42
  });
41
- var e, g, m, f;
42
- this.el = t, this.xRange = i, this.yRange = h, this.speed = r, this.time = l, this.isPlaying = !0, this.lerpFactor = 1, this.lerpSpeed = s, this.targetLerpFactor = 1, this.lastX = 0, this.lastY = 0, this.hasPercentages = !1, (i && (a(e = o, n, u).call(e, i.min) || a(g = o, n, u).call(g, i.max)) || h && (a(m = o, n, u).call(m, h.min) || a(f = o, n, u).call(f, h.max))) && (this.hasPercentages = !0), t ? (this.initialX = t.offsetLeft, this.initialY = t.offsetTop, this.hasPercentages && (this.handleResize = this.handleResize.bind(this), window.addEventListener("resize", this.handleResize))) : (this.initialX = 0, this.initialY = 0), this.animate = this.animate.bind(this), this.init(l);
43
+ var m, g, p, u;
44
+ if (this.el = t, this.xRange = s, this.yRange = e, this.speed = h, this.time = o, this.isPlaying = !0, this.lerpFactor = 1, this.lerpSpeed = i, this.targetLerpFactor = 1, this.lastX = 0, this.lastY = 0, this.preserveBaseTranslation = a, this.hasPercentages = !!(s && (n(m = l, r, d).call(m, s.min) || n(g = l, r, d).call(g, s.max)) || e && (n(p = l, r, d).call(p, e.min) || n(u = l, r, d).call(u, e.max))), t) {
45
+ const R = window.getComputedStyle(t);
46
+ R.position === "static" && (t.style.position = "relative"), this.originalInlineTransform = t.style.transform || "", this.baseTransform = n(this, f, B).call(this, R.transform, this.preserveBaseTranslation), this.hasPercentages && (this.handleResize = this.handleResize.bind(this), window.addEventListener("resize", this.handleResize));
47
+ } else
48
+ this.originalInlineTransform = "", this.baseTransform = "";
49
+ this.animate = this.animate.bind(this), this.init(o);
43
50
  }
44
51
  init(t) {
45
- var i;
46
- this.noise = a(this, p, S).call(this, a(i = o, n, H).call(i, t)), this.isPlaying = !0, this.lerpFactor = 1, this.targetLerpFactor = 1, this.raf = requestAnimationFrame(this.animate), console.log("PerlinDOM initialized");
52
+ var s;
53
+ this.noise = n(this, f, W).call(this, n(s = l, r, I).call(s, t)), this.isPlaying = !0, this.lerpFactor = 1, this.targetLerpFactor = 1, this.raf = requestAnimationFrame(this.animate);
54
+ }
55
+ // Permite refrescar el transform base si cambian clases/estilos en runtime
56
+ refreshBaseTransform(t = this.preserveBaseTranslation) {
57
+ if (!this.el) return;
58
+ const s = window.getComputedStyle(this.el);
59
+ this.baseTransform = n(this, f, B).call(this, s.transform, t);
47
60
  }
48
61
  // Handle window resize for percentage-based values
49
62
  handleResize() {
50
- this.hasPercentages && this.el && (this.needsRecalculation = !0);
51
63
  }
52
64
  pause() {
53
- this.isPlaying && (this.targetLerpFactor = 0, this.isPlaying = !1, console.log("PerlinDOM pausing..."));
65
+ this.isPlaying && (this.targetLerpFactor = 0, this.isPlaying = !1);
54
66
  }
55
67
  play() {
56
- this.isPlaying || (this.targetLerpFactor = 1, this.isPlaying = !0, this.lerpFactor === 0 && (this.raf = requestAnimationFrame(this.animate)), console.log("PerlinDOM playing..."));
68
+ this.isPlaying || (this.targetLerpFactor = 1, this.isPlaying = !0, this.lerpFactor === 0 && (this.raf = requestAnimationFrame(this.animate)));
57
69
  }
58
70
  destroy() {
59
- cancelAnimationFrame(this.raf), this.hasPercentages && window.removeEventListener("resize", this.handleResize);
71
+ cancelAnimationFrame(this.raf), this.el && (this.el.style.transform = this.originalInlineTransform || ""), this.hasPercentages && window.removeEventListener("resize", this.handleResize);
60
72
  }
61
73
  };
62
- n = new WeakSet(), W = function(t) {
74
+ r = new WeakSet(), E = function(t) {
63
75
  return function() {
64
- let i = t += 1831565813;
65
- return i = Math.imul(i ^ i >>> 15, i | 1), i ^= i + Math.imul(i ^ i >>> 7, i | 61), ((i ^ i >>> 14) >>> 0) / 4294967296;
76
+ let s = t += 1831565813;
77
+ return s = Math.imul(s ^ s >>> 15, s | 1), s ^= s + Math.imul(s ^ s >>> 7, s | 61), ((s ^ s >>> 14) >>> 0) / 4294967296;
66
78
  };
67
- }, H = function(t = 0) {
68
- var r;
69
- const i = Array.from({ length: 256 }, (l, s) => s), h = a(r = o, n, W).call(r, t);
70
- for (let l = 255; l > 0; l--) {
71
- const s = Math.floor(h() * (l + 1));
72
- [i[l], i[s]] = [i[s], i[l]];
79
+ }, I = function(t = 0) {
80
+ var h;
81
+ const s = Array.from({ length: 256 }, (o, i) => i), e = n(h = l, r, E).call(h, t);
82
+ for (let o = 255; o > 0; o--) {
83
+ const i = Math.floor(e() * (o + 1));
84
+ [s[o], s[i]] = [s[i], s[o]];
73
85
  }
74
- return i.concat(i);
75
- }, u = function(t) {
86
+ return s.concat(s);
87
+ }, d = function(t) {
76
88
  return typeof t == "string" && t.endsWith("%");
77
- }, X = function(t, i) {
78
- var r;
79
- return a(r = o, n, u).call(r, t) ? parseFloat(t) / 100 * i : t;
80
- }, p = new WeakSet(), S = function(t) {
81
- const i = (s) => s * s * s * (s * (s * 6 - 15) + 10), h = (s, e, g) => e + s * (g - e), r = (s, e, g) => {
82
- const m = s & 15, f = m < 8 ? e : g, R = m < 4 ? g : m === 12 || m === 14 ? e : 0;
83
- return (m & 1 ? -f : f) + (m & 2 ? -R : R);
84
- }, l = (s, e) => s & 1 ? -e : e;
89
+ }, P = function(t, s) {
90
+ var h;
91
+ return n(h = l, r, d).call(h, t) ? parseFloat(t) / 100 * s : t;
92
+ }, f = new WeakSet(), W = function(t) {
93
+ const s = (i) => i * i * i * (i * (i * 6 - 15) + 10), e = (i, a, m) => a + i * (m - a), h = (i, a, m) => {
94
+ const g = i & 15, p = g < 8 ? a : m, u = g < 4 ? m : g === 12 || g === 14 ? a : 0;
95
+ return (g & 1 ? -p : p) + (g & 2 ? -u : u);
96
+ }, o = (i, a) => i & 1 ? -a : a;
85
97
  return {
86
98
  // Original 1D Perlin noise function
87
- perlin1(s) {
88
- const e = Math.floor(s) & 255;
89
- s -= Math.floor(s);
90
- const g = i(s);
91
- return h(g, l(t[e], s), l(t[e + 1], s - 1));
99
+ perlin1(i) {
100
+ const a = Math.floor(i) & 255;
101
+ i -= Math.floor(i);
102
+ const m = s(i);
103
+ return e(m, o(t[a], i), o(t[a + 1], i - 1));
92
104
  },
93
105
  // New 2D Perlin noise function
94
- perlin2(s, e) {
95
- const g = Math.floor(s) & 255, m = Math.floor(e) & 255;
96
- s -= Math.floor(s), e -= Math.floor(e);
97
- const f = i(s), R = i(e), y = t[g] + m, P = t[g + 1] + m, Y = t[y], d = t[y + 1], F = t[P], x = t[P + 1];
98
- return h(
99
- R,
100
- h(
101
- f,
102
- r(t[Y], s, e),
103
- r(t[F], s - 1, e)
104
- ),
105
- h(
106
- f,
107
- r(t[d], s, e - 1),
108
- r(t[x], s - 1, e - 1)
109
- )
106
+ perlin2(i, a) {
107
+ const m = Math.floor(i) & 255, g = Math.floor(a) & 255;
108
+ i -= Math.floor(i), a -= Math.floor(a);
109
+ const p = s(i), u = s(a), R = t[m] + g, x = t[m + 1] + g, b = t[R], F = t[R + 1], y = t[x], v = t[x + 1];
110
+ return e(
111
+ u,
112
+ e(p, h(t[b], i, a), h(t[y], i - 1, a)),
113
+ e(p, h(t[F], i, a - 1), h(t[v], i - 1, a - 1))
110
114
  );
111
115
  }
112
116
  };
113
- }, T = function(t, i, h) {
114
- return t + h * (i - t);
115
- }, L = function(t, i, h, r, l) {
116
- return (t - i) * (l - r) / (h - i) + r;
117
- }, A(o, n);
118
- let E = o;
117
+ }, C = function(t, s, e) {
118
+ return t + e * (s - t);
119
+ }, T = function(t, s, e, h, o) {
120
+ return (t - s) * (o - h) / (e - s) + h;
121
+ }, // Quita o preserva la traslación del transform base en 2D según flag
122
+ B = function(t, s = !1) {
123
+ if (!t || t === "none") return "";
124
+ try {
125
+ const e = new DOMMatrixReadOnly(t);
126
+ if (e.is2D) {
127
+ const h = s ? e.e : 0, o = s ? e.f : 0;
128
+ return `matrix(${e.a}, ${e.b}, ${e.c}, ${e.d}, ${h}, ${o})`;
129
+ } else
130
+ return t;
131
+ } catch {
132
+ return t;
133
+ }
134
+ }, A(l, r);
135
+ let q = l;
119
136
  export {
120
- E as default
137
+ q as default
121
138
  };
@@ -1 +1 @@
1
- (function(a,t){typeof exports=="object"&&typeof module<"u"?module.exports=t():typeof define=="function"&&define.amd?define(t):(a=typeof globalThis<"u"?globalThis:a||self,a.PerlinDOM=t())})(this,function(){"use strict";var O=Object.defineProperty;var T=a=>{throw TypeError(a)};var S=(a,t,p)=>t in a?O(a,t,{enumerable:!0,configurable:!0,writable:!0,value:p}):a[t]=p;var q=(a,t,p)=>S(a,typeof t!="symbol"?t+"":t,p),$=(a,t,p)=>t.has(a)||T("Cannot "+p);var M=(a,t,p)=>t.has(a)?T("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(a):t.set(a,p);var h=(a,t,p)=>($(a,t,"access private method"),p);var t,E,W,d,L,f,j,H,Y;const o=class o{constructor({element:e,x:i=null,y:r=null,speed:l=.01,seed:c=0,lerpSpeed:s=.1}){M(this,f);q(this,"animate",()=>{var e,i,r,l,c,s,n,g,m,u,R,P;if(this.lerpFactor!==this.targetLerpFactor&&(this.lerpFactor=h(this,f,H).call(this,this.lerpFactor,this.targetLerpFactor,this.lerpSpeed),Math.abs(this.lerpFactor-this.targetLerpFactor)<.001&&(this.lerpFactor=this.targetLerpFactor)),this.lerpFactor>0){this.time+=this.speed*this.lerpFactor;const x=this.noise.perlin2(this.time,0),v=this.noise.perlin2(this.time,100);if(this.el){let F,y,X,A;if(this.hasPercentages){const B=this.el.parentElement||document.body,w=B.clientWidth,D=B.clientHeight;this.xRange&&(F=h(e=o,t,d).call(e,this.xRange.min)?h(i=o,t,L).call(i,this.xRange.min,w):this.xRange.min,y=h(r=o,t,d).call(r,this.xRange.max)?h(l=o,t,L).call(l,this.xRange.max,w):this.xRange.max),this.yRange&&(X=h(c=o,t,d).call(c,this.yRange.min)?h(s=o,t,L).call(s,this.yRange.min,D):this.yRange.min,A=h(n=o,t,d).call(n,this.yRange.max)?h(g=o,t,L).call(g,this.yRange.max,D):this.yRange.max)}else F=(m=this.xRange)==null?void 0:m.min,y=(u=this.xRange)==null?void 0:u.max,X=(R=this.yRange)==null?void 0:R.min,A=(P=this.yRange)==null?void 0:P.max;const z=this.xRange?h(this,f,Y).call(this,x,-1,1,F,y):0,b=this.yRange?h(this,f,Y).call(this,v,-1,1,X,A):0;this.lastX=z,this.lastY=b,this.el.style.left=`${this.initialX+z}px`,this.el.style.top=`${this.initialY+b}px`}else{const F=this.xRange?h(this,f,Y).call(this,x,-1,1,this.xRange.min,this.xRange.max):0,y=this.yRange?h(this,f,Y).call(this,v,-1,1,this.yRange.min,this.yRange.max):0;this.lastX=F,this.lastY=y}}(this.lerpFactor>0||this.targetLerpFactor>0)&&(this.raf=requestAnimationFrame(this.animate))});var n,g,m,u;this.el=e,this.xRange=i,this.yRange=r,this.speed=l,this.time=c,this.isPlaying=!0,this.lerpFactor=1,this.lerpSpeed=s,this.targetLerpFactor=1,this.lastX=0,this.lastY=0,this.hasPercentages=!1,(i&&(h(n=o,t,d).call(n,i.min)||h(g=o,t,d).call(g,i.max))||r&&(h(m=o,t,d).call(m,r.min)||h(u=o,t,d).call(u,r.max)))&&(this.hasPercentages=!0),e?(this.initialX=e.offsetLeft,this.initialY=e.offsetTop,this.hasPercentages&&(this.handleResize=this.handleResize.bind(this),window.addEventListener("resize",this.handleResize))):(this.initialX=0,this.initialY=0),this.animate=this.animate.bind(this),this.init(c)}init(e){var i;this.noise=h(this,f,j).call(this,h(i=o,t,W).call(i,e)),this.isPlaying=!0,this.lerpFactor=1,this.targetLerpFactor=1,this.raf=requestAnimationFrame(this.animate),console.log("PerlinDOM initialized")}handleResize(){this.hasPercentages&&this.el&&(this.needsRecalculation=!0)}pause(){this.isPlaying&&(this.targetLerpFactor=0,this.isPlaying=!1,console.log("PerlinDOM pausing..."))}play(){this.isPlaying||(this.targetLerpFactor=1,this.isPlaying=!0,this.lerpFactor===0&&(this.raf=requestAnimationFrame(this.animate)),console.log("PerlinDOM playing..."))}destroy(){cancelAnimationFrame(this.raf),this.hasPercentages&&window.removeEventListener("resize",this.handleResize)}};t=new WeakSet,E=function(e){return function(){let i=e+=1831565813;return i=Math.imul(i^i>>>15,i|1),i^=i+Math.imul(i^i>>>7,i|61),((i^i>>>14)>>>0)/4294967296}},W=function(e=0){var l;const i=Array.from({length:256},(c,s)=>s),r=h(l=o,t,E).call(l,e);for(let c=255;c>0;c--){const s=Math.floor(r()*(c+1));[i[c],i[s]]=[i[s],i[c]]}return i.concat(i)},d=function(e){return typeof e=="string"&&e.endsWith("%")},L=function(e,i){var l;return h(l=o,t,d).call(l,e)?parseFloat(e)/100*i:e},f=new WeakSet,j=function(e){const i=s=>s*s*s*(s*(s*6-15)+10),r=(s,n,g)=>n+s*(g-n),l=(s,n,g)=>{const m=s&15,u=m<8?n:g,R=m<4?g:m===12||m===14?n:0;return(m&1?-u:u)+(m&2?-R:R)},c=(s,n)=>s&1?-n:n;return{perlin1(s){const n=Math.floor(s)&255;s-=Math.floor(s);const g=i(s);return r(g,c(e[n],s),c(e[n+1],s-1))},perlin2(s,n){const g=Math.floor(s)&255,m=Math.floor(n)&255;s-=Math.floor(s),n-=Math.floor(n);const u=i(s),R=i(n),P=e[g]+m,x=e[g+1]+m,v=e[P],F=e[P+1],y=e[x],X=e[x+1];return r(R,r(u,l(e[v],s,n),l(e[y],s-1,n)),r(u,l(e[F],s,n-1),l(e[X],s-1,n-1)))}}},H=function(e,i,r){return e+r*(i-e)},Y=function(e,i,r,l,c){return(e-i)*(c-l)/(r-i)+l},M(o,t);let a=o;return a});
1
+ (function(h,s){typeof exports=="object"&&typeof module<"u"?module.exports=s():typeof define=="function"&&define.amd?define(s):(h=typeof globalThis<"u"?globalThis:h||self,h.PerlinDOM=s())})(this,function(){"use strict";var j=Object.defineProperty;var S=h=>{throw TypeError(h)};var C=(h,s,u)=>s in h?j(h,s,{enumerable:!0,configurable:!0,writable:!0,value:u}):h[s]=u;var q=(h,s,u)=>C(h,typeof s!="symbol"?s+"":s,u),H=(h,s,u)=>s.has(h)||S("Cannot "+u);var B=(h,s,u)=>s.has(h)?S("Cannot add the same private member more than once"):s instanceof WeakSet?s.add(h):s.set(h,u);var r=(h,s,u)=>(H(h,s,"access private method"),u);var s,D,E,R,P,g,I,W,b,X;const c=class c{constructor({element:t,x:i=null,y:n=null,speed:o=.01,seed:l=0,lerpSpeed:e=.1,preserveBaseTranslation:a=!1}){B(this,g);q(this,"animate",()=>{var t,i,n,o,l,e,a,m,f,p,d,y;if(this.lerpFactor!==this.targetLerpFactor&&(this.lerpFactor=r(this,g,W).call(this,this.lerpFactor,this.targetLerpFactor,this.lerpSpeed),Math.abs(this.lerpFactor-this.targetLerpFactor)<.001&&(this.lerpFactor=this.targetLerpFactor)),this.lerpFactor>0){this.time+=this.speed*this.lerpFactor;const T=this.noise.perlin2(this.time,0),L=this.noise.perlin2(this.time,100);if(this.el){let F,x,v,A;if(this.hasPercentages){const Y=this.el.parentElement||document.body,$=Y.clientWidth,z=Y.clientHeight;this.xRange&&(F=r(t=c,s,R).call(t,this.xRange.min)?r(i=c,s,P).call(i,this.xRange.min,$):this.xRange.min,x=r(n=c,s,R).call(n,this.xRange.max)?r(o=c,s,P).call(o,this.xRange.max,$):this.xRange.max),this.yRange&&(v=r(l=c,s,R).call(l,this.yRange.min)?r(e=c,s,P).call(e,this.yRange.min,z):this.yRange.min,A=r(a=c,s,R).call(a,this.yRange.max)?r(m=c,s,P).call(m,this.yRange.max,z):this.yRange.max)}else F=(f=this.xRange)==null?void 0:f.min,x=(p=this.xRange)==null?void 0:p.max,v=(d=this.yRange)==null?void 0:d.min,A=(y=this.yRange)==null?void 0:y.max;const w=this.xRange?r(this,g,b).call(this,T,-1,1,F,x):0,M=this.yRange?r(this,g,b).call(this,L,-1,1,v,A):0;this.lastX=w,this.lastY=M,this.el.style.transform=`translate3d(${w}px, ${M}px, 0) ${this.baseTransform}`.trim()}else{const F=this.xRange?r(this,g,b).call(this,T,-1,1,this.xRange.min,this.xRange.max):0,x=this.yRange?r(this,g,b).call(this,L,-1,1,this.yRange.min,this.yRange.max):0;this.lastX=F,this.lastY=x}}(this.lerpFactor>0||this.targetLerpFactor>0)&&(this.raf=requestAnimationFrame(this.animate))});var m,f,p,d;if(this.el=t,this.xRange=i,this.yRange=n,this.speed=o,this.time=l,this.isPlaying=!0,this.lerpFactor=1,this.lerpSpeed=e,this.targetLerpFactor=1,this.lastX=0,this.lastY=0,this.preserveBaseTranslation=a,this.hasPercentages=!!(i&&(r(m=c,s,R).call(m,i.min)||r(f=c,s,R).call(f,i.max))||n&&(r(p=c,s,R).call(p,n.min)||r(d=c,s,R).call(d,n.max))),t){const y=window.getComputedStyle(t);y.position==="static"&&(t.style.position="relative"),this.originalInlineTransform=t.style.transform||"",this.baseTransform=r(this,g,X).call(this,y.transform,this.preserveBaseTranslation),this.hasPercentages&&(this.handleResize=this.handleResize.bind(this),window.addEventListener("resize",this.handleResize))}else this.originalInlineTransform="",this.baseTransform="";this.animate=this.animate.bind(this),this.init(l)}init(t){var i;this.noise=r(this,g,I).call(this,r(i=c,s,E).call(i,t)),this.isPlaying=!0,this.lerpFactor=1,this.targetLerpFactor=1,this.raf=requestAnimationFrame(this.animate)}refreshBaseTransform(t=this.preserveBaseTranslation){if(!this.el)return;const i=window.getComputedStyle(this.el);this.baseTransform=r(this,g,X).call(this,i.transform,t)}handleResize(){}pause(){this.isPlaying&&(this.targetLerpFactor=0,this.isPlaying=!1)}play(){this.isPlaying||(this.targetLerpFactor=1,this.isPlaying=!0,this.lerpFactor===0&&(this.raf=requestAnimationFrame(this.animate)))}destroy(){cancelAnimationFrame(this.raf),this.el&&(this.el.style.transform=this.originalInlineTransform||""),this.hasPercentages&&window.removeEventListener("resize",this.handleResize)}};s=new WeakSet,D=function(t){return function(){let i=t+=1831565813;return i=Math.imul(i^i>>>15,i|1),i^=i+Math.imul(i^i>>>7,i|61),((i^i>>>14)>>>0)/4294967296}},E=function(t=0){var o;const i=Array.from({length:256},(l,e)=>e),n=r(o=c,s,D).call(o,t);for(let l=255;l>0;l--){const e=Math.floor(n()*(l+1));[i[l],i[e]]=[i[e],i[l]]}return i.concat(i)},R=function(t){return typeof t=="string"&&t.endsWith("%")},P=function(t,i){var o;return r(o=c,s,R).call(o,t)?parseFloat(t)/100*i:t},g=new WeakSet,I=function(t){const i=e=>e*e*e*(e*(e*6-15)+10),n=(e,a,m)=>a+e*(m-a),o=(e,a,m)=>{const f=e&15,p=f<8?a:m,d=f<4?m:f===12||f===14?a:0;return(f&1?-p:p)+(f&2?-d:d)},l=(e,a)=>e&1?-a:a;return{perlin1(e){const a=Math.floor(e)&255;e-=Math.floor(e);const m=i(e);return n(m,l(t[a],e),l(t[a+1],e-1))},perlin2(e,a){const m=Math.floor(e)&255,f=Math.floor(a)&255;e-=Math.floor(e),a-=Math.floor(a);const p=i(e),d=i(a),y=t[m]+f,T=t[m+1]+f,L=t[y],F=t[y+1],x=t[T],v=t[T+1];return n(d,n(p,o(t[L],e,a),o(t[x],e-1,a)),n(p,o(t[F],e,a-1),o(t[v],e-1,a-1)))}}},W=function(t,i,n){return t+n*(i-t)},b=function(t,i,n,o,l){return(t-i)*(l-o)/(n-i)+o},X=function(t,i=!1){if(!t||t==="none")return"";try{const n=new DOMMatrixReadOnly(t);if(n.is2D){const o=i?n.e:0,l=i?n.f:0;return`matrix(${n.a}, ${n.b}, ${n.c}, ${n.d}, ${o}, ${l})`}else return t}catch{return t}},B(c,s);let h=c;return h});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@andresclua/perlindom",
3
3
  "private": false,
4
- "version": "0.0.4",
4
+ "version": "0.0.6",
5
5
  "description": "A lightweight JavaScript library for creating smooth, organic animations for DOM elements using Perlin noise",
6
6
  "type": "module",
7
7
  "main": "./dist/PerlinDOM.umd.js",
package/readme.md CHANGED
@@ -336,6 +336,8 @@ See [CHANGELOG.md](./CHANGELOG.md) for detailed version history.
336
336
 
337
337
  ### Recent Updates
338
338
 
339
+ - **v0.0.6**: Enhanced PerlinDOM to preserve design transforms
340
+ - **v0.0.4**: Package now public on npm, enhanced module exports configuration
339
341
  - **v0.0.3**: Fixed positioning conflicts, improved automatic position detection
340
342
  - **v0.0.2**: Added percentage support and responsive animations
341
343
  - **v0.0.1**: Initial release with core Perlin noise animations
package/src/index.html CHANGED
@@ -62,6 +62,8 @@
62
62
  left: calc(50% - 40px);
63
63
  top: calc(50% - 40px);
64
64
  filter: blur(5px);
65
+ transform: scale(3.5) skewX(120deg);
66
+
65
67
  }
66
68
 
67
69
  /* Example 2: Horizontal Only */
@@ -1,310 +1,318 @@
1
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
- }
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
+ }
21
11
 
22
- // Helper to check if a value is a percentage string
23
- static #isPercentage(value) {
24
- return typeof value === 'string' && value.endsWith('%');
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]];
25
18
  }
19
+ return permutation.concat(permutation);
20
+ }
26
21
 
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
- }) {
42
- this.el = element;
43
- this.xRange = x;
44
- this.yRange = y;
45
- this.speed = speed;
46
- this.time = seed;
47
- this.isPlaying = true;
48
- this.lerpFactor = 1; // 1 = full speed, 0 = paused
49
- this.lerpSpeed = lerpSpeed; // How fast to transition between play/pause states
50
- this.targetLerpFactor = 1; // Target state (1 = play, 0 = pause)
51
- this.lastX = 0;
52
- this.lastY = 0;
53
-
54
- // Check if we have percentage values
55
- this.hasPercentages = false;
56
- if (x && (PerlinDOM.#isPercentage(x.min) || PerlinDOM.#isPercentage(x.max)) ||
57
- y && (PerlinDOM.#isPercentage(y.min) || PerlinDOM.#isPercentage(y.max))) {
58
- this.hasPercentages = true;
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';
59
68
  }
60
-
61
- // Solo inicializar estas propiedades si el elemento no es null
62
- if (element) {
63
- // Ensure element has positioning for transform to work properly
64
- const computedStyle = window.getComputedStyle(element);
65
- if (computedStyle.position === 'static') {
66
- element.style.position = 'relative';
67
- }
68
-
69
- // Initialize transform if it doesn't exist
70
- const currentTransform = computedStyle.transform;
71
- if (!currentTransform || currentTransform === 'none') {
72
- element.style.transform = 'translate3d(0px, 0px, 0px)';
73
- }
74
-
75
- // If using percentages, add resize listener
76
- if (this.hasPercentages) {
77
- this.handleResize = this.handleResize.bind(this);
78
- window.addEventListener('resize', this.handleResize);
79
- }
80
-
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);
81
83
  }
82
-
83
- this.animate = this.animate.bind(this);
84
-
85
- this.init(seed);
84
+ } else {
85
+ this.originalInlineTransform = '';
86
+ this.baseTransform = '';
86
87
  }
87
-
88
+
89
+ this.animate = this.animate.bind(this);
90
+ this.init(seed);
91
+ }
92
+
88
93
  init(seed) {
89
- this.noise = this.#createPerlin(PerlinDOM.#generatePermutation(seed));
90
- this.isPlaying = true;
91
- this.lerpFactor = 1;
92
- this.targetLerpFactor = 1;
93
- this.raf = requestAnimationFrame(this.animate);
94
- console.log('PerlinDOM initialized');
95
- }
96
-
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
+
97
108
  // Handle window resize for percentage-based values
98
109
  handleResize() {
99
- // Only recalculate if we're using percentages
100
- if (this.hasPercentages && this.el) {
101
- // Force a recalculation on next animation frame
102
- this.needsRecalculation = true;
103
- }
104
- }
105
-
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
+
106
114
  pause() {
107
- if (this.isPlaying) {
108
- this.targetLerpFactor = 0; // Target paused state
109
- this.isPlaying = false;
110
- console.log('PerlinDOM pausing...');
111
- }
115
+ if (this.isPlaying) {
116
+ this.targetLerpFactor = 0; // Target paused state
117
+ this.isPlaying = false;
112
118
  }
113
-
119
+ }
120
+
114
121
  play() {
115
- if (!this.isPlaying) {
116
- this.targetLerpFactor = 1; // Target playing state
117
- this.isPlaying = true;
118
-
119
- // Only start a new animation frame if we're completely paused
120
- if (this.lerpFactor === 0) {
121
- this.raf = requestAnimationFrame(this.animate);
122
- }
123
-
124
- console.log('PerlinDOM playing...');
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);
125
129
  }
126
130
  }
127
-
128
- #createPerlin(p) {
129
- const fade = t => t * t * t * (t * (t * 6 - 15) + 10);
130
- const lerp = (t, a, b) => a + t * (b - a);
131
-
132
- // Enhanced gradient function for 2D
133
- const grad2D = (hash, x, y) => {
134
- const h = hash & 15;
135
- const u = h < 8 ? x : y;
136
- const v = h < 4 ? y : (h === 12 || h === 14 ? x : 0);
137
- return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
138
- };
139
-
140
- // 1D gradient (kept for backward compatibility)
141
- const grad1D = (hash, x) => (hash & 1 ? -x : x);
142
-
143
- return {
144
- // Original 1D Perlin noise function
145
- perlin1(x) {
146
- const X = Math.floor(x) & 255;
147
- x -= Math.floor(x);
148
- const u = fade(x);
149
- return lerp(u, grad1D(p[X], x), grad1D(p[X + 1], x - 1));
150
- },
151
-
152
- // New 2D Perlin noise function
153
- perlin2(x, y) {
154
- // Integer parts of coordinates
155
- const X = Math.floor(x) & 255;
156
- const Y = Math.floor(y) & 255;
157
-
158
- // Fractional parts of coordinates
159
- x -= Math.floor(x);
160
- y -= Math.floor(y);
161
-
162
- // Fade curves for x and y
163
- const u = fade(x);
164
- const v = fade(y);
165
-
166
- // Hash coordinates of the 4 square corners
167
- const A = p[X] + Y;
168
- const B = p[X + 1] + Y;
169
- const AA = p[A];
170
- const AB = p[A + 1];
171
- const BA = p[B];
172
- const BB = p[B + 1];
173
-
174
- // Blend the four corner gradients
175
- return lerp(
176
- v,
177
- lerp(
178
- u,
179
- grad2D(p[AA], x, y),
180
- grad2D(p[BA], x - 1, y)
181
- ),
182
- lerp(
183
- u,
184
- grad2D(p[AB], x, y - 1),
185
- grad2D(p[BB], x - 1, y - 1)
186
- )
187
- );
188
- }
189
- };
190
- }
191
-
192
- #lerp(a, b, t) {
193
- return a + t * (b - a);
194
- }
195
-
196
- animate = () => {
197
- // Update lerp factor towards target
198
- if (this.lerpFactor !== this.targetLerpFactor) {
199
- this.lerpFactor = this.#lerp(
200
- this.lerpFactor,
201
- this.targetLerpFactor,
202
- this.lerpSpeed
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))
203
184
  );
204
-
205
- // Snap to target if very close
206
- if (Math.abs(this.lerpFactor - this.targetLerpFactor) < 0.001) {
207
- this.lerpFactor = this.targetLerpFactor;
208
- }
209
185
  }
210
-
211
- // Only update time if not completely paused
212
- if (this.lerpFactor > 0) {
213
- // Scale time increment by lerp factor for smooth speed transition
214
- this.time += this.speed * this.lerpFactor;
215
-
216
- // Use 2D Perlin noise for more natural movement
217
- // We use time for one dimension and a fixed offset for the other
218
- // This creates a path through the 2D noise field
219
- const noiseX = this.noise.perlin2(this.time, 0);
220
- const noiseY = this.noise.perlin2(this.time, 100); // Different slice of the noise field
221
-
222
- // Only process if we have an element
223
- if (this.el) {
224
- let minX, maxX, minY, maxY;
225
-
226
- // Get parent dimensions for percentage calculations if needed
227
- if (this.hasPercentages) {
228
- const parent = this.el.parentElement || document.body;
229
- const parentWidth = parent.clientWidth;
230
- const parentHeight = parent.clientHeight;
231
-
232
- // Convert percentage values to pixels if needed
233
- if (this.xRange) {
234
- minX = PerlinDOM.#isPercentage(this.xRange.min)
235
- ? PerlinDOM.#percentToPixels(this.xRange.min, parentWidth)
236
- : this.xRange.min;
237
-
238
- maxX = PerlinDOM.#isPercentage(this.xRange.max)
239
- ? PerlinDOM.#percentToPixels(this.xRange.max, parentWidth)
240
- : this.xRange.max;
241
- }
242
-
243
- if (this.yRange) {
244
- minY = PerlinDOM.#isPercentage(this.yRange.min)
245
- ? PerlinDOM.#percentToPixels(this.yRange.min, parentHeight)
246
- : this.yRange.min;
247
-
248
- maxY = PerlinDOM.#isPercentage(this.yRange.max)
249
- ? PerlinDOM.#percentToPixels(this.yRange.max, parentHeight)
250
- : this.yRange.max;
251
- }
252
- } else {
253
- // Use the original values if not using percentages
254
- minX = this.xRange?.min;
255
- maxX = this.xRange?.max;
256
- minY = this.yRange?.min;
257
- maxY = this.yRange?.max;
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;
258
242
  }
259
-
260
- // Calculate the actual pixel values
261
- const valX = this.xRange
262
- ? this.#map(noiseX, -1, 1, minX, maxX)
263
- : 0;
264
-
265
- const valY = this.yRange
266
- ? this.#map(noiseY, -1, 1, minY, maxY)
267
- : 0;
268
-
269
- // Store current values for interpolation
270
- this.lastX = valX;
271
- this.lastY = valY;
272
-
273
- // Update position using transform for better performance
274
- this.el.style.transform = `translate3d(${valX}px, ${valY}px, 0)`;
275
243
  } else {
276
- // If no element, just calculate and store the values
277
- const valX = this.xRange
278
- ? this.#map(noiseX, -1, 1, this.xRange.min, this.xRange.max)
279
- : 0;
280
-
281
- const valY = this.yRange
282
- ? this.#map(noiseY, -1, 1, this.yRange.min, this.yRange.max)
283
- : 0;
284
-
285
- // Store current values for interpolation
286
- this.lastX = valX;
287
- this.lastY = valY;
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;
288
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;
289
269
  }
290
-
291
- // Continue animation if not completely paused or still transitioning
292
- if (this.lerpFactor > 0 || this.targetLerpFactor > 0) {
293
- this.raf = requestAnimationFrame(this.animate);
294
- }
295
- };
296
-
297
- #map(n, inMin, inMax, outMin, outMax) {
298
- return ((n - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
299
270
  }
300
-
301
- destroy() {
302
- cancelAnimationFrame(this.raf);
303
-
304
- // Remove resize listener if it was added
305
- if (this.hasPercentages) {
306
- window.removeEventListener('resize', this.handleResize);
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;
307
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);
308
314
  }
309
315
  }
310
- export default PerlinDOM;
316
+ }
317
+
318
+ export default PerlinDOM;