Jump to content


  • Posts

  • Joined

  • Last visited

iongion's Achievements

  1. 5 years after - having similar issues. So far, the problems I seen emerging are when creating custom objects in fabricjs with custom properties. Here is my attempt at a plugin. All properties should be updated in fabric using `set(key, value)` - some of them work directly through `fobj.prop = value` - but if one subclasses `fabric.Object` and decorates it with a custom property, gsap won't interpolate it. I actually don't know why. Here is my attempt at solving this - using a Proxy - intercept calls and then use the fabric way of setting / getting properties. But it is ugly as then props must be placed in the plugin registered key like this anim.to(pi, { fabric: { progress: 75, top: 20, }, duration: 3, ease: "none", onComplete: () => { pi.setCoords(); }, }); And here is the ugly plugin - hopefully another human in 5 years from now will find it useful. /* eslint-disable */ let gsap, _coreInitted, _win, _fabricjs, _windowExists = () => typeof window !== "undefined", _getGSAP = () => gsap || (_windowExists() && (gsap = window.gsap) && gsap.registerPlugin && gsap), _warn = (message) => console.warn(message), _initCore = (core) => { gsap = core || _getGSAP(); if (_windowExists()) { _win = window; } if (gsap) { _coreInitted = 1; } }; export const FabricJSPlugin = { version: "3.11.3", name: "fabric", init(target, value, tween, index, targets) { if (!_coreInitted) { _initCore(); if (!gsap) { _warn("Please gsap.registerPlugin(FabricJSPlugin)"); } } this.target = new Proxy(target, { get(obj, key) { return obj.get(key); }, set(obj, key, val) { obj.set(key, val); return obj; }, }); let p, end; for (p in value) { end = value[p]; if (this.target[p] != null) { this.add(this.target, p, "get", end); } } }, register: _initCore, }; FabricJSPlugin.registerFabricJS = (fabricjs) => { _fabricjs = fabricjs; }; _getGSAP() && gsap.registerPlugin(FabricJSPlugin); export { FabricJSPlugin as default }; Thank you guys, for such awesome tools and libraries.
  2. Given two nested timelines added a parent timeline that is controlled by a scrub bar as follows ------------------^----------------- -----[t1s...t1e]-----[t2s...t2e]---- When I am seeking past a certain nested timeline positively I see progress never reaches 1, it stops around 0.9. When I am seeking negatively, they always reach 0 Is there a way to ensure 1 is reached ? I rely on this to be able to hide some graphical elements completely from the DOM. As I notice, when first loading the timeline, if I let it progress naturally with a pseudo play control, that does progress update of the main timeline, all happens as expected, elements are properly hidden / unhidden from the DOM. But if I seek directly to a certain spot, they don't hide properly, some remain visible as if the onComplete is never reached.
  3. Oh man, that is it, it was as simple as that, I've replaced all the seek / pause with timeline.invalidate() after path changes! Using gsap and nothing else since flash days!
  4. Thanks guys, will try to make a minimal example. The example from @akapowl did help a bit. I actually don't understand why the svg path & guide are not followed after alteration/changing by the user using the control points. The const guide is what changes its points over time by user performing actions on a bezier curve (the svg path behind the guide variable) The location of the circle is constrained by the timeline time and bezier curve alteration. What works is to intercept whenever the bezier curve changes and re-animate (re-create) the gsap timeline. I thought it is not needed, I thought there is something to tell the tween to re-parse the svg path once it is altered. In your demos it appears to do so by default, I don't understand why it doesn't do it in my approach. I am using a senseless setPath dependency just to recreate the tween, I suspect it might be heavy with many tweens. useLayoutEffect(() => { console.debug("re-animate"); const durationFrames = frameEnd - frameStart; const durationSeconds = durationFrames / framerate; const duration = durationSeconds * 1000; const guide = `#ProgressIndicatorMotionPath-${id}`; const targetProps = { duration, transition: "linear", motionPath: { path: guide, align: guide, autoRotate: false, alignOrigin: [0.5, 0.5], // immediateRender: true, // curviness: 1.5, }, }; const startTime = (frameStart / framerate) * 1000; const ctx = gsap.context(() => { const tween = gsapTimeline.to(ref.current, targetProps, startTime); tweenRef.current = tween; }); return () => ctx.revert(); }, [path, id, frameStart, frameEnd, framerate, gsapTimeline]); percentageRef.current = currentFrame / framesCount; const onMotionGuideChange = useCallback((e: any) => { setPath(e); if (tweenRef.current) { const current = tweenRef.current.progress(); tweenRef.current?.restart(); tweenRef.current?.progress(current); tweenRef.current?.pause(); } }, []);
  5. They are close, but I am altering the svg path definition points programatically. Only some of them due to the constraints. What I have found working is re-initializing the entire timeline when path definition changes. But the experience is not that smooth.
  6. I am using an existing CodePen to exemplify the problem. If one uses inspect element and manipulates directly the motion guide / path definition, then the motionPath plugin still uses the previous definition. Is there a way to make it follow dynamic transform of the motion path ? I am planning to animate the motion path itself.
  7. Lovely, it works like a charm! Many thanks!
  8. In React 18 we must ensure resilience of apps when multi rendering to detect leaks. I am using this kind of code. Without the ability to cleanup previous motion path helpers, I see the helper twice on the screen. Is there a way to clean-up ? useLayoutEffect(() => { const guide = `#ProgressIndicatorMotionPath-${id}`; const targetProps = { // log: true, duration, transition: "linear", motionPath: { path: guide, align: guide, autoRotate: false, alignOrigin: [0.5, 0.5], }, }; const startTime = (frameStart / 60) * 1000; console.debug("Adding tween", targetProps, startTime); const tween = gsapTimeline.to(ref.current, targetProps, startTime); const helper = MotionPathHelper.create(guide); return () => { tween.kill(); // gsap.killTweensOf(helper); }; }, [id, target, frameStart, duration, pathSelector, gsapTimeline]);
  9. I have tried to disable / enable while jumping from section to section using getById https://codepen.io/iongion/pen/oNzejeG But it seems triggers stay disabled even after enabling them. Now everything works, tada! 😁 The goal is to have the current viewport scroll trigger(s) do its(theirs) leave and destination one to do its enter (from front or back) but I still need the in between to be disabled (I am adding 3d scene transitions so If I keep the scroll trigger for all, it becomes a visual abuse)
  10. Wow, thank you @ZachSaucier I think I have a good global progress bar now - https://codepen.io/iongion/pen/dypRExv But is it reliable ? I am using `window.scrollY` and `ScrollTrigger.maxScroll(window)` to know the progress Most likely I will have to take care of window resizing to make it more scalable.
  11. I try to understand the following - Disable animations temporarily while jumping between sections - Know the total progress and add it to a linear scrollbar of .globalProgressbar input slider Context for disabling I would like to disable animations this way, when a user clicks directly to go to a section, then all should be suspended except the start one and destination. I need this because on a typical workflow, there are nested complex animations linked to the scroll trigger, 3d transitions and when users jump directly to a section then there is an abuse of animations for the browser, would like to make it more efficient. Context for slider I would like the slider to indicate and control the complete scroll progress as one. I tried summing up per section but sometimes the onUpdate for a certain section is not completing to 100% It is my first try of gsap for something useful after 7 years of moving away from Flash and I am so excited, thank you, it remembers me the good times when minimalcomps made me fall for UI forever!