Initial commit, v1.0.0 v1.0.0
authorChip Black <bytex64@bytex64.net>
Tue, 23 Aug 2011 08:36:53 +0000 (03:36 -0500)
committerChip Black <bytex64@bytex64.net>
Tue, 23 Aug 2011 08:36:53 +0000 (03:36 -0500)
32 files changed:
COPYING [new file with mode: 0644]
HacksSelectorCanvas.js [new file with mode: 0644]
Main.css [new file with mode: 0644]
Main.js [new file with mode: 0644]
appinfo.json [new file with mode: 0644]
depends.js [new file with mode: 0644]
hacks/Hack.js [new file with mode: 0644]
hacks/Landscape/Landscape.js [new file with mode: 0644]
hacks/Landscape/clouds.png [new file with mode: 0644]
hacks/Landscape/mountains.png [new file with mode: 0644]
hacks/Landscape/trees.png [new file with mode: 0644]
hacks/Munch/Munch.js [new file with mode: 0644]
hacks/Nimbus/Nimbus.js [new file with mode: 0644]
hacks/Orbit/Orbit.js [new file with mode: 0644]
hacks/Orbit/chrome_ball.png [new file with mode: 0644]
hacks/Pixelfade/Pixelfade.js [new file with mode: 0644]
hacks/Pixelfade/pixelfade0.gif [new file with mode: 0644]
hacks/Pixelfade/pixelfade1.gif [new file with mode: 0644]
hacks/Pixelfade/pixelfade2.gif [new file with mode: 0644]
hacks/Pixelfade/pixelfade3.gif [new file with mode: 0644]
hacks/Pixelfade/pixelfade4.gif [new file with mode: 0644]
hacks/Pixelfade/pixelfade5.gif [new file with mode: 0644]
hacks/Pixelfade/pixelfade6.gif [new file with mode: 0644]
hacks/Pixelfade/pixelfade7.gif [new file with mode: 0644]
hacks/Pixelfade/pixelfade8.gif [new file with mode: 0644]
hacks/Pixelfade/pixelfade9.gif [new file with mode: 0644]
hacks/Swarm/Swarm.js [new file with mode: 0644]
hacks/XSpinner/XSpinner.js [new file with mode: 0644]
hacks/XSpinnerCGA/XSpinnerCGA.js [new file with mode: 0644]
icon.png [new file with mode: 0644]
icon_48.png [new file with mode: 0644]
index.html [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..840acd4
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,22 @@
+Copyright (c) 2011, The Dominion of Awesome
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/HacksSelectorCanvas.js b/HacksSelectorCanvas.js
new file mode 100644 (file)
index 0000000..6eb4405
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+enyo.kind({
+       name: "HacksSelector",
+       kind: "Control",
+       nodeTag: "canvas",
+       className: "hacks-selector",
+       style: "opacity: 0",
+       width: "748px",
+       height: "192px",
+       index: 0,
+       published: {
+               hacksList: null
+       },
+       hacksThumbs: {},
+       rendered: function() {
+               this.inherited(arguments);
+               var node = this.hasNode();
+               node.width = 748;
+               node.height = 192;
+               this.ctx = node.getContext('2d');
+               this.ctx.fillStyle = 'white';
+               this.fadeGradient = this.ctx.createLinearGradient(0, 0, 0, 128);
+               this.fadeGradient.addColorStop(0.6, 'rgba(0,0,0,0)');
+               this.fadeGradient.addColorStop(1.0, 'rgba(255,255,255,0.5)');
+       },
+       setHacksList: function(newHacksList) {
+               this.hacksList = newHacksList;
+               for (var i = 0; i < this.hacksList.length; i++) {
+                       if (this.hacksThumbs[this.hacksList[i]])
+                               continue;
+                       var img = new Image();
+                       img.src = "hacks/" + this.hacksList[i] + "/thumbnail.png";
+                       img.onload = this.draw.bind(this);
+                       this.hacksThumbs[this.hacksList[i]] = img;
+               }
+       },
+       show: function() {
+               if (this.hideTimer)
+                       clearTimeout(this.hideTimer);
+               this.hideTimer = setTimeout(function() {
+                       this.setStyle('opacity: 0; -webkit-transition: opacity 0.5s linear');
+               }.bind(this), 1500);
+               this.setStyle('opacity: 1.0; -webkit-transition: opacity 0.25s linear');
+       },
+       draw: function() {
+               this.ctx.clearRect(0, 0, 750, 256);
+               if (!this.hacksList) return;
+               for (var i = -2; i <= 3; i++) {
+                       var frac = this.index - Math.floor(this.index);
+                       var x = 311 + (i - frac) * 146;
+                       var j = Math.floor(this.index) + i;
+                       if (j < 0 || j > this.hacksList.length - 1)
+                              continue;
+                       var h = this.hacksList[j];
+
+                       this.ctx.save();
+                       this.ctx.translate(x, 0);
+                       this.ctx.drawImage(this.hacksThumbs[h], 0, 0);
+                       this.ctx.scale(1, -1);
+                       this.ctx.translate(0, -256);
+                       this.ctx.beginPath();
+                       this.ctx.fillStyle = this.fadeGradient;
+                       this.ctx.rect(0, 0, 128, 128);
+                       this.ctx.fill();
+                       this.ctx.globalCompositeOperation = 'source-in';
+                       this.ctx.drawImage(this.hacksThumbs[h], 0, 0);
+                       this.ctx.restore();
+
+                       this.ctx.save();
+                       this.ctx.shadowColor = 'white';
+                       this.ctx.shadowBlur = '3';
+                       this.ctx.beginPath();
+                       this.ctx.arc(374, 160, 5, 0, Math.PI * 2);
+                       this.ctx.fill();
+                       this.ctx.restore();
+               }
+       }
+});
diff --git a/Main.css b/Main.css
new file mode 100644 (file)
index 0000000..1fe2ca5
--- /dev/null
+++ b/Main.css
@@ -0,0 +1,29 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+@font-face {
+       font-family: PCSenior;
+       src: url(fonts/pcsenior.ttf);
+}
+
+.hacks-selector {
+       position: absolute;
+       bottom: 64px;
+       margin-left: -374px;
+       left: 50%;
+}
+
+.info {
+       position: absolute;
+       left: 0;
+       bottom: 0;
+       width: 100%;
+       padding: 24px;
+       font-size: 24px;
+       -webkit-transition-property: opacity;
+       -webkit-transition-duration: 0.6s;
+       color: #303030;
+}
+
+.info.dark {
+       color: #AFAFAf;
+}
diff --git a/Main.js b/Main.js
new file mode 100644 (file)
index 0000000..eb02da9
--- /dev/null
+++ b/Main.js
@@ -0,0 +1,139 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+enyo.kind({
+       name: "Main",
+       kind: "VFlexBox",
+       style: "background-color: black",
+       components: [
+               {kind: "ApplicationEvents", onWindowActivated: "windowActivated", onWindowDeactivated: "windowDeactivated"},
+               {name: "hacksCarousel", kind: "Carousel", flex: 1, onGetLeft: "getLeft", onGetRight: "getRight", onScroll: "scrolling", onScrollStart: "startScroll", onScrollStop: "stopScroll"},
+               //{name: "hacksSelector", kind: "HacksSelector"}
+               {name: "info", kind: "HFlexBox", className: "info", style: "opacity: 0", showing: false, components: [
+                       {name: "title"},
+                       {kind: "Spacer"},
+                       {name: "notice", className: "notice"}
+               ]}
+       ],
+       hacksList: [
+               {name: "Nimbus", kind: "Nimbus", dark: false},
+               {name: "Landscape", kind: "Landscape", dark: false},
+               {name: "Munch", kind: "Munch", dark: true},
+               {name: "Orbit", kind: "Orbit", dark: false},
+               {name: "Pixelfade", kind: "Pixelfade", dark: true},
+               //{name: "Swarm", kind: "Swarm", dark: false},       // crashy
+               //{name: "Spinner.CGA", kind: "XSpinnerCGA", dark: true}, // no webfont support
+               {name: "Spinner", kind: "XSpinner", dark: true}
+       ],
+       create: function() {
+               this.inherited(arguments);
+               /*
+               this.index = localStorage.getItem('hack.index');
+               if (!this.index)
+                       this.index = 0;
+               */
+               this.index = 0;
+               this.lastScrollPos = 0;
+               this.$.hacksCarousel.setCenterView(this.getHack(this.index));
+               //this.$.hacksSelector.setHacksList(this.hacksList);
+       },
+       ready: function() {
+               this.startHack();
+               window.addEventListener('resize', this.resizeHack.bind(this), false);
+               this.setNotice('Swipe for more...');
+               this.setTitle(this.hacksList[this.index].name);
+       },
+       setTitle: function(title) {
+               this.$.title.setContent(title);
+               this.infoFade();
+       },
+       setNotice: function(notice) {
+               this.$.notice.setContent(notice);
+               this.infoFade();
+       },
+       infoFade: function() {
+               this.$.info.setStyle('opacity: 1');
+               this.$.info.show();
+
+               clearTimeout(this.noticeTimer);
+               this.noticeTimer = setTimeout(function() {
+                       this.$.info.setStyle('opacity: 0');
+                       setTimeout(function() {
+                               this.$.info.hide();
+                               this.setNotice('');
+                               this.setTitle('');
+                       }.bind(this), 600);
+               }.bind(this), 5000);
+       },
+       windowActivated: function() {
+               this.startHack();
+       },
+       windowDeactivated: function() {
+               this.stopHack();
+       },
+       startHack: function(direction) {
+               var view = this.$.hacksCarousel.fetchView(direction || 'center');
+               //enyo.log('starting view ' + view);
+               if (view)
+                       view.start();
+               //localStorage.setItem('hack.index', this.index);
+       },
+       stopHack: function(direction) {
+               var view = this.$.hacksCarousel.fetchView(direction || 'center');
+               //enyo.log('stopping view ' + view);
+               if (view)
+                       view.stop();
+       },
+       resizeHack: function() {
+               var view = this.$.hacksCarousel.fetchView('center');
+
+               //enyo.log('resizing view ' + view);
+               if (view)
+                       view.resize(window.innerWidth, window.innerHeight);
+       },
+       hackHidden: function(direction) {
+               var view = this.$.hacksCarousel.fetchView(direction);
+               //enyo.log('view ' + view + ' hidden');
+               if (view)
+                       view.hidden();
+       },
+       getHack: function(index) {
+               return {kind: this.hacksList[index].kind};
+       },
+       getLeft: function(inSender, inSnap) {
+               if (inSnap && this.index > 0) {
+                       this.index--;
+                       this.hackHidden('right');
+                       this.setTitle(this.hacksList[this.index].name);
+                       this.$.info.addRemoveClass('dark', this.hacksList[this.index].dark);
+               }
+               if (this.index == 0)
+                       return null;
+               else
+                       return this.getHack(this.index - 1);
+       },
+       getRight: function(inSender, inSnap) {
+               if (inSnap && this.index < this.hacksList.length) {
+                       this.index++;
+                       this.hackHidden('left');
+                       this.setTitle(this.hacksList[this.index].name);
+                       this.$.info.addRemoveClass('dark', this.hacksList[this.index].dark);
+               }
+               if (this.index == this.hacksList.length - 1)
+                       return null;
+               else
+                       return this.getHack(this.index + 1);
+       },
+       scrolling: function(inSender) {
+               if (inSender.scrollLeft == 0 || inSender.scrollLeft == inSender.getBoundaries().right)
+                       this.startHack();
+               //this.$.hacksSelector.index = this.index + ((inSender.scrollLeft - this.lastScrollPos) / window.innerWidth);
+               //this.$.hacksSelector.draw();
+       },
+       startScroll: function(inSender) {
+               this.stopHack();
+       },
+       stopScroll: function(inSender) {
+               this.lastScrollPos = this.$.hacksCarousel.scrollLeft;
+               this.startHack();
+       }
+});
diff --git a/appinfo.json b/appinfo.json
new file mode 100644 (file)
index 0000000..7c95063
--- /dev/null
@@ -0,0 +1,11 @@
+{
+       "id": "com.dominionofawesome.hacks",
+       "version": "1.0.0",
+       "vendor": "The Dominion of Awesome",
+       "type": "web",
+       "main": "index.html",
+       "title": "Hacks!",
+       "icon": "icon.png",
+       "uiRevision": 2,
+       "dockMode": true
+}
diff --git a/depends.js b/depends.js
new file mode 100644 (file)
index 0000000..6e775a3
--- /dev/null
@@ -0,0 +1,14 @@
+enyo.depends(
+       "Main.js",
+       "Main.css",
+       //"HacksSelector.js",
+       "hacks/Hack.js",
+       "hacks/Nimbus/Nimbus.js",
+       "hacks/Landscape/Landscape.js",
+       "hacks/Munch/Munch.js",
+       "hacks/Orbit/Orbit.js",
+       "hacks/Pixelfade/Pixelfade.js",
+       //"hacks/Swarm/Swarm.js",
+       //"hacks/XSpinnerCGA/XSpinnerCGA.js",
+       "hacks/XSpinner/XSpinner.js"
+);
diff --git a/hacks/Hack.js b/hacks/Hack.js
new file mode 100644 (file)
index 0000000..28cfad7
--- /dev/null
@@ -0,0 +1,14 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+enyo.kind({
+       name: "Hack",
+       kind: "VFlexBox",
+       stop: function() {
+       },
+       start: function() {
+       },
+       resize: function() {
+       },
+       hidden: function() {
+       }
+});
diff --git a/hacks/Landscape/Landscape.js b/hacks/Landscape/Landscape.js
new file mode 100644 (file)
index 0000000..590cb2c
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+enyo.kind({
+       name: "Landscape",
+       kind: "Hack",
+       style: "background-color: #2ab40f",
+       components: [
+               {name: "clouds", style: "height: 200px; background-image: url(hacks/landscape/clouds.png)"},
+               {name: "mountains", style: "height: 200px; background-image: url(hacks/landscape/mountains.png)"},
+               {name: "trees", style: "height: 200px; background-image: url(hacks/landscape/trees.png)"}
+       ],
+       create: function() {
+               this.inherited(arguments);
+               this.n = 0;
+       },
+       start: function() {
+               if (!this.timer)
+                       this.timer = setInterval(this.draw.bind(this), 33);
+       },
+       stop: function() {
+               clearInterval(this.timer);
+               this.timer = null;
+       },
+       draw: function() {
+               this.n--;
+               if (this.n == -1600)
+                      this.n = 0;
+
+               this.$.clouds.applyStyle("background-position", (this.n * 1.5) + "px top");
+               this.$.mountains.applyStyle("background-position", (this.n * 2.5) + "px top");
+               this.$.trees.applyStyle("background-position", (this.n * 7.5) + "px top");
+       }
+});
diff --git a/hacks/Landscape/clouds.png b/hacks/Landscape/clouds.png
new file mode 100644 (file)
index 0000000..7c7fe85
Binary files /dev/null and b/hacks/Landscape/clouds.png differ
diff --git a/hacks/Landscape/mountains.png b/hacks/Landscape/mountains.png
new file mode 100644 (file)
index 0000000..99a5a51
Binary files /dev/null and b/hacks/Landscape/mountains.png differ
diff --git a/hacks/Landscape/trees.png b/hacks/Landscape/trees.png
new file mode 100644 (file)
index 0000000..c395192
Binary files /dev/null and b/hacks/Landscape/trees.png differ
diff --git a/hacks/Munch/Munch.js b/hacks/Munch/Munch.js
new file mode 100644 (file)
index 0000000..2acc90a
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+enyo.kind({
+       name: 'Munch',
+       kind: 'Hack',
+       pack: "center",
+       align: "center",
+       style: "background-color: black",
+       components: [
+               {kind: enyo.Control, nodeTag: "canvas", name: "display", width: "512px", height: "512px"}
+       ],
+
+       t: 0,
+       timer: null,
+
+       rendered: function() {
+               var node = this.$.display.hasNode();
+               node.width = 256;
+               node.height = 256;
+               this.ctx = node.getContext('2d');
+               this.ctx.fillStyle = 'black';
+               this.ctx.fillRect(0, 0, 255, 255);
+               this.ctx.fillStyle = 'rgba(0,0,0,0.075)';
+               this.ctx.strokeStyle = '#00FF00';
+               this.draw();
+       },
+
+       draw: function() {
+               this.ctx.fillRect(0, 0, 256, 256);
+               this.ctx.beginPath();
+               for (var x = 0; x < 256; x++) {
+                       var y = x ^ this.t;
+                       this.ctx.moveTo(x, y);
+                       this.ctx.lineTo(x+1, y+1);
+               }
+               this.ctx.stroke();
+               this.t = (this.t + 1) % 255;
+       },
+
+       start: function() {
+               if (this.timer) return;
+               this.timer = setInterval(this.draw.bind(this), 20);
+       },
+
+       stop: function() {
+               clearInterval(this.timer);
+               this.timer = null;
+       }
+});
diff --git a/hacks/Nimbus/Nimbus.js b/hacks/Nimbus/Nimbus.js
new file mode 100644 (file)
index 0000000..f8ed719
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+enyo.kind({
+       name: "Drop",
+       constructor: function() {
+               this.live = false;
+       },
+       start: function(w, h, perspective) {
+               this.x = Math.random() * w;
+               this.y = (Math.random() * h) / perspective;
+               this.t = (new Date()).getTime();
+               this.live = true;
+       },
+       draw: function(ctx, t) {
+               var dt = t - this.t;
+               if (dt < 100) {
+                       ctx.save();
+                       ctx.globalAlpha = 0.25;
+                       ctx.beginPath();
+                       ctx.moveTo(this.x, 0);
+                       ctx.lineTo(this.x, this.y);
+                       ctx.stroke();
+                       ctx.restore();
+               } else if (dt < 750) {
+                       ctx.save();
+                       ctx.globalAlpha = (1.0 - ((dt - 500) / 250));
+                       ctx.beginPath();
+                       ctx.arc(this.x, this.y, Math.sqrt(dt) * 5, 0, 2 * Math.PI, false);
+                       ctx.stroke();
+                       ctx.restore();
+               } else {
+                       this.live = false;
+               }
+       }
+});
+
+enyo.kind({
+       name: "Nimbus",
+       kind: "Hack",
+       style: "background-color: white",
+       drop_c: 0,
+       drops: [],
+       perspective: 0.3,
+       components: [
+               {name: "raindrops", nodeTag: "canvas"}
+       ],
+       rendered: function() {
+               this.raindrops = this.$.raindrops.hasNode();
+               this.ctx = this.raindrops.getContext('2d');
+               this.resize(window.innerWidth, window.innerHeight);
+
+               for (var i = 0; i < 100; i++)
+                       this.drops.push(new Drop());
+       },
+       start: function() {
+               if (!this.timer)
+                       this.timer = setInterval(this.draw.bind(this), 50);
+       },
+       stop: function() {
+               clearInterval(this.timer);
+               this.timer = null;
+       },
+       resize: function(w, h) {
+               this.raindrops.width = this.w = w;
+               this.raindrops.height = this.h = h;
+
+               this.ctx.fillStyle = 'rgba(255,255,255,0.7)';
+               this.ctx.strokeStyle = 'rgb(128,128,128)';
+               this.ctx.lineWidth = '2';
+       },
+       draw: function() {
+               if (Math.random() > 0.3) {
+                       this.drops[this.drop_c].start(this.w, this.h, this.perspective);
+                       this.drop_c = (this.drop_c + 1) % 100;
+               }
+               var now = (new Date()).getTime();
+               this.ctx.fillRect(0, 0, this.w, this.h);
+               this.ctx.save();
+               this.ctx.scale(1.0, this.perspective);
+               for (var i = 0; i < this.drops.length; i++)
+                       if (this.drops[i].live)
+                               this.drops[i].draw(this.ctx, now);
+               this.ctx.restore();
+       }
+});
diff --git a/hacks/Orbit/Orbit.js b/hacks/Orbit/Orbit.js
new file mode 100644 (file)
index 0000000..0bc7fac
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+enyo.kind({
+       name: "Orbit",
+       kind: "Hack",
+       pack: "center",
+       align: "center",
+       style: "background-color: lightgray",
+       components: [
+               {kind: "Control", nodeTag: "canvas", name: "canvas", width: "250px", height: "250px"}
+       ],
+       rendered: function() {
+               var canvas = this.$.canvas.hasNode();
+               canvas.width = 250;
+               canvas.height = 250;
+               this.context = canvas.getContext('2d');
+
+               this.center_x = canvas.width / 2;
+               this.center_y = canvas.height / 2;
+               this.radius = 100;
+               this.zr = 0;
+               this.xr = 0;
+
+               this.chromeball = new Image();
+               this.chromeball.onload = this.setReady.bind(this);
+               this.chromeball.src = "hacks/orbit/chrome_ball.png";
+       },
+       setReady: function() {
+               this.ready = true;
+               this.engine();
+       },
+       start: function() {
+               if (this.ready && !this.timer)
+                       this.timer = setInterval(this.engine.bind(this), 20);
+       },
+       stop: function() {
+               clearInterval(this.timer);
+               this.timer = null;
+       },
+       engine: function() {
+               this.context.clearRect(this.center_x - this.radius - 25, this.center_y - this.radius - 25, this.radius * 2 + 50, this.radius * 2 + 50);
+               this.zr += 0.1;
+               this.xr += 0.05;
+               var objects = [];
+               for (var i = 0; i < 8; i++) {
+                       var czr = this.zr + i * Math.PI/4;
+                       var cxr = this.xr + Math.PI + i * Math.PI/4;
+                       var cx = this.center_x + this.radius * Math.sin(czr);
+                       var cy = this.center_y + this.radius * Math.cos(czr) * Math.cos(this.xr);
+                       var r = 20 + 10 * Math.cos(czr) * Math.cos(this.xr + Math.PI/2);
+
+                       objects.push({
+                               x: cx - r,
+                               y: cy - r,
+                               s: r * 2
+                       });
+               }
+               // Sort by size to simulate z-ordering
+               objects.sort(function(a,b) {
+                       return a.s - b.s;
+               });
+               for (var i = 0; i < 8; i++)
+                       this.context.drawImage(this.chromeball, objects[i].x, objects[i].y, objects[i].s, objects[i].s);
+       }
+});
diff --git a/hacks/Orbit/chrome_ball.png b/hacks/Orbit/chrome_ball.png
new file mode 100644 (file)
index 0000000..6614330
Binary files /dev/null and b/hacks/Orbit/chrome_ball.png differ
diff --git a/hacks/Pixelfade/Pixelfade.js b/hacks/Pixelfade/Pixelfade.js
new file mode 100644 (file)
index 0000000..b91d5d2
--- /dev/null
@@ -0,0 +1,148 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+enyo.kind({
+       name: "Pixelfade",
+       kind: "Hack",
+       style: "background-color: yellow; background-position: center center",
+       components: [
+               {name: "canvas", nodeTag: "canvas", onclick: "canvasClick"},
+               {name: "wallpaperService", kind: "PalmService",
+                service: 'palm://com.palm.systemservice',
+                method: 'getPreferences',
+                onSuccess: "gotWallpaper"}
+       ],
+       create: function() {
+               this.inherited(arguments);
+               this.$.wallpaperService.call({
+                       keys: ['wallpaper'],
+                       subscribe: false
+               });
+       },
+       rendered: function() {
+               this.canvas = this.$.canvas.hasNode();
+               this.context = this.canvas.getContext('2d');
+               this.resize(window.innerWidth, window.innerHeight);
+               this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
+
+               this.faders = [];
+               for (var i = 0; i < 10; i++) {
+                       var img = new Image();
+                       img.src = "hacks/Pixelfade/pixelfade" + i + ".gif";
+                       this.faders.push(img);
+               }
+       },
+       start: function() {
+               this.resize(window.innerWidth, window.innerHeight);
+
+               if (this.timer)
+                       clearInterval(this.timer);
+               this.fade_val = 9;
+               this.fade_dir = -1;
+               this.fade_end = -1;
+               this.timer = setInterval(this.fade_all.bind(this), 50);
+
+               if (!this.spotTimer)
+                       this.spotTimer = setInterval(this.do_fade_spot.bind(this), 3000);
+       },
+       stop: function() {
+               clearInterval(this.timer);
+               this.timer = null;
+               clearInterval(this.spotTimer);
+               this.spotTimer = null;
+               clearTimeout(this.fadeInTimer);
+               this.fadeInTimer = null;
+       },
+       resize: function(w, h) {
+               this.canvas.style.width = w + 'px';
+               this.canvas.style.height = h + 'px';
+               this.canvas.width = w;
+               this.canvas.height = h;
+               this.context.fillColor = 'black';
+               this.context.fillRect(0, 0, w, h);
+       },
+       hidden: function() {
+               this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
+       },
+       canvasClick: function(inSender, inEvent) {
+               clearTimeout(this.fadeInTimer);
+               clearInterval(this.spotTimer);
+               this.spotTimer = setInterval(this.do_fade_spot.bind(this), 3000);
+               this.fader_go(inEvent.clientX, inEvent.clientY);
+       },
+       gotWallpaper: function(inSender, inResponse) {
+               enyo.log("got background: " + JSON.stringify(inResponse));
+               this.setStyle('background-image: url(' + inResponse.wallpaper.wallpaperFile + '); background-alignment: center center');
+       },
+       do_fade_spot: function() {
+               var x = Math.floor(Math.random() * this.canvas.width);
+               var y = Math.floor(Math.random() * this.canvas.height);
+               this.fader_go(x, y);
+       },
+       fade_all: function() {
+               this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
+               if (this.fade_val == this.fade_end) {
+                       clearInterval(this.timer);
+                       this.timer = null;
+                       if (this.fade_dir == -1)
+                               this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
+                       else
+                               this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
+               } else {
+                       for (var x = 0; x < this.canvas.width; x += 64) {
+                               for (var y = 0; y < this.canvas.height; y += 64) {
+                                       this.context.drawImage(this.faders[this.fade_val], x, y);
+                               }
+                       }
+               }
+               this.fade_val += this.fade_dir;
+       },
+       fader_go: function(x, y) {
+               this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
+               this.fader_count = 0;
+               this.time_faders(x, y);
+               this.faderptr = new Array(10);
+               for (var i=0; i < 10; i++)
+                       this.faderptr[i] = 0;
+               this.t0 = (new Date()).getTime();
+               this.faderRunning = true;
+               clearInterval(this.timer);
+               this.timer = setInterval(this.fader.bind(this), 50);
+       },
+       time_faders: function(xpos, ypos) {
+               this.fadertimes = [];
+               for (var y = 0; y < this.canvas.height; y += 64) {
+                       for (var x = 0; x < this.canvas.width; x += 64) {
+                               var xd = x - xpos;
+                               var yd = y - ypos;
+                               this.fadertimes.push({
+                                       t: 125 - Math.sqrt(xd*xd + yd*yd) / 8,
+                                       x: x,
+                                       y: y
+                               });
+                       }
+               }
+               this.fadertimes.sort(function(a, b) { return a.t - b.t });
+       },
+       fader: function() {
+               var tnow = (new Date()).getTime();
+               var td = (tnow - this.t0) / 8.0;
+               for (var i = 0; i < 10; i++) {
+                       while (this.faderptr[i] < this.fadertimes.length && this.fadertimes[this.faderptr[i]].t < td - i * 10) {
+                               var xpos = this.fadertimes[this.faderptr[i]].x;
+                               var ypos = this.fadertimes[this.faderptr[i]].y;
+                               this.context.clearRect(xpos, ypos, 64, 64);
+                               this.context.drawImage(this.faders[i], xpos, ypos);
+                               this.faderptr[i]++;
+                       }
+               }
+               if (this.faderptr[9] >= this.fadertimes.length) {
+                       clearTimeout(this.timer);
+                       this.fadeInTimer = setTimeout(function() {
+                               this.fade_val = 9;
+                               this.fade_dir = -1;
+                               this.fade_end = -1;
+                               this.timer = setInterval(this.fade_all.bind(this), 50);
+                       }.bind(this), 750);
+               }
+       }
+});
diff --git a/hacks/Pixelfade/pixelfade0.gif b/hacks/Pixelfade/pixelfade0.gif
new file mode 100644 (file)
index 0000000..5521700
Binary files /dev/null and b/hacks/Pixelfade/pixelfade0.gif differ
diff --git a/hacks/Pixelfade/pixelfade1.gif b/hacks/Pixelfade/pixelfade1.gif
new file mode 100644 (file)
index 0000000..f4dda0e
Binary files /dev/null and b/hacks/Pixelfade/pixelfade1.gif differ
diff --git a/hacks/Pixelfade/pixelfade2.gif b/hacks/Pixelfade/pixelfade2.gif
new file mode 100644 (file)
index 0000000..20ef3ed
Binary files /dev/null and b/hacks/Pixelfade/pixelfade2.gif differ
diff --git a/hacks/Pixelfade/pixelfade3.gif b/hacks/Pixelfade/pixelfade3.gif
new file mode 100644 (file)
index 0000000..d586808
Binary files /dev/null and b/hacks/Pixelfade/pixelfade3.gif differ
diff --git a/hacks/Pixelfade/pixelfade4.gif b/hacks/Pixelfade/pixelfade4.gif
new file mode 100644 (file)
index 0000000..dd226d9
Binary files /dev/null and b/hacks/Pixelfade/pixelfade4.gif differ
diff --git a/hacks/Pixelfade/pixelfade5.gif b/hacks/Pixelfade/pixelfade5.gif
new file mode 100644 (file)
index 0000000..c7f2eed
Binary files /dev/null and b/hacks/Pixelfade/pixelfade5.gif differ
diff --git a/hacks/Pixelfade/pixelfade6.gif b/hacks/Pixelfade/pixelfade6.gif
new file mode 100644 (file)
index 0000000..c4633ce
Binary files /dev/null and b/hacks/Pixelfade/pixelfade6.gif differ
diff --git a/hacks/Pixelfade/pixelfade7.gif b/hacks/Pixelfade/pixelfade7.gif
new file mode 100644 (file)
index 0000000..5bc10e1
Binary files /dev/null and b/hacks/Pixelfade/pixelfade7.gif differ
diff --git a/hacks/Pixelfade/pixelfade8.gif b/hacks/Pixelfade/pixelfade8.gif
new file mode 100644 (file)
index 0000000..93cef76
Binary files /dev/null and b/hacks/Pixelfade/pixelfade8.gif differ
diff --git a/hacks/Pixelfade/pixelfade9.gif b/hacks/Pixelfade/pixelfade9.gif
new file mode 100644 (file)
index 0000000..f72f9f9
Binary files /dev/null and b/hacks/Pixelfade/pixelfade9.gif differ
diff --git a/hacks/Swarm/Swarm.js b/hacks/Swarm/Swarm.js
new file mode 100644 (file)
index 0000000..cfe7f32
--- /dev/null
@@ -0,0 +1,137 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+enyo.kind({
+       name: "Pixel",
+       constructor: function(canvas) {
+               this.x = Math.random() * canvas.width;
+               this.y = Math.random() * canvas.height;
+               this.vx = Math.random() * 20.0 - 10.0;
+               this.vy = Math.random() * 20.0 - 10.0;
+               this.lastupdate = (new Date()).getTime();
+       },
+       accel: function(x, y) {
+               this.vx += x;
+               if (this.vx > 200.0)
+                       this.vx = 200.0;
+               else if (this.vx < -200.0)
+                       this.vx = -200.0;
+               this.vy += y;
+               if (this.vy > 200.0)
+                       this.vy = 200.0;
+               else if (this.vy < -200.0)
+                       this.vy = -200.0;
+       },
+       update: function() {
+               var now = (new Date()).getTime();
+               var dt = (now - this.lastupdate) / 75.0;
+               this.x += this.vx * dt;
+               this.y += this.vy * dt;
+               this.lastupdate = now;
+       },
+       draw: function(ctx) {   
+               ctx.beginPath();
+               ctx.moveTo(this.x,this.y);
+               ctx.lineTo(this.x - this.vx / 4.0, this.y - this.vy / 4.0);
+               ctx.stroke();
+               ctx.closePath();
+       }       
+});
+
+enyo.kind({
+       name: "Swarm",
+       kind: "Hack",
+       align: "stretch",
+       pack: "stretch",
+       components: [
+               {name: "canvas", nodeTag: "canvas", style: "background-color: gray",
+                onmousemove: "mouseMove", onmousedown: "mouseDown"}
+       ],
+       npixels: 100,
+       pixels: [],
+       rendered: function() {
+               this.canvas = this.$.canvas.hasNode();
+               this.resize();
+               this.mx = this.canvas.width / 2;
+               this.my = this.canvas.width / 2;
+               for (var x = 0; x < this.npixels; x++)
+                       this.pixels.push(new Pixel(this.canvas));
+               //this.stopTime = (new Date()).getTime();
+               this.engine();
+       },
+       start: function() {
+               if (this.stopTime) {
+                       var delta = (new Date()).getTime() - this.stopTime;
+                       for (var i = 0; i < this.npixels; i++)
+                               this.pixels[i].lastupdate += delta;
+                       this.stopTime = null;
+               }
+               if (!this.timer)
+                       this.timer = setInterval(this.engine.bind(this), 20);
+       },
+       stop: function() {
+               this.stopTime = (new Date()).getTime();
+               clearInterval(this.timer);
+               this.timer = null;
+       },
+       resize: function(w, h) {
+               this.canvas.width = w;
+               this.canvas.height = h;
+               //this.canvas.style.width = w + 'px';
+               //this.canvas.style.height = h + 'px';
+               this.context = this.canvas.getContext('2d');
+               this.context.strokeStyle = '#000000';
+               this.context.lineCap = 'round';
+               this.context.lineWidth = 1.5;
+       },
+       mouseMove: function(inSender, inEvent) {
+               this.mx = inEvent.clientX;
+               this.my = inEvent.clientY;
+       },
+       mouseDown: function(inSender, inEvent) {
+               this.mouseMove(inSender, inEvent);
+               // Apply force to each pixel outwards from the mouse
+               for (var i = 0; i < this.npixels; i++) {
+                       // Get the direction
+                       var dx = this.pixels[i].x - inEvent.clientX;
+                       var dy = this.pixels[i].y - inEvent.clientY;
+                       var mag = Math.sqrt(dx*dx + dy*dy);
+                       dx /= mag;
+                       dy /= mag;
+
+                       // Apply force.
+                       this.pixels[i].accel(dx * 40.0, dy * 40.0);
+               }
+       },
+       engine: function() {
+               // Clear the canvas
+               this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
+               // Update all pixel objects
+               for (var i = 0; i < this.npixels; i++) {
+                       // Get distance
+                       var dx = this.mx - this.pixels[i].x;
+                       var dy = this.my - this.pixels[i].y;
+                       var d = Math.sqrt(dx*dx + dy*dy);
+
+                       // Apply acceleration to pixels towards the mouse cursor
+                       var ax = dx / 50.0;
+                       var ay = dy / 50.0;
+
+                       // Apply a drag proportional to the distance from the cursor
+                       if (d > 100.0) {
+                               ax += -this.pixels[i].vx * (d - 100.0) / 2000.0;
+                               ay += -this.pixels[i].vy * (d - 100.0) / 2000.0;
+                       }
+
+                       // And a "chaotic" acceleration inversely proportional
+                       // to the distance from the cursor
+                       ax += (Math.random() * 160.0 - 80.0) / d;
+                       ay += (Math.random() * 160.0 - 80.0) / d;
+
+                       this.pixels[i].accel(ax,ay);
+                       this.pixels[i].update();
+                       this.pixels[i].draw(this.context);
+               }
+
+               this.context.strokeRect(this.mx - 10, this.my - 10, 20, 20);
+       }
+});
diff --git a/hacks/XSpinner/XSpinner.js b/hacks/XSpinner/XSpinner.js
new file mode 100644 (file)
index 0000000..9fd0a33
--- /dev/null
@@ -0,0 +1,80 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+enyo.kind({
+       name: "XSpinner",
+       kind: "Hack",
+       style: "background-color: black; color: #00FF00; font-family: Courier, sans-serif; font-size: 12px",
+       pack: "center",
+       align: "center",
+       components: [
+               {style: "border: 2px solid green; padding: 4px", components: [
+                       {name: "terminal", nodeTag: "pre", style: "margin: 0"},
+                       {nodeTag: "pre", style: "margin: 0",
+content: "SESSION 1      80x24                                           CAPS NUM SCR <span style=\"color: black; background-color: #00FF00\" id=\"spinner_blinker\">RAVE</blink>"}
+               ]}
+       ],
+       create: function() {
+               this.inherited(arguments);
+               this.w = 80;
+               this.h = 24;
+               this.delay = 20;
+               this.rate = 360.0 / 1000.0;
+               this.cw = this.w / 2;
+               this.ch = this.h / 2;
+       },
+       rendered: function() {
+               this.terminal = this.$.terminal.hasNode();
+               this.blinker = document.getElementById('spinner_blinker');
+               this.blink_active = true;
+               this.spinner();
+       },
+       start: function() {
+               if (!this.timer) {
+                       this.timer = setInterval(this.spinner.bind(this), this.delay);
+                       this.blinkerTimer = setInterval(this.blink.bind(this), 500);
+               }
+       },
+       stop: function() {
+               clearInterval(this.timer);
+               clearInterval(this.blinkerTimer);
+               this.timer = null;
+               this.blinkerTimer = null;
+       },
+       spinner: function() {
+               // Get date
+               var ms = (new Date()).getMilliseconds();
+               var r = ms * this.rate;
+               var a = Math.tan((r / 180.0) * Math.PI);
+               var b = Math.tan(((r+90) / 180.0) * Math.PI);
+
+               var t = '';
+               for (var j=0; j < this.h; j++) {
+                       for (var i=0; i < this.w; i++) {
+                               if ((r > 90 && r <= 180) || (r > 270 && r < 360) || r == 0) {
+                                       if ((j-this.ch) * 2 > a * (i-this.cw) && (j-this.ch) * 2 < b * (i-this.cw) ||
+                                           (j-this.ch) * 2 < a * (i-this.cw) && (j-this.ch) * 2 > b * (i-this.cw) ) {
+                                               t += '*';
+                                       } else {
+                                               t += ' ';
+                                       }
+                               } else {
+                                       if ((j-this.ch) * 2 > a * (i-this.cw) && (j-this.ch) * 2 > b * (i-this.cw) ||
+                                           (j-this.ch) * 2 < a * (i-this.cw) && (j-this.ch) * 2 < b * (i-this.cw) ) {
+                                               t += '*';
+                                       } else {
+                                               t += ' ';
+                                       }
+                               }
+                       }
+                       t += "\n";
+               }
+               this.terminal.innerHTML = t;
+       },
+       blink: function() {
+               if (this.blink_active)
+                       this.blinker.style.color = '#00FF00';
+               else
+                       this.blinker.style.color = 'black';
+               this.blink_active = !this.blink_active;
+       }
+});
diff --git a/hacks/XSpinnerCGA/XSpinnerCGA.js b/hacks/XSpinnerCGA/XSpinnerCGA.js
new file mode 100644 (file)
index 0000000..9ff7634
--- /dev/null
@@ -0,0 +1,78 @@
+/* Copyright 2011 The Dominion of Awesome
+ * See COPYING for licensing information */
+enyo.kind({
+       name: "XSpinnerCGA",
+       kind: "Hack",
+       style: "background-color: black",
+       pack: "center",
+       align: "center",
+       components: [
+               {style: "border: 2px solid green; padding: 4px", components: [
+                       {name: "terminal", nodeTag: "pre", style: "margin: 0; font-family: PCSenior; font-size: 16px"}
+               ]}
+       ],
+       create: function() {
+               this.inherited(arguments);
+               this.w = 40;
+               this.h = 24;
+               this.delay = 20;
+               this.rate = 360.0 / 1000.0;
+               this.cw = this.w / 2;
+               this.ch = this.h / 2;
+       },
+       rendered: function() {
+               this.terminal = this.$.terminal.hasNode();
+               this.blinker = document.getElementById('spinner_blinker');
+               this.blink_active = true;
+               this.spinner();
+       },
+       start: function() {
+               if (!this.timer) {
+                       this.timer = setInterval(this.spinner.bind(this), this.delay);
+                       this.blinkerTimer = setInterval(this.blink.bind(this), 500);
+               }
+       },
+       stop: function() {
+               clearInterval(this.timer);
+               clearInterval(this.blinkerTimer);
+               this.timer = null;
+               this.blinkerTimer = null;
+       },
+       spinner: function() {
+               // Get date
+               var ms = (new Date()).getMilliseconds();
+               var r = ms * this.rate;
+               var a = Math.tan((r / 180.0) * Math.PI);
+               var b = Math.tan(((r+90) / 180.0) * Math.PI);
+
+               var t = '';
+               for (var j=0; j < this.h; j++) {
+                       for (var i=0; i < this.w; i++) {
+                               if ((r > 90 && r <= 180) || (r > 270 && r < 360) || r == 0) {
+                                       if ((j-this.ch) * 2 > a * (i-this.cw) && (j-this.ch) * 2 < b * (i-this.cw) ||
+                                           (j-this.ch) * 2 < a * (i-this.cw) && (j-this.ch) * 2 > b * (i-this.cw) ) {
+                                               t += '*';
+                                       } else {
+                                               t += ' ';
+                                       }
+                               } else {
+                                       if ((j-this.ch) * 2 > a * (i-this.cw) && (j-this.ch) * 2 > b * (i-this.cw) ||
+                                           (j-this.ch) * 2 < a * (i-this.cw) && (j-this.ch) * 2 < b * (i-this.cw) ) {
+                                               t += '*';
+                                       } else {
+                                               t += ' ';
+                                       }
+                               }
+                       }
+                       t += "\n";
+               }
+               this.terminal.innerHTML = t;
+       },
+       blink: function() {
+               if (this.blink_active)
+                       this.blinker.style.color = '#00FF00';
+               else
+                       this.blinker.style.color = 'black';
+               this.blink_active = !this.blink_active;
+       }
+});
diff --git a/icon.png b/icon.png
new file mode 100644 (file)
index 0000000..f5d77e6
Binary files /dev/null and b/icon.png differ
diff --git a/icon_48.png b/icon_48.png
new file mode 100644 (file)
index 0000000..6a77b6a
Binary files /dev/null and b/icon_48.png differ
diff --git a/index.html b/index.html
new file mode 100644 (file)
index 0000000..95db2f1
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<!-- Copyright 2011 The Dominion of Awesome
+     See COPYING for license information -->
+<html>
+<head>
+<title>Hacks!</title>
+<script src="/Program%20Files%20(x86)/HP%20webOS/SDK/share/refcode/webos-framework/enyo/1.0/framework/enyo.js" type="text/javascript"></script>
+</head>
+<body>
+<script type="text/javascript">
+var munch = enyo.create({kind: "Main"}).renderInto(document.body);
+</script>
+</body>
+</html>