@andresclua/perlindom 0.0.1 → 0.0.3

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/src/index.html CHANGED
@@ -59,8 +59,8 @@
59
59
  background-color: #3498db;
60
60
  border-radius: 50%;
61
61
  position: absolute;
62
- left: calc(50% - 40px); /* 50% - half width */
63
- top: calc(50% - 40px); /* 50% - half height */
62
+ left: calc(50% - 40px);
63
+ top: calc(50% - 40px);
64
64
  filter: blur(5px);
65
65
  }
66
66
 
@@ -86,6 +86,32 @@
86
86
  filter: blur(10px);
87
87
  }
88
88
 
89
+ /* Positioning for particles - these are initial positions, PerlinDOM will animate from here */
90
+ .particle:nth-child(1) {
91
+ left: 30%;
92
+ top: 30%;
93
+ }
94
+
95
+ .particle:nth-child(2) {
96
+ left: 50%;
97
+ top: 50%;
98
+ }
99
+
100
+ .particle:nth-child(3) {
101
+ left: 70%;
102
+ top: 70%;
103
+ }
104
+
105
+ .particle:nth-child(4) {
106
+ left: 30%;
107
+ top: 70%;
108
+ }
109
+
110
+ .particle:nth-child(5) {
111
+ left: 70%;
112
+ top: 30%;
113
+ }
114
+
89
115
  /* Example 4: Background Effect */
90
116
  .bg-container {
91
117
  background-color: #34495e;
@@ -403,11 +429,11 @@
403
429
  });
404
430
  </div>
405
431
  <div class="example-container">
406
- <div class="particle" style="left: 30%; top: 30%"></div>
407
- <div class="particle" style="left: 50%; top: 50%"></div>
408
- <div class="particle" style="left: 70%; top: 70%"></div>
409
- <div class="particle" style="left: 30%; top: 70%"></div>
410
- <div class="particle" style="left: 70%; top: 30%"></div>
432
+ <div class="particle"></div>
433
+ <div class="particle"></div>
434
+ <div class="particle"></div>
435
+ <div class="particle"></div>
436
+ <div class="particle"></div>
411
437
  </div>
412
438
 
413
439
  <!-- Example 4: Background Effect -->
@@ -644,6 +670,96 @@
644
670
  </div>
645
671
  </div>
646
672
 
673
+ <!-- Example 9: Pixel vs. Percentage Values -->
674
+ <h2>9. Pixel vs. Percentage Values</h2>
675
+ <div class="code-block">
676
+ // Pixel-based animation (fixed size)<br>
677
+ const pixelAnimation = new PerlinDOM({<br>
678
+ &nbsp;&nbsp;element: document.querySelector('.pixel-element'),<br>
679
+ &nbsp;&nbsp;x: { min: -50, max: 50 },<br>
680
+ &nbsp;&nbsp;y: { min: -50, max: 50 },<br>
681
+ &nbsp;&nbsp;speed: 0.01,<br>
682
+ &nbsp;&nbsp;seed: 123<br>
683
+ });<br><br>
684
+
685
+ // Percentage-based animation (responsive)<br>
686
+ const percentageAnimation = new PerlinDOM({<br>
687
+ &nbsp;&nbsp;element: document.querySelector('.percentage-element'),<br>
688
+ &nbsp;&nbsp;x: { min: '-20%', max: '20%' },<br>
689
+ &nbsp;&nbsp;y: { min: '-20%', max: '20%' },<br>
690
+ &nbsp;&nbsp;speed: 0.01,<br>
691
+ &nbsp;&nbsp;seed: 123<br>
692
+ });
693
+ </div>
694
+ <div class="example-container">
695
+ <div style="display: flex; justify-content: space-between; height: 100%;">
696
+ <div style="width: 48%; height: 100%; position: relative; border: 1px dashed #ccc; border-radius: 5px; overflow: hidden;">
697
+ <div style="position: absolute; top: 10px; left: 0; width: 100%; text-align: center; font-weight: bold; color: #7f8c8d; z-index: 10;">Pixel Values (Fixed)</div>
698
+ <div class="pixel-element" style="width: 80px; height: 80px; background-color: #3498db; border-radius: 50%; position: absolute; left: calc(50% - 40px); top: calc(50% - 40px); filter: blur(5px);"></div>
699
+ <div style="position: absolute; bottom: 10px; left: 0; width: 100%; text-align: center; font-size: 12px; color: #7f8c8d;">Resize your browser window - animation range stays the same</div>
700
+ </div>
701
+ <div style="width: 48%; height: 100%; position: relative; border: 1px dashed #ccc; border-radius: 5px; overflow: hidden;">
702
+ <div style="position: absolute; top: 10px; left: 0; width: 100%; text-align: center; font-weight: bold; color: #7f8c8d; z-index: 10;">Percentage Values (Responsive)</div>
703
+ <div class="percentage-element" style="width: 80px; height: 80px; background-color: #e74c3c; border-radius: 50%; position: absolute; left: calc(50% - 40px); top: calc(50% - 40px); filter: blur(5px);"></div>
704
+ <div style="position: absolute; bottom: 10px; left: 0; width: 100%; text-align: center; font-size: 12px; color: #7f8c8d;">Resize your browser window - animation range adapts</div>
705
+ </div>
706
+ </div>
707
+ </div>
708
+
709
+ <!-- Example 10: Resizable Container with Percentage Values -->
710
+ <h2>10. Resizable Container with Percentage Values</h2>
711
+ <div class="code-block">
712
+ const responsiveAnimation = new PerlinDOM({<br>
713
+ &nbsp;&nbsp;element: document.querySelector('.responsive-element'),<br>
714
+ &nbsp;&nbsp;x: { min: '-25%', max: '25%' },<br>
715
+ &nbsp;&nbsp;y: { min: '-25%', max: '25%' },<br>
716
+ &nbsp;&nbsp;speed: 0.008,<br>
717
+ &nbsp;&nbsp;seed: 456<br>
718
+ });
719
+ </div>
720
+ <div class="example-container">
721
+ <div style="height: 100%; position: relative; border: 1px solid #ddd; border-radius: 5px; overflow: hidden; resize: both; min-width: 200px; min-height: 200px; background-color: #f0f0f0;">
722
+ <div class="responsive-element" style="width: 60px; height: 60px; background-color: #9b59b6; border-radius: 50%; position: absolute; left: calc(50% - 30px); top: calc(50% - 30px);"></div>
723
+ <div style="position: absolute; bottom: 10px; right: 10px; font-size: 12px; color: #7f8c8d;">↘️ Drag this corner to resize the container</div>
724
+ </div>
725
+ </div>
726
+
727
+ <!-- Example 11: Mixed Pixel and Percentage Values -->
728
+ <h2>11. Mixed Pixel and Percentage Values</h2>
729
+ <div class="code-block">
730
+ // Horizontal percentage, vertical pixel<br>
731
+ const horizontalPercentAnimation = new PerlinDOM({<br>
732
+ &nbsp;&nbsp;element: document.querySelector('.horizontal-percent-element'),<br>
733
+ &nbsp;&nbsp;x: { min: '-30%', max: '30%' },<br>
734
+ &nbsp;&nbsp;y: { min: -40, max: 40 },<br>
735
+ &nbsp;&nbsp;speed: 0.01,<br>
736
+ &nbsp;&nbsp;seed: 789<br>
737
+ });<br><br>
738
+
739
+ // Horizontal pixel, vertical percentage<br>
740
+ const verticalPercentAnimation = new PerlinDOM({<br>
741
+ &nbsp;&nbsp;element: document.querySelector('.vertical-percent-element'),<br>
742
+ &nbsp;&nbsp;x: { min: -80, max: 80 },<br>
743
+ &nbsp;&nbsp;y: { min: '-20%', max: '20%' },<br>
744
+ &nbsp;&nbsp;speed: 0.01,<br>
745
+ &nbsp;&nbsp;seed: 789<br>
746
+ });
747
+ </div>
748
+ <div class="example-container">
749
+ <div style="display: flex; justify-content: space-between; height: 100%;">
750
+ <div style="width: 48%; height: 100%; position: relative; border: 1px dashed #ccc; border-radius: 5px; overflow: hidden;">
751
+ <div style="position: absolute; top: 10px; left: 0; width: 100%; text-align: center; font-weight: bold; color: #7f8c8d; z-index: 10;">Horizontal % / Vertical px</div>
752
+ <div class="horizontal-percent-element" style="width: 60px; height: 60px; background-color: #f39c12; border-radius: 10px; position: absolute; left: calc(50% - 30px); top: calc(50% - 30px);"></div>
753
+ <div style="position: absolute; bottom: 10px; left: 0; width: 100%; text-align: center; font-size: 12px; color: #7f8c8d;">Horizontal movement adapts to width, vertical is fixed</div>
754
+ </div>
755
+ <div style="width: 48%; height: 100%; position: relative; border: 1px dashed #ccc; border-radius: 5px; overflow: hidden;">
756
+ <div style="position: absolute; top: 10px; left: 0; width: 100%; text-align: center; font-weight: bold; color: #7f8c8d; z-index: 10;">Horizontal px / Vertical %</div>
757
+ <div class="vertical-percent-element" style="width: 60px; height: 60px; background-color: #f39c12; border-radius: 10px; position: absolute; left: calc(50% - 30px); top: calc(50% - 30px);"></div>
758
+ <div style="position: absolute; bottom: 10px; left: 0; width: 100%; text-align: center; font-size: 12px; color: #7f8c8d;">Horizontal movement is fixed, vertical adapts to height</div>
759
+ </div>
760
+ </div>
761
+ </div>
762
+
647
763
  <!-- Load all scripts -->
