JSFiddle - React, Tailwind, and code Playground
by philippkuehn
HTML
<div class="viewport">
<div class="wall-wrapper">
<div class="wall"></div>
</div>
</div>
CSS
* {
margin: 0;
padding: 0;
border: none;
-webkit-box-sizing : border-box;
-moz-box-sizing : border-box;
box-sizing : border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-text-size-adjust: none;
-webkit-touch-callout: none;
outline: none;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
html,
body {
width: 100%;
height: 100%;
}
body {
}
.viewport{
position: relative;
width: 100%;
height: 100%;
overflow: scroll;
background: #090909;
}
.wall-wrapper {
position: relative;
}
.wall-wrapper:after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 100px solid #090909;
pointer-events: none;
}
.wall {
position: relative;
}
.chunk {
position: absolute;
visibility: hidden;
opacity: 0;
-webkit-transition: opacity 1s ease-out, visibility 1s ease-out;
}
.chunk.is--loaded {
visibility: visible;
opacity: 1;
}
.star {
position: absolute;
background: #fff;
-webkit-border-radius: 50%;
-webkit-box-shadow: 0 0 4px #fff;
display: none;
}
.star__size--1 {
width: 1px;
height: 1px;
}
.star__size--2 {
width: 2px;
height: 2px;
}
.star__size--3 {
width: 3px;
height: 3px;
-webkit-box-shadow: 0 0 30px 3px rgba(255,255,255,0.4), 0 0 10px 1px rgba(255,255,255,0.4);
}
.star__opacity--1 {
opacity: 1;
}
.star__opacity--2 {
opacity: 0.5;
}
.star__opacity--3 {
opacity: 0.2;
}
JavaScript
jQuery(document).ready(function($) {
var $doc = $(document),
$win = $(window),
$viewport = $('.viewport'),
$wallWrapper = $('.wall-wrapper'),
$wall = $('.wall'),
chunkWidth = 500;
var universe = {
init: function($element) {
$viewport.on('scroll', universe.helper.debounce(function() {
var needToGenerate = [];
if ($viewport.scrollTop() <= 100) {
needToGenerate.push('top');
}
if ($viewport.scrollTop() + $viewport.height() > $wallWrapper.height() - 100) {
needToGenerate.push('bottom');
}
if ($viewport.scrollLeft() <= 100) {
needToGenerate.push('left');
}
if ($viewport.scrollLeft() + $viewport.width() > $wallWrapper.width() - 100) {
needToGenerate.push('right');
}
universe.generate.chunks(needToGenerate);
universe.showAroundCenter(universe.getPosition());
universe.generate.stars();
}, 100));
universe.generate.chunks(false, true);
},
getPosition: function() {
var centerPosX = $viewport.scrollLeft() + ($viewport.width() / 2),
centerPosY = $viewport.scrollTop() + ($viewport.height() / 2),
overX = parseFloat($wall.attr('data-from-x')) + Math.floor(centerPosX / chunkWidth),
overY = parseFloat($wall.attr('data-from-y')) + Math.floor(centerPosY / chunkWidth);
return [overX, overY];
},
showAroundCenter: function(center) {
var newFromX = center[0] - 1,
newToX = center[0] + 1,
newFromY = center[1] - 1,
newToY = center[1] + 1,
coordinates = universe.helper.getCoordinatesBetween(newFromX, newToX, newFromY, newToY);
$('.chunk').removeClass('is--in-viewport');
for (i = 0, l = coordinates.length; i < l; i++) {
$('.chunk[data-x="' + coordinates[i]['x'] + '"][data-y="' + coordinates[i]['y'] + '"]').addClass('is--in-viewport');
}
$('.chunk').not('.is--in-viewport').empty().removeClass('is--loaded');
},
generate: {
chunks:...