cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

Quick-add: + add another resource

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.

Quick-add: + add another resource

Code Indentation

     

Save Automatically?

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.

            
              <div id="container">  
  
  <div id="maskSide"></div>
  <div id="maskBottom"></div>

  <div id="viewport">
    <div id="background" class="resize"></div>
    <div id="hills" class="scrolling resize"></div>
    <div id="town" class="scrolling resize">
      <canvas id="didyouhearthat"></canvas>
    </div>
    <div id="utilities" class="scrolling resize"><a href="https://tinymediaempire.tumblr.com/" target="_blank">"i didn't hear you arrive, i didn't hear you go" &copy; Daniel Danger</a></div>
    <div id="thevisitorPanel" class="scrolling resize">
          <div id="thevisitor" class="giant burp"></div>
    </div>
  </div>
  <div id="scrollHint" class="animate resize">
    <div class="chevron animated neon3"></div>
    <div class="line animated neon2"></div>
    <div class="line animated neon1"></div>
    <div class="title1">i didn't hear you arrive,</div>
    <div class="title2">i didn't hear you go.</div>
  </div>

</div>

            
          
!
            
              @import "compass/css3";

/***** MIXINS *****/
@mixin bgSize() {
  -webkit-background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  background-size: cover;
}

$easeInOutSine: all 1s cubic-bezier(0.39, 0.575, 0.565, 1);

// border box reset on all objects
*, *:before, *:after {
  //reset
  padding: 0;
  margin: 0;
  @include box-sizing(border-box);
}

body {
  font-family: 'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace;
}

#container {
  // height: 1200vh; -- can't use due to iOS bug
  height: 2500px;
  background-color: silver;
  position: relative;
  overflow: hidden;
  top: 0;
  left: 0;
}

#maskSide {
  position: fixed;
  top: 0;
  bottom: 0;
  right: 0;
  z-index: 1000;
  
  background-color: black;
}

#maskBottom {
  position: fixed;
  bottom: 0;
  right: 0;
  left: 0;
  z-index: 1000;
  
  background-color: black;
}

#viewport {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;  
  
  // the secret sauce to using z-index for depth!
  @include perspective(10px);
  @include perspective-origin(10% 25%)
  //@include transform-style(flat);
}

#background {
  // moon and red sky
  position: absolute;
  background:url(https://s3-us-west-2.amazonaws.com/evildonald.codepen.io/iDidntHearYouArrive/background.jpg) no-repeat;
  @include bgSize();
}

.scrolling {
  position: absolute;  
  @include transition($easeInOutSine);  
  @include opacity(0);
  @include translate3d(0,0,0);
}

#hills {
  background: url(https://s3-us-west-2.amazonaws.com/evildonald.codepen.io/iDidntHearYouArrive/hills.gif) no-repeat;
  @include bgSize();
  z-index: 10;
}
#town {
  // houses
  background: url(https://s3-us-west-2.amazonaws.com/evildonald.codepen.io/iDidntHearYouArrive/town.gif) no-repeat;
  @include bgSize();
  z-index: 20;
  
  #didyouhearthat {
    position: absolute;

    // broken on some browsers
    //height: 100%;
    //width: 100%;
  }

}
#utilities {
  background: url(https://s3-us-west-2.amazonaws.com/evildonald.codepen.io/iDidntHearYouArrive/lightpost.png) no-repeat;
  @include bgSize();
  z-index: 30;
  
  a {
    // Daniel Danger link
    color: #777;
    background-color: black; 
    font-size: 1em;
    padding: 2px;
    
    position: absolute;
    bottom: 0;
    right: 0;      
  }
}

#thevisitorPanel {
  z-index: 15;
  #thevisitor {
  background: url(https://s3-us-west-2.amazonaws.com/evildonald.codepen.io/iDidntHearYouArrive/giant.png) no-repeat;
    height: 100%;
    @include bgSize();
  }
}
/**** scroll hint ****/
$scrollHint-color: #F45300;

#scrollHint {
  position: relative;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2000;
  
  .title1, .title2 {
    text-align: center;
    font-size: 1em;
    margin: 0 auto;
    position: relative;    
  }
}

