Skip to content

Instantly share code, notes, and snippets.

@grancalavera
Created March 3, 2013 18:39
Show Gist options
  • Save grancalavera/5077536 to your computer and use it in GitHub Desktop.
Save grancalavera/5077536 to your computer and use it in GitHub Desktop.
A CodePen by Leon Coto. Second Cube - Infinite sequences The faces of the cube are represented by an infinite object sequence, which contains five diferent objects: floor left back right front Each one of these objects sets its own state, and has the ability to return the next object in the sequence. The relevant difference in each object's stat…
<header>
<h1>Second Cube</h1>
<p>An experiment on infinite sequences and CSS animations.</p>
<p>Based on <a href="http://ffffound.com/image/15cca3c0766a634da538fb4bc8b23e2f5a4fe8a7">this image</a> from ffffound.</p>
</header>
<div id="viewport">
<div id="tower">
<div id="cubes"></div>
</div>
</div>
<script type="text/template" id="face">
<svg
x="0px" y="0px"
width="<%= size %>px"
height="<%= size %>px"
viewBox="0 0 <%= size %> <%= size %>"
class="face <%= position %>"
style="bottom: <%= bottom %>px;"
id="<%= id %>"
>
<g class="background">
<rect width="<%= size %>" height="<%= size %>"/>
</g>
<g class="corners">
<g>
<polygon points="<%= points.tr %>"/>
<polygon class="tl" points="<%= points.tl %>"/>
<polygon points="<%= points.bl %>"/>
<polygon points="<%= points.br %>"/>
</g>
</g>
<g class="cross">
<polygon points="<%= points.cross %>"/>
</g>
</svg>
</script>
$(function() {
//--------------------------------------------------------------------------
//
// Framework
//
//--------------------------------------------------------------------------
var points = {
tr: [[0.83, 0], [0.83,0.01], [0.99,0.01], [0.99,0.17], [1,0.17], [1, 0]],
tl: [[0.01, 0.01], [0.17,0.01], [0.17,0], [0,0], [0,0.17], [0.01, 0.17]],
bl: [[0.01, 0.99], [0.01,0.83], [0,0.83], [0,1], [0.17,1], [0.17, 0.99]],
br: [[0.99, 0.99], [0.83,0.99], [0.83,1], [1,1], [1,0.83], [0.99, 0.83]],
cross: [
[0.67, 0.50],
[0.50, 0.50],
[0.50, 0.33],
[0.49, 0.33],
[0.49, 0.50],
[0.33, 0.50],
[0.33, 0.51],
[0.49, 0.51],
[0.49, 0.67],
[0.50, 0.67],
[0.50, 0.51],
[0.67, 0.51]
]
};
var scalePoint = function (point, scale) {
return _.map(point, function (value) {
return value * scale;
});
};
var makeContext = function (size) {
size = parseFloat(size);
size = _.isNaN(size) ? 100 : size;
var context = {};
context.size = size;
context.points = _.reduce(points, function (scaledPoints, points, property) {
scaledPoints[property] = _.map(points, function (point) {
return scalePoint(point, size);
});
return scaledPoints;
}, {});
return context;
};
var faceMaker = function (position, next) {
return function (template, context, level) {
context = _.extend({}, context, {position: position});
var face = {
};
face.next = function (level) {
return next(template, context, level);
};
face.render = function () {
context.bottom = context.size * level;
context.id = face.id();
return template(context);
};
face.id = function () {
return context.position + level;
};
return face;
};
};
var floor = faceMaker('floor', function (t, c, l) { return left(t, c, l) });
var left = faceMaker('left', function (t, c, l) { return back(t, c, l) });
var back = faceMaker('back', function (t, c, l) { return right(t, c, l) });
var right = faceMaker('right', function (t, c, l) { return front(t, c, l) });
var front = faceMaker('front', function (t, c, l) { return floor(t, c, l) });
//--------------------------------------------------------------------------
//
// App
//
//--------------------------------------------------------------------------
var tmpl = _.template($('#face').html()),
$tower = $('#tower'),
$cubes = $('#cubes'),
size = 200,
ctx = makeContext(size),
limit = 40,
count = 0,
level = 0,
levels = [[]],
face = floor(tmpl, ctx, 0)
maxLevels = 4;
var moveTower = function () {
var distance = size / 5;
var css = 'translateY(' + (distance * count) + 'px)';
$tower.css('transform', css);
};
var cleanupOldLevels = function () {
if (levels.length > maxLevels) {
var first = levels.shift().join(',');
$(first).remove();
};
};
var updateLevels = function () {
var l = Math.floor(count / 5);
if (l !== level) {
level = l;
levels.push([]);
cleanupOldLevels();
};
};
var appendFace = function () {
$cubes.append(face.render());
levels[levels.length - 1].push('#' + face.id());
count ++;
updateLevels();
moveTower();
face = face.next(level);
};
$cubes.bind('webkitAnimationEnd animationend', function () {
appendFace();
});
appendFace();
});
body {
background-color: black;
color: #cccccc;
}
a {
color:#333333;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
header {
margin: 30px;
position: relative;
z-index: 100;
max-width: 270px;
}
@media (max-width: 570px) {
header {
margin: 15px;
max-width: 160px;
}
#cubes {
transform: translate3d(0, 0, -500px) rotateY(45deg);
}
}
// Configuration
@faceColor: black;
@lineColor: white;
@size: 200px;
@halfSize: @size / 2;
@perspective: 500px;
@duration: 0.5s;
@opacity: 0.7;
// Utils
.hCenter (@theWidth) {
left: 50%;
margin-left: -@theWidth / 2;
}
.animation-defaults {
animation-duration: @duration;
animation-fill-mode: forwards;
animation-timing-function: linear;
}
// Structure
#viewport {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
perspective: @perspective;
overflow: hidden;
}
#tower {
width: 100%;
height: 100%;
top: 0;
left: 0;
transition: transform @duration * 5 linear;
transform-style: preserve-3d;
}
#cubes {
transform-style: preserve-3d;
width: 100%;
height: 100%;
top: 0;
left: 0;
perspective-origin:50% 100%;
transform: translate3d(0, -@halfSize, -300px) rotateY(45deg);
}
.face {
position:absolute;
.animation-defaults;
bottom: 0;
.hCenter(@size);
.background rect {
fill-opacity: @opacity;
fill:@faceColor;
}
.corners polygon, .cross polygon {
fill:@lineColor;
}
}
// Animations
.from(floor) {
transform: translateY(@size) translateZ(@halfSize);
}
.to(floor) {
transform: translateY(@size) translateZ(@halfSize) rotateX(-90deg);
}
.from(left) {
transform: translateX(-@halfSize) rotateY(-90deg) rotateX(90deg);
}
.to(left) {
transform: translateX(-@halfSize) rotateY(-90deg) rotateX(0deg);
}
.from(back) {
transform: translateX(-@size) translateZ(-@halfSize) rotateY(90deg);
}
.to(back) {
transform: translateX(-@size) translateZ(-@halfSize) rotateY(180deg);
}
.from(right) {
transform: translateZ(-@halfSize);
}
.to(right) {
transform: translateZ(-@halfSize) rotateY(90deg);
}
.from(front) {
transform: translateZ(@halfSize) rotateY(-90deg);
}
.to(front) {
transform: translateZ(@halfSize) rotateY(0deg);
}
.face {
&.floor {
.from(floor);
transform-origin: 0 0;
animation-name: floor-animation;
}
&.left {
.from(left);
transform-origin: @halfSize @size;
animation-name: left-animation;
}
&.back {
.from(back);
transform-origin: @size 0;
animation-name: back-animation;
}
&.right {
.from(right);
transform-origin: @size 0;
animation-name: right-animation;
}
&.front {
.from(front);
transform-origin: @size 0;
animation-name: front-animation;
}
}
// Keyframes
.keyframes (@face) {
from {
.from(@face);
}
to {
.to(@face);
}
}
@keyframes floor-animation {
.keyframes (floor);
}
@keyframes left-animation {
.keyframes (left);
}
@keyframes back-animation {
.keyframes (back);
}
@keyframes right-animation {
.keyframes (right);
}
@keyframes front-animation {
.keyframes (front);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment