Search the Community
Showing results for tags 'performace'.
-
Hi GSAP Community, I'm currently facing some performance issues with a project that I've been working on. According to Google PageSpeed Insights, I'm seeing significant main thread blocking time and high JavaScript execution time. Specifically, the report indicates: Minimize the impact of third-party code: Third-party code blocked the main thread for 44,300 ms Reduce JavaScript execution time: 25.1 s I'm not sure if this is due to the way I have written my code or if there might be other underlying issues. Here is the JSFiddle for my project: JSFiddle The Website / Test-Side which isnt published yet Test-Animation-Web For context, my project involves animating multiple bars using Three.js and GSAP. Below is a brief overview of my setup: I initialize the scene, camera, and renderer using Three.js. I load textures and create bar objects. I animate the bars using GSAP for both initial animation and continuous looping animation. I am very new and inexperienced with GSAP, but I'm really proud of what I've achieved so far. Here is a snippet of my code: let scene, camera, renderer, bars = []; let barCount = 500; // Number of bars let barWidth = 2 / barCount; // Width of the bars let texture, noiseTexture; function init() { const container = document.getElementById('container'); // Initialize scene and camera scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.z = 1; camera.position.x = -2.5; // Initialize renderer renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; container.appendChild(renderer.domElement); // Add lights const light = new THREE.PointLight(0xffffff, 1, 100); light.position.set(0, 5, 5); light.castShadow = true; scene.add(light); const ambientLight = new THREE.AmbientLight(0x404040); scene.add(ambientLight); // Load textures const loader = new THREE.TextureLoader(); loader.load( 'https://cors-anywhere.herokuapp.com/https://logton.de/lo-gt-on-sb92/wp-content/uploads/2024/07/DIE-LOGISTIKEXPERTEN-Logton.png', (tex) => { texture = tex; loader.load( 'https://threejs.org/examples/textures/disturb.jpg', (noiseTex) => { noiseTexture = noiseTex; createBars(texture, noiseTexture); initialAnimation(); } ); }, undefined, (err) => { console.error('Error loading texture:', err); } ); window.addEventListener('resize', onWindowResize); onWindowResize(); animate(); } function createBars(texture, noiseTexture) { const aspectRatio = texture.image.width / texture.image.height; const barHeight = 1.7; for (let i = 0; i < barCount; i++) { let geometry = new THREE.PlaneGeometry(barWidth, barHeight); let material = new THREE.MeshStandardMaterial({ map: texture, transparent: true, opacity: 0.9, onBeforeCompile: (shader) => { shader.uniforms.noiseTexture = { value: noiseTexture }; shader.fragmentShader = ` uniform sampler2D noiseTexture; ${shader.fragmentShader} `.replace( `#include <dithering_fragment>`, ` vec4 noise = texture2D(noiseTexture, vUv); gl_FragColor.rgb += noise.rgb * 0.1; #include <dithering_fragment> ` ); } }); let uvs = geometry.attributes.uv.array; for (let j = 0; j < uvs.length; j += 2) { uvs[j] = uvs[j] * (1 / barCount) + (i / barCount); } geometry.attributes.uv.needsUpdate = true; let bar = new THREE.Mesh(geometry, material); bar.position.x = (i - barCount / 2) * barWidth * aspectRatio; bar.position.y = Math.random() * 2 - 1; bar.scale.y = 10; bar.castShadow = true; bar.receiveShadow = true; bars.push(bar); scene.add(bar); } } function initialAnimation() { gsap.to(bars.map(bar => bar.position), { y: 0, duration: 2.5, ease: 'power4.inOut', stagger: 0.005 }); gsap.to(bars.map(bar => bar.scale), { y: 1, duration: 2.5, ease: 'power4.inOut', stagger: 0.005, onComplete: mainAnimation }); } function mainAnimation() { const animationPhases = [ { scaleY: 5, duration: 0.3, yOffset: 0.5 }, { scaleY: 0.2, duration: 0.125, yOffset: 0.2 }, { scaleY: 3, duration: 0.4, yOffset: 0.4 }, { scaleY: 2, duration: 0.5, yOffset: 0.3 }, { scaleY: 1.5, duration: 0.6, yOffset: 0.2 } ]; let currentPhase = 0; function animatePhase() { const { scaleY, duration, yOffset } = animationPhases[currentPhase]; bars.forEach((bar, i) => { const delay = Math.random() * 0.2; gsap.to(bar.position, { y: (Math.random() - 0.5) * yOffset, duration: duration, ease: 'power2.inOut', yoyo: true, repeat: 1, delay: delay, onComplete: () => { bar.position.y = 0; } }); gsap.to(bar.scale, { y: Math.random() * scaleY + 1, duration: duration, ease: 'power2.inOut', yoyo: true, repeat: 1, delay: delay }); }); currentPhase = (currentPhase + 1) % animationPhases.length; } animatePhase(); setInterval(animatePhase, 2000); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } function scrollContainer() { gsap.to(camera.position, { x: 2.5, duration: 16, ease: "linear", repeat: -1, onRepeat: () => { camera.position.x = -2.5; } }); } init(); scrollContainer(); I would appreciate any insights or suggestions on how to improve the performance and reduce the blocking time and execution time. Thank you!
-
Hey guys, I am happy to be here and use your amazing tools for my upcoming personal website. That being said, I need your advice. What would you say would be best practices when dealing with multiple reveal animations on scrolling? I've found that mobile performance (on Chrome, since Firefox seems to perform beautifully) is pretty bad when it comes to the way my reveal animations trigger. They feel stuttery and somewhat low-fps. I've tried slowly scrolling to avoid overriding them by dragging the screen (to see if multiple animations firing at once could be the cause), but the choppy animation effect is pretty much the same even if only one animation triggers. For reference, I've set up my reveal animations using attributes. I place certain attributes on certain elements, and a switch statement detects the type of animation that needs to be fired for each element. Here's more or less how this code is setup. Maybe you have some pointers on how would be best to setup something like this? function loadGSAPAnimations() { let selector = "[data-reveal]"; // Base selector for elements to animate // Query the DOM once for each modified selector let itemsToAnimate = document.querySelectorAll(selector); itemsToAnimate.forEach((itemFound) => { const elementTimeline = gsap.timeline({ delay: itemFound.dataset.delay || 0, // If "data-delay" attribute is present, adjust value defaults: { duration: 1, ease: "power4.out" }, }), animationType = itemFound.dataset.reveal; switch (animationType) { case "multi-element-reveal": const childElements = itemFound.querySelectorAll(childSelector); gsap.set(childElements, { opacity: 0, y: 115, willChange: "transform, translateY", }); elementTimeline.to( childElements, { opacity: 1, y: 0, stagger: 0.2, ease: "power4.out", onComplete: () => { gsap.set(childElements, { willChange: "auto" }); }, }, "+=0.3" ); break; case "element-reveal": gsap.set(itemFound, { opacity: 0, y: 115, willChange: "transform, translateY", }); elementTimeline.to( itemFound, { opacity: 1, y: 0, duration: 1, ease: "power4.out", stagger: 0.15, onComplete: () => { gsap.set(itemFound, { willChange: "auto" }); }, }, "+=0.3" ); break; case "title-reveal": let elementText = new SplitType(itemFound, { types: "lines", lineClass: "title-line", tagName: "span", }); gsap.set(elementText.lines, { opacity: 0, y: 115, willChange: "transform, translateY", }); elementTimeline.to( elementText.lines, { opacity: 1, y: 0, duration: 1, stagger: 0.15, ease: "power4.out", onComplete: () => { gsap.set(elementText.lines, { willChange: "auto" }); elementText.revert(); }, }, "+=0.3" ); break; case "image-reveal": const image = itemFound.querySelector("img"); const innerWrapper = image.closest(".image-animation-wrapper"); gsap.set(innerWrapper, { scale: 1.15, "--reveal-scale": 1, force3D: true, willChange: "scale, transform, translateY", }); elementTimeline.to( innerWrapper, { "--reveal-scale": 0, scale: 1, duration: 1.5, ease: "power4.out", onComplete: () => { gsap.set(innerWrapper, { willChange: "auto" }); }, }, "+=0.3" ); break; } //Controls the distance from the screen when the item gets revealed on scroll const revealOffset = itemFound.dataset.offset || 84; // Create the ScrollTrigger instance ScrollTrigger.create({ trigger: itemFound, animation: elementTimeline, start: `top ${revealOffset}%`, end: "bottom 35%", refreshPriority: -1, }); }); }
- 4 replies
-
- scrolltriger
- performance framerate
-
(and 3 more)
Tagged with:
-
I am creating an animated presentation. This presentation needs to run at 6240x2700 resolution. The image assets I am using are the same resolution varrying in size from 2MB to 10MB. I have multiple different timelines that will be used in a master timeline. The initial layout animations without content worked great (no surprise). But once I added the large images, the jittering got out of control. I am only changing scale and transform origin right now. There are other parts of the final product that will change opacity and position. I know this is a big screen and these are big files. But it does not change what I have been tasked to do. Things I am doing v what have tried: - I am using a grid layout for my content. I have tried placing everything in the body with absolute positioning - I am currently using background image css but I have tried using image tags - I have tried creating a smaller, more normal, screen size and then scaling it up to 6240x2700 with transforms - I serving images via a url. I have tried loading the images off localhost. - I have played with some image preloading techniques An interesting thing is that from time to time, the animation seems to hit a sweet spot after multiple loops and will run so smooth. It looks great and it leads me to think this can work. It needs to run smooth first round though. To test: The easiest way to test this at scale is to use chrome responsive layouts and create a layout for 6240X2700
-
Hi all I created a prototype some time ago. It has many GSAP animations. I want to focus on the animations that appears when you scroll. For instance the shortcut icons. If you compare my prototype with the production site you'll see that the animations are running slower on the production site. Prototype: http://yousee.grandorf.dk/homepage/homepage-clean.html Production site: https://yousee.dk/ The code is the exact same: import inView from 'in-view'; import { TimelineLite, TweenLite } from 'gsap'; export function heroAnimation() { inView('.hero--animated').once('enter', () => { const items = ['.hero__title', '.hero__lead', '.hero__action', '.hero__legal-text']; const tl = new TimelineLite({delay: .4}); tl.staggerTo(items, 1, {opacity: 1, y: 0, ease: window.Power2.easeOut}, .15) .to('.hero__brand-logo-image', 2, {opacity: 1, ease: window.Power2.easeOut}); }); } export function shortcutAnimation() { inView('.gsap-shortcuts').on('enter', el => { const items = el.querySelectorAll('.ys-shortcut'); const tl = new TimelineLite({delay: .25}); tl.staggerTo(items, .3, {opacity: 1, scale: 1, ease: window.Back.easeOut}, .15); }); } export function mediaboxAnimation() { inView('.media-box--animated').on('enter', el => { TweenLite.to(el, 1, {opacity: 1, y: 0, ease: window.Power2.easeOut}); }); } export function mediacardAnimation() { inView('.gsap-media-card').on('enter', el => { const items = el.querySelectorAll('.media-card--animated'); const tl = new TimelineLite({delay: .5}); tl.staggerTo(items, .5, {opacity: 1, y: 0, ease: window.Power2.easeOut}, .2); }); } What can cause this issue? Any ideas or help will be appreciated a lot. Thanks If you focus on the icons staggering in - you should be able to see the difference:
-
I tried use TweenLite in this pen: http://codepen.io/lagden/pen/QjQbwp?editors=001 and nothing happens! I would like to use TweenLite, but I don't know which feature is missing for it works!! TweenMax is very heavy for it! This is my current code! It is using TweenMax and it's working. TweenMax.fromTo(circle, duration, { x, y, scale: 0, opacity: 1, transformOrigin: '50% 50%' }, { scale: 10, opacity: 0 });
- 3 replies
-
- size
- performace
-
(and 2 more)
Tagged with: