diff --git a/README.md b/README.md
index 7a87fff7..989e8723 100644
--- a/README.md
+++ b/README.md
@@ -5,11 +5,24 @@ The goal is to create an easy-to-use/in-the-cloud/web-based 2d animation editor.
Try it at : http://juliandescottes.github.com/piskel/
-v0.0something (with 2 pull requests from grosbouddha)
+v0.0almostthere
+------------------------------------
+**30 Aug 2012** : Many new features in 2 days :
+* __save animations__, they are persisted in the cloud, and can be retrieved via a __unique URL__
+* __color picker__, no longer limited to black and white
+* __local storage__, your work is automatically backed up locally
+* __color palette__, listing all the colors already used in the animation
+* __slider__ for choosing the speed of the preview
+
+UI was slightly updated :
+
+![Screenshot 2](https://dl.dropbox.com/u/17803671/screen_piskel_2.png "Screenshot 2")
+
+v0.0something
------------------------------------
**28 Aug 2012** : Thanks to grosbouddha, new features added to Piskel :
* modify preview speed !
-* remove (shitty) frames
+* remove frames
* transparent background
v0.0whatever (aka the thing I did last night)
diff --git a/css/style.css b/css/style.css
index d9011854..8ef86e8d 100644
--- a/css/style.css
+++ b/css/style.css
@@ -152,7 +152,8 @@ ul, li {
border: #F0C36D 1px solid;
border-bottom: 0;
font-weight: bold;
- font-size: 14px;
+ font-size: 14px;
+ z-index: 10000;
}
/* Force apparition of scrollbars on leopard */
diff --git a/js/piskel.js b/js/piskel.js
index 350456fa..1064ecf8 100644
--- a/js/piskel.js
+++ b/js/piskel.js
@@ -55,6 +55,7 @@
var frameId = this.getFrameIdFromUrl();
if (frameId) {
+ this.displayMessage("Loading animation with id : [" + frameId + "]");
this.loadFramesheetFromService(frameId);
} else {
this.finishInit();
@@ -86,10 +87,12 @@
xhr.onload = function(e) {
frameSheet.deserialize(this.responseText);
+ piskel.removeMessage();
piskel.finishInit();
};
xhr.onerror = function () {
+ piskel.removeMessage();
piskel.finishInit();
};
@@ -98,16 +101,25 @@
initLocalStorageBackup: function() {
if(window.localStorage && window.localStorage['snapShot']) {
- var message = document.createElement('div');
- message.id = "user-message";
- message.className = "user-message";
var reloadLink = "reload";
var discardLink = "discard";
- message.innerHTML = "Non saved version found. " + reloadLink + " or " + discardLink;
- message.onclick = function() {
- message.parentNode.removeChild(message);
- };
- document.body.appendChild(message);
+ this.displayMessage("Non saved version found. " + reloadLink + " or " + discardLink);
+ }
+ },
+
+ displayMessage : function (content) {
+ var message = document.createElement('div');
+ message.id = "user-message";
+ message.className = "user-message";
+ message.innerHTML = content;
+ message.onclick = this.removeMessage;
+ document.body.appendChild(message);
+ },
+
+ removeMessage : function () {
+ var message = $("user-message");
+ if (message) {
+ message.parentNode.removeChild(message);
}
},
diff --git a/preview/css/piskel.css b/preview/css/piskel.css
deleted file mode 100644
index c384327b..00000000
--- a/preview/css/piskel.css
+++ /dev/null
@@ -1,36 +0,0 @@
-html, body {
- height : 100%;
-}
-
-.debug {
- border : 1px Solid black;
-}
-
-.left-nav {
- position:absolute;
- top : 0;
- bottom : 0;
- width : 200px;
- background : #000;
-}
-
-.main-panel {
- position:absolute;
- top : 0;
- bottom : 0;
- left : 200px;
- right : 0;
- background : #ccc;
-}
-
-.preview-container {
- position : absolute;
- top : 30px;
- right : 0;
- height : 200px;
- width : 200px;
- background : white;
- border : 0px Solid black;
- border-radius:5px 0px 0px 5px;
- box-shadow : 0px 0px 2px rgba(0,0,0,0.2);
-}
\ No newline at end of file
diff --git a/preview/css/style.css b/preview/css/style.css
deleted file mode 100644
index 9136c5f0..00000000
--- a/preview/css/style.css
+++ /dev/null
@@ -1,140 +0,0 @@
-html, body {
- height : 100%;
- margin : 0;
- cursor : default;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -khtml-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-ul, li {
- margin : 0;
- padding : 0;
-}
-
-.debug {
- border : 1px Solid black;
-}
-
-.left-nav {
- position:absolute;
- top : 0;
- bottom : 0;
- width : 200px;
- overflow-y: scroll;
- background : #000;
- padding : 10px;
-}
-
-.main-panel {
- position:absolute;
- top : 0;
- bottom : 0;
- left : 220px;
- right : 0;
- background : #ccc;
-}
-
-.preview-container {
- position : absolute;
- top : 30px;
- right : 0;
- height : 256px;
- width : 256px;
- background : white;
- border : 0px Solid black;
- border-radius:5px 0px 0px 5px;
- box-shadow : 0px 0px 2px rgba(0,0,0,0.2);
-}
-
-.preview-container canvas {
- border : 0px Solid transparent;
- border-radius:5px 0px 0px 5px;
-}
-
-#cursorInfo {
- position : fixed;
- cursor : default;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -khtml-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-.action-button {
- background-color : white;
- width : 150px;
- display : inline-block;
-}
-
-#preview-list {
- list-style-type: none;
-}
-
-.preview-tile {
- padding : 10px;
- overflow: hidden;
- background-color: gray;
-}
-
-.preview-tile .canvas-container {
- float: left;
-}
-
-.preview-tile .tile-view {
- float: left;
- border: blue 1px solid;
-}
-
-.preview-tile .tile-action {
- display: none;
- float: right;
-}
-
-.preview-tile:hover .tile-action {
- display: block;
-}
-
-.preview-tile:hover {
- background-color: lightgray;
-}
-
-#preview-list .preview-tile.selected {
- background-color: lightyellow;
-}
-
-.canvas-container {
- position: relative;
- display: block;
-}
-
-.canvas-container .canvas-background {
- background: url(../img/transparent_background.png) repeat;
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
-}
-
-.canvas {
- position: relative;
- z-index: 1;
-}
-
-/* Force apparition of scrollbars on leopard */
-::-webkit-scrollbar {
- -webkit-appearance: none;
- width: 7px;
-}
-
-::-webkit-scrollbar-thumb {
- border-radius: 4px;
- background-color: rgba(180,180,180,.7);
- -webkit-box-shadow: 0 0 1px rgba(255,255,255,.5);
-}
\ No newline at end of file
diff --git a/preview/img/transparent_background.png b/preview/img/transparent_background.png
deleted file mode 100644
index 4a1f7a8e..00000000
Binary files a/preview/img/transparent_background.png and /dev/null differ
diff --git a/preview/index.html b/preview/index.html
deleted file mode 100644
index c08fa6e8..00000000
--- a/preview/index.html
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
-
-
- Piskel
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/preview/js/app.js b/preview/js/app.js
deleted file mode 100644
index d66a847f..00000000
--- a/preview/js/app.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// Generated by CoffeeScript 1.3.1
-(function() {
-
- $(document).ready(function() {
- var Piskel;
- Piskel = Em.Application.create();
- Piskel.mainView = Em.View.create({
- templateName: 'main',
- onCanvasClick: function() {}
- });
- Piskel.mainView.append;
- Piskel.Art = Ember.Object.extend({
- setContext: function(context) {
- this.context = context;
- },
- clear: function() {
- this.context.save();
- return this.context.clearRect(0, 0, this.context.canvas.width, this.context.canvas.height);
- }
- });
- $('#main').ready(function() {
- var context, mainCanvas;
- mainCanvas = document.getElementById('main');
- context = mainCanvas.getContext('2d');
- context.save();
- context.clearRect(0, 0, context.canvas.width, context.canvas.height);
- context.fillStyle = 'white';
- context.fillRect(0, 0, context.canvas.width, context.canvas.height);
- context.restore();
- return Piskel.mainCanvas = document.getElementById('main');
- });
- return window.Piskel = Piskel;
- });
-
-}).call(this);
diff --git a/preview/js/frameSheetModel.js b/preview/js/frameSheetModel.js
deleted file mode 100644
index d4d2712b..00000000
--- a/preview/js/frameSheetModel.js
+++ /dev/null
@@ -1,101 +0,0 @@
-var FrameSheetModel = (function() {
-
- var inst;
- var frames = [];
- var width;
- var height;
-
- var createEmptyFrame_ = function() {
- var emptyFrame = new Array(width);
- for (var columnIndex=0; columnIndex < width; columnIndex++) {
- emptyFrame[columnIndex] = new Array(height);
- }
- return emptyFrame;
- };
-
- var serializeFrame_ = function (frame) {
- var buffer = [];
- for (var i = 0 ; i < frame.length ; i++) {
- var serializedLine = "";
- for(var j = 0 ; j < frame[i].length ; j++) {
- if (typeof frame[i][j] == 'undefined' || frame[i][j] == 'tc') {
- serializedLine += "0"
- } else {
- serializedLine += "1"
- }
- }
- buffer.push(parseInt(serializedLine, 2).toString(36));
-
- }
- return buffer.join(",");
- };
-
- return {
- validate: function() {
- return true; // I'm always right dude
- },
-
- // Could be use to pass around model using long GET param (good enough for simple models) and
- // do some temporary locastorage
- serialize: function() {
- var buffer = [];
- for (var i = 0 ; i < frames.length ; i++) {
- buffer.push(serializeFrame_(frames[i]));
- }
- return buffer.join("+");
- //throw "FrameSheet.serialize Not implemented"
- },
-
- addEmptyFrame: function() {
- this.addFrame(createEmptyFrame_());
- },
-
- addFrame : function (frame) {
- frames.push(frame);
- },
-
- getFrameCount: function() {
- return frames.length;
- },
-
- getFrameByIndex: function(index) {
- if (isNaN(index)) {
- throw "Bad argument value for getFrameByIndex method: <" + index + ">"
- } else if (index < 0 || index > frames.length) {
- throw "Out of bound index for frameSheet object."
- }
-
- return frames[index];
- },
-
- removeFrameByIndex: function(index) {
- if(index < 0 || index > inst.getFrameCount()) {
- throw "Bad index value for removeFrameByIndex.";
- }
- frames.splice(index, 1);
- },
-
- duplicateFrameByIndex: function(frameToDuplicateIndex) {
- var frame = inst.getFrameByIndex(frameToDuplicateIndex);
- var clonedFrame = [];
- for(var i=0, l=frame.length; i 100) {
- animPreviewFPS = 100;
- }
- animFPSTuner.value = animPreviewFPS;
- refreshUpdater = startPreviewRefresh();
- });
- },
-
- createPreviews : function () {
- var container = $('preview-list'), previewTile;
- container.innerHTML = "";
- for (var i = 0, l = frameSheet.getFrameCount(); i < l ; i++) {
- previewTile = this.createPreviewTile(i);
- container.appendChild(previewTile);
- }
- },
-
- createPreviewTile: function(tileNumber) {
- var previewTileRoot = document.createElement("li");
- var classname = "preview-tile";
-
- if (this.getActiveFrameIndex() == tileNumber) {
- classname += " selected";
- }
- previewTileRoot.className = classname;
-
- var canvasContainer = document.createElement("div");
- canvasContainer.className = "canvas-container";
- canvasContainer.setAttribute('style',
- 'width:' + framePixelWidth * previewTileCanvasDpi + 'px; height:' + framePixelHeight * previewTileCanvasDpi + 'px;');
-
- var canvasBackground = document.createElement("div");
- canvasBackground.className = "canvas-background";
- canvasContainer.appendChild(canvasBackground);
-
- var canvasPreview = document.createElement("canvas");
- canvasPreview.className = "canvas tile-view"
-
- canvasPreview.setAttribute('width', framePixelWidth * previewTileCanvasDpi);
- canvasPreview.setAttribute('height', framePixelHeight * previewTileCanvasDpi);
-
- previewTileRoot.addEventListener('click', function(evt) {
- // has not class tile-action:
- // TODO: let me know when you want to start using a framework :)
- if(!evt.target.className.match(new RegExp('(\\s|^)'+ 'tile-action' +'(\\s|$)'))) {
- piskel.setActiveFrameAndRedraw(tileNumber);
- }
- });
-
- var canvasPreviewDuplicateAction = document.createElement("button");
- canvasPreviewDuplicateAction.className = "tile-action"
- canvasPreviewDuplicateAction.innerHTML = "dup"
-
- canvasPreviewDuplicateAction.addEventListener('click', function(evt) {
- piskel.duplicateFrame(tileNumber);
- });
-
- this.drawFrameToCanvas(frameSheet.getFrameByIndex(tileNumber), canvasPreview, previewTileCanvasDpi);
- canvasContainer.appendChild(canvasPreview);
- previewTileRoot.appendChild(canvasContainer);
- previewTileRoot.appendChild(canvasPreviewDuplicateAction);
-
- if(tileNumber > 0 || frameSheet.getFrameCount() > 1) {
- var canvasPreviewDeleteAction = document.createElement("button");
- canvasPreviewDeleteAction.className = "tile-action"
- canvasPreviewDeleteAction.innerHTML = "del"
- canvasPreviewDeleteAction.addEventListener('click', function(evt) {
- frameSheet.removeFrameByIndex(tileNumber);
- animIndex = 0;
- piskel.createPreviews();
- });
- previewTileRoot.appendChild(canvasPreviewDeleteAction);
- }
-
- return previewTileRoot;
- },
-
- refreshAnimatedPreview : function () {
- piskel.drawFrameToCanvas(frameSheet.getFrameByIndex(animIndex), previewCanvas, previewAnimationCanvasDpi);
- animIndex++;
- if (animIndex == frameSheet.getFrameCount()) {
- animIndex = 0;
- }
- },
-
- removeFrame: function(frameIndex) {
- frameSheet.removeFrameByIndex(frameIndex);
-
- this.setActiveFrameAndRedraw(frameIndex - 1);
- },
-
- duplicateFrame: function(frameIndex) {
- frameSheet.duplicateFrameByIndex(frameIndex);
-
- this.setActiveFrameAndRedraw(frameIndex + 1);
- },
-
- updateCursorInfo : function (event) {
- var cursor = $('cursorInfo');
- cursor.style.top = event.clientY + 10 + "px";
- cursor.style.left = event.clientX + 10 + "px";
-
- var coordinates = this.getRelativeCoordinates(event.clientX, event.clientY)
- cursor.innerHTML = [
- "X : " + coordinates.x,
- "Y : " + coordinates.y
- ].join(", ");
- },
-
- onCanvasMousedown : function (event) {
- isClicked = true;
- var coords = this.getRelativeCoordinates(event.clientX, event.clientY);
- if(event.button == 0) {
- this.drawAt(coords.x, coords.y, penColor);
- } else {
- // Right click used to delete.
- isRightClicked = true;
- this.drawAt(coords.x, coords.y, TRANSPARENT_COLOR);
- }
- },
-
- onCanvasMousemove : function (event) {
- //this.updateCursorInfo(event);
- if (isClicked) {
- var coords = this.getRelativeCoordinates(event.clientX, event.clientY);
- if(isRightClicked) {
- this.drawAt(coords.x, coords.y, TRANSPARENT_COLOR);
- } else {
- this.drawAt(coords.x, coords.y, penColor);
- }
- }
- },
-
- onCanvasMouseup : function (event) {
- if(isClicked || isRightClicked) {
- // A mouse button was clicked on the drawing canvas before this mouseup event,
- // the user was probably drawing on the canvas.
- // Note: The mousemove movement (and the mouseup) may end up outside
- // of the drawing canvas.
- this.createPreviews();
- }
- isClicked = false;
- isRightClicked = false;
- },
-
- drawAt : function (x, y, color) {
- var pixelWidthIndex = (x - x%drawingCanvasDpi) / 10;
- var pixelHeightIndex = (y - y%drawingCanvasDpi) / 10;
-
- // Update model:
- var currentFrame = frameSheet.getFrameByIndex(this.getActiveFrameIndex());
-
- // TODO: make a better accessor for pixel state update:
- // TODO: Make pen color dynamic:
- currentFrame[pixelWidthIndex][pixelHeightIndex] = color;
-
- // Update view:
- // TODO: Create a per pixel update function for perf ?
- this.drawFrameToCanvas(currentFrame, drawingAreaCanvas, drawingCanvasDpi);
- },
-
- // TODO: move that to a FrameRenderer (/w cache) ?
- drawFrameToCanvas: function(frame, canvasElement, dpi) {
- var pixelColor, context = canvasElement.getContext('2d');
- for(var col = 0, num_col = frame.length; col < num_col; col++) {
- for(var row = 0, num_row = frame[col].length; row < num_row; row++) {
- pixelColor = frame[col][row];
-
- if(pixelColor == undefined || pixelColor == TRANSPARENT_COLOR) {
- context.clearRect(col * dpi, row * dpi, dpi, dpi);
- } else {
- context.fillStyle = pixelColor;
- context.fillRect(col * dpi, row * dpi, dpi, dpi);
- }
-
-
- }
- }
- },
-
- onCanvasContextMenu : function (event) {
- event.preventDefault();
- event.stopPropagation();
- event.cancelBubble = true;
- return false;
- },
-
- getRelativeCoordinates : function (x, y) {
- var canvasRect = drawingAreaCanvas.getBoundingClientRect();
- return {
- x : x - canvasRect.left,
- y : y - canvasRect.top
- }
- }
- };
-
- window.piskel = piskel;
- piskel.init();
-
-})(function(id){return document.getElementById(id)});
\ No newline at end of file