Jump to content

Search In
  • More options...
Find results that contain...
Find results in...

Johan ⚡️ Nerdmanship

  • Posts

  • Joined

  • Last visited

Everything posted by Johan ⚡️ Nerdmanship

  1. Ah perfect – thanks a lot, Jack! And by including a css wrapper GSAP won't change the objects, I presume. TweenMax.set(blueDot.target, { css:pointObjects[i] });
  2. This looks so simple but I just can't figure out what the problem is. I'm creating a bezierPlugin demo and use an array of point objects both to define the bezier path and to distribute visual guides. TweenMax throws an error `invalid css tween value: [object Object]` like the objects aren't valid, but everything looks fine to me. The loop and pen works fine with any hardcoded object such as `{ x: 100, y: 100 }`. Why is the referenced object invalid in the `TweenMax.set()`? // Create dots and distribute them along the bezier path for (var i=0; i<6; i++) { var blueDot = new Dot(container); blueDot.target.className = "blue-dot"; //TweenMax.set(blueDot.target, pointObjects[i]); console.log(pointObjects[i]); // Looks like a valid object to me } Un-comment line 38 and see it break. Many thanks!
  3. A million thanks, Jack! I went with the less optimal but to me conceptually familiar method. There are so many new concepts to me in this project, so adding another one – even if it's a small one – felt daunting. The methods I ended up using were good enough tho and are silky smooth on all devices I've tested on. Very pleased! The code is messy but it's working. For sake of learning tho I'm gonna refactor it as soon as I get the chance, and I will definitely use your suggested solution when I do. I sense there's some very usable concepts in there, and I recognise some from Coding Math (as recommended by Blake). Seems to be "animation standards" of sorts and as an aspiring web animator... I kinda like that. Here is the end result for whoever is interested: https://nerdmanship.github.io/DMSS-Logo-animation/dist/
  4. Thanks for some pretty code and your precious time, Jack! ❤️ I need to touch up my trigonometry to fully understand what's going on. At this point I can't determine if this will solve my problem or not. The actual project has large parts of it developed already and I depend on a solution in which I can use the x and y values from one elements gsTransform object and the rotation of another. In the actual project the particles will not be explicitly animated but respond to the coordinates of the colourful rectangles and the rotation value of a group element surrounding them. (mockup) My plan is to give each particle its own TweenMax object with its own modifier function feeding x and y values based on values from the leading elements gsTransform object. Here's a simplified part of that: TweenMax.to(particle, 1, { x: 0, y: 0, repeat: -1, ease: Linear.easeNone, modifiers: { // Distributes the particles exponentially between 0 and the current position of rect x: function() { return (indexSq / countSq) * rect._gsTransform.x; }, y: function() { return (indexSq / countSq) * rect._gsTransform.y; } } }); I'm not sure, but it seems like I could use the intended x/y/rotation values from gsTransform objects to update radius/angle of a proxy to generate x/y values for each particles. The math of it is possibly too advanced for me tho, so I might have to fall back on the SVG 2 style just because I can wrap my head around it.
  5. Every dev around me get excited when I show them what can be done with HTML5 and GSAP. Most of them start playing with the idea to apply the same concept of programmed, and potentially data driven, animation to whatever project they are working on. Very often I get the question if you can do the same things for other platforms, i.e. native iOS or android apps, and I simply don't know how to answer. My initial thought is that you can use GSAP wherever you can use JS, but I don't have enough experience from projects on these platforms. Any experience, thoughts or recommendations on this? <3
  6. I learned a lot big and small from exercises such as Wes Bos' Javascript 30: javascript30.com/ I also enjoy watching conf talks on all different Js topics. It goes beyond syntax and coding techniques, and slowly but surely provides a great general knowledge on how JS things work and why. This in turn gives you a really good understanding on why devs do like they do. I.e: What the heck is the event loop anyway? I also follow people on youtube and listen to their opinions and watch them code live. I.e. FunFunFunctions GLHF!
  7. I worship your input as a divine scripture. Thanks again for sharing! Since you shared the technique of map func, modifiers and storing values in an object I've not only been writing better code, but thinking more creatively about animations. I don't see many reasons not to use modifiers at the moment. I recommend anyone reading to check out Blake's forum posts about norm, lerp and map functions here, how he updates a tween with modifiersPlugin in this pen and how he combines map and modifier in this pen. ✌️
  8. Blake, what a surprise! Let me know if you ever need a kidney. I noticed this in the project I'm working on, and honestly I had no idea "let" created a new scope on each iteration. After knowing this and studying more of your mentioned pens, I rewrote my code and, as usual, it works better. My brain hurts tho. To me, using the let/const is a first step into ES6 and a little affirmation to myself that I'm not afraid of new syntax (which - of course - I am). Whenever I use var, I feel like I'm resorting to my comfort zone where I develop less. This is clearly not rational. Understanding var on a fundamental level would obviously not set me back. But when I think about it that's probably my main motivation. I bet a lot of people, just like me, don't fully understand what we're doing and why. However, this tend to put me in tricky situations in which I'm forced to learn. Edit: Oh, kind of on the same topic... you said in this post that you wouldn't use mouse position for some values in a real project. Why is that?
  9. Greetings! I'm using Blakes clever method of using a mouse object to update a modifier function (pen), but in my case I have multiple targets. It feels like a pretty common use case, so I assumed there's a good practise to do it. In the example I want the boxes to follow the mouse movement depending on their respective index in the collection. The pen works, but I wonder if there's a way to do it without a for loop, like the way you can with "function based values". This is what I've got: (pen) // A collection of five boxes const boxes = document.querySelectorAll(".box"); // Mouse object as input in modifier function const mouse = { x: 0 } // Bind mouse to update function window.addEventListener("mousemove", updateMouseObj); // Updates mouse object function updateMouseObj(e) { mouse.x = e.clientX; } // Working example with for loop for (let i = 0; i < boxes.length; i++) { TweenMax.to(boxes[i], 1, { x: 0, repeat: -1, ease: Linear.easeNone, modifiers: { x: function() { return mouse.x * i; } } }); } /* // Seems lengthy and fragile, Codepen throws an infinite loop error TweenMax.to(boxes, 1, { x: 0, repeat: -1, ease: Linear.easeNone, modifiers: { x: function(x, target) { for (let i = 0; i < boxes.length; i++) { if (target === boxes[i]) { return mouse.x * i; } } } } }); // Would wanna do something like this TweenMax.to(boxes, 1, { x: 0, repeat: -1, ease: Linear.easeNone, modifiers: { x: function(i) { return mouse.x * i; } } }); // ...like function based values work TweenMax.to(boxes, 1, { x: function(i) { return 50*i; } }); */ Thanks! <3
  10. Thank you so much for your thoughts and pens, guys! Great advice, Dipscom – thanks! Of course I ran in to this problem and my solution was to kill the interval on window.blur and recreated it on window.focus. It works well, but it doesn't feel robust enough. This (code below) was what I could imagine from your suggestion, but I realised that it probably would end up out of sync in the tab use case. It also kinda does the same as the previous version, only looping thru the array differently. What did you have in mind? var boxes = []; var dur = 2; // create one timeline that repeats itself tl.to(boxes, dur, { bezier: [ { autoAlpha: 0 }, { autoAlpha: 1 }, { autoAlpha: 0 } ], repeat: -1 }); // updates the contents of the boxes at a specific point in time setInterval(function() { // update stuff }, (dur*1000)/2) // Half way thru timeline duration - - Thanks Blake – always great advice and so useful resources! Thanks for both offering me what I was looking for and also a better way to approach it.
  11. Thanks Carl! Sorry for the private settings, I wasn't aware it was limiting in that sense. It's update and public here: http://codepen.io/nerdmanship/pen/bBbbwE The brackets did do the trick with passing the i. It was sloppy of me and I haven't had this issue in other projects. I discovered that the callback was working only because $box was leaking to the global object, since I forgot to declare it with "var". I don't want that, I want to keep the variable in the local scope. So I'm still wondering about scope. By logging this from the callback function I can see that the scope is changed successfully from the timeline to the newItems function by writing like so: .call(getRandomItem, [i], newItems) However, the $box variable in the callback still throws a reference error. Which is my initial problem and query. If I would declare the callback function inside newItems function then $box is referenced properly. This is what I want to achieve, but I want to declare the function outside that scope to make it accessible to other functions too. If this is too much of a general Js question I could turn to Stack Overflow and then come back here and share any results. --- Just some context to clarify why I'm asking... - I want each function to have one job (as long as it makes sense) - I want to be able to reuse functions in other functions - I don't want to repeat myself and declare the same variable multiple times This is why I run into challenges regarding scope a lot. I'm practising and researching it a lot, but I still have some missing knowledge it seems. In this case I could solve this by re-assigning $box = $boxes in the callback function, but it seems like bad practice. Especially if you'd have a bunch of variables. The code eventually gets bloated, harder to overview and manage, and more prone to bugs. If this problem is solved there will still be a timing issue. The loop will perform all of its iterations before the first timeline has reached the first callback. All callbacks will reference the same $box – the last item of the $boxes array. Edit: Removed jQuery
  12. Thanks Jonathan! Yes, I've read it. It only says that the scope is the scope scope : * (default = null) — The scope in which the callback should be called (basically, what "this" refers to in the function). NOTE: this parameter only exists in the JavaScript and AS2 versions. I want to set the scope in the TimelineMax.call() so that the callback function can access the scope of the calling function and the current iteration (able to reference variables $box and i). It's a general question about how to set the scope in TimelineMax.call() method, but I've made a pen about it as simple as I could: http://codepen.io/nerdmanship/pen/faceacc19dde87ebaca7e49e703ddecd // I want the callback function to have access to the variables i and $box // I assume I can achieve that by setting the scope in the TimelineMax.call() // --- // #fruits box only wants fruits // #animals box only wants animals var $boxes = $("[data-box]"); // $boxes[0] & $boxes[1] // Array of two arrays of items var arr = [ ["Apple", "Banana", "Citrus"], ["Dog", "Elephant", "Ferret"] ]; function newItems() { // Iterate thru $boxes for (var i = 0; i < $boxes.length; i++) { $box = $($boxes[i]); var tl = new TimelineMax(); // Fade it out, inject new random item, fade back in tl.to($box, 1, { autoAlpha: 0, delay: i*0.2 }) .call(getRandomItem, i, newItems) .to($box, 1, { autoAlpha: 1 }); } } // Injects a random fruit item to fruit box and animal item to animal box function getRandomItem(i) { // Sets newItem to i.e. arr[1][0] which is "dog" var newItem = arr[i][Math.floor(Math.random()*arr[i].length)]; // i from for loop in newItems() $box.html(newItem); // $box from newItems() } // Renew items in boxes every 4 seconds setInterval(newItems, 4000); Thanks!
  13. I often use the call() method in my timelines. tl.call(func, ["param1"], this, 2); A typical situation looks like this (code below), where I wanna iterate through an array and for each item in the array I wanna create a timeline and then also run another function which use the same elements as in the current iteration. If I just run the function someplace inside the loop, that works fine, but I don't have the timing control. And if I run it as a callback in timeline I can't reference the elements in the current iteration. So I solve that by passing i as a parameter and then I repeat myself and declare "var elem = myArray" again in the callback function, which seems like a hack. var myArray = [ myElem, myOtherElem ]; function myFunction() { for (var i = 0; i < myArray.length; i++) { var elem = myArray[i]; // I want to access this element in my callback var tl = new TimelineMax(); tl.to(elem, 1, { autoAlpha: 0}) .call(myOtherFunction) // This guy can't access the "elem" in the current iteration .to(elem, 1, { autoAlpha: 1 }); myOtherFunction(); // But this guy can } } Is there a way to write the call() method so the "myOtherFunction" can use the variable "elem" in the current iteration without passing it as a parameter??
  14. Animating transforms are great for sure – but I can definitely not stick to it. I guess I'll do some experimentation and post here again when I've got something. Thanks a bunch for your time and the reading tips!
  15. Hi, thanks for your reply! I'll elaborate this brain fart a little bit, so please bare with me. -- At first I was hoping for an implicit test of sorts, like the way that some feature detection seems to work. Instead of asking someone what languages they speak, you could say something in German and see if they get it. And then French, Italian, etc. So instead of explicitly asking the system about its RAM/CPU, you'd throw it a task and see how it responds. I don't know, like ask the browser to create and kill a thousand elements, or make a latency/fps test, or measure how fast the browser parse a specific document. Measure the result of whatever test and rank it between fast and slow. Are these crazy-thoughts? -- Another idea would be to forget about the actual hardware and focus on feature detection that relate to hardware. Let's say we had an animation that could be done in a light, moderate and rich fashion. Never mind the blur, just anything resource heavy. Wouldn't it be possible to combine information that is likely to be related to performance and then make assumptions about the system from there? Examples: What's significant for a system likely to be above average? Condition 1: It has a retina display, but it isn't a touch device (true for most modern laptops) Condition 2: It has force touch, but it isn't a touch device (true for any new macbook) Condition 3: ..? What's significant for a system likely to be below average? Condition 1: Runs <IE10 Condition 2: Any Samsung user agent and is mobile device Condition 3: ..? Anything that doesn't qualify in above or below average falls back in moderate. if (aboveAverage) { initRich() } else if (belowAverage) { initLight() } else { initModerate() } Wouldn't something like this be useful? What other conditions could be added? -- Maybe none of this is doable, desirable or usable... I don't know. My experience in hardware and computer science is very limited. But GSAP does unlock some really cool possibilities for "conventional" animators, motion graphics artists and interaction designers, and we could definitely optimise the user experience if we have some (any) knowledge about the user's system. Maybe the topic should be something like: Graceful degradation and progressive enhancement for graphics and motion?
  16. Designing by screen size and available features is common practice, but what about hardware? I wanna do something like this: if (powerfulCPU) { // Use a crazy amount of blur } else { // Skip everything fancy but still deliver a killer animation } Is there a way to perform a quick CPU test in the loading sequence of a website in a similar manner that Modernizr does feature testing? Or do you have any other thoughts on how to achieve something similar?
  17. Thanks, I cleaned up the pen! The stroke width makes a lot of sense, thanks!
  18. Hey community! Can't figure this one out. I need your help! <3 I want to tween a path from "0% 0%" to "0% 100%" with the drawSVG plugin, but it behaves like the 0-position is offset from the actual beginning of the path. When I flip it around to "100% 100%" to "0% 100%" it works fine. Clueless 0.o // It seems like 0% is offset from the beginning of the path TweenMax.fromTo("#backPathP", 0.5, {drawSVG: "0% 0%"}, {drawSVG: "0% 100%", repeat: -1, yoyo: true }) // If I flip it over it behaves like I want to // TweenMax.fromTo("#backPathP", 0.5, {drawSVG: "100% 100%"}, {drawSVG: "0% 100%", repeat: -1, yoyo: true })
  19. Masking vs Clipping I'm not sure this is a gotcha, but it's definitely a confusing matter that has been very time-consuming for me. Dropping it here to maybe save someone else. Here's a pen using the same path for both masking and clipping to compare the two. I expected the exact same result, but the mask clearly includes all the attributes and the clipPath is ignoring the stroke attributes and just renders the inside of the path (like a fill would). "For the clipping, every path inside the clipPath is inspected and evaluated together with its stroke properties and transformation." Mozilla Docs: Clipping and Masking I don't think the doc is wrong, but it's definitely confusing. I understand this as the stroke properties will be included. "A clipping path is conceptually equivalent to a custom viewport for the referencing element." Mozilla Docs <clipPath> This, to me, means never do anything fancy with clipPath. Just use it to define a "viewport".
  20. "Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime." Thanks a bunch, Blake – great answer! I feel like I got a fish, fishing equipment, fishing lessons and some fishing literature recommendations. I can see how this is a powerful method in combination with GSAP. I'm new to the reduce() method (as I am to most methods ), and yes, it's indeed a little difficult to wrap my head around. I'm gonna think out loud here and hopefully provide some value to others at my skill level. The reduce() method pretty much take all my things and does whatever I specify with each one, then accumulates them into one thing and returns it. What's tricky to me are mainly two things, 1) what the "accumulation" means and 2) what the parameters that I input means. 1) The purpose of the method is to reduce many things into one thing. So when it accumulates, it just means that the one thing is added to the other – each round it adds one unit to a whole. Like playing with Legos, you got a stack of a dozen pieces and you wanna build a tower. Each round you take one piece from the stack, you orient it properly, and then add it to the tower. The pieces are accumulated to a tower one piece at the time. 2) In this case the method takes three parameters; previousValue ( parent ), currentValue ( rect ) and initialValue ( new TimelineMax() ). previousValue is whatever has been accumulated so far and starts at either the first lego piece in the stack or whatever initialValue is specified as currentValue is the lego piece you're working with right now and starts at either the first or the second piece depending on if previousValue starts at the first piece or initialValue initialValue is optional and if specified it's what the method starts with (as previousValue), i.e. a base plate to build the lego tower upon rects.reduce(function(parent, rect) { // array.reduce(function(previousValue, currentValue) var tl = new TimelineMax(); // do the next three lines of code to each value in my array... tl.from(rect, 1, { scale: 0 }); // "rect" is "currentValue", which in this case starts at rect[0] because an initialValue is provided return parent.add(tl); // "parent" is "previousValue", which in this case start at "new TimelineMax()" because the initialValue is provided }, new TimelineMax() ); // this is the initialValue So when running it, I guess this happens... //first round returns new TimelineMax() // this is previousValue as specified by initialValue .add(new TimelineMax().from(rect[0], 1, { scale: 0 })) // rect[0] is currentValue //second round returns new TimelineMax().add(new TimelineMax().from(rect[0], 1, { scale: 0 })) // this is previousValue from round 1 .add(new TimelineMax().from(rect[1], 1, { scale: 0 })) // rect[1] is currentValue //third round returns // whatever was returned from round 2 is previousValue // rect[2] is currentValue and is injected to the specified tl and is accumulated to previousValue //nth round returns whatever was returned from the previous round plus the current round //if my array contains 12 rect the reduce() method spits out something like this new TimelineMax().add(new TimelineMax().from(rect[0], 1, { scale: 0 }))/* ... */.add(new TimelineMax().from(rect[11], 1, { scale: 0 })) I learned a lot writing this, given it's correct. Please correct me if I screwed anything up! Thanks again, Blake!
  21. I have created a grid of rects in an SVG element and for each rect in the grid I'm trying to create a unique sub-timeline to add to a main timeline. I haven't isolated the problem in the pen, but I will if necessary. Line 1–70 is just code for generating the grid, as far as I know, you can just ignore this. The creation of timelines start at line 70. I have an array of 12 rects and I want to loop through them and create sub-timelines with random durations and add them to the main timeline. var rects = selectAll(".rectangle"); // Array of rects var mainTl = new TimelineMax(); // Main timeline // Loop through the array and output a timeline for each rect in the array function makeTls() { for(var i = 0; i<rects.length; i++){ var tl = new TimelineMax(); // Create a sub-timeline var ranDur = randomBetween(0.5, 3); // Generate a random duration tl.from(rects[i], ranDur, { scale: 0 }); // Specify unique tween return tl; // Return a unique timeline } } mainTl.add( makeTls() ); // How to add a dynamic number of tls to the main tl? I understand why this doesn't work, but I can't figure out how to output as many unique timelines as I have rects in my array and add them to the main timeline. Can you point me in a direction? I'm aware that I can use staggerFrom() and cycle the duration property with a randomising function, but I wish to explore the loop option for learning purposes.