.chevron {
  position: relative;
  margin: 0 auto 1em auto;
  width: 1em; 
  height: 4em;
  border-radius: .5em/.25em;
}
.chevron:before, .chevron:after {
  position: absolute;
  background: $scrollHint-color;
  width: inherit; height: inherit;
  border-radius: inherit;
  content: '';
}
.chevron:before {
  @include transform(rotate(60deg) translateY(1.6em));
}
.chevron:after {
  @include transform(rotate(-60deg) translateY(1.6em));
}

.line {
  position: relative;
  margin: 1em auto;
  width: 6em; 
  height: 1em;
  border-radius: .5em/.25em;
  background: $scrollHint-color;
}

/************ ANIMATION ***************/
.animated { 
  @include transition(opacity .2s);
  @include animation-duration(2s);
  @include animation-fill-mode(both);
  @include animation-timing-function(ease-in); 
  @include animation-iteration-count(infinite); 
} 

@include keyframes(neon1) {
  0%, 15% { opacity: 0; }
  20% { opacity: 1; } 
  80% { opacity: 1; } 
  100% { opacity: 0; }
}
.neon1 {
    @include animation-name(neon1);
}
@include keyframes(neon2) {
  0% { opacity: 0; }
  35% { opacity: 0; }
  40% { opacity: 1; } 
  80% { opacity: 1; } 
  100% { opacity: 0; }
}
.neon2 {
    @include animation-name(neon2);
}
@include keyframes(neon3) {
  0% { opacity: 0; }
  55% { opacity: 0; } 
  60% { opacity: 1; } 
  80% { opacity: 1; } 
  100% { opacity: 0; }
}
.neon3 {
    @include animation-name(neon3);
}

/************ GIANT ***************/
.giant { 
  @include transition(all .5s);
  @include animation-duration(15s);
  @include animation-fill-mode(both);
  @include animation-timing-function(ease-in-out); 
  @include animation-iteration-count(infinite); 
  @include animation-name(burpAndSway);
} 

@include keyframes(burpAndSway) {
  10%, 13% { @include translateX(2px); }
  11%, 14% { @include translateX(-2px); } 
  9%, 13% { @include translateY(1px); }
  12%, 14% { @include translateY(-1px); } 
  // sway
  0%, 100% { @include skewX(0deg); }
  40% { @include skewX(-1.5deg); }
  75% { @include skewX(3deg); }  
  90% { @include skewX(-1.5deg); }  
}

/**** title text ***/
.title1, .title2 {
  @include transition(width .5s);
  @include animation-duration(30s);
  @include animation-fill-mode(both);
  @include animation-iteration-count(infinite); 
  overflow: hidden;
  white-space: nowrap;
  box-shadow: inset -250px 0 50px 10px transparent;
}

.title1 {
    @include animation-name(titleFade1);
}
.title2 {
    @include animation-name(titleFade2);
}

@include keyframes(titleFade1) {
    0% {width:0%;}
    50% {width:100%;}
    99% {width:100%;}
    100% {width:0%;}
}
@include keyframes(titleFade2) {
    0%, 15% {width:0%;}
    65% {width:100%;}
    99% {width:100%;}
    100% {width:0%;}
}

            
          
!
            
              /* TODO
*/
/******* Asset Controls ***********/
function init() {
  
  window.data = {};
  buildAssets();

  window.addEventListener("orientationchange", fixAspectRatio);
  window.addEventListener("scroll", listenScroll);
  window.addEventListener("resize", fixAspectRatio);
}

function buildAssets() {
  
  data.container = document.getElementById("container");
  data.maskSide = document.getElementById("maskSide");
  data.maskBottom = document.getElementById("maskBottom");
  data.canvas = document.getElementById("didyouhearthat");
  data.resizeItems = document.getElementsByClassName("resize");
  data.scrollHint = document.getElementById("scrollHint");

  if (data.canvas && data.canvas.getContext) {
	  data.canvasContext = data.canvas.getContext("2d");
  }

  
  data.panels = {}
  data.panels.hills = document.getElementById("hills");
  data.panels.town = document.getElementById("town");
  data.panels.utilities = document.getElementById("utilities");
  data.panels.thevisitorPanel = document.getElementById("thevisitorPanel");

  data.lastScrollPos = -100; // always render first scroll
  
  // controls the axis and direction of scroll
  data.scale = {
    "hills":{"y":.5, "z":2}, 
    "town":{"y":.8, "z": 10}, 
    "utilities":{"y":2.75, "z":20}, 
    "thevisitorPanel":{"x":3.5}
  };

  // position of the window shutters
  data.houses = {
    "house1" : {"windows" : [
      [10.5,57.3,1,3.6],
      [13,57.3,1.2,3.8],
      [15.3,57.3,1.1,3.7],
      [21.25,58.4,1,2.2]
    ]},
    "house2" : {"windows" : [
      [8.1,49.1,1.5, 3.7],
      [11.25,48.85,1.6,3.5],
      [14.2,48.85,1.75,2.2],
      [18.75,50.20,1.3,3.8],
      [21.5,50.25,1,4]
    ]},
    "house3" : {"windows" : [
      [89.8,60.8,2.1,3.5],
      [83.9,59.8,2,6],
      [80.75,59.65,1.1,5.5]
    ]}
  };
    
  listenScroll(); // fire one time
  fixAspectRatio(); // fire one time
  canvas.didYouHearThat(); // canvas window sprites
  
}

