diff --git a/mergejs.js b/mergejs.js
index 821fe8d..6692b72 100644
--- a/mergejs.js
+++ b/mergejs.js
@@ -26,4 +26,5 @@ ${modSource}
`);
});
-fs.writeSync(1, outputCode.join('\n'));
+fs.writeSync(1, outputCode.map(a => a.trim()).join('\n'));
+
diff --git a/public/index.html b/public/index.html
index b6dde28..5beb735 100644
--- a/public/index.html
+++ b/public/index.html
@@ -6,6 +6,7 @@
+
diff --git a/src/js/assets.js b/src/js/assets.js
new file mode 100644
index 0000000..c575954
--- /dev/null
+++ b/src/js/assets.js
@@ -0,0 +1,79 @@
+const ProgressBar=require('progress');
+
+const assetSpecs=[
+ { name: 'fruit', filename: 'apple32.png', type: 'image' },
+ { name: 'wall', filename: 'wall32.png', type: 'image' },
+ { name: 'snake', filename: 'snake.json', type: 'json' }
+];
+
+const cvs=document.createElement('canvas');
+cvs.width=400;
+cvs.height=50;
+cvs.classList.add('progressBar');
+cvs.classList.add('hiddenBottom');
+
+const bar=new ProgressBar(assetSpecs.length*2);
+bar.addUpdateListener(() => bar.draw(cvs));
+bar.draw(cvs);
+
+document.body.appendChild(cvs);
+setTimeout(() => cvs.classList.remove('hiddenBottom'), 0);
+
+bar.addReadyListener(() => {
+ cvs.classList.add('hiddenBottom');
+ setTimeout(() => document.body.removeChild(cvs), 1000);
+});
+
+//XXX purposefully slow down asset loading
+const sleep=(ms) => new Promise(ok => setTimeout(ok, ms));
+
+const loadAsset=async (asset) => {
+ const response=await fetch('assets/'+asset.filename);
+ await sleep(1000*Math.random());
+ bar.update();
+ let result;
+ switch(asset.type) {
+ case 'json':
+ result=await response.json();
+ break;
+
+ case 'image':
+ result=await createImageBitmap(await response.blob());
+ break;
+ }
+ await sleep(1000*Math.random());
+ bar.update();
+ return [asset.name, result];
+};
+
+let assets=Object.create(null);
+let ready=false;
+let readyListeners=[];
+
+Promise
+ .all(
+ assetSpecs.map(a => loadAsset(a))
+ ).then(arr => {
+ arr.forEach(([name, value]) => {
+ assets[name]=value;
+ });
+ ready=true;
+ readyListeners.forEach(fn => fn.bind(fn)());
+ readyListeners=null;
+ });
+
+const onReady=(fn) => {
+ if(ready) fn.bind(fn)();
+ else readyListeners.push(ready);
+};
+
+const get=(name) => {
+ let asset=assets[name];
+ if(!asset) throw new Error("Unknown asset: "+name);
+ return asset;
+};
+
+return {
+ onReady, get
+};
+
diff --git a/src/js/progress.js b/src/js/progress.js
new file mode 100644
index 0000000..973f0bc
--- /dev/null
+++ b/src/js/progress.js
@@ -0,0 +1,44 @@
+class ProgressBar {
+ constructor(taskCount) {
+ this.taskCount=taskCount;
+ this.completeCount=0;
+ this.updateListeneres=[];
+ }
+
+ get percent() {
+ return Math.floor(this.completeCount/this.taskCount*100);
+ }
+
+ get ready() {
+ return this.completeCount==this.taskCount;
+ }
+
+ addUpdateListener(fn) {
+ this.updateListeneres.push(fn.bind(this));
+ }
+ addReadyListener(fn) {
+ this.updateListeneres.push(() => {
+ if(this.ready) fn.bind(this)();
+ });
+ }
+
+ update() {
+ this.completeCount++;
+ this.updateListeneres.forEach(l => l(this));
+ }
+
+ draw(canvas, bgColor='red', textColor='black') {
+ let ctx=canvas.getContext('2d');
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ ctx.fillStyle=bgColor;
+ ctx.fillRect(0, 0, canvas.width*this.completeCount/this.taskCount, canvas.height);
+ ctx.fillStyle=textColor;
+ ctx.textAlign='center';
+ ctx.textBaseline='center';
+ ctx.font=`${canvas.height/2}px 'Fira Code'`;
+ ctx.fillText(this.percent+'%', canvas.width/2, canvas.height/2);
+ }
+}
+
+return ProgressBar;
+
diff --git a/src/js/snek.js b/src/js/snek.js
index f32c0cb..b577f14 100644
--- a/src/js/snek.js
+++ b/src/js/snek.js
@@ -1,4 +1,4 @@
-const Assets=require('assets');
+const assets=require('assets');
const [EMPTY, FOOD, WALL, SNAKE]=Array(4).keys();
@@ -47,7 +47,7 @@ class SnekGame {
const offsetY=(this.canvas.height-cellSize*this.dimensions[1])/2;
// draw our walls
- const wall=Assets.get('wall');
+ const wall=assets.get('wall');
for(let x=0; x {
this.ctx.drawImage(
fruit,
diff --git a/fullreset.less b/src/less/fullreset.less
similarity index 100%
rename from fullreset.less
rename to src/less/fullreset.less
diff --git a/src/less/progressBar.less b/src/less/progressBar.less
new file mode 100644
index 0000000..38c9854
--- /dev/null
+++ b/src/less/progressBar.less
@@ -0,0 +1,15 @@
+.progressBar {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ background: white;
+ box-shadow: black 0 0 2rem;
+ border-radius: 100vh;
+ transform: translate(-50%, -50%);
+ transition: top .5s ease-in-out;
+
+ &.hiddenBottom {
+ top: 200vh;
+ }
+}
+
diff --git a/src/less/snek.less b/src/less/snek.less
index d24f1c5..469f7ac 100644
--- a/src/less/snek.less
+++ b/src/less/snek.less
@@ -79,3 +79,6 @@ h2 {
p {
font-size: 1.6rem;
}
+
+// setup the progress bar
+@import 'progressBar';