github.com/outbrain/consul@v1.4.5/website/source/assets/javascripts/animations.js (about)

     1  document.addEventListener('turbolinks:load', initializeAnimations)
     2  
     3  function initializeAnimations() {
     4    var qs = document.querySelector.bind(document)
     5    var qsa = document.querySelectorAll.bind(document)
     6  
     7    //
     8    // home page
     9    //
    10  
    11    var $indexDynamic = qs('#index-dynamic-animation')
    12    if ($indexDynamic) {
    13      var initiated = false
    14      var observer = new IntersectionObserver(
    15        function(entries) {
    16          if (!initiated && entries[0].isIntersecting) {
    17            $indexDynamic.classList.add('active')
    18            var lines = qsa(
    19              '#lines-origin-aws > *, #lines-origin-azure > *, #lines-origin-gcp > *'
    20            )
    21            setTimeout(function() {
    22              timer = setInterval(function() {
    23                lines[parseInt(Math.random() * lines.length)].classList.toggle(
    24                  'off'
    25                )
    26              }, 800)
    27            }, 3000)
    28            initiated = true
    29          }
    30        },
    31        { threshold: 0.5 }
    32      )
    33      observer.observe($indexDynamic)
    34    }
    35  
    36    //
    37    // configuration page
    38    //
    39  
    40    var $configChallenge = qs('#configuration-challenge-animation')
    41    var $configSolution = qs('#configuration-solution-animation')
    42  
    43    if ($configChallenge) {
    44      // challenge animation
    45  
    46      var configChallengeTimeline = new TimelineLite({
    47        onComplete: function() {
    48          configChallengeTimeline.restart()
    49          configSolutionTimeline.restart()
    50        }
    51      })
    52  
    53      var line1 = qs('#c-line-1')
    54      var line2 = qs('#c-line-2')
    55      var line3 = qs('#c-line-3')
    56      var line4 = qs('#c-line-4')
    57      var line5 = qs('#c-line-5')
    58      var line6 = qs('#c-line-6')
    59      var line7 = qs('#c-line-7')
    60      var line8 = qs('#c-line-8')
    61      var box1 = qs('#c-box-1')
    62      var box2 = qs('#c-box-2')
    63      var box3 = qs('#c-box-3')
    64      var box4 = qs('#c-box-4')
    65      var box5 = qs('#c-box-5')
    66      var box6 = qs('#c-box-6')
    67      var box7 = qs('#c-box-7')
    68      var box8 = qs('#c-box-8')
    69      var progressBar = qs('#c-loading-bar > rect:last-child')
    70      var cog = qs('#c-configuration-server > g > path')
    71  
    72      configChallengeTimeline
    73        .to(box1, 1, {})
    74        .staggerTo(
    75          [line1, line2, line3, line4, line5, line6, line7, line8],
    76          1.5,
    77          { css: { strokeDashoffset: 0 } },
    78          0.3,
    79          'start'
    80        )
    81        .staggerTo(
    82          [box1, box2, box3, box4, box5, box6, box7, box8],
    83          0.3,
    84          { opacity: 1 },
    85          0.3,
    86          '-=2.5'
    87        )
    88        .fromTo(
    89          progressBar,
    90          3.5,
    91          { attr: { width: 0 } },
    92          { attr: { width: 40 } },
    93          'start'
    94        )
    95        .to(
    96          cog,
    97          3.5,
    98          { rotation: 360, svgOrigin: '136px 127px', ease: Power1.easeOut },
    99          'start'
   100        )
   101        .call(function () {
   102          configSolutionTimeline.resume(configSolutionTimeline.time())
   103        })
   104        .to(line1, 2, {})
   105        .to(
   106          [line1, line2, line3, line4, line5, line6, line7, line8, progressBar],
   107          0.5,
   108          { opacity: 0 },
   109          'reset'
   110        )
   111        .to(
   112          [box1, box2, box3, box4, box5, box6, box7, box8],
   113          0.5,
   114          { opacity: 0.5 },
   115          'reset'
   116        )
   117        .pause()
   118  
   119      // solution animation
   120  
   121      var configSolutionTimeline = new TimelineLite()
   122  
   123      var lines = qsa(
   124        '#s-line-1, #s-line-2, #s-line-3, #s-line-4, #s-line-5, #s-line-6, #s-line-7, #s-line-8'
   125      )
   126      var dots = qs('#s-dots')
   127      var boxes = qsa(
   128        '#s-service-box-1, #s-service-box-2, #s-service-box-3, #s-service-box-4, #s-service-box-5, #s-service-box-6, #s-service-box-7, #s-service-box-8'
   129      )
   130      var progress = qs('#s-progress-indicator')
   131  
   132      configSolutionTimeline
   133        .to(boxes, 1, {})
   134        .to(lines, 1, { css: { strokeDashoffset: 0 } }, 'start')
   135        .to(boxes, 0.5, { opacity: 1 }, '-=0.4')
   136        .fromTo(
   137          progress,
   138          1,
   139          { attr: { width: 0 } },
   140          { attr: { width: 40 } },
   141          'start'
   142        )
   143        .to(dots, 0.25, { opacity: 1 }, '-=0.5')
   144        .addPause()
   145        .to(progress, 2, {})
   146        .to(lines, 0.5, { opacity: 0 }, 'reset')
   147        .to(boxes, 0.5, { opacity: 0.5 }, 'reset')
   148        .to(progress, 0.5, { opacity: 0 }, 'reset')
   149        .to(dots, 0.5, { opacity: 0 }, 'reset')
   150        .pause()
   151  
   152      // kick off
   153      $configChallenge.classList.add('active')
   154      $configSolution.classList.add('active')
   155      configChallengeTimeline.play()
   156      configSolutionTimeline.play()
   157    }
   158  
   159    //
   160    // discovery page
   161    //
   162  
   163    var $discoveryChallenge = qs('#discovery-challenge-animation')
   164    var $discoverySolution = qs('#discovery-solution-animation')
   165  
   166    if ($discoveryChallenge) {
   167      // challenge animation
   168      var discoveryChallengeTimeline = new TimelineLite({
   169        onComplete: function() {
   170          discoveryChallengeTimeline.restart()
   171          discoverySolutionTimeline.restart()
   172        }
   173      })
   174  
   175      // First, we get each of the elements we need to animate
   176      var box = qs('#c-active-box')
   177      var leftPlacement = qs('#c-box-left-placement')
   178      var rightPlacement = qs('#c-box-right-placement')
   179      var leftConnectionLines = qsa(
   180        '#c-line-top-left > *, #c-line-bottom-left > *, #c-line-horizontal-left > *, #c-line-vertical-down > *'
   181      )
   182      var rightConnectionLines = qsa(
   183        '#c-line-top-right > *, #c-line-bottom-right > *, #c-line-horizontal-left > *, #c-line-vertical-down > *, #c-line-horizontal-right > *'
   184      )
   185      var leftConnectionTop = qs('#c-line-top-left')
   186      var leftConnectionBottom = qs('#c-line-bottom-left')
   187      var rightHorizontalConnection = qs('#c-line-horizontal-right')
   188      var rightConnectionTop = qs('#c-line-top-right')
   189      var rightConnectionBottom = qs('#c-line-bottom-right')
   190      var rightConnectionLinesStroke = qsa(
   191        '#c-line-top-right > *, #c-line-bottom-right > *, #c-line-horizontal-right > *, #c-line-horizontal-left > *, #c-line-vertical-down > *'
   192      )
   193      var leftConnectionLinesStroke = qsa(
   194        '#c-line-top-left > *, #c-line-bottom-left > *, #c-line-horizontal-left > *, #c-line-vertical-down > *'
   195      )
   196      var brokenLinkLeft = qs('#c-broken-link-left')
   197      var brokenLinkRight = qs('#c-broken-link-right')
   198      var computer = qs('#c-computer')
   199      var codeLines = qs('#c-computer > g')
   200      var toLoadBalancerDown = qsa(
   201        '#c-computer-to-load-balancers #c-arrow-down, #c-computer-to-load-balancers #c-circle'
   202      )
   203      var toLoadBalancerRight = qs('#c-computer-to-load-balancers #c-arrow-right')
   204      var toLoadBalancerLeft = qs('#c-computer-to-load-balancers #c-arrow-left')
   205      var toLoadBalancerRest = qs('#c-computer-to-load-balancers #c-edit-box')
   206      var progressBars = qsa(
   207        '#c-load-balancer-left > #c-progress-bar, #c-load-balancer-right > #c-progress-bar-2, #c-load-balancer-middle > #c-progress-bar-3'
   208      )
   209      var progressBarsBars = qsa(
   210        '#c-load-balancer-left > #c-progress-bar > *:last-child, #c-load-balancer-right > #c-progress-bar-2  > *:last-child, #c-load-balancer-middle > #c-progress-bar-3  > *:last-child'
   211      )
   212      var farLeftBoxBorder = qs('#c-box-far-left > path')
   213  
   214      // Then, we run each step of the animation using GSAP's TimelineLine, a
   215      // fantastic way to set up a series of complex movements
   216      discoveryChallengeTimeline
   217        .to(box, 1, {})
   218        // box moves to new position
   219        .to(box, 1, { css: { transform: 'translate(96px, 48px)' } })
   220        .to(leftPlacement, 0.5, { css: { opacity: 1 } }, '-=1')
   221        .to(rightPlacement, 0.25, { css: { opacity: 0 } }, '-=0.25')
   222        // connection lines turn black
   223        .to(leftConnectionLines, 0.5, { css: { stroke: '#000' } })
   224        .to(farLeftBoxBorder, 0.5, { css: { fill: '#000' } }, '-=0.5')
   225        // broken link appears
   226        .to(
   227          leftConnectionTop,
   228          0.1,
   229          {
   230            css: { strokeDashoffset: 6 },
   231            ease: Linear.easeNone
   232          },
   233          '-=0.3'
   234        )
   235        .to(brokenLinkLeft, 0.2, { css: { opacity: 1 } }, '-=0.15')
   236        // computer appears and code is written
   237        .to(computer, 0.5, { css: { opacity: 1 } })
   238        .staggerFrom(
   239          codeLines,
   240          0.4,
   241          {
   242            css: { transform: 'translate(-64px, 0)', opacity: 0 }
   243          },
   244          0.1
   245        )
   246        .to(codeLines, 0.3, {
   247          css: { transform: 'translate(0, 0)', opacity: 1 }
   248        })
   249        // code moves to load balancers
   250        .to(toLoadBalancerRest, 0.4, { css: { opacity: 1 } })
   251        .to(toLoadBalancerLeft, 0.2, { css: { opacity: 1 } }, 'loadBalancerArrows')
   252        .to(toLoadBalancerRight, 0.2, { css: { opacity: 1 } }, 'loadBalancerArrows')
   253        .to(toLoadBalancerDown, 0.2, { css: { opacity: 1 } }, 'loadBalancerArrows')
   254        // load balancers progress bars, old broken link fades out
   255        .to(progressBars, 0.2, { css: { opacity: 1 } })
   256        .staggerFromTo(
   257          progressBarsBars,
   258          1.5,
   259          { attr: { width: 0 } },
   260          { attr: { width: 40 } },
   261          0.3
   262        )
   263        .to(
   264          []
   265            .concat(toLoadBalancerRest)
   266            .concat([].slice.call(toLoadBalancerDown))
   267            .concat([
   268              toLoadBalancerRight,
   269              toLoadBalancerLeft,
   270              brokenLinkLeft,
   271              leftConnectionTop,
   272              leftConnectionBottom
   273            ]),
   274          0.5,
   275          { css: { opacity: 0 } },
   276          '-=0.75'
   277        )
   278        .to(computer, 0.5, { css: { opacity: .12 } }, '-=0.75')
   279        .to(progressBars, 0.5, { css: { opacity: 0 } })
   280        // new connection is drawn
   281        .to(rightHorizontalConnection, 0.3, { css: { strokeDashoffset: 0 } })
   282        .to(rightConnectionTop, 0.2, {
   283          css: { strokeDashoffset: 0 },
   284          ease: Linear.easeNone
   285        })
   286        .to(rightConnectionBottom, 0.3, {
   287          css: { strokeDashoffset: 0 },
   288          ease: Linear.easeNone
   289        })
   290        // connection lines turn blue
   291        .to(
   292          rightConnectionLinesStroke,
   293          0.5,
   294          { css: { stroke: '#3969ED' } },
   295          '-=0.3'
   296        )
   297        .to(farLeftBoxBorder, 0.5, { css: { fill: '#3969ED' } }, '-=0.5')
   298        // wait three seconds
   299        .to(box, 3, {})
   300        // box moves back to original position
   301        .to(box, 1, { css: { transform: 'translate(0, 0)' } }, 'loop2')
   302        .to(leftPlacement, 0.25, { css: { opacity: 0 } }, '-=0.25')
   303        .to(rightPlacement, 0.5, { css: { opacity: 1 } }, '-=0.5')
   304        // connection lines turn black
   305        .to(rightConnectionLines, 0.5, { css: { stroke: '#000' } })
   306        .to(farLeftBoxBorder, 0.5, { css: { fill: '#000' } }, '-=0.5')
   307        // broken link appears
   308        .to(
   309          rightConnectionTop,
   310          0.1,
   311          {
   312            css: { strokeDashoffset: 6 },
   313            ease: Linear.easeNone
   314          },
   315          '-=0.3'
   316        )
   317        .to(brokenLinkRight, 0.2, { css: { opacity: 1 } }, '-=0.15')
   318        // computer appears and code is written
   319        .from(codeLines, 0.1, { css: { opacity: 0 } })
   320        .to(computer, 0.5, { css: { opacity: 1 } }, '-=0.1')
   321        .staggerFromTo(
   322          codeLines,
   323          0.4,
   324          { css: { transform: 'translate(-64px, 0)', opacity: 0 } },
   325          { css: { transform: 'translate(0, 0)', opacity: 1 } },
   326          0.1
   327        )
   328        // code moves to load balancers
   329        .to(toLoadBalancerRest, 0.4, { css: { opacity: 1 } })
   330        .to(toLoadBalancerLeft, 0.2, { css: { opacity: 1 } }, 'loadBalancerArrows2')
   331        .to(
   332          toLoadBalancerRight,
   333          0.2,
   334          { css: { opacity: 1 } },
   335          'loadBalancerArrows2'
   336        )
   337        .to(toLoadBalancerDown, 0.2, { css: { opacity: 1 } }, 'loadBalancerArrows2')
   338        // load balancers progress bars, old broken link fades out
   339        .to(progressBarsBars, 0.1, { attr: { width: 0 } })
   340        .to(progressBars, 0.2, { attr: { opacity: 1 } })
   341        .staggerFromTo(
   342          progressBarsBars,
   343          1.5,
   344          { css: { width: 0 } },
   345          { css: { width: 40 } },
   346          0.3
   347        )
   348        .to(
   349          []
   350            .concat(toLoadBalancerRest)
   351            .concat([].slice.call(toLoadBalancerDown))
   352            .concat([
   353              toLoadBalancerRight,
   354              toLoadBalancerLeft,
   355              brokenLinkRight,
   356              rightConnectionTop,
   357              rightConnectionBottom,
   358              rightHorizontalConnection
   359            ]),
   360          0.5,
   361          { css: { opacity: 0 } },
   362          '-=0.75'
   363        )
   364        .to(computer, 0.5, { css: { opacity: .12 } }, '-=0.75')
   365        .to(progressBars, 0.5, { css: { opacity: 0 } })
   366        // new connection is drawn
   367        .to(leftConnectionTop, 0.01, { css: { strokeDashoffset: 17 } })
   368        .to(leftConnectionBottom, 0.01, { css: { strokeDashoffset: 56 } })
   369        .to([leftConnectionTop, leftConnectionBottom], 0.01, {
   370          css: { opacity: 1 }
   371        })
   372        .to(leftConnectionTop, 0.2, {
   373          css: { strokeDashoffset: 0 },
   374          ease: Linear.easeNone
   375        })
   376        .to(leftConnectionBottom, 0.3, {
   377          css: { strokeDashoffset: 0 },
   378          ease: Linear.easeNone
   379        })
   380        // connection lines turn blue
   381        .to(leftConnectionLinesStroke, 0.5, { css: { stroke: '#3969ED' } }, '-=0.3')
   382        .to(farLeftBoxBorder, 0.5, { css: { fill: '#3969ED' } }, '-=0.5')
   383        .call(function () {
   384          discoverySolutionTimeline.resume(discoverySolutionTimeline.time())
   385        })
   386        .to(box, 2, {})
   387        .pause()
   388  
   389      // solution animation
   390      var discoverySolutionTimeline = new TimelineLite()
   391  
   392      var inactiveBox = qs('#s-active-service-1')
   393      var inactiveBoxStroke = qs('#s-active-service-1 > path')
   394      var activeBox = qs('#s-active-service-2')
   395      var activeBoxStroke = qs('#s-active-service-2 > path')
   396      var leftPlacement = qs('#s-dotted-service-box-2')
   397      var rightPlacement = qs('#s-dotted-service-box-3')
   398      var leftConnectionLine = qs('#s-connected-line-1')
   399      var rightConnectionLine = qs('#s-connected-line-2')
   400      var dottedLineLeft = qs('#s-dotted-line-left')
   401      var dottedLineRight = qs('#s-dotted-lines-right')
   402      var dottedLineRightPrimary = qs('#s-dotted-lines-right > path:nth-child(2)')
   403      var dottedLineRightAlt = qs('#s-dotted-lines-right > path:last-child')
   404      var syncLeft = qs('#s-dynamic-sync-left')
   405      var syncRight = qs('#s-dynamic-sync-right')
   406      var syncSpinnerLeft = qs('#s-dynamic-sync-left > path')
   407      var syncSpinnerRight = qs('#s-dynamic-sync-right > path')
   408  
   409      discoverySolutionTimeline
   410        .to(activeBox, 1, {})
   411        // box moves
   412        .to(activeBox, 0.5, { x: 96, y: 48 })
   413        .to(leftPlacement, 0.25, { css: { opacity: 1 } }, '-=0.5')
   414        .to(rightPlacement, 0.25, { css: { opacity: 0 } }, '-=0.1')
   415        // connection is broken
   416        .to(leftConnectionLine, 0.75, { css: { strokeDashoffset: 222 } }, '-=0.5')
   417        // box color changes to black
   418        .to(activeBoxStroke, 0.25, { css: { fill: '#000' } }, '-=0.4')
   419        .to(inactiveBoxStroke, 0.25, { css: { fill: '#000' } }, '-=0.4')
   420        // right sync lines appear
   421        .to(dottedLineRight, 0.4, { css: { opacity: 1 } })
   422        .to(syncRight, 0.2, { css: { opacity: 1 } }, '-=0.2')
   423        .to(syncSpinnerRight, 1, { rotation: 360, svgOrigin: '232px 127px' })
   424        // left sync lines appear
   425        .to(dottedLineLeft, 0.4, { css: { opacity: 1 } }, '-=0.6')
   426        .to(syncLeft, 0.2, { css: { opacity: 1 } }, '-=0.2')
   427        .to(syncSpinnerLeft, 1, { rotation: 360, svgOrigin: '88px 127px' })
   428        // connection is redrawn
   429        .to(rightConnectionLine, 0.75, { css: { strokeDashoffset: 0 } })
   430        // right sync lines disappear
   431        .to(dottedLineRight, 0.4, { css: { opacity: 0 } }, '-=1.2')
   432        .to(syncRight, 0.2, { css: { opacity: 0 } }, '-=1.2')
   433        // left sync lines disappear
   434        .to(dottedLineLeft, 0.4, { css: { opacity: 0 } }, '-=0.5')
   435        .to(syncLeft, 0.2, { css: { opacity: 0 } }, '-=0.5')
   436        // box color changes to pink
   437        .to(activeBoxStroke, 0.25, { css: { fill: '#ca2171' } }, '-=0.2')
   438        .to(inactiveBoxStroke, 0.25, { css: { fill: '#ca2171' } }, '-=0.2')
   439        // wait three seconds
   440        .to(activeBox, 3, {})
   441        // box moves
   442        .to(activeBox, 0.5, { x: 0, y: 0 })
   443        .to(leftPlacement, 0.25, { css: { opacity: 0 } }, '-=0.1')
   444        .to(rightPlacement, 0.25, { css: { opacity: 1 } }, '-=0.5')
   445        // connection is broken
   446        .to(rightConnectionLine, 0.75, { css: { strokeDashoffset: 270 } }, '-=0.5')
   447        // box color changes to black
   448        .to(activeBoxStroke, 0.25, { css: { fill: '#000' } }, '-=0.4')
   449        .to(inactiveBoxStroke, 0.25, { css: { fill: '#000' } }, '-=0.4')
   450        // right sync lines appear
   451        .to(dottedLineRightAlt, 0.01, { css: { opacity: 1 } })
   452        .to(dottedLineRightPrimary, 0.01, { css: { opacity: 0 } })
   453        .to(dottedLineRight, 0.4, { css: { opacity: 1 } })
   454        .to(syncRight, 0.2, { css: { opacity: 1 } }, '-=0.2')
   455        .fromTo(
   456          syncSpinnerRight,
   457          1,
   458          { rotation: 0 },
   459          { rotation: 360, svgOrigin: '232px 127px' }
   460        )
   461        // left sync lines appear
   462        .to(dottedLineLeft, 0.4, { css: { opacity: 1 } }, '-=0.6')
   463        .to(syncLeft, 0.2, { css: { opacity: 1 } }, '-=0.2')
   464        .fromTo(
   465          syncSpinnerLeft,
   466          1,
   467          { rotation: 0 },
   468          { rotation: 360, svgOrigin: '88px 127px' }
   469        )
   470        // connection is redrawn
   471        .to(leftConnectionLine, 0.75, { css: { strokeDashoffset: 0 } })
   472        // right sync lines disappear
   473        .to(dottedLineRight, 0.4, { css: { opacity: 0 } }, '-=1.2')
   474        .to(syncRight, 0.2, { css: { opacity: 0 } }, '-=1.2')
   475        // left sync lines disappear
   476        .to(dottedLineLeft, 0.4, { css: { opacity: 0 } }, '-=0.5')
   477        .to(syncLeft, 0.2, { css: { opacity: 0 } }, '-=0.5')
   478        // box color changes to pink
   479        .to(activeBoxStroke, 0.25, { css: { fill: '#ca2171' } }, '-=0.2')
   480        .to(inactiveBoxStroke, 0.25, { css: { fill: '#ca2171' } }, '-=0.2')
   481        .addPause()
   482        // wait three seconds
   483        .to(activeBox, 2, {})
   484        .pause()
   485  
   486      // kick it off
   487      $discoveryChallenge.classList.add('active')
   488      $discoverySolution.classList.add('active')
   489      discoveryChallengeTimeline.play()
   490      discoverySolutionTimeline.play()
   491    }
   492  
   493    //
   494    // discovery page
   495    //
   496  
   497    var $segmentationChallenge = qs('#segmentation-challenge-animation')
   498    var $segmentationSolution = qs('#segmentation-solution-animation')
   499  
   500    if ($segmentationChallenge) {
   501      // challenge animation
   502      var segmentationChallengeTimeline = new TimelineLite({
   503        onComplete: function() {
   504          segmentationChallengeTimeline.restart()
   505          segmentationSolutionTimeline.restart()
   506        }
   507      })
   508  
   509      var computerUpdatePath = qs('#c-firewall-updates #c-update_path')
   510      var computerUpdateBox = qs('#c-firewall-updates #c-edit')
   511      var computer = qs('#c-computer')
   512      var progressBars = qsa(
   513        '#c-progress-indicator, #c-progress-indicator-2, #c-progress-indicator-3'
   514      )
   515      var progressBarBars = qsa(
   516        '#c-progress-indicator > rect:last-child, #c-progress-indicator-2 > rect:last-child, #c-progress-indicator-3 > rect:last-child'
   517      )
   518      var brokenLinks = qsa('#c-broken-link-1, #c-broken-link-2, #c-broken-link-3')
   519      var box2 = qs('#c-box-2')
   520      var box2Border = qs('#c-box-2 > path')
   521      var box4 = qs('#c-box-4')
   522      var box4Border = qs('#c-box-4 > path')
   523      var box6 = qs('#c-box-6')
   524      var box6Border = qs('#c-box-6 > path')
   525      var box7 = qs('#c-box-7')
   526      var box7Border = qs('#c-box-7 > path')
   527      var path1a = qs('#c-path-1 > *:nth-child(2)')
   528      var path1b = qs('#c-path-1 > *:nth-child(3)')
   529      var path1c = qs('#c-path-1 > *:nth-child(1)')
   530      var path2a = qs('#c-path-2 > *:nth-child(1)')
   531      var path2b = qs('#c-path-2 > *:nth-child(3)')
   532      var path2c = qs('#c-path-2 > *:nth-child(2)')
   533      var path3a = qs('#c-path-3 > *:nth-child(2)')
   534      var path3b = qs('#c-path-3 > *:nth-child(3)')
   535      var path3c = qs('#c-path-3 > *:nth-child(1)')
   536  
   537      segmentationChallengeTimeline
   538        .to(box2, 1, {})
   539        // box 4 and 6 appear
   540        .to(box4Border, 0.4, { css: { fill: '#000' } }, 'box4-in')
   541        .fromTo(
   542          box4,
   543          0.3,
   544          { scale: 0, rotation: 200, opacity: 0, svgOrigin: '291px 41px' },
   545          { scale: 1, rotation: 360, opacity: 1 },
   546          'box4-in'
   547        )
   548        .to(box6Border, 0.4, { css: { fill: '#000' } }, '-=0.2')
   549        .fromTo(
   550          box6,
   551          0.3,
   552          { scale: 0, rotation: 200, opacity: 0, svgOrigin: '195px 289px' },
   553          { scale: 1, rotation: 360, opacity: 1 },
   554          '-=0.4'
   555        )
   556        // wait for a moment
   557        .to(box2, 1, {})
   558        // computer appears and sends updates to firewalls
   559        .to(computer, 0.5, { opacity: 1 })
   560        .to(computerUpdateBox, 0.3, { opacity: 1 }, '-=0.2')
   561        .to(computerUpdatePath, 0.3, { opacity: 1 }, '-=0.2')
   562        // firewall progress bars
   563        .to(progressBarBars, 0.01, { attr: { width: 0 } })
   564        .to(progressBars, 0.2, { opacity: 1 })
   565        .staggerTo(progressBarBars, 0.6, { attr: { width: 40 } }, 0.2)
   566        // connection 1 made
   567        .to(path1a, 0.3, { css: { strokeDashoffset: 0 }, ease: Linear.easeNone })
   568        .to(path1b, 0.3, { css: { strokeDashoffset: 0 }, ease: Linear.easeNone })
   569        .to(path1c, 0.3, { css: { strokeDashoffset: 0 }, ease: Linear.easeNone })
   570        // progress bars and firewall update lines fade out
   571        .to(progressBars, 0.7, { opacity: 0 }, 'resetComputer1')
   572        .to(computerUpdateBox, 0.7, { opacity: 0 }, 'resetComputer1')
   573        .to(computerUpdatePath, 0.7, { opacity: 0 }, 'resetComputer1')
   574        // connection turns blue
   575        .to(
   576          [path1a, path1b, path1c],
   577          0.5,
   578          { css: { stroke: '#3969ED' } },
   579          'resetComputer1'
   580        )
   581        .to(
   582          [box4Border, box6Border],
   583          0.5,
   584          { css: { fill: '#3969ED' } },
   585          'resetComputer1'
   586        )
   587        // second connection draws
   588        .to(
   589          path2a,
   590          0.3,
   591          { css: { strokeDashoffset: 0 }, ease: Linear.easeNone },
   592          '-=0.3'
   593        )
   594        .to(path2b, 0.3, { css: { strokeDashoffset: 0 }, ease: Linear.easeNone })
   595        .to(path2c, 0.2, { css: { strokeDashoffset: 0 }, ease: Linear.easeNone })
   596        // second connection turns blue
   597        .to([path2a, path2b, path2c], 0.5, { css: { stroke: '#3969ED' } }, '-=0.1')
   598        .to(box7Border, 0.5, { css: { fill: '#3969ED' } }, '-=0.3')
   599        // wait a moment
   600        .to(box2, 2, {})
   601        // blue elements fade back to gray
   602        .to(
   603          [path1a, path1b, path1c, path2a, path2b, path2c],
   604          0.5,
   605          {
   606            css: { stroke: '#b5b8c4' }
   607          },
   608          'colorReset1'
   609        )
   610        .to(
   611          [box7Border, box4Border, box6Border],
   612          0.5,
   613          { css: { fill: '#b5b8c4' } },
   614          'colorReset1'
   615        )
   616        // box 2 appears
   617        .to(box2Border, 0.4, { css: { fill: '#000' } }, 'colorReset1')
   618        .fromTo(
   619          box2,
   620          0.3,
   621          { scale: 0, rotation: 200, opacity: 0, svgOrigin: '195px 42px' },
   622          { scale: 1, rotation: 360, opacity: 1 },
   623          '-=0.4'
   624        )
   625        // wait a moment
   626        .to(box2, 1, {})
   627        // computer updates firewalls
   628        .to(computerUpdateBox, 0.3, { opacity: 1 }, '-=0.2')
   629        .to(computerUpdatePath, 0.3, { opacity: 1 }, '-=0.2')
   630        // firewall progress bars
   631        .to(progressBarBars, 0.01, { width: 0 })
   632        .to(progressBars, 0.2, { opacity: 1 })
   633        .staggerTo(progressBarBars, 0.6, { width: 40 }, 0.2)
   634        // third connection made
   635        .to(path3a, 0.3, { css: { strokeDashoffset: 0 }, ease: Linear.easeNone })
   636        .to(path3b, 0.3, { css: { strokeDashoffset: 0 }, ease: Linear.easeNone })
   637        .to(path3c, 0.3, { css: { strokeDashoffset: 0 }, ease: Linear.easeNone })
   638        // progress bars & computer arrows fade out
   639        .to(progressBars, 0.5, { opacity: 0 }, 'computerReset2')
   640        .to(computerUpdateBox, 0.5, { opacity: 0 }, 'computerReset2')
   641        .to(computerUpdatePath, 0.5, { opacity: 0 }, 'computerReset2')
   642        // third connection turns blue
   643        .to(
   644          [path3a, path3b, path3c],
   645          0.5,
   646          { css: { stroke: '#3969ED' } },
   647          'computerReset2'
   648        )
   649        .to(
   650          [box2Border, box7Border],
   651          0.5,
   652          { css: { fill: '#3969ED' } },
   653          'computerReset2'
   654        )
   655        // wait a bit
   656        .to(box2, 2, {})
   657        // third connection turns back to gray
   658        .to(
   659          [path3a, path3b, path3c],
   660          0.5,
   661          { css: { stroke: '#b5b8c4' } },
   662          'colorReset2'
   663        )
   664        .to(
   665          [box2Border, box7Border],
   666          0.5,
   667          { css: { fill: '#b5b8c4' } },
   668          'colorReset2'
   669        )
   670        // boxes 2, 4, and 6 disappear
   671        .to(
   672          [box2, box4, box6],
   673          0.6,
   674          { scale: 0, rotation: 200, opacity: 0 },
   675          '-=0.4'
   676        )
   677        // lines turn red and broken links appear
   678        .to(
   679          [path1a, path1b, path1c, path2a, path2b, path2c, path3a, path3b, path3c],
   680          0.3,
   681          { css: { stroke: '#ED4168' } },
   682          '-=0.2'
   683        )
   684        .to(brokenLinks, 0.3, { opacity: 1 }, '-=0.3')
   685        // wait a moment
   686        .to(box2, 1, {})
   687        // code sent to firewalls
   688        .to(computerUpdateBox, 0.3, { opacity: 1 })
   689        .to(computerUpdatePath, 0.3, { opacity: 1 })
   690        // firewall progress bars
   691        .to(progressBarBars, 0.01, { width: 0 })
   692        .to(progressBars, 0.2, { opacity: 1 })
   693        .staggerTo(progressBarBars, 0.6, { width: 40 }, 0.2)
   694        .to(box2, 0.5, {})
   695        // faulty connections removed
   696        .to(
   697          [
   698            path1a,
   699            path1b,
   700            path1c,
   701            path2a,
   702            path2b,
   703            path2c,
   704            path3a,
   705            path3b,
   706            path3c
   707          ].concat(brokenLinks),
   708          0.7,
   709          { opacity: 0 }
   710        )
   711        // progress bars and connection arrows fade out
   712        .to(progressBars, 0.5, { opacity: 0 }, 'computerReset3')
   713        .to(computerUpdateBox, 0.5, { opacity: 0 }, 'computerReset3')
   714        .to(computerUpdatePath, 0.5, { opacity: 0 }, 'computerReset3')
   715        .to(computer, 0.5, { opacity: 0 }, 'computerReset3')
   716        .call(function () {
   717          segmentationSolutionTimeline.resume(segmentationSolutionTimeline.time())
   718        })
   719        // wait a moment before the loop
   720        .to(box2, 1, {})
   721        .pause()
   722  
   723      // solution animation
   724      var segmentationSolutionTimeline = new TimelineLite()
   725  
   726      // service boxes
   727      var box1 = qs('#s-service-2')
   728      var box1Border = qs('#s-service-2 > path')
   729      var box1Lock = qs('#s-service-2 #s-secure-indicator-2')
   730      var box2 = qs('#s-service-4')
   731      var box2Border = qs('#s-service-4 > path')
   732      var box2Lock = qs('#s-service-4 #s-secure-indicator-4')
   733      var box3 = qs('#s-service-6')
   734      var box3Border = qs('#s-service-6 > path')
   735      var box3Lock = qs('#s-service-6 #s-secure-indicator-6')
   736  
   737      // connection paths
   738      var path1a = qs('#s-connection-path-2')
   739      var path1b = qs('#s-connection-path-8')
   740      var path2a = qs('#s-connection-path-9')
   741      var path2b = qs('#s-connection-path-10')
   742      var path3a = qs('#s-connection-path-1')
   743      var path3b = qs('#s-connection-path-4')
   744      var path3c = qs('#s-connection-path-5')
   745      var path3d = qs('#s-connection-path-6')
   746  
   747      // inbound consul updates
   748      var inboundPathLower = qs('#s-consul-inbound-paths-lower')
   749      var inboundUpdateLower = qs('#s-dynamic-update-inbound-lower')
   750      var inboundUpdateLowerSpinner = qs('#s-dynamic-update-inbound-lower > path')
   751      var inboundPathUpper = qs('#s-consul-inbound-paths-upper')
   752      var inboundUpdateUpper = qs('#s-dynamic-update-inbound-upper')
   753      var inboundUpdateUpperSpinner = qs('#s-dynamic-update-inbound-upper > path')
   754  
   755      // outbound consul updates
   756      var outboundPathsLower = qsa(
   757        '#s-consul-server-connection-lower, #s-consul-outbound-5, #s-consul-outbound-6, #s-consul-outbound-7'
   758      )
   759      var outboundUpdateLower = qsa(
   760        '#s-dynamic-update-outbound-ower, #s-tls-cert-lower'
   761      )
   762      var outboundUpdateLowerSpinner = qs('#s-dynamic-update-outbound-ower > path')
   763      var outboundPathsUpper1 = qsa(
   764        '#s-consul-server-connection-upper, #s-consul-outbound-3, #s-consul-outbound-4'
   765      )
   766      var outboundPathsUpper2 = qsa(
   767        '#s-consul-server-connection-upper, #s-consul-outbound-1, #s-soncul-outbound-2'
   768      )
   769      var outboundUpdateUpper = qsa(
   770        '#s-tls-cert-upper, #s-dynamic-update-outbound-upper'
   771      )
   772      var outboundUpdateUpperSpinner = qs('#s-dynamic-update-outbound-upper > path')
   773  
   774      segmentationSolutionTimeline
   775        .to(box2, 1, {})
   776        // boxes 2 and 3 appear
   777        .fromTo(
   778          box2,
   779          0.3,
   780          { scale: 0, rotation: 200, opacity: 0, svgOrigin: '281px 104px' },
   781          { scale: 1, rotation: 360, opacity: 1 }
   782        )
   783        .fromTo(
   784          box3,
   785          0.3,
   786          { scale: 0, rotation: 200, opacity: 0, svgOrigin: '185px 226px' },
   787          { scale: 1, rotation: 360, opacity: 1 },
   788          '-=0.1'
   789        )
   790        // wait a moment
   791        .to(box1, 0.5, {})
   792        // consul speaks to each box that needs a connection made
   793        .to(outboundPathsUpper1, 0.5, { opacity: 1 })
   794        .to(outboundPathsLower, 0.5, { opacity: 1 }, '-=0.3')
   795        .to(outboundUpdateUpper, 0.3, { opacity: 1 }, '-=0.3')
   796        .to(outboundUpdateLower, 0.3, { opacity: 1 }, '-=0.1')
   797        .to(
   798          outboundUpdateUpperSpinner,
   799          0.7,
   800          {
   801            rotation: 360,
   802            svgOrigin: '44px 99px'
   803          },
   804          '-=0.5'
   805        )
   806        .to(
   807          outboundUpdateLowerSpinner,
   808          0.7,
   809          {
   810            rotation: 360,
   811            svgOrigin: '44px 246px'
   812          },
   813          '-=0.3'
   814        )
   815        // pink borders, locks, connections drawn, consul talk fades
   816        .to(box2Lock, 0.3, { opacity: 1 }, 'connections-1')
   817        .to(box2Border, 0.3, { fill: '#CA2270' }, 'connections-1')
   818        .to(box3Lock, 0.3, { opacity: 1 }, 'connections-1')
   819        .to(box3Border, 0.3, { fill: '#CA2270' }, 'connections-1')
   820        .to(outboundPathsUpper1, 0.7, { opacity: 0 }, 'connections-1')
   821        .to(outboundPathsLower, 0.7, { opacity: 0 }, 'connections-1')
   822        .to(outboundUpdateUpper, 0.7, { opacity: 0 }, 'connections-1')
   823        .to(outboundUpdateLower, 0.7, { opacity: 0 }, 'connections-1')
   824        .to(
   825          path1a,
   826          0.5,
   827          { css: { strokeDashoffset: 0, stroke: '#CA2270' } },
   828          'connections-1'
   829        )
   830        .to(
   831          path1b,
   832          0.5,
   833          { css: { strokeDashoffset: 0, stroke: '#CA2270' } },
   834          'connections-1'
   835        )
   836        .to(
   837          path2a,
   838          0.5,
   839          { css: { strokeDashoffset: 0, stroke: '#CA2270' } },
   840          'connections-1'
   841        )
   842        .to(
   843          path2b,
   844          0.5,
   845          { css: { strokeDashoffset: 0, stroke: '#CA2270' } },
   846          'connections-1'
   847        )
   848        // wait a moment
   849        .to(box1, 0.5, {})
   850        // box 1 appears
   851        .fromTo(
   852          box1,
   853          0.3,
   854          { scale: 0, rotation: 200, opacity: 0, svgOrigin: '185px 104px' },
   855          { scale: 1, rotation: 360, opacity: 1 },
   856          '-=0.1'
   857        )
   858        // wait a moment, previous paths fade ('#EEB9D1')
   859        .to(box1, 0.5, {}, 'stage-1-complete')
   860        .to(box2Border, 0.5, { fill: '#EEB9D1' }, 'stage-1-complete')
   861        .to(box3Border, 0.5, { fill: '#EEB9D1' }, 'stage-1-complete')
   862        .to(path1a, 0.5, { css: { stroke: '#EEB9D1' } }, 'stage-1-complete')
   863        .to(path1b, 0.5, { css: { stroke: '#EEB9D1' } }, 'stage-1-complete')
   864        .to(path2a, 0.5, { css: { stroke: '#EEB9D1' } }, 'stage-1-complete')
   865        .to(path2b, 0.5, { css: { stroke: '#EEB9D1' } }, 'stage-1-complete')
   866        // consul speaks to each box that needs a connection made
   867        .to(outboundPathsUpper2, 0.5, { opacity: 1 })
   868        .to(outboundPathsLower, 0.5, { opacity: 1 }, '-=0.3')
   869        .to(outboundUpdateUpper, 0.3, { opacity: 1 }, '-=0.3')
   870        .to(outboundUpdateLower, 0.3, { opacity: 1 }, '-=0.1')
   871        .to(
   872          outboundUpdateUpperSpinner,
   873          0.7,
   874          {
   875            rotation: 720,
   876            svgOrigin: '44px 99px'
   877          },
   878          '-=0.5'
   879        )
   880        .to(
   881          outboundUpdateLowerSpinner,
   882          0.7,
   883          {
   884            rotation: 720,
   885            svgOrigin: '44px 246px'
   886          },
   887          '-=0.3'
   888        )
   889        // connections drawn
   890        .to(box1Lock, 0.3, { opacity: 1 }, 'connections-2')
   891        .to(box1Border, 0.3, { fill: '#CA2270' }, 'connections-2')
   892        .to(
   893          path3a,
   894          0.5,
   895          { css: { strokeDashoffset: 0, stroke: '#CA2270' } },
   896          'connections-2'
   897        )
   898        .to(
   899          path3b,
   900          0.5,
   901          { css: { strokeDashoffset: 0, stroke: '#CA2270' } },
   902          'connections-2'
   903        )
   904        .to(
   905          path3c,
   906          0.5,
   907          { css: { strokeDashoffset: 0, stroke: '#CA2270' } },
   908          'connections-2'
   909        )
   910        .to(
   911          path3d,
   912          0.5,
   913          { css: { strokeDashoffset: 0, stroke: '#CA2270' } },
   914          'connections-2'
   915        )
   916        .to(box1, 0.7, {}, 'stage-2-complete')
   917        .to(outboundPathsUpper2, 0.7, { opacity: 0 }, 'stage-2-complete')
   918        .to(outboundPathsLower, 0.7, { opacity: 0 }, 'stage-2-complete')
   919        .to(outboundUpdateUpper, 0.7, { opacity: 0 }, 'stage-2-complete')
   920        .to(outboundUpdateLower, 0.7, { opacity: 0 }, 'stage-2-complete')
   921        .to(box1Border, 0.5, { fill: '#EEB9D1' }, 'path-fade-2')
   922        .to(path3a, 0.5, { css: { stroke: '#EEB9D1' } }, 'path-fade-2')
   923        .to(path3b, 0.5, { css: { stroke: '#EEB9D1' } }, 'path-fade-2')
   924        .to(path3c, 0.5, { css: { stroke: '#EEB9D1' } }, 'path-fade-2')
   925        .to(path3d, 0.5, { css: { stroke: '#EEB9D1' } }, 'path-fade-2')
   926        // wait a moment
   927        .to(box1, 1, {})
   928        // all new boxes and connections fade
   929        .to(
   930          [
   931            box1,
   932            box2,
   933            box3,
   934            path1a,
   935            path1b,
   936            path2a,
   937            path2b,
   938            path3a,
   939            path3b,
   940            path3c,
   941            path3d
   942          ],
   943          0.5,
   944          { opacity: 0.3 }
   945        )
   946        // faded boxes speak to consul
   947        .to(inboundPathLower, 0.5, { opacity: 1 }, 'inbound')
   948        .to(inboundPathUpper, 0.5, { opacity: 1 }, 'inbound')
   949        .to(inboundUpdateLower, 0.5, { opacity: 1 }, 'inbound')
   950        .to(inboundUpdateUpper, 0.5, { opacity: 1 }, 'inbound')
   951        .to(
   952          inboundUpdateLowerSpinner,
   953          0.7,
   954          {
   955            rotation: 360,
   956            svgOrigin: '44px 237px'
   957          },
   958          '-=0.3'
   959        )
   960        .to(
   961          inboundUpdateUpperSpinner,
   962          0.7,
   963          {
   964            rotation: 360,
   965            svgOrigin: '44px 91px'
   966          },
   967          '-=0.3'
   968        )
   969        // consul removes faded boxes and connections
   970        .to(
   971          [
   972            box1,
   973            box2,
   974            box3,
   975            path1a,
   976            path1b,
   977            path2a,
   978            path2b,
   979            path3a,
   980            path3b,
   981            path3c,
   982            path3d,
   983            inboundPathLower,
   984            inboundPathUpper,
   985            inboundUpdateLower,
   986            inboundUpdateUpper
   987          ],
   988          0.5,
   989          { opacity: 0.0 }
   990        )
   991        .addPause()
   992        // wait a moment before the loop
   993        .to(box1, 1, {})
   994        .pause()
   995  
   996      // kick it off
   997      $segmentationChallenge.classList.add('active')
   998      $segmentationSolution.classList.add('active')
   999      segmentationChallengeTimeline.play()
  1000      segmentationSolutionTimeline.play()
  1001    }
  1002  }