648
764
  <script type="module" src="./js/index.js"></script>
649
765
  <script type="module" src="./js/basic-examples.js"></script>
@@ -651,5 +767,51 @@
651
767
  <script type="module" src="./js/interactive-controls.js"></script>
652
768
  <script type="module" src="./js/animated-button.js"></script>
653
769
  <script type="module" src="./js/triangle-animation.js"></script>
770
+ <script type="module">
771
+ import PerlinDOM from './js/PerlinDom.js';
772
+
773
+ // Example 9: Pixel vs. Percentage Values
774
+ const pixelAnimation = new PerlinDOM({
775
+ element: document.querySelector('.pixel-element'),
776
+ x: { min: -50, max: 50 },
777
+ y: { min: -50, max: 50 },
778
+ speed: 0.01,
779
+ seed: 123
780
+ });
781
+
782
+ const percentageAnimation = new PerlinDOM({
783
+ element: document.querySelector('.percentage-element'),
784
+ x: { min: '-20%', max: '20%' },
785
+ y: { min: '-20%', max: '20%' },
786
+ speed: 0.01,
787
+ seed: 123
788
+ });
789
+
790
+ // Example 10: Resizable Container
791
+ const responsiveAnimation = new PerlinDOM({
792
+ element: document.querySelector('.responsive-element'),
793
+ x: { min: '-25%', max: '25%' },
794
+ y: { min: '-25%', max: '25%' },
795
+ speed: 0.008,
796
+ seed: 456
797
+ });
798
+
799
+ // Example 11: Mixed Values
800
+ const horizontalPercentAnimation = new PerlinDOM({
801
+ element: document.querySelector('.horizontal-percent-element'),
802
+ x: { min: '-30%', max: '30%' },
803
+ y: { min: -40, max: 40 },
804
+ speed: 0.01,
805
+ seed: 789
806
+ });
807
+
808
+ const verticalPercentAnimation = new PerlinDOM({
809
+ element: document.querySelector('.vertical-percent-element'),
810
+ x: { min: -80, max: 80 },
811
+ y: { min: '-20%', max: '20%' },
812
+ speed: 0.01,
813
+ seed: 789
814
+ });
815
+ </script>
654
816
  </body>
655
817
  </html>
@@ -18,6 +18,18 @@ class PerlinDOM {
18
18
  }
19
19
  return permutation.concat(permutation);
20
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
+ }
21
33
 