// much faster than jQuery scrollTop
function scrollTop() {
  var value = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
  return value;
}

// when we scroll, see how far we've moved as a % and apply that to the image panels multipied by their scale
function listenScroll(evt) {
  var scrollPos = scrollTop();
  var endScrollPos = (data.container.offsetHeight - window.innerHeight) - scrollPos;
  var diff = data.lastScrollPos - scrollPos;
  var sensitivity = 125;
  if (diff > sensitivity || diff < (-1 * sensitivity) || scrollPos < sensitivity || endScrollPos < sensitivity) {
    data.lastScrollPos = scrollPos;
    var percent = 1 - scrollPos / (data.container.offsetHeight - window.innerHeight);
        
    setPanelOpacity("hills", setPanelPosition("hills", percent));
    setPanelOpacity("town", setPanelPosition("town", percent));
    setPanelOpacity("utilities", setPanelPosition("utilities", percent));
    setPanelOpacity("thevisitorPanel", setPanelPosition("thevisitorPanel", percent));
  }
  
}

function setPanelPosition(id, percent) {
  // needed to return to let other functions know where the control will be, post-animation
  var newPosition = {"percent":percent};
  
  if (typeof data.scale[id] !== "undefined") {
    
    var translateX = 0, translateY = 0, translateZ = 0;
    
    // move up/down
    if (typeof data.scale[id].y !== "undefined") {
      newPosition.y = window.innerHeight * data.scale[id].y * Math.easeHelper(percent);
      translateY =  newPosition.y;
    }

    // move left/right
    if (typeof data.scale[id].x !== "undefined") {
      newPosition.x = (window.innerWidth * data.scale[id].x * Math.easeHelper(percent));
      //newPosition.xOffset = data.maskSide.offsetWidth;
      translateX = newPosition.x;
    }
    
        // move int/out
    if (typeof data.scale[id].z !== "undefined") {
      newPosition.z = data.scale[id].z * Math.easeHelper(percent);
      translateZ = newPosition.z;
    }

    data.panels[id].style["-moz-transform"] = "translate3d(" + translateX + "px, " + translateY + "px, " + translateZ + "px)";
    data.panels[id].style["-webkit-transform"] = "translate3d(" + translateX + "px, " + translateY + "px, " + translateZ + "px)";
    data.panels[id].style["transform"] = "translate3d(" + translateX + "px, " + translateY + "px, " + translateZ + "px)";

  }
	console.log(id, newPosition);
  return newPosition;
}

// calculates the perentage of the item visible in the viewport
// percentage is offset by an easing function to make it less linear
function setPanelOpacity(id, newPosition) {
  
  var percent;
  if (typeof newPosition.y !== "undefined") {
    if (newPosition.y < 0) {
      percent = 1 + newPosition.y / (window.innerHeight);
    }
    else {
      percent = 1 - newPosition.y / (window.innerHeight);
    }
    opacityHelper(data.panels[id], Math.easeHelper(percent));
  } 
  else if (typeof newPosition.x !== "undefined") {
    if (newPosition.x < 0) {
      percent = 1 + newPosition.x / (window.innerWidth);
    }
    else {
      percent = 1 - newPosition.x / (window.innerWidth);
    }
    opacityHelper(data.panels[id], Math.easeHelper(percent));
  }
  else {
    opacityHelper(data.panels[id], Math.easeHelper(1 - newPosition.percent));
  }
}

