PageSourceSearch

https://obrixlabs.com/wp-content/themes/aimo/elements/assets/js/elementor.js?ver=1.0.1

js obrixlabs.com collected 2026-10-07 00:30:53 UTC 48,447 bytes, 1,279 lines download raw bytes

1(function ($) {
2    "use strict";
3    function aimo_section_start_render() {
4        var _elementor = typeof elementor != 'undefined' ? elementor : elementorFrontend;
5
6        _elementor.hooks.addFilter('pxl_section_start_render', function (html, settings, el) {
7
8            if (typeof settings.pxl_parallax_bg_img != 'undefined' && settings.pxl_parallax_bg_img.url != '') {
9                html += '<div class="pxl-section-bg-parallax"></div>';
10            }
11
12            if (typeof settings.pxl_color_offset != 'undefined' && settings.pxl_color_offset != 'none') {
13                html += '<div class="pxl-section-overlay-color"></div>';
14            }
15
16            if (typeof settings.pxl_overlay_img != 'undefined' && settings.pxl_overlay_img.url != '') {
17                html += '<div class="pxl-overlay--image pxl-overlay--imageLeft"><div class="bg-image"></div></div>';
18            }
19
20            if (typeof settings.pxl_overlay_img2 != 'undefined' && settings.pxl_overlay_img2.url != '') {
21                html += '<div class="pxl-overlay--image pxl-overlay--imageRight"><div class="bg-image"></div></div>';
22            }
23
24            return html;
25        });
26
27        $('.pxl-section-bg-parallax').parent('.elementor-element').addClass('pxl-section-parallax-overflow');
28    }
29
30    function aimo_column_before_render() {
31        var _elementor = typeof elementor != 'undefined' ? elementor : elementorFrontend;
32        _elementor.hooks.addFilter('pxl-custom-column/before-render', function (html, settings, el) {
33            if (typeof settings.pxl_column_parallax_bg_img != 'undefined' && settings.pxl_column_parallax_bg_img.url != '') {
34                html += '<div class="pxl-column-bg-parallax"></div>';
35            }
36            return html;
37        });
38    }
39
40    function aimo_css_inline_js() {
41        var _inline_css = "<style>";
42        $(document).find('.pxl-inline-css').each(function () {
43            var _this = $(this);
44            _inline_css += _this.attr("data-css") + " ";
45            _this.remove();
46        });
47        _inline_css += "</style>";
48        $('head').append(_inline_css);
49    }
50
51    function aimo_section_before_render() {
52        var _elementor = typeof elementor != 'undefined' ? elementor : elementorFrontend;
53        _elementor.hooks.addFilter('pxl-custom-section/before-render', function (html, settings, el) {
54            if (typeof settings['row_divider'] !== 'undefined') {
55                if (settings['row_divider'] == 'angle-top' || settings['row_divider'] == 'angle-bottom' || settings['row_divider'] == 'angle-top-right' || settings['row_divider'] == 'angle-bottom-left') {
56                    html = '<svg class="pxl-row-angle" style="fill:#ffffff" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" height="130px"><path stroke="" stroke-width="0" d="M0 100 L100 0 L200 100"></path></svg>';
57                    return html;
58                }
59                if (settings['row_divider'] == 'angle-top-bottom' || settings['row_divider'] == 'angle-top-bottom-left') {
60                    html = '<svg class="pxl-row-angle pxl-row-angle-top" style="fill:#ffffff" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" height="130px"><path stroke="" stroke-width="0" d="M0 100 L100 0 L200 100"></path></svg><svg class="pxl-row-angle pxl-row-angle-bottom" style="fill:#ffffff" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" height="130px"><path stroke="" stroke-width="0" d="M0 100 L100 0 L200 100"></path></svg>';
61                    return html;
62                }
63                if (settings['row_divider'] == 'wave-animation-top' || settings['row_divider'] == 'wave-animation-bottom') {
64                    html = '<svg class="pxl-row-angle" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 1440 150" fill="#fff">
64<path d="M 0 26.1978 C 275.76 83.8152 430.707 65.0509 716.279 25.6386 C 930.422 -3.86123 1210.32 -3.98357 1439 9.18045 C 2072.34 45.9691 2201.93 62.4429 2560 26.198 V 172.199 L 0 172.199 V 26.1978 Z"><animate repeatCount="indefinite" fill="freeze" attributeName="d" dur="10s" values="M0 25.9086C277 84.5821 433 65.736 720 25.9086C934.818 -3.9019 1214.06 -5.23669 1442 8.06597C2079 45.2421 2208 63.5007 2560 25.9088V171.91L0 171.91V25.9086Z; M0 86.3149C316 86.315 444 159.155 884 51.1554C1324 -56.8446 1320.29 34.1214 1538 70.4063C1814 116.407 2156 188.408 2560 86.315V232.317L0 232.316V86.3149Z; M0 53.6584C158 11.0001 213 0 363 0C513 0 855.555 115.001 1154 115.001C1440 115.001 1626 -38.0004 2560 53.6585V199.66L0 199.66V53.6584Z; M0 25.9086C277 84.5821 433 65.736 720 25.9086C934.818 -3.9019 1214.06 -5.23669 1442 8.06597C2079 45.2421 2208 63.5007 2560 25.9088V171.91L0 171.91V25.9086Z"></animate></path></svg>';
65                    return html;
66                }
67                if (settings['row_divider'] == 'curved-top' || settings['row_divider'] == 'curved-bottom') {
68                    html = '<svg class="pxl-row-angle" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 1920 128" version="1.1" preserveAspectRatio="none" style="fill:#ffffff"><path stroke-width="0" d="M-1,126a3693.886,3693.886,0,0,1,1921,2.125V-192H-7Z"></path></svg>';
69                    return html;
70                }
71            }
72        });
73    }
74
75    var PXL_Icon_Contact_Form = function ($scope, $) {
76
77        setTimeout(function () {
78            $('.pxl--item').each(function () {
79                var icon_input = $(this).find(".pxl--form-icon"),
80                    control_wrap = $(this).find('.wpcf7-form-control');
81                control_wrap.before(icon_input.clone());
82                icon_input.remove();
83            });
84        }, 10);
85
86    };
87
88    function aimo_split_text($scope) {
89
90        setTimeout(function () {
91
92            var st = $scope.find(".pxl-split-text");
93            if (st.length == 0) return;
94            gsap.registerPlugin(SplitText);
95            st.each(function (index, el) {
96                el.split = new SplitText(el, {
97                    type: "lines,words,chars",
98                    linesClass: "split-line"
99                });
100                gsap.set(el, { perspective: 400 });
101
102                if ($(el).hasClass('split-in-fade')) {
103                    $(el).addClass('active');
104                    gsap.set(el.split.chars, {
105                        opacity: 0,
106                        ease: "Back.easeOut",
107                    });
108                }
109                if ($(el).hasClass('split-in-right')) {
110                    gsap.set(el.split.chars, {
111                        opacity: 0,
112                        x: "50",
113                        ease: "Back.easeOut",
114                    });
115                }
116                if ($(el).hasClass('split-in-left')) {
117                    gsap.set(el.split.chars, {
118                        opacity: 0,
119                        x: "-50",
120                        ease: "circ.out",
121                    });
122                }
123                if ($(el).hasClass('split-in-up')) {
124                    gsap.set(el.split.chars, {
125                        opacity: 0,
126                        y: "80",
127                        ease: "circ.out",
128                    });
129                }
130                if ($(el).hasClass('split-in-down')) {
131                    gsap.set(el.split.chars, {
132                        opacity: 0,
133                        y: "-80",
134                        ease: "circ.out",
135                    });
136                }
137                if ($(el).hasClass('split-in-rotate')) {
138                    gsap.set(el.split.chars, {
139                        opacity: 0,
140                        rotateX: "50deg",
141                        ease: "circ.out",
142                    });
143                }
144                if ($(el).hasClass('split-in-scale')) {
145                    gsap.set(el.split.chars, {
146                        opacity: 0,
147                        scale: "0.5",
148                        ease: "circ.out",
149                    });
150                }
151                el.anim = gsap.to(el.split.chars, {
152                    scrollTrigger: {
153                        trigger: el,
154                        toggleActions: "restart pause resume reverse",
155                        start: "top 90%",
156                    },
157                    x: "0",
158                    y: "0",
159                    rotateX: "0",
160                    scale: 1,
161                    opacity: 1,
162                    duration: 0.8,
163                    stagger: 0.02,
164                });
165            });
166
167        }, 200);
168    }
169
170    function aimo_zoom_point() {
171        elementorFrontend.waypoint($(document).find('.pxl-zoom-point'), function () {
172            var offset = $(this).offset();
173            var offset_top = offset.top;
174            var scroll_top = $(window).scrollTop();
175        }, {
176            offset: -100,
177            triggerOnce: true
178        });
179    }
180
181    function aimo_scroll_fixed_section() {
182        if ($('.pxl-section-fix-top').length > 0) {
183            ScrollTrigger.matchMedia({
184                "(min-width: 991px)": function () {
185                    const pinnedSections = ['.pxl-section-fix-top'];
186                    pinnedSections.forEach(className => {
187                        gsap.to(".pxl-section-fix-bottom", {
188                            scrollTrigger: {
189                                trigger: ".pxl-section-fix-bottom",
190                                scrub: true,
191                                pin: className,
192                                pinSpacing: false,
193                                start: 'top bottom',
194                                end: "bottom top",
195                            },
196                        });
197                    });
198                }
199            });
200        }
201    }
202
203    function aimo_item_marquee($scope) {
204        const logos = $scope.find('.pxl-item--marquee');
205        gsap.set(logos, { autoAlpha: 1 })
206
207        logos.each(function (index, el) {
208            gsap.set(el, { xPercent: 100 * index });
209        });
210
211        if (logos.length > 2) {
212            const logosWrap = gsap.utils.wrap(-100, ((logos.length - 1) * 100));
213            const durationNumber = logos.data('duration');
214            const slipType = logos.data('slip-type');
215            var slipResult = `-=${logos.length * 100}`;
216            if (slipType == 'right') {
217                slipResult = `+=${logos.length * 100}`;
218            }
219            gsap.to(logos, {
220                xPercent: slipResult,
221                duration: durationNumber,
222                repeat: -1,
223                ease: 'none',
224                modifiers: {
225                    xPercent: xPercent => logosWrap(parseFloat(xPercent))
226                }
227            });
228        }
229    }
230
231    function aimo_item_marquee2($scope) {
232        const textWrapper = $scope.find('.pxl-text-marquee');
233        const text_marquee = textWrapper.find('.pxl-text--marquee');
234        const boxes = gsap.utils.toArray(text_marquee);
235
236        const isRTL = textWrapper.hasClass('pxl-right-to-left');
237        const isLTR = textWrapper.hasClass('pxl-left-to-right');
238
239        const loop = text_horizontalLoop(boxes, {
240            paused: false,
241            repeat: -1,
242            reversed: isLTR // ← nếu là Left to Right thì reverse
243        });
244
245        function text_horizontalLoop(items, config) {
246            items = gsap.utils.toArray(items);
247            config = config || {};
248            let tl = gsap.timeline({
249                repeat: config.repeat,
250                paused: config.paused,
251                defaults: { ease: "none" },
252                onReverseComplete: () => tl.totalTime(tl.rawTime() + tl.duration() * 100)
253            }),
254                length = items.length,
255                startX = items[0].offsetLeft,
256                times = [],
257                widths = [],
258                xPercents = [],
259                curIndex = 0,
260                pixelsPerSecond = (config.speed || 1) * 100,
261                snap = config.snap === false ? v => v : gsap.utils.snap(config.snap || 1),
262                totalWidth, curX, distanceToStart, distanceToLoop, item, i;
263
264            gsap.set(items, {
265                xPercent: (i, el) => {
266                    let w = widths[i] = parseFloat(gsap.getProperty(el, "width", "px"));
267                    xPercents[i] = snap(parseFloat(gsap.getProperty(el, "x", "px")) / w * 100 + gsap.getProperty(el, "xPercent"));
268                    return xPercents[i];
269                }
270            });
271
272            gsap.set(items, { x: 0 });
273
274            totalWidth = items[length - 1].offsetLeft + xPercents[length - 1] / 100 * widths[length - 1] - startX + items[length - 1].offsetWidth * gsap.getProperty(items[length - 1], "scaleX") + (parseFloat(config.paddingRight) || 0);
275
276            for (i = 0; i < length; i++) {
277                item = items[i];
278                curX = xPercents[i] / 100 * widths[i];
279                distanceToStart = item.offsetLeft + curX - startX;
280                distanceToLoop = distanceToStart + widths[i] * gsap.getProperty(item, "scaleX");
281
282                tl.to(item, {
283                    xPercent: snap((curX - distanceToLoop) / widths[i] * 100),
284                    duration: distanceToLoop / pixelsPerSecond
285                }, 0)
286                    .fromTo(item, {
287                        xPercent: snap((curX - distanceToLoop + totalWidth) / widths[i] * 100)
288                    }, {
289                        xPercent: xPercents[i],
290                        duration: (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond,
291                        immediateRender: false
292                    }, distanceToLoop / pixelsPerSecond)
293                    .add("label" + i, distanceToStart / pixelsPerSecond);
294
295                times[i] = distanceToStart / pixelsPerSecond;
296            }
297
298            function toIndex(index, vars) {
299                vars = vars || {};
300                if (Math.abs(index - curIndex) > length / 2) {
301                    index += (index > curIndex) ? -length : length;
302                }
303                let newIndex = gsap.utils.wrap(0, length, index),
304                    time = times[newIndex];
305                if ((time > tl.time()) !== (index > curIndex)) {
306                    vars.modifiers = { time: gsap.utils.wrap(0, tl.duration()) };
307                    time += tl.duration() * (index > curIndex ? 1 : -1);
308                }
309                curIndex = newIndex;
310                vars.overwrite = true;
311                return tl.tweenTo(time, vars);
312            }
313
314            tl.next = vars => toIndex(curIndex + 1, vars);
315            tl.previous = vars => toIndex(curIndex - 1, vars);
316            tl.current = () => curIndex;
317            tl.toIndex = (index, vars) => toIndex(index, vars);
318            tl.times = times;
319            tl.progress(1, true).progress(0, true);
320
321            if (config.reversed) {
322                tl.vars.onReverseComplete();
323                tl.reverse();
324            }
325
326            return tl;
327        }
328    }
329
330
331    function aimo_animation_image() {
332        let revealContainers = document.querySelectorAll(".pxl-scroll-reveal");
333        if (revealContainers.length > 0 && window.innerWidth > 767) {
334            gsap.registerPlugin(ScrollTrigger);
335
336            revealContainers.forEach((container) => {
337                let image = container.querySelector("img");
338
339                let tl = gsap.timeline({
340                    scrollTrigger: {
341                        trigger: container,
342                        toggleActions: "play none none none"
343                    }
344                });
345
346                tl.set(container, { autoAlpha: 1 });
347
348                tl.from(container, {
349                    xPercent: -100,
350                    duration: 1.5,
351                    ease: Power2.out
352                });
353
354                tl.from(image, {
355                    xPercent: 100,
356                    scale: 1.3,
357                    duration: 1.5,
358                    delay: -1.5,
359                    ease: Power2.out
360                });
361            });
362        }
363
364    }
365    function aimo_process3() {
366        const cards = document.querySelectorAll(".pxl-process3 .pxl--item");
367
368        if (window.innerWidth > 960) {
369            cards.forEach((card, index) => {
370                card.style.left = `${index * 120}px`;
371                card.style.top = `${index * 52}px`;
372                card.style.position = "absolute";
373                card.style.transition = "transform 0.3s ease, z-index 0s";
374
375                card.addEventListener("click", (event) => {
376                    event.stopPropagation();
377
378                    cards.forEach((otherCard) => {
379                        otherCard.style.zIndex = "1";
380                        otherCard.style.transform = "scale(1)";
381                        const icon = otherCard.querySelector(".pxl-icon");
382                        if (icon) {
383                            icon.classList.remove("pxl_spin");
384                        }
385                        const image = otherCard.querySelector("img");
386                        if (image) {
387                            image.style.borderRadius = "12px";
388                        }
389                    });
390
391                    card.style.zIndex = "10";
392                    card.style.transform = "scale(1.1)";
393
394                    const icon = card.querySelector(".pxl-icon");
395                    if (icon) {
396                        icon.classList.add("pxl_spin");
397                    }
398                    const image = card.querySelector("img");
399                    if (image) {
400                        image.style.borderRadius = "0px";
401                    }
402                });
403            });
404
405            document.addEventListener("click", () => {
406                cards.forEach((card) => {
407                    card.style.zIndex = "1";
408                    card.style.transform = "scale(1)";
409                    const icon = card.querySelector(".pxl-icon");
410                    if (icon) {
411                        icon.classList.remove("pxl_spin");
412                    }
413                    const image = card.querySelector("img");
414                    if (image) {
415                        image.style.borderRadius = "12px";
416                    }
417                });
418            });
419        }
420    }
421    window.addEventListener("resize", aimo_process3);
422
423    /*//////////////*/
424    function aimo_split_scroll_color() {
425        var revealContainers = document.querySelectorAll(".pxl-heading .pxl-heading--text-scroll");
426
427        if (revealContainers.length > 0) {
428            revealContainers.forEach((container) => {
429                var text = new SplitText(container, { type: 'words, chars' });
430
431                text.words.forEach((word) => {
432                    if (word.children.length > 0) {
433                        word.children[0].classList.add("first-char");
434                    }
435                });
436
437                gsap.fromTo(text.chars,
438                    {
439                        position: 'relative',
440                        display: 'inline-block',
441                        opacity: 0.2,
442                        x: -5,
443                    },
444                    {
445                        opacity: 1,
446                        x: 0,
447                        stagger: 0.1,
448                        scrollTrigger: {
449                            trigger: container,
450                            toggleActions: "play pause reverse pause",
451                            start: "top 90%",
452                            end: "top 40%",
453                            scrub: 0.7,
454                        }
455                    }
456                );
457            });
458        }
459    }
460
461    function aimo_image_split() {
462        let boxWidth = 0;
463        let lastScrollY = window.scrollY;
464        const mq = window.matchMedia("(max-width: 1200px)");
465        let isScrolling = false;
466
467        function handleScroll() {
468            const container = document.querySelector('.pxl-image-split .containers');
469            const box = document.querySelector('.pxl-image-split .pxl-width');
470            const fillerSpace = document.querySelector('.pxl-image-split .filler-space');
471            if (container && box && fillerSpace) {
472                const containerTop = container.getBoundingClientRect().top;
473                const fillerBottom = fillerSpace.getBoundingClientRect().bottom;
474                const fillerTop = fillerSpace.getBoundingClientRect().top;
475                const boxTop = box.getBoundingClientRect().top;
476                const deltaY = window.scrollY - lastScrollY;
477
478                if (containerTop <= 0) {
479                    if (deltaY > 0) {
480                        boxWidth = Math.min(100, boxWidth + deltaY * 0.1);
481                    }
482
483                    if (deltaY < 0 && fillerBottom >= window.innerHeight) {
484                        boxWidth = Math.max(0, boxWidth - Math.abs(deltaY) * 0.15);
485                    }
486                    if (fillerTop >= boxTop) {
487                        boxWidth = 0;
488                    }
489                    box.style.width = boxWidth + '%';
490                }
491            }
492
493            lastScrollY = window.scrollY;
494            isScrolling = false;
495        }
496
497        function smoothScrollHandler() {
498            if (!isScrolling) {
499                isScrolling = true;
500                requestAnimationFrame(handleScroll);
501            }
502        }
503
504        function checkMediaQuery() {
505            if (!mq.matches) {
506                window.addEventListener('scroll', smoothScrollHandler);
507            } else {
508                window.removeEventListener('scroll', smoothScrollHandler);
509            }
510        }
511
512        function handleResize() {
513            checkMediaQuery();
514        }
515
516        if (document.querySelector('.pxl-image-split .containers') &&
517            document.querySelector('.pxl-image-split .pxl-width') &&
518            document.querySelector('.pxl-image-split .filler-space')) {
519            checkMediaQuery();
520            mq.addEventListener('change', checkMediaQuery);
521            window.addEventListener('resize', handleResize);
522        }
523    }
524    /* Custom WebGL Effects */
525    function aimo_webgl_effects() {
526        var WebGL_vs = `#ifdef GL_ES
527        precision mediump float;
528        #endif
529
530        attribute vec3 aVertexPosition;
531        attribute vec2 aTextureCoord;
532
533        uniform mat4 uMVMatrix;
534        uniform mat4 uPMatrix;
535
536        uniform mat4 texture0Matrix;
537        uniform mat4 texture1Matrix;
538        uniform mat4 mapMatrix;
539
540        varying vec3 vVertexPosition;
541        varying vec2 vTextureCoord0;
542        varying vec2 vTextureCoord1;
543        varying vec2 vTextureCoordMap;
544
545        void main() {
546            vec3 vertexPosition = aVertexPosition;
547
548            gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0
548);
549
550            vTextureCoord0 = (texture0Matrix * vec4(aTextureCoord, 0., 1.)).xy;
551            vTextureCoord1 = (texture1Matrix * vec4(aTextureCoord, 0., 1.)).xy;
552            vTextureCoordMap = (mapMatrix * vec4(aTextureCoord, 0., 1.)).xy;
553            vVertexPosition = vertexPosition;
554        }`;
555
556        var WebGL_fs = `#ifdef GL_ES
557        precision mediump float;
558        #endif
559
560        #define PI2 6.28318530718
561        #define PI 3.14159265359
562        #define S(a,b,n) smoothstep(a,b,n)
563
564        uniform float uTime;
565        uniform float uProgress;
566        uniform vec2 uReso;
567        uniform vec2 uMouse;
568
569        varying vec3 vVertexPosition;
570        varying vec2 vTextureCoord0;
571        varying vec2 vTextureCoord1;
572        varying vec2 vTextureCoordMap;
573
574        uniform sampler2D texture0;
575        uniform sampler2D texture1;
576        uniform sampler2D map;
577
578        float exponentialEasing (float x, float a){
579
580            float epsilon = 0.00001;
581            float min_param_a = 0.0 + epsilon;
582            float max_param_a = 1.0 - epsilon;
583            a = max(min_param_a, min(max_param_a, a));
584
585            if (a < 0.5){
586                a = 2.0 * a;
587                float y = pow(x, a);
588                return y;
589            } else {
590                a = 2.0 * (a-0.5);
591                float y = pow(x, 1.0 / (1.-a));
592                return y;
593            }
594        }
595
596        vec4 blur13(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
597            vec4 color = vec4(0.0);
598            vec2 off1 = vec2(1.411764705882353) * direction;
599            vec2 off2 = vec2(3.2941176470588234) * direction;
600            vec2 off3 = vec2(5.176470588235294) * direction;
601            color += texture2D(image, uv) * 0.1964825501511404;
602            color += texture2D(image, uv + (off1 / resolution)) * 0.2969069646728344;
603            color += texture2D(image, uv - (off1 / resolution)) * 0.2969069646728344;
604            color += texture2D(image, uv + (off2 / resolution)) * 0.09447039785044732;
605            color += texture2D(image, uv - (off2 / resolution)) * 0.09447039785044732;
606            color += texture2D(image, uv + (off3 / resolution)) * 0.010381362401148057;
607            color += texture2D(image, uv - (off3 / resolution)) * 0.010381362401148057;
608            return color;
609        }
610
611        void main(){
612            vec2 uv0 = vTextureCoord0;
613            vec2 uv1 = vTextureCoord1;
614
615            float progress0 = uProgress;
616            float progress1 = 1. - uProgress;
617
618            vec4 map = blur13(map, vTextureCoordMap, uReso, vec2(2.)) + 0.5;
619
620            uv0.x += progress0 * map.r;
621            uv1.x -= progress1 * map.r;
622
623            vec4 color = texture2D( texture0, uv0 );
624            vec4 color1 = texture2D( texture1, uv1 );
625
626            gl_FragColor = mix(color, color1, progress0 );
627        }`;
628        class WebglHover {
629            constructor(set) {
630                this.canvas = set.canvas;
631                this.webGLCurtain = new Curtains({
632                    container: this.canvas,
633                    watchScroll: false,
634                    pixelRatio: Math.min(1.5, window.devicePixelRatio)
635                })
636                this.planeElement = set.planeElement;
637                this.mouse = {
638                    x: 0,
639                    y: 0
640                };
641                this.params = {
642                    vertexShader: WebGL_vs,
643                    fragmentShader: WebGL_fs,
644                    widthSegments: 40,
645                    heightSegments: 40,
646                    uniforms: {
647                        time: {
648                            name: "uTime",
649                            type: "1f",
650                            value: 0
651                        },
652                        mousepos: {
653                            name: "uMouse",
654                            type: "2f",
655                            value: [0, 0]
656                        },
657                        resolution: {
658                            name: "uReso",
659                            type: "2f",
660                            value: [innerWidth, innerHeight]
661                        },
662                        progress: {
663                            name: "uProgress",
664                            type: "1f",
665                            value: 0
666                        }
667                    }
668                };
669                this.initPlane();
670            }
671
672            initPlane() {
673                this.plane = this.webGLCurtain.addPlane(this.planeElement, this.params);
674                // this.plane = new Plane(this.webGLCurtain, this.planeElement, this.params)
675
676                if (this.plane) {
677                    this.plane.onReady(() => {
678                        this.update();
679                        this.initEvent();
680                    });
681                }
682            }
683
684            update() {
685                this.plane.onRender(() => {
686                    this.plane.uniforms.time.value += 0.01;
687                    this.plane.uniforms.resolution.value = [innerWidth, innerHeight];
688                });
689            }
690
691            initEvent() {
692                this.planeElement.addEventListener("mouseenter", e => {
693                    gsap.to(this.plane.uniforms.progress, .8, {
694                        value: 1
695                    });
696                });
697
698                this.planeElement.addEventListener("mouseout", e => {
699                    gsap.to(this.plane.uniforms.progress, .8, {
700                        value: 0
701                    });
702                });
703            }
704        }
705
706        if (navigator.userAgent.indexOf('Safari') == -1 || navigator.userAgent.indexOf('Chrome') > -1) {
707            $('.pxl-image-effect1.normal').each(function () {
708                const $this = $(this),
709                    canvas = $this.find('.canvas')[0],
710                    planeElement = $this.find('.item--image')[0],
711                    initialized = $this.data('initialized');
712
713                if (!initialized && canvas && planeElement) {
714                    new WebglHover({
715                        canvas: canvas,
716                        planeElement: planeElement
717                    });
718                    $this.data('initialized', true);
719                }
720            });
721        }
722
723        // Effect Expo
724        var WebExpo_vs = `#ifdef GL_ES
725        precision mediump float;
726        #endif
727
728        attribute vec3 aVertexPosition;
729        attribute vec2 aTextureCoord;
730
731        uniform mat4 uMVMatrix;
732        uniform mat4 uPMatrix;
733
734        varying vec2 vTextureCoord;
735
736        void main() {
737            gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0
737);
738
739            vTextureCoord = aTextureCoord;
740        }`;
741
742        var WebExpo_fs = `
743        #ifdef GL_ES
744        precision mediump float;
745        #endif
746
747        varying vec3 vVertexPosition;
748        varying vec2 vTextureCoord;
749
750        uniform float uTime;
751
752        uniform sampler2D planeTexture;
753
754        void main() {
755            vec2 textureCoord = vTextureCoord;
756
757            const float PI = 3.141592;
758
759            textureCoord.x += (
760            sin(textureCoord.x * 2.5 + ((uTime * (PI / 3.0)) * 0.031))
761            + sin(textureCoord.y * 2.5 + ((uTime * (PI / 2.489)) * 0.017))
762            ) * 0.0075;
763
764            textureCoord.y += (
765            sin(textureCoord.y * 2.5 + ((uTime * (PI / 2.023)) * 0.023))
766            + sin(textureCoord.x * 2.5 + ((uTime * (PI / 3.1254)) * 0.037))
767            ) * 0.0125;
768
769            gl_FragColor = texture2D(planeTexture, textureCoord);
770        }
771        `;
772
773        class WebGLExpo {
774            constructor(set) {
775                this.canvas = set.canvas;
776                this.webGLCurtain = new Curtains({
777                    container: this.canvas,
778                    watchScroll: false,
779                    pixelRatio: Math.min(1.5, window.devicePixelRatio)
780                })
781                this.planeElement = set.planeElement;
782                this.mouse = {
783                    x: 0,
784                    y: 0
785                };
786                this.params = {
787                    vertexShader: WebExpo_vs,
788                    fragmentShader: WebExpo_fs,
789                    widthSegments: 40,
790                    heightSegments: 40,
791                    uniforms: {
792                        time: {
793                            name: "uTime",
794                            type: "1f",
795                            value: 0
796                        },
797                        mousepos: {
798                            name: "uMouse",
799                            type: "2f",
800                            value: [0, 0]
801                        },
802                        resolution: {
803                            name: "uReso",
804                            type: "2f",
805                            value: [innerWidth, innerHeight]
806                        },
807                        progress: {
808                            name: "uProgress",
809                            type: "1f",
810                            value: 0
811                        }
812                    }
813                };
814                this.initPlane();
815            }
816
817            initPlane() {
818                this.plane = this.webGLCurtain.addPlane(this.planeElement, this.params);
819                this.plane = new Plane(this.webGLCurtain, this.planeElement, this.params)
820
821                if (this.plane) {
822                    this.plane.onReady(() => {
823                        this.update();
824                        this.initEvent();
825                    });
826                }
827            }
828
829            update() {
830                this.plane.onRender(() => {
831                    this.plane.uniforms.resolution.value = [innerWidth, innerHeight];
832                });
833            }
834
835            initEvent() {
836                let isHovered = false;
837
838                this.planeElement.addEventListener("mouseenter", e => {
839                    isHovered = true;
840                });
841
842                this.planeElement.addEventListener("mouseout", e => {
843                    isHovered = false;
844                });
845
846                this.plane.onRender(() => {
847                    if (isHovered) {
848                        this.plane.uniforms.time.value++;
849                    }
850                });
851
852            }
853        }
854
855        if (navigator.userAgent.indexOf('Safari') == -1 || navigator.userAgent.indexOf('Chrome') > -1) {
856            $('.pxl-image-effect1.expo').each(function () {
857                const $this = $(this),
858                    canvas = $this.find('.canvas')[0],
859                    planeElement = $this.find('.item--image')[0],
860                    initialized = $this.data('initialized');
861
862                if (!initialized && canvas && planeElement) {
863                    new WebGLExpo({
864                        canvas: canvas,
865                        planeElement: planeElement
866                    });
867                    $this.data('initialized', true);
868                }
869            });
870        }
871
872        // Effect Wave
873        const WebWave_vs = `
874        precision mediump float;
875
876        attribute vec3 aVertexPosition;
877        attribute vec2 aTextureCoord;
878
879        uniform mat4 uMVMatrix;
880        uniform mat4 uPMatrix;
881
882        varying vec3 vVertexPosition;
883        varying vec2 vTextureCoord;
884
885        uniform float uTime;
886
887        void main() {
888            vec3 vertexPosition = aVertexPosition;
889
890            float waveCoords = ((uTime / 45.0) * 3.5) - 1.75;
891
892            float distanceToWave = distance(vec2(vertexPosition.x, 0.0), vec2(waveCoords, 0.0
892));
893
894            vertexPosition.z -= (cos(clamp(distanceToWave, 0.0, 0.75) * 3.141592) - cos(0.75 * 3.141592) + (2.0 * sin(3.141592 * uTime / 90.0))) * 0.025;
895
896            gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0);
897
898            vTextureCoord = aTextureCoord;
899            vVertexPosition = vertexPosition;
900        }
901        `;
902
903        const WebWave_fs = `precision mediump float;
904
905        uniform float uTime;
906
907        varying vec3 vVertexPosition;
908        varying vec2 vTextureCoord;
909
910        uniform sampler2D uExample;
911
912
913        void main() {
914
915            vec2 textureCoords = vec2(vTextureCoord.x, vTextureCoord.y);
916            vec4 finalColor = texture2D(uExample, textureCoords);
917
918            gl_FragColor = finalColor;
919        }`;
920
921        class ImgCurtain {
922            constructor(set) {
923                this.canvas = set.canvas;
924                this.webGLCurtain = new Curtains({
925                    container: this.canvas,
926                    watchScroll: false,
927                    pixelRatio: Math.min(1.5, window.devicePixelRatio)
928                })
929                this.planeElement = set.planeElement;
930                this.mouse = {
931                    x: 0,
932                    y: 0
933                };
934                this.params = {
935                    vertexShader: WebWave_vs,
936                    fragmentShader: WebWave_fs,
937                    widthSegments: 40,
938                    heightSegments: 40,
939                    uniforms: {
940                        time: {
941                            name: "uTime",
942                            type: "1f",
943                            value: 0
944                        },
945                        resolution: {
946                            name: "uReso",
947                            type: "2f",
948                            value: [innerWidth, innerHeight]
949                        }
950                    }
951                };
952                this.initPlane();
953            }
954
955            initPlane() {
956                this.plane = this.webGLCurtain.addPlane(this.planeElement, this.params);
957
958                if (this.plane) {
959                    this.plane.onReady(() => {
960                        this.update();
961                        this.initEvent();
962                    });
963                }
964            }
965
966            update() {
967                this.plane.onRender(() => {
968                    this.plane.uniforms.time.value += 0.01;
969                    this.plane.uniforms.resolution.value = [innerWidth, innerHeight];
970                });
971            }
972
973            initEvent() {
974                let isHovered = false;
975
976                this.planeElement.addEventListener("mouseenter", e => {
977                    isHovered = true;
978                });
979
980                this.planeElement.addEventListener("mouseout", e => {
981                    isHovered = false;
982                });
983
984                this.plane.onRender(() => {
985                    if (isHovered) {
986                        this.plane.uniforms.time.value += (45 - this.plane.uniforms.time.value) * 0.0375;
987                    } else {
988                        this.plane.uniforms.time.value += (0 - this.plane.uniforms.time.value) * 0.0375;
989                    }
990                });
991            }
992        }
993
994        if (navigator.userAgent.indexOf('Safari') == -1 || navigator.userAgent.indexOf('Chrome') > -1) {
995            $('.pxl-image-effect1.wave').each(function () {
996                const $this = $(this),
997                    canvas = $this.find('.canvas')[0],
998                    planeElement = $this.find('.item--image')[0],
999                    initialized = $this.data('initialized');
1000
1001                if (!initialized && canvas && planeElement) {
1002                    new ImgCurtain({
1003                        canvas: canvas,
1004                        planeElement: planeElement
1005                    });
1006                    $this.data('initialized', true);
1007                }
1008            });
1009        }
1010
1011
1012        if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
1013            $('.pxl-image-effect1 .image-front').css('opacity', '1');
1014        }
1015
1016    }
1017    /* Img Carousel 4 */
1018    function aimo_img_2d($scope) {
1019        const items = gsap.utils.toArray($scope.find(".pxl-image-2d .item"));
1020        if (!items.length) return;
1021
1022        const radiusX = 1200;
1023        const radiusY = 1000;
1024        const activeAngle = -90;
1025        const angleStep = 360 / items.length;
1026
1027        let rotation = 0;
1028        let activeIndex = 0;
1029
1030        let isDragging = false;
1031        let wasDragging = false;
1032        let startX = 0;
1033
1034        function updatePositions() {
1035            const rad = Math.PI / 180;
1036
1037            items.forEach((el, i) => {
1038                const angle = (rotation + i * angleStep + activeAngle) * rad;
1039                const x = Math.cos(angle) * radiusX;
1040                const y = Math.sin(angle) * radiusY;
1041
1042                const relativeIndex = (i - activeIndex + items.length) % items.length;
1043
1044                let opacity = 0;
1045                let rotate = 0;
1046
1047                if (relativeIndex === 0) {
1048                    opacity = 1;
1049                    rotate = 0;
1050                } else if (relativeIndex === 1 || relativeIndex === items.length - 1) {
1051                    opacity = 1;
1052                    rotate = relativeIndex === 1 ? 18 : -18;
1053                } else if (relativeIndex === 2 || relativeIndex === items.length - 2) {
1054                    opacity = 1;
1055                    rotate = relativeIndex === 2 ? 30 : -30;
1056                }
1057
1058                gsap.to(el, {
1059                    x,
1060                    y,
1061                    rotate,
1062                    opacity,
1063                    duration: 0.4,
1064                    ease: "power2.out"
1065                });
1066
1067                el.classList.toggle("active", i === activeIndex);
1068            });
1069        }
1070
1071        function goTo(index) {
1072            activeIndex = (index + items.length) % items.length;
1073            rotation = -activeIndex * angleStep;
1074            updatePositions();
1075        }
1076
1077        // Initial render
1078        goTo(0);
1079
1080        // Click item để chuyển
1081        items.forEach((el, i) => {
1082            el.addEventListener("click", (e) => {
1083                // Nếu vừa kéo thì không xử lý click
1084                if (wasDragging) return;
1085                goTo(i);
1086            });
1087
1088            // FIX: Nếu img nằm trong <a>, ngăn mở link khi drag
1089            const link = el.querySelector('a');
1090            if (link) {
1091                link.addEventListener("click", (e) => {
1092                    if (wasDragging) {
1093                        e.preventDefault();
1094                        e.stopPropagation();
1095                    }
1096                });
1097            }
1098        });
1099
1100        // Scroll page để chuyển
1101        let scrollTween;
1102
1103        window.addEventListener("wheel", (e) => {
1104            if (scrollTween && scrollTween.isActive()) return;
1105            if (e.deltaY <= 0) return;
1106
1107            const stepAmount = angleStep / 2;
1108
1109            const targetRotation = rotation - stepAmount; // sang trái
1110            const snappedIndex = Math.round(-targetRotation / angleStep);
1111
1112            scrollTween = gsap.to({ value: rotation }, {
1113                value: -snappedIndex * angleStep, // tween đến rotation snap luôn
1114                duration: 3,
1115                ease: "power3.out",
1116                onUpdate: function () {
1117                    rotation = this.targets()[0].value;
1118                    updatePositions();
1119                },
1120                onComplete: () => {
1121                    goTo(snappedIndex); // đảm bảo index & rotation đồng bộ
1122                }
1123            });
1124        });
1125
1126
1127
1128
1129        // Drag tay để chuyển
1130        $scope.on("mousedown touchstart", (e) => {
1131            isDragging = true;
1132            wasDragging = false;
1133            startX = e.pageX || e.originalEvent.touches[0].pageX;
1134        });
1135
1136        $(document).on("mousemove touchmove", (e) => {
1137            if (!isDragging) return;
1138            const currentX = e.pageX || e.originalEvent.touches[0].pageX;
1139            const diffX = currentX - startX;
1140
1141            if (Math.abs(diffX) > 10) {
1142                wasDragging = true;
1143                goTo(activeIndex + (diffX < 0 ? 1 : -1));
1144                isDragging = false;
1145            }
1146        });
1147
1148        $(document).on("mouseup touchend", () => {
1149            isDragging = false;
1150            setTimeout(() => {
1151                wasDragging = false;
1152            }, 100);
1153        });
1154
1155        // Tự động xoay sau mỗi 5s
1156        setInterval(() => {
1157            goTo(activeIndex + 1);
1158        }, 5000);
1159    }
1160
1161    //animation_scroll
1162    function aimo_animation_scroll() {
1163        const elements = document.querySelectorAll('.animate-on-scroll');
1164        if (window.innerWidth > 991 && elements.length > 0) {
1165            elements.forEach(function (el) {
1166                gsap.fromTo(el,
1167                    { transform: 'translateY(200px)', opacity: 0 },
1168                    {
1169                        transform: 'translateY(0)',
1170                        opacity: 1,
1171                        duration: 1.15,
1172                        ease: 'power2.out',
1173                        scrollTrigger: {
1174                            trigger: el,
1175                            start: 'top bottom',
1176                            toggleActions: 'play none none none'
1177                        }
1178                    }
1179                );
1180            });
1181        }
1182    }
1183    /* ScrollEffect */
1184    function aimo_ScrollEffect() {
1185        const textElements = document.querySelectorAll('.pxl---text-scroll');
1186
1187        if (textElements.length > 0) {
1188            textElements.forEach(function (textElement) {
1189                const splitter = new SplitText(textElement, {
1190                    type: "words,chars"
1191                });
1192
1193                const chars = splitter.chars;
1194
1195                gsap.fromTo(chars, {
1196                    filter: 'blur(10px) brightness(30%)',
1197                    willChange: 'filter'
1198                }, {
1199                    filter: 'blur(0px) brightness(100%)',
1200                    ease: 'none',
1201                    stagger: 0.05,
1202                    scrollTrigger: {
1203                        trigger: textElement,
1204                        start: 'top bottom-=15%',
1205                        end: 'bottom center+=15%',
1206                        scrub: 0.2,
1207                    },
1208                });
1209            });
1210        }
1211    }
1212
1213    ///image box
1214    function aimo_image_rotate($scope) {
1215        const images = $scope.find('.pxl-image-box2.pxl-image-box-animation .pxl-box-inner .img-counter');
1216        let current = 0;
1217
1218        function rotateImage(img) {
1219            return gsap.to(img, {
1220                rotation: 360,
1221                duration: 6,
1222                ease: 'linear',
1223            });
1224        }
1225
1226        function showNextImage() {
1227            const prev = images[current];
1228            current = (current + 1) % images.length;
1229            const next = images[current];
1230
1231            // Reset z-index
1232            images.each(function () {
1233                $(this).css('zIndex', 0);
1234            });
1235            $(next).css('zIndex', 1);
1236
1237            gsap.set(next, { rotation: 0, opacity: 0 });
1238            gsap.to(next, { opacity: 1, duration: 1 });
1239            rotateImage(next);
1240
1241            gsap.to(prev, { opacity: 0, duration: 1 });
1242        }
1243
1244        gsap.set(images[0], { opacity: 1 });
1245        rotateImage(images[0]);
1246
1247        setInterval(showNextImage, 6000);
1248    }
1249
1250    $(window).on('elementor/frontend/init', function () {
1251        aimo_section_start_render();
1252        aimo_column_before_render();
1253        aimo_css_inline_js();
1254        aimo_section_before_render();
1255        aimo_zoom_point();
1256        aimo_scroll_fixed_section();
1257        aimo_animation_image();
1258        aimo_process3();
1259        aimo_split_scroll_color();
1260        aimo_image_split();
1261        aimo_webgl_effects();
1262        aimo_animation_scroll();
1263        aimo_ScrollEffect();
1264        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_image_carousel.default', function ($scope) {
1265            aimo_img_2d($scope);
1266        });
1267        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_contact_form.default', PXL_Icon_Contact_Form);
1268        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_heading.default', function ($scope) {
1269            aimo_split_text($scope);
1270        });
1271        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_text_marquee.default', function ($scope) {
1272            aimo_item_marquee2($scope);
1273        });
1274        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_image_box.default', function ($scope) {
1275            aimo_image_rotate($scope);
1276        });
1277    });
1278
1279})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.