diff --git a/public/index.html b/public/index.html index 15cba8e..2bdf638 100644 --- a/public/index.html +++ b/public/index.html @@ -6,9 +6,9 @@ + -

Ludum Dare, here we come again!!

diff --git a/public/vendors/playground.js b/public/vendors/playground.js new file mode 100644 index 0000000..b4eb2f6 --- /dev/null +++ b/public/vendors/playground.js @@ -0,0 +1,1440 @@ +/* + Playground 1.0.2 + http://canvasquery.org + (c) 2012-2014 http://rezoner.net + Playground may be freely distributed under the MIT license. +*/ + +function playground(args) { + return new Playground(args); +}; + +/* utitlities */ + +playground.extend = function() { + for (var i = 1; i < arguments.length; i++) { + for (var j in arguments[i]) { + arguments[0][j] = arguments[i][j]; + } + } + + return arguments[0]; +}; + +playground.throttle = function(fn, threshold) { + threshold || (threshold = 250); + var last, + deferTimer; + return function() { + var context = this; + + var now = +new Date, + args = arguments; + if (last && now < last + threshold) { + // hold on to it + clearTimeout(deferTimer); + deferTimer = setTimeout(function() { + last = now; + fn.apply(context, args); + }, threshold); + } else { + last = now; + fn.apply(context, args); + } + }; +}; + +/* constructor */ + +function Playground(args) { + + /* defaults */ + + playground.extend(this, { + smoothing: 1, + scale: 1, + preventKeyboardDefault: true, + preventContextMenu: true + }, args); + + + if (!this.width || !this.height) this.fitToContainer = true; + + if (!this.container) this.container = document.body; + if (this.container !== document.body) this.customContainer = true; + if (typeof this.container === "string") this.container = document.querySelector(this.container); + + /* state */ + + this.state = {}; + + /* layer */ + + if (!args.layer) { + cq.smoothing = this.smoothing; + + if (window.CocoonJS) { + this.layer = cq.cocoon(1, 1); + this.layer.appendTo(this.container); + this.screen = this.layer; + } else { + this.layer = cq(1, 1); + + if (this.scaleToFit) { + this.screen = cq(1, 1); + this.screen.appendTo(this.container); + } else { + this.layer.appendTo(this.container); + this.screen = this.layer; + } + } + + } + + var canvas = this.screen.canvas; + + /* events */ + + this.eventsHandler = this.eventsHandler.bind(this); + + /* mouse */ + + this.mouse = new playground.Mouse(canvas); + this.mouse.on("event", this.eventsHandler); + + this.mouse.preventContextMenu = this.preventContextMenu; + + /* touch */ + + this.touch = new playground.Touch(canvas); + this.touch.on("event", this.eventsHandler); + + /* keyboard */ + + this.keyboard = new playground.Keyboard(); + + this.keyboard.preventDefault = this.preventKeyboardDefault; + this.keyboard.on("event", this.eventsHandler); + + /* gamepads */ + + this.gamepads = new playground.Gamepads(); + this.gamepads.on("event", this.eventsHandler); + + /* window resize */ + + window.addEventListener("resize", this.resizeHandler.bind(this)); + + setTimeout(this.resizeHandler.bind(this), 1); + + /* video recorder */ + + this.videoRecorder = new playground.VideoRecorder(this); + + /* game loop */ + + var self = this; + + var lastTick = Date.now(); + + function step() { + + requestAnimationFrame(step); + + var delta = Date.now() - lastTick; + lastTick = Date.now(); + + if (delta > 1000) return; + + var dt = delta / 1000; + + if (self.loader.count <= 0) { + + if (self.step) self.step(dt); + if (self.state.step) self.state.step(dt); + + if (self.render) self.render(dt); + if (self.state.render) self.state.render(dt); + + if (self.postrender) self.postrender(dt); + if (self.state.postrender) self.state.postrender(dt); + + } else { + self.renderLoader(dt); + } + + if (self.scaleToFit) { + self.screen.save(); + self.screen.translate(self.offsetX, self.offsetY); + self.screen.scale(self.scale, self.scale); + // self.layer.drawImage(self.scanlines.canvas, 0, 0); + self.screen.drawImage(self.layer.canvas, 0, 0); + self.screen.restore(); + } + + self.gamepads.step(dt); + self.videoRecorder.step(dt); + + }; + + requestAnimationFrame(step); + + /* assets */ + + /* default audio format */ + + var canPlayMp3 = (new Audio).canPlayType("audio/mp3"); + var canPlayOgg = (new Audio).canPlayType('audio/ogg; codecs="vorbis"'); + + if (canPlayMp3) this.audioFormat = "mp3"; + else this.audioFormat = "ogg"; + + this.loader = new playground.Loader(); + + this.images = {}; + this.sounds = {}; + + this.loadFoo(0.5); + + if (this.create) setTimeout(this.create.bind(this)); + + this.loader.on("ready", function() { + if (self.ready) self.ready(); + + self.ready = function() {}; + }); + + + +}; + +Playground.prototype = { + + setState: function(state) { + state.app = this; + + if (this.state && this.state.leave) this.state.leave(); + + this.state = state; + + if (this.state && this.state.enter) this.state.enter(); + }, + + eventsHandler: function(event, data) { + + if (this[event]) this[event](data); + if (this.state[event]) this.state[event](data); + + }, + + resizeHandler: function() { + + if (this.customContainer) { + var containerWidth = this.container.offsetWidth; + var containerHeight = this.container.offsetHeight; + } else { + var containerWidth = window.innerWidth; + var containerHeight = window.innerHeight; + } + + if (this.fitToContainer) { + this.width = this.containerWidth; + this.height = this.containerHeight; + } + + if (!this.scaleToFit) { + + if (this.fitToContainer) { + this.width = containerWidth; + this.height = containerHeight; + } + + this.offsetX = 0; + this.offsetY = 0; + + } else { + + this.screen.width = containerWidth; + this.screen.height = containerHeight; + + this.scale = Math.min(containerWidth / this.width, containerHeight / this.height); + + if (this.roundScale) this.scale = Math.max(1, Math.floor(this.scale)); + + this.offsetX = containerWidth / 2 - this.scale * (this.width / 2) | 0; + this.offsetY = containerHeight / 2 - this.scale * (this.height / 2) | 0; + + this.mouse.scale = this.scale; + this.mouse.offsetX = this.offsetX; + this.mouse.offsetY = this.offsetY; + + this.touch.scale = this.scale; + this.touch.offsetX = this.offsetX; + this.touch.offsetY = this.offsetY; + } + + this.layer.width = this.width; + this.layer.height = this.height; + + this.center = { + x: this.width / 2 | 0, + y: this.height / 2 | 0 + }; + + this.screen.clear("#000"); + + this.eventsHandler("resize"); + + this.mouse.update(); + this.touch.update(); + }, + + renderLoader: function() { + + var height = this.height / 10 | 0; + var x = 32; + var width = this.width - x * 2; + var y = this.height / 2 - height / 2 | 0; + + this.layer.clear("#000"); + this.layer.strokeStyle("#fff").lineWidth(2).strokeRect(x, y, width, height); + this.layer.fillStyle("#fff").fillRect(x, y, width * this.loader.progress | 0, height); + + }, + + record: function(args) { + this.videoRecorder.toggle(args); + }, + + /* imaginary timeout to delay loading */ + + loadFoo: function(timeout) { + if (!this.foofooLoader) this.foofooLoader = 0; + + var loader = this.loader; + + this.loader.add("foo " + timeout); + + setTimeout(function() { + loader.ready("foo " + timeout); + }, (this.foofooLoader += timeout * 1000)); + + }, + + /* images */ + + loadImages: function() { + + for (var i = 0; i < arguments.length; i++) { + + var arg = arguments[i]; + + /* polymorphism at its finest */ + + if (typeof arg === "object") { + + for (var key in arg) this.addImages(arg[key]); + + } else { + + /* if argument is not an object/array let's try to load it */ + + var filename = arg; + + var loader = this.loader; + + var fileinfo = filename.match(/(.*)\..*/); + var key = fileinfo ? fileinfo[1] : filename; + + /* filename defaults to png */ + + if (!fileinfo) filename += ".png"; + + var path = "images/" + filename; + + this.loader.add(path); + + var image = this.images[key] = new Image; + + image.addEventListener("load", function() { + loader.ready(path); + }); + + image.addEventListener("error", function() { + loader.error(path); + }); + + image.src = path; + } + } + }, + + /* sounds */ + + loadSounds: function() { + + for (var i = 0; i < arguments.length; i++) { + + var arg = arguments[i]; + + /* polymorphism at its finest */ + + if (typeof arg === "object") { + + for (var key in arg) this.loadSounds(arg[key]); + + } else { + + /* if argument is not an object/array let's try to load it */ + + var filename = arg; + + var loader = this.loader; + + var key = filename; + + filename += "." + this.audioFormat; + + var path = "sounds/" + filename; + + this.loader.add(path); + + var audio = this.sounds[key] = new Audio; + + audio.addEventListener("canplay", function() { + loader.ready(path); + }); + + audio.addEventListener("error", function() { + loader.error(path); + }); + + audio.src = path; + } + } + + }, + + loadFont: function(name) { + var styleNode = document.createElement("style"); + styleNode.type = "text/css"; + + var formats = { + "woff": "woff", + "ttf": "truetype" + }; + + var sources = ""; + + for (var ext in formats) { + var type = formats[ext]; + sources += " url(\"fonts/" + name + "." + ext + "\") format('" + type + "');" + } + + styleNode.textContent = "@font-face { font-family: '" + name + "'; src: " + sources + " }"; + + document.head.appendChild(styleNode); + + var layer = cq(32, 32); + + layer.font("10px huj"); + layer.fillText(16, 16, 16).trim(); + + var width = layer.width; + var height = layer.height; + + this.loader.add("font " + name); + + var self = this; + + function check() { + var layer = cq(32, 32); + layer.font("10px " + name).fillText(16, 16, 16); + layer.trim(); + + if (layer.width !== width || layer.height !== height) { + self.loader.ready("font " + name); + } else { + setTimeout(check, 250); + } + }; + + check(); + }, + + playSound: function(key, loop) { + var sound = this.sounds[key]; + sound.currentTime = 0; + sound.loop = loop; + sound.play(); + return sound; + }, + + stopSound: function(sound) { + if (typeof sound === "string") sound = this.sounds[sound]; + sound.pause(); + } + + +}; + +playground.Events = function() { + + this.listeners = {}; + +}; + +playground.Events.prototype = { + + on: function(event, callback) { + if (!this.listeners[event]) this.listeners[event] = []; + + this.listeners[event].push(callback); + + return callback; + }, + + once: function(event, callback) { + callback.once = true; + + if (!this.listeners[event]) this.listeners[event] = []; + + this.listeners[event].push(callback); + + return callback; + }, + + off: function(event, callback) { + for (var i = 0, len = this.listeners[event].length; i < len; i++) { + if (this.listeners[event][i]._remove) { + this.listeners[event].splice(i--, 1); + len--; + } + } + }, + + trigger: function(event, data) { + + /* if you prefer events pipe */ + + if (this.listeners["event"]) { + for (var i = 0, len = this.listeners["event"].length; i < len; i++) { + this.listeners["event"][i](event, data); + } + } + + /* or subscribed to single event */ + + if (this.listeners[event]) { + for (var i = 0, len = this.listeners[event].length; i < len; i++) { + var listener = this.listeners[event][i]; + listener(data); + + if (listener.once) { + this.listeners[event].splice(i--, 1); + } + } + } + } +}; + +/* Mouse */ + +playground.Mouse = function(element) { + + var self = this; + + playground.Events.call(this); + + this.element = element; + + this.buttons = {}; + + this.mousemoveEvent = {}; + this.mousedownEvent = {}; + this.mouseupEvent = {}; + this.mousewheelEvent = {}; + + this.x = 0; + this.y = 0; + + this.offsetX = 0; + this.offsetY = 0; + this.scale = 1; + + element.addEventListener("mousemove", this.mousemove.bind(this)); + element.addEventListener("mousedown", this.mousedown.bind(this)); + element.addEventListener("mouseup", this.mouseup.bind(this)); + + this.enableMousewheel(); + + this.element.addEventListener("contextmenu", function(e) { + if (self.preventContextMenu) e.preventDefault(); + }); + +}; + +playground.Mouse.prototype = { + + getElementOffset: function(element) { + + var offsetX = 0; + var offsetY = 0; + + do { + offsetX += element.offsetLeft; + offsetY += element.offsetTop; + } + + while ((element = element.offsetParent)); + + return { + x: offsetX, + y: offsetY + }; + + }, + + update: function() { + this.elementOffset = this.getElementOffset(this.element); + }, + + mousemove: function(e) { + this.x = this.mousemoveEvent.x = (e.pageX - this.elementOffset.x - this.offsetX) / this.scale | 0; + this.y = this.mousemoveEvent.y = (e.pageY - this.elementOffset.y - this.offsetY) / this.scale | 0; + + this.mousemoveEvent.original = e; + + this.trigger("mousemove", this.mousemoveEvent); + }, + + mousedown: function(e) { + + var buttonName = ["left", "middle", "right"][e.button]; + + this.mousedownEvent.x = this.mousemoveEvent.x; + this.mousedownEvent.y = this.mousemoveEvent.y; + this.mousedownEvent.button = buttonName; + this.mousedownEvent.original = e; + + this[buttonName] = true; + + this.trigger("mousedown", this.mousedownEvent); + }, + + mouseup: function(e) { + + var buttonName = ["left", "middle", "right"][e.button]; + + this.mouseupEvent.x = this.mousemoveEvent.x; + this.mouseupEvent.y = this.mousemoveEvent.y; + this.mouseupEvent.button = buttonName; + this.mouseupEvent.original = e; + + this[buttonName] = false; + + this.trigger("mouseup", this.mouseupEvent); + }, + + mousewheel: function(e) { + this.mousewheelEvent.x = this.mousemoveEvent.x; + this.mousewheelEvent.y = this.mousemoveEvent.y; + this.mousewheelEvent.button = ["none", "left", "middle", "right"][e.button]; + this.mousewheelEvent.original = e; + + this[e.button] = false; + + this.trigger("mousewheel", this.mousewheelEvent); + }, + + + enableMousewheel: function() { + + var eventNames = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll']; + var callback = this.mousewheel.bind(this); + var self = this; + + for (var i = eventNames.length; i;) { + + self.element.addEventListener(eventNames[--i], playground.throttle(function(event) { + + var orgEvent = event || window.event, + args = [].slice.call(arguments, 1), + delta = 0, + deltaX = 0, + deltaY = 0, + absDelta = 0, + absDeltaXY = 0, + fn; + event.type = "mousewheel"; + + // Old school scrollwheel delta + if (orgEvent.wheelDelta) { + delta = orgEvent.wheelDelta; + } + + if (orgEvent.detail) { + delta = orgEvent.detail * -1; + } + + // New school wheel delta (wheel event) + if (orgEvent.deltaY) { + deltaY = orgEvent.deltaY * -1; + delta = deltaY; + } + + // Webkit + if (orgEvent.wheelDeltaY !== undefined) { + deltaY = orgEvent.wheelDeltaY; + } + + var result = delta ? delta : deltaY; + + self.mousewheelEvent.x = self.mousemoveEvent.x; + self.mousewheelEvent.y = self.mousemoveEvent.y; + self.mousewheelEvent.delta = result / Math.abs(result); + self.mousewheelEvent.original = orgEvent; + + callback(self.mousewheelEvent); + + event.preventDefault(); + + }, 40), false); + } + + } + +}; + +playground.extend(playground.Mouse.prototype, playground.Events.prototype); + +/* Touch */ + +playground.Touch = function(element) { + + playground.Events.call(this); + + this.element = element; + + this.buttons = {}; + + this.touchmoveEvent = {}; + this.touchstartEvent = {}; + this.touchendEvent = {}; + + this.x = 0; + this.y = 0; + + this.offsetX = 0; + this.offsetY = 0; + this.scale = 1; + + element.addEventListener("touchmove", this.touchmove.bind(this)); + element.addEventListener("touchstart", this.touchstart.bind(this)); + element.addEventListener("touchend", this.touchend.bind(this)); +}; + +playground.Touch.prototype = { + + getElementOffset: function(element) { + + var offsetX = 0; + var offsetY = 0; + + do { + offsetX += element.offsetLeft; + offsetY += element.offsetTop; + } + + while ((element = element.offsetParent)); + + return { + x: offsetX, + y: offsetY + }; + + }, + + update: function() { + this.elementOffset = this.getElementOffset(this.element); + }, + + touchmove: function(e) { + var touch = e.touches[0] || e.changedTouches[0]; + + this.x = this.touchmoveEvent.x = (touch.pageX - this.elementOffset.x - this.offsetX) / this.scale | 0; + this.y = this.touchmoveEvent.y = (touch.pageY - this.elementOffset.y - this.offsetY) / this.scale | 0; + + this.touchmoveEvent.original = e; + this.touchmoveEvent.identifier = e.identifier; + + this.trigger("touchmove", this.touchmoveEvent); + + e.preventDefault(); + }, + + touchstart: function(e) { + this.touchstartEvent.x = this.touchmoveEvent.x; + this.touchstartEvent.y = this.touchmoveEvent.y; + + this.touchstartEvent.original = e; + this.touchstartEvent.identifier = e.identifier; + + this.pressed = true; + + this.trigger("touchstart", this.touchstartEvent); + }, + + touchend: function(e) { + this.touchendEvent.x = this.touchmoveEvent.x; + this.touchendEvent.y = this.touchmoveEvent.y; + + this.touchendEvent.original = e; + this.touchendEvent.identifier = e.identifier; + + this.pressed = false; + + this.trigger("touchend", this.touchendEvent); + } + +}; + +playground.extend(playground.Touch.prototype, playground.Events.prototype); + +/* Keyboard */ + +playground.Keyboard = function() { + + playground.Events.call(this); + + this.keys = {}; + + document.addEventListener("keydown", this.keydown.bind(this)); + document.addEventListener("keyup", this.keyup.bind(this)); + document.addEventListener("keypress", this.keypress.bind(this)); + + this.keydownEvent = {}; + this.keyupEvent = {}; + +}; + +playground.Keyboard.prototype = { + + keycodes: { + 37: "left", + 38: "up", + 39: "right", + 40: "down", + 45: "insert", + 46: "delete", + 8: "backspace", + 9: "tab", + 13: "enter", + 16: "shift", + 17: "ctrl", + 18: "alt", + 19: "pause", + 20: "capslock", + 27: "escape", + 32: "space", + 33: "pageup", + 34: "pagedown", + 35: "end", + 36: "home", + 112: "f1", + 113: "f2", + 114: "f3", + 115: "f4", + 116: "f5", + 117: "f6", + 118: "f7", + 119: "f8", + 120: "f9", + 121: "f10", + 122: "f11", + 123: "f12", + 144: "numlock", + 145: "scrolllock", + 186: "semicolon", + 187: "equal", + 188: "comma", + 189: "dash", + 190: "period", + 191: "slash", + 192: "graveaccent", + 219: "openbracket", + 220: "backslash", + 221: "closebraket", + 222: "singlequote" + }, + + keypress: function(e) { + + }, + + keydown: function(e) { + if (e.which >= 48 && e.which <= 90) var keyName = String.fromCharCode(e.which).toLowerCase(); + else var keyName = this.keycodes[e.which]; + + if (this.keys[keyName]) return; + + this.keydownEvent.key = keyName; + this.keydownEvent.original = e; + + this.keys[keyName] = true; + + this.trigger("keydown", this.keydownEvent); + + if (this.preventDefault && document.activeElement === document.body) { + e.returnValue = false; + e.keyCode = 0; + e.preventDefault(); + e.stopPropagation(); + } + }, + + keyup: function(e) { + + if (e.which >= 48 && e.which <= 90) var keyName = String.fromCharCode(e.which).toLowerCase(); + else var keyName = this.keycodes[e.which]; + + this.keyupEvent.key = keyName; + this.keyupEvent.original = e; + + this.keys[keyName] = false; + + this.trigger("keyup", this.keyupEvent); + } + +}; + +playground.extend(playground.Keyboard.prototype, playground.Events.prototype); + +/* Gamepad */ + +playground.Gamepads = function() { + + playground.Events.call(this); + + this.getGamepads = navigator.getGamepads || navigator.webkitGetGamepads; + + this.gamepadmoveEvent = {}; + this.gamepaddownEvent = {}; + this.gamepadupEvent = {}; + + this.gamepads = {}; + +}; + +playground.Gamepads.prototype = { + + buttons: { + 0: "1", + 1: "2", + 2: "3", + 3: "4", + 4: "l1", + 5: "r1", + 6: "l2", + 7: "r2", + 8: "select", + 9: "start", + 12: "up", + 13: "down", + 14: "left", + 15: "right" + }, + + zeroState: function() { + var buttons = []; + + for (var i = 0; i <= 15; i++) { + buttons.push({ + pressed: false, + value: 0 + }); + } + + return { + axes: [], + buttons: buttons + }; + }, + + createGamepad: function() { + var result = { + buttons: {}, + sticks: [{ + x: 0, + y: 0 + }, { + x: 0, + y: 0 + }] + }; + + + for (var i = 0; i < 16; i++) { + var key = this.buttons[i]; + result.buttons[key] = false; + } + + return result; + }, + + step: function() { + if (!navigator.getGamepads) return; + + var gamepads = navigator.getGamepads(); + + for (var i = 0; i < gamepads.length; i++) { + var current = gamepads[i]; + + if (!current) continue; + + if (!this[i]) this[i] = this.createGamepad(); + + /* have to concat the current.buttons because the are read-only */ + + var buttons = [].concat(current.buttons); + + /* hack for missing dpads */ + + for (var h = 12; h <= 15; h++) { + if (!buttons[h]) buttons[h] = { + pressed: false, + value: 0 + }; + } + + var previous = this[i]; + + /* axes (sticks) to buttons */ + + if (current.axes) { + + if (current.axes[0] < 0) buttons[14].pressed = true; + if (current.axes[0] > 0) buttons[15].pressed = true; + if (current.axes[1] < 0) buttons[12].pressed = true; + if (current.axes[1] > 0) buttons[13].pressed = true; + + previous.sticks[0].x = current.axes[0].value; + previous.sticks[0].y = current.axes[1].value; + previous.sticks[1].x = current.axes[2].value; + previous.sticks[1].y = current.axes[3].value; + + } + + /* check buttons changes */ + + for (var j = 0; j < buttons.length; j++) { + + var key = this.buttons[j]; + + /* gamepad down */ + + if (buttons[j].pressed && !previous.buttons[key]) { + previous.buttons[key] = true; + this.gamepaddownEvent.button = this.buttons[j]; + this.gamepaddownEvent.gamepad = i; + this.trigger("gamepaddown", this.gamepaddownEvent); + } + + /* gamepad up */ + else if (!buttons[j].pressed && previous.buttons[key]) { + previous.buttons[key] = false; + this.gamepadupEvent.button = this.buttons[j]; + this.gamepadupEvent.gamepad = i; + this.trigger("gamepadup", this.gamepadupEvent); + } + + } + + } + + } +}; + +playground.extend(playground.Gamepads.prototype, playground.Events.prototype); + + +/* Loader */ + +playground.Loader = function() { + + playground.Events.call(this); + + this.reset(); + +}; + +playground.Loader.prototype = { + + /* loader */ + + add: function(id) { + this.queue++; + this.count++; + this.trigger("add", id); + }, + + error: function(id) { + console.log("unable to load " + id); + this.trigger("error", id); + }, + + ready: function(id) { + this.queue--; + + this.progress = 1 - this.queue / this.count; + + this.trigger("load", id); + + if (this.queue <= 0) { + this.trigger("ready"); + this.reset(); + } + }, + + reset: function() { + this.progress = 0; + this.queue = 0; + this.count = 0; + } +}; + +playground.extend(playground.Loader.prototype, playground.Events.prototype); + +CanvasQuery.Layer.prototype.playground = function(args) { + args.layer = this; + return playground(args); +}; + +/* Video recorder */ + +/* whammy - https://github.com/antimatter15/whammy */ + +window.Whammy = function() { + function h(a, b) { + for (var c = r(a), c = [{ + id: 440786851, + data: [{ + data: 1, + id: 17030 + }, { + data: 1, + id: 17143 + }, { + data: 4, + id: 17138 + }, { + data: 8, + id: 17139 + }, { + data: "webm", + id: 17026 + }, { + data: 2, + id: 17031 + }, { + data: 2, + id: 17029 + }] + }, { + id: 408125543, + data: [{ + id: 357149030, + data: [{ + data: 1E6, + id: 2807729 + }, { + data: "whammy", + id: 19840 + }, { + data: "whammy", + id: 22337 + }, { + data: s(c.duration), + id: 17545 + }] + }, { + id: 374648427, + data: [{ + id: 174, + data: [{ + data: 1, + id: 215 + }, { + data: 1, + id: 25541 + }, { + data: 0, + id: 156 + }, { + data: "und", + id: 2274716 + }, { + data: "V_VP8", + id: 134 + }, { + data: "VP8", + id: 2459272 + }, { + data: 1, + id: 131 + }, { + id: 224, + data: [{ + data: c.width, + id: 176 + }, { + data: c.height, + id: 186 + }] + }] + }] + }] + }], e = 0, d = 0; e < a.length;) { + var g = [], + f = 0; + do g.push(a[e]), f += a[e].duration, e++; while (e < a.length && 3E4 > f); + var h = 0, + g = { + id: 524531317, + data: [{ + data: d, + id: 231 + }].concat(g.map(function(a) { + var b = t({ + discardable: 0, + frame: a.data.slice(4), + invisible: 0, + keyframe: 1, + lacing: 0, + trackNum: 1, + timecode: Math.round(h) + }); + h += a.duration; + return { + data: b, + id: 163 + } + })) + }; + c[1].data.push(g); + d += f + } + return m(c, b) + } + + function r(a) { + for (var b = a[0].width, c = a[0].height, e = a[0].duration, + d = 1; d < a.length; d++) { + if (a[d].width != b) throw "Frame " + (d + 1) + " has a different width"; + if (a[d].height != c) throw "Frame " + (d + 1) + " has a different height"; + if (0 > a[d].duration || 32767 < a[d].duration) throw "Frame " + (d + 1) + " has a weird duration (must be between 0 and 32767)"; + e += a[d].duration + } + return { + duration: e, + width: b, + height: c + } + } + + function u(a) { + for (var b = []; 0 < a;) b.push(a & 255), a >>= 8; + return new Uint8Array(b.reverse()) + } + + function n(a) { + var b = []; + a = (a.length % 8 ? Array(9 - a.length % 8).join("0") : "") + a; + for (var c = 0; c < a.length; c += 8) b.push(parseInt(a.substr(c, + 8), 2)); + return new Uint8Array(b) + } + + function m(a, b) { + for (var c = [], e = 0; e < a.length; e++) { + var d = a[e].data; + "object" == typeof d && (d = m(d, b)); + "number" == typeof d && (d = n(d.toString(2))); + if ("string" == typeof d) { + for (var g = new Uint8Array(d.length), f = 0; f < d.length; f++) g[f] = d.charCodeAt(f); + d = g + } + f = d.size || d.byteLength || d.length; + g = Math.ceil(Math.ceil(Math.log(f) / Math.log(2)) / 8); + f = f.toString(2); + f = Array(7 * g + 8 - f.length).join("0") + f; + g = Array(g).join("0") + "1" + f; + c.push(u(a[e].id)); + c.push(n(g)); + c.push(d) + } + return b ? (c = p(c), new Uint8Array(c)) : + new Blob(c, { + type: "video/webm" + }) + } + + function p(a, b) { + null == b && (b = []); + for (var c = 0; c < a.length; c++) "object" == typeof a[c] ? p(a[c], b) : b.push(a[c]); + return b + } + + function t(a) { + var b = 0; + a.keyframe && (b |= 128); + a.invisible && (b |= 8); + a.lacing && (b |= a.lacing << 1); + a.discardable && (b |= 1); + if (127 < a.trackNum) throw "TrackNumber > 127 not supported"; + return [a.trackNum | 128, a.timecode >> 8, a.timecode & 255, b].map(function(a) { + return String.fromCharCode(a) + }).join("") + a.frame + } + + function q(a) { + for (var b = a.RIFF[0].WEBP[0], c = b.indexOf("\u009d\u0001*"), + e = 0, d = []; 4 > e; e++) d[e] = b.charCodeAt(c + 3 + e); + e = d[1] << 8 | d[0]; + c = e & 16383; + e = d[3] << 8 | d[2]; + return { + width: c, + height: e & 16383, + data: b, + riff: a + } + } + + function k(a) { + for (var b = 0, c = {}; b < a.length;) { + var e = a.substr(b, 4), + d = parseInt(a.substr(b + 4, 4).split("").map(function(a) { + a = a.charCodeAt(0).toString(2); + return Array(8 - a.length + 1).join("0") + a + }).join(""), 2), + g = a.substr(b + 4 + 4, d), + b = b + (8 + d); + c[e] = c[e] || []; + "RIFF" == e || "LIST" == e ? c[e].push(k(g)) : c[e].push(g) + } + return c + } + + function s(a) { + return [].slice.call(new Uint8Array((new Float64Array([a])).buffer), + 0).map(function(a) { + return String.fromCharCode(a) + }).reverse().join("") + } + + function l(a, b) { + this.frames = []; + this.duration = 1E3 / a; + this.quality = b || .8 + } + l.prototype.add = function(a, b) { + if ("undefined" != typeof b && this.duration) throw "you can't pass a duration if the fps is set"; + if ("undefined" == typeof b && !this.duration) throw "if you don't have the fps set, you ned to have durations here."; + "canvas" in a && (a = a.canvas); + if ("toDataURL" in a) a = a.toDataURL("image/webp", this.quality); + else if ("string" != typeof a) throw "frame must be a a HTMLCanvasElement, a CanvasRenderingContext2D or a DataURI formatted string"; + if (!/^data:image\/webp;base64,/ig.test(a)) throw "Input must be formatted properly as a base64 encoded DataURI of type image/webp"; + this.frames.push({ + image: a, + duration: b || this.duration + }) + }; + l.prototype.compile = function(a) { + return new h(this.frames.map(function(a) { + var c = q(k(atob(a.image.slice(23)))); + c.duration = a.duration; + return c + }), a) + }; + return { + Video: l, + fromImageArray: function(a, b, c) { + return h(a.map(function(a) { + a = q(k(atob(a.slice(23)))); + a.duration = 1E3 / b; + return a + }), c) + }, + toWebM: h + } +}(); + +playground.VideoRecorder = function(app, args) { + + this.app = app; + +}; + +playground.VideoRecorder.prototype = { + + setup: function(args) { + + this.region = false; + + playground.extend(this, { + followMouse: false, + framerate: 20, + scale: 1 + }, args); + + if (!this.region) { + this.region = [0, 0, this.app.layer.width, this.app.layer.height]; + } + + this.playbackRate = this.framerate / 60; + + this.layer = cq(this.region[2] * this.scale | 0, this.region[3] * this.scale | 0); + }, + + start: function(args) { + this.setup(args); + this.encoder = new Whammy.Video(this.framerate); + this.captureTimeout = 0; + this.recording = true; + }, + + step: function(delta) { + + if (this.encoder) { + + this.captureTimeout -= delta * 1000; + + if (this.captureTimeout <= 0) { + this.captureTimeout = 1000 / this.framerate + this.captureTimeout; + + this.layer.drawImage(this.app.layer.canvas, this.region[0], this.region[1], this.region[2], this.region[3], 0, 0, this.layer.width, this.layer.height); + this.encoder.add(this.layer.canvas); + } + + this.app.screen.save().lineWidth(8).strokeStyle("#c00").strokeRect(0, 0, this.app.screen.width, this.app.screen.height).restore(); + } + + }, + + stop: function() { + if (!this.encoder) return; + var output = this.encoder.compile(); + var url = (window.webkitURL || window.URL).createObjectURL(output); + window.open(url); + this.recording = false; + + delete this.encoder; + }, + + toggle: function(args) { + if (this.encoder) this.stop(); + else this.start(args); + } + +}; \ No newline at end of file diff --git a/src/entities/base_entity.coffee b/src/entities/base_entity.coffee new file mode 100644 index 0000000..e69de29 diff --git a/src/main.coffee b/src/main.coffee index 7aab7a7..cfc6c65 100644 --- a/src/main.coffee +++ b/src/main.coffee @@ -1,3 +1,20 @@ $ -> - console.log "Hi dude!" - console.log "Awesome, dude. :D" \ No newline at end of file + playground({ + width: 16*20, + height: 16*20, + scaleToFit: true, + smoothing: false, + + create: -> + # TODO: Load images + + ready: -> + # TODO: Start the game + # TODO: setTimeout? + + step: -> + # TODO: For internal stuff like progress bar + + render: -> + # TODO: this.game.render? + })