function opacityHelper(obj, value) {
  obj.style.filter = "progid:DXImageTransform.Microsoft.Alpha(Opacity=" + (value * 100) + ")";
  obj.style.opacity = value;
}

// when the screen resizes, for the aspect ratio or else it gets truncated and looks dumb!
// image aspect ratio is 3:2 (width:height)
function fixAspectRatio() {

  var h = window.innerHeight, w = window.innerWidth;
  if (h > w) {
    data.assetWidth = w;
    data.assetHeight = window.innerWidth / 1.5;
  }
  else {
    data.assetHeight = h;
    data.assetWidth = data.assetHeight * 1.5;
  }
  for (var index = 0; index < data.resizeItems.length; index++) {
    data.resizeItems[index].style.height = data.assetHeight + "px";
    data.resizeItems[index].style.width = data.assetWidth + "px";
  }
  
  //apply maskSide to hide sieways animations
  data.maskSide.style.left = data.assetWidth + "px";
  data.maskBottom.style.top = data.assetHeight + "px";
  
  // resize canvas with attributes, because it currently warps if you use css width and height
  // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_usage#The_<canvas>_element
  if (data.canvas) {
    // resize of canvas that uses attribute rather than css for dimensions will wipe it! FFS.
    data.canvas.setAttribute("width", data.assetWidth + "px");
		data.canvas.setAttribute("height", data.assetHeight + "px");
    
    canvas.resetLights();
  }
  
  if (data.scrollHint) {
    data.scrollHint.style["padding-top"] = (data.assetHeight * 0.5) + "px";
  }
}

/********* Canvas object *********/
var canvas = {
  didYouHearThat: function() {
    setTimeout(function() {
      canvas.drawHouse("house1");
      setInterval(function() {
        canvas.drawHouse("house1");
      }, 10.1 * 1000);
    }, 5 * 1000);

    setTimeout(function() {
      canvas.drawHouse("house2");
      setInterval(function() {
        canvas.drawHouse("house2");
      }, 9.2 * 1000);
    }, 1 * 1000);

    setTimeout(function() {
      canvas.drawHouse("house3");
      setInterval(function() {
        canvas.drawHouse("house3");
      }, 11.3 * 1000);
    }, 3 * 1000);

  },

  // draws the house lights
  drawHouse : function(houseName, lightOverride) {

    var windows = data.houses[houseName].windows;
    var lights = lightOverride || data.houses[houseName].lights || "fill";

    for (var index = 0; index < windows.length; index++) {
      var item = windows[index];
      canvas.drawCanvas(item[0], item[1], item[2], item[3], lights);
    }
    if (lights === "clear") {
      data.houses[houseName].lights = "fill";
    }
    else {
      data.houses[houseName].lights = "clear";
    }
  },

  // canvas helper
  drawCanvas : function(left, top, width, height, _action, _color) {

    if (data.canvasContext) {

      if (_color != null) { 
        data.canvasContext.fillStyle = _color;//"rgb(0,200,200)";
      }

      if (_action === "clear") {
        data.canvasContext.clearRect(
          canvas.percentToWidth(left), 
          canvas.percentToHeight(top), 
          canvas.percentToWidth(width), 
          canvas.percentToHeight(height));
      }
      else {
        data.canvasContext.fillRect(
          canvas.percentToWidth(left), 
          canvas.percentToHeight(top), 
          canvas.percentToWidth(width), 
          canvas.percentToHeight(height));
      }
    }
  },
  
  percentToWidth : function(value) {
    return value / 100 * data.assetWidth;
  },
  
  percentToHeight : function(value) {
    return value / 100 * data.assetHeight;
  },
  
  resetLights : function() {
  	data.houses.house1.lights = "fill";
  	data.houses.house2.lights = "fill";
  	data.houses.house3.lights = "fill";
	}
}


/********* Math Functions *********/
// http://gizma.com/easing/

Math.easeInSine = function (t, b, c, d) {
	return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
};

Math.easeHelper = function (scrollPercentage) {
  // generate range 0 to 1 from percentage (0[t] to 1) scrolled.
  var outputMin = 0, outputMax = 1;
	var timeMax = 1;
	return Math.easeInSine(scrollPercentage, outputMin, outputMax, timeMax);
};

// Document Ready!
document.addEventListener("DOMContentLoaded", init);


            
          
!
999px
Loading ..................

Console