GODRICH
#css-animation#button#loader#transition#scroll#dashboard#ui#design-trends

Intro Animation CSS: 9 Website Intro Animations

Intro animation css is the short opening a page plays over its first screen, and all nine here end the same way: an intro you can skip, with no library to

Auto-plays · click a tile to jump to its section · all nine in one zip

The order runs roughly from the largest covered surface down to the smallest. It opens with full covers — two panels in 01, a circle in 04, three sweeping bands in 09 — that hide the page and then get out of the way, and the subject keeps shrinking from there: a logo mark in 02, one headline in 03, a single digit at a time in 05, until 06 is drawing a thin line and 08 is moving two halves of a word by a few pixels. That is also a difficulty ramp, because the covers need nothing but a transform while the later ones want a mask, an SVG stroke, or a cut that has to land on an exact frame. Underneath, every one of them is the same opening animation css shape: the resting state of the markup is the finished page, and the keyframes describe the state before it.

01Curtain lift

Two panels split away from the middle of the viewport and the headline rises a beat behind them, which is the half second a brand landing page buys before the words have to carry it.

Curtain lift
Open in a new tab

01 · Curtain lift — Measured area 99.947% · moving frames 19/23Original by GODRICH · SCSS and React ship in the zip · See the password

translateYanimation-fill-mode$ease-spring

The resting state is the finished page

// Two panels covering the screen. The default transform is the open position, off screen
.cl__veil { position: absolute; left: 0; right: 0; height: 50.5%; background: $color; z-index: 2; }
.cl__veil--top { top: 0; transform: translateY(-102%); }
.cl__veil--bot { bottom: 0; transform: translateY(102%); }
.cl__veil--top {
  animation-name: clTopOnce; animation-duration: $duration; animation-timing-function: $easing;
  animation-delay: .08s; animation-fill-mode: both;
}
@keyframes clTopOnce { from { transform: translateY(0); } to { transform: translateY(-102%); } }
@keyframes clRiseOnce { from { transform: translateY(24px); } to { transform: none; } }

The closed screen exists only inside the 0% keyframe and animation-fill-mode: both holds it through the delay, so switching the animation off anywhere — a skip click, a returning visitor, a reduced-motion setting — lands on the opened page instead of a half-lifted curtain.

One function for skip, Escape, and the second visit

// Send the intro to its finished state — turning the animation off reveals the default, opened screen
function finish(announce) {
  root.classList.remove('is-demo');
  root.classList.add('is-done');
  try { sessionStorage.setItem(KEY, '1'); } catch (e) {}
  if (announce) live.textContent = 'Skipped the intro';
}
document.getElementById('cl-skip').addEventListener('click', function () { finish(true); });
document.addEventListener('keydown', function (e) {
  if (e.key === 'Escape') finish(true);
});

That function is the entire scripting budget for the item, and its preview loop measures 19 of 23 frame gaps as moving while 99.95% of the canvas changes at least once.

02Logo assemble

Four quadrants fly in from four directions one beat apart and lock into a single mark, the shape a company page wants when the logo has to land before any sentence does.

Logo assemble
Open in a new tab

02 · Logo assemble — Measured area 21.906% · moving frames 19/23Original by GODRICH · SCSS and React ship in the zip · See the password

clip-pathtransform-originanimation-delay

One circle cut into four pieces

.la__mark { position: relative; width: 96px; height: 96px; }
.la__q {
  position: absolute; inset: 0; border-radius: 50%;
  transform-origin: 50% 50%;   // The pivot is the circle's center, the point where a piece joins the logo
}
.la__q--tl { background: $subject-ink;    clip-path: inset(0 51% 51% 0); }
.la__q--tr { background: $color;          clip-path: inset(0 0 51% 51%); }
.la__q--br { background: $chart-3;        clip-path: inset(51% 0 0 51%); }
.la__q--bl { background: $stage-orange;   clip-path: inset(51% 51% 0 0); }

All four pieces are the same 96px circle and clip-path: inset() is what leaves each one a different quarter, with the extra 1% on two sides opening the hairline gap that keeps the mark from reading as a solid disc.

Arrival order written as delays

.la__q--tr {
  animation-name: laInTr; animation-duration: $duration; animation-timing-function: $easing;
  animation-delay: .08s; animation-fill-mode: both;
}
.la__q--br {
  animation-name: laInBr; animation-duration: $duration; animation-timing-function: $easing;
  animation-delay: .16s; animation-fill-mode: both;
}
@keyframes laInTl { from { transform: translate(-150px, 0) rotate(-10deg); } to { transform: none; } }
@keyframes laInTr { from { transform: translate(0, -150px) rotate(8deg); } to { transform: none; } }
@keyframes laInBr { from { transform: translate(150px, 0) rotate(10deg); } to { transform: none; } }
@keyframes laInBl { from { transform: translate(0, 150px) rotate(-8deg); } to { transform: none; } }

Each piece is 80ms behind the one before it and carries a small rotation home, so the four read as one arrival rather than four entrances, and the preview puts 19 of 23 gaps in motion over 21.91% of the canvas.

03Letter mask stagger

Every letter sits in its own clipping box and is pushed up from underneath one index at a time, so the headline appears to grow out of the floor instead of fading in.

Letter mask stagger
Open in a new tab

03 · Letter mask stagger — Measured area 6.092% · moving frames 21/23Original by GODRICH · SCSS and React ship in the zip · See the password

overflow: hidden--ianimation-delay

The box is the mask

.tt__row { display: flex; gap: $sp-1; margin: 0; }
.tt__box { display: block; overflow: hidden; }
.tt__ch {
  display: block; color: $color;
  font-weight: 800; font-size: clamp(26px, 7vw, 36px); line-height: 1.15;
}
.tt__ch {
  animation-name: ttChOnce; animation-duration: $duration; animation-timing-function: $easing;
  animation-delay: calc(var(--i) * .05s); animation-fill-mode: both;
}
@keyframes ttChOnce { from { transform: translateY(112%); } to { transform: none; } }

There is no opacity anywhere in this item, since a letter is either inside its box or clipped away by it, which is why no still frame ever catches a half-transparent ghost of the headline.

The markup hands CSS the index

<h1 class="tt__row" aria-label="GODRICH">
  <span class="tt__box" aria-hidden="true" style="--i:0"><span class="tt__ch">G</span></span>
  <span class="tt__box" aria-hidden="true" style="--i:1"><span class="tt__ch">O</span></span>
  <span class="tt__box" aria-hidden="true" style="--i:2"><span class="tt__ch">D</span></span>
  <span class="tt__box" aria-hidden="true" style="--i:3"><span class="tt__ch">R</span></span>
  <span class="tt__box" aria-hidden="true" style="--i:4"><span class="tt__ch">I</span></span>
  <span class="tt__box" aria-hidden="true" style="--i:5"><span class="tt__ch">C</span></span>
  <span class="tt__box" aria-hidden="true" style="--i:6"><span class="tt__ch">H</span></span>
</h1>

A single --i per span is all the stylesheet needs to space the letters 50ms apart, and with four or five glyphs in the air at once this is the busiest item of the nine: 21 of 23 gaps register movement even though the letters only ever touch 6.09% of the canvas.

04Circle mask wipe

A clip-path circle grows out of one dot in the middle until it runs past the edges, and the page it uncovers was lying underneath fully painted the whole time.

Circle mask wipe
Open in a new tab

04 · Circle mask wipe — Measured area 97.503% · moving frames 16/23Original by GODRICH · SCSS and React ship in the zip · See the password

clip-path: circle$ease-outanimation-fill-mode

Nothing expands, a cover gets erased

// The cover is the ink sheet underneath. The wider the circle, the more of it .iw__site hides
.iw__cover { position: absolute; inset: 0; z-index: 1; background: $subject-ink; }
.iw__site {
  position: absolute; inset: 0; z-index: 2;
  display: grid; place-items: center;
  box-sizing: border-box; padding: $sp-4;
  background: $stage-paper;
}
@keyframes iwOpen {
  0% { clip-path: circle(0% at 50% 50%); }
  62% { clip-path: circle(75% at 50% 50%); }
  100% { clip-path: circle(75% at 50% 50%); }
}

The circle is applied to the finished page rather than to the cover, so the whole reveal is one animated property and the 97.50% of the canvas that changes is just the ink sheet vanishing behind an opaque background.

Why the radius stops at 75%

// A seed dot marks the center of circle(0%) so the very first frame is never an empty screen
.iw__seed {
  position: absolute; left: 50%; top: 50%;
  width: 12px; height: 12px; border-radius: 50%;
  transform: translate(-50%, -50%);
  background: $subject-cream;
}
@keyframes iwSettle {
  0% { transform: scale(1.045); }
  78% { transform: scale(1); }
  100% { transform: scale(1); }
}

A percentage radius is resolved against the box's reference length, which on the 480×300 stage works out to 400px, so 75% draws a 300px radius and clears the 283px distance to the corner with room left over.

05Countdown lead

Three, two, and one swap inside a single frame while each digit pops down to its resting size and the whole count creeps closer, the screen an event or a live stream opens on.

Countdown lead
Open in a new tab

05 · Countdown lead — Measured area 10.317% · moving frames 14/23Original by GODRICH · SCSS and React ship in the zip · See the password

steps(1, end)font-variant-numericscale

Three numbers stacked in one cell

.cd__nums {
  position: absolute; left: 50%; top: 50%; z-index: 2;
  display: grid; justify-items: center; row-gap: $sp-2;
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.cd__n {
  grid-area: 1 / 1;
  color: $color;
  font-weight: 800; font-size: clamp(72px, 24vw, 104px); line-height: 1;
  font-variant-numeric: tabular-nums;   // 3, 2 and 1 share one width so a cut never shifts the center
  opacity: 0;                            // In the finished state there is no number left at all
}

All three digits share grid-area: 1 / 1, which turns the count into one stack whose visible layer is chosen by opacity, and tabular-nums keeps the glyph advance identical so the number does not jitter between cuts.

A pop keyframe for every digit

// One keyframes per number — stacking two animations on the same property lets the later one win and the order falls apart
@keyframes cdPop3 { 0% { transform: scale(1.5); } 12% { transform: scale(1); } 100% { transform: scale(1); } }
@keyframes cdPop2 { 0%, 14% { transform: scale(1.5); } 26% { transform: scale(1); } 100% { transform: scale(1); } }
@keyframes cdPop1 { 0%, 28% { transform: scale(1.5); } 40% { transform: scale(1); } 100% { transform: scale(1); } }
@keyframes cdDolly {
  0% { transform: translate(-50%, -50%) scale(1); }
  42% { transform: translate(-50%, -50%) scale(1.12); }
  100% { transform: translate(-50%, -50%) scale(1.12); }
}

Delaying one shared pop would leave backwards fill painting a digit whose turn has not come, so each number carries its own keyframes while the dolly runs on the wrapper, where the centering translate has to be repeated in every step of the scale — and because a cut lands between two samples, this item moves in only 14 of 23 gaps while touching 10.32% of the canvas.

06Line drawing frame

An SVG frame draws itself in one stroke and the words inside switch on once the line closes, the cover-page entrance an exhibition or a magazine issue tends to want.

Line drawing frame
Open in a new tab

06 · Line drawing frame — Measured area 6.66% · moving frames 18/23Original by GODRICH · SCSS and React ship in the zip · See the password

stroke-dasharraystroke-dashoffsetpathLength

pathLength takes the arithmetic out

.ld__rect {
  fill: none; stroke: $color; stroke-width: 3;
  stroke-dasharray: 100;   // Measured against pathLength 100 — the full length that can be drawn
  stroke-dashoffset: 0;    // The default of 0 is the finished state, with the line fully closed
}
@keyframes ldDraw {
  0% { stroke-dashoffset: 100; }
  56% { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: 0; }
}

With pathLength="100" set on the rect, the browser rescales the real perimeter to 100 units, so the dash pattern is effectively written in percent and nothing has to be re-measured in script when the frame changes size.

Text that waits for the line to close

.ld.is-demo .ld__kicker,
.ld.is-demo .ld__title,
.ld.is-demo .ld__sub {
  animation-name: ldTextOn, ldTextRise;
  animation-duration: $duration, $duration;
  animation-timing-function: steps(1, end), $easing;
  animation-iteration-count: infinite, infinite;
  animation-fill-mode: backwards, backwards;
}
// From 56% (1.12s), the moment the line closes — kicker first, then title, then subtitle
.ld.is-demo .ld__kicker { animation-delay: 1.12s, 1.12s; }
.ld.is-demo .ld__title { animation-delay: 1.2s, 1.2s; }
.ld.is-demo .ld__sub { animation-delay: 1.28s, 1.28s; }

Two animations share each element, a steps(1, end) cut for visibility and an eased rise for position, and backwards fill is what stops the delayed text from flashing its finished state on the first frame of a 6.66% footprint that still moves in 18 of 23 gaps.

07Split screen open

The two halves covering the screen slide out in opposite directions, the seam between them collapses first, and the product page underneath is already sitting there in full opacity.

Split screen open
Open in a new tab

07 · Split screen open — Measured area 78.636% · moving frames 14/23Original by GODRICH · SCSS and React ship in the zip · See the password

translateXwill-change$dur-enter

Halves that leave by 102%

.scr__panel {
  position: absolute; top: 0; bottom: 0; width: 50.5%; z-index: 2;
  display: flex; align-items: center;
  will-change: transform;          // Promote to a compositor layer before the move starts
}
.scr__panel--l {
  left: 0; justify-content: flex-end; padding-right: $sp-1;
  background: $color;
  transform: translateX(-102%);    // A little past its own width so the join never shows
  animation-name: scrPanelLOnce; animation-duration: $duration;
  animation-timing-function: $easing; animation-iteration-count: 1; animation-fill-mode: backwards;
}
@keyframes scrPanelLOnce {
  0% { transform: translateX(0); }
  100% { transform: translateX(-102%); }
}

Half a percent of extra width on each panel and two percent of overshoot on the travel are what keep a one-pixel seam of background from flickering where the halves meet on fractional device pixels.

The seam goes before the panels do

.scr__seam {
  position: absolute; top: 10%; bottom: 10%; left: 50%; width: 4px; z-index: 3;
  border-radius: $r-pill; background: $stage-orange;
  transform: translateX(-50%) scaleY(0);
  animation-name: scrSeamOnce; animation-duration: $dur-quick;
  animation-timing-function: $easing; animation-iteration-count: 1; animation-fill-mode: backwards;
}
@keyframes scrSeamOnce {
  0% { transform: translateX(-50%) scaleY(1); }
  40%, 100% { transform: translateX(-50%) scaleY(0); }
}

The line shrinks along its own axis in the first 40% of $dur-quick so the eye reads a latch being released before anything slides, and with two full-height panels then crossing the stage this item posts the second-biggest single-gap change of the nine at 35.79% of the canvas.

08Glitch boot

The headline arrives as two clipped copies that jump sideways with colored afterimages, then the offset converges on zero and the word snaps into one line.

Glitch boot
Open in a new tab

08 · Glitch boot — Measured area 9.744% · moving frames 17/23Original by GODRICH · SCSS and React ship in the zip · See the password

text-shadowclip-pathanimation-iteration-count

One title, two clipped copies

<div class="gl__head">
  <p class="gl__kicker">New release</p>
  <div class="gl__titlewrap">
    <h1 class="gl__title">Neon Arcade</h1>
    <span class="gl__slice gl__slice--a" aria-hidden="true">Neon Arcade</span>
    <span class="gl__slice gl__slice--b" aria-hidden="true">Neon Arcade</span>
  </div>
</div>

The real h1 is never touched and the two aria-hidden copies stacked over it take the top and bottom halves through clip-path: inset(), so the tearing is purely decorative and a screen reader still hears the title exactly once.

Five steps that converge on zero

@keyframes glSliceAOnce {
  0% { transform: translate(-9px, 0); text-shadow: 5px 0 $color; clip-path: inset(0 0 52% 0); }
  7% { transform: translate(5px, -1px); text-shadow: -4px 0 $subject-orange-deep; clip-path: inset(0 0 48% 0); }
  14% { transform: translate(-6px, 1px); text-shadow: 4px 0 $color; clip-path: inset(0 0 55% 0); }
  21% { transform: translate(3px, 0); text-shadow: -3px 0 $subject-orange-deep; clip-path: inset(0 0 47% 0); }
  28% { transform: translate(-2px, 0); text-shadow: 2px 0 $color; clip-path: inset(0 0 50% 0); }
  34%, 100% { transform: translate(0, 0); text-shadow: 0 0 transparent; clip-path: inset(0 0 50% 0); }
}

The swing narrows from 9px to 2px before it settles at zero on 34%, the shadow flips to the opposite side on every step, and since the moving thing is a few pixels of text the item registers 17 of 23 gaps over 9.74% of the canvas.

09Color flood

Three color bands sweep the screen one after another and the last one folds away to the right, leaving the page a brand built on its palette wants seen first.

Color flood
Open in a new tab

09 · Color flood — Measured area 79.442% · moving frames 13/23Original by GODRICH · SCSS and React ship in the zip · See the password

scaleXtransform-originanimation-fill-mode

Growing from the left, folding to the right

.cf__band {
  position: absolute; inset: 0; z-index: 2;
  transform-origin: left center;
  transform: translateX(0) scaleX(0);
  will-change: transform;
  animation-timing-function: linear;   // A wave front at constant speed — growth and fold share one curve so the join never opens
  animation-iteration-count: 1; animation-fill-mode: backwards;
}
@keyframes cfBand1 {
  0% { transform: translateX(0) scaleX(0); }
  13% { transform: translateX(0) scaleX(1); }
  26%, 100% { transform: translateX(100%) scaleX(0); }
}

A transform-origin cannot be swapped halfway through an animation, so the exit is written as translateX(100%) scaleX(0) against an origin that stays on the left, a pair that interpolates together and keeps the band's right edge pinned while it collapses.

Three bands queued 13% apart

@keyframes cfBand2 {
  0%, 13% { transform: translateX(0) scaleX(0); }
  26% { transform: translateX(0) scaleX(1); }
  39%, 100% { transform: translateX(100%) scaleX(0); }
}
@keyframes cfBand3 {
  0%, 26% { transform: translateX(0) scaleX(0); }
  39% { transform: translateX(0) scaleX(1); }
  52%, 100% { transform: translateX(100%) scaleX(0); }
}
@keyframes cfContentOnce {
  0%, 38% { opacity: 0; transform: translateY(16px); }
  54%, 100% { opacity: 1; transform: translateY(0); }
}

Every band starts growing at the percentage where the one before it finished, so the three read as a single wave handed over twice, and the page rises between 38% and 54% while the last band folds — which is how 79.44% of the canvas can change in only 13 of 23 gaps.

How far does a website intro animation go with CSS alone?

All nine keep the same division of labor: keyframes stage the show and the script swaps two class names, which is as far as an intro animation html css build needs to go. The ceiling is anything whose playhead has to be scrubbed by code — a sequence pinned to scroll position, particles on a canvas, captions locked to a video timeline — and those are a timeline library's job, not a stylesheet's. Below that line a cover, a headline, and a few bands cost one stylesheet and about ten lines of script. If what you need is a screen that waits for data rather than one that gets out of the way, 9 Loading Screen Designs is the closer match, and for the pause between two routes instead of the entrance to the first one, Page Loading Animation CSS picks the thread up.

Where it breaks — the trap

An intro covers the entire viewport, and at that size three failures turn up that a card or a button never produces.

A scale on a full-bleed element breaks the responsive check

// The dolly-out belongs on this box, which is smaller than the screen — scaling a full-bleed element overflows scrollWidth
.iw__box {
  display: flex; flex-direction: column; align-items: center;
  width: min(84%, 400px); gap: $sp-2; text-align: center;
}
@keyframes iwSettle {
  0% { transform: scale(1.045); }
  78% { transform: scale(1); }
  100% { transform: scale(1); }
}

The first build of 04 put scale(1.045) straight onto the inset: 0 element that fills the stage. Adding overflow: hidden does not save it, because scrollWidth is read from the transformed border box, so the 4.5% enlargement was reported as horizontal overflow and the responsive check failed at the narrow width. The rule to take away is that a full-bleed layer may translate and it may be clipped, but the moment it scales it is wider than its parent by definition. Moving the scale onto an inner box that is already narrower than the viewport fixed it, and 05 keeps its rise on the inner content block for the same reason, which is why both items now measure clean at both widths.

A return faster than the entrance turns the poster into an empty screen

@keyframes clTopLoop {
  0%, 4% { transform: translateY(0); }
  26%, 66% { transform: translateY(-102%); animation-timing-function: linear; }
  88%, 100% { transform: translateY(0); }
}
@keyframes laTlLoop {
  0% { transform: translate(-150px, 0) rotate(-10deg); }
  14%, 76% { transform: none; animation-timing-function: linear; }
  86%, 100% { transform: translate(-150px, 0) rotate(-10deg); }
}

The still image that represents each item in the grid is picked automatically: 24 frames are sampled, neighbors are compared to give 23 gaps, and the gap with the largest changed area wins. An intro loop has to close again before it can replay, and if the closing is short and sharp, that single gap beats every frame of the opening — so the poster ends up being the covered, empty screen. The password for the zip that holds all nine is g2nru27q, and the fix that made those posters usable was to keep the spring on the way out and stretch the way back with animation-timing-function: linear written into the middle keyframe, a per-keyframe override that applies from that stop onwards. Disappearing is handled the same way: the panels come back to cover the content instead of the content fading, because a fade produces exactly the kind of half-transparent frame a poster should never freeze on.

A one-step cut has to land on a middle keyframe

// steps(1, end) changes value only at the end of a step — the cut points are written as middle keyframes at 14, 28 and 42%
.cd.is-demo .cd__site {
  animation-name: cdSite;
  animation-duration: $duration;
  animation-timing-function: steps(1, end);
  animation-iteration-count: infinite;
  animation-fill-mode: both;
}
@keyframes cdN2   { 0% { opacity: 0; } 14% { opacity: 1; } 28% { opacity: 0; } 100% { opacity: 0; } }
@keyframes cdSite { 0% { opacity: 0; } 42% { opacity: 1; } 100% { opacity: 1; } }

A timing function applies between one keyframe and the next, and steps(1, end) treats that span as a single step whose value changes at its end. Write the two values on 0% and 100% only and the swap happens as the animation finishes, which on screen means nothing happened at all. The countdown in 05 therefore stamps its cuts as real keyframes at 14%, 28%, and 42%, one for each digit swap and one for the page behind them, and the text in 06 does the same with a cut at 2% rather than at 0%. The habit worth keeping is simple: with a stepped timing function, a keyframe is not a description of a moment, it is the moment the value is allowed to change.

Three variants and accessibility

Three token values retune all nine at once.

Three values that retune all nine

name changed value feel
duration $dur-enter 600ms → 300ms panels and letters clear the screen twice as fast
easing $ease-spring → $ease-pop the headline bounces once more as it settles
color $subject-blue → $stage-orange the cover moves from the cold side of the palette to the warm

What is left when motion is reduced

Because the resting state of every item is the finished page, prefers-reduced-motion needs to do nothing but switch the animations off and the reader arrives on the opened screen. Items 01 through 06 use animation: none !important while 07, 08, and 09 use animation-name: none !important, the !important being there to outrank the three-class preview selectors. Nobody has to wait for a state to rewind, because there is no state to rewind to.

What the ear gets instead of the animation

Decorative layers — panels, quadrants, bands, and the glitch copies — all carry aria-hidden="true", and the one thing a screen reader is told is the outcome, announced through an aria-live="polite" line when the intro is skipped or finished. Text contrast was calculated from the token values across 42 samples in the nine screens with nothing below AA: the headline in 01 reads 17.11:1 on ink #17141a, the letters in 03 reach 5.50:1 on orange #ff4d1f, and the kicker in 09 sits at 5.69:1 on the same ink. The techniques themselves are documented in clip-path, stroke-dasharray, and sessionStorage.

FAQ

Should a website intro animation play on every reload?

No, and all nine leave a flag in sessionStorage so a second visit in the same tab opens straight on the finished page. Closing the tab clears the flag, which means a first-time reader sees the opening once and a returning one never waits. Browsers that block storage throw on the write, the exception is swallowed, and the intro simply plays.

Does an intro make the first screen feel slower?

Not by itself, since nothing extra is fetched: no images, no library, just keyframes and about ten lines of script. The content sits opaque under the cover from the first paint, so it is hidden rather than built late, and the skip control is in the tab order from the beginning. If you still want it shorter, dropping the duration variant to 300ms is the smallest change that helps.

What does a screen reader hear while the intro is playing?

The covers and pieces are hidden from the accessibility tree, so they are never announced, and split headlines like 03 carry an aria-label on the row so the word is read once instead of letter by letter. The skip button is one of the first stops in the tab order, and Escape calls the same function, so a keyboard user can get past the opening in one keystroke.

Enter the archive password

The password is inside this article. You will find it as you read.