Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div class="network-banner">
  <p>From the &quot;Oh that&apos;s a baseball!&quot; network:</p>
</div>
<div class="title-banner">
  <h1>Today&apos;s Games</h1>
</div>

<div class="main-container">

  <div class="section s1">
    <div class="game-info-container">
      <div id="gi1" class="game-info">
        <h2>JAGUARS<br>vs<br>COUGARS</h2>
        <span>The Dunkin&apos; Mega Area</span>
        <span>11:00am CST</span>
      </div>
    </div>
  </div>

  <div class="section s2">
    <div class="game-info-container">
      <div id="gi2" class="game-info">
        <h2>SLUGGERS<br>vs<br>SNAILERS</h2>
        <span>The Gaucamole Technology Stadium</span>
        <span>2:00pm PST</span>
      </div>
    </div>
  </div>

  <div class="section s3">
    <div class="game-info-container">
      <div id="gi3" class="game-info">
        <h2>BATTERS<br>vs<br>HATTERS</h2>
        <span>The Wendy&apos;s Twitter Account Sports Complex</span>
        <span>12:00pm MST</span>
      </div>
    </div>
  </div>

  <div class="baseball-container">
    <div class="baseball-texture"></div>
  </div>

</div>

<div class="footer">
  <div class="footer-graphics">
    <svg class="bat" width="100%" height="100%" viewBox="0 0 850 300" fill="none" xmlns="http://www.w3.org/2000/svg">
      <g clip-path="url(#clip0_1_2)">
        <g class="impact">
          <path d="M651.415 67.5476L719.367 12.2933L706.924 75.4987L704.795 86.3144L714.335 80.7917L793.265 35.0995L751.884 97.3945L747.299 104.296L755.542 105.135L797.969 109.454L738.521 130.033L722.174 135.692L739.019 139.627L791.553 151.9L726.39 159.173L725.089 168.785L795.011 196.724H746.773L744.667 206.26L798.353 231.18H746.773H736.9L742.742 239.139L771.465 278.269L672.133 222.344L666.779 219.33L664.916 225.185L646.16 284.114L609.847 243.284L606.564 239.592L602.833 242.831L553.252 285.878L533.944 244.493L531.944 240.204L527.552 241.966L428.449 281.717L484.141 217.124L491.267 208.859H480.354H400.083L468.83 157.654L479.497 149.709L466.238 148.66L417.339 144.789L433.793 135.298L441.677 130.751L433.611 126.535L402.834 110.452L473.676 105.147L487.094 104.142L476.275 96.1412L422.297 56.2184L503.506 73.3005L509.535 74.5687V68.4076V6.71726L577.575 79.8697L583.37 86.1003L585.993 78.0055L607.66 11.1277L644.085 66.4189L647.126 71.035L651.415 67.5476Z" fill="#E02726" stroke="white" stroke-width="10" />
          <path d="M617.5 69L626.064 108.227L677.354 80.5L659.161 114.882L745 80.5L682.184 127.204L716 120L673.909 145.194L716 155.015L677.354 164L716 180.017H677.354L730.5 197.934H682.184L709.5 228L637.217 193.005V228L604.12 203.355L564.188 237V203.355L502.67 228L538.645 186.327H481L523 145.194L486.5 139L502.67 130.642L491.5 120L534.974 127.204L497.274 99.3554L551.235 110.692L534.974 69L591.169 114.882L617.5 69Z" fill="#F2AB27" />
        </g>
        <path d="M422.299 204.975L422.649 205H423H788C794.417 205 806.866 202.442 817.948 194.505C829.61 186.152 839.5 171.975 839.5 150C839.5 128.278 830.329 114.056 818.803 105.572C807.819 97.4857 795.276 95 788 95C782.482 95 691.206 95.2501 601.347 95.5C556.41 95.625 511.816 95.75 478.456 95.8438L438.204 95.9571L426.95 95.9888L423.988 95.9972L423.228 95.9993L423.036 95.9999L422.988 96L422.976 96C422.973 96 422.972 96 423 106L422.972 96L422.658 96.0009L422.346 96.0214L209.172 110H179.5H149.5H119.5H89.5001H71.5H55.0461C54.275 109.317 53.3848 108.571 52.3968 107.814C49.1976 105.361 43.4718 101.601 36.6652 101.147C32.9585 100.9 28.9188 101.64 25.1417 104.032C21.4521 106.369 18.7117 109.837 16.714 113.899C12.8695 121.716 11 133.312 11 149.5C11 165.707 12.8754 177.324 16.6859 185.199C18.6602 189.28 21.3486 192.759 24.9452 195.156C28.6302 197.613 32.6118 198.493 36.3332 198.369C43.1914 198.141 48.9866 194.533 52.2261 192.158C53.2437 191.412 54.1585 190.674 54.9478 190H71.5H89.5001H119.5H149.5H179.5H209.149L422.299 204.975Z" stroke="white" stroke-width="20" />
        <path class="bat-path" d="M49.2693 188.126C50.8282 186.983 52.1243 185.856 53.046 185H71.5H89.5001H119.5H149.5H179.5H209.325L422.65 199.988L422.825 200H423H788C793.459 200 804.87 197.721 815.036 190.44C825.492 182.951 834.5 170.237 834.5 150C834.5 129.889 826.102 117.153 815.839 109.598C805.847 102.243 794.388 100 788 100C782.491 100 691.228 100.25 601.361 100.5C556.424 100.625 511.83 100.75 478.47 100.844L438.218 100.957L426.964 100.989L424.002 100.997L423.243 100.999L423.05 101L423.002 101L422.99 101C422.987 101 422.986 101 423 106L422.986 101L422.829 101L422.673 101.011L209.336 115H179.5H149.5H119.5H89.5001H71.5H53.0941C52.1786 114.12 50.8957 112.963 49.3547 111.782C46.3488 109.477 41.6109 106.488 36.3326 106.136C33.5417 105.95 30.5844 106.504 27.8169 108.256C25.0932 109.981 22.9027 112.645 21.2008 116.106C17.8723 122.874 16 133.531 16 149.5C16 165.479 17.8752 176.178 21.1867 183.022C22.877 186.515 25.0415 189.211 27.7187 190.996C30.4401 192.81 33.3684 193.465 36.1666 193.372C41.4707 193.195 46.2433 190.345 49.2693 188.126Z" fill="#F2AB27" stroke="#0A2140" stroke-width="10" />
        <path d="M209.5 120L179.5 150L144 185.5M209.5 150L174 185.5M184.5 115L149.5 150L114 185.5M154.5 115L84.0001 185.5M124.5 115L71.5 168M93.5 115L71.5 137" stroke="#A67E33" stroke-width="10" />
        <path d="M21 149.5C21 86.5 51 120 51 120C58.5865 144.583 58.7331 157.743 51 180C51 180 21 212.5 21 149.5Z" stroke="#0A2140" stroke-width="10" />
        <path d="M209.5 150V115H71.5V137V168V184.5H209.5V150Z" stroke="#0A2140" stroke-width="10" />
        <path d="M237.25 133.008C235.046 133.146 233.37 135.045 233.508 137.249C233.646 139.454 235.545 141.13 237.75 140.992L237.25 133.008ZM397.75 130.992C399.954 130.854 401.63 128.955 401.492 126.75C401.354 124.546 399.455 122.87 397.25 123.008L397.75 130.992ZM447.5 123C445.291 123 443.5 124.791 443.5 127C443.5 129.209 445.291 131 447.5 131V123ZM580 131C582.209 131 584 129.209 584 127C584 124.791 582.209 123 580 123V131ZM671.5 123C669.291 123 667.5 124.791 667.5 127C667.5 129.209 669.291 131 671.5 131V123ZM769 127L771.71 124.058C770.971 123.378 770.004 123 769 123V127ZM785.29 147.442C786.915 148.939 789.446 148.835 790.942 147.21C792.439 145.585 792.335 143.054 790.71 141.558L785.29 147.442ZM237.75 140.992L397.75 130.992L397.25 123.008L237.25 133.008L237.75 140.992ZM447.5 131H580V123H447.5V131ZM671.5 131H769V123H671.5V131ZM766.29 129.942L785.29 147.442L790.71 141.558L771.71 124.058L766.29 129.942Z" fill="#A67E33" />
        <path d="M780.5 185.5C780.5 185.5 816 184.25 816 146" stroke="#A67E33" stroke-width="10" />
      </g>
      <defs>
        <clipPath id="clip0_1_2">
          <rect width="850" height="300" fill="white" />
        </clipPath>
      </defs>
    </svg>
  </div>

  <div class="footer-text">
    <h3>More from the &quot;Oh that&apos;s a baseball!&quot; network:</h3>
    <div class="links-grid">
      <a href="#">Today&apos;s Scores</a>
      <a href="#">Fantasy Team Selection</a>
      <a href="#">Super Stats</a>
      <a href="#">Our Sponsors</a>
      <a href="#">FAQ</a>
      <a href="#">America&apos;s Favorite Passtime?</a>
      <a href="#">Baseball Card Listings</a>
      <a href="#">Top Stadium Food Hacks</a>
      <a href="#">Mystery Link</a>
    </div>

    <small>Just to be super clear, none of this is real.</small>
  </div>
</div>
              
            
!

CSS

              
                :root {
  --theme1: #e02726;
  --theme2: #0a2140;
  --theme3: #f2ab27;
  --theme4: #a67e33;
  --theme5: #bababa;
  --text: #ffffff;
}

h1 {
  color: var(--theme2);
  font-family: "Graduate", sans-serif;
  text-align: center;
  font-size: 40px;
  padding-bottom: 10px;
  margin: 10px 0;
}

h2 {
  color: var(--theme3);
  font-family: "Big Shoulders Inline Text", sans-serif;
  font-weight: 900;
  font-size: 70px;
  margin: 0 8px;
}

h3 {
  font-family: "Playball", cursive;
}

span {
  display: block;
}

body {
  padding: 0;
  margin: 0;
  overflow-x: hidden;
  height: 2570px;
  overscroll-behavior-y: none;
}

.network-banner {
  background-color: var(--theme3);
  display: block;
  min-height: 30px;
  overflow: auto;
}

.network-banner p {
  color: var(--theme2);
  margin: auto 0;
  padding: 8px 16px;
  text-align: center;
  font-family: "Playball", cursive;
}

.title-banner {
  background-color: var(--theme3);
  display: block;
  min-height: 50px;
  overflow: auto;
}

.main-container {
  width: 100%;
  height: 2100px;
  overflow: hidden;
  position: relative;
}

