Our Team

We’re on a mission to uplift people and economies through entrepreneurship, innovation and education.

Our people come from all walks of life, bringing together knowledge and insight from a wide range of industries and backgrounds. Work with passionate, experienced professionals who take a personalised approach and are genuinely invested in your growth.

Our people

Meet the team

David Williamson
Chief Executive Officer
Tess Melville
Chief Operating Officer
Talya Pecen
Digital Coordinator
Jess Suyudy
Business Support Officer
Our people

Meet the board

Tina Cao
Mitchell Bryce
Chris James
Deborah Johnston
Lawrence Pigot
Nathaniel Bolton
Chris Koulouris
Simon Serebryanikov

Join a welcoming community made up of both fellow entrepreneurs and the Melbourne Innovation Centre team - people who understand your journey and want to see you succeed.

Connect

const getCookie = name => { const nameExpression = `${name}=`; const cookies = document.cookie.split(';'); const cookie = cookies.find(currentCookie => currentCookie.includes(nameExpression)); return cookie ? cookie.trim().substring(nameExpression.length, cookie.length) : null; } const setCookie = (name, value, expire = 365, path = '/') => { const date = new Date(); date.setTime(date.getTime() + (expire * 24 * 3600 * 1000)); const expires = date.toUTCString(); document.cookie = `${name}=${value}; expires=${expires}; path=${path}`; }; const openCtaPopup = () => { const popup = document.querySelector('.event-popup'); gsap.set(popup, { autoAlpha: 0 }); document.querySelector('.popup-wrapper').style.display = 'block'; const tl = gsap.timeline() .fromTo(popup, { yPercent: 100, autoAlpha: 0 }, { yPercent: 0, duration: 1, autoAlpha: 1, ease: 'back.out(1.1)' }); } const closeCtaPopup = () => { const popup = document.querySelector('.popup-wrapper'); const type = popup.dataset.popupType setCookie(`${type}-popup`, "show", 2); gsap.to(popup, { autoAlpha: 0, duration: 0.5 }); } addEventListener("DOMContentLoaded", (e) => { gsap.to(window, {duration: 1, scrollTo: 0}) const header = document.querySelector('section.header-wrapper'); const positionHeader = () => { const height = calcHeight(header.querySelector('.navbarcontent'), header); header.classList.add('sticky'); document.getElementById('smooth-wrapper').style.marginTop = `${height}px`; } positionHeader(); const hasPopup = document.querySelector('.popup-wrapper'); if(hasPopup) { const type = hasPopup.dataset.popupType; window.popupCookie = getCookie(`${type}-popup`); if(window.popupCookie !== 'show') { setTimeout(() => { openCtaPopup(); }, 7000); } } document.querySelectorAll('[data-close-popup]').forEach(i => { i.addEventListener('click', (e) => { e.preventDefault(); closeCtaPopup(); }); }); const gradientSection = document.querySelector('[data-gradient-scroll]'); if(gradientSection) { const percentage = gradientSection.dataset.gradientScroll ?? 61; gsap.set(gradientSection, { background: `linear-gradient(0deg, #beced8 ${percentage}%, #341716)` }); gsap.timeline({ scrollTrigger: { trigger: gradientSection, start: 'top bottom', end: 'bottom bottom' } }) .to(gradientSection, { duration: 1, background: `linear-gradient(0deg, #beced8 ${percentage}%, #beced8)` }); } //gsap.timeline({ //scrollTrigger: { //trigger: 'footer', //start: 'top bottom', //end: 'bottom bottom' //} //}) //.to('.animated-footer-logo-wrapper', { //width: 'auto', //duration: 2, //ease: 'power1.out' //}); const openNavbarDropdown = (link) => { const element = document.getElementById(link.dataset.dropdownTrigger); const svg = link.querySelector('svg'); if(svg) { gsap.to(svg, { rotate: 180, duration: 0.4 }); } gsap.to(element, { autoAlpha: 1, y: 0, yPercent: 0, duration: 1, ease: 'power1.out', onStart: () => { element.setAttribute('data-open', "loading"); }, onComplete: () => { element.setAttribute('data-open', "true"); window.setTimeout(() => { element.focus(); }, 100); } }); } const closeNavbarDropdown = (dropdown) => { dropdown.setAttribute('data-open', "loading"); const link = document.querySelector(`[data-dropdown-trigger="${dropdown.getAttribute('id')}"]`); const svg = link?.querySelector('svg'); if(svg) { gsap.to(svg, { rotate: 0, duration: 0.4 }); } gsap.to(dropdown, { autoAlpha: 0, yPercent: -200, duration: 1, ease: 'power1.out', onComplete: () => { dropdown.removeAttribute('data-open'); } }); } document.querySelectorAll('[data-dropdown-trigger]').forEach(i => { const element = document.getElementById(i.dataset.dropdownTrigger); if(element) { element.addEventListener('blur', (e) => { if(e && (element.contains(e.relatedTarget) || e.relatedTarget === i || i.contains(e.relatedTarget))) { return false; } closeNavbarDropdown(element); }) } i.addEventListener('click', (e) => { e.preventDefault(); const element = document.getElementById(i.dataset.dropdownTrigger); if(!element) { return; } if(element.dataset.open === 'loading') { return; } if(element.hasAttribute('data-open')) { closeNavbarDropdown(element); return; } openNavbarDropdown(i); }); }); setTimeout(() => { // const firstAnchor = document.querySelector('.smooth-content [data-cta-anchor="true"]'); //if(firstAnchor && firstAnchor.checkVisibility()) { //gsap.timeline({ //scrollTrigger: { //trigger: firstAnchor, //start: 'top +200px', //scrub: 1 //} //}) //.to('.header-wrapper.sticky', { // yPercent: -100, //duration: 2 //}, 0) //.to('#smooth-wrapper', { //y: 0, //marginTop: 0, //duration: 1 //}, 0); gsap.timeline({ scrollTrigger: { trigger: header, start: '+=50', scrub: 1 } }) .to('.header-wrapper.sticky .header', { paddingTop: 12, paddingBottom: 12, duration: 0.6 }, 0) .to('#smooth-wrapper', { y: -48, duration: 0.4 }, 0); //} document.querySelectorAll('[trigger-aside-open]').forEach(i => { i.addEventListener('click', (e) => { const section = i.getAttribute('trigger-aside-open'); e.preventDefault(); openAside(); if(section === 'services') { openServicesPanel(); } else if(section === 'contact') { openContactPanel() } }); }); // document.querySelectorAll('[trigger-services-open]').forEach(i => { // i.addEventListener('click', (e) => { // openServicesPanel(); // }); // }); // document.querySelectorAll('[trigger-contact-open]').forEach(i => { // i.addEventListener('click', (e) => { // openContactPanel(); // }); // }); // document.querySelectorAll('[trigger-main-open]').forEach(i => { // i.addEventListener('click', (e) => { // openAside(); // }); // }); document.querySelectorAll('[trigger-aside-close]').forEach(i => { i.addEventListener('click', (e) => { e.preventDefault(); closeAside(); }); }); }, 1200) ScrollSmoother.create({ smooth: 2, smoothTouch: 0.1, effects: true, normalizeScroll: false, ignoreMobileResize: true, wholePixels: true }) const aside = document.getElementById('menu-aside'); aside.querySelector('.menu-panel').addEventListener('click', e => { if(e.target.classList.contains('dropdown')) { return; } if(e.target.classList.contains('navlink')) { closeAside(); return; } if(e.target.hasAttribute('trigger-aside-close')) { return; } if(e.currentTarget.classList.contains('active')) { return; } e.preventDefault(); openAside(); }); document.querySelectorAll('[data-horizontal-scroll]').forEach(i => { const items = i.querySelectorAll('[data-horizontal-items]'); const wrapper = i.querySelector('[data-horizontal-wrapper]'); const styles = window.getComputedStyle(i); const type = i.dataset.horizontalScroll ?? 'standard'; if(type === 'standard') { const tl = gsap.to(wrapper, { scrollTrigger: { trigger: i, scrub: 1.2, pin: wrapper, anticipatePin: 1, start: "center center", end: () => `+=${wrapper.scrollWidth}`, invalidateOnRefresh: true }, x: () => -(wrapper.scrollWidth - (wrapper.offsetWidth)), ease: 'none' }) } else if(type === 'sticky') { const items = i.querySelectorAll('[data-horizontal-items]:not(:first-of-type)'); items.forEach((image, k) => { gsap.set(image, {position: 'absolute'}); const tl = gsap.fromTo(image, {xPercent: 100}, { scrollTrigger: { trigger: i, start: () => "+=" + (wrapper.offsetWidth * k), end: () => "+=" + wrapper.offsetWidth, scrub: 1.2, markers: false, invalidateOnRefresh: true, toggleActions: "play none reverse none", }, x: () => `-${wrapper.offsetWidth}`, ease: 'none' }); }) ScrollTrigger.create({ trigger: i, scrub: true, markers: false, pin: true, anticipatePin: 1, start: () => `center center`, end: () => "+=" + (wrapper.offsetWidth * (items.length + 0.5)), invalidateOnRefresh: true }); } }); document.querySelectorAll('[data-vertical-pin]').forEach(i => { gsap.set(i.querySelectorAll('[data-pinned-item]'), { zIndex: (i, target, targets) => targets.length - i }); const items = i.querySelectorAll('[data-pinned-item]:not(:last-of-type)'); items.forEach((image, k) => { const tl = gsap.timeline({ scrollTrigger: { trigger: i, start: () => "top -" + (window.innerHeight < 800 ? window.innerHeight : 800) * (k + 0.5), end: () => "+=" + (window.innerHeight < 800 ? window.innerHeight : 800), scrub: 0.5, markers: false, invalidateOnRefresh: true, toggleActions: "play none reverse none", } }); tl.to(image, { height: 0 }); }); const start = window.innerHeight < 800 ? "0" : (window.innerHeight - 800) / 2 ScrollTrigger.create({ trigger: i, scrub: true, markers: false, pin: true, anticipatePin: 1, start: () => `center center`, end: () => "+=" + (items.length + 1) * (window.innerHeight < 800 ? window.innerHeight : 800), invalidateOnRefresh: true }) }); document.querySelectorAll('[data-horizontal-loop]').forEach(i => { const speed = i.dataset.horizontalLoop ?? 1; const padding = i.dataset.horizontalPadding ?? 0; if(i.querySelectorAll('[data-loop-item]').length < 2) { return false; } i.querySelectorAll('[data-loop-item]').forEach(item => { const clone = item.cloneNode(true); i.append(clone); }); const items = i.querySelectorAll('[data-loop-item]'); const reversed = i.dataset.reverseLoop === 'true'; const loop = horizontalLoop(items, {paused: true, repeat: -1, speed: speed, paddingRight: padding, reversed: reversed}); reversed ? loop.reverse() : loop.play(); const pauseListener = debounce(() => { if(!i.matches(':hover')) { return; } i.removeEventListener('mouseover', this.pauseListener); loop.pause(); const pauseInterval = setInterval(() => { if (!i.matches(':hover')) { reversed ? loop.reverse() : loop.play(); i.addEventListener('mouseover', pauseListener) } }, 1000) }, 500) i.addEventListener('mouseover', pauseListener) }); }); class AnimatedStat extends HTMLElement { connectedCallback() { this.start = parseInt(this.dataset.start); this.steps = parseInt(this.dataset.steps); this.value = parseInt(this.dataset.value); this.shouldFormat = this.dataset.formatValue === 'true'; this.unit = this.dataset.unit ?? ''; this.element = this.querySelector('[data-animated-value]'); this.element.innerText = this.shouldFormat ? `${numberWithCommas(this.start)}` : `${this.start}`; this.setupAnimation(); } setupAnimation() { gsap.registerPlugin(ScrollTrigger) gsap.registerEffect({ name:"counter", extendTimeline:true, defaults:{ end:0, duration:0.5, ease:"power1", increment: 1, }, effect: (targets, config) => { let tl = gsap.timeline() let num = targets[0].innerText.replace(/\,/g,'') targets[0].innerText = num tl.to(targets, {duration:config.duration, innerText: config.end, //snap:{innerText:config.increment}, modifiers:{ innerText:function(innerText){ return config.format ? gsap.utils.snap(config.increment, `${innerText}${config.unit ?? ''}`).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : gsap.utils.snap(config.increment, `${innerText}${config.unit ?? ''}`).toString(); } }, ease:config.ease}, 0) return tl } }) let tl = gsap.timeline({ scrollTrigger: { trigger: this.element, start: "top bottom" } }) tl.counter(this.element, {end: this.value, increment: this.steps, duration: 4, unit: this.unit, format: this.shouldFormat}) } } customElements.define('animated-stat', AnimatedStat); class CollapsibleTab extends HTMLElement { connectedCallback() { this.contentHeight = 0; this.content = this.querySelector('[data-collapsible-content]'); if(!this.content) { throw new Error('Collapsible tab requires a content element.'); } this.trigger = this.querySelector('[data-collapsible-trigger]'); if(!this.trigger) { throw new Error('Collapsible tab requires a trigger element.'); } const styles = window.getComputedStyle(this.content); const startHeight = parseInt(styles.height) > 0 ? parseFloat(styles.height) : 0; if(startHeight > 0) { this.setAttribute('data-state', 'active'); } else { this.setAttribute('data-state', 'closed'); } this.content.style.setProperty('--content-height', `${startHeight}px`); this.content.style.height = 'var(--content-height)'; this.calcHeight(); this.trigger.addEventListener('click', this.toggle.bind(this)); window.addEventListener('resize', this.calcHeight.bind(this)); } toggle() { this.dataset.state === 'active' ? this.close() : this.open(); } calcHeight() { this.contentHeight = calcHeight(this.content.querySelector('.div-block-85'), this.content) + 12; } open() { this.calcHeight(); this.content.style.setProperty('--content-height', `${this.contentHeight}px`); this.setAttribute('data-state', 'active'); setTimeout(() => { ScrollTrigger.refresh(); }, 300); } close() { this.content.style.setProperty('--content-height', `0px`); this.setAttribute('data-state', 'closed'); setTimeout(() => { ScrollTrigger.refresh(); }, 300); } } customElements.define('collapsible-tab', CollapsibleTab); class FaqTabs extends HTMLElement { connectedCallback() { this.tabs = this.querySelectorAll('.faq-tab'); this.tabs[0].classList.add('active'); this.containers = this.querySelectorAll('.w-layout-blockcontainer'); this.containers[0].classList.add('active'); this.activeIndex = 0; this.tabs.forEach((i,k) => { i.addEventListener('click', e => { e.preventDefault(); if(k === this.activeIndex) { return } this.tabs[this.activeIndex]?.classList?.remove('active'); this.containers[this.activeIndex]?.classList?.remove('active'); this.tabs[k]?.classList?.add('active'); this.containers[k]?.classList?.add('active'); this.activeIndex = k; }); }); } } customElements.define('faq-tabs', FaqTabs); function numberWithCommas(x) { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } function debounce(fn, wait) { let t; return (...args) => { clearTimeout(t); t = setTimeout(() => fn.apply(this, args), wait); }; } function calcHeight(element, container) { const clone = element.cloneNode(true); Object.assign(clone.style, { overflow: 'visible', height: 'auto', maxHeight: 'none', opacity: '0', visibility: 'hidden', display: 'block' }); container.after(clone); const height = clone.offsetHeight; clone.remove(); return height; } function horizontalLoop(items, config) { let timeline; items = gsap.utils.toArray(items); config = config || {}; gsap.context(() => { // use a context so that if this is called from within another context or a gsap.matchMedia(), we can perform proper cleanup like the "resize" event handler on the window let onChange = config.onChange, lastIndex = 0, tl = gsap.timeline({repeat: config.repeat, onUpdate: onChange && function() { let i = tl.closestIndex(); if (lastIndex !== i) { lastIndex = i; onChange(items[i], i); } }, paused: config.paused, defaults: {ease: "none"}, onReverseComplete: () => tl.totalTime(tl.rawTime() + tl.duration() * 100)}), length = items.length, startX = items[0].offsetLeft, times = [], widths = [], spaceBefore = [], xPercents = [], curIndex = 0, indexIsDirty = false, center = config.center, pixelsPerSecond = (config.speed || 1) * 100, snap = config.snap === false ? v => v : gsap.utils.snap(config.snap || 1), // some browsers shift by a pixel to accommodate flex layouts, so for example if width is 20% the first element's width might be 242px, and the next 243px, alternating back and forth. So we snap to 5 percentage points to make things look more natural timeOffset = 0, container = center === true ? items[0].parentNode : gsap.utils.toArray(center)[0] || items[0].parentNode, totalWidth, getTotalWidth = () => items[length-1].offsetLeft + xPercents[length-1] / 100 * widths[length-1] - startX + spaceBefore[0] + items[length-1].offsetWidth * gsap.getProperty(items[length-1], "scaleX") + (parseFloat(config.paddingRight) || 0), populateWidths = () => { let b1 = container.getBoundingClientRect(), b2; items.forEach((el, i) => { widths[i] = parseFloat(gsap.getProperty(el, "width", "px")); xPercents[i] = snap(parseFloat(gsap.getProperty(el, "x", "px")) / widths[i] * 100 + gsap.getProperty(el, "xPercent")); b2 = el.getBoundingClientRect(); spaceBefore[i] = b2.left - (i ? b1.right : b1.left); b1 = b2; }); gsap.set(items, { // convert "x" to "xPercent" to make things responsive, and populate the widths/xPercents Arrays to make lookups faster. xPercent: i => xPercents[i] }); totalWidth = getTotalWidth(); }, timeWrap, populateOffsets = () => { timeOffset = center ? tl.duration() * (container.offsetWidth / 2) / totalWidth : 0; center && times.forEach((t, i) => { times[i] = timeWrap(tl.labels["label" + i] + tl.duration() * widths[i] / 2 / totalWidth - timeOffset); }); }, getClosest = (values, value, wrap) => { let i = values.length, closest = 1e10, index = 0, d; while (i--) { d = Math.abs(values[i] - value); if (d > wrap / 2) { d = wrap - d; } if (d < closest) { closest = d; index = i; } } return index; }, populateTimeline = () => { let i, item, curX, distanceToStart, distanceToLoop; tl.clear(); for (i = 0; i < length; i++) { item = items[i]; curX = xPercents[i] / 100 * widths[i]; distanceToStart = item.offsetLeft + curX - startX + spaceBefore[0]; distanceToLoop = distanceToStart + widths[i] * gsap.getProperty(item, "scaleX"); tl.to(item, {xPercent: snap((curX - distanceToLoop) / widths[i] * 100), duration: distanceToLoop / pixelsPerSecond}, 0) .fromTo(item, {xPercent: snap((curX - distanceToLoop + totalWidth) / widths[i] * 100)}, {xPercent: xPercents[i], duration: (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond, immediateRender: false}, distanceToLoop / pixelsPerSecond) .add("label" + i, distanceToStart / pixelsPerSecond); times[i] = distanceToStart / pixelsPerSecond; } timeWrap = gsap.utils.wrap(0, tl.duration()); }, refresh = (deep) => { let progress = tl.progress(); tl.progress(0, true); populateWidths(); deep && populateTimeline(); populateOffsets(); deep && tl.draggable ? tl.time(times[curIndex], true) : tl.progress(progress, true); }, onResize = () => refresh(true), proxy; gsap.set(items, {x: 0}); populateWidths(); populateTimeline(); populateOffsets(); window.addEventListener("resize", onResize); function toIndex(index, vars) { vars = vars || {}; (Math.abs(index - curIndex) > length / 2) && (index += index > curIndex ? -length : length); // always go in the shortest direction let newIndex = gsap.utils.wrap(0, length, index), time = times[newIndex]; if (time > tl.time() !== index > curIndex && index !== curIndex) { // if we're wrapping the timeline's playhead, make the proper adjustments time += tl.duration() * (index > curIndex ? 1 : -1); } if (time < 0 || time > tl.duration()) { vars.modifiers = {time: timeWrap}; } curIndex = newIndex; vars.overwrite = true; gsap.killTweensOf(proxy); return vars.duration === 0 ? tl.time(timeWrap(time)) : tl.tweenTo(time, vars); } tl.toIndex = (index, vars) => toIndex(index, vars); tl.closestIndex = setCurrent => { let index = getClosest(times, tl.time(), tl.duration()); if (setCurrent) { curIndex = index; indexIsDirty = false; } return index; }; tl.current = () => indexIsDirty ? tl.closestIndex(true) : curIndex; tl.next = vars => toIndex(tl.current()+1, vars); tl.previous = vars => toIndex(tl.current()-1, vars); tl.times = times; tl.progress(1, true).progress(0, true); // pre-render for performance if (config.reversed) { tl.vars.onReverseComplete(); tl.reverse(); } if (config.draggable && typeof(Draggable) === "function") { proxy = document.createElement("div") let wrap = gsap.utils.wrap(0, 1), ratio, startProgress, draggable, dragSnap, lastSnap, initChangeX, wasPlaying, align = () => tl.progress(wrap(startProgress + (draggable.startX - draggable.x) * ratio)), syncIndex = () => tl.closestIndex(true); typeof(InertiaPlugin) === "undefined" && console.warn("InertiaPlugin required for momentum-based scrolling and snapping. https://greensock.com/club"); draggable = Draggable.create(proxy, { trigger: items[0].parentNode, type: "x", onPressInit() { let x = this.x; gsap.killTweensOf(tl); wasPlaying = !tl.paused(); tl.pause(); startProgress = tl.progress(); refresh(); ratio = 1 / totalWidth; initChangeX = (startProgress / -ratio) - x; gsap.set(proxy, {x: startProgress / -ratio}); }, onDrag: align, onThrowUpdate: align, overshootTolerance: 0, inertia: true, snap(value) { //note: if the user presses and releases in the middle of a throw, due to the sudden correction of proxy.x in the onPressInit(), the velocity could be very large, throwing off the snap. So sense that condition and adjust for it. We also need to set overshootTolerance to 0 to prevent the inertia from causing it to shoot past and come back if (Math.abs(startProgress / -ratio - this.x) < 10) { return lastSnap + initChangeX } let time = -(value * ratio) * tl.duration(), wrappedTime = timeWrap(time), snapTime = times[getClosest(times, wrappedTime, tl.duration())], dif = snapTime - wrappedTime; Math.abs(dif) > tl.duration() / 2 && (dif += dif < 0 ? tl.duration() : -tl.duration()); lastSnap = (time + dif) / tl.duration() / -ratio; return lastSnap; }, onRelease() { syncIndex(); draggable.isThrowing && (indexIsDirty = true); }, onThrowComplete: () => { syncIndex(); wasPlaying && tl.play(); } })[0]; tl.draggable = draggable; } tl.closestIndex(true); lastIndex = curIndex; onChange && onChange(items[curIndex], curIndex); timeline = tl; return () => window.removeEventListener("resize", onResize); // cleanup }); return timeline; } function openServicesPanel() { const aside = document.getElementById('menu-aside'); gsap.context(() => { const tl = gsap.timeline({ onComplete:() => { aside.querySelector('.services-panel').classList.add('active'); aside.querySelector('.contact-panel').classList.remove('active'); aside.querySelector('.menu-panel').classList.remove('active'); } }) .to('.menu-aside-content', { autoAlpha: 0, duration: 0.5 }) .to('.menu-panel', { x: 650, xPercent: 0, duration: 1, ease: 'back.out(1.1)' }) .to('.services-panel', { xPercent: 0, x: 0, right: 0, duration: 1, ease: 'back.out(1.1)' }, '<0.1') .to('.services-panel .menu-aside-content', { autoAlpha: 1, duration: 0.5 }); }, aside); } function openContactPanel() { const aside = document.getElementById('menu-aside'); gsap.context(() => { const tl = gsap.timeline({ onComplete:() => { aside.querySelector('.services-panel').classList.remove('active'); aside.querySelector('.contact-panel').classList.add('active'); aside.querySelector('.menu-panel').classList.remove('active'); } }) .to('.menu-aside-content', { autoAlpha: 0, duration: 0.5 }) .to('.menu-panel', { x: 650, xPercent: 0, duration: 1, ease: 'back.out(1.1)' }) .to('.services-panel', { x: 650, xPercent: 0, duration: 1, ease: 'back.out(1.1)' }, '<0.1') .to('.contact-panel .menu-aside-content', { autoAlpha: 1, duration: 1 }); }, aside); } function openAside() { const aside = document.getElementById('menu-aside'); window.asideCtx = gsap.context(() => { const tl = gsap.timeline({ onComplete:() => { // aside.querySelector('.services-panel').classList.remove('active'); // aside.querySelector('.contact-panel').classList.remove('active'); aside.querySelector('.menu-panel').classList.add('active'); } }); tl.set(aside, {display: 'block', pointerEvents: 'auto'}) .to(aside, { autoAlpha: 1, duration: 0.5 }) .to('.menu-panel', { xPercent: 0, x: 0, duration: 1, ease: 'back.out(1.1)' }) // .to('.services-panel', { // xPercent: 0, // x: 0, // right: 0, // duration: 1, // ease: 'back.out(1.1)' // }, '<0.1') // .to('.contact-panel', { // xPercent: 0, // x: 0, // duration: 1, // ease: 'back.out(1.1)', // right: 50 // }, '<0.1') window.asideTl = tl; }, aside); } function closeAside() { const aside = document.getElementById('menu-aside'); gsap.context(() => { // aside.querySelector('.services-panel').classList.remove('active'); // aside.querySelector('.contact-panel').classList.remove('active'); aside.querySelector('.menu-panel').classList.remove('active'); gsap.timeline() // .to('.contact-panel', { // xPercent: 100, // x: 0, // right: -50, // duration: 0.8 // }, 0.5) // .to('.services-panel', { // xPercent: 100, // x: 0, // right: -50, // duration: 0.9 // }, 0.5) .to('.menu-panel', { xPercent: 100, x: 0, right: -50, duration: 1 }, 0.5) .set('.menu-panel, .services-panel, .contact-panel', { 'transform': 'translateX(100%)' }) .set(aside, {display: 'block', pointerEvents: 'auto'}) .to(aside, { autoAlpha: 0, duration: 0.5 }, 1.5); }, aside); }