Chrome only !!! a Rubik's Cube made in HTML, JavaScript and CSS.
Drag to play
Now works in Firefox!!!!
A Pen by Gregor Adams on CodePen.
| link(href='http://fonts.googleapis.com/css?family=Lato:300,400' | |
| rel='stylesheet' | |
| type='text/css') | |
| mixin cubePart(x, y, z) | |
| div(class="cube-part-wrapper cube-part-wrapper-#{x}#{y}#{z}" | |
| data-x="#{x}" | |
| data-y="#{y}" | |
| data-z="#{z}") | |
| .axis.axis-part | |
| ul.cube-part | |
| li(class=z>1?"side top white" : "side top") | |
| .sticker | |
| li(class=z<1?"side bottom yellow" : "side bottom") | |
| .sticker | |
| li(class=y>1?"side right orange" : "side right") | |
| .sticker | |
| li(class=y<1?"side left red" : "side left") | |
| .sticker | |
| li(class=x>1?"side back green" : "side back") | |
| .sticker | |
| li(class=x<1?"side front blue" : "side front") | |
| .sticker | |
| // --- @start control section | |
| .controls | |
| // --- @start button-wrapper | |
| .button-wrapper | |
| div | |
| - each theme in ["flat", "realistic"] | |
| button(type="button" | |
| class=theme==="flat"?"themer selected" : "themer" | |
| data-theme="#{theme}") #{theme} | |
| button(type="button" | |
| class="scrambler") Scramble | |
| h1 RubiCCS cube | |
| h2 drag anywhere to rotate | |
| h2 drag cube to play | |
| h3 The middle slice does not turn, just like a real Rubik's cube | |
| // --- @start canvas | |
| .canvas.theme-flat | |
| .cube-wrapper | |
| .cube | |
| .swiper.top(data-x="y" | |
| data-y="x" | |
| data-control="top") | |
| .swiper.bottom(data-x="y" | |
| data-y="x" | |
| data-control="bottom") | |
| .swiper.left(data-x="y" | |
| data-y="z" | |
| data-control="left") | |
| .swiper.right(data-x="y" | |
| data-y="z" | |
| data-control="right") | |
| .swiper.front(data-x="z" | |
| data-y="x" | |
| data-control="front") | |
| .swiper.back(data-x="z" | |
| data-y="x" | |
| data-control="back") | |
| // --- @start grip | |
| .grip | |
| .axis.axis-grip | |
| // --- @start parts | |
| - for (var x = 0; x < 3; x++) | |
| - for (var y = 0; y < 3; y++) | |
| - for (var z = 0; z < 3; z++) | |
| +cubePart(x, y, z) | |
Chrome only !!! a Rubik's Cube made in HTML, JavaScript and CSS.
Drag to play
Now works in Firefox!!!!
A Pen by Gregor Adams on CodePen.
| /* jshint sub: true */ | |
| (function($, window, document, undefined) { | |
| 'use strict'; | |
| var data = {}; | |
| var allTurns = ['base', 'left', 'right']; | |
| var allAx = ['x', 'y', 'z']; | |
| for (var a = 0; a < allAx.length; a++) { | |
| data[allAx[a]] = {}; | |
| for (var l = 0; l < allTurns.length; l++) { | |
| data[allAx[a]][allTurns[l]] = {}; | |
| } | |
| } | |
| var makeData1 = function(m, n, o, i, dir) { | |
| var v = $.extend(true, [], data[m].base[i]); | |
| var w = $.extend(true, [], data[m].base[i]); | |
| data[m][dir][i] = v.sort(function(a, b) { | |
| if (a[o] > b[o]) { | |
| return 1; | |
| } else if (a[o] < b[o]) { | |
| return -1; | |
| } else { | |
| if (a[n] > b[n]) { | |
| return -1; | |
| } else { | |
| return 1; | |
| } | |
| } | |
| }); | |
| }; | |
| var makeData2 = function(m, n, o, i, dir) { | |
| var v = $.extend(true, [], data[m].base[i]); | |
| var w = $.extend(true, [], data[m].base[i]); | |
| data[m][dir][i] = w.sort(function(a, b) { | |
| if (a[o] > b[o]) { | |
| return -1; | |
| } else if (a[o] < b[o]) { | |
| return 1; | |
| } else { | |
| if (a[n] > b[n]) { | |
| return 1; | |
| } else { | |
| return -1; | |
| } | |
| } | |
| }); | |
| }; | |
| var makeData3 = function(m, n, o, i, dir) { | |
| var v = $.extend(true, [], data[m].base[i]); | |
| var w = $.extend(true, [], data[m].base[i]); | |
| data[m][dir][i] = v.sort(function(a, b) { | |
| if (a[o] > b[o]) { | |
| return 1; | |
| } else if (a[o] < b[o]) { | |
| return -1; | |
| } else { | |
| if (a[n] > b[n]) { | |
| return 1; | |
| } else { | |
| return -1; | |
| } | |
| } | |
| }); | |
| }; | |
| var makeData4 = function(m, n, o, i, dir) { | |
| var v = $.extend(true, [], data[m].base[i]); | |
| var w = $.extend(true, [], data[m].base[i]); | |
| data[m][dir][i] = w.sort(function(a, b) { | |
| if (a[o] > b[o]) { | |
| return -1; | |
| } else if (a[o] < b[o]) { | |
| return 1; | |
| } else { | |
| if (a[n] > b[n]) { | |
| return -1; | |
| } else { | |
| return 1; | |
| } | |
| } | |
| }); | |
| }; | |
| for (var i = 0; i < 3; i++) { | |
| data['x']['base'][i] = [{ | |
| 'x': i, | |
| 'y': 0, | |
| 'z': 0 | |
| }, { | |
| 'x': i, | |
| 'y': 0, | |
| 'z': 1 | |
| }, { | |
| 'x': i, | |
| 'y': 0, | |
| 'z': 2 | |
| }, { | |
| 'x': i, | |
| 'y': 1, | |
| 'z': 0 | |
| }, { | |
| 'x': i, | |
| 'y': 1, | |
| 'z': 1 | |
| }, { | |
| 'x': i, | |
| 'y': 1, | |
| 'z': 2 | |
| }, { | |
| 'x': i, | |
| 'y': 2, | |
| 'z': 0 | |
| }, { | |
| 'x': i, | |
| 'y': 2, | |
| 'z': 1 | |
| }, { | |
| 'x': i, | |
| 'y': 2, | |
| 'z': 2 | |
| }]; | |
| data['y']['base'][i] = [{ | |
| 'x': 0, | |
| 'y': i, | |
| 'z': 0 | |
| }, { | |
| 'x': 0, | |
| 'y': i, | |
| 'z': 1 | |
| }, { | |
| 'x': 0, | |
| 'y': i, | |
| 'z': 2 | |
| }, { | |
| 'x': 1, | |
| 'y': i, | |
| 'z': 0 | |
| }, { | |
| 'x': 1, | |
| 'y': i, | |
| 'z': 1 | |
| }, { | |
| 'x': 1, | |
| 'y': i, | |
| 'z': 2 | |
| }, { | |
| 'x': 2, | |
| 'y': i, | |
| 'z': 0 | |
| }, { | |
| 'x': 2, | |
| 'y': i, | |
| 'z': 1 | |
| }, { | |
| 'x': 2, | |
| 'y': i, | |
| 'z': 2 | |
| }]; | |
| data['z']['base'][i] = [{ | |
| 'x': 0, | |
| 'y': 2, | |
| 'z': i | |
| }, { | |
| 'x': 1, | |
| 'y': 2, | |
| 'z': i | |
| }, { | |
| 'x': 2, | |
| 'y': 2, | |
| 'z': i | |
| }, { | |
| 'x': 0, | |
| 'y': 1, | |
| 'z': i | |
| }, { | |
| 'x': 1, | |
| 'y': 1, | |
| 'z': i | |
| }, { | |
| 'x': 2, | |
| 'y': 1, | |
| 'z': i | |
| }, { | |
| 'x': 0, | |
| 'y': 0, | |
| 'z': i | |
| }, { | |
| 'x': 1, | |
| 'y': 0, | |
| 'z': i | |
| }, { | |
| 'x': 2, | |
| 'y': 0, | |
| 'z': i | |
| }]; | |
| makeData1('x', 'y', 'z', i, 'left'); | |
| makeData2('x', 'y', 'z', i, 'right'); | |
| makeData2('y', 'x', 'z', i, 'left'); | |
| makeData1('y', 'x', 'z', i, 'right'); | |
| makeData3('z', 'y', 'x', i, 'left'); | |
| makeData4('z', 'y', 'x', i, 'right'); | |
| } | |
| var rotate3d = { | |
| 'x': '1,0,0,', | |
| 'y': '0,1,0,', | |
| 'z': '0,0,1,' | |
| }; | |
| var $gripAxis; | |
| var cubeRotationSpeed = 1.5; | |
| var cache = {}; | |
| var canvas = { | |
| 'threshold': 10, | |
| 'block': false, | |
| 'down': false, | |
| 'axis': null, | |
| 'css': '', | |
| 'mouse': { | |
| 'distance': 0, | |
| 'time': 0 | |
| } | |
| }; | |
| var randomNumber = function(min, max) { | |
| return Math.floor(Math.random() * (max - min + 1)) + min; | |
| }; | |
| var classWithPrefix = function(regex) { | |
| return function(index, classes) { | |
| return classes.split(/\s+/).filter(function(el) { | |
| return regex.test(el); | |
| }).join(' '); | |
| }; | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.clearHelpers | |
| * @description | |
| * clear the grip after the rotation | |
| */ | |
| var clearHelpers = function() { | |
| var $gripAxis = $('.grip .axis'); | |
| $gripAxis.css({ | |
| transition: 'none', | |
| transform: '' | |
| }); | |
| setTimeout(function() { | |
| $gripAxis.css({ | |
| transition: '' | |
| }); | |
| }, 0); | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.positionParts | |
| * @description | |
| * puts the cubes in the new position | |
| */ | |
| var positionParts = function(turnAxis, level, direction) { | |
| if (!turnAxis) { | |
| return false; | |
| } | |
| var axis = ['x', 'y', 'z']; | |
| var elements = []; | |
| var oppositeDirection = direction === 'right' ? 'left' : 'right'; | |
| $.each(data[turnAxis]['base'][level], function(i, obj) { | |
| var selector3d = '[data-x="'; | |
| selector3d += obj['x']; | |
| selector3d += '"][data-y="'; | |
| selector3d += obj['y']; | |
| selector3d += '"][data-z="'; | |
| selector3d += obj['z'] + '"]'; | |
| elements.push($(selector3d)); | |
| }); | |
| $.each(elements, function(i, el) { | |
| $.each(axis, function(j, ax) { | |
| $(el).attr('data-' + | |
| ax, data[turnAxis][oppositeDirection][level][i][ax]); | |
| }); | |
| }); | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.performTurn | |
| * @description | |
| * performes the turn. | |
| * allows a callback when the turn is done | |
| */ | |
| var performTurn = function(rotate3d, turnAxis, direction, callback) { | |
| var degree = direction === 'right' ? 90 : -90; | |
| $('.grip').find('.axis-grip:first').css({ | |
| transform: 'rotate3d(' + | |
| rotate3d[turnAxis] + | |
| degree + | |
| 'deg)' | |
| }).one('transitionend', callback); | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.rotateParts | |
| * @description | |
| * rotates the parts | |
| */ | |
| var rotateParts = function(rotate3d, turnAxis, direction) { | |
| $('.grip .cube-part-wrapper').each(function(i, el) { | |
| var degree = direction === 'right' ? 90 : -90; | |
| var css = $(el).find('.axis-part')[0].style.transform; | |
| css = css === 'none' ? '' : css; | |
| css = 'rotate3d(' + | |
| rotate3d[turnAxis] + | |
| degree + | |
| 'deg) ' + | |
| css; | |
| $(el).find('.axis-part').css({ | |
| transform: css | |
| }); | |
| }); | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.attachParts | |
| * @description | |
| * puts the parts back into the cube | |
| */ | |
| var attachParts = function(turnAxis, level) { | |
| $('[data-' + turnAxis + '=' + level + ']') | |
| .appendTo('.cube'); | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.detachParts | |
| * @description | |
| * puts the parts into the grip | |
| */ | |
| var detachParts = function(turnAxis, level) { | |
| $('[data-' + turnAxis + '=' + level + ']') | |
| .appendTo('.grip .axis-grip'); | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.autoTurn | |
| * @description | |
| * automatically turn | |
| */ | |
| var autoTurn = function(turnAxis, level, direction) { | |
| if (!canvas.block) { | |
| canvas.block = true; | |
| turnAxis = turnAxis || 'x'; | |
| level = level || 0; | |
| detachParts(turnAxis, level); | |
| performTurn(rotate3d, turnAxis, direction, function() { | |
| rotateParts(rotate3d, turnAxis, direction); | |
| attachParts(turnAxis, level); | |
| clearHelpers(); | |
| positionParts(turnAxis, level, direction); | |
| window.setTimeout(function() { | |
| canvas.block = false; | |
| }, 2); | |
| }); | |
| } else { | |
| return; | |
| } | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.scrambleCube | |
| * @description | |
| * scramble the cube | |
| */ | |
| var scrambleCube = function(n) { | |
| var axis = ['x', 'y', 'z']; | |
| var direction = ['left', 'right']; | |
| $gripAxis.addClass('fast'); | |
| var duration = $gripAxis.css('transition-duration'); | |
| duration = (parseFloat(duration) + 0.1) * 1000; | |
| var play = setInterval(function() { | |
| var dir = direction[randomNumber(0, 1)]; | |
| var axi = axis[randomNumber(0, 2)]; | |
| var level = randomNumber(0, 2); | |
| dir = cache.dir === dir ? (dir === 'left' ? 'right' : 'left') : dir; | |
| axi = cache.axi === axi ? (axi === 'x' ? 'y' : 'z') : axi; | |
| axi = cache.axi === axi ? (axi === 'z' ? 'x' : 'y') : axi; | |
| axi = cache.axi === axi ? (axi === 'y' ? 'z' : 'x') : axi; | |
| level = level === 1 ? randomNumber(0, 2) : level; | |
| level = level === 1 ? 2 : level; | |
| level = cache.level === level ? (level === 0 ? 2 : 0) : level; | |
| level = cache.level === level ? (level === 2 ? 0 : 2) : level; | |
| cache = { | |
| dir: dir, | |
| axi: axi, | |
| level: level | |
| }; | |
| autoTurn(axi, level, dir); | |
| }, duration); | |
| setTimeout(function() { | |
| $gripAxis.removeClass('fast'); | |
| if (play) { | |
| clearTimeout(play); | |
| } | |
| }, duration * n); | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.releaseSwiper | |
| * @description | |
| * release the Swiper | |
| */ | |
| var releaseSwiper = function(e) { | |
| if (canvas.swiper && canvas.swiper.play) { | |
| canvas.swiper.play = false; | |
| if (!canvas.swiper.move) { | |
| return false; | |
| } | |
| canvas.swiper.move = false; | |
| if (canvas.swiper.degree >= -30 && canvas.swiper.degree <= 30) { | |
| $gripAxis.removeClass('manual').css({ | |
| transform: 'rotate3d(0,0,0,0deg)' | |
| }).one('transitionend', function() { | |
| attachParts(canvas.swiper.axis, canvas.swiper.level); | |
| clearHelpers(); | |
| }); | |
| } else { | |
| var direction = canvas.swiper.degree > 0 ? 'right' : 'left'; | |
| $gripAxis.removeClass('manual').css({ | |
| transform: 'rotate3d(' + | |
| rotate3d[canvas.swiper.axis] + | |
| (canvas.swiper.degree > 0 ? '90' : '-90') + 'deg)' | |
| }).one('transitionend', function() { | |
| rotateParts(rotate3d, canvas.swiper.axis, direction); | |
| attachParts(canvas.swiper.axis, canvas.swiper.level); | |
| clearHelpers(); | |
| positionParts(canvas.swiper.axis, canvas.swiper.level, direction); | |
| canvas.swiper = false; | |
| }); | |
| } | |
| } | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.moveSwiper | |
| * @description | |
| * movement on the the Swiper | |
| */ | |
| var moveSwiper = function(e) { | |
| if (canvas.swiper && canvas.swiper.play) { | |
| e.preventDefault(); | |
| canvas.swiper.move = { | |
| 'x': e.offsetX || e.originalEvent.layerX, | |
| 'y': e.offsetY || e.originalEvent.layerY | |
| }; | |
| canvas.swiper.distance = {}; | |
| canvas.swiper.distance.x = (canvas.swiper.start.x - | |
| canvas.swiper.move.x) / | |
| canvas.swiper.size.x * 90; | |
| canvas.swiper.distance.y = (canvas.swiper.start.y - | |
| canvas.swiper.move.y) / | |
| canvas.swiper.size.x * 90; | |
| if (!canvas.swiper.active && | |
| (canvas.swiper.distance.x > canvas.threshold || | |
| canvas.swiper.distance.x < -1 * canvas.threshold)) { | |
| canvas.swiper.axis = canvas.swiper.sides.x; | |
| canvas.swiper.degree = (canvas.swiper.start.x - | |
| canvas.swiper.move.x) / | |
| canvas.swiper.size.x * 90; | |
| canvas.swiper.side = 'y'; | |
| canvas.swiper.turn = 'x'; | |
| canvas.swiper.active = true; | |
| } else if (!canvas.swiper.active && | |
| (canvas.swiper.distance.y > canvas.threshold || | |
| canvas.swiper.distance.y < -1 * canvas.threshold)) { | |
| canvas.swiper.axis = canvas.swiper.sides.y; | |
| canvas.swiper.side = 'x'; | |
| canvas.swiper.turn = 'y'; | |
| canvas.swiper.active = true; | |
| } | |
| if (canvas.swiper.axis) { | |
| if (!canvas.swiper.init) { | |
| canvas.swiper.init = true; | |
| if (canvas.swiper.delta[canvas.swiper.side] < 1.5) { | |
| canvas.swiper.level = canvas.swiper.side === 'x' ? 0 : 2; | |
| canvas.swiper.level = canvas.swiper.side === 'y' && | |
| canvas.swiper.control === 'right' ? 0 : canvas.swiper.level; | |
| canvas.swiper.level = canvas.swiper.side === 'x' && | |
| canvas.swiper.control === 'front' ? 2 : canvas.swiper.level; | |
| canvas.swiper.level = canvas.swiper.side === 'x' && | |
| canvas.swiper.control === 'bottom' ? 2 : canvas.swiper.level; | |
| canvas.swiper.level = canvas.swiper.controls === 'front' && | |
| canvas.swiper.side === 'x' ? 0 : canvas.swiper.level; | |
| } else if (canvas.swiper.delta[canvas.swiper.side] < 3) { | |
| return false; // can't turn ceter slice | |
| canvas.swiper.level = 1; | |
| } else { | |
| canvas.swiper.level = canvas.swiper.side === 'x' ? 2 : 0; | |
| canvas.swiper.level = canvas.swiper.side === 'y' && | |
| canvas.swiper.control === 'right' ? 2 : canvas.swiper.level; | |
| canvas.swiper.level = canvas.swiper.side === 'x' && | |
| canvas.swiper.control === 'front' ? 0 : canvas.swiper.level; | |
| canvas.swiper.level = canvas.swiper.side === 'x' && | |
| canvas.swiper.control === 'bottom' ? 0 : canvas.swiper.level; | |
| } | |
| detachParts(canvas.swiper.axis, canvas.swiper.level); | |
| $gripAxis | |
| .addClass('manual'); | |
| } | |
| var factor = 1; | |
| factor = canvas.swiper.side === 'x' && | |
| canvas.swiper.control === 'front' ? -1 : factor; | |
| factor = canvas.swiper.side === 'y' && | |
| canvas.swiper.control === 'right' ? -1 : factor; | |
| factor = canvas.swiper.side === 'x' && | |
| canvas.swiper.control === 'bottom' ? -1 : factor; | |
| canvas.swiper.degree = (canvas.swiper.start[canvas.swiper.turn] - | |
| canvas.swiper.move[canvas.swiper.turn]) / | |
| canvas.swiper.size[canvas.swiper.side] * 90 * factor; | |
| $gripAxis.css({ | |
| transform: 'rotate3d(' + | |
| rotate3d[canvas.swiper.axis] + | |
| canvas.swiper.degree + 'deg)' | |
| }); | |
| } | |
| } | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.initSwiper | |
| * @description | |
| * init the Swiper | |
| */ | |
| var initSwiper = function(e) { | |
| canvas.swiper = {}; | |
| canvas.swiper.control = $(this).data('control'); | |
| canvas.swiper.play = true; | |
| canvas.swiper.sides = { | |
| 'x': $(this).data('x'), | |
| 'y': $(this).data('y') | |
| }; | |
| canvas.swiper.size = { | |
| 'x': e.target.clientWidth, | |
| 'y': e.target.clientHeight | |
| }; | |
| canvas.swiper.start = { | |
| 'x': e.offsetX || e.originalEvent.layerX, | |
| 'y': e.offsetY || e.originalEvent.layerY | |
| }; | |
| canvas.swiper.delta = { | |
| 'x': canvas.swiper.size.x / canvas.swiper.start.x, | |
| 'y': canvas.swiper.size.y / canvas.swiper.start.y | |
| }; | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.moveCube | |
| * @description | |
| * rotates the cube itself | |
| */ | |
| var moveCube = function(e) { | |
| if (!canvas.down) { | |
| return false; | |
| } | |
| e.preventDefault(); | |
| var x = (e.pageX - canvas['mouse']['x']) / 4; | |
| var y = (e.pageY - canvas['mouse']['y']) / -4; | |
| var transformation = ''; | |
| if ((x > canvas.threshold || | |
| x < -1 * canvas.threshold) && | |
| canvas['axis'] !== 'x') { | |
| canvas['axis'] = 'y'; | |
| transformation += 'rotate3d(0, 1, 0, '; | |
| transformation += x * cubeRotationSpeed; | |
| transformation += 'deg) '; | |
| transformation += canvas['css']; | |
| canvas['mouse']['distance'] = x; | |
| canvas.moved = true; | |
| } else if ((y > canvas.threshold || | |
| y < -1 * canvas.threshold) && | |
| canvas['axis'] !== 'y') { | |
| canvas['axis'] = 'x'; | |
| transformation += 'rotate3d(1, 0, 0, '; | |
| transformation += y * cubeRotationSpeed; | |
| transformation += 'deg) '; | |
| transformation += canvas['css']; | |
| canvas['mouse']['distance'] = y; | |
| canvas.moved = true; | |
| } else { | |
| canvas.moved = false; | |
| return false; | |
| } | |
| if (canvas.moved) { | |
| $('.cube-wrapper').css({ | |
| transform: transformation | |
| }); | |
| } | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.releaseCuber | |
| * @description | |
| * release the Cube | |
| */ | |
| var releaseCube = function(e) { | |
| if (canvas.down) { | |
| canvas.down = false; | |
| if (!canvas.moved) { | |
| return false; | |
| } | |
| canvas.moved = false; | |
| canvas['mouse']['end'] = +new Date(); | |
| canvas['mouse']['time'] = canvas['mouse']['end'] - | |
| canvas['mouse']['start']; | |
| canvas['mouse']['bouce'] = (canvas['mouse']['distance'] / | |
| canvas['mouse']['time']) * | |
| 100; | |
| canvas['css'] = $('.cube-wrapper')[0].style.transform; | |
| canvas['mouse']['bouce'] = Math.abs(canvas['mouse']['bouce']) <= | |
| 5 ? 0 : canvas['mouse']['bouce']; | |
| $('.cube-wrapper').css({ | |
| transitionDuration: Math.min(Math.abs(canvas['mouse']['bouce'] * | |
| 20), 300) + | |
| 'ms', | |
| transform: 'rotate3d(' + | |
| rotate3d[canvas['axis']] + | |
| canvas['mouse']['bouce'] * | |
| cubeRotationSpeed + | |
| 'deg) ' + | |
| canvas['css'] | |
| }).one('transitionend', function() { | |
| $('.cube-wrapper').css({ | |
| transitionDuration: '' | |
| }); | |
| }); | |
| } | |
| }; | |
| /** | |
| * @jsdoc function | |
| * @name rubics.onMouseDown | |
| * @description | |
| * check where we are then perform cubeRotation | |
| * if not on buttons or cube | |
| */ | |
| var onMouseDown = function(e) { | |
| e.preventDefault(); | |
| if ($(e.target).is('.swiper') || | |
| $(e.target).closest('.controls').length) { | |
| return false; | |
| } | |
| canvas.down = true; | |
| canvas['axis'] = false; | |
| canvas['mouse']['x'] = e.pageX; | |
| canvas['mouse']['y'] = e.pageY; | |
| canvas['css'] = $('.cube-wrapper')[0].style.transform; | |
| canvas['mouse']['start'] = +new Date(); | |
| }; | |
| $(function() { | |
| var $themer = $('.themer'); | |
| var $canvas = $('.canvas'); | |
| $gripAxis = $('.grip').find('.axis-grip:first'); | |
| $(document) | |
| .on('mousedown', onMouseDown) | |
| .on('mouseup', releaseCube) | |
| .on('mousemove', moveCube); | |
| $('.swiper') | |
| .on('mousedown', initSwiper) | |
| .on('mouseleave mouseup', releaseSwiper) | |
| .on('mousemove', moveSwiper); | |
| $('.themer') | |
| .on('click', function() { | |
| var theme = $(this).data('theme'); | |
| $canvas.removeClass(classWithPrefix(/^theme-/)); | |
| $themer.removeClass('selected'); | |
| $canvas.addClass('theme-' + theme); | |
| $(this).addClass('selected'); | |
| }); | |
| $('.scrambler') | |
| .on('click', function() { | |
| scrambleCube(30); | |
| }); | |
| }); | |
| })(window.jQuery, window, document); |
| <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> |
| // ██╗ ██╗ █████╗ ██████╗ ███████╗ | |
| // ██║ ██║██╔══██╗██╔══██╗██╔════╝ | |
| // ██║ ██║███████║██████╔╝███████╗ | |
| // ╚██╗ ██╔╝██╔══██║██╔══██╗╚════██║ | |
| // ╚████╔╝ ██║ ██║██║ ██║███████║ | |
| // ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ | |
| // | |
| @cube-size: 15rem; | |
| @cube-part-count: 3; | |
| @cube-part-size: @cube-size / @cube-part-count; | |
| @border-width: 0.3rem; | |
| @border-radius: @border-width * 2; | |
| @cube-color: rgb(30, 30, 30); | |
| @cube-hover-color: #f92672; | |
| @fast: 200ms; | |
| @medium: @fast * 2; | |
| @slow: @medium * 2; | |
| @base-mix-perc: 15%; | |
| @hover-mix-perc: 35%; | |
| @hover-base-mix-perc: 5%; | |
| @button-color: #2b4746; | |
| @base-font-size: 16px; | |
| @rotater-size: 1.8rem; | |
| @rotater-factor: 1; | |
| @gutter-width: 1rem; | |
| @radius: 0.1rem; | |
| @arrow-size: @cube-part-size / 3; | |
| @red: #c41e3a; | |
| @green: #009e60; | |
| @blue: #0051ba; | |
| @orange: #ff5800; | |
| @yellow: #ffd500; | |
| @white: #fff; | |
| .for(@i, @n) {.-each(@i)} | |
| .for(@n) when (isnumber(@n)) {.for(1, @n)} | |
| .for(@i, @n) when not (@i = @n) { | |
| .for((@i + ((@n - @i) / abs(@n - @i))), @n); | |
| } | |
| .for(@array) when (default()) {.for-impl_(length(@array))} | |
| .for-impl_(@i) when (@i > 1) {.for-impl_((@i - 1))} | |
| .for-impl_(@i) {.-each(extract(@array, @i));} | |
| /** ██████╗ █████╗ ███████╗███████╗ | |
| * ██╔══██╗██╔══██╗██╔════╝██╔════╝ | |
| * ██████╔╝███████║███████╗█████╗ | |
| * ██╔══██╗██╔══██║╚════██║██╔══╝ | |
| * ██████╔╝██║ ██║███████║███████╗ | |
| * ╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝ | |
| */ | |
| *, | |
| *:before, | |
| *:after { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| font-family: inherit; | |
| line-height: inherit; | |
| font-weight: 300; | |
| user-select: none; | |
| } | |
| html { | |
| height: 100%; | |
| min-height: 100%; | |
| font-size: @base-font-size; | |
| font-family: 'Lato', sans-serif; | |
| line-height: 1.25; | |
| color: @white; | |
| } | |
| html, | |
| body { | |
| overflow: hidden; | |
| } | |
| body { | |
| background: @button-color; | |
| } | |
| ul, | |
| ol { | |
| list-style: none; | |
| li { | |
| list-style: inherit; | |
| } | |
| } | |
| h1 { | |
| font-size: 1.5em; | |
| margin: 0 @gutter-width 0.5em; | |
| } | |
| h2 { | |
| font-size: 1.3em; | |
| margin: 0 @gutter-width 0.5em; | |
| } | |
| h3 { | |
| font-size: 1.1em; | |
| margin: 0 @gutter-width 0.5em; | |
| } | |
| /** | |
| * ███████╗██████╗ █████╗ ███╗ ███╗███████╗ | |
| * ██╔════╝██╔══██╗██╔══██╗████╗ ████║██╔════╝ | |
| * █████╗ ██████╔╝███████║██╔████╔██║█████╗ | |
| * ██╔══╝ ██╔══██╗██╔══██║██║╚██╔╝██║██╔══╝ | |
| * ██║ ██║ ██║██║ ██║██║ ╚═╝ ██║███████╗ | |
| * ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ | |
| * | |
| */ | |
| body { | |
| cursor: grab; | |
| &:active { | |
| cursor: grabbing; | |
| } | |
| } | |
| .canvas { | |
| position: absolute; | |
| height: @cube-size * 1.5; | |
| width: @cube-size; | |
| overflow: visible; | |
| top: 14em; | |
| left: 50%; | |
| margin-left: @cube-size/-2; | |
| perspective: 700px; | |
| &:hover { | |
| cursor: grab; | |
| } | |
| &:active { | |
| cursor: grabbing; | |
| } | |
| } | |
| /** | |
| * ███████╗ ██████╗ ██████╗ ███╗ ███╗███████╗ | |
| * ██╔════╝██╔═══██╗██╔══██╗████╗ ████║██╔════╝ | |
| * █████╗ ██║ ██║██████╔╝██╔████╔██║███████╗ | |
| * ██╔══╝ ██║ ██║██╔══██╗██║╚██╔╝██║╚════██║ | |
| * ██║ ╚██████╔╝██║ ██║██║ ╚═╝ ██║███████║ | |
| * ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ | |
| */ | |
| ::-moz-focus-inner { | |
| outline: 0; | |
| } | |
| button { | |
| line-height: 1; | |
| &:focus { | |
| outline: 0; | |
| } | |
| } | |
| button { | |
| margin: 0 @gutter-width @gutter-width; | |
| padding: 1em; | |
| font-size: 0.6rem; | |
| background: @button-color; | |
| border: 0.1rem solid #fff; | |
| color: #fff; | |
| box-shadow: none; | |
| border-radius: @radius; | |
| cursor: pointer; | |
| font-variant: small-caps; | |
| &:focus, &:hover { | |
| color: darken(@button-color, 10%); | |
| background: #fff; | |
| border-color: darken(@button-color, 10%); | |
| } | |
| &:active { | |
| color: #fff; | |
| border-color: darken(@button-color, 10%); | |
| background-color: darken(@button-color, 10%); | |
| } | |
| &:focus { | |
| outline: 0; | |
| } | |
| &.selected { | |
| color: #fff; | |
| border-color: darken(@button-color, 10%); | |
| background-color: darken(@button-color, 10%); | |
| } | |
| } | |
| .controls { | |
| position: absolute; | |
| top: 0; | |
| right: 0; | |
| max-width: 20rem; | |
| z-index: 5; | |
| padding-left: @gutter-width; | |
| padding-top: @gutter-width; | |
| cursor: default; | |
| } | |
| /** | |
| * ██████╗██╗ ██╗██████╗ ███████╗███████╗ | |
| * ██╔════╝██║ ██║██╔══██╗██╔════╝██╔════╝ | |
| * ██║ ██║ ██║██████╔╝█████╗ ███████╗ | |
| * ██║ ██║ ██║██╔══██╗██╔══╝ ╚════██║ | |
| * ╚██████╗╚██████╔╝██████╔╝███████╗███████║ | |
| * ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝ | |
| */ | |
| .cube { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| height: inherit; | |
| width: inherit; | |
| transition: transform @medium linear; | |
| transform-style: preserve-3d; | |
| //backface-visibility: hidden; | |
| transform: rotate3d(0, 1, 0, -35deg) rotate3d(1, 0, 0, 35deg); | |
| .swiper { | |
| position: absolute; | |
| left: 0; | |
| top: 0; | |
| height: @cube-size; | |
| width: @cube-size; | |
| outline-offset: 10px; | |
| visibility: visible; | |
| //&:hover { | |
| // box-shadow: 0 0 5px 15px @cube-hover-color; | |
| //} | |
| &.top { | |
| transform: rotate3d(0,1,0,-180deg) | |
| translate3d(0,0,@cube-size/-1.9); | |
| } | |
| &.bottom { | |
| transform: translate3d(0,0,@cube-size/-1.9); | |
| } | |
| &.left { | |
| transform: rotate3d(0,1,0,90deg) | |
| translate3d(0,0,@cube-size/-1.9); | |
| } | |
| &.right { | |
| transform: rotate3d(0,0,1,-180deg) | |
| rotate3d(0,1,0,90deg) | |
| translate3d(0,0,@cube-size/-1.9); | |
| } | |
| &.front { | |
| transform: rotate3d(1,0,0,-180deg) | |
| rotate3d(1,0,0,-90deg) | |
| translate3d(0,0,@cube-size/-1.9); | |
| } | |
| &.back { | |
| transform: rotate3d(0,1,0,-180deg) | |
| rotate3d(1,0,0,-90deg) | |
| translate3d(0,0,@cube-size/-1.9); | |
| } | |
| } | |
| } | |
| .cube-wrapper { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| height: @cube-size; | |
| width: @cube-size; | |
| transform: translate3d(0, 0, 0); | |
| transition-property: transform; | |
| transition-timing-function: ease-out; | |
| transition-duration: 0; | |
| transform-style: preserve-3d; | |
| visibility: hidden; | |
| } | |
| .cube-part { | |
| height: inherit; | |
| width: inherit; | |
| .side { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| height: inherit; | |
| width: inherit; | |
| line-height: @cube-part-size; | |
| text-align: center; | |
| transform-style: preserve-3d; | |
| border-radius: @border-radius; | |
| &.white , | |
| &.blue , | |
| &.orange , | |
| &.red , | |
| &.green , | |
| &.yellow { | |
| background: @cube-color; | |
| .sticker { | |
| transform-style: preserve-3d; | |
| visibility: visible; | |
| } | |
| } | |
| &.front { | |
| transform: translate3d((@cube-part-size /-2), 0, 0) | |
| rotate3d(0, 1, 0, -90deg) scale(1); | |
| } | |
| &.back { | |
| transform: translate3d((@cube-part-size / 2), 0, 0) | |
| rotate3d(0, 1, 0, 90deg) scale(1); | |
| } | |
| &.right { | |
| transform: translate3d(0, (@cube-part-size / 2), 0) | |
| rotate3d(1, 0, 0, -90deg) scale(1); | |
| } | |
| &.left { | |
| transform: translate3d(0, (@cube-part-size / -2), 0) | |
| rotate3d(1, 0, 0, 90deg) scale(1); | |
| } | |
| &.top { | |
| transform: translate3d(0, 0, (@cube-part-size / 2)) | |
| rotate3d(1, 0, 0, 0) scale(1); | |
| } | |
| &.bottom { | |
| transform: translate3d(0, 0, (@cube-part-size / -2)) | |
| rotate3d(1, 0, 0, -180deg) scale(1); | |
| } | |
| } | |
| } | |
| .cube-part-wrapper { | |
| position: absolute; | |
| height: @cube-part-size; | |
| width: @cube-part-size; | |
| z-index: 0; | |
| transform-style: preserve-3d; | |
| backface-visibility: hidden; | |
| transition-property: all; | |
| transition-duration: @slow; | |
| pointer-events: none; | |
| visibility: hidden; | |
| &[data-x="0"] { | |
| left: 0; | |
| } | |
| &[data-x="1"] { | |
| left: @cube-part-size; | |
| } | |
| &[data-x="2"] { | |
| left: @cube-part-size * 2; | |
| } | |
| &[data-y="0"] { | |
| top: 0; | |
| } | |
| &[data-y="1"] { | |
| top: @cube-part-size; | |
| } | |
| &[data-y="2"] { | |
| top: @cube-part-size * 2; | |
| } | |
| &[data-z="0"] { | |
| transform+_: translate3d(0, 0, (@cube-part-size / -1)); | |
| } | |
| &[data-z="1"] { | |
| transform+_: translate3d(0, 0, 0); | |
| } | |
| &[data-z="2"] { | |
| transform+_: translate3d(0, 0, @cube-part-size); | |
| } | |
| } | |
| /** | |
| * ██████╗ ██████╗ ██╗██████╗ | |
| * ██╔════╝ ██╔══██╗██║██╔══██╗ | |
| * ██║ ███╗██████╔╝██║██████╔╝ | |
| * ██║ ██║██╔══██╗██║██╔═══╝ | |
| * ╚██████╔╝██║ ██║██║██║ | |
| * ╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ | |
| * | |
| */ | |
| .grip { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| height: inherit; | |
| width: inherit; | |
| pointer-events: none; | |
| transform-style: preserve-3d; | |
| backface-visibility: hidden; | |
| pointer-events: none; | |
| .axis { | |
| &.manual { | |
| transition: none; | |
| } | |
| transition: transform @medium; | |
| &.fast { | |
| transition: transform @fast; | |
| } | |
| } | |
| } | |
| .axis { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| height: inherit; | |
| width: inherit; | |
| transform-style: preserve-3d; | |
| backface-visibility: hidden; | |
| } | |
| /** | |
| * ████████╗██╗ ██╗███████╗███╗ ███╗███████╗ | |
| * ╚══██╔══╝██║ ██║██╔════╝████╗ ████║██╔════╝ | |
| * ██║ ███████║█████╗ ██╔████╔██║█████╗ | |
| * ██║ ██╔══██║██╔══╝ ██║╚██╔╝██║██╔══╝ | |
| * ██║ ██║ ██║███████╗██║ ╚═╝ ██║███████╗ | |
| * ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝ | |
| */ | |
| .theme-flat { | |
| @border-radius: @border-width; | |
| .cube-part-wrapper-112 { | |
| .cube-part .side.white .sticker { | |
| background-image: | |
| url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/28359/rubik-logo.png'); | |
| background-size: 100% auto; | |
| } | |
| } | |
| .cube-part { | |
| .side { | |
| //background: @cube-color; | |
| background: none; | |
| border-radius: 0; | |
| &.white, | |
| &.blue, | |
| &.orange, | |
| &.red, | |
| &.green, | |
| &.yellow { | |
| .sticker { | |
| transform: translateZ(1px); | |
| position: absolute; | |
| top: @border-width; | |
| left: @border-width; | |
| right: @border-width; | |
| bottom: @border-width; | |
| border-radius: @border-radius; | |
| z-index: 2; | |
| backface-visibility: hidden; | |
| } | |
| } | |
| &.white .sticker { | |
| background-color: @white; | |
| } | |
| &.blue .sticker { | |
| background-color: @blue; | |
| } | |
| &.orange .sticker { | |
| background-color: @orange; | |
| } | |
| &.red .sticker { | |
| background-color: @red; | |
| } | |
| &.green .sticker { | |
| background-color: @green; | |
| } | |
| &.yellow .sticker { | |
| background-color: @yellow; | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * ████████╗██╗ ██╗███████╗███╗ ███╗███████╗ | |
| * ╚══██╔══╝██║ ██║██╔════╝████╗ ████║██╔════╝ | |
| * ██║ ███████║█████╗ ██╔████╔██║█████╗ | |
| * ██║ ██╔══██║██╔══╝ ██║╚██╔╝██║██╔══╝ | |
| * ██║ ██║ ██║███████╗██║ ╚═╝ ██║███████╗ | |
| * ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝ | |
| */ | |
| .theme-realistic { | |
| .cube-part-wrapper-112 { | |
| .cube-part .side.white .sticker { | |
| background-image: | |
| url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/28359/rubik-logo.png'); | |
| background-size: 100% auto; | |
| } | |
| } | |
| .cube-part { | |
| .side { | |
| visibility: visible; | |
| box-shadow: | |
| 0 0 2px 0 | |
| lighten(@cube-color, 13%) inset, | |
| 0 0 0 @border-width | |
| lighten(@cube-color, 5%) inset; | |
| border-radius: @border-radius; | |
| background-color: @cube-color; | |
| .sticker { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| border-radius: @border-radius; | |
| z-index: 2; | |
| background-color: @cube-color; | |
| box-shadow: | |
| 0 0 2px 0 | |
| lighten(@cube-color, 13%) inset, | |
| 0 0 0 @border-width | |
| lighten(@cube-color, 5%) inset, | |
| 0 0 1px (@border-width + 0.1) | |
| rgba(255, 255, 255, 0.2) inset; | |
| background-image: | |
| radial-gradient(ellipse farthest-corner, | |
| rgba(255, 255, 255, 0.1) 0%, | |
| rgba(255, 255, 255, 0) 60%, | |
| rgba(255, 255, 255, 0)); | |
| } | |
| &.white .sticker{ | |
| background-color: @white; | |
| } | |
| &.blue .sticker{ | |
| background-color: @blue; | |
| } | |
| &.orange .sticker{ | |
| background-color: @orange; | |
| } | |
| &.red .sticker{ | |
| background-color: @red; | |
| } | |
| &.green .sticker{ | |
| background-color: @green; | |
| } | |
| &.yellow .sticker{ | |
| background-color: @yellow; | |
| } | |
| &.white, | |
| &.blue, | |
| &.orange, | |
| &.red, | |
| &.green, | |
| &.yellow { | |
| .sticker { | |
| transform: translateZ(1px); | |
| } | |
| } | |
| } | |
| } | |
| } |