.baseball-container {
  z-index: 20;
  display: block;
  position: absolute;
  background: url();
  width: 20%;
}

.baseball-container:before {
  content: "";
  display: block;
  padding-top: 100%; /* initial ratio of 1:1*/
}

.baseball-texture {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  border-radius: 50%;
  background-image: url("https://assets.codepen.io/713593/baseball_texture.jpg");
  background-size: 100%;
  background-repeat: repeat;
  background-position: 100% 50%;
  margin: 8px;
  -webkit-box-shadow: 5px 5px 15px 5px rgba(0, 0, 0, 0.6);
  box-shadow: 5px 5px 15px 5px rgba(0, 0, 0, 0.6);
}

.section {
  box-sizing: border-box;
  height: 700px;
  width: 100%;
  position: absolute;
  left: 0;
  border-top: 20px solid var(--text);
}

.s1 {
  background-color: var(--theme2);
  top: 0;
}

.s2 {
  background-color: var(--theme1);
  z-index: 10;
  top: 700px;
}

.s3 {
  background-color: var(--theme2);
  z-index: 10;
  top: 1400px;
}

.game-info-container {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 20%;
}

.game-info {
  text-align: center;
}

.game-info span {
  color: var(--theme5);
  font-family: "Big Shoulders Inline Text", sans-serif;
  font-weight: 300;
  font-size: 20px;
}

#gi1 {
  align-self: flex-start;
}

#gi2 {
  align-self: flex-end;
}

#gi3 {
  align-self: flex-start;
}

svg {
  box-sizing: border-box;
}

.footer-graphics {
  position: absolute;
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  box-sizing: border-box;
  border-top: 20px solid var(--text);
}

.footer-text {
  position: relative;
  display: block;
  padding-top: 20%;
  padding-right: 20px;
  padding-left: 20px;
}

.bat {
  box-sizing: border-box;
  position: relative;
  transform-origin: center left;
  width: 100%;
  z-index: 20;
  overflow: hidden;
  padding: 0 20px;
  margin: 0;
}

.footer {
  box-sizing: border-box;
  text-align: center;
  position: relative;
  min-height: 600px;
  width: 100%;
  background-color: var(--theme3);
}