22
34
  constructor({
23
35
  element,
@@ -38,14 +50,33 @@ class PerlinDOM {
38
50
  this.targetLerpFactor = 1; // Target state (1 = play, 0 = pause)
39
51
  this.lastX = 0;
40
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;
59
+ }
41
60
 
42
61
  // Solo inicializar estas propiedades si el elemento no es null
43
62
  if (element) {
44
- this.initialX = element.offsetLeft;
45
- this.initialY = element.offsetTop;
46
- } else {
47
- this.initialX = 0;
48
- this.initialY = 0;
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
+ }
49
80
  }
50
81
 
51
82
  this.animate = this.animate.bind(this);
@@ -62,6 +93,15 @@ class PerlinDOM {
62
93
  console.log('PerlinDOM initialized');
63
94
  }
64
95
 
96
+ // Handle window resize for percentage-based values
97
+ handleResize() {
98
+ // Only recalculate if we're using percentages
99
+ if (this.hasPercentages && this.el) {
100
+ // Force a recalculation on next animation frame
101
+ this.needsRecalculation = true;
102
+ }
103
+ }
104
+
65
105
  pause() {
66
106
  if (this.isPlaying) {
67
107
  this.targetLerpFactor = 0; // Target paused state
@@ -178,23 +218,72 @@ class PerlinDOM {
178
218
  const noiseX = this.noise.perlin2(this.time, 0);
179
219
  const noiseY = this.noise.perlin2(this.time, 100); // Different slice of the noise field
180
220
 
181
- const valX = this.xRange
182
- ? this.#map(noiseX, -1, 1, this.xRange.min, this.xRange.max)
183
- : 0;
184
-
185
- const valY = this.yRange
186
- ? this.#map(noiseY, -1, 1, this.yRange.min, this.yRange.max)
187
- : 0;
188
-
189
- // Store current values for interpolation
190
- this.lastX = valX;
191
- this.lastY = valY;
192
-
193
- // Update position using left/top instead of transform
194
- // Solo actualizar el elemento si existe
221
+ // Only process if we have an element
195
222
  if (this.el) {
196
- this.el.style.left = `${this.initialX + valX}px`;
197
- this.el.style.top = `${this.initialY + valY}px`;
223
+ let minX, maxX, minY, maxY;
224
+
225
+ // Get parent dimensions for percentage calculations if needed
226
+ if (this.hasPercentages) {
227
+ const parent = this.el.parentElement || document.body;
228
+ const parentWidth = parent.clientWidth;
229
+ const parentHeight = parent.clientHeight;
230
+
231
+ // Convert percentage values to pixels if needed
232
+ if (this.xRange) {
233
+ minX = PerlinDOM.#isPercentage(this.xRange.min)
234
+ ? PerlinDOM.#percentToPixels(this.xRange.min, parentWidth)
235
+ : this.xRange.min;
236
+
237
+ maxX = PerlinDOM.#isPercentage(this.xRange.max)
238
+ ? PerlinDOM.#percentToPixels(this.xRange.max, parentWidth)
239
+ : this.xRange.max;
240
+ }
241
+
242
+ if (this.yRange) {
243
+ minY = PerlinDOM.#isPercentage(this.yRange.min)
244
+ ? PerlinDOM.#percentToPixels(this.yRange.min, parentHeight)
245
+ : this.yRange.min;
246
+
247
+ maxY = PerlinDOM.#isPercentage(this.yRange.max)
248
+ ? PerlinDOM.#percentToPixels(this.yRange.max, parentHeight)
249
+ : this.yRange.max;
250
+ }
251
+ } else {
252
+ // Use the original values if not using percentages
253
+ minX = this.xRange?.min;
254
+ maxX = this.xRange?.max;
255
+ minY = this.yRange?.min;
256
+ maxY = this.yRange?.max;
257
+ }
258
+
259
+ // Calculate the actual pixel values
260
+ const valX = this.xRange
261
+ ? this.#map(noiseX, -1, 1, minX, maxX)
262
+ : 0;
263
+
264
+ const valY = this.yRange
265
+ ? this.#map(noiseY, -1, 1, minY, maxY)
266
+ : 0;
267
+
268
+ // Store current values for interpolation
269
+ this.lastX = valX;
270
+ this.lastY = valY;
271
+
272
+ // Update position using transform for better performance
273
+ this.el.style.transform = `translate3d(${valX}px, ${valY}px, 0)`;
274
+ } else {
275
+ // If no element, just calculate and store the values
276
+ const valX = this.xRange
277
+ ? this.#map(noiseX, -1, 1, this.xRange.min, this.xRange.max)
278
+ : 0;
279
+
280
+ const valY = this.yRange
281
+ ? this.#map(noiseY, -1, 1, this.yRange.min, this.yRange.max)
282
+ : 0;
283
+
284
+ // Store current values for interpolation
285
+ this.lastX = valX;
286
+ this.lastY = valY;
198
287
  }
199
288
  }
200
289
 
@@ -210,6 +299,11 @@ class PerlinDOM {
210
299
 
211
300
  destroy() {
212
301
  cancelAnimationFrame(this.raf);
302
+
303
+ // Remove resize listener if it was added
304
+ if (this.hasPercentages) {
305
+ window.removeEventListener('resize', this.handleResize);
306
+ }
213
307
  }
214
308
  }
215
309
  export default PerlinDOM;