Added image support for this Isometric Builder by Nicolas Gryman.
This pen is using the obelisk.js library.
<header><h1><span>obelisk</span> buildr</h1> | |
<aside id="auth"> | |
<button class="login is-hidden"><span>log in</span><span class="icon icon-github"></span></button> | |
<button class="logged is-hidden" title="connected to github"><span class="icon icon-github"></span></button> | |
</aside> | |
</header> | |
<div id="help" class="pane"> | |
<ul> | |
<li><p><b>B</b>: Brush tool.</p></li> | |
<li><p><b>E</b>: Erase tool.</p></li> | |
<li><p><b>spacebar</b>: Color palette.</p></li> | |
<li><p><b>←</b>, <b>→</b>: Rotate view.</p></li> | |
<li><p><b>+</b>, <b>-</b>, <b>scroll</b>: Move draw layer up / down.</p></li> | |
<li><p><b>CTRL + Z</b>: Undo.</p></li> | |
<li><p><b>CTRL + S</b>: Save to gist.</p></li> | |
<li><p><b>N</b>: New art.</p></li> | |
<li><p><b>F</b>: Full canvas.</p></li> | |
<li><p><b>H</b>: Toggle this thing.</p></li> | |
</ul> | |
</div> | |
<main> | |
<h2 class="select">Select an icon to be displayed using the <strong>ObeliskBuilder</strong></h2> | |
<ul class="thumbnails"> | |
<li class="active"><a href="#"><img src="data:image/gif;base64,R0lGODlhFAAUANUAAAAAAP///+/3997e1tbWzv/nIf/eEP/eGPfWGO/OGPfOAP/WCNa1EM6tEKWMEOfGGOe9EN61EMalELWUEO/GGL2UCKWECKWce9alCLWMCK2ECJRzCN6tEJx7EGNSGHNjMZyUe86cCL2MCKV7CIxrCGtSCKWchIxjANacCJxzCHNjOXtrQmtKCGNKGGtSIZSEY3tjOaWUe9bOxufn5////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADQALAAAAAAUABQAAAbRwIBwSCwaiQKCadVqrUwEwVE4i5UcjASlYSnFZkeCqpNAHA4IRAKyURGKA5cEUajb1Y+MazAUvCZ0dnZoayMvUgEAiouMjYtCMYpCjpOLMUIwDI51jhUwQh4PB4yCjBAhHqAPZoKtBgoRqJgNga11aA8cIp8BMQ5ltgWEEBgpIEIyJRDAggcGCbkhLDJCfhYPZYwL0BHFh0NxExDYCQkKDxAcGBoefEQEHyQcERAQEeohJx9vRlUsKSIwoBCRgsWXKQEEyLigoomKCzIQIZxIJAgAOw==" alt=""></a></li> | |
<li><a href="#"><img src="data:image/gif;base64,R0lGODlhFAAUAKIAAAAAAP///+3u7wByvP///wAAAAAAAAAAACH5BAEAAAQALAAAAAAUABQAAAMpOLrc/jDKOYS9VF2ct82VJ3kkx5Slg5LqurXu18Tmw3Yi/uo16P/AQQIAOw==" alt=""></a></li> | |
<li><a href="#"><img src="data:image/gif;base64,R0lGODlhFAAUAPcAAORkE/F+GN1aHfOMMvqFDeelefWJIut6J/Gvg/upVthOF/aMKedtIeyBN//69eN7OvaLJul1KuiGPveJHOt1JfXh1fGBJ/3RpvOIKeeEOuaFOOCCQeWAOeNpIex5JdtVHd1bFvWGH/OFH//17fulTtlLC/7t3+52FOhxIviQK/qQJPeOK+WKQ/WLK+uKPuqJO/zMm+eHOe16JetxGuJlIf6aLvuWL/uULfqSK/iRLPiNJfKHKvKFJeaDOvGBKOWDOOSAN+V9POR+N+N9OeJ7OOt3I+RrGPuWLP3q2OBhH/mTLPqUK+eDPOiGO+58Ju93FuaidfjAk+F9N/Xj2+98JuymhfGodu14IOJ8NeWAPP/38Pi5gfmSK/SJKuJ5OPuUJ+SecO98IPqYNfR8CuFiGO98Hv3x6PioXfvIlvvRq/F5D9tTEvi3ff/37/e4hfuSJfbn4fSJKPe3f/KEKeR8O+55HfOUQPCEJvzy7f/+/vKaUu11Fe6ke/mLHOdqFeNfDeRpH+ZrHeSZZe59JvXj2falW/7s2/u/hut0GfecRvqdQfKCHPS0h/eHGeeIV+lyJN5lLvmVLO6TVfqTKd9hH/rj1vKeXOdsGutyH/yXLu12GPu9ge+BJu5wCvmSKfjWw+h9O/iGEvzAhPzr3+eGO/isaPbm3frawNtcIv3dwOF3NvWSN/iPK/mXNPehT+WBOuOCPvB4EuhvHt9TAd5YD99eGd1cH/qpWfysWv/+//B+IP7r2P3Wr+qbdffo3/R+DvKjad1XEvnXvPSOL/717t95NfmRJ+tpB+57JfuSJv7p0/qPIfyWK+KGRNlQF/CMQPqTLPe8ifSLKfa2gv7v4vzv5vGFKfKHKOWbaOWdbu96GeaHPfOVRvXKsfXMtfKGJ/fKqNxUGP7+/+iFTf///vGYVt5aEvaNKueFO/eydv338vvdxPuMGPe1fOdoEPu4dON+Nv/u3u+nfOF8PuVqHvmPJOBdEPKIKuR/OeWbZ+mHOumHO/fq4vzq2+99Jv///yH5BAAAAAAALAAAAAAUABQAAAj/AP/xgwJLCAcOr3qgQ9dE374XL7Zlm/LP1wYjgS5h8jDIgrUdXVakuGEjkwEpFQoYARShwQFEe8rcwRBnQQolS47UMCCoGQMAVsz0EzaN2yIRInEeOQItBSksj9wx+kf1n4M0iSZ4irSUywIMLuBRmFEO3ClqVbVsUvGF6YJvFlwAkSFDU6dY90qlqnrhjbFz1zhRkQDESR09bAoN+zXhHTGqFwzw8IHMA2EfT6JRNYGmFQES8ai2e+KkyCMmP3YEkFP1n6EEn0f8I/ZsBgoGqDHwWHXmEBKqbRKMSUcVnB96HbJoaCENQqNQk2CI+2digLZ1/9SBIkMjiIYV53SIuSGRjB0MqlGOASP3jw+tJN5z6FCkLBevehB+j/IQodo/b8EIQEcMN/QhSlWuqOHGP3lI8scn/1RiSzgPxGDDMrg48M8uA5xgCVXyzNLNP3hAosADLDBzxBu3bGGHLlc0gAAC45jjSBW9oOLMAwWIUAMOIQQQBjJFyAKAPbVQskYJJSgAQj6mbCACK13M4Y8HFDDQAQ1JCCDABx+AUEwF/8ABBgtNoJNBD6/gM8QQRBDhhSrzYEPIPwEBADs=" alt=""></a></li> | |
<li><a href="#"><img src="data:image/gif;base64,R0lGODlhFAAUAOYAAAAAAP///8S0A0lDAUVAAUI9AePQBODOBN7MBNfFBM++BLKkA//qBf7pBf3oBfznBfvmBfjkBffjBfbiBfTgBfDcBe/bBerXBeXSBePRBeLQBd/NBcu6BMm5BMKyBLmqBJWJA5GFA42CA4h9A4Z7A/znBvvmBvTgBvPfBqmbBE1HAsW1BvTgCOvYCOjWCObUCODOB9jHB+zaCdnICMq6CMa3CKibB0tFA9vKCtLBCsCxCdfGC8+/DMa2C7aoCp6SCTYyA5mNCb2vDLytDLqsDLaoDMGyDYN5CbKkDaaaDaGVDYB2CjEuBJyQDZmNDXZtCl1WCCglBODNBOLPBV1VAvrlBu3ZBpiLBPbhB+7aB+PQB8m4Bsq5Bzs2AsCwB5GFB869C7ipCmtiBsu6DKudC7GiDZ+SDF5WB6SXDWRcCIp/DGZeCY2CDf8AAPr6+tXV1cvLy7CwsKysrIuLi4aGhnR0dG9vb11dXVhYWFNTUzMzMyUlJSAgIAwMDAUFBf///yH5BAEAAH8ALAAAAAAUABQAAAf/gAGCgm5yeHp+fnp4cm6Dj4JvegMgHxpSCyIFe3GQgnN9JBUUExMUFRcHV111kHVUChNVDw0NDxASFgYdKq2CcQQYEQ8AAAzHDcUWBx5AnW58KRPEgsYMANUXCSN8hQMVENiDxY8ACCtAcnchFA7iAHDF8QHxU1tid3wcE8lw9HLF5PwDoIHLlz1+MvC7BgfgMXgAUcCo8aOPnwPtHlrTWCXLDB1B+vARAK7BsZMnS2B5kSPMkT14RFyQQAslgwYmsMjA0YPMGUYFNliIAMDkTQdVWMgAAKZIkyiN+FzZYOVEsatXeQxBs6ZbADldvMTQ4qIFgDZtAOwYQySJGqiDOurcsEEjx46zaY0gUcIGiC9CdPqk8TFESLEySZykiWLHESRJTMQsMdPkCZQonDwNKpRHTzE9eRpBCgQAOw==" alt=""></a></li> | |
<li><a href="#"><img src="data:image/gif;base64,R0lGODlhFAAUAOYAAAAAAP////3+//z+//X8/83y/9n1/+n5/zPM/zTM/zXM/zXN/zfN/znN/znO/zrO/z7P/0TQ/0XQ/0XR/0fR/0jR/0vS/03S/03T/1DT/1HT/1TU/1bV/2HY/2jZ/2ra/27b/3jd/3re/3ze/4Lg/4Tg/4Xh/5Hj/5Hk/5rm/53n/6Dn/6Ho/6Po/6nq/6vq/7Ps/7bt/7nt/7ru/7zu/7/v/8Dv/8Pw/8ny/8zy/83z/87z/9Dz/9H0/9P0/9b1/9r2/9/3/+P4/+b5/+r6/+v6/+/7//P8//f9//H8//L8//b9//n+//3//////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAE4ALAAAAAAUABQAAAeZgAGCg4SFhoeIiYdJPUOHTYg+FxEth0sjMQSERxgIDRsuhygIGitFgioIqqoshkEZqhQvSxWrqg0HhT4Oth0JtqomMzqENRbAyAgfPIQ2C8m2EiQ/hAI3GtCqNIgeDNAcTIJCSIQ4E8kMO4NDJyk0MCUQyQ8yhUQh2QgdzIc6IhUKVCWIAILGAEUBlAApkMOAEYQQI0qcSCgQADs=" alt=""></a></li> | |
</ul> | |
<div class="drop-zone"></div><span><-- or drop your 20x20 image here...</span> | |
<br><h2 class="currently">Currently Displaying: </h2><img class="drop-image" src="" /> | |
<canvas id="myCanvas" width="20" height="20"> | |
<!-- Insert fallback content here --> | |
</canvas> | |
<div id="buildr"> | |
<canvas id="scene"></canvas> | |
</div> | |
<div id="palette" class="is-hidden"> | |
<button class="red" data-tool="brush" data-value="#c82829">1</button> | |
<button class="orange" data-tool="brush" data-value="#f5871f">2</button> | |
<button class="yellow" data-tool="brush" data-value="#eab700">3</button> | |
<button class="green" data-tool="brush" data-value="#718c00">4</button> | |
<button class="aqua" data-tool="brush" data-value="#3e999f">5</button> | |
<button class="blue" data-tool="brush" data-value="#4271ae">6</button> | |
<button class="purple" data-tool="brush" data-value="#8959a8">7</button> | |
<button class="black" data-tool="brush" data-value="#4d4d4c">8</button> | |
<button class="white is-active" data-tool="brush" data-value="#eeeeee">9</button> | |
</div > | |
<div id="overlay" class="is-hidden"></div> | |
<div id="notification" class="is-hidden"></div> | |
<div id="help" class="pane is-hidden"> | |
<ul> | |
<li><p><b>B</b>: Brush tool.</p></li> | |
<li><p><b>E</b>: Erase tool.</p></li> | |
<li><p><b>spacebar</b>: Color palette.</p></li> | |
<li><p><b>←</b>, <b>→</b>: Rotate view.</p></li> | |
<li><p><b>+</b>, <b>-</b>, <b>scroll</b>: Move draw layer up / down.</p></li> | |
<li><p><b>CTRL + Z</b>: Undo.</p></li> | |
<li><p><b>CTRL + S</b>: Save to gist.</p></li> | |
<li><p><b>N</b>: New art.</p></li> | |
<li><p><b>F</b>: Full canvas.</p></li> | |
<li><p><b>H</b>: Toggle this thing.</p></li> | |
</ul> | |
</div> | |
<div id="welcome" class="pane is-hidden"> | |
<div class="content"> | |
<h2>Welcome to obelisk buildr!</h2> | |
<p>This little experiment makes use of the great <a target="_blank" href="https://github.com/nosir/obelisk.js">obelisk.js</a> library.</p> | |
<ul> | |
<li><p>Everything is driven by shortcuts here, no UI, I'm lazy :)<br> | |
Press <b>H</b> to list all of them.</li> | |
<li><p>You can draw on 20 layers of height. Scroll your mouse up or down to adjust elevation.</p></li> | |
<li><p>Available tools are brush (<b>B</b>) and erase (<b>E</b>).</p></li> | |
<li><p>Press the <b>spacebar</b> to spawn a 9 colors palette. Colors are also | |
accessible form <b>1</b> to <b>9</b>. </p></li> | |
<li><p>Rotate the view with <b>←</b> and <b>→</b> arrow keys</p></li> | |
<li><p>Your work is automatically saved locally in the browser.<br> | |
Press <b>CTRL + S</b> to save it to a github gist. | |
If you log in, you will be able to fork and edit your own gists. | |
If not, anonymous gists will be created each time you save! So please consider logging in.</p></li> | |
<li><p>Press any key to continue...</p></li> | |
</ul> | |
</div> | |
</div> | |
</main> | |
<footer> | |
<a href="https://github.com/kostasx/obelisk-buildr/tree/image-dropper"><em>Github</em></a> | <a href="https://twitter.com/kostas_mns">Follow <strong>@kostas_mns</strong> on <em>Twitter</em></a> | |
<a href="https://github.com/ngryman/obelisk-builder"> // Original Source on <em>Github</em></a> | | |
<a href="http://twitter.com/ngryman">Follow <strong>@ngryman</strong> on <em>Twitter</em></a> | |
</footer> |
Added image support for this Isometric Builder by Nicolas Gryman.
This pen is using the obelisk.js library.
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
// TODO: move this elsewhere | |
obelisk.Point3D.prototype.clone = function() { | |
return new obelisk.Point3D(this.x, this.y, this.z); | |
}; | |
/** | |
* Module dependencies. | |
*/ | |
var ui = require('./ui'), | |
tool = require('./tool'), | |
pointer = require('./pointer'), | |
history = require('./history'), | |
storage = require('./storage'); | |
/** | |
* Private variables | |
*/ | |
var canvasEl = document.getElementById('scene'); | |
var persistLock = false; | |
var autoSaveTimeout; | |
var resizeTimeout; | |
var fullCanvased = false; | |
/** | |
* Module declaration. | |
*/ | |
var app = {}; | |
/** | |
* Shift Detect | |
*/ | |
app.shiftHandler = false; | |
// Wow! What a bad, bad practice... Shame on me! | |
app.createPixelArray = function( imageDataArray, width, height ){ | |
var pixelArray = []; // Array( width * height ) | |
var initial = 0; | |
var tetarto = 0; | |
var x = 0; | |
var y = 0; | |
var z = 0; | |
$.each( imageDataArray.data, function( index, value ){ | |
if ( index % 4 === 0 ){ | |
pixelArray[initial] = { "x" : x, "y" : y, "z" : z, "c" : value.toString()[0], "rgba": [value] }; | |
tetarto = 0; | |
initial++; | |
x++; | |
if ( x % 20 === 0 && index !== 0 ){ | |
// console.log(index, y); | |
x = 0; | |
y = ( y + 1 ); | |
} | |
} else { | |
pixelArray[initial-1].rgba.push(value); | |
tetarto++; | |
} | |
}); | |
return pixelArray; | |
}; | |
app.getImageData = function( imageData, image, imageCtx ){ | |
var pixelArray = this.createPixelArray( imageData, imageData.width, imageData.height ); | |
pixelArray = { "colors":["0x333399","9999984","0xFFFFFF","15382272","15658734"], "data": pixelArray }; | |
return pixelArray; | |
}; | |
/** | |
* | |
*/ | |
app.init = function() { | |
ui.auth.init(); | |
ui.scene.init(); | |
ui.welcome.init(function() { | |
ui.palette.init(); | |
tool.init(ui.scene) | |
.use('brush'); | |
pointer.init(ui.scene) | |
.click(tool.click) | |
.drag(tool.drag); | |
bindShortcuts(); | |
bindScroll(); | |
bindResize(); | |
touchDisclaimer(); | |
/* | |
// fetches initial art | |
storage.fetch(function(err, data, info) { | |
if (err) return ui.notification.error(err); | |
if (data) ui.scene.load(data); | |
if (info) ui.notification.info(info); | |
// auto save from now on | |
ui.scene.changed(onAutoSave); | |
}); | |
*/ | |
}); | |
loadImage( "data:image/gif;base64,R0lGODlhFAAUANUAAAAAAP///+/3997e1tbWzv/nIf/eEP/eGPfWGO/OGPfOAP/WCNa1EM6tEKWMEOfGGOe9EN61EMalELWUEO/GGL2UCKWECKWce9alCLWMCK2ECJRzCN6tEJx7EGNSGHNjMZyUe86cCL2MCKV7CIxrCGtSCKWchIxjANacCJxzCHNjOXtrQmtKCGNKGGtSIZSEY3tjOaWUe9bOxufn5////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADQALAAAAAAUABQAAAbRwIBwSCwaiQKCadVqrUwEwVE4i5UcjASlYSnFZkeCqpNAHA4IRAKyURGKA5cEUajb1Y+MazAUvCZ0dnZoayMvUgEAiouMjYtCMYpCjpOLMUIwDI51jhUwQh4PB4yCjBAhHqAPZoKtBgoRqJgNga11aA8cIp8BMQ5ltgWEEBgpIEIyJRDAggcGCbkhLDJCfhYPZYwL0BHFh0NxExDYCQkKDxAcGBoefEQEHyQcERAQEeohJx9vRlUsKSIwoBCRgsWXKQEEyLigoomKCzIQIZxIJAgAOw==" ); | |
// HANDLE THUMBNAIL CHANGE | |
$(".thumbnails li").click(function(e){ | |
var imgSrc = $(this).find("img").attr("src"); | |
$(".thumbnails").find("li").removeClass('active'); | |
$(this).addClass("active"); | |
$("#myCanvas").show(); | |
$(".drop-image").hide(); | |
loadImage( imgSrc ); | |
}); | |
// HANDLE DRAG & DROP | |
$('html').on('dragenter dragover', function(e) { e.stopPropagation(); }); | |
$('.drop-image').on('load', function() { | |
if ( this.naturalWidth > 20 || this.naturalHeight > 20 ) { | |
console.log("IMAGE TOO LARGE"); | |
} else { | |
$("#myCanvas").hide(); | |
$(".thumbnails li").removeClass("active"); | |
loadImage( this.src ); | |
$(this).show(); | |
$('.drop-placeholder').hide(); | |
} | |
}); | |
$('.drop-zone') | |
.on('dragover', function() { | |
$(this).addClass('drop-over'); | |
return false; | |
}) | |
.on('dragleave', function() { | |
$(this).removeClass('drop-over'); | |
return false; | |
}) | |
.on('drop', function(e) { | |
if(e.originalEvent.dataTransfer){ | |
if(e.originalEvent.dataTransfer.files.length) { | |
// $('.drop-image').hide(); | |
$(this).removeClass('drop-over'); | |
var file = e.originalEvent.dataTransfer.files[0]; | |
if (!file || file.type.indexOf('image/') !== 0) { | |
console.log("NOT AN IMAGE"); | |
} else { | |
if ( true ){ | |
var reader = new FileReader(); | |
reader.onload = function(e) { | |
$('.drop-image').attr('src', e.target.result ); | |
}; | |
reader.readAsDataURL(file); | |
} | |
} | |
e.preventDefault(); | |
return false; | |
} | |
} | |
}); | |
$('.drop-image, .drop-samples img').on('dragstart', function(e) { | |
e.preventDefault(); | |
}); | |
// logCurious(); | |
}; | |
/** | |
* @private | |
*/ | |
function loadImage(imgSrc){ | |
var imageData; | |
var imageCanvas = document.getElementById("myCanvas"); | |
var imageCtx = imageCanvas.getContext("2d"); | |
var image = new Image(); | |
image.src = imgSrc; | |
$(image).load(function() { | |
imageCtx.drawImage(image, 0, 0, 20, 20); | |
imageData = imageCtx.getImageData(0, 0, 20, 20); | |
var output = app.getImageData( imageData, image, imageCtx ); | |
storage.fetch(function(err, output, info) { | |
if (err) return ui.notification.error(err); | |
// if (output) ui.scene.load(output); | |
if (output) ui.scene.load( output, "rgba" ); | |
if (info) ui.notification.info(info); | |
ui.scene.changed(onAutoSave); // auto save from now on | |
}, output ); | |
}); | |
} | |
/** | |
* @private | |
*/ | |
function logCurious() { | |
console.log('Hey! Curious or having bugs?'); | |
console.log('Please post ideas or issues here: https://github.com/ngryman/obelisk-buildr/issues.'); | |
console.log('You can play with the window.scene object.'); | |
if (console.table) { | |
var methods = { | |
snapshot: { description: 'Returns a base64 image of the current scene.' }, | |
load: { description: 'Loads a scene. Same format as the art.json file in gists.' }, | |
save: { description: 'Returns data associated with the current scene. Same format as the art.json file in gists.' } | |
}; | |
console.table(methods); | |
} | |
} | |
/** | |
* @private | |
*/ | |
function bindShortcuts() { | |
document.addEventListener('keydown', onKeyDown); | |
document.addEventListener('keyup', onKeyUp); | |
} | |
/** | |
* @private | |
*/ | |
function bindScroll() { | |
var isFirefox = /Firefox/i.test(navigator.userAgent); | |
document.addEventListener(isFirefox ? 'DOMMouseScroll' : 'mousewheel', onScroll); | |
} | |
/** | |
* @private | |
*/ | |
function bindResize() { | |
window.addEventListener('resize', onResize); | |
} | |
/** | |
* @private | |
*/ | |
function touchDisclaimer() { | |
var isChrome = /chrome/i.exec(navigator.userAgent), | |
isAndroid = /android/i.exec(navigator.userAgent), | |
hasTouch = 'ontouchstart' in window && !(isChrome && !isAndroid); | |
if (hasTouch) | |
ui.notification.error('Hey! For now, there is no real support for touch devices. Yeah i know...'); | |
} | |
/** | |
* @param {boolean} silent | |
* @returns {object} | |
* @private | |
*/ | |
function save(silent) { | |
var data = ui.scene.save(silent); | |
storage.local(data); | |
return data; | |
} | |
/** | |
* @private | |
*/ | |
function persist( local ) { | |
if (persistLock) return; | |
persistLock = true; | |
// nothing to persist | |
if (!ui.scene.changed() && !storage.orphan()) { | |
persistLock = false; | |
return ui.notification.error('nothing to save'); | |
} | |
// saves locally | |
var data = save(); | |
if ( local ) { | |
console.log(JSON.stringify(data)); | |
persistLock = false; | |
return; | |
} | |
// persist to a gist | |
storage.persist(data, function(err, info) { | |
persistLock = false; | |
if (err) return ui.notification.error(err); | |
var anchor = '<a target="_blank" href="' + info.url + '">' + info.id + '</a>'; | |
ui.notification.info(info.action + ' gist ' + anchor); | |
}); | |
} | |
/** | |
* @private | |
*/ | |
function create() { | |
storage.flush(); | |
ui.scene.clear(); | |
ui.notification.info('new craft!'); | |
} | |
/** | |
* @private | |
*/ | |
function fullCanvas() { | |
var display = fullCanvased ? 'block' : 'none'; | |
document.querySelector('header').style.display = display; | |
document.querySelector('footer').style.display = display; | |
var padding = fullCanvased ? '70px' : '0px'; | |
document.querySelector('main').style.paddingTop = padding; | |
document.querySelector('main').style.paddingBottom = padding; | |
ui.scene.resize(); | |
fullCanvased = !fullCanvased; | |
} | |
/** | |
* @param {event} e | |
* @private | |
*/ | |
function onKeyDown(e) { | |
switch (e.keyCode) { | |
// + | |
case 107: | |
ui.scene.adjustFloor(+1); | |
break; | |
// - | |
case 109: | |
ui.scene.adjustFloor(-1); | |
break; | |
// left | |
case 37: | |
ui.scene.rotate(+1); | |
break; | |
// right | |
case 39: | |
ui.scene.rotate(-1); | |
break; | |
// b | |
case 66: | |
tool.use('brush'); | |
break; | |
// e | |
case 69: | |
tool.use('erase'); | |
break; | |
// space bar | |
case 32: | |
ui.palette.toggle(); | |
break; | |
// ctrl + z | |
case 90: | |
if (e.ctrlKey) history.back(); | |
break; | |
// ctrl + s | |
case 83: | |
e.preventDefault(); | |
if (e.ctrlKey) { | |
if (e.shiftKey){ | |
persist( true ); | |
} else { | |
persist(); | |
} | |
} | |
break; | |
// n | |
case 78: | |
create(); | |
break; | |
// f | |
case 70: | |
fullCanvas(); | |
break; | |
// h | |
case 72: | |
e.preventDefault(); | |
ui.help.toggle(); | |
break; | |
} | |
// 123456789 | |
if (e.keyCode >= 49 && e.keyCode <= 57) | |
tool.use('brush').set(ui.palette.color(e.keyCode - 49)); | |
// Shift Button Pressed | |
if ( e.keyIdentifier === "Shift" ) | |
app.shiftHandler = true; | |
} | |
/** | |
* @param {event} e | |
* @private | |
*/ | |
function onKeyUp(e) { | |
if ( e.keyIdentifier === "Shift" ) | |
// Shift Button Unpressed | |
app.shiftHandler = false; | |
} | |
/** | |
* @param {event} e | |
* @private | |
*/ | |
function onScroll(e) { | |
var delta = e.detail ? -e.detail : e.wheelDelta; | |
ui.scene.adjustFloor(delta > 0 ? -1 : +1); | |
} | |
/** | |
* @param {event} e | |
* @private | |
*/ | |
function onResize(e) { | |
// hide on first event | |
if (null == resizeTimeout) | |
canvasEl.style.visibility = 'hidden'; | |
// debounce scene resize | |
clearTimeout(resizeTimeout); | |
resizeTimeout = setTimeout(function() { | |
ui.scene.resize(); | |
canvasEl.style.visibility = 'visible'; | |
resizeTimeout = null; | |
}, 100); | |
} | |
/** | |
* @private | |
*/ | |
function onAutoSave() { | |
// debounce auto save | |
clearTimeout(autoSaveTimeout); | |
autoSaveTimeout = setTimeout(save.bind(null, true), 1000); | |
} | |
/** | |
* Global export. | |
*/ | |
window.app = app; | |
/** | |
* Exports for hackers | |
*/ | |
window.scene = ui.scene; | |
},{"./history":3,"./pointer":4,"./storage":5,"./tool":6,"./ui":11}],2:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Private variables | |
*/ | |
var anonymousMessage = 'View and edit it on http://ngryman.sh/obelisk-buildr.\n\n' + | |
'As this is an anonymous gist, you have to manually copy and paste its id, and append it' + | |
'to the url (i.e. http://ngryman.sh/obelisk-buildr#1337).'; | |
var authenticatedMessage = 'View and edit it on http://ngryman.sh/obelisk-buildr/#{0}.'; | |
var token; | |
/** | |
* Module declaration. | |
*/ | |
var github = {}; | |
/** | |
* | |
* @returns {boolean} | |
*/ | |
github.authenticated = function() { | |
return (null != token); | |
}; | |
/** | |
* | |
*/ | |
github.connect = function() { | |
location.href = 'https://github.com/login/oauth/authorize?client_id=717772a46c3c521155d3&scope=gist'; | |
}; | |
/** | |
* | |
*/ | |
github.disconnect = function() { | |
localStorage.removeItem('token'); | |
token = null; | |
}; | |
/** | |
* | |
* @param content | |
* @param callback | |
*/ | |
github.newGist = function(content, callback) { | |
var data = { | |
description: 'An awesome pixel art chef d\'oeuvre', | |
public: true, | |
files: { | |
'data.json': { | |
content: content | |
} | |
} | |
}; | |
// anonymous art.json | |
if (!token) | |
data.files['art.md'] = { | |
content: anonymousMessage | |
}; | |
request('post', '/gists', data, token ? editMessage.bind(null, callback) : callback); | |
}; | |
/** | |
* | |
* @param id | |
* @param content | |
* @param callback | |
*/ | |
github.editGist = function(id, content, callback) { | |
var data = { | |
files: { | |
'data.json': { | |
content: content | |
} | |
} | |
}; | |
request('patch', '/gists/' + id, data, callback); | |
}; | |
/** | |
* | |
* @param id | |
* @param callback | |
*/ | |
github.forkGist = function(id, callback) { | |
request('post', '/gists/' + id + '/forks', null, token ? editMessage.bind(null, callback) : callback); | |
}; | |
/** | |
* | |
* @param id | |
* @param callback | |
*/ | |
github.getGist = function(id, callback) { | |
request('get', '/gists/' + id, null, callback); | |
}; | |
/** | |
* | |
* @param {function} callback | |
* @param {object} err | |
* @param {object} res | |
* @private | |
*/ | |
function editMessage(callback, err, res) { | |
if (err) return callback(err); | |
// art.json with the correct link. | |
var data = { | |
files: { | |
'art.md': { | |
content: authenticatedMessage.replace('{0}', res.id) | |
} | |
} | |
}; | |
request('patch', '/gists/' + res.id, data, callback); | |
} | |
/** | |
* @param {string} method | |
* @param {string} uri | |
* @param {object} data | |
* @param {function} callback | |
* @private | |
*/ | |
function request(method, uri, data, callback) { | |
var qs = ''; | |
if (token) | |
qs = '?access_token=' + token; | |
reqwest({ | |
url: 'https://api.github.com' + uri + qs, | |
method: method, | |
type: 'json', | |
data: data ? JSON.stringify(data) : null, | |
error: callback, | |
success: callback.bind(null, null) | |
}); | |
} | |
// TODO: github init | |
/** | |
* @private | |
*/ | |
function fetchToken() { | |
// priority from url | |
if (~location.search.indexOf('?token=')) { | |
token = location.search.match(/\?token=(.{40})/)[1]; | |
localStorage.setItem('token', token); | |
// remove token from query string | |
location.replace(location.protocol + '//' + location.host + location.pathname); | |
} | |
// from local storage | |
else | |
token = localStorage.getItem('token'); | |
} | |
fetchToken(); | |
/** | |
* Exports. | |
*/ | |
module.exports = github; | |
},{}],3:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Private variables | |
*/ | |
var stack = []; | |
var sequence = null; | |
/** | |
* Module declaration. | |
*/ | |
var history = {}; | |
/** | |
* | |
* @param {function} fn | |
*/ | |
history.push = function(fn) { | |
if (!sequence) | |
return stack.push(fn); | |
sequence.push(fn); | |
}; | |
/** | |
* | |
*/ | |
history.startSequence = function() { | |
sequence = []; | |
}; | |
/** | |
* | |
*/ | |
history.stopSequence = function() { | |
var seq = sequence; | |
stack.push(function() { | |
seq.forEach(function(action) { | |
action(); | |
}); | |
}); | |
sequence = null; | |
}; | |
/** | |
* | |
* @returns {boolean} | |
*/ | |
history.isSequenced = function() { | |
return (null != sequence); | |
}; | |
/** | |
* | |
*/ | |
history.back = function() { | |
if (0 === stack.length) return; | |
stack.pop()(); | |
}; | |
/** | |
* Exports. | |
*/ | |
module.exports = history; | |
},{}],4:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Module dependencies. | |
*/ | |
var history = require('./history'); | |
/** | |
* Private variables | |
*/ | |
var canvasEl = document.getElementById('scene'); | |
var canvasOffset = new obelisk.Point(); | |
var scene; | |
var x, y;// TODO: screenPos | |
var viewPoint = new obelisk.Point3D(); // TODO: viewPos | |
var loopStarted = false; | |
var loopStopIn = 0; | |
var down = false; | |
var dragging = false; | |
var clickHandler; | |
var dragHandler; | |
var moveHandler; | |
/** | |
* Module declaration. | |
*/ | |
var pointer = {}; | |
/** | |
* | |
* @param {scene} _scene | |
* @returns {pointer} | |
*/ | |
pointer.init = function(_scene) { | |
var main = document.querySelector('#buildr'); | |
main.addEventListener('mousedown', onDown); | |
main.addEventListener('mousemove', onMove); | |
main.addEventListener('mouseup', onUp); | |
main.addEventListener('mouseleave', onUp); | |
window.addEventListener('resize', onResize); | |
Loop.on('tick', apply); | |
onResize(); | |
scene = _scene; | |
return pointer; | |
}; | |
/** | |
* | |
* @param {function} handler | |
* @returns {pointer} | |
*/ | |
pointer.click = function(handler) { | |
clickHandler = handler; | |
return pointer; | |
}; | |
/** | |
* | |
* @param {function} handler | |
* @returns {pointer} | |
*/ | |
pointer.drag = function(handler) { | |
dragHandler = handler; | |
return pointer; | |
}; | |
/** | |
* | |
* @param {function} handler | |
* @returns {pointer} | |
*/ | |
pointer.move = function(handler) { | |
moveHandler = handler; | |
return pointer; | |
}; | |
/** | |
* @private | |
*/ | |
function onDown() { | |
down = true; | |
} | |
/** | |
* @private | |
*/ | |
function onUp() { | |
// may happen when called by mouseleave | |
if (!down) return; | |
down = false; | |
if (!dragging) { | |
if (clickHandler) clickHandler(); | |
return; | |
} | |
dragging = false; | |
if (history.isSequenced()) | |
history.stopSequence(); | |
} | |
/** | |
* @param {event} e | |
* @private | |
*/ | |
function onMove(e) { | |
x = e.pageX - canvasOffset.x; | |
y = e.pageY - canvasOffset.y; | |
if (down && !dragging) | |
dragging = true; | |
if (!loopStarted) { | |
Loop.start(); | |
loopStarted = true; | |
} | |
loopStopIn = 1; | |
} | |
/** | |
* @private | |
*/ | |
function onResize() { | |
canvasOffset.x = canvasEl.offsetLeft; | |
canvasOffset.y = canvasEl.offsetTop; | |
} | |
/** | |
* @private | |
*/ | |
function apply() { | |
scene.screenToView(x, y, viewPoint); | |
scene.select(viewPoint); | |
if (dragging) { | |
if (dragHandler) dragHandler(); | |
return; | |
} | |
if (moveHandler) moveHandler(); | |
if (0 === loopStopIn) { | |
Loop.stop(); | |
loopStarted = false; | |
} | |
loopStopIn--; | |
} | |
/** | |
* Exports. | |
*/ | |
module.exports = pointer; | |
},{"./history":3}],5:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Module dependencies. | |
*/ | |
var github = require('./github'); | |
/** | |
* Private variables | |
*/ | |
var errors = { | |
sadSave: "could not save your awesome art on the cloud :(", | |
unknownGist: "it seems this gist does not exist anymore :(", | |
invalidGist: "this gist does not behaves well, loading failed :(", | |
forkFailed: "fork failed :(<br>does this gist still exists?" | |
}; | |
var gist; | |
/** | |
* Module declaration. | |
*/ | |
var storage = {}; | |
/** | |
* | |
* @param data | |
*/ | |
storage.local = function(data) { | |
localStorage.setItem(gist ? gist : 'orphan', JSON.stringify(data)); | |
}; | |
/** | |
* | |
* @returns {boolean} | |
*/ | |
storage.orphan = function() { | |
return (null == gist); | |
}; | |
/** | |
* | |
* @param {object} data | |
* @param {function} callback | |
*/ | |
storage.persist = function(data, callback) { | |
var content = JSON.stringify(data, null, 2), | |
action = 'created'; | |
// working on an existing gist? | |
if (gist) { | |
// edit it | |
github.editGist(gist, content, function(err, res) { | |
// tried to edit a gist that is not ours | |
if (err) { | |
if (401 == err.status || 404 == err.status) { | |
// fork it if we are authenticated | |
// anonymous gist can't be edited after being forked | |
if (github.authenticated()) { | |
github.forkGist(gist, function(err, res) { | |
if (err) return callback(errors.forkFailed); | |
// then add changes | |
action = 'forked gist ' + gist + ' to'; | |
github.editGist(res.id, content, onData); | |
}); | |
} | |
// if not, well, simply create it :p | |
else | |
github.newGist(content, onData); | |
} | |
else | |
callback(errors.sadSave); | |
return; | |
} | |
action = 'saved to'; | |
onData(err, res); | |
}); | |
return; | |
} | |
// create a new one | |
github.newGist(content, onData); | |
function onData(err, res) { | |
if (err) return callback(errors.sadSave); | |
// remove orphan data | |
if (storage.orphan()) | |
localStorage.removeItem('orphan'); | |
// set this gist as the current one | |
gist = res.id; | |
// and the last one we worked on | |
localStorage.setItem('last', gist); | |
// make sure the hash is up to date | |
if (gist != location.hash.slice(1)) | |
location.hash = gist; | |
// save it locally too | |
storage.local(data); | |
var info = { | |
id: res.id, | |
url: res.html_url, | |
action: action | |
}; | |
callback(null, info); | |
} | |
}; | |
/** | |
* | |
* @param {function} callback | |
*/ | |
storage.fetch = function(callback, data) { | |
// LOAD LOCAL DATA ( STATISTICS ) | |
// var data = { "colors":["7441408","9001384","13117481","15382272","15658734"], "data":[{"x":0,"y":0,"z":0,"c":2},{"x":0,"y":1,"z":0,"c":2},{"x":0,"y":1,"z":1,"c":2},{"x":0,"y":2,"z":0,"c":2},{"x":0,"y":2,"z":1,"c":2},{"x":0,"y":2,"z":2,"c":2},{"x":0,"y":2,"z":3,"c":2},{"x":0,"y":2,"z":4,"c":2},{"x":0,"y":2,"z":5,"c":2},{"x":0,"y":3,"z":0,"c":2},{"x":0,"y":3,"z":1,"c":2},{"x":0,"y":3,"z":2,"c":2},{"x":0,"y":3,"z":3,"c":2},{"x":0,"y":4,"z":0,"c":2},{"x":0,"y":4,"z":1,"c":2},{"x":0,"y":4,"z":2,"c":2},{"x":0,"y":5,"z":0,"c":2},{"x":0,"y":5,"z":1,"c":2},{"x":0,"y":5,"z":2,"c":2},{"x":0,"y":6,"z":0,"c":2},{"x":0,"y":6,"z":1,"c":2},{"x":0,"y":6,"z":2,"c":2},{"x":0,"y":6,"z":3,"c":2},{"x":0,"y":7,"z":0,"c":2},{"x":0,"y":7,"z":1,"c":2},{"x":0,"y":7,"z":2,"c":2},{"x":0,"y":7,"z":3,"c":2},{"x":0,"y":7,"z":4,"c":2},{"x":0,"y":7,"z":5,"c":2},{"x":0,"y":7,"z":6,"c":2},{"x":0,"y":8,"z":0,"c":2},{"x":0,"y":8,"z":1,"c":2},{"x":0,"y":8,"z":2,"c":2},{"x":0,"y":8,"z":3,"c":2},{"x":0,"y":8,"z":4,"c":2},{"x":0,"y":9,"z":0,"c":2},{"x":0,"y":9,"z":1,"c":2},{"x":0,"y":9,"z":2,"c":2},{"x":0,"y":9,"z":3,"c":2},{"x":0,"y":10,"z":0,"c":2},{"x":0,"y":10,"z":1,"c":2},{"x":0,"y":10,"z":2,"c":2},{"x":0,"y":11,"z":0,"c":2},{"x":0,"y":11,"z":1,"c":2},{"x":0,"y":12,"z":0,"c":2},{"x":0,"y":12,"z":1,"c":2},{"x":0,"y":12,"z":2,"c":2},{"x":0,"y":13,"z":0,"c":2},{"x":0,"y":13,"z":1,"c":2},{"x":0,"y":13,"z":2,"c":2},{"x":0,"y":13,"z":3,"c":2},{"x":0,"y":13,"z":4,"c":2},{"x":0,"y":14,"z":0,"c":2},{"x":0,"y":14,"z":1,"c":2},{"x":0,"y":14,"z":2,"c":2},{"x":0,"y":14,"z":3,"c":2},{"x":0,"y":14,"z":4,"c":2},{"x":0,"y":14,"z":5,"c":2},{"x":0,"y":15,"z":0,"c":2},{"x":0,"y":15,"z":1,"c":2},{"x":0,"y":15,"z":2,"c":2},{"x":0,"y":15,"z":3,"c":2},{"x":0,"y":15,"z":4,"c":2},{"x":0,"y":16,"z":0,"c":2},{"x":0,"y":16,"z":1,"c":2},{"x":0,"y":16,"z":2,"c":2},{"x":0,"y":16,"z":3,"c":2},{"x":0,"y":17,"z":0,"c":2},{"x":0,"y":17,"z":1,"c":2},{"x":0,"y":17,"z":2,"c":2},{"x":0,"y":18,"z":0,"c":2},{"x":0,"y":18,"z":1,"c":2},{"x":0,"y":19,"z":0,"c":2},{"x":4,"y":0,"z":0,"c":4},{"x":5,"y":0,"z":0,"c":0},{"x":5,"y":0,"z":1,"c":0},{"x":5,"y":0,"z":2,"c":0},{"x":5,"y":1,"z":0,"c":0},{"x":5,"y":1,"z":1,"c":0},{"x":5,"y":1,"z":2,"c":0},{"x":5,"y":1,"z":3,"c":0},{"x":5,"y":1,"z":4,"c":0},{"x":5,"y":2,"z":0,"c":0},{"x":5,"y":2,"z":1,"c":0},{"x":5,"y":2,"z":2,"c":0},{"x":5,"y":3,"z":0,"c":0},{"x":5,"y":3,"z":1,"c":0},{"x":5,"y":4,"z":0,"c":0},{"x":5,"y":5,"z":0,"c":0},{"x":5,"y":6,"z":0,"c":0},{"x":5,"y":7,"z":0,"c":0},{"x":5,"y":7,"z":1,"c":0},{"x":5,"y":8,"z":0,"c":0},{"x":5,"y":8,"z":1,"c":0},{"x":5,"y":9,"z":0,"c":0},{"x":5,"y":9,"z":1,"c":0},{"x":5,"y":9,"z":2,"c":0},{"x":5,"y":10,"z":0,"c":0},{"x":5,"y":10,"z":1,"c":0},{"x":5,"y":10,"z":2,"c":0},{"x":5,"y":10,"z":3,"c":0},{"x":5,"y":11,"z":0,"c":0},{"x":5,"y":11,"z":1,"c":0},{"x":5,"y":11,"z":2,"c":0},{"x":5,"y":11,"z":3,"c":0},{"x":5,"y":11,"z":4,"c":0},{"x":5,"y":11,"z":5,"c":0},{"x":5,"y":11,"z":6,"c":0},{"x":5,"y":11,"z":7,"c":0},{"x":5,"y":12,"z":0,"c":0},{"x":5,"y":12,"z":1,"c":0},{"x":5,"y":12,"z":2,"c":0},{"x":5,"y":12,"z":3,"c":0},{"x":5,"y":13,"z":0,"c":0},{"x":5,"y":13,"z":1,"c":0},{"x":5,"y":13,"z":2,"c":0},{"x":5,"y":14,"z":0,"c":0},{"x":5,"y":14,"z":1,"c":0},{"x":5,"y":14,"z":2,"c":0},{"x":5,"y":14,"z":3,"c":0},{"x":5,"y":15,"z":0,"c":0},{"x":5,"y":15,"z":1,"c":0},{"x":5,"y":15,"z":2,"c":0},{"x":5,"y":16,"z":0,"c":0},{"x":5,"y":16,"z":1,"c":0},{"x":5,"y":17,"z":0,"c":0},{"x":5,"y":17,"z":1,"c":0},{"x":5,"y":18,"z":0,"c":0},{"x":5,"y":18,"z":1,"c":0},{"x":5,"y":19,"z":0,"c":0},{"x":10,"y":1,"z":0,"c":3},{"x":10,"y":1,"z":1,"c":3},{"x":10,"y":1,"z":2,"c":3},{"x":10,"y":2,"z":0,"c":3},{"x":10,"y":2,"z":1,"c":3},{"x":10,"y":3,"z":0,"c":3},{"x":10,"y":3,"z":1,"c":3},{"x":10,"y":4,"z":0,"c":3},{"x":10,"y":4,"z":1,"c":3},{"x":10,"y":4,"z":2,"c":3},{"x":10,"y":4,"z":3,"c":3},{"x":10,"y":5,"z":0,"c":3},{"x":10,"y":5,"z":1,"c":3},{"x":10,"y":5,"z":2,"c":3},{"x":10,"y":6,"z":0,"c":3},{"x":10,"y":6,"z":1,"c":3},{"x":10,"y":6,"z":2,"c":3},{"x":10,"y":7,"z":0,"c":3},{"x":10,"y":7,"z":1,"c":3},{"x":10,"y":7,"z":2,"c":3},{"x":10,"y":8,"z":0,"c":3},{"x":10,"y":8,"z":1,"c":3},{"x":10,"y":8,"z":2,"c":3},{"x":10,"y":9,"z":0,"c":3},{"x":10,"y":9,"z":1,"c":3},{"x":10,"y":10,"z":0,"c":3},{"x":10,"y":11,"z":0,"c":3},{"x":10,"y":12,"z":0,"c":3},{"x":10,"y":12,"z":1,"c":3},{"x":10,"y":13,"z":0,"c":3},{"x":10,"y":13,"z":1,"c":3},{"x":10,"y":13,"z":2,"c":3},{"x":10,"y":14,"z":0,"c":3},{"x":10,"y":14,"z":1,"c":3},{"x":10,"y":14,"z":2,"c":3},{"x":10,"y":14,"z":3,"c":3},{"x":10,"y":15,"z":0,"c":3},{"x":10,"y":15,"z":1,"c":3},{"x":10,"y":15,"z":2,"c":3},{"x":10,"y":16,"z":0,"c":3},{"x":10,"y":16,"z":1,"c":3},{"x":10,"y":17,"z":0,"c":3},{"x":10,"y":18,"z":0,"c":3},{"x":10,"y":19,"z":0,"c":3},{"x":15,"y":0,"z":0,"c":1},{"x":15,"y":0,"z":1,"c":1},{"x":15,"y":0,"z":2,"c":1},{"x":15,"y":1,"z":0,"c":1},{"x":15,"y":1,"z":1,"c":1},{"x":15,"y":2,"z":0,"c":1},{"x":15,"y":3,"z":0,"c":1},{"x":15,"y":3,"z":1,"c":1},{"x":15,"y":3,"z":2,"c":1},{"x":15,"y":3,"z":3,"c":1},{"x":15,"y":4,"z":0,"c":1},{"x":15,"y":5,"z":0,"c":1},{"x":15,"y":6,"z":0,"c":1},{"x":15,"y":6,"z":1,"c":1},{"x":15,"y":7,"z":0,"c":1},{"x":15,"y":8,"z":0,"c":1},{"x":15,"y":9,"z":0,"c":1},{"x":15,"y":9,"z":1,"c":1},{"x":15,"y":9,"z":2,"c":1},{"x":15,"y":9,"z":3,"c":1},{"x":15,"y":9,"z":4,"c":1},{"x":15,"y":10,"z":0,"c":1},{"x":15,"y":10,"z":1,"c":1},{"x":15,"y":10,"z":2,"c":1},{"x":15,"y":11,"z":0,"c":1},{"x":15,"y":11,"z":1,"c":1},{"x":15,"y":12,"z":0,"c":1},{"x":15,"y":12,"z":1,"c":1},{"x":15,"y":13,"z":0,"c":1},{"x":15,"y":14,"z":0,"c":1},{"x":15,"y":15,"z":0,"c":1},{"x":15,"y":16,"z":0,"c":1},{"x":15,"y":16,"z":1,"c":1},{"x":15,"y":16,"z":2,"c":1},{"x":15,"y":16,"z":3,"c":1},{"x":15,"y":16,"z":4,"c":1},{"x":15,"y":16,"z":5,"c":1},{"x":15,"y":16,"z":6,"c":1},{"x":15,"y":17,"z":0,"c":1},{"x":15,"y":17,"z":1,"c":1},{"x":15,"y":17,"z":2,"c":1},{"x":15,"y":17,"z":3,"c":1},{"x":15,"y":18,"z":0,"c":1},{"x":15,"y":18,"z":1,"c":1},{"x":15,"y":18,"z":2,"c":1},{"x":15,"y":19,"z":0,"c":1}]}; | |
// LOAD DATA FROM IMAGE | |
return callback(null, JSON.parse(JSON.stringify(data)), 'LOADED DATA FROM IMAGE'); | |
/* CODE TEMPORARILY DISABLED | |
// priority to url | |
if (location.hash) { | |
gist = location.hash.slice(1); | |
// if it was a gist we were working on, load local data as it is more fresh | |
data = localStorage.getItem(gist); | |
if (data) | |
return callback(null, JSON.parse(data), 'loaded your last local changes for ' + gist); | |
// if not loads the gist | |
github.getGist(gist, function(err, res) { | |
if (err) return callback(errors.unknownGist); | |
var data; | |
try { | |
data = JSON.parse(res.files['data.json'].content); | |
} | |
catch (e) { | |
return callback(errors.invalidGist); | |
} | |
callback(null, data); | |
}); | |
return; | |
} | |
// well, load the last working gist? | |
gist = localStorage.getItem('last'); | |
data = localStorage.getItem(gist); | |
if (data) { | |
location.hash = gist; | |
return callback(null, JSON.parse(data), 'loaded your last saved stuff'); | |
} | |
// ok ok, load the last orphan art? | |
data = localStorage.getItem('orphan'); | |
if (data) return callback(null, JSON.parse(data), 'loaded your last local stuff'); | |
// i can't do nothing more dude, new one! | |
callback(null, null, 'new'); | |
*/ | |
}; | |
/** | |
* | |
*/ | |
storage.flush = function() { | |
localStorage.removeItem('last'); | |
location.hash = ''; | |
}; | |
module.exports = storage; | |
},{"./github":2}],6:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Module dependencies. | |
*/ | |
var tools = { | |
brush: require('./tools/brush'), | |
erase: require('./tools/erase') | |
}; | |
/** | |
* Private variables | |
*/ | |
var scene; | |
var current; | |
/** | |
* Module declaration. | |
*/ | |
var tool = {}; | |
/** | |
* | |
* @param _scene | |
* @returns {tool} | |
*/ | |
tool.init = function(_scene) { | |
scene = _scene; | |
return tool; | |
}; | |
/** | |
* | |
* @param type | |
* @returns {tool} | |
*/ | |
tool.use = function(type) { | |
current = tools[type]; | |
return tool; | |
}; | |
/** | |
* | |
* @param value | |
* @returns {tool} | |
*/ | |
tool.set = function(value) { | |
if (current.set) current.set(value); | |
return tool; | |
}; | |
/** | |
* | |
* @returns {tool} | |
*/ | |
tool.click = function() { | |
current.click(scene); | |
return tool; | |
}; | |
/** | |
* | |
* @returns {tool} | |
*/ | |
tool.drag = function() { | |
current.drag(scene); | |
return tool; | |
}; | |
/** | |
* Exports. | |
*/ | |
module.exports = tool; | |
},{"./tools/brush":7,"./tools/erase":8}],7:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Module dependencies. | |
*/ | |
var history = require('../history'); | |
/** | |
* Private variables | |
*/ | |
var color = obelisk.ColorPattern.GRAY; | |
/** | |
* Module declaration. | |
*/ | |
var brush = {}; | |
/** | |
* | |
* @param {string} value | |
*/ | |
brush.set = function(value) { | |
// strip # | |
value = value.slice(1); | |
// convert to number | |
value = parseInt(value, 16); | |
color = value; | |
}; | |
/** | |
* | |
* @param {scene} scene | |
*/ | |
brush.click = function(scene) { | |
if (scene.add(color)) | |
history.push(scene.remove.bind(scene, scene.selected().clone())); | |
}; | |
/** | |
* | |
* @param {scene} scene | |
*/ | |
brush.drag = function(scene) { | |
if (scene.add(color)) { | |
if (!history.isSequenced()) | |
history.startSequence(); | |
history.push(scene.remove.bind(scene, scene.selected().clone())); | |
} | |
}; | |
/** | |
* Exports. | |
*/ | |
module.exports = brush; | |
},{"../history":3}],8:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Module dependencies. | |
*/ | |
var history = require('../history'); | |
/** | |
* Module declaration. | |
*/ | |
var erase = {}; | |
/** | |
* | |
* @param {scene} scene | |
*/ | |
erase.click = function(scene) { | |
var color = scene.color(); | |
if (scene.remove()) | |
history.push(scene.add.bind(scene, | |
color, | |
scene.selected().clone() | |
)); | |
}; | |
/** | |
* | |
* @param {scene} scene | |
*/ | |
erase.drag = function(scene) { | |
var color = scene.color(); | |
if (scene.remove()) { | |
if (!history.isSequenced()) | |
history.startSequence(); | |
history.push(scene.add.bind(scene, | |
color, | |
scene.selected().clone() | |
)); | |
} | |
}; | |
/** | |
* Exports. | |
*/ | |
module.exports = erase; | |
},{"../history":3}],9:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Module dependencies. | |
*/ | |
var github = require('./../github'); | |
/** | |
* Private variables | |
*/ | |
var loginEl = document.querySelector('#auth .login'); | |
var loggedEl = document.querySelector('#auth .logged'); | |
/** | |
* Module declaration. | |
*/ | |
var auth = {}; | |
/** | |
* | |
*/ | |
auth.init = function() { | |
// login button | |
loginEl.addEventListener('click', onLoginBtnClick); | |
// logged button | |
loggedEl.addEventListener('click', onLoggedBtnClick); | |
// initial ui state | |
if (github.authenticated()) | |
loggedEl.classList.remove('is-hidden'); | |
else | |
loginEl.classList.remove('is-hidden'); | |
}; | |
/** | |
* @private | |
*/ | |
function toggle() { | |
loginEl.classList.toggle('is-hidden'); | |
loggedEl.classList.toggle('is-hidden'); | |
} | |
/** | |
* @param {event} e | |
* @private | |
*/ | |
function onLoginBtnClick(e) { | |
if (this.classList.contains('is-disabled')) return; | |
this.querySelector('span:first-child').innerText = 'wait for it...'; | |
this.classList.add('is-disabled'); | |
github.connect(); | |
} | |
/** | |
* @param {event} e | |
* @private | |
*/ | |
function onLoggedBtnClick(e) { | |
var res = confirm('Disconnect from Github?'); | |
if (!res) return; | |
github.disconnect(); | |
toggle(); | |
// avoids spacebar to trigger it again | |
this.blur(); | |
} | |
/** | |
* Exports. | |
*/ | |
module.exports = auth; | |
},{"./../github":2}],10:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Private variables | |
*/ | |
var el = document.querySelector('#help'); | |
var overlayEl = document.getElementById('overlay'); | |
/** | |
* Module declaration. | |
*/ | |
var help = {}; | |
help.toggle = function() { | |
el.classList.toggle('is-hidden'); | |
overlayEl.classList.toggle('is-hidden'); | |
}; | |
/** | |
* Exports. | |
*/ | |
module.exports = help; | |
},{}],11:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Exports. | |
*/ | |
module.exports = { | |
auth: require('./auth'), | |
notification: require('./notification'), | |
palette: require('./palette'), | |
scene: require('./scene'), | |
welcome: require('./welcome'), | |
help: require('./help') | |
}; | |
},{"./auth":9,"./help":10,"./notification":12,"./palette":13,"./scene":14,"./welcome":15}],12:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Private variables | |
*/ | |
var el = document.getElementById('notification'); | |
var timeout = null; | |
var queue = []; | |
var currentMessage; | |
var count = 0; | |
/** | |
* Module declaration. | |
*/ | |
var notification = {}; | |
/** | |
* | |
* @param {string} type | |
* @param {string} message | |
*/ | |
notification.push = function(type, message) { | |
// a message is being displayed, enqueue | |
if (timeout) { | |
// is it the same message? | |
// if so don't enqueue, add multiplier | |
if (message == currentMessage) { | |
el.innerHTML = message + ' (' + (++count) + ')'; | |
return; | |
} | |
// else enqueue | |
return queue.push({ | |
type: type, | |
message: message | |
}); | |
} | |
display(type, message); | |
}; | |
/** Shortcuts */ | |
notification.info = notification.push.bind(null, 'info'); | |
notification.error = notification.push.bind(null, 'error'); | |
/** | |
* @param {string} type | |
* @param {string} message | |
* @private | |
*/ | |
function display(type, message) { | |
el.innerHTML = message; | |
el.dataset.type = type; | |
el.classList.remove('is-hidden'); | |
timeout = setTimeout(onHide, 5000); | |
currentMessage = message; | |
} | |
/** | |
* @private | |
*/ | |
function onHide() { | |
el.classList.add('is-hidden'); | |
// messages in the queue, pop | |
if (queue.length > 0) { | |
var notif = queue.pop(); | |
setTimeout(display.bind(null, | |
notif.type, | |
notif.message | |
), 300); | |
return; | |
} | |
timeout = null; | |
currentMessage = null; | |
count = 0; | |
} | |
/** | |
* Exports. | |
*/ | |
module.exports = notification; | |
},{}],13:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Module dependencies. | |
*/ | |
var tool = require('./../tool'); | |
/** | |
* Private variables | |
*/ | |
var el = document.getElementById('palette'); | |
var overlayEl = document.getElementById('overlay'); | |
var active = document.querySelector('#palette .is-active'); | |
var visible = false; | |
var x, y; | |
var width, height; | |
/** | |
* Module declaration. | |
*/ | |
var palette = {}; | |
/** | |
* | |
*/ | |
palette.init = function() { | |
var style = getComputedStyle(el); | |
width = parseInt(style.width); | |
height = parseInt(style.height); | |
window.addEventListener('mousemove', function(e) { | |
x = e.clientX; | |
y = e.clientY; | |
}); | |
el.addEventListener('click', function(e) { | |
var btn = e.target; | |
if ('BUTTON' != btn.tagName) return; | |
if (active) | |
active.classList.remove('is-active'); | |
btn.classList.add('is-active'); | |
// tool selection and value | |
tool.use(btn.dataset.tool).set(btn.dataset.value); | |
active = e.target; | |
}); | |
}; | |
/** | |
* | |
*/ | |
palette.toggle = function() { | |
if (!visible) { | |
el.style.left = (x - width / 2) + 'px'; | |
el.style.top = (y - height / 2) + 'px'; | |
} | |
el.classList.toggle('is-hidden'); | |
overlayEl.classList.toggle('is-hidden'); | |
visible = !visible; | |
}; | |
/** | |
* | |
* @param {number} index | |
* @returns {string} | |
*/ | |
palette.color = function(index) { | |
var btn = el.querySelector('button:nth-child(' + (index + 1) + ')'); | |
return btn.dataset.value; | |
}; | |
/** | |
* Exports. | |
*/ | |
module.exports = palette; | |
},{"./../tool":6}],14:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Private variables | |
*/ | |
var canvasEl = document.getElementById('scene'); | |
var SIZE = 20; | |
var BLOCK_SIZE = 20; | |
var view; | |
var floor; | |
var cubes; | |
var blocks; | |
var origin; | |
var changed = false; | |
var changedHandler; | |
/** | |
* Module declaration. | |
*/ | |
var scene = {}; | |
/** | |
* | |
* @returns {scene} | |
*/ | |
scene.init = function() { | |
cubes = {}; | |
cubes[obelisk.ColorPattern.GRAY] = createCube(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, obelisk.ColorPattern.GRAY); | |
floor = { | |
normal: createBrick(BLOCK_SIZE, BLOCK_SIZE, '0xFF222222'), | |
elevated: createBrick(BLOCK_SIZE + 2, BLOCK_SIZE + 2, '0xFF222222'), | |
highlighted: createBrick(BLOCK_SIZE, BLOCK_SIZE, '0xFF444444'), | |
elevatedHighlighted: createBrick(BLOCK_SIZE + 2, BLOCK_SIZE + 2, '0xFF555555'), | |
selected: new obelisk.Point3D(-1, -1, 0), | |
offset: 0 | |
}; | |
blocks = matrix(SIZE); | |
scene.resize(); | |
return scene; | |
}; | |
/** | |
* | |
*/ | |
scene.resize = function() { | |
// 1:1 ratio | |
var style = getComputedStyle(canvasEl); | |
canvasEl.width = parseInt(style.width); | |
canvasEl.height = parseInt(style.height); | |
origin = new obelisk.Point(canvasEl.width / 2, canvasEl.height / 2); | |
view = new obelisk.PixelView(canvasEl, new obelisk.Point( | |
origin.x, origin.y | |
)); | |
var oldBlockSize = BLOCK_SIZE; | |
// small screens | |
if (canvasEl.width < 800 || canvasEl.height < 800) { | |
var size = Math.min(canvasEl.width, canvasEl.height); | |
// compute new block size | |
BLOCK_SIZE = Math.floor(size / 40); | |
// ensure it's even (obelisk needs it) | |
BLOCK_SIZE = BLOCK_SIZE - (BLOCK_SIZE % 2); | |
} | |
// ensure block size comes back to its original size | |
else | |
BLOCK_SIZE = 20; | |
// adapt existing geom to the correct size | |
if (oldBlockSize != BLOCK_SIZE) { | |
for (var color in cubes) { | |
if (!cubes.hasOwnProperty(color)) continue; | |
cubes[color] = createCube(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, parseInt(color)); | |
} | |
floor.normal = createBrick(BLOCK_SIZE, BLOCK_SIZE, '0xFF222222'); | |
floor.elevated = createBrick(BLOCK_SIZE + 2, BLOCK_SIZE + 2, '0xFF222222'); | |
floor.highlighted = createBrick(BLOCK_SIZE, BLOCK_SIZE, '0xFF444444'); | |
floor.elevatedHighlighted = createBrick(BLOCK_SIZE + 2, BLOCK_SIZE + 2, '0xFF555555'); | |
} | |
scene.draw(); | |
}; | |
/** | |
* | |
*/ | |
scene.draw = function() { | |
view.clear(); | |
drawBlocks(view, blocks, cubes, 0, floor.offset); | |
drawFloor(view, floor); | |
drawBlocks(view, blocks, cubes, floor.offset, SIZE); | |
}; | |
/** | |
* | |
* @param {number} x | |
* @param {number} y | |
* @param {obelisk.Point3D} point | |
*/ | |
scene.screenToView = function(x, y, point) { | |
x -= origin.x; | |
y -= origin.y; | |
point.x = Math.floor(((x + 2 * y) / 2) / BLOCK_SIZE) + floor.offset; | |
point.y = Math.floor(((-x + 2 * y) / 2) / BLOCK_SIZE) + floor.offset; | |
point.z = floor.offset; | |
}; | |
/** | |
* | |
* @param {obelisk.Point3D} point | |
*/ | |
scene.select = function(point) { | |
clampBounds(point); | |
floor.selected.x = point.x; | |
floor.selected.y = point.y; | |
floor.selected.z = point.z; | |
scene.draw(); | |
}; | |
/** | |
* | |
* @returns {obelisk.Point} | |
*/ | |
scene.selected = function() { | |
return floor.selected; | |
}; | |
/** | |
* | |
* @param {obelisk.Point3D} point | |
* @returns {number|null} | |
*/ | |
scene.color = function(point) { | |
point = point || scene.selected(); | |
var block = blocks[point.x][point.y][point.z]; | |
if (!block) return null; | |
return block.color; | |
}; | |
/** | |
* | |
* @param {number} color | |
* @param {obelisk.Point3D} point | |
* @returns {boolean} | |
*/ | |
scene.add = function(color, point) { | |
point = point || floor.selected; | |
// already exists | |
if (null != blocks[point.x][point.y][point.z]) return false; | |
// if a cube with the given color does not exist, create it | |
if (null == cubes[color]) | |
cubes[color] = createCube(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, color); | |
var block = point.clone(); | |
block.color = color; | |
blocks[block.x][block.y][block.z] = block; | |
scene.draw(); | |
changed = true; | |
if (changedHandler) changedHandler(); | |
return true; | |
}; | |
/** | |
* | |
* @param {obelisk.Point3D} point | |
* @returns {boolean} | |
*/ | |
scene.remove = function(point) { | |
point = point || floor.selected; | |
if (null == blocks[point.x][point.y][point.z]) return false; | |
blocks[point.x][point.y][point.z] = null; | |
scene.draw(); | |
changed = true; | |
if (changedHandler) changedHandler(); | |
return true; | |
}; | |
/** | |
* | |
* @param {number} delta | |
*/ | |
scene.adjustFloor = function(delta) { | |
floor.offset += delta; | |
if (floor.offset < 0) floor.offset = 0; | |
else if (floor.offset >= SIZE) floor.offset = SIZE - 1; | |
scene.draw(); | |
}; | |
/** | |
* | |
* @param {number} direction | |
*/ | |
scene.rotate = function(direction) { | |
var b = blocks, | |
n = SIZE, | |
x, y, z, start, end; | |
// transpose | |
for (z = 0; z < n; z++) | |
for (x = 0; x < n; x++) | |
for (y = 0; y < n; y++) | |
if (x < y) swap(b, x, y, y, x, z); | |
if (1 === direction) { | |
// reverse rows | |
for (z = 0; z < n; z++) | |
for (x = 0; x < n; x++) | |
for (start = 0, end = n - 1; start < end; start++, end--) | |
swap(b, x, start, x, end, z); | |
} | |
else if (-1 == direction) { | |
// reverse cols | |
for (z = 0; z < n; z++) | |
for (y = 0; y < n; y++) | |
for (start = 0, end = n - 1; start < end; start++, end--) | |
swap(b, start, y, end, y, z); | |
} | |
scene.draw(); | |
}; | |
/** | |
* | |
* @param {boolean} silent | |
* @returns {object} | |
*/ | |
scene.save = function(silent) { | |
var data = []; | |
// creates a color table | |
var colors = [], colorsHash = {}; | |
for (var p in cubes) { | |
if (!cubes.hasOwnProperty(p)) continue; | |
colorsHash[p] = colors.length; | |
colors.push(p); | |
} | |
// basically "compact" the memory structure by only saving existing blocks, | |
// referencing colors in color table, with short properties name | |
for (var x = 0; x < SIZE; x++) { | |
for (var y = 0; y < SIZE; y++) { | |
for (var z = 0; z < SIZE; z++) { | |
if (null != blocks[x][y][z]) { | |
var b = blocks[x][y][z]; | |
data.push({ | |
x: b.x, | |
y: b.y, | |
z: b.z, | |
c: colorsHash[b.color] | |
}); | |
} | |
} | |
} | |
} | |
if (!silent) changed = false; | |
return { | |
colors: colors, | |
data: data | |
}; | |
}; | |
/** | |
* | |
* @param {object} data | |
*/ | |
scene.load = function( data, colorFormat ) { | |
var i; | |
// ensure colors are numbers | |
var colors = data.colors; | |
for (i = 0; i < colors.length; i++) | |
colors[i] = parseInt(colors[i]); | |
data = data.data; | |
blocks = matrix(SIZE); | |
function componentToHex(c) { | |
var hex = c.toString(16); | |
return hex.length == 1 ? "0" + hex : hex; | |
} | |
function rgbToHex(r, g, b) { | |
return "0x" + componentToHex(r) + componentToHex(g) + componentToHex(b); | |
} | |
var currentColor; | |
for (i = 0; i < data.length; i++){ | |
currentColor = ( colorFormat === "rgba" ) ? parseInt( rgbToHex( data[i].rgba[0], data[i].rgba[1], data[i].rgba[2] ) ) : colors[data[i].c]; | |
scene.add( currentColor, new obelisk.Point3D(data[i].x, data[i].y, data[i].z) ); | |
} | |
scene.draw(); | |
changed = false; | |
}; | |
/** | |
* | |
* @returns {string} | |
*/ | |
scene.snapshot = function() { | |
// isolate art | |
view.clear(); | |
view.context.fillStyle = '#222222'; | |
view.context.fillRect(0, 0, canvasEl.width, canvasEl.height); | |
drawBlocks(view, blocks, cubes, 0, SIZE); | |
var image = canvasEl.toDataURL("image/png"); | |
scene.draw(); | |
return image; | |
}; | |
/** | |
* | |
*/ | |
scene.clear = function() { | |
blocks = matrix(SIZE); | |
scene.draw(); | |
}; | |
/** | |
* | |
* @param {function} callback | |
* @returns {boolean|undefined} | |
*/ | |
scene.changed = function(callback) { | |
if (!callback) return changed; | |
changedHandler = callback; | |
return this; | |
}; | |
/** | |
* | |
* @param {number} width | |
* @param {number} height | |
* @param {string} hexColor | |
* @returns {obelisk.Brick} | |
* @private | |
*/ | |
function createBrick(width, height, hexColor) { | |
var dimension = new obelisk.BrickDimension(width, height); | |
var color = new obelisk.SideColor().getByInnerColor(hexColor); | |
return new obelisk.Brick(dimension, color, false); | |
} | |
/** | |
* | |
* @param {number} width | |
* @param {number} height | |
* @param {number} depth | |
* @param {string} hexColor | |
* @returns {obelisk.Cube} | |
* @private | |
*/ | |
function createCube(width, height, depth, hexColor) { | |
var dimension = new obelisk.CubeDimension(width, height, depth); | |
var color = new obelisk.CubeColor( | |
obelisk.ColorGeom.applyBrightness(hexColor, -20 * 4), | |
obelisk.ColorGeom.applyBrightness(hexColor, 60), | |
obelisk.ColorGeom.applyBrightness(hexColor, -20 * 2), | |
obelisk.ColorGeom.applyBrightness(hexColor, -20), | |
hexColor | |
); | |
return new obelisk.Cube(dimension, color); | |
} | |
/** | |
* | |
* @param {obelisk.Point3D} point | |
* @private | |
*/ | |
function clampBounds(point) { | |
if (point.x < 0) point.x = 0; | |
else if (point.x >= SIZE) point.x = SIZE - 1; | |
if (point.y < 0) point.y = 0; | |
else if (point.y >= SIZE) point.y = SIZE - 1; | |
if (point.z < 0) point.z = 0; | |
else if (point.z >= SIZE) point.z = SIZE - 1; | |
} | |
/** | |
* | |
* @param {number} size | |
* @returns {array} | |
* @private | |
*/ | |
function matrix(size) { | |
var m = new Array(size); | |
for (var x = 0; x < size; x++) { | |
m[x] = new Array(size); | |
for (var y = 0; y < size; y++) { | |
m[x][y] = new Array(size); | |
} | |
} | |
return m; | |
} | |
/** | |
* | |
* @param {number} m | |
* @param {number} x1 | |
* @param {number} y1 | |
* @param {number} x2 | |
* @param {number} y2 | |
* @param {number} z | |
* @private | |
*/ | |
function swap(m, x1, y1, x2, y2, z) { | |
var tmp = m[x2][y2][z], c; | |
c = m[x2][y2][z] = m[x1][y1][z]; | |
if (c) { | |
c.x = x2; | |
c.y = y2; | |
} | |
c = m[x1][y1][z] = tmp; | |
if (c) { | |
c.x = x1; | |
c.y = y1; | |
} | |
} | |
/** | |
* | |
* @param {obelisk.PixelView} view | |
* @param {object} floor | |
* @private | |
*/ | |
function drawFloor(view, floor) { | |
var normal = floor.normal, | |
highlighted = floor.highlighted, | |
point = new obelisk.Point3D(); | |
if (floor.offset > 0) { | |
normal = floor.elevated; | |
highlighted = floor.elevatedHighlighted; | |
view.context.globalAlpha = 0.7; | |
} | |
for (var x = 0; x < 20; x++) { | |
for (var y = 0; y < 20; y++) { | |
if (x == floor.selected.x && y == floor.selected.y) continue; | |
point.x = x * BLOCK_SIZE; | |
point.y = y * BLOCK_SIZE; | |
point.z = floor.offset * BLOCK_SIZE; | |
view.renderObject(normal, point); | |
} | |
} | |
if (-1 != floor.selected.x) { | |
point.x = floor.selected.x * BLOCK_SIZE; | |
point.y = floor.selected.y * BLOCK_SIZE; | |
point.z = floor.offset * BLOCK_SIZE; | |
view.renderObject(highlighted, point); | |
} | |
view.context.globalAlpha = 1; | |
} | |
/** | |
* | |
* @param {obelisk.PixelView} view | |
* @param {array} blocks | |
* @param {object} cubes | |
* @param {number} startZ | |
* @param {number} endZ | |
* @private | |
*/ | |
function drawBlocks(view, blocks, cubes, startZ, endZ) { | |
var point = new obelisk.Point3D(); | |
for (var x = 0; x < SIZE; x++) { | |
for (var y = 0; y < SIZE; y++) { | |
for (var z = startZ; z < endZ; z++) { | |
var block = blocks[x][y][z]; | |
if (!block) continue; | |
point.x = block.x * BLOCK_SIZE; | |
point.y = block.y * BLOCK_SIZE; | |
point.z = block.z * BLOCK_SIZE; | |
view.renderObject(cubes[block.color], point); | |
} | |
} | |
} | |
} | |
/** | |
* Exports. | |
*/ | |
module.exports = scene; | |
},{}],15:[function(require,module,exports){ | |
/*! | |
* obelisk-builder | |
* Copyright (c) 2013 Nicolas Gryman <[email protected]> | |
* MIT Licensed | |
*/ | |
'use strict'; | |
/** | |
* Private variables | |
*/ | |
var el = document.querySelector('#welcome'); | |
var overlayEl = document.getElementById('overlay'); | |
var onHideCallback; | |
/** | |
* Module declaration. | |
*/ | |
var welcome = {}; | |
/** | |
* | |
*/ | |
welcome.init = function(callback) { | |
if (localStorage.getItem('visited')) return callback(); | |
window.addEventListener('load', function() { | |
setTimeout(show, 500); | |
}); | |
onHideCallback = callback; | |
}; | |
/** | |
* @private | |
*/ | |
function show() { | |
toggle(); | |
document.addEventListener('keypress', hide); | |
localStorage.setItem('visited', true); | |
} | |
/** | |
* @private | |
*/ | |
function hide() { | |
document.removeEventListener('keypress', hide); | |
toggle(); | |
onHideCallback(); | |
} | |
/** | |
* @private | |
*/ | |
function toggle() { | |
el.classList.toggle('is-hidden'); | |
overlayEl.classList.toggle('is-hidden'); | |
} | |
/** | |
* Exports. | |
*/ | |
module.exports = welcome; | |
},{}]},{},[1]); | |
app.init(); |
@font-face { | |
font-family: Lato; | |
src: url('https://github.com/ngryman/obelisk-buildr/raw/master/fonts/lato.woff?92048847') format('woff'), | |
url('https://github.com/ngryman/obelisk-buildr/raw/master/fonts/lato.ttf?92048847') format('truetype'); | |
font-weight: normal; | |
font-style: normal; | |
} | |
#auth button { | |
display: inline-block; | |
vertical-align: middle; | |
margin: 0; | |
padding: 8px; | |
color: #eee; | |
background-color: transparent; | |
cursor: pointer; | |
} | |
#auth button.is-disabled, | |
#auth button:active { | |
color: #999; | |
} | |
#auth button > span { | |
display: inline-block; | |
vertical-align: middle; | |
} | |
#auth button .icon { | |
margin-left: 10px; | |
font-size: 25px; | |
width: 25px; | |
} | |
#auth button.login { | |
border: 1px solid #444; | |
background: #000; | |
} | |
#auth button.login .icon { | |
text-shadow: 0 0 2px #eee; | |
} | |
#auth button.logged { | |
color: #00B2B2; | |
} | |
#auth button.logged .icon { | |
-webkit-animation: glow 4s linear infinite; | |
animation: glow 4s linear infinite; | |
} | |
#auth button.is-hidden { | |
display: none; | |
} | |
@-webkit-keyframes glow { | |
50% { | |
text-shadow: 0 0 20px #00B2B2; | |
} | |
} | |
@keyframes glow { | |
50% { | |
text-shadow: 0 0 20px #00B2B2; | |
} | |
} | |
/** position fixed on small screens when they are in landscape mode */ | |
@media (orientation: landscape) and (max-height: 400px) { | |
#auth { | |
position: fixed; | |
top: 0; | |
right: 0; | |
} | |
} | |
* { | |
-moz-box-sizing: border-box; | |
box-sizing: border-box; | |
} | |
a, | |
a:active | |
a:visited { | |
color: #eee; | |
} | |
a:active { | |
text-decoration: none; | |
} | |
button { | |
margin: 2px; | |
padding: 0; | |
border: none; | |
outline: none; | |
} | |
html, body, main { | |
margin: 0; | |
width: 100%; | |
height: 100%; | |
overflow: hidden; | |
} | |
body { | |
min-width: 320px; | |
background-color: #111; | |
color: #eee; | |
font-family: Lato, Arial, sans-serif; | |
-webkit-user-select: none; | |
-moz-user-select: none; | |
-ms-user-select: none; | |
user-select: none; | |
} | |
main { | |
text-align: center; | |
} | |
@media (min-width: 700px) and (min-height: 700px), (min-height: 700px) { | |
main { | |
padding-top: 70px; | |
padding-bottom: 70px; | |
} | |
} | |
#buildr { | |
height: 95%; /* Stretching a little... */margin-top: -30px; | |
} | |
#overlay { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background: #000; | |
opacity: .3; | |
transition: opacity 200ms; | |
-webkit-backface-visibility: hidden; | |
backface-visibility: hidden; | |
} | |
#overlay.is-hidden { | |
opacity: 0; | |
pointer-events: none; | |
} | |
footer { | |
display: none; | |
} | |
@media (min-width: 700px) and (min-height: 700px), (min-height: 700px) { | |
footer { | |
display: block; | |
position: absolute; | |
bottom: 15px; | |
left: 0; | |
padding: 10px; | |
width: 100%; | |
text-align: center; | |
color: #999; | |
} | |
footer a { | |
padding: 6px; | |
color: #999; | |
font-size: 14px; | |
text-decoration: none; | |
text-shadow: 0 0 2px black; | |
border-radius: 4px; | |
transition: all 200ms; | |
} | |
footer a:hover { | |
background: black; | |
} | |
footer a strong, | |
footer a em { | |
font-style: normal; | |
font-weight: normal; | |
color: #eee; | |
} | |
footer a strong { | |
transition: all 200ms 200ms; | |
} | |
footer a strong:hover { | |
text-shadow: 0 0 1px #fff; | |
} | |
} | |
header { | |
display: block; | |
position: absolute; | |
z-index: 1; | |
padding: 6px 15px; | |
width: 100%; | |
text-align: justify; | |
} | |
header::after { | |
content: ''; | |
display: inline-block; | |
width: 100%; | |
height: 0; | |
font-size: 0; | |
line-height: 0; | |
} | |
header > * { | |
display: inline-block; | |
vertical-align: middle; | |
} | |
header h1 { | |
margin: 0; | |
height: 54px; | |
line-height: 54px; | |
color: #fff; | |
text-align: left; | |
font-weight: 300; | |
} | |
header h1 span { | |
color: #00B2B2; | |
} | |
header h1:before { | |
content: ''; | |
display: inline-block; | |
vertical-align: text-top; | |
margin-right: 15px; | |
width: 40px; | |
height: 40px; | |
background-image: url(http://ngryman.sh/obelisk-buildr/logo.png); | |
background-position: left center; | |
background-repeat: no-repeat; | |
background-size: 40px; | |
-webkit-animation: doodle 4s linear infinite; | |
animation: doodle 4s linear infinite; | |
} | |
@-webkit-keyframes doodle { | |
25% { -webkit-transform: rotate(5deg); transform: rotate(5deg); } | |
75% { -webkit-transform: rotate(-5deg); transform: rotate(-5deg); } | |
} | |
@keyframes doodle { | |
25% { -webkit-transform: rotate(5deg); transform: rotate(5deg); } | |
75% { -webkit-transform: rotate(-5deg); transform: rotate(-5deg); } | |
} | |
/** | |
* hide on small screens when they are in landscape mode | |
* | |
* [1]: using top instead of transform, because we can't have | |
* position fixed elements in transformed elements. This | |
* is needed for github auth buttons on small screens. | |
*/ | |
@media (orientation: landscape) and (max-height: 400px) { | |
header { | |
top: -70px; /* [1] */ | |
} | |
} | |
#help { | |
top: 25%; | |
left: 0; | |
width: 300px; | |
} | |
#help.is-hidden { | |
opacity: 0; | |
-webkit-transform: translateX(-100%) scale(.8); | |
transform: translateX(-100%) scale(.8); | |
} | |
.icon { | |
display: inline-block; | |
font-style: normal; | |
font-weight: normal; | |
speak: none; | |
text-decoration: inherit; | |
width: 1em; | |
margin-right: .2em; | |
text-align: center; | |
} | |
.icon-git:before { content: '\e801'; } | |
.icon-github:before { content: '\e800'; } | |
/** | |
* [1]: fixes blurry text on Chrome because of transform... | |
*/ | |
#notification { | |
position: absolute; | |
top: 0; | |
left: 50%; | |
z-index: 1; | |
width: 100%; | |
max-width: 400px; | |
padding: 5px 40px; | |
color: #fff; | |
font-size: 16px; /* [1] */ | |
-webkit-transform: translateX(-50%); /* [1] */ | |
transform: translateX(-50%); | |
transition: -webkit-transform 300ms; | |
transition: transform 300ms; | |
} | |
#notification.is-hidden { | |
-webkit-transform: translate(-50%, -200%); | |
transform: translate(-50%, -200%); | |
} | |
#notification a, | |
#notification a:active | |
#notification a:visited { | |
color: #fff; | |
} | |
#notification[data-type=info] { | |
background-color: #00B2B2; | |
} | |
#notification[data-type=error] { | |
background-color: #c82829; | |
} | |
#palette { | |
position: fixed; | |
z-index: 1; | |
padding: 5px; | |
width: 200px; | |
background: rgba(17, 17, 17, .9); | |
opacity: 1; | |
text-align: left; | |
-webkit-transform: scale(1); | |
transform: scale(1); | |
/*transform: translateX(-50%) translateY(-50%);*/ | |
-webkit-backface-visibility: hidden; | |
/*transform: translateX(-50%) translateY(-50%);*/ | |
backface-visibility: hidden; | |
border: 1px solid #444; | |
box-shadow: 0 0 0 1px #000, 0 0 15px rgba(0, 0, 0, .5); | |
transition: opacity 100ms, -webkit-transform 100ms; | |
transition: opacity 100ms, transform 100ms; | |
} | |
#palette.is-hidden { | |
opacity: 0; | |
-webkit-transform: scale(.7); | |
transform: scale(.7); | |
pointer-events: none; | |
} | |
#palette button { | |
width: 30px; | |
height: 30px; | |
font-size: 10px; | |
} | |
#palette button.is-active { | |
box-shadow: 0 0 0 1px rgba(255, 255, 255, .4) inset; | |
} | |
#palette .red { | |
background: linear-gradient(#c82829, rgba(200, 40, 41, 0.80)); | |
} | |
#palette .red:active { | |
background: linear-gradient(#af2829, rgba(175, 40, 41, 0.80)); | |
} | |
#palette .orange { | |
background: linear-gradient(#f5871f, rgba(245, 135, 31, 0.80)); | |
} | |
#palette .orange:active { | |
background: linear-gradient(#c8651f, rgba(200, 104, 31, 0.80)); | |
} | |
#palette .yellow { | |
background: linear-gradient(#eab700, rgba(234, 183, 0, 0.80)); | |
} | |
#palette .yellow:active { | |
background: linear-gradient(#bd8b00, rgba(189, 147, 0, 0.80)); | |
} | |
#palette .green { | |
background: linear-gradient(#718c00, rgba(113, 140, 0, 0.80)); | |
} | |
#palette .green:active { | |
background: linear-gradient(#475f00, rgba(71, 95, 0, 0.80)); | |
} | |
#palette .aqua { | |
background: linear-gradient(#3e999f, rgba(62, 153, 159, 0.81)); | |
} | |
#palette .aqua:active { | |
background: linear-gradient(#396c72, rgba(53, 108, 114, 0.81)); | |
} | |
#palette .blue { | |
background: linear-gradient(#4271ae, rgba(66, 113, 174, 0.81)); | |
} | |
#palette .blue:active { | |
background: linear-gradient(#404681, rgba(62, 71, 129, 0.81)); | |
} | |
#palette .purple { | |
background: linear-gradient(#8959a8, rgba(137, 89, 168, 0.80)); | |
} | |
#palette .purple:active { | |
background: linear-gradient(#5c3b7b, rgba(93, 59, 123, 0.80)); | |
} | |
#palette .black { | |
background: linear-gradient(#4d4d4c, rgba(77, 77, 76, 0.80)); | |
} | |
#palette .black:active { | |
background: linear-gradient(#20201f, rgba(32, 32, 31, 0.80)); | |
} | |
#palette .white { | |
background: linear-gradient(#ddd, rgba(221, 221, 221, 0.80)); | |
} | |
#palette .white:active { | |
background: linear-gradient(#b0b0b0, rgba(176, 176, 176, 0.80)); | |
} | |
.pane { | |
position: fixed; | |
z-index: 1; | |
padding: 15px 30px; | |
background: rgba(17, 17, 17, .9); | |
border: 1px solid #444; | |
box-shadow: 0 0 0 1px #000, 0 0 15px rgba(0, 0, 0, .5); | |
transition: all 300ms; | |
border-radius: 2px; | |
} | |
.pane h2 { | |
font-weight: 300; | |
} | |
.pane ul { | |
margin-top: 20px; | |
padding-left: 20px; | |
} | |
.pane p { | |
text-align: left; | |
} | |
.pane b { | |
margin: 0 2px; | |
padding: 0 2px; | |
font-weight: 300; | |
color: #000; | |
background: #fff; | |
} | |
#scene { | |
width: 100%; | |
height: 100%; | |
-webkit-backface-visibility: hidden; | |
backface-visibility: hidden; | |
} | |
@media (min-width: 800px) { | |
#scene { | |
width: 800px; | |
} | |
} | |
#welcome { | |
top: 70px; | |
width: 100%; | |
-webkit-transform: scale(1) rotate(0deg); | |
transform: scale(1) rotate(0deg); | |
transition: all 500ms; | |
} | |
@media (min-width: 500px) and (min-height: 600px) { | |
/** | |
* [1]: fixes blurry text on Chrome because of transform -50%... | |
*/ | |
#welcome { | |
left: 50%; | |
margin-left: -250px; /* [1] */ | |
width: 500px; | |
} | |
} | |
@media (min-height: 700px) { | |
#welcome { | |
top: 25%; | |
} | |
} | |
#welcome.is-hidden { | |
opacity: 0; | |
-webkit-transform: scale(0) rotate(720deg); | |
transform: scale(0) rotate(720deg); | |
} | |
.thumbnails { | |
list-style: none; | |
margin: 10px 0 8px 0; | |
display: inline-block; | |
} | |
.thumbnails li { | |
display: inline; | |
margin: 10px; | |
} | |
.thumbnails li.active { | |
border-top: 10px solid rgb(70, 157, 70); | |
} | |
.currently { | |
margin: 0; | |
padding: 0 0 0 0; | |
display: inline-block; | |
font-size: 18px; | |
margin-right: 25px; | |
} | |
.select { | |
font-size: 18px; | |
margin: 0; | |
} | |
.drop-image { | |
display: none; | |
} | |
.drop-zone { | |
display: inline-block; | |
height: 20px; | |
width: 20px; | |
border: 2px dashed #666; | |
margin-left: 10px; | |
margin-right: 10px; | |
} | |
.drop-over { | |
border-color: #CACACA; | |
background-color: #2d2d2d; | |
} |