.links-grid {
  margin: 0 auto;
  display: flex;
  justify-content: center;
  align-content: center;
  flex-grow: 2;
  flex-wrap: wrap;
  width: 100%;
  margin-bottom: 50px;
}

.links-grid a {
  color: var(--theme2);
  font-family: "Big Shoulders Inline Text", sans-serif;
  font-weight: 300;
  font-size: 20px;
  padding: 10px;
  width: 30%;
}

small {
  font-family: "Big Shoulders Inline Text", sans-serif;
  color: var(--theme2);
  margin-bottom: 20px;
}

              
            
!

JS

              
                // Relative to top left (0, 0)
const baseball = {
  p0: { x: 0.65, y: 0 },
  p1: { x: -0.4, y: 0.4 },
  p2: { x: 0.65, y: 1 }
};
let _width, _height, _scrollHeight, _ballheight, _ballwidth;
let _scrollPercent = 0;
let _textureYOffset = 50;
const _mainHeight = 2100;
const safetyOverlap = 10;
const baseballElem = document.getElementsByClassName("baseball-container")[0];
const textureElem = document.getElementsByClassName("baseball-texture")[0];
const batElem = document.getElementsByClassName("bat")[0];
const batOutlineElem = document.getElementsByClassName("bat-path")[0];
const impactElem = document.getElementsByClassName("impact")[0];

function threePointBezier(t, p0, p1, p2) {
  // Individual components of equations
  const comp1 = (coord) => Math.pow(1 - t, 2) * coord;
  const comp2 = (coord) => 2 * (1 - t) * t * coord;
  const comp3 = (coord) => Math.pow(t, 2) * coord;

  const x = comp1(p0.x) + comp2(p1.x) + comp3(p2.x);
  const y = comp1(p0.y) + comp2(p1.y) + comp3(p2.y);

  return { x, y };
}

// Not actually using right now
function linearInterpolation(x, y, a) {
  return x * (1 - a) + y * a;
}

// Clamps numbers between a max and min
function clamp(num, min, max) {
  return Math.min(Math.max(num, min), max);
}

// Sets the position of the baseball relative to the scroll
// Also sets the background position to give the illusion of rotating
function updateBaseballPosition() {
  // Fudging the numbers quite a bit here
  let t = clamp(_scrollPercent, 0, 1);
  const yMax =
    _mainHeight -
    _ballheight -
    batOutlineElem.getBBox().height / 4 +
    safetyOverlap;
  const pos = threePointBezier(t, baseball.p0, baseball.p1, baseball.p2);
  const x = clamp(pos.x * _width, 0, _width - _ballwidth - _width / 10);
  const y = clamp(pos.y * _mainHeight, 20, yMax);
  baseballElem.style.transform = `translate(${x}px, ${y}px)`;
  textureElem.style["background-position"] = `0px ${
    _textureYOffset - t * 200
  }%`;
}

// Sets the styling for the swing and appearance of impact shape
// again based on scroll position
function updateBatStyle() {
  let t = clamp(_scrollPercent, 0, 1);
  if (t >= 0.75) {
    let degrees = 90 * ((1 - t) * 4);
    batElem.style.transform = `rotate(${degrees}deg) translateY(-50%)`;
  } else {
    batElem.style.transform = `rotate(90deg) translateY(-50%)`;
    impactElem.style.opacity = 0;
  }

  if (t === 1) {
    impactElem.style.opacity = 1;
  } else {
    impactElem.style.opacity = 0;
  }
}

// Callback function that gathers up the measurements we need on resize
function resize() {
  _width = window.innerWidth;
  _height = window.innerHeight;
  _ballwidth = baseballElem.offsetWidth;
  _ballheight = baseballElem.offsetHeight;
  _scrollHeight = _mainHeight - _height + _ballheight;
}

// Callback for request animation frame, should really be prefixed
function animationLoop() {
  _scrollOffset = (window.pageYOffset || window.scrollTop) - 100;
  _scrollPercent = _scrollOffset / _scrollHeight || 0;
  updateBaseballPosition();
  updateBatStyle();
  window.requestAnimationFrame(animationLoop);
}

// Run it
resize();
animationLoop();
window.addEventListener("resize", resize);

              
            
!
